intel_pm.c revision 1450
/*
* Copyright © 2012-2013 Intel Corporation
*
* 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,
* 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:
* Eugeni Dodonov <eugeni.dodonov@intel.com>
*
*/
/*
*/
#include "drmP.h"
#include "i915_drv.h"
#include "intel_drv.h"
#include <sys/archsystm.h>
#define FORCEWAKE_ACK_TIMEOUT_MS 2
/* FBC, or Frame Buffer Compression, is a technique employed to compress the
* framebuffer contents in-memory, aiming at reducing the required bandwidth
* during in-memory transfers and, therefore, reduce the power packet.
*
* The benefits of FBC are mostly visible with solid backgrounds and
* variation-less patterns.
*
* FBC-related functionality can be enabled by the means of the
* i915.i915_enable_fbc parameter
*/
{
/* Be paranoid as we can arrive here with only partial
* state retrieved from the hardware during setup.
*/
}
{
/* Disable compression */
if ((fbc_ctl & FBC_CTL_EN) == 0)
return;
fbc_ctl &= ~FBC_CTL_EN;
/* Wait for compressing bit to clear */
DRM_DEBUG_KMS("FBC idle timed out\n");
return;
}
DRM_DEBUG_KMS("disabled FBC\n");
}
{
int cfb_pitch;
int plane, i;
/* FBC_CTL wants 64B units */
/* Clear old tags */
/* Set it up... */
/* enable it... */
DRM_DEBUG_KMS("enabled FBC, pitch %d, yoff %d, plane %c, ",
}
{
}
{
unsigned long stall_watermark = 200;
/* enable it... */
}
{
/* Disable compression */
if (dpfc_ctl & DPFC_CTL_EN) {
dpfc_ctl &= ~DPFC_CTL_EN;
DRM_DEBUG_KMS("disabled FBC\n");
}
}
{
}
{
/* Make sure blitter notifies FBC of writes */
blt_ecoskpd &= ~(GEN6_BLITTER_FBC_NOTIFY <<
}
{
unsigned long stall_watermark = 200;
/* Set persistent mode for front-buffer rendering, ala X. */
/* enable it... */
}
}
{
/* Disable compression */
if (dpfc_ctl & DPFC_CTL_EN) {
dpfc_ctl &= ~DPFC_CTL_EN;
if (IS_IVYBRIDGE(dev))
/* WaFbcDisableDpfcClockGating:ivb */
if (IS_HASWELL(dev))
/* WaFbcDisableDpfcClockGating:hsw */
DRM_DEBUG_KMS("disabled FBC\n");
}
}
{
}
{
if (IS_IVYBRIDGE(dev)) {
/* WaFbcAsynchFlipDisableFbcQueue:ivb */
/* WaFbcDisableDpfcClockGating:ivb */
} else {
/* WaFbcAsynchFlipDisableFbcQueue:hsw */
/* WaFbcDisableDpfcClockGating:hsw */
}
}
{
return false;
}
{
work);
/* Double check that we haven't switched fb without cancelling
* the prior work.
*/
}
}
}
void
intel_fbc_work_timer(void *device)
{
}
{
return;
DRM_DEBUG_KMS("cancelling pending FBC enable\n");
/* Synchronisation is provided by struct_mutex and checking of
* dev_priv->fbc_work, so we can perform the cancellation
* entirely asynchronously.
*/
/* tasklet was killed before being run, clean up */
/* Mark the work as no longer wanted so that if it does
* wake-up (because the work was already running and waiting
* for our mutex), it will discover that is no longer
* necessary to run.
*/
}
{
struct intel_fbc_work *work;
return;
return;
}
(void *)work);
DRM_DEBUG_KMS("scheduling delayed FBC enable\n");
/* Delay the actual enabling to let pageflipping cease and the
* display to settle before starting the compression. Note that
* this delay also serves a second purpose: it allows for a
* vblank to pass after disabling the FBC before we attempt
* to modify the control registers.
*
* A more complicated solution would involve tracking vblanks
* following the termination of the page-flipping sequence
* and indeed performing the enable as a co-routine and not
* waiting synchronously upon the vblank.
*/
}
{
return;
}
/**
* @mode: mode in use
*
* Set up the framebuffer compression hardware at mode set time. We
* enable it if possible:
* - plane A only (on pre-965)
* - no alpha buffer discard
* - no dual wide
* - framebuffer <= 2048 in width, 1536 in height
*
* We can't assume that any compression will take place (worst case),
* so the compressed buffer has to be the same size as the uncompressed
* one. It also must reside (along with the line length buffer) in
* stolen memory.
*
*/
{
struct intel_crtc *intel_crtc;
struct drm_framebuffer *fb;
struct intel_framebuffer *intel_fb;
struct drm_i915_gem_object *obj;
int enable_fbc;
unsigned int max_hdisplay, max_vdisplay;
if (!i915_powersave)
return;
if (!I915_HAS_FBC(dev))
return;
/*
* If FBC is already on, we just have to verify that we can
* keep it that way...
* Need to disable if:
* - more than one pipe is active
* - changing FBC params (stride, fence, mode)
* - new fb is too large to fit in compressed buffer
* - going to an unsupported config (interlace, pixel multiply, etc.)
*/
if (intel_crtc_active(tmp_crtc) &&
if (crtc) {
DRM_DEBUG_KMS("more than one pipe active, disabling compression\n");
goto out_disable;
}
}
}
DRM_DEBUG_KMS("no output, disabling\n");
goto out_disable;
}
if (enable_fbc < 0) {
DRM_DEBUG_KMS("fbc set to per-chip default\n");
enable_fbc = 1;
enable_fbc = 0;
}
if (!enable_fbc) {
DRM_DEBUG_KMS("fbc disabled per module param\n");
goto out_disable;
}
DRM_DEBUG_KMS("mode incompatible with compression, "
"disabling\n");
goto out_disable;
}
max_hdisplay = 4096;
max_vdisplay = 2048;
} else {
max_hdisplay = 2048;
max_vdisplay = 1536;
}
DRM_DEBUG_KMS("mode too large for compression, disabling\n");
goto out_disable;
}
intel_crtc->plane != 0) {
DRM_DEBUG_KMS("plane not 0, disabling compression\n");
goto out_disable;
}
/* The use of a CPU fence is mandatory in order to detect writes
* by the CPU to the scanout and trigger updates to the FBC.
*/
DRM_DEBUG_KMS("framebuffer not tiled or fenced, disabling compression\n");
goto out_disable;
}
/* If the kernel debugger is active, always disable compression */
/*LINTED*/
if (in_dbg_master())
goto out_disable;
DRM_DEBUG_KMS("framebuffer too large, disabling compression\n");
goto out_disable;
}
/* If the scanout has not changed, don't modify the FBC settings.
* Note that we make the fundamental assumption that the fb->obj
* cannot be unpinned (and have its GTT offset and fence revoked)
* without first being decoupled from the scanout and FBC disabled.
*/
return;
if (intel_fbc_enabled(dev)) {
* configuration (modeswitching) and after page-flipping
* finishes. For the latter, we know that not only did
* we disable the FBC at the start of the page-flip
* sequence, but also more than one vblank has passed.
*
* For the former case of modeswitching, it is possible
* to switch between two FBC valid configurations
* instantaneously so we do need to disable the FBC
* before we can modify its control registers. We also
* have to wait for the next vblank for that to take
* effect. However, since we delay enabling FBC we can
* assume that a vblank has passed since disabling and
* that we can safely alter the registers in the deferred
* callback.
*
* In the scenario that we go from a valid to invalid
* and then back to valid FBC configuration we have
* no strict enforcement that a vblank occurred since
* disabling the FBC. However, along all current pipe
* disabling paths we do need to wait for a vblank at
* some point. And we wait before enabling FBC anyway.
*/
DRM_DEBUG_KMS("disabling active FBC for update\n");
}
return;
/* Multiple disables should be harmless */
if (intel_fbc_enabled(dev)) {
DRM_DEBUG_KMS("unsupported config, disabling FBC\n");
}
}
{
switch (tmp & CLKCFG_FSB_MASK) {
case CLKCFG_FSB_533:
break;
case CLKCFG_FSB_800:
break;
case CLKCFG_FSB_667:
break;
case CLKCFG_FSB_400:
break;
}
switch (tmp & CLKCFG_MEM_MASK) {
case CLKCFG_MEM_533:
break;
case CLKCFG_MEM_667:
break;
case CLKCFG_MEM_800:
break;
}
/* detect pineview DDR3 setting */
}
{
switch (ddrpll & 0xff) {
case 0xc:
break;
case 0x10:
break;
case 0x14:
break;
case 0x18:
break;
default:
DRM_DEBUG_DRIVER("unknown memory frequency 0x%02x\n",
ddrpll & 0xff);
break;
}
switch (csipll & 0x3ff) {
case 0x00c:
break;
case 0x00e:
break;
case 0x010:
break;
case 0x012:
break;
case 0x014:
break;
case 0x016:
break;
case 0x018:
break;
default:
DRM_DEBUG_DRIVER("unknown fsb frequency 0x%04x\n",
csipll & 0x3ff);
break;
}
} else {
}
}
static const struct cxsr_latency cxsr_latency_table[] = {
{1, 0, 800, 400, 3382, 33382, 3983, 33983}, /* DDR2-400 SC */
{1, 0, 800, 667, 3354, 33354, 3807, 33807}, /* DDR2-667 SC */
{1, 0, 800, 800, 3347, 33347, 3763, 33763}, /* DDR2-800 SC */
{1, 1, 800, 667, 6420, 36420, 6873, 36873}, /* DDR3-667 SC */
{1, 1, 800, 800, 5902, 35902, 6318, 36318}, /* DDR3-800 SC */
{1, 0, 667, 400, 3400, 33400, 4021, 34021}, /* DDR2-400 SC */
{1, 0, 667, 667, 3372, 33372, 3845, 33845}, /* DDR2-667 SC */
{1, 0, 667, 800, 3386, 33386, 3822, 33822}, /* DDR2-800 SC */
{1, 1, 667, 667, 6438, 36438, 6911, 36911}, /* DDR3-667 SC */
{1, 1, 667, 800, 5941, 35941, 6377, 36377}, /* DDR3-800 SC */
{1, 0, 400, 400, 3472, 33472, 4173, 34173}, /* DDR2-400 SC */
{1, 0, 400, 667, 3443, 33443, 3996, 33996}, /* DDR2-667 SC */
{1, 0, 400, 800, 3430, 33430, 3946, 33946}, /* DDR2-800 SC */
{1, 1, 400, 667, 6509, 36509, 7062, 37062}, /* DDR3-667 SC */
{1, 1, 400, 800, 5985, 35985, 6501, 36501}, /* DDR3-800 SC */
{0, 0, 800, 400, 3438, 33438, 4065, 34065}, /* DDR2-400 SC */
{0, 0, 800, 667, 3410, 33410, 3889, 33889}, /* DDR2-667 SC */
{0, 0, 800, 800, 3403, 33403, 3845, 33845}, /* DDR2-800 SC */
{0, 1, 800, 667, 6476, 36476, 6955, 36955}, /* DDR3-667 SC */
{0, 1, 800, 800, 5958, 35958, 6400, 36400}, /* DDR3-800 SC */
{0, 0, 667, 400, 3456, 33456, 4103, 34106}, /* DDR2-400 SC */
{0, 0, 667, 667, 3428, 33428, 3927, 33927}, /* DDR2-667 SC */
{0, 0, 667, 800, 3443, 33443, 3905, 33905}, /* DDR2-800 SC */
{0, 1, 667, 667, 6494, 36494, 6993, 36993}, /* DDR3-667 SC */
{0, 1, 667, 800, 5998, 35998, 6460, 36460}, /* DDR3-800 SC */
{0, 0, 400, 400, 3528, 33528, 4255, 34255}, /* DDR2-400 SC */
{0, 0, 400, 667, 3500, 33500, 4079, 34079}, /* DDR2-667 SC */
{0, 0, 400, 800, 3487, 33487, 4029, 34029}, /* DDR2-800 SC */
{0, 1, 400, 667, 6566, 36566, 7145, 37145}, /* DDR3-667 SC */
{0, 1, 400, 800, 6042, 36042, 6584, 36584}, /* DDR3-800 SC */
};
int is_ddr3,
int fsb,
int mem)
{
const struct cxsr_latency *latency;
int i;
return NULL;
for (i = 0; i < ARRAY_SIZE(cxsr_latency_table); i++) {
latency = &cxsr_latency_table[i];
return latency;
}
DRM_DEBUG_KMS("Unknown FSB/MEM found, disable CxSR\n");
return NULL;
}
{
/* deactivate cxsr */
}
/*
* Latency for FIFO fetches is dependent on several factors:
* - memory configuration (speed, channels)
* - chipset
* - current MCH state
* It can be fairly high in some situations, so here we assume a fairly
* pessimal value. It's a tradeoff between extra memory fetches (if we
* set this value too high, the FIFO will fetch frequently to stay full)
* and power consumption (set it too low to save power and we might see
* FIFO underruns and display "flicker").
*
* A value of 5us seems to be a good balance; safe for very low end
* platforms but not overly aggressive on lower latency configs.
*/
static const int latency_ns = 5000;
{
int size;
if (plane)
return size;
}
{
int size;
if (plane)
return size;
}
{
int size;
size);
return size;
}
{
int size;
return size;
}
/* Pineview has different values for various configs */
static const struct intel_watermark_params pineview_display_wm = {
};
static const struct intel_watermark_params pineview_display_hplloff_wm = {
};
static const struct intel_watermark_params pineview_cursor_wm = {
};
static const struct intel_watermark_params pineview_cursor_hplloff_wm = {
};
static const struct intel_watermark_params g4x_wm_info = {
2,
};
static const struct intel_watermark_params g4x_cursor_wm_info = {
2,
};
static const struct intel_watermark_params valleyview_wm_info = {
2,
};
static const struct intel_watermark_params valleyview_cursor_wm_info = {
2,
};
static const struct intel_watermark_params i965_cursor_wm_info = {
2,
};
static const struct intel_watermark_params i945_wm_info = {
1,
2,
};
static const struct intel_watermark_params i915_wm_info = {
1,
2,
};
static const struct intel_watermark_params i855_wm_info = {
1,
2,
};
static const struct intel_watermark_params i830_wm_info = {
1,
2,
};
static const struct intel_watermark_params ironlake_display_wm_info = {
2,
};
static const struct intel_watermark_params ironlake_cursor_wm_info = {
2,
};
static const struct intel_watermark_params ironlake_display_srwm_info = {
2,
};
static const struct intel_watermark_params ironlake_cursor_srwm_info = {
2,
};
static const struct intel_watermark_params sandybridge_display_wm_info = {
2,
};
static const struct intel_watermark_params sandybridge_cursor_wm_info = {
2,
};
static const struct intel_watermark_params sandybridge_display_srwm_info = {
2,
};
static const struct intel_watermark_params sandybridge_cursor_srwm_info = {
2,
};
/**
* intel_calculate_wm - calculate watermark level
* @clock_in_khz: pixel clock
* @wm: chip FIFO params
* @pixel_size: display pixel size
* @latency_ns: memory latency for the platform
*
* Calculate the watermark level (the level at which the display plane will
* start fetching from memory again). Each chip has a different display
* FIFO size and allocation, so the caller needs to figure that out and pass
* in the correct intel_watermark_params structure.
*
* As the pixel clock runs, the FIFO will be drained at a rate that depends
* on the pixel size. When it reaches the watermark level, it'll start
* fetching FIFO line sized based chunks from memory until the FIFO fills
* past the watermark point. If the FIFO drains completely, a FIFO underrun
* will occur, and a display engine hang could result.
*/
static unsigned long intel_calculate_wm(unsigned long clock_in_khz,
const struct intel_watermark_params *wm,
int fifo_size,
int pixel_size,
unsigned long latency_ns)
{
long entries_required, wm_size;
/*
* Note: we need to make sure we don't overflow for various clock &
* latency values.
* clocks go from a few thousand to several hundred thousand.
* latency is usually a few thousand
*/
1000;
/* Don't promote wm_size to unsigned... */
if (wm_size <= 0)
return wm_size;
}
{
if (intel_crtc_active(crtc)) {
if (enabled)
return NULL;
}
}
return enabled;
}
{
const struct cxsr_latency *latency;
unsigned long wm;
if (!latency) {
DRM_DEBUG_KMS("Unknown FSB/MEM found, disable CxSR\n");
return;
}
if (crtc) {
/* Display SR */
reg &= ~DSPFW_SR_MASK;
/* cursor SR */
reg &= ~DSPFW_CURSOR_SR_MASK;
/* Display HPLL off SR */
reg &= ~DSPFW_HPLL_SR_MASK;
/* cursor HPLL off SR */
/* activate cxsr */
DRM_DEBUG_KMS("Self-refresh is enabled\n");
} else {
DRM_DEBUG_KMS("Self-refresh is disabled\n");
}
}
int plane,
const struct intel_watermark_params *display,
int display_latency_ns,
const struct intel_watermark_params *cursor,
int cursor_latency_ns,
int *plane_wm,
int *cursor_wm)
{
int line_time_us, line_count;
if (!intel_crtc_active(crtc)) {
return false;
}
/* Use the small buffer method to calculate plane watermark */
if (tlb_miss > 0)
/* Use the large buffer method to calculate cursor watermark */
if (tlb_miss > 0)
return true;
}
/*
* Check the wm result.
*
* If any calculated watermark values is larger than the maximum value that
* can be programmed into the associated watermark register, that watermark
* must be disabled.
*/
int display_wm, int cursor_wm,
const struct intel_watermark_params *display,
const struct intel_watermark_params *cursor)
{
DRM_DEBUG_KMS("SR watermark: display plane %d, cursor %d\n",
DRM_DEBUG_KMS("display watermark is too large(%d/%ld), disabling\n",
return false;
}
DRM_DEBUG_KMS("cursor watermark is too large(%d/%ld), disabling\n",
return false;
}
if (!(display_wm || cursor_wm)) {
DRM_DEBUG_KMS("SR latency is 0, disabling\n");
return false;
}
return true;
}
int plane,
int latency_ns,
const struct intel_watermark_params *display,
const struct intel_watermark_params *cursor,
int *display_wm, int *cursor_wm)
{
unsigned long line_time_us;
int line_count, line_size;
int entries;
if (!latency_ns) {
*display_wm = *cursor_wm = 0;
return false;
}
/* Use the minimum of the small and large buffer method for primary */
/* calculate the self-refresh watermark for display cursor */
return g4x_check_srwm(dev,
*display_wm, *cursor_wm,
}
int plane,
int *plane_prec_mult,
int *plane_dl,
int *cursor_prec_mult,
int *cursor_dl)
{
int clock, pixel_size;
int entries;
if (!intel_crtc_active(crtc))
return false;
return true;
}
/*
* Update drain latency registers of memory arbiter
*
* Valleyview SoC has a new memory arbiter and needs drain latency registers
* to be programmed. Each plane has a drain latency multiplier and a drain
* latency value.
*/
{
either 16 or 32 */
/* For plane A, Cursor A */
&cursor_prec_mult, &cursora_dl)) {
(cursora_dl << DDL_CURSORA_SHIFT) |
planea_prec | planea_dl);
}
/* For plane B, Cursor B */
&cursor_prec_mult, &cursorb_dl)) {
(cursorb_dl << DDL_CURSORB_SHIFT) |
planeb_prec | planeb_dl);
}
}
#define single_plane_enabled(x) ((x) != 0 && (((x) & ((x) - 1)) == 0))
{
static const int sr_latency_ns = 12000;
unsigned int enabled = 0;
&planea_wm, &cursora_wm))
&planeb_wm, &cursorb_wm))
if (single_plane_enabled(enabled) &&
&plane_sr, &ignore_cursor_sr) &&
&ignore_plane_sr, &cursor_sr)) {
} else {
}
DRM_DEBUG_KMS("Setting FIFO watermarks - A: plane=%d, cursor=%d, B: plane=%d, cursor=%d, SR: plane=%d, cursor=%d\n",
(plane_sr << DSPFW_SR_SHIFT) |
(cursorb_wm << DSPFW_CURSORB_SHIFT) |
(planeb_wm << DSPFW_PLANEB_SHIFT) |
(cursora_wm << DSPFW_CURSORA_SHIFT));
(cursor_sr << DSPFW_CURSOR_SR_SHIFT));
}
{
static const int sr_latency_ns = 12000;
unsigned int enabled = 0;
&planea_wm, &cursora_wm))
&planeb_wm, &cursorb_wm))
if (single_plane_enabled(enabled) &&
} else {
}
DRM_DEBUG_KMS("Setting FIFO watermarks - A: plane=%d, cursor=%d, B: plane=%d, cursor=%d, SR: plane=%d, cursor=%d\n",
(plane_sr << DSPFW_SR_SHIFT) |
(cursorb_wm << DSPFW_CURSORB_SHIFT) |
(planeb_wm << DSPFW_PLANEB_SHIFT) |
(cursora_wm << DSPFW_CURSORA_SHIFT));
/* HPLL off in SR has some issues on G4x... disable it */
(cursor_sr << DSPFW_CURSOR_SR_SHIFT));
}
{
int srwm = 1;
int cursor_sr = 16;
/* Calc sr entries for one plane configs */
if (crtc) {
/* self-refresh has much higher latency */
static const int sr_latency_ns = 12000;
unsigned long line_time_us;
int entries;
if (srwm < 0)
srwm = 1;
srwm &= 0x1ff;
DRM_DEBUG_KMS("self-refresh entries: %d, wm: %d\n",
pixel_size * 64;
DRM_DEBUG_KMS("self-refresh watermark: display plane %d "
if (IS_CRESTLINE(dev))
} else {
/* Turn off self refresh if both pipes are enabled */
if (IS_CRESTLINE(dev))
& ~FW_BLC_SELF_EN);
}
DRM_DEBUG_KMS("Setting FIFO watermarks - A: 8, B: 8, C: 8, SR %d\n",
srwm);
/* 965 has limitations... */
(8 << 16) | (8 << 8) | (8 << 0));
/* update cursor SR watermark */
}
{
const struct intel_watermark_params *wm_info;
int fifo_size;
wm_info = &i945_wm_info;
wm_info = &i915_wm_info;
else
wm_info = &i855_wm_info;
if (intel_crtc_active(crtc)) {
cpp = 4;
} else
if (intel_crtc_active(crtc)) {
cpp = 4;
else
} else
/*
* Overlay gets an aggressive default since video jitter is bad.
*/
cwm = 2;
/* Play safe and disable self-refresh before adjusting watermarks. */
/* Calc sr entries for one plane configs */
/* self-refresh has much higher latency */
static const int sr_latency_ns = 6000;
unsigned long line_time_us;
int entries;
if (srwm < 0)
srwm = 1;
}
DRM_DEBUG_KMS("Setting FIFO watermarks - A: %d, B: %d, C: %d, SR %d\n",
/* Set request length to 8 cachelines per fetch */
if (HAS_FW_BLC(dev)) {
if (enabled) {
DRM_DEBUG_KMS("memory self refresh enabled\n");
} else
DRM_DEBUG_KMS("memory self refresh disabled\n");
}
}
{
int planea_wm;
return;
4, latency_ns);
}
#define ILK_LP0_PLANE_LATENCY 700
#define ILK_LP0_CURSOR_LATENCY 1300
/*
* Check the wm result.
*
* If any calculated watermark values is larger than the maximum value that
* can be programmed into the associated watermark register, that watermark
* must be disabled.
*/
const struct intel_watermark_params *display,
const struct intel_watermark_params *cursor)
{
DRM_DEBUG_KMS("watermark %d: display plane %d, fbc lines %d,"
if (fbc_wm > SNB_FBC_MAX_SRWM) {
DRM_DEBUG_KMS("fbc watermark(%d) is too large(%d), disabling wm%d+\n",
/* fbc has it's own way to disable FBC WM */
return false;
/* enable FBC WM (except on ILK, where it must remain off) */
}
DRM_DEBUG_KMS("display watermark(%d) is too large(%d), disabling wm%d+\n",
return false;
}
DRM_DEBUG_KMS("cursor watermark(%d) is too large(%d), disabling wm%d+\n",
return false;
}
return false;
}
return true;
}
/*
* Compute watermark values of WM[1-3],
*/
int latency_ns,
const struct intel_watermark_params *display,
const struct intel_watermark_params *cursor,
{
unsigned long line_time_us;
int line_count, line_size;
int entries;
if (!latency_ns) {
return false;
}
/* Use the minimum of the small and large buffer method for primary */
/*
* Spec says:
* FBC WM = ((Final Primary WM * 64) / number of bytes per line) + 2
*/
/* calculate the self-refresh watermark for display cursor */
}
{
unsigned int enabled;
enabled = 0;
DRM_DEBUG_KMS("FIFO watermarks For pipe A -"
" plane %d, " "cursor: %d\n",
}
DRM_DEBUG_KMS("FIFO watermarks For pipe B -"
" plane %d, cursor: %d\n",
}
/*
* Calculate and update the self-refresh watermark only when one
* display plane is used.
*/
I915_WRITE(WM3_LP_ILK, 0);
I915_WRITE(WM2_LP_ILK, 0);
I915_WRITE(WM1_LP_ILK, 0);
if (!single_plane_enabled(enabled))
return;
/* WM1 */
ILK_READ_WM1_LATENCY() * 500,
return;
(ILK_READ_WM1_LATENCY() << WM1_LP_LATENCY_SHIFT) |
(fbc_wm << WM1_LP_FBC_SHIFT) |
(plane_wm << WM1_LP_SR_SHIFT) |
/* WM2 */
ILK_READ_WM2_LATENCY() * 500,
return;
(ILK_READ_WM2_LATENCY() << WM1_LP_LATENCY_SHIFT) |
(fbc_wm << WM1_LP_FBC_SHIFT) |
(plane_wm << WM1_LP_SR_SHIFT) |
/*
* WM3 is unsupported on ILK, probably because we don't have latency
* data for that power state
*/
}
{
unsigned int enabled;
enabled = 0;
DRM_DEBUG_KMS("FIFO watermarks For pipe A -"
" plane %d, " "cursor: %d\n",
}
DRM_DEBUG_KMS("FIFO watermarks For pipe B -"
" plane %d, cursor: %d\n",
}
/*
* Calculate and update the self-refresh watermark only when one
* display plane is used.
*
* SNB support 3 levels of watermark.
*
* and disabled in the descending order
*
*/
I915_WRITE(WM3_LP_ILK, 0);
I915_WRITE(WM2_LP_ILK, 0);
I915_WRITE(WM1_LP_ILK, 0);
if (!single_plane_enabled(enabled) ||
return;
/* WM1 */
SNB_READ_WM1_LATENCY() * 500,
return;
(SNB_READ_WM1_LATENCY() << WM1_LP_LATENCY_SHIFT) |
(fbc_wm << WM1_LP_FBC_SHIFT) |
(plane_wm << WM1_LP_SR_SHIFT) |
/* WM2 */
SNB_READ_WM2_LATENCY() * 500,
return;
(SNB_READ_WM2_LATENCY() << WM1_LP_LATENCY_SHIFT) |
(fbc_wm << WM1_LP_FBC_SHIFT) |
(plane_wm << WM1_LP_SR_SHIFT) |
/* WM3 */
SNB_READ_WM3_LATENCY() * 500,
return;
(SNB_READ_WM3_LATENCY() << WM1_LP_LATENCY_SHIFT) |
(fbc_wm << WM1_LP_FBC_SHIFT) |
(plane_wm << WM1_LP_SR_SHIFT) |
}
{
unsigned int enabled;
enabled = 0;
DRM_DEBUG_KMS("FIFO watermarks For pipe A -"
" plane %d, " "cursor: %d\n",
}
DRM_DEBUG_KMS("FIFO watermarks For pipe B -"
" plane %d, cursor: %d\n",
}
DRM_DEBUG_KMS("FIFO watermarks For pipe C -"
" plane %d, cursor: %d\n",
}
/*
* Calculate and update the self-refresh watermark only when one
* display plane is used.
*
* SNB support 3 levels of watermark.
*
* and disabled in the descending order
*
*/
I915_WRITE(WM3_LP_ILK, 0);
I915_WRITE(WM2_LP_ILK, 0);
I915_WRITE(WM1_LP_ILK, 0);
if (!single_plane_enabled(enabled) ||
return;
/* WM1 */
SNB_READ_WM1_LATENCY() * 500,
return;
(SNB_READ_WM1_LATENCY() << WM1_LP_LATENCY_SHIFT) |
(fbc_wm << WM1_LP_FBC_SHIFT) |
(plane_wm << WM1_LP_SR_SHIFT) |
/* WM2 */
SNB_READ_WM2_LATENCY() * 500,
return;
(SNB_READ_WM2_LATENCY() << WM1_LP_LATENCY_SHIFT) |
(fbc_wm << WM1_LP_FBC_SHIFT) |
(plane_wm << WM1_LP_SR_SHIFT) |
/* WM3, note we have to correct the cursor latency */
SNB_READ_WM3_LATENCY() * 500,
return;
(SNB_READ_WM3_LATENCY() << WM1_LP_LATENCY_SHIFT) |
(fbc_wm << WM1_LP_FBC_SHIFT) |
(plane_wm << WM1_LP_SR_SHIFT) |
}
{
/* We only use IF-ID interlacing. If we ever use PF-ID we'll need to
* adjust the pixel_rate here. */
if (pfit_size) {
}
return pixel_rate;
}
{
}
{
return ret;
}
{
}
struct hsw_pipe_wm_parameters {
bool active;
bool sprite_enabled;
};
struct hsw_wm_maximums {
};
struct hsw_lp_wm_result {
bool enable;
bool fbc_enable;
};
struct hsw_wm_values {
bool enable_fbc_wm;
};
enum hsw_data_buf_partitioning {
};
/* For both WM_PIPE and WM_LP. */
bool is_lp)
{
/* TODO: for now, assume the primary plane is always enabled. */
return 0;
if (!is_lp)
return method1;
}
/* For both WM_PIPE and WM_LP. */
{
return 0;
}
/* For both WM_PIPE and WM_LP. */
{
return 0;
}
/* Only for WM_LP. */
{
return 0;
return hsw_wm_fbc(pri_val,
}
struct hsw_pipe_wm_parameters *params,
struct hsw_lp_wm_result *result)
{
}
result->fbc_enable = false;
} else {
result->fbc_enable = true;
}
}
struct hsw_pipe_wm_parameters *params)
{
if(pri_val > 127)
DRM_ERROR("Primary WM error, mode not supported for pipe %c\n",
if(spr_val > 127)
DRM_ERROR("Sprite WM error, mode not supported for pipe %c\n",
if(cur_val > 63)
DRM_ERROR("Cursor WM error, mode not supported for pipe %c\n",
return (pri_val << WM0_PIPE_PLANE_SHIFT) |
(spr_val << WM0_PIPE_SPRITE_SHIFT) |
}
static uint32_t
{
if (!intel_crtc_active(crtc))
return 0;
/* The WM are computed with base on how long it takes to fill a single
* row at the given clock rate, multiplied by 8.
* */
return PIPE_WM_LINETIME_IPS_LINETIME(ips_linetime) |
}
struct hsw_pipe_wm_parameters *params,
struct hsw_wm_maximums *lp_max_1_2,
struct hsw_wm_maximums *lp_max_5_6)
{
int pipes_active = 0, sprites_enabled = 0;
else
struct hsw_pipe_wm_parameters *p;
if (!p->active)
continue;
pipes_active++;
p->cur_bytes_per_pixel = 4;
p->pri_horiz_pixels =
p->cur_horiz_pixels = 64;
}
struct hsw_pipe_wm_parameters *p;
if (p->sprite_enabled)
}
if (pipes_active > 1) {
} else {
}
}
struct hsw_pipe_wm_parameters *params,
struct hsw_wm_maximums *lp_maximums,
struct hsw_wm_values *results)
{
break;
/* The spec says it is preferred to disable FBC WMs instead of disabling
* a WM level. */
results->enable_fbc_wm = true;
results->enable_fbc_wm = false;
break;
}
}
const struct hsw_lp_wm_result *r;
break;
r->fbc_val,
r->pri_val,
r->cur_val);
}
pipe,
}
}
/* 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. */
struct hsw_wm_values *r2)
{
for (i = 0; i < 3; i++) {
}
return r2;
else
return r1;
return r1;
} else {
return r2;
}
}
/*
* The spec says we shouldn't write when we don't need, because every write
* causes WMs to be re-evaluated, expending some power.
*/
struct hsw_wm_values *results,
{
struct hsw_wm_values previous;
bool prev_enable_fbc_wm;
sizeof(results->wm_linetime)) == 0 &&
return;
I915_WRITE(WM3_LP_ILK, 0);
I915_WRITE(WM2_LP_ILK, 0);
I915_WRITE(WM1_LP_ILK, 0);
if (prev_partitioning != partitioning) {
if (partitioning == HSW_DATA_BUF_PART_1_2)
else
}
if (results->enable_fbc_wm)
val &= ~DISP_FBC_WM_DIS;
else
val |= DISP_FBC_WM_DIS;
}
}
{
&results_5_6);
} else {
}
}
bool enable)
{
break;
}
}
}
static bool
const struct intel_watermark_params *display,
int display_latency_ns, int *sprite_wm)
{
int clock;
if (!intel_crtc_active(crtc)) {
return false;
}
/* Use the small buffer method to calculate the sprite watermark */
sprite_width * 8;
if (tlb_miss > 0)
return true;
}
static bool
const struct intel_watermark_params *display,
int latency_ns, int *sprite_wm)
{
unsigned long line_time_us;
int clock;
int line_count, line_size;
int entries;
if (!latency_ns) {
*sprite_wm = 0;
return false;
}
if (!clock) {
*sprite_wm = 0;
return false;
}
if (!line_time_us) {
*sprite_wm = 0;
return false;
}
/* Use the minimum of the small and large buffer method for primary */
return *sprite_wm > 0x3ff ? false : true;
}
bool enable)
{
int ret;
if (!enable)
return;
switch (pipe) {
case 0:
reg = WM0_PIPEA_ILK;
break;
case 1:
reg = WM0_PIPEB_ILK;
break;
case 2:
reg = WM0_PIPEC_IVB;
break;
default:
return; /* bad pipe */
}
if (!ret) {
DRM_DEBUG_KMS("failed to compute sprite wm for pipe %c\n",
return;
}
val &= ~WM0_PIPE_SPRITE_MASK;
SNB_READ_WM1_LATENCY() * 500,
&sprite_wm);
if (!ret) {
DRM_DEBUG_KMS("failed to compute sprite lp1 wm on pipe %c\n",
return;
}
/* Only IVB has two more LP watermarks for sprite */
if (!IS_IVYBRIDGE(dev))
return;
SNB_READ_WM2_LATENCY() * 500,
&sprite_wm);
if (!ret) {
DRM_DEBUG_KMS("failed to compute sprite lp2 wm on pipe %c\n",
return;
}
SNB_READ_WM3_LATENCY() * 500,
&sprite_wm);
if (!ret) {
DRM_DEBUG_KMS("failed to compute sprite lp3 wm on pipe %c\n",
return;
}
}
/**
* intel_update_watermarks - update FIFO watermark values based on current modes
*
* Calculate watermark values for the various WM regs based on current mode
* and plane configuration.
*
* There are several cases to deal with here:
* - normal (i.e. non-self-refresh)
* - self-refresh (SR) mode
* - lines are large relative to FIFO size (buffer can hold up to 2)
* - lines are small relative to FIFO size (buffer can hold more than 2
* lines), so need to account for TLB latency
*
* The normal calculation is:
* watermark = dotclock * bytes per pixel * latency
* where latency is platform & configuration dependent (we assume pessimal
* values here).
*
* The SR calculation is:
* bytes per pixel
* where
* line time = htotal / dotclock
* surface width = hdisplay for normal plane and 64 for cursor
* and latency is assumed to be high, as above.
*
* The final value programmed to the register should always be rounded up,
* and include an extra 2 entries to account for clock crossings.
*
* We don't use the sprite, so we can ignore that. And on Crestline we have
* to set the non-SR watermarks to 8.
*/
{
}
bool enable)
{
pixel_size, enable);
}
static struct drm_i915_gem_object *
{
struct drm_i915_gem_object *ctx;
int ret;
if (!ctx) {
DRM_DEBUG("failed to alloc power context, RC6 disabled\n");
return NULL;
}
if (ret) {
goto err_unref;
}
if (ret) {
goto err_unpin;
}
return ctx;
return NULL;
}
/**
* Lock protecting IPS related data structures
*/
/* Global for IPS driver to get at the current i915 device. Protected by
* mchdev_lock. */
static struct drm_i915_private *i915_mch_dev;
{
if (rgvswctl & MEMCTL_CMD_STS) {
DRM_DEBUG("gpu busy, RCS change rejected\n");
return false; /* still busy with another command */
}
return true;
}
{
/* Enable temp reporting */
/* 100ms RC evaluation intervals */
/* Set up min, max, and cur for interrupt handling */
DRM_DEBUG_DRIVER("fmax: %d, fmin: %d, fstart: %d\n",
/*
* Interrupts will be enabled in ironlake_irq_postinstall
*/
DRM_ERROR("stuck trying to change perf mode\n");
msleep(1);
I915_READ(0x112e0);
}
{
/* Ack interrupts, disable EFC interrupt */
/* Go back to the starting frequency */
msleep(1);
msleep(1);
}
/* There's a funny hw issue where the hw returns all 0 when reading from
* GEN6_RP_INTERRUPT_LIMITS. Hence we always need to compute the desired value
* ourselves, instead of doing a rmw cycle (which might result in us clearing
* all limits and the gpu stuck at whatever frequency it is at atm).
*/
{
limits = 0;
/* Only set the down limit when we've reached the lowest level to avoid
* getting more interrupts, otherwise leave this clear. This prevents a
* race in the hw when coming out of rc6: There's a tiny window where
* the hw runs at the minimal clock before selecting the desired
* frequency, if the down threshold expires in that window we will not
* receive a down interrupt. */
}
return limits;
}
{
return;
if (IS_HASWELL(dev))
HSW_FREQUENCY(val));
else
GEN6_OFFSET(0) |
/* Make sure we continue to get interrupts
* until we hit the minimum or maximum frequencies.
*/
}
/*
* Wait until the previous freq change has completed,
* or the timeout elapsed, and then update our notion
* of the current GPU frequency.
*/
{
do {
DRM_DEBUG_DRIVER("timed out waiting for Punit\n");
break;
}
udelay(10);
} while (pval & 1);
pval >>= 8;
DRM_DEBUG_DRIVER("Punit overrode GPU freq: %d MHz (%u) requested, but got %d Mhz (%u)\n",
}
{
DRM_DEBUG_DRIVER("GPU freq request from %d MHz (%u) to %d MHz (%u)\n",
return;
}
{
/* Complete PM interrupt masking here doesn't race with the rps work
* item again unmasking PM interrupts because that is using a different
* register (PMIMR) to mask PM interrupts. The only risk is in leaving
* stale bits in PMIIR and PMIMR which gen6_enable_rps will clean up. */
}
{
I915_WRITE(GEN6_PMIER, 0);
/* Complete PM interrupt masking here doesn't race with the rps work
* item again unmasking PM interrupts because that is using a different
* register (PMIMR) to mask PM interrupts. The only risk is in leaving
* stale bits in PMIIR and PMIMR which gen6_enable_rps will clean up. */
}
}
{
/* Respect the kernel parameter if it is set */
if (i915_enable_rc6 >= 0)
return i915_enable_rc6;
/* Disable RC6 on Ironlake */
return 0;
if (IS_HASWELL(dev)) {
DRM_DEBUG_DRIVER("Haswell: only RC6 available\n");
return INTEL_RC6_ENABLE;
}
DRM_DEBUG_DRIVER("Sandybridge: deep RC6 disabled\n");
return INTEL_RC6_ENABLE;
}
DRM_DEBUG_DRIVER("RC6 and deep RC6 enabled\n");
return (INTEL_RC6_ENABLE | INTEL_RC6p_ENABLE);
}
{
struct intel_ring_buffer *ring;
int rc6_mode;
int i, ret;
/* Here begins a magic sequence of register writes to enable
* auto-downclocking.
*
* Perhaps there might be some value in exposing these to
* userspace...
*/
I915_WRITE(GEN6_RC_STATE, 0);
/* Clear the DBG now so we don't confuse earlier errors */
}
/* In units of 100MHz */
/* disable the counters and set deterministic thresholds */
I915_WRITE(GEN6_RC_SLEEP, 0);
/* Check if we are enabling RC6 */
if (rc6_mode & INTEL_RC6_ENABLE)
/* We don't use those on Haswell */
if (!IS_HASWELL(dev)) {
if (rc6_mode & INTEL_RC6p_ENABLE)
if (rc6_mode & INTEL_RC6pp_ENABLE)
}
DRM_INFO("Enabling RC6 states: RC6 %s, RC6p %s, RC6pp %s\n",
rc6_mask |
GEN6_RC_CTL_EI_MODE(1) |
if (IS_HASWELL(dev)) {
HSW_FREQUENCY(10));
HSW_FREQUENCY(12));
} else {
GEN6_FREQUENCY(10) |
GEN6_OFFSET(0) |
GEN6_FREQUENCY(12));
}
if (!ret) {
pcu_mbox = 0;
DRM_DEBUG_DRIVER("Overclocking supported. Max: %dMHz, Overclock max: %dMHz\n",
}
} else {
DRM_DEBUG_DRIVER("Failed to set the min frequency\n");
}
/* requires MSI enabled */
/* FIXME: Our interrupt enabling sequence is bonghits.
* dev_priv->rps.pm_iir really should be 0 here. */
/* enable all PM interrupts */
I915_WRITE(GEN6_PMINTRMSK, 0);
rc6vids = 0;
DRM_DEBUG_DRIVER("Couldn't check for BIOS workaround\n");
DRM_DEBUG_DRIVER("You should update your BIOS. Correcting minimum rc6 voltage (%dmV->%dmV)\n",
rc6vids &= 0xffff00;
if (ret)
DRM_ERROR("Couldn't fix incorrect rc6 voltage\n");
}
}
{
int min_freq = 15;
unsigned int gpu_freq;
unsigned int max_ia_freq, min_ring_freq;
int scaling_factor = 180;
if (cpu_freq == 0)
return;
/* convert DDR frequency from units of 133.3MHz to bandwidth */
/*
* For each potential GPU frequency, load a ring frequency we'd like
* to use for memory access. We do this by specifying the IA frequency
* the PCU should use as a reference to determine the ring frequency.
*/
gpu_freq--) {
if (IS_HASWELL(dev)) {
/* leave ia_freq as the default, chosen by cpufreq */
} else {
/* On older processors, there is no separate ring
* clock domain, so in order to boost the bandwidth
* of the ring, we need to upclock the CPU (ia_freq).
*
* For GPU frequencies less than 750MHz, just use the lowest
* ring freq.
*/
ia_freq = 800;
else
}
gpu_freq);
}
}
{
/* Clamp to max */
return rp0;
}
{
return rpe;
}
{
}
#if 0
{
/*
* Timer fired, we must be idle. Drop to min voltage state.
* Note: we use RPe here since it should match the
* Vmin we were shooting for. That should give us better
* perf when we come back out of RC6 than if we used the
* min freq available.
*/
}
#endif
{
struct drm_i915_gem_object *pctx;
unsigned long pctx_paddr;
if (pcbr) {
/* BIOS set it up already, grab the pre-alloc'd space */
int pcbr_offset;
-1,
goto out;
}
/*
* From the Gunit register HAS:
* The Gfx driver is expected to program this register and ensure
* proper allocation within Gfx stolen memory. For example, this
* register should be programmed such than the PCBR range does not
* overlap with other ranges, such as the frame buffer, protected
* memory, or any other relevant ranges.
*/
if (!pctx) {
DRM_DEBUG("not enough stolen space for PCTX, disabling\n");
return;
}
out:
}
{
struct intel_ring_buffer *ring;
int i;
}
/* allows RC6 residency counter to work */
case 0:
case 1:
break;
case 2:
break;
case 3:
break;
}
DRM_DEBUG_DRIVER("current GPU freq: %d MHz (%u)\n",
DRM_DEBUG_DRIVER("max GPU freq: %d MHz (%u)\n",
DRM_DEBUG_DRIVER("RPe GPU freq: %d MHz (%u)\n",
DRM_DEBUG_DRIVER("min GPU freq: %d MHz (%u)\n",
DRM_DEBUG_DRIVER("setting GPU freq to %d MHz (%u)\n",
//INIT_DELAYED_WORK(&dev_priv->rps.vlv_work, vlv_rps_timer_work);
/* requires MSI enabled */
I915_WRITE(GEN6_PMIMR, 0);
/* enable all PM interrupts */
I915_WRITE(GEN6_PMINTRMSK, 0);
}
{
}
}
}
{
/* Wake the GPU, prevent RC6, then restore RSTDBYCTL */
50);
I915_WRITE(PWRCTXA, 0);
}
}
{
return -ENOMEM;
return -ENOMEM;
}
return 0;
}
{
bool was_interruptible;
int ret;
/* rc6 disabled by default due to repeated reports of hanging during
* boot and resume.
*/
if (!intel_enable_rc6(dev))
return;
if (ret)
return;
/*
* GPU can automatically power down the render unit if given a page
* to save state.
*/
if (ret) {
return;
}
/*
* Wait for the command parser to advance past MI_SET_CONTEXT. The HW
* does an implicit flush, combined with MI_FLUSH above, it should be
* safe to assume that renderctx is valid
*/
if (ret) {
DRM_ERROR("failed to enable ironlake power savings\n");
return;
}
}
{
unsigned long freq;
if (!pre)
return 0;
return freq;
}
static const struct cparams {
u16 i;
u16 t;
u16 m;
u16 c;
} cparams[] = {
{ 1, 1333, 301, 28664 },
{ 1, 1066, 294, 24460 },
{ 1, 800, 294, 25192 },
{ 0, 1333, 276, 27605 },
{ 0, 1066, 276, 27605 },
{ 0, 800, 231, 23784 },
};
{
int i;
/* Disable to program */
I915_WRITE(ECR, 0);
/* Program energy weights for various events */
for (i = 0; i < 5; i++)
for (i = 0; i < 3; i++)
/* Program P-state weights to account for frequency power adjustment */
for (i = 0; i < 16; i++) {
unsigned long val;
val *= 255;
if (val > 0xff)
}
/* Render standby states get 0 weight */
pxw[14] = 0;
pxw[15] = 0;
for (i = 0; i < 4; i++) {
}
/* Adjust magic regs to magic values (more experimental results) */
I915_WRITE(OGW0, 0);
I915_WRITE(OGW1, 0);
I915_WRITE(EG6, 0);
I915_WRITE(EG7, 0);
for (i = 0; i < 8; i++)
/* Enable PMON + select events */
}
{
/* Interrupts should be disabled already to avoid re-arming. */
/* fix me i915_quiesce */
// WARN_ON(dev->irq_enabled);
if (IS_IRONLAKE_M(dev)) {
// if (IS_VALLEYVIEW(dev))
// cancel_delayed_work_sync(&dev_priv->rps.vlv_work);
if (IS_VALLEYVIEW(dev))
else
}
}
{
if (IS_VALLEYVIEW(dev)) {
} else {
}
}
void
{
}
{
if (IS_IRONLAKE_M(dev)) {
/*
* PCU communication is slow and this doesn't need to be
* done at any specific time, so do this out of our fast path
* to make resume and init faster.
*/
}
}
{
/*
* On Ibex Peak and Cougar Point, we need to disable clock
* gating for the panel power sequencer or it will fail to
* start up when no ports are active.
*/
}
{
int pipe;
}
}
{
/* Required for FBC */
/*
* According to the spec the following bits should be set in
* order to enable memory self-refresh
* The bit 22/21 of 0x42004
* The bit 5 of 0x42020
* The bit 15 of 0x45000
*/
I915_WRITE(WM3_LP_ILK, 0);
I915_WRITE(WM2_LP_ILK, 0);
I915_WRITE(WM1_LP_ILK, 0);
/*
* Based on the document from hardware guys the following bits
* should be set unconditionally in order to enable FBC.
* The bit 22 of 0x42000
* The bit 22 of 0x42004
* The bit 7,8,9 of 0x42020.
*/
if (IS_IRONLAKE_M(dev)) {
}
_3D_CHICKEN2_WM_READ_PIPELINED << 16 |
/* WaDisableRenderCachePipelinedFlush */
}
{
int pipe;
/*
* On Ibex Peak and Cougar Point, we need to disable clock
* gating for the panel power sequencer or it will fail to
* start up when no ports are active.
*/
/* The below fixes the weird display corruption, a few pixels shifted
* downward, on (only) LVDS of some HP laptops with IVY.
*/
}
/* WADP0ClockGatingDisable */
}
}
{
DRM_INFO("This can cause pipe underruns and display issues.\n");
DRM_INFO("Please upgrade your BIOS to fix this.\n");
}
}
{
/* WaDisableHiZPlanesWhenMSAAEnabled */
/* WaSetupGtModeTdRowDispatch */
if (IS_SNB_GT1(dev))
I915_WRITE(WM3_LP_ILK, 0);
I915_WRITE(WM2_LP_ILK, 0);
I915_WRITE(WM1_LP_ILK, 0);
/* According to the BSpec vol1g, bit 12 (RCPBUNIT) clock
* gating disable must be set. Failure to set it results in
* flickering pixels due to Z write ordering failures after
* some amount of runtime in the Mesa "fire" demo, and Unigine
* Sanctuary and Tropics, and apparently anything else with
* alpha test or pixel discard.
*
* According to the spec, bit 11 (RCCUNIT) must also be set,
* but we didn't debug actual testcases to find it out.
*
* Also apply WaDisableVDSUnitClockGating and
* WaDisableRCPBUnitClockGating.
*/
/* Bspec says we need to always set all mask bits. */
/*
* According to the spec the following bits should be
* set in order to enable memory self-refresh and fbc:
* The bit21 and bit22 of 0x42000
* The bit21 and bit22 of 0x42004
* The bit5 and bit7 of 0x42020
* The bit14 of 0x70180
* The bit14 of 0x71180
*/
/* WaMbcDriverBootEnable */
/* The default value should be 0x200 according to docs, but the two
* platforms I checked have a 0 for this. (Maybe BIOS overrides?) */
}
{
reg &= ~GEN7_FF_SCHED_MASK;
}
{
/*
* TODO: this bit should only be enabled when really needed, then
* disabled when not needed anymore in order to save power.
*/
/* WADPOClockGatingDisable:hsw */
}
{
}
}
{
I915_WRITE(WM3_LP_ILK, 0);
I915_WRITE(WM2_LP_ILK, 0);
I915_WRITE(WM1_LP_ILK, 0);
/* According to the spec, bit 13 (RCZUNIT) must be set on IVB.
* This implements the WaDisableRCZUnitClockGating workaround.
*/
/* Apply the WaDisableRHWOOptimizationForRenderHang workaround. */
/* WaApplyL3ControlAndL3ChickenMode requires those two on Ivy Bridge */
/* This is required by WaCatErrorRejectionIssue */
/* WaDisable4x2SubspanOptimization */
/* WaMbcDriverBootEnable */
/* WaSwitchSolVfFArbitrationPriority:hsw */
/* WaRsPkgCStateDisplayPMReq:hsw */
}
{
I915_WRITE(WM3_LP_ILK, 0);
I915_WRITE(WM2_LP_ILK, 0);
I915_WRITE(WM1_LP_ILK, 0);
/* WaDisableEarlyCull */
/* WaDisableBackToBackFlipFix */
/* WaDisablePSDDualDispatchEnable */
if (IS_IVB_GT1(dev))
else
/* Apply the WaDisableRHWOOptimizationForRenderHang workaround. */
/* WaApplyL3ControlAndL3ChickenMode requires those two on Ivy Bridge */
if (IS_IVB_GT1(dev))
else
/* WaForceL3Serialization */
/* According to the BSpec vol1g, bit 12 (RCPBUNIT) clock
* gating disable must be set. Failure to set it results in
* flickering pixels due to Z write ordering failures after
* some amount of runtime in the Mesa "fire" demo, and Unigine
* Sanctuary and Tropics, and apparently anything else with
* alpha test or pixel discard.
*
* According to the spec, bit 11 (RCCUNIT) must also be set,
* but we didn't debug actual testcases to find it out.
*
* According to the spec, bit 13 (RCZUNIT) must be set on IVB.
* This implements the WaDisableRCZUnitClockGating workaround.
*/
/* This is required by WaCatErrorRejectionIssue */
/* WaMbcDriverBootEnable */
/* WaVSRefCountFullforceMissDisable:ivb */
/* WaDisable4x2SubspanOptimization */
snpcr &= ~GEN6_MBC_SNPCR_MASK;
if (!HAS_PCH_NOP(dev))
}
{
/* WaDisableEarlyCull */
/* WaDisableBackToBackFlipFix */
/* Apply the WaDisableRHWOOptimizationForRenderHang workaround. */
/* WaApplyL3ControlAndL3ChickenMode requires those two on Ivy Bridge */
/* WaForceL3Serialization */
/* WaDisableDopClockGating */
/* This is required by WaCatErrorRejectionIssue */
/* WaMbcDriverBootEnable */
/* According to the BSpec vol1g, bit 12 (RCPBUNIT) clock
* gating disable must be set. Failure to set it results in
* flickering pixels due to Z write ordering failures after
* some amount of runtime in the Mesa "fire" demo, and Unigine
* Sanctuary and Tropics, and apparently anything else with
* alpha test or pixel discard.
*
* According to the spec, bit 11 (RCCUNIT) must also be set,
* but we didn't debug actual testcases to find it out.
*
* According to the spec, bit 13 (RCZUNIT) must be set on IVB.
* This implements the WaDisableRCZUnitClockGating workaround.
*
* Also apply WaDisableVDSUnitClockGating and
* WaDisableRCPBUnitClockGating.
*/
/*
* On ValleyView, the GUnit needs to signal the GT
* when flip and other events complete. So enable
* all the GUnit->GT interrupts here
*/
/* Conservative clock gating settings for now */
}
{
I915_WRITE(RENCLK_GATE_D1, 0);
I915_WRITE(RAMCLK_GATE_D, 0);
/* WaDisableRenderCachePipelinedFlush */
}
{
I915_WRITE(RENCLK_GATE_D2, 0);
I915_WRITE(DSPCLK_GATE_D, 0);
I915_WRITE(RAMCLK_GATE_D, 0);
I915_WRITE16(DEUC, 0);
}
{
I915_WRITE(RENCLK_GATE_D2, 0);
}
{
if (IS_PINEVIEW(dev))
/* IIR "flip pending" means done if this bit is set */
}
{
}
{
}
{
}
{
if (HAS_PCH_LPT(dev))
}
/**
* We should only use the power well if we explicitly asked the hardware to
* enable it, so check if it's enabled and also check if we've requested it to
* be enabled.
*/
{
if (!HAS_POWER_WELL(dev))
return true;
switch (domain) {
case POWER_DOMAIN_PIPE_A:
return true;
case POWER_DOMAIN_PIPE_B:
case POWER_DOMAIN_PIPE_C:
return I915_READ(HSW_PWR_WELL_DRIVER) ==
default:
BUG();
return false;
}
}
{
bool is_enabled, enable_requested;
if (enable) {
if (!enable_requested)
if (!is_enabled) {
DRM_DEBUG_KMS("Enabling power well\n");
HSW_PWR_WELL_STATE), 20))
DRM_ERROR("Timeout enabling power well\n");
}
} else {
if (enable_requested) {
unsigned long irqflags;
enum pipe p;
DRM_DEBUG_KMS("Requesting to disable the power well\n");
/*
* After this, the registers on the pipes that are part
* of the power well will become zero, so we have to
* adjust our counters according to that.
*
* FIXME: Should we do this in general in
* drm_vblank_post_modeset?
*/
if (p != PIPE_A)
dev->last_vblank[p] = 0;
}
}
}
static struct i915_power_well *hsw_pwr;
/* Display audio driver power well request */
void i915_request_power_well(void)
{
if (!hsw_pwr)
return;
}
/* Display audio driver power well release */
void i915_release_power_well(void)
{
if (!hsw_pwr)
return;
}
{
return 0;
}
{
}
{
if (!HAS_POWER_WELL(dev))
return;
if (!i915_disable_power_well && !enable)
return;
/* only reject "disable" power well request */
return;
}
}
/*
* Starting with Haswell, we have a "Power Down Well" that can be turned off
* when not needed anymore. We have 4 registers that can request the power well
* to be enabled, and it will only be disabled if none of the registers is
* requesting it to be enabled.
*/
{
if (!HAS_POWER_WELL(dev))
return;
/* For now, we need the power well to be always enabled. */
intel_set_power_well(dev, true);
/* We're taking over the BIOS, so clear any requests made by it since
* the driver is in charge now. */
}
/* Set up chip specific power management-related functions */
{
if (I915_HAS_FBC(dev)) {
if (HAS_PCH_SPLIT(dev)) {
else
} else if (IS_CRESTLINE(dev)) {
}
/* 855GM needs testing */
}
/* For cxsr */
if (IS_PINEVIEW(dev))
/* For FIFO watermark updates */
if (HAS_PCH_SPLIT(dev)) {
else {
DRM_DEBUG_KMS("Failed to get proper latency. "
"Disable CxSR\n");
}
if (SNB_READ_WM0_LATENCY()) {
} else {
DRM_DEBUG_KMS("Failed to read display plane latency. "
"Disable CxSR\n");
}
} else if (IS_IVYBRIDGE(dev)) {
/* FIXME: detect B0+ stepping and use auto training */
if (SNB_READ_WM0_LATENCY()) {
} else {
DRM_DEBUG_KMS("Failed to read display plane latency. "
"Disable CxSR\n");
}
} else if (IS_HASWELL(dev)) {
if (I915_READ64(MCH_SSKPD)) {
} else {
DRM_DEBUG_KMS("Failed to read display plane latency. "
"Disable CxSR\n");
}
} else
} else if (IS_VALLEYVIEW(dev)) {
} else if (IS_PINEVIEW(dev)) {
DRM_INFO("failed to find known CxSR latency "
"(found ddr%s fsb freq %d, mem freq %d), "
"disabling CxSR\n",
/* Disable CxSR and never update its watermark again */
} else
if (IS_CRESTLINE(dev))
else if (IS_BROADWATER(dev))
} else {
else
}
}
{
else
/* w/a for a sporadic read returning 0 by waiting for the GT
* thread to wake up.
*/
if (wait_for_atomic((I915_READ_NOTRACE(GEN6_GT_THREAD_STATUS_REG) & gt_thread_status_mask) == 0, 1))
DRM_INFO("GT thread status wait timed out\n");
}
{
}
{
DRM_INFO("Timed out waiting for forcewake old ack to clear.\n");
DRM_INFO("Timed out waiting for forcewake to ack request.\n");
}
{
}
{
else
DRM_INFO("Timed out waiting for forcewake old ack to clear.\n");
/* something from same cacheline, but !FORCEWAKE_MT */
DRM_INFO("Timed out waiting for forcewake to ack request.\n");
}
/*
* Generally this is called implicitly by the register read function. However,
* if some sequence requires the GT to not power down then this function should
* be called at the beginning of the sequence followed by a call to
* gen6_gt_force_wake_put() at the end of the sequence.
*/
{
unsigned long irqflags;
if (dev_priv->forcewake_count++ == 0)
}
{
if (gtfifodbg & GT_FIFO_CPU_ERROR_MASK) {
}
}
{
/* gen6_gt_check_fifodbg doubles as the POSTING_READ */
}
{
/* gen6_gt_check_fifodbg doubles as the POSTING_READ */
}
/*
* see gen6_gt_force_wake_get()
*/
{
unsigned long irqflags;
if (--dev_priv->forcewake_count == 0)
}
{
int ret = 0;
int loop = 500;
udelay(10);
}
++ret;
}
}
return ret;
}
{
/* something from same cacheline, but !FORCEWAKE_VLV */
}
{
DRM_ERROR("Timed out waiting for forcewake old ack to clear.\n");
DRM_ERROR("Timed out waiting for GT to ack forcewake request.\n");
DRM_ERROR("Timed out waiting for media to ack forcewake request.\n");
}
{
/* The below doubles as a POSTING_READ */
}
{
if (IS_VALLEYVIEW(dev)) {
}
/* BIOS often leaves RC6 enabled, but disable it for hw init */
}
{
if (IS_VALLEYVIEW(dev)) {
} else if (IS_HASWELL(dev)) {
} else if (IS_IVYBRIDGE(dev)) {
/* 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.
*/
if (ecobus & FORCEWAKE_MT_ENABLE) {
} 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");
}
}
}
{
(void *)dev);
}
{
DRM_DEBUG_DRIVER("warning: pcode (read) mailbox access failed\n");
return -EAGAIN;
}
500)) {
return -ETIMEDOUT;
}
return 0;
}
{
DRM_DEBUG_DRIVER("warning: pcode (write) mailbox access failed\n");
return -EAGAIN;
}
500)) {
return -ETIMEDOUT;
}
return 0;
}
{
switch (ddr_freq) {
case 800:
mult = 20;
base = 120;
break;
case 1066:
mult = 22;
base = 133;
break;
case 1333:
mult = 21;
base = 125;
break;
default:
return -1;
}
}
{
switch (ddr_freq) {
case 800:
mult = 20;
base = 120;
break;
case 1066:
mult = 22;
base = 133;
break;
case 1333:
mult = 21;
base = 125;
break;
default:
return -1;
}
val += 0xbd;
if (val > 0xea)
val = 0xea;
return val;
}