diff --git a/src/i810_reg.h b/src/i810_reg.h index bc462fa..f961fcc 100644 --- a/src/i810_reg.h +++ b/src/i810_reg.h @@ -550,6 +550,7 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #define MM_FIFO_WATERMARK 0x0001F000 #define LM_BURST_LENGTH 0x00000700 #define LM_FIFO_WATERMARK 0x0000001F +#define FWATER_BLC_SELF 0x20e0 /* Fence/Tiling ranges [0..7] diff --git a/src/i830.h b/src/i830.h index f933917..23cd80c 100644 --- a/src/i830.h +++ b/src/i830.h @@ -627,6 +627,10 @@ typedef struct _I830Rec { enum backlight_control backlight_control_method; uint32_t saveDSPARB; + uint32_t saveDSPFW1; + uint32_t saveDSPFW2; + uint32_t saveFWATER_BLC; + uint32_t saveFWATER_BLC2; uint32_t saveDSPACNTR; uint32_t saveDSPBCNTR; uint32_t savePIPEACONF; diff --git a/src/i830_display.c b/src/i830_display.c index dd1310f..b26ce42 100644 --- a/src/i830_display.c +++ b/src/i830_display.c @@ -1484,66 +1484,168 @@ i830_panel_fitter_pipe(I830Ptr pI830) } /** - * Sets up the DSPARB register to split the display fifo appropriately between - * the display planes. + * i830_update_watermarks - update FIFO watermark values based on current modes * - * Adjusting this register requires that the planes be off. + * 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: + * watermark = (trunc(latency/line time)+1) * surface width * + * bytes per pixel + * where + * line time = htotal / dotclock + * 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. */ static void -i830_update_dsparb(ScrnInfoPtr pScrn) +i830_update_watermarks(ScrnInfoPtr pScrn) { xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); I830Ptr pI830 = I830PTR(pScrn); - int total_hdisplay = 0, planea_hdisplay = 0, planeb_hdisplay = 0; - int fifo_entries = 0, planea_entries = 0, planeb_entries = 0, i; - - if ((INREG(DSPACNTR) & DISPLAY_PLANE_ENABLE) && - (INREG(DSPBCNTR) & DISPLAY_PLANE_ENABLE)) - xf86DrvMsg(pScrn->scrnIndex, X_ERROR, - "tried to update DSPARB with both planes enabled!\n"); - - /* - * FIFO entries will be split based on programmed modes - */ - if (IS_I965GM(pI830)) + int total_hdisplay = 0, planea_hdisplay = 0, planeb_hdisplay = 0, sr_hdisplay = 0; + int planea_entries = 0, planeb_entries = 0, sr_entries = 0, i; + float planea_dotclock = 0, planeb_dotclock = 0, sr_dotclock = 0; + int fifo_entries = 0, line_size = 0, enabled = 0; + float latency = .000003; /* fairly pessimistic value */ + uint32_t dsparb = INREG(DSPARB); + + if (IS_I965GM(pI830) || IS_I945GM(pI830)) { fifo_entries = 127; - else if (IS_I9XX(pI830)) + line_size = 64; + } else if (IS_I9XX(pI830)) { fifo_entries = 95; - else if (IS_MOBILE(pI830)) { + line_size = 64; + } else if (IS_MOBILE(pI830)) { fifo_entries = 255; + line_size = 32; } else { - /* The 845/865 only have a AEND field. Though the field size would + /* The 845/865 only have a AEND field. Though the field size would * allow 128 entries, the 865 rendered the cursor wrong then. * The BIOS set it up for 96. */ - fifo_entries = 95; + line_size = 32; + fifo_entries = 95; } for (i = 0; i < xf86_config->num_crtc; i++) { xf86CrtcPtr crtc = xf86_config->crtc[i]; I830CrtcPrivatePtr intel_crtc = crtc->driver_private; if (crtc->enabled) { + enabled++; total_hdisplay += crtc->mode.HDisplay; - if (intel_crtc->plane == 0) + if (intel_crtc->plane == 0) { planea_hdisplay = crtc->mode.HDisplay; - else + planea_dotclock = crtc->mode.Clock * 1000; + } else { planeb_hdisplay = crtc->mode.HDisplay; + planeb_dotclock = crtc->mode.Clock * 1000; + } + sr_hdisplay = crtc->mode.HDisplay; + sr_dotclock = crtc->mode.Clock * 1000; } } - planea_entries = fifo_entries * planea_hdisplay / total_hdisplay; - planeb_entries = fifo_entries * planeb_hdisplay / total_hdisplay; - - if (IS_I9XX(pI830)) - OUTREG(DSPARB, - ((planea_entries + planeb_entries) << DSPARB_CSTART_SHIFT) | - (planea_entries << DSPARB_BSTART_SHIFT)); - else if (IS_MOBILE(pI830)) - OUTREG(DSPARB, - ((planea_entries + planeb_entries) << DSPARB_BEND_SHIFT) | - (planea_entries << DSPARB_AEND_SHIFT)); - else - OUTREG(DSPARB, planea_entries << DSPARB_AEND_SHIFT); + planea_entries = rint(planea_dotclock * pI830->cpp * latency) / line_size; + planeb_entries = rint(planeb_dotclock * pI830->cpp * latency) / line_size; + + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "FIFO entries - A: %d, B: %d\n", + planea_entries, planeb_entries); + + if (enabled == 1) { + float line_time = sr_hdisplay / sr_dotclock; + + sr_entries = ((latency / line_time) + 1) * pI830->cpp * sr_hdisplay; + sr_entries = rint((double)sr_entries / (double)line_size); + } + + if (IS_I965G(pI830)) { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "Setting FIFO watermarks - A: 8, B: 8, C: 8, SR 8\n"); + + /* 965 has limitations... */ + OUTREG(DSPFW1, (8 << 16) | (8 << 8) | (8 << 0)); + OUTREG(DSPFW2, (8 << 8) | (8 << 0)); + } else if (IS_I9XX(pI830) || IS_MOBILE(pI830)) { + uint32_t fwater_lo = INREG(FWATER_BLC) & MM_FIFO_WATERMARK; + uint32_t fwater_hi = INREG(FWATER_BLC2) & LM_FIFO_WATERMARK; + unsigned int bsize, asize, cwm, bwm = 1, awm = 1, srwm = 1; + + if (IS_I9XX(pI830)) { + asize = dsparb & 0x7f; + bsize = (dsparb >> DSPARB_CSTART_SHIFT) & 0x7f; + } else { + asize = dsparb & 0x1ff; + bsize = (dsparb >> DSPARB_BEND_SHIFT) & 0x1ff; + } + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "FIFO size - A: %d, B: %d\n", + asize, bsize); + + /* Two extra entries for padding */ + awm = asize - (planea_entries + 2); + bwm = bsize - (planeb_entries + 2); + + /* Sanity check against potentially bad FIFO allocations */ + if (planea_entries <= 0) { + /* pipe is on but has too few FIFO entries */ + if (planea_entries != 0) + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, + "plane A needs more FIFO entries\n"); + awm = 1; + } + if (planeb_entries <= 0) { + if (planeb_entries != 0) + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, + "plane B needs more FIFO entries\n"); + bwm = 1; + } + + /* + * Overlay gets an aggressive default since video jitter is bad. + */ + cwm = 2; + if (sr_entries < fifo_entries) + srwm = fifo_entries - sr_entries; + + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "Setting FIFO watermarks - A: %d, B: %d, C: %d, SR %d\n", + awm, bwm, cwm, srwm); + + fwater_lo = fwater_lo | ((bwm & 0x1f) << 16) | (awm & 0x1f); + fwater_hi = fwater_hi | (cwm & 0x1f); + + OUTREG(FWATER_BLC, fwater_lo); + OUTREG(FWATER_BLC2, fwater_hi); + if (IS_I9XX(pI830)) + OUTREG(FWATER_BLC_SELF, srwm); + } else { + uint32_t fwater_lo = INREG(FWATER_BLC) & MM_FIFO_WATERMARK; + unsigned int asize, awm; + + asize = dsparb & 0x7f; + + awm = asize - planea_entries; + + fwater_lo = fwater_lo | awm; + + OUTREG(FWATER_BLC, fwater_lo); + } } /** @@ -1889,7 +1991,7 @@ i830_crtc_mode_set(xf86CrtcPtr crtc, DisplayModePtr mode, usleep(150); if (!DSPARB_HWCONTROL(pI830)) - i830_update_dsparb(pScrn); + i830_update_watermarks(pScrn); OUTREG(htot_reg, (adjusted_mode->CrtcHDisplay - 1) | ((adjusted_mode->CrtcHTotal - 1) << 16)); diff --git a/src/i830_driver.c b/src/i830_driver.c index d7ee615..7093e5e 100644 --- a/src/i830_driver.c +++ b/src/i830_driver.c @@ -846,11 +846,12 @@ i830_update_front_offset(ScrnInfoPtr pScrn) if (drm_intel_gem_bo_map_gtt(bo)) xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "%s: bo map failed\n", __FUNCTION__); + data = bo->virtual; } else { /* Will already be pinned by bind_all_memory in this case */ drm_intel_gem_bo_start_gtt_access(bo, 1); + data = pI830->FbBase + bo->offset; } - data = bo->virtual; } } if (!pScreen->ModifyPixmapHeader(pScreen->GetScreenPixmap(pScreen), @@ -2162,6 +2163,14 @@ SaveHWState(ScrnInfoPtr pScrn) if (!DSPARB_HWCONTROL(pI830)) pI830->saveDSPARB = INREG(DSPARB); + if (IS_I965G(pI830)) { + pI830->saveDSPFW1 = INREG(DSPFW1); + pI830->saveDSPFW2 = INREG(DSPFW2); + } else { + pI830->saveFWATER_BLC = INREG(FWATER_BLC); + pI830->saveFWATER_BLC2 = INREG(FWATER_BLC2); + } + pI830->saveDSPACNTR = INREG(DSPACNTR); pI830->savePIPEACONF = INREG(PIPEACONF); pI830->savePIPEASRC = INREG(PIPEASRC); @@ -2306,6 +2315,14 @@ RestoreHWState(ScrnInfoPtr pScrn) if (!DSPARB_HWCONTROL(pI830)) OUTREG(DSPARB, pI830->saveDSPARB); + if (IS_I965G(pI830)) { + OUTREG(DSPFW1, pI830->saveDSPFW1); + OUTREG(DSPFW2, pI830->saveDSPFW2); + } else { + OUTREG(FWATER_BLC, pI830->saveFWATER_BLC); + OUTREG(FWATER_BLC2, pI830->saveFWATER_BLC2); + } + OUTREG(DSPCLK_GATE_D, pI830->saveDSPCLK_GATE_D); OUTREG(RENCLK_GATE_D1, pI830->saveRENCLK_GATE_D1); diff --git a/src/i830_exa.c b/src/i830_exa.c index fc4e66c..39011bc 100644 --- a/src/i830_exa.c +++ b/src/i830_exa.c @@ -867,12 +867,13 @@ i830_uxa_prepare_access (PixmapPtr pixmap, uxa_access_t access) __FUNCTION__); return FALSE; } + pixmap->devPrivate.ptr = bo->virtual; } else { /* or not... */ if (drm_intel_bo_pin(bo, 4096) != 0) return FALSE; drm_intel_gem_bo_start_gtt_access(bo, access == UXA_ACCESS_RW); + pixmap->devPrivate.ptr = i830->FbBase + bo->offset; } - pixmap->devPrivate.ptr = bo->virtual; } return TRUE; }