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;
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.