summaryrefslogtreecommitdiff
path: root/drivers/gpu/drm/i915/display/intel_fbc.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm/i915/display/intel_fbc.c')
-rw-r--r--drivers/gpu/drm/i915/display/intel_fbc.c238
1 files changed, 143 insertions, 95 deletions
diff --git a/drivers/gpu/drm/i915/display/intel_fbc.c b/drivers/gpu/drm/i915/display/intel_fbc.c
index 160fd2bdafe5..465dc4e97ea8 100644
--- a/drivers/gpu/drm/i915/display/intel_fbc.c
+++ b/drivers/gpu/drm/i915/display/intel_fbc.c
@@ -49,6 +49,14 @@
#include "intel_fbc.h"
#include "intel_frontbuffer.h"
+#define for_each_fbc_id(__dev_priv, __fbc_id) \
+ for ((__fbc_id) = INTEL_FBC_A; (__fbc_id) < I915_MAX_FBCS; (__fbc_id)++) \
+ for_each_if(INTEL_INFO(__dev_priv)->display.fbc_mask & BIT(__fbc_id))
+
+#define for_each_intel_fbc(__dev_priv, __fbc, __fbc_id) \
+ for_each_fbc_id((__dev_priv), (__fbc_id)) \
+ for_each_if((__fbc) = (__dev_priv)->fbc[(__fbc_id)])
+
struct intel_fbc_funcs {
void (*activate)(struct intel_fbc *fbc);
void (*deactivate)(struct intel_fbc *fbc);
@@ -85,6 +93,8 @@ struct intel_fbc {
struct drm_mm_node compressed_fb;
struct drm_mm_node compressed_llb;
+ enum intel_fbc_id id;
+
u8 limit;
bool false_color;
@@ -454,10 +464,10 @@ static void ilk_fbc_activate(struct intel_fbc *fbc)
struct intel_fbc_state *fbc_state = &fbc->state;
struct drm_i915_private *i915 = fbc->i915;
- intel_de_write(i915, ILK_DPFC_FENCE_YOFF,
+ intel_de_write(i915, ILK_DPFC_FENCE_YOFF(fbc->id),
fbc_state->fence_y_offset);
- intel_de_write(i915, ILK_DPFC_CONTROL,
+ intel_de_write(i915, ILK_DPFC_CONTROL(fbc->id),
DPFC_CTL_EN | g4x_dpfc_ctl(fbc));
}
@@ -467,28 +477,28 @@ static void ilk_fbc_deactivate(struct intel_fbc *fbc)
u32 dpfc_ctl;
/* Disable compression */
- dpfc_ctl = intel_de_read(i915, ILK_DPFC_CONTROL);
+ dpfc_ctl = intel_de_read(i915, ILK_DPFC_CONTROL(fbc->id));
if (dpfc_ctl & DPFC_CTL_EN) {
dpfc_ctl &= ~DPFC_CTL_EN;
- intel_de_write(i915, ILK_DPFC_CONTROL, dpfc_ctl);
+ intel_de_write(i915, ILK_DPFC_CONTROL(fbc->id), dpfc_ctl);
}
}
static bool ilk_fbc_is_active(struct intel_fbc *fbc)
{
- return intel_de_read(fbc->i915, ILK_DPFC_CONTROL) & DPFC_CTL_EN;
+ return intel_de_read(fbc->i915, ILK_DPFC_CONTROL(fbc->id)) & DPFC_CTL_EN;
}
static bool ilk_fbc_is_compressing(struct intel_fbc *fbc)
{
- return intel_de_read(fbc->i915, ILK_DPFC_STATUS) & DPFC_COMP_SEG_MASK;
+ return intel_de_read(fbc->i915, ILK_DPFC_STATUS(fbc->id)) & DPFC_COMP_SEG_MASK;
}
static void ilk_fbc_program_cfb(struct intel_fbc *fbc)
{
struct drm_i915_private *i915 = fbc->i915;
- intel_de_write(i915, ILK_DPFC_CB_BASE, fbc->compressed_fb.start);
+ intel_de_write(i915, ILK_DPFC_CB_BASE(fbc->id), fbc->compressed_fb.start);
}
static const struct intel_fbc_funcs ilk_fbc_funcs = {
@@ -524,8 +534,8 @@ static void snb_fbc_nuke(struct intel_fbc *fbc)
{
struct drm_i915_private *i915 = fbc->i915;
- intel_de_write(i915, MSG_FBC_REND_STATE, FBC_REND_NUKE);
- intel_de_posting_read(i915, MSG_FBC_REND_STATE);
+ intel_de_write(i915, MSG_FBC_REND_STATE(fbc->id), FBC_REND_NUKE);
+ intel_de_posting_read(i915, MSG_FBC_REND_STATE(fbc->id));
}
static const struct intel_fbc_funcs snb_fbc_funcs = {
@@ -547,7 +557,7 @@ static void glk_fbc_program_cfb_stride(struct intel_fbc *fbc)
val |= FBC_STRIDE_OVERRIDE |
FBC_STRIDE(fbc_state->override_cfb_stride / fbc->limit);
- intel_de_write(i915, GLK_FBC_STRIDE, val);
+ intel_de_write(i915, GLK_FBC_STRIDE(fbc->id), val);
}
static void skl_fbc_program_cfb_stride(struct intel_fbc *fbc)
@@ -598,19 +608,19 @@ static void ivb_fbc_activate(struct intel_fbc *fbc)
if (i915->ggtt.num_fences)
snb_fbc_program_fence(fbc);
- intel_de_write(i915, ILK_DPFC_CONTROL,
+ intel_de_write(i915, ILK_DPFC_CONTROL(fbc->id),
DPFC_CTL_EN | ivb_dpfc_ctl(fbc));
}
static bool ivb_fbc_is_compressing(struct intel_fbc *fbc)
{
- return intel_de_read(fbc->i915, ILK_DPFC_STATUS2) & DPFC_COMP_SEG_MASK_IVB;
+ return intel_de_read(fbc->i915, ILK_DPFC_STATUS2(fbc->id)) & DPFC_COMP_SEG_MASK_IVB;
}
static void ivb_fbc_set_false_color(struct intel_fbc *fbc,
bool enable)
{
- intel_de_rmw(fbc->i915, ILK_DPFC_CONTROL,
+ intel_de_rmw(fbc->i915, ILK_DPFC_CONTROL(fbc->id),
DPFC_CTL_FALSE_COLOR, enable ? DPFC_CTL_FALSE_COLOR : 0);
}
@@ -810,16 +820,16 @@ static void __intel_fbc_cleanup_cfb(struct intel_fbc *fbc)
void intel_fbc_cleanup(struct drm_i915_private *i915)
{
- struct intel_fbc *fbc = i915->fbc;
-
- if (!fbc)
- return;
+ struct intel_fbc *fbc;
+ enum intel_fbc_id fbc_id;
- mutex_lock(&fbc->lock);
- __intel_fbc_cleanup_cfb(fbc);
- mutex_unlock(&fbc->lock);
+ for_each_intel_fbc(i915, fbc, fbc_id) {
+ mutex_lock(&fbc->lock);
+ __intel_fbc_cleanup_cfb(fbc);
+ mutex_unlock(&fbc->lock);
- kfree(fbc);
+ kfree(fbc);
+ }
}
static bool stride_is_valid(const struct intel_plane_state *plane_state)
@@ -1305,15 +1315,10 @@ static unsigned int intel_fbc_get_frontbuffer_bit(struct intel_fbc *fbc)
return fbc->possible_framebuffer_bits;
}
-void intel_fbc_invalidate(struct drm_i915_private *i915,
- unsigned int frontbuffer_bits,
- enum fb_op_origin origin)
+static void __intel_fbc_invalidate(struct intel_fbc *fbc,
+ unsigned int frontbuffer_bits,
+ enum fb_op_origin origin)
{
- struct intel_fbc *fbc = i915->fbc;
-
- if (!fbc)
- return;
-
if (origin == ORIGIN_FLIP || origin == ORIGIN_CURSOR_UPDATE)
return;
@@ -1327,14 +1332,22 @@ void intel_fbc_invalidate(struct drm_i915_private *i915,
mutex_unlock(&fbc->lock);
}
-void intel_fbc_flush(struct drm_i915_private *i915,
- unsigned int frontbuffer_bits, enum fb_op_origin origin)
+void intel_fbc_invalidate(struct drm_i915_private *i915,
+ unsigned int frontbuffer_bits,
+ enum fb_op_origin origin)
{
- struct intel_fbc *fbc = i915->fbc;
+ struct intel_fbc *fbc;
+ enum intel_fbc_id fbc_id;
- if (!fbc)
- return;
+ for_each_intel_fbc(i915, fbc, fbc_id)
+ __intel_fbc_invalidate(fbc, frontbuffer_bits, origin);
+
+}
+static void __intel_fbc_flush(struct intel_fbc *fbc,
+ unsigned int frontbuffer_bits,
+ enum fb_op_origin origin)
+{
mutex_lock(&fbc->lock);
fbc->busy_bits &= ~frontbuffer_bits;
@@ -1354,6 +1367,17 @@ out:
mutex_unlock(&fbc->lock);
}
+void intel_fbc_flush(struct drm_i915_private *i915,
+ unsigned int frontbuffer_bits,
+ enum fb_op_origin origin)
+{
+ struct intel_fbc *fbc;
+ enum intel_fbc_id fbc_id;
+
+ for_each_intel_fbc(i915, fbc, fbc_id)
+ __intel_fbc_flush(fbc, frontbuffer_bits, origin);
+}
+
int intel_fbc_atomic_check(struct intel_atomic_state *state)
{
struct intel_plane_state *plane_state;
@@ -1483,15 +1507,15 @@ void intel_fbc_update(struct intel_atomic_state *state,
*/
void intel_fbc_global_disable(struct drm_i915_private *i915)
{
- struct intel_fbc *fbc = i915->fbc;
-
- if (!fbc)
- return;
+ struct intel_fbc *fbc;
+ enum intel_fbc_id fbc_id;
- mutex_lock(&fbc->lock);
- if (fbc->state.plane)
- __intel_fbc_disable(fbc);
- mutex_unlock(&fbc->lock);
+ for_each_intel_fbc(i915, fbc, fbc_id) {
+ mutex_lock(&fbc->lock);
+ if (fbc->state.plane)
+ __intel_fbc_disable(fbc);
+ mutex_unlock(&fbc->lock);
+ }
}
static void intel_fbc_underrun_work_fn(struct work_struct *work)
@@ -1516,19 +1540,9 @@ out:
mutex_unlock(&fbc->lock);
}
-/*
- * intel_fbc_reset_underrun - reset FBC fifo underrun status.
- * @i915: the i915 device
- *
- * See intel_fbc_handle_fifo_underrun_irq(). For automated testing we
- * want to re-enable FBC after an underrun to increase test coverage.
- */
-void intel_fbc_reset_underrun(struct drm_i915_private *i915)
+static void __intel_fbc_reset_underrun(struct intel_fbc *fbc)
{
- struct intel_fbc *fbc = i915->fbc;
-
- if (!fbc)
- return;
+ struct drm_i915_private *i915 = fbc->i915;
cancel_work_sync(&fbc->underrun_work);
@@ -1544,6 +1558,38 @@ void intel_fbc_reset_underrun(struct drm_i915_private *i915)
mutex_unlock(&fbc->lock);
}
+/*
+ * intel_fbc_reset_underrun - reset FBC fifo underrun status.
+ * @i915: the i915 device
+ *
+ * See intel_fbc_handle_fifo_underrun_irq(). For automated testing we
+ * want to re-enable FBC after an underrun to increase test coverage.
+ */
+void intel_fbc_reset_underrun(struct drm_i915_private *i915)
+{
+ struct intel_fbc *fbc;
+ enum intel_fbc_id fbc_id;
+
+ for_each_intel_fbc(i915, fbc, fbc_id)
+ __intel_fbc_reset_underrun(fbc);
+}
+
+static void __intel_fbc_handle_fifo_underrun_irq(struct intel_fbc *fbc)
+{
+ /*
+ * There's no guarantee that underrun_detected won't be set to true
+ * right after this check and before the work is scheduled, but that's
+ * not a problem since we'll check it again under the work function
+ * while FBC is locked. This check here is just to prevent us from
+ * unnecessarily scheduling the work, and it relies on the fact that we
+ * never switch underrun_detect back to false after it's true.
+ */
+ if (READ_ONCE(fbc->underrun_detected))
+ return;
+
+ schedule_work(&fbc->underrun_work);
+}
+
/**
* intel_fbc_handle_fifo_underrun_irq - disable FBC when we get a FIFO underrun
* @i915: i915 device
@@ -1560,21 +1606,11 @@ void intel_fbc_reset_underrun(struct drm_i915_private *i915)
*/
void intel_fbc_handle_fifo_underrun_irq(struct drm_i915_private *i915)
{
- struct intel_fbc *fbc = i915->fbc;
-
- if (!fbc)
- return;
-
- /* There's no guarantee that underrun_detected won't be set to true
- * right after this check and before the work is scheduled, but that's
- * not a problem since we'll check it again under the work function
- * while FBC is locked. This check here is just to prevent us from
- * unnecessarily scheduling the work, and it relies on the fact that we
- * never switch underrun_detect back to false after it's true. */
- if (READ_ONCE(fbc->underrun_detected))
- return;
+ struct intel_fbc *fbc;
+ enum intel_fbc_id fbc_id;
- schedule_work(&fbc->underrun_work);
+ for_each_intel_fbc(i915, fbc, fbc_id)
+ __intel_fbc_handle_fifo_underrun_irq(fbc);
}
/*
@@ -1622,7 +1658,8 @@ void intel_fbc_add_plane(struct intel_fbc *fbc, struct intel_plane *plane)
fbc->possible_framebuffer_bits |= plane->frontbuffer_bit;
}
-static struct intel_fbc *intel_fbc_create(struct drm_i915_private *i915)
+static struct intel_fbc *intel_fbc_create(struct drm_i915_private *i915,
+ enum intel_fbc_id fbc_id)
{
struct intel_fbc *fbc;
@@ -1630,6 +1667,7 @@ static struct intel_fbc *intel_fbc_create(struct drm_i915_private *i915)
if (!fbc)
return NULL;
+ fbc->id = fbc_id;
fbc->i915 = i915;
INIT_WORK(&fbc->underrun_work, intel_fbc_underrun_work_fn);
mutex_init(&fbc->lock);
@@ -1658,32 +1696,35 @@ static struct intel_fbc *intel_fbc_create(struct drm_i915_private *i915)
*/
void intel_fbc_init(struct drm_i915_private *i915)
{
- struct intel_fbc *fbc;
+ enum intel_fbc_id fbc_id;
if (!drm_mm_initialized(&i915->mm.stolen))
- mkwrite_device_info(i915)->display.has_fbc = false;
+ mkwrite_device_info(i915)->display.fbc_mask = 0;
if (need_fbc_vtd_wa(i915))
- mkwrite_device_info(i915)->display.has_fbc = false;
+ mkwrite_device_info(i915)->display.fbc_mask = 0;
i915->params.enable_fbc = intel_sanitize_fbc_option(i915);
drm_dbg_kms(&i915->drm, "Sanitized enable_fbc value: %d\n",
i915->params.enable_fbc);
- if (!HAS_FBC(i915))
- return;
+ for_each_fbc_id(i915, fbc_id) {
+ struct intel_fbc *fbc;
- fbc = intel_fbc_create(i915);
- if (!fbc)
- return;
+ fbc = intel_fbc_create(i915, fbc_id);
+ if (!fbc)
+ continue;
- /* We still don't have any sort of hardware state readout for FBC, so
- * deactivate it in case the BIOS activated it to make sure software
- * matches the hardware state. */
- if (intel_fbc_hw_is_active(fbc))
- intel_fbc_hw_deactivate(fbc);
+ /*
+ * We still don't have any sort of hardware state readout
+ * for FBC, so deactivate it in case the BIOS activated it
+ * to make sure software matches the hardware state.
+ */
+ if (intel_fbc_hw_is_active(fbc))
+ intel_fbc_hw_deactivate(fbc);
- i915->fbc = fbc;
+ i915->fbc[fbc->id] = fbc;
+ }
}
static int intel_fbc_debugfs_status_show(struct seq_file *m, void *unused)
@@ -1759,25 +1800,32 @@ DEFINE_SIMPLE_ATTRIBUTE(intel_fbc_debugfs_false_color_fops,
intel_fbc_debugfs_false_color_set,
"%llu\n");
-static void intel_fbc_debugfs_add(struct intel_fbc *fbc)
+static void intel_fbc_debugfs_add(struct intel_fbc *fbc,
+ struct dentry *parent)
{
- struct drm_i915_private *i915 = fbc->i915;
- struct drm_minor *minor = i915->drm.primary;
-
- debugfs_create_file("i915_fbc_status", 0444,
- minor->debugfs_root, fbc,
- &intel_fbc_debugfs_status_fops);
+ debugfs_create_file("i915_fbc_status", 0444, parent,
+ fbc, &intel_fbc_debugfs_status_fops);
if (fbc->funcs->set_false_color)
- debugfs_create_file("i915_fbc_false_color", 0644,
- minor->debugfs_root, fbc,
- &intel_fbc_debugfs_false_color_fops);
+ debugfs_create_file("i915_fbc_false_color", 0644, parent,
+ fbc, &intel_fbc_debugfs_false_color_fops);
}
+void intel_fbc_crtc_debugfs_add(struct intel_crtc *crtc)
+{
+ struct intel_plane *plane = to_intel_plane(crtc->base.primary);
+
+ if (plane->fbc)
+ intel_fbc_debugfs_add(plane->fbc, crtc->base.debugfs_entry);
+}
+
+/* FIXME: remove this once igt is on board with per-crtc stuff */
void intel_fbc_debugfs_register(struct drm_i915_private *i915)
{
- struct intel_fbc *fbc = i915->fbc;
+ struct drm_minor *minor = i915->drm.primary;
+ struct intel_fbc *fbc;
+ fbc = i915->fbc[INTEL_FBC_A];
if (fbc)
- intel_fbc_debugfs_add(fbc);
+ intel_fbc_debugfs_add(fbc, minor->debugfs_root);
}