val = vlv_punit_read(display->drm, PUNIT_REG_DDR_SETUP2); if (enable)
val &= ~FORCE_DDR_HIGH_FREQ; else
val |= FORCE_DDR_HIGH_FREQ;
val &= ~FORCE_DDR_LOW_FREQ;
val |= FORCE_DDR_FREQ_REQ_ACK;
vlv_punit_write(display->drm, PUNIT_REG_DDR_SETUP2, val);
if (wait_for((vlv_punit_read(display->drm, PUNIT_REG_DDR_SETUP2) &
FORCE_DDR_FREQ_REQ_ACK) == 0, 3))
drm_err(display->drm, "timed out waiting for Punit DDR DVFS request\n");
val = vlv_punit_read(display->drm, PUNIT_REG_DSPSSPM); if (enable)
val |= DSP_MAXFIFO_PM5_ENABLE; else
val &= ~DSP_MAXFIFO_PM5_ENABLE;
vlv_punit_write(display->drm, PUNIT_REG_DSPSSPM, val);
drm_dbg_kms(display->drm, "memory self-refresh is %s (was %s)\n",
str_enabled_disabled(enable),
str_enabled_disabled(was_enabled));
return was_enabled;
}
/** * intel_set_memory_cxsr - Configure CxSR state * @display: display device * @enable: Allow vs. disallow CxSR * * Allow or disallow the system to enter a special CxSR * (C-state self refresh) state. What typically happens in CxSR mode * is that several display FIFOs may get combined into a single larger * FIFO for a particular plane (so called max FIFO mode) to allow the * system to defer memory fetches longer, and the memory will enter * self refresh. * * Note that enabling CxSR does not guarantee that the system enter * this special mode, nor does it guarantee that the system stays * in that mode once entered. So this just allows/disallows the system * to autonomously utilize the CxSR mode. Other factors such as core * C-states will affect when/if the system actually enters/exits the * CxSR mode. * * Note that on VLV/CHV this actually only controls the max FIFO mode, * and the system is free to enter/exit memory self refresh at any time * even when the use of CxSR has been disallowed. * * While the system is actually in the CxSR/max FIFO mode, some plane * control registers will not get latched on vblank. Thus in order to * guarantee the system will respond to changes in the plane registers * we must always disallow CxSR prior to making changes to those registers. * Unfortunately the system will re-evaluate the CxSR conditions at * frame start which happens after vblank start (which is when the plane * registers would get latched), so we can't proceed with the plane update * during the same frame where we disallowed CxSR. * * Certain platforms also have a deeper HPLL SR mode. Fortunately the * HPLL SR mode depends on CxSR itself, so we don't have to hand hold * the hardware w.r.t. HPLL SR when writing to plane registers. * Disallowing just CxSR is sufficient.
*/ bool intel_set_memory_cxsr(struct intel_display *display, bool enable)
{ bool ret;
mutex_lock(&display->wm.wm_mutex);
ret = _intel_set_memory_cxsr(display, enable); if (display->platform.valleyview || display->platform.cherryview)
display->wm.vlv.cxsr = enable; elseif (display->platform.g4x)
display->wm.g4x.cxsr = enable;
mutex_unlock(&display->wm.wm_mutex);
return ret;
}
/* * 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.
*/ staticconstint pessimal_latency_ns = 5000;
/** * intel_wm_method1 - Method 1 / "small buffer" watermark formula * @pixel_rate: Pipe pixel rate in kHz * @cpp: Plane bytes per pixel * @latency: Memory wakeup latency in 0.1us units * * Compute the watermark using the method 1 or "small buffer" * formula. The caller may additionally add extra cachelines * to account for TLB misses and clock crossings. * * This method is concerned with the short term drain rate * of the FIFO, ie. it does not account for blanking periods * which would effectively reduce the average drain rate across * a longer period. The name "small" refers to the fact the * FIFO is relatively small compared to the amount of data * fetched. * * The FIFO level vs. time graph might look something like: * * |\ |\ * | \ | \ * __---__---__ (- plane active, _ blanking) * -> time * * or perhaps like this: * * |\|\ |\|\ * __----__----__ (- plane active, _ blanking) * -> time * * Returns: * The watermark in bytes
*/ staticunsignedint intel_wm_method1(unsignedint pixel_rate, unsignedint cpp, unsignedint latency)
{
u64 ret;
ret = mul_u32_u32(pixel_rate, cpp * latency);
ret = DIV_ROUND_UP_ULL(ret, 10000);
return ret;
}
/** * intel_wm_method2 - Method 2 / "large buffer" watermark formula * @pixel_rate: Pipe pixel rate in kHz * @htotal: Pipe horizontal total * @width: Plane width in pixels * @cpp: Plane bytes per pixel * @latency: Memory wakeup latency in 0.1us units * * Compute the watermark using the method 2 or "large buffer" * formula. The caller may additionally add extra cachelines * to account for TLB misses and clock crossings. * * This method is concerned with the long term drain rate * of the FIFO, ie. it does account for blanking periods * which effectively reduce the average drain rate across * a longer period. The name "large" refers to the fact the * FIFO is relatively large compared to the amount of data * fetched. * * The FIFO level vs. time graph might look something like: * * |\___ |\___ * | \___ | \___ * | \ | \ * __ --__--__--__--__--__--__ (- plane active, _ blanking) * -> time * * Returns: * The watermark in bytes
*/ staticunsignedint intel_wm_method2(unsignedint pixel_rate, unsignedint htotal, unsignedint width, unsignedint cpp, unsignedint latency)
{ unsignedint ret;
/* * FIXME remove once all users are computing * watermarks in the correct place.
*/ if (WARN_ON_ONCE(htotal == 0))
htotal = 1;
ret = (latency * pixel_rate) / (htotal * 10000);
ret = (ret + 1) * width * cpp;
return ret;
}
/** * intel_calculate_wm - calculate watermark level * @display: display device * @pixel_rate: pixel clock * @wm: chip FIFO params * @fifo_size: size of the FIFO buffer * @cpp: bytes per pixel * @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.
*/ staticunsignedint intel_calculate_wm(struct intel_display *display, int pixel_rate, conststruct intel_watermark_params *wm, int fifo_size, int cpp, unsignedint latency_ns)
{ int entries, 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
*/
entries = intel_wm_method1(pixel_rate, cpp,
latency_ns / 100);
entries = DIV_ROUND_UP(entries, wm->cacheline_size) +
wm->guard_size;
drm_dbg_kms(display->drm, "FIFO entries required for mode: %d\n", entries);
/* Don't promote wm_size to unsigned... */ if (wm_size > wm->max_wm)
wm_size = wm->max_wm; if (wm_size <= 0)
wm_size = wm->default_wm;
/* * Bspec seems to indicate that the value shouldn't be lower than * 'burst size + 1'. Certainly 830 is quite unhappy with low values. * Lets go for 8 which is the burst size since certain platforms * already use a hardcoded 8 (which is what the spec says should be * done).
*/ if (wm_size <= 8)
wm_size = 8;
return wm_size;
}
staticbool is_disabling(int old, intnew, int threshold)
{ return old >= threshold && new < threshold;
}
staticbool is_enabling(int old, intnew, int threshold)
{ return old < threshold && new >= threshold;
}
staticbool intel_crtc_active(struct intel_crtc *crtc)
{ /* Be paranoid as we can arrive here with only partial * state retrieved from the hardware during setup. * * We can ditch the adjusted_mode.crtc_clock check as soon * as Haswell has gained clock readout/fastboot support. * * We can ditch the crtc->primary->state->fb check as soon as we can * properly reconstruct framebuffers. * * FIXME: The intel_crtc->active here should be switched to * crtc->state->active once we have proper CRTC states wired up * for atomic.
*/ return crtc->active && crtc->base.primary->state->fb &&
crtc->config->hw.adjusted_mode.crtc_clock;
}
/* * Documentation says: * "If the line size is small, the TLB fetches can get in the way of the * data fetches, causing some lag in the pixel data return which is not * accounted for in the above formulas. The following adjustment only * needs to be applied if eight whole lines fit in the buffer at once. * The WM is adjusted upwards by the difference between the FIFO size * and the size of 8 whole lines. This adjustment is always performed * in the actual pixel depth regardless of whether FBC is enabled or not."
*/ staticunsignedint g4x_tlb_miss_wa(int fifo_size, int width, int cpp)
{ int tlb_miss = fifo_size * 64 - width * cpp * 8;
/* * Zero the (unused) WM1 watermarks, and also clear all the * high order bits so that there are no out of bounds values * present in the registers during the reprogramming.
*/
intel_de_write(display, DSPHOWM, 0);
intel_de_write(display, DSPHOWM1, 0);
intel_de_write(display, DSPFW4, 0);
intel_de_write(display, DSPFW5, 0);
intel_de_write(display, DSPFW6, 0);
staticvoid g4x_setup_wm_latency(struct intel_display *display)
{ /* all latencies in usec */
display->wm.pri_latency[G4X_WM_LEVEL_NORMAL] = 5;
display->wm.pri_latency[G4X_WM_LEVEL_SR] = 12;
display->wm.pri_latency[G4X_WM_LEVEL_HPLL] = 35;
display->wm.num_levels = G4X_WM_LEVEL_HPLL + 1;
}
staticint g4x_plane_fifo_size(enum plane_id plane_id, int level)
{ /* * DSPCNTR[13] supposedly controls whether the * primary plane can use the FIFO space otherwise * reserved for the sprite plane. It's not 100% clear * what the actual FIFO size is, but it looks like we * can happily set both primary and sprite watermarks * up to 127 cachelines. So that would seem to mean * that either DSPCNTR[13] doesn't do anything, or that * the total FIFO is >= 256 cachelines in size. Either * way, we don't seem to have to worry about this * repartitioning as the maximum watermark value the * register can hold for each plane is lower than the * minimum FIFO size.
*/ switch (plane_id) { case PLANE_CURSOR: return 63; case PLANE_PRIMARY: return level == G4X_WM_LEVEL_NORMAL ? 127 : 511; case PLANE_SPRITE0: return level == G4X_WM_LEVEL_NORMAL ? 127 : 0; default:
MISSING_CASE(plane_id); return 0;
}
}
if (!intel_wm_plane_visible(crtc_state, plane_state)) return 0;
cpp = plane_state->hw.fb->format->cpp[0];
/* * WaUse32BppForSRWM:ctg,elk * * The spec fails to list this restriction for the * HPLL watermark, which seems a little strange. * Let's use 32bpp for the HPLL watermark as well.
*/ if (plane->id == PLANE_PRIMARY &&
level != G4X_WM_LEVEL_NORMAL)
cpp = max(cpp, 4u);
/* mark all levels starting from 'level' as invalid */ staticvoid g4x_invalidate_wms(struct intel_crtc *crtc, struct g4x_wm_state *wm_state, int level)
{ if (level <= G4X_WM_LEVEL_NORMAL) { enum plane_id plane_id;
out: if (level == G4X_WM_LEVEL_NORMAL) return -EINVAL;
/* invalidate the higher levels */
g4x_invalidate_wms(crtc, wm_state, level);
/* * Determine if the FBC watermark(s) can be used. IF * this isn't the case we prefer to disable the FBC * watermark(s) rather than disable the SR/HPLL * level(s) entirely. 'level-1' is the highest valid * level here.
*/
wm_state->fbc_en = g4x_compute_fbc_en(wm_state, level - 1);
out: /* * If our intermediate WM are identical to the final WM, then we can * omit the post-vblank programming; only update if it's different.
*/ if (memcmp(intermediate, optimal, sizeof(*intermediate)) != 0)
new_crtc_state->wm.need_postvbl_update = true;
return 0;
}
staticint g4x_compute_watermarks(struct intel_atomic_state *state, struct intel_crtc *crtc)
{ int ret;
ret = g4x_compute_pipe_wm(state, crtc); if (ret) return ret;
ret = g4x_compute_intermediate_wm(state, crtc); if (ret) return ret;
if (plane->id == PLANE_CURSOR) { /* * FIXME the formula gives values that are * too big for the cursor FIFO, and hence we * would never be able to use cursors. For * now just hardcode the watermark.
*/
wm = 63;
} else {
wm = vlv_wm_method2(pixel_rate, htotal, width, cpp,
display->wm.pri_latency[level] * 10);
}
/* * When enabling sprite0 after sprite1 has already been enabled * we tend to get an underrun unless sprite0 already has some * FIFO space allocated. Hence we always allocate at least one * cacheline for sprite0 whenever sprite1 is enabled. * * All other plane enable sequences appear immune to this problem.
*/ if (vlv_need_sprite0_fifo_workaround(active_planes))
sprite0_fifo_extra = 1;
/* give it all to the first plane if none are active */ if (active_planes == 0) {
drm_WARN_ON(display->drm, fifo_left != fifo_size);
fifo_state->plane[PLANE_PRIMARY] = fifo_left;
}
return 0;
}
/* mark all levels starting from 'level' as invalid */ staticvoid vlv_invalidate_wms(struct intel_crtc *crtc, struct vlv_wm_state *wm_state, int level)
{ struct intel_display *display = to_intel_display(crtc);
for (; level < display->wm.num_levels; level++) { enum plane_id plane_id;
/* initially allow all levels */
wm_state->num_levels = display->wm.num_levels; /* * Note that enabling cxsr with no primary/sprite planes * enabled can wedge the pipe. Hence we only allow cxsr * with exactly one enabled primary/sprite plane.
*/
wm_state->cxsr = crtc->pipe != PIPE_C && num_active_planes == 1;
if (vlv_raw_plane_wm_compute(crtc_state, new_plane_state))
dirty |= BIT(plane->id);
}
/* * DSPARB registers may have been reset due to the * power well being turned off. Make sure we restore * them to a consistent state even if no primary/sprite * planes are initially active. We also force a FIFO * recomputation so that we are sure to sanitize the * FIFO setting we took over from the BIOS even if there * are no active planes on the crtc.
*/ if (intel_crtc_needs_modeset(crtc_state))
dirty = ~0;
/* * uncore.lock serves a double purpose here. It allows us to * use the less expensive I915_{READ,WRITE}_FW() functions, and * it protects the DSPARB registers from getting clobbered by * parallel updates from multiple pipes. * * intel_pipe_update_start() has already disabled interrupts * for us, so a plain spin_lock() is sufficient here.
*/
spin_lock(&uncore->lock);
out: /* * If our intermediate WM are identical to the final WM, then we can * omit the post-vblank programming; only update if it's different.
*/ if (memcmp(intermediate, optimal, sizeof(*intermediate)) != 0)
new_crtc_state->wm.need_postvbl_update = true;
return 0;
}
staticint vlv_compute_watermarks(struct intel_atomic_state *state, struct intel_crtc *crtc)
{ int ret;
ret = vlv_compute_pipe_wm(state, crtc); if (ret) return ret;
ret = vlv_compute_intermediate_wm(state, crtc); if (ret) return ret;
/* self-refresh seems busted with untiled */ if (!intel_bo_is_tiled(obj))
crtc = NULL;
}
/* * Overlay gets an aggressive default since video jitter is bad.
*/
cwm = 2;
/* Play safe and disable self-refresh before adjusting watermarks. */
intel_set_memory_cxsr(display, false);
/* Calc sr entries for one plane configs */ if (HAS_FW_BLC(display) && crtc) { /* self-refresh has much higher latency */ staticconstint sr_latency_ns = 6000; conststruct drm_display_mode *pipe_mode =
&crtc->config->hw.pipe_mode; conststruct drm_framebuffer *fb =
crtc->base.primary->state->fb; int pixel_rate = crtc->config->pixel_rate; int htotal = pipe_mode->crtc_htotal; int width = drm_rect_width(&crtc->base.primary->state->src) >> 16; int cpp; int entries;
/* latency must be in 0.1us units. */ staticunsignedint ilk_wm_method1(unsignedint pixel_rate, unsignedint cpp, unsignedint latency)
{ unsignedint ret;
ret = intel_wm_method1(pixel_rate, cpp, latency);
ret = DIV_ROUND_UP(ret, 64) + 2;
return ret;
}
/* latency must be in 0.1us units. */ staticunsignedint ilk_wm_method2(unsignedint pixel_rate, unsignedint htotal, unsignedint width, unsignedint cpp, unsignedint latency)
{ unsignedint ret;
ret = intel_wm_method2(pixel_rate, htotal,
width, cpp, latency);
ret = DIV_ROUND_UP(ret, 64) + 2;
return ret;
}
static u32 ilk_wm_fbc(u32 pri_val, u32 horiz_pixels, u8 cpp)
{ /* * Neither of these should be possible since this function shouldn't be * called if the CRTC is off or the plane is invisible. But let's be * extra paranoid to avoid a potential divide-by-zero if we screw up * elsewhere in the driver.
*/ if (WARN_ON(!cpp)) return 0; if (WARN_ON(!horiz_pixels)) return 0;
/* * For both WM_PIPE and WM_LP. * mem_value must be in 0.1us units.
*/ static u32 ilk_compute_pri_wm(conststruct intel_crtc_state *crtc_state, conststruct intel_plane_state *plane_state,
u32 mem_value, bool is_lp)
{
u32 method1, method2; int cpp;
if (mem_value == 0) return U32_MAX;
if (!intel_wm_plane_visible(crtc_state, plane_state)) return 0;
/* * For both WM_PIPE and WM_LP. * mem_value must be in 0.1us units.
*/ static u32 ilk_compute_spr_wm(conststruct intel_crtc_state *crtc_state, conststruct intel_plane_state *plane_state,
u32 mem_value)
{
u32 method1, method2; int cpp;
if (mem_value == 0) return U32_MAX;
if (!intel_wm_plane_visible(crtc_state, plane_state)) return 0;
/* * For both WM_PIPE and WM_LP. * mem_value must be in 0.1us units.
*/ static u32 ilk_compute_cur_wm(conststruct intel_crtc_state *crtc_state, conststruct intel_plane_state *plane_state,
u32 mem_value)
{ int cpp;
if (mem_value == 0) return U32_MAX;
if (!intel_wm_plane_visible(crtc_state, plane_state)) return 0;
/* Calculate the maximum primary/sprite plane watermark */ staticunsignedint ilk_plane_wm_max(struct intel_display *display, int level, conststruct intel_wm_config *config, enum intel_ddb_partitioning ddb_partitioning, bool is_sprite)
{ unsignedint fifo_size = ilk_display_fifo_size(display);
/* if sprites aren't enabled, sprites get nothing */ if (is_sprite && !config->sprites_enabled) return 0;
/* HSW allows LP1+ watermarks even with multiple pipes */ if (level == 0 || config->num_pipes_active > 1) {
fifo_size /= INTEL_NUM_PIPES(display);
/* * For some reason the non self refresh * FIFO size is only half of the self * refresh FIFO size on ILK/SNB.
*/ if (DISPLAY_VER(display) < 7)
fifo_size /= 2;
}
if (config->sprites_enabled) { /* level 0 is always calculated with 1:1 split */ if (level > 0 && ddb_partitioning == INTEL_DDB_PART_5_6) { if (is_sprite)
fifo_size *= 5;
fifo_size /= 6;
} else {
fifo_size /= 2;
}
}
/* clamp to max that the registers can hold */ return min(fifo_size, ilk_plane_wm_reg_max(display, level, is_sprite));
}
/* Calculate the maximum cursor plane watermark */ staticunsignedint ilk_cursor_wm_max(struct intel_display *display, int level, conststruct intel_wm_config *config)
{ /* HSW LP1+ watermarks w/ multiple pipes */ if (level > 0 && config->num_pipes_active > 1) return 64;
/* otherwise just report max that registers can hold */ return ilk_cursor_wm_reg_max(display, level);
}
/* * HACK until we can pre-compute everything, * and thus fail gracefully if LP0 watermarks * are exceeded...
*/ if (level == 0 && !result->enable) { if (result->pri_val > max->pri)
drm_dbg_kms(display->drm, "Primary WM%d too large %u (max %u)\n",
level, result->pri_val, max->pri); if (result->spr_val > max->spr)
drm_dbg_kms(display->drm, "Sprite WM%d too large %u (max %u)\n",
level, result->spr_val, max->spr); if (result->cur_val > max->cur)
drm_dbg_kms(display->drm, "Cursor WM%d too large %u (max %u)\n",
level, result->cur_val, max->cur);
staticvoid snb_wm_lp3_irq_quirk(struct intel_display *display)
{ /* * On some SNB machines (Thinkpad X220 Tablet at least) * LP3 usage can cause vblank interrupts to be lost. * The DEIIR bit will go high but it looks like the CPU * never gets interrupted. * * It's not clear whether other interrupt source could * be affected or if this is somehow limited to vblank * interrupts only. To play it safe we disable LP3 * watermarks entirely.
*/ if (display->wm.pri_latency[3] == 0 &&
display->wm.spr_latency[3] == 0 &&
display->wm.cur_latency[3] == 0) return;
drm_dbg_kms(display->drm, "LP3 watermarks disabled due to potential for lost interrupts\n");
intel_print_wm_latency(display, "Primary", display->wm.pri_latency);
intel_print_wm_latency(display, "Sprite", display->wm.spr_latency);
intel_print_wm_latency(display, "Cursor", display->wm.cur_latency);
}
/* At least LP0 must be valid */ if (!ilk_validate_wm_level(display, 0, &max, &pipe_wm->wm[0])) {
drm_dbg_kms(display->drm, "LP0 watermark invalid\n"); returnfalse;
}
/* * Disable any watermark level that exceeds the * register maximums since such watermarks are * always invalid.
*/ if (!ilk_validate_wm_level(display, level, &max, wm)) {
memset(wm, 0, sizeof(*wm)); break;
}
}
return 0;
}
/* * Build a set of 'intermediate' watermark values that satisfy both the old * state and the new state. These can be programmed to the hardware * immediately.
*/ staticint ilk_compute_intermediate_wm(struct intel_atomic_state *state, struct intel_crtc *crtc)
{ struct intel_display *display = to_intel_display(crtc); struct intel_crtc_state *new_crtc_state =
intel_atomic_get_new_crtc_state(state, crtc); conststruct intel_crtc_state *old_crtc_state =
intel_atomic_get_old_crtc_state(state, crtc); struct intel_pipe_wm *intermediate = &new_crtc_state->wm.ilk.intermediate; conststruct intel_pipe_wm *optimal = &new_crtc_state->wm.ilk.optimal; conststruct intel_pipe_wm *active = &old_crtc_state->wm.ilk.optimal; int level;
/* * Start with the final, target watermarks, then combine with the * currently active watermarks to get values that are safe both before * and after the vblank.
*/
*intermediate = *optimal; if (!new_crtc_state->hw.active ||
intel_crtc_needs_modeset(new_crtc_state) ||
state->skip_intermediate_wm) return 0;
/* * We need to make sure that these merged watermark values are * actually a valid configuration themselves. If they're not, * there's no safe way to transition from the old state to * the new state, so we need to fail the atomic transaction.
*/ if (!ilk_validate_pipe_wm(display, intermediate)) return -EINVAL;
/* * If our intermediate WM are identical to the final WM, then we can * omit the post-vblank programming; only update if it's different.
*/ if (memcmp(intermediate, optimal, sizeof(*intermediate)) != 0)
new_crtc_state->wm.need_postvbl_update = true;
return 0;
}
staticint ilk_compute_watermarks(struct intel_atomic_state *state, struct intel_crtc *crtc)
{ int ret;
ret = ilk_compute_pipe_wm(state, crtc); if (ret) return ret;
ret = ilk_compute_intermediate_wm(state, crtc); if (ret) return ret;
return 0;
}
/* * Merge the watermarks from all active pipes for a specific level.
*/ staticvoid ilk_merge_wm_level(struct intel_display *display, int level, struct intel_wm_level *ret_wm)
{ conststruct intel_crtc *crtc;
/* * The watermark values may have been used in the past, * so we must maintain them in the registers for some * time even if the level is now disabled.
*/ if (!wm->enable)
ret_wm->enable = false;
/* * Merge all low power watermarks for all active pipes.
*/ staticvoid ilk_wm_merge(struct intel_display *display, conststruct intel_wm_config *config, conststruct ilk_wm_maximums *max, struct intel_pipe_wm *merged)
{ int level, num_levels = display->wm.num_levels; int last_enabled_level = num_levels - 1;
/* ILK/SNB/IVB: LP1+ watermarks only w/ single pipe */ if ((DISPLAY_VER(display) < 7 || display->platform.ivybridge) &&
config->num_pipes_active > 1)
last_enabled_level = 0;
/* ILK: FBC WM must be disabled always */
merged->fbc_wm_enabled = DISPLAY_VER(display) >= 6;
/* merge each WM1+ level */ for (level = 1; level < num_levels; level++) { struct intel_wm_level *wm = &merged->wm[level];
ilk_merge_wm_level(display, level, wm);
if (level > last_enabled_level)
wm->enable = false; elseif (!ilk_validate_wm_level(display, level, max, wm)) /* make sure all following levels get disabled */
last_enabled_level = level - 1;
/* * The spec says it is preferred to disable * FBC WMs instead of disabling a WM level.
*/ if (wm->fbc_val > max->fbc) { if (wm->enable)
merged->fbc_wm_enabled = false;
wm->fbc_val = 0;
}
}
/* ILK: LP2+ must be disabled when FBC WM is disabled but FBC enabled */ if (DISPLAY_VER(display) == 5 && HAS_FBC(display) &&
display->params.enable_fbc && !merged->fbc_wm_enabled) { for (level = 2; level < num_levels; level++) { struct intel_wm_level *wm = &merged->wm[level];
wm->enable = false;
}
}
}
staticint ilk_wm_lp_to_level(int wm_lp, conststruct intel_pipe_wm *pipe_wm)
{ /* LP1,LP2,LP3 levels are either 1,2,3 or 1,3,4 */ return wm_lp + (wm_lp >= 2 && pipe_wm->wm[4].enable);
}
/* The value we need to program into the WM_LPx latency field */ staticunsignedint ilk_wm_lp_latency(struct intel_display *display, int level)
{ if (display->platform.haswell || display->platform.broadwell) return 2 * level; else return display->wm.pri_latency[level];
}
/* * Maintain the watermark values even if the level is * disabled. Doing otherwise could cause underruns.
*/
results->wm_lp[wm_lp - 1] =
WM_LP_LATENCY(ilk_wm_lp_latency(display, level)) |
WM_LP_PRIMARY(r->pri_val) |
WM_LP_CURSOR(r->cur_val);
if (r->enable)
results->wm_lp[wm_lp - 1] |= WM_LP_ENABLE;
/* * Always set WM_LP_SPRITE_EN when spr_val != 0, even if the * level is disabled. Doing otherwise could cause underruns.
*/ if (DISPLAY_VER(display) < 7 && r->spr_val) {
drm_WARN_ON(display->drm, wm_lp != 1);
results->wm_lp_spr[wm_lp - 1] |= WM_LP_SPRITE_ENABLE;
}
}
/* * 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.
*/ staticstruct intel_pipe_wm *
ilk_find_best_result(struct intel_display *display, struct intel_pipe_wm *r1, struct intel_pipe_wm *r2)
{ int level, level1 = 0, level2 = 0;
for (level = 1; level < display->wm.num_levels; level++) { if (r1->wm[level].enable)
level1 = level; if (r2->wm[level].enable)
level2 = level;
}
/* * Don't touch WM_LP_SPRITE_ENABLE here. * Doing so could cause underruns.
*/
return changed;
}
/* * The spec says we shouldn't write when we don't need, because every write * causes WMs to be re-evaluated, expending some power.
*/ staticvoid ilk_write_wm_values(struct intel_display *display, struct ilk_wm_values *results)
{ struct ilk_wm_values *previous = &display->wm.hw; unsignedint dirty;
dirty = ilk_compute_wm_dirty(display, previous, results); if (!dirty) return;
_ilk_disable_lp_wm(display, dirty);
if (dirty & WM_DIRTY_PIPE(PIPE_A))
intel_de_write(display, WM0_PIPE_ILK(PIPE_A), results->wm_pipe[0]); if (dirty & WM_DIRTY_PIPE(PIPE_B))
intel_de_write(display, WM0_PIPE_ILK(PIPE_B), results->wm_pipe[1]); if (dirty & WM_DIRTY_PIPE(PIPE_C))
intel_de_write(display, WM0_PIPE_ILK(PIPE_C), results->wm_pipe[2]);
if (active->pipe_enabled) {
u32 tmp = hw->wm_pipe[pipe];
/* * For active pipes LP0 watermark is marked as * enabled, and LP1+ watermaks as disabled since * we can't really reverse compute them in case * multiple pipes are active.
*/
active->wm[0].enable = true;
active->wm[0].pri_val = REG_FIELD_GET(WM0_PIPE_PRIMARY_MASK, tmp);
active->wm[0].spr_val = REG_FIELD_GET(WM0_PIPE_SPRITE_MASK, tmp);
active->wm[0].cur_val = REG_FIELD_GET(WM0_PIPE_CURSOR_MASK, tmp);
} else { int level;
/* * For inactive pipes, all watermark levels * should be marked as enabled but zeroed, * which is what we'd compute them to.
*/ for (level = 0; level < display->wm.num_levels; level++)
active->wm[level].enable = true;
}
plane_state = drm_atomic_get_plane_state(state, plane); if (IS_ERR(plane_state)) return PTR_ERR(plane_state);
}
return 0;
}
/* * Calculate what we think the watermarks should be for the state we've read * out of the hardware and then immediately program those watermarks so that * we ensure the hardware settings match our internal state. * * We can calculate what we think WM's should be by creating a duplicate of the * current state (which was constructed during hardware readout) and running it * through the atomic check code to calculate new watermark values in the * state object.
*/ void ilk_wm_sanitize(struct intel_display *display)
{ struct drm_atomic_state *state; struct intel_atomic_state *intel_state; struct intel_crtc *crtc; struct intel_crtc_state *crtc_state; struct drm_modeset_acquire_ctx ctx; int ret; int i;
/* Only supported on platforms that use atomic watermark design */ if (!display->funcs.wm->optimize_watermarks) return;
if (drm_WARN_ON(display->drm, DISPLAY_VER(display) >= 9)) return;
state = drm_atomic_state_alloc(display->drm); if (drm_WARN_ON(display->drm, !state)) return;
retry: /* * Hardware readout is the only time we don't want to calculate * intermediate watermarks (since we don't trust the current * watermarks).
*/ if (!HAS_GMCH(display))
intel_state->skip_intermediate_wm = true;
ret = ilk_sanitize_watermarks_add_affected(state); if (ret) goto fail;
ret = intel_atomic_check(display->drm, state); if (ret) goto fail;
/* * If we fail here, it means that the hardware appears to be * programmed in a way that shouldn't be possible, given our * understanding of watermark requirements. This might mean a * mistake in the hardware readout code or a mistake in the * watermark calculations for a given platform. Raise a WARN * so that this is noticeable. * * If this actually happens, we'll have to just leave the * BIOS-programmed watermarks untouched and hope for the best.
*/
drm_WARN(display->drm, ret, "Could not determine valid watermarks for inherited state\n");
if (display->platform.cherryview) {
vlv_punit_get(display->drm);
val = vlv_punit_read(display->drm, PUNIT_REG_DSPSSPM); if (val & DSP_MAXFIFO_PM5_ENABLE)
wm->level = VLV_WM_LEVEL_PM5;
/* * If DDR DVFS is disabled in the BIOS, Punit * will never ack the request. So if that happens * assume we don't have to enable/disable DDR DVFS * dynamically. To test that just set the REQ_ACK * bit to poke the Punit, but don't change the * HIGH/LOW bits so that we don't actually change * the current state.
*/
val = vlv_punit_read(display->drm, PUNIT_REG_DDR_SETUP2);
val |= FORCE_DDR_FREQ_REQ_ACK;
vlv_punit_write(display->drm, PUNIT_REG_DDR_SETUP2, val);
if (wait_for((vlv_punit_read(display->drm, PUNIT_REG_DDR_SETUP2) &
FORCE_DDR_FREQ_REQ_ACK) == 0, 3)) {
drm_dbg_kms(display->drm, "Punit not acking DDR DVFS request, " "assuming DDR DVFS is disabled\n");
display->wm.num_levels = VLV_WM_LEVEL_PM5 + 1;
} else {
val = vlv_punit_read(display->drm, PUNIT_REG_DDR_SETUP2); if ((val & FORCE_DDR_HIGH_FREQ) == 0)
wm->level = VLV_WM_LEVEL_DDR_DVFS;
}
¤ Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.0.65Bemerkung:
(vorverarbeitet am 2026-04-26)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.