Let's compute the watermarks first and the FIFO size second. This way we
can make sure the FIFO split is the most accommodating to the watermarks.
Previously we could have potentially computed a FIFO split that couldn't
accommodate the PM2 watermarks simply due to a bad split even if the
total FIFO size would have been sufficient.
It'll also allow us to avoid recomputing the wms for all planes whenever
the FIFO split would change. Thus we don't have to add any extra planes
to the state when the FIFO needs to be repartitioned.
To help with this we'll keep around copies of the non-inverted
watermarks in the crtc state. For now that doesn't help too much, but
once we start to do the watermark computation only for the planes
that change we'll need the non-inverted values around for the other
planes.
v2: s/noninverted/raw/ for consistency with other platforms
Fix the memset() of the "raw" watermarks
Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
Reviewed-by: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
Link: http://patchwork.freedesktop.org/patch/msgid/20170302171508.1666-7-ville.syrjala@linux.intel.com
+ /* "raw" watermarks (not inverted) */
+ struct vlv_pipe_wm raw[NUM_VLV_WM_LEVELS];
/* optimal watermarks (inverted) */
struct vlv_wm_state optimal;
/* display FIFO split */
/* optimal watermarks (inverted) */
struct vlv_wm_state optimal;
/* display FIFO split */
return min_t(int, wm, USHRT_MAX);
}
return min_t(int, wm, USHRT_MAX);
}
-static void vlv_compute_fifo(struct intel_crtc_state *crtc_state)
+static int vlv_compute_fifo(struct intel_crtc_state *crtc_state)
{
struct intel_crtc *crtc = to_intel_crtc(crtc_state->base.crtc);
{
struct intel_crtc *crtc = to_intel_crtc(crtc_state->base.crtc);
- struct vlv_wm_state *wm_state = &crtc_state->wm.vlv.optimal;
+ const struct vlv_pipe_wm *raw =
+ &crtc_state->wm.vlv.raw[VLV_WM_LEVEL_PM2];
struct vlv_fifo_state *fifo_state = &crtc_state->wm.vlv.fifo_state;
struct vlv_fifo_state *fifo_state = &crtc_state->wm.vlv.fifo_state;
- struct drm_device *dev = crtc->base.dev;
- struct intel_plane *plane;
- unsigned int total_rate = 0;
- const int fifo_size = 512 - 1;
+ unsigned int active_planes = crtc_state->active_planes & ~BIT(PLANE_CURSOR);
+ int num_active_planes = hweight32(active_planes);
+ const int fifo_size = 511;
int fifo_extra, fifo_left = fifo_size;
int fifo_extra, fifo_left = fifo_size;
+ unsigned int total_rate;
+ enum plane_id plane_id;
- for_each_intel_plane_on_crtc(dev, crtc, plane) {
- struct intel_plane_state *state =
- to_intel_plane_state(plane->base.state);
+ total_rate = raw->plane[PLANE_PRIMARY] +
+ raw->plane[PLANE_SPRITE0] +
+ raw->plane[PLANE_SPRITE1];
- if (plane->id == PLANE_CURSOR)
- continue;
+ if (total_rate > fifo_size)
+ return -EINVAL;
- if (state->base.visible) {
- wm_state->num_active_planes++;
- total_rate += state->base.fb->format->cpp[0];
- }
- }
+ if (total_rate == 0)
+ total_rate = 1;
- for_each_intel_plane_on_crtc(dev, crtc, plane) {
- struct intel_plane_state *state =
- to_intel_plane_state(plane->base.state);
+ for_each_plane_id_on_crtc(crtc, plane_id) {
- if (plane->id == PLANE_CURSOR) {
- fifo_state->plane[plane->id] = 63;
- continue;
- }
-
- if (!state->base.visible) {
- fifo_state->plane[plane->id] = 0;
+ if ((active_planes & BIT(plane_id)) == 0) {
+ fifo_state->plane[plane_id] = 0;
- rate = state->base.fb->format->cpp[0];
- fifo_state->plane[plane->id] = fifo_size * rate / total_rate;
- fifo_left -= fifo_state->plane[plane->id];
+ rate = raw->plane[plane_id];
+ fifo_state->plane[plane_id] = fifo_size * rate / total_rate;
+ fifo_left -= fifo_state->plane[plane_id];
- fifo_extra = DIV_ROUND_UP(fifo_left, wm_state->num_active_planes ?: 1);
+ fifo_state->plane[PLANE_CURSOR] = 63;
+
+ fifo_extra = DIV_ROUND_UP(fifo_left, num_active_planes ?: 1);
/* spread the remainder evenly */
/* spread the remainder evenly */
- for_each_intel_plane_on_crtc(dev, crtc, plane) {
+ for_each_plane_id_on_crtc(crtc, plane_id) {
int plane_extra;
if (fifo_left == 0)
break;
int plane_extra;
if (fifo_left == 0)
break;
- if (plane->id == PLANE_CURSOR)
- continue;
-
- /* give it all to the first plane if none are active */
- if (fifo_state->plane[plane->id] == 0 &&
- wm_state->num_active_planes)
+ if ((active_planes & BIT(plane_id)) == 0)
continue;
plane_extra = min(fifo_extra, fifo_left);
continue;
plane_extra = min(fifo_extra, fifo_left);
- fifo_state->plane[plane->id] += plane_extra;
+ fifo_state->plane[plane_id] += plane_extra;
fifo_left -= plane_extra;
}
fifo_left -= plane_extra;
}
- WARN_ON(fifo_left != 0);
+ WARN_ON(active_planes != 0 && fifo_left != 0);
+
+ /* give it all to the first plane if none are active */
+ if (active_planes == 0) {
+ WARN_ON(fifo_left != fifo_size);
+ fifo_state->plane[PLANE_PRIMARY] = fifo_left;
+ }
+
+ return 0;
}
static u16 vlv_invert_wm_value(u16 wm, u16 fifo_size)
}
static u16 vlv_invert_wm_value(u16 wm, u16 fifo_size)
struct intel_crtc *crtc = to_intel_crtc(crtc_state->base.crtc);
struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
struct vlv_wm_state *wm_state = &crtc_state->wm.vlv.optimal;
struct intel_crtc *crtc = to_intel_crtc(crtc_state->base.crtc);
struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
struct vlv_wm_state *wm_state = &crtc_state->wm.vlv.optimal;
- const struct vlv_fifo_state *fifo_state =
- &crtc_state->wm.vlv.fifo_state;
struct intel_plane *plane;
int level;
memset(wm_state, 0, sizeof(*wm_state));
struct intel_plane *plane;
int level;
memset(wm_state, 0, sizeof(*wm_state));
+ memset(&crtc_state->wm.vlv.raw, 0, sizeof(crtc_state->wm.vlv.raw));
wm_state->cxsr = crtc->pipe != PIPE_C && crtc->wm.cxsr_allowed;
wm_state->num_levels = dev_priv->wm.max_level + 1;
wm_state->num_active_planes = 0;
wm_state->cxsr = crtc->pipe != PIPE_C && crtc->wm.cxsr_allowed;
wm_state->num_levels = dev_priv->wm.max_level + 1;
wm_state->num_active_planes = 0;
- vlv_compute_fifo(crtc_state);
-
if (wm_state->num_active_planes != 1)
wm_state->cxsr = false;
for_each_intel_plane_on_crtc(&dev_priv->drm, crtc, plane) {
struct intel_plane_state *state =
to_intel_plane_state(plane->base.state);
if (wm_state->num_active_planes != 1)
wm_state->cxsr = false;
for_each_intel_plane_on_crtc(&dev_priv->drm, crtc, plane) {
struct intel_plane_state *state =
to_intel_plane_state(plane->base.state);
if (!state->base.visible)
continue;
if (!state->base.visible)
continue;
- /* normal watermarks */
for (level = 0; level < wm_state->num_levels; level++) {
for (level = 0; level < wm_state->num_levels; level++) {
+ struct vlv_pipe_wm *raw = &crtc_state->wm.vlv.raw[level];
int wm = vlv_compute_wm_level(crtc_state, state, level);
int wm = vlv_compute_wm_level(crtc_state, state, level);
- int max_wm = fifo_state->plane[plane->id];
+ int max_wm = plane->id == PLANE_CURSOR ? 63 : 511;
/* hack */
if (WARN_ON(level == 0 && wm > max_wm))
/* hack */
if (WARN_ON(level == 0 && wm > max_wm))
- wm_state->wm[level].plane[plane->id] = wm;
+ raw->plane[plane->id] = wm;
}
wm_state->num_levels = level;
}
wm_state->num_levels = level;
- if (!wm_state->cxsr)
- continue;
+ vlv_compute_fifo(crtc_state);
- /* maxfifo watermarks */
- if (plane->id == PLANE_CURSOR) {
- for (level = 0; level < wm_state->num_levels; level++)
- wm_state->sr[level].cursor =
- wm_state->wm[level].plane[PLANE_CURSOR];
- } else {
- for (level = 0; level < wm_state->num_levels; level++)
- wm_state->sr[level].plane =
- max(wm_state->sr[level].plane,
- wm_state->wm[level].plane[plane->id]);
- }
+ for (level = 0; level < wm_state->num_levels; level++) {
+ struct vlv_pipe_wm *raw = &crtc_state->wm.vlv.raw[level];
+
+ wm_state->wm[level] = *raw;
+
+ wm_state->sr[level].plane = max3(raw->plane[PLANE_PRIMARY],
+ raw->plane[PLANE_SPRITE0],
+ raw->plane[PLANE_SPRITE1]);
+ wm_state->sr[level].cursor = raw->plane[PLANE_CURSOR];
}
/* clear any (partially) filled invalid levels */
}
/* clear any (partially) filled invalid levels */