Commit d210246a authored by Chris Wilson's avatar Chris Wilson

drm/i915: Refactor self-refresh watermark calculations

Move the plane->mode config to the point of use rather than repeatedly
querying the same information.
Signed-off-by: default avatarChris Wilson <chris@chris-wilson.co.uk>
parent 29ee3991
...@@ -202,9 +202,7 @@ struct drm_i915_display_funcs { ...@@ -202,9 +202,7 @@ struct drm_i915_display_funcs {
void (*disable_fbc)(struct drm_device *dev); void (*disable_fbc)(struct drm_device *dev);
int (*get_display_clock_speed)(struct drm_device *dev); int (*get_display_clock_speed)(struct drm_device *dev);
int (*get_fifo_size)(struct drm_device *dev, int plane); int (*get_fifo_size)(struct drm_device *dev, int plane);
void (*update_wm)(struct drm_device *dev, int planea_clock, void (*update_wm)(struct drm_device *dev);
int planeb_clock, int sr_hdisplay, int sr_htotal,
int pixel_size);
/* clock updates for mode set */ /* clock updates for mode set */
/* cursor updates */ /* cursor updates */
/* render clock increase/decrease */ /* render clock increase/decrease */
......
...@@ -1895,7 +1895,7 @@ static void intel_update_fbc(struct drm_device *dev) ...@@ -1895,7 +1895,7 @@ static void intel_update_fbc(struct drm_device *dev)
* - going to an unsupported config (interlace, pixel multiply, etc.) * - going to an unsupported config (interlace, pixel multiply, etc.)
*/ */
list_for_each_entry(tmp_crtc, &dev->mode_config.crtc_list, head) { list_for_each_entry(tmp_crtc, &dev->mode_config.crtc_list, head) {
if (tmp_crtc->enabled) { if (tmp_crtc->enabled && tmp_crtc->fb) {
if (crtc) { if (crtc) {
DRM_DEBUG_KMS("more than one pipe active, disabling compression\n"); DRM_DEBUG_KMS("more than one pipe active, disabling compression\n");
dev_priv->no_fbc_reason = FBC_MULTIPLE_PIPES; dev_priv->no_fbc_reason = FBC_MULTIPLE_PIPES;
...@@ -3207,77 +3207,77 @@ struct intel_watermark_params { ...@@ -3207,77 +3207,77 @@ struct intel_watermark_params {
}; };
/* Pineview has different values for various configs */ /* Pineview has different values for various configs */
static struct intel_watermark_params pineview_display_wm = { static const struct intel_watermark_params pineview_display_wm = {
PINEVIEW_DISPLAY_FIFO, PINEVIEW_DISPLAY_FIFO,
PINEVIEW_MAX_WM, PINEVIEW_MAX_WM,
PINEVIEW_DFT_WM, PINEVIEW_DFT_WM,
PINEVIEW_GUARD_WM, PINEVIEW_GUARD_WM,
PINEVIEW_FIFO_LINE_SIZE PINEVIEW_FIFO_LINE_SIZE
}; };
static struct intel_watermark_params pineview_display_hplloff_wm = { static const struct intel_watermark_params pineview_display_hplloff_wm = {
PINEVIEW_DISPLAY_FIFO, PINEVIEW_DISPLAY_FIFO,
PINEVIEW_MAX_WM, PINEVIEW_MAX_WM,
PINEVIEW_DFT_HPLLOFF_WM, PINEVIEW_DFT_HPLLOFF_WM,
PINEVIEW_GUARD_WM, PINEVIEW_GUARD_WM,
PINEVIEW_FIFO_LINE_SIZE PINEVIEW_FIFO_LINE_SIZE
}; };
static struct intel_watermark_params pineview_cursor_wm = { static const struct intel_watermark_params pineview_cursor_wm = {
PINEVIEW_CURSOR_FIFO, PINEVIEW_CURSOR_FIFO,
PINEVIEW_CURSOR_MAX_WM, PINEVIEW_CURSOR_MAX_WM,
PINEVIEW_CURSOR_DFT_WM, PINEVIEW_CURSOR_DFT_WM,
PINEVIEW_CURSOR_GUARD_WM, PINEVIEW_CURSOR_GUARD_WM,
PINEVIEW_FIFO_LINE_SIZE, PINEVIEW_FIFO_LINE_SIZE,
}; };
static struct intel_watermark_params pineview_cursor_hplloff_wm = { static const struct intel_watermark_params pineview_cursor_hplloff_wm = {
PINEVIEW_CURSOR_FIFO, PINEVIEW_CURSOR_FIFO,
PINEVIEW_CURSOR_MAX_WM, PINEVIEW_CURSOR_MAX_WM,
PINEVIEW_CURSOR_DFT_WM, PINEVIEW_CURSOR_DFT_WM,
PINEVIEW_CURSOR_GUARD_WM, PINEVIEW_CURSOR_GUARD_WM,
PINEVIEW_FIFO_LINE_SIZE PINEVIEW_FIFO_LINE_SIZE
}; };
static struct intel_watermark_params g4x_wm_info = { static const struct intel_watermark_params g4x_wm_info = {
G4X_FIFO_SIZE, G4X_FIFO_SIZE,
G4X_MAX_WM, G4X_MAX_WM,
G4X_MAX_WM, G4X_MAX_WM,
2, 2,
G4X_FIFO_LINE_SIZE, G4X_FIFO_LINE_SIZE,
}; };
static struct intel_watermark_params g4x_cursor_wm_info = { static const struct intel_watermark_params g4x_cursor_wm_info = {
I965_CURSOR_FIFO, I965_CURSOR_FIFO,
I965_CURSOR_MAX_WM, I965_CURSOR_MAX_WM,
I965_CURSOR_DFT_WM, I965_CURSOR_DFT_WM,
2, 2,
G4X_FIFO_LINE_SIZE, G4X_FIFO_LINE_SIZE,
}; };
static struct intel_watermark_params i965_cursor_wm_info = { static const struct intel_watermark_params i965_cursor_wm_info = {
I965_CURSOR_FIFO, I965_CURSOR_FIFO,
I965_CURSOR_MAX_WM, I965_CURSOR_MAX_WM,
I965_CURSOR_DFT_WM, I965_CURSOR_DFT_WM,
2, 2,
I915_FIFO_LINE_SIZE, I915_FIFO_LINE_SIZE,
}; };
static struct intel_watermark_params i945_wm_info = { static const struct intel_watermark_params i945_wm_info = {
I945_FIFO_SIZE, I945_FIFO_SIZE,
I915_MAX_WM, I915_MAX_WM,
1, 1,
2, 2,
I915_FIFO_LINE_SIZE I915_FIFO_LINE_SIZE
}; };
static struct intel_watermark_params i915_wm_info = { static const struct intel_watermark_params i915_wm_info = {
I915_FIFO_SIZE, I915_FIFO_SIZE,
I915_MAX_WM, I915_MAX_WM,
1, 1,
2, 2,
I915_FIFO_LINE_SIZE I915_FIFO_LINE_SIZE
}; };
static struct intel_watermark_params i855_wm_info = { static const struct intel_watermark_params i855_wm_info = {
I855GM_FIFO_SIZE, I855GM_FIFO_SIZE,
I915_MAX_WM, I915_MAX_WM,
1, 1,
2, 2,
I830_FIFO_LINE_SIZE I830_FIFO_LINE_SIZE
}; };
static struct intel_watermark_params i830_wm_info = { static const struct intel_watermark_params i830_wm_info = {
I830_FIFO_SIZE, I830_FIFO_SIZE,
I915_MAX_WM, I915_MAX_WM,
1, 1,
...@@ -3285,31 +3285,28 @@ static struct intel_watermark_params i830_wm_info = { ...@@ -3285,31 +3285,28 @@ static struct intel_watermark_params i830_wm_info = {
I830_FIFO_LINE_SIZE I830_FIFO_LINE_SIZE
}; };
static struct intel_watermark_params ironlake_display_wm_info = { static const struct intel_watermark_params ironlake_display_wm_info = {
ILK_DISPLAY_FIFO, ILK_DISPLAY_FIFO,
ILK_DISPLAY_MAXWM, ILK_DISPLAY_MAXWM,
ILK_DISPLAY_DFTWM, ILK_DISPLAY_DFTWM,
2, 2,
ILK_FIFO_LINE_SIZE ILK_FIFO_LINE_SIZE
}; };
static const struct intel_watermark_params ironlake_cursor_wm_info = {
static struct intel_watermark_params ironlake_cursor_wm_info = {
ILK_CURSOR_FIFO, ILK_CURSOR_FIFO,
ILK_CURSOR_MAXWM, ILK_CURSOR_MAXWM,
ILK_CURSOR_DFTWM, ILK_CURSOR_DFTWM,
2, 2,
ILK_FIFO_LINE_SIZE ILK_FIFO_LINE_SIZE
}; };
static const struct intel_watermark_params ironlake_display_srwm_info = {
static struct intel_watermark_params ironlake_display_srwm_info = {
ILK_DISPLAY_SR_FIFO, ILK_DISPLAY_SR_FIFO,
ILK_DISPLAY_MAX_SRWM, ILK_DISPLAY_MAX_SRWM,
ILK_DISPLAY_DFT_SRWM, ILK_DISPLAY_DFT_SRWM,
2, 2,
ILK_FIFO_LINE_SIZE ILK_FIFO_LINE_SIZE
}; };
static const struct intel_watermark_params ironlake_cursor_srwm_info = {
static struct intel_watermark_params ironlake_cursor_srwm_info = {
ILK_CURSOR_SR_FIFO, ILK_CURSOR_SR_FIFO,
ILK_CURSOR_MAX_SRWM, ILK_CURSOR_MAX_SRWM,
ILK_CURSOR_DFT_SRWM, ILK_CURSOR_DFT_SRWM,
...@@ -3317,31 +3314,28 @@ static struct intel_watermark_params ironlake_cursor_srwm_info = { ...@@ -3317,31 +3314,28 @@ static struct intel_watermark_params ironlake_cursor_srwm_info = {
ILK_FIFO_LINE_SIZE ILK_FIFO_LINE_SIZE
}; };
static struct intel_watermark_params sandybridge_display_wm_info = { static const struct intel_watermark_params sandybridge_display_wm_info = {
SNB_DISPLAY_FIFO, SNB_DISPLAY_FIFO,
SNB_DISPLAY_MAXWM, SNB_DISPLAY_MAXWM,
SNB_DISPLAY_DFTWM, SNB_DISPLAY_DFTWM,
2, 2,
SNB_FIFO_LINE_SIZE SNB_FIFO_LINE_SIZE
}; };
static const struct intel_watermark_params sandybridge_cursor_wm_info = {
static struct intel_watermark_params sandybridge_cursor_wm_info = {
SNB_CURSOR_FIFO, SNB_CURSOR_FIFO,
SNB_CURSOR_MAXWM, SNB_CURSOR_MAXWM,
SNB_CURSOR_DFTWM, SNB_CURSOR_DFTWM,
2, 2,
SNB_FIFO_LINE_SIZE SNB_FIFO_LINE_SIZE
}; };
static const struct intel_watermark_params sandybridge_display_srwm_info = {
static struct intel_watermark_params sandybridge_display_srwm_info = {
SNB_DISPLAY_SR_FIFO, SNB_DISPLAY_SR_FIFO,
SNB_DISPLAY_MAX_SRWM, SNB_DISPLAY_MAX_SRWM,
SNB_DISPLAY_DFT_SRWM, SNB_DISPLAY_DFT_SRWM,
2, 2,
SNB_FIFO_LINE_SIZE SNB_FIFO_LINE_SIZE
}; };
static const struct intel_watermark_params sandybridge_cursor_srwm_info = {
static struct intel_watermark_params sandybridge_cursor_srwm_info = {
SNB_CURSOR_SR_FIFO, SNB_CURSOR_SR_FIFO,
SNB_CURSOR_MAX_SRWM, SNB_CURSOR_MAX_SRWM,
SNB_CURSOR_DFT_SRWM, SNB_CURSOR_DFT_SRWM,
...@@ -3369,7 +3363,8 @@ static struct intel_watermark_params sandybridge_cursor_srwm_info = { ...@@ -3369,7 +3363,8 @@ static struct intel_watermark_params sandybridge_cursor_srwm_info = {
* will occur, and a display engine hang could result. * will occur, and a display engine hang could result.
*/ */
static unsigned long intel_calculate_wm(unsigned long clock_in_khz, static unsigned long intel_calculate_wm(unsigned long clock_in_khz,
struct intel_watermark_params *wm, const struct intel_watermark_params *wm,
int fifo_size,
int pixel_size, int pixel_size,
unsigned long latency_ns) unsigned long latency_ns)
{ {
...@@ -3387,7 +3382,7 @@ static unsigned long intel_calculate_wm(unsigned long clock_in_khz, ...@@ -3387,7 +3382,7 @@ static unsigned long intel_calculate_wm(unsigned long clock_in_khz,
DRM_DEBUG_KMS("FIFO entries required for mode: %d\n", entries_required); DRM_DEBUG_KMS("FIFO entries required for mode: %d\n", entries_required);
wm_size = wm->fifo_size - (entries_required + wm->guard_size); wm_size = fifo_size - (entries_required + wm->guard_size);
DRM_DEBUG_KMS("FIFO watermark level: %d\n", wm_size); DRM_DEBUG_KMS("FIFO watermark level: %d\n", wm_size);
...@@ -3560,15 +3555,28 @@ static int i830_get_fifo_size(struct drm_device *dev, int plane) ...@@ -3560,15 +3555,28 @@ static int i830_get_fifo_size(struct drm_device *dev, int plane)
return size; return size;
} }
static void pineview_update_wm(struct drm_device *dev, int planea_clock, static struct drm_crtc *single_enabled_crtc(struct drm_device *dev)
int planeb_clock, int sr_hdisplay, int unused, {
int pixel_size) struct drm_crtc *crtc, *enabled = NULL;
list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
if (crtc->enabled && crtc->fb) {
if (enabled)
return NULL;
enabled = crtc;
}
}
return enabled;
}
static void pineview_update_wm(struct drm_device *dev)
{ {
struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_private *dev_priv = dev->dev_private;
struct drm_crtc *crtc;
const struct cxsr_latency *latency; const struct cxsr_latency *latency;
u32 reg; u32 reg;
unsigned long wm; unsigned long wm;
int sr_clock;
latency = intel_get_cxsr_latency(IS_PINEVIEW_G(dev), dev_priv->is_ddr3, latency = intel_get_cxsr_latency(IS_PINEVIEW_G(dev), dev_priv->is_ddr3,
dev_priv->fsb_freq, dev_priv->mem_freq); dev_priv->fsb_freq, dev_priv->mem_freq);
...@@ -3578,11 +3586,14 @@ static void pineview_update_wm(struct drm_device *dev, int planea_clock, ...@@ -3578,11 +3586,14 @@ static void pineview_update_wm(struct drm_device *dev, int planea_clock,
return; return;
} }
if (!planea_clock || !planeb_clock) { crtc = single_enabled_crtc(dev);
sr_clock = planea_clock ? planea_clock : planeb_clock; if (crtc) {
int clock = crtc->mode.clock;
int pixel_size = crtc->fb->bits_per_pixel / 8;
/* Display SR */ /* Display SR */
wm = intel_calculate_wm(sr_clock, &pineview_display_wm, wm = intel_calculate_wm(clock, &pineview_display_wm,
pineview_display_wm.fifo_size,
pixel_size, latency->display_sr); pixel_size, latency->display_sr);
reg = I915_READ(DSPFW1); reg = I915_READ(DSPFW1);
reg &= ~DSPFW_SR_MASK; reg &= ~DSPFW_SR_MASK;
...@@ -3591,7 +3602,8 @@ static void pineview_update_wm(struct drm_device *dev, int planea_clock, ...@@ -3591,7 +3602,8 @@ static void pineview_update_wm(struct drm_device *dev, int planea_clock,
DRM_DEBUG_KMS("DSPFW1 register is %x\n", reg); DRM_DEBUG_KMS("DSPFW1 register is %x\n", reg);
/* cursor SR */ /* cursor SR */
wm = intel_calculate_wm(sr_clock, &pineview_cursor_wm, wm = intel_calculate_wm(clock, &pineview_cursor_wm,
pineview_display_wm.fifo_size,
pixel_size, latency->cursor_sr); pixel_size, latency->cursor_sr);
reg = I915_READ(DSPFW3); reg = I915_READ(DSPFW3);
reg &= ~DSPFW_CURSOR_SR_MASK; reg &= ~DSPFW_CURSOR_SR_MASK;
...@@ -3599,7 +3611,8 @@ static void pineview_update_wm(struct drm_device *dev, int planea_clock, ...@@ -3599,7 +3611,8 @@ static void pineview_update_wm(struct drm_device *dev, int planea_clock,
I915_WRITE(DSPFW3, reg); I915_WRITE(DSPFW3, reg);
/* Display HPLL off SR */ /* Display HPLL off SR */
wm = intel_calculate_wm(sr_clock, &pineview_display_hplloff_wm, wm = intel_calculate_wm(clock, &pineview_display_hplloff_wm,
pineview_display_hplloff_wm.fifo_size,
pixel_size, latency->display_hpll_disable); pixel_size, latency->display_hpll_disable);
reg = I915_READ(DSPFW3); reg = I915_READ(DSPFW3);
reg &= ~DSPFW_HPLL_SR_MASK; reg &= ~DSPFW_HPLL_SR_MASK;
...@@ -3607,7 +3620,8 @@ static void pineview_update_wm(struct drm_device *dev, int planea_clock, ...@@ -3607,7 +3620,8 @@ static void pineview_update_wm(struct drm_device *dev, int planea_clock,
I915_WRITE(DSPFW3, reg); I915_WRITE(DSPFW3, reg);
/* cursor HPLL off SR */ /* cursor HPLL off SR */
wm = intel_calculate_wm(sr_clock, &pineview_cursor_hplloff_wm, wm = intel_calculate_wm(clock, &pineview_cursor_hplloff_wm,
pineview_display_hplloff_wm.fifo_size,
pixel_size, latency->cursor_hpll_disable); pixel_size, latency->cursor_hpll_disable);
reg = I915_READ(DSPFW3); reg = I915_READ(DSPFW3);
reg &= ~DSPFW_HPLL_CURSOR_MASK; reg &= ~DSPFW_HPLL_CURSOR_MASK;
...@@ -3709,12 +3723,14 @@ static bool g4x_check_srwm(struct drm_device *dev, ...@@ -3709,12 +3723,14 @@ static bool g4x_check_srwm(struct drm_device *dev,
} }
static bool g4x_compute_srwm(struct drm_device *dev, static bool g4x_compute_srwm(struct drm_device *dev,
int hdisplay, int htotal, int plane,
int pixel_size, int clock, int latency_ns, int latency_ns,
const struct intel_watermark_params *display, const struct intel_watermark_params *display,
const struct intel_watermark_params *cursor, const struct intel_watermark_params *cursor,
int *display_wm, int *cursor_wm) int *display_wm, int *cursor_wm)
{ {
struct drm_crtc *crtc;
int hdisplay, htotal, pixel_size, clock;
unsigned long line_time_us; unsigned long line_time_us;
int line_count, line_size; int line_count, line_size;
int small, large; int small, large;
...@@ -3725,6 +3741,12 @@ static bool g4x_compute_srwm(struct drm_device *dev, ...@@ -3725,6 +3741,12 @@ static bool g4x_compute_srwm(struct drm_device *dev,
return false; return false;
} }
crtc = intel_get_crtc_for_plane(dev, plane);
hdisplay = crtc->mode.hdisplay;
htotal = crtc->mode.htotal;
clock = crtc->mode.clock;
pixel_size = crtc->fb->bits_per_pixel / 8;
line_time_us = (htotal * 1000) / clock; line_time_us = (htotal * 1000) / clock;
line_count = (latency_ns / line_time_us + 1000) / 1000; line_count = (latency_ns / line_time_us + 1000) / 1000;
line_size = hdisplay * pixel_size; line_size = hdisplay * pixel_size;
...@@ -3746,32 +3768,35 @@ static bool g4x_compute_srwm(struct drm_device *dev, ...@@ -3746,32 +3768,35 @@ static bool g4x_compute_srwm(struct drm_device *dev,
display, cursor); display, cursor);
} }
static void g4x_update_wm(struct drm_device *dev, static inline bool single_plane_enabled(unsigned int mask)
int planea_clock, int planeb_clock, {
int hdisplay, int htotal, int pixel_size) return mask && (mask & -mask) == 0;
}
static void g4x_update_wm(struct drm_device *dev)
{ {
static const int sr_latency_ns = 12000; static const int sr_latency_ns = 12000;
struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_private *dev_priv = dev->dev_private;
int planea_wm, planeb_wm, cursora_wm, cursorb_wm; int planea_wm, planeb_wm, cursora_wm, cursorb_wm;
int enabled = 0, plane_sr, cursor_sr, clock; int plane_sr, cursor_sr;
unsigned int enabled = 0;
if (g4x_compute_wm0(dev, 0, if (g4x_compute_wm0(dev, 0,
&g4x_wm_info, latency_ns, &g4x_wm_info, latency_ns,
&g4x_cursor_wm_info, latency_ns, &g4x_cursor_wm_info, latency_ns,
&planea_wm, &cursora_wm)) &planea_wm, &cursora_wm))
enabled++; enabled |= 1;
if (g4x_compute_wm0(dev, 1, if (g4x_compute_wm0(dev, 1,
&g4x_wm_info, latency_ns, &g4x_wm_info, latency_ns,
&g4x_cursor_wm_info, latency_ns, &g4x_cursor_wm_info, latency_ns,
&planeb_wm, &cursorb_wm)) &planeb_wm, &cursorb_wm))
enabled++; enabled |= 2;
plane_sr = cursor_sr = 0; plane_sr = cursor_sr = 0;
clock = planea_clock ? planea_clock : planeb_clock; if (single_plane_enabled(enabled) &&
if (enabled == 1 && g4x_compute_srwm(dev, ffs(enabled) - 1,
g4x_compute_srwm(dev, hdisplay, htotal, pixel_size, sr_latency_ns,
clock, sr_latency_ns,
&g4x_wm_info, &g4x_wm_info,
&g4x_cursor_wm_info, &g4x_cursor_wm_info,
&plane_sr, &cursor_sr)) &plane_sr, &cursor_sr))
...@@ -3799,39 +3824,43 @@ static void g4x_update_wm(struct drm_device *dev, ...@@ -3799,39 +3824,43 @@ static void g4x_update_wm(struct drm_device *dev,
(cursor_sr << DSPFW_CURSOR_SR_SHIFT)); (cursor_sr << DSPFW_CURSOR_SR_SHIFT));
} }
static void i965_update_wm(struct drm_device *dev, int planea_clock, static void i965_update_wm(struct drm_device *dev)
int planeb_clock, int sr_hdisplay, int sr_htotal,
int pixel_size)
{ {
struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_private *dev_priv = dev->dev_private;
unsigned long line_time_us; struct drm_crtc *crtc;
int sr_clock, sr_entries, srwm = 1; int srwm = 1;
int cursor_sr = 16; int cursor_sr = 16;
/* Calc sr entries for one plane configs */ /* Calc sr entries for one plane configs */
if (sr_hdisplay && (!planea_clock || !planeb_clock)) { crtc = single_enabled_crtc(dev);
if (crtc) {
/* self-refresh has much higher latency */ /* self-refresh has much higher latency */
static const int sr_latency_ns = 12000; static const int sr_latency_ns = 12000;
int clock = crtc->mode.clock;
int htotal = crtc->mode.htotal;
int hdisplay = crtc->mode.hdisplay;
int pixel_size = crtc->fb->bits_per_pixel / 8;
unsigned long line_time_us;
int entries;
sr_clock = planea_clock ? planea_clock : planeb_clock; line_time_us = ((htotal * 1000) / clock);
line_time_us = ((sr_htotal * 1000) / sr_clock);
/* Use ns/us then divide to preserve precision */ /* Use ns/us then divide to preserve precision */
sr_entries = (((sr_latency_ns / line_time_us) + 1000) / 1000) * entries = (((sr_latency_ns / line_time_us) + 1000) / 1000) *
pixel_size * sr_hdisplay; pixel_size * hdisplay;
sr_entries = DIV_ROUND_UP(sr_entries, I915_FIFO_LINE_SIZE); entries = DIV_ROUND_UP(entries, I915_FIFO_LINE_SIZE);
DRM_DEBUG("self-refresh entries: %d\n", sr_entries); DRM_DEBUG("self-refresh entries: %d\n", entries);
srwm = I965_FIFO_SIZE - sr_entries; srwm = I965_FIFO_SIZE - entries;
if (srwm < 0) if (srwm < 0)
srwm = 1; srwm = 1;
srwm &= 0x1ff; srwm &= 0x1ff;
sr_entries = (((sr_latency_ns / line_time_us) + 1000) / 1000) * entries = (((sr_latency_ns / line_time_us) + 1000) / 1000) *
pixel_size * 64; pixel_size * 64;
sr_entries = DIV_ROUND_UP(sr_entries, entries = DIV_ROUND_UP(entries,
i965_cursor_wm_info.cacheline_size); i965_cursor_wm_info.cacheline_size);
cursor_sr = i965_cursor_wm_info.fifo_size - cursor_sr = i965_cursor_wm_info.fifo_size -
(sr_entries + i965_cursor_wm_info.guard_size); (entries + i965_cursor_wm_info.guard_size);
if (cursor_sr > i965_cursor_wm_info.max_wm) if (cursor_sr > i965_cursor_wm_info.max_wm)
cursor_sr = i965_cursor_wm_info.max_wm; cursor_sr = i965_cursor_wm_info.max_wm;
...@@ -3859,39 +3888,50 @@ static void i965_update_wm(struct drm_device *dev, int planea_clock, ...@@ -3859,39 +3888,50 @@ static void i965_update_wm(struct drm_device *dev, int planea_clock,
I915_WRITE(DSPFW3, (cursor_sr << DSPFW_CURSOR_SR_SHIFT)); I915_WRITE(DSPFW3, (cursor_sr << DSPFW_CURSOR_SR_SHIFT));
} }
static void i9xx_update_wm(struct drm_device *dev, int planea_clock, static void i9xx_update_wm(struct drm_device *dev)
int planeb_clock, int sr_hdisplay, int sr_htotal,
int pixel_size)
{ {
struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_private *dev_priv = dev->dev_private;
const struct intel_watermark_params *wm_info;
uint32_t fwater_lo; uint32_t fwater_lo;
uint32_t fwater_hi; uint32_t fwater_hi;
int total_size, cacheline_size, cwm, srwm = 1; int cwm, srwm = 1;
int fifo_size;
int planea_wm, planeb_wm; int planea_wm, planeb_wm;
struct intel_watermark_params planea_params, planeb_params; struct drm_crtc *crtc, *enabled = NULL;
unsigned long line_time_us;
int sr_clock, sr_entries = 0, sr_enabled = 0;
/* Create copies of the base settings for each pipe */ /* Create copies of the base settings for each pipe */
if (IS_CRESTLINE(dev) || IS_I945GM(dev)) if (IS_CRESTLINE(dev) || IS_I945GM(dev))
planea_params = planeb_params = i945_wm_info; wm_info = &i945_wm_info;
else if (!IS_GEN2(dev)) else if (!IS_GEN2(dev))
planea_params = planeb_params = i915_wm_info; wm_info = &i915_wm_info;
else else
planea_params = planeb_params = i855_wm_info; wm_info = &i855_wm_info;
/* Grab a couple of global values before we overwrite them */ fifo_size = dev_priv->display.get_fifo_size(dev, 0);
total_size = planea_params.fifo_size; crtc = intel_get_crtc_for_plane(dev, 0);
cacheline_size = planea_params.cacheline_size; if (crtc->enabled && crtc->fb) {
planea_wm = intel_calculate_wm(crtc->mode.clock,
/* Update per-plane FIFO sizes */ wm_info, fifo_size,
planea_params.fifo_size = dev_priv->display.get_fifo_size(dev, 0); crtc->fb->bits_per_pixel / 8,
planeb_params.fifo_size = dev_priv->display.get_fifo_size(dev, 1); latency_ns);
enabled = crtc;
} else
planea_wm = fifo_size - wm_info->guard_size;
fifo_size = dev_priv->display.get_fifo_size(dev, 1);
crtc = intel_get_crtc_for_plane(dev, 1);
if (crtc->enabled && crtc->fb) {
planeb_wm = intel_calculate_wm(crtc->mode.clock,
wm_info, fifo_size,
crtc->fb->bits_per_pixel / 8,
latency_ns);
if (enabled == NULL)
enabled = crtc;
else
enabled = NULL;
} else
planeb_wm = fifo_size - wm_info->guard_size;
planea_wm = intel_calculate_wm(planea_clock, &planea_params,
pixel_size, latency_ns);
planeb_wm = intel_calculate_wm(planeb_clock, &planeb_params,
pixel_size, latency_ns);
DRM_DEBUG_KMS("FIFO watermarks - A: %d, B: %d\n", planea_wm, planeb_wm); DRM_DEBUG_KMS("FIFO watermarks - A: %d, B: %d\n", planea_wm, planeb_wm);
/* /*
...@@ -3906,20 +3946,24 @@ static void i9xx_update_wm(struct drm_device *dev, int planea_clock, ...@@ -3906,20 +3946,24 @@ static void i9xx_update_wm(struct drm_device *dev, int planea_clock,
I915_WRITE(INSTPM, I915_READ(INSTPM) & ~INSTPM_SELF_EN); I915_WRITE(INSTPM, I915_READ(INSTPM) & ~INSTPM_SELF_EN);
/* Calc sr entries for one plane configs */ /* Calc sr entries for one plane configs */
if (HAS_FW_BLC(dev) && sr_hdisplay && if (HAS_FW_BLC(dev) && enabled) {
(!planea_clock || !planeb_clock)) {
/* self-refresh has much higher latency */ /* self-refresh has much higher latency */
static const int sr_latency_ns = 6000; static const int sr_latency_ns = 6000;
int clock = enabled->mode.clock;
int htotal = enabled->mode.htotal;
int hdisplay = enabled->mode.hdisplay;
int pixel_size = enabled->fb->bits_per_pixel / 8;
unsigned long line_time_us;
int entries;
sr_clock = planea_clock ? planea_clock : planeb_clock; line_time_us = (htotal * 1000) / clock;
line_time_us = ((sr_htotal * 1000) / sr_clock);
/* Use ns/us then divide to preserve precision */ /* Use ns/us then divide to preserve precision */
sr_entries = (((sr_latency_ns / line_time_us) + 1000) / 1000) * entries = (((sr_latency_ns / line_time_us) + 1000) / 1000) *
pixel_size * sr_hdisplay; pixel_size * hdisplay;
sr_entries = DIV_ROUND_UP(sr_entries, cacheline_size); entries = DIV_ROUND_UP(entries, wm_info->cacheline_size);
DRM_DEBUG_KMS("self-refresh entries: %d\n", sr_entries); DRM_DEBUG_KMS("self-refresh entries: %d\n", entries);
srwm = total_size - sr_entries; srwm = wm_info->fifo_size - entries;
if (srwm < 0) if (srwm < 0)
srwm = 1; srwm = 1;
...@@ -3928,8 +3972,6 @@ static void i9xx_update_wm(struct drm_device *dev, int planea_clock, ...@@ -3928,8 +3972,6 @@ static void i9xx_update_wm(struct drm_device *dev, int planea_clock,
FW_BLC_SELF_FIFO_MASK | (srwm & 0xff)); FW_BLC_SELF_FIFO_MASK | (srwm & 0xff));
else if (IS_I915GM(dev)) else if (IS_I915GM(dev))
I915_WRITE(FW_BLC_SELF, srwm & 0x3f); I915_WRITE(FW_BLC_SELF, srwm & 0x3f);
sr_enabled = 1;
} }
DRM_DEBUG_KMS("Setting FIFO watermarks - A: %d, B: %d, C: %d, SR %d\n", DRM_DEBUG_KMS("Setting FIFO watermarks - A: %d, B: %d, C: %d, SR %d\n",
...@@ -3945,28 +3987,35 @@ static void i9xx_update_wm(struct drm_device *dev, int planea_clock, ...@@ -3945,28 +3987,35 @@ static void i9xx_update_wm(struct drm_device *dev, int planea_clock,
I915_WRITE(FW_BLC, fwater_lo); I915_WRITE(FW_BLC, fwater_lo);
I915_WRITE(FW_BLC2, fwater_hi); I915_WRITE(FW_BLC2, fwater_hi);
if (sr_enabled) { if (HAS_FW_BLC(dev)) {
if (IS_I945G(dev) || IS_I945GM(dev)) if (enabled) {
I915_WRITE(FW_BLC_SELF, if (IS_I945G(dev) || IS_I945GM(dev))
FW_BLC_SELF_EN_MASK | FW_BLC_SELF_EN); I915_WRITE(FW_BLC_SELF,
else if (IS_I915GM(dev)) FW_BLC_SELF_EN_MASK | FW_BLC_SELF_EN);
I915_WRITE(INSTPM, I915_READ(INSTPM) | INSTPM_SELF_EN); else if (IS_I915GM(dev))
DRM_DEBUG_KMS("memory self refresh enabled\n"); I915_WRITE(INSTPM, I915_READ(INSTPM) | INSTPM_SELF_EN);
} else DRM_DEBUG_KMS("memory self refresh enabled\n");
DRM_DEBUG_KMS("memory self refresh disabled\n"); } else
DRM_DEBUG_KMS("memory self refresh disabled\n");
}
} }
static void i830_update_wm(struct drm_device *dev, int planea_clock, int unused, static void i830_update_wm(struct drm_device *dev)
int unused2, int unused3, int pixel_size)
{ {
struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_private *dev_priv = dev->dev_private;
uint32_t fwater_lo = I915_READ(FW_BLC) & ~0xfff; struct drm_crtc *crtc;
uint32_t fwater_lo;
int planea_wm; int planea_wm;
i830_wm_info.fifo_size = dev_priv->display.get_fifo_size(dev, 0); crtc = single_enabled_crtc(dev);
if (crtc == NULL)
return;
planea_wm = intel_calculate_wm(planea_clock, &i830_wm_info, planea_wm = intel_calculate_wm(crtc->mode.clock, &i830_wm_info,
pixel_size, latency_ns); dev_priv->display.get_fifo_size(dev, 0),
crtc->fb->bits_per_pixel / 8,
latency_ns);
fwater_lo = I915_READ(FW_BLC) & ~0xfff;
fwater_lo |= (3<<8) | planea_wm; fwater_lo |= (3<<8) | planea_wm;
DRM_DEBUG_KMS("Setting FIFO watermarks - A: %d\n", planea_wm); DRM_DEBUG_KMS("Setting FIFO watermarks - A: %d\n", planea_wm);
...@@ -4075,15 +4124,15 @@ static bool ironlake_check_srwm(struct drm_device *dev, int level, ...@@ -4075,15 +4124,15 @@ static bool ironlake_check_srwm(struct drm_device *dev, int level,
/* /*
* Compute watermark values of WM[1-3], * Compute watermark values of WM[1-3],
*/ */
static bool ironlake_compute_srwm(struct drm_device *dev, int level, static bool ironlake_compute_srwm(struct drm_device *dev, int level, int plane,
int hdisplay, int htotal, int latency_ns,
int pixel_size, int clock, int latency_ns,
const struct intel_watermark_params *display, const struct intel_watermark_params *display,
const struct intel_watermark_params *cursor, const struct intel_watermark_params *cursor,
int *fbc_wm, int *display_wm, int *cursor_wm) int *fbc_wm, int *display_wm, int *cursor_wm)
{ {
struct drm_crtc *crtc;
unsigned long line_time_us; unsigned long line_time_us;
int hdisplay, htotal, pixel_size, clock;
int line_count, line_size; int line_count, line_size;
int small, large; int small, large;
int entries; int entries;
...@@ -4093,6 +4142,12 @@ static bool ironlake_compute_srwm(struct drm_device *dev, int level, ...@@ -4093,6 +4142,12 @@ static bool ironlake_compute_srwm(struct drm_device *dev, int level,
return false; return false;
} }
crtc = intel_get_crtc_for_plane(dev, plane);
hdisplay = crtc->mode.hdisplay;
htotal = crtc->mode.htotal;
clock = crtc->mode.clock;
pixel_size = crtc->fb->bits_per_pixel / 8;
line_time_us = (htotal * 1000) / clock; line_time_us = (htotal * 1000) / clock;
line_count = (latency_ns / line_time_us + 1000) / 1000; line_count = (latency_ns / line_time_us + 1000) / 1000;
line_size = hdisplay * pixel_size; line_size = hdisplay * pixel_size;
...@@ -4120,14 +4175,11 @@ static bool ironlake_compute_srwm(struct drm_device *dev, int level, ...@@ -4120,14 +4175,11 @@ static bool ironlake_compute_srwm(struct drm_device *dev, int level,
display, cursor); display, cursor);
} }
static void ironlake_update_wm(struct drm_device *dev, static void ironlake_update_wm(struct drm_device *dev)
int planea_clock, int planeb_clock,
int hdisplay, int htotal,
int pixel_size)
{ {
struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_private *dev_priv = dev->dev_private;
int fbc_wm, plane_wm, cursor_wm, enabled; int fbc_wm, plane_wm, cursor_wm;
int clock; unsigned int enabled;
enabled = 0; enabled = 0;
if (ironlake_compute_wm0(dev, 0, if (ironlake_compute_wm0(dev, 0,
...@@ -4141,7 +4193,7 @@ static void ironlake_update_wm(struct drm_device *dev, ...@@ -4141,7 +4193,7 @@ static void ironlake_update_wm(struct drm_device *dev,
DRM_DEBUG_KMS("FIFO watermarks For pipe A -" DRM_DEBUG_KMS("FIFO watermarks For pipe A -"
" plane %d, " "cursor: %d\n", " plane %d, " "cursor: %d\n",
plane_wm, cursor_wm); plane_wm, cursor_wm);
enabled++; enabled |= 1;
} }
if (ironlake_compute_wm0(dev, 1, if (ironlake_compute_wm0(dev, 1,
...@@ -4155,7 +4207,7 @@ static void ironlake_update_wm(struct drm_device *dev, ...@@ -4155,7 +4207,7 @@ static void ironlake_update_wm(struct drm_device *dev,
DRM_DEBUG_KMS("FIFO watermarks For pipe B -" DRM_DEBUG_KMS("FIFO watermarks For pipe B -"
" plane %d, cursor: %d\n", " plane %d, cursor: %d\n",
plane_wm, cursor_wm); plane_wm, cursor_wm);
enabled++; enabled |= 2;
} }
/* /*
...@@ -4166,14 +4218,13 @@ static void ironlake_update_wm(struct drm_device *dev, ...@@ -4166,14 +4218,13 @@ static void ironlake_update_wm(struct drm_device *dev,
I915_WRITE(WM2_LP_ILK, 0); I915_WRITE(WM2_LP_ILK, 0);
I915_WRITE(WM1_LP_ILK, 0); I915_WRITE(WM1_LP_ILK, 0);
if (enabled != 1) if (!single_plane_enabled(enabled))
return; return;
enabled = ffs(enabled) - 1;
clock = planea_clock ? planea_clock : planeb_clock;
/* WM1 */ /* WM1 */
if (!ironlake_compute_srwm(dev, 1, hdisplay, htotal, pixel_size, if (!ironlake_compute_srwm(dev, 1, enabled,
clock, ILK_READ_WM1_LATENCY() * 500, ILK_READ_WM1_LATENCY() * 500,
&ironlake_display_srwm_info, &ironlake_display_srwm_info,
&ironlake_cursor_srwm_info, &ironlake_cursor_srwm_info,
&fbc_wm, &plane_wm, &cursor_wm)) &fbc_wm, &plane_wm, &cursor_wm))
...@@ -4187,8 +4238,8 @@ static void ironlake_update_wm(struct drm_device *dev, ...@@ -4187,8 +4238,8 @@ static void ironlake_update_wm(struct drm_device *dev,
cursor_wm); cursor_wm);
/* WM2 */ /* WM2 */
if (!ironlake_compute_srwm(dev, 2, hdisplay, htotal, pixel_size, if (!ironlake_compute_srwm(dev, 2, enabled,
clock, ILK_READ_WM2_LATENCY() * 500, ILK_READ_WM2_LATENCY() * 500,
&ironlake_display_srwm_info, &ironlake_display_srwm_info,
&ironlake_cursor_srwm_info, &ironlake_cursor_srwm_info,
&fbc_wm, &plane_wm, &cursor_wm)) &fbc_wm, &plane_wm, &cursor_wm))
...@@ -4207,15 +4258,12 @@ static void ironlake_update_wm(struct drm_device *dev, ...@@ -4207,15 +4258,12 @@ static void ironlake_update_wm(struct drm_device *dev,
*/ */
} }
static void sandybridge_update_wm(struct drm_device *dev, static void sandybridge_update_wm(struct drm_device *dev)
int planea_clock, int planeb_clock,
int hdisplay, int htotal,
int pixel_size)
{ {
struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_private *dev_priv = dev->dev_private;
int latency = SNB_READ_WM0_LATENCY() * 100; /* In unit 0.1us */ int latency = SNB_READ_WM0_LATENCY() * 100; /* In unit 0.1us */
int fbc_wm, plane_wm, cursor_wm, enabled; int fbc_wm, plane_wm, cursor_wm;
int clock; unsigned int enabled;
enabled = 0; enabled = 0;
if (ironlake_compute_wm0(dev, 0, if (ironlake_compute_wm0(dev, 0,
...@@ -4227,7 +4275,7 @@ static void sandybridge_update_wm(struct drm_device *dev, ...@@ -4227,7 +4275,7 @@ static void sandybridge_update_wm(struct drm_device *dev,
DRM_DEBUG_KMS("FIFO watermarks For pipe A -" DRM_DEBUG_KMS("FIFO watermarks For pipe A -"
" plane %d, " "cursor: %d\n", " plane %d, " "cursor: %d\n",
plane_wm, cursor_wm); plane_wm, cursor_wm);
enabled++; enabled |= 1;
} }
if (ironlake_compute_wm0(dev, 1, if (ironlake_compute_wm0(dev, 1,
...@@ -4239,7 +4287,7 @@ static void sandybridge_update_wm(struct drm_device *dev, ...@@ -4239,7 +4287,7 @@ static void sandybridge_update_wm(struct drm_device *dev,
DRM_DEBUG_KMS("FIFO watermarks For pipe B -" DRM_DEBUG_KMS("FIFO watermarks For pipe B -"
" plane %d, cursor: %d\n", " plane %d, cursor: %d\n",
plane_wm, cursor_wm); plane_wm, cursor_wm);
enabled++; enabled |= 2;
} }
/* /*
...@@ -4256,14 +4304,13 @@ static void sandybridge_update_wm(struct drm_device *dev, ...@@ -4256,14 +4304,13 @@ static void sandybridge_update_wm(struct drm_device *dev,
I915_WRITE(WM2_LP_ILK, 0); I915_WRITE(WM2_LP_ILK, 0);
I915_WRITE(WM1_LP_ILK, 0); I915_WRITE(WM1_LP_ILK, 0);
if (enabled != 1) if (!single_plane_enabled(enabled))
return; return;
enabled = ffs(enabled) - 1;
clock = planea_clock ? planea_clock : planeb_clock;
/* WM1 */ /* WM1 */
if (!ironlake_compute_srwm(dev, 1, hdisplay, htotal, pixel_size, if (!ironlake_compute_srwm(dev, 1, enabled,
clock, SNB_READ_WM1_LATENCY() * 500, SNB_READ_WM1_LATENCY() * 500,
&sandybridge_display_srwm_info, &sandybridge_display_srwm_info,
&sandybridge_cursor_srwm_info, &sandybridge_cursor_srwm_info,
&fbc_wm, &plane_wm, &cursor_wm)) &fbc_wm, &plane_wm, &cursor_wm))
...@@ -4277,9 +4324,8 @@ static void sandybridge_update_wm(struct drm_device *dev, ...@@ -4277,9 +4324,8 @@ static void sandybridge_update_wm(struct drm_device *dev,
cursor_wm); cursor_wm);
/* WM2 */ /* WM2 */
if (!ironlake_compute_srwm(dev, 2, if (!ironlake_compute_srwm(dev, 2, enabled,
hdisplay, htotal, pixel_size, SNB_READ_WM2_LATENCY() * 500,
clock, SNB_READ_WM2_LATENCY() * 500,
&sandybridge_display_srwm_info, &sandybridge_display_srwm_info,
&sandybridge_cursor_srwm_info, &sandybridge_cursor_srwm_info,
&fbc_wm, &plane_wm, &cursor_wm)) &fbc_wm, &plane_wm, &cursor_wm))
...@@ -4293,9 +4339,8 @@ static void sandybridge_update_wm(struct drm_device *dev, ...@@ -4293,9 +4339,8 @@ static void sandybridge_update_wm(struct drm_device *dev,
cursor_wm); cursor_wm);
/* WM3 */ /* WM3 */
if (!ironlake_compute_srwm(dev, 3, if (!ironlake_compute_srwm(dev, 3, enabled,
hdisplay, htotal, pixel_size, SNB_READ_WM3_LATENCY() * 500,
clock, SNB_READ_WM3_LATENCY() * 500,
&sandybridge_display_srwm_info, &sandybridge_display_srwm_info,
&sandybridge_cursor_srwm_info, &sandybridge_cursor_srwm_info,
&fbc_wm, &plane_wm, &cursor_wm)) &fbc_wm, &plane_wm, &cursor_wm))
...@@ -4344,43 +4389,9 @@ static void sandybridge_update_wm(struct drm_device *dev, ...@@ -4344,43 +4389,9 @@ static void sandybridge_update_wm(struct drm_device *dev,
static void intel_update_watermarks(struct drm_device *dev) static void intel_update_watermarks(struct drm_device *dev)
{ {
struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_private *dev_priv = dev->dev_private;
struct drm_crtc *crtc;
int sr_hdisplay = 0;
unsigned long planea_clock = 0, planeb_clock = 0;
int enabled = 0, pixel_size = 0;
int sr_htotal = 0;
if (!dev_priv->display.update_wm)
return;
/* Get the clock config from both planes */
list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
if (intel_crtc->active) {
enabled++;
if (intel_crtc->plane == 0) {
DRM_DEBUG_KMS("plane A (pipe %d) clock: %d\n",
intel_crtc->pipe, crtc->mode.clock);
planea_clock = crtc->mode.clock;
} else {
DRM_DEBUG_KMS("plane B (pipe %d) clock: %d\n",
intel_crtc->pipe, crtc->mode.clock);
planeb_clock = crtc->mode.clock;
}
sr_hdisplay = crtc->mode.hdisplay;
sr_htotal = crtc->mode.htotal;
if (crtc->fb)
pixel_size = crtc->fb->bits_per_pixel / 8;
else
pixel_size = 4; /* by default */
}
}
if (enabled <= 0)
return;
dev_priv->display.update_wm(dev, planea_clock, planeb_clock, if (dev_priv->display.update_wm)
sr_hdisplay, sr_htotal, pixel_size); dev_priv->display.update_wm(dev);
} }
static inline bool intel_panel_use_ssc(struct drm_i915_private *dev_priv) static inline bool intel_panel_use_ssc(struct drm_i915_private *dev_priv)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment