From c43d0188d7be6e45eb52a27ed9df714ca2e04e0a Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Tue, 11 Dec 2012 12:01:42 +0000 Subject: drm/i915: Fixup cursor latency used for IVB lp3 watermarks It operates at twice the declared latency, so adjust the computation to avoid potential flicker at low power. Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=50248 Signed-off-by: Chris Wilson CC: Jesse Barnes Reviewed-by: Jesse Barnes Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_pm.c | 117 ++++++++++++++++++++++++++++++++++++++-- 1 file changed, 112 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 42839fc73499..9f1ee07ec4ae 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -1811,8 +1811,110 @@ static void sandybridge_update_wm(struct drm_device *dev) enabled |= 2; } - if ((dev_priv->num_pipe == 3) && - g4x_compute_wm0(dev, 2, + /* + * Calculate and update the self-refresh watermark only when one + * display plane is used. + * + * SNB support 3 levels of watermark. + * + * WM1/WM2/WM2 watermarks have to be enabled in the ascending order, + * and disabled in the descending order + * + */ + I915_WRITE(WM3_LP_ILK, 0); + I915_WRITE(WM2_LP_ILK, 0); + I915_WRITE(WM1_LP_ILK, 0); + + if (!single_plane_enabled(enabled) || + dev_priv->sprite_scaling_enabled) + return; + enabled = ffs(enabled) - 1; + + /* WM1 */ + if (!ironlake_compute_srwm(dev, 1, enabled, + SNB_READ_WM1_LATENCY() * 500, + &sandybridge_display_srwm_info, + &sandybridge_cursor_srwm_info, + &fbc_wm, &plane_wm, &cursor_wm)) + return; + + I915_WRITE(WM1_LP_ILK, + WM1_LP_SR_EN | + (SNB_READ_WM1_LATENCY() << WM1_LP_LATENCY_SHIFT) | + (fbc_wm << WM1_LP_FBC_SHIFT) | + (plane_wm << WM1_LP_SR_SHIFT) | + cursor_wm); + + /* WM2 */ + if (!ironlake_compute_srwm(dev, 2, enabled, + SNB_READ_WM2_LATENCY() * 500, + &sandybridge_display_srwm_info, + &sandybridge_cursor_srwm_info, + &fbc_wm, &plane_wm, &cursor_wm)) + return; + + I915_WRITE(WM2_LP_ILK, + WM2_LP_EN | + (SNB_READ_WM2_LATENCY() << WM1_LP_LATENCY_SHIFT) | + (fbc_wm << WM1_LP_FBC_SHIFT) | + (plane_wm << WM1_LP_SR_SHIFT) | + cursor_wm); + + /* WM3 */ + if (!ironlake_compute_srwm(dev, 3, enabled, + SNB_READ_WM3_LATENCY() * 500, + &sandybridge_display_srwm_info, + &sandybridge_cursor_srwm_info, + &fbc_wm, &plane_wm, &cursor_wm)) + return; + + I915_WRITE(WM3_LP_ILK, + WM3_LP_EN | + (SNB_READ_WM3_LATENCY() << WM1_LP_LATENCY_SHIFT) | + (fbc_wm << WM1_LP_FBC_SHIFT) | + (plane_wm << WM1_LP_SR_SHIFT) | + cursor_wm); +} + +static void ivybridge_update_wm(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + int latency = SNB_READ_WM0_LATENCY() * 100; /* In unit 0.1us */ + u32 val; + int fbc_wm, plane_wm, cursor_wm; + int ignore_fbc_wm, ignore_plane_wm, ignore_cursor_wm; + unsigned int enabled; + + enabled = 0; + if (g4x_compute_wm0(dev, 0, + &sandybridge_display_wm_info, latency, + &sandybridge_cursor_wm_info, latency, + &plane_wm, &cursor_wm)) { + val = I915_READ(WM0_PIPEA_ILK); + val &= ~(WM0_PIPE_PLANE_MASK | WM0_PIPE_CURSOR_MASK); + I915_WRITE(WM0_PIPEA_ILK, val | + ((plane_wm << WM0_PIPE_PLANE_SHIFT) | cursor_wm)); + DRM_DEBUG_KMS("FIFO watermarks For pipe A -" + " plane %d, " "cursor: %d\n", + plane_wm, cursor_wm); + enabled |= 1; + } + + if (g4x_compute_wm0(dev, 1, + &sandybridge_display_wm_info, latency, + &sandybridge_cursor_wm_info, latency, + &plane_wm, &cursor_wm)) { + val = I915_READ(WM0_PIPEB_ILK); + val &= ~(WM0_PIPE_PLANE_MASK | WM0_PIPE_CURSOR_MASK); + I915_WRITE(WM0_PIPEB_ILK, val | + ((plane_wm << WM0_PIPE_PLANE_SHIFT) | cursor_wm)); + DRM_DEBUG_KMS("FIFO watermarks For pipe B -" + " plane %d, cursor: %d\n", + plane_wm, cursor_wm); + enabled |= 2; + } + + if (g4x_compute_wm0(dev, 2, &sandybridge_display_wm_info, latency, &sandybridge_cursor_wm_info, latency, &plane_wm, &cursor_wm)) { @@ -1875,12 +1977,17 @@ static void sandybridge_update_wm(struct drm_device *dev) (plane_wm << WM1_LP_SR_SHIFT) | cursor_wm); - /* WM3 */ + /* WM3, note we have to correct the cursor latency */ if (!ironlake_compute_srwm(dev, 3, enabled, SNB_READ_WM3_LATENCY() * 500, &sandybridge_display_srwm_info, &sandybridge_cursor_srwm_info, - &fbc_wm, &plane_wm, &cursor_wm)) + &fbc_wm, &plane_wm, &ignore_cursor_wm) || + !ironlake_compute_srwm(dev, 3, enabled, + 2 * SNB_READ_WM3_LATENCY() * 500, + &sandybridge_display_srwm_info, + &sandybridge_cursor_srwm_info, + &ignore_fbc_wm, &ignore_plane_wm, &cursor_wm)) return; I915_WRITE(WM3_LP_ILK, @@ -4005,7 +4112,7 @@ void intel_init_pm(struct drm_device *dev) } else if (IS_IVYBRIDGE(dev)) { /* FIXME: detect B0+ stepping and use auto training */ if (SNB_READ_WM0_LATENCY()) { - dev_priv->display.update_wm = sandybridge_update_wm; + dev_priv->display.update_wm = ivybridge_update_wm; dev_priv->display.update_sprite_wm = sandybridge_update_sprite_wm; } else { DRM_DEBUG_KMS("Failed to read display plane latency. " -- cgit v1.2.3 From af6c4575afada1a9c411e42439b5d40908865b11 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Tue, 11 Dec 2012 12:01:43 +0000 Subject: drm/i915: Double the cursor self-refresh latency on Valleyview It operates at twice the declared latency, so double the latency value used for the cursor watermark calculation. Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=50248 Signed-off-by: Chris Wilson CC: Jesse Barnes Reviewed-by: Jesse Barnes Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_pm.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 9f1ee07ec4ae..cdd70e654af5 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -1286,6 +1286,7 @@ static void valleyview_update_wm(struct drm_device *dev) struct drm_i915_private *dev_priv = dev->dev_private; int planea_wm, planeb_wm, cursora_wm, cursorb_wm; int plane_sr, cursor_sr; + int ignore_plane_sr, ignore_cursor_sr; unsigned int enabled = 0; vlv_update_drain_latency(dev); @@ -1308,7 +1309,12 @@ static void valleyview_update_wm(struct drm_device *dev) sr_latency_ns, &valleyview_wm_info, &valleyview_cursor_wm_info, - &plane_sr, &cursor_sr)) + &plane_sr, &ignore_cursor_sr) && + g4x_compute_srwm(dev, ffs(enabled) - 1, + 2*sr_latency_ns, + &valleyview_wm_info, + &valleyview_cursor_wm_info, + &ignore_plane_sr, &cursor_sr)) I915_WRITE(FW_BLC_SELF_VLV, FW_CSPWRDWNEN); else I915_WRITE(FW_BLC_SELF_VLV, -- cgit v1.2.3 From 52bd02d8e3fd83201a1a81bdb4ec6fc0b54d24a0 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Fri, 7 Dec 2012 10:43:24 +0000 Subject: drm/i915: Clear self-refresh watermarks when disabled If we elect to disable self-refresh as they require too many FIFO entries, clear the values prior to writing them into the registers. If they are too large they may occupy more bits than available and so corrupt neighbouring WM values. Signed-off-by: Chris Wilson Reviewed-by: Jesse Barnes Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_pm.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index cdd70e654af5..bfc46529f6df 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -1303,7 +1303,6 @@ static void valleyview_update_wm(struct drm_device *dev) &planeb_wm, &cursorb_wm)) enabled |= 2; - plane_sr = cursor_sr = 0; if (single_plane_enabled(enabled) && g4x_compute_srwm(dev, ffs(enabled) - 1, sr_latency_ns, @@ -1314,11 +1313,13 @@ static void valleyview_update_wm(struct drm_device *dev) 2*sr_latency_ns, &valleyview_wm_info, &valleyview_cursor_wm_info, - &ignore_plane_sr, &cursor_sr)) + &ignore_plane_sr, &cursor_sr)) { I915_WRITE(FW_BLC_SELF_VLV, FW_CSPWRDWNEN); - else + } else { I915_WRITE(FW_BLC_SELF_VLV, I915_READ(FW_BLC_SELF_VLV) & ~FW_CSPWRDWNEN); + plane_sr = cursor_sr = 0; + } DRM_DEBUG_KMS("Setting FIFO watermarks - A: plane=%d, cursor=%d, B: plane=%d, cursor=%d, SR: plane=%d, cursor=%d\n", planea_wm, cursora_wm, @@ -1358,17 +1359,18 @@ static void g4x_update_wm(struct drm_device *dev) &planeb_wm, &cursorb_wm)) enabled |= 2; - plane_sr = cursor_sr = 0; if (single_plane_enabled(enabled) && g4x_compute_srwm(dev, ffs(enabled) - 1, sr_latency_ns, &g4x_wm_info, &g4x_cursor_wm_info, - &plane_sr, &cursor_sr)) + &plane_sr, &cursor_sr)) { I915_WRITE(FW_BLC_SELF, FW_BLC_SELF_EN); - else + } else { I915_WRITE(FW_BLC_SELF, I915_READ(FW_BLC_SELF) & ~FW_BLC_SELF_EN); + plane_sr = cursor_sr = 0; + } DRM_DEBUG_KMS("Setting FIFO watermarks - A: plane=%d, cursor=%d, B: plane=%d, cursor=%d, SR: plane=%d, cursor=%d\n", planea_wm, cursora_wm, -- cgit v1.2.3 From f20e0b08b8b2a8432e6abf3683960099f0ab2958 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Fri, 7 Dec 2012 10:43:25 +0000 Subject: drm/i915: Prefer CRTC 'active' rather than 'enabled' during WM computations Only the intel_crtc->active is accurate at the point where we wish to perform WM computations, so use it instead of crtc->enabled. Signed-off-by: Chris Wilson Reviewed-by: Jesse Barnes Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_pm.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index bfc46529f6df..5835277d9632 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -405,7 +405,7 @@ void intel_update_fbc(struct drm_device *dev) * - going to an unsupported config (interlace, pixel multiply, etc.) */ list_for_each_entry(tmp_crtc, &dev->mode_config.crtc_list, head) { - if (tmp_crtc->enabled && + if (to_intel_crtc(tmp_crtc)->active && !to_intel_crtc(tmp_crtc)->primary_disabled && tmp_crtc->fb) { if (crtc) { @@ -992,7 +992,7 @@ static struct drm_crtc *single_enabled_crtc(struct drm_device *dev) struct drm_crtc *crtc, *enabled = NULL; list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { - if (crtc->enabled && crtc->fb) { + if (to_intel_crtc(crtc)->active && crtc->fb) { if (enabled) return NULL; enabled = crtc; @@ -1086,7 +1086,7 @@ static bool g4x_compute_wm0(struct drm_device *dev, int entries, tlb_miss; crtc = intel_get_crtc_for_plane(dev, plane); - if (crtc->fb == NULL || !crtc->enabled) { + if (crtc->fb == NULL || !to_intel_crtc(crtc)->active) { *cursor_wm = cursor->guard_size; *plane_wm = display->guard_size; return false; @@ -1215,7 +1215,7 @@ static bool vlv_compute_drain_latency(struct drm_device *dev, int entries; crtc = intel_get_crtc_for_plane(dev, plane); - if (crtc->fb == NULL || !crtc->enabled) + if (crtc->fb == NULL || !to_intel_crtc(crtc)->active) return false; clock = crtc->mode.clock; /* VESA DOT Clock */ @@ -1476,7 +1476,7 @@ static void i9xx_update_wm(struct drm_device *dev) fifo_size = dev_priv->display.get_fifo_size(dev, 0); crtc = intel_get_crtc_for_plane(dev, 0); - if (crtc->enabled && crtc->fb) { + if (to_intel_crtc(crtc)->active && crtc->fb) { int cpp = crtc->fb->bits_per_pixel / 8; if (IS_GEN2(dev)) cpp = 4; @@ -1490,7 +1490,7 @@ static void i9xx_update_wm(struct drm_device *dev) fifo_size = dev_priv->display.get_fifo_size(dev, 1); crtc = intel_get_crtc_for_plane(dev, 1); - if (crtc->enabled && crtc->fb) { + if (to_intel_crtc(crtc)->active && crtc->fb) { int cpp = crtc->fb->bits_per_pixel / 8; if (IS_GEN2(dev)) cpp = 4; @@ -2044,7 +2044,7 @@ sandybridge_compute_sprite_wm(struct drm_device *dev, int plane, int entries, tlb_miss; crtc = intel_get_crtc_for_plane(dev, plane); - if (crtc->fb == NULL || !crtc->enabled) { + if (crtc->fb == NULL || !to_intel_crtc(crtc)->active) { *sprite_wm = display->guard_size; return false; } -- cgit v1.2.3 From 4283908ef7f11a72c3b80dd4cf026f1a86429f82 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Fri, 14 Dec 2012 23:38:28 +0100 Subject: drm/i915: Implement WaDisableHiZPlanesWhenMSAAEnabled Quoting from Bspec, 3D_CHICKEN1, bit 10 This bit needs to be set always to "1", Project: DevSNB " Reviewed-by: Rodrigo Vivi Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_reg.h | 1 + drivers/gpu/drm/i915/intel_pm.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 3f75cfaf1c3f..e0019378f8b1 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -517,6 +517,7 @@ * the enables for writing to the corresponding low bit. */ #define _3D_CHICKEN 0x02084 +#define _3D_CHICKEN_HIZ_PLANE_DISABLE_MSAA_4X_SNB (1 << 10) #define _3D_CHICKEN2 0x0208c /* Disables pipelining of read flushes past the SF-WIZ interface. * Required on all Ironlake steppings according to the B-Spec, but the diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 5835277d9632..3b85660ce4e4 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -3592,6 +3592,10 @@ static void gen6_init_clock_gating(struct drm_device *dev) I915_READ(ILK_DISPLAY_CHICKEN2) | ILK_ELPIN_409_SELECT); + /* WaDisableHiZPlanesWhenMSAAEnabled */ + I915_WRITE(_3D_CHICKEN, + _MASKED_BIT_ENABLE(_3D_CHICKEN_HIZ_PLANE_DISABLE_MSAA_4X_SNB)); + I915_WRITE(WM3_LP_ILK, 0); I915_WRITE(WM2_LP_ILK, 0); I915_WRITE(WM1_LP_ILK, 0); -- cgit v1.2.3 From 6547fbdbfff62c99e4f7b4f985ff8b3454f33b0f Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Fri, 14 Dec 2012 23:38:29 +0100 Subject: drm/i915: Implement WaSetupGtModeTdRowDispatch I'm not really sure, since the w/a entry is as thin on details as ever, and Bspec doesn't say anything about it. But I've figured only dispatching to rows 0&1 instead of all four should be the right thing for GT1. Reviewed-by: Rodrigo Vivi [danvet: Add the missing snb server GT1 to the check, spotted by Chris Wilson.] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 3 +++ drivers/gpu/drm/i915/i915_reg.h | 3 ++- drivers/gpu/drm/i915/intel_pm.c | 5 +++++ 3 files changed, 10 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 557843dd4b2e..062a60b381b7 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1166,6 +1166,9 @@ struct drm_i915_file_private { #define IS_IVB_GT1(dev) ((dev)->pci_device == 0x0156 || \ (dev)->pci_device == 0x0152 || \ (dev)->pci_device == 0x015a) +#define IS_SNB_GT1(dev) ((dev)->pci_device == 0x0102 || \ + (dev)->pci_device == 0x0106 || \ + (dev)->pci_device == 0x010A) #define IS_VALLEYVIEW(dev) (INTEL_INFO(dev)->is_valleyview) #define IS_HASWELL(dev) (INTEL_INFO(dev)->is_haswell) #define IS_MOBILE(dev) (INTEL_INFO(dev)->is_mobile) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index e0019378f8b1..186ee5c85b51 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -533,7 +533,8 @@ # define MI_FLUSH_ENABLE (1 << 12) #define GEN6_GT_MODE 0x20d0 -#define GEN6_GT_MODE_HI (1 << 9) +#define GEN6_GT_MODE_HI (1 << 9) +#define GEN6_TD_FOUR_ROW_DISPATCH_DISABLE (1 << 5) #define GFX_MODE 0x02520 #define GFX_MODE_GEN7 0x0229c diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 3b85660ce4e4..55f7a896a121 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -3596,6 +3596,11 @@ static void gen6_init_clock_gating(struct drm_device *dev) I915_WRITE(_3D_CHICKEN, _MASKED_BIT_ENABLE(_3D_CHICKEN_HIZ_PLANE_DISABLE_MSAA_4X_SNB)); + /* WaSetupGtModeTdRowDispatch */ + if (IS_SNB_GT1(dev)) + I915_WRITE(GEN6_GT_MODE, + _MASKED_BIT_ENABLE(GEN6_TD_FOUR_ROW_DISPATCH_DISABLE)); + I915_WRITE(WM3_LP_ILK, 0); I915_WRITE(WM2_LP_ILK, 0); I915_WRITE(WM1_LP_ILK, 0); -- cgit v1.2.3 From b45305fce5bb1abec263fcff9d81ebecd6306ede Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Mon, 17 Dec 2012 16:21:27 +0100 Subject: drm/i915: Implement workaround for broken CS tlb on i830/845 Now that Chris Wilson demonstrated that the key for stability on early gen 2 is to simple _never_ exchange the physical backing storage of batch buffers I've tried a stab at a kernel solution. Doesn't look too nefarious imho, now that I don't try to be too clever for my own good any more. v2: After discussing the various techniques, we've decided to always blit batches on the suspect devices, but allow userspace to opt out of the kernel workaround assume full responsibility for providing coherent batches. The principal reason is that avoiding the blit does improve performance in a few key microbenchmarks and also in cairo-trace replays. Signed-Off-by: Daniel Vetter Signed-off-by: Chris Wilson [danvet: - Drop the hunk which uses HAS_BROKEN_CS_TLB to implement the ring wrap w/a. Suggested by Chris Wilson. - Also add the ACTHD check from Chris Wilson for the error state dumping, so that we still catch batches when userspace opts out of the w/a.] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_dma.c | 3 ++ drivers/gpu/drm/i915/i915_drv.h | 4 ++ drivers/gpu/drm/i915/i915_gem_execbuffer.c | 2 + drivers/gpu/drm/i915/i915_irq.c | 12 +++++ drivers/gpu/drm/i915/intel_ringbuffer.c | 76 ++++++++++++++++++++++++++---- drivers/gpu/drm/i915/intel_ringbuffer.h | 1 + include/uapi/drm/i915_drm.h | 10 ++++ 7 files changed, 100 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index 8f63cd5de4b4..99daa896105d 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -989,6 +989,9 @@ static int i915_getparam(struct drm_device *dev, void *data, case I915_PARAM_HAS_SECURE_BATCHES: value = capable(CAP_SYS_ADMIN); break; + case I915_PARAM_HAS_PINNED_BATCHES: + value = 1; + break; default: DRM_DEBUG_DRIVER("Unknown parameter %d\n", param->param); diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 062a60b381b7..1a4c3a1c111f 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1100,6 +1100,7 @@ struct drm_i915_gem_object { */ atomic_t pending_flip; }; +#define to_gem_object(obj) (&((struct drm_i915_gem_object *)(obj))->base) #define to_intel_bo(x) container_of(x, struct drm_i915_gem_object, base) @@ -1199,6 +1200,9 @@ struct drm_i915_file_private { #define HAS_OVERLAY(dev) (INTEL_INFO(dev)->has_overlay) #define OVERLAY_NEEDS_PHYSICAL(dev) (INTEL_INFO(dev)->overlay_needs_physical) +/* Early gen2 have a totally busted CS tlb and require pinned batches. */ +#define HAS_BROKEN_CS_TLB(dev) (IS_I830(dev) || IS_845G(dev)) + /* 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_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c index ee8f97f0539e..d6a994a07393 100644 --- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c +++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c @@ -808,6 +808,8 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, flags |= I915_DISPATCH_SECURE; } + if (args->flags & I915_EXEC_IS_PINNED) + flags |= I915_DISPATCH_PINNED; switch (args->flags & I915_EXEC_RING_MASK) { case I915_EXEC_DEFAULT: diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index a4dc97f8b9f0..2220dec3e5d9 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -1087,6 +1087,18 @@ i915_error_first_batchbuffer(struct drm_i915_private *dev_priv, if (!ring->get_seqno) return NULL; + if (HAS_BROKEN_CS_TLB(dev_priv->dev)) { + u32 acthd = I915_READ(ACTHD); + + if (WARN_ON(ring->id != RCS)) + return NULL; + + obj = ring->private; + if (acthd >= obj->gtt_offset && + acthd < obj->gtt_offset + obj->base.size) + return i915_error_object_create(dev_priv, obj); + } + seqno = ring->get_seqno(ring, false); list_for_each_entry(obj, &dev_priv->mm.active_list, mm_list) { if (obj->ring != ring) diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index 2346b920bd86..ae253e04c391 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -547,9 +547,14 @@ static int init_render_ring(struct intel_ring_buffer *ring) static void render_ring_cleanup(struct intel_ring_buffer *ring) { + struct drm_device *dev = ring->dev; + if (!ring->private) return; + if (HAS_BROKEN_CS_TLB(dev)) + drm_gem_object_unreference(to_gem_object(ring->private)); + cleanup_pipe_control(ring); } @@ -969,6 +974,8 @@ i965_dispatch_execbuffer(struct intel_ring_buffer *ring, return 0; } +/* Just userspace ABI convention to limit the wa batch bo to a resonable size */ +#define I830_BATCH_LIMIT (256*1024) static int i830_dispatch_execbuffer(struct intel_ring_buffer *ring, u32 offset, u32 len, @@ -976,15 +983,47 @@ i830_dispatch_execbuffer(struct intel_ring_buffer *ring, { int ret; - ret = intel_ring_begin(ring, 4); - if (ret) - return ret; + if (flags & I915_DISPATCH_PINNED) { + ret = intel_ring_begin(ring, 4); + if (ret) + return ret; - intel_ring_emit(ring, MI_BATCH_BUFFER); - intel_ring_emit(ring, offset | (flags & I915_DISPATCH_SECURE ? 0 : MI_BATCH_NON_SECURE)); - intel_ring_emit(ring, offset + len - 8); - intel_ring_emit(ring, 0); - intel_ring_advance(ring); + intel_ring_emit(ring, MI_BATCH_BUFFER); + intel_ring_emit(ring, offset | (flags & I915_DISPATCH_SECURE ? 0 : MI_BATCH_NON_SECURE)); + intel_ring_emit(ring, offset + len - 8); + intel_ring_emit(ring, MI_NOOP); + intel_ring_advance(ring); + } else { + struct drm_i915_gem_object *obj = ring->private; + u32 cs_offset = obj->gtt_offset; + + if (len > I830_BATCH_LIMIT) + return -ENOSPC; + + ret = intel_ring_begin(ring, 9+3); + if (ret) + return ret; + /* Blit the batch (which has now all relocs applied) to the stable batch + * scratch bo area (so that the CS never stumbles over its tlb + * invalidation bug) ... */ + intel_ring_emit(ring, XY_SRC_COPY_BLT_CMD | + XY_SRC_COPY_BLT_WRITE_ALPHA | + XY_SRC_COPY_BLT_WRITE_RGB); + intel_ring_emit(ring, BLT_DEPTH_32 | BLT_ROP_GXCOPY | 4096); + intel_ring_emit(ring, 0); + intel_ring_emit(ring, (DIV_ROUND_UP(len, 4096) << 16) | 1024); + intel_ring_emit(ring, cs_offset); + intel_ring_emit(ring, 0); + intel_ring_emit(ring, 4096); + intel_ring_emit(ring, offset); + intel_ring_emit(ring, MI_FLUSH); + + /* ... and execute it. */ + intel_ring_emit(ring, MI_BATCH_BUFFER); + intel_ring_emit(ring, cs_offset | (flags & I915_DISPATCH_SECURE ? 0 : MI_BATCH_NON_SECURE)); + intel_ring_emit(ring, cs_offset + len - 8); + intel_ring_advance(ring); + } return 0; } @@ -1596,6 +1635,27 @@ int intel_init_render_ring_buffer(struct drm_device *dev) ring->init = init_render_ring; ring->cleanup = render_ring_cleanup; + /* Workaround batchbuffer to combat CS tlb bug. */ + if (HAS_BROKEN_CS_TLB(dev)) { + struct drm_i915_gem_object *obj; + int ret; + + obj = i915_gem_alloc_object(dev, I830_BATCH_LIMIT); + if (obj == NULL) { + DRM_ERROR("Failed to allocate batch bo\n"); + return -ENOMEM; + } + + ret = i915_gem_object_pin(obj, 0, true, false); + if (ret != 0) { + drm_gem_object_unreference(&obj->base); + DRM_ERROR("Failed to ping batch bo\n"); + return ret; + } + + ring->private = obj; + } + return intel_init_ring_buffer(dev, ring); } diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h index 526182ed0c6d..6af87cd05725 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.h +++ b/drivers/gpu/drm/i915/intel_ringbuffer.h @@ -94,6 +94,7 @@ struct intel_ring_buffer { u32 offset, u32 length, unsigned flags); #define I915_DISPATCH_SECURE 0x1 +#define I915_DISPATCH_PINNED 0x2 void (*cleanup)(struct intel_ring_buffer *ring); int (*sync_to)(struct intel_ring_buffer *ring, struct intel_ring_buffer *to, diff --git a/include/uapi/drm/i915_drm.h b/include/uapi/drm/i915_drm.h index b746a3cf5fa9..c4d2e9c74002 100644 --- a/include/uapi/drm/i915_drm.h +++ b/include/uapi/drm/i915_drm.h @@ -307,6 +307,7 @@ typedef struct drm_i915_irq_wait { #define I915_PARAM_HAS_PRIME_VMAP_FLUSH 21 #define I915_PARAM_RSVD_FOR_FUTURE_USE 22 #define I915_PARAM_HAS_SECURE_BATCHES 23 +#define I915_PARAM_HAS_PINNED_BATCHES 24 typedef struct drm_i915_getparam { int param; @@ -677,6 +678,15 @@ struct drm_i915_gem_execbuffer2 { */ #define I915_EXEC_SECURE (1<<9) +/** Inform the kernel that the batch is and will always be pinned. This + * negates the requirement for a workaround to be performed to avoid + * an incoherent CS (such as can be found on 830/845). If this flag is + * not passed, the kernel will endeavour to make sure the batch is + * coherent with the CS before execution. If this flag is passed, + * userspace assumes the responsibility for ensuring the same. + */ +#define I915_EXEC_IS_PINNED (1<<10) + #define I915_EXEC_CONTEXT_ID_MASK (0xffffffff) #define i915_execbuffer2_set_context_id(eb2, context) \ (eb2).rsvd1 = context & I915_EXEC_CONTEXT_ID_MASK -- cgit v1.2.3 From b0a2658acb5bf9ca86b4aab011b7106de3af0add Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Tue, 18 Dec 2012 09:37:54 +0100 Subject: drm/i915: don't disable disconnected outputs This piece of neat lore has been ported painstakingly and bug-for-bug compatible from the old crtc helper code. Imo it's utter nonsense. If you disconnected a cable and before you reconnect it, userspace (or the kernel) does an set_crtc call, this will result in that connector getting disabled. Which will result in a nice black screen when plugging in the cable again. There's absolutely no reason the kernel does such policy enforcements - if userspace tries to set up a mode on something disconnected we might fail loudly (since the dp link training fails), but silently adjusting the output configuration behind userspace's back is a recipe for disaster. Specifically I think that this could explain some of our MI_WAIT hangs around suspend, where userspace issues a scanline wait on a disable pipe. This mechanisims here could explain how that pipe got disabled without userspace noticing. Note that this fixes a NULL deref at BIOS takeover when the firmware sets up a disconnected output in a clone configuration with a connected output on the 2nd pipe: When doing the full modeset we don't have a mode for the 2nd pipe and OOPS. On the first pipe this doesn't matter, since at boot-up the fbdev helpers will set up the choosen configuration on that on first. Since this is now the umptenth bug around handling this imo brain-dead semantics correctly, I think it's time to kill it and see whether there's any userspace out there which relies on this. It also nicely demonstrates that we have a tiny window where DP hotplug can still kill the driver. Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=58396 Cc: stable@vger.kernel.org Tested-by: Peter Ujfalusi Reviewed-by: Rodrigo Vivi Reviewed-by: Jesse Barnes Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 82267b27b8f6..bc0b7aa0ab96 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -8133,10 +8133,6 @@ intel_modeset_stage_output_state(struct drm_device *dev, DRM_DEBUG_KMS("encoder changed, full mode switch\n"); config->mode_changed = true; } - - /* Disable all disconnected encoders. */ - if (connector->base.status == connector_status_disconnected) - connector->new_encoder = NULL; } /* connector->new_encoder is now updated for all connectors. */ -- cgit v1.2.3 From b81034506fc9b879cb726feb01342be0cdbe6e25 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Fri, 7 Dec 2012 20:37:06 +0000 Subject: drm: Export routines for inserting preallocated nodes into the mm manager Required by i915 in order to avoid the allocation in the middle of manipulating the drm_mm lists. Use a pair of stubs to preserve the existing EXPORT_SYMBOLs for backporting; to be removed later. Cc: Dave Airlie Cc: dri-devel@lists.freedesktop.org Signed-off-by: Chris Wilson Reviewed-by: Jani Nikula [danvet: bikeshedded-away the atomic parameter, it's not yet used anywhere.] Acked-by: Dave Airlie Signed-off-by: Daniel Vetter --- drivers/gpu/drm/drm_mm.c | 41 +++++++++++++++++++++++++++++------------ include/drm/drm_mm.h | 25 +++++++++++++++++++++---- 2 files changed, 50 insertions(+), 16 deletions(-) diff --git a/drivers/gpu/drm/drm_mm.c b/drivers/gpu/drm/drm_mm.c index 0761a03cdbb2..2bf9670ba29b 100644 --- a/drivers/gpu/drm/drm_mm.c +++ b/drivers/gpu/drm/drm_mm.c @@ -184,19 +184,27 @@ EXPORT_SYMBOL(drm_mm_get_block_generic); * -ENOSPC if no suitable free area is available. The preallocated memory node * must be cleared. */ -int drm_mm_insert_node(struct drm_mm *mm, struct drm_mm_node *node, - unsigned long size, unsigned alignment) +int drm_mm_insert_node_generic(struct drm_mm *mm, struct drm_mm_node *node, + unsigned long size, unsigned alignment, + unsigned long color) { struct drm_mm_node *hole_node; - hole_node = drm_mm_search_free(mm, size, alignment, false); + hole_node = drm_mm_search_free_generic(mm, size, alignment, + color, 0); if (!hole_node) return -ENOSPC; - drm_mm_insert_helper(hole_node, node, size, alignment, 0); - + drm_mm_insert_helper(hole_node, node, size, alignment, color); return 0; } +EXPORT_SYMBOL(drm_mm_insert_node_generic); + +int drm_mm_insert_node(struct drm_mm *mm, struct drm_mm_node *node, + unsigned long size, unsigned alignment) +{ + return drm_mm_insert_node_generic(mm, node, size, alignment, 0); +} EXPORT_SYMBOL(drm_mm_insert_node); static void drm_mm_insert_helper_range(struct drm_mm_node *hole_node, @@ -275,22 +283,31 @@ EXPORT_SYMBOL(drm_mm_get_block_range_generic); * -ENOSPC if no suitable free area is available. This is for range * restricted allocations. The preallocated memory node must be cleared. */ -int drm_mm_insert_node_in_range(struct drm_mm *mm, struct drm_mm_node *node, - unsigned long size, unsigned alignment, - unsigned long start, unsigned long end) +int drm_mm_insert_node_in_range_generic(struct drm_mm *mm, struct drm_mm_node *node, + unsigned long size, unsigned alignment, unsigned long color, + unsigned long start, unsigned long end) { struct drm_mm_node *hole_node; - hole_node = drm_mm_search_free_in_range(mm, size, alignment, - start, end, false); + hole_node = drm_mm_search_free_in_range_generic(mm, + size, alignment, color, + start, end, 0); if (!hole_node) return -ENOSPC; - drm_mm_insert_helper_range(hole_node, node, size, alignment, 0, + drm_mm_insert_helper_range(hole_node, node, + size, alignment, color, start, end); - return 0; } +EXPORT_SYMBOL(drm_mm_insert_node_in_range_generic); + +int drm_mm_insert_node_in_range(struct drm_mm *mm, struct drm_mm_node *node, + unsigned long size, unsigned alignment, + unsigned long start, unsigned long end) +{ + return drm_mm_insert_node_in_range_generic(mm, node, size, alignment, 0, start, end); +} EXPORT_SYMBOL(drm_mm_insert_node_in_range); /** diff --git a/include/drm/drm_mm.h b/include/drm/drm_mm.h index 06d7f798a08c..0f4a366f6fa6 100644 --- a/include/drm/drm_mm.h +++ b/include/drm/drm_mm.h @@ -158,12 +158,29 @@ static inline struct drm_mm_node *drm_mm_get_block_atomic_range( return drm_mm_get_block_range_generic(parent, size, alignment, 0, start, end, 1); } -extern int drm_mm_insert_node(struct drm_mm *mm, struct drm_mm_node *node, - unsigned long size, unsigned alignment); + +extern int drm_mm_insert_node(struct drm_mm *mm, + struct drm_mm_node *node, + unsigned long size, + unsigned alignment); extern int drm_mm_insert_node_in_range(struct drm_mm *mm, struct drm_mm_node *node, - unsigned long size, unsigned alignment, - unsigned long start, unsigned long end); + unsigned long size, + unsigned alignment, + unsigned long start, + unsigned long end); +extern int drm_mm_insert_node_generic(struct drm_mm *mm, + struct drm_mm_node *node, + unsigned long size, + unsigned alignment, + unsigned long color); +extern int drm_mm_insert_node_in_range_generic(struct drm_mm *mm, + struct drm_mm_node *node, + unsigned long size, + unsigned alignment, + unsigned long color, + unsigned long start, + unsigned long end); extern void drm_mm_put_block(struct drm_mm_node *cur); extern void drm_mm_remove_node(struct drm_mm_node *node); extern void drm_mm_replace_node(struct drm_mm_node *old, struct drm_mm_node *new); -- cgit v1.2.3 From dc9dd7a20fde95aa81a8307cde79c2dff9f83f3d Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Fri, 7 Dec 2012 20:37:07 +0000 Subject: drm/i915: Preallocate the drm_mm_node prior to manipulating the GTT drm_mm manager As we may reap neighbouring objects in order to free up pages for allocations, we need to be careful not to allocate in the middle of the drm_mm manager. To accomplish this, we can simply allocate the drm_mm_node up front and then use the combined search & insert drm_mm routines, reducing our code footprint in the process. Fixes (partially) i-g-t/gem_tiled_swapping Reported-by: Mika Kuoppala Signed-off-by: Chris Wilson Reviewed-by: Jani Nikula [danvet: Again fixup atomic bikeshed.] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem.c | 62 +++++++++++++++++------------------------ 1 file changed, 25 insertions(+), 37 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index c1f691958f89..5feda1f67042 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -2890,7 +2890,7 @@ i915_gem_object_bind_to_gtt(struct drm_i915_gem_object *obj, { struct drm_device *dev = obj->base.dev; drm_i915_private_t *dev_priv = dev->dev_private; - struct drm_mm_node *free_space; + struct drm_mm_node *node; u32 size, fence_size, fence_alignment, unfenced_alignment; bool mappable, fenceable; int ret; @@ -2936,66 +2936,54 @@ i915_gem_object_bind_to_gtt(struct drm_i915_gem_object *obj, i915_gem_object_pin_pages(obj); + node = kzalloc(sizeof(*node), GFP_KERNEL); + if (node == NULL) { + i915_gem_object_unpin_pages(obj); + return -ENOMEM; + } + search_free: if (map_and_fenceable) - free_space = drm_mm_search_free_in_range_color(&dev_priv->mm.gtt_space, - size, alignment, obj->cache_level, - 0, dev_priv->mm.gtt_mappable_end, - false); + ret = drm_mm_insert_node_in_range_generic(&dev_priv->mm.gtt_space, node, + size, alignment, obj->cache_level, + 0, dev_priv->mm.gtt_mappable_end); else - free_space = drm_mm_search_free_color(&dev_priv->mm.gtt_space, - size, alignment, obj->cache_level, - false); - - if (free_space != NULL) { - if (map_and_fenceable) - free_space = - drm_mm_get_block_range_generic(free_space, - size, alignment, obj->cache_level, - 0, dev_priv->mm.gtt_mappable_end, - false); - else - free_space = - drm_mm_get_block_generic(free_space, - size, alignment, obj->cache_level, - false); - } - if (free_space == NULL) { + ret = drm_mm_insert_node_generic(&dev_priv->mm.gtt_space, node, + size, alignment, obj->cache_level); + if (ret) { ret = i915_gem_evict_something(dev, size, alignment, obj->cache_level, map_and_fenceable, nonblocking); - if (ret) { - i915_gem_object_unpin_pages(obj); - return ret; - } + if (ret == 0) + goto search_free; - goto search_free; + i915_gem_object_unpin_pages(obj); + kfree(node); + return ret; } - if (WARN_ON(!i915_gem_valid_gtt_space(dev, - free_space, - obj->cache_level))) { + if (WARN_ON(!i915_gem_valid_gtt_space(dev, node, obj->cache_level))) { i915_gem_object_unpin_pages(obj); - drm_mm_put_block(free_space); + drm_mm_put_block(node); return -EINVAL; } ret = i915_gem_gtt_prepare_object(obj); if (ret) { i915_gem_object_unpin_pages(obj); - drm_mm_put_block(free_space); + drm_mm_put_block(node); return ret; } list_move_tail(&obj->gtt_list, &dev_priv->mm.bound_list); list_add_tail(&obj->mm_list, &dev_priv->mm.inactive_list); - obj->gtt_space = free_space; - obj->gtt_offset = free_space->start; + obj->gtt_space = node; + obj->gtt_offset = node->start; fenceable = - free_space->size == fence_size && - (free_space->start & (fence_alignment - 1)) == 0; + node->size == fence_size && + (node->start & (fence_alignment - 1)) == 0; mappable = obj->gtt_offset + obj->base.size <= dev_priv->mm.gtt_mappable_end; -- cgit v1.2.3 From 0fde901f1ddd2ce0e380a6444f1fb7ca555859e9 Mon Sep 17 00:00:00 2001 From: Krzysztof Mazur Date: Wed, 19 Dec 2012 11:03:41 +0100 Subject: i915: ensure that VGA plane is disabled Some broken systems (like HP nc6120) in some cases, usually after LID close/open, enable VGA plane, making display unusable (black screen on LVDS, some strange mode on VGA output). We used to disable VGA plane only once at startup. Now we also check, if VGA plane is still disabled while changing mode, and fix that if something changed it. Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=57434 Signed-off-by: Krzysztof Mazur Cc: stable@vger.kernel.org Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index bc0b7aa0ab96..7395f6a389a5 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -9152,6 +9152,23 @@ static void intel_sanitize_encoder(struct intel_encoder *encoder) * the crtc fixup. */ } +static void i915_redisable_vga(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + u32 vga_reg; + + if (HAS_PCH_SPLIT(dev)) + vga_reg = CPU_VGACNTRL; + else + vga_reg = VGACNTRL; + + if (I915_READ(vga_reg) != VGA_DISP_DISABLE) { + DRM_DEBUG_KMS("Something enabled VGA plane, disabling it\n"); + I915_WRITE(vga_reg, VGA_DISP_DISABLE); + POSTING_READ(vga_reg); + } +} + /* Scan out the current hw modeset state, sanitizes it and maps it into the drm * and i915 state tracking structures. */ void intel_modeset_setup_hw_state(struct drm_device *dev, @@ -9260,6 +9277,8 @@ void intel_modeset_setup_hw_state(struct drm_device *dev, intel_set_mode(&crtc->base, &crtc->base.mode, crtc->base.x, crtc->base.y, crtc->base.fb); } + + i915_redisable_vga(dev); } else { intel_modeset_update_staged_output_state(dev); } -- cgit v1.2.3 From 76903b96adbfbb38b049765add21e02e44c387a5 Mon Sep 17 00:00:00 2001 From: Jerome Glisse Date: Mon, 17 Dec 2012 10:29:06 -0500 Subject: drm/radeon: don't leave fence blocked process on failed GPU reset MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Force all fence to signal if GPU reset failed so no process get stuck on waiting fence. Signed-off-by: Jerome Glisse Reviewed-by: Christian König Signed-off-by: Alex Deucher Cc: stable@vger.kernel.org --- drivers/gpu/drm/radeon/radeon.h | 1 + drivers/gpu/drm/radeon/radeon_device.c | 1 + drivers/gpu/drm/radeon/radeon_fence.c | 19 +++++++++++++++++++ 3 files changed, 21 insertions(+) diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h index 5dc744d43d12..aae73141d63a 100644 --- a/drivers/gpu/drm/radeon/radeon.h +++ b/drivers/gpu/drm/radeon/radeon.h @@ -225,6 +225,7 @@ struct radeon_fence { int radeon_fence_driver_start_ring(struct radeon_device *rdev, int ring); int radeon_fence_driver_init(struct radeon_device *rdev); void radeon_fence_driver_fini(struct radeon_device *rdev); +void radeon_fence_driver_force_completion(struct radeon_device *rdev); int radeon_fence_emit(struct radeon_device *rdev, struct radeon_fence **fence, int ring); void radeon_fence_process(struct radeon_device *rdev, int ring); bool radeon_fence_signaled(struct radeon_fence *fence); diff --git a/drivers/gpu/drm/radeon/radeon_device.c b/drivers/gpu/drm/radeon/radeon_device.c index 49b06590001e..e81d6cab9959 100644 --- a/drivers/gpu/drm/radeon/radeon_device.c +++ b/drivers/gpu/drm/radeon/radeon_device.c @@ -1358,6 +1358,7 @@ retry: } } } else { + radeon_fence_driver_force_completion(rdev); for (i = 0; i < RADEON_NUM_RINGS; ++i) { kfree(ring_data[i]); } diff --git a/drivers/gpu/drm/radeon/radeon_fence.c b/drivers/gpu/drm/radeon/radeon_fence.c index 410a975a8eec..a9b0fa5608eb 100644 --- a/drivers/gpu/drm/radeon/radeon_fence.c +++ b/drivers/gpu/drm/radeon/radeon_fence.c @@ -868,6 +868,25 @@ void radeon_fence_driver_fini(struct radeon_device *rdev) mutex_unlock(&rdev->ring_lock); } +/** + * radeon_fence_driver_force_completion - force all fence waiter to complete + * + * @rdev: radeon device pointer + * + * In case of GPU reset failure make sure no process keep waiting on fence + * that will never complete. + */ +void radeon_fence_driver_force_completion(struct radeon_device *rdev) +{ + int ring; + + for (ring = 0; ring < RADEON_NUM_RINGS; ring++) { + if (!rdev->fence_drv[ring].initialized) + continue; + radeon_fence_write(rdev, rdev->fence_drv[ring].sync_seq[ring], ring); + } +} + /* * Fence debugfs -- cgit v1.2.3 From 5f8f635edd8ad5a6416bff4c5ff486500357f473 Mon Sep 17 00:00:00 2001 From: Jerome Glisse Date: Mon, 17 Dec 2012 11:04:32 -0500 Subject: drm/radeon: avoid deadlock in pm path when waiting for fence MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit radeon_fence_wait_empty_locked should not trigger GPU reset as no place where it's call from would benefit from such thing and it actually lead to a kernel deadlock in case the reset is triggered from pm codepath. Instead force ring completion in place where it makes sense or return early in others. Signed-off-by: Jerome Glisse Reviewed-by: Christian König Signed-off-by: Alex Deucher Cc: stable@vger.kernel.org --- drivers/gpu/drm/radeon/radeon.h | 2 +- drivers/gpu/drm/radeon/radeon_device.c | 13 +++++++++++-- drivers/gpu/drm/radeon/radeon_fence.c | 30 ++++++++++++++---------------- drivers/gpu/drm/radeon/radeon_pm.c | 15 ++++++++++++--- 4 files changed, 38 insertions(+), 22 deletions(-) diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h index aae73141d63a..9b9422c4403a 100644 --- a/drivers/gpu/drm/radeon/radeon.h +++ b/drivers/gpu/drm/radeon/radeon.h @@ -231,7 +231,7 @@ void radeon_fence_process(struct radeon_device *rdev, int ring); bool radeon_fence_signaled(struct radeon_fence *fence); int radeon_fence_wait(struct radeon_fence *fence, bool interruptible); int radeon_fence_wait_next_locked(struct radeon_device *rdev, int ring); -void radeon_fence_wait_empty_locked(struct radeon_device *rdev, int ring); +int radeon_fence_wait_empty_locked(struct radeon_device *rdev, int ring); int radeon_fence_wait_any(struct radeon_device *rdev, struct radeon_fence **fences, bool intr); diff --git a/drivers/gpu/drm/radeon/radeon_device.c b/drivers/gpu/drm/radeon/radeon_device.c index e81d6cab9959..a6617b53a9c6 100644 --- a/drivers/gpu/drm/radeon/radeon_device.c +++ b/drivers/gpu/drm/radeon/radeon_device.c @@ -1164,6 +1164,7 @@ int radeon_suspend_kms(struct drm_device *dev, pm_message_t state) struct drm_crtc *crtc; struct drm_connector *connector; int i, r; + bool force_completion = false; if (dev == NULL || dev->dev_private == NULL) { return -ENODEV; @@ -1206,8 +1207,16 @@ int radeon_suspend_kms(struct drm_device *dev, pm_message_t state) mutex_lock(&rdev->ring_lock); /* wait for gpu to finish processing current batch */ - for (i = 0; i < RADEON_NUM_RINGS; i++) - radeon_fence_wait_empty_locked(rdev, i); + for (i = 0; i < RADEON_NUM_RINGS; i++) { + r = radeon_fence_wait_empty_locked(rdev, i); + if (r) { + /* delay GPU reset to resume */ + force_completion = true; + } + } + if (force_completion) { + radeon_fence_driver_force_completion(rdev); + } mutex_unlock(&rdev->ring_lock); radeon_save_bios_scratch_regs(rdev); diff --git a/drivers/gpu/drm/radeon/radeon_fence.c b/drivers/gpu/drm/radeon/radeon_fence.c index a9b0fa5608eb..34356252567a 100644 --- a/drivers/gpu/drm/radeon/radeon_fence.c +++ b/drivers/gpu/drm/radeon/radeon_fence.c @@ -609,26 +609,20 @@ int radeon_fence_wait_next_locked(struct radeon_device *rdev, int ring) * Returns 0 if the fences have passed, error for all other cases. * Caller must hold ring lock. */ -void radeon_fence_wait_empty_locked(struct radeon_device *rdev, int ring) +int radeon_fence_wait_empty_locked(struct radeon_device *rdev, int ring) { uint64_t seq = rdev->fence_drv[ring].sync_seq[ring]; + int r; - while(1) { - int r; - r = radeon_fence_wait_seq(rdev, seq, ring, false, false); + r = radeon_fence_wait_seq(rdev, seq, ring, false, false); + if (r) { if (r == -EDEADLK) { - mutex_unlock(&rdev->ring_lock); - r = radeon_gpu_reset(rdev); - mutex_lock(&rdev->ring_lock); - if (!r) - continue; - } - if (r) { - dev_err(rdev->dev, "error waiting for ring to become" - " idle (%d)\n", r); + return -EDEADLK; } - return; + dev_err(rdev->dev, "error waiting for ring[%d] to become idle (%d)\n", + ring, r); } + return 0; } /** @@ -854,13 +848,17 @@ int radeon_fence_driver_init(struct radeon_device *rdev) */ void radeon_fence_driver_fini(struct radeon_device *rdev) { - int ring; + int ring, r; mutex_lock(&rdev->ring_lock); for (ring = 0; ring < RADEON_NUM_RINGS; ring++) { if (!rdev->fence_drv[ring].initialized) continue; - radeon_fence_wait_empty_locked(rdev, ring); + r = radeon_fence_wait_empty_locked(rdev, ring); + if (r) { + /* no need to trigger GPU reset as we are unloading */ + radeon_fence_driver_force_completion(rdev); + } wake_up_all(&rdev->fence_queue); radeon_scratch_free(rdev, rdev->fence_drv[ring].scratch_reg); rdev->fence_drv[ring].initialized = false; diff --git a/drivers/gpu/drm/radeon/radeon_pm.c b/drivers/gpu/drm/radeon/radeon_pm.c index aa14dbb7e4fb..0bfa656aa87d 100644 --- a/drivers/gpu/drm/radeon/radeon_pm.c +++ b/drivers/gpu/drm/radeon/radeon_pm.c @@ -234,7 +234,7 @@ static void radeon_set_power_state(struct radeon_device *rdev) static void radeon_pm_set_clocks(struct radeon_device *rdev) { - int i; + int i, r; /* no need to take locks, etc. if nothing's going to change */ if ((rdev->pm.requested_clock_mode_index == rdev->pm.current_clock_mode_index) && @@ -248,8 +248,17 @@ static void radeon_pm_set_clocks(struct radeon_device *rdev) /* wait for the rings to drain */ for (i = 0; i < RADEON_NUM_RINGS; i++) { struct radeon_ring *ring = &rdev->ring[i]; - if (ring->ready) - radeon_fence_wait_empty_locked(rdev, i); + if (!ring->ready) { + continue; + } + r = radeon_fence_wait_empty_locked(rdev, i); + if (r) { + /* needs a GPU reset dont reset here */ + mutex_unlock(&rdev->ring_lock); + up_write(&rdev->pm.mclk_lock); + mutex_unlock(&rdev->ddev->struct_mutex); + return; + } } radeon_unmap_vram_bos(rdev); -- cgit v1.2.3 From d3493574e267c203836bfdcb9c58d8af46fc0da1 Mon Sep 17 00:00:00 2001 From: Jerome Glisse Date: Fri, 14 Dec 2012 16:20:46 -0500 Subject: drm/radeon: restore modeset late in GPU reset path Modeset path seems to conflict sometimes with the memory management leading to kernel deadlock. This move modesetting reset after GPU acceleration reset. Signed-off-by: Jerome Glisse Signed-off-by: Alex Deucher Cc: stable@vger.kernel.org --- drivers/gpu/drm/radeon/radeon_device.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/radeon/radeon_device.c b/drivers/gpu/drm/radeon/radeon_device.c index a6617b53a9c6..cd756262924d 100644 --- a/drivers/gpu/drm/radeon/radeon_device.c +++ b/drivers/gpu/drm/radeon/radeon_device.c @@ -1347,7 +1347,6 @@ retry: } radeon_restore_bios_scratch_regs(rdev); - drm_helper_resume_force_mode(rdev->ddev); if (!r) { for (i = 0; i < RADEON_NUM_RINGS; ++i) { @@ -1373,6 +1372,8 @@ retry: } } + drm_helper_resume_force_mode(rdev->ddev); + ttm_bo_unlock_delayed_workqueue(&rdev->mman.bdev, resched); if (r) { /* bad news, how to tell it to userspace ? */ -- cgit v1.2.3 From 4613ca14b9739428abb53bef9cd0f8b3fee23a95 Mon Sep 17 00:00:00 2001 From: Jerome Glisse Date: Wed, 19 Dec 2012 12:26:45 -0500 Subject: drm/radeon: add support for MEM_WRITE packet To make it easier to debug some lockup from userspace add support to MEM_WRITE packet. Signed-off-by: Jerome Glisse Signed-off-by: Alex Deucher --- drivers/gpu/drm/radeon/evergreen_cs.c | 29 +++++++++++++++++++++++++++++ drivers/gpu/drm/radeon/r600_cs.c | 29 +++++++++++++++++++++++++++++ drivers/gpu/drm/radeon/radeon_drv.c | 3 ++- 3 files changed, 60 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/radeon/evergreen_cs.c b/drivers/gpu/drm/radeon/evergreen_cs.c index 74c6b42d2597..5cea852237ee 100644 --- a/drivers/gpu/drm/radeon/evergreen_cs.c +++ b/drivers/gpu/drm/radeon/evergreen_cs.c @@ -2654,6 +2654,35 @@ static int evergreen_packet3_check(struct radeon_cs_parser *p, ib[idx+4] = upper_32_bits(offset) & 0xff; } break; + case PACKET3_MEM_WRITE: + { + u64 offset; + + if (pkt->count != 3) { + DRM_ERROR("bad MEM_WRITE (invalid count)\n"); + return -EINVAL; + } + r = evergreen_cs_packet_next_reloc(p, &reloc); + if (r) { + DRM_ERROR("bad MEM_WRITE (missing reloc)\n"); + return -EINVAL; + } + offset = radeon_get_ib_value(p, idx+0); + offset += ((u64)(radeon_get_ib_value(p, idx+1) & 0xff)) << 32UL; + if (offset & 0x7) { + DRM_ERROR("bad MEM_WRITE (address not qwords aligned)\n"); + return -EINVAL; + } + if ((offset + 8) > radeon_bo_size(reloc->robj)) { + DRM_ERROR("bad MEM_WRITE bo too small: 0x%llx, 0x%lx\n", + offset + 8, radeon_bo_size(reloc->robj)); + return -EINVAL; + } + offset += reloc->lobj.gpu_offset; + ib[idx+0] = offset; + ib[idx+1] = upper_32_bits(offset) & 0xff; + break; + } case PACKET3_COPY_DW: if (pkt->count != 4) { DRM_ERROR("bad COPY_DW (invalid count)\n"); diff --git a/drivers/gpu/drm/radeon/r600_cs.c b/drivers/gpu/drm/radeon/r600_cs.c index 0be768be530c..9ea13d07cc55 100644 --- a/drivers/gpu/drm/radeon/r600_cs.c +++ b/drivers/gpu/drm/radeon/r600_cs.c @@ -2294,6 +2294,35 @@ static int r600_packet3_check(struct radeon_cs_parser *p, ib[idx+4] = upper_32_bits(offset) & 0xff; } break; + case PACKET3_MEM_WRITE: + { + u64 offset; + + if (pkt->count != 3) { + DRM_ERROR("bad MEM_WRITE (invalid count)\n"); + return -EINVAL; + } + r = r600_cs_packet_next_reloc(p, &reloc); + if (r) { + DRM_ERROR("bad MEM_WRITE (missing reloc)\n"); + return -EINVAL; + } + offset = radeon_get_ib_value(p, idx+0); + offset += ((u64)(radeon_get_ib_value(p, idx+1) & 0xff)) << 32UL; + if (offset & 0x7) { + DRM_ERROR("bad MEM_WRITE (address not qwords aligned)\n"); + return -EINVAL; + } + if ((offset + 8) > radeon_bo_size(reloc->robj)) { + DRM_ERROR("bad MEM_WRITE bo too small: 0x%llx, 0x%lx\n", + offset + 8, radeon_bo_size(reloc->robj)); + return -EINVAL; + } + offset += reloc->lobj.gpu_offset; + ib[idx+0] = offset; + ib[idx+1] = upper_32_bits(offset) & 0xff; + break; + } case PACKET3_COPY_DW: if (pkt->count != 4) { DRM_ERROR("bad COPY_DW (invalid count)\n"); diff --git a/drivers/gpu/drm/radeon/radeon_drv.c b/drivers/gpu/drm/radeon/radeon_drv.c index 9b1a727d3c9e..ff7593498a74 100644 --- a/drivers/gpu/drm/radeon/radeon_drv.c +++ b/drivers/gpu/drm/radeon/radeon_drv.c @@ -68,9 +68,10 @@ * 2.25.0 - eg+: new info request for num SE and num SH * 2.26.0 - r600-eg: fix htile size computation * 2.27.0 - r600-SI: Add CS ioctl support for async DMA + * 2.28.0 - r600-eg: Add MEM_WRITE packet support */ #define KMS_DRIVER_MAJOR 2 -#define KMS_DRIVER_MINOR 27 +#define KMS_DRIVER_MINOR 28 #define KMS_DRIVER_PATCHLEVEL 0 int radeon_driver_load_kms(struct drm_device *dev, unsigned long flags); int radeon_driver_unload_kms(struct drm_device *dev); -- cgit v1.2.3 From 5b42427fc38ecb9056c4e64deaff36d6d6ba1b67 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Thu, 20 Dec 2012 10:51:09 +1000 Subject: drm/i915: fix flags in dma buf exporting As pointed out by Seung-Woo Kim this should have been passing flags like nouveau/radeon have. Cc: stable@vger.kernel.org Signed-off-by: Dave Airlie Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem_dmabuf.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/i915_gem_dmabuf.c b/drivers/gpu/drm/i915/i915_gem_dmabuf.c index 773ef77b6c22..7be4241e8242 100644 --- a/drivers/gpu/drm/i915/i915_gem_dmabuf.c +++ b/drivers/gpu/drm/i915/i915_gem_dmabuf.c @@ -226,7 +226,7 @@ struct dma_buf *i915_gem_prime_export(struct drm_device *dev, { struct drm_i915_gem_object *obj = to_intel_bo(gem_obj); - return dma_buf_export(obj, &i915_dmabuf_ops, obj->base.size, 0600); + return dma_buf_export(obj, &i915_dmabuf_ops, obj->base.size, flags); } static int i915_gem_object_get_pages_dmabuf(struct drm_i915_gem_object *obj) -- cgit v1.2.3 From 677feac291c1ea7f0b84c6e499e858d440b96c7b Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Wed, 19 Dec 2012 14:33:45 +0100 Subject: drm/i915: optionally disable shrinker lock stealing commit 5774506f157a91400c587b85d1ce4de56f0d32f6 Author: Chris Wilson Date: Wed Nov 21 13:04:04 2012 +0000 drm/i915: Borrow our struct_mutex for the direct reclaim added a nice trick to steal the struct_mutex lock in the shrinker if it's the current task holding it. But this also caused the requirement that every place which allocates memory needs to be careful about the gem state of objects, since the shrinker could have pulled the rug out from under it. We've usually solved this by carefully preallocating things or ensure that buffers are pinned already. But the shrinker also reaps mmap offset, so allocating those needs to be careful, too. Now that code has been factored out into some common helpers, so either we have fragile code depending upon the common helper not doing something we don't want it to do. Or we need to reimplement the mmap offset creation and so also leak implementation details into our code. Since this all results in leaky abstraction, cop out by disabling the lock borrowing trick while calling down into the helpers. That way our craziness is nicely confined to files in drm/i915. v2: Split out the change to create_mmap_offset as request by Chris Wilson. Cc: Chris Wilson Cc: Mika Kuoppala Reviewed-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 1 + drivers/gpu/drm/i915/i915_gem.c | 3 +++ 2 files changed, 4 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 1a4c3a1c111f..ed3059575576 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -780,6 +780,7 @@ typedef struct drm_i915_private { struct i915_hw_ppgtt *aliasing_ppgtt; struct shrinker inactive_shrinker; + bool shrinker_no_lock_stealing; /** * List of objects currently involved in rendering. diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 5feda1f67042..ad6f321083a6 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -4380,6 +4380,9 @@ i915_gem_inactive_shrink(struct shrinker *shrinker, struct shrink_control *sc) if (!mutex_is_locked_by(&dev->struct_mutex, current)) return 0; + if (dev_priv->mm.shrinker_no_lock_stealing) + return 0; + unlock = false; } -- cgit v1.2.3 From da494d7ca5e0a1afca3480826b5060e15c951e80 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Thu, 20 Dec 2012 15:11:16 +0100 Subject: drm/i915: disable shrinker lock stealing for create_mmap_offset The mmap offset structure is not part of the drm/i915 code, but provided by gem helpers. To avoid leaky abstractions (by either depending upon implementation details of said helper wrt to preallocations, or reimplementing it in our code and so fuzzing around in internal details of that helpr) simply disable the shrinker lock stealing accross calls into the helper functions. This should fix igt/gem_tiled_swapping. v2: Fix cleanup path confusion bemoaned by Chris Wilson. Reported-by: Mika Kuoppala Cc: Chris Wilson Cc: Mika Kuoppala Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index ad6f321083a6..84146ad565da 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -1517,9 +1517,11 @@ static int i915_gem_object_create_mmap_offset(struct drm_i915_gem_object *obj) if (obj->base.map_list.map) return 0; + dev_priv->mm.shrinker_no_lock_stealing = true; + ret = drm_gem_create_mmap_offset(&obj->base); if (ret != -ENOSPC) - return ret; + goto out; /* Badly fragmented mmap space? The only way we can recover * space is by destroying unwanted objects. We can't randomly release @@ -1531,10 +1533,14 @@ static int i915_gem_object_create_mmap_offset(struct drm_i915_gem_object *obj) i915_gem_purge(dev_priv, obj->base.size >> PAGE_SHIFT); ret = drm_gem_create_mmap_offset(&obj->base); if (ret != -ENOSPC) - return ret; + goto out; i915_gem_shrink_all(dev_priv); - return drm_gem_create_mmap_offset(&obj->base); + ret = drm_gem_create_mmap_offset(&obj->base); +out: + dev_priv->mm.shrinker_no_lock_stealing = false; + + return ret; } static void i915_gem_object_free_mmap_offset(struct drm_i915_gem_object *obj) -- cgit v1.2.3 From 668bbc81baf0f34df832d8aca5c7d5e19a493c68 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Thu, 20 Dec 2012 21:19:32 -0500 Subject: drm/radeon: add WAIT_UNTIL to evergreen VM safe reg list It's used in a recent mesa commit: http://cgit.freedesktop.org/mesa/mesa/commit/?id=24b1206ab2dcd506aaac3ef656aebc8bc20cd27a and there may be some other cases in the future where it's required. Signed-off-by: Alex Deucher Reviewed-by: Jerome Glisse Cc: stable@vger.kernel.org --- drivers/gpu/drm/radeon/evergreen_cs.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/radeon/evergreen_cs.c b/drivers/gpu/drm/radeon/evergreen_cs.c index 5cea852237ee..7a445666e71f 100644 --- a/drivers/gpu/drm/radeon/evergreen_cs.c +++ b/drivers/gpu/drm/radeon/evergreen_cs.c @@ -3316,6 +3316,7 @@ static bool evergreen_vm_reg_valid(u32 reg) /* check config regs */ switch (reg) { + case WAIT_UNTIL: case GRBM_GFX_INDEX: case CP_STRMOUT_CNTL: case CP_COHER_CNTL: -- cgit v1.2.3 From caba557020d1e7cbb0dd21811e453589fb51ba53 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 6 Dec 2012 14:45:57 +1000 Subject: drm/nouveau: initial support for GK106 Modesetting seems to work alright, as does graphics (using binary driver fuc from nve7...). Lots to be done no doubt, but this'll get an image on the screen for people. Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/core/engine/graph/nvc0.h | 1 + drivers/gpu/drm/nouveau/core/engine/graph/nve0.c | 1 + drivers/gpu/drm/nouveau/core/subdev/device/nve0.c | 28 +++++++++++++++++++++++ 3 files changed, 30 insertions(+) diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/nvc0.h b/drivers/gpu/drm/nouveau/core/engine/graph/nvc0.h index 18d2210e12eb..a1e78de46456 100644 --- a/drivers/gpu/drm/nouveau/core/engine/graph/nvc0.h +++ b/drivers/gpu/drm/nouveau/core/engine/graph/nvc0.h @@ -121,6 +121,7 @@ nvc0_graph_class(void *obj) return 0x9297; case 0xe4: case 0xe7: + case 0xe6: return 0xa097; default: return 0; diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/nve0.c b/drivers/gpu/drm/nouveau/core/engine/graph/nve0.c index 539d4c72f192..261cfce2728c 100644 --- a/drivers/gpu/drm/nouveau/core/engine/graph/nve0.c +++ b/drivers/gpu/drm/nouveau/core/engine/graph/nve0.c @@ -252,6 +252,7 @@ nve0_graph_ctor(struct nouveau_object *parent, struct nouveau_object *engine, priv->magic_not_rop_nr = 1; break; case 0xe7: + case 0xe6: priv->magic_not_rop_nr = 1; break; default: diff --git a/drivers/gpu/drm/nouveau/core/subdev/device/nve0.c b/drivers/gpu/drm/nouveau/core/subdev/device/nve0.c index 9b7881e76634..03a652876e73 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/device/nve0.c +++ b/drivers/gpu/drm/nouveau/core/subdev/device/nve0.c @@ -109,6 +109,34 @@ nve0_identify(struct nouveau_device *device) device->oclass[NVDEV_ENGINE_VP ] = &nve0_vp_oclass; device->oclass[NVDEV_ENGINE_PPP ] = &nvc0_ppp_oclass; break; + case 0xe6: + device->cname = "GK106"; + device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; + device->oclass[NVDEV_SUBDEV_GPIO ] = &nvd0_gpio_oclass; + device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass; + device->oclass[NVDEV_SUBDEV_CLOCK ] = &nvc0_clock_oclass; + device->oclass[NVDEV_SUBDEV_THERM ] = &nv50_therm_oclass; + device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; + device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass; + device->oclass[NVDEV_SUBDEV_MC ] = &nvc0_mc_oclass; + device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; + device->oclass[NVDEV_SUBDEV_FB ] = &nvc0_fb_oclass; + device->oclass[NVDEV_SUBDEV_LTCG ] = &nvc0_ltcg_oclass; + device->oclass[NVDEV_SUBDEV_IBUS ] = &nve0_ibus_oclass; + device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv50_instmem_oclass; + device->oclass[NVDEV_SUBDEV_VM ] = &nvc0_vmmgr_oclass; + device->oclass[NVDEV_SUBDEV_BAR ] = &nvc0_bar_oclass; + device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nvd0_dmaeng_oclass; + device->oclass[NVDEV_ENGINE_FIFO ] = &nve0_fifo_oclass; + device->oclass[NVDEV_ENGINE_SW ] = &nvc0_software_oclass; + device->oclass[NVDEV_ENGINE_GR ] = &nve0_graph_oclass; + device->oclass[NVDEV_ENGINE_DISP ] = &nve0_disp_oclass; + device->oclass[NVDEV_ENGINE_COPY0 ] = &nve0_copy0_oclass; + device->oclass[NVDEV_ENGINE_COPY1 ] = &nve0_copy1_oclass; + device->oclass[NVDEV_ENGINE_BSP ] = &nve0_bsp_oclass; + device->oclass[NVDEV_ENGINE_VP ] = &nve0_vp_oclass; + device->oclass[NVDEV_ENGINE_PPP ] = &nvc0_ppp_oclass; + break; default: nv_fatal(device, "unknown Kepler chipset\n"); return -EINVAL; -- cgit v1.2.3 From d2bcea686f21e11415828fcca21a4eb200c6251f Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Fri, 7 Dec 2012 10:09:17 +1000 Subject: drm/nouveau/bios: update gpio parsing apis to match current design Signed-off-by: Ben Skeggs --- .../drm/nouveau/core/include/subdev/bios/gpio.h | 8 +- drivers/gpu/drm/nouveau/core/subdev/bios/gpio.c | 128 ++++++++++++--------- drivers/gpu/drm/nouveau/core/subdev/gpio/base.c | 7 +- drivers/gpu/drm/nouveau/core/subdev/gpio/nv50.c | 4 +- drivers/gpu/drm/nouveau/core/subdev/gpio/nvd0.c | 4 +- 5 files changed, 90 insertions(+), 61 deletions(-) diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/bios/gpio.h b/drivers/gpu/drm/nouveau/core/include/subdev/bios/gpio.h index 2bf178082a36..e6563b5cb08e 100644 --- a/drivers/gpu/drm/nouveau/core/include/subdev/bios/gpio.h +++ b/drivers/gpu/drm/nouveau/core/include/subdev/bios/gpio.h @@ -25,9 +25,11 @@ struct dcb_gpio_func { u8 param; }; -u16 dcb_gpio_table(struct nouveau_bios *); -u16 dcb_gpio_entry(struct nouveau_bios *, int idx, int ent, u8 *ver); -int dcb_gpio_parse(struct nouveau_bios *, int idx, u8 func, u8 line, +u16 dcb_gpio_table(struct nouveau_bios *, u8 *ver, u8 *hdr, u8 *cnt, u8 *len); +u16 dcb_gpio_entry(struct nouveau_bios *, int idx, int ent, u8 *ver, u8 *len); +u16 dcb_gpio_parse(struct nouveau_bios *, int idx, int ent, u8 *ver, u8 *len, struct dcb_gpio_func *); +u16 dcb_gpio_match(struct nouveau_bios *, int idx, u8 func, u8 line, + u8 *ver, u8 *len, struct dcb_gpio_func *); #endif diff --git a/drivers/gpu/drm/nouveau/core/subdev/bios/gpio.c b/drivers/gpu/drm/nouveau/core/subdev/bios/gpio.c index c90d4aa3ae4f..c84e93fa6d95 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/bios/gpio.c +++ b/drivers/gpu/drm/nouveau/core/subdev/bios/gpio.c @@ -27,84 +27,105 @@ #include u16 -dcb_gpio_table(struct nouveau_bios *bios) +dcb_gpio_table(struct nouveau_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len) { - u8 ver, hdr, cnt, len; - u16 dcb = dcb_table(bios, &ver, &hdr, &cnt, &len); + u16 data = 0x0000; + u16 dcb = dcb_table(bios, ver, hdr, cnt, len); if (dcb) { - if (ver >= 0x30 && hdr >= 0x0c) - return nv_ro16(bios, dcb + 0x0a); - if (ver >= 0x22 && nv_ro08(bios, dcb - 1) >= 0x13) - return nv_ro16(bios, dcb - 0x0f); + if (*ver >= 0x30 && *hdr >= 0x0c) + data = nv_ro16(bios, dcb + 0x0a); + else + if (*ver >= 0x22 && nv_ro08(bios, dcb - 1) >= 0x13) + data = nv_ro16(bios, dcb - 0x0f); + + if (data) { + *ver = nv_ro08(bios, data + 0x00); + if (*ver < 0x30) { + *hdr = 3; + *cnt = nv_ro08(bios, data + 0x02); + *len = nv_ro08(bios, data + 0x01); + } else + if (*ver <= 0x41) { + *hdr = nv_ro08(bios, data + 0x01); + *cnt = nv_ro08(bios, data + 0x02); + *len = nv_ro08(bios, data + 0x03); + } else { + data = 0x0000; + } + } } - return 0x0000; + return data; } u16 -dcb_gpio_entry(struct nouveau_bios *bios, int idx, int ent, u8 *ver) +dcb_gpio_entry(struct nouveau_bios *bios, int idx, int ent, u8 *ver, u8 *len) { - u16 gpio = dcb_gpio_table(bios); - if (gpio) { - *ver = nv_ro08(bios, gpio); - if (*ver < 0x30 && ent < nv_ro08(bios, gpio + 2)) - return gpio + 3 + (ent * nv_ro08(bios, gpio + 1)); - else if (ent < nv_ro08(bios, gpio + 2)) - return gpio + nv_ro08(bios, gpio + 1) + - (ent * nv_ro08(bios, gpio + 3)); - } + u8 hdr, cnt; + u16 gpio = !idx ? dcb_gpio_table(bios, ver, &hdr, &cnt, len) : 0x0000; + if (gpio && ent < cnt) + return gpio + hdr + (ent * *len); return 0x0000; } -int -dcb_gpio_parse(struct nouveau_bios *bios, int idx, u8 func, u8 line, +u16 +dcb_gpio_parse(struct nouveau_bios *bios, int idx, int ent, u8 *ver, u8 *len, struct dcb_gpio_func *gpio) { - u8 ver, hdr, cnt, len; - u16 entry; - int i = -1; - - while ((entry = dcb_gpio_entry(bios, idx, ++i, &ver))) { - if (ver < 0x40) { - u16 data = nv_ro16(bios, entry); + u16 data = dcb_gpio_entry(bios, idx, ent, ver, len); + if (data) { + if (*ver < 0x40) { + u16 info = nv_ro16(bios, data); *gpio = (struct dcb_gpio_func) { - .line = (data & 0x001f) >> 0, - .func = (data & 0x07e0) >> 5, - .log[0] = (data & 0x1800) >> 11, - .log[1] = (data & 0x6000) >> 13, - .param = !!(data & 0x8000), + .line = (info & 0x001f) >> 0, + .func = (info & 0x07e0) >> 5, + .log[0] = (info & 0x1800) >> 11, + .log[1] = (info & 0x6000) >> 13, + .param = !!(info & 0x8000), }; } else - if (ver < 0x41) { - u32 data = nv_ro32(bios, entry); + if (*ver < 0x41) { + u32 info = nv_ro32(bios, data); *gpio = (struct dcb_gpio_func) { - .line = (data & 0x0000001f) >> 0, - .func = (data & 0x0000ff00) >> 8, - .log[0] = (data & 0x18000000) >> 27, - .log[1] = (data & 0x60000000) >> 29, - .param = !!(data & 0x80000000), + .line = (info & 0x0000001f) >> 0, + .func = (info & 0x0000ff00) >> 8, + .log[0] = (info & 0x18000000) >> 27, + .log[1] = (info & 0x60000000) >> 29, + .param = !!(info & 0x80000000), }; } else { - u32 data = nv_ro32(bios, entry + 0); - u8 data1 = nv_ro32(bios, entry + 4); + u32 info = nv_ro32(bios, data + 0); + u8 info1 = nv_ro32(bios, data + 4); *gpio = (struct dcb_gpio_func) { - .line = (data & 0x0000003f) >> 0, - .func = (data & 0x0000ff00) >> 8, - .log[0] = (data1 & 0x30) >> 4, - .log[1] = (data1 & 0xc0) >> 6, - .param = !!(data & 0x80000000), + .line = (info & 0x0000003f) >> 0, + .func = (info & 0x0000ff00) >> 8, + .log[0] = (info1 & 0x30) >> 4, + .log[1] = (info1 & 0xc0) >> 6, + .param = !!(info & 0x80000000), }; } + } + + return data; +} +u16 +dcb_gpio_match(struct nouveau_bios *bios, int idx, u8 func, u8 line, + u8 *ver, u8 *len, struct dcb_gpio_func *gpio) +{ + u8 hdr, cnt, i = 0; + u16 data; + + while ((data = dcb_gpio_parse(bios, idx, i++, ver, len, gpio))) { if ((line == 0xff || line == gpio->line) && (func == 0xff || func == gpio->func)) - return 0; + return data; } /* DCB 2.2, fixed TVDAC GPIO data */ - if ((entry = dcb_table(bios, &ver, &hdr, &cnt, &len))) { - if (ver >= 0x22 && ver < 0x30 && func == DCB_GPIO_TVDAC0) { - u8 conf = nv_ro08(bios, entry - 5); - u8 addr = nv_ro08(bios, entry - 4); + if ((data = dcb_table(bios, ver, &hdr, &cnt, len))) { + if (*ver >= 0x22 && *ver < 0x30 && func == DCB_GPIO_TVDAC0) { + u8 conf = nv_ro08(bios, data - 5); + u8 addr = nv_ro08(bios, data - 4); if (conf & 0x01) { *gpio = (struct dcb_gpio_func) { .func = DCB_GPIO_TVDAC0, @@ -112,10 +133,11 @@ dcb_gpio_parse(struct nouveau_bios *bios, int idx, u8 func, u8 line, .log[0] = !!(conf & 0x02), .log[1] = !(conf & 0x02), }; - return 0; + *ver = 0x00; + return data; } } } - return -EINVAL; + return 0x0000; } diff --git a/drivers/gpu/drm/nouveau/core/subdev/gpio/base.c b/drivers/gpu/drm/nouveau/core/subdev/gpio/base.c index acf818c58bf0..39f267c3241e 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/gpio/base.c +++ b/drivers/gpu/drm/nouveau/core/subdev/gpio/base.c @@ -43,10 +43,15 @@ static int nouveau_gpio_find(struct nouveau_gpio *gpio, int idx, u8 tag, u8 line, struct dcb_gpio_func *func) { + struct nouveau_bios *bios = nouveau_bios(gpio); + u8 ver, len; + u16 data; + if (line == 0xff && tag == 0xff) return -EINVAL; - if (!dcb_gpio_parse(nouveau_bios(gpio), idx, tag, line, func)) + data = dcb_gpio_match(bios, idx, tag, line, &ver, &len, func); + if (data) return 0; /* Apple iMac G4 NV18 */ diff --git a/drivers/gpu/drm/nouveau/core/subdev/gpio/nv50.c b/drivers/gpu/drm/nouveau/core/subdev/gpio/nv50.c index f3502c961cd9..da2341392ced 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/gpio/nv50.c +++ b/drivers/gpu/drm/nouveau/core/subdev/gpio/nv50.c @@ -33,11 +33,11 @@ nv50_gpio_reset(struct nouveau_gpio *gpio) { struct nouveau_bios *bios = nouveau_bios(gpio); struct nv50_gpio_priv *priv = (void *)gpio; + u8 ver, len; u16 entry; - u8 ver; int ent = -1; - while ((entry = dcb_gpio_entry(bios, 0, ++ent, &ver))) { + while ((entry = dcb_gpio_entry(bios, 0, ++ent, &ver, &len))) { static const u32 regs[] = { 0xe100, 0xe28c }; u32 data = nv_ro32(bios, entry); u8 line = (data & 0x0000001f); diff --git a/drivers/gpu/drm/nouveau/core/subdev/gpio/nvd0.c b/drivers/gpu/drm/nouveau/core/subdev/gpio/nvd0.c index 8d18fcad26e0..cda607f24230 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/gpio/nvd0.c +++ b/drivers/gpu/drm/nouveau/core/subdev/gpio/nvd0.c @@ -33,11 +33,11 @@ nvd0_gpio_reset(struct nouveau_gpio *gpio) { struct nouveau_bios *bios = nouveau_bios(gpio); struct nvd0_gpio_priv *priv = (void *)gpio; + u8 ver, len; u16 entry; - u8 ver; int ent = -1; - while ((entry = dcb_gpio_entry(bios, 0, ++ent, &ver))) { + while ((entry = dcb_gpio_entry(bios, 0, ++ent, &ver, &len))) { u32 data = nv_ro32(bios, entry); u8 line = (data & 0x0000003f); u8 defs = !!(data & 0x00000080); -- cgit v1.2.3 From 1ed731668d011d0ee894d949b80dc3d11fc9ef75 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Fri, 7 Dec 2012 13:46:52 +1000 Subject: drm/nouveau/bios: implement opcode 0xa9 Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/core/include/subdev/gpio.h | 2 +- drivers/gpu/drm/nouveau/core/subdev/bios/init.c | 47 +++++++++++++++++++++- drivers/gpu/drm/nouveau/core/subdev/gpio/base.c | 2 +- drivers/gpu/drm/nouveau/core/subdev/gpio/nv50.c | 5 ++- drivers/gpu/drm/nouveau/core/subdev/gpio/nvd0.c | 5 ++- 5 files changed, 53 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/gpio.h b/drivers/gpu/drm/nouveau/core/include/subdev/gpio.h index 9ea2b12cc15d..b75e8f18e52c 100644 --- a/drivers/gpu/drm/nouveau/core/include/subdev/gpio.h +++ b/drivers/gpu/drm/nouveau/core/include/subdev/gpio.h @@ -11,7 +11,7 @@ struct nouveau_gpio { struct nouveau_subdev base; /* hardware interfaces */ - void (*reset)(struct nouveau_gpio *); + void (*reset)(struct nouveau_gpio *, u8 func); int (*drive)(struct nouveau_gpio *, int line, int dir, int out); int (*sense)(struct nouveau_gpio *, int line); void (*irq_enable)(struct nouveau_gpio *, int line, bool); diff --git a/drivers/gpu/drm/nouveau/core/subdev/bios/init.c b/drivers/gpu/drm/nouveau/core/subdev/bios/init.c index ae168bbb86d8..98f78cf318b0 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/bios/init.c +++ b/drivers/gpu/drm/nouveau/core/subdev/bios/init.c @@ -2,11 +2,12 @@ #include #include -#include #include #include +#include #include #include +#include #include #include #include @@ -1781,7 +1782,7 @@ init_gpio(struct nvbios_init *init) init->offset += 1; if (init_exec(init) && gpio && gpio->reset) - gpio->reset(gpio); + gpio->reset(gpio, DCB_GPIO_UNUSED); } /** @@ -1995,6 +1996,47 @@ init_i2c_long_if(struct nvbios_init *init) init_exec_set(init, false); } +/** + * INIT_GPIO_NE - opcode 0xa9 + * + */ +static void +init_gpio_ne(struct nvbios_init *init) +{ + struct nouveau_bios *bios = init->bios; + struct nouveau_gpio *gpio = nouveau_gpio(bios); + struct dcb_gpio_func func; + u8 count = nv_ro08(bios, init->offset + 1); + u8 idx = 0, ver, len; + u16 data, i; + + trace("GPIO_NE\t"); + init->offset += 2; + + for (i = init->offset; i < init->offset + count; i++) + cont("0x%02x ", nv_ro08(bios, i)); + cont("\n"); + + while ((data = dcb_gpio_parse(bios, 0, idx++, &ver, &len, &func))) { + if (func.func != DCB_GPIO_UNUSED) { + for (i = init->offset; i < init->offset + count; i++) { + if (func.func == nv_ro08(bios, i)) + break; + } + + trace("\tFUNC[0x%02x]", func.func); + if (i == (init->offset + count)) { + cont(" *"); + if (init_exec(init) && gpio && gpio->reset) + gpio->reset(gpio, func.func); + } + cont("\n"); + } + } + + init->offset += count; +} + static struct nvbios_init_opcode { void (*exec)(struct nvbios_init *); } init_opcode[] = { @@ -2059,6 +2101,7 @@ static struct nvbios_init_opcode { [0x98] = { init_auxch }, [0x99] = { init_zm_auxch }, [0x9a] = { init_i2c_long_if }, + [0xa9] = { init_gpio_ne }, }; #define init_opcode_nr (sizeof(init_opcode) / sizeof(init_opcode[0])) diff --git a/drivers/gpu/drm/nouveau/core/subdev/gpio/base.c b/drivers/gpu/drm/nouveau/core/subdev/gpio/base.c index 39f267c3241e..9fb0f9b92d49 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/gpio/base.c +++ b/drivers/gpu/drm/nouveau/core/subdev/gpio/base.c @@ -270,7 +270,7 @@ nouveau_gpio_init(struct nouveau_gpio *gpio) int ret = nouveau_subdev_init(&gpio->base); if (ret == 0 && gpio->reset) { if (dmi_check_system(gpio_reset_ids)) - gpio->reset(gpio); + gpio->reset(gpio, DCB_GPIO_UNUSED); } return ret; } diff --git a/drivers/gpu/drm/nouveau/core/subdev/gpio/nv50.c b/drivers/gpu/drm/nouveau/core/subdev/gpio/nv50.c index da2341392ced..bf13a1200f26 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/gpio/nv50.c +++ b/drivers/gpu/drm/nouveau/core/subdev/gpio/nv50.c @@ -29,7 +29,7 @@ struct nv50_gpio_priv { }; static void -nv50_gpio_reset(struct nouveau_gpio *gpio) +nv50_gpio_reset(struct nouveau_gpio *gpio, u8 match) { struct nouveau_bios *bios = nouveau_bios(gpio); struct nv50_gpio_priv *priv = (void *)gpio; @@ -48,7 +48,8 @@ nv50_gpio_reset(struct nouveau_gpio *gpio) u32 val = (unk1 << 16) | unk0; u32 reg = regs[line >> 4]; line &= 0x0f; - if (func == 0xff) + if ( func == DCB_GPIO_UNUSED || + (match != DCB_GPIO_UNUSED && match != func)) continue; gpio->set(gpio, 0, func, line, defs); diff --git a/drivers/gpu/drm/nouveau/core/subdev/gpio/nvd0.c b/drivers/gpu/drm/nouveau/core/subdev/gpio/nvd0.c index cda607f24230..83e8b8f16e6a 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/gpio/nvd0.c +++ b/drivers/gpu/drm/nouveau/core/subdev/gpio/nvd0.c @@ -29,7 +29,7 @@ struct nvd0_gpio_priv { }; static void -nvd0_gpio_reset(struct nouveau_gpio *gpio) +nvd0_gpio_reset(struct nouveau_gpio *gpio, u8 match) { struct nouveau_bios *bios = nouveau_bios(gpio); struct nvd0_gpio_priv *priv = (void *)gpio; @@ -45,7 +45,8 @@ nvd0_gpio_reset(struct nouveau_gpio *gpio) u8 unk0 = (data & 0x00ff0000) >> 16; u8 unk1 = (data & 0x1f000000) >> 24; - if (func == 0xff) + if ( func == DCB_GPIO_UNUSED || + (match != DCB_GPIO_UNUSED && match != func)) continue; gpio->set(gpio, 0, func, line, defs); -- cgit v1.2.3 From 0dd660d4ab9ceb48f24f4df2ebab3e73d908a1e8 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Tue, 11 Dec 2012 12:49:18 +1000 Subject: drm/nouveau/bios: parse/display extra version component Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/core/include/subdev/bios.h | 1 + drivers/gpu/drm/nouveau/core/subdev/bios/base.c | 5 +++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/bios.h b/drivers/gpu/drm/nouveau/core/include/subdev/bios.h index d145b25e6be4..5bd1ca8cd20d 100644 --- a/drivers/gpu/drm/nouveau/core/include/subdev/bios.h +++ b/drivers/gpu/drm/nouveau/core/include/subdev/bios.h @@ -17,6 +17,7 @@ struct nouveau_bios { u8 chip; u8 minor; u8 micro; + u8 patch; } version; }; diff --git a/drivers/gpu/drm/nouveau/core/subdev/bios/base.c b/drivers/gpu/drm/nouveau/core/subdev/bios/base.c index dd111947eb86..f621f69fa1a2 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/bios/base.c +++ b/drivers/gpu/drm/nouveau/core/subdev/bios/base.c @@ -447,6 +447,7 @@ nouveau_bios_ctor(struct nouveau_object *parent, bios->version.chip = nv_ro08(bios, bit_i.offset + 2); bios->version.minor = nv_ro08(bios, bit_i.offset + 1); bios->version.micro = nv_ro08(bios, bit_i.offset + 0); + bios->version.patch = nv_ro08(bios, bit_i.offset + 4); } else if (bmp_version(bios)) { bios->version.major = nv_ro08(bios, bios->bmp_offset + 13); @@ -455,9 +456,9 @@ nouveau_bios_ctor(struct nouveau_object *parent, bios->version.micro = nv_ro08(bios, bios->bmp_offset + 10); } - nv_info(bios, "version %02x.%02x.%02x.%02x\n", + nv_info(bios, "version %02x.%02x.%02x.%02x.%02x\n", bios->version.major, bios->version.chip, - bios->version.minor, bios->version.micro); + bios->version.minor, bios->version.micro, bios->version.patch); return 0; } -- cgit v1.2.3 From 3d8ec277394ee0cf9fdd5a411017c3b4f1b0aff2 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Tue, 11 Dec 2012 13:32:59 +1000 Subject: drm/nouveau/mxm: silence output if no bios data Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/core/subdev/mxm/base.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/nouveau/core/subdev/mxm/base.c b/drivers/gpu/drm/nouveau/core/subdev/mxm/base.c index 93e3ddf7303a..e286e132c7e7 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/mxm/base.c +++ b/drivers/gpu/drm/nouveau/core/subdev/mxm/base.c @@ -260,7 +260,7 @@ nouveau_mxm_create_(struct nouveau_object *parent, data = mxm_table(bios, &ver, &len); if (!data || !(ver = nv_ro08(bios, data))) { - nv_info(mxm, "no VBIOS data, nothing to do\n"); + nv_debug(mxm, "no VBIOS data, nothing to do\n"); return 0; } -- cgit v1.2.3 From 5ddf4d4a543dd3303b20d7e9a4b3549589c5f095 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Dec 2012 07:48:51 +1000 Subject: drm/nouveau/bios: cache ramcfg strap on later chipsets This fixes suspend/resume on at least Quadro 400. Signed-off-by: Ben Skeggs --- .../gpu/drm/nouveau/core/include/subdev/bios/init.h | 1 + drivers/gpu/drm/nouveau/core/subdev/bios/init.c | 18 +++++++++++++++++- 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/bios/init.h b/drivers/gpu/drm/nouveau/core/include/subdev/bios/init.h index e69a8bdc6e97..ca2f6bf37f46 100644 --- a/drivers/gpu/drm/nouveau/core/include/subdev/bios/init.h +++ b/drivers/gpu/drm/nouveau/core/include/subdev/bios/init.h @@ -13,6 +13,7 @@ struct nvbios_init { u32 nested; u16 repeat; u16 repend; + u32 ramcfg; }; int nvbios_exec(struct nvbios_init *); diff --git a/drivers/gpu/drm/nouveau/core/subdev/bios/init.c b/drivers/gpu/drm/nouveau/core/subdev/bios/init.c index 98f78cf318b0..2917d552689b 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/bios/init.c +++ b/drivers/gpu/drm/nouveau/core/subdev/bios/init.c @@ -410,10 +410,26 @@ init_ram_restrict_group_count(struct nvbios_init *init) return 0x00; } +static u8 +init_ram_restrict_strap(struct nvbios_init *init) +{ + /* This appears to be the behaviour of the VBIOS parser, and *is* + * important to cache the NV_PEXTDEV_BOOT0 on later chipsets to + * avoid fucking up the memory controller (somehow) by reading it + * on every INIT_RAM_RESTRICT_ZM_GROUP opcode. + * + * Preserving the non-caching behaviour on earlier chipsets just + * in case *not* re-reading the strap causes similar breakage. + */ + if (!init->ramcfg || init->bios->version.major < 0x70) + init->ramcfg = init_rd32(init, 0x101000); + return (init->ramcfg & 0x00000003c) >> 2; +} + static u8 init_ram_restrict(struct nvbios_init *init) { - u32 strap = (init_rd32(init, 0x101000) & 0x0000003c) >> 2; + u8 strap = init_ram_restrict_strap(init); u16 table = init_ram_restrict_table(init); if (table) return nv_ro08(init->bios, table + strap); -- cgit v1.2.3 From 902530693ef38f3bb007efae594e54443d84fa56 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Dec 2012 12:50:52 +1000 Subject: drm/nvc0/graph: fix fuc, and enable acceleration on GF119 Signed-off-by: Ben Skeggs --- .../drm/nouveau/core/engine/graph/fuc/hubnvc0.fuc | 10 ++ .../nouveau/core/engine/graph/fuc/hubnvc0.fuc.h | 147 +++++++++++---------- drivers/gpu/drm/nouveau/core/engine/graph/nvc0.c | 11 +- 3 files changed, 85 insertions(+), 83 deletions(-) diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnvc0.fuc b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnvc0.fuc index acfc457654bd..0bcfa4d447e5 100644 --- a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnvc0.fuc +++ b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnvc0.fuc @@ -754,6 +754,16 @@ ctx_mmio_exec: // on load it means: "a save preceeded this load" // ctx_xfer: + // according to mwk, some kind of wait for idle + mov $r15 0xc00 + shl b32 $r15 6 + mov $r14 4 + iowr I[$r15 + 0x200] $r14 + ctx_xfer_idle: + iord $r14 I[$r15 + 0x000] + and $r14 0x2000 + bra ne #ctx_xfer_idle + bra not $p1 #ctx_xfer_pre bra $p2 #ctx_xfer_pre_load ctx_xfer_pre: diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnvc0.fuc.h b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnvc0.fuc.h index 85a8d556f484..bb03d2a1d57b 100644 --- a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnvc0.fuc.h +++ b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnvc0.fuc.h @@ -799,79 +799,80 @@ uint32_t nvc0_grhub_code[] = { 0x01fa0613, 0xf803f806, /* 0x0829: ctx_xfer */ - 0x0611f400, -/* 0x082f: ctx_xfer_pre */ - 0xf01102f4, - 0x21f510f7, - 0x21f50698, - 0x11f40631, -/* 0x083d: ctx_xfer_pre_load */ - 0x02f7f01c, - 0x065721f5, - 0x066621f5, - 0x067821f5, - 0x21f5f4bd, - 0x21f50657, -/* 0x0856: ctx_xfer_exec */ - 0x019806b8, - 0x1427f116, - 0x0624b604, - 0xf10020d0, - 0xf0a500e7, - 0x1fb941e3, - 0x8d21f402, - 0xf004e0b6, - 0x2cf001fc, - 0x0124b602, - 0xf405f2fd, - 0x17f18d21, - 0x13f04afc, - 0x0c27f002, - 0xf50012d0, - 0xf1020721, - 0xf047fc27, - 0x20d00223, - 0x012cf000, - 0xd00320b6, - 0xacf00012, - 0x06a5f001, - 0x9800b7f0, - 0x0d98140c, - 0x00e7f015, - 0x015c21f5, - 0xf508a7f0, - 0xf5010321, - 0xf4020721, - 0xa7f02201, - 0xc921f40c, - 0x0a1017f1, - 0xf00614b6, - 0x12d00527, -/* 0x08dd: ctx_xfer_post_save_wait */ - 0x0012cf00, - 0xf40522fd, - 0x02f4fa1b, -/* 0x08e9: ctx_xfer_post */ - 0x02f7f032, - 0x065721f5, - 0x21f5f4bd, - 0x21f50698, - 0x21f50226, - 0xf4bd0666, - 0x065721f5, - 0x981011f4, - 0x11fd8001, - 0x070bf405, - 0x07df21f5, -/* 0x0914: ctx_xfer_no_post_mmio */ - 0x064921f5, -/* 0x0918: ctx_xfer_done */ - 0x000000f8, - 0x00000000, - 0x00000000, - 0x00000000, - 0x00000000, - 0x00000000, + 0x00f7f100, + 0x06f4b60c, + 0xd004e7f0, +/* 0x0836: ctx_xfer_idle */ + 0xfecf80fe, + 0x00e4f100, + 0xf91bf420, + 0xf40611f4, +/* 0x0846: ctx_xfer_pre */ + 0xf7f01102, + 0x9821f510, + 0x3121f506, + 0x1c11f406, +/* 0x0854: ctx_xfer_pre_load */ + 0xf502f7f0, + 0xf5065721, + 0xf5066621, + 0xbd067821, + 0x5721f5f4, + 0xb821f506, +/* 0x086d: ctx_xfer_exec */ + 0x16019806, + 0x041427f1, + 0xd00624b6, + 0xe7f10020, + 0xe3f0a500, + 0x021fb941, + 0xb68d21f4, + 0xfcf004e0, + 0x022cf001, + 0xfd0124b6, + 0x21f405f2, + 0xfc17f18d, + 0x0213f04a, + 0xd00c27f0, + 0x21f50012, + 0x27f10207, + 0x23f047fc, + 0x0020d002, + 0xb6012cf0, + 0x12d00320, + 0x01acf000, + 0xf006a5f0, + 0x0c9800b7, + 0x150d9814, + 0xf500e7f0, + 0xf0015c21, + 0x21f508a7, + 0x21f50103, + 0x01f40207, + 0x0ca7f022, + 0xf1c921f4, + 0xb60a1017, + 0x27f00614, + 0x0012d005, +/* 0x08f4: ctx_xfer_post_save_wait */ + 0xfd0012cf, + 0x1bf40522, + 0x3202f4fa, +/* 0x0900: ctx_xfer_post */ + 0xf502f7f0, + 0xbd065721, + 0x9821f5f4, + 0x2621f506, + 0x6621f502, + 0xf5f4bd06, + 0xf4065721, + 0x01981011, + 0x0511fd80, + 0xf5070bf4, +/* 0x092b: ctx_xfer_no_post_mmio */ + 0xf507df21, +/* 0x092f: ctx_xfer_done */ + 0xf8064921, 0x00000000, 0x00000000, 0x00000000, diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/nvc0.c b/drivers/gpu/drm/nouveau/core/engine/graph/nvc0.c index 47a02081d708..45aff5f5085a 100644 --- a/drivers/gpu/drm/nouveau/core/engine/graph/nvc0.c +++ b/drivers/gpu/drm/nouveau/core/engine/graph/nvc0.c @@ -516,18 +516,9 @@ nvc0_graph_ctor(struct nouveau_object *parent, struct nouveau_object *engine, { struct nouveau_device *device = nv_device(parent); struct nvc0_graph_priv *priv; - bool enable = true; int ret, i; - switch (device->chipset) { - case 0xd9: /* known broken without binary driver firmware */ - enable = false; - break; - default: - break; - } - - ret = nouveau_graph_create(parent, engine, oclass, enable, &priv); + ret = nouveau_graph_create(parent, engine, oclass, true, &priv); *pobject = nv_object(priv); if (ret) return ret; -- cgit v1.2.3 From eca15296a9c2a5d5d7d8281a710ba4bd0c2e7cd3 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Dec 2012 12:52:06 +1000 Subject: drm/nve0/graph: fix fuc, and enable acceleration on all known chipsets Also adds GK106 to chipsets known by ucode. Signed-off-by: Ben Skeggs --- .../drm/nouveau/core/engine/graph/fuc/gpcnve0.fuc | 5 + .../nouveau/core/engine/graph/fuc/gpcnve0.fuc.h | 17 ++- .../drm/nouveau/core/engine/graph/fuc/hubnve0.fuc | 13 ++ .../nouveau/core/engine/graph/fuc/hubnve0.fuc.h | 157 +++++++++++---------- drivers/gpu/drm/nouveau/core/engine/graph/nve0.c | 2 +- 5 files changed, 108 insertions(+), 86 deletions(-) diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcnve0.fuc b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcnve0.fuc index 7b715fda2763..62ab231cd6b6 100644 --- a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcnve0.fuc +++ b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcnve0.fuc @@ -57,6 +57,11 @@ chipsets: .b16 #nve4_gpc_mmio_tail .b16 #nve4_tpc_mmio_head .b16 #nve4_tpc_mmio_tail +.b8 0xe6 0 0 0 +.b16 #nve4_gpc_mmio_head +.b16 #nve4_gpc_mmio_tail +.b16 #nve4_tpc_mmio_head +.b16 #nve4_tpc_mmio_tail .b8 0 0 0 0 // GPC mmio lists diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcnve0.fuc.h b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcnve0.fuc.h index 26c2165bad0f..09ee4702c8b2 100644 --- a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcnve0.fuc.h +++ b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcnve0.fuc.h @@ -34,13 +34,16 @@ uint32_t nve0_grgpc_data[] = { 0x00000000, /* 0x0064: chipsets */ 0x000000e4, - 0x01040080, - 0x014c0104, + 0x0110008c, + 0x01580110, 0x000000e7, - 0x01040080, - 0x014c0104, + 0x0110008c, + 0x01580110, + 0x000000e6, + 0x0110008c, + 0x01580110, 0x00000000, -/* 0x0080: nve4_gpc_mmio_head */ +/* 0x008c: nve4_gpc_mmio_head */ 0x00000380, 0x04000400, 0x0800040c, @@ -74,8 +77,8 @@ uint32_t nve0_grgpc_data[] = { 0x14003100, 0x000031d0, 0x040031e0, -/* 0x0104: nve4_gpc_mmio_tail */ -/* 0x0104: nve4_tpc_mmio_head */ +/* 0x0110: nve4_gpc_mmio_tail */ +/* 0x0110: nve4_tpc_mmio_head */ 0x00000048, 0x00000064, 0x00000088, diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnve0.fuc b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnve0.fuc index 138eeaa28665..7fe9d7cf486b 100644 --- a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnve0.fuc +++ b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnve0.fuc @@ -44,6 +44,9 @@ chipsets: .b8 0xe7 0 0 0 .b16 #nve4_hub_mmio_head .b16 #nve4_hub_mmio_tail +.b8 0xe6 0 0 0 +.b16 #nve4_hub_mmio_head +.b16 #nve4_hub_mmio_tail .b8 0 0 0 0 nve4_hub_mmio_head: @@ -680,6 +683,16 @@ ctx_mmio_exec: // on load it means: "a save preceeded this load" // ctx_xfer: + // according to mwk, some kind of wait for idle + mov $r15 0xc00 + shl b32 $r15 6 + mov $r14 4 + iowr I[$r15 + 0x200] $r14 + ctx_xfer_idle: + iord $r14 I[$r15 + 0x000] + and $r14 0x2000 + bra ne #ctx_xfer_idle + bra not $p1 #ctx_xfer_pre bra $p2 #ctx_xfer_pre_load ctx_xfer_pre: diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnve0.fuc.h b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnve0.fuc.h index decf0c60ca3b..e3421af68ab9 100644 --- a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnve0.fuc.h +++ b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnve0.fuc.h @@ -30,11 +30,13 @@ uint32_t nve0_grhub_data[] = { 0x00000000, /* 0x005c: chipsets */ 0x000000e4, - 0x013c0070, + 0x01440078, 0x000000e7, - 0x013c0070, + 0x01440078, + 0x000000e6, + 0x01440078, 0x00000000, -/* 0x0070: nve4_hub_mmio_head */ +/* 0x0078: nve4_hub_mmio_head */ 0x0417e91c, 0x04400204, 0x18404010, @@ -86,9 +88,7 @@ uint32_t nve0_grhub_data[] = { 0x00408840, 0x08408900, 0x00408980, -/* 0x013c: nve4_hub_mmio_tail */ - 0x00000000, - 0x00000000, +/* 0x0144: nve4_hub_mmio_tail */ 0x00000000, 0x00000000, 0x00000000, @@ -781,77 +781,78 @@ uint32_t nve0_grhub_code[] = { 0x0613f002, 0xf80601fa, /* 0x07fb: ctx_xfer */ - 0xf400f803, - 0x02f40611, -/* 0x0801: ctx_xfer_pre */ - 0x10f7f00d, - 0x067221f5, -/* 0x080b: ctx_xfer_pre_load */ - 0xf01c11f4, - 0x21f502f7, - 0x21f50631, - 0x21f50640, - 0xf4bd0652, - 0x063121f5, - 0x069221f5, -/* 0x0824: ctx_xfer_exec */ - 0xf1160198, - 0xb6041427, - 0x20d00624, - 0x00e7f100, - 0x41e3f0a5, - 0xf4021fb9, - 0xe0b68d21, - 0x01fcf004, - 0xb6022cf0, - 0xf2fd0124, - 0x8d21f405, - 0x4afc17f1, - 0xf00213f0, - 0x12d00c27, - 0x0721f500, - 0xfc27f102, - 0x0223f047, - 0xf00020d0, - 0x20b6012c, - 0x0012d003, - 0xf001acf0, - 0xb7f006a5, - 0x140c9800, - 0xf0150d98, - 0x21f500e7, - 0xa7f0015c, - 0x0321f508, - 0x0721f501, - 0x2201f402, - 0xf40ca7f0, - 0x17f1c921, - 0x14b60a10, - 0x0527f006, -/* 0x08ab: ctx_xfer_post_save_wait */ - 0xcf0012d0, - 0x22fd0012, - 0xfa1bf405, -/* 0x08b7: ctx_xfer_post */ - 0xf02e02f4, - 0x21f502f7, - 0xf4bd0631, - 0x067221f5, - 0x022621f5, - 0x064021f5, - 0x21f5f4bd, - 0x11f40631, - 0x80019810, - 0xf40511fd, - 0x21f5070b, -/* 0x08e2: ctx_xfer_no_post_mmio */ -/* 0x08e2: ctx_xfer_done */ - 0x00f807b1, - 0x00000000, - 0x00000000, - 0x00000000, - 0x00000000, - 0x00000000, - 0x00000000, + 0xf100f803, + 0xb60c00f7, + 0xe7f006f4, + 0x80fed004, +/* 0x0808: ctx_xfer_idle */ + 0xf100fecf, + 0xf42000e4, + 0x11f4f91b, + 0x0d02f406, +/* 0x0818: ctx_xfer_pre */ + 0xf510f7f0, + 0xf4067221, +/* 0x0822: ctx_xfer_pre_load */ + 0xf7f01c11, + 0x3121f502, + 0x4021f506, + 0x5221f506, + 0xf5f4bd06, + 0xf5063121, +/* 0x083b: ctx_xfer_exec */ + 0x98069221, + 0x27f11601, + 0x24b60414, + 0x0020d006, + 0xa500e7f1, + 0xb941e3f0, + 0x21f4021f, + 0x04e0b68d, + 0xf001fcf0, + 0x24b6022c, + 0x05f2fd01, + 0xf18d21f4, + 0xf04afc17, + 0x27f00213, + 0x0012d00c, + 0x020721f5, + 0x47fc27f1, + 0xd00223f0, + 0x2cf00020, + 0x0320b601, + 0xf00012d0, + 0xa5f001ac, + 0x00b7f006, + 0x98140c98, + 0xe7f0150d, + 0x5c21f500, + 0x08a7f001, + 0x010321f5, + 0x020721f5, + 0xf02201f4, + 0x21f40ca7, + 0x1017f1c9, + 0x0614b60a, + 0xd00527f0, +/* 0x08c2: ctx_xfer_post_save_wait */ + 0x12cf0012, + 0x0522fd00, + 0xf4fa1bf4, +/* 0x08ce: ctx_xfer_post */ + 0xf7f02e02, + 0x3121f502, + 0xf5f4bd06, + 0xf5067221, + 0xf5022621, + 0xbd064021, + 0x3121f5f4, + 0x1011f406, + 0xfd800198, + 0x0bf40511, + 0xb121f507, +/* 0x08f9: ctx_xfer_no_post_mmio */ +/* 0x08f9: ctx_xfer_done */ + 0x0000f807, 0x00000000, }; diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/nve0.c b/drivers/gpu/drm/nouveau/core/engine/graph/nve0.c index 261cfce2728c..9f82e9702b46 100644 --- a/drivers/gpu/drm/nouveau/core/engine/graph/nve0.c +++ b/drivers/gpu/drm/nouveau/core/engine/graph/nve0.c @@ -203,7 +203,7 @@ nve0_graph_ctor(struct nouveau_object *parent, struct nouveau_object *engine, struct nvc0_graph_priv *priv; int ret, i; - ret = nouveau_graph_create(parent, engine, oclass, false, &priv); + ret = nouveau_graph_create(parent, engine, oclass, true, &priv); *pobject = nv_object(priv); if (ret) return ret; -- cgit v1.2.3 From 4049508988a6ad03f51c33bf035bd9b603454830 Mon Sep 17 00:00:00 2001 From: Lucas Stach Date: Wed, 19 Dec 2012 21:38:52 +0000 Subject: drm: tegra: fix front_porch <-> back_porch mixup Fixes wrong picture offset observed when using HDMI output with a Technisat HD TV. Signed-off-by: Lucas Stach Acked-by: Mark Zhang Tested-by: Mark Zhang Signed-off-by: Dave Airlie --- drivers/gpu/drm/tegra/dc.c | 8 ++++---- drivers/gpu/drm/tegra/hdmi.c | 6 +++--- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/tegra/dc.c b/drivers/gpu/drm/tegra/dc.c index 074410371e2a..54683e430c77 100644 --- a/drivers/gpu/drm/tegra/dc.c +++ b/drivers/gpu/drm/tegra/dc.c @@ -102,12 +102,12 @@ static int tegra_dc_set_timings(struct tegra_dc *dc, ((mode->hsync_end - mode->hsync_start) << 0); tegra_dc_writel(dc, value, DC_DISP_SYNC_WIDTH); - value = ((mode->vsync_start - mode->vdisplay) << 16) | - ((mode->hsync_start - mode->hdisplay) << 0); - tegra_dc_writel(dc, value, DC_DISP_BACK_PORCH); - value = ((mode->vtotal - mode->vsync_end) << 16) | ((mode->htotal - mode->hsync_end) << 0); + tegra_dc_writel(dc, value, DC_DISP_BACK_PORCH); + + value = ((mode->vsync_start - mode->vdisplay) << 16) | + ((mode->hsync_start - mode->hdisplay) << 0); tegra_dc_writel(dc, value, DC_DISP_FRONT_PORCH); value = (mode->vdisplay << 16) | mode->hdisplay; diff --git a/drivers/gpu/drm/tegra/hdmi.c b/drivers/gpu/drm/tegra/hdmi.c index ab4016412bbf..81ea934214f1 100644 --- a/drivers/gpu/drm/tegra/hdmi.c +++ b/drivers/gpu/drm/tegra/hdmi.c @@ -479,7 +479,7 @@ static void tegra_hdmi_setup_avi_infoframe(struct tegra_hdmi *hdmi, return; } - h_front_porch = mode->htotal - mode->hsync_end; + h_front_porch = mode->hsync_start - mode->hdisplay; memset(&frame, 0, sizeof(frame)); frame.r = HDMI_AVI_R_SAME; @@ -634,8 +634,8 @@ static int tegra_output_hdmi_enable(struct tegra_output *output) pclk = mode->clock * 1000; h_sync_width = mode->hsync_end - mode->hsync_start; - h_front_porch = mode->htotal - mode->hsync_end; - h_back_porch = mode->hsync_start - mode->hdisplay; + h_back_porch = mode->htotal - mode->hsync_end; + h_front_porch = mode->hsync_start - mode->hdisplay; err = regulator_enable(hdmi->vdd); if (err < 0) { -- cgit v1.2.3 From 4026bfb39a3e63e32b3c4a648bb1ac1fd8c6b162 Mon Sep 17 00:00:00 2001 From: Lucas Stach Date: Wed, 19 Dec 2012 21:38:53 +0000 Subject: drm: tegra: don't leave clients host1x member uninitialized No real problem for now, as nothing is using this, but leaving it unitialized is asking for trouble later on. Signed-off-by: Lucas Stach Signed-off-by: Dave Airlie --- drivers/gpu/drm/tegra/host1x.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/gpu/drm/tegra/host1x.c b/drivers/gpu/drm/tegra/host1x.c index bdb97a564d82..5d17b113a6fc 100644 --- a/drivers/gpu/drm/tegra/host1x.c +++ b/drivers/gpu/drm/tegra/host1x.c @@ -239,6 +239,8 @@ int host1x_register_client(struct host1x *host1x, struct host1x_client *client) } } + client->host1x = host1x; + return 0; } -- cgit v1.2.3 From 83c0bcb694be31dcd6c04bdd935b96a95a0af548 Mon Sep 17 00:00:00 2001 From: Lucas Stach Date: Wed, 19 Dec 2012 21:38:54 +0000 Subject: drm: tegra: protect DC register access with mutex Window properties are programmed through a shared aperture and have to happen atomically. Also we do the read-update-write dance on some of the shared regs. To make sure that different functions don't stumble over each other protect the register access with a mutex. Signed-off-by: Lucas Stach Signed-off-by: Dave Airlie --- drivers/gpu/drm/tegra/dc.c | 13 +++++++++++++ drivers/gpu/drm/tegra/drm.h | 1 + 2 files changed, 14 insertions(+) diff --git a/drivers/gpu/drm/tegra/dc.c b/drivers/gpu/drm/tegra/dc.c index 54683e430c77..b256574409e7 100644 --- a/drivers/gpu/drm/tegra/dc.c +++ b/drivers/gpu/drm/tegra/dc.c @@ -171,6 +171,8 @@ static int tegra_crtc_mode_set(struct drm_crtc *crtc, return err; } + mutex_lock(&dc->regs_mutex); + /* program display mode */ tegra_dc_set_timings(dc, mode); @@ -269,6 +271,8 @@ static int tegra_crtc_mode_set(struct drm_crtc *crtc, tegra_dc_writel(dc, 0xff00, DC_WIN_BLEND_NOKEY); tegra_dc_writel(dc, 0xff00, DC_WIN_BLEND_1WIN); + mutex_unlock(&dc->regs_mutex); + return 0; } @@ -287,6 +291,8 @@ static void tegra_crtc_prepare(struct drm_crtc *crtc) else syncpt = SYNCPT_VBLANK0; + mutex_lock(&dc->regs_mutex); + /* initialize display controller */ tegra_dc_writel(dc, 0x00000100, DC_CMD_GENERAL_INCR_SYNCPT_CNTRL); tegra_dc_writel(dc, 0x100 | syncpt, DC_CMD_CONT_SYNCPT_VSYNC); @@ -320,6 +326,8 @@ static void tegra_crtc_prepare(struct drm_crtc *crtc) value = VBLANK_INT | WIN_A_UF_INT | WIN_B_UF_INT | WIN_C_UF_INT; tegra_dc_writel(dc, value, DC_CMD_INT_ENABLE); + + mutex_unlock(&dc->regs_mutex); } static void tegra_crtc_commit(struct drm_crtc *crtc) @@ -330,6 +338,8 @@ static void tegra_crtc_commit(struct drm_crtc *crtc) update_mask = GENERAL_ACT_REQ | WIN_A_ACT_REQ; + mutex_lock(&dc->regs_mutex); + tegra_dc_writel(dc, update_mask << 8, DC_CMD_STATE_CONTROL); value = tegra_dc_readl(dc, DC_CMD_INT_ENABLE); @@ -341,6 +351,8 @@ static void tegra_crtc_commit(struct drm_crtc *crtc) tegra_dc_writel(dc, value, DC_CMD_INT_MASK); tegra_dc_writel(dc, update_mask, DC_CMD_STATE_CONTROL); + + mutex_unlock(&dc->regs_mutex); } static void tegra_crtc_load_lut(struct drm_crtc *crtc) @@ -747,6 +759,7 @@ static int tegra_dc_probe(struct platform_device *pdev) return -ENOMEM; INIT_LIST_HEAD(&dc->list); + mutex_init(&dc->regs_mutex); dc->dev = &pdev->dev; dc->clk = devm_clk_get(&pdev->dev, NULL); diff --git a/drivers/gpu/drm/tegra/drm.h b/drivers/gpu/drm/tegra/drm.h index 3a843a77ddc7..eae1f564b716 100644 --- a/drivers/gpu/drm/tegra/drm.h +++ b/drivers/gpu/drm/tegra/drm.h @@ -84,6 +84,7 @@ struct tegra_dc { struct clk *clk; + struct mutex regs_mutex; void __iomem *regs; int irq; -- cgit v1.2.3 From fa416ddc0ae5996d894b10f7f49efc2a494b048b Mon Sep 17 00:00:00 2001 From: Lucas Stach Date: Wed, 19 Dec 2012 21:38:55 +0000 Subject: drm: tegra: remove redundant tegra2_tmds_config entry The 720p and 1080p entries are completely redundant, as we are matching the table entries against <=pclk. Also generalize the comment, as we are using those table entries even when driving other modes than the standard TV ones. Signed-off-by: Lucas Stach Signed-off-by: Dave Airlie --- drivers/gpu/drm/tegra/hdmi.c | 19 +++---------------- 1 file changed, 3 insertions(+), 16 deletions(-) diff --git a/drivers/gpu/drm/tegra/hdmi.c b/drivers/gpu/drm/tegra/hdmi.c index 81ea934214f1..e060c7e6434d 100644 --- a/drivers/gpu/drm/tegra/hdmi.c +++ b/drivers/gpu/drm/tegra/hdmi.c @@ -149,7 +149,7 @@ struct tmds_config { }; static const struct tmds_config tegra2_tmds_config[] = { - { /* 480p modes */ + { /* slow pixel clock modes */ .pclk = 27000000, .pll0 = SOR_PLL_BG_V17_S(3) | SOR_PLL_ICHPMP(1) | SOR_PLL_RESISTORSEL | SOR_PLL_VCOCAP(0) | @@ -163,21 +163,8 @@ static const struct tmds_config tegra2_tmds_config[] = { DRIVE_CURRENT_LANE1(DRIVE_CURRENT_7_125_mA) | DRIVE_CURRENT_LANE2(DRIVE_CURRENT_7_125_mA) | DRIVE_CURRENT_LANE3(DRIVE_CURRENT_7_125_mA), - }, { /* 720p modes */ - .pclk = 74250000, - .pll0 = SOR_PLL_BG_V17_S(3) | SOR_PLL_ICHPMP(1) | - SOR_PLL_RESISTORSEL | SOR_PLL_VCOCAP(1) | - SOR_PLL_TX_REG_LOAD(3), - .pll1 = SOR_PLL_TMDS_TERM_ENABLE | SOR_PLL_PE_EN, - .pe_current = PE_CURRENT0(PE_CURRENT_6_0_mA) | - PE_CURRENT1(PE_CURRENT_6_0_mA) | - PE_CURRENT2(PE_CURRENT_6_0_mA) | - PE_CURRENT3(PE_CURRENT_6_0_mA), - .drive_current = DRIVE_CURRENT_LANE0(DRIVE_CURRENT_7_125_mA) | - DRIVE_CURRENT_LANE1(DRIVE_CURRENT_7_125_mA) | - DRIVE_CURRENT_LANE2(DRIVE_CURRENT_7_125_mA) | - DRIVE_CURRENT_LANE3(DRIVE_CURRENT_7_125_mA), - }, { /* 1080p modes */ + }, + { /* high pixel clock modes */ .pclk = UINT_MAX, .pll0 = SOR_PLL_BG_V17_S(3) | SOR_PLL_ICHPMP(1) | SOR_PLL_RESISTORSEL | SOR_PLL_VCOCAP(1) | -- cgit v1.2.3 From e39250aa5246b43aae882274e345620f665ab5ef Mon Sep 17 00:00:00 2001 From: Lucas Stach Date: Wed, 19 Dec 2012 21:38:56 +0000 Subject: drm: tegra: clean out old gem prototypes There is no gem.c anymore, those functions are implemented by the drm_cma_helpers now. Signed-off-by: Lucas Stach Signed-off-by: Dave Airlie --- drivers/gpu/drm/tegra/drm.h | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/drivers/gpu/drm/tegra/drm.h b/drivers/gpu/drm/tegra/drm.h index eae1f564b716..71e61f2b0741 100644 --- a/drivers/gpu/drm/tegra/drm.h +++ b/drivers/gpu/drm/tegra/drm.h @@ -205,24 +205,6 @@ extern int tegra_output_parse_dt(struct tegra_output *output); extern int tegra_output_init(struct drm_device *drm, struct tegra_output *output); extern int tegra_output_exit(struct tegra_output *output); -/* from gem.c */ -extern struct tegra_gem_object *tegra_gem_alloc(struct drm_device *drm, - size_t size); -extern int tegra_gem_handle_create(struct drm_device *drm, - struct drm_file *file, size_t size, - unsigned long flags, uint32_t *handle); -extern int tegra_gem_dumb_create(struct drm_file *file, struct drm_device *drm, - struct drm_mode_create_dumb *args); -extern int tegra_gem_dumb_map_offset(struct drm_file *file, - struct drm_device *drm, uint32_t handle, - uint64_t *offset); -extern int tegra_gem_dumb_destroy(struct drm_file *file, - struct drm_device *drm, uint32_t handle); -extern int tegra_drm_gem_mmap(struct file *filp, struct vm_area_struct *vma); -extern int tegra_gem_init_object(struct drm_gem_object *obj); -extern void tegra_gem_free_object(struct drm_gem_object *obj); -extern struct vm_operations_struct tegra_gem_vm_ops; - /* from fb.c */ extern int tegra_drm_fb_init(struct drm_device *drm); extern void tegra_drm_fb_exit(struct drm_device *drm); -- cgit v1.2.3 From 500df2e5d870ef5be3d37f0798f770028b69fd47 Mon Sep 17 00:00:00 2001 From: Lucas Stach Date: Wed, 19 Dec 2012 21:38:57 +0000 Subject: drm: tegra: program only one window during modeset The intention is to program exactly WIN_A, not WIN_A and possibly others. Signed-off-by: Lucas Stach Signed-off-by: Dave Airlie --- drivers/gpu/drm/tegra/dc.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/gpu/drm/tegra/dc.c b/drivers/gpu/drm/tegra/dc.c index b256574409e7..3475bd9f9719 100644 --- a/drivers/gpu/drm/tegra/dc.c +++ b/drivers/gpu/drm/tegra/dc.c @@ -223,8 +223,7 @@ static int tegra_crtc_mode_set(struct drm_crtc *crtc, win.stride = crtc->fb->pitches[0]; /* program window registers */ - value = tegra_dc_readl(dc, DC_CMD_DISPLAY_WINDOW_HEADER); - value |= WINDOW_A_SELECT; + value = WINDOW_A_SELECT; tegra_dc_writel(dc, value, DC_CMD_DISPLAY_WINDOW_HEADER); tegra_dc_writel(dc, win.fmt, DC_WIN_COLOR_DEPTH); -- cgit v1.2.3 From d5757dbe79870d825d0dec30074d48683e1d7e9a Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Sun, 30 Dec 2012 21:58:20 +1000 Subject: Revert "drm: tegra: protect DC register access with mutex" This reverts commit 83c0bcb694be31dcd6c04bdd935b96a95a0af548. Lucas pointed out this was a mistake, and I missed the discussion, so just revert it out to save a rebase. Signed-off-by: Dave Airlie --- drivers/gpu/drm/tegra/dc.c | 13 ------------- drivers/gpu/drm/tegra/drm.h | 1 - 2 files changed, 14 deletions(-) diff --git a/drivers/gpu/drm/tegra/dc.c b/drivers/gpu/drm/tegra/dc.c index 3475bd9f9719..656b2e3334a6 100644 --- a/drivers/gpu/drm/tegra/dc.c +++ b/drivers/gpu/drm/tegra/dc.c @@ -171,8 +171,6 @@ static int tegra_crtc_mode_set(struct drm_crtc *crtc, return err; } - mutex_lock(&dc->regs_mutex); - /* program display mode */ tegra_dc_set_timings(dc, mode); @@ -270,8 +268,6 @@ static int tegra_crtc_mode_set(struct drm_crtc *crtc, tegra_dc_writel(dc, 0xff00, DC_WIN_BLEND_NOKEY); tegra_dc_writel(dc, 0xff00, DC_WIN_BLEND_1WIN); - mutex_unlock(&dc->regs_mutex); - return 0; } @@ -290,8 +286,6 @@ static void tegra_crtc_prepare(struct drm_crtc *crtc) else syncpt = SYNCPT_VBLANK0; - mutex_lock(&dc->regs_mutex); - /* initialize display controller */ tegra_dc_writel(dc, 0x00000100, DC_CMD_GENERAL_INCR_SYNCPT_CNTRL); tegra_dc_writel(dc, 0x100 | syncpt, DC_CMD_CONT_SYNCPT_VSYNC); @@ -325,8 +319,6 @@ static void tegra_crtc_prepare(struct drm_crtc *crtc) value = VBLANK_INT | WIN_A_UF_INT | WIN_B_UF_INT | WIN_C_UF_INT; tegra_dc_writel(dc, value, DC_CMD_INT_ENABLE); - - mutex_unlock(&dc->regs_mutex); } static void tegra_crtc_commit(struct drm_crtc *crtc) @@ -337,8 +329,6 @@ static void tegra_crtc_commit(struct drm_crtc *crtc) update_mask = GENERAL_ACT_REQ | WIN_A_ACT_REQ; - mutex_lock(&dc->regs_mutex); - tegra_dc_writel(dc, update_mask << 8, DC_CMD_STATE_CONTROL); value = tegra_dc_readl(dc, DC_CMD_INT_ENABLE); @@ -350,8 +340,6 @@ static void tegra_crtc_commit(struct drm_crtc *crtc) tegra_dc_writel(dc, value, DC_CMD_INT_MASK); tegra_dc_writel(dc, update_mask, DC_CMD_STATE_CONTROL); - - mutex_unlock(&dc->regs_mutex); } static void tegra_crtc_load_lut(struct drm_crtc *crtc) @@ -758,7 +746,6 @@ static int tegra_dc_probe(struct platform_device *pdev) return -ENOMEM; INIT_LIST_HEAD(&dc->list); - mutex_init(&dc->regs_mutex); dc->dev = &pdev->dev; dc->clk = devm_clk_get(&pdev->dev, NULL); diff --git a/drivers/gpu/drm/tegra/drm.h b/drivers/gpu/drm/tegra/drm.h index 71e61f2b0741..741b5dc2742c 100644 --- a/drivers/gpu/drm/tegra/drm.h +++ b/drivers/gpu/drm/tegra/drm.h @@ -84,7 +84,6 @@ struct tegra_dc { struct clk *clk; - struct mutex regs_mutex; void __iomem *regs; int irq; -- cgit v1.2.3