From 5035c275af811b93dec5df6d064e0b2319cf59c8 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Fri, 4 Oct 2013 09:58:46 +0100 Subject: drm/i915: Call io_schedule() whilst whilsting for the GPU Since we are waiting upon IO completion, inform the kernel through use of the io_schedule() call rather than the regular schedule(). This should allow the kernel to make better decisions regarding scheduling and power management. Signed-off-by: Chris Wilson Cc: Daniel Vetter Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 13c885d66383..7dc9c9c7778c 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -1082,7 +1082,7 @@ static int __wait_seqno(struct intel_ring_buffer *ring, u32 seqno, mod_timer(&timer, expire); } - schedule(); + io_schedule(); if (timeout) timeout_jiffies = expire - jiffies; -- cgit v1.2.2 From d9973b4356096e8b040d6eba02407bccdaf101af Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Fri, 4 Oct 2013 10:33:00 +0100 Subject: drm/i915: Fix type mismatch and accounting in i915_gem_shrink The interface uses an unsigned long, and we can use the unsigned counter throughout our code, so do so. In the process, we notice one instance where the shrink count is based on a heuristic rather than the result, and another where we ask for too many pages to be purged. v2: nr_to_scan needs to be promoted to a long as well, so just use sc->nr_to_scan directly. Signed-off-by: Chris Wilson Cc: Daniel Vetter Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem.c | 29 +++++++++++++++-------------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 7dc9c9c7778c..ed9311aaabe7 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -64,8 +64,8 @@ static unsigned long i915_gem_inactive_count(struct shrinker *shrinker, struct shrink_control *sc); static unsigned long i915_gem_inactive_scan(struct shrinker *shrinker, struct shrink_control *sc); -static long i915_gem_purge(struct drm_i915_private *dev_priv, long target); -static long i915_gem_shrink_all(struct drm_i915_private *dev_priv); +static unsigned long i915_gem_purge(struct drm_i915_private *dev_priv, long target); +static unsigned long i915_gem_shrink_all(struct drm_i915_private *dev_priv); static void i915_gem_object_truncate(struct drm_i915_gem_object *obj); static bool cpu_cache_is_coherent(struct drm_device *dev, @@ -1728,13 +1728,13 @@ i915_gem_object_put_pages(struct drm_i915_gem_object *obj) return 0; } -static long +static unsigned long __i915_gem_shrink(struct drm_i915_private *dev_priv, long target, bool purgeable_only) { struct list_head still_bound_list; struct drm_i915_gem_object *obj, *next; - long count = 0; + unsigned long count = 0; list_for_each_entry_safe(obj, next, &dev_priv->mm.unbound_list, @@ -1800,13 +1800,13 @@ __i915_gem_shrink(struct drm_i915_private *dev_priv, long target, return count; } -static long +static unsigned long i915_gem_purge(struct drm_i915_private *dev_priv, long target) { return __i915_gem_shrink(dev_priv, target, true); } -static long +static unsigned long i915_gem_shrink_all(struct drm_i915_private *dev_priv) { struct drm_i915_gem_object *obj, *next; @@ -1816,9 +1816,8 @@ i915_gem_shrink_all(struct drm_i915_private *dev_priv) list_for_each_entry_safe(obj, next, &dev_priv->mm.unbound_list, global_list) { - if (obj->pages_pin_count == 0) + if (i915_gem_object_put_pages(obj) == 0) freed += obj->base.size >> PAGE_SHIFT; - i915_gem_object_put_pages(obj); } return freed; } @@ -4947,6 +4946,7 @@ i915_gem_inactive_count(struct shrinker *shrinker, struct shrink_control *sc) if (unlock) mutex_unlock(&dev->struct_mutex); + return count; } @@ -5018,7 +5018,6 @@ i915_gem_inactive_scan(struct shrinker *shrinker, struct shrink_control *sc) struct drm_i915_private, mm.inactive_shrinker); struct drm_device *dev = dev_priv->dev; - int nr_to_scan = sc->nr_to_scan; unsigned long freed; bool unlock = true; @@ -5032,15 +5031,17 @@ i915_gem_inactive_scan(struct shrinker *shrinker, struct shrink_control *sc) unlock = false; } - freed = i915_gem_purge(dev_priv, nr_to_scan); - if (freed < nr_to_scan) - freed += __i915_gem_shrink(dev_priv, nr_to_scan, - false); - if (freed < nr_to_scan) + freed = i915_gem_purge(dev_priv, sc->nr_to_scan); + if (freed < sc->nr_to_scan) + freed += __i915_gem_shrink(dev_priv, + sc->nr_to_scan - freed, + false); + if (freed < sc->nr_to_scan) freed += i915_gem_shrink_all(dev_priv); if (unlock) mutex_unlock(&dev->struct_mutex); + return freed; } -- cgit v1.2.2 From 389246f9c1a96c2db3b72006fd862a3af45fa663 Mon Sep 17 00:00:00 2001 From: Damien Lespiau Date: Fri, 4 Oct 2013 12:27:00 +0100 Subject: drm/i915: Remove yet another unused define Signed-off-by: Damien Lespiau Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_debugfs.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index 61fd61969e21..5fd6a5db6eb5 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -38,9 +38,6 @@ #include #include "i915_drv.h" -#define DRM_I915_RING_DEBUG 1 - - #if defined(CONFIG_DEBUG_FS) enum { -- cgit v1.2.2 From 953d22e870e2f15963976c77985b263afcceafc9 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Fri, 4 Oct 2013 15:08:47 +0300 Subject: drm/i915/dp: use sizeof for memset instead of magic value Signed-off-by: Jani Nikula Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_dp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 4f52ec75b39f..d9090d0340c7 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -2389,7 +2389,7 @@ static bool intel_dp_reset_link_train(struct intel_dp *intel_dp, uint32_t *DP, uint8_t dp_train_pat) { - memset(intel_dp->train_set, 0, 4); + memset(intel_dp->train_set, 0, sizeof(intel_dp->train_set)); intel_dp_set_signal_levels(intel_dp, DP); return intel_dp_set_link_train(intel_dp, DP, dp_train_pat); } -- cgit v1.2.2 From 69e4f900be175fd80fe69221a329c8993b16925b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Tue, 24 Sep 2013 21:26:20 +0300 Subject: drm/i915: Make vlv_find_best_dpll() ppm calculation safe MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use div_u64() to make the ppm calculation in vlv_find_best_dpll() safe against interger overflows. Signed-off-by: Ville Syrjälä Reviewed-by: Mika Kuoppala Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 617b963dfb67..dc5077560c74 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -672,13 +672,11 @@ vlv_find_best_dpll(const intel_limit_t *limit, struct drm_crtc *crtc, u32 p1, p2, m1, m2, vco, bestn, bestm1, bestm2, bestp1, bestp2; u32 m, n, fastclk; u32 updrate, minupdate, p; - unsigned long bestppm, ppm, absppm; + unsigned int bestppm = 1000000; int dotclk, flag; flag = 0; dotclk = target * 1000; - bestppm = 1000000; - ppm = absppm = 0; fastclk = dotclk / (2*100); updrate = 0; minupdate = 19200; @@ -695,6 +693,8 @@ vlv_find_best_dpll(const intel_limit_t *limit, struct drm_crtc *crtc, p = p1 * p2; /* based on hardware requirement, prefer bigger m1,m2 values */ for (m1 = limit->m1.min; m1 <= limit->m1.max; m1++) { + unsigned int ppm, diff; + m2 = DIV_ROUND_CLOSEST(fastclk * p * n, refclk * m1); m = m1 * m2; vco = updrate * m; @@ -702,14 +702,14 @@ vlv_find_best_dpll(const intel_limit_t *limit, struct drm_crtc *crtc, if (vco < limit->vco.min || vco >= limit->vco.max) continue; - ppm = 1000000 * ((vco / p) - fastclk) / fastclk; - absppm = (ppm > 0) ? ppm : (-ppm); - if (absppm < 100 && ((p1 * p2) > (bestp1 * bestp2))) { + diff = abs(vco / p - fastclk); + ppm = div_u64(1000000ULL * diff, fastclk); + if (ppm < 100 && ((p1 * p2) > (bestp1 * bestp2))) { bestppm = 0; flag = 1; } - if (absppm < bestppm - 10) { - bestppm = absppm; + if (ppm < bestppm - 10) { + bestppm = ppm; flag = 1; } if (flag) { -- cgit v1.2.2 From c686122c638838ce7113aeb22e4f1c50446de6eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Tue, 24 Sep 2013 21:26:21 +0300 Subject: drm/i915: Don't underflow bestppm MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We do 'bestppm - 10' in vlv_find_best_dpll() but never check whether that might underflow. Add such a check. Signed-off-by: Ville Syrjälä Reviewed-by: Mika Kuoppala Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index dc5077560c74..789e6ab8fb19 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -708,7 +708,7 @@ vlv_find_best_dpll(const intel_limit_t *limit, struct drm_crtc *crtc, bestppm = 0; flag = 1; } - if (ppm < bestppm - 10) { + if (bestppm >= 10 && ppm < bestppm - 10) { bestppm = ppm; flag = 1; } -- cgit v1.2.2 From 6b4bf1c4952a65fae6b4043054b146642f031f19 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Fri, 27 Sep 2013 16:54:19 +0300 Subject: drm/i915: Rewrite vlv_find_best_dpll() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Rewrite vlv_find_best_dpll() to use intel_clock_t rather than an army of local variables. Also extract the code to calculate the derived values into vlv_clock(). v2: Split up the earlier fixes, extract vlv_clock() v3: Initialize best_clock Signed-off-by: Ville Syrjälä Reviewed-by: Mika Kuoppala Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 74 ++++++++++++++++-------------------- 1 file changed, 33 insertions(+), 41 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 789e6ab8fb19..d984b10831a7 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -335,6 +335,14 @@ static const intel_limit_t intel_limits_vlv_hdmi = { .p2_slow = 2, .p2_fast = 20 }, }; +static void vlv_clock(int refclk, intel_clock_t *clock) +{ + clock->m = clock->m1 * clock->m2; + clock->p = clock->p1 * clock->p2; + clock->vco = refclk * clock->m / clock->n; + clock->dot = clock->vco / clock->p; +} + /** * Returns whether any output on the specified pipe is of the specified type */ @@ -669,66 +677,50 @@ vlv_find_best_dpll(const intel_limit_t *limit, struct drm_crtc *crtc, int target, int refclk, intel_clock_t *match_clock, intel_clock_t *best_clock) { - u32 p1, p2, m1, m2, vco, bestn, bestm1, bestm2, bestp1, bestp2; - u32 m, n, fastclk; - u32 updrate, minupdate, p; + intel_clock_t clock; + u32 minupdate = 19200; unsigned int bestppm = 1000000; - int dotclk, flag; - flag = 0; - dotclk = target * 1000; - fastclk = dotclk / (2*100); - updrate = 0; - minupdate = 19200; - n = p = p1 = p2 = m = m1 = m2 = vco = bestn = 0; - bestm1 = bestm2 = bestp1 = bestp2 = 0; + target *= 5; /* fast clock */ + + memset(best_clock, 0, sizeof(*best_clock)); /* based on hardware requirement, prefer smaller n to precision */ - for (n = limit->n.min; n <= ((refclk) / minupdate); n++) { - updrate = refclk / n; - for (p1 = limit->p1.max; p1 > limit->p1.min; p1--) { - for (p2 = limit->p2.p2_fast+1; p2 > 0; p2--) { - if (p2 > 10) - p2 = p2 - 1; - p = p1 * p2; + for (clock.n = limit->n.min; clock.n <= ((refclk) / minupdate); clock.n++) { + for (clock.p1 = limit->p1.max; clock.p1 > limit->p1.min; clock.p1--) { + for (clock.p2 = limit->p2.p2_fast+1; clock.p2 > 0; clock.p2--) { + if (clock.p2 > 10) + clock.p2--; + clock.p = clock.p1 * clock.p2; /* based on hardware requirement, prefer bigger m1,m2 values */ - for (m1 = limit->m1.min; m1 <= limit->m1.max; m1++) { + for (clock.m1 = limit->m1.min; clock.m1 <= limit->m1.max; clock.m1++) { unsigned int ppm, diff; - m2 = DIV_ROUND_CLOSEST(fastclk * p * n, refclk * m1); - m = m1 * m2; - vco = updrate * m; + clock.m2 = DIV_ROUND_CLOSEST(target * clock.p * clock.n, + refclk * clock.m1); + + vlv_clock(refclk, &clock); - if (vco < limit->vco.min || vco >= limit->vco.max) + if (clock.vco < limit->vco.min || + clock.vco >= limit->vco.max) continue; - diff = abs(vco / p - fastclk); - ppm = div_u64(1000000ULL * diff, fastclk); - if (ppm < 100 && ((p1 * p2) > (bestp1 * bestp2))) { + diff = abs(clock.dot - target); + ppm = div_u64(1000000ULL * diff, target); + + if (ppm < 100 && clock.p > best_clock->p) { bestppm = 0; - flag = 1; + *best_clock = clock; } + if (bestppm >= 10 && ppm < bestppm - 10) { bestppm = ppm; - flag = 1; - } - if (flag) { - bestn = n; - bestm1 = m1; - bestm2 = m2; - bestp1 = p1; - bestp2 = p2; - flag = 0; + *best_clock = clock; } } } } } - best_clock->n = bestn; - best_clock->m1 = bestm1; - best_clock->m2 = bestm2; - best_clock->p1 = bestp1; - best_clock->p2 = bestp2; return true; } -- cgit v1.2.2 From c1a9ae43885246df7a35c790960d7a703b2841d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Tue, 24 Sep 2013 21:26:23 +0300 Subject: drm/i915: De-magic the VLV p2 divider step size MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The p2 divider on VLV needs to be even when it's > 10. The current code to make that happen is rather weird. Just make the step size adjustement in the for loop decrement step. Signed-off-by: Ville Syrjälä Reviewed-by: Mika Kuoppala Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index d984b10831a7..62cfada50735 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -688,9 +688,8 @@ vlv_find_best_dpll(const intel_limit_t *limit, struct drm_crtc *crtc, /* based on hardware requirement, prefer smaller n to precision */ for (clock.n = limit->n.min; clock.n <= ((refclk) / minupdate); clock.n++) { for (clock.p1 = limit->p1.max; clock.p1 > limit->p1.min; clock.p1--) { - for (clock.p2 = limit->p2.p2_fast+1; clock.p2 > 0; clock.p2--) { - if (clock.p2 > 10) - clock.p2--; + for (clock.p2 = limit->p2.p2_fast; clock.p2 > 0; + clock.p2 -= clock.p2 > 10 ? 2 : 1) { clock.p = clock.p1 * clock.p2; /* based on hardware requirement, prefer bigger m1,m2 values */ for (clock.m1 = limit->m1.min; clock.m1 <= limit->m1.max; clock.m1++) { -- cgit v1.2.2 From 27e639bf024a0706015dbb348eb32619a9bb9329 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Tue, 24 Sep 2013 21:26:24 +0300 Subject: drm/i915: Make sure we respect n.max on VLV MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We limit the maximum n divider value in order to make sure the PLL's reference inout is at least 19.2 MHz. I assume that is done to satisfy some hardware requirement. However we never check whether that calculated limit is below the maximum supoorted N divider value (7). In practice that is always true since we only support 100 MHz reference clock, but making the code safe against higher reference clocks seems like a reasoanble thing to do. Signed-off-by: Ville Syrjälä Reviewed-by: Mika Kuoppala Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 62cfada50735..ed95eb25833a 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -678,15 +678,16 @@ vlv_find_best_dpll(const intel_limit_t *limit, struct drm_crtc *crtc, intel_clock_t *best_clock) { intel_clock_t clock; - u32 minupdate = 19200; unsigned int bestppm = 1000000; + /* min update 19.2 MHz */ + int max_n = min(limit->n.max, refclk / 19200); target *= 5; /* fast clock */ memset(best_clock, 0, sizeof(*best_clock)); /* based on hardware requirement, prefer smaller n to precision */ - for (clock.n = limit->n.min; clock.n <= ((refclk) / minupdate); clock.n++) { + for (clock.n = limit->n.min; clock.n <= max_n; clock.n++) { for (clock.p1 = limit->p1.max; clock.p1 > limit->p1.min; clock.p1--) { for (clock.p2 = limit->p2.p2_fast; clock.p2 > 0; clock.p2 -= clock.p2 > 10 ? 2 : 1) { -- cgit v1.2.2 From 811bbf05447b17db2fb13387da9b7d553438d5c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Tue, 24 Sep 2013 21:26:25 +0300 Subject: drm/i915: Clarify VLV PLL p1 limits MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit For some reason there's a sort of off by one issue with the p1 divider. The actual p1 limits according to VLV2_DPLL_mphy_hsdpll_frequency_table_ww6_rev1p1.xlsm is 2-3, so we should just say that instead of saying 1-3 and avoiding the 1 via the choice of comparison operator. I don't know why we're using different p1 limits for intel_limits_vlv_dac and intel_limits_vlv_hdmi, but let's preserve that for now. Signed-off-by: Ville Syrjälä Reviewed-by: Mika Kuoppala Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index ed95eb25833a..99c56b8f6462 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -317,7 +317,7 @@ static const intel_limit_t intel_limits_vlv_dac = { .m1 = { .min = 2, .max = 3 }, .m2 = { .min = 11, .max = 156 }, .p = { .min = 10, .max = 30 }, - .p1 = { .min = 1, .max = 3 }, + .p1 = { .min = 2, .max = 3 }, .p2 = { .dot_limit = 270000, .p2_slow = 2, .p2_fast = 20 }, }; @@ -330,7 +330,7 @@ static const intel_limit_t intel_limits_vlv_hdmi = { .m1 = { .min = 2, .max = 3 }, .m2 = { .min = 11, .max = 156 }, .p = { .min = 10, .max = 30 }, - .p1 = { .min = 2, .max = 3 }, + .p1 = { .min = 3, .max = 3 }, .p2 = { .dot_limit = 270000, .p2_slow = 2, .p2_fast = 20 }, }; @@ -688,7 +688,7 @@ vlv_find_best_dpll(const intel_limit_t *limit, struct drm_crtc *crtc, /* based on hardware requirement, prefer smaller n to precision */ for (clock.n = limit->n.min; clock.n <= max_n; clock.n++) { - for (clock.p1 = limit->p1.max; clock.p1 > limit->p1.min; clock.p1--) { + for (clock.p1 = limit->p1.max; clock.p1 >= limit->p1.min; clock.p1--) { for (clock.p2 = limit->p2.p2_fast; clock.p2 > 0; clock.p2 -= clock.p2 > 10 ? 2 : 1) { clock.p = clock.p1 * clock.p2; -- cgit v1.2.2 From b99ab66301f384766b8e37abe52719c65a7da140 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Tue, 24 Sep 2013 21:26:26 +0300 Subject: drm/i915: Allow p1 divider 2 on VLV MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit According to VLV2_DPLL_mphy_hsdpll_frequency_table_ww6_rev1p1.xlsm p1 can be 2-3 always. Signed-off-by: Ville Syrjälä Reviewed-by: Mika Kuoppala Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 99c56b8f6462..c4658e7c3bb6 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -330,7 +330,7 @@ static const intel_limit_t intel_limits_vlv_hdmi = { .m1 = { .min = 2, .max = 3 }, .m2 = { .min = 11, .max = 156 }, .p = { .min = 10, .max = 30 }, - .p1 = { .min = 3, .max = 3 }, + .p1 = { .min = 2, .max = 3 }, .p2 = { .dot_limit = 270000, .p2_slow = 2, .p2_fast = 20 }, }; -- cgit v1.2.2 From 889059d8f0eff8d179d98c3fee64a27d7ff6312f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Tue, 24 Sep 2013 21:26:27 +0300 Subject: drm/i915: Respect p2 divider minimum limit on VLV MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit VLV2_DPLL_mphy_hsdpll_frequency_table_ww6_rev1p1.xlsm tells us that the minimum p2 divider is 2. Use that limit on the code. Signed-off-by: Ville Syrjälä Reviewed-by: Mika Kuoppala Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index c4658e7c3bb6..89d04612cc29 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -319,7 +319,7 @@ static const intel_limit_t intel_limits_vlv_dac = { .p = { .min = 10, .max = 30 }, .p1 = { .min = 2, .max = 3 }, .p2 = { .dot_limit = 270000, - .p2_slow = 2, .p2_fast = 20 }, + .p2_slow = 2, .p2_fast = 20 }, /* slow=min, fast=max */ }; static const intel_limit_t intel_limits_vlv_hdmi = { @@ -332,7 +332,7 @@ static const intel_limit_t intel_limits_vlv_hdmi = { .p = { .min = 10, .max = 30 }, .p1 = { .min = 2, .max = 3 }, .p2 = { .dot_limit = 270000, - .p2_slow = 2, .p2_fast = 20 }, + .p2_slow = 2, .p2_fast = 20 }, /* slow=min, fast=max */ }; static void vlv_clock(int refclk, intel_clock_t *clock) @@ -689,7 +689,7 @@ vlv_find_best_dpll(const intel_limit_t *limit, struct drm_crtc *crtc, /* based on hardware requirement, prefer smaller n to precision */ for (clock.n = limit->n.min; clock.n <= max_n; clock.n++) { for (clock.p1 = limit->p1.max; clock.p1 >= limit->p1.min; clock.p1--) { - for (clock.p2 = limit->p2.p2_fast; clock.p2 > 0; + for (clock.p2 = limit->p2.p2_fast; clock.p2 >= limit->p2.p2_slow; clock.p2 -= clock.p2 > 10 ? 2 : 1) { clock.p = clock.p1 * clock.p2; /* based on hardware requirement, prefer bigger m1,m2 values */ -- cgit v1.2.2 From 41504046e95fe9c2ca3753a3adc562c1df910b11 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Tue, 24 Sep 2013 21:26:28 +0300 Subject: drm/i915: Remove the unused p and m limits for VLV MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We never check the p and m limits (which according to comments are based on someone's guesswork), so just remove them. VLV2_DPLL_mphy_hsdpll_frequency_table_ww6_rev1p1.xlsm has no p and m limits listed. Signed-off-by: Ville Syrjälä Reviewed-by: Mika Kuoppala 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 89d04612cc29..d041d007cfe5 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -313,10 +313,8 @@ static const intel_limit_t intel_limits_vlv_dac = { .dot = { .min = 25000, .max = 270000 }, .vco = { .min = 4000000, .max = 6000000 }, .n = { .min = 1, .max = 7 }, - .m = { .min = 22, .max = 450 }, /* guess */ .m1 = { .min = 2, .max = 3 }, .m2 = { .min = 11, .max = 156 }, - .p = { .min = 10, .max = 30 }, .p1 = { .min = 2, .max = 3 }, .p2 = { .dot_limit = 270000, .p2_slow = 2, .p2_fast = 20 }, /* slow=min, fast=max */ @@ -326,10 +324,8 @@ static const intel_limit_t intel_limits_vlv_hdmi = { .dot = { .min = 25000, .max = 270000 }, .vco = { .min = 4000000, .max = 6000000 }, .n = { .min = 1, .max = 7 }, - .m = { .min = 60, .max = 300 }, /* guess */ .m1 = { .min = 2, .max = 3 }, .m2 = { .min = 11, .max = 156 }, - .p = { .min = 10, .max = 30 }, .p1 = { .min = 2, .max = 3 }, .p2 = { .dot_limit = 270000, .p2_slow = 2, .p2_fast = 20 }, /* slow=min, fast=max */ -- cgit v1.2.2 From 5fdc9c49f676cc9224df0830a26f7f993ada2517 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Tue, 24 Sep 2013 21:26:29 +0300 Subject: drm/i915: Remove unused dot_limit from VLV PLL limits MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We don't use .dot_limit for anything on VLV, so don't populate it. Signed-off-by: Ville Syrjälä Reviewed-by: Mika Kuoppala Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index d041d007cfe5..83739d2401ab 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -316,8 +316,7 @@ static const intel_limit_t intel_limits_vlv_dac = { .m1 = { .min = 2, .max = 3 }, .m2 = { .min = 11, .max = 156 }, .p1 = { .min = 2, .max = 3 }, - .p2 = { .dot_limit = 270000, - .p2_slow = 2, .p2_fast = 20 }, /* slow=min, fast=max */ + .p2 = { .p2_slow = 2, .p2_fast = 20 }, /* slow=min, fast=max */ }; static const intel_limit_t intel_limits_vlv_hdmi = { @@ -327,8 +326,7 @@ static const intel_limit_t intel_limits_vlv_hdmi = { .m1 = { .min = 2, .max = 3 }, .m2 = { .min = 11, .max = 156 }, .p1 = { .min = 2, .max = 3 }, - .p2 = { .dot_limit = 270000, - .p2_slow = 2, .p2_fast = 20 }, /* slow=min, fast=max */ + .p2 = { .p2_slow = 2, .p2_fast = 20 }, /* slow=min, fast=max */ }; static void vlv_clock(int refclk, intel_clock_t *clock) -- cgit v1.2.2 From dc730512be540c7e438f1411e11662edbd8638ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Tue, 24 Sep 2013 21:26:30 +0300 Subject: drm/i915: intel_limits_vlv_dac and intel_limits_vlv_hdmi are the same MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit After aligning the p1 divider limits, and removing the unused p and m limits, intel_limits_vlv_dac and intel_limits_vlv_hdmi are identical. Signed-off-by: Ville Syrjälä Reviewed-by: Mika Kuoppala Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 17 ++--------------- 1 file changed, 2 insertions(+), 15 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 83739d2401ab..1ea6d49b9380 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -309,17 +309,7 @@ static const intel_limit_t intel_limits_ironlake_dual_lvds_100m = { .p2_slow = 7, .p2_fast = 7 }, }; -static const intel_limit_t intel_limits_vlv_dac = { - .dot = { .min = 25000, .max = 270000 }, - .vco = { .min = 4000000, .max = 6000000 }, - .n = { .min = 1, .max = 7 }, - .m1 = { .min = 2, .max = 3 }, - .m2 = { .min = 11, .max = 156 }, - .p1 = { .min = 2, .max = 3 }, - .p2 = { .p2_slow = 2, .p2_fast = 20 }, /* slow=min, fast=max */ -}; - -static const intel_limit_t intel_limits_vlv_hdmi = { +static const intel_limit_t intel_limits_vlv = { .dot = { .min = 25000, .max = 270000 }, .vco = { .min = 4000000, .max = 6000000 }, .n = { .min = 1, .max = 7 }, @@ -412,10 +402,7 @@ static const intel_limit_t *intel_limit(struct drm_crtc *crtc, int refclk) else limit = &intel_limits_pineview_sdvo; } else if (IS_VALLEYVIEW(dev)) { - if (intel_pipe_has_type(crtc, INTEL_OUTPUT_ANALOG)) - limit = &intel_limits_vlv_dac; - else - limit = &intel_limits_vlv_hdmi; + limit = &intel_limits_vlv; } else if (!IS_GEN2(dev)) { if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)) limit = &intel_limits_i9xx_lvds; -- cgit v1.2.2 From 49e497ef43e06dbf65e0a3637bcaedb31ce17d34 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Tue, 24 Sep 2013 21:26:31 +0300 Subject: drm/i915: Don't lie about findind suitable PLL settings on VLV MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If vlv_find_best_dpll() couldn't find suitable PLL settings, just say so instead of lying to caller. Signed-off-by: Ville Syrjälä Reviewed-by: Mika Kuoppala Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 1ea6d49b9380..0e87970a03f6 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -662,6 +662,7 @@ vlv_find_best_dpll(const intel_limit_t *limit, struct drm_crtc *crtc, unsigned int bestppm = 1000000; /* min update 19.2 MHz */ int max_n = min(limit->n.max, refclk / 19200); + bool found = false; target *= 5; /* fast clock */ @@ -692,18 +693,20 @@ vlv_find_best_dpll(const intel_limit_t *limit, struct drm_crtc *crtc, if (ppm < 100 && clock.p > best_clock->p) { bestppm = 0; *best_clock = clock; + found = true; } if (bestppm >= 10 && ppm < bestppm - 10) { bestppm = ppm; *best_clock = clock; + found = true; } } } } } - return true; + return found; } bool intel_crtc_active(struct drm_crtc *crtc) -- cgit v1.2.2 From f01b796283e0fb2aa70b7cceb7067340f8ec6626 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Fri, 27 Sep 2013 16:55:49 +0300 Subject: drm/i915: Use intel_PLL_is_valid() in vlv_find_best_dpll() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Everyone else uses intel_PLL_is_valid(), so make VLV use it as well. We don't have any special p and m limits on VLV, so skip those tests, and we also need to skip the m1<=m2 test line PNV. Reorganize the function a bit to move the n check alongside the rest of the test for the non-derived dividers, and check the derived values afterwards. Note that this changes vlv_find_best_dpll() in two ways: - The .vco comparison is now >max instead of >=max, and since we round down when calculating that stuff, we may now allow frequencies slightly above the max as we do on other platforms. The previous method disallowed exactly max and anything above it. - We now check the .dot frequency against the data rate limits, which we didn't do before. Signed-off-by: Ville Syrjälä Reviewed-by: Mika Kuoppala Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 35 ++++++++++++++++++++++++----------- 1 file changed, 24 insertions(+), 11 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 0e87970a03f6..183eb82e9beb 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -310,7 +310,13 @@ static const intel_limit_t intel_limits_ironlake_dual_lvds_100m = { }; static const intel_limit_t intel_limits_vlv = { - .dot = { .min = 25000, .max = 270000 }, + /* + * These are the data rate limits (measured in fast clocks) + * since those are the strictest limits we have. The fast + * clock and actual rate limits are more relaxed, so checking + * them would make no difference. + */ + .dot = { .min = 25000 * 5, .max = 270000 * 5 }, .vco = { .min = 4000000, .max = 6000000 }, .n = { .min = 1, .max = 7 }, .m1 = { .min = 2, .max = 3 }, @@ -451,20 +457,26 @@ static bool intel_PLL_is_valid(struct drm_device *dev, const intel_limit_t *limit, const intel_clock_t *clock) { + if (clock->n < limit->n.min || limit->n.max < clock->n) + INTELPllInvalid("n out of range\n"); if (clock->p1 < limit->p1.min || limit->p1.max < clock->p1) INTELPllInvalid("p1 out of range\n"); - if (clock->p < limit->p.min || limit->p.max < clock->p) - INTELPllInvalid("p out of range\n"); if (clock->m2 < limit->m2.min || limit->m2.max < clock->m2) INTELPllInvalid("m2 out of range\n"); if (clock->m1 < limit->m1.min || limit->m1.max < clock->m1) INTELPllInvalid("m1 out of range\n"); - if (clock->m1 <= clock->m2 && !IS_PINEVIEW(dev)) - INTELPllInvalid("m1 <= m2\n"); - if (clock->m < limit->m.min || limit->m.max < clock->m) - INTELPllInvalid("m out of range\n"); - if (clock->n < limit->n.min || limit->n.max < clock->n) - INTELPllInvalid("n out of range\n"); + + if (!IS_PINEVIEW(dev) && !IS_VALLEYVIEW(dev)) + if (clock->m1 <= clock->m2) + INTELPllInvalid("m1 <= m2\n"); + + if (!IS_VALLEYVIEW(dev)) { + if (clock->p < limit->p.min || limit->p.max < clock->p) + INTELPllInvalid("p out of range\n"); + if (clock->m < limit->m.min || limit->m.max < clock->m) + INTELPllInvalid("m out of range\n"); + } + if (clock->vco < limit->vco.min || limit->vco.max < clock->vco) INTELPllInvalid("vco out of range\n"); /* XXX: We may need to be checking "Dot clock" depending on the multiplier, @@ -658,6 +670,7 @@ vlv_find_best_dpll(const intel_limit_t *limit, struct drm_crtc *crtc, int target, int refclk, intel_clock_t *match_clock, intel_clock_t *best_clock) { + struct drm_device *dev = crtc->dev; intel_clock_t clock; unsigned int bestppm = 1000000; /* min update 19.2 MHz */ @@ -683,8 +696,8 @@ vlv_find_best_dpll(const intel_limit_t *limit, struct drm_crtc *crtc, vlv_clock(refclk, &clock); - if (clock.vco < limit->vco.min || - clock.vco >= limit->vco.max) + if (!intel_PLL_is_valid(dev, limit, + &clock)) continue; diff = abs(clock.dot - target); -- cgit v1.2.2 From e1553faa904f3f8bdd734ee1404ce39c652bc9c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Fri, 4 Oct 2013 20:32:25 +0300 Subject: drm/i915: Fix VGA_DISP_DISABLE check MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The VGACNTRL register contains a bunch of other stuff besides the VGA_DISP_DISABLE bit. When we write the register we always set those other bits to zero, so normally the current check would work. However on HSW disabling and re-enabling the power well will reset the VGACNTRL register to its default value, which has several of the other bits set as well. So only look at the VGA_DISP_DISABLE bit when checking whether the VGA plane needs re-disabling. Signed-off-by: Ville Syrjälä Reviewed-by: Jesse Barnes Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 183eb82e9beb..a003bc572a00 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -10663,7 +10663,7 @@ void i915_redisable_vga(struct drm_device *dev) (I915_READ(HSW_PWR_WELL_DRIVER) & HSW_PWR_WELL_STATE_ENABLED) == 0) return; - if (I915_READ(vga_reg) != VGA_DISP_DISABLE) { + if (!(I915_READ(vga_reg) & VGA_DISP_DISABLE)) { DRM_DEBUG_KMS("Something enabled VGA plane, disabling it\n"); i915_disable_vga(dev); i915_disable_vga_mem(dev); -- cgit v1.2.2 From 3def84b34c80518cd0375440dde8ce690795b369 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Sat, 5 Oct 2013 16:13:56 +0300 Subject: drm/i915/dp: promote clock recovery failures to DRM_ERROR If channel equalization succeeds, there's no indication something went wrong in clock recovery (unless debug is enabled). We should shout about the failures and fix them instead of hiding them under the carpet. This has allowed bugs like [1] stay dormant for a long time. [1] https://bugs.freedesktop.org/show_bug.cgi?id=70117 Signed-off-by: Jani Nikula Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_dp.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index d9090d0340c7..377014783e74 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -2507,7 +2507,7 @@ intel_dp_start_link_train(struct intel_dp *intel_dp) if (i == intel_dp->lane_count) { ++loop_tries; if (loop_tries == 5) { - DRM_DEBUG_KMS("too many full retries, give up\n"); + DRM_ERROR("too many full retries, give up\n"); break; } intel_dp_reset_link_train(intel_dp, &DP, @@ -2521,7 +2521,7 @@ intel_dp_start_link_train(struct intel_dp *intel_dp) if ((intel_dp->train_set[0] & DP_TRAIN_VOLTAGE_SWING_MASK) == voltage) { ++voltage_tries; if (voltage_tries == 5) { - DRM_DEBUG_KMS("too many voltage retries, give up\n"); + DRM_ERROR("too many voltage retries, give up\n"); break; } } else -- cgit v1.2.2 From 939c2fe8bdb0fbf163dc8555a08c5ca863babd89 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Tue, 1 Oct 2013 18:02:10 +0300 Subject: drm/i915: Set primary_disabled in intel_{enable, disable}_plane MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If the primary gets marked as disabled while the pipe is off for instance, we should still re-enable it when the pipe is turned on, unless the sprite covers it fully also in that configuration. Unfortunately we do the plane visibility checks only in the sprite code, which is executed after the primary enabling when turning the pipe off. Ideally we should compute the plane visibility before touching the hardware at all, but for now just set the primary_disabld flag in intel_{enable,disable}_plane. Signed-off-by: Ville Syrjälä Reviewed-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index a003bc572a00..579becbc46ec 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -1832,12 +1832,16 @@ void intel_flush_display_plane(struct drm_i915_private *dev_priv, static void intel_enable_plane(struct drm_i915_private *dev_priv, enum plane plane, enum pipe pipe) { + struct intel_crtc *intel_crtc = + to_intel_crtc(dev_priv->pipe_to_crtc_mapping[pipe]); int reg; u32 val; /* If the pipe isn't enabled, we can't pump pixels and may hang */ assert_pipe_enabled(dev_priv, pipe); + intel_crtc->primary_disabled = false; + reg = DSPCNTR(plane); val = I915_READ(reg); if (val & DISPLAY_PLANE_ENABLE) @@ -1859,9 +1863,13 @@ static void intel_enable_plane(struct drm_i915_private *dev_priv, static void intel_disable_plane(struct drm_i915_private *dev_priv, enum plane plane, enum pipe pipe) { + struct intel_crtc *intel_crtc = + to_intel_crtc(dev_priv->pipe_to_crtc_mapping[pipe]); int reg; u32 val; + intel_crtc->primary_disabled = true; + reg = DSPCNTR(plane); val = I915_READ(reg); if ((val & DISPLAY_PLANE_ENABLE) == 0) -- cgit v1.2.2 From 03c5b25f6efd8190dab133eeecf1c0dae307dea8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Tue, 1 Oct 2013 18:02:11 +0300 Subject: drm/i915: Allow sprites to be configured on a disabled pipe MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We allow cursors to be set up when the pipe is disabled. Do the same for sprites as well. We need to be somewhat careful with the primary disable logic as we don't want to accidentally enable the primary plane on a disabled pipe. v2: Skip primary enable/disable and plane registers writes on disabled pipe Signed-off-by: Ville Syrjälä Reviewed-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_sprite.c | 65 ++++++++++++++++++------------------- 1 file changed, 32 insertions(+), 33 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_sprite.c b/drivers/gpu/drm/i915/intel_sprite.c index cae10bc746d0..9161a1db8dff 100644 --- a/drivers/gpu/drm/i915/intel_sprite.c +++ b/drivers/gpu/drm/i915/intel_sprite.c @@ -623,14 +623,10 @@ intel_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, uint32_t src_w, uint32_t src_h) { struct drm_device *dev = plane->dev; - struct drm_i915_private *dev_priv = dev->dev_private; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); struct intel_plane *intel_plane = to_intel_plane(plane); struct intel_framebuffer *intel_fb; struct drm_i915_gem_object *obj, *old_obj; - int pipe = intel_plane->pipe; - enum transcoder cpu_transcoder = intel_pipe_to_cpu_transcoder(dev_priv, - pipe); int ret = 0; bool disable_primary = false; bool visible; @@ -652,8 +648,8 @@ intel_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, .y2 = crtc_y + crtc_h, }; const struct drm_rect clip = { - .x2 = intel_crtc->config.pipe_src_w, - .y2 = intel_crtc->config.pipe_src_h, + .x2 = intel_crtc->active ? intel_crtc->config.pipe_src_w : 0, + .y2 = intel_crtc->active ? intel_crtc->config.pipe_src_h : 0, }; intel_fb = to_intel_framebuffer(fb); @@ -670,12 +666,6 @@ intel_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, intel_plane->src_w = src_w; intel_plane->src_h = src_h; - /* Pipe must be running... */ - if (!(I915_READ(PIPECONF(cpu_transcoder)) & PIPECONF_ENABLE)) { - DRM_DEBUG_KMS("Pipe disabled\n"); - return -EINVAL; - } - /* Don't modify another pipe's plane */ if (intel_plane->pipe != intel_crtc->pipe) { DRM_DEBUG_KMS("Wrong plane <-> crtc mapping\n"); @@ -810,7 +800,7 @@ intel_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, * we can disable the primary and save power. */ disable_primary = drm_rect_equals(&dst, &clip); - WARN_ON(disable_primary && !visible); + WARN_ON(disable_primary && !visible && intel_crtc->active); mutex_lock(&dev->struct_mutex); @@ -825,22 +815,24 @@ intel_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, intel_plane->obj = obj; - /* - * Be sure to re-enable the primary before the sprite is no longer - * covering it fully. - */ - if (!disable_primary) - intel_enable_primary(crtc); - - if (visible) - intel_plane->update_plane(plane, crtc, fb, obj, - crtc_x, crtc_y, crtc_w, crtc_h, - src_x, src_y, src_w, src_h); - else - intel_plane->disable_plane(plane, crtc); - - if (disable_primary) - intel_disable_primary(crtc); + if (intel_crtc->active) { + /* + * Be sure to re-enable the primary before the sprite is no longer + * covering it fully. + */ + if (!disable_primary) + intel_enable_primary(crtc); + + if (visible) + intel_plane->update_plane(plane, crtc, fb, obj, + crtc_x, crtc_y, crtc_w, crtc_h, + src_x, src_y, src_w, src_h); + else + intel_plane->disable_plane(plane, crtc); + + if (disable_primary) + intel_disable_primary(crtc); + } /* Unpin old obj after new one is active to avoid ugliness */ if (old_obj) { @@ -852,7 +844,8 @@ intel_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, */ if (old_obj != obj) { mutex_unlock(&dev->struct_mutex); - intel_wait_for_vblank(dev, to_intel_crtc(crtc)->pipe); + if (intel_crtc->active) + intel_wait_for_vblank(dev, to_intel_crtc(crtc)->pipe); mutex_lock(&dev->struct_mutex); } intel_unpin_fb_obj(old_obj); @@ -868,6 +861,7 @@ intel_disable_plane(struct drm_plane *plane) { struct drm_device *dev = plane->dev; struct intel_plane *intel_plane = to_intel_plane(plane); + struct intel_crtc *intel_crtc; int ret = 0; if (!plane->fb) @@ -876,13 +870,18 @@ intel_disable_plane(struct drm_plane *plane) if (WARN_ON(!plane->crtc)) return -EINVAL; - intel_enable_primary(plane->crtc); - intel_plane->disable_plane(plane, plane->crtc); + intel_crtc = to_intel_crtc(plane->crtc); + + if (intel_crtc->active) { + intel_enable_primary(plane->crtc); + intel_plane->disable_plane(plane, plane->crtc); + } if (!intel_plane->obj) goto out; - intel_wait_for_vblank(dev, intel_plane->pipe); + if (intel_crtc->active) + intel_wait_for_vblank(dev, intel_plane->pipe); mutex_lock(&dev->struct_mutex); intel_unpin_fb_obj(intel_plane->obj); -- cgit v1.2.2 From 82284b6becdbef6d8cd3fb43e8698510833a5129 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Tue, 1 Oct 2013 18:02:12 +0300 Subject: drm/i915: Reduce the time we hold struct mutex in sprite update_plane code MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We used to call the entire intel specific update_plane hook while holding struct_mutex. Actually we only need to hold struct_mutex while pinning/unpinning the obj. The plane state itself is protected by the kms locks, and as the object is pinned we can dig out the offset and tiling information from it without fearing that it would change underneath us. So now we don't need to drop and reacquire the lock around the wait_for_vblank. Also we will need another wait_for_vblank in the IVB specific update_plane hook, and this way we don't need to worry about struct_mutex there either. Also move the intel_plane->obj=NULL assignment outside strut_mutex in disable_plane to make it clear that it's not protected by struct_mutex. Signed-off-by: Ville Syrjälä Reviewed-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_sprite.c | 29 ++++++++++++++++++----------- 1 file changed, 18 insertions(+), 11 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_sprite.c b/drivers/gpu/drm/i915/intel_sprite.c index 9161a1db8dff..b859f944b53b 100644 --- a/drivers/gpu/drm/i915/intel_sprite.c +++ b/drivers/gpu/drm/i915/intel_sprite.c @@ -525,7 +525,10 @@ intel_enable_primary(struct drm_crtc *crtc) return; intel_crtc->primary_disabled = false; + + mutex_lock(&dev->struct_mutex); intel_update_fbc(dev); + mutex_unlock(&dev->struct_mutex); I915_WRITE(reg, I915_READ(reg) | DISPLAY_PLANE_ENABLE); } @@ -544,7 +547,10 @@ intel_disable_primary(struct drm_crtc *crtc) I915_WRITE(reg, I915_READ(reg) & ~DISPLAY_PLANE_ENABLE); intel_crtc->primary_disabled = true; + + mutex_lock(&dev->struct_mutex); intel_update_fbc(dev); + mutex_unlock(&dev->struct_mutex); } static int @@ -810,8 +816,11 @@ intel_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, * the sprite planes only require 128KiB alignment and 32 PTE padding. */ ret = intel_pin_and_fence_fb_obj(dev, obj, NULL); + + mutex_unlock(&dev->struct_mutex); + if (ret) - goto out_unlock; + return ret; intel_plane->obj = obj; @@ -842,18 +851,15 @@ intel_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, * wait for vblank to avoid ugliness, we only need to * do the pin & ref bookkeeping. */ - if (old_obj != obj) { - mutex_unlock(&dev->struct_mutex); - if (intel_crtc->active) - intel_wait_for_vblank(dev, to_intel_crtc(crtc)->pipe); - mutex_lock(&dev->struct_mutex); - } + if (old_obj != obj && intel_crtc->active) + intel_wait_for_vblank(dev, to_intel_crtc(crtc)->pipe); + + mutex_lock(&dev->struct_mutex); intel_unpin_fb_obj(old_obj); + mutex_unlock(&dev->struct_mutex); } -out_unlock: - mutex_unlock(&dev->struct_mutex); - return ret; + return 0; } static int @@ -885,8 +891,9 @@ intel_disable_plane(struct drm_plane *plane) mutex_lock(&dev->struct_mutex); intel_unpin_fb_obj(intel_plane->obj); - intel_plane->obj = NULL; mutex_unlock(&dev->struct_mutex); + + intel_plane->obj = NULL; out: return ret; -- cgit v1.2.2 From 5f3fb46bbd643ddacde33fd5fe6f4db4ca963312 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Tue, 1 Oct 2013 18:02:13 +0300 Subject: drm/i915: Kill a goto from sprite disable code MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Let's not use goto when a simple if suffices. This is not error handling code or anything, so the goto looks out of place. Signed-off-by: Ville Syrjälä Reviewed-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_sprite.c | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_sprite.c b/drivers/gpu/drm/i915/intel_sprite.c index b859f944b53b..b5e30b16a9cc 100644 --- a/drivers/gpu/drm/i915/intel_sprite.c +++ b/drivers/gpu/drm/i915/intel_sprite.c @@ -868,7 +868,6 @@ intel_disable_plane(struct drm_plane *plane) struct drm_device *dev = plane->dev; struct intel_plane *intel_plane = to_intel_plane(plane); struct intel_crtc *intel_crtc; - int ret = 0; if (!plane->fb) return 0; @@ -883,20 +882,18 @@ intel_disable_plane(struct drm_plane *plane) intel_plane->disable_plane(plane, plane->crtc); } - if (!intel_plane->obj) - goto out; - - if (intel_crtc->active) - intel_wait_for_vblank(dev, intel_plane->pipe); + if (intel_plane->obj) { + if (intel_crtc->active) + intel_wait_for_vblank(dev, intel_plane->pipe); - mutex_lock(&dev->struct_mutex); - intel_unpin_fb_obj(intel_plane->obj); - mutex_unlock(&dev->struct_mutex); + mutex_lock(&dev->struct_mutex); + intel_unpin_fb_obj(intel_plane->obj); + mutex_unlock(&dev->struct_mutex); - intel_plane->obj = NULL; -out: + intel_plane->obj = NULL; + } - return ret; + return 0; } static void intel_destroy_plane(struct drm_plane *plane) -- cgit v1.2.2 From 2afd9efd23437e2534a1caa6f8be4e70fd0d51c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Tue, 1 Oct 2013 18:02:14 +0300 Subject: drm/i915: Do a bit of cleanup in the sprite code MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Move the variable initialization to where the variables are declared, and kill a pointless to_intel_crtc() cast when we already have the casted pointer. Signed-off-by: Ville Syrjälä Reviewed-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_sprite.c | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_sprite.c b/drivers/gpu/drm/i915/intel_sprite.c index b5e30b16a9cc..549243a795fa 100644 --- a/drivers/gpu/drm/i915/intel_sprite.c +++ b/drivers/gpu/drm/i915/intel_sprite.c @@ -631,9 +631,10 @@ intel_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, struct drm_device *dev = plane->dev; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); struct intel_plane *intel_plane = to_intel_plane(plane); - struct intel_framebuffer *intel_fb; - struct drm_i915_gem_object *obj, *old_obj; - int ret = 0; + struct intel_framebuffer *intel_fb = to_intel_framebuffer(fb); + struct drm_i915_gem_object *obj = intel_fb->obj; + struct drm_i915_gem_object *old_obj = intel_plane->obj; + int ret; bool disable_primary = false; bool visible; int hscale, vscale; @@ -658,11 +659,6 @@ intel_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, .y2 = intel_crtc->active ? intel_crtc->config.pipe_src_h : 0, }; - intel_fb = to_intel_framebuffer(fb); - obj = intel_fb->obj; - - old_obj = intel_plane->obj; - intel_plane->crtc_x = crtc_x; intel_plane->crtc_y = crtc_y; intel_plane->crtc_w = crtc_w; @@ -852,7 +848,7 @@ intel_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, * do the pin & ref bookkeeping. */ if (old_obj != obj && intel_crtc->active) - intel_wait_for_vblank(dev, to_intel_crtc(crtc)->pipe); + intel_wait_for_vblank(dev, intel_crtc->pipe); mutex_lock(&dev->struct_mutex); intel_unpin_fb_obj(old_obj); -- cgit v1.2.2 From 098ebd6b7e3ed53bdb0a368b7c2bae29f3914c88 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Tue, 1 Oct 2013 18:02:15 +0300 Subject: drm/i915: Save user requested plane coordinates only on success MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If the setplane operation fails, we shouldn't save the user's requested plane coordinates. Since we adjust the coordinates during the clipping process, make a copy of the originals, and once the operation has succeeded save them for later reuse when the plane gets re-enabled. Signed-off-by: Ville Syrjälä Reviewed-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_sprite.c | 31 ++++++++++++++++++++++--------- 1 file changed, 22 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_sprite.c b/drivers/gpu/drm/i915/intel_sprite.c index 549243a795fa..276c3a6a9168 100644 --- a/drivers/gpu/drm/i915/intel_sprite.c +++ b/drivers/gpu/drm/i915/intel_sprite.c @@ -658,15 +658,20 @@ intel_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, .x2 = intel_crtc->active ? intel_crtc->config.pipe_src_w : 0, .y2 = intel_crtc->active ? intel_crtc->config.pipe_src_h : 0, }; - - intel_plane->crtc_x = crtc_x; - intel_plane->crtc_y = crtc_y; - intel_plane->crtc_w = crtc_w; - intel_plane->crtc_h = crtc_h; - intel_plane->src_x = src_x; - intel_plane->src_y = src_y; - intel_plane->src_w = src_w; - intel_plane->src_h = src_h; + const struct { + int crtc_x, crtc_y; + unsigned int crtc_w, crtc_h; + uint32_t src_x, src_y, src_w, src_h; + } orig = { + .crtc_x = crtc_x, + .crtc_y = crtc_y, + .crtc_w = crtc_w, + .crtc_h = crtc_h, + .src_x = src_x, + .src_y = src_y, + .src_w = src_w, + .src_h = src_h, + }; /* Don't modify another pipe's plane */ if (intel_plane->pipe != intel_crtc->pipe) { @@ -818,6 +823,14 @@ intel_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, if (ret) return ret; + intel_plane->crtc_x = orig.crtc_x; + intel_plane->crtc_y = orig.crtc_y; + intel_plane->crtc_w = orig.crtc_w; + intel_plane->crtc_h = orig.crtc_h; + intel_plane->src_x = orig.src_x; + intel_plane->src_y = orig.src_y; + intel_plane->src_w = orig.src_w; + intel_plane->src_h = orig.src_h; intel_plane->obj = obj; if (intel_crtc->active) { -- cgit v1.2.2 From abae50ed12b6f556afce0febb41639f0ede28fb9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Tue, 1 Oct 2013 18:02:16 +0300 Subject: drm/i915: Do the fbc vs. primary plane enable/disable in the right order MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Disable fbc before disabling the primary plane, and enable fbc after the primary plane has been enabled again. Also use intel_disable_fbc() to disable FBC to avoid the pointless overhead of intel_update_fbc(), and especially avoid having to clean up and set up the stolen mem compressed buffer again. Signed-off-by: Ville Syrjälä Reviewed-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_sprite.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_sprite.c b/drivers/gpu/drm/i915/intel_sprite.c index 276c3a6a9168..d19146992f34 100644 --- a/drivers/gpu/drm/i915/intel_sprite.c +++ b/drivers/gpu/drm/i915/intel_sprite.c @@ -526,11 +526,11 @@ intel_enable_primary(struct drm_crtc *crtc) intel_crtc->primary_disabled = false; + I915_WRITE(reg, I915_READ(reg) | DISPLAY_PLANE_ENABLE); + mutex_lock(&dev->struct_mutex); intel_update_fbc(dev); mutex_unlock(&dev->struct_mutex); - - I915_WRITE(reg, I915_READ(reg) | DISPLAY_PLANE_ENABLE); } static void @@ -544,13 +544,14 @@ intel_disable_primary(struct drm_crtc *crtc) if (intel_crtc->primary_disabled) return; - I915_WRITE(reg, I915_READ(reg) & ~DISPLAY_PLANE_ENABLE); - intel_crtc->primary_disabled = true; mutex_lock(&dev->struct_mutex); - intel_update_fbc(dev); + if (dev_priv->fbc.plane == intel_crtc->plane) + intel_disable_fbc(dev); mutex_unlock(&dev->struct_mutex); + + I915_WRITE(reg, I915_READ(reg) & ~DISPLAY_PLANE_ENABLE); } static int -- cgit v1.2.2 From 20bc86739b835da21476ea0bf7381f6aab03be64 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Tue, 1 Oct 2013 18:02:17 +0300 Subject: drm/i915: Enable/disable IPS when primary is enabled/disabled MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit IPS should be OK as long as one plane is enabled on the pipe, but it does seem to cause problems when going between primary only and sprite only. This needs more investigations, but for now just disable IPS whenever the primary plane is disabled. Signed-off-by: Ville Syrjälä Acked-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 4 ++-- drivers/gpu/drm/i915/intel_drv.h | 2 ++ drivers/gpu/drm/i915/intel_sprite.c | 19 +++++++++++++++++++ 3 files changed, 23 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 579becbc46ec..fdaa672f148a 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -3329,7 +3329,7 @@ static void intel_disable_planes(struct drm_crtc *crtc) intel_plane_disable(&intel_plane->base); } -static void hsw_enable_ips(struct intel_crtc *crtc) +void hsw_enable_ips(struct intel_crtc *crtc) { struct drm_i915_private *dev_priv = crtc->base.dev->dev_private; @@ -3344,7 +3344,7 @@ static void hsw_enable_ips(struct intel_crtc *crtc) I915_WRITE(IPS_CTL, IPS_ENABLE); } -static void hsw_disable_ips(struct intel_crtc *crtc) +void hsw_disable_ips(struct intel_crtc *crtc) { struct drm_device *dev = crtc->base.dev; struct drm_i915_private *dev_priv = dev->dev_private; diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index eaf0003ddfd9..55c8bc4b7d9f 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -677,6 +677,8 @@ ironlake_check_encoder_dotclock(const struct intel_crtc_config *pipe_config, int dotclock); bool intel_crtc_active(struct drm_crtc *crtc); void i915_disable_vga_mem(struct drm_device *dev); +void hsw_enable_ips(struct intel_crtc *crtc); +void hsw_disable_ips(struct intel_crtc *crtc); /* intel_dp.c */ diff --git a/drivers/gpu/drm/i915/intel_sprite.c b/drivers/gpu/drm/i915/intel_sprite.c index d19146992f34..76d0e2f5c4aa 100644 --- a/drivers/gpu/drm/i915/intel_sprite.c +++ b/drivers/gpu/drm/i915/intel_sprite.c @@ -528,6 +528,17 @@ intel_enable_primary(struct drm_crtc *crtc) I915_WRITE(reg, I915_READ(reg) | DISPLAY_PLANE_ENABLE); + /* + * FIXME IPS should be fine as long as one plane is + * enabled, but in practice it seems to have problems + * when going from primary only to sprite only and vice + * versa. + */ + if (intel_crtc->config.ips_enabled) { + intel_wait_for_vblank(dev, intel_crtc->pipe); + hsw_enable_ips(intel_crtc); + } + mutex_lock(&dev->struct_mutex); intel_update_fbc(dev); mutex_unlock(&dev->struct_mutex); @@ -551,6 +562,14 @@ intel_disable_primary(struct drm_crtc *crtc) intel_disable_fbc(dev); mutex_unlock(&dev->struct_mutex); + /* + * FIXME IPS should be fine as long as one plane is + * enabled, but in practice it seems to have problems + * when going from primary only to sprite only and vice + * versa. + */ + hsw_disable_ips(intel_crtc); + I915_WRITE(reg, I915_READ(reg) & ~DISPLAY_PLANE_ENABLE); } -- cgit v1.2.2 From 1dba99f495fb2b8712d83f53a769a7393ea127d3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Tue, 1 Oct 2013 18:02:18 +0300 Subject: drm/i915: Rename intel_flush_display_plane to intel_flush_primary_plane MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The intel_flush_primary_plane name actually tells us which plane we're talking about. Also reorganize the internals a bit and add a missing POSTING_READ() to make sure the hardware has seen the changes by the time we return from the function. Signed-off-by: Ville Syrjälä Reviewed-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 16 ++++++++-------- drivers/gpu/drm/i915/intel_drv.h | 2 +- drivers/gpu/drm/i915/intel_pm.c | 2 +- drivers/gpu/drm/i915/intel_tv.c | 4 ++-- 4 files changed, 12 insertions(+), 12 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index fdaa672f148a..985c389e14ef 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -1812,13 +1812,13 @@ static void intel_disable_pipe(struct drm_i915_private *dev_priv, * Plane regs are double buffered, going from enabled->disabled needs a * trigger in order to latch. The display address reg provides this. */ -void intel_flush_display_plane(struct drm_i915_private *dev_priv, - enum plane plane) +void intel_flush_primary_plane(struct drm_i915_private *dev_priv, + enum plane plane) { - if (dev_priv->info->gen >= 4) - I915_WRITE(DSPSURF(plane), I915_READ(DSPSURF(plane))); - else - I915_WRITE(DSPADDR(plane), I915_READ(DSPADDR(plane))); + u32 reg = dev_priv->info->gen >= 4 ? DSPSURF(plane) : DSPADDR(plane); + + I915_WRITE(reg, I915_READ(reg)); + POSTING_READ(reg); } /** @@ -1848,7 +1848,7 @@ static void intel_enable_plane(struct drm_i915_private *dev_priv, return; I915_WRITE(reg, val | DISPLAY_PLANE_ENABLE); - intel_flush_display_plane(dev_priv, plane); + intel_flush_primary_plane(dev_priv, plane); intel_wait_for_vblank(dev_priv->dev, pipe); } @@ -1876,7 +1876,7 @@ static void intel_disable_plane(struct drm_i915_private *dev_priv, return; I915_WRITE(reg, val & ~DISPLAY_PLANE_ENABLE); - intel_flush_display_plane(dev_priv, plane); + intel_flush_primary_plane(dev_priv, plane); intel_wait_for_vblank(dev_priv->dev, pipe); } diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 55c8bc4b7d9f..dea20ce65e59 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -811,7 +811,7 @@ bool intel_sdvo_init(struct drm_device *dev, uint32_t sdvo_reg, bool is_sdvob); /* intel_sprite.c */ int intel_plane_init(struct drm_device *dev, enum pipe pipe, int plane); -void intel_flush_display_plane(struct drm_i915_private *dev_priv, +void intel_flush_primary_plane(struct drm_i915_private *dev_priv, enum plane plane); void intel_plane_restore(struct drm_plane *plane); void intel_plane_disable(struct drm_plane *plane); diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 008ec0bb017f..da24825acc84 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -4773,7 +4773,7 @@ static void g4x_disable_trickle_feed(struct drm_device *dev) I915_WRITE(DSPCNTR(pipe), I915_READ(DSPCNTR(pipe)) | DISPPLANE_TRICKLE_FEED_DISABLE); - intel_flush_display_plane(dev_priv, pipe); + intel_flush_primary_plane(dev_priv, pipe); } } diff --git a/drivers/gpu/drm/i915/intel_tv.c b/drivers/gpu/drm/i915/intel_tv.c index d61aec23a523..18c406246a2d 100644 --- a/drivers/gpu/drm/i915/intel_tv.c +++ b/drivers/gpu/drm/i915/intel_tv.c @@ -1094,7 +1094,7 @@ static void intel_tv_mode_set(struct intel_encoder *encoder) unsigned int xsize, ysize; /* Pipe must be off here */ I915_WRITE(dspcntr_reg, dspcntr & ~DISPLAY_PLANE_ENABLE); - intel_flush_display_plane(dev_priv, intel_crtc->plane); + intel_flush_primary_plane(dev_priv, intel_crtc->plane); /* Wait for vblank for the disable to take effect */ if (IS_GEN2(dev)) @@ -1123,7 +1123,7 @@ static void intel_tv_mode_set(struct intel_encoder *encoder) I915_WRITE(pipeconf_reg, pipeconf); I915_WRITE(dspcntr_reg, dspcntr); - intel_flush_display_plane(dev_priv, intel_crtc->plane); + intel_flush_primary_plane(dev_priv, intel_crtc->plane); } j = 0; -- cgit v1.2.2 From d1de00efcb4992da3936a4b0300b8b9b244080cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Tue, 1 Oct 2013 18:02:19 +0300 Subject: drm/i915: Rename intel_{enable, disable}_plane to intel_{enable, disable}_primary_plane MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The new names make it clearer which plane we're talking about. Signed-off-by: Ville Syrjälä Reviewed-by: Chris Wilson [danvet: Resolve small conflict with the haswell_crtc_disable_planes extraction.] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 985c389e14ef..a2acf79c365d 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -1822,15 +1822,15 @@ void intel_flush_primary_plane(struct drm_i915_private *dev_priv, } /** - * intel_enable_plane - enable a display plane on a given pipe + * intel_enable_primary_plane - enable the primary plane on a given pipe * @dev_priv: i915 private structure * @plane: plane to enable * @pipe: pipe being fed * * Enable @plane on @pipe, making sure that @pipe is running first. */ -static void intel_enable_plane(struct drm_i915_private *dev_priv, - enum plane plane, enum pipe pipe) +static void intel_enable_primary_plane(struct drm_i915_private *dev_priv, + enum plane plane, enum pipe pipe) { struct intel_crtc *intel_crtc = to_intel_crtc(dev_priv->pipe_to_crtc_mapping[pipe]); @@ -1853,15 +1853,15 @@ static void intel_enable_plane(struct drm_i915_private *dev_priv, } /** - * intel_disable_plane - disable a display plane + * intel_disable_primary_plane - disable the primary plane * @dev_priv: i915 private structure * @plane: plane to disable * @pipe: pipe consuming the data * * Disable @plane; should be an independent operation. */ -static void intel_disable_plane(struct drm_i915_private *dev_priv, - enum plane plane, enum pipe pipe) +static void intel_disable_primary_plane(struct drm_i915_private *dev_priv, + enum plane plane, enum pipe pipe) { struct intel_crtc *intel_crtc = to_intel_crtc(dev_priv->pipe_to_crtc_mapping[pipe]); @@ -3451,7 +3451,7 @@ static void ironlake_crtc_enable(struct drm_crtc *crtc) intel_update_watermarks(crtc); intel_enable_pipe(dev_priv, pipe, intel_crtc->config.has_pch_encoder, false); - intel_enable_plane(dev_priv, plane, pipe); + intel_enable_primary_plane(dev_priv, plane, pipe); intel_enable_planes(crtc); intel_crtc_update_cursor(crtc, true); @@ -3493,7 +3493,7 @@ static void haswell_crtc_enable_planes(struct drm_crtc *crtc) int pipe = intel_crtc->pipe; int plane = intel_crtc->plane; - intel_enable_plane(dev_priv, plane, pipe); + intel_enable_primary_plane(dev_priv, plane, pipe); intel_enable_planes(crtc); intel_crtc_update_cursor(crtc, true); @@ -3523,7 +3523,7 @@ static void haswell_crtc_disable_planes(struct drm_crtc *crtc) intel_crtc_update_cursor(crtc, false); intel_disable_planes(crtc); - intel_disable_plane(dev_priv, plane, pipe); + intel_disable_primary_plane(dev_priv, plane, pipe); } /* @@ -3662,7 +3662,7 @@ static void ironlake_crtc_disable(struct drm_crtc *crtc) intel_crtc_update_cursor(crtc, false); intel_disable_planes(crtc); - intel_disable_plane(dev_priv, plane, pipe); + intel_disable_primary_plane(dev_priv, plane, pipe); if (intel_crtc->config.has_pch_encoder) intel_set_pch_fifo_underrun_reporting(dev, pipe, false); @@ -3870,7 +3870,7 @@ static void valleyview_crtc_enable(struct drm_crtc *crtc) intel_update_watermarks(crtc); intel_enable_pipe(dev_priv, pipe, false, is_dsi); - intel_enable_plane(dev_priv, plane, pipe); + intel_enable_primary_plane(dev_priv, plane, pipe); intel_enable_planes(crtc); intel_crtc_update_cursor(crtc, true); @@ -3908,7 +3908,7 @@ static void i9xx_crtc_enable(struct drm_crtc *crtc) intel_update_watermarks(crtc); intel_enable_pipe(dev_priv, pipe, false, false); - intel_enable_plane(dev_priv, plane, pipe); + intel_enable_primary_plane(dev_priv, plane, pipe); intel_enable_planes(crtc); /* The fixup needs to happen before cursor is enabled */ if (IS_G4X(dev)) @@ -3964,7 +3964,7 @@ static void i9xx_crtc_disable(struct drm_crtc *crtc) intel_crtc_dpms_overlay(intel_crtc, false); intel_crtc_update_cursor(crtc, false); intel_disable_planes(crtc); - intel_disable_plane(dev_priv, plane, pipe); + intel_disable_primary_plane(dev_priv, plane, pipe); intel_disable_pipe(dev_priv, pipe); -- cgit v1.2.2 From 0037f71c4b7fc0cc70714c5a076f54f348c04dea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Tue, 1 Oct 2013 18:02:20 +0300 Subject: drm/i915: WARN if primary plane state doesn't match expectations MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Ville Syrjälä Reviewed-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index a2acf79c365d..2e3289c37034 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -1840,6 +1840,8 @@ static void intel_enable_primary_plane(struct drm_i915_private *dev_priv, /* If the pipe isn't enabled, we can't pump pixels and may hang */ assert_pipe_enabled(dev_priv, pipe); + WARN(!intel_crtc->primary_disabled, "Primary plane already enabled\n"); + intel_crtc->primary_disabled = false; reg = DSPCNTR(plane); @@ -1868,6 +1870,8 @@ static void intel_disable_primary_plane(struct drm_i915_private *dev_priv, int reg; u32 val; + WARN(intel_crtc->primary_disabled, "Primary plane already disabled\n"); + intel_crtc->primary_disabled = true; reg = DSPCNTR(plane); -- cgit v1.2.2 From 0fc9f5996340a637665ccb4faa69aab498dc4067 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Tue, 1 Oct 2013 18:02:21 +0300 Subject: drm/i915: Flush primary plane changes in sprite code MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Flush the primary plane changes when enabling/disabling the primary plane in response to sprite visibility. Signed-off-by: Ville Syrjälä Reviewed-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_sprite.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/gpu/drm/i915/intel_sprite.c b/drivers/gpu/drm/i915/intel_sprite.c index 76d0e2f5c4aa..e001d2c35c39 100644 --- a/drivers/gpu/drm/i915/intel_sprite.c +++ b/drivers/gpu/drm/i915/intel_sprite.c @@ -527,6 +527,7 @@ intel_enable_primary(struct drm_crtc *crtc) intel_crtc->primary_disabled = false; I915_WRITE(reg, I915_READ(reg) | DISPLAY_PLANE_ENABLE); + intel_flush_primary_plane(dev_priv, intel_crtc->plane); /* * FIXME IPS should be fine as long as one plane is @@ -571,6 +572,7 @@ intel_disable_primary(struct drm_crtc *crtc) hsw_disable_ips(intel_crtc); I915_WRITE(reg, I915_READ(reg) & ~DISPLAY_PLANE_ENABLE); + intel_flush_primary_plane(dev_priv, intel_crtc->plane); } static int -- cgit v1.2.2 From eda796422aeb23a155b92ddc89cd70b9beffbad6 Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Mon, 7 Oct 2013 17:15:48 -0300 Subject: drm/i915: Use the real cpu max frequency for ring scaling The policy's max frequency is not equal to the CPU's max frequency. The ring frequency is derived from the CPU frequency, and not the policy frequency. One example of how this may differ through sysfs. If the sysfs max frequency is modified, that will be used for the max ring frequency calculation. (/sys/devices/system/cpu/cpu0/cpufreq/scaling_max_freq). As far as I know, no current governor uses anything but max as the default, but in theory, they could. Similarly distributions might set policy as part of their init process. It's ideal to use the real frequency because when we're currently scaled up on the GPU. In this case we likely want to race to idle, and using a less than max ring frequency is non-optimal for this situation. AFAIK, this patch should have no impact on a majority of people. This behavior hasn't been changed since it was first introduced: commit 23b2f8bb92feb83127679c53633def32d3108e70 Author: Jesse Barnes Date: Tue Jun 28 13:04:16 2011 -0700 drm/i915: load a ring frequency scaling table v3 CC: Jesse Barnes Signed-off-by: Ben Widawsky Reviewed-by: Chris Wilson Signed-off-by: Rodrigo Vivi Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_pm.c | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index da24825acc84..9534e72fdbcb 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -3740,16 +3740,21 @@ void gen6_update_ring_freq(struct drm_device *dev) unsigned int gpu_freq; unsigned int max_ia_freq, min_ring_freq; int scaling_factor = 180; + struct cpufreq_policy *policy; WARN_ON(!mutex_is_locked(&dev_priv->rps.hw_lock)); - max_ia_freq = cpufreq_quick_get_max(0); - /* - * Default to measured freq if none found, PCU will ensure we don't go - * over - */ - if (!max_ia_freq) + policy = cpufreq_cpu_get(0); + if (policy) { + max_ia_freq = policy->cpuinfo.max_freq; + cpufreq_cpu_put(policy); + } else { + /* + * Default to measured freq if none found, PCU will ensure we + * don't go over + */ max_ia_freq = tsc_khz; + } /* Convert from kHz to MHz */ max_ia_freq /= 1000; -- cgit v1.2.2 From a4945f9522d27e1e6d64a02ad055e83768cb0896 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Tue, 8 Oct 2013 11:16:59 +0100 Subject: drm/i915: Undo the PIPEA quirk for i845 The PIPEA quirk is specifically for the issue with the PIPEB PLL on 830gm being slaved to the PIPEA PLL, and so to use PIPEB requires PIPEA running. i845 doesn't even have the second PLL or pipe, and enabling the quirk results in a blank DVO LVDS. Signed-off-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 2e3289c37034..a6d8698d36a1 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -10305,8 +10305,7 @@ static struct intel_quirk intel_quirks[] = { /* ThinkPad T60 needs pipe A force quirk (bug #16494) */ { 0x2782, 0x17aa, 0x201a, quirk_pipea_force }, - /* 830/845 need to leave pipe A & dpll A up */ - { 0x2562, PCI_ANY_ID, PCI_ANY_ID, quirk_pipea_force }, + /* 830 needs to leave pipe A & dpll A up */ { 0x3577, PCI_ANY_ID, PCI_ANY_ID, quirk_pipea_force }, /* Lenovo U160 cannot use SSC on LVDS */ -- cgit v1.2.2 From 3bbbe706e8e6dac36ae893dc23bdb378dd4f4413 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Mon, 7 Oct 2013 17:15:45 -0300 Subject: drm/i915: check that the i965g/gm 4G limit is really obeyed In truly crazy circumstances shmem might give us the wrong type of page. So be a bit paranoid and double check this. Reviewer: Damien Lespiau Cc: Rob Clark References: http://lkml.org/lkml/2011/7/11/238 Signed-off-by: Daniel Vetter Signed-off-by: Rodrigo Vivi Reviewed-by: Damien Lespiau Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index ed9311aaabe7..71dd0305eb32 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -1902,6 +1902,9 @@ i915_gem_object_get_pages_gtt(struct drm_i915_gem_object *obj) sg->length += PAGE_SIZE; } last_pfn = page_to_pfn(page); + + /* Check that the i965g/gm workaround works. */ + WARN_ON((gfp & __GFP_DMA32) && (last_pfn >= 0x00100000UL)); } #ifdef CONFIG_SWIOTLB if (!swiotlb_nr_tbl()) -- cgit v1.2.2 From e252d07aff961f8553822cda621490d9aeef8a06 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Tue, 8 Oct 2013 12:25:41 +0200 Subject: drm/i915: rip out gen2 reset code At least on my i830M here it reliably results in hard system hangs nowadays. This is much worse than falling back to software rendering, so I think we should simply rip this out. After all we don't have any gpu reset for gen3 either, and there are a lot more of those still around. Cc: Chris Wilson Acked-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_uncore.c | 31 ------------------------------- 1 file changed, 31 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_uncore.c b/drivers/gpu/drm/i915/intel_uncore.c index 288a3a654f06..bfc1a65fcd90 100644 --- a/drivers/gpu/drm/i915/intel_uncore.c +++ b/drivers/gpu/drm/i915/intel_uncore.c @@ -490,36 +490,6 @@ int i915_reg_read_ioctl(struct drm_device *dev, return 0; } -static int i8xx_do_reset(struct drm_device *dev) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - - if (IS_I85X(dev)) - return -ENODEV; - - I915_WRITE(D_STATE, I915_READ(D_STATE) | DSTATE_GFX_RESET_I830); - POSTING_READ(D_STATE); - - if (IS_I830(dev) || IS_845G(dev)) { - I915_WRITE(DEBUG_RESET_I830, - DEBUG_RESET_DISPLAY | - DEBUG_RESET_RENDER | - DEBUG_RESET_FULL); - POSTING_READ(DEBUG_RESET_I830); - msleep(1); - - I915_WRITE(DEBUG_RESET_I830, 0); - POSTING_READ(DEBUG_RESET_I830); - } - - msleep(1); - - I915_WRITE(D_STATE, I915_READ(D_STATE) & ~DSTATE_GFX_RESET_I830); - POSTING_READ(D_STATE); - - return 0; -} - static int i965_reset_complete(struct drm_device *dev) { u8 gdrst; @@ -621,7 +591,6 @@ int intel_gpu_reset(struct drm_device *dev) case 6: return gen6_do_reset(dev); case 5: return ironlake_do_reset(dev); case 4: return i965_do_reset(dev); - case 2: return i8xx_do_reset(dev); default: return -ENODEV; } } -- cgit v1.2.2 From 78511f2a6fc6960c8917d9655fffb687822a0225 Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Fri, 4 Oct 2013 21:22:49 -0700 Subject: drm/i915: Prevent using uninitialized MMIO funcs For upcoming patches which will have GEN specific MMIO functions, we'll need to initialize the uncore data structure earlier than we do today. If we do not do this, the following will be problematic: intel_uncore_sanitize intel_disable_gt_powersave gen6_disable_rps I915_WRITE(GEN6_RC_CONTROL, 0); <--- MMIO intel_uncore_init // initializes MMIO By initializing the function pointers first, we should be safe. Signed-off-by: Ben Widawsky Reviewed-by: Damien Lespiau Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_dma.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index b3873c945d1b..ff2083e805ee 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -1614,8 +1614,8 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) intel_irq_init(dev); intel_pm_init(dev); - intel_uncore_sanitize(dev); intel_uncore_init(dev); + intel_uncore_sanitize(dev); /* Try to make sure MCHBAR is enabled before poking at it */ intel_setup_mchbar(dev); -- cgit v1.2.2 From 18ce39943eb82e457e4c46dc86b1975d79b30aa7 Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Fri, 4 Oct 2013 21:22:50 -0700 Subject: drm/i915: Move edram detection early_sanitize In order to be able to have virtual functions for the MMIO, we need to use the raw access function. To keep things simple, just move this to our early_sanitize code in uncore. Signed-off-by: Ben Widawsky Reviewed-by: Damien Lespiau Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_dma.c | 10 ---------- drivers/gpu/drm/i915/intel_uncore.c | 11 +++++++++++ 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index ff2083e805ee..3316a6f37cec 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -1542,16 +1542,6 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) intel_uncore_early_sanitize(dev); - if (IS_HASWELL(dev) && (I915_READ(HSW_EDRAM_PRESENT) == 1)) { - /* The docs do not explain exactly how the calculation can be - * made. It is somewhat guessable, but for now, it's always - * 128MB. - * NB: We can't write IDICR yet because we do not have gt funcs - * set up */ - dev_priv->ellc_size = 128; - DRM_INFO("Found %zuMB of eLLC\n", dev_priv->ellc_size); - } - ret = i915_gem_gtt_init(dev); if (ret) goto out_regs; diff --git a/drivers/gpu/drm/i915/intel_uncore.c b/drivers/gpu/drm/i915/intel_uncore.c index bfc1a65fcd90..2d16590d5478 100644 --- a/drivers/gpu/drm/i915/intel_uncore.c +++ b/drivers/gpu/drm/i915/intel_uncore.c @@ -222,6 +222,17 @@ void intel_uncore_early_sanitize(struct drm_device *dev) if (HAS_FPGA_DBG_UNCLAIMED(dev)) __raw_i915_write32(dev_priv, FPGA_DBG, FPGA_DBG_RM_NOCLAIM); + + if (IS_HASWELL(dev) && + (__raw_i915_read32(dev_priv, HSW_EDRAM_PRESENT) == 1)) { + /* The docs do not explain exactly how the calculation can be + * made. It is somewhat guessable, but for now, it's always + * 128MB. + * NB: We can't write IDICR yet because we do not have gt funcs + * set up */ + dev_priv->ellc_size = 128; + DRM_INFO("Found %zuMB of eLLC\n", dev_priv->ellc_size); + } } void intel_uncore_init(struct drm_device *dev) -- cgit v1.2.2 From 0b27448141bbe9da34a2fdf965dcba6f0f1b75c5 Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Fri, 4 Oct 2013 21:22:51 -0700 Subject: drm/i915: Create MMIO virtual functions In preparation for having per GEN MMIO functions, create, and start using MMIO functions in our uncore data structure. This simply makes the transition easier by allowing us to just plug in the per GEN stuff later. For simplicity, I moved the intel_uncore_init() function down since those rely on static functions defined lower in the file. This is most of the churn in this patch. I made one unrelated change here by using off_t datatype for the offset of the register to write. I like the clarity that this brings to the code. If I did it as a separate patch, I am pretty certain it would get bikeshedded to oblivion. Requested-by: Daniel Vetter Signed-off-by: Ben Widawsky Reviewed-by: Damien Lespiau Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 60 ++++++++-------- drivers/gpu/drm/i915/intel_uncore.c | 139 +++++++++++++++++++----------------- 2 files changed, 104 insertions(+), 95 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 6a5b7ab0c3fa..957771fc60fa 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -399,6 +399,20 @@ struct drm_i915_display_funcs { struct intel_uncore_funcs { void (*force_wake_get)(struct drm_i915_private *dev_priv); void (*force_wake_put)(struct drm_i915_private *dev_priv); + + uint8_t (*mmio_readb)(struct drm_i915_private *dev_priv, off_t offset, bool trace); + uint16_t (*mmio_readw)(struct drm_i915_private *dev_priv, off_t offset, bool trace); + uint32_t (*mmio_readl)(struct drm_i915_private *dev_priv, off_t offset, bool trace); + uint64_t (*mmio_readq)(struct drm_i915_private *dev_priv, off_t offset, bool trace); + + void (*mmio_writeb)(struct drm_i915_private *dev_priv, off_t offset, + uint8_t val, bool trace); + void (*mmio_writew)(struct drm_i915_private *dev_priv, off_t offset, + uint16_t val, bool trace); + void (*mmio_writel)(struct drm_i915_private *dev_priv, off_t offset, + uint32_t val, bool trace); + void (*mmio_writeq)(struct drm_i915_private *dev_priv, off_t offset, + uint64_t val, bool trace); }; struct intel_uncore { @@ -2337,37 +2351,21 @@ void intel_sbi_write(struct drm_i915_private *dev_priv, u16 reg, u32 value, int vlv_gpu_freq(int ddr_freq, int val); int vlv_freq_opcode(int ddr_freq, int val); -#define __i915_read(x) \ - u##x i915_read##x(struct drm_i915_private *dev_priv, u32 reg, bool trace); -__i915_read(8) -__i915_read(16) -__i915_read(32) -__i915_read(64) -#undef __i915_read - -#define __i915_write(x) \ - void i915_write##x(struct drm_i915_private *dev_priv, u32 reg, u##x val, bool trace); -__i915_write(8) -__i915_write(16) -__i915_write(32) -__i915_write(64) -#undef __i915_write - -#define I915_READ8(reg) i915_read8(dev_priv, (reg), true) -#define I915_WRITE8(reg, val) i915_write8(dev_priv, (reg), (val), true) - -#define I915_READ16(reg) i915_read16(dev_priv, (reg), true) -#define I915_WRITE16(reg, val) i915_write16(dev_priv, (reg), (val), true) -#define I915_READ16_NOTRACE(reg) i915_read16(dev_priv, (reg), false) -#define I915_WRITE16_NOTRACE(reg, val) i915_write16(dev_priv, (reg), (val), false) - -#define I915_READ(reg) i915_read32(dev_priv, (reg), true) -#define I915_WRITE(reg, val) i915_write32(dev_priv, (reg), (val), true) -#define I915_READ_NOTRACE(reg) i915_read32(dev_priv, (reg), false) -#define I915_WRITE_NOTRACE(reg, val) i915_write32(dev_priv, (reg), (val), false) - -#define I915_WRITE64(reg, val) i915_write64(dev_priv, (reg), (val), true) -#define I915_READ64(reg) i915_read64(dev_priv, (reg), true) +#define I915_READ8(reg) dev_priv->uncore.funcs.mmio_readb(dev_priv, (reg), true) +#define I915_WRITE8(reg, val) dev_priv->uncore.funcs.mmio_writeb(dev_priv, (reg), (val), true) + +#define I915_READ16(reg) dev_priv->uncore.funcs.mmio_readw(dev_priv, (reg), true) +#define I915_WRITE16(reg, val) dev_priv->uncore.funcs.mmio_writew(dev_priv, (reg), (val), true) +#define I915_READ16_NOTRACE(reg) dev_priv->uncore.funcs.mmio_readw(dev_priv, (reg), false) +#define I915_WRITE16_NOTRACE(reg, val) dev_priv->uncore.funcs.mmio_writew(dev_priv, (reg), (val), false) + +#define I915_READ(reg) dev_priv->uncore.funcs.mmio_readl(dev_priv, (reg), true) +#define I915_WRITE(reg, val) dev_priv->uncore.funcs.mmio_writel(dev_priv, (reg), (val), true) +#define I915_READ_NOTRACE(reg) dev_priv->uncore.funcs.mmio_readl(dev_priv, (reg), false) +#define I915_WRITE_NOTRACE(reg, val) dev_priv->uncore.funcs.mmio_writel(dev_priv, (reg), (val), false) + +#define I915_WRITE64(reg, val) dev_priv->uncore.funcs.mmio_writeq(dev_priv, (reg), (val), true) +#define I915_READ64(reg) dev_priv->uncore.funcs.mmio_readq(dev_priv, (reg), true) #define POSTING_READ(reg) (void)I915_READ_NOTRACE(reg) #define POSTING_READ16(reg) (void)I915_READ16_NOTRACE(reg) diff --git a/drivers/gpu/drm/i915/intel_uncore.c b/drivers/gpu/drm/i915/intel_uncore.c index 2d16590d5478..8d032aeedc41 100644 --- a/drivers/gpu/drm/i915/intel_uncore.c +++ b/drivers/gpu/drm/i915/intel_uncore.c @@ -235,68 +235,6 @@ void intel_uncore_early_sanitize(struct drm_device *dev) } } -void intel_uncore_init(struct drm_device *dev) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - - INIT_DELAYED_WORK(&dev_priv->uncore.force_wake_work, - gen6_force_wake_work); - - if (IS_VALLEYVIEW(dev)) { - dev_priv->uncore.funcs.force_wake_get = vlv_force_wake_get; - dev_priv->uncore.funcs.force_wake_put = vlv_force_wake_put; - } else if (IS_HASWELL(dev)) { - dev_priv->uncore.funcs.force_wake_get = __gen6_gt_force_wake_mt_get; - dev_priv->uncore.funcs.force_wake_put = __gen6_gt_force_wake_mt_put; - } else if (IS_IVYBRIDGE(dev)) { - u32 ecobus; - - /* IVB configs may use multi-threaded forcewake */ - - /* A small trick here - if the bios hasn't configured - * MT forcewake, and if the device is in RC6, then - * force_wake_mt_get will not wake the device and the - * ECOBUS read will return zero. Which will be - * (correctly) interpreted by the test below as MT - * forcewake being disabled. - */ - mutex_lock(&dev->struct_mutex); - __gen6_gt_force_wake_mt_get(dev_priv); - ecobus = __raw_i915_read32(dev_priv, ECOBUS); - __gen6_gt_force_wake_mt_put(dev_priv); - mutex_unlock(&dev->struct_mutex); - - if (ecobus & FORCEWAKE_MT_ENABLE) { - dev_priv->uncore.funcs.force_wake_get = - __gen6_gt_force_wake_mt_get; - dev_priv->uncore.funcs.force_wake_put = - __gen6_gt_force_wake_mt_put; - } else { - DRM_INFO("No MT forcewake available on Ivybridge, this can result in issues\n"); - DRM_INFO("when using vblank-synced partial screen updates.\n"); - dev_priv->uncore.funcs.force_wake_get = - __gen6_gt_force_wake_get; - dev_priv->uncore.funcs.force_wake_put = - __gen6_gt_force_wake_put; - } - } else if (IS_GEN6(dev)) { - dev_priv->uncore.funcs.force_wake_get = - __gen6_gt_force_wake_get; - dev_priv->uncore.funcs.force_wake_put = - __gen6_gt_force_wake_put; - } -} - -void intel_uncore_fini(struct drm_device *dev) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - - flush_delayed_work(&dev_priv->uncore.force_wake_work); - - /* Paranoia: make sure we have disabled everything before we exit. */ - intel_uncore_sanitize(dev); -} - static void intel_uncore_forcewake_reset(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; @@ -404,7 +342,8 @@ hsw_unclaimed_reg_check(struct drm_i915_private *dev_priv, u32 reg) } #define __i915_read(x) \ -u##x i915_read##x(struct drm_i915_private *dev_priv, u32 reg, bool trace) { \ +static u##x \ +i915_read##x(struct drm_i915_private *dev_priv, off_t reg, bool trace) { \ unsigned long irqflags; \ u##x val = 0; \ spin_lock_irqsave(&dev_priv->uncore.lock, irqflags); \ @@ -431,7 +370,8 @@ __i915_read(64) #undef __i915_read #define __i915_write(x) \ -void i915_write##x(struct drm_i915_private *dev_priv, u32 reg, u##x val, bool trace) { \ +static void \ +i915_write##x(struct drm_i915_private *dev_priv, off_t reg, u##x val, bool trace) { \ unsigned long irqflags; \ u32 __fifo_ret = 0; \ trace_i915_reg_rw(true, reg, val, sizeof(val), trace); \ @@ -455,6 +395,77 @@ __i915_write(32) __i915_write(64) #undef __i915_write +void intel_uncore_init(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + + INIT_DELAYED_WORK(&dev_priv->uncore.force_wake_work, + gen6_force_wake_work); + + if (IS_VALLEYVIEW(dev)) { + dev_priv->uncore.funcs.force_wake_get = vlv_force_wake_get; + dev_priv->uncore.funcs.force_wake_put = vlv_force_wake_put; + } else if (IS_HASWELL(dev)) { + dev_priv->uncore.funcs.force_wake_get = __gen6_gt_force_wake_mt_get; + dev_priv->uncore.funcs.force_wake_put = __gen6_gt_force_wake_mt_put; + } else if (IS_IVYBRIDGE(dev)) { + u32 ecobus; + + /* IVB configs may use multi-threaded forcewake */ + + /* A small trick here - if the bios hasn't configured + * MT forcewake, and if the device is in RC6, then + * force_wake_mt_get will not wake the device and the + * ECOBUS read will return zero. Which will be + * (correctly) interpreted by the test below as MT + * forcewake being disabled. + */ + mutex_lock(&dev->struct_mutex); + __gen6_gt_force_wake_mt_get(dev_priv); + ecobus = __raw_i915_read32(dev_priv, ECOBUS); + __gen6_gt_force_wake_mt_put(dev_priv); + mutex_unlock(&dev->struct_mutex); + + if (ecobus & FORCEWAKE_MT_ENABLE) { + dev_priv->uncore.funcs.force_wake_get = + __gen6_gt_force_wake_mt_get; + dev_priv->uncore.funcs.force_wake_put = + __gen6_gt_force_wake_mt_put; + } else { + DRM_INFO("No MT forcewake available on Ivybridge, this can result in issues\n"); + DRM_INFO("when using vblank-synced partial screen updates.\n"); + dev_priv->uncore.funcs.force_wake_get = + __gen6_gt_force_wake_get; + dev_priv->uncore.funcs.force_wake_put = + __gen6_gt_force_wake_put; + } + } else if (IS_GEN6(dev)) { + dev_priv->uncore.funcs.force_wake_get = + __gen6_gt_force_wake_get; + dev_priv->uncore.funcs.force_wake_put = + __gen6_gt_force_wake_put; + } + + dev_priv->uncore.funcs.mmio_readb = i915_read8; + dev_priv->uncore.funcs.mmio_readw = i915_read16; + dev_priv->uncore.funcs.mmio_readl = i915_read32; + dev_priv->uncore.funcs.mmio_readq = i915_read64; + dev_priv->uncore.funcs.mmio_writeb = i915_write8; + dev_priv->uncore.funcs.mmio_writew = i915_write16; + dev_priv->uncore.funcs.mmio_writel = i915_write32; + dev_priv->uncore.funcs.mmio_writeq = i915_write64; +} + +void intel_uncore_fini(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + + flush_delayed_work(&dev_priv->uncore.force_wake_work); + + /* Paranoia: make sure we have disabled everything before we exit. */ + intel_uncore_sanitize(dev); +} + static const struct register_whitelist { uint64_t offset; uint32_t size; -- cgit v1.2.2 From 5d738795968dfa8f034e5f0d30f65d362c450455 Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Fri, 4 Oct 2013 21:24:53 -0700 Subject: drm/i915: Extract common MMIO lines Just to make the churn and code duplication in upcoming patches a bit less, turn code which is common to all GEN MMIO functions into a macro. v2: Fix typo in subject Signed-off-by: Ben Widawsky Reviewed-by: Damien Lespiau Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_uncore.c | 30 +++++++++++++++++++++--------- 1 file changed, 21 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_uncore.c b/drivers/gpu/drm/i915/intel_uncore.c index 8d032aeedc41..b8b659714a31 100644 --- a/drivers/gpu/drm/i915/intel_uncore.c +++ b/drivers/gpu/drm/i915/intel_uncore.c @@ -341,12 +341,20 @@ hsw_unclaimed_reg_check(struct drm_i915_private *dev_priv, u32 reg) } } +#define REG_READ_HEADER(x) \ + unsigned long irqflags; \ + u##x val = 0; \ + spin_lock_irqsave(&dev_priv->uncore.lock, irqflags) + +#define REG_READ_FOOTER \ + spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags); \ + trace_i915_reg_rw(false, reg, val, sizeof(val), trace); \ + return val + #define __i915_read(x) \ static u##x \ i915_read##x(struct drm_i915_private *dev_priv, off_t reg, bool trace) { \ - unsigned long irqflags; \ - u##x val = 0; \ - spin_lock_irqsave(&dev_priv->uncore.lock, irqflags); \ + REG_READ_HEADER(x); \ if (dev_priv->info->gen == 5) \ ilk_dummy_write(dev_priv); \ if (NEEDS_FORCE_WAKE((dev_priv), (reg))) { \ @@ -358,9 +366,7 @@ i915_read##x(struct drm_i915_private *dev_priv, off_t reg, bool trace) { \ } else { \ val = __raw_i915_read##x(dev_priv, reg); \ } \ - spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags); \ - trace_i915_reg_rw(false, reg, val, sizeof(val), trace); \ - return val; \ + REG_READ_FOOTER; \ } __i915_read(8) @@ -368,14 +374,19 @@ __i915_read(16) __i915_read(32) __i915_read(64) #undef __i915_read +#undef REG_READ_FOOTER +#undef REG_READ_HEADER + +#define REG_WRITE_HEADER \ + unsigned long irqflags; \ + trace_i915_reg_rw(true, reg, val, sizeof(val), trace); \ + spin_lock_irqsave(&dev_priv->uncore.lock, irqflags) #define __i915_write(x) \ static void \ i915_write##x(struct drm_i915_private *dev_priv, off_t reg, u##x val, bool trace) { \ - unsigned long irqflags; \ u32 __fifo_ret = 0; \ - trace_i915_reg_rw(true, reg, val, sizeof(val), trace); \ - spin_lock_irqsave(&dev_priv->uncore.lock, irqflags); \ + REG_WRITE_HEADER; \ if (NEEDS_FORCE_WAKE((dev_priv), (reg))) { \ __fifo_ret = __gen6_gt_wait_for_fifo(dev_priv); \ } \ @@ -394,6 +405,7 @@ __i915_write(16) __i915_write(32) __i915_write(64) #undef __i915_write +#undef REG_WRITE_HEADER void intel_uncore_init(struct drm_device *dev) { -- cgit v1.2.2 From 3967018ed67f9480b2f47f8908b44b66bdbd40b5 Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Fri, 4 Oct 2013 21:22:53 -0700 Subject: drm/i915: Create GEN specific read MMIO Extracting the MMIO read functionality makes per gen handling a bit simpler, and the overall function a lot easier to read. The increasing complexity of reads doesn't get too bad as the generation number increases: gen[2-4]: Nothing special gen5: ILK dummy write workaround gen6+: forcewake shenanigans Signed-off-by: Ben Widawsky Reviewed-by: Damien Lespiau Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_uncore.c | 72 ++++++++++++++++++++++++++++++------- 1 file changed, 59 insertions(+), 13 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_uncore.c b/drivers/gpu/drm/i915/intel_uncore.c index b8b659714a31..d1b32c848a44 100644 --- a/drivers/gpu/drm/i915/intel_uncore.c +++ b/drivers/gpu/drm/i915/intel_uncore.c @@ -351,12 +351,27 @@ hsw_unclaimed_reg_check(struct drm_i915_private *dev_priv, u32 reg) trace_i915_reg_rw(false, reg, val, sizeof(val), trace); \ return val -#define __i915_read(x) \ +#define __gen4_read(x) \ static u##x \ -i915_read##x(struct drm_i915_private *dev_priv, off_t reg, bool trace) { \ +gen4_read##x(struct drm_i915_private *dev_priv, off_t reg, bool trace) { \ + REG_READ_HEADER(x); \ + val = __raw_i915_read##x(dev_priv, reg); \ + REG_READ_FOOTER; \ +} + +#define __gen5_read(x) \ +static u##x \ +gen5_read##x(struct drm_i915_private *dev_priv, off_t reg, bool trace) { \ + REG_READ_HEADER(x); \ + ilk_dummy_write(dev_priv); \ + val = __raw_i915_read##x(dev_priv, reg); \ + REG_READ_FOOTER; \ +} + +#define __gen6_read(x) \ +static u##x \ +gen6_read##x(struct drm_i915_private *dev_priv, off_t reg, bool trace) { \ REG_READ_HEADER(x); \ - if (dev_priv->info->gen == 5) \ - ilk_dummy_write(dev_priv); \ if (NEEDS_FORCE_WAKE((dev_priv), (reg))) { \ if (dev_priv->uncore.forcewake_count == 0) \ dev_priv->uncore.funcs.force_wake_get(dev_priv); \ @@ -369,11 +384,22 @@ i915_read##x(struct drm_i915_private *dev_priv, off_t reg, bool trace) { \ REG_READ_FOOTER; \ } -__i915_read(8) -__i915_read(16) -__i915_read(32) -__i915_read(64) -#undef __i915_read +__gen6_read(8) +__gen6_read(16) +__gen6_read(32) +__gen6_read(64) +__gen5_read(8) +__gen5_read(16) +__gen5_read(32) +__gen5_read(64) +__gen4_read(8) +__gen4_read(16) +__gen4_read(32) +__gen4_read(64) + +#undef __gen6_read +#undef __gen5_read +#undef __gen4_read #undef REG_READ_FOOTER #undef REG_READ_HEADER @@ -400,6 +426,7 @@ i915_write##x(struct drm_i915_private *dev_priv, off_t reg, u##x val, bool trace hsw_unclaimed_reg_check(dev_priv, reg); \ spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags); \ } + __i915_write(8) __i915_write(16) __i915_write(32) @@ -458,10 +485,29 @@ void intel_uncore_init(struct drm_device *dev) __gen6_gt_force_wake_put; } - dev_priv->uncore.funcs.mmio_readb = i915_read8; - dev_priv->uncore.funcs.mmio_readw = i915_read16; - dev_priv->uncore.funcs.mmio_readl = i915_read32; - dev_priv->uncore.funcs.mmio_readq = i915_read64; + switch (INTEL_INFO(dev)->gen) { + case 7: + case 6: + dev_priv->uncore.funcs.mmio_readb = gen6_read8; + dev_priv->uncore.funcs.mmio_readw = gen6_read16; + dev_priv->uncore.funcs.mmio_readl = gen6_read32; + dev_priv->uncore.funcs.mmio_readq = gen6_read64; + break; + case 5: + dev_priv->uncore.funcs.mmio_readb = gen5_read8; + dev_priv->uncore.funcs.mmio_readw = gen5_read16; + dev_priv->uncore.funcs.mmio_readl = gen5_read32; + dev_priv->uncore.funcs.mmio_readq = gen5_read64; + break; + case 4: + case 3: + case 2: + dev_priv->uncore.funcs.mmio_readb = gen4_read8; + dev_priv->uncore.funcs.mmio_readw = gen4_read16; + dev_priv->uncore.funcs.mmio_readl = gen4_read32; + dev_priv->uncore.funcs.mmio_readq = gen4_read64; + break; + } dev_priv->uncore.funcs.mmio_writeb = i915_write8; dev_priv->uncore.funcs.mmio_writew = i915_write16; dev_priv->uncore.funcs.mmio_writel = i915_write32; -- cgit v1.2.2 From 4032ef4315475dd9605d6cde461168fb85d776ea Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Fri, 4 Oct 2013 21:22:54 -0700 Subject: drm/i915: Create GEN specific write MMIO Similar to the previous patch which implemented GEN specific reads; this patch does the same for writes. Writes have a bit of adding complexity due to the FPGA_DBG feature of HSW plus: gen[2-4]: nothing special gen5: ILK dummy write gen[6-7]: forcewake shenanigans gen[HSW}: forcewake shenanigans + FPGA_DBG I was a bit torn about whether or not to combine 6-HSW as one function, since the FPGA_DBG is cleanly separated, and it wouldn't make the 6-7 MMIO too messy. In the end, I chose the clearest possible solution which splits out HSW. Signed-off-by: Ben Widawsky Reviewed-by: Damien Lespiau Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_uncore.c | 87 +++++++++++++++++++++++++++++++------ 1 file changed, 74 insertions(+), 13 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_uncore.c b/drivers/gpu/drm/i915/intel_uncore.c index d1b32c848a44..7e8dcbeb0cac 100644 --- a/drivers/gpu/drm/i915/intel_uncore.c +++ b/drivers/gpu/drm/i915/intel_uncore.c @@ -408,16 +408,46 @@ __gen4_read(64) trace_i915_reg_rw(true, reg, val, sizeof(val), trace); \ spin_lock_irqsave(&dev_priv->uncore.lock, irqflags) -#define __i915_write(x) \ +#define __gen4_write(x) \ static void \ -i915_write##x(struct drm_i915_private *dev_priv, off_t reg, u##x val, bool trace) { \ +gen4_write##x(struct drm_i915_private *dev_priv, off_t reg, u##x val, bool trace) { \ + REG_WRITE_HEADER; \ + __raw_i915_write##x(dev_priv, reg, val); \ + spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags); \ +} + +#define __gen5_write(x) \ +static void \ +gen5_write##x(struct drm_i915_private *dev_priv, off_t reg, u##x val, bool trace) { \ + REG_WRITE_HEADER; \ + ilk_dummy_write(dev_priv); \ + __raw_i915_write##x(dev_priv, reg, val); \ + spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags); \ +} + +#define __gen6_write(x) \ +static void \ +gen6_write##x(struct drm_i915_private *dev_priv, off_t reg, u##x val, bool trace) { \ + u32 __fifo_ret = 0; \ + REG_WRITE_HEADER; \ + if (NEEDS_FORCE_WAKE((dev_priv), (reg))) { \ + __fifo_ret = __gen6_gt_wait_for_fifo(dev_priv); \ + } \ + __raw_i915_write##x(dev_priv, reg, val); \ + if (unlikely(__fifo_ret)) { \ + gen6_gt_check_fifodbg(dev_priv); \ + } \ + spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags); \ +} + +#define __hsw_write(x) \ +static void \ +hsw_write##x(struct drm_i915_private *dev_priv, off_t reg, u##x val, bool trace) { \ u32 __fifo_ret = 0; \ REG_WRITE_HEADER; \ if (NEEDS_FORCE_WAKE((dev_priv), (reg))) { \ __fifo_ret = __gen6_gt_wait_for_fifo(dev_priv); \ } \ - if (dev_priv->info->gen == 5) \ - ilk_dummy_write(dev_priv); \ hsw_unclaimed_reg_clear(dev_priv, reg); \ __raw_i915_write##x(dev_priv, reg, val); \ if (unlikely(__fifo_ret)) { \ @@ -427,11 +457,27 @@ i915_write##x(struct drm_i915_private *dev_priv, off_t reg, u##x val, bool trace spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags); \ } -__i915_write(8) -__i915_write(16) -__i915_write(32) -__i915_write(64) -#undef __i915_write +__hsw_write(8) +__hsw_write(16) +__hsw_write(32) +__hsw_write(64) +__gen6_write(8) +__gen6_write(16) +__gen6_write(32) +__gen6_write(64) +__gen5_write(8) +__gen5_write(16) +__gen5_write(32) +__gen5_write(64) +__gen4_write(8) +__gen4_write(16) +__gen4_write(32) +__gen4_write(64) + +#undef __hsw_write +#undef __gen6_write +#undef __gen5_write +#undef __gen4_write #undef REG_WRITE_HEADER void intel_uncore_init(struct drm_device *dev) @@ -488,12 +534,27 @@ void intel_uncore_init(struct drm_device *dev) switch (INTEL_INFO(dev)->gen) { case 7: case 6: + if (IS_HASWELL(dev)) { + dev_priv->uncore.funcs.mmio_writeb = hsw_write8; + dev_priv->uncore.funcs.mmio_writew = hsw_write16; + dev_priv->uncore.funcs.mmio_writel = hsw_write32; + dev_priv->uncore.funcs.mmio_writeq = hsw_write64; + } else { + dev_priv->uncore.funcs.mmio_writeb = gen6_write8; + dev_priv->uncore.funcs.mmio_writew = gen6_write16; + dev_priv->uncore.funcs.mmio_writel = gen6_write32; + dev_priv->uncore.funcs.mmio_writeq = gen6_write64; + } dev_priv->uncore.funcs.mmio_readb = gen6_read8; dev_priv->uncore.funcs.mmio_readw = gen6_read16; dev_priv->uncore.funcs.mmio_readl = gen6_read32; dev_priv->uncore.funcs.mmio_readq = gen6_read64; break; case 5: + dev_priv->uncore.funcs.mmio_writeb = gen5_write8; + dev_priv->uncore.funcs.mmio_writew = gen5_write16; + dev_priv->uncore.funcs.mmio_writel = gen5_write32; + dev_priv->uncore.funcs.mmio_writeq = gen5_write64; dev_priv->uncore.funcs.mmio_readb = gen5_read8; dev_priv->uncore.funcs.mmio_readw = gen5_read16; dev_priv->uncore.funcs.mmio_readl = gen5_read32; @@ -502,16 +563,16 @@ void intel_uncore_init(struct drm_device *dev) case 4: case 3: case 2: + dev_priv->uncore.funcs.mmio_writeb = gen4_write8; + dev_priv->uncore.funcs.mmio_writew = gen4_write16; + dev_priv->uncore.funcs.mmio_writel = gen4_write32; + dev_priv->uncore.funcs.mmio_writeq = gen4_write64; dev_priv->uncore.funcs.mmio_readb = gen4_read8; dev_priv->uncore.funcs.mmio_readw = gen4_read16; dev_priv->uncore.funcs.mmio_readl = gen4_read32; dev_priv->uncore.funcs.mmio_readq = gen4_read64; break; } - dev_priv->uncore.funcs.mmio_writeb = i915_write8; - dev_priv->uncore.funcs.mmio_writew = i915_write16; - dev_priv->uncore.funcs.mmio_writel = i915_write32; - dev_priv->uncore.funcs.mmio_writeq = i915_write64; } void intel_uncore_fini(struct drm_device *dev) -- cgit v1.2.2 From ab484f8fd62c97fc52dbb380d8b7cf3ff77b1e70 Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Sat, 5 Oct 2013 17:57:11 -0700 Subject: drm/i915: Remove gen specific checks in MMIO Now that MMIO has been split up into gen specific functions it is obvious when HAS_FPGA_DBG_UNCLAIMED, HAS_FORCE_WAKE are needed. As such, we can remove this extraneous condition. As a result of this, as well as previously existing function pointers for forcewake, we no longer need the has_force_wake member in the device specific data structure. Signed-off-by: Ben Widawsky Reviewed-by: Damien Lespiau Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.c | 5 +---- drivers/gpu/drm/i915/i915_drv.h | 3 --- drivers/gpu/drm/i915/intel_ringbuffer.c | 6 ++---- drivers/gpu/drm/i915/intel_uncore.c | 16 +++++++++------- 4 files changed, 12 insertions(+), 18 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index 96f230497cbe..59649c060986 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -257,7 +257,6 @@ static const struct intel_device_info intel_sandybridge_d_info = { .has_bsd_ring = 1, .has_blt_ring = 1, .has_llc = 1, - .has_force_wake = 1, }; static const struct intel_device_info intel_sandybridge_m_info = { @@ -267,7 +266,6 @@ static const struct intel_device_info intel_sandybridge_m_info = { .has_bsd_ring = 1, .has_blt_ring = 1, .has_llc = 1, - .has_force_wake = 1, }; #define GEN7_FEATURES \ @@ -275,8 +273,7 @@ static const struct intel_device_info intel_sandybridge_m_info = { .need_gfx_hws = 1, .has_hotplug = 1, \ .has_bsd_ring = 1, \ .has_blt_ring = 1, \ - .has_llc = 1, \ - .has_force_wake = 1 + .has_llc = 1 static const struct intel_device_info intel_ivybridge_d_info = { GEN7_FEATURES, diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 957771fc60fa..9cac93c41e10 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -441,7 +441,6 @@ struct intel_uncore { func(is_valleyview) sep \ func(is_haswell) sep \ func(is_preliminary) sep \ - func(has_force_wake) sep \ func(has_fbc) sep \ func(has_pipe_cxsr) sep \ func(has_hotplug) sep \ @@ -1729,8 +1728,6 @@ struct drm_i915_file_private { #define HAS_PCH_NOP(dev) (INTEL_PCH_TYPE(dev) == PCH_NOP) #define HAS_PCH_SPLIT(dev) (INTEL_PCH_TYPE(dev) != PCH_NONE) -#define HAS_FORCE_WAKE(dev) (INTEL_INFO(dev)->has_force_wake) - /* DPF == dynamic parity feature */ #define HAS_L3_DPF(dev) (IS_IVYBRIDGE(dev) || IS_HASWELL(dev)) #define NUM_L3_SLICES(dev) (IS_HSW_GT3(dev) ? 2 : HAS_L3_DPF(dev)) diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index b67104aaade5..4e108fc3c340 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -395,8 +395,7 @@ static int init_ring_common(struct intel_ring_buffer *ring) int ret = 0; u32 head; - if (HAS_FORCE_WAKE(dev)) - gen6_gt_force_wake_get(dev_priv); + gen6_gt_force_wake_get(dev_priv); if (I915_NEED_GFX_HWS(dev)) intel_ring_setup_status_page(ring); @@ -469,8 +468,7 @@ static int init_ring_common(struct intel_ring_buffer *ring) memset(&ring->hangcheck, 0, sizeof(ring->hangcheck)); out: - if (HAS_FORCE_WAKE(dev)) - gen6_gt_force_wake_put(dev_priv); + gen6_gt_force_wake_put(dev_priv); return ret; } diff --git a/drivers/gpu/drm/i915/intel_uncore.c b/drivers/gpu/drm/i915/intel_uncore.c index 7e8dcbeb0cac..f6fae35c568e 100644 --- a/drivers/gpu/drm/i915/intel_uncore.c +++ b/drivers/gpu/drm/i915/intel_uncore.c @@ -282,6 +282,9 @@ void gen6_gt_force_wake_get(struct drm_i915_private *dev_priv) { unsigned long irqflags; + if (!dev_priv->uncore.funcs.force_wake_get) + return; + spin_lock_irqsave(&dev_priv->uncore.lock, irqflags); if (dev_priv->uncore.forcewake_count++ == 0) dev_priv->uncore.funcs.force_wake_get(dev_priv); @@ -295,6 +298,9 @@ void gen6_gt_force_wake_put(struct drm_i915_private *dev_priv) { unsigned long irqflags; + if (!dev_priv->uncore.funcs.force_wake_put) + return; + spin_lock_irqsave(&dev_priv->uncore.lock, irqflags); if (--dev_priv->uncore.forcewake_count == 0) { dev_priv->uncore.forcewake_count++; @@ -307,9 +313,7 @@ void gen6_gt_force_wake_put(struct drm_i915_private *dev_priv) /* We give fast paths for the really cool registers */ #define NEEDS_FORCE_WAKE(dev_priv, reg) \ - ((HAS_FORCE_WAKE((dev_priv)->dev)) && \ - ((reg) < 0x40000) && \ - ((reg) != FORCEWAKE)) + ((reg) < 0x40000 && (reg) != FORCEWAKE) static void ilk_dummy_write(struct drm_i915_private *dev_priv) @@ -323,8 +327,7 @@ ilk_dummy_write(struct drm_i915_private *dev_priv) static void hsw_unclaimed_reg_clear(struct drm_i915_private *dev_priv, u32 reg) { - if (HAS_FPGA_DBG_UNCLAIMED(dev_priv->dev) && - (__raw_i915_read32(dev_priv, FPGA_DBG) & FPGA_DBG_RM_NOCLAIM)) { + if (__raw_i915_read32(dev_priv, FPGA_DBG) & FPGA_DBG_RM_NOCLAIM) { DRM_ERROR("Unknown unclaimed register before writing to %x\n", reg); __raw_i915_write32(dev_priv, FPGA_DBG, FPGA_DBG_RM_NOCLAIM); @@ -334,8 +337,7 @@ hsw_unclaimed_reg_clear(struct drm_i915_private *dev_priv, u32 reg) static void hsw_unclaimed_reg_check(struct drm_i915_private *dev_priv, u32 reg) { - if (HAS_FPGA_DBG_UNCLAIMED(dev_priv->dev) && - (__raw_i915_read32(dev_priv, FPGA_DBG) & FPGA_DBG_RM_NOCLAIM)) { + if (__raw_i915_read32(dev_priv, FPGA_DBG) & FPGA_DBG_RM_NOCLAIM) { DRM_ERROR("Unclaimed write to %x\n", reg); __raw_i915_write32(dev_priv, FPGA_DBG, FPGA_DBG_RM_NOCLAIM); } -- cgit v1.2.2 From 076e29f225bb7a5d97fa95b78b8dca61599b4198 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Tue, 8 Oct 2013 19:39:29 +0200 Subject: drm/i915: Keep intel_drv.h tidy Something already got misplaced (although it's from a patch from before Paulo's cleanup). Move it to the right spot. v2: Remove the line to keep a neat block, requested by Paulo. Reported-by: Paulo Zanoni Cc: Paulo Zanoni Reviewed-by: Paulo Zanoni Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_drv.h | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index dea20ce65e59..ce80289de69e 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -801,6 +801,8 @@ void intel_enable_gt_powersave(struct drm_device *dev); void intel_disable_gt_powersave(struct drm_device *dev); void ironlake_teardown_rc6(struct drm_device *dev); void gen6_update_ring_freq(struct drm_device *dev); +void gen6_rps_idle(struct drm_i915_private *dev_priv); +void gen6_rps_boost(struct drm_i915_private *dev_priv); void intel_aux_display_runtime_get(struct drm_i915_private *dev_priv); void intel_aux_display_runtime_put(struct drm_i915_private *dev_priv); @@ -824,7 +826,4 @@ int intel_sprite_get_colorkey(struct drm_device *dev, void *data, /* intel_tv.c */ void intel_tv_init(struct drm_device *dev); -void gen6_rps_idle(struct drm_i915_private *dev_priv); -void gen6_rps_boost(struct drm_i915_private *dev_priv); - #endif /* __INTEL_DRV_H__ */ -- cgit v1.2.2 From 5ade2c2f5813733f23bbb2f21e8ba5c3f8474a2b Mon Sep 17 00:00:00 2001 From: Paulo Zanoni Date: Thu, 19 Sep 2013 17:03:06 -0300 Subject: drm/i915: wait for IPS_ENABLE when enabling IPS At the end of haswell_crtc_enable we have an intel_wait_for_vblank with a big comment, and the message suggests it's a workaround for something we don't really understand. So I removed that wait and started getting HW state readout error messages saying that the IPS state is not what we expected. I investigated and concluded that after you write IPS_ENABLE to IPS_CTL, the bit will only actually become 1 on the next vblank. So add code to wait for the IPS_ENABLE bit. We don't really need this wait right now due to the wait I already mentioned, but at least this one has a reason to be there, while the other one is just to workaround some problem: we may remove it in the future. The wait also acts as a POSTING_READ which we missed. Signed-off-by: Paulo Zanoni Reviewed-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index a6d8698d36a1..f5126b81b435 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -3346,6 +3346,14 @@ void hsw_enable_ips(struct intel_crtc *crtc) * for a vblank, so all we need to do here is to enable the IPS bit. */ assert_plane_enabled(dev_priv, crtc->plane); I915_WRITE(IPS_CTL, IPS_ENABLE); + + /* The bit only becomes 1 in the next vblank, so this wait here is + * essentially intel_wait_for_vblank. If we don't have this and don't + * wait for vblanks until the end of crtc_enable, then the HW state + * readout code will complain that the expected IPS_CTL value is not the + * one we read. */ + if (wait_for(I915_READ_NOTRACE(IPS_CTL) & IPS_ENABLE, 50)) + DRM_ERROR("Timed out waiting for IPS enable\n"); } void hsw_disable_ips(struct intel_crtc *crtc) -- cgit v1.2.2 From c3d685a7a5cd9f18865a717468d2b02092dcefdd Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Tue, 8 Oct 2013 16:31:03 -0700 Subject: drm/i915: Do PCH and uncore init earlier For future platforms we'll need to initialize our MMIO function pointers even earlier. Specifically, we'll need to be able to have register reads/writes at GTT initialization (in i915_gem_gtt_init). Similarly, these platforms also have MMIO differences based on the PCH id, so while moving stuff around, also move the PCH initialization. CC: Chris Wilson Signed-off-by: Ben Widawsky [danvet: Mention the function where we need register access.] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_dma.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index 3316a6f37cec..0c86c4840df3 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -1542,6 +1542,11 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) intel_uncore_early_sanitize(dev); + /* This must be called before any calls to HAS_PCH_* */ + intel_detect_pch(dev); + + intel_uncore_init(dev); + ret = i915_gem_gtt_init(dev); if (ret) goto out_regs; @@ -1599,12 +1604,8 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) goto out_mtrrfree; } - /* This must be called before any calls to HAS_PCH_* */ - intel_detect_pch(dev); - intel_irq_init(dev); intel_pm_init(dev); - intel_uncore_init(dev); intel_uncore_sanitize(dev); /* Try to make sure MCHBAR is enabled before poking at it */ @@ -1689,6 +1690,7 @@ out_gtt: drm_mm_takedown(&dev_priv->gtt.base.mm); dev_priv->gtt.base.cleanup(&dev_priv->gtt.base); out_regs: + intel_uncore_fini(dev); pci_iounmap(dev->pdev, dev_priv->regs); put_bridge: pci_dev_put(dev_priv->bridge_dev); -- cgit v1.2.2 From 2cdfe6c8efb9d7dab577d610b6cdab198482cec1 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Fri, 4 Oct 2013 15:08:48 +0300 Subject: drm/i915/dp: update training set in a burst write with training pattern set MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The DP spec allows this, and requires it when full link training is started with non-minimum voltage swing and/or non-zero pre-emphasis. Signed-off-by: Jani Nikula Reviewed-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_dp.c | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 377014783e74..bee09e16725c 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -2297,7 +2297,8 @@ intel_dp_set_link_train(struct intel_dp *intel_dp, struct drm_device *dev = intel_dig_port->base.base.dev; struct drm_i915_private *dev_priv = dev->dev_private; enum port port = intel_dig_port->port; - int ret; + uint8_t buf[sizeof(intel_dp->train_set) + 1]; + int ret, len; if (HAS_DDI(dev)) { uint32_t temp = I915_READ(DP_TP_CTL(port)); @@ -2367,22 +2368,21 @@ intel_dp_set_link_train(struct intel_dp *intel_dp, I915_WRITE(intel_dp->output_reg, *DP); POSTING_READ(intel_dp->output_reg); - ret = intel_dp_aux_native_write_1(intel_dp, DP_TRAINING_PATTERN_SET, - dp_train_pat); - if (ret != 1) - return false; - - if ((dp_train_pat & DP_TRAINING_PATTERN_MASK) != + buf[0] = dp_train_pat; + if ((dp_train_pat & DP_TRAINING_PATTERN_MASK) == DP_TRAINING_PATTERN_DISABLE) { - ret = intel_dp_aux_native_write(intel_dp, - DP_TRAINING_LANE0_SET, - intel_dp->train_set, - intel_dp->lane_count); - if (ret != intel_dp->lane_count) - return false; + /* don't write DP_TRAINING_LANEx_SET on disable */ + len = 1; + } else { + /* DP_TRAINING_LANEx_SET follow DP_TRAINING_PATTERN_SET */ + memcpy(buf + 1, intel_dp->train_set, intel_dp->lane_count); + len = intel_dp->lane_count + 1; } - return true; + ret = intel_dp_aux_native_write(intel_dp, DP_TRAINING_PATTERN_SET, + buf, len); + + return ret == len; } static bool -- cgit v1.2.2 From 4a28ae58c0abad2d45a45db21e86c7166b2b4462 Mon Sep 17 00:00:00 2001 From: Paulo Zanoni Date: Wed, 9 Oct 2013 13:52:36 -0300 Subject: drm/i915: don't leak dp_connector at intel_ddi_init Regression introduced by: commit 311a20949f047a70935d6591010f42336f5402e7 Author: Paulo Zanoni drm/i915: don't init DP or HDMI when not supported by DDI port Since the commit above it is possible to have a DDI encoder that has the HDMI connector but not the DP connector (in case the port doesn't support DP). In this case, we must properly free the DP connector. We just leak this once, so it's not a big deal. Reported by kmemleak. Signed-off-by: Paulo Zanoni Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_ddi.c | 62 +++++++++++++++++++++++++++------------- 1 file changed, 42 insertions(+), 20 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c index 6d335f8ca343..31f4fe271388 100644 --- a/drivers/gpu/drm/i915/intel_ddi.c +++ b/drivers/gpu/drm/i915/intel_ddi.c @@ -1345,6 +1345,41 @@ static const struct drm_encoder_funcs intel_ddi_funcs = { .destroy = intel_ddi_destroy, }; +static struct intel_connector * +intel_ddi_init_dp_connector(struct intel_digital_port *intel_dig_port) +{ + struct intel_connector *connector; + enum port port = intel_dig_port->port; + + connector = kzalloc(sizeof(*connector), GFP_KERNEL); + if (!connector) + return NULL; + + intel_dig_port->dp.output_reg = DDI_BUF_CTL(port); + if (!intel_dp_init_connector(intel_dig_port, connector)) { + kfree(connector); + return NULL; + } + + return connector; +} + +static struct intel_connector * +intel_ddi_init_hdmi_connector(struct intel_digital_port *intel_dig_port) +{ + struct intel_connector *connector; + enum port port = intel_dig_port->port; + + connector = kzalloc(sizeof(*connector), GFP_KERNEL); + if (!connector) + return NULL; + + intel_dig_port->hdmi.hdmi_reg = DDI_BUF_CTL(port); + intel_hdmi_init_connector(intel_dig_port, connector); + + return connector; +} + void intel_ddi_init(struct drm_device *dev, enum port port) { struct drm_i915_private *dev_priv = dev->dev_private; @@ -1369,12 +1404,6 @@ void intel_ddi_init(struct drm_device *dev, enum port port) if (!intel_dig_port) return; - dp_connector = kzalloc(sizeof(*dp_connector), GFP_KERNEL); - if (!dp_connector) { - kfree(intel_dig_port); - return; - } - intel_encoder = &intel_dig_port->base; encoder = &intel_encoder->base; @@ -1394,29 +1423,22 @@ void intel_ddi_init(struct drm_device *dev, enum port port) intel_dig_port->saved_port_bits = I915_READ(DDI_BUF_CTL(port)) & (DDI_BUF_PORT_REVERSAL | DDI_A_4_LANES); - intel_dig_port->dp.output_reg = DDI_BUF_CTL(port); intel_encoder->type = INTEL_OUTPUT_UNKNOWN; intel_encoder->crtc_mask = (1 << 0) | (1 << 1) | (1 << 2); intel_encoder->cloneable = false; intel_encoder->hot_plug = intel_ddi_hot_plug; - if (init_dp && !intel_dp_init_connector(intel_dig_port, dp_connector)) { - drm_encoder_cleanup(encoder); - kfree(intel_dig_port); - kfree(dp_connector); - return; - } + if (init_dp) + dp_connector = intel_ddi_init_dp_connector(intel_dig_port); /* In theory we don't need the encoder->type check, but leave it just in * case we have some really bad VBTs... */ - if (intel_encoder->type != INTEL_OUTPUT_EDP && init_hdmi) { - hdmi_connector = kzalloc(sizeof(*hdmi_connector), - GFP_KERNEL); - if (!hdmi_connector) - return; + if (intel_encoder->type != INTEL_OUTPUT_EDP && init_hdmi) + hdmi_connector = intel_ddi_init_hdmi_connector(intel_dig_port); - intel_dig_port->hdmi.hdmi_reg = DDI_BUF_CTL(port); - intel_hdmi_init_connector(intel_dig_port, hdmi_connector); + if (!dp_connector && !hdmi_connector) { + drm_encoder_cleanup(encoder); + kfree(intel_dig_port); } } -- cgit v1.2.2 From e5b611fd4493d09eb5164f5244ac0a5325346895 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Wed, 9 Oct 2013 17:24:57 +0300 Subject: drm/i915: Populate primary_disabled in intel_modeset_readout_hw_state() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Make sure our primary_disabled matches our expectations after driver init. Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=70270 Tested-by: Paulo Zanoni Signed-off-by: Ville Syrjälä Tested-by: shui yangwei Reviewed-by: Jani Nikula Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index f5126b81b435..b54a4cf899f9 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -10706,6 +10706,7 @@ static void intel_modeset_readout_hw_state(struct drm_device *dev) &crtc->config); crtc->base.enabled = crtc->active; + crtc->primary_disabled = !crtc->active; DRM_DEBUG_KMS("[CRTC:%d] hw state readout: %s\n", crtc->base.base.id, -- cgit v1.2.2 From 4c445e0ebc648ee42c0d21713b8f76597854d47a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Wed, 9 Oct 2013 17:24:58 +0300 Subject: drm/i915: Rename primary_disabled to primary_enabled MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Let's try to avoid these confusing negated booleans. Signed-off-by: Ville Syrjälä Reviewed-by: Jani Nikula Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 10 +++++----- drivers/gpu/drm/i915/intel_drv.h | 2 +- drivers/gpu/drm/i915/intel_pm.c | 2 +- drivers/gpu/drm/i915/intel_sprite.c | 8 ++++---- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index b54a4cf899f9..ebe5d0840a86 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -1840,9 +1840,9 @@ static void intel_enable_primary_plane(struct drm_i915_private *dev_priv, /* If the pipe isn't enabled, we can't pump pixels and may hang */ assert_pipe_enabled(dev_priv, pipe); - WARN(!intel_crtc->primary_disabled, "Primary plane already enabled\n"); + WARN(intel_crtc->primary_enabled, "Primary plane already enabled\n"); - intel_crtc->primary_disabled = false; + intel_crtc->primary_enabled = true; reg = DSPCNTR(plane); val = I915_READ(reg); @@ -1870,9 +1870,9 @@ static void intel_disable_primary_plane(struct drm_i915_private *dev_priv, int reg; u32 val; - WARN(intel_crtc->primary_disabled, "Primary plane already disabled\n"); + WARN(!intel_crtc->primary_enabled, "Primary plane already disabled\n"); - intel_crtc->primary_disabled = true; + intel_crtc->primary_enabled = false; reg = DSPCNTR(plane); val = I915_READ(reg); @@ -10706,7 +10706,7 @@ static void intel_modeset_readout_hw_state(struct drm_device *dev) &crtc->config); crtc->base.enabled = crtc->active; - crtc->primary_disabled = !crtc->active; + crtc->primary_enabled = crtc->active; DRM_DEBUG_KMS("[CRTC:%d] hw state readout: %s\n", crtc->base.base.id, diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index ce80289de69e..b497a96af082 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -321,7 +321,7 @@ struct intel_crtc { */ bool active; bool eld_vld; - bool primary_disabled; /* is the crtc obscured by a plane? */ + bool primary_enabled; /* is the primary plane (partially) visible? */ bool lowfreq_avail; struct intel_overlay *overlay; struct intel_unpin_work *unpin_work; diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 9534e72fdbcb..c91087a542ec 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -475,7 +475,7 @@ void intel_update_fbc(struct drm_device *dev) */ list_for_each_entry(tmp_crtc, &dev->mode_config.crtc_list, head) { if (intel_crtc_active(tmp_crtc) && - !to_intel_crtc(tmp_crtc)->primary_disabled) { + to_intel_crtc(tmp_crtc)->primary_enabled) { if (crtc) { if (set_no_fbc_reason(dev_priv, FBC_MULTIPLE_PIPES)) DRM_DEBUG_KMS("more than one pipe active, disabling compression\n"); diff --git a/drivers/gpu/drm/i915/intel_sprite.c b/drivers/gpu/drm/i915/intel_sprite.c index e001d2c35c39..8afaad6bcc48 100644 --- a/drivers/gpu/drm/i915/intel_sprite.c +++ b/drivers/gpu/drm/i915/intel_sprite.c @@ -521,10 +521,10 @@ intel_enable_primary(struct drm_crtc *crtc) struct intel_crtc *intel_crtc = to_intel_crtc(crtc); int reg = DSPCNTR(intel_crtc->plane); - if (!intel_crtc->primary_disabled) + if (intel_crtc->primary_enabled) return; - intel_crtc->primary_disabled = false; + intel_crtc->primary_enabled = true; I915_WRITE(reg, I915_READ(reg) | DISPLAY_PLANE_ENABLE); intel_flush_primary_plane(dev_priv, intel_crtc->plane); @@ -553,10 +553,10 @@ intel_disable_primary(struct drm_crtc *crtc) struct intel_crtc *intel_crtc = to_intel_crtc(crtc); int reg = DSPCNTR(intel_crtc->plane); - if (intel_crtc->primary_disabled) + if (!intel_crtc->primary_enabled) return; - intel_crtc->primary_disabled = true; + intel_crtc->primary_enabled = false; mutex_lock(&dev->struct_mutex); if (dev_priv->fbc.plane == intel_crtc->plane) -- cgit v1.2.2 From 09e14bf3ba4b72be4d57d99e3620beae4fb1ecd8 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 10 Oct 2013 09:37:19 +0100 Subject: drm/i915: Capture the initial error-state when kicking stuck rings We lost the ability to capture the first error for a stuck ring in the recent hangcheck robustification. Whilst both error states are interesting (why does the GPU not recover is also essential to debug), our primary goal is to fix the initial hang and so we need to capture the first error state upon taking hangcheck action. Signed-off-by: Chris Wilson Reviewed-by: Mika Kuoppala Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_irq.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 418ad642c742..36279202ddc0 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -1988,6 +1988,7 @@ ring_stuck(struct intel_ring_buffer *ring, u32 acthd) if (tmp & RING_WAIT) { DRM_ERROR("Kicking stuck wait on %s\n", ring->name); + i915_handle_error(dev, false); I915_WRITE_CTL(ring, tmp); return HANGCHECK_KICK; } @@ -1999,6 +2000,7 @@ ring_stuck(struct intel_ring_buffer *ring, u32 acthd) case 1: DRM_ERROR("Kicking stuck semaphore on %s\n", ring->name); + i915_handle_error(dev, false); I915_WRITE_CTL(ring, tmp); return HANGCHECK_KICK; case 0: -- cgit v1.2.2 From 5c9669cee534cbb834d51aae115267f5e561b622 Mon Sep 17 00:00:00 2001 From: Tom O'Rourke Date: Mon, 16 Sep 2013 14:56:43 -0700 Subject: drm/i915: Finish enabling rps before use by sysfs or debugfs Enabling rps (turbo setup) was put in a work queue because it may take quite awhile. This change flushes the work queue to initialize rps values before use by sysfs or debugfs. Specifically, rps.delayed_resume_work is flushed before using rps.hw_max, rps.max_delay, rps.min_delay, or rps.cur_delay. This change fixes a problem in sysfs where show functions using uninitialized values show incorrect values and store functions using uninitialized values in range checks incorrectly fail to store valid input values. This change also addresses similar use before initialized problems in debugfs. Signed-off-by: Tom O'Rourke Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_debugfs.c | 12 ++++++++++++ drivers/gpu/drm/i915/i915_sysfs.c | 10 ++++++++++ 2 files changed, 22 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index 5fd6a5db6eb5..a569597125db 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -847,6 +847,8 @@ static int i915_cur_delayinfo(struct seq_file *m, void *unused) drm_i915_private_t *dev_priv = dev->dev_private; int ret; + flush_delayed_work(&dev_priv->rps.delayed_resume_work); + if (IS_GEN5(dev)) { u16 rgvswctl = I915_READ16(MEMSWCTL); u16 rgvstat = I915_READ16(MEMSTAT_ILK); @@ -1325,6 +1327,8 @@ static int i915_ring_freq_table(struct seq_file *m, void *unused) return 0; } + flush_delayed_work(&dev_priv->rps.delayed_resume_work); + ret = mutex_lock_interruptible(&dev_priv->rps.hw_lock); if (ret) return ret; @@ -1940,6 +1944,8 @@ i915_max_freq_get(void *data, u64 *val) if (!(IS_GEN6(dev) || IS_GEN7(dev))) return -ENODEV; + flush_delayed_work(&dev_priv->rps.delayed_resume_work); + ret = mutex_lock_interruptible(&dev_priv->rps.hw_lock); if (ret) return ret; @@ -1964,6 +1970,8 @@ i915_max_freq_set(void *data, u64 val) if (!(IS_GEN6(dev) || IS_GEN7(dev))) return -ENODEV; + flush_delayed_work(&dev_priv->rps.delayed_resume_work); + DRM_DEBUG_DRIVER("Manually setting max freq to %llu\n", val); ret = mutex_lock_interruptible(&dev_priv->rps.hw_lock); @@ -2002,6 +2010,8 @@ i915_min_freq_get(void *data, u64 *val) if (!(IS_GEN6(dev) || IS_GEN7(dev))) return -ENODEV; + flush_delayed_work(&dev_priv->rps.delayed_resume_work); + ret = mutex_lock_interruptible(&dev_priv->rps.hw_lock); if (ret) return ret; @@ -2026,6 +2036,8 @@ i915_min_freq_set(void *data, u64 val) if (!(IS_GEN6(dev) || IS_GEN7(dev))) return -ENODEV; + flush_delayed_work(&dev_priv->rps.delayed_resume_work); + DRM_DEBUG_DRIVER("Manually setting min freq to %llu\n", val); ret = mutex_lock_interruptible(&dev_priv->rps.hw_lock); diff --git a/drivers/gpu/drm/i915/i915_sysfs.c b/drivers/gpu/drm/i915/i915_sysfs.c index 8003886361b8..9ff1e4d96909 100644 --- a/drivers/gpu/drm/i915/i915_sysfs.c +++ b/drivers/gpu/drm/i915/i915_sysfs.c @@ -251,6 +251,8 @@ static ssize_t gt_cur_freq_mhz_show(struct device *kdev, struct drm_i915_private *dev_priv = dev->dev_private; int ret; + flush_delayed_work(&dev_priv->rps.delayed_resume_work); + mutex_lock(&dev_priv->rps.hw_lock); if (IS_VALLEYVIEW(dev_priv->dev)) { u32 freq; @@ -283,6 +285,8 @@ static ssize_t gt_max_freq_mhz_show(struct device *kdev, struct device_attribute struct drm_i915_private *dev_priv = dev->dev_private; int ret; + flush_delayed_work(&dev_priv->rps.delayed_resume_work); + mutex_lock(&dev_priv->rps.hw_lock); if (IS_VALLEYVIEW(dev_priv->dev)) ret = vlv_gpu_freq(dev_priv->mem_freq, dev_priv->rps.max_delay); @@ -307,6 +311,8 @@ static ssize_t gt_max_freq_mhz_store(struct device *kdev, if (ret) return ret; + flush_delayed_work(&dev_priv->rps.delayed_resume_work); + mutex_lock(&dev_priv->rps.hw_lock); if (IS_VALLEYVIEW(dev_priv->dev)) { @@ -355,6 +361,8 @@ static ssize_t gt_min_freq_mhz_show(struct device *kdev, struct device_attribute struct drm_i915_private *dev_priv = dev->dev_private; int ret; + flush_delayed_work(&dev_priv->rps.delayed_resume_work); + mutex_lock(&dev_priv->rps.hw_lock); if (IS_VALLEYVIEW(dev_priv->dev)) ret = vlv_gpu_freq(dev_priv->mem_freq, dev_priv->rps.min_delay); @@ -379,6 +387,8 @@ static ssize_t gt_min_freq_mhz_store(struct device *kdev, if (ret) return ret; + flush_delayed_work(&dev_priv->rps.delayed_resume_work); + mutex_lock(&dev_priv->rps.hw_lock); if (IS_VALLEYVIEW(dev)) { -- cgit v1.2.2 From f468980171fa6293917a8b59bfec71c6616e06c9 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Wed, 9 Oct 2013 19:22:22 +0200 Subject: drm/i915: Educate users in dmesg about reporting gpu hangs Untangling me-too reports that actually aren't is really messy. And we need to make sure the blame is put where it should be right from the start ;-) v2: Improve the wording from Ben's suggestions. Cc: Ben Widawsky Acked-by: Ben Widawsky [danvet: Frob the message as suggested by Paulo on irc.] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gpu_error.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gpu_error.c b/drivers/gpu/drm/i915/i915_gpu_error.c index 915c8ca08969..5dde81026471 100644 --- a/drivers/gpu/drm/i915/i915_gpu_error.c +++ b/drivers/gpu/drm/i915/i915_gpu_error.c @@ -910,8 +910,12 @@ void i915_capture_error_state(struct drm_device *dev) return; } - DRM_INFO("capturing error event; look for more information in " - "/sys/class/drm/card%d/error\n", dev->primary->index); + DRM_INFO("GPU crash dump saved to /sys/class/drm/card%d/error\n", + dev->primary->index); + DRM_INFO("GPU hangs can indicate a bug anywhere in the entire gfx stack, including userspace.\n"); + DRM_INFO("Please file a _new_ bug report on bugs.freedesktop.org against DRI -> DRM/Intel\n"); + DRM_INFO("drm/i915 developers can then reassign to the right component if it's not a kernel issue.\n"); + DRM_INFO("The gpu crash dump is required to analyze gpu hangs, so please always attach it.\n"); kref_init(&error->ref); error->eir = I915_READ(EIR); -- cgit v1.2.2 From e147accbd19f55489dabdcc4dc3551cc3e3f2553 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Thu, 10 Oct 2013 15:25:37 +0300 Subject: drm/i915: tell the user KMS is required for gen6+ MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Educate the users why i915 won't load on gen6+ and nomodeset. Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=61671 Signed-off-by: Jani Nikula Reviewed-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_dma.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index 0c86c4840df3..9a5424180127 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -1477,8 +1477,11 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) info = (struct intel_device_info *) flags; /* Refuse to load on gen6+ without kms enabled. */ - if (info->gen >= 6 && !drm_core_check_feature(dev, DRIVER_MODESET)) + if (info->gen >= 6 && !drm_core_check_feature(dev, DRIVER_MODESET)) { + DRM_INFO("Your hardware requires kernel modesetting (KMS)\n"); + DRM_INFO("See CONFIG_DRM_I915_KMS, nomodeset, and i915.modeset parameters\n"); return -ENODEV; + } dev_priv = kzalloc(sizeof(*dev_priv), GFP_KERNEL); if (dev_priv == NULL) -- cgit v1.2.2 From c0951f0c97bc1528262a92b193fed7942cc6c54c Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 10 Oct 2013 21:58:50 +0100 Subject: drm/i915: Avoid tweaking RPS before it is enabled As we delay the initial RPS enabling (upon boot and after resume), there is a chance that we may start to render and trigger RPS boosts before we set up the punit. Any changes we make could result in inconsistent hardware state, with a danger of causing undefined behaviour. However, as the boosting is a optional tweak to RPS, we can simply ignore it whilst RPS is not yet enabled. Signed-off-by: Chris Wilson Cc: Daniel Vetter Cc: Jesse Barnes Reviewed-by: Jesse Barnes Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 1 + drivers/gpu/drm/i915/intel_pm.c | 26 ++++++++++++++++---------- 2 files changed, 17 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 9cac93c41e10..36b82cc48b4c 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -862,6 +862,7 @@ struct intel_gen6_power_mgmt { int last_adj; enum { LOW_POWER, BETWEEN, HIGH_POWER } power; + bool enabled; struct delayed_work delayed_resume_work; /* diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index c91087a542ec..ca3dd566974a 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -3442,22 +3442,26 @@ void gen6_set_rps(struct drm_device *dev, u8 val) void gen6_rps_idle(struct drm_i915_private *dev_priv) { mutex_lock(&dev_priv->rps.hw_lock); - if (dev_priv->info->is_valleyview) - valleyview_set_rps(dev_priv->dev, dev_priv->rps.min_delay); - else - gen6_set_rps(dev_priv->dev, dev_priv->rps.min_delay); - dev_priv->rps.last_adj = 0; + if (dev_priv->rps.enabled) { + if (dev_priv->info->is_valleyview) + valleyview_set_rps(dev_priv->dev, dev_priv->rps.min_delay); + else + gen6_set_rps(dev_priv->dev, dev_priv->rps.min_delay); + dev_priv->rps.last_adj = 0; + } mutex_unlock(&dev_priv->rps.hw_lock); } void gen6_rps_boost(struct drm_i915_private *dev_priv) { mutex_lock(&dev_priv->rps.hw_lock); - if (dev_priv->info->is_valleyview) - valleyview_set_rps(dev_priv->dev, dev_priv->rps.max_delay); - else - gen6_set_rps(dev_priv->dev, dev_priv->rps.max_delay); - dev_priv->rps.last_adj = 0; + if (dev_priv->rps.enabled) { + if (dev_priv->info->is_valleyview) + valleyview_set_rps(dev_priv->dev, dev_priv->rps.max_delay); + else + gen6_set_rps(dev_priv->dev, dev_priv->rps.max_delay); + dev_priv->rps.last_adj = 0; + } mutex_unlock(&dev_priv->rps.hw_lock); } @@ -4716,6 +4720,7 @@ void intel_disable_gt_powersave(struct drm_device *dev) valleyview_disable_rps(dev); else gen6_disable_rps(dev); + dev_priv->rps.enabled = false; mutex_unlock(&dev_priv->rps.hw_lock); } } @@ -4735,6 +4740,7 @@ static void intel_gen6_powersave_work(struct work_struct *work) gen6_enable_rps(dev); gen6_update_ring_freq(dev); } + dev_priv->rps.enabled = true; mutex_unlock(&dev_priv->rps.hw_lock); } -- cgit v1.2.2 From 4994aa8cc10177f620b096738be52eee8a181a9a Mon Sep 17 00:00:00 2001 From: Paulo Zanoni Date: Wed, 9 Oct 2013 16:39:57 -0300 Subject: drm/i915: increase the SWSCI DSLP default timeout to 50ms The spec says the default timeout should be 2ms, but on my machine this doesn't seem to be enough. Sometimes it works, sometimes I get these messages when booting: - SWSCI request timed out - SWSCI request already in progress And my guess is that the "already in progress" message is because the first one is still happening. I did some experiments on my machine (that has CONFIG_HZ=1000) and the wait_for function usually takes 4-6 jiffies to finish, but I've seen up to 9. So increase the timeout to 50ms. We only expect to wait for the actual amount of time the operation takes, so even a huge timeout shouldn't delay us more than what the hardware actually requires. Cc: Jani Nikula Signed-off-by: Paulo Zanoni Reviewed-by: Jani Nikula Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_opregion.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/intel_opregion.c b/drivers/gpu/drm/i915/intel_opregion.c index 2acf5cae20e4..904464023c8f 100644 --- a/drivers/gpu/drm/i915/intel_opregion.c +++ b/drivers/gpu/drm/i915/intel_opregion.c @@ -258,7 +258,9 @@ static int swsci(struct drm_device *dev, u32 function, u32 parm, u32 *parm_out) /* Driver sleep timeout in ms. */ dslp = ioread32(&swsci->dslp); if (!dslp) { - dslp = 2; + /* The spec says 2ms should be the default, but it's too small + * for some machines. */ + dslp = 50; } else if (dslp > 500) { /* Hey bios, trust must be earned. */ WARN_ONCE(1, "excessive driver sleep timeout (DSPL) %u\n", dslp); -- cgit v1.2.2 From fbf49ea21bd4f2ed88d678f7fc8b34a7dd0a7460 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Fri, 11 Oct 2013 14:21:31 +0300 Subject: drm/i915: Fix pipe off timeout handling for pre-gen4 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The current pre-gen4 pipe off code might break out of the loop due to the timeout, but then the fail to print the warning. Refactor the code a bit to use wait_for() to avoid the problem, and that we also re-check the condition after the timeout has expired. v2: Use wait_for() Signed-off-by: Ville Syrjälä Reviewed-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 35 ++++++++++++++++++++--------------- 1 file changed, 20 insertions(+), 15 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index ebe5d0840a86..502f000e252c 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -800,6 +800,25 @@ void intel_wait_for_vblank(struct drm_device *dev, int pipe) DRM_DEBUG_KMS("vblank wait timed out\n"); } +static bool pipe_dsl_stopped(struct drm_device *dev, enum pipe pipe) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + u32 reg = PIPEDSL(pipe); + u32 line1, line2; + u32 line_mask; + + if (IS_GEN2(dev)) + line_mask = DSL_LINEMASK_GEN2; + else + line_mask = DSL_LINEMASK_GEN3; + + line1 = I915_READ(reg) & line_mask; + mdelay(5); + line2 = I915_READ(reg) & line_mask; + + return line1 == line2; +} + /* * intel_wait_for_pipe_off - wait for pipe to turn off * @dev: drm device @@ -831,22 +850,8 @@ void intel_wait_for_pipe_off(struct drm_device *dev, int pipe) 100)) WARN(1, "pipe_off wait timed out\n"); } else { - u32 last_line, line_mask; - int reg = PIPEDSL(pipe); - unsigned long timeout = jiffies + msecs_to_jiffies(100); - - if (IS_GEN2(dev)) - line_mask = DSL_LINEMASK_GEN2; - else - line_mask = DSL_LINEMASK_GEN3; - /* Wait for the display line to settle */ - do { - last_line = I915_READ(reg) & line_mask; - mdelay(5); - } while (((I915_READ(reg) & line_mask) != last_line) && - time_after(timeout, jiffies)); - if (time_after(jiffies, timeout)) + if (wait_for(pipe_dsl_stopped(dev, pipe), 100)) WARN(1, "pipe_off wait timed out\n"); } } -- cgit v1.2.2 From e8cde23b4607e19bd079a8173393a0d16aadfe31 Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Fri, 11 Oct 2013 12:09:29 -0700 Subject: drm/i915: don't save/restore CACHE_MODE_0 on gen7+ On gen7+, CACHE_MODE_0 moved, so we're clobbering some other reg rather than restoring CACHE_MODE_0. Don't do that. Signed-off-by: Jesse Barnes Reviewed-by: Paulo Zanoni Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_suspend.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_suspend.c b/drivers/gpu/drm/i915/i915_suspend.c index 3538370e3a47..a088f1f46bdb 100644 --- a/drivers/gpu/drm/i915/i915_suspend.c +++ b/drivers/gpu/drm/i915/i915_suspend.c @@ -369,7 +369,8 @@ int i915_save_state(struct drm_device *dev) intel_disable_gt_powersave(dev); /* Cache mode state */ - dev_priv->regfile.saveCACHE_MODE_0 = I915_READ(CACHE_MODE_0); + if (INTEL_INFO(dev)->gen < 7) + dev_priv->regfile.saveCACHE_MODE_0 = I915_READ(CACHE_MODE_0); /* Memory Arbitration state */ dev_priv->regfile.saveMI_ARB_STATE = I915_READ(MI_ARB_STATE); @@ -418,7 +419,9 @@ int i915_restore_state(struct drm_device *dev) } /* Cache mode state */ - I915_WRITE(CACHE_MODE_0, dev_priv->regfile.saveCACHE_MODE_0 | 0xffff0000); + if (INTEL_INFO(dev)->gen < 7) + I915_WRITE(CACHE_MODE_0, dev_priv->regfile.saveCACHE_MODE_0 | + 0xffff0000); /* Memory arbitration state */ I915_WRITE(MI_ARB_STATE, dev_priv->regfile.saveMI_ARB_STATE | 0xffff0000); -- cgit v1.2.2 From d8228d0d51fcd6f14c5a96319539dce14508bf19 Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Fri, 11 Oct 2013 12:09:30 -0700 Subject: drm/i915/vlv: add doc names to sideband file So digging out the right ones is a little easier. Signed-off-by: Jesse Barnes Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_sideband.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/intel_sideband.c b/drivers/gpu/drm/i915/intel_sideband.c index acd1cfe8b7dd..9944d8135e87 100644 --- a/drivers/gpu/drm/i915/intel_sideband.c +++ b/drivers/gpu/drm/i915/intel_sideband.c @@ -25,7 +25,10 @@ #include "i915_drv.h" #include "intel_drv.h" -/* IOSF sideband */ +/* + * IOSF sideband, see VLV2_SidebandMsg_HAS.docx and + * VLV_VLV2_PUNIT_HAS_0.8.docx + */ static int vlv_sideband_rw(struct drm_i915_private *dev_priv, u32 devfn, u32 port, u32 opcode, u32 addr, u32 *val) { -- cgit v1.2.2 From 25a2e2d0f35e3297c7c8c6daf12d35fca7a51e44 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Fri, 11 Oct 2013 22:24:41 +0300 Subject: drm/i915: Fix VLV frame counter registers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Supposedly VLV uses the CTG+ style frame counter registers instead of the old gen3/4 style. Add the magic offset to the correct registers. We should already be taking the correct codepaths for .get_vblank_counter() and .get_scanout_position(). Signed-off-by: Ville Syrjälä Reviewed-by: Jesse Barnes Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_reg.h | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 95385023e0ba..35c9d868b893 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -3348,17 +3348,17 @@ * } while (high1 != high2); * frame = (high1 << 8) | low1; */ -#define _PIPEAFRAMEHIGH (dev_priv->info->display_mmio_offset + 0x70040) +#define _PIPEAFRAMEHIGH 0x70040 #define PIPE_FRAME_HIGH_MASK 0x0000ffff #define PIPE_FRAME_HIGH_SHIFT 0 -#define _PIPEAFRAMEPIXEL (dev_priv->info->display_mmio_offset + 0x70044) +#define _PIPEAFRAMEPIXEL 0x70044 #define PIPE_FRAME_LOW_MASK 0xff000000 #define PIPE_FRAME_LOW_SHIFT 24 #define PIPE_PIXEL_MASK 0x00ffffff #define PIPE_PIXEL_SHIFT 0 /* GM45+ just has to be different */ -#define _PIPEA_FRMCOUNT_GM45 0x70040 -#define _PIPEA_FLIPCOUNT_GM45 0x70044 +#define _PIPEA_FRMCOUNT_GM45 (dev_priv->info->display_mmio_offset + 0x70040) +#define _PIPEA_FLIPCOUNT_GM45 (dev_priv->info->display_mmio_offset + 0x70044) #define PIPE_FRMCOUNT_GM45(pipe) _PIPE(pipe, _PIPEA_FRMCOUNT_GM45, _PIPEB_FRMCOUNT_GM45) /* Cursor A & B regs */ @@ -3489,10 +3489,10 @@ #define _PIPEBDSL (dev_priv->info->display_mmio_offset + 0x71000) #define _PIPEBCONF (dev_priv->info->display_mmio_offset + 0x71008) #define _PIPEBSTAT (dev_priv->info->display_mmio_offset + 0x71024) -#define _PIPEBFRAMEHIGH (dev_priv->info->display_mmio_offset + 0x71040) -#define _PIPEBFRAMEPIXEL (dev_priv->info->display_mmio_offset + 0x71044) -#define _PIPEB_FRMCOUNT_GM45 0x71040 -#define _PIPEB_FLIPCOUNT_GM45 0x71044 +#define _PIPEBFRAMEHIGH 0x71040 +#define _PIPEBFRAMEPIXEL 0x71044 +#define _PIPEB_FRMCOUNT_GM45 (dev_priv->info->display_mmio_offset + 0x71040) +#define _PIPEB_FLIPCOUNT_GM45 (dev_priv->info->display_mmio_offset + 0x71044) /* Display B control */ -- cgit v1.2.2 From 92b6f89f6b85f433ddac1f4a9eb0962dc96380fe Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Tue, 8 Oct 2013 17:44:47 +0200 Subject: drm: Add separate Kconfig option for fbdev helpers For drivers which might want to disable fbdev legacy support. Select the new option in all drivers for now, so this shouldn't result in any change. Drivers need some work anyway to make fbdev support optional (if they have it implemented, that is), so the recommended way to expose this is by adding per-driver options. At least as long as most drivers don't support disabling the fbdev support. v2: Update for new drm drivers msm and rcar-du. Note that Rob's msm driver can already take advantage of this, which allows us to build msm without any fbdev depencies in the kernel! v3: Move the MODULE_* stuff from the fbdev helper file to drm_crtc_helper.c. Cc: David Herrmann Cc: Rob Clark Reviewed-by: Rob Clark Acked-by: Dave Airlie Reviewed-by: Chon Ming Lee Signed-off-by: Daniel Vetter --- drivers/gpu/drm/Kconfig | 11 ++++++++++- drivers/gpu/drm/Makefile | 3 ++- drivers/gpu/drm/ast/Kconfig | 1 + drivers/gpu/drm/cirrus/Kconfig | 1 + drivers/gpu/drm/drm_crtc_helper.c | 4 ++++ drivers/gpu/drm/drm_fb_helper.c | 4 ---- drivers/gpu/drm/exynos/Kconfig | 1 + drivers/gpu/drm/gma500/Kconfig | 1 + drivers/gpu/drm/mgag200/Kconfig | 1 + drivers/gpu/drm/msm/Kconfig | 1 + drivers/gpu/drm/nouveau/Kconfig | 1 + drivers/gpu/drm/omapdrm/Kconfig | 1 + drivers/gpu/drm/qxl/Kconfig | 1 + drivers/gpu/drm/rcar-du/Kconfig | 1 + drivers/gpu/drm/shmobile/Kconfig | 1 + drivers/gpu/drm/tilcdc/Kconfig | 1 + drivers/gpu/drm/udl/Kconfig | 1 + drivers/gpu/host1x/drm/Kconfig | 1 + drivers/staging/imx-drm/Kconfig | 1 + 19 files changed, 31 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig index 955555d6ec88..3104b6d06f1a 100644 --- a/drivers/gpu/drm/Kconfig +++ b/drivers/gpu/drm/Kconfig @@ -29,11 +29,17 @@ config DRM_USB config DRM_KMS_HELPER tristate depends on DRM + help + CRTC helpers for KMS drivers. + +config DRM_KMS_FB_HELPER + bool + depends on DRM_KMS_HELPER select FB select FRAMEBUFFER_CONSOLE if !EXPERT select FRAMEBUFFER_CONSOLE_DETECT_PRIMARY if FRAMEBUFFER_CONSOLE help - FB and CRTC helpers for KMS drivers. + FBDEV helpers for KMS drivers. config DRM_LOAD_EDID_FIRMWARE bool "Allow to specify an EDID data set instead of probing for it" @@ -64,6 +70,7 @@ config DRM_GEM_CMA_HELPER config DRM_KMS_CMA_HELPER bool select DRM_GEM_CMA_HELPER + select DRM_KMS_FB_HELPER select FB_SYS_FILLRECT select FB_SYS_COPYAREA select FB_SYS_IMAGEBLIT @@ -96,6 +103,7 @@ config DRM_RADEON select FB_CFB_IMAGEBLIT select FW_LOADER select DRM_KMS_HELPER + select DRM_KMS_FB_HELPER select DRM_TTM select POWER_SUPPLY select HWMON @@ -130,6 +138,7 @@ config DRM_I915 select SHMEM select TMPFS select DRM_KMS_HELPER + select DRM_KMS_FB_HELPER select FB_CFB_FILLRECT select FB_CFB_COPYAREA select FB_CFB_IMAGEBLIT diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile index f089adfe70ee..5af240bfd29f 100644 --- a/drivers/gpu/drm/Makefile +++ b/drivers/gpu/drm/Makefile @@ -21,8 +21,9 @@ drm-$(CONFIG_PCI) += ati_pcigart.o drm-usb-y := drm_usb.o -drm_kms_helper-y := drm_fb_helper.o drm_crtc_helper.o drm_dp_helper.o +drm_kms_helper-y := drm_crtc_helper.o drm_dp_helper.o drm_kms_helper-$(CONFIG_DRM_LOAD_EDID_FIRMWARE) += drm_edid_load.o +drm_kms_helper-$(CONFIG_DRM_KMS_FB_HELPER) += drm_fb_helper.o drm_kms_helper-$(CONFIG_DRM_KMS_CMA_HELPER) += drm_fb_cma_helper.o obj-$(CONFIG_DRM_KMS_HELPER) += drm_kms_helper.o diff --git a/drivers/gpu/drm/ast/Kconfig b/drivers/gpu/drm/ast/Kconfig index da4a51eae824..8a784c460c89 100644 --- a/drivers/gpu/drm/ast/Kconfig +++ b/drivers/gpu/drm/ast/Kconfig @@ -6,6 +6,7 @@ config DRM_AST select FB_SYS_FILLRECT select FB_SYS_IMAGEBLIT select DRM_KMS_HELPER + select DRM_KMS_FB_HELPER select DRM_TTM help Say yes for experimental AST GPU driver. Do not enable diff --git a/drivers/gpu/drm/cirrus/Kconfig b/drivers/gpu/drm/cirrus/Kconfig index bf67b22723f9..9864559e5fb9 100644 --- a/drivers/gpu/drm/cirrus/Kconfig +++ b/drivers/gpu/drm/cirrus/Kconfig @@ -5,6 +5,7 @@ config DRM_CIRRUS_QEMU select FB_SYS_COPYAREA select FB_SYS_IMAGEBLIT select DRM_KMS_HELPER + select DRM_KMS_FB_HELPER select DRM_TTM help This is a KMS driver for emulated cirrus device in qemu. diff --git a/drivers/gpu/drm/drm_crtc_helper.c b/drivers/gpu/drm/drm_crtc_helper.c index 5fcb9d487672..0d6469d74be4 100644 --- a/drivers/gpu/drm/drm_crtc_helper.c +++ b/drivers/gpu/drm/drm_crtc_helper.c @@ -39,6 +39,10 @@ #include #include +MODULE_AUTHOR("David Airlie, Jesse Barnes"); +MODULE_DESCRIPTION("DRM KMS helper"); +MODULE_LICENSE("GPL and additional rights"); + /** * drm_helper_move_panel_connectors_to_head() - move panels to the front in the * connector list diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c index 21742a81cb9c..720352345452 100644 --- a/drivers/gpu/drm/drm_fb_helper.c +++ b/drivers/gpu/drm/drm_fb_helper.c @@ -39,10 +39,6 @@ #include #include -MODULE_AUTHOR("David Airlie, Jesse Barnes"); -MODULE_DESCRIPTION("DRM KMS helper"); -MODULE_LICENSE("GPL and additional rights"); - static LIST_HEAD(kernel_fb_helper_list); /** diff --git a/drivers/gpu/drm/exynos/Kconfig b/drivers/gpu/drm/exynos/Kconfig index 45b6ef595965..f227f544aa36 100644 --- a/drivers/gpu/drm/exynos/Kconfig +++ b/drivers/gpu/drm/exynos/Kconfig @@ -2,6 +2,7 @@ config DRM_EXYNOS tristate "DRM Support for Samsung SoC EXYNOS Series" depends on OF && DRM && (PLAT_SAMSUNG || ARCH_MULTIPLATFORM) select DRM_KMS_HELPER + select DRM_KMS_FB_HELPER select FB_CFB_FILLRECT select FB_CFB_COPYAREA select FB_CFB_IMAGEBLIT diff --git a/drivers/gpu/drm/gma500/Kconfig b/drivers/gpu/drm/gma500/Kconfig index 1f6e2dfaaeae..508cf99a292d 100644 --- a/drivers/gpu/drm/gma500/Kconfig +++ b/drivers/gpu/drm/gma500/Kconfig @@ -5,6 +5,7 @@ config DRM_GMA500 select FB_CFB_FILLRECT select FB_CFB_IMAGEBLIT select DRM_KMS_HELPER + select DRM_KMS_FB_HELPER select DRM_TTM # GMA500 depends on ACPI_VIDEO when ACPI is enabled, just like i915 select ACPI_VIDEO if ACPI diff --git a/drivers/gpu/drm/mgag200/Kconfig b/drivers/gpu/drm/mgag200/Kconfig index b487cdec5ee7..3a1c5fbae54a 100644 --- a/drivers/gpu/drm/mgag200/Kconfig +++ b/drivers/gpu/drm/mgag200/Kconfig @@ -5,6 +5,7 @@ config DRM_MGAG200 select FB_SYS_COPYAREA select FB_SYS_IMAGEBLIT select DRM_KMS_HELPER + select DRM_KMS_FB_HELPER select DRM_TTM help This is a KMS driver for the MGA G200 server chips, it diff --git a/drivers/gpu/drm/msm/Kconfig b/drivers/gpu/drm/msm/Kconfig index a06c19cc56f8..f39ab7554fc9 100644 --- a/drivers/gpu/drm/msm/Kconfig +++ b/drivers/gpu/drm/msm/Kconfig @@ -14,6 +14,7 @@ config DRM_MSM config DRM_MSM_FBDEV bool "Enable legacy fbdev support for MSM modesetting driver" depends on DRM_MSM + select DRM_KMS_FB_HELPER select FB_SYS_FILLRECT select FB_SYS_COPYAREA select FB_SYS_IMAGEBLIT diff --git a/drivers/gpu/drm/nouveau/Kconfig b/drivers/gpu/drm/nouveau/Kconfig index ff80f12480ea..7cf787d697b1 100644 --- a/drivers/gpu/drm/nouveau/Kconfig +++ b/drivers/gpu/drm/nouveau/Kconfig @@ -3,6 +3,7 @@ config DRM_NOUVEAU depends on DRM && PCI select FW_LOADER select DRM_KMS_HELPER + select DRM_KMS_FB_HELPER select DRM_TTM select FB_CFB_FILLRECT select FB_CFB_COPYAREA diff --git a/drivers/gpu/drm/omapdrm/Kconfig b/drivers/gpu/drm/omapdrm/Kconfig index 20c41e73d448..6c220cd3497a 100644 --- a/drivers/gpu/drm/omapdrm/Kconfig +++ b/drivers/gpu/drm/omapdrm/Kconfig @@ -5,6 +5,7 @@ config DRM_OMAP depends on ARCH_OMAP2PLUS || ARCH_MULTIPLATFORM depends on OMAP2_DSS select DRM_KMS_HELPER + select DRM_KMS_FB_HELPER select FB_SYS_FILLRECT select FB_SYS_COPYAREA select FB_SYS_IMAGEBLIT diff --git a/drivers/gpu/drm/qxl/Kconfig b/drivers/gpu/drm/qxl/Kconfig index d6c12796023c..037d324bf58f 100644 --- a/drivers/gpu/drm/qxl/Kconfig +++ b/drivers/gpu/drm/qxl/Kconfig @@ -6,6 +6,7 @@ config DRM_QXL select FB_SYS_IMAGEBLIT select FB_DEFERRED_IO select DRM_KMS_HELPER + select DRM_KMS_FB_HELPER select DRM_TTM help QXL virtual GPU for Spice virtualization desktop integration. Do not enable this driver unless your distro ships a corresponding X.org QXL driver that can handle kernel modesetting. diff --git a/drivers/gpu/drm/rcar-du/Kconfig b/drivers/gpu/drm/rcar-du/Kconfig index c590cd9dca0b..d8e835ac2c5e 100644 --- a/drivers/gpu/drm/rcar-du/Kconfig +++ b/drivers/gpu/drm/rcar-du/Kconfig @@ -4,6 +4,7 @@ config DRM_RCAR_DU select DRM_KMS_HELPER select DRM_KMS_CMA_HELPER select DRM_GEM_CMA_HELPER + select DRM_KMS_FB_HELPER help Choose this option if you have an R-Car chipset. If M is selected the module will be called rcar-du-drm. diff --git a/drivers/gpu/drm/shmobile/Kconfig b/drivers/gpu/drm/shmobile/Kconfig index ca498d151a76..d1372862d871 100644 --- a/drivers/gpu/drm/shmobile/Kconfig +++ b/drivers/gpu/drm/shmobile/Kconfig @@ -2,6 +2,7 @@ config DRM_SHMOBILE tristate "DRM Support for SH Mobile" depends on DRM && (ARM || SUPERH) select DRM_KMS_HELPER + select DRM_KMS_FB_HELPER select DRM_KMS_CMA_HELPER select DRM_GEM_CMA_HELPER help diff --git a/drivers/gpu/drm/tilcdc/Kconfig b/drivers/gpu/drm/tilcdc/Kconfig index 7a4d10106906..7c3ef79fcb37 100644 --- a/drivers/gpu/drm/tilcdc/Kconfig +++ b/drivers/gpu/drm/tilcdc/Kconfig @@ -2,6 +2,7 @@ config DRM_TILCDC tristate "DRM Support for TI LCDC Display Controller" depends on DRM && OF && ARM select DRM_KMS_HELPER + select DRM_KMS_FB_HELPER select DRM_KMS_CMA_HELPER select DRM_GEM_CMA_HELPER select VIDEOMODE_HELPERS diff --git a/drivers/gpu/drm/udl/Kconfig b/drivers/gpu/drm/udl/Kconfig index 6222af19f456..f02528686cd5 100644 --- a/drivers/gpu/drm/udl/Kconfig +++ b/drivers/gpu/drm/udl/Kconfig @@ -8,6 +8,7 @@ config DRM_UDL select FB_SYS_IMAGEBLIT select FB_DEFERRED_IO select DRM_KMS_HELPER + select DRM_KMS_FB_HELPER help This is a KMS driver for the USB displaylink video adapters. Say M/Y to add support for these devices via drm/kms interfaces. diff --git a/drivers/gpu/host1x/drm/Kconfig b/drivers/gpu/host1x/drm/Kconfig index 69853a4de40a..0f36ddd74e87 100644 --- a/drivers/gpu/host1x/drm/Kconfig +++ b/drivers/gpu/host1x/drm/Kconfig @@ -2,6 +2,7 @@ config DRM_TEGRA bool "NVIDIA Tegra DRM" depends on DRM select DRM_KMS_HELPER + select DRM_KMS_FB_HELPER select FB_SYS_FILLRECT select FB_SYS_COPYAREA select FB_SYS_IMAGEBLIT diff --git a/drivers/staging/imx-drm/Kconfig b/drivers/staging/imx-drm/Kconfig index 394254f7d6b5..5032ff7c2259 100644 --- a/drivers/staging/imx-drm/Kconfig +++ b/drivers/staging/imx-drm/Kconfig @@ -1,6 +1,7 @@ config DRM_IMX tristate "DRM Support for Freescale i.MX" select DRM_KMS_HELPER + select DRM_KMS_FB_HELPER select VIDEOMODE_HELPERS select DRM_GEM_CMA_HELPER select DRM_KMS_CMA_HELPER -- cgit v1.2.2 From 4520f53a159fb81b8c27afe52428a0959aff259c Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Wed, 9 Oct 2013 09:18:51 +0200 Subject: drm/i915: Kconfig option to disable the legacy fbdev support Boots Just Fine (tm)! The only glitch seems to be that at least on Fedora the boot splash gets confused and doesn't display much at all. And since there's no ugly console flickering anymore in between, the flicker while switching between X servers (VT support is still enabled) is even more jarring. Also, I'm unsure whether we don't need to somehow kick out vgacon, now that nothing else gets in the way. But stuff seems to work, so I don't care. Also everything still works as well with VGA_CONSOLE=n Also the #ifdef mess needs a bit of a cleanup, follow-up patches will do just that. To keep the Kconfig tidy, extract all the i915 options into its own file. v2: - Rebase on top of the preliminary hw support option and the intel_drv.h cleanup. - Shut up warnings in i915_debugfs.c v3: Use the right CONFIG variable, spotted by Chon Ming. Cc: Lee, Chon Ming Cc: David Herrmann Reviewed-by: Chon Ming Lee Signed-off-by: Daniel Vetter --- drivers/gpu/drm/Kconfig | 60 +------------------------------- drivers/gpu/drm/i915/Kconfig | 67 ++++++++++++++++++++++++++++++++++++ drivers/gpu/drm/i915/Makefile | 3 +- drivers/gpu/drm/i915/i915_debugfs.c | 9 ++--- drivers/gpu/drm/i915/i915_dma.c | 6 ++++ drivers/gpu/drm/i915/i915_drv.h | 2 ++ drivers/gpu/drm/i915/intel_display.c | 10 ++++++ drivers/gpu/drm/i915/intel_drv.h | 36 +++++++++++++++---- 8 files changed, 122 insertions(+), 71 deletions(-) create mode 100644 drivers/gpu/drm/i915/Kconfig diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig index 3104b6d06f1a..b4e4fc0d6650 100644 --- a/drivers/gpu/drm/Kconfig +++ b/drivers/gpu/drm/Kconfig @@ -128,65 +128,7 @@ config DRM_I810 selected, the module will be called i810. AGP support is required for this driver to work. -config DRM_I915 - tristate "Intel 8xx/9xx/G3x/G4x/HD Graphics" - depends on DRM - depends on AGP - depends on AGP_INTEL - # we need shmfs for the swappable backing store, and in particular - # the shmem_readpage() which depends upon tmpfs - select SHMEM - select TMPFS - select DRM_KMS_HELPER - select DRM_KMS_FB_HELPER - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT - # i915 depends on ACPI_VIDEO when ACPI is enabled - # but for select to work, need to select ACPI_VIDEO's dependencies, ick - select BACKLIGHT_LCD_SUPPORT if ACPI - select BACKLIGHT_CLASS_DEVICE if ACPI - select VIDEO_OUTPUT_CONTROL if ACPI - select INPUT if ACPI - select THERMAL if ACPI - select ACPI_VIDEO if ACPI - select ACPI_BUTTON if ACPI - help - Choose this option if you have a system that has "Intel Graphics - Media Accelerator" or "HD Graphics" integrated graphics, - including 830M, 845G, 852GM, 855GM, 865G, 915G, 945G, 965G, - G35, G41, G43, G45 chipsets and Celeron, Pentium, Core i3, - Core i5, Core i7 as well as Atom CPUs with integrated graphics. - If M is selected, the module will be called i915. AGP support - is required for this driver to work. This driver is used by - the Intel driver in X.org 6.8 and XFree86 4.4 and above. It - replaces the older i830 module that supported a subset of the - hardware in older X.org releases. - - Note that the older i810/i815 chipsets require the use of the - i810 driver instead, and the Atom z5xx series has an entirely - different implementation. - -config DRM_I915_KMS - bool "Enable modesetting on intel by default" - depends on DRM_I915 - help - Choose this option if you want kernel modesetting enabled by default, - and you have a new enough userspace to support this. Running old - userspaces with this enabled will cause pain. Note that this causes - the driver to bind to PCI devices, which precludes loading things - like intelfb. - -config DRM_I915_PRELIMINARY_HW_SUPPORT - bool "Enable preliminary support for prerelease Intel hardware by default" - depends on DRM_I915 - help - Choose this option if you have prerelease Intel hardware and want the - i915 driver to support it by default. You can enable such support at - runtime with the module option i915.preliminary_hw_support=1; this - option changes the default for that module option. - - If in doubt, say "N". +source "drivers/gpu/drm/i915/Kconfig" config DRM_MGA tristate "Matrox g200/g400" diff --git a/drivers/gpu/drm/i915/Kconfig b/drivers/gpu/drm/i915/Kconfig new file mode 100644 index 000000000000..6199d0b5b958 --- /dev/null +++ b/drivers/gpu/drm/i915/Kconfig @@ -0,0 +1,67 @@ +config DRM_I915 + tristate "Intel 8xx/9xx/G3x/G4x/HD Graphics" + depends on DRM + depends on AGP + depends on AGP_INTEL + # we need shmfs for the swappable backing store, and in particular + # the shmem_readpage() which depends upon tmpfs + select SHMEM + select TMPFS + select DRM_KMS_HELPER + # i915 depends on ACPI_VIDEO when ACPI is enabled + # but for select to work, need to select ACPI_VIDEO's dependencies, ick + select BACKLIGHT_LCD_SUPPORT if ACPI + select BACKLIGHT_CLASS_DEVICE if ACPI + select VIDEO_OUTPUT_CONTROL if ACPI + select INPUT if ACPI + select ACPI_VIDEO if ACPI + select ACPI_BUTTON if ACPI + help + Choose this option if you have a system that has "Intel Graphics + Media Accelerator" or "HD Graphics" integrated graphics, + including 830M, 845G, 852GM, 855GM, 865G, 915G, 945G, 965G, + G35, G41, G43, G45 chipsets and Celeron, Pentium, Core i3, + Core i5, Core i7 as well as Atom CPUs with integrated graphics. + If M is selected, the module will be called i915. AGP support + is required for this driver to work. This driver is used by + the Intel driver in X.org 6.8 and XFree86 4.4 and above. It + replaces the older i830 module that supported a subset of the + hardware in older X.org releases. + + Note that the older i810/i815 chipsets require the use of the + i810 driver instead, and the Atom z5xx series has an entirely + different implementation. + +config DRM_I915_KMS + bool "Enable modesetting on intel by default" + depends on DRM_I915 + help + Choose this option if you want kernel modesetting enabled by default, + and you have a new enough userspace to support this. Running old + userspaces with this enabled will cause pain. Note that this causes + the driver to bind to PCI devices, which precludes loading things + like intelfb. + +config DRM_I915_FBDEV + bool "Enable legacy fbdev support for the modesettting intel driver" + depends on DRM_I915 + select DRM_KMS_FB_HELPER + select FB_CFB_FILLRECT + select FB_CFB_COPYAREA + select FB_CFB_IMAGEBLIT + default y + help + Choose this option if you have a need for the legacy fbdev + support. Note that this support also provide the linux console + support on top of the intel modesetting driver. + +config DRM_I915_PRELIMINARY_HW_SUPPORT + bool "Enable preliminary support for prerelease Intel hardware by default" + depends on DRM_I915 + help + Choose this option if you have prerelease Intel hardware and want the + i915 driver to support it by default. You can enable such support at + runtime with the module option i915.preliminary_hw_support=1; this + option changes the default for that module option. + + If in doubt, say "N". diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile index 65e60d26891b..45e14a8db2f3 100644 --- a/drivers/gpu/drm/i915/Makefile +++ b/drivers/gpu/drm/i915/Makefile @@ -33,7 +33,6 @@ i915-y := i915_drv.o i915_dma.o i915_irq.o \ intel_panel.o \ intel_pm.o \ intel_i2c.o \ - intel_fb.o \ intel_tv.o \ intel_dvo.o \ intel_ringbuffer.o \ @@ -54,6 +53,8 @@ i915-$(CONFIG_COMPAT) += i915_ioc32.o i915-$(CONFIG_ACPI) += intel_acpi.o +i915-$(CONFIG_DRM_I915_FBDEV) += intel_fb.o + obj-$(CONFIG_DRM_I915) += i915.o CFLAGS_i915_trace_points.o := -I$(src) diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index a569597125db..72d04588eccb 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -1403,12 +1403,12 @@ static int i915_gem_framebuffer_info(struct seq_file *m, void *data) { struct drm_info_node *node = (struct drm_info_node *) m->private; struct drm_device *dev = node->minor->dev; - drm_i915_private_t *dev_priv = dev->dev_private; - struct intel_fbdev *ifbdev; + struct intel_fbdev *ifbdev = NULL; struct intel_framebuffer *fb; - int ret; - ret = mutex_lock_interruptible(&dev->mode_config.mutex); +#ifdef CONFIG_DRM_I915_FBDEV + struct drm_i915_private *dev_priv = dev->dev_private; + int ret = mutex_lock_interruptible(&dev->mode_config.mutex); if (ret) return ret; @@ -1424,6 +1424,7 @@ static int i915_gem_framebuffer_info(struct seq_file *m, void *data) describe_obj(m, fb->obj); seq_putc(m, '\n'); mutex_unlock(&dev->mode_config.mutex); +#endif mutex_lock(&dev->mode_config.fb_lock); list_for_each_entry(fb, &dev->mode_config.fb_list, base.head) { diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index 9a5424180127..53c958ce3a02 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -1416,6 +1416,7 @@ void i915_master_destroy(struct drm_device *dev, struct drm_master *master) master->driver_priv = NULL; } +#ifdef CONFIG_DRM_I915_FBDEV static void i915_kick_out_firmware_fb(struct drm_i915_private *dev_priv) { struct apertures_struct *ap; @@ -1436,6 +1437,11 @@ static void i915_kick_out_firmware_fb(struct drm_i915_private *dev_priv) kfree(ap); } +#else +static void i915_kick_out_firmware_fb(struct drm_i915_private *dev_priv) +{ +} +#endif static void i915_dump_device_info(struct drm_i915_private *dev_priv) { diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 36b82cc48b4c..2ea66f23c2be 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1368,8 +1368,10 @@ typedef struct drm_i915_private { struct drm_i915_gem_object *vlv_pctx; +#ifdef CONFIG_DRM_I915_FBDEV /* list of fbdev register on this device */ struct intel_fbdev *fbdev; +#endif /* * The console may be contended at resume, but we don't diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 502f000e252c..fd38c3762518 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -7335,6 +7335,7 @@ static struct drm_framebuffer * mode_fits_in_fbdev(struct drm_device *dev, struct drm_display_mode *mode) { +#ifdef CONFIG_DRM_I915_FBDEV struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_gem_object *obj; struct drm_framebuffer *fb; @@ -7355,6 +7356,9 @@ mode_fits_in_fbdev(struct drm_device *dev, return NULL; return fb; +#else + return NULL; +#endif } bool intel_get_load_detect_pipe(struct drm_connector *connector, @@ -10101,6 +10105,12 @@ intel_user_framebuffer_create(struct drm_device *dev, return intel_framebuffer_create(dev, mode_cmd, obj); } +#ifndef CONFIG_DRM_I915_FBDEV +static inline void intel_fb_output_poll_changed(struct drm_device *dev) +{ +} +#endif + static const struct drm_mode_config_funcs intel_mode_funcs = { .fb_create = intel_user_framebuffer_create, .output_poll_changed = intel_fb_output_poll_changed, diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index b497a96af082..0f8402bc4222 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -713,14 +713,36 @@ bool intel_dsi_init(struct drm_device *dev); void intel_dvo_init(struct drm_device *dev); -/* intel_fb.c */ -int intel_fbdev_init(struct drm_device *dev); -void intel_fbdev_initial_config(struct drm_device *dev); -void intel_fbdev_fini(struct drm_device *dev); -void intel_fbdev_set_suspend(struct drm_device *dev, int state); -void intel_fb_output_poll_changed(struct drm_device *dev); -void intel_fb_restore_mode(struct drm_device *dev); +/* legacy fbdev emulation in intel_fb.c */ +#ifdef CONFIG_DRM_I915_FBDEV +extern int intel_fbdev_init(struct drm_device *dev); +extern void intel_fbdev_initial_config(struct drm_device *dev); +extern void intel_fbdev_fini(struct drm_device *dev); +extern void intel_fbdev_set_suspend(struct drm_device *dev, int state); +extern void intel_fb_output_poll_changed(struct drm_device *dev); +extern void intel_fb_restore_mode(struct drm_device *dev); +#else +static inline int intel_fbdev_init(struct drm_device *dev) +{ + return 0; +} +static inline void intel_fbdev_initial_config(struct drm_device *dev) +{ +} + +static inline void intel_fbdev_fini(struct drm_device *dev) +{ +} + +static inline void intel_fbdev_set_suspend(struct drm_device *dev, int state) +{ +} + +static inline void intel_fb_restore_mode(struct drm_device *dev) +{ +} +#endif /* intel_hdmi.c */ void intel_hdmi_init(struct drm_device *dev, int hdmi_reg, enum port port); -- cgit v1.2.2 From 0632fef669912a63c99c8ce4c2ca10c6ea04f0df Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Tue, 8 Oct 2013 17:44:49 +0200 Subject: drm/i915: rename intel_fb.c to intel_fbdev.c This file is all about the legacy fbdev support. If we want to extract framebuffer functions, we better put those into a separate file. Also rename functions accordingly, only two have used the intel_fb_ prefix anyway. Reviewed-by: Chon Ming Lee Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/Makefile | 2 +- drivers/gpu/drm/i915/i915_dma.c | 2 +- drivers/gpu/drm/i915/intel_display.c | 4 +- drivers/gpu/drm/i915/intel_drv.h | 8 +- drivers/gpu/drm/i915/intel_fb.c | 323 ----------------------------------- drivers/gpu/drm/i915/intel_fbdev.c | 323 +++++++++++++++++++++++++++++++++++ 6 files changed, 331 insertions(+), 331 deletions(-) delete mode 100644 drivers/gpu/drm/i915/intel_fb.c create mode 100644 drivers/gpu/drm/i915/intel_fbdev.c diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile index 45e14a8db2f3..41838eaa799c 100644 --- a/drivers/gpu/drm/i915/Makefile +++ b/drivers/gpu/drm/i915/Makefile @@ -53,7 +53,7 @@ i915-$(CONFIG_COMPAT) += i915_ioc32.o i915-$(CONFIG_ACPI) += intel_acpi.o -i915-$(CONFIG_DRM_I915_FBDEV) += intel_fb.o +i915-$(CONFIG_DRM_I915_FBDEV) += intel_fbdev.o obj-$(CONFIG_DRM_I915) += i915.o diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index 53c958ce3a02..42cddc11c23c 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -1853,7 +1853,7 @@ void i915_driver_lastclose(struct drm_device * dev) return; if (drm_core_check_feature(dev, DRIVER_MODESET)) { - intel_fb_restore_mode(dev); + intel_fbdev_restore_mode(dev); vga_switcheroo_process_delayed_switch(); return; } diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index fd38c3762518..4a8a2e4a332b 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -10106,14 +10106,14 @@ intel_user_framebuffer_create(struct drm_device *dev, } #ifndef CONFIG_DRM_I915_FBDEV -static inline void intel_fb_output_poll_changed(struct drm_device *dev) +static inline void intel_fbdev_output_poll_changed(struct drm_device *dev) { } #endif static const struct drm_mode_config_funcs intel_mode_funcs = { .fb_create = intel_user_framebuffer_create, - .output_poll_changed = intel_fb_output_poll_changed, + .output_poll_changed = intel_fbdev_output_poll_changed, }; /* Set up chip specific display functions */ diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 0f8402bc4222..189257df7a0f 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -713,14 +713,14 @@ bool intel_dsi_init(struct drm_device *dev); void intel_dvo_init(struct drm_device *dev); -/* legacy fbdev emulation in intel_fb.c */ +/* legacy fbdev emulation in intel_fbdev.c */ #ifdef CONFIG_DRM_I915_FBDEV extern int intel_fbdev_init(struct drm_device *dev); extern void intel_fbdev_initial_config(struct drm_device *dev); extern void intel_fbdev_fini(struct drm_device *dev); extern void intel_fbdev_set_suspend(struct drm_device *dev, int state); -extern void intel_fb_output_poll_changed(struct drm_device *dev); -extern void intel_fb_restore_mode(struct drm_device *dev); +extern void intel_fbdev_output_poll_changed(struct drm_device *dev); +extern void intel_fbdev_restore_mode(struct drm_device *dev); #else static inline int intel_fbdev_init(struct drm_device *dev) { @@ -739,7 +739,7 @@ static inline void intel_fbdev_set_suspend(struct drm_device *dev, int state) { } -static inline void intel_fb_restore_mode(struct drm_device *dev) +static inline void intel_fbdev_restore_mode(struct drm_device *dev) { } #endif diff --git a/drivers/gpu/drm/i915/intel_fb.c b/drivers/gpu/drm/i915/intel_fb.c deleted file mode 100644 index d883b77b1b78..000000000000 --- a/drivers/gpu/drm/i915/intel_fb.c +++ /dev/null @@ -1,323 +0,0 @@ -/* - * Copyright © 2007 David Airlie - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice (including the next - * paragraph) shall be included in all copies or substantial portions of the - * Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - * - * Authors: - * David Airlie - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include "intel_drv.h" -#include -#include "i915_drv.h" - -static struct fb_ops intelfb_ops = { - .owner = THIS_MODULE, - .fb_check_var = drm_fb_helper_check_var, - .fb_set_par = drm_fb_helper_set_par, - .fb_fillrect = cfb_fillrect, - .fb_copyarea = cfb_copyarea, - .fb_imageblit = cfb_imageblit, - .fb_pan_display = drm_fb_helper_pan_display, - .fb_blank = drm_fb_helper_blank, - .fb_setcmap = drm_fb_helper_setcmap, - .fb_debug_enter = drm_fb_helper_debug_enter, - .fb_debug_leave = drm_fb_helper_debug_leave, -}; - -static int intelfb_create(struct drm_fb_helper *helper, - struct drm_fb_helper_surface_size *sizes) -{ - struct intel_fbdev *ifbdev = - container_of(helper, struct intel_fbdev, helper); - struct drm_device *dev = helper->dev; - struct drm_i915_private *dev_priv = dev->dev_private; - struct fb_info *info; - struct drm_framebuffer *fb; - struct drm_mode_fb_cmd2 mode_cmd = {}; - struct drm_i915_gem_object *obj; - struct device *device = &dev->pdev->dev; - int size, ret; - - /* we don't do packed 24bpp */ - if (sizes->surface_bpp == 24) - sizes->surface_bpp = 32; - - mode_cmd.width = sizes->surface_width; - mode_cmd.height = sizes->surface_height; - - mode_cmd.pitches[0] = ALIGN(mode_cmd.width * ((sizes->surface_bpp + 7) / - 8), 64); - mode_cmd.pixel_format = drm_mode_legacy_fb_format(sizes->surface_bpp, - sizes->surface_depth); - - size = mode_cmd.pitches[0] * mode_cmd.height; - size = ALIGN(size, PAGE_SIZE); - obj = i915_gem_object_create_stolen(dev, size); - if (obj == NULL) - obj = i915_gem_alloc_object(dev, size); - if (!obj) { - DRM_ERROR("failed to allocate framebuffer\n"); - ret = -ENOMEM; - goto out; - } - - mutex_lock(&dev->struct_mutex); - - /* Flush everything out, we'll be doing GTT only from now on */ - ret = intel_pin_and_fence_fb_obj(dev, obj, NULL); - if (ret) { - DRM_ERROR("failed to pin fb: %d\n", ret); - goto out_unref; - } - - info = framebuffer_alloc(0, device); - if (!info) { - ret = -ENOMEM; - goto out_unpin; - } - - info->par = helper; - - ret = intel_framebuffer_init(dev, &ifbdev->ifb, &mode_cmd, obj); - if (ret) - goto out_unpin; - - fb = &ifbdev->ifb.base; - - ifbdev->helper.fb = fb; - ifbdev->helper.fbdev = info; - - strcpy(info->fix.id, "inteldrmfb"); - - info->flags = FBINFO_DEFAULT | FBINFO_CAN_FORCE_OUTPUT; - info->fbops = &intelfb_ops; - - ret = fb_alloc_cmap(&info->cmap, 256, 0); - if (ret) { - ret = -ENOMEM; - goto out_unpin; - } - /* setup aperture base/size for vesafb takeover */ - info->apertures = alloc_apertures(1); - if (!info->apertures) { - ret = -ENOMEM; - goto out_unpin; - } - info->apertures->ranges[0].base = dev->mode_config.fb_base; - info->apertures->ranges[0].size = dev_priv->gtt.mappable_end; - - info->fix.smem_start = dev->mode_config.fb_base + i915_gem_obj_ggtt_offset(obj); - info->fix.smem_len = size; - - info->screen_base = - ioremap_wc(dev_priv->gtt.mappable_base + i915_gem_obj_ggtt_offset(obj), - size); - if (!info->screen_base) { - ret = -ENOSPC; - goto out_unpin; - } - info->screen_size = size; - - /* This driver doesn't need a VT switch to restore the mode on resume */ - info->skip_vt_switch = true; - - drm_fb_helper_fill_fix(info, fb->pitches[0], fb->depth); - drm_fb_helper_fill_var(info, &ifbdev->helper, sizes->fb_width, sizes->fb_height); - - /* If the object is shmemfs backed, it will have given us zeroed pages. - * If the object is stolen however, it will be full of whatever - * garbage was left in there. - */ - if (ifbdev->ifb.obj->stolen) - memset_io(info->screen_base, 0, info->screen_size); - - /* Use default scratch pixmap (info->pixmap.flags = FB_PIXMAP_SYSTEM) */ - - DRM_DEBUG_KMS("allocated %dx%d fb: 0x%08lx, bo %p\n", - fb->width, fb->height, - i915_gem_obj_ggtt_offset(obj), obj); - - - mutex_unlock(&dev->struct_mutex); - vga_switcheroo_client_fb_set(dev->pdev, info); - return 0; - -out_unpin: - i915_gem_object_unpin(obj); -out_unref: - drm_gem_object_unreference(&obj->base); - mutex_unlock(&dev->struct_mutex); -out: - return ret; -} - -/** Sets the color ramps on behalf of RandR */ -static void intel_crtc_fb_gamma_set(struct drm_crtc *crtc, u16 red, u16 green, - u16 blue, int regno) -{ - struct intel_crtc *intel_crtc = to_intel_crtc(crtc); - - intel_crtc->lut_r[regno] = red >> 8; - intel_crtc->lut_g[regno] = green >> 8; - intel_crtc->lut_b[regno] = blue >> 8; -} - -static void intel_crtc_fb_gamma_get(struct drm_crtc *crtc, u16 *red, u16 *green, - u16 *blue, int regno) -{ - struct intel_crtc *intel_crtc = to_intel_crtc(crtc); - - *red = intel_crtc->lut_r[regno] << 8; - *green = intel_crtc->lut_g[regno] << 8; - *blue = intel_crtc->lut_b[regno] << 8; -} - -static struct drm_fb_helper_funcs intel_fb_helper_funcs = { - .gamma_set = intel_crtc_fb_gamma_set, - .gamma_get = intel_crtc_fb_gamma_get, - .fb_probe = intelfb_create, -}; - -static void intel_fbdev_destroy(struct drm_device *dev, - struct intel_fbdev *ifbdev) -{ - if (ifbdev->helper.fbdev) { - struct fb_info *info = ifbdev->helper.fbdev; - - unregister_framebuffer(info); - iounmap(info->screen_base); - if (info->cmap.len) - fb_dealloc_cmap(&info->cmap); - - framebuffer_release(info); - } - - drm_fb_helper_fini(&ifbdev->helper); - - drm_framebuffer_unregister_private(&ifbdev->ifb.base); - intel_framebuffer_fini(&ifbdev->ifb); -} - -int intel_fbdev_init(struct drm_device *dev) -{ - struct intel_fbdev *ifbdev; - struct drm_i915_private *dev_priv = dev->dev_private; - int ret; - - ifbdev = kzalloc(sizeof(*ifbdev), GFP_KERNEL); - if (!ifbdev) - return -ENOMEM; - - dev_priv->fbdev = ifbdev; - ifbdev->helper.funcs = &intel_fb_helper_funcs; - - ret = drm_fb_helper_init(dev, &ifbdev->helper, - INTEL_INFO(dev)->num_pipes, - 4); - if (ret) { - kfree(ifbdev); - return ret; - } - - drm_fb_helper_single_add_all_connectors(&ifbdev->helper); - - return 0; -} - -void intel_fbdev_initial_config(struct drm_device *dev) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - - /* Due to peculiar init order wrt to hpd handling this is separate. */ - drm_fb_helper_initial_config(&dev_priv->fbdev->helper, 32); -} - -void intel_fbdev_fini(struct drm_device *dev) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - if (!dev_priv->fbdev) - return; - - intel_fbdev_destroy(dev, dev_priv->fbdev); - kfree(dev_priv->fbdev); - dev_priv->fbdev = NULL; -} - -void intel_fbdev_set_suspend(struct drm_device *dev, int state) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - struct intel_fbdev *ifbdev = dev_priv->fbdev; - struct fb_info *info; - - if (!ifbdev) - return; - - info = ifbdev->helper.fbdev; - - /* On resume from hibernation: If the object is shmemfs backed, it has - * been restored from swap. If the object is stolen however, it will be - * full of whatever garbage was left in there. - */ - if (state == FBINFO_STATE_RUNNING && ifbdev->ifb.obj->stolen) - memset_io(info->screen_base, 0, info->screen_size); - - fb_set_suspend(info, state); -} - -MODULE_LICENSE("GPL and additional rights"); - -void intel_fb_output_poll_changed(struct drm_device *dev) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - drm_fb_helper_hotplug_event(&dev_priv->fbdev->helper); -} - -void intel_fb_restore_mode(struct drm_device *dev) -{ - int ret; - struct drm_i915_private *dev_priv = dev->dev_private; - - if (INTEL_INFO(dev)->num_pipes == 0) - return; - - drm_modeset_lock_all(dev); - - ret = drm_fb_helper_restore_fbdev_mode(&dev_priv->fbdev->helper); - if (ret) - DRM_DEBUG("failed to restore crtc mode\n"); - - drm_modeset_unlock_all(dev); -} diff --git a/drivers/gpu/drm/i915/intel_fbdev.c b/drivers/gpu/drm/i915/intel_fbdev.c new file mode 100644 index 000000000000..acc839569c3f --- /dev/null +++ b/drivers/gpu/drm/i915/intel_fbdev.c @@ -0,0 +1,323 @@ +/* + * Copyright © 2007 David Airlie + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Authors: + * David Airlie + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include "intel_drv.h" +#include +#include "i915_drv.h" + +static struct fb_ops intelfb_ops = { + .owner = THIS_MODULE, + .fb_check_var = drm_fb_helper_check_var, + .fb_set_par = drm_fb_helper_set_par, + .fb_fillrect = cfb_fillrect, + .fb_copyarea = cfb_copyarea, + .fb_imageblit = cfb_imageblit, + .fb_pan_display = drm_fb_helper_pan_display, + .fb_blank = drm_fb_helper_blank, + .fb_setcmap = drm_fb_helper_setcmap, + .fb_debug_enter = drm_fb_helper_debug_enter, + .fb_debug_leave = drm_fb_helper_debug_leave, +}; + +static int intelfb_create(struct drm_fb_helper *helper, + struct drm_fb_helper_surface_size *sizes) +{ + struct intel_fbdev *ifbdev = + container_of(helper, struct intel_fbdev, helper); + struct drm_device *dev = helper->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + struct fb_info *info; + struct drm_framebuffer *fb; + struct drm_mode_fb_cmd2 mode_cmd = {}; + struct drm_i915_gem_object *obj; + struct device *device = &dev->pdev->dev; + int size, ret; + + /* we don't do packed 24bpp */ + if (sizes->surface_bpp == 24) + sizes->surface_bpp = 32; + + mode_cmd.width = sizes->surface_width; + mode_cmd.height = sizes->surface_height; + + mode_cmd.pitches[0] = ALIGN(mode_cmd.width * ((sizes->surface_bpp + 7) / + 8), 64); + mode_cmd.pixel_format = drm_mode_legacy_fb_format(sizes->surface_bpp, + sizes->surface_depth); + + size = mode_cmd.pitches[0] * mode_cmd.height; + size = ALIGN(size, PAGE_SIZE); + obj = i915_gem_object_create_stolen(dev, size); + if (obj == NULL) + obj = i915_gem_alloc_object(dev, size); + if (!obj) { + DRM_ERROR("failed to allocate framebuffer\n"); + ret = -ENOMEM; + goto out; + } + + mutex_lock(&dev->struct_mutex); + + /* Flush everything out, we'll be doing GTT only from now on */ + ret = intel_pin_and_fence_fb_obj(dev, obj, NULL); + if (ret) { + DRM_ERROR("failed to pin fb: %d\n", ret); + goto out_unref; + } + + info = framebuffer_alloc(0, device); + if (!info) { + ret = -ENOMEM; + goto out_unpin; + } + + info->par = helper; + + ret = intel_framebuffer_init(dev, &ifbdev->ifb, &mode_cmd, obj); + if (ret) + goto out_unpin; + + fb = &ifbdev->ifb.base; + + ifbdev->helper.fb = fb; + ifbdev->helper.fbdev = info; + + strcpy(info->fix.id, "inteldrmfb"); + + info->flags = FBINFO_DEFAULT | FBINFO_CAN_FORCE_OUTPUT; + info->fbops = &intelfb_ops; + + ret = fb_alloc_cmap(&info->cmap, 256, 0); + if (ret) { + ret = -ENOMEM; + goto out_unpin; + } + /* setup aperture base/size for vesafb takeover */ + info->apertures = alloc_apertures(1); + if (!info->apertures) { + ret = -ENOMEM; + goto out_unpin; + } + info->apertures->ranges[0].base = dev->mode_config.fb_base; + info->apertures->ranges[0].size = dev_priv->gtt.mappable_end; + + info->fix.smem_start = dev->mode_config.fb_base + i915_gem_obj_ggtt_offset(obj); + info->fix.smem_len = size; + + info->screen_base = + ioremap_wc(dev_priv->gtt.mappable_base + i915_gem_obj_ggtt_offset(obj), + size); + if (!info->screen_base) { + ret = -ENOSPC; + goto out_unpin; + } + info->screen_size = size; + + /* This driver doesn't need a VT switch to restore the mode on resume */ + info->skip_vt_switch = true; + + drm_fb_helper_fill_fix(info, fb->pitches[0], fb->depth); + drm_fb_helper_fill_var(info, &ifbdev->helper, sizes->fb_width, sizes->fb_height); + + /* If the object is shmemfs backed, it will have given us zeroed pages. + * If the object is stolen however, it will be full of whatever + * garbage was left in there. + */ + if (ifbdev->ifb.obj->stolen) + memset_io(info->screen_base, 0, info->screen_size); + + /* Use default scratch pixmap (info->pixmap.flags = FB_PIXMAP_SYSTEM) */ + + DRM_DEBUG_KMS("allocated %dx%d fb: 0x%08lx, bo %p\n", + fb->width, fb->height, + i915_gem_obj_ggtt_offset(obj), obj); + + + mutex_unlock(&dev->struct_mutex); + vga_switcheroo_client_fb_set(dev->pdev, info); + return 0; + +out_unpin: + i915_gem_object_unpin(obj); +out_unref: + drm_gem_object_unreference(&obj->base); + mutex_unlock(&dev->struct_mutex); +out: + return ret; +} + +/** Sets the color ramps on behalf of RandR */ +static void intel_crtc_fb_gamma_set(struct drm_crtc *crtc, u16 red, u16 green, + u16 blue, int regno) +{ + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + + intel_crtc->lut_r[regno] = red >> 8; + intel_crtc->lut_g[regno] = green >> 8; + intel_crtc->lut_b[regno] = blue >> 8; +} + +static void intel_crtc_fb_gamma_get(struct drm_crtc *crtc, u16 *red, u16 *green, + u16 *blue, int regno) +{ + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + + *red = intel_crtc->lut_r[regno] << 8; + *green = intel_crtc->lut_g[regno] << 8; + *blue = intel_crtc->lut_b[regno] << 8; +} + +static struct drm_fb_helper_funcs intel_fb_helper_funcs = { + .gamma_set = intel_crtc_fb_gamma_set, + .gamma_get = intel_crtc_fb_gamma_get, + .fb_probe = intelfb_create, +}; + +static void intel_fbdev_destroy(struct drm_device *dev, + struct intel_fbdev *ifbdev) +{ + if (ifbdev->helper.fbdev) { + struct fb_info *info = ifbdev->helper.fbdev; + + unregister_framebuffer(info); + iounmap(info->screen_base); + if (info->cmap.len) + fb_dealloc_cmap(&info->cmap); + + framebuffer_release(info); + } + + drm_fb_helper_fini(&ifbdev->helper); + + drm_framebuffer_unregister_private(&ifbdev->ifb.base); + intel_framebuffer_fini(&ifbdev->ifb); +} + +int intel_fbdev_init(struct drm_device *dev) +{ + struct intel_fbdev *ifbdev; + struct drm_i915_private *dev_priv = dev->dev_private; + int ret; + + ifbdev = kzalloc(sizeof(*ifbdev), GFP_KERNEL); + if (!ifbdev) + return -ENOMEM; + + dev_priv->fbdev = ifbdev; + ifbdev->helper.funcs = &intel_fb_helper_funcs; + + ret = drm_fb_helper_init(dev, &ifbdev->helper, + INTEL_INFO(dev)->num_pipes, + 4); + if (ret) { + kfree(ifbdev); + return ret; + } + + drm_fb_helper_single_add_all_connectors(&ifbdev->helper); + + return 0; +} + +void intel_fbdev_initial_config(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + + /* Due to peculiar init order wrt to hpd handling this is separate. */ + drm_fb_helper_initial_config(&dev_priv->fbdev->helper, 32); +} + +void intel_fbdev_fini(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + if (!dev_priv->fbdev) + return; + + intel_fbdev_destroy(dev, dev_priv->fbdev); + kfree(dev_priv->fbdev); + dev_priv->fbdev = NULL; +} + +void intel_fbdev_set_suspend(struct drm_device *dev, int state) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_fbdev *ifbdev = dev_priv->fbdev; + struct fb_info *info; + + if (!ifbdev) + return; + + info = ifbdev->helper.fbdev; + + /* On resume from hibernation: If the object is shmemfs backed, it has + * been restored from swap. If the object is stolen however, it will be + * full of whatever garbage was left in there. + */ + if (state == FBINFO_STATE_RUNNING && ifbdev->ifb.obj->stolen) + memset_io(info->screen_base, 0, info->screen_size); + + fb_set_suspend(info, state); +} + +MODULE_LICENSE("GPL and additional rights"); + +void intel_fbdev_output_poll_changed(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + drm_fb_helper_hotplug_event(&dev_priv->fbdev->helper); +} + +void intel_fbdev_restore_mode(struct drm_device *dev) +{ + int ret; + struct drm_i915_private *dev_priv = dev->dev_private; + + if (INTEL_INFO(dev)->num_pipes == 0) + return; + + drm_modeset_lock_all(dev); + + ret = drm_fb_helper_restore_fbdev_mode(&dev_priv->fbdev->helper); + if (ret) + DRM_DEBUG("failed to restore crtc mode\n"); + + drm_modeset_unlock_all(dev); +} -- cgit v1.2.2 From 391f75e2bf13f105d9e4a120736ccdd8e3bc638b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Wed, 25 Sep 2013 19:55:26 +0300 Subject: drm/i915: Fix pre-CTG vblank counter MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The old style frame counter increments at the start of active video. However for i915_get_vblank_counter() we want a counter that increments at the start of vblank. Fortunately the low frame counter register also contains the pixel counter for the current frame. We can can compare that against the vblank start pixel count to determine if we need to increment the frame counter by 1 to get the correct answer. Also reorganize the function pointer assignments in intel_irq_init() a bit to avoid confusing people. Cc: Mario Kleiner Signed-off-by: Ville Syrjälä Reviewed-by: Mario Kleiner Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_irq.c | 36 +++++++++++++++++++++++++++++++----- 1 file changed, 31 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 36279202ddc0..1f91e1a8bfd1 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -526,7 +526,7 @@ static u32 i915_get_vblank_counter(struct drm_device *dev, int pipe) drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; unsigned long high_frame; unsigned long low_frame; - u32 high1, high2, low; + u32 high1, high2, low, pixel, vbl_start; if (!i915_pipe_enabled(dev, pipe)) { DRM_DEBUG_DRIVER("trying to get vblank count for disabled " @@ -534,6 +534,24 @@ static u32 i915_get_vblank_counter(struct drm_device *dev, int pipe) return 0; } + if (drm_core_check_feature(dev, DRIVER_MODESET)) { + struct intel_crtc *intel_crtc = + to_intel_crtc(dev_priv->pipe_to_crtc_mapping[pipe]); + const struct drm_display_mode *mode = + &intel_crtc->config.adjusted_mode; + + vbl_start = mode->crtc_vblank_start * mode->crtc_htotal; + } else { + enum transcoder cpu_transcoder = + intel_pipe_to_cpu_transcoder(dev_priv, pipe); + u32 htotal; + + htotal = ((I915_READ(HTOTAL(cpu_transcoder)) >> 16) & 0x1fff) + 1; + vbl_start = (I915_READ(VBLANK(cpu_transcoder)) & 0x1fff) + 1; + + vbl_start *= htotal; + } + high_frame = PIPEFRAME(pipe); low_frame = PIPEFRAMEPIXEL(pipe); @@ -544,13 +562,20 @@ static u32 i915_get_vblank_counter(struct drm_device *dev, int pipe) */ do { high1 = I915_READ(high_frame) & PIPE_FRAME_HIGH_MASK; - low = I915_READ(low_frame) & PIPE_FRAME_LOW_MASK; + low = I915_READ(low_frame); high2 = I915_READ(high_frame) & PIPE_FRAME_HIGH_MASK; } while (high1 != high2); high1 >>= PIPE_FRAME_HIGH_SHIFT; + pixel = low & PIPE_PIXEL_MASK; low >>= PIPE_FRAME_LOW_SHIFT; - return (high1 << 8) | low; + + /* + * The frame counter increments at beginning of active. + * Cook up a vblank counter by also checking the pixel + * counter against vblank start. + */ + return ((high1 << 8) | low) + (pixel >= vbl_start); } static u32 gm45_get_vblank_counter(struct drm_device *dev, int pipe) @@ -3155,11 +3180,12 @@ void intel_irq_init(struct drm_device *dev) pm_qos_add_request(&dev_priv->pm_qos, PM_QOS_CPU_DMA_LATENCY, PM_QOS_DEFAULT_VALUE); - dev->driver->get_vblank_counter = i915_get_vblank_counter; - dev->max_vblank_count = 0xffffff; /* only 24 bits of frame count */ if (IS_G4X(dev) || INTEL_INFO(dev)->gen >= 5) { dev->max_vblank_count = 0xffffffff; /* full 32 bit counter */ dev->driver->get_vblank_counter = gm45_get_vblank_counter; + } else { + dev->driver->get_vblank_counter = i915_get_vblank_counter; + dev->max_vblank_count = 0xffffff; /* only 24 bits of frame count */ } if (drm_core_check_feature(dev, DRIVER_MODESET)) -- cgit v1.2.2 From 540b5d02766863c561afe9f9d56ce0425022a731 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sun, 13 Oct 2013 12:56:31 +0100 Subject: drm/i915: Add breadcrumbs for why the backlight is being set At the moment we have 3 paths that lead to actually_set_backlight(), from modesetting, ACPI/OpRegion requests and our very own intel_backlight interface, and we have no way of distinguishing them in the debug log. So add a debug breadcrumb to explain the source of the backlight changes. Signed-off-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_opregion.c | 1 + drivers/gpu/drm/i915/intel_panel.c | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/drivers/gpu/drm/i915/intel_opregion.c b/drivers/gpu/drm/i915/intel_opregion.c index 904464023c8f..b82050c96f3e 100644 --- a/drivers/gpu/drm/i915/intel_opregion.c +++ b/drivers/gpu/drm/i915/intel_opregion.c @@ -407,6 +407,7 @@ static u32 asle_set_backlight(struct drm_device *dev, u32 bclp) if (bclp > 255) return ASLC_BACKLIGHT_FAILED; + DRM_DEBUG_KMS("updating opregion backlight %d/255\n", bclp); intel_panel_set_backlight(dev, bclp, 255); iowrite32(DIV_ROUND_UP(bclp * 100, 255) | ASLE_CBLV_VALID, &asle->cblv); diff --git a/drivers/gpu/drm/i915/intel_panel.c b/drivers/gpu/drm/i915/intel_panel.c index 54684168de1e..1f2996031ad9 100644 --- a/drivers/gpu/drm/i915/intel_panel.c +++ b/drivers/gpu/drm/i915/intel_panel.c @@ -574,6 +574,8 @@ void intel_panel_enable_backlight(struct drm_device *dev, intel_pipe_to_cpu_transcoder(dev_priv, pipe); unsigned long flags; + DRM_DEBUG_KMS("pipe=%d\n", pipe); + spin_lock_irqsave(&dev_priv->backlight.lock, flags); if (dev_priv->backlight.level == 0) { @@ -680,6 +682,8 @@ intel_panel_detect(struct drm_device *dev) static int intel_panel_update_status(struct backlight_device *bd) { struct drm_device *dev = bl_get_data(bd); + DRM_DEBUG_KMS("updating intel_backlight, brightness=%d/%d\n", + bd->props.brightness, bd->props.max_brightness); intel_panel_set_backlight(dev, bd->props.brightness, bd->props.max_brightness); return 0; -- cgit v1.2.2 From fb03ac0106bcc1d5576f1e94161e41a2ef4da1f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Mon, 14 Oct 2013 14:50:30 +0300 Subject: drm/i915: Use DIV_ROUND_CLOSEST() to calculate dot/vco MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Rounding down when calculating the dot/vco frequencies doesn't make much sense. Round to closest should give slightly nicer answers. Signed-off-by: Ville Syrjälä Reviewed-by: Jesse Barnes Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 4a8a2e4a332b..5e7127b08ada 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -329,8 +329,8 @@ static void vlv_clock(int refclk, intel_clock_t *clock) { clock->m = clock->m1 * clock->m2; clock->p = clock->p1 * clock->p2; - clock->vco = refclk * clock->m / clock->n; - clock->dot = clock->vco / clock->p; + clock->vco = DIV_ROUND_CLOSEST(refclk * clock->m, clock->n); + clock->dot = DIV_ROUND_CLOSEST(clock->vco, clock->p); } /** @@ -430,8 +430,8 @@ static void pineview_clock(int refclk, intel_clock_t *clock) { clock->m = clock->m2 + 2; clock->p = clock->p1 * clock->p2; - clock->vco = refclk * clock->m / clock->n; - clock->dot = clock->vco / clock->p; + clock->vco = DIV_ROUND_CLOSEST(refclk * clock->m, clock->n); + clock->dot = DIV_ROUND_CLOSEST(clock->vco, clock->p); } static uint32_t i9xx_dpll_compute_m(struct dpll *dpll) @@ -443,8 +443,8 @@ static void i9xx_clock(int refclk, intel_clock_t *clock) { clock->m = i9xx_dpll_compute_m(clock); clock->p = clock->p1 * clock->p2; - clock->vco = refclk * clock->m / (clock->n + 2); - clock->dot = clock->vco / clock->p; + clock->vco = DIV_ROUND_CLOSEST(refclk * clock->m, clock->n + 2); + clock->dot = DIV_ROUND_CLOSEST(clock->vco, clock->p); } #define INTELPllInvalid(s) do { /* DRM_DEBUG(s); */ return false; } while (0) -- cgit v1.2.2 From f646628b9f40cbd1c13a0eb190901c6a78395be6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Mon, 14 Oct 2013 14:50:31 +0300 Subject: drm/i915: Use vlv_clock() in vlv_crtc_clock_get() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Avoid some code duplication. Signed-off-by: Ville Syrjälä Reviewed-by: Jesse Barnes Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 5e7127b08ada..e6a4ca16f33c 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -5215,10 +5215,10 @@ static void vlv_crtc_clock_get(struct intel_crtc *crtc, clock.p1 = (mdiv >> DPIO_P1_SHIFT) & 7; clock.p2 = (mdiv >> DPIO_P2_SHIFT) & 0x1f; - clock.vco = refclk * clock.m1 * clock.m2 / clock.n; - clock.dot = 2 * clock.vco / (clock.p1 * clock.p2); + vlv_clock(refclk, &clock); - pipe_config->port_clock = clock.dot / 10; + /* clock.dot is the fast clock */ + pipe_config->port_clock = clock.dot / 5; } static bool i9xx_get_pipe_config(struct intel_crtc *crtc, -- cgit v1.2.2 From c2baf4b7097cb66e7ee3c2fa0f585d386dab6300 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Mon, 23 Sep 2013 14:48:50 +0300 Subject: drm/i915: Skip register reads in i915_get_crtc_scanoutpos() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We have all the information we need in the mode structure, so going and reading it from the hardware is pointless, and slower. We never populated ->get_vblank_timestamp() in the UMS case, and as that is the only way we'd ever call ->get_scanout_position(), we can completely ignore UMS in i915_get_crtc_scanoutpos(). Also reorganize intel_irq_init() a bit to clarify the KMS vs. UMS situation. v2: Drop UMS code Cc: Mario Kleiner Signed-off-by: Ville Syrjälä Reviewed-by: mario.kleiner.de@gmail.com Tested-by: mario.kleiner.de@gmail.com Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_irq.c | 43 ++++++++++++++++------------------------- 1 file changed, 17 insertions(+), 26 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 1f91e1a8bfd1..cc35d52f0166 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -595,24 +595,29 @@ static u32 gm45_get_vblank_counter(struct drm_device *dev, int pipe) static int i915_get_crtc_scanoutpos(struct drm_device *dev, int pipe, int *vpos, int *hpos) { - drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; - u32 vbl = 0, position = 0; + struct drm_i915_private *dev_priv = dev->dev_private; + struct drm_crtc *crtc = dev_priv->pipe_to_crtc_mapping[pipe]; + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + const struct drm_display_mode *mode = &intel_crtc->config.adjusted_mode; + u32 position; int vbl_start, vbl_end, htotal, vtotal; bool in_vbl = true; int ret = 0; - enum transcoder cpu_transcoder = intel_pipe_to_cpu_transcoder(dev_priv, - pipe); - if (!i915_pipe_enabled(dev, pipe)) { + if (!intel_crtc->active) { DRM_DEBUG_DRIVER("trying to get scanoutpos for disabled " "pipe %c\n", pipe_name(pipe)); return 0; } - /* Get vtotal. */ - vtotal = 1 + ((I915_READ(VTOTAL(cpu_transcoder)) >> 16) & 0x1fff); + htotal = mode->crtc_htotal; + vtotal = mode->crtc_vtotal; + vbl_start = mode->crtc_vblank_start; + vbl_end = mode->crtc_vblank_end; - if (INTEL_INFO(dev)->gen >= 4) { + ret |= DRM_SCANOUTPOS_VALID | DRM_SCANOUTPOS_ACCURATE; + + if (IS_G4X(dev) || INTEL_INFO(dev)->gen >= 5) { /* No obvious pixelcount register. Only query vertical * scanout position from Display scan line register. */ @@ -630,29 +635,16 @@ static int i915_get_crtc_scanoutpos(struct drm_device *dev, int pipe, */ position = (I915_READ(PIPEFRAMEPIXEL(pipe)) & PIPE_PIXEL_MASK) >> PIPE_PIXEL_SHIFT; - htotal = 1 + ((I915_READ(HTOTAL(cpu_transcoder)) >> 16) & 0x1fff); *vpos = position / htotal; *hpos = position - (*vpos * htotal); } - /* Query vblank area. */ - vbl = I915_READ(VBLANK(cpu_transcoder)); - - /* Test position against vblank region. */ - vbl_start = vbl & 0x1fff; - vbl_end = (vbl >> 16) & 0x1fff; - - if ((*vpos < vbl_start) || (*vpos > vbl_end)) - in_vbl = false; + in_vbl = *vpos >= vbl_start && *vpos < vbl_end; /* Inside "upper part" of vblank area? Apply corrective offset: */ if (in_vbl && (*vpos >= vbl_start)) *vpos = *vpos - vtotal; - /* Readouts valid? */ - if (vbl > 0) - ret |= DRM_SCANOUTPOS_VALID | DRM_SCANOUTPOS_ACCURATE; - /* In vblank? */ if (in_vbl) ret |= DRM_SCANOUTPOS_INVBL; @@ -3188,11 +3180,10 @@ void intel_irq_init(struct drm_device *dev) dev->max_vblank_count = 0xffffff; /* only 24 bits of frame count */ } - if (drm_core_check_feature(dev, DRIVER_MODESET)) + if (drm_core_check_feature(dev, DRIVER_MODESET)) { dev->driver->get_vblank_timestamp = i915_get_vblank_timestamp; - else - dev->driver->get_vblank_timestamp = NULL; - dev->driver->get_scanout_position = i915_get_crtc_scanoutpos; + dev->driver->get_scanout_position = i915_get_crtc_scanoutpos; + } if (IS_VALLEYVIEW(dev)) { dev->driver->irq_handler = valleyview_irq_handler; -- cgit v1.2.2 From 3aa18df8f22f24ab6ccd4155cb34ef6bff2f2a1c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Fri, 11 Oct 2013 19:10:32 +0300 Subject: drm/i915: Fix scanoutpos calculations MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The reported scanout position must be relative to the end of vblank. Currently we manage to fumble that in a few ways. First we don't consider the case when vtotal != vbl_end. While that isn't very common (happens maybe only w/ old panel fitting hardware), we can fix it easily enough. The second issue is that on pre-CTG hardware we convert the pixel count to horizontal/vertical components at the very beginning, and then forget to adjust the horizontal component to be relative to vbl_end. So instead we should keep our numbers in the pixel count domain while we're adjusting the position to be relative to vbl_end. Then when we do the conversion in the end, both vertical _and_ horizontal components will come out correct. v2: Change position to int from u32 to avoid sign issues Cc: Mario Kleiner Signed-off-by: Ville Syrjälä Reviewed-by: mario.kleiner.de@gmail.com Tested-by: mario.kleiner.de@gmail.com Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_irq.c | 39 +++++++++++++++++++++++++-------------- 1 file changed, 25 insertions(+), 14 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index cc35d52f0166..a923dea245ac 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -599,7 +599,7 @@ static int i915_get_crtc_scanoutpos(struct drm_device *dev, int pipe, struct drm_crtc *crtc = dev_priv->pipe_to_crtc_mapping[pipe]; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); const struct drm_display_mode *mode = &intel_crtc->config.adjusted_mode; - u32 position; + int position; int vbl_start, vbl_end, htotal, vtotal; bool in_vbl = true; int ret = 0; @@ -621,13 +621,7 @@ static int i915_get_crtc_scanoutpos(struct drm_device *dev, int pipe, /* No obvious pixelcount register. Only query vertical * scanout position from Display scan line register. */ - position = I915_READ(PIPEDSL(pipe)); - - /* Decode into vertical scanout position. Don't have - * horizontal scanout position. - */ - *vpos = position & 0x1fff; - *hpos = 0; + position = I915_READ(PIPEDSL(pipe)) & 0x1fff; } else { /* Have access to pixelcount since start of frame. * We can split this into vertical and horizontal @@ -635,15 +629,32 @@ static int i915_get_crtc_scanoutpos(struct drm_device *dev, int pipe, */ position = (I915_READ(PIPEFRAMEPIXEL(pipe)) & PIPE_PIXEL_MASK) >> PIPE_PIXEL_SHIFT; - *vpos = position / htotal; - *hpos = position - (*vpos * htotal); + /* convert to pixel counts */ + vbl_start *= htotal; + vbl_end *= htotal; + vtotal *= htotal; } - in_vbl = *vpos >= vbl_start && *vpos < vbl_end; + in_vbl = position >= vbl_start && position < vbl_end; + + /* + * While in vblank, position will be negative + * counting up towards 0 at vbl_end. And outside + * vblank, position will be positive counting + * up since vbl_end. + */ + if (position >= vbl_start) + position -= vbl_end; + else + position += vtotal - vbl_end; - /* Inside "upper part" of vblank area? Apply corrective offset: */ - if (in_vbl && (*vpos >= vbl_start)) - *vpos = *vpos - vtotal; + if (IS_G4X(dev) || INTEL_INFO(dev)->gen >= 5) { + *vpos = position; + *hpos = 0; + } else { + *vpos = position / htotal; + *hpos = position - (*vpos * htotal); + } /* In vblank? */ if (in_vbl) -- cgit v1.2.2 From 54ddcbd26a677524d4bcd9f2a9539e6d743592d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Mon, 23 Sep 2013 13:02:07 +0300 Subject: drm/i915: Improve the accuracy of get_scanout_pos on CTG+ MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The DSL register increments at the start of horizontal sync, so it manages to miss the entire active portion of the current line. Improve the get_scanoutpos accuracy a bit when the scanout position is close to the start or end of vblank. We can do that by double checking the DSL value against the vblank status bit from ISR. Cc: Mario Kleiner Signed-off-by: Ville Syrjälä Reviewed-by: mario.kleiner.de@gmail.com Tested-by: mario.kleiner.de@gmail.com Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_irq.c | 53 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index a923dea245ac..dfa5c68c2763 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -592,6 +592,47 @@ static u32 gm45_get_vblank_counter(struct drm_device *dev, int pipe) return I915_READ(reg); } +static bool g4x_pipe_in_vblank(struct drm_device *dev, enum pipe pipe) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + uint32_t status; + + if (IS_VALLEYVIEW(dev)) { + status = pipe == PIPE_A ? + I915_DISPLAY_PIPE_A_VBLANK_INTERRUPT : + I915_DISPLAY_PIPE_B_VBLANK_INTERRUPT; + + return I915_READ(VLV_ISR) & status; + } else if (IS_G4X(dev)) { + status = pipe == PIPE_A ? + I915_DISPLAY_PIPE_A_VBLANK_INTERRUPT : + I915_DISPLAY_PIPE_B_VBLANK_INTERRUPT; + + return I915_READ(ISR) & status; + } else if (INTEL_INFO(dev)->gen < 7) { + status = pipe == PIPE_A ? + DE_PIPEA_VBLANK : + DE_PIPEB_VBLANK; + + return I915_READ(DEISR) & status; + } else { + switch (pipe) { + default: + case PIPE_A: + status = DE_PIPEA_VBLANK_IVB; + break; + case PIPE_B: + status = DE_PIPEB_VBLANK_IVB; + break; + case PIPE_C: + status = DE_PIPEC_VBLANK_IVB; + break; + } + + return I915_READ(DEISR) & status; + } +} + static int i915_get_crtc_scanoutpos(struct drm_device *dev, int pipe, int *vpos, int *hpos) { @@ -622,6 +663,18 @@ static int i915_get_crtc_scanoutpos(struct drm_device *dev, int pipe, * scanout position from Display scan line register. */ position = I915_READ(PIPEDSL(pipe)) & 0x1fff; + + /* + * The scanline counter increments at the leading edge + * of hsync, ie. it completely misses the active portion + * of the line. Fix up the counter at both edges of vblank + * to get a more accurate picture whether we're in vblank + * or not. + */ + in_vbl = g4x_pipe_in_vblank(dev, pipe); + if ((in_vbl && position == vbl_start - 1) || + (!in_vbl && position == vbl_end - 1)) + position = (position + 1) % vtotal; } else { /* Have access to pixelcount since start of frame. * We can split this into vertical and horizontal -- cgit v1.2.2 From 7c06b08a3073de570f6f0261dae6247cce98f2ab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Fri, 11 Oct 2013 21:52:43 +0300 Subject: drm/i915: Fix gen2 scanout position readout MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Gen2 doesn't have the pixelcount register that gen3 and gen4 have. Instead we must use the scanline counter like we do for ctg+. Signed-off-by: Ville Syrjälä Reviewed-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_irq.c | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index dfa5c68c2763..a7174ac7c5e6 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -592,7 +592,7 @@ static u32 gm45_get_vblank_counter(struct drm_device *dev, int pipe) return I915_READ(reg); } -static bool g4x_pipe_in_vblank(struct drm_device *dev, enum pipe pipe) +static bool intel_pipe_in_vblank(struct drm_device *dev, enum pipe pipe) { struct drm_i915_private *dev_priv = dev->dev_private; uint32_t status; @@ -603,7 +603,13 @@ static bool g4x_pipe_in_vblank(struct drm_device *dev, enum pipe pipe) I915_DISPLAY_PIPE_B_VBLANK_INTERRUPT; return I915_READ(VLV_ISR) & status; - } else if (IS_G4X(dev)) { + } else if (IS_GEN2(dev)) { + status = pipe == PIPE_A ? + I915_DISPLAY_PIPE_A_VBLANK_INTERRUPT : + I915_DISPLAY_PIPE_B_VBLANK_INTERRUPT; + + return I915_READ16(ISR) & status; + } else if (INTEL_INFO(dev)->gen < 5) { status = pipe == PIPE_A ? I915_DISPLAY_PIPE_A_VBLANK_INTERRUPT : I915_DISPLAY_PIPE_B_VBLANK_INTERRUPT; @@ -658,11 +664,14 @@ static int i915_get_crtc_scanoutpos(struct drm_device *dev, int pipe, ret |= DRM_SCANOUTPOS_VALID | DRM_SCANOUTPOS_ACCURATE; - if (IS_G4X(dev) || INTEL_INFO(dev)->gen >= 5) { + if (IS_GEN2(dev) || IS_G4X(dev) || INTEL_INFO(dev)->gen >= 5) { /* No obvious pixelcount register. Only query vertical * scanout position from Display scan line register. */ - position = I915_READ(PIPEDSL(pipe)) & 0x1fff; + if (IS_GEN2(dev)) + position = I915_READ(PIPEDSL(pipe)) & DSL_LINEMASK_GEN2; + else + position = I915_READ(PIPEDSL(pipe)) & DSL_LINEMASK_GEN3; /* * The scanline counter increments at the leading edge @@ -671,7 +680,7 @@ static int i915_get_crtc_scanoutpos(struct drm_device *dev, int pipe, * to get a more accurate picture whether we're in vblank * or not. */ - in_vbl = g4x_pipe_in_vblank(dev, pipe); + in_vbl = intel_pipe_in_vblank(dev, pipe); if ((in_vbl && position == vbl_start - 1) || (!in_vbl && position == vbl_end - 1)) position = (position + 1) % vtotal; @@ -701,7 +710,7 @@ static int i915_get_crtc_scanoutpos(struct drm_device *dev, int pipe, else position += vtotal - vbl_end; - if (IS_G4X(dev) || INTEL_INFO(dev)->gen >= 5) { + if (IS_GEN2(dev) || IS_G4X(dev) || INTEL_INFO(dev)->gen >= 5) { *vpos = position; *hpos = 0; } else { -- cgit v1.2.2 From 4cdb83ec9a72f741c75e20c8e412c505fc037f5f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Fri, 11 Oct 2013 21:52:44 +0300 Subject: drm/i915: Don't pretend that gen2 has a hardware frame counter MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Gen2 doesn't have a hardware frame counter that can be read out. Just provide a stub .get_vblank_counter() that always returns 0 instead of trying to read non-existing registers. Signed-off-by: Ville Syrjälä Reviewed-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_irq.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index a7174ac7c5e6..26753b6ac0a1 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -518,6 +518,12 @@ i915_pipe_enabled(struct drm_device *dev, int pipe) } } +static u32 i8xx_get_vblank_counter(struct drm_device *dev, int pipe) +{ + /* Gen2 doesn't have a hardware frame counter */ + return 0; +} + /* Called from drm generic code, passed a 'crtc', which * we use as a pipe index */ @@ -3245,7 +3251,10 @@ void intel_irq_init(struct drm_device *dev) pm_qos_add_request(&dev_priv->pm_qos, PM_QOS_CPU_DMA_LATENCY, PM_QOS_DEFAULT_VALUE); - if (IS_G4X(dev) || INTEL_INFO(dev)->gen >= 5) { + if (IS_GEN2(dev)) { + dev->max_vblank_count = 0; + dev->driver->get_vblank_counter = i8xx_get_vblank_counter; + } else if (IS_G4X(dev) || INTEL_INFO(dev)->gen >= 5) { dev->max_vblank_count = 0xffffffff; /* full 32 bit counter */ dev->driver->get_vblank_counter = gm45_get_vblank_counter; } else { -- cgit v1.2.2 From 0301b3ac38708003a46f5b8ece1103ba6dc23f7c Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Tue, 15 Oct 2013 09:36:08 +0300 Subject: drm/i915/dp: constify link_status MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Follow-up to commit 0aec288130713cf7bcf97c929ac5fab6a8e00e44 Author: Jani Nikula Date: Fri Sep 27 19:01:01 2013 +0300 drm/dp: constify DP DPCD helpers Requested-by: Ville Syrjälä Signed-off-by: Jani Nikula Reviewed-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_dp.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index bee09e16725c..7ee9210e6133 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -2095,7 +2095,8 @@ static uint32_t intel_vlv_signal_levels(struct intel_dp *intel_dp) } static void -intel_get_adjust_train(struct intel_dp *intel_dp, uint8_t link_status[DP_LINK_STATUS_SIZE]) +intel_get_adjust_train(struct intel_dp *intel_dp, + const uint8_t link_status[DP_LINK_STATUS_SIZE]) { uint8_t v = 0; uint8_t p = 0; @@ -2396,7 +2397,7 @@ intel_dp_reset_link_train(struct intel_dp *intel_dp, uint32_t *DP, static bool intel_dp_update_link_train(struct intel_dp *intel_dp, uint32_t *DP, - uint8_t link_status[DP_LINK_STATUS_SIZE]) + const uint8_t link_status[DP_LINK_STATUS_SIZE]) { struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp); struct drm_device *dev = intel_dig_port->base.base.dev; -- cgit v1.2.2 From 0b2ae6d72e445b58ae39cfa6ec0b8d3f53ff7a6f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Wed, 9 Oct 2013 19:17:55 +0300 Subject: drm/i915: Add intel_pipe_wm and prepare for watermark pre-compute MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Introduce a new struct intel_pipe_wm which contains all the watermarks for a single pipe. Use it to unify the LP0 and LP1+ watermark computations so that we can just iterate through the watermark levels neatly and call ilk_compute_wm_level() for each. Also add another tool ilk_wm_merge() that merges the LP1+ watermarks from all pipes. For that, embed one intel_pipe_wm inside intel_crtc that contains the currently valid watermarks for each pipe. This is mainly preparatory work for pre-computing the watermarks for each pipe and merging them at a later time. For now the merging still happens immediately. v2: Add some comments about level 0 DDB split and intel_wm_config Add WARN_ON for level 0 being disabled s/lp_wm/merged Signed-off-by: Ville Syrjälä Reviewed-by: Paulo Zanoni Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_drv.h | 12 +++ drivers/gpu/drm/i915/intel_pm.c | 192 +++++++++++++++++++++++---------------- 2 files changed, 128 insertions(+), 76 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 189257df7a0f..5d5d34911a7e 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -309,6 +309,12 @@ struct intel_crtc_config { bool double_wide; }; +struct intel_pipe_wm { + struct intel_wm_level wm[5]; + uint32_t linetime; + bool fbc_wm_enabled; +}; + struct intel_crtc { struct drm_crtc base; enum pipe pipe; @@ -349,6 +355,12 @@ struct intel_crtc { /* Access to these should be protected by dev_priv->irq_lock. */ bool cpu_fifo_underrun_disabled; bool pch_fifo_underrun_disabled; + + /* per-pipe watermark state */ + struct { + /* watermarks currently being used */ + struct intel_pipe_wm active; + } wm; }; struct intel_plane_wm_parameters { diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index ca3dd566974a..3e1b50359afb 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -2458,53 +2458,6 @@ static void ilk_compute_wm_level(struct drm_i915_private *dev_priv, result->enable = true; } -static bool hsw_compute_lp_wm(struct drm_i915_private *dev_priv, - int level, const struct hsw_wm_maximums *max, - const struct hsw_pipe_wm_parameters *params, - struct intel_wm_level *result) -{ - enum pipe pipe; - struct intel_wm_level res[3]; - - for (pipe = PIPE_A; pipe <= PIPE_C; pipe++) - ilk_compute_wm_level(dev_priv, level, ¶ms[pipe], &res[pipe]); - - result->pri_val = max3(res[0].pri_val, res[1].pri_val, res[2].pri_val); - result->spr_val = max3(res[0].spr_val, res[1].spr_val, res[2].spr_val); - result->cur_val = max3(res[0].cur_val, res[1].cur_val, res[2].cur_val); - result->fbc_val = max3(res[0].fbc_val, res[1].fbc_val, res[2].fbc_val); - result->enable = true; - - return ilk_check_wm(level, max, result); -} - - -static uint32_t hsw_compute_wm_pipe(struct drm_device *dev, - const struct hsw_pipe_wm_parameters *params) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - struct intel_wm_config config = { - .num_pipes_active = 1, - .sprites_enabled = params->spr.enabled, - .sprites_scaled = params->spr.scaled, - }; - struct hsw_wm_maximums max; - struct intel_wm_level res; - - if (!params->active) - return 0; - - ilk_wm_max(dev, 0, &config, INTEL_DDB_PART_1_2, &max); - - ilk_compute_wm_level(dev_priv, 0, params, &res); - - ilk_check_wm(0, &max, &res); - - return (res.pri_val << WM0_PIPE_PLANE_SHIFT) | - (res.spr_val << WM0_PIPE_SPRITE_SHIFT) | - res.cur_val; -} - static uint32_t hsw_compute_linetime_wm(struct drm_device *dev, struct drm_crtc *crtc) { @@ -2687,44 +2640,123 @@ static void hsw_compute_wm_parameters(struct drm_device *dev, *lp_max_5_6 = *lp_max_1_2; } +/* Compute new watermarks for the pipe */ +static bool intel_compute_pipe_wm(struct drm_crtc *crtc, + const struct hsw_pipe_wm_parameters *params, + struct intel_pipe_wm *pipe_wm) +{ + struct drm_device *dev = crtc->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + int level, max_level = ilk_wm_max_level(dev); + /* LP0 watermark maximums depend on this pipe alone */ + struct intel_wm_config config = { + .num_pipes_active = 1, + .sprites_enabled = params->spr.enabled, + .sprites_scaled = params->spr.scaled, + }; + struct hsw_wm_maximums max; + + memset(pipe_wm, 0, sizeof(*pipe_wm)); + + /* LP0 watermarks always use 1/2 DDB partitioning */ + ilk_wm_max(dev, 0, &config, INTEL_DDB_PART_1_2, &max); + + for (level = 0; level <= max_level; level++) + ilk_compute_wm_level(dev_priv, level, params, + &pipe_wm->wm[level]); + + pipe_wm->linetime = hsw_compute_linetime_wm(dev, crtc); + + /* At least LP0 must be valid */ + return ilk_check_wm(0, &max, &pipe_wm->wm[0]); +} + +/* + * Merge the watermarks from all active pipes for a specific level. + */ +static void ilk_merge_wm_level(struct drm_device *dev, + int level, + struct intel_wm_level *ret_wm) +{ + const struct intel_crtc *intel_crtc; + + list_for_each_entry(intel_crtc, &dev->mode_config.crtc_list, base.head) { + const struct intel_wm_level *wm = + &intel_crtc->wm.active.wm[level]; + + if (!wm->enable) + return; + + ret_wm->pri_val = max(ret_wm->pri_val, wm->pri_val); + ret_wm->spr_val = max(ret_wm->spr_val, wm->spr_val); + ret_wm->cur_val = max(ret_wm->cur_val, wm->cur_val); + ret_wm->fbc_val = max(ret_wm->fbc_val, wm->fbc_val); + } + + ret_wm->enable = true; +} + +/* + * Merge all low power watermarks for all active pipes. + */ +static void ilk_wm_merge(struct drm_device *dev, + const struct hsw_wm_maximums *max, + struct intel_pipe_wm *merged) +{ + int level, max_level = ilk_wm_max_level(dev); + + merged->fbc_wm_enabled = true; + + /* merge each WM1+ level */ + for (level = 1; level <= max_level; level++) { + struct intel_wm_level *wm = &merged->wm[level]; + + ilk_merge_wm_level(dev, level, wm); + + if (!ilk_check_wm(level, max, wm)) + break; + + /* + * The spec says it is preferred to disable + * FBC WMs instead of disabling a WM level. + */ + if (wm->fbc_val > max->fbc) { + merged->fbc_wm_enabled = false; + wm->fbc_val = 0; + } + } +} + static void hsw_compute_wm_results(struct drm_device *dev, const struct hsw_pipe_wm_parameters *params, const struct hsw_wm_maximums *lp_maximums, struct hsw_wm_values *results) { - struct drm_i915_private *dev_priv = dev->dev_private; - struct drm_crtc *crtc; - struct intel_wm_level lp_results[4] = {}; - enum pipe pipe; - int level, max_level, wm_lp; + struct intel_crtc *intel_crtc; + int level, wm_lp; + struct intel_pipe_wm merged = {}; - for (level = 1; level <= 4; level++) - if (!hsw_compute_lp_wm(dev_priv, level, - lp_maximums, params, - &lp_results[level - 1])) - break; - max_level = level - 1; + list_for_each_entry(intel_crtc, &dev->mode_config.crtc_list, base.head) + intel_compute_pipe_wm(&intel_crtc->base, + ¶ms[intel_crtc->pipe], + &intel_crtc->wm.active); + + ilk_wm_merge(dev, lp_maximums, &merged); memset(results, 0, sizeof(*results)); - /* The spec says it is preferred to disable FBC WMs instead of disabling - * a WM level. */ - results->enable_fbc_wm = true; - for (level = 1; level <= max_level; level++) { - if (lp_results[level - 1].fbc_val > lp_maximums->fbc) { - results->enable_fbc_wm = false; - lp_results[level - 1].fbc_val = 0; - } - } + results->enable_fbc_wm = merged.fbc_wm_enabled; + /* LP1+ register values */ for (wm_lp = 1; wm_lp <= 3; wm_lp++) { const struct intel_wm_level *r; - level = (max_level == 4 && wm_lp > 1) ? wm_lp + 1 : wm_lp; - if (level > max_level) + level = wm_lp + (wm_lp >= 2 && merged.wm[4].enable); + + r = &merged.wm[level]; + if (!r->enable) break; - r = &lp_results[level - 1]; results->wm_lp[wm_lp - 1] = HSW_WM_LP_VAL(level * 2, r->fbc_val, r->pri_val, @@ -2732,13 +2764,21 @@ static void hsw_compute_wm_results(struct drm_device *dev, results->wm_lp_spr[wm_lp - 1] = r->spr_val; } - for_each_pipe(pipe) - results->wm_pipe[pipe] = hsw_compute_wm_pipe(dev, - ¶ms[pipe]); + /* LP0 register values */ + list_for_each_entry(intel_crtc, &dev->mode_config.crtc_list, base.head) { + enum pipe pipe = intel_crtc->pipe; + const struct intel_wm_level *r = + &intel_crtc->wm.active.wm[0]; - for_each_pipe(pipe) { - crtc = dev_priv->pipe_to_crtc_mapping[pipe]; - results->wm_linetime[pipe] = hsw_compute_linetime_wm(dev, crtc); + if (WARN_ON(!r->enable)) + continue; + + results->wm_linetime[pipe] = intel_crtc->wm.active.linetime; + + results->wm_pipe[pipe] = + (r->pri_val << WM0_PIPE_PLANE_SHIFT) | + (r->spr_val << WM0_PIPE_SPRITE_SHIFT) | + r->cur_val; } } -- cgit v1.2.2 From 7c4a395ff8f441acb7876281c6777624e6410349 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Wed, 9 Oct 2013 19:17:56 +0300 Subject: drm/i915: Don't re-compute pipe watermarks except for the affected pipe MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit No point in re-computing the watermarks for all pipes, when only one pipe has changed. The watermarks stored under intel_crtc.wm.active are still valid for the other pipes. We just need to redo the merging. We can also skip the merge/update procedure completely if the new watermarks for the affected pipe come out unchanged. Signed-off-by: Ville Syrjälä Reviewed-by: Paulo Zanoni Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_pm.c | 67 +++++++++++++++++------------------------ 1 file changed, 28 insertions(+), 39 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 3e1b50359afb..3699f1d574c5 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -2584,29 +2584,19 @@ static void intel_setup_wm_latency(struct drm_device *dev) intel_print_wm_latency(dev, "Cursor", dev_priv->wm.cur_latency); } -static void hsw_compute_wm_parameters(struct drm_device *dev, - struct hsw_pipe_wm_parameters *params, +static void hsw_compute_wm_parameters(struct drm_crtc *crtc, + struct hsw_pipe_wm_parameters *p, struct hsw_wm_maximums *lp_max_1_2, struct hsw_wm_maximums *lp_max_5_6) { - struct drm_crtc *crtc; - struct drm_plane *plane; - enum pipe pipe; + struct drm_device *dev = crtc->dev; + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + enum pipe pipe = intel_crtc->pipe; struct intel_wm_config config = {}; + struct drm_plane *plane; - list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { - struct intel_crtc *intel_crtc = to_intel_crtc(crtc); - struct hsw_pipe_wm_parameters *p; - - pipe = intel_crtc->pipe; - p = ¶ms[pipe]; - - p->active = intel_crtc_active(crtc); - if (!p->active) - continue; - - config.num_pipes_active++; - + p->active = intel_crtc_active(crtc); + if (p->active) { p->pipe_htotal = intel_crtc->config.adjusted_mode.htotal; p->pixel_rate = ilk_pipe_pixel_rate(dev, crtc); p->pri.bytes_per_pixel = crtc->fb->bits_per_pixel / 8; @@ -2618,17 +2608,17 @@ static void hsw_compute_wm_parameters(struct drm_device *dev, p->cur.enabled = true; } + list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) + config.num_pipes_active += intel_crtc_active(crtc); + list_for_each_entry(plane, &dev->mode_config.plane_list, head) { struct intel_plane *intel_plane = to_intel_plane(plane); - struct hsw_pipe_wm_parameters *p; - - pipe = intel_plane->pipe; - p = ¶ms[pipe]; - p->spr = intel_plane->wm; + if (intel_plane->pipe == pipe) + p->spr = intel_plane->wm; - config.sprites_enabled |= p->spr.enabled; - config.sprites_scaled |= p->spr.scaled; + config.sprites_enabled |= intel_plane->wm.enabled; + config.sprites_scaled |= intel_plane->wm.scaled; } ilk_wm_max(dev, 1, &config, INTEL_DDB_PART_1_2, lp_max_1_2); @@ -2656,8 +2646,6 @@ static bool intel_compute_pipe_wm(struct drm_crtc *crtc, }; struct hsw_wm_maximums max; - memset(pipe_wm, 0, sizeof(*pipe_wm)); - /* LP0 watermarks always use 1/2 DDB partitioning */ ilk_wm_max(dev, 0, &config, INTEL_DDB_PART_1_2, &max); @@ -2728,7 +2716,6 @@ static void ilk_wm_merge(struct drm_device *dev, } static void hsw_compute_wm_results(struct drm_device *dev, - const struct hsw_pipe_wm_parameters *params, const struct hsw_wm_maximums *lp_maximums, struct hsw_wm_values *results) { @@ -2736,11 +2723,6 @@ static void hsw_compute_wm_results(struct drm_device *dev, int level, wm_lp; struct intel_pipe_wm merged = {}; - list_for_each_entry(intel_crtc, &dev->mode_config.crtc_list, base.head) - intel_compute_pipe_wm(&intel_crtc->base, - ¶ms[intel_crtc->pipe], - &intel_crtc->wm.active); - ilk_wm_merge(dev, lp_maximums, &merged); memset(results, 0, sizeof(*results)); @@ -2907,20 +2889,27 @@ static void hsw_write_wm_values(struct drm_i915_private *dev_priv, static void haswell_update_wm(struct drm_crtc *crtc) { + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); struct drm_device *dev = crtc->dev; struct drm_i915_private *dev_priv = dev->dev_private; struct hsw_wm_maximums lp_max_1_2, lp_max_5_6; - struct hsw_pipe_wm_parameters params[3]; + struct hsw_pipe_wm_parameters params = {}; struct hsw_wm_values results_1_2, results_5_6, *best_results; enum intel_ddb_partitioning partitioning; + struct intel_pipe_wm pipe_wm = {}; + + hsw_compute_wm_parameters(crtc, ¶ms, &lp_max_1_2, &lp_max_5_6); + + intel_compute_pipe_wm(crtc, ¶ms, &pipe_wm); + + if (!memcmp(&intel_crtc->wm.active, &pipe_wm, sizeof(pipe_wm))) + return; - hsw_compute_wm_parameters(dev, params, &lp_max_1_2, &lp_max_5_6); + intel_crtc->wm.active = pipe_wm; - hsw_compute_wm_results(dev, params, - &lp_max_1_2, &results_1_2); + hsw_compute_wm_results(dev, &lp_max_1_2, &results_1_2); if (lp_max_1_2.pri != lp_max_5_6.pri) { - hsw_compute_wm_results(dev, params, - &lp_max_5_6, &results_5_6); + hsw_compute_wm_results(dev, &lp_max_5_6, &results_5_6); best_results = hsw_find_best_result(&results_1_2, &results_5_6); } else { best_results = &results_1_2; -- cgit v1.2.2 From 0362c7816c8ad5d838ecd93f5526c1c725a1a8fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Wed, 9 Oct 2013 19:17:57 +0300 Subject: drm/i915: Move LP1+ watermark merging out from hsw_compute_wm_results() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit I want to convert hsw_find_best_result() to use intel_pipe_wm, so we need to move the merging to happen outside hsw_compute_wm_results(). Signed-off-by: Ville Syrjälä Reviewed-by: Paulo Zanoni Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_pm.c | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 3699f1d574c5..71524ae0f07a 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -2716,26 +2716,23 @@ static void ilk_wm_merge(struct drm_device *dev, } static void hsw_compute_wm_results(struct drm_device *dev, - const struct hsw_wm_maximums *lp_maximums, + const struct intel_pipe_wm *merged, struct hsw_wm_values *results) { struct intel_crtc *intel_crtc; int level, wm_lp; - struct intel_pipe_wm merged = {}; - - ilk_wm_merge(dev, lp_maximums, &merged); memset(results, 0, sizeof(*results)); - results->enable_fbc_wm = merged.fbc_wm_enabled; + results->enable_fbc_wm = merged->fbc_wm_enabled; /* LP1+ register values */ for (wm_lp = 1; wm_lp <= 3; wm_lp++) { const struct intel_wm_level *r; - level = wm_lp + (wm_lp >= 2 && merged.wm[4].enable); + level = wm_lp + (wm_lp >= 2 && merged->wm[4].enable); - r = &merged.wm[level]; + r = &merged->wm[level]; if (!r->enable) break; @@ -2897,6 +2894,7 @@ static void haswell_update_wm(struct drm_crtc *crtc) struct hsw_wm_values results_1_2, results_5_6, *best_results; enum intel_ddb_partitioning partitioning; struct intel_pipe_wm pipe_wm = {}; + struct intel_pipe_wm lp_wm_1_2 = {}, lp_wm_5_6 = {}; hsw_compute_wm_parameters(crtc, ¶ms, &lp_max_1_2, &lp_max_5_6); @@ -2907,9 +2905,12 @@ static void haswell_update_wm(struct drm_crtc *crtc) intel_crtc->wm.active = pipe_wm; - hsw_compute_wm_results(dev, &lp_max_1_2, &results_1_2); + ilk_wm_merge(dev, &lp_max_1_2, &lp_wm_1_2); + ilk_wm_merge(dev, &lp_max_5_6, &lp_wm_5_6); + + hsw_compute_wm_results(dev, &lp_wm_1_2, &results_1_2); if (lp_max_1_2.pri != lp_max_5_6.pri) { - hsw_compute_wm_results(dev, &lp_max_5_6, &results_5_6); + hsw_compute_wm_results(dev, &lp_wm_5_6, &results_5_6); best_results = hsw_find_best_result(&results_1_2, &results_5_6); } else { best_results = &results_1_2; -- cgit v1.2.2 From 198a1e9b1822099f60945a6c46b1f59727347817 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Wed, 9 Oct 2013 19:17:58 +0300 Subject: drm/i915: Use intel_pipe_wm in hsw_find_best_results MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Let's try to keep using the intermediate intel_pipe_wm representation for as long as possible. It avoids subtle knowledge about the internals of the hardware registers when trying to choose the best watermark configuration. While at it replace the memset() w/ zero initialization. Signed-off-by: Ville Syrjälä Reviewed-by: Paulo Zanoni Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_pm.c | 42 ++++++++++++++++++++--------------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 71524ae0f07a..91147722ee75 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -2722,8 +2722,6 @@ static void hsw_compute_wm_results(struct drm_device *dev, struct intel_crtc *intel_crtc; int level, wm_lp; - memset(results, 0, sizeof(*results)); - results->enable_fbc_wm = merged->fbc_wm_enabled; /* LP1+ register values */ @@ -2763,24 +2761,26 @@ static void hsw_compute_wm_results(struct drm_device *dev, /* Find the result with the highest level enabled. Check for enable_fbc_wm in * case both are at the same level. Prefer r1 in case they're the same. */ -static struct hsw_wm_values *hsw_find_best_result(struct hsw_wm_values *r1, - struct hsw_wm_values *r2) +static struct intel_pipe_wm *hsw_find_best_result(struct drm_device *dev, + struct intel_pipe_wm *r1, + struct intel_pipe_wm *r2) { - int i, val_r1 = 0, val_r2 = 0; + int level, max_level = ilk_wm_max_level(dev); + int level1 = 0, level2 = 0; - for (i = 0; i < 3; i++) { - if (r1->wm_lp[i] & WM3_LP_EN) - val_r1 = r1->wm_lp[i] & WM1_LP_LATENCY_MASK; - if (r2->wm_lp[i] & WM3_LP_EN) - val_r2 = r2->wm_lp[i] & WM1_LP_LATENCY_MASK; + for (level = 1; level <= max_level; level++) { + if (r1->wm[level].enable) + level1 = level; + if (r2->wm[level].enable) + level2 = level; } - if (val_r1 == val_r2) { - if (r2->enable_fbc_wm && !r1->enable_fbc_wm) + if (level1 == level2) { + if (r2->fbc_wm_enabled && !r1->fbc_wm_enabled) return r2; else return r1; - } else if (val_r1 > val_r2) { + } else if (level1 > level2) { return r1; } else { return r2; @@ -2891,10 +2891,10 @@ static void haswell_update_wm(struct drm_crtc *crtc) struct drm_i915_private *dev_priv = dev->dev_private; struct hsw_wm_maximums lp_max_1_2, lp_max_5_6; struct hsw_pipe_wm_parameters params = {}; - struct hsw_wm_values results_1_2, results_5_6, *best_results; + struct hsw_wm_values results = {}; enum intel_ddb_partitioning partitioning; struct intel_pipe_wm pipe_wm = {}; - struct intel_pipe_wm lp_wm_1_2 = {}, lp_wm_5_6 = {}; + struct intel_pipe_wm lp_wm_1_2 = {}, lp_wm_5_6 = {}, *best_lp_wm; hsw_compute_wm_parameters(crtc, ¶ms, &lp_max_1_2, &lp_max_5_6); @@ -2908,18 +2908,18 @@ static void haswell_update_wm(struct drm_crtc *crtc) ilk_wm_merge(dev, &lp_max_1_2, &lp_wm_1_2); ilk_wm_merge(dev, &lp_max_5_6, &lp_wm_5_6); - hsw_compute_wm_results(dev, &lp_wm_1_2, &results_1_2); if (lp_max_1_2.pri != lp_max_5_6.pri) { - hsw_compute_wm_results(dev, &lp_wm_5_6, &results_5_6); - best_results = hsw_find_best_result(&results_1_2, &results_5_6); + best_lp_wm = hsw_find_best_result(dev, &lp_wm_1_2, &lp_wm_5_6); } else { - best_results = &results_1_2; + best_lp_wm = &lp_wm_1_2; } - partitioning = (best_results == &results_1_2) ? + hsw_compute_wm_results(dev, best_lp_wm, &results); + + partitioning = (best_lp_wm == &lp_wm_1_2) ? INTEL_DDB_PART_1_2 : INTEL_DDB_PART_5_6; - hsw_write_wm_values(dev_priv, best_results, partitioning); + hsw_write_wm_values(dev_priv, &results, partitioning); } static void haswell_update_sprite_wm(struct drm_plane *plane, -- cgit v1.2.2 From a485bfb8d0d70ba24662aab5e00b2914c646220b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Wed, 9 Oct 2013 19:17:59 +0300 Subject: drm/i915: Move some computations out from hsw_compute_wm_parameters() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Move the watermark max computations into haswell_update_wm(). This allows keeping the 1/2 vs. 5/6 split code in one place, and avoid having to pass around so many things. We also save a bit of stack space by only requiring one copy of struct hsw_wm_maximums. Also move the intel_wm_config out from hsw_compute_wm_parameters() and pass it it. We'll have some need for it in haswell_update_wm() later. Signed-off-by: Ville Syrjälä Reviewed-by: Paulo Zanoni Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_pm.c | 33 ++++++++++++++------------------- 1 file changed, 14 insertions(+), 19 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 91147722ee75..3d3f1134f16b 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -2586,13 +2586,11 @@ static void intel_setup_wm_latency(struct drm_device *dev) static void hsw_compute_wm_parameters(struct drm_crtc *crtc, struct hsw_pipe_wm_parameters *p, - struct hsw_wm_maximums *lp_max_1_2, - struct hsw_wm_maximums *lp_max_5_6) + struct intel_wm_config *config) { struct drm_device *dev = crtc->dev; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); enum pipe pipe = intel_crtc->pipe; - struct intel_wm_config config = {}; struct drm_plane *plane; p->active = intel_crtc_active(crtc); @@ -2609,7 +2607,7 @@ static void hsw_compute_wm_parameters(struct drm_crtc *crtc, } list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) - config.num_pipes_active += intel_crtc_active(crtc); + config->num_pipes_active += intel_crtc_active(crtc); list_for_each_entry(plane, &dev->mode_config.plane_list, head) { struct intel_plane *intel_plane = to_intel_plane(plane); @@ -2617,17 +2615,9 @@ static void hsw_compute_wm_parameters(struct drm_crtc *crtc, if (intel_plane->pipe == pipe) p->spr = intel_plane->wm; - config.sprites_enabled |= intel_plane->wm.enabled; - config.sprites_scaled |= intel_plane->wm.scaled; + config->sprites_enabled |= intel_plane->wm.enabled; + config->sprites_scaled |= intel_plane->wm.scaled; } - - ilk_wm_max(dev, 1, &config, INTEL_DDB_PART_1_2, lp_max_1_2); - - /* 5/6 split only in single pipe config on IVB+ */ - if (INTEL_INFO(dev)->gen >= 7 && config.num_pipes_active <= 1) - ilk_wm_max(dev, 1, &config, INTEL_DDB_PART_5_6, lp_max_5_6); - else - *lp_max_5_6 = *lp_max_1_2; } /* Compute new watermarks for the pipe */ @@ -2889,14 +2879,15 @@ static void haswell_update_wm(struct drm_crtc *crtc) struct intel_crtc *intel_crtc = to_intel_crtc(crtc); struct drm_device *dev = crtc->dev; struct drm_i915_private *dev_priv = dev->dev_private; - struct hsw_wm_maximums lp_max_1_2, lp_max_5_6; + struct hsw_wm_maximums max; struct hsw_pipe_wm_parameters params = {}; struct hsw_wm_values results = {}; enum intel_ddb_partitioning partitioning; struct intel_pipe_wm pipe_wm = {}; struct intel_pipe_wm lp_wm_1_2 = {}, lp_wm_5_6 = {}, *best_lp_wm; + struct intel_wm_config config = {}; - hsw_compute_wm_parameters(crtc, ¶ms, &lp_max_1_2, &lp_max_5_6); + hsw_compute_wm_parameters(crtc, ¶ms, &config); intel_compute_pipe_wm(crtc, ¶ms, &pipe_wm); @@ -2905,10 +2896,14 @@ static void haswell_update_wm(struct drm_crtc *crtc) intel_crtc->wm.active = pipe_wm; - ilk_wm_merge(dev, &lp_max_1_2, &lp_wm_1_2); - ilk_wm_merge(dev, &lp_max_5_6, &lp_wm_5_6); + ilk_wm_max(dev, 1, &config, INTEL_DDB_PART_1_2, &max); + ilk_wm_merge(dev, &max, &lp_wm_1_2); + + /* 5/6 split only in single pipe config on IVB+ */ + if (INTEL_INFO(dev)->gen >= 7 && config.num_pipes_active <= 1) { + ilk_wm_max(dev, 1, &config, INTEL_DDB_PART_5_6, &max); + ilk_wm_merge(dev, &max, &lp_wm_5_6); - if (lp_max_1_2.pri != lp_max_5_6.pri) { best_lp_wm = hsw_find_best_result(dev, &lp_wm_1_2, &lp_wm_5_6); } else { best_lp_wm = &lp_wm_1_2; -- cgit v1.2.2 From a5db6b62577b14a9fbe639af0aba9ec7ae85ae3e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Fri, 11 Oct 2013 15:26:26 +0300 Subject: drm/i915: Check 5/6 DDB split only when sprites are enabled MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Using the 5/6 DDB split make sense only when sprites are enabled. So check that before we waste any cycles computing the merged watermarks with the 5/6 DDB split. Signed-off-by: Ville Syrjälä Reviewed-by: Paulo Zanoni Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_pm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 3d3f1134f16b..a5503cd7a1c8 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -2900,7 +2900,7 @@ static void haswell_update_wm(struct drm_crtc *crtc) ilk_wm_merge(dev, &max, &lp_wm_1_2); /* 5/6 split only in single pipe config on IVB+ */ - if (INTEL_INFO(dev)->gen >= 7 && config.num_pipes_active <= 1) { + if (INTEL_INFO(dev)->gen >= 7 && config.num_pipes_active == 1) { ilk_wm_max(dev, 1, &config, INTEL_DDB_PART_5_6, &max); ilk_wm_merge(dev, &max, &lp_wm_5_6); -- cgit v1.2.2 From b380ca3caa821150fddab0052dcce624d18e88ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Wed, 9 Oct 2013 19:18:01 +0300 Subject: drm/i915: Refactor wm_lp to level calculation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On HSW the LP1,LP2,LP3 levels are either 1,2,3 or 1,3,4. We make the conversion from LPn to to the level at one point current. Later we're going to do it in a few places, so move it to a separate function. Signed-off-by: Ville Syrjälä Reviewed-by: Paulo Zanoni 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 a5503cd7a1c8..9f33e37f8a2d 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -2705,6 +2705,12 @@ static void ilk_wm_merge(struct drm_device *dev, } } +static int ilk_wm_lp_to_level(int wm_lp, const struct intel_pipe_wm *pipe_wm) +{ + /* LP1,LP2,LP3 levels are either 1,2,3 or 1,3,4 */ + return wm_lp + (wm_lp >= 2 && pipe_wm->wm[4].enable); +} + static void hsw_compute_wm_results(struct drm_device *dev, const struct intel_pipe_wm *merged, struct hsw_wm_values *results) @@ -2718,7 +2724,7 @@ static void hsw_compute_wm_results(struct drm_device *dev, for (wm_lp = 1; wm_lp <= 3; wm_lp++) { const struct intel_wm_level *r; - level = wm_lp + (wm_lp >= 2 && merged->wm[4].enable); + level = ilk_wm_lp_to_level(wm_lp, merged); r = &merged->wm[level]; if (!r->enable) -- cgit v1.2.2 From 7eaa4d56107dac87946f3b45faf37bc831f8de83 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Wed, 9 Oct 2013 19:18:02 +0300 Subject: drm/i915: Kill fbc_wm_enabled from intel_wm_config MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The fbc_wm_enabled member in intel_wm_config is useless for the time being. The original idea for it was that we'd pre-compute it and so that the WM merging process could know whether it needs to worry about FBC watermarks at all. But we don't have a convenient way to pre-check for the possibility of FBC being used. intel_update_fbc() should be split up for that. Signed-off-by: Ville Syrjälä Reviewed-by: Paulo Zanoni Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_pm.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 9f33e37f8a2d..abea03c1e480 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -2213,7 +2213,6 @@ struct intel_wm_config { unsigned int num_pipes_active; bool sprites_enabled; bool sprites_scaled; - bool fbc_wm_enabled; }; /* -- cgit v1.2.2 From 609cedef6a9d5d90574903c71e81bd1c1f311f06 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Wed, 9 Oct 2013 19:18:03 +0300 Subject: drm/i915: Store current watermark state in dev_priv->wm MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit To make it easier to check what watermark updates are actually necessary, keep copies of the relevant bits that match the current hardware state. Also add DDB partitioning into hsw_wm_values as that's another piece of state we want to track. We don't read out the hardware state on init yet, so we can't really start using this yet, but it will be used later. Signed-off-by: Ville Syrjälä Reviewed-by: Paulo Zanoni [danvet: Paulo asked for a comment around the memcmp to say that we depend upon zero-initializing the entire structures due to padding. But a later patch in this series removes the memcmp again. So this is ok as-is.] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 12 +++++++++++ drivers/gpu/drm/i915/intel_pm.c | 46 ++++++++++++++--------------------------- 2 files changed, 27 insertions(+), 31 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 2ea66f23c2be..6106d3d710c5 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1141,6 +1141,15 @@ struct intel_wm_level { uint32_t fbc_val; }; +struct hsw_wm_values { + uint32_t wm_pipe[3]; + uint32_t wm_lp[3]; + uint32_t wm_lp_spr[3]; + uint32_t wm_linetime[3]; + bool enable_fbc_wm; + enum intel_ddb_partitioning partitioning; +}; + /* * This struct tracks the state needed for the Package C8+ feature. * @@ -1402,6 +1411,9 @@ typedef struct drm_i915_private { uint16_t spr_latency[5]; /* cursor */ uint16_t cur_latency[5]; + + /* current hardware state */ + struct hsw_wm_values hw; } wm; struct i915_package_c8 pc8; diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index abea03c1e480..6d3d5f62dd6b 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -2200,14 +2200,6 @@ struct hsw_wm_maximums { uint16_t fbc; }; -struct hsw_wm_values { - uint32_t wm_pipe[3]; - uint32_t wm_lp[3]; - uint32_t wm_lp_spr[3]; - uint32_t wm_linetime[3]; - bool enable_fbc_wm; -}; - /* used in computing the new watermarks state */ struct intel_wm_config { unsigned int num_pipes_active; @@ -2712,12 +2704,14 @@ static int ilk_wm_lp_to_level(int wm_lp, const struct intel_pipe_wm *pipe_wm) static void hsw_compute_wm_results(struct drm_device *dev, const struct intel_pipe_wm *merged, + enum intel_ddb_partitioning partitioning, struct hsw_wm_values *results) { struct intel_crtc *intel_crtc; int level, wm_lp; results->enable_fbc_wm = merged->fbc_wm_enabled; + results->partitioning = partitioning; /* LP1+ register values */ for (wm_lp = 1; wm_lp <= 3; wm_lp++) { @@ -2787,13 +2781,10 @@ static struct intel_pipe_wm *hsw_find_best_result(struct drm_device *dev, * causes WMs to be re-evaluated, expending some power. */ static void hsw_write_wm_values(struct drm_i915_private *dev_priv, - struct hsw_wm_values *results, - enum intel_ddb_partitioning partitioning) + struct hsw_wm_values *results) { struct hsw_wm_values previous; uint32_t val; - enum intel_ddb_partitioning prev_partitioning; - bool prev_enable_fbc_wm; previous.wm_pipe[0] = I915_READ(WM0_PIPEA_ILK); previous.wm_pipe[1] = I915_READ(WM0_PIPEB_ILK); @@ -2808,21 +2799,12 @@ static void hsw_write_wm_values(struct drm_i915_private *dev_priv, previous.wm_linetime[1] = I915_READ(PIPE_WM_LINETIME(PIPE_B)); previous.wm_linetime[2] = I915_READ(PIPE_WM_LINETIME(PIPE_C)); - prev_partitioning = (I915_READ(WM_MISC) & WM_MISC_DATA_PARTITION_5_6) ? + previous.partitioning = (I915_READ(WM_MISC) & WM_MISC_DATA_PARTITION_5_6) ? INTEL_DDB_PART_5_6 : INTEL_DDB_PART_1_2; - prev_enable_fbc_wm = !(I915_READ(DISP_ARB_CTL) & DISP_FBC_WM_DIS); - - if (memcmp(results->wm_pipe, previous.wm_pipe, - sizeof(results->wm_pipe)) == 0 && - memcmp(results->wm_lp, previous.wm_lp, - sizeof(results->wm_lp)) == 0 && - memcmp(results->wm_lp_spr, previous.wm_lp_spr, - sizeof(results->wm_lp_spr)) == 0 && - memcmp(results->wm_linetime, previous.wm_linetime, - sizeof(results->wm_linetime)) == 0 && - partitioning == prev_partitioning && - results->enable_fbc_wm == prev_enable_fbc_wm) + previous.enable_fbc_wm = !(I915_READ(DISP_ARB_CTL) & DISP_FBC_WM_DIS); + + if (memcmp(results, &previous, sizeof(*results)) == 0) return; if (previous.wm_lp[2] != 0) @@ -2846,16 +2828,16 @@ static void hsw_write_wm_values(struct drm_i915_private *dev_priv, if (previous.wm_linetime[2] != results->wm_linetime[2]) I915_WRITE(PIPE_WM_LINETIME(PIPE_C), results->wm_linetime[2]); - if (prev_partitioning != partitioning) { + if (previous.partitioning != results->partitioning) { val = I915_READ(WM_MISC); - if (partitioning == INTEL_DDB_PART_1_2) + if (results->partitioning == INTEL_DDB_PART_1_2) val &= ~WM_MISC_DATA_PARTITION_5_6; else val |= WM_MISC_DATA_PARTITION_5_6; I915_WRITE(WM_MISC, val); } - if (prev_enable_fbc_wm != results->enable_fbc_wm) { + if (previous.enable_fbc_wm != results->enable_fbc_wm) { val = I915_READ(DISP_ARB_CTL); if (results->enable_fbc_wm) val &= ~DISP_FBC_WM_DIS; @@ -2877,6 +2859,8 @@ static void hsw_write_wm_values(struct drm_i915_private *dev_priv, I915_WRITE(WM2_LP_ILK, results->wm_lp[1]); if (results->wm_lp[2] != 0) I915_WRITE(WM3_LP_ILK, results->wm_lp[2]); + + dev_priv->wm.hw = *results; } static void haswell_update_wm(struct drm_crtc *crtc) @@ -2914,12 +2898,12 @@ static void haswell_update_wm(struct drm_crtc *crtc) best_lp_wm = &lp_wm_1_2; } - hsw_compute_wm_results(dev, best_lp_wm, &results); - partitioning = (best_lp_wm == &lp_wm_1_2) ? INTEL_DDB_PART_1_2 : INTEL_DDB_PART_5_6; - hsw_write_wm_values(dev_priv, &results, partitioning); + hsw_compute_wm_results(dev, best_lp_wm, partitioning, &results); + + hsw_write_wm_values(dev_priv, &results); } static void haswell_update_sprite_wm(struct drm_plane *plane, -- cgit v1.2.2 From 49a687c471396d063bb3d3cf04d62568efe7ec5e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Fri, 11 Oct 2013 19:39:52 +0300 Subject: drm/i915: Improve watermark dirtyness checks MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently hsw_write_vm_values() may write to certain watermark registers needlessly. For instance if only, say, LP3 changes, the current code will again disable all LP1+ watermarks even though only LP3 needs to be reconfigured. Add an easy to read function that will compute the dirtyness of the watermarks, and use that information to further optimize the watermark programming. v2: Disable LP1+ watermarks around changing LP0 watermarks for Paulo Signed-off-by: Ville Syrjälä Reviewed-by: Paulo Zanoni Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_pm.c | 98 +++++++++++++++++++++++++++++++++-------- 1 file changed, 80 insertions(+), 18 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 6d3d5f62dd6b..6d0c3d0e80fd 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -2776,6 +2776,66 @@ static struct intel_pipe_wm *hsw_find_best_result(struct drm_device *dev, } } +/* dirty bits used to track which watermarks need changes */ +#define WM_DIRTY_PIPE(pipe) (1 << (pipe)) +#define WM_DIRTY_LINETIME(pipe) (1 << (8 + (pipe))) +#define WM_DIRTY_LP(wm_lp) (1 << (15 + (wm_lp))) +#define WM_DIRTY_LP_ALL (WM_DIRTY_LP(1) | WM_DIRTY_LP(2) | WM_DIRTY_LP(3)) +#define WM_DIRTY_FBC (1 << 24) +#define WM_DIRTY_DDB (1 << 25) + +static unsigned int ilk_compute_wm_dirty(struct drm_device *dev, + const struct hsw_wm_values *old, + const struct hsw_wm_values *new) +{ + unsigned int dirty = 0; + enum pipe pipe; + int wm_lp; + + for_each_pipe(pipe) { + if (old->wm_linetime[pipe] != new->wm_linetime[pipe]) { + dirty |= WM_DIRTY_LINETIME(pipe); + /* Must disable LP1+ watermarks too */ + dirty |= WM_DIRTY_LP_ALL; + } + + if (old->wm_pipe[pipe] != new->wm_pipe[pipe]) { + dirty |= WM_DIRTY_PIPE(pipe); + /* Must disable LP1+ watermarks too */ + dirty |= WM_DIRTY_LP_ALL; + } + } + + if (old->enable_fbc_wm != new->enable_fbc_wm) { + dirty |= WM_DIRTY_FBC; + /* Must disable LP1+ watermarks too */ + dirty |= WM_DIRTY_LP_ALL; + } + + if (old->partitioning != new->partitioning) { + dirty |= WM_DIRTY_DDB; + /* Must disable LP1+ watermarks too */ + dirty |= WM_DIRTY_LP_ALL; + } + + /* LP1+ watermarks already deemed dirty, no need to continue */ + if (dirty & WM_DIRTY_LP_ALL) + return dirty; + + /* Find the lowest numbered LP1+ watermark in need of an update... */ + for (wm_lp = 1; wm_lp <= 3; wm_lp++) { + if (old->wm_lp[wm_lp - 1] != new->wm_lp[wm_lp - 1] || + old->wm_lp_spr[wm_lp - 1] != new->wm_lp_spr[wm_lp - 1]) + break; + } + + /* ...and mark it and all higher numbered LP1+ watermarks as dirty */ + for (; wm_lp <= 3; wm_lp++) + dirty |= WM_DIRTY_LP(wm_lp); + + return dirty; +} + /* * The spec says we shouldn't write when we don't need, because every write * causes WMs to be re-evaluated, expending some power. @@ -2784,6 +2844,7 @@ static void hsw_write_wm_values(struct drm_i915_private *dev_priv, struct hsw_wm_values *results) { struct hsw_wm_values previous; + unsigned int dirty; uint32_t val; previous.wm_pipe[0] = I915_READ(WM0_PIPEA_ILK); @@ -2804,31 +2865,32 @@ static void hsw_write_wm_values(struct drm_i915_private *dev_priv, previous.enable_fbc_wm = !(I915_READ(DISP_ARB_CTL) & DISP_FBC_WM_DIS); - if (memcmp(results, &previous, sizeof(*results)) == 0) + dirty = ilk_compute_wm_dirty(dev_priv->dev, &previous, results); + if (!dirty) return; - if (previous.wm_lp[2] != 0) + if (dirty & WM_DIRTY_LP(3) && previous.wm_lp[2] != 0) I915_WRITE(WM3_LP_ILK, 0); - if (previous.wm_lp[1] != 0) + if (dirty & WM_DIRTY_LP(2) && previous.wm_lp[1] != 0) I915_WRITE(WM2_LP_ILK, 0); - if (previous.wm_lp[0] != 0) + if (dirty & WM_DIRTY_LP(1) && previous.wm_lp[0] != 0) I915_WRITE(WM1_LP_ILK, 0); - if (previous.wm_pipe[0] != results->wm_pipe[0]) + if (dirty & WM_DIRTY_PIPE(PIPE_A)) I915_WRITE(WM0_PIPEA_ILK, results->wm_pipe[0]); - if (previous.wm_pipe[1] != results->wm_pipe[1]) + if (dirty & WM_DIRTY_PIPE(PIPE_B)) I915_WRITE(WM0_PIPEB_ILK, results->wm_pipe[1]); - if (previous.wm_pipe[2] != results->wm_pipe[2]) + if (dirty & WM_DIRTY_PIPE(PIPE_C)) I915_WRITE(WM0_PIPEC_IVB, results->wm_pipe[2]); - if (previous.wm_linetime[0] != results->wm_linetime[0]) + if (dirty & WM_DIRTY_LINETIME(PIPE_A)) I915_WRITE(PIPE_WM_LINETIME(PIPE_A), results->wm_linetime[0]); - if (previous.wm_linetime[1] != results->wm_linetime[1]) + if (dirty & WM_DIRTY_LINETIME(PIPE_B)) I915_WRITE(PIPE_WM_LINETIME(PIPE_B), results->wm_linetime[1]); - if (previous.wm_linetime[2] != results->wm_linetime[2]) + if (dirty & WM_DIRTY_LINETIME(PIPE_C)) I915_WRITE(PIPE_WM_LINETIME(PIPE_C), results->wm_linetime[2]); - if (previous.partitioning != results->partitioning) { + if (dirty & WM_DIRTY_DDB) { val = I915_READ(WM_MISC); if (results->partitioning == INTEL_DDB_PART_1_2) val &= ~WM_MISC_DATA_PARTITION_5_6; @@ -2837,7 +2899,7 @@ static void hsw_write_wm_values(struct drm_i915_private *dev_priv, I915_WRITE(WM_MISC, val); } - if (previous.enable_fbc_wm != results->enable_fbc_wm) { + if (dirty & WM_DIRTY_FBC) { val = I915_READ(DISP_ARB_CTL); if (results->enable_fbc_wm) val &= ~DISP_FBC_WM_DIS; @@ -2846,18 +2908,18 @@ static void hsw_write_wm_values(struct drm_i915_private *dev_priv, I915_WRITE(DISP_ARB_CTL, val); } - if (previous.wm_lp_spr[0] != results->wm_lp_spr[0]) + if (dirty & WM_DIRTY_LP(1) && previous.wm_lp_spr[0] != results->wm_lp_spr[0]) I915_WRITE(WM1S_LP_ILK, results->wm_lp_spr[0]); - if (previous.wm_lp_spr[1] != results->wm_lp_spr[1]) + if (dirty & WM_DIRTY_LP(2) && previous.wm_lp_spr[1] != results->wm_lp_spr[1]) I915_WRITE(WM2S_LP_IVB, results->wm_lp_spr[1]); - if (previous.wm_lp_spr[2] != results->wm_lp_spr[2]) + if (dirty & WM_DIRTY_LP(3) && previous.wm_lp_spr[2] != results->wm_lp_spr[2]) I915_WRITE(WM3S_LP_IVB, results->wm_lp_spr[2]); - if (results->wm_lp[0] != 0) + if (dirty & WM_DIRTY_LP(1) && results->wm_lp[0] != 0) I915_WRITE(WM1_LP_ILK, results->wm_lp[0]); - if (results->wm_lp[1] != 0) + if (dirty & WM_DIRTY_LP(2) && results->wm_lp[1] != 0) I915_WRITE(WM2_LP_ILK, results->wm_lp[1]); - if (results->wm_lp[2] != 0) + if (dirty & WM_DIRTY_LP(3) && results->wm_lp[2] != 0) I915_WRITE(WM3_LP_ILK, results->wm_lp[2]); dev_priv->wm.hw = *results; -- cgit v1.2.2 From 243e6a44b9ca5aa3c9ce47459a53e03b1dc7e665 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Mon, 14 Oct 2013 14:55:24 +0300 Subject: drm/i915: Init HSW watermark tracking in intel_modeset_setup_hw_state() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fill out the HSW watermark s/w tracking structures with the current hardware state in intel_modeset_setup_hw_state(). This allows us to skip the HW state readback during watermark programming and just use the values we keep around in dev_priv->wm. Reduces the overhead of the watermark programming quite a bit. v2: s/init_wm/wm_get_hw_state Remove stale comment about sprites Make DDB partitioning readout safer Signed-off-by: Ville Syrjälä Reviewed-by: Paulo Zanoni [danvet: Fix whitespace fail.] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 3 ++ drivers/gpu/drm/i915/intel_drv.h | 1 + drivers/gpu/drm/i915/intel_pm.c | 102 ++++++++++++++++++++++++++--------- 3 files changed, 80 insertions(+), 26 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index e6a4ca16f33c..53ad5cb9e802 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -10839,6 +10839,9 @@ void intel_modeset_setup_hw_state(struct drm_device *dev, pll->on = false; } + if (IS_HASWELL(dev)) + ilk_wm_get_hw_state(dev); + if (force_restore) { i915_redisable_vga(dev); diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 5d5d34911a7e..e33f387d4185 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -839,6 +839,7 @@ void gen6_rps_idle(struct drm_i915_private *dev_priv); void gen6_rps_boost(struct drm_i915_private *dev_priv); void intel_aux_display_runtime_get(struct drm_i915_private *dev_priv); void intel_aux_display_runtime_put(struct drm_i915_private *dev_priv); +void ilk_wm_get_hw_state(struct drm_device *dev); /* intel_sdvo.c */ diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 6d0c3d0e80fd..77ee14fa007b 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -2843,37 +2843,19 @@ static unsigned int ilk_compute_wm_dirty(struct drm_device *dev, static void hsw_write_wm_values(struct drm_i915_private *dev_priv, struct hsw_wm_values *results) { - struct hsw_wm_values previous; + struct hsw_wm_values *previous = &dev_priv->wm.hw; unsigned int dirty; uint32_t val; - previous.wm_pipe[0] = I915_READ(WM0_PIPEA_ILK); - previous.wm_pipe[1] = I915_READ(WM0_PIPEB_ILK); - previous.wm_pipe[2] = I915_READ(WM0_PIPEC_IVB); - previous.wm_lp[0] = I915_READ(WM1_LP_ILK); - previous.wm_lp[1] = I915_READ(WM2_LP_ILK); - previous.wm_lp[2] = I915_READ(WM3_LP_ILK); - previous.wm_lp_spr[0] = I915_READ(WM1S_LP_ILK); - previous.wm_lp_spr[1] = I915_READ(WM2S_LP_IVB); - previous.wm_lp_spr[2] = I915_READ(WM3S_LP_IVB); - previous.wm_linetime[0] = I915_READ(PIPE_WM_LINETIME(PIPE_A)); - previous.wm_linetime[1] = I915_READ(PIPE_WM_LINETIME(PIPE_B)); - previous.wm_linetime[2] = I915_READ(PIPE_WM_LINETIME(PIPE_C)); - - previous.partitioning = (I915_READ(WM_MISC) & WM_MISC_DATA_PARTITION_5_6) ? - INTEL_DDB_PART_5_6 : INTEL_DDB_PART_1_2; - - previous.enable_fbc_wm = !(I915_READ(DISP_ARB_CTL) & DISP_FBC_WM_DIS); - - dirty = ilk_compute_wm_dirty(dev_priv->dev, &previous, results); + dirty = ilk_compute_wm_dirty(dev_priv->dev, previous, results); if (!dirty) return; - if (dirty & WM_DIRTY_LP(3) && previous.wm_lp[2] != 0) + if (dirty & WM_DIRTY_LP(3) && previous->wm_lp[2] != 0) I915_WRITE(WM3_LP_ILK, 0); - if (dirty & WM_DIRTY_LP(2) && previous.wm_lp[1] != 0) + if (dirty & WM_DIRTY_LP(2) && previous->wm_lp[1] != 0) I915_WRITE(WM2_LP_ILK, 0); - if (dirty & WM_DIRTY_LP(1) && previous.wm_lp[0] != 0) + if (dirty & WM_DIRTY_LP(1) && previous->wm_lp[0] != 0) I915_WRITE(WM1_LP_ILK, 0); if (dirty & WM_DIRTY_PIPE(PIPE_A)) @@ -2908,11 +2890,11 @@ static void hsw_write_wm_values(struct drm_i915_private *dev_priv, I915_WRITE(DISP_ARB_CTL, val); } - if (dirty & WM_DIRTY_LP(1) && previous.wm_lp_spr[0] != results->wm_lp_spr[0]) + if (dirty & WM_DIRTY_LP(1) && previous->wm_lp_spr[0] != results->wm_lp_spr[0]) I915_WRITE(WM1S_LP_ILK, results->wm_lp_spr[0]); - if (dirty & WM_DIRTY_LP(2) && previous.wm_lp_spr[1] != results->wm_lp_spr[1]) + if (dirty & WM_DIRTY_LP(2) && previous->wm_lp_spr[1] != results->wm_lp_spr[1]) I915_WRITE(WM2S_LP_IVB, results->wm_lp_spr[1]); - if (dirty & WM_DIRTY_LP(3) && previous.wm_lp_spr[2] != results->wm_lp_spr[2]) + if (dirty & WM_DIRTY_LP(3) && previous->wm_lp_spr[2] != results->wm_lp_spr[2]) I915_WRITE(WM3S_LP_IVB, results->wm_lp_spr[2]); if (dirty & WM_DIRTY_LP(1) && results->wm_lp[0] != 0) @@ -3145,6 +3127,74 @@ static void sandybridge_update_sprite_wm(struct drm_plane *plane, I915_WRITE(WM3S_LP_IVB, sprite_wm); } +static void ilk_pipe_wm_get_hw_state(struct drm_crtc *crtc) +{ + struct drm_device *dev = crtc->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + struct hsw_wm_values *hw = &dev_priv->wm.hw; + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + struct intel_pipe_wm *active = &intel_crtc->wm.active; + enum pipe pipe = intel_crtc->pipe; + static const unsigned int wm0_pipe_reg[] = { + [PIPE_A] = WM0_PIPEA_ILK, + [PIPE_B] = WM0_PIPEB_ILK, + [PIPE_C] = WM0_PIPEC_IVB, + }; + + hw->wm_pipe[pipe] = I915_READ(wm0_pipe_reg[pipe]); + hw->wm_linetime[pipe] = I915_READ(PIPE_WM_LINETIME(pipe)); + + if (intel_crtc_active(crtc)) { + u32 tmp = hw->wm_pipe[pipe]; + + /* + * For active pipes LP0 watermark is marked as + * enabled, and LP1+ watermaks as disabled since + * we can't really reverse compute them in case + * multiple pipes are active. + */ + active->wm[0].enable = true; + active->wm[0].pri_val = (tmp & WM0_PIPE_PLANE_MASK) >> WM0_PIPE_PLANE_SHIFT; + active->wm[0].spr_val = (tmp & WM0_PIPE_SPRITE_MASK) >> WM0_PIPE_SPRITE_SHIFT; + active->wm[0].cur_val = tmp & WM0_PIPE_CURSOR_MASK; + active->linetime = hw->wm_linetime[pipe]; + } else { + int level, max_level = ilk_wm_max_level(dev); + + /* + * For inactive pipes, all watermark levels + * should be marked as enabled but zeroed, + * which is what we'd compute them to. + */ + for (level = 0; level <= max_level; level++) + active->wm[level].enable = true; + } +} + +void ilk_wm_get_hw_state(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + struct hsw_wm_values *hw = &dev_priv->wm.hw; + struct drm_crtc *crtc; + + list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) + ilk_pipe_wm_get_hw_state(crtc); + + hw->wm_lp[0] = I915_READ(WM1_LP_ILK); + hw->wm_lp[1] = I915_READ(WM2_LP_ILK); + hw->wm_lp[2] = I915_READ(WM3_LP_ILK); + + hw->wm_lp_spr[0] = I915_READ(WM1S_LP_ILK); + hw->wm_lp_spr[1] = I915_READ(WM2S_LP_IVB); + hw->wm_lp_spr[2] = I915_READ(WM3S_LP_IVB); + + hw->partitioning = (I915_READ(WM_MISC) & WM_MISC_DATA_PARTITION_5_6) ? + INTEL_DDB_PART_5_6 : INTEL_DDB_PART_1_2; + + hw->enable_fbc_wm = + !(I915_READ(DISP_ARB_CTL) & DISP_FBC_WM_DIS); +} + /** * intel_update_watermarks - update FIFO watermark values based on current modes * -- cgit v1.2.2 From dcaf13f7924b86b201f163fd71aad31a5a64fd71 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Wed, 9 Oct 2013 19:18:06 +0300 Subject: drm/i915: Remove a somewhat silly debug print from watermark code MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This debug print just adds overhead to the watermark merging process, and doesn't really give enough information to be useful. Just kill and let's add something much better a bit later. Signed-off-by: Ville Syrjälä Reviewed-by: Paulo Zanoni Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_pm.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 77ee14fa007b..63b3f5e4b258 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -2421,8 +2421,6 @@ static bool ilk_check_wm(int level, result->enable = true; } - DRM_DEBUG_KMS("WM%d: %sabled\n", level, result->enable ? "en" : "dis"); - return ret; } -- cgit v1.2.2 From 1996d624403483aa8b4192f39584b0d9421ed6a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Wed, 9 Oct 2013 19:18:07 +0300 Subject: drm/i915: Adjust watermark register masks MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We want to be able to use the masks to decode the register contents regardless of the hardware generation. So just expand the masks to cover all available bits, even if those are reserved on some generations. v2: Don't extend WM1_LP_SR_MASK so far, for the *future* Signed-off-by: Ville Syrjälä Reviewed-by: Paulo Zanoni Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_reg.h | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 35c9d868b893..88f76714dba3 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -3251,11 +3251,11 @@ /* define the Watermark register on Ironlake */ #define WM0_PIPEA_ILK 0x45100 -#define WM0_PIPE_PLANE_MASK (0x7f<<16) +#define WM0_PIPE_PLANE_MASK (0xffff<<16) #define WM0_PIPE_PLANE_SHIFT 16 -#define WM0_PIPE_SPRITE_MASK (0x3f<<8) +#define WM0_PIPE_SPRITE_MASK (0xff<<8) #define WM0_PIPE_SPRITE_SHIFT 8 -#define WM0_PIPE_CURSOR_MASK (0x1f) +#define WM0_PIPE_CURSOR_MASK (0xff) #define WM0_PIPEB_ILK 0x45104 #define WM0_PIPEC_IVB 0x45200 @@ -3265,9 +3265,9 @@ #define WM1_LP_LATENCY_MASK (0x7f<<24) #define WM1_LP_FBC_MASK (0xf<<20) #define WM1_LP_FBC_SHIFT 20 -#define WM1_LP_SR_MASK (0x1ff<<8) +#define WM1_LP_SR_MASK (0x7ff<<8) #define WM1_LP_SR_SHIFT 8 -#define WM1_LP_CURSOR_MASK (0x3f) +#define WM1_LP_CURSOR_MASK (0xff) #define WM2_LP_ILK 0x4510c #define WM2_LP_EN (1<<31) #define WM3_LP_ILK 0x45110 -- cgit v1.2.2 From 34982fe1303b7e4f24fb8a0a238ebffc8135af84 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Wed, 9 Oct 2013 19:18:09 +0300 Subject: drm/i915: Rename ilk_wm_max to ilk_compute_wm_maximums MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Makes the intention more clear. Signed-off-by: Ville Syrjälä Reviewed-by: Paulo Zanoni Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_pm.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 63b3f5e4b258..493a31334158 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -2371,11 +2371,11 @@ static unsigned int ilk_fbc_wm_max(void) return 15; } -static void ilk_wm_max(struct drm_device *dev, - int level, - const struct intel_wm_config *config, - enum intel_ddb_partitioning ddb_partitioning, - struct hsw_wm_maximums *max) +static void ilk_compute_wm_maximums(struct drm_device *dev, + int level, + const struct intel_wm_config *config, + enum intel_ddb_partitioning ddb_partitioning, + struct hsw_wm_maximums *max) { max->pri = ilk_plane_wm_max(dev, level, config, ddb_partitioning, false); max->spr = ilk_plane_wm_max(dev, level, config, ddb_partitioning, true); @@ -2626,7 +2626,7 @@ static bool intel_compute_pipe_wm(struct drm_crtc *crtc, struct hsw_wm_maximums max; /* LP0 watermarks always use 1/2 DDB partitioning */ - ilk_wm_max(dev, 0, &config, INTEL_DDB_PART_1_2, &max); + ilk_compute_wm_maximums(dev, 0, &config, INTEL_DDB_PART_1_2, &max); for (level = 0; level <= max_level; level++) ilk_compute_wm_level(dev_priv, level, params, @@ -2927,12 +2927,12 @@ static void haswell_update_wm(struct drm_crtc *crtc) intel_crtc->wm.active = pipe_wm; - ilk_wm_max(dev, 1, &config, INTEL_DDB_PART_1_2, &max); + ilk_compute_wm_maximums(dev, 1, &config, INTEL_DDB_PART_1_2, &max); ilk_wm_merge(dev, &max, &lp_wm_1_2); /* 5/6 split only in single pipe config on IVB+ */ if (INTEL_INFO(dev)->gen >= 7 && config.num_pipes_active == 1) { - ilk_wm_max(dev, 1, &config, INTEL_DDB_PART_5_6, &max); + ilk_compute_wm_maximums(dev, 1, &config, INTEL_DDB_PART_5_6, &max); ilk_wm_merge(dev, &max, &lp_wm_5_6); best_lp_wm = hsw_find_best_result(dev, &lp_wm_1_2, &lp_wm_5_6); -- cgit v1.2.2 From d9395655b92bc80c33cb6fbacbefb9ebf16403d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Wed, 9 Oct 2013 19:18:10 +0300 Subject: drm/i915: Rename ilk_check_wm to ilk_validate_wm_level MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Makes the behaviour of the function more clear. Signed-off-by: Ville Syrjälä Reviewed-by: Paulo Zanoni Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_pm.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 493a31334158..cdd78f69a28b 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -2383,9 +2383,9 @@ static void ilk_compute_wm_maximums(struct drm_device *dev, max->fbc = ilk_fbc_wm_max(); } -static bool ilk_check_wm(int level, - const struct hsw_wm_maximums *max, - struct intel_wm_level *result) +static bool ilk_validate_wm_level(int level, + const struct hsw_wm_maximums *max, + struct intel_wm_level *result) { bool ret; @@ -2635,7 +2635,7 @@ static bool intel_compute_pipe_wm(struct drm_crtc *crtc, pipe_wm->linetime = hsw_compute_linetime_wm(dev, crtc); /* At least LP0 must be valid */ - return ilk_check_wm(0, &max, &pipe_wm->wm[0]); + return ilk_validate_wm_level(0, &max, &pipe_wm->wm[0]); } /* @@ -2680,7 +2680,7 @@ static void ilk_wm_merge(struct drm_device *dev, ilk_merge_wm_level(dev, level, wm); - if (!ilk_check_wm(level, max, wm)) + if (!ilk_validate_wm_level(level, max, wm)) break; /* -- cgit v1.2.2 From ec98c8d1ffdc87c54ec0896db45db5b7bd22eca9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Fri, 11 Oct 2013 15:26:26 +0300 Subject: drm/i915: Check 5/6 DDB split only when sprites are enabled MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Using the 5/6 DDB split make sense only when sprites are enabled. So check that before we waste any cycles computing the merged watermarks with the 5/6 DDB split. Signed-off-by: Ville Syrjälä Reviewed-by: Paulo Zanoni Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_pm.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index cdd78f69a28b..8064ff927bcc 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -2931,7 +2931,8 @@ static void haswell_update_wm(struct drm_crtc *crtc) ilk_wm_merge(dev, &max, &lp_wm_1_2); /* 5/6 split only in single pipe config on IVB+ */ - if (INTEL_INFO(dev)->gen >= 7 && config.num_pipes_active == 1) { + if (INTEL_INFO(dev)->gen >= 7 && + config.num_pipes_active == 1 && config.sprites_enabled) { ilk_compute_wm_maximums(dev, 1, &config, INTEL_DDB_PART_5_6, &max); ilk_wm_merge(dev, &max, &lp_wm_5_6); -- cgit v1.2.2 From 3d57e5bd1284f44e325f3a52d966259ed42f9e05 Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Mon, 14 Oct 2013 10:01:36 -0700 Subject: drm/i915: Do a fuller init after reset I had this lying around from he original PPGTT series, and thought we might try to get it in by itself. It's convenient to just call i915_gem_init_hw at reset because we'll be adding new things to that function, and having just one function to call instead of reimplementing it in two places is nice. In order to accommodate we cleanup ringbuffers in order to bring them back up cleanly. Optionally, we could also teardown/re initialize the default context but this was causing some problems on reset which I wasn't able to fully debug, and is unnecessary with the previous context init/enable split. This essentially reverts: commit 8e88a2bd5987178d16d53686197404e149e996d9 Author: Daniel Vetter Date: Tue Jun 19 18:40:00 2012 +0200 drm/i915: don't call modeset_init_hw in i915_reset It seems to work for me on ILK now. Perhaps it's due to: commit 8a5c2ae753c588bcb2a4e38d1c6a39865dbf1ff3 Author: Jesse Barnes Date: Thu Mar 28 13:57:19 2013 -0700 drm/i915: fix ILK GPU reset for render Signed-off-by: Ben Widawsky Reviewed-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.c | 29 ++++++++--------------------- drivers/gpu/drm/i915/i915_gem.c | 2 ++ drivers/gpu/drm/i915/intel_ringbuffer.c | 4 +++- 3 files changed, 13 insertions(+), 22 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index 59649c060986..db84e242306d 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -744,30 +744,17 @@ int i915_reset(struct drm_device *dev) */ if (drm_core_check_feature(dev, DRIVER_MODESET) || !dev_priv->ums.mm_suspended) { - struct intel_ring_buffer *ring; - int i; - + bool hw_contexts_disabled = dev_priv->hw_contexts_disabled; dev_priv->ums.mm_suspended = 0; - i915_gem_init_swizzling(dev); - - for_each_ring(ring, dev_priv, i) - ring->init(ring); - - i915_gem_context_init(dev); - if (dev_priv->mm.aliasing_ppgtt) { - ret = dev_priv->mm.aliasing_ppgtt->enable(dev); - if (ret) - i915_gem_cleanup_aliasing_ppgtt(dev); - } - - /* - * It would make sense to re-init all the other hw state, at - * least the rps/rc6/emon init done within modeset_init_hw. For - * some unknown reason, this blows up my ilk, so don't. - */ - + ret = i915_gem_init_hw(dev); + if (!hw_contexts_disabled && dev_priv->hw_contexts_disabled) + DRM_ERROR("HW contexts didn't survive reset\n"); mutex_unlock(&dev->struct_mutex); + if (ret) { + DRM_ERROR("Failed hw init on reset %d\n", ret); + return ret; + } drm_irq_uninstall(dev); drm_irq_install(dev); diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 71dd0305eb32..1d22c99601ed 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -2406,6 +2406,8 @@ void i915_gem_reset(struct drm_device *dev) for_each_ring(ring, dev_priv, i) i915_gem_reset_ring_lists(dev_priv, ring); + i915_gem_cleanup_ringbuffer(dev); + i915_gem_restore_fences(dev); } diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index 4e108fc3c340..2dec134f75eb 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -1324,7 +1324,7 @@ void intel_cleanup_ring_buffer(struct intel_ring_buffer *ring) /* Disable the ring buffer. The ring must be idle at this point */ dev_priv = ring->dev->dev_private; ret = intel_ring_idle(ring); - if (ret) + if (ret && !i915_reset_in_progress(&dev_priv->gpu_error)) DRM_ERROR("failed to quiesce %s whilst cleaning up: %d\n", ring->name, ret); @@ -1335,6 +1335,8 @@ void intel_cleanup_ring_buffer(struct intel_ring_buffer *ring) i915_gem_object_unpin(ring->obj); drm_gem_object_unreference(&ring->obj->base); ring->obj = NULL; + ring->preallocated_lazy_request = NULL; + ring->outstanding_lazy_seqno = 0; if (ring->cleanup) ring->cleanup(ring); -- cgit v1.2.2 From 71b76d004f48b4b217a3895bfe058e2e5eefed39 Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Mon, 14 Oct 2013 10:01:37 -0700 Subject: drm/i915: cleanup context fini I had this lying around from he original PPGTT series, and thought we might try to get it in by itself. With the introduction of context refcounting we never explicitly ref/unref the backing object. As such, the previous fix was a bit wonky. Aside from fixing the above, this patch also puts us in good shape for an upcoming patch which allows a failure to occur in between context_init and the first do_switch. CC: Mika Kuoppala Signed-off-by: Ben Widawsky Reviewed-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem_context.c | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem_context.c b/drivers/gpu/drm/i915/i915_gem_context.c index 1a877a547290..cc619c138777 100644 --- a/drivers/gpu/drm/i915/i915_gem_context.c +++ b/drivers/gpu/drm/i915/i915_gem_context.c @@ -220,7 +220,6 @@ static int create_default_context(struct drm_i915_private *dev_priv) * may not be available. To avoid this we always pin the * default context. */ - dev_priv->ring[RCS].default_context = ctx; ret = i915_gem_obj_ggtt_pin(ctx->obj, CONTEXT_ALIGN, false, false); if (ret) { DRM_DEBUG_DRIVER("Couldn't pin %d\n", ret); @@ -233,6 +232,8 @@ static int create_default_context(struct drm_i915_private *dev_priv) goto err_unpin; } + dev_priv->ring[RCS].default_context = ctx; + DRM_DEBUG_DRIVER("Default HW context loaded\n"); return 0; @@ -288,16 +289,24 @@ void i915_gem_context_fini(struct drm_device *dev) * other code, leading to spurious errors. */ intel_gpu_reset(dev); - i915_gem_object_unpin(dctx->obj); - /* When default context is created and switched to, base object refcount * will be 2 (+1 from object creation and +1 from do_switch()). * i915_gem_context_fini() will be called after gpu_idle() has switched * to default context. So we need to unreference the base object once * to offset the do_switch part, so that i915_gem_context_unreference() * can then free the base object correctly. */ - drm_gem_object_unreference(&dctx->obj->base); + WARN_ON(!dev_priv->ring[RCS].last_context); + if (dev_priv->ring[RCS].last_context == dctx) { + /* Fake switch to NULL context */ + WARN_ON(dctx->obj->active); + i915_gem_object_unpin(dctx->obj); + i915_gem_context_unreference(dctx); + } + + i915_gem_object_unpin(dctx->obj); i915_gem_context_unreference(dctx); + dev_priv->ring[RCS].default_context = NULL; + dev_priv->ring[RCS].last_context = NULL; } static int context_idr_cleanup(int id, void *p, void *data) -- cgit v1.2.2 From 73ae478cdf6ab886b107f39269cbbf6d33ad2abe Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Tue, 15 Oct 2013 10:02:57 -0700 Subject: drm/i915: Replace has_bsd/blt/vebox with a mask I've sent this patch several times for various reasons. It essentially cleans up a lot of code where we need to do something per ring, and want to query whether or not the ring exists on that hardware. It has various uses coming up, but for now it shouldn't be too offensive. v2: Big conflict resolution on Damien's DEV_INFO_FOR_EACH stuff v3: Resolved vebox addition v4: Rebased after months of disuse. Also made failed ringbuffer init cleaner. v5: Remove the init cleaner from v4. There is a better way to do it. (Chris) Reviewed-by: Chris Wilson Signed-off-by: Ben Widawsky Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.c | 32 ++++++++++++++++++++------------ drivers/gpu/drm/i915/i915_drv.h | 14 ++++++++------ 2 files changed, 28 insertions(+), 18 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index db84e242306d..e9dfadca2d71 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -160,49 +160,58 @@ extern int intel_agp_enabled; static const struct intel_device_info intel_i830_info = { .gen = 2, .is_mobile = 1, .cursor_needs_physical = 1, .num_pipes = 2, .has_overlay = 1, .overlay_needs_physical = 1, + .ring_mask = RENDER_RING, }; static const struct intel_device_info intel_845g_info = { .gen = 2, .num_pipes = 1, .has_overlay = 1, .overlay_needs_physical = 1, + .ring_mask = RENDER_RING, }; static const struct intel_device_info intel_i85x_info = { .gen = 2, .is_i85x = 1, .is_mobile = 1, .num_pipes = 2, .cursor_needs_physical = 1, .has_overlay = 1, .overlay_needs_physical = 1, + .ring_mask = RENDER_RING, }; static const struct intel_device_info intel_i865g_info = { .gen = 2, .num_pipes = 1, .has_overlay = 1, .overlay_needs_physical = 1, + .ring_mask = RENDER_RING, }; static const struct intel_device_info intel_i915g_info = { .gen = 3, .is_i915g = 1, .cursor_needs_physical = 1, .num_pipes = 2, .has_overlay = 1, .overlay_needs_physical = 1, + .ring_mask = RENDER_RING, }; static const struct intel_device_info intel_i915gm_info = { .gen = 3, .is_mobile = 1, .num_pipes = 2, .cursor_needs_physical = 1, .has_overlay = 1, .overlay_needs_physical = 1, .supports_tv = 1, + .ring_mask = RENDER_RING, }; static const struct intel_device_info intel_i945g_info = { .gen = 3, .has_hotplug = 1, .cursor_needs_physical = 1, .num_pipes = 2, .has_overlay = 1, .overlay_needs_physical = 1, + .ring_mask = RENDER_RING, }; static const struct intel_device_info intel_i945gm_info = { .gen = 3, .is_i945gm = 1, .is_mobile = 1, .num_pipes = 2, .has_hotplug = 1, .cursor_needs_physical = 1, .has_overlay = 1, .overlay_needs_physical = 1, .supports_tv = 1, + .ring_mask = RENDER_RING, }; static const struct intel_device_info intel_i965g_info = { .gen = 4, .is_broadwater = 1, .num_pipes = 2, .has_hotplug = 1, .has_overlay = 1, + .ring_mask = RENDER_RING, }; static const struct intel_device_info intel_i965gm_info = { @@ -210,18 +219,20 @@ static const struct intel_device_info intel_i965gm_info = { .is_mobile = 1, .has_fbc = 1, .has_hotplug = 1, .has_overlay = 1, .supports_tv = 1, + .ring_mask = RENDER_RING, }; static const struct intel_device_info intel_g33_info = { .gen = 3, .is_g33 = 1, .num_pipes = 2, .need_gfx_hws = 1, .has_hotplug = 1, .has_overlay = 1, + .ring_mask = RENDER_RING, }; static const struct intel_device_info intel_g45_info = { .gen = 4, .is_g4x = 1, .need_gfx_hws = 1, .num_pipes = 2, .has_pipe_cxsr = 1, .has_hotplug = 1, - .has_bsd_ring = 1, + .ring_mask = RENDER_RING | BSD_RING, }; static const struct intel_device_info intel_gm45_info = { @@ -229,7 +240,7 @@ static const struct intel_device_info intel_gm45_info = { .is_mobile = 1, .need_gfx_hws = 1, .has_fbc = 1, .has_pipe_cxsr = 1, .has_hotplug = 1, .supports_tv = 1, - .has_bsd_ring = 1, + .ring_mask = RENDER_RING | BSD_RING, }; static const struct intel_device_info intel_pineview_info = { @@ -241,21 +252,20 @@ static const struct intel_device_info intel_pineview_info = { static const struct intel_device_info intel_ironlake_d_info = { .gen = 5, .num_pipes = 2, .need_gfx_hws = 1, .has_hotplug = 1, - .has_bsd_ring = 1, + .ring_mask = RENDER_RING | BSD_RING, }; static const struct intel_device_info intel_ironlake_m_info = { .gen = 5, .is_mobile = 1, .num_pipes = 2, .need_gfx_hws = 1, .has_hotplug = 1, .has_fbc = 1, - .has_bsd_ring = 1, + .ring_mask = RENDER_RING | BSD_RING, }; static const struct intel_device_info intel_sandybridge_d_info = { .gen = 6, .num_pipes = 2, .need_gfx_hws = 1, .has_hotplug = 1, - .has_bsd_ring = 1, - .has_blt_ring = 1, + .ring_mask = RENDER_RING | BSD_RING | BLT_RING, .has_llc = 1, }; @@ -263,16 +273,14 @@ static const struct intel_device_info intel_sandybridge_m_info = { .gen = 6, .is_mobile = 1, .num_pipes = 2, .need_gfx_hws = 1, .has_hotplug = 1, .has_fbc = 1, - .has_bsd_ring = 1, - .has_blt_ring = 1, + .ring_mask = RENDER_RING | BSD_RING | BLT_RING, .has_llc = 1, }; #define GEN7_FEATURES \ .gen = 7, .num_pipes = 3, \ .need_gfx_hws = 1, .has_hotplug = 1, \ - .has_bsd_ring = 1, \ - .has_blt_ring = 1, \ + .ring_mask = RENDER_RING | BSD_RING | BLT_RING, \ .has_llc = 1 static const struct intel_device_info intel_ivybridge_d_info = { @@ -315,7 +323,7 @@ static const struct intel_device_info intel_haswell_d_info = { .is_haswell = 1, .has_ddi = 1, .has_fpga_dbg = 1, - .has_vebox_ring = 1, + .ring_mask = RENDER_RING | BSD_RING | BLT_RING | VEBOX_RING, }; static const struct intel_device_info intel_haswell_m_info = { @@ -325,7 +333,7 @@ static const struct intel_device_info intel_haswell_m_info = { .has_ddi = 1, .has_fpga_dbg = 1, .has_fbc = 1, - .has_vebox_ring = 1, + .ring_mask = RENDER_RING | BSD_RING | BLT_RING | VEBOX_RING, }; /* diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 6106d3d710c5..3d374aa1a2b0 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -448,9 +448,6 @@ struct intel_uncore { func(has_overlay) sep \ func(overlay_needs_physical) sep \ func(supports_tv) sep \ - func(has_bsd_ring) sep \ - func(has_blt_ring) sep \ - func(has_vebox_ring) sep \ func(has_llc) sep \ func(has_ddi) sep \ func(has_fpga_dbg) @@ -462,6 +459,7 @@ struct intel_device_info { u32 display_mmio_offset; u8 num_pipes:3; u8 gen; + u8 ring_mask; /* Rings supported by the HW */ DEV_INFO_FOR_EACH_FLAG(DEFINE_FLAG, SEP_SEMICOLON); }; @@ -1691,9 +1689,13 @@ struct drm_i915_file_private { #define IS_GEN6(dev) (INTEL_INFO(dev)->gen == 6) #define IS_GEN7(dev) (INTEL_INFO(dev)->gen == 7) -#define HAS_BSD(dev) (INTEL_INFO(dev)->has_bsd_ring) -#define HAS_BLT(dev) (INTEL_INFO(dev)->has_blt_ring) -#define HAS_VEBOX(dev) (INTEL_INFO(dev)->has_vebox_ring) +#define RENDER_RING (1<ring_mask & BSD_RING) +#define HAS_BLT(dev) (INTEL_INFO(dev)->ring_mask & BLT_RING) +#define HAS_VEBOX(dev) (INTEL_INFO(dev)->ring_mask & VEBOX_RING) #define HAS_LLC(dev) (INTEL_INFO(dev)->has_llc) #define HAS_WT(dev) (IS_HASWELL(dev) && to_i915(dev)->ellc_size) #define I915_NEED_GFX_HWS(dev) (INTEL_INFO(dev)->need_gfx_hws) -- cgit v1.2.2 From 8bf1e9f1d2aa1fafd2b262683a13cbb7f934c6d0 Mon Sep 17 00:00:00 2001 From: Shuang He Date: Tue, 15 Oct 2013 18:55:27 +0100 Subject: drm/i915: Expose latest 200 CRC value for pipe through debugfs There are several points in the display pipeline where CRCs can be computed on the bits flowing there. For instance, it's usually possible to compute the CRCs of the primary plane, the sprite plane or the CRCs of the bits after the panel fitter (collectively called pipe CRCs). v2: Quite a bit of rework here and there (Damien) Signed-off-by: Shuang He Signed-off-by: Damien Lespiau [danvet: Fix intermediate compile file reported by Wu Fengguang's kernel builder.] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_debugfs.c | 33 +++++++++++++++++++++++++++++++++ drivers/gpu/drm/i915/i915_drv.h | 15 +++++++++++++++ drivers/gpu/drm/i915/i915_irq.c | 35 +++++++++++++++++++++++++++++++++++ drivers/gpu/drm/i915/i915_reg.h | 36 +++++++++++++++++++++++++++++++++++- 4 files changed, 118 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index 72d04588eccb..e1d45aaf6881 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -1732,6 +1732,36 @@ static int i915_pc8_status(struct seq_file *m, void *unused) return 0; } +static int i915_pipe_crc(struct seq_file *m, void *data) +{ + struct drm_info_node *node = (struct drm_info_node *) m->private; + struct drm_device *dev = node->minor->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + enum pipe pipe = (enum pipe)node->info_ent->data; + const struct intel_pipe_crc *pipe_crc = &dev_priv->pipe_crc[pipe]; + int i; + int start; + + if (!IS_IVYBRIDGE(dev)) { + seq_puts(m, "unsupported\n"); + return 0; + } + + start = atomic_read(&pipe_crc->slot) + 1; + seq_puts(m, " timestamp CRC1 CRC2 CRC3 CRC4 CRC5\n"); + for (i = 0; i < INTEL_PIPE_CRC_ENTRIES_NR; i++) { + const struct intel_pipe_crc_entry *entry = + &pipe_crc->entries[(start + i) % + INTEL_PIPE_CRC_ENTRIES_NR]; + + seq_printf(m, "%12u %8x %8x %8x %8x %8x\n", entry->timestamp, + entry->crc[0], entry->crc[1], entry->crc[2], + entry->crc[3], entry->crc[4]); + } + + return 0; +} + static int i915_wedged_get(void *data, u64 *val) { @@ -2247,6 +2277,9 @@ static struct drm_info_list i915_debugfs_list[] = { {"i915_edp_psr_status", i915_edp_psr_status, 0}, {"i915_energy_uJ", i915_energy_uJ, 0}, {"i915_pc8_status", i915_pc8_status, 0}, + {"i915_pipe_A_crc", i915_pipe_crc, 0, (void *)PIPE_A}, + {"i915_pipe_B_crc", i915_pipe_crc, 0, (void *)PIPE_B}, + {"i915_pipe_C_crc", i915_pipe_crc, 0, (void *)PIPE_C}, }; #define I915_DEBUGFS_ENTRIES ARRAY_SIZE(i915_debugfs_list) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 3d374aa1a2b0..b040ef82208f 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1217,6 +1217,17 @@ struct i915_package_c8 { } regsave; }; +struct intel_pipe_crc_entry { + uint32_t timestamp; + uint32_t crc[5]; +}; + +#define INTEL_PIPE_CRC_ENTRIES_NR 200 +struct intel_pipe_crc { + struct intel_pipe_crc_entry entries[INTEL_PIPE_CRC_ENTRIES_NR]; + atomic_t slot; +}; + typedef struct drm_i915_private { struct drm_device *dev; struct kmem_cache *slab; @@ -1421,6 +1432,10 @@ typedef struct drm_i915_private { struct i915_dri1_state dri1; /* Old ums support infrastructure, same warning applies. */ struct i915_ums_state ums; + +#ifdef CONFIG_DEBUG_FS + struct intel_pipe_crc pipe_crc[I915_MAX_PIPES]; +#endif } drm_i915_private_t; static inline struct drm_i915_private *to_i915(const struct drm_device *dev) diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 26753b6ac0a1..d2074f129a36 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -1188,6 +1188,32 @@ static void dp_aux_irq_handler(struct drm_device *dev) wake_up_all(&dev_priv->gmbus_wait_queue); } +#if defined(CONFIG_DEBUG_FS) +static void ivb_pipe_crc_update(struct drm_device *dev, enum pipe pipe) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_pipe_crc *pipe_crc = &dev_priv->pipe_crc[pipe]; + struct intel_pipe_crc_entry *entry; + ktime_t now; + int ts, slot; + + now = ktime_get(); + ts = ktime_to_us(now); + + slot = (atomic_read(&pipe_crc->slot) + 1) % INTEL_PIPE_CRC_ENTRIES_NR; + entry = &pipe_crc->entries[slot]; + entry->timestamp = ts; + entry->crc[0] = I915_READ(PIPE_CRC_RES_1_IVB(pipe)); + entry->crc[1] = I915_READ(PIPE_CRC_RES_2_IVB(pipe)); + entry->crc[2] = I915_READ(PIPE_CRC_RES_3_IVB(pipe)); + entry->crc[3] = I915_READ(PIPE_CRC_RES_4_IVB(pipe)); + entry->crc[4] = I915_READ(PIPE_CRC_RES_5_IVB(pipe)); + atomic_set(&dev_priv->pipe_crc[pipe].slot, slot); +} +#else +static void ivb_pipe_crc_update(struct drm_device *dev, int pipe) {} +#endif + /* The RPS events need forcewake, so we add them to a work queue and mask their * IMR bits until the work is done. Other interrupts can be processed without * the work queue. */ @@ -1366,6 +1392,15 @@ static void ivb_err_int_handler(struct drm_device *dev) if (intel_set_cpu_fifo_underrun_reporting(dev, PIPE_C, false)) DRM_DEBUG_DRIVER("Pipe C FIFO underrun\n"); + if (err_int & ERR_INT_PIPE_CRC_DONE_A) + ivb_pipe_crc_update(dev, PIPE_A); + + if (err_int & ERR_INT_PIPE_CRC_DONE_B) + ivb_pipe_crc_update(dev, PIPE_B); + + if (err_int & ERR_INT_PIPE_CRC_DONE_C) + ivb_pipe_crc_update(dev, PIPE_C); + I915_WRITE(GEN7_ERR_INT, err_int); } diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 88f76714dba3..8161521003ed 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -722,8 +722,11 @@ #define GEN7_ERR_INT 0x44040 #define ERR_INT_POISON (1<<31) #define ERR_INT_MMIO_UNCLAIMED (1<<13) +#define ERR_INT_PIPE_CRC_DONE_C (1<<8) #define ERR_INT_FIFO_UNDERRUN_C (1<<6) +#define ERR_INT_PIPE_CRC_DONE_B (1<<5) #define ERR_INT_FIFO_UNDERRUN_B (1<<3) +#define ERR_INT_PIPE_CRC_DONE_A (1<<2) #define ERR_INT_FIFO_UNDERRUN_A (1<<0) #define ERR_INT_FIFO_UNDERRUN(pipe) (1<<(pipe*3)) @@ -1835,6 +1838,38 @@ * Display engine regs */ +/* Pipe A CRC regs */ +#define _PIPE_CRC_CTL_A (dev_priv->info->display_mmio_offset + 0x60050) +#define PIPE_CRC_ENABLE (1 << 31) +#define PIPE_CRC_SOURCE_PRIMARY_IVB (0 << 29) +#define PIPE_CRC_SOURCE_SPRITE_IVB (1 << 29) +#define PIPE_CRC_SOURCE_PF_IVB (2 << 29) +#define _PIPE_CRC_RES_1_A_IVB (dev_priv->info->display_mmio_offset + 0x60064) +#define _PIPE_CRC_RES_2_A_IVB (dev_priv->info->display_mmio_offset + 0x60068) +#define _PIPE_CRC_RES_3_A_IVB (dev_priv->info->display_mmio_offset + 0x6006c) +#define _PIPE_CRC_RES_4_A_IVB (dev_priv->info->display_mmio_offset + 0x60070) +#define _PIPE_CRC_RES_5_A_IVB (dev_priv->info->display_mmio_offset + 0x60074) + +/* Pipe B CRC regs */ +#define _PIPE_CRC_CTL_B (dev_priv->info->display_mmio_offset + 0x61050) +#define _PIPE_CRC_RES_1_B_IVB (dev_priv->info->display_mmio_offset + 0x61064) +#define _PIPE_CRC_RES_2_B_IVB (dev_priv->info->display_mmio_offset + 0x61068) +#define _PIPE_CRC_RES_3_B_IVB (dev_priv->info->display_mmio_offset + 0x6106c) +#define _PIPE_CRC_RES_4_B_IVB (dev_priv->info->display_mmio_offset + 0x61070) +#define _PIPE_CRC_RES_5_B_IVB (dev_priv->info->display_mmio_offset + 0x61074) + +#define PIPE_CRC_CTL(pipe) _PIPE(pipe, _PIPE_CRC_CTL_A, _PIPE_CRC_CTL_B) +#define PIPE_CRC_RES_1_IVB(pipe) \ + _PIPE(pipe, _PIPE_CRC_RES_1_A_IVB, _PIPE_CRC_RES_1_B_IVB) +#define PIPE_CRC_RES_2_IVB(pipe) \ + _PIPE(pipe, _PIPE_CRC_RES_2_A_IVB, _PIPE_CRC_RES_2_B_IVB) +#define PIPE_CRC_RES_3_IVB(pipe) \ + _PIPE(pipe, _PIPE_CRC_RES_3_A_IVB, _PIPE_CRC_RES_3_B_IVB) +#define PIPE_CRC_RES_4_IVB(pipe) \ + _PIPE(pipe, _PIPE_CRC_RES_4_A_IVB, _PIPE_CRC_RES_4_B_IVB) +#define PIPE_CRC_RES_5_IVB(pipe) \ + _PIPE(pipe, _PIPE_CRC_RES_5_A_IVB, _PIPE_CRC_RES_5_B_IVB) + /* Pipe A timing regs */ #define _HTOTAL_A (dev_priv->info->display_mmio_offset + 0x60000) #define _HBLANK_A (dev_priv->info->display_mmio_offset + 0x60004) @@ -1857,7 +1892,6 @@ #define _BCLRPAT_B (dev_priv->info->display_mmio_offset + 0x61020) #define _VSYNCSHIFT_B (dev_priv->info->display_mmio_offset + 0x61028) - #define HTOTAL(trans) _TRANSCODER(trans, _HTOTAL_A, _HTOTAL_B) #define HBLANK(trans) _TRANSCODER(trans, _HBLANK_A, _HBLANK_B) #define HSYNC(trans) _TRANSCODER(trans, _HSYNC_A, _HSYNC_B) -- cgit v1.2.2 From 926321d503406d1fefb2fae9651beca14160529a Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Wed, 16 Oct 2013 13:30:34 +0200 Subject: drm/i915: Add a control file for pipe CRCs Note the "return -ENODEV;" in pipe_crc_set_source(). The ctl file is disabled until the end of the series to be able to do incremental improvements. Signed-off-by: Damien Lespiau Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_debugfs.c | 217 +++++++++++++++++++++++++++++++++++- drivers/gpu/drm/i915/i915_drv.h | 9 ++ 2 files changed, 224 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index e1d45aaf6881..0d8a9a397a24 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -27,6 +27,7 @@ */ #include +#include #include #include #include @@ -1742,8 +1743,8 @@ static int i915_pipe_crc(struct seq_file *m, void *data) int i; int start; - if (!IS_IVYBRIDGE(dev)) { - seq_puts(m, "unsupported\n"); + if (dev_priv->pipe_crc[pipe].source == INTEL_PIPE_CRC_SOURCE_NONE) { + seq_puts(m, "none\n"); return 0; } @@ -1762,6 +1763,217 @@ static int i915_pipe_crc(struct seq_file *m, void *data) return 0; } +static const char *pipe_crc_sources[] = { + "none", + "plane1", + "plane2", + "pf", +}; + +static const char *pipe_crc_source_name(enum intel_pipe_crc_source source) +{ + BUILD_BUG_ON(ARRAY_SIZE(pipe_crc_sources) != INTEL_PIPE_CRC_SOURCE_MAX); + return pipe_crc_sources[source]; +} + +static int pipe_crc_ctl_show(struct seq_file *m, void *data) +{ + struct drm_device *dev = m->private; + struct drm_i915_private *dev_priv = dev->dev_private; + int i; + + for (i = 0; i < I915_MAX_PIPES; i++) + seq_printf(m, "%c %s\n", pipe_name(i), + pipe_crc_source_name(dev_priv->pipe_crc[i].source)); + + return 0; +} + +static int pipe_crc_ctl_open(struct inode *inode, struct file *file) +{ + struct drm_device *dev = inode->i_private; + + return single_open(file, pipe_crc_ctl_show, dev); +} + +static int pipe_crc_set_source(struct drm_device *dev, enum pipe pipe, + enum intel_pipe_crc_source source) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + u32 val; + + + return -ENODEV; + + if (!IS_IVYBRIDGE(dev)) + return -ENODEV; + + dev_priv->pipe_crc[pipe].source = source; + + switch (source) { + case INTEL_PIPE_CRC_SOURCE_PLANE1: + val = PIPE_CRC_ENABLE | PIPE_CRC_SOURCE_PRIMARY_IVB; + break; + case INTEL_PIPE_CRC_SOURCE_PLANE2: + val = PIPE_CRC_ENABLE | PIPE_CRC_SOURCE_SPRITE_IVB; + break; + case INTEL_PIPE_CRC_SOURCE_PF: + val = PIPE_CRC_ENABLE | PIPE_CRC_SOURCE_PF_IVB; + break; + case INTEL_PIPE_CRC_SOURCE_NONE: + default: + val = 0; + break; + } + + I915_WRITE(PIPE_CRC_CTL(pipe), val); + POSTING_READ(PIPE_CRC_CTL(pipe)); + + return 0; +} + +/* + * Parse pipe CRC command strings: + * command: wsp* pipe wsp+ source wsp* + * pipe: (A | B | C) + * source: (none | plane1 | plane2 | pf) + * wsp: (#0x20 | #0x9 | #0xA)+ + * + * eg.: + * "A plane1" -> Start CRC computations on plane1 of pipe A + * "A none" -> Stop CRC + */ +static int pipe_crc_ctl_tokenize(char *buf, char *words[], int max_words) +{ + int n_words = 0; + + while (*buf) { + char *end; + + /* skip leading white space */ + buf = skip_spaces(buf); + if (!*buf) + break; /* end of buffer */ + + /* find end of word */ + for (end = buf; *end && !isspace(*end); end++) + ; + + if (n_words == max_words) { + DRM_DEBUG_DRIVER("too many words, allowed <= %d\n", + max_words); + return -EINVAL; /* ran out of words[] before bytes */ + } + + if (*end) + *end++ = '\0'; + words[n_words++] = buf; + buf = end; + } + + return n_words; +} + +static int pipe_crc_ctl_parse_pipe(const char *buf, enum pipe *pipe) +{ + const char name = buf[0]; + + if (name < 'A' || name >= pipe_name(I915_MAX_PIPES)) + return -EINVAL; + + *pipe = name - 'A'; + + return 0; +} + +static int +pipe_crc_ctl_parse_source(const char *buf, enum intel_pipe_crc_source *source) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(pipe_crc_sources); i++) + if (!strcmp(buf, pipe_crc_sources[i])) { + *source = i; + return 0; + } + + return -EINVAL; +} + +static int pipe_crc_ctl_parse(struct drm_device *dev, char *buf, size_t len) +{ +#define MAX_WORDS 2 + int n_words; + char *words[MAX_WORDS]; + enum pipe pipe; + enum intel_pipe_crc_source source; + + n_words = pipe_crc_ctl_tokenize(buf, words, MAX_WORDS); + if (n_words != 2) { + DRM_DEBUG_DRIVER("tokenize failed, a command is 2 words\n"); + return -EINVAL; + } + + if (pipe_crc_ctl_parse_pipe(words[0], &pipe) < 0) { + DRM_DEBUG_DRIVER("unknown pipe %s\n", words[0]); + return -EINVAL; + } + + if (pipe_crc_ctl_parse_source(words[1], &source) < 0) { + DRM_DEBUG_DRIVER("unknown source %s\n", words[1]); + return -EINVAL; + } + + return pipe_crc_set_source(dev, pipe, source); +} + +static ssize_t pipe_crc_ctl_write(struct file *file, const char __user *ubuf, + size_t len, loff_t *offp) +{ + struct seq_file *m = file->private_data; + struct drm_device *dev = m->private; + char *tmpbuf; + int ret; + + if (len == 0) + return 0; + + if (len > PAGE_SIZE - 1) { + DRM_DEBUG_DRIVER("expected <%lu bytes into pipe crc control\n", + PAGE_SIZE); + return -E2BIG; + } + + tmpbuf = kmalloc(len + 1, GFP_KERNEL); + if (!tmpbuf) + return -ENOMEM; + + if (copy_from_user(tmpbuf, ubuf, len)) { + ret = -EFAULT; + goto out; + } + tmpbuf[len] = '\0'; + + ret = pipe_crc_ctl_parse(dev, tmpbuf, len); + +out: + kfree(tmpbuf); + if (ret < 0) + return ret; + + *offp += len; + return len; +} + +static const struct file_operations i915_pipe_crc_ctl_fops = { + .owner = THIS_MODULE, + .open = pipe_crc_ctl_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, + .write = pipe_crc_ctl_write +}; + static int i915_wedged_get(void *data, u64 *val) { @@ -2297,6 +2509,7 @@ static struct i915_debugfs_files { {"i915_gem_drop_caches", &i915_drop_caches_fops}, {"i915_error_state", &i915_error_state_fops}, {"i915_next_seqno", &i915_next_seqno_fops}, + {"i915_pipe_crc_ctl", &i915_pipe_crc_ctl_fops}, }; int i915_debugfs_init(struct drm_minor *minor) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index b040ef82208f..bfaaaaee8a5b 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1217,6 +1217,14 @@ struct i915_package_c8 { } regsave; }; +enum intel_pipe_crc_source { + INTEL_PIPE_CRC_SOURCE_NONE, + INTEL_PIPE_CRC_SOURCE_PLANE1, + INTEL_PIPE_CRC_SOURCE_PLANE2, + INTEL_PIPE_CRC_SOURCE_PF, + INTEL_PIPE_CRC_SOURCE_MAX, +}; + struct intel_pipe_crc_entry { uint32_t timestamp; uint32_t crc[5]; @@ -1225,6 +1233,7 @@ struct intel_pipe_crc_entry { #define INTEL_PIPE_CRC_ENTRIES_NR 200 struct intel_pipe_crc { struct intel_pipe_crc_entry entries[INTEL_PIPE_CRC_ENTRIES_NR]; + enum intel_pipe_crc_source source; atomic_t slot; }; -- cgit v1.2.2 From b2c88f5b1dea77b57759387728917a124eb1c098 Mon Sep 17 00:00:00 2001 From: Damien Lespiau Date: Tue, 15 Oct 2013 18:55:29 +0100 Subject: drm/i915: Keep the CRC values into a circular buffer There are a few good properties to a circular buffer, for instance it has a number of entries (before we were always dumping the full buffer). Signed-off-by: Damien Lespiau Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_debugfs.c | 20 ++++++++++++-------- drivers/gpu/drm/i915/i915_drv.h | 4 ++-- drivers/gpu/drm/i915/i915_irq.c | 19 +++++++++++++++---- 3 files changed, 29 insertions(+), 14 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index 0d8a9a397a24..991abff94e1e 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -27,6 +27,7 @@ */ #include +#include #include #include #include @@ -1739,25 +1740,28 @@ static int i915_pipe_crc(struct seq_file *m, void *data) struct drm_device *dev = node->minor->dev; struct drm_i915_private *dev_priv = dev->dev_private; enum pipe pipe = (enum pipe)node->info_ent->data; - const struct intel_pipe_crc *pipe_crc = &dev_priv->pipe_crc[pipe]; - int i; - int start; + struct intel_pipe_crc *pipe_crc = &dev_priv->pipe_crc[pipe]; + int head, tail; if (dev_priv->pipe_crc[pipe].source == INTEL_PIPE_CRC_SOURCE_NONE) { seq_puts(m, "none\n"); return 0; } - start = atomic_read(&pipe_crc->slot) + 1; seq_puts(m, " timestamp CRC1 CRC2 CRC3 CRC4 CRC5\n"); - for (i = 0; i < INTEL_PIPE_CRC_ENTRIES_NR; i++) { - const struct intel_pipe_crc_entry *entry = - &pipe_crc->entries[(start + i) % - INTEL_PIPE_CRC_ENTRIES_NR]; + head = atomic_read(&pipe_crc->head); + tail = atomic_read(&pipe_crc->tail); + + while (CIRC_CNT(head, tail, INTEL_PIPE_CRC_ENTRIES_NR) >= 1) { + struct intel_pipe_crc_entry *entry = &pipe_crc->entries[tail]; seq_printf(m, "%12u %8x %8x %8x %8x %8x\n", entry->timestamp, entry->crc[0], entry->crc[1], entry->crc[2], entry->crc[3], entry->crc[4]); + + BUILD_BUG_ON_NOT_POWER_OF_2(INTEL_PIPE_CRC_ENTRIES_NR); + tail = (tail + 1) & (INTEL_PIPE_CRC_ENTRIES_NR - 1); + atomic_set(&pipe_crc->tail, tail); } return 0; diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index bfaaaaee8a5b..a29a4a1d300a 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1230,11 +1230,11 @@ struct intel_pipe_crc_entry { uint32_t crc[5]; }; -#define INTEL_PIPE_CRC_ENTRIES_NR 200 +#define INTEL_PIPE_CRC_ENTRIES_NR 128 struct intel_pipe_crc { struct intel_pipe_crc_entry entries[INTEL_PIPE_CRC_ENTRIES_NR]; enum intel_pipe_crc_source source; - atomic_t slot; + atomic_t head, tail; }; typedef struct drm_i915_private { diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index d2074f129a36..73d76af13ed4 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -30,6 +30,7 @@ #include #include +#include #include #include #include "i915_drv.h" @@ -1195,20 +1196,30 @@ static void ivb_pipe_crc_update(struct drm_device *dev, enum pipe pipe) struct intel_pipe_crc *pipe_crc = &dev_priv->pipe_crc[pipe]; struct intel_pipe_crc_entry *entry; ktime_t now; - int ts, slot; + int ts, head, tail; + + head = atomic_read(&pipe_crc->head); + tail = atomic_read(&pipe_crc->tail); + + if (CIRC_SPACE(head, tail, INTEL_PIPE_CRC_ENTRIES_NR) < 1) { + DRM_ERROR("CRC buffer overflowing\n"); + return; + } + + entry = &pipe_crc->entries[head]; now = ktime_get(); ts = ktime_to_us(now); - slot = (atomic_read(&pipe_crc->slot) + 1) % INTEL_PIPE_CRC_ENTRIES_NR; - entry = &pipe_crc->entries[slot]; entry->timestamp = ts; entry->crc[0] = I915_READ(PIPE_CRC_RES_1_IVB(pipe)); entry->crc[1] = I915_READ(PIPE_CRC_RES_2_IVB(pipe)); entry->crc[2] = I915_READ(PIPE_CRC_RES_3_IVB(pipe)); entry->crc[3] = I915_READ(PIPE_CRC_RES_4_IVB(pipe)); entry->crc[4] = I915_READ(PIPE_CRC_RES_5_IVB(pipe)); - atomic_set(&dev_priv->pipe_crc[pipe].slot, slot); + + head = (head + 1) & (INTEL_PIPE_CRC_ENTRIES_NR - 1); + atomic_set(&pipe_crc->head, head); } #else static void ivb_pipe_crc_update(struct drm_device *dev, int pipe) {} -- cgit v1.2.2 From ac2300d4d5c2e9e4d82361a582cf1df3ec22fec7 Mon Sep 17 00:00:00 2001 From: Damien Lespiau Date: Tue, 15 Oct 2013 18:55:30 +0100 Subject: drm/i915: Sample the frame counter instead of a timestamp for CRCs Signed-off-by: Damien Lespiau Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_debugfs.c | 4 ++-- drivers/gpu/drm/i915/i915_drv.h | 2 +- drivers/gpu/drm/i915/i915_irq.c | 8 ++------ 3 files changed, 5 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index 991abff94e1e..58c6fd4c8610 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -1748,14 +1748,14 @@ static int i915_pipe_crc(struct seq_file *m, void *data) return 0; } - seq_puts(m, " timestamp CRC1 CRC2 CRC3 CRC4 CRC5\n"); + seq_puts(m, " frame CRC1 CRC2 CRC3 CRC4 CRC5\n"); head = atomic_read(&pipe_crc->head); tail = atomic_read(&pipe_crc->tail); while (CIRC_CNT(head, tail, INTEL_PIPE_CRC_ENTRIES_NR) >= 1) { struct intel_pipe_crc_entry *entry = &pipe_crc->entries[tail]; - seq_printf(m, "%12u %8x %8x %8x %8x %8x\n", entry->timestamp, + seq_printf(m, "%8u %8x %8x %8x %8x %8x\n", entry->frame, entry->crc[0], entry->crc[1], entry->crc[2], entry->crc[3], entry->crc[4]); diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index a29a4a1d300a..f8a36d038457 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1226,7 +1226,7 @@ enum intel_pipe_crc_source { }; struct intel_pipe_crc_entry { - uint32_t timestamp; + uint32_t frame; uint32_t crc[5]; }; diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 73d76af13ed4..0b218285c2c1 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -1195,8 +1195,7 @@ static void ivb_pipe_crc_update(struct drm_device *dev, enum pipe pipe) struct drm_i915_private *dev_priv = dev->dev_private; struct intel_pipe_crc *pipe_crc = &dev_priv->pipe_crc[pipe]; struct intel_pipe_crc_entry *entry; - ktime_t now; - int ts, head, tail; + int head, tail; head = atomic_read(&pipe_crc->head); tail = atomic_read(&pipe_crc->tail); @@ -1208,10 +1207,7 @@ static void ivb_pipe_crc_update(struct drm_device *dev, enum pipe pipe) entry = &pipe_crc->entries[head]; - now = ktime_get(); - ts = ktime_to_us(now); - - entry->timestamp = ts; + entry->frame = I915_READ(PIPEFRAME(pipe)); entry->crc[0] = I915_READ(PIPE_CRC_RES_1_IVB(pipe)); entry->crc[1] = I915_READ(PIPE_CRC_RES_2_IVB(pipe)); entry->crc[2] = I915_READ(PIPE_CRC_RES_3_IVB(pipe)); -- cgit v1.2.2 From cc3da175b0807a3e15f0fb3dad2bc9c7ff071440 Mon Sep 17 00:00:00 2001 From: Damien Lespiau Date: Tue, 15 Oct 2013 18:55:31 +0100 Subject: drm/i915: Make switching to the same CRC source a no-op Signed-off-by: Damien Lespiau Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_debugfs.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index 58c6fd4c8610..8c750d5110a1 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -1804,6 +1804,7 @@ static int pipe_crc_set_source(struct drm_device *dev, enum pipe pipe, enum intel_pipe_crc_source source) { struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_pipe_crc *pipe_crc = &dev_priv->pipe_crc[pipe]; u32 val; @@ -1812,7 +1813,10 @@ static int pipe_crc_set_source(struct drm_device *dev, enum pipe pipe, if (!IS_IVYBRIDGE(dev)) return -ENODEV; - dev_priv->pipe_crc[pipe].source = source; + if (pipe_crc->source == source) + return 0; + + pipe_crc->source = source; switch (source) { case INTEL_PIPE_CRC_SOURCE_PLANE1: -- cgit v1.2.2 From ae676fcd2a93bf1809cddbd79e37b37609791dc2 Mon Sep 17 00:00:00 2001 From: Damien Lespiau Date: Tue, 15 Oct 2013 18:55:32 +0100 Subject: drm/i915: Enforce going back to none before changing CRC source This way we can have some init/fini code on those transitions. Signed-off-by: Damien Lespiau Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_debugfs.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index 8c750d5110a1..787c50d194d4 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -1816,6 +1816,10 @@ static int pipe_crc_set_source(struct drm_device *dev, enum pipe pipe, if (pipe_crc->source == source) return 0; + /* forbid changing the source without going back to 'none' */ + if (pipe_crc->source && source) + return -EINVAL; + pipe_crc->source = source; switch (source) { -- cgit v1.2.2 From 4b584369c6d6b75c9dbfeeb0896853874d031897 Mon Sep 17 00:00:00 2001 From: Damien Lespiau Date: Tue, 15 Oct 2013 18:55:33 +0100 Subject: drm/i915: Empty the circular buffer when asked for a new source So we don't read out stale CRCs from a previous run left in the buffer. Signed-off-by: Damien Lespiau Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_debugfs.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index 787c50d194d4..ec9151afa240 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -1820,6 +1820,12 @@ static int pipe_crc_set_source(struct drm_device *dev, enum pipe pipe, if (pipe_crc->source && source) return -EINVAL; + /* none -> real source transition */ + if (source) { + atomic_set(&pipe_crc->head, 0); + atomic_set(&pipe_crc->tail, 0); + } + pipe_crc->source = source; switch (source) { -- cgit v1.2.2 From e5f75aca193837c57a886c3fb83442fda88142e9 Mon Sep 17 00:00:00 2001 From: Damien Lespiau Date: Tue, 15 Oct 2013 18:55:34 +0100 Subject: drm/i915: Dynamically allocate the CRC circular buffer So we don't eat that memory when not needed. Signed-off-by: Damien Lespiau Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_debugfs.c | 12 ++++++++++++ drivers/gpu/drm/i915/i915_drv.h | 2 +- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index ec9151afa240..53a3f2224d1f 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -1822,6 +1822,12 @@ static int pipe_crc_set_source(struct drm_device *dev, enum pipe pipe, /* none -> real source transition */ if (source) { + pipe_crc->entries = kzalloc(sizeof(*pipe_crc->entries) * + INTEL_PIPE_CRC_ENTRIES_NR, + GFP_KERNEL); + if (!pipe_crc->entries) + return -ENOMEM; + atomic_set(&pipe_crc->head, 0); atomic_set(&pipe_crc->tail, 0); } @@ -1847,6 +1853,12 @@ static int pipe_crc_set_source(struct drm_device *dev, enum pipe pipe, I915_WRITE(PIPE_CRC_CTL(pipe), val); POSTING_READ(PIPE_CRC_CTL(pipe)); + /* real source -> none transition */ + if (source == INTEL_PIPE_CRC_SOURCE_NONE) { + kfree(pipe_crc->entries); + pipe_crc->entries = NULL; + } + return 0; } diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index f8a36d038457..1faeaac5f9f3 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1232,7 +1232,7 @@ struct intel_pipe_crc_entry { #define INTEL_PIPE_CRC_ENTRIES_NR 128 struct intel_pipe_crc { - struct intel_pipe_crc_entry entries[INTEL_PIPE_CRC_ENTRIES_NR]; + struct intel_pipe_crc_entry *entries; enum intel_pipe_crc_source source; atomic_t head, tail; }; -- cgit v1.2.2 From b94dec877f97d22a27096d0c3d399c1427157aa2 Mon Sep 17 00:00:00 2001 From: Damien Lespiau Date: Tue, 15 Oct 2013 18:55:35 +0100 Subject: drm/i915: Generalize the CRC command format for future work Let's move from writing 'A plane1' to 'pipe A plane1' to i915_pipe_crc_ctl. This will allow us to extend the interface to transcoders or DDIs in the future. Signed-off-by: Damien Lespiau Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_debugfs.c | 56 ++++++++++++++++++++++++++++--------- 1 file changed, 43 insertions(+), 13 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index 53a3f2224d1f..c609783dd9d3 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -1864,14 +1864,15 @@ static int pipe_crc_set_source(struct drm_device *dev, enum pipe pipe, /* * Parse pipe CRC command strings: - * command: wsp* pipe wsp+ source wsp* - * pipe: (A | B | C) + * command: wsp* object wsp+ name wsp+ source wsp* + * object: 'pipe' + * name: (A | B | C) * source: (none | plane1 | plane2 | pf) * wsp: (#0x20 | #0x9 | #0xA)+ * * eg.: - * "A plane1" -> Start CRC computations on plane1 of pipe A - * "A none" -> Stop CRC + * "pipe A plane1" -> Start CRC computations on plane1 of pipe A + * "pipe A none" -> Stop CRC */ static int pipe_crc_ctl_tokenize(char *buf, char *words[], int max_words) { @@ -1904,6 +1905,28 @@ static int pipe_crc_ctl_tokenize(char *buf, char *words[], int max_words) return n_words; } +enum intel_pipe_crc_object { + PIPE_CRC_OBJECT_PIPE, +}; + +static const char *pipe_crc_objects[] = { + "pipe", +}; + +static int +pipe_crc_ctl_parse_object(const char *buf, enum intel_pipe_crc_object *object) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(pipe_crc_objects); i++) + if (!strcmp(buf, pipe_crc_objects[i])) { + *object = i; + return 0; + } + + return -EINVAL; +} + static int pipe_crc_ctl_parse_pipe(const char *buf, enum pipe *pipe) { const char name = buf[0]; @@ -1932,25 +1955,32 @@ pipe_crc_ctl_parse_source(const char *buf, enum intel_pipe_crc_source *source) static int pipe_crc_ctl_parse(struct drm_device *dev, char *buf, size_t len) { -#define MAX_WORDS 2 +#define N_WORDS 3 int n_words; - char *words[MAX_WORDS]; + char *words[N_WORDS]; enum pipe pipe; + enum intel_pipe_crc_object object; enum intel_pipe_crc_source source; - n_words = pipe_crc_ctl_tokenize(buf, words, MAX_WORDS); - if (n_words != 2) { - DRM_DEBUG_DRIVER("tokenize failed, a command is 2 words\n"); + n_words = pipe_crc_ctl_tokenize(buf, words, N_WORDS); + if (n_words != N_WORDS) { + DRM_DEBUG_DRIVER("tokenize failed, a command is %d words\n", + N_WORDS); + return -EINVAL; + } + + if (pipe_crc_ctl_parse_object(words[0], &object) < 0) { + DRM_DEBUG_DRIVER("unknown object %s\n", words[0]); return -EINVAL; } - if (pipe_crc_ctl_parse_pipe(words[0], &pipe) < 0) { - DRM_DEBUG_DRIVER("unknown pipe %s\n", words[0]); + if (pipe_crc_ctl_parse_pipe(words[1], &pipe) < 0) { + DRM_DEBUG_DRIVER("unknown pipe %s\n", words[1]); return -EINVAL; } - if (pipe_crc_ctl_parse_source(words[1], &source) < 0) { - DRM_DEBUG_DRIVER("unknown source %s\n", words[1]); + if (pipe_crc_ctl_parse_source(words[2], &source) < 0) { + DRM_DEBUG_DRIVER("unknown source %s\n", words[2]); return -EINVAL; } -- cgit v1.2.2 From bd9db02ffcf33348f3fb5d33b8623e78d7831d66 Mon Sep 17 00:00:00 2001 From: Damien Lespiau Date: Tue, 15 Oct 2013 18:55:36 +0100 Subject: drm/i915: Rename i915_pipe_crc_ctl to i915_display_crc_ctl In the same spirit than: drm/i915: Generalize the CRC command format for future work Let's move from writing 'A plane1' to 'pipe A plane1' to i915_pipe_crc_ctl. This will allow us to extend the interface to transcoders or DDIs in the future. Let's rename the CRC control file to be more generic. Signed-off-by: Damien Lespiau Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_debugfs.c | 42 ++++++++++++++++++------------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index c609783dd9d3..471c2585e5bc 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -1780,7 +1780,7 @@ static const char *pipe_crc_source_name(enum intel_pipe_crc_source source) return pipe_crc_sources[source]; } -static int pipe_crc_ctl_show(struct seq_file *m, void *data) +static int display_crc_ctl_show(struct seq_file *m, void *data) { struct drm_device *dev = m->private; struct drm_i915_private *dev_priv = dev->dev_private; @@ -1793,11 +1793,11 @@ static int pipe_crc_ctl_show(struct seq_file *m, void *data) return 0; } -static int pipe_crc_ctl_open(struct inode *inode, struct file *file) +static int display_crc_ctl_open(struct inode *inode, struct file *file) { struct drm_device *dev = inode->i_private; - return single_open(file, pipe_crc_ctl_show, dev); + return single_open(file, display_crc_ctl_show, dev); } static int pipe_crc_set_source(struct drm_device *dev, enum pipe pipe, @@ -1874,7 +1874,7 @@ static int pipe_crc_set_source(struct drm_device *dev, enum pipe pipe, * "pipe A plane1" -> Start CRC computations on plane1 of pipe A * "pipe A none" -> Stop CRC */ -static int pipe_crc_ctl_tokenize(char *buf, char *words[], int max_words) +static int display_crc_ctl_tokenize(char *buf, char *words[], int max_words) { int n_words = 0; @@ -1914,20 +1914,20 @@ static const char *pipe_crc_objects[] = { }; static int -pipe_crc_ctl_parse_object(const char *buf, enum intel_pipe_crc_object *object) +display_crc_ctl_parse_object(const char *buf, enum intel_pipe_crc_object *o) { int i; for (i = 0; i < ARRAY_SIZE(pipe_crc_objects); i++) if (!strcmp(buf, pipe_crc_objects[i])) { - *object = i; + *o = i; return 0; } return -EINVAL; } -static int pipe_crc_ctl_parse_pipe(const char *buf, enum pipe *pipe) +static int display_crc_ctl_parse_pipe(const char *buf, enum pipe *pipe) { const char name = buf[0]; @@ -1940,20 +1940,20 @@ static int pipe_crc_ctl_parse_pipe(const char *buf, enum pipe *pipe) } static int -pipe_crc_ctl_parse_source(const char *buf, enum intel_pipe_crc_source *source) +display_crc_ctl_parse_source(const char *buf, enum intel_pipe_crc_source *s) { int i; for (i = 0; i < ARRAY_SIZE(pipe_crc_sources); i++) if (!strcmp(buf, pipe_crc_sources[i])) { - *source = i; + *s = i; return 0; } return -EINVAL; } -static int pipe_crc_ctl_parse(struct drm_device *dev, char *buf, size_t len) +static int display_crc_ctl_parse(struct drm_device *dev, char *buf, size_t len) { #define N_WORDS 3 int n_words; @@ -1962,24 +1962,24 @@ static int pipe_crc_ctl_parse(struct drm_device *dev, char *buf, size_t len) enum intel_pipe_crc_object object; enum intel_pipe_crc_source source; - n_words = pipe_crc_ctl_tokenize(buf, words, N_WORDS); + n_words = display_crc_ctl_tokenize(buf, words, N_WORDS); if (n_words != N_WORDS) { DRM_DEBUG_DRIVER("tokenize failed, a command is %d words\n", N_WORDS); return -EINVAL; } - if (pipe_crc_ctl_parse_object(words[0], &object) < 0) { + if (display_crc_ctl_parse_object(words[0], &object) < 0) { DRM_DEBUG_DRIVER("unknown object %s\n", words[0]); return -EINVAL; } - if (pipe_crc_ctl_parse_pipe(words[1], &pipe) < 0) { + if (display_crc_ctl_parse_pipe(words[1], &pipe) < 0) { DRM_DEBUG_DRIVER("unknown pipe %s\n", words[1]); return -EINVAL; } - if (pipe_crc_ctl_parse_source(words[2], &source) < 0) { + if (display_crc_ctl_parse_source(words[2], &source) < 0) { DRM_DEBUG_DRIVER("unknown source %s\n", words[2]); return -EINVAL; } @@ -1987,8 +1987,8 @@ static int pipe_crc_ctl_parse(struct drm_device *dev, char *buf, size_t len) return pipe_crc_set_source(dev, pipe, source); } -static ssize_t pipe_crc_ctl_write(struct file *file, const char __user *ubuf, - size_t len, loff_t *offp) +static ssize_t display_crc_ctl_write(struct file *file, const char __user *ubuf, + size_t len, loff_t *offp) { struct seq_file *m = file->private_data; struct drm_device *dev = m->private; @@ -2014,7 +2014,7 @@ static ssize_t pipe_crc_ctl_write(struct file *file, const char __user *ubuf, } tmpbuf[len] = '\0'; - ret = pipe_crc_ctl_parse(dev, tmpbuf, len); + ret = display_crc_ctl_parse(dev, tmpbuf, len); out: kfree(tmpbuf); @@ -2025,13 +2025,13 @@ out: return len; } -static const struct file_operations i915_pipe_crc_ctl_fops = { +static const struct file_operations i915_display_crc_ctl_fops = { .owner = THIS_MODULE, - .open = pipe_crc_ctl_open, + .open = display_crc_ctl_open, .read = seq_read, .llseek = seq_lseek, .release = single_release, - .write = pipe_crc_ctl_write + .write = display_crc_ctl_write }; static int @@ -2569,7 +2569,7 @@ static struct i915_debugfs_files { {"i915_gem_drop_caches", &i915_drop_caches_fops}, {"i915_error_state", &i915_error_state_fops}, {"i915_next_seqno", &i915_next_seqno_fops}, - {"i915_pipe_crc_ctl", &i915_pipe_crc_ctl_fops}, + {"i915_display_crc_ctl", &i915_display_crc_ctl_fops}, }; int i915_debugfs_init(struct drm_minor *minor) -- cgit v1.2.2 From 0c912c79eede0ba3dcc717a6e13de8766404c736 Mon Sep 17 00:00:00 2001 From: Damien Lespiau Date: Tue, 15 Oct 2013 18:55:37 +0100 Subject: drm/i915: Warn if we receive an interrupt after freeing the buffer This shouldn't happen as the buffer is freed after disable pipe CRCs, but better be safe than sorry. Signed-off-by: Damien Lespiau Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_irq.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 0b218285c2c1..b201a214279e 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -1197,6 +1197,11 @@ static void ivb_pipe_crc_update(struct drm_device *dev, enum pipe pipe) struct intel_pipe_crc_entry *entry; int head, tail; + if (!pipe_crc->entries) { + DRM_ERROR("spurious interrupt\n"); + return; + } + head = atomic_read(&pipe_crc->head); tail = atomic_read(&pipe_crc->tail); -- cgit v1.2.2 From 7cd6ccff85a13a8e5755cffa50129032d83c7c72 Mon Sep 17 00:00:00 2001 From: Damien Lespiau Date: Tue, 15 Oct 2013 18:55:38 +0100 Subject: drm/i915: Add log messages when CRCs collection is started/stopped Signed-off-by: Damien Lespiau Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_debugfs.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index 471c2585e5bc..dee85d7ab52f 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -1822,6 +1822,9 @@ static int pipe_crc_set_source(struct drm_device *dev, enum pipe pipe, /* none -> real source transition */ if (source) { + DRM_DEBUG_DRIVER("collecting CRCs for pipe %c, %s\n", + pipe_name(pipe), pipe_crc_source_name(source)); + pipe_crc->entries = kzalloc(sizeof(*pipe_crc->entries) * INTEL_PIPE_CRC_ENTRIES_NR, GFP_KERNEL); @@ -1855,6 +1858,9 @@ static int pipe_crc_set_source(struct drm_device *dev, enum pipe pipe, /* real source -> none transition */ if (source == INTEL_PIPE_CRC_SOURCE_NONE) { + DRM_DEBUG_DRIVER("stopping CRCs for pipe %c\n", + pipe_name(pipe)); + kfree(pipe_crc->entries); pipe_crc->entries = NULL; } -- cgit v1.2.2 From 497666d80587933fc65dbe40d8fe6b6cc89ac9ad Mon Sep 17 00:00:00 2001 From: Damien Lespiau Date: Tue, 15 Oct 2013 18:55:39 +0100 Subject: drm/i915: Move drm_add_fake_info_node() higher in the file Following commit needs drm_add_fake_info_node() higher in the file to avoid having a forward declaration. Move this helper near the top of the file. This also makes the next commit diff a bit easier to review. Signed-off-by: Damien Lespiau Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_debugfs.c | 52 ++++++++++++++++++------------------- 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index dee85d7ab52f..baa2e430bd5b 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -53,6 +53,32 @@ static const char *yesno(int v) return v ? "yes" : "no"; } +/* As the drm_debugfs_init() routines are called before dev->dev_private is + * allocated we need to hook into the minor for release. */ +static int +drm_add_fake_info_node(struct drm_minor *minor, + struct dentry *ent, + const void *key) +{ + struct drm_info_node *node; + + node = kmalloc(sizeof(*node), GFP_KERNEL); + if (node == NULL) { + debugfs_remove(ent); + return -ENOMEM; + } + + node->minor = minor; + node->dent = ent; + node->info_ent = (void *) key; + + mutex_lock(&minor->debugfs_lock); + list_add(&node->list, &minor->debugfs_list); + mutex_unlock(&minor->debugfs_lock); + + return 0; +} + static int i915_capabilities(struct seq_file *m, void *data) { struct drm_info_node *node = (struct drm_info_node *) m->private; @@ -2425,32 +2451,6 @@ DEFINE_SIMPLE_ATTRIBUTE(i915_cache_sharing_fops, i915_cache_sharing_get, i915_cache_sharing_set, "%llu\n"); -/* As the drm_debugfs_init() routines are called before dev->dev_private is - * allocated we need to hook into the minor for release. */ -static int -drm_add_fake_info_node(struct drm_minor *minor, - struct dentry *ent, - const void *key) -{ - struct drm_info_node *node; - - node = kmalloc(sizeof(*node), GFP_KERNEL); - if (node == NULL) { - debugfs_remove(ent); - return -ENOMEM; - } - - node->minor = minor; - node->dent = ent; - node->info_ent = (void *) key; - - mutex_lock(&minor->debugfs_lock); - list_add(&node->list, &minor->debugfs_list); - mutex_unlock(&minor->debugfs_lock); - - return 0; -} - static int i915_forcewake_open(struct inode *inode, struct file *file) { struct drm_device *dev = inode->i_private; -- cgit v1.2.2 From 071444280bcbb96ec38a1fb1ee3924ca7860844a Mon Sep 17 00:00:00 2001 From: Damien Lespiau Date: Tue, 15 Oct 2013 18:55:40 +0100 Subject: drm/i915: Implement blocking read for pipe CRC files seq_file is not quite the right interface for these ones. We have a circular buffer with a new entry per vblank on one side and a process wanting to dequeue the CRC with a read(). It's quite racy to wait for vblank in user land and then try to read a pipe_crc file, sometimes the CRC interrupt hasn't been fired and we end up with an EOF. So, let's have the read on the pipe_crc file block until the interrupt gives us a new entry. At that point we can wake the reading process. Signed-off-by: Damien Lespiau Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_debugfs.c | 164 +++++++++++++++++++++++++++++++----- drivers/gpu/drm/i915/i915_dma.c | 2 + drivers/gpu/drm/i915/i915_drv.h | 6 ++ drivers/gpu/drm/i915/i915_irq.c | 2 + 4 files changed, 155 insertions(+), 19 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index baa2e430bd5b..5137f8f97b8a 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -1760,37 +1760,138 @@ static int i915_pc8_status(struct seq_file *m, void *unused) return 0; } -static int i915_pipe_crc(struct seq_file *m, void *data) +struct pipe_crc_info { + const char *name; + struct drm_device *dev; + enum pipe pipe; +}; + +static int i915_pipe_crc_open(struct inode *inode, struct file *filep) +{ + filep->private_data = inode->i_private; + + return 0; +} + +static int i915_pipe_crc_release(struct inode *inode, struct file *filep) +{ + return 0; +} + +/* (6 fields, 8 chars each, space separated (5) + '\n') */ +#define PIPE_CRC_LINE_LEN (6 * 8 + 5 + 1) +/* account for \'0' */ +#define PIPE_CRC_BUFFER_LEN (PIPE_CRC_LINE_LEN + 1) + +static int pipe_crc_data_count(struct intel_pipe_crc *pipe_crc) { - struct drm_info_node *node = (struct drm_info_node *) m->private; - struct drm_device *dev = node->minor->dev; - struct drm_i915_private *dev_priv = dev->dev_private; - enum pipe pipe = (enum pipe)node->info_ent->data; - struct intel_pipe_crc *pipe_crc = &dev_priv->pipe_crc[pipe]; int head, tail; - if (dev_priv->pipe_crc[pipe].source == INTEL_PIPE_CRC_SOURCE_NONE) { - seq_puts(m, "none\n"); + head = atomic_read(&pipe_crc->head); + tail = atomic_read(&pipe_crc->tail); + + return CIRC_CNT(head, tail, INTEL_PIPE_CRC_ENTRIES_NR); +} + +static ssize_t +i915_pipe_crc_read(struct file *filep, char __user *user_buf, size_t count, + loff_t *pos) +{ + struct pipe_crc_info *info = filep->private_data; + struct drm_device *dev = info->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_pipe_crc *pipe_crc = &dev_priv->pipe_crc[info->pipe]; + char buf[PIPE_CRC_BUFFER_LEN]; + int head, tail, n_entries, n; + ssize_t bytes_read; + + /* + * Don't allow user space to provide buffers not big enough to hold + * a line of data. + */ + if (count < PIPE_CRC_LINE_LEN) + return -EINVAL; + + if (pipe_crc->source == INTEL_PIPE_CRC_SOURCE_NONE) return 0; + + /* nothing to read */ + while (pipe_crc_data_count(pipe_crc) == 0) { + if (filep->f_flags & O_NONBLOCK) + return -EAGAIN; + + if (wait_event_interruptible(pipe_crc->wq, + pipe_crc_data_count(pipe_crc))) + return -ERESTARTSYS; } - seq_puts(m, " frame CRC1 CRC2 CRC3 CRC4 CRC5\n"); + /* We now have one or more entries to read */ head = atomic_read(&pipe_crc->head); tail = atomic_read(&pipe_crc->tail); - - while (CIRC_CNT(head, tail, INTEL_PIPE_CRC_ENTRIES_NR) >= 1) { + n_entries = min((size_t)CIRC_CNT(head, tail, INTEL_PIPE_CRC_ENTRIES_NR), + count / PIPE_CRC_LINE_LEN); + bytes_read = 0; + n = 0; + do { struct intel_pipe_crc_entry *entry = &pipe_crc->entries[tail]; + int ret; - seq_printf(m, "%8u %8x %8x %8x %8x %8x\n", entry->frame, - entry->crc[0], entry->crc[1], entry->crc[2], - entry->crc[3], entry->crc[4]); + bytes_read += snprintf(buf, PIPE_CRC_BUFFER_LEN, + "%8u %8x %8x %8x %8x %8x\n", + entry->frame, entry->crc[0], + entry->crc[1], entry->crc[2], + entry->crc[3], entry->crc[4]); + + ret = copy_to_user(user_buf + n * PIPE_CRC_LINE_LEN, + buf, PIPE_CRC_LINE_LEN); + if (ret == PIPE_CRC_LINE_LEN) + return -EFAULT; BUILD_BUG_ON_NOT_POWER_OF_2(INTEL_PIPE_CRC_ENTRIES_NR); tail = (tail + 1) & (INTEL_PIPE_CRC_ENTRIES_NR - 1); atomic_set(&pipe_crc->tail, tail); - } + n++; + } while (--n_entries); - return 0; + return bytes_read; +} + +static const struct file_operations i915_pipe_crc_fops = { + .owner = THIS_MODULE, + .open = i915_pipe_crc_open, + .read = i915_pipe_crc_read, + .release = i915_pipe_crc_release, +}; + +static struct pipe_crc_info i915_pipe_crc_data[I915_MAX_PIPES] = { + { + .name = "i915_pipe_A_crc", + .pipe = PIPE_A, + }, + { + .name = "i915_pipe_B_crc", + .pipe = PIPE_B, + }, + { + .name = "i915_pipe_C_crc", + .pipe = PIPE_C, + }, +}; + +static int i915_pipe_crc_create(struct dentry *root, struct drm_minor *minor, + enum pipe pipe) +{ + struct drm_device *dev = minor->dev; + struct dentry *ent; + struct pipe_crc_info *info = &i915_pipe_crc_data[pipe]; + + info->dev = dev; + ent = debugfs_create_file(info->name, S_IRUGO, root, info, + &i915_pipe_crc_fops); + if (IS_ERR(ent)) + return PTR_ERR(ent); + + return drm_add_fake_info_node(minor, ent, info); } static const char *pipe_crc_sources[] = { @@ -2555,9 +2656,6 @@ static struct drm_info_list i915_debugfs_list[] = { {"i915_edp_psr_status", i915_edp_psr_status, 0}, {"i915_energy_uJ", i915_energy_uJ, 0}, {"i915_pc8_status", i915_pc8_status, 0}, - {"i915_pipe_A_crc", i915_pipe_crc, 0, (void *)PIPE_A}, - {"i915_pipe_B_crc", i915_pipe_crc, 0, (void *)PIPE_B}, - {"i915_pipe_C_crc", i915_pipe_crc, 0, (void *)PIPE_C}, }; #define I915_DEBUGFS_ENTRIES ARRAY_SIZE(i915_debugfs_list) @@ -2578,6 +2676,18 @@ static struct i915_debugfs_files { {"i915_display_crc_ctl", &i915_display_crc_ctl_fops}, }; +void intel_display_crc_init(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + int i; + + for (i = 0; i < INTEL_INFO(dev)->num_pipes; i++) { + struct intel_pipe_crc *pipe_crc = &dev_priv->pipe_crc[i]; + + init_waitqueue_head(&pipe_crc->wq); + } +} + int i915_debugfs_init(struct drm_minor *minor) { int ret, i; @@ -2586,6 +2696,12 @@ int i915_debugfs_init(struct drm_minor *minor) if (ret) return ret; + for (i = 0; i < ARRAY_SIZE(i915_pipe_crc_data); i++) { + ret = i915_pipe_crc_create(minor->debugfs_root, minor, i); + if (ret) + return ret; + } + for (i = 0; i < ARRAY_SIZE(i915_debugfs_files); i++) { ret = i915_debugfs_create(minor->debugfs_root, minor, i915_debugfs_files[i].name, @@ -2601,12 +2717,22 @@ int i915_debugfs_init(struct drm_minor *minor) void i915_debugfs_cleanup(struct drm_minor *minor) { + struct drm_device *dev = minor->dev; int i; drm_debugfs_remove_files(i915_debugfs_list, I915_DEBUGFS_ENTRIES, minor); + drm_debugfs_remove_files((struct drm_info_list *) &i915_forcewake_fops, 1, minor); + + for (i = 0; i < INTEL_INFO(dev)->num_pipes; i++) { + struct drm_info_list *info_list = + (struct drm_info_list *)&i915_pipe_crc_data[i]; + + drm_debugfs_remove_files(info_list, 1, minor); + } + for (i = 0; i < ARRAY_SIZE(i915_debugfs_files); i++) { struct drm_info_list *info_list = (struct drm_info_list *) i915_debugfs_files[i].fops; diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index 42cddc11c23c..9f71bc204e38 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -1514,6 +1514,8 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) dev_priv->pc8.disable_count = 2; /* requirements_met + gpu_idle */ INIT_DELAYED_WORK(&dev_priv->pc8.enable_work, hsw_enable_pc8_work); + intel_display_crc_init(dev); + i915_dump_device_info(dev_priv); /* Not all pre-production machines fall into this category, only the diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 1faeaac5f9f3..7408f1184347 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1235,6 +1235,7 @@ struct intel_pipe_crc { struct intel_pipe_crc_entry *entries; enum intel_pipe_crc_source source; atomic_t head, tail; + wait_queue_head_t wq; }; typedef struct drm_i915_private { @@ -2233,6 +2234,11 @@ int i915_verify_lists(struct drm_device *dev); /* i915_debugfs.c */ int i915_debugfs_init(struct drm_minor *minor); void i915_debugfs_cleanup(struct drm_minor *minor); +#if defined(CONFIG_DEBUG_FS) +void intel_display_crc_init(struct drm_device *dev); +#else +void intel_display_crc_init(struct drm_device *dev) {} +#endif /* i915_gpu_error.c */ __printf(2, 3) diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index b201a214279e..b2be05791b2f 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -1221,6 +1221,8 @@ static void ivb_pipe_crc_update(struct drm_device *dev, enum pipe pipe) head = (head + 1) & (INTEL_PIPE_CRC_ENTRIES_NR - 1); atomic_set(&pipe_crc->head, head); + + wake_up_interruptible(&pipe_crc->wq); } #else static void ivb_pipe_crc_update(struct drm_device *dev, int pipe) {} -- cgit v1.2.2 From be5c7a90753fb9f74c867f74489abe822ffb4b26 Mon Sep 17 00:00:00 2001 From: Damien Lespiau Date: Tue, 15 Oct 2013 18:55:41 +0100 Subject: drm/i915: Only one open() allowed on pipe CRC result files It doesn't really make sense to have two processes dequeueing the CRC values at the same time. Forbid that usage. Signed-off-by: Damien Lespiau Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_debugfs.c | 16 ++++++++++++++++ drivers/gpu/drm/i915/i915_drv.h | 1 + 2 files changed, 17 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index 5137f8f97b8a..826ebcead3c4 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -1768,6 +1768,15 @@ struct pipe_crc_info { static int i915_pipe_crc_open(struct inode *inode, struct file *filep) { + struct pipe_crc_info *info = inode->i_private; + struct drm_i915_private *dev_priv = info->dev->dev_private; + struct intel_pipe_crc *pipe_crc = &dev_priv->pipe_crc[info->pipe]; + + if (!atomic_dec_and_test(&pipe_crc->available)) { + atomic_inc(&pipe_crc->available); + return -EBUSY; /* already open */ + } + filep->private_data = inode->i_private; return 0; @@ -1775,6 +1784,12 @@ static int i915_pipe_crc_open(struct inode *inode, struct file *filep) static int i915_pipe_crc_release(struct inode *inode, struct file *filep) { + struct pipe_crc_info *info = inode->i_private; + struct drm_i915_private *dev_priv = info->dev->dev_private; + struct intel_pipe_crc *pipe_crc = &dev_priv->pipe_crc[info->pipe]; + + atomic_inc(&pipe_crc->available); /* release the device */ + return 0; } @@ -2684,6 +2699,7 @@ void intel_display_crc_init(struct drm_device *dev) for (i = 0; i < INTEL_INFO(dev)->num_pipes; i++) { struct intel_pipe_crc *pipe_crc = &dev_priv->pipe_crc[i]; + atomic_set(&pipe_crc->available, 1); init_waitqueue_head(&pipe_crc->wq); } } diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 7408f1184347..9aeddc0b27b8 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1232,6 +1232,7 @@ struct intel_pipe_crc_entry { #define INTEL_PIPE_CRC_ENTRIES_NR 128 struct intel_pipe_crc { + atomic_t available; /* exclusive access to the device */ struct intel_pipe_crc_entry *entries; enum intel_pipe_crc_source source; atomic_t head, tail; -- cgit v1.2.2 From d8882ac707f1536615d676fd6338d2a27d3911ed Mon Sep 17 00:00:00 2001 From: Damien Lespiau Date: Tue, 15 Oct 2013 18:55:42 +0100 Subject: drm/i915: Enable pipe CRCs It's time to declare them ready. Unleash the beast. Signed-off-by: Damien Lespiau Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_debugfs.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index 826ebcead3c4..d1674b6b749b 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -1949,9 +1949,6 @@ static int pipe_crc_set_source(struct drm_device *dev, enum pipe pipe, struct intel_pipe_crc *pipe_crc = &dev_priv->pipe_crc[pipe]; u32 val; - - return -ENODEV; - if (!IS_IVYBRIDGE(dev)) return -ENODEV; -- cgit v1.2.2 From f8c168fa45b8bbb3ad67768c0f0b6f8054743648 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Wed, 16 Oct 2013 11:49:58 +0200 Subject: drm/i915: static inline for dummy crc functions Also use #ifdef to keep consistent with all other such cases. Cc: Damien Lespiau Acked-by: Damien Lespiau Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 4 ++-- drivers/gpu/drm/i915/i915_irq.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 9aeddc0b27b8..b39a548f6a3c 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -2235,10 +2235,10 @@ int i915_verify_lists(struct drm_device *dev); /* i915_debugfs.c */ int i915_debugfs_init(struct drm_minor *minor); void i915_debugfs_cleanup(struct drm_minor *minor); -#if defined(CONFIG_DEBUG_FS) +#ifdef CONFIG_DEBUG_FS void intel_display_crc_init(struct drm_device *dev); #else -void intel_display_crc_init(struct drm_device *dev) {} +static inline void intel_display_crc_init(struct drm_device *dev) {} #endif /* i915_gpu_error.c */ diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index b2be05791b2f..8c9148c2f82b 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -1225,7 +1225,7 @@ static void ivb_pipe_crc_update(struct drm_device *dev, enum pipe pipe) wake_up_interruptible(&pipe_crc->wq); } #else -static void ivb_pipe_crc_update(struct drm_device *dev, int pipe) {} +static inline void ivb_pipe_crc_update(struct drm_device *dev, int pipe) {} #endif /* The RPS events need forcewake, so we add them to a work queue and mask their -- cgit v1.2.2 From e8dfcf789591965abf3ad72856137c35abe3edc2 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Wed, 16 Oct 2013 11:51:54 +0200 Subject: drm/i915: constify harder We not only want const strings, but a const array of them. Reported by checkpatch.pl Cc: Damien Lespiau Acked-by: Damien Lespiau Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_debugfs.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index d1674b6b749b..5fce5d89b68a 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -1909,7 +1909,7 @@ static int i915_pipe_crc_create(struct dentry *root, struct drm_minor *minor, return drm_add_fake_info_node(minor, ent, info); } -static const char *pipe_crc_sources[] = { +static const char * const pipe_crc_sources[] = { "none", "plane1", "plane2", @@ -2054,7 +2054,7 @@ enum intel_pipe_crc_object { PIPE_CRC_OBJECT_PIPE, }; -static const char *pipe_crc_objects[] = { +static const char * const pipe_crc_objects[] = { "pipe", }; -- cgit v1.2.2 From 9514ac6e7a55328b1fad4b7fc7227d3beb01d7ad Mon Sep 17 00:00:00 2001 From: Chon Ming Lee Date: Wed, 16 Oct 2013 17:07:41 +0800 Subject: drm/i915: Move some hdmi enable function name to vlv specific. There is no functional change on this patch. Only rename several hdmi encoder function name which suppose to use only by valleyview from intel_hdmi_pre_pll_enable to vlv_hdmi_pre_pll_enable, and etc. Signed-off-by: Chon Ming Lee Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_hdmi.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c index 4f4d346db8f0..51a8336dec2e 100644 --- a/drivers/gpu/drm/i915/intel_hdmi.c +++ b/drivers/gpu/drm/i915/intel_hdmi.c @@ -1074,7 +1074,7 @@ done: return 0; } -static void intel_hdmi_pre_enable(struct intel_encoder *encoder) +static void vlv_hdmi_pre_enable(struct intel_encoder *encoder) { struct intel_digital_port *dport = enc_to_dig_port(&encoder->base); struct drm_device *dev = encoder->base.dev; @@ -1127,7 +1127,7 @@ static void intel_hdmi_pre_enable(struct intel_encoder *encoder) vlv_wait_port_ready(dev_priv, port); } -static void intel_hdmi_pre_pll_enable(struct intel_encoder *encoder) +static void vlv_hdmi_pre_pll_enable(struct intel_encoder *encoder) { struct intel_digital_port *dport = enc_to_dig_port(&encoder->base); struct drm_device *dev = encoder->base.dev; @@ -1163,7 +1163,7 @@ static void intel_hdmi_pre_pll_enable(struct intel_encoder *encoder) mutex_unlock(&dev_priv->dpio_lock); } -static void intel_hdmi_post_disable(struct intel_encoder *encoder) +static void vlv_hdmi_post_disable(struct intel_encoder *encoder) { struct intel_digital_port *dport = enc_to_dig_port(&encoder->base); struct drm_i915_private *dev_priv = encoder->base.dev->dev_private; @@ -1313,10 +1313,10 @@ void intel_hdmi_init(struct drm_device *dev, int hdmi_reg, enum port port) intel_encoder->get_hw_state = intel_hdmi_get_hw_state; intel_encoder->get_config = intel_hdmi_get_config; if (IS_VALLEYVIEW(dev)) { - intel_encoder->pre_pll_enable = intel_hdmi_pre_pll_enable; - intel_encoder->pre_enable = intel_hdmi_pre_enable; + intel_encoder->pre_pll_enable = vlv_hdmi_pre_pll_enable; + intel_encoder->pre_enable = vlv_hdmi_pre_enable; intel_encoder->enable = vlv_enable_hdmi; - intel_encoder->post_disable = intel_hdmi_post_disable; + intel_encoder->post_disable = vlv_hdmi_post_disable; } else { intel_encoder->enable = intel_enable_hdmi; } -- cgit v1.2.2 From 45c5f2022c798b2938d4c0d1c14795787f610ccd Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 16 Oct 2013 11:50:01 +0100 Subject: drm/i915: Disable all GEM timers and work on unload We have two once very similar functions, i915_gpu_idle() and i915_gem_idle(). The former is used as the lower level operation to flush work on the GPU, whereas the latter is the high level interface to flush the GEM bookkeeping in addition to flushing the GPU. As such i915_gem_idle() also clears out the request and activity lists and cancels the delayed work. This is what we need for unloading the driver, unfortunately we called i915_gpu_idle() instead. In the process, make sure that when cancelling the delayed work and timer, which is synchronous, that we do not hold any locks to prevent a deadlock if the work item is already waiting upon the mutex. This requires us to push the mutex down from the caller to i915_gem_idle(). v2: s/i915_gem_idle/i915_gem_suspend/ Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=70334 Signed-off-by: Chris Wilson Tested-by: xunx.fang@intel.com [danvet: Only set ums.suspended for !kms as discussed earlier. Chris noticed that this slipped through.] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_dma.c | 8 +------- drivers/gpu/drm/i915/i915_drv.c | 4 +--- drivers/gpu/drm/i915/i915_drv.h | 2 +- drivers/gpu/drm/i915/i915_gem.c | 45 ++++++++++++++++++----------------------- 4 files changed, 23 insertions(+), 36 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index 9f71bc204e38..437886641d90 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -1732,15 +1732,9 @@ int i915_driver_unload(struct drm_device *dev) if (dev_priv->mm.inactive_shrinker.scan_objects) unregister_shrinker(&dev_priv->mm.inactive_shrinker); - mutex_lock(&dev->struct_mutex); - ret = i915_gpu_idle(dev); + ret = i915_gem_suspend(dev); if (ret) DRM_ERROR("failed to idle hardware: %d\n", ret); - i915_gem_retire_requests(dev); - mutex_unlock(&dev->struct_mutex); - - /* Cancel the retire work handler, which should be idle now. */ - cancel_delayed_work_sync(&dev_priv->mm.retire_work); io_mapping_free(dev_priv->gtt.mappable); arch_phys_wc_del(dev_priv->gtt.mtrr); diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index e9dfadca2d71..1060a96d2184 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -487,9 +487,7 @@ static int i915_drm_freeze(struct drm_device *dev) if (drm_core_check_feature(dev, DRIVER_MODESET)) { int error; - mutex_lock(&dev->struct_mutex); - error = i915_gem_idle(dev); - mutex_unlock(&dev->struct_mutex); + error = i915_gem_suspend(dev); if (error) { dev_err(&dev->pdev->dev, "GEM idle failed, resume might fail\n"); diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index b39a548f6a3c..e2bf930c2e91 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -2037,7 +2037,7 @@ int i915_gem_l3_remap(struct intel_ring_buffer *ring, int slice); void i915_gem_init_swizzling(struct drm_device *dev); void i915_gem_cleanup_ringbuffer(struct drm_device *dev); int __must_check i915_gpu_idle(struct drm_device *dev); -int __must_check i915_gem_idle(struct drm_device *dev); +int __must_check i915_gem_suspend(struct drm_device *dev); int __i915_add_request(struct intel_ring_buffer *ring, struct drm_file *file, struct drm_i915_gem_object *batch_obj, diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 1d22c99601ed..f10ae6498bce 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -4265,17 +4265,18 @@ void i915_gem_vma_destroy(struct i915_vma *vma) } int -i915_gem_idle(struct drm_device *dev) +i915_gem_suspend(struct drm_device *dev) { drm_i915_private_t *dev_priv = dev->dev_private; - int ret; + int ret = 0; + mutex_lock(&dev->struct_mutex); if (dev_priv->ums.mm_suspended) - return 0; + goto err; ret = i915_gpu_idle(dev); if (ret) - return ret; + goto err; i915_gem_retire_requests(dev); @@ -4283,16 +4284,26 @@ i915_gem_idle(struct drm_device *dev) if (!drm_core_check_feature(dev, DRIVER_MODESET)) i915_gem_evict_everything(dev); - del_timer_sync(&dev_priv->gpu_error.hangcheck_timer); - i915_kernel_lost_context(dev); i915_gem_cleanup_ringbuffer(dev); - /* Cancel the retire work handler, which should be idle now. */ + /* Hack! Don't let anybody do execbuf while we don't control the chip. + * We need to replace this with a semaphore, or something. + * And not confound ums.mm_suspended! + */ + dev_priv->ums.mm_suspended = !drm_core_check_feature(dev, + DRIVER_MODESET); + mutex_unlock(&dev->struct_mutex); + + del_timer_sync(&dev_priv->gpu_error.hangcheck_timer); cancel_delayed_work_sync(&dev_priv->mm.retire_work); cancel_delayed_work_sync(&dev_priv->mm.idle_work); return 0; + +err: + mutex_unlock(&dev->struct_mutex); + return ret; } int i915_gem_l3_remap(struct intel_ring_buffer *ring, int slice) @@ -4545,26 +4556,12 @@ int i915_gem_leavevt_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv) { - struct drm_i915_private *dev_priv = dev->dev_private; - int ret; - if (drm_core_check_feature(dev, DRIVER_MODESET)) return 0; drm_irq_uninstall(dev); - mutex_lock(&dev->struct_mutex); - ret = i915_gem_idle(dev); - - /* Hack! Don't let anybody do execbuf while we don't control the chip. - * We need to replace this with a semaphore, or something. - * And not confound ums.mm_suspended! - */ - if (ret != 0) - dev_priv->ums.mm_suspended = 1; - mutex_unlock(&dev->struct_mutex); - - return ret; + return i915_gem_suspend(dev); } void @@ -4575,11 +4572,9 @@ i915_gem_lastclose(struct drm_device *dev) if (drm_core_check_feature(dev, DRIVER_MODESET)) return; - mutex_lock(&dev->struct_mutex); - ret = i915_gem_idle(dev); + ret = i915_gem_suspend(dev); if (ret) DRM_ERROR("failed to idle hardware: %d\n", ret); - mutex_unlock(&dev->struct_mutex); } static void -- cgit v1.2.2 From 6f2bcceb27b6120af6b76a865a72eafa50323d41 Mon Sep 17 00:00:00 2001 From: Damien Lespiau Date: Wed, 16 Oct 2013 12:29:54 +0100 Subject: drm/i915: Use pipe_name() instead of the pipe number MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Yet other direct usages of the pipe number instead of pipe_name(). We've been tracking them lately but managed to miss these last ones. v2: Catch them all! (Ville) Reviewed-by: Ville Syrjälä (v1) Signed-off-by: Damien Lespiau Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 4 ++-- drivers/gpu/drm/i915/intel_dsi.c | 2 +- drivers/gpu/drm/i915/intel_panel.c | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 53ad5cb9e802..d3d5adc4379d 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -10762,11 +10762,11 @@ static void intel_modeset_readout_hw_state(struct drm_device *dev) } encoder->connectors_active = false; - DRM_DEBUG_KMS("[ENCODER:%d:%s] hw state readout: %s, pipe=%i\n", + DRM_DEBUG_KMS("[ENCODER:%d:%s] hw state readout: %s, pipe %c\n", encoder->base.base.id, drm_get_encoder_name(&encoder->base), encoder->base.crtc ? "enabled" : "disabled", - pipe); + pipe_name(pipe)); } list_for_each_entry(connector, &dev->mode_config.connector_list, diff --git a/drivers/gpu/drm/i915/intel_dsi.c b/drivers/gpu/drm/i915/intel_dsi.c index 9a2fdd2a7e34..d257b093ca68 100644 --- a/drivers/gpu/drm/i915/intel_dsi.c +++ b/drivers/gpu/drm/i915/intel_dsi.c @@ -350,7 +350,7 @@ static void intel_dsi_mode_set(struct intel_encoder *intel_encoder) unsigned int bpp = intel_crtc->config.pipe_bpp; u32 val, tmp; - DRM_DEBUG_KMS("pipe %d\n", pipe); + DRM_DEBUG_KMS("pipe %c\n", pipe_name(pipe)); /* Update the DSI PLL */ vlv_enable_dsi_pll(intel_encoder); diff --git a/drivers/gpu/drm/i915/intel_panel.c b/drivers/gpu/drm/i915/intel_panel.c index 1f2996031ad9..de1518614827 100644 --- a/drivers/gpu/drm/i915/intel_panel.c +++ b/drivers/gpu/drm/i915/intel_panel.c @@ -574,7 +574,7 @@ void intel_panel_enable_backlight(struct drm_device *dev, intel_pipe_to_cpu_transcoder(dev_priv, pipe); unsigned long flags; - DRM_DEBUG_KMS("pipe=%d\n", pipe); + DRM_DEBUG_KMS("pipe %c\n", pipe_name(pipe)); spin_lock_irqsave(&dev_priv->backlight.lock, flags); -- cgit v1.2.2 From 585a94b80ec2393fbb09739a355fb8ba9e7c27c4 Mon Sep 17 00:00:00 2001 From: Artem Bityutskiy Date: Wed, 16 Oct 2013 18:10:41 +0300 Subject: drm/i915: preserve dispaly init order on ByT This patch changes HDMI port registration order for the BayTrail platform. The story is that in kernel version 3.11 i915 supported only one HDMI port - the HDMIB port. So this port ended up being HDMI-1 in user-space. But commit '6f6005a drm/i915: expose HDMI connectors on port C on BYT' introduced HDMIC port support. And added HDMIC registration prior to HDMIB, so HDMIB became HDMI-2 and HDMIC became HDMI-1. Well, this is fine as far as the kernel is concerned. i915 does not give any guarantees to the numbering, and has never given them. However, this breaks wayland setup in Tizen IVI. We have only one single HDMI port on our hardware, and it is connected to HDMIB. Our configuration relies on the fact that it is HDMI-1. Well, certainly this is user-space problem which was exposed with Jesse's patch. However, there is a reason why we have to do this assumption - we use touchscreen monitors and we have to associate event devices with the monitors, and this is not easy to do dynamically, so we just have a static setup. Anyway, while the user-space setup will have to be fixed regardless, let's chane the HDMI port registration order so that HDMIB stays HDMI-1, just like it was in 3.11. Simply because there is no strong reason for changing the order in the kernel, and it'll help setups like ours in sense that we'll have more time for fixing the issue properly. Also amend the commentary which looks a bit out-of-date. Signed-off-by: Artem Bityutskiy [danvet: Drop the commment, SDVOC is gone and we have a proper HDMIC define now.] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index d3d5adc4379d..0bbf9215637b 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -9884,7 +9884,13 @@ static void intel_setup_outputs(struct drm_device *dev) if (I915_READ(PCH_DP_D) & DP_DETECTED) intel_dp_init(dev, PCH_DP_D, PORT_D); } else if (IS_VALLEYVIEW(dev)) { - /* Check for built-in panel first. Shares lanes with HDMI on SDVOC */ + if (I915_READ(VLV_DISPLAY_BASE + GEN4_HDMIB) & SDVO_DETECTED) { + intel_hdmi_init(dev, VLV_DISPLAY_BASE + GEN4_HDMIB, + PORT_B); + if (I915_READ(VLV_DISPLAY_BASE + DP_B) & DP_DETECTED) + intel_dp_init(dev, VLV_DISPLAY_BASE + DP_B, PORT_B); + } + if (I915_READ(VLV_DISPLAY_BASE + GEN4_HDMIC) & SDVO_DETECTED) { intel_hdmi_init(dev, VLV_DISPLAY_BASE + GEN4_HDMIC, PORT_C); @@ -9893,13 +9899,6 @@ static void intel_setup_outputs(struct drm_device *dev) PORT_C); } - if (I915_READ(VLV_DISPLAY_BASE + GEN4_HDMIB) & SDVO_DETECTED) { - intel_hdmi_init(dev, VLV_DISPLAY_BASE + GEN4_HDMIB, - PORT_B); - if (I915_READ(VLV_DISPLAY_BASE + DP_B) & DP_DETECTED) - intel_dp_init(dev, VLV_DISPLAY_BASE + DP_B, PORT_B); - } - intel_dsi_init(dev); } else if (SUPPORTS_DIGITAL_OUTPUTS(dev)) { bool found = false; -- cgit v1.2.2 From fbf460259bfecb3f99a33ba2aa30766c5f7e6e2c Mon Sep 17 00:00:00 2001 From: Thomas Wood Date: Wed, 16 Oct 2013 15:58:50 +0100 Subject: drm: add support for additional stereo 3D modes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Parse the 3D_Structure_ALL and 3D_MASK fields of the HDMI Vendor Specific Data Block to expose more stereo 3D modes. v2: Use (1 << 0) for consistency. (Ville Syrjälä) Skip adding any modes if 3D_MASK is indicated as being present but the length only includes 3D_Structure_ALL. (Ville Syrjälä) Check that the value of HDMI_3D_LEN is large enough to include 3D_Structure_ALL and 3D_MASK, if they are present. (Ville Syrjälä) v3: Increment offset before the length checks. (Ville Syrjälä) Signed-off-by: Thomas Wood Reviewed-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/gpu/drm/drm_edid.c | 103 +++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 94 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index 9e81609b1e29..f1764ec5818b 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -2652,6 +2652,50 @@ static int add_hdmi_mode(struct drm_connector *connector, u8 vic) return 1; } +static int add_3d_struct_modes(struct drm_connector *connector, u16 structure, + const u8 *video_db, u8 video_len, u8 video_index) +{ + struct drm_device *dev = connector->dev; + struct drm_display_mode *newmode; + int modes = 0; + u8 cea_mode; + + if (video_db == NULL || video_index > video_len) + return 0; + + /* CEA modes are numbered 1..127 */ + cea_mode = (video_db[video_index] & 127) - 1; + if (cea_mode >= ARRAY_SIZE(edid_cea_modes)) + return 0; + + if (structure & (1 << 0)) { + newmode = drm_mode_duplicate(dev, &edid_cea_modes[cea_mode]); + if (newmode) { + newmode->flags |= DRM_MODE_FLAG_3D_FRAME_PACKING; + drm_mode_probed_add(connector, newmode); + modes++; + } + } + if (structure & (1 << 6)) { + newmode = drm_mode_duplicate(dev, &edid_cea_modes[cea_mode]); + if (newmode) { + newmode->flags |= DRM_MODE_FLAG_3D_TOP_AND_BOTTOM; + drm_mode_probed_add(connector, newmode); + modes++; + } + } + if (structure & (1 << 8)) { + newmode = drm_mode_duplicate(dev, &edid_cea_modes[cea_mode]); + if (newmode) { + newmode->flags = DRM_MODE_FLAG_3D_SIDE_BY_SIDE_HALF; + drm_mode_probed_add(connector, newmode); + modes++; + } + } + + return modes; +} + /* * do_hdmi_vsdb_modes - Parse the HDMI Vendor Specific data block * @connector: connector corresponding to the HDMI sink @@ -2662,10 +2706,13 @@ static int add_hdmi_mode(struct drm_connector *connector, u8 vic) * also adds the stereo 3d modes when applicable. */ static int -do_hdmi_vsdb_modes(struct drm_connector *connector, const u8 *db, u8 len) +do_hdmi_vsdb_modes(struct drm_connector *connector, const u8 *db, u8 len, + const u8 *video_db, u8 video_len) { - int modes = 0, offset = 0, i; - u8 vic_len; + int modes = 0, offset = 0, i, multi_present = 0; + u8 vic_len, hdmi_3d_len = 0; + u16 mask; + u16 structure_all; if (len < 8) goto out; @@ -2689,11 +2736,16 @@ do_hdmi_vsdb_modes(struct drm_connector *connector, const u8 *db, u8 len) /* 3D_Present */ offset++; - if (db[8 + offset] & (1 << 7)) + if (db[8 + offset] & (1 << 7)) { modes += add_hdmi_mandatory_stereo_modes(connector); + /* 3D_Multi_present */ + multi_present = (db[8 + offset] & 0x60) >> 5; + } + offset++; vic_len = db[8 + offset] >> 5; + hdmi_3d_len = db[8 + offset] & 0x1f; for (i = 0; i < vic_len && len >= (9 + offset + i); i++) { u8 vic; @@ -2701,6 +2753,35 @@ do_hdmi_vsdb_modes(struct drm_connector *connector, const u8 *db, u8 len) vic = db[9 + offset + i]; modes += add_hdmi_mode(connector, vic); } + offset += 1 + vic_len; + + if (!(multi_present == 1 || multi_present == 2)) + goto out; + + if ((multi_present == 1 && len < (9 + offset)) || + (multi_present == 2 && len < (11 + offset))) + goto out; + + if ((multi_present == 1 && hdmi_3d_len < 2) || + (multi_present == 2 && hdmi_3d_len < 4)) + goto out; + + /* 3D_Structure_ALL */ + structure_all = (db[8 + offset] << 8) | db[9 + offset]; + + /* check if 3D_MASK is present */ + if (multi_present == 2) + mask = (db[10 + offset] << 8) | db[11 + offset]; + else + mask = 0xffff; + + for (i = 0; i < 16; i++) { + if (mask & (1 << i)) + modes += add_3d_struct_modes(connector, + structure_all, + video_db, + video_len, i); + } out: return modes; @@ -2759,8 +2840,8 @@ static int add_cea_modes(struct drm_connector *connector, struct edid *edid) { const u8 *cea = drm_find_cea_extension(edid); - const u8 *db, *hdmi = NULL; - u8 dbl, hdmi_len; + const u8 *db, *hdmi = NULL, *video = NULL; + u8 dbl, hdmi_len, video_len = 0; int modes = 0; if (cea && cea_revision(cea) >= 3) { @@ -2773,8 +2854,11 @@ add_cea_modes(struct drm_connector *connector, struct edid *edid) db = &cea[i]; dbl = cea_db_payload_len(db); - if (cea_db_tag(db) == VIDEO_BLOCK) - modes += do_cea_modes(connector, db + 1, dbl); + if (cea_db_tag(db) == VIDEO_BLOCK) { + video = db + 1; + video_len = dbl; + modes += do_cea_modes(connector, video, dbl); + } else if (cea_db_is_hdmi_vsdb(db)) { hdmi = db; hdmi_len = dbl; @@ -2787,7 +2871,8 @@ add_cea_modes(struct drm_connector *connector, struct edid *edid) * be patching their flags when the sink supports stereo 3D. */ if (hdmi) - modes += do_hdmi_vsdb_modes(connector, hdmi, hdmi_len); + modes += do_hdmi_vsdb_modes(connector, hdmi, hdmi_len, video, + video_len); return modes; } -- cgit v1.2.2 From 533df0fecdeda3e116ee8ffc8bfef96216e814bc Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Wed, 16 Oct 2013 20:39:24 +0300 Subject: drm/i915: vlv: fix VGA hotplug after modeset Since commit 912d812e84cea8689a2bf3dd13b11dfe191f0f1e Author: Daniel Vetter Date: Thu Oct 11 20:08:23 2012 +0200 drm/i915/crt: don't set HOTPLUG bits on !PCH on VLV we don't detect any VGA unplug event after a modeset, since there we reset the ADPA hotplug bits. Fix it by preserving the hotplug bits on VLV as well. Signed-off-by: Imre Deak [danvet: For consistency use gen >= 5 like in Chris' exact same fix in intel_crt_reset.] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_crt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/intel_crt.c b/drivers/gpu/drm/i915/intel_crt.c index 942b9acb0d8e..2e01bd3a5d8c 100644 --- a/drivers/gpu/drm/i915/intel_crt.c +++ b/drivers/gpu/drm/i915/intel_crt.c @@ -274,7 +274,7 @@ static void intel_crt_mode_set(struct intel_encoder *encoder) struct drm_display_mode *adjusted_mode = &crtc->config.adjusted_mode; u32 adpa; - if (HAS_PCH_SPLIT(dev)) + if (INTEL_INFO(dev)->gen >= 5) adpa = ADPA_HOTPLUG_BITS; else adpa = 0; -- cgit v1.2.2 From dd4916c55aa4bacb26c343d0f0faa64e7aaef918 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Wed, 9 Oct 2013 21:23:51 +0200 Subject: drm/i915: grab dev->struct_mutex around framebuffer_init MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We look at gem state (like obj->tiling/obj->stride), we better have the relevant locks. Right now this doesn't matter much since most of these checks are a curtesy to safe buggy userspace, but I'd like to freeze the tiling once we have framebuffer objects attached. And then locking matters. Cc: Ville Syrjälä Reviewed-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 0bbf9215637b..88e560070bec 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -7285,14 +7285,21 @@ intel_framebuffer_create(struct drm_device *dev, return ERR_PTR(-ENOMEM); } + ret = i915_mutex_lock_interruptible(dev); + if (ret) + goto err; + ret = intel_framebuffer_init(dev, intel_fb, mode_cmd, obj); - if (ret) { - drm_gem_object_unreference_unlocked(&obj->base); - kfree(intel_fb); - return ERR_PTR(ret); - } + mutex_unlock(&dev->struct_mutex); + if (ret) + goto err; return &intel_fb->base; +err: + drm_gem_object_unreference_unlocked(&obj->base); + kfree(intel_fb); + + return ERR_PTR(ret); } static u32 @@ -9989,6 +9996,8 @@ int intel_framebuffer_init(struct drm_device *dev, int pitch_limit; int ret; + WARN_ON(!mutex_is_locked(&dev->struct_mutex)); + if (obj->tiling_mode == I915_TILING_Y) { DRM_DEBUG("hardware does not support tiling Y\n"); return -EINVAL; -- cgit v1.2.2 From 80075d492f8773209e26d11d6bb13ba624ef95a4 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Wed, 9 Oct 2013 21:23:52 +0200 Subject: drm/i915: prevent tiling changes on framebuffer backing storage MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Assuming that all framebuffer related metadata is invariant simplifies our userspace input data checking. And current userspace always first updates the tiling of an object before creating a framebuffer with it. This allows us to upconvert a check in pin_and_fence to a WARN. In the future it should also be helpful to know which buffer objects are potential scanout targets for e.g. frontbuffer rendering tracking and similar things. Note that SNA shipped for one prerelease with code which will be broken through this patch. But users shouldn't notice since it's purely an optimization and will transparently fall back to allocating a new fb. i-g-t also had offending code (now fixed), but we don't really care about breaking the test-suite. Cc: Ville Syrjälä Reviewed-by: Ville Syrjälä Grumpily-reviewed-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 3 +++ drivers/gpu/drm/i915/i915_gem_tiling.c | 2 +- drivers/gpu/drm/i915/intel_display.c | 7 +++---- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index e2bf930c2e91..759de9f123fd 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1597,6 +1597,9 @@ struct drm_i915_gem_object { /** Current tiling stride for the object, if it's tiled. */ uint32_t stride; + /** References from framebuffers, locks out tiling changes. */ + unsigned long framebuffer_references; + /** Record of address bit 17 of each page at last unbind. */ unsigned long *bit_17; diff --git a/drivers/gpu/drm/i915/i915_gem_tiling.c b/drivers/gpu/drm/i915/i915_gem_tiling.c index ac9ebe98f8b0..b13905348048 100644 --- a/drivers/gpu/drm/i915/i915_gem_tiling.c +++ b/drivers/gpu/drm/i915/i915_gem_tiling.c @@ -308,7 +308,7 @@ i915_gem_set_tiling(struct drm_device *dev, void *data, return -EINVAL; } - if (obj->pin_count) { + if (obj->pin_count || obj->framebuffer_references) { drm_gem_object_unreference_unlocked(&obj->base); return -EBUSY; } diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 88e560070bec..97ee553a81e5 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -1921,10 +1921,7 @@ intel_pin_and_fence_fb_obj(struct drm_device *dev, alignment = 0; break; case I915_TILING_Y: - /* Despite that we check this in framebuffer_init userspace can - * screw us over and change the tiling after the fact. Only - * pinned buffers can't change their tiling. */ - DRM_DEBUG_DRIVER("Y tiled not allowed for scan out buffers\n"); + WARN(1, "Y tiled bo slipped through, driver bug!\n"); return -EINVAL; default: BUG(); @@ -9962,6 +9959,7 @@ static void intel_setup_outputs(struct drm_device *dev) void intel_framebuffer_fini(struct intel_framebuffer *fb) { drm_framebuffer_cleanup(&fb->base); + WARN_ON(!fb->obj->framebuffer_references--); drm_gem_object_unreference_unlocked(&fb->obj->base); } @@ -10088,6 +10086,7 @@ int intel_framebuffer_init(struct drm_device *dev, drm_helper_mode_fill_fb_struct(&intel_fb->base, mode_cmd); intel_fb->obj = obj; + intel_fb->obj->framebuffer_references++; ret = drm_framebuffer_init(dev, &intel_fb->base, &intel_fb_funcs); if (ret) { -- cgit v1.2.2 From aa5f8021811aede2e40aa715c55fbd87d945a443 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Thu, 10 Oct 2013 14:46:37 +0200 Subject: drm/i915: Use unsigned long for obj->user_pin_count MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit At least on linux sizeof(long) == sizeof(void*) and the thinking is that you can grab about as many references as there's memory. Doesn't really matter, just a bit of OCD since the fixed size data type in a pure in-kernel datastructure look off. v2: Ville asked for an overflow check since no one prevents userspace from incrementing the pin count forever. v3: s/INT/LONG/, noticed by Chris. Cc: Chris Wilson Cc: Ville Syrjälä Reviewed-by: Ville Syrjälä Reviewed-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 2 +- drivers/gpu/drm/i915/i915_gem.c | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 759de9f123fd..e4ff8e91d939 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1604,7 +1604,7 @@ struct drm_i915_gem_object { unsigned long *bit_17; /** User space pin count and filp owning the pin */ - uint32_t user_pin_count; + unsigned long user_pin_count; struct drm_file *pin_filp; /** for phy allocated objects */ diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index f10ae6498bce..34df59b660f8 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -3931,6 +3931,11 @@ i915_gem_pin_ioctl(struct drm_device *dev, void *data, goto out; } + if (obj->user_pin_count == ULONG_MAX) { + ret = -EBUSY; + goto out; + } + if (obj->user_pin_count == 0) { ret = i915_gem_obj_ggtt_pin(obj, args->alignment, true, false); if (ret) -- cgit v1.2.2 From 53155c0a5949d5cc3bd434d838e5b0c6e0542f9b Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Wed, 9 Oct 2013 21:55:33 +0200 Subject: drm/i915: check gem bo size when creating framebuffers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It's better to catch such fallout early, and this way we can rely on the checking done by the drm core on fb->heigh/width at modeset time. If we ever support planar formats on intel we might want to look into a common helper to do all this, but for now this is good enough. v2: Take tiling into account, requested by Ville. v3: Fix tile height on gen2, spotted by Ville. Cc: Ville Syrjälä Requested-by: Chris Wilson Cc: Chris Wilson Reviewed-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 97ee553a81e5..94b39bedc9cc 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -9991,6 +9991,7 @@ int intel_framebuffer_init(struct drm_device *dev, struct drm_mode_fb_cmd2 *mode_cmd, struct drm_i915_gem_object *obj) { + int aligned_height, tile_height; int pitch_limit; int ret; @@ -10084,6 +10085,13 @@ int intel_framebuffer_init(struct drm_device *dev, if (mode_cmd->offsets[0] != 0) return -EINVAL; + tile_height = IS_GEN2(dev) ? 16 : 8; + aligned_height = ALIGN(mode_cmd->height, + obj->tiling_mode ? tile_height : 1); + /* FIXME drm helper for size checks (especially planar formats)? */ + if (obj->base.size < aligned_height * mode_cmd->pitches[0]) + return -EINVAL; + drm_helper_mode_fill_fb_struct(&intel_fb->base, mode_cmd); intel_fb->obj = obj; intel_fb->obj->framebuffer_references++; -- cgit v1.2.2 From c75b505ddaa08098940441226bb3a87c5b3179c0 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Tue, 8 Oct 2013 10:56:11 +0200 Subject: cpufreq: Add dummy cpufreq_cpu_get/put for CONFIG_CPU_FREQ=n The drm/i915 driver wants to adjust it's own power policies using the cpu policies as a guideline (we can implicitly boost the cpus through the gpus on some platforms). To avoid a dreaded select (since a depends will leave users wondering where where their driver has gone too) add dummy functions. Reported-by: kbuild test robot Cc: kbuild test robot Cc: "Rafael J. Wysocki" Cc: Viresh Kumar Cc: cpufreq@vger.kernel.org Cc: linux-pm@vger.kernel.org Cc: linux-kernel@vger.kernel.org Acked-by: Rafael J. Wysocki Signed-off-by: Daniel Vetter --- include/linux/cpufreq.h | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/include/linux/cpufreq.h b/include/linux/cpufreq.h index fcabc42d66ab..5ad9a4e2bc59 100644 --- a/include/linux/cpufreq.h +++ b/include/linux/cpufreq.h @@ -93,8 +93,16 @@ struct cpufreq_policy { #define CPUFREQ_SHARED_TYPE_ALL (2) /* All dependent CPUs should set freq */ #define CPUFREQ_SHARED_TYPE_ANY (3) /* Freq can be set from any dependent CPU*/ +#ifdef CONFIG_CPU_FREQ struct cpufreq_policy *cpufreq_cpu_get(unsigned int cpu); void cpufreq_cpu_put(struct cpufreq_policy *policy); +#else +static inline struct cpufreq_policy *cpufreq_cpu_get(unsigned int cpu) +{ + return NULL; +} +static inline void cpufreq_cpu_put(struct cpufreq_policy *policy) { } +#endif static inline bool policy_is_shared(struct cpufreq_policy *policy) { -- cgit v1.2.2 From 34427052ebb450cbf1d0f2851436fbe216f56417 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Wed, 16 Oct 2013 12:34:47 +0300 Subject: drm/i915: pass mode to ELD write vfuncs This will be needed for setting the HDMI pixel clock for audio config. No functional changes. v2: Now with a commit message. Signed-off-by: Jani Nikula Reviewed-by: Rodrigo Vivi Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 3 ++- drivers/gpu/drm/i915/intel_display.c | 11 +++++++---- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index e4ff8e91d939..1292b40d2a44 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -379,7 +379,8 @@ struct drm_i915_display_funcs { void (*crtc_disable)(struct drm_crtc *crtc); void (*off)(struct drm_crtc *crtc); void (*write_eld)(struct drm_connector *connector, - struct drm_crtc *crtc); + struct drm_crtc *crtc, + struct drm_display_mode *mode); void (*fdi_link_train)(struct drm_crtc *crtc); void (*init_clock_gating)(struct drm_device *dev); int (*queue_flip)(struct drm_device *dev, struct drm_crtc *crtc, diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 94b39bedc9cc..a4d76319f029 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -6753,7 +6753,8 @@ static bool intel_eld_uptodate(struct drm_connector *connector, } static void g4x_write_eld(struct drm_connector *connector, - struct drm_crtc *crtc) + struct drm_crtc *crtc, + struct drm_display_mode *mode) { struct drm_i915_private *dev_priv = connector->dev->dev_private; uint8_t *eld = connector->eld; @@ -6793,7 +6794,8 @@ static void g4x_write_eld(struct drm_connector *connector, } static void haswell_write_eld(struct drm_connector *connector, - struct drm_crtc *crtc) + struct drm_crtc *crtc, + struct drm_display_mode *mode) { struct drm_i915_private *dev_priv = connector->dev->dev_private; uint8_t *eld = connector->eld; @@ -6880,7 +6882,8 @@ static void haswell_write_eld(struct drm_connector *connector, } static void ironlake_write_eld(struct drm_connector *connector, - struct drm_crtc *crtc) + struct drm_crtc *crtc, + struct drm_display_mode *mode) { struct drm_i915_private *dev_priv = connector->dev->dev_private; uint8_t *eld = connector->eld; @@ -6975,7 +6978,7 @@ void intel_write_eld(struct drm_encoder *encoder, connector->eld[6] = drm_av_sync_delay(connector, mode) / 2; if (dev_priv->display.write_eld) - dev_priv->display.write_eld(connector, crtc); + dev_priv->display.write_eld(connector, crtc, mode); } static void i845_update_cursor(struct drm_crtc *crtc, u32 base) -- cgit v1.2.2 From 1a91510dc3b8098930ebda3018f5cd72e8428243 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Wed, 16 Oct 2013 12:34:48 +0300 Subject: drm/i915: set HDMI pixel clock in audio configuration MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The HDMI audio expects HDMI pixel clock to be set in the audio configuration. We've currently just set 0, using 25.2 / 1.001 kHz frequency, which fails with some modes. v2: Now with a commit message. Reference: http://mid.gmane.org/CAGpEb3Ep1LRZETPxHGRfBDqr5Ts2tAc8gCukWwugUf1U5NYv1g@mail.gmail.com Reference: http://mid.gmane.org/20130206213533.GA16367@hardeman.nu Reported-by: David Härdeman Reported-by: Jasper Smet Tested-by: Jasper Smet Signed-off-by: Jani Nikula Reviewed-by: Rodrigo Vivi Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_reg.h | 12 ++++++++- drivers/gpu/drm/i915/intel_display.c | 48 +++++++++++++++++++++++++++++++++--- 2 files changed, 55 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 8161521003ed..b0f77a2b01e0 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -4901,7 +4901,17 @@ #define AUD_CONFIG_LOWER_N_SHIFT 4 #define AUD_CONFIG_LOWER_N_VALUE (0xfff << 4) #define AUD_CONFIG_PIXEL_CLOCK_HDMI_SHIFT 16 -#define AUD_CONFIG_PIXEL_CLOCK_HDMI (0xf << 16) +#define AUD_CONFIG_PIXEL_CLOCK_HDMI_MASK (0xf << 16) +#define AUD_CONFIG_PIXEL_CLOCK_HDMI_25175 (0 << 16) +#define AUD_CONFIG_PIXEL_CLOCK_HDMI_25200 (1 << 16) +#define AUD_CONFIG_PIXEL_CLOCK_HDMI_27000 (2 << 16) +#define AUD_CONFIG_PIXEL_CLOCK_HDMI_27027 (3 << 16) +#define AUD_CONFIG_PIXEL_CLOCK_HDMI_54000 (4 << 16) +#define AUD_CONFIG_PIXEL_CLOCK_HDMI_54054 (5 << 16) +#define AUD_CONFIG_PIXEL_CLOCK_HDMI_74176 (6 << 16) +#define AUD_CONFIG_PIXEL_CLOCK_HDMI_74250 (7 << 16) +#define AUD_CONFIG_PIXEL_CLOCK_HDMI_148352 (8 << 16) +#define AUD_CONFIG_PIXEL_CLOCK_HDMI_148500 (9 << 16) #define AUD_CONFIG_DISABLE_NCTS (1 << 3) /* HSW Audio */ diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index a4d76319f029..42b1c755d676 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -6723,6 +6723,44 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc, return 0; } +static struct { + int clock; + u32 config; +} hdmi_audio_clock[] = { + { DIV_ROUND_UP(25200 * 1000, 1001), AUD_CONFIG_PIXEL_CLOCK_HDMI_25175 }, + { 25200, AUD_CONFIG_PIXEL_CLOCK_HDMI_25200 }, /* default per bspec */ + { 27000, AUD_CONFIG_PIXEL_CLOCK_HDMI_27000 }, + { 27000 * 1001 / 1000, AUD_CONFIG_PIXEL_CLOCK_HDMI_27027 }, + { 54000, AUD_CONFIG_PIXEL_CLOCK_HDMI_54000 }, + { 54000 * 1001 / 1000, AUD_CONFIG_PIXEL_CLOCK_HDMI_54054 }, + { DIV_ROUND_UP(74250 * 1000, 1001), AUD_CONFIG_PIXEL_CLOCK_HDMI_74176 }, + { 74250, AUD_CONFIG_PIXEL_CLOCK_HDMI_74250 }, + { DIV_ROUND_UP(148500 * 1000, 1001), AUD_CONFIG_PIXEL_CLOCK_HDMI_148352 }, + { 148500, AUD_CONFIG_PIXEL_CLOCK_HDMI_148500 }, +}; + +/* get AUD_CONFIG_PIXEL_CLOCK_HDMI_* value for mode */ +static u32 audio_config_hdmi_pixel_clock(struct drm_display_mode *mode) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(hdmi_audio_clock); i++) { + if (mode->clock == hdmi_audio_clock[i].clock) + break; + } + + if (i == ARRAY_SIZE(hdmi_audio_clock)) { + DRM_DEBUG_KMS("HDMI audio pixel clock setting for %d not found, falling back to defaults\n", mode->clock); + i = 1; + } + + DRM_DEBUG_KMS("Configuring HDMI audio for pixel clock %d (0x%08x)\n", + hdmi_audio_clock[i].clock, + hdmi_audio_clock[i].config); + + return hdmi_audio_clock[i].config; +} + static bool intel_eld_uptodate(struct drm_connector *connector, int reg_eldv, uint32_t bits_eldv, int reg_elda, uint32_t bits_elda, @@ -6848,8 +6886,9 @@ static void haswell_write_eld(struct drm_connector *connector, DRM_DEBUG_DRIVER("ELD: DisplayPort detected\n"); eld[5] |= (1 << 2); /* Conn_Type, 0x1 = DisplayPort */ I915_WRITE(aud_config, AUD_CONFIG_N_VALUE_INDEX); /* 0x1 = DP */ - } else - I915_WRITE(aud_config, 0); + } else { + I915_WRITE(aud_config, audio_config_hdmi_pixel_clock(mode)); + } if (intel_eld_uptodate(connector, aud_cntrl_st2, eldv, @@ -6927,8 +6966,9 @@ static void ironlake_write_eld(struct drm_connector *connector, DRM_DEBUG_DRIVER("ELD: DisplayPort detected\n"); eld[5] |= (1 << 2); /* Conn_Type, 0x1 = DisplayPort */ I915_WRITE(aud_config, AUD_CONFIG_N_VALUE_INDEX); /* 0x1 = DP */ - } else - I915_WRITE(aud_config, 0); + } else { + I915_WRITE(aud_config, audio_config_hdmi_pixel_clock(mode)); + } if (intel_eld_uptodate(connector, aud_cntrl_st2, eldv, -- cgit v1.2.2 From 131a56dc41b8c026f97466341167d86deb25357b Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Thu, 17 Oct 2013 14:35:31 +0200 Subject: drm/i915: don't Oops in debugfs for I915_FBDEV=n Failed to properly test this. Reported-by: Chris Wilson Cc: Chris Wilson Tested-by: Chris Wilson Reviewed-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_debugfs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index 5fce5d89b68a..7811bf40dd2c 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -1456,7 +1456,7 @@ static int i915_gem_framebuffer_info(struct seq_file *m, void *data) mutex_lock(&dev->mode_config.fb_lock); list_for_each_entry(fb, &dev->mode_config.fb_list, base.head) { - if (&fb->base == ifbdev->helper.fb) + if (ifbdev && &fb->base == ifbdev->helper.fb) continue; seq_printf(m, "user size: %d x %d, depth %d, %d bpp, refcount %d, obj ", -- cgit v1.2.2 From eba94eb90138caf0b22797dc5fd802e28d253dcf Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Wed, 16 Oct 2013 22:55:46 +0200 Subject: drm/i915: extract display_pipe_crc_update The ringbuffer update logic should always be the same, but different platforms have different amounts of CRC registers. Hence extract it. Reviewed-by: Damien Lespiau Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_irq.c | 30 +++++++++++++++++++++++------- 1 file changed, 23 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 8c9148c2f82b..df031bb6c501 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -1190,7 +1190,10 @@ static void dp_aux_irq_handler(struct drm_device *dev) } #if defined(CONFIG_DEBUG_FS) -static void ivb_pipe_crc_update(struct drm_device *dev, enum pipe pipe) +static void display_pipe_crc_update(struct drm_device *dev, enum pipe pipe, + uint32_t crc0, uint32_t crc1, + uint32_t crc2, uint32_t crc3, + uint32_t crc4, uint32_t frame) { struct drm_i915_private *dev_priv = dev->dev_private; struct intel_pipe_crc *pipe_crc = &dev_priv->pipe_crc[pipe]; @@ -1212,18 +1215,31 @@ static void ivb_pipe_crc_update(struct drm_device *dev, enum pipe pipe) entry = &pipe_crc->entries[head]; - entry->frame = I915_READ(PIPEFRAME(pipe)); - entry->crc[0] = I915_READ(PIPE_CRC_RES_1_IVB(pipe)); - entry->crc[1] = I915_READ(PIPE_CRC_RES_2_IVB(pipe)); - entry->crc[2] = I915_READ(PIPE_CRC_RES_3_IVB(pipe)); - entry->crc[3] = I915_READ(PIPE_CRC_RES_4_IVB(pipe)); - entry->crc[4] = I915_READ(PIPE_CRC_RES_5_IVB(pipe)); + entry->frame = frame; + entry->crc[0] = crc0; + entry->crc[1] = crc1; + entry->crc[2] = crc2; + entry->crc[3] = crc3; + entry->crc[4] = crc4; head = (head + 1) & (INTEL_PIPE_CRC_ENTRIES_NR - 1); atomic_set(&pipe_crc->head, head); wake_up_interruptible(&pipe_crc->wq); } + +static void ivb_pipe_crc_update(struct drm_device *dev, enum pipe pipe) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + + display_pipe_crc_update(dev, pipe, + I915_READ(PIPE_CRC_RES_1_IVB(pipe)), + I915_READ(PIPE_CRC_RES_2_IVB(pipe)), + I915_READ(PIPE_CRC_RES_3_IVB(pipe)), + I915_READ(PIPE_CRC_RES_4_IVB(pipe)), + I915_READ(PIPE_CRC_RES_5_IVB(pipe)), + I915_READ(PIPEFRAME(pipe))); +} #else static inline void ivb_pipe_crc_update(struct drm_device *dev, int pipe) {} #endif -- cgit v1.2.2 From 5a6b5c84e494336935a32909a640c2da267fda0d Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Wed, 16 Oct 2013 22:55:47 +0200 Subject: drm/i915: add CRC #defines for ilk/snb Also add a new _PIPE_INC macro which takes an base plus increment. Much less likely to botch the job by missing an s/A/B/ somewhere. v2: They've moved the bitfield. Argh! Reviewed-by: Damien Lespiau Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_reg.h | 46 +++++++++++++++++++++++++++++++---------- 1 file changed, 35 insertions(+), 11 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index b0f77a2b01e0..11bd8b27d923 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -26,6 +26,7 @@ #define _I915_REG_H_ #define _PIPE(pipe, a, b) ((a) + (pipe)*((b)-(a))) +#define _PIPE_INC(pipe, base, inc) ((base) + (pipe)*(inc)) #define _TRANSCODER(tran, a, b) ((a) + (tran)*((b)-(a))) #define _PORT(port, a, b) ((a) + (port)*((b)-(a))) @@ -1844,19 +1845,31 @@ #define PIPE_CRC_SOURCE_PRIMARY_IVB (0 << 29) #define PIPE_CRC_SOURCE_SPRITE_IVB (1 << 29) #define PIPE_CRC_SOURCE_PF_IVB (2 << 29) -#define _PIPE_CRC_RES_1_A_IVB (dev_priv->info->display_mmio_offset + 0x60064) -#define _PIPE_CRC_RES_2_A_IVB (dev_priv->info->display_mmio_offset + 0x60068) -#define _PIPE_CRC_RES_3_A_IVB (dev_priv->info->display_mmio_offset + 0x6006c) -#define _PIPE_CRC_RES_4_A_IVB (dev_priv->info->display_mmio_offset + 0x60070) -#define _PIPE_CRC_RES_5_A_IVB (dev_priv->info->display_mmio_offset + 0x60074) +#define PIPE_CRC_SOURCE_PRIMARY_ILK (0 << 28) +#define PIPE_CRC_SOURCE_SPRITE_ILK (1 << 28) +#define PIPE_CRC_SOURCE_PIPE_ILK (2 << 28) +/* embedded DP port on the north display block, reserved on ivb */ +#define PIPE_CRC_SOURCE_PORT_A_ILK (4 << 28) +#define PIPE_CRC_SOURCE_FDI_ILK (5 << 28) /* reserved on ivb */ +#define _PIPE_CRC_RES_1_A_IVB 0x60064 +#define _PIPE_CRC_RES_2_A_IVB 0x60068 +#define _PIPE_CRC_RES_3_A_IVB 0x6006c +#define _PIPE_CRC_RES_4_A_IVB 0x60070 +#define _PIPE_CRC_RES_5_A_IVB 0x60074 + +#define _PIPE_CRC_RES_RED_A_ILK 0x60060 +#define _PIPE_CRC_RES_GREEN_A_ILK 0x60064 +#define _PIPE_CRC_RES_BLUE_A_ILK 0x60068 +#define _PIPE_CRC_RES_RES1_A_ILK 0x6006c +#define _PIPE_CRC_RES_RES2_A_ILK 0x60080 /* Pipe B CRC regs */ -#define _PIPE_CRC_CTL_B (dev_priv->info->display_mmio_offset + 0x61050) -#define _PIPE_CRC_RES_1_B_IVB (dev_priv->info->display_mmio_offset + 0x61064) -#define _PIPE_CRC_RES_2_B_IVB (dev_priv->info->display_mmio_offset + 0x61068) -#define _PIPE_CRC_RES_3_B_IVB (dev_priv->info->display_mmio_offset + 0x6106c) -#define _PIPE_CRC_RES_4_B_IVB (dev_priv->info->display_mmio_offset + 0x61070) -#define _PIPE_CRC_RES_5_B_IVB (dev_priv->info->display_mmio_offset + 0x61074) +#define _PIPE_CRC_CTL_B 0x61050 +#define _PIPE_CRC_RES_1_B_IVB 0x61064 +#define _PIPE_CRC_RES_2_B_IVB 0x61068 +#define _PIPE_CRC_RES_3_B_IVB 0x6106c +#define _PIPE_CRC_RES_4_B_IVB 0x61070 +#define _PIPE_CRC_RES_5_B_IVB 0x61074 #define PIPE_CRC_CTL(pipe) _PIPE(pipe, _PIPE_CRC_CTL_A, _PIPE_CRC_CTL_B) #define PIPE_CRC_RES_1_IVB(pipe) \ @@ -1870,6 +1883,17 @@ #define PIPE_CRC_RES_5_IVB(pipe) \ _PIPE(pipe, _PIPE_CRC_RES_5_A_IVB, _PIPE_CRC_RES_5_B_IVB) +#define PIPE_CRC_RES_RED_ILK(pipe) \ + _PIPE_INC(pipe, _PIPE_CRC_RES_RED_A_ILK, 0x01000) +#define PIPE_CRC_RES_GREEN_ILK(pipe) \ + _PIPE_INC(pipe, _PIPE_CRC_RES_GREEN_A_ILK, 0x01000) +#define PIPE_CRC_RES_BLUE_ILK(pipe) \ + _PIPE_INC(pipe, _PIPE_CRC_RES_BLUE_A_ILK, 0x01000) +#define PIPE_CRC_RES_RES1_ILK(pipe) \ + _PIPE_INC(pipe, _PIPE_CRC_RES_RES1_A_ILK, 0x01000) +#define PIPE_CRC_RES_RES2_ILK(pipe) \ + _PIPE_INC(pipe, _PIPE_CRC_RES_RES2_A_ILK, 0x01000) + /* Pipe A timing regs */ #define _HTOTAL_A (dev_priv->info->display_mmio_offset + 0x60000) #define _HBLANK_A (dev_priv->info->display_mmio_offset + 0x60004) -- cgit v1.2.2 From 5b3a856bcfa3d24496035a77ab086548773a633d Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Wed, 16 Oct 2013 22:55:48 +0200 Subject: drm/i915: wire up CRC interrupt for ilk/snb We enable the interrupt unconditionally and only control it through the enable bit in the CRC control register. v2: Extract per-platform helpers to compute the register values. Reviewed-by: Damien Lespiau Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_debugfs.c | 74 ++++++++++++++++++++++++++++--------- drivers/gpu/drm/i915/i915_drv.h | 1 + drivers/gpu/drm/i915/i915_irq.c | 26 ++++++++++++- drivers/gpu/drm/i915/i915_reg.h | 2 + 4 files changed, 84 insertions(+), 19 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index 7811bf40dd2c..baa527234b93 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -1914,6 +1914,7 @@ static const char * const pipe_crc_sources[] = { "plane1", "plane2", "pf", + "pipe", }; static const char *pipe_crc_source_name(enum intel_pipe_crc_source source) @@ -1942,14 +1943,61 @@ static int display_crc_ctl_open(struct inode *inode, struct file *file) return single_open(file, display_crc_ctl_show, dev); } +static int ilk_pipe_crc_ctl_reg(enum intel_pipe_crc_source source, + uint32_t *val) +{ + switch (source) { + case INTEL_PIPE_CRC_SOURCE_PLANE1: + *val = PIPE_CRC_ENABLE | PIPE_CRC_SOURCE_PRIMARY_ILK; + break; + case INTEL_PIPE_CRC_SOURCE_PLANE2: + *val = PIPE_CRC_ENABLE | PIPE_CRC_SOURCE_SPRITE_ILK; + break; + case INTEL_PIPE_CRC_SOURCE_PF: + return -EINVAL; + case INTEL_PIPE_CRC_SOURCE_PIPE: + *val = PIPE_CRC_ENABLE | PIPE_CRC_SOURCE_PIPE_ILK; + break; + default: + *val = 0; + break; + } + + return 0; +} + +static int ivb_pipe_crc_ctl_reg(enum intel_pipe_crc_source source, + uint32_t *val) +{ + switch (source) { + case INTEL_PIPE_CRC_SOURCE_PLANE1: + *val = PIPE_CRC_ENABLE | PIPE_CRC_SOURCE_PRIMARY_IVB; + break; + case INTEL_PIPE_CRC_SOURCE_PLANE2: + *val = PIPE_CRC_ENABLE | PIPE_CRC_SOURCE_SPRITE_IVB; + break; + case INTEL_PIPE_CRC_SOURCE_PF: + *val = PIPE_CRC_ENABLE | PIPE_CRC_SOURCE_PF_IVB; + break; + case INTEL_PIPE_CRC_SOURCE_PIPE: + return -EINVAL; + default: + *val = 0; + break; + } + + return 0; +} + static int pipe_crc_set_source(struct drm_device *dev, enum pipe pipe, enum intel_pipe_crc_source source) { struct drm_i915_private *dev_priv = dev->dev_private; struct intel_pipe_crc *pipe_crc = &dev_priv->pipe_crc[pipe]; u32 val; + int ret; - if (!IS_IVYBRIDGE(dev)) + if (!(IS_IVYBRIDGE(dev) || IS_GEN5(dev) || IS_GEN6(dev))) return -ENODEV; if (pipe_crc->source == source) @@ -1959,6 +2007,14 @@ static int pipe_crc_set_source(struct drm_device *dev, enum pipe pipe, if (pipe_crc->source && source) return -EINVAL; + if (IS_GEN5(dev) || IS_GEN6(dev)) + ret = ilk_pipe_crc_ctl_reg(source, &val); + else + ret = ivb_pipe_crc_ctl_reg(source, &val); + + if (ret != 0) + return ret; + /* none -> real source transition */ if (source) { DRM_DEBUG_DRIVER("collecting CRCs for pipe %c, %s\n", @@ -1976,22 +2032,6 @@ static int pipe_crc_set_source(struct drm_device *dev, enum pipe pipe, pipe_crc->source = source; - switch (source) { - case INTEL_PIPE_CRC_SOURCE_PLANE1: - val = PIPE_CRC_ENABLE | PIPE_CRC_SOURCE_PRIMARY_IVB; - break; - case INTEL_PIPE_CRC_SOURCE_PLANE2: - val = PIPE_CRC_ENABLE | PIPE_CRC_SOURCE_SPRITE_IVB; - break; - case INTEL_PIPE_CRC_SOURCE_PF: - val = PIPE_CRC_ENABLE | PIPE_CRC_SOURCE_PF_IVB; - break; - case INTEL_PIPE_CRC_SOURCE_NONE: - default: - val = 0; - break; - } - I915_WRITE(PIPE_CRC_CTL(pipe), val); POSTING_READ(PIPE_CRC_CTL(pipe)); diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 1292b40d2a44..2ea33eebf01c 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1223,6 +1223,7 @@ enum intel_pipe_crc_source { INTEL_PIPE_CRC_SOURCE_PLANE1, INTEL_PIPE_CRC_SOURCE_PLANE2, INTEL_PIPE_CRC_SOURCE_PF, + INTEL_PIPE_CRC_SOURCE_PIPE, INTEL_PIPE_CRC_SOURCE_MAX, }; diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index df031bb6c501..36465eff2d90 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -1240,8 +1240,22 @@ static void ivb_pipe_crc_update(struct drm_device *dev, enum pipe pipe) I915_READ(PIPE_CRC_RES_5_IVB(pipe)), I915_READ(PIPEFRAME(pipe))); } + +static void ilk_pipe_crc_update(struct drm_device *dev, enum pipe pipe) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + + display_pipe_crc_update(dev, pipe, + I915_READ(PIPE_CRC_RES_RED_ILK(pipe)), + I915_READ(PIPE_CRC_RES_GREEN_ILK(pipe)), + I915_READ(PIPE_CRC_RES_BLUE_ILK(pipe)), + I915_READ(PIPE_CRC_RES_RES1_ILK(pipe)), + I915_READ(PIPE_CRC_RES_RES2_ILK(pipe)), + I915_READ(PIPEFRAME(pipe))); +} #else static inline void ivb_pipe_crc_update(struct drm_device *dev, int pipe) {} +static inline void ilk_pipe_crc_update(struct drm_device *dev, int pipe) {} #endif /* The RPS events need forcewake, so we add them to a work queue and mask their @@ -1524,6 +1538,12 @@ static void ilk_display_irq_handler(struct drm_device *dev, u32 de_iir) if (intel_set_cpu_fifo_underrun_reporting(dev, PIPE_B, false)) DRM_DEBUG_DRIVER("Pipe B FIFO underrun\n"); + if (de_iir & DE_PIPEA_CRC_DONE) + ilk_pipe_crc_update(dev, PIPE_A); + + if (de_iir & DE_PIPEB_CRC_DONE) + ilk_pipe_crc_update(dev, PIPE_B); + if (de_iir & DE_PLANEA_FLIP_DONE) { intel_prepare_page_flip(dev, 0); intel_finish_page_flip_plane(dev, 0); @@ -2500,8 +2520,10 @@ static int ironlake_irq_postinstall(struct drm_device *dev) } else { display_mask = (DE_MASTER_IRQ_CONTROL | DE_GSE | DE_PCH_EVENT | DE_PLANEA_FLIP_DONE | DE_PLANEB_FLIP_DONE | - DE_AUX_CHANNEL_A | DE_PIPEB_FIFO_UNDERRUN | - DE_PIPEA_FIFO_UNDERRUN | DE_POISON); + DE_AUX_CHANNEL_A | + DE_PIPEB_FIFO_UNDERRUN | DE_PIPEA_FIFO_UNDERRUN | + DE_PIPEB_CRC_DONE | DE_PIPEA_CRC_DONE | + DE_POISON); extra_mask = DE_PIPEA_VBLANK | DE_PIPEB_VBLANK | DE_PCU_EVENT; } diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 11bd8b27d923..8b1f2dbc6009 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -3918,12 +3918,14 @@ #define DE_PIPEB_ODD_FIELD (1 << 13) #define DE_PIPEB_LINE_COMPARE (1 << 12) #define DE_PIPEB_VSYNC (1 << 11) +#define DE_PIPEB_CRC_DONE (1 << 10) #define DE_PIPEB_FIFO_UNDERRUN (1 << 8) #define DE_PIPEA_VBLANK (1 << 7) #define DE_PIPEA_EVEN_FIELD (1 << 6) #define DE_PIPEA_ODD_FIELD (1 << 5) #define DE_PIPEA_LINE_COMPARE (1 << 4) #define DE_PIPEA_VSYNC (1 << 3) +#define DE_PIPEA_CRC_DONE (1 << 2) #define DE_PIPEA_FIFO_UNDERRUN (1 << 0) /* More Ivybridge lolz */ -- cgit v1.2.2 From 8bc5e955f4819331ed470b251043bbfd5e2aab71 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Wed, 16 Oct 2013 22:55:49 +0200 Subject: drm/i915: use ->get_vblank_counter for the crc frame counter MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Suggested by Ville. Cc: Ville Syrjälä Reviewed-by: Damien Lespiau Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_irq.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 36465eff2d90..eaf12680c2ea 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -1193,7 +1193,7 @@ static void dp_aux_irq_handler(struct drm_device *dev) static void display_pipe_crc_update(struct drm_device *dev, enum pipe pipe, uint32_t crc0, uint32_t crc1, uint32_t crc2, uint32_t crc3, - uint32_t crc4, uint32_t frame) + uint32_t crc4) { struct drm_i915_private *dev_priv = dev->dev_private; struct intel_pipe_crc *pipe_crc = &dev_priv->pipe_crc[pipe]; @@ -1215,7 +1215,7 @@ static void display_pipe_crc_update(struct drm_device *dev, enum pipe pipe, entry = &pipe_crc->entries[head]; - entry->frame = frame; + entry->frame = dev->driver->get_vblank_counter(dev, pipe); entry->crc[0] = crc0; entry->crc[1] = crc1; entry->crc[2] = crc2; @@ -1237,8 +1237,7 @@ static void ivb_pipe_crc_update(struct drm_device *dev, enum pipe pipe) I915_READ(PIPE_CRC_RES_2_IVB(pipe)), I915_READ(PIPE_CRC_RES_3_IVB(pipe)), I915_READ(PIPE_CRC_RES_4_IVB(pipe)), - I915_READ(PIPE_CRC_RES_5_IVB(pipe)), - I915_READ(PIPEFRAME(pipe))); + I915_READ(PIPE_CRC_RES_5_IVB(pipe))); } static void ilk_pipe_crc_update(struct drm_device *dev, enum pipe pipe) @@ -1250,8 +1249,7 @@ static void ilk_pipe_crc_update(struct drm_device *dev, enum pipe pipe) I915_READ(PIPE_CRC_RES_GREEN_ILK(pipe)), I915_READ(PIPE_CRC_RES_BLUE_ILK(pipe)), I915_READ(PIPE_CRC_RES_RES1_ILK(pipe)), - I915_READ(PIPE_CRC_RES_RES2_ILK(pipe)), - I915_READ(PIPEFRAME(pipe))); + I915_READ(PIPE_CRC_RES_RES2_ILK(pipe))); } #else static inline void ivb_pipe_crc_update(struct drm_device *dev, int pipe) {} -- cgit v1.2.2 From bcf17ab2e9a9b15abdfce83461d4f98e0d11aa1a Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Wed, 16 Oct 2013 22:55:50 +0200 Subject: drm/i915: wait one vblank when disabling CRCs This avoids a spurious spurious interrupt warning. Reviewed-by: Damien Lespiau Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_debugfs.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index baa527234b93..e85507b335e5 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -2040,6 +2040,8 @@ static int pipe_crc_set_source(struct drm_device *dev, enum pipe pipe, DRM_DEBUG_DRIVER("stopping CRCs for pipe %c\n", pipe_name(pipe)); + intel_wait_for_vblank(dev, pipe); + kfree(pipe_crc->entries); pipe_crc->entries = NULL; } -- cgit v1.2.2 From e309a9977087fa0f2cb16d0a0790f7c05ccb5171 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Wed, 16 Oct 2013 22:55:51 +0200 Subject: drm/i915: fix CRC debugfs setup We've set up all files, but removed only those for which we have a pipe. Which leaves the one for pipe C on machines with less than 2 pipes, breaking module reload. v2: We can't get at the drm device this early (wtf), so just register all the files and also remove them all again. Reviewed-by: Damien Lespiau Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_debugfs.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index e85507b335e5..649c00ebf6e0 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -2772,7 +2772,6 @@ int i915_debugfs_init(struct drm_minor *minor) void i915_debugfs_cleanup(struct drm_minor *minor) { - struct drm_device *dev = minor->dev; int i; drm_debugfs_remove_files(i915_debugfs_list, @@ -2781,7 +2780,7 @@ void i915_debugfs_cleanup(struct drm_minor *minor) drm_debugfs_remove_files((struct drm_info_list *) &i915_forcewake_fops, 1, minor); - for (i = 0; i < INTEL_INFO(dev)->num_pipes; i++) { + for (i = 0; i < ARRAY_SIZE(i915_pipe_crc_data); i++) { struct drm_info_list *info_list = (struct drm_info_list *)&i915_pipe_crc_data[i]; -- cgit v1.2.2 From 5a69b89f853fb35adf51b8b45c026bad0934bf97 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Wed, 16 Oct 2013 22:55:52 +0200 Subject: drm/i915: crc support for hsw hw designers decided to change the CRC registers and coalesce them all into one. Otherwise nothing changed. I've opted for a new hsw_ version to grab the crc sample since hsw+1 will have the same crc registers, but different interrupt source registers. So this little helper function will come handy there. Also refactor the display error handler with a neat pipe loop. v2: Use for_each_pipe. Reviewed-by: Damien Lespiau Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_debugfs.c | 2 +- drivers/gpu/drm/i915/i915_irq.c | 44 +++++++++++++++++++++---------------- drivers/gpu/drm/i915/i915_reg.h | 1 + 3 files changed, 27 insertions(+), 20 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index 649c00ebf6e0..061182a0ce1b 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -1997,7 +1997,7 @@ static int pipe_crc_set_source(struct drm_device *dev, enum pipe pipe, u32 val; int ret; - if (!(IS_IVYBRIDGE(dev) || IS_GEN5(dev) || IS_GEN6(dev))) + if (!(INTEL_INFO(dev)->gen >= 5 && !IS_VALLEYVIEW(dev))) return -ENODEV; if (pipe_crc->source == source) diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index eaf12680c2ea..156a1a4d8e51 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -1228,6 +1228,15 @@ static void display_pipe_crc_update(struct drm_device *dev, enum pipe pipe, wake_up_interruptible(&pipe_crc->wq); } +static void hsw_pipe_crc_update(struct drm_device *dev, enum pipe pipe) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + + display_pipe_crc_update(dev, pipe, + I915_READ(PIPE_CRC_RES_1_IVB(pipe)), + 0, 0, 0, 0); +} + static void ivb_pipe_crc_update(struct drm_device *dev, enum pipe pipe) { struct drm_i915_private *dev_priv = dev->dev_private; @@ -1252,6 +1261,7 @@ static void ilk_pipe_crc_update(struct drm_device *dev, enum pipe pipe) I915_READ(PIPE_CRC_RES_RES2_ILK(pipe))); } #else +static inline void hsw_pipe_crc_update(struct drm_device *dev, int pipe) {} static inline void ivb_pipe_crc_update(struct drm_device *dev, int pipe) {} static inline void ilk_pipe_crc_update(struct drm_device *dev, int pipe) {} #endif @@ -1418,30 +1428,26 @@ static void ivb_err_int_handler(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; u32 err_int = I915_READ(GEN7_ERR_INT); + enum pipe pipe; if (err_int & ERR_INT_POISON) DRM_ERROR("Poison interrupt\n"); - if (err_int & ERR_INT_FIFO_UNDERRUN_A) - if (intel_set_cpu_fifo_underrun_reporting(dev, PIPE_A, false)) - DRM_DEBUG_DRIVER("Pipe A FIFO underrun\n"); - - if (err_int & ERR_INT_FIFO_UNDERRUN_B) - if (intel_set_cpu_fifo_underrun_reporting(dev, PIPE_B, false)) - DRM_DEBUG_DRIVER("Pipe B FIFO underrun\n"); - - if (err_int & ERR_INT_FIFO_UNDERRUN_C) - if (intel_set_cpu_fifo_underrun_reporting(dev, PIPE_C, false)) - DRM_DEBUG_DRIVER("Pipe C FIFO underrun\n"); - - if (err_int & ERR_INT_PIPE_CRC_DONE_A) - ivb_pipe_crc_update(dev, PIPE_A); - - if (err_int & ERR_INT_PIPE_CRC_DONE_B) - ivb_pipe_crc_update(dev, PIPE_B); + for_each_pipe(pipe) { + if (err_int & ERR_INT_FIFO_UNDERRUN(pipe)) { + if (intel_set_cpu_fifo_underrun_reporting(dev, pipe, + false)) + DRM_DEBUG_DRIVER("Pipe %c FIFO underrun\n", + pipe_name(pipe)); + } - if (err_int & ERR_INT_PIPE_CRC_DONE_C) - ivb_pipe_crc_update(dev, PIPE_C); + if (err_int & ERR_INT_PIPE_CRC_DONE(pipe)) { + if (IS_IVYBRIDGE(dev)) + ivb_pipe_crc_update(dev, pipe); + else + hsw_pipe_crc_update(dev, pipe); + } + } I915_WRITE(GEN7_ERR_INT, err_int); } diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 8b1f2dbc6009..0e7488b64965 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -728,6 +728,7 @@ #define ERR_INT_PIPE_CRC_DONE_B (1<<5) #define ERR_INT_FIFO_UNDERRUN_B (1<<3) #define ERR_INT_PIPE_CRC_DONE_A (1<<2) +#define ERR_INT_PIPE_CRC_DONE(pipe) (1<<(2 + pipe*3)) #define ERR_INT_FIFO_UNDERRUN_A (1<<0) #define ERR_INT_FIFO_UNDERRUN(pipe) (1<<(pipe*3)) -- cgit v1.2.2 From 3c9d87e3acb6d2e5a3c3f42ab42f206cbac13807 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Thu, 17 Oct 2013 22:44:31 +0200 Subject: drm/i915: remove dead code in ironlake_crtc_mode_set MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In Author: Daniel Vetter Date: Wed Jun 5 13:34:23 2013 +0200 drm/i915: consolidate pch pll enable sequence I've removed all the code from this if block, but somehow forgotten to kill the block itself. Reviewed-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 42b1c755d676..8905f83166f2 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -6072,11 +6072,6 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc, else intel_crtc->lowfreq_avail = false; - if (intel_crtc->config.has_pch_encoder) { - pll = intel_crtc_to_shared_dpll(intel_crtc); - - } - intel_set_pipe_timings(intel_crtc); if (intel_crtc->config.has_pch_encoder) { -- cgit v1.2.2 From 6da7f10d296f4ac625f96b39eef22c41398727e3 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Wed, 16 Oct 2013 17:06:17 +0300 Subject: drm/i915/dp: don't mention eDP bpp clamping if it doesn't affect bpp This is useful with the follow-up patch that frobs dev_priv->vbt.edp_bpp, and the value no longer comes directly from VBT. Signed-off-by: Jani Nikula Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_dp.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 7ee9210e6133..cea8624a0c1a 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -822,10 +822,11 @@ intel_dp_compute_config(struct intel_encoder *encoder, /* Walk through all bpp values. Luckily they're all nicely spaced with 2 * bpc in between. */ bpp = pipe_config->pipe_bpp; - if (is_edp(intel_dp) && dev_priv->vbt.edp_bpp) { + if (is_edp(intel_dp) && dev_priv->vbt.edp_bpp && + dev_priv->vbt.edp_bpp < bpp) { DRM_DEBUG_KMS("clamping bpp for eDP panel to BIOS-provided %i\n", dev_priv->vbt.edp_bpp); - bpp = min_t(int, bpp, dev_priv->vbt.edp_bpp); + bpp = dev_priv->vbt.edp_bpp; } for (; bpp >= 6*3; bpp -= 2*3) { -- cgit v1.2.2