From 8c1566e2d9cdcdaa94728516b8e6839545fc396c Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Tue, 29 Oct 2013 18:17:39 +0200 Subject: tools/intel_display_poller: Add a new tool that will poll various display registers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit intel_poller can be used to poll various display registers (IIR,scanline/pixel/flip/frame counter, live address, etc.). It can be used to determine eg. at which scanline or pixel count certain events occur. v2: s/intel_poller/intel_display_poller/ Signed-off-by: Ville Syrjälä --- tools/intel_display_poller.c | 1471 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1471 insertions(+) create mode 100644 tools/intel_display_poller.c (limited to 'tools/intel_display_poller.c') diff --git a/tools/intel_display_poller.c b/tools/intel_display_poller.c new file mode 100644 index 00000000..ebc594a0 --- /dev/null +++ b/tools/intel_display_poller.c @@ -0,0 +1,1471 @@ +/* + * Copyright © 2014 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, + * and/or sell copies of the Software, and to permit persons to whom the + * 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. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "intel_chipset.h" +#include "intel_io.h" +#include "igt_debugfs.h" +#include "drmtest.h" + +#define min(a,b) ((a) < (b) ? (a) : (b)) +#define max(a,b) ((a) > (b) ? (a) : (b)) + +enum test { + TEST_INVALID, + TEST_PIPESTAT, + TEST_IIR, + TEST_IIR_GEN2, + TEST_IIR_GEN3, + TEST_DEIIR, + TEST_FRAMECOUNT, + TEST_FRAMECOUNT_GEN3, + TEST_FRAMECOUNT_G4X, + TEST_FLIPCOUNT, + TEST_PAN, + TEST_FLIP, + TEST_SURFLIVE, + TEST_WRAP, + TEST_FIELD, +}; + +static uint32_t vlv_offset; + +static volatile bool quit; + +static void sighandler(int x) +{ + quit = true; +} + +static uint16_t read_reg_16(uint32_t reg) +{ + return *(volatile uint16_t *)((volatile char*)mmio + vlv_offset + reg); +} + +static uint32_t read_reg(uint32_t reg) +{ + return *(volatile uint32_t *)((volatile char*)mmio + vlv_offset + reg); +} + +static void write_reg_16(uint32_t reg, uint16_t val) +{ + *(volatile uint16_t *)((volatile char*)mmio + vlv_offset + reg) = val; +} + +static void write_reg(uint32_t reg, uint32_t val) +{ + *(volatile uint32_t *)((volatile char*)mmio + vlv_offset + reg) = val; +} + +static int pipe_to_plane(uint32_t devid, int pipe) +{ + if (!IS_GEN2(devid) && !IS_GEN3(devid)) + return pipe; + + switch (pipe) { + case 0: + if ((read_reg(DSPACNTR) & DISPPLANE_SEL_PIPE_MASK) == DISPPLANE_SEL_PIPE_B) + return 1; + return 0; + case 1: + if ((read_reg(DSPACNTR) & DISPPLANE_SEL_PIPE_MASK) == DISPPLANE_SEL_PIPE_A) + return 0; + return 1; + } + + assert(0); + + return 0; +} + +static uint32_t dspoffset_reg(uint32_t devid, int pipe) +{ + bool use_tileoff; + + pipe = pipe_to_plane(devid, pipe); + + if (IS_GEN2(devid) || IS_GEN3(devid)) + use_tileoff = false; + if (IS_HASWELL(devid) || IS_BROADWELL(devid)) + use_tileoff = true; + else { + switch (pipe) { + case 0: + use_tileoff = read_reg(DSPACNTR) & DISPLAY_PLANE_TILED; + break; + case 1: + use_tileoff = read_reg(DSPBCNTR) & DISPLAY_PLANE_TILED; + break; + case 2: + use_tileoff = read_reg(DSPCCNTR) & DISPLAY_PLANE_TILED; + break; + } + } + + if (use_tileoff) { + switch (pipe) { + case 0: + return DSPATILEOFF; + case 1: + return DSPBTILEOFF; + case 2: + return DSPCTILEOFF; + } + } else { + switch (pipe) { + case 0: + return DSPABASE; + case 1: + return DSPBBASE; + case 2: + return DSPCBASE; + } + } + + assert(0); + + return 0; +} + +static uint32_t dspsurf_reg(uint32_t devid, int pipe) +{ + pipe = pipe_to_plane(devid, pipe); + + if (IS_GEN2(devid) || IS_GEN3(devid)) { + switch (pipe) { + case 0: + return DSPABASE; + case 1: + return DSPBBASE; + case 2: + return DSPCBASE; + } + } else { + switch (pipe) { + case 0: + return DSPASURF; + case 1: + return DSPBSURF; + case 2: + return DSPCSURF; + } + } + + assert(0); + + return 0; +} + +static uint32_t dsl_reg(int pipe) +{ + switch (pipe) { + case 0: + return PIPEA_DSL; + case 1: + return PIPEB_DSL; + case 2: + return PIPEC_DSL; + } + + assert(0); + + return 0; +} + +static void poll_pixel_pipestat(int pipe, int bit, uint32_t *min, uint32_t *max, const int count) +{ + uint32_t pix, pix1, pix2, iir, iir1, iir2, iir_bit, iir_mask; + int i = 0; + + switch (pipe) { + case 0: + pix = PIPEAFRAMEPIXEL; + iir_bit = 1 << bit; + iir = PIPEASTAT; + break; + case 1: + pix = PIPEBFRAMEPIXEL; + iir_bit = 1 << bit; + iir = PIPEBSTAT; + break; + default: + return; + } + + iir_mask = read_reg(iir) & 0x7fff0000; + + write_reg(iir, iir_mask | iir_bit); + + while (!quit) { + pix1 = read_reg(pix); + iir1 = read_reg(iir); + iir2 = read_reg(iir); + pix2 = read_reg(pix); + + if (!(iir2 & iir_bit)) + continue; + + if (iir1 & iir_bit) { + write_reg(iir, iir_mask | iir_bit); + continue; + } + + pix1 &= PIPE_PIXEL_MASK; + pix2 &= PIPE_PIXEL_MASK; + + min[i] = pix1; + max[i] = pix2; + if (++i >= count) + break; + } +} + +static void poll_pixel_iir_gen3(int pipe, int bit, uint32_t *min, uint32_t *max, const int count) +{ + uint32_t pix, pix1, pix2, iir1, iir2, imr_save, ier_save; + int i = 0; + + bit = 1 << bit; + + switch (pipe) { + case 0: + pix = PIPEAFRAMEPIXEL; + break; + case 1: + pix = PIPEBFRAMEPIXEL; + break; + default: + return; + } + + imr_save = read_reg(IMR); + ier_save = read_reg(IER); + + write_reg(IER, ier_save & ~bit); + write_reg(IMR, imr_save & ~bit); + + write_reg(IIR, bit); + + while (!quit) { + pix1 = read_reg(pix); + iir1 = read_reg(IIR); + iir2 = read_reg(IIR); + pix2 = read_reg(pix); + + if (!(iir2 & bit)) + continue; + + write_reg(IIR, bit); + + if (iir1 & bit) + continue; + + pix1 &= PIPE_PIXEL_MASK; + pix2 &= PIPE_PIXEL_MASK; + + min[i] = pix1; + max[i] = pix2; + if (++i >= count) + break; + } + + write_reg(IMR, imr_save); + write_reg(IER, ier_save); +} + +static void poll_pixel_framecount_gen3(int pipe, uint32_t *min, uint32_t *max, const int count) +{ + uint32_t pix, pix1, pix2, frm1, frm2; + int i = 0; + + switch (pipe) { + case 0: + pix = PIPEAFRAMEPIXEL; + break; + case 1: + pix = PIPEBFRAMEPIXEL; + break; + default: + return; + } + + while (!quit) { + pix1 = read_reg(pix); + pix2 = read_reg(pix); + + frm1 = pix1 >> 24; + frm2 = pix2 >> 24; + + if (frm1 + 1 != frm2) + continue; + + pix1 &= PIPE_PIXEL_MASK; + pix2 &= PIPE_PIXEL_MASK; + + min[i] = pix1; + max[i] = pix2; + if (++i >= count) + break; + } +} + +static void poll_pixel_pan(uint32_t devid, int pipe, int target_pixel, int target_fuzz, + uint32_t *min, uint32_t *max, const int count) +{ + uint32_t pix, pix1 = 0, pix2 = 0; + uint32_t saved, surf = 0; + int i = 0; + + switch (pipe) { + case 0: + pix = PIPEAFRAMEPIXEL; + break; + case 1: + pix = PIPEBFRAMEPIXEL; + break; + default: + return; + } + + surf = dspoffset_reg(devid, pipe); + + saved = read_reg(surf); + + while (!quit) { + while (!quit){ + pix1 = read_reg(pix) & PIPE_PIXEL_MASK; + if (pix1 == target_pixel) + break; + } + + write_reg(surf, saved+256); + + while (!quit){ + pix2 = read_reg(pix) & PIPE_PIXEL_MASK; + if (pix2 >= target_pixel + target_fuzz) + break; + } + + write_reg(surf, saved); + + min[i] = pix1; + max[i] = pix2; + if (++i >= count) + break; + } + + write_reg(surf, saved); +} + +static void poll_pixel_flip(uint32_t devid, int pipe, int target_pixel, int target_fuzz, + uint32_t *min, uint32_t *max, const int count) +{ + uint32_t pix, pix1, pix2; + uint32_t saved, surf = 0; + int i = 0; + + switch (pipe) { + case 0: + pix = PIPEAFRAMEPIXEL; + case 1: + pix = PIPEBFRAMEPIXEL; + default: + return; + } + + surf = dspsurf_reg(devid, pipe); + + saved = read_reg(surf); + + while (!quit) { + while (!quit){ + pix1 = read_reg(pix) & PIPE_PIXEL_MASK; + if (pix1 == target_pixel) + break; + } + + write_reg(surf, saved+4096); + + while (!quit){ + pix2 = read_reg(pix) & PIPE_PIXEL_MASK; + if (pix2 >= target_pixel + target_fuzz) + break; + } + + write_reg(surf, saved); + + min[i] = pix1; + max[i] = pix2; + if (++i >= count) + break; + } + + write_reg(surf, saved); +} + +static void poll_pixel_wrap(int pipe, uint32_t *min, uint32_t *max, const int count) +{ + uint32_t pix, pix1, pix2; + int i = 0; + + switch (pipe) { + case 0: + pix = PIPEAFRAMEPIXEL; + break; + case 1: + pix = PIPEBFRAMEPIXEL; + break; + default: + return; + } + + while (!quit) { + pix1 = read_reg(pix); + pix2 = read_reg(pix); + + pix1 &= PIPE_PIXEL_MASK; + pix2 &= PIPE_PIXEL_MASK; + + if (pix2 >= pix1) + continue; + + min[i] = pix1; + max[i] = pix2; + if (++i >= count) + break; + } +} + +static void poll_dsl_pipestat(int pipe, int bit, + uint32_t *min, uint32_t *max, const int count) +{ + uint32_t dsl, dsl1, dsl2, iir, iir1, iir2, iir_bit, iir_mask; + bool field1, field2; + int i[2] = {}; + + switch (pipe) { + case 0: + iir_bit = 1 << bit; + iir = PIPEASTAT; + break; + case 1: + iir_bit = 1 << bit; + iir = PIPEBSTAT; + break; + default: + return; + } + + dsl = dsl_reg(pipe); + + iir_mask = read_reg(iir) & 0x7fff0000; + + write_reg(iir, iir_mask | iir_bit); + + while (!quit) { + dsl1 = read_reg(dsl); + iir1 = read_reg(iir); + iir2 = read_reg(iir); + dsl2 = read_reg(dsl); + + field1 = dsl1 & 0x80000000; + field2 = dsl2 & 0x80000000; + dsl1 &= ~0x80000000; + dsl2 &= ~0x80000000; + + if (!(iir2 & iir_bit)) + continue; + + if (iir1 & iir_bit) { + write_reg(iir, iir_mask | iir_bit); + continue; + } + + if (field1 != field2) + printf("fields are different (%u:%u -> %u:%u)\n", + field1, dsl1, field2, dsl2); + + min[field1*count+i[field1]] = dsl1; + max[field1*count+i[field1]] = dsl2; + if (++i[field1] >= count) + break; + } +} + +static void poll_dsl_iir_gen2(int pipe, int bit, + uint32_t *min, uint32_t *max, const int count) +{ + uint32_t dsl, dsl1, dsl2, iir1, iir2, imr_save, ier_save; + bool field1, field2; + int i[2] = {}; + + bit = 1 << bit; + + dsl = dsl_reg(pipe); + + imr_save = read_reg_16(IMR); + ier_save = read_reg_16(IER); + + write_reg_16(IER, ier_save & ~bit); + write_reg_16(IMR, imr_save & ~bit); + + write_reg_16(IIR, bit); + + while (!quit) { + dsl1 = read_reg(dsl); + iir1 = read_reg_16(IIR); + iir2 = read_reg_16(IIR); + dsl2 = read_reg(dsl); + + field1 = dsl1 & 0x80000000; + field2 = dsl2 & 0x80000000; + dsl1 &= ~0x80000000; + dsl2 &= ~0x80000000; + + if (!(iir2 & bit)) + continue; + + write_reg_16(IIR, bit); + + if (iir1 & bit) + continue; + + if (field1 != field2) + printf("fields are different (%u:%u -> %u:%u)\n", + field1, dsl1, field2, dsl2); + + min[field1*count+i[field1]] = dsl1; + max[field1*count+i[field1]] = dsl2; + if (++i[field1] >= count) + break; + } + + write_reg_16(IMR, imr_save); + write_reg_16(IER, ier_save); +} + +static void poll_dsl_iir_gen3(int pipe, int bit, + uint32_t *min, uint32_t *max, const int count) +{ + uint32_t dsl, dsl1, dsl2, iir1, iir2, imr_save, ier_save; + bool field1, field2; + int i[2] = {}; + + bit = 1 << bit; + + dsl = dsl_reg(pipe); + + imr_save = read_reg(IMR); + ier_save = read_reg(IER); + + write_reg(IER, ier_save & ~bit); + write_reg(IMR, imr_save & ~bit); + + write_reg(IIR, bit); + + while (!quit) { + dsl1 = read_reg(dsl); + iir1 = read_reg(IIR); + iir2 = read_reg(IIR); + dsl2 = read_reg(dsl); + + field1 = dsl1 & 0x80000000; + field2 = dsl2 & 0x80000000; + dsl1 &= ~0x80000000; + dsl2 &= ~0x80000000; + + if (!(iir2 & bit)) + continue; + + write_reg(IIR, bit); + + if (iir1 & bit) + continue; + + if (field1 != field2) + printf("fields are different (%u:%u -> %u:%u)\n", + field1, dsl1, field2, dsl2); + + min[field1*count+i[field1]] = dsl1; + max[field1*count+i[field1]] = dsl2; + if (++i[field1] >= count) + break; + } + + write_reg(IMR, imr_save); + write_reg(IER, ier_save); +} + +static void poll_dsl_deiir(uint32_t devid, int pipe, int bit, + uint32_t *min, uint32_t *max, const int count) +{ + uint32_t dsl, dsl1, dsl2, iir1, iir2, imr_save, ier_save; + bool field1, field2; + uint32_t iir, ier, imr; + int i[2] = {}; + + bit = 1 << bit; + + dsl = dsl_reg(pipe); + + if (IS_GEN8(devid)) { + iir = GEN8_DE_PIPE_IIR(pipe); + ier = GEN8_DE_PIPE_IER(pipe); + imr = GEN8_DE_PIPE_IMR(pipe); + } else { + iir = DEIIR; + ier = DEIER; + imr = DEIMR; + } + + imr_save = read_reg(imr); + ier_save = read_reg(ier); + + write_reg(ier, ier_save & ~bit); + write_reg(imr, imr_save & ~bit); + + write_reg(iir, bit); + + while (!quit) { + dsl1 = read_reg(dsl); + iir1 = read_reg(iir); + iir2 = read_reg(iir); + dsl2 = read_reg(dsl); + + field1 = dsl1 & 0x80000000; + field2 = dsl2 & 0x80000000; + dsl1 &= ~0x80000000; + dsl2 &= ~0x80000000; + + if (!(iir2 & bit)) + continue; + + write_reg(iir, bit); + + if (iir1 & bit) + continue; + + if (field1 != field2) + printf("fields are different (%u:%u -> %u:%u)\n", + field1, dsl1, field2, dsl2); + + min[field1*count+i[field1]] = dsl1; + max[field1*count+i[field1]] = dsl2; + if (++i[field1] >= count) + break; + } + + write_reg(imr, imr_save); + write_reg(ier, ier_save); +} + +static void poll_dsl_framecount_g4x(int pipe, uint32_t *min, uint32_t *max, const int count) +{ + uint32_t dsl, dsl1, dsl2, frm, frm1, frm2; + bool field1, field2; + int i[2] = {}; + + switch (pipe) { + case 0: + frm = PIPEAFRMCOUNT_G4X; + break; + case 1: + frm = PIPEBFRMCOUNT_G4X; + break; + case 2: + frm = PIPECFRMCOUNT_G4X; + break; + default: + return; + } + + dsl = dsl_reg(pipe); + + while (!quit) { + dsl1 = read_reg(dsl); + frm1 = read_reg(frm); + frm2 = read_reg(frm); + dsl2 = read_reg(dsl); + + field1 = dsl1 & 0x80000000; + field2 = dsl2 & 0x80000000; + dsl1 &= ~0x80000000; + dsl2 &= ~0x80000000; + + if (frm1 + 1 != frm2) + continue; + + if (field1 != field2) + printf("fields are different (%u:%u -> %u:%u)\n", + field1, dsl1, field2, dsl2); + + min[field1*count+i[field1]] = dsl1; + max[field1*count+i[field1]] = dsl2; + if (++i[field1] >= count) + break; + } +} + +static void poll_dsl_flipcount_g4x(uint32_t devid, int pipe, + uint32_t *min, uint32_t *max, const int count) +{ + uint32_t dsl, dsl1, dsl2, flp, flp1, flp2, surf; + bool field1, field2; + int i[2] = {}; + + switch (pipe) { + case 0: + flp = PIPEAFLIPCOUNT_G4X; + break; + case 1: + flp = PIPEBFLIPCOUNT_G4X; + break; + case 2: + flp = PIPECFLIPCOUNT_G4X; + break; + default: + return; + } + + dsl = dsl_reg(pipe); + surf = dspsurf_reg(devid, pipe); + + while (!quit) { + usleep(10); + dsl1 = read_reg(dsl); + flp1 = read_reg(flp); + dsl2 = read_reg(dsl); + + field1 = dsl1 & 0x80000000; + field2 = dsl2 & 0x80000000; + dsl1 &= ~0x80000000; + dsl2 &= ~0x80000000; + + if (field1 != field2) + printf("fields are different (%u:%u -> %u:%u)\n", + field1, dsl1, field2, dsl2); + + min[field1*count+i[field1]] = dsl1; + max[field1*count+i[field1]] = dsl2; + if (++i[field1] >= count) + return; + + write_reg(surf, read_reg(surf)); + + while (!quit) { + dsl1 = read_reg(dsl); + flp2 = read_reg(flp); + dsl2 = read_reg(dsl); + + field1 = dsl1 & 0x80000000; + field2 = dsl2 & 0x80000000; + dsl1 &= ~0x80000000; + dsl2 &= ~0x80000000; + + if (flp1 == flp2) + continue; + + if (field1 != field2) + printf("fields are different (%u:%u -> %u:%u)\n", + field1, dsl1, field2, dsl2); + + min[field1*count+i[field1]] = dsl1; + max[field1*count+i[field1]] = dsl2; + if (++i[field1] >= count) + break; + } + if (i[field1] >= count) + break; + } +} + +static void poll_dsl_framecount_gen3(int pipe, uint32_t *min, uint32_t *max, const int count) +{ + uint32_t dsl, dsl1, dsl2, frm, frm1, frm2; + bool field1, field2; + int i[2] = {}; + + switch (pipe) { + case 0: + frm = PIPEAFRAMEPIXEL; + break; + case 1: + frm = PIPEBFRAMEPIXEL; + break; + default: + return; + } + + dsl = dsl_reg(pipe); + + while (!quit) { + dsl1 = read_reg(dsl); + frm1 = read_reg(frm) >> 24; + frm2 = read_reg(frm) >> 24; + dsl2 = read_reg(dsl); + + field1 = dsl1 & 0x80000000; + field2 = dsl2 & 0x80000000; + dsl1 &= ~0x80000000; + dsl2 &= ~0x80000000; + + if (frm1 + 1 != frm2) + continue; + + if (field1 != field2) + printf("fields are different (%u:%u -> %u:%u)\n", + field1, dsl1, field2, dsl2); + + min[field1*count+i[field1]] = dsl1; + max[field1*count+i[field1]] = dsl2; + if (++i[field1] >= count) + break; + } +} + +static void poll_dsl_pan(uint32_t devid, int pipe, int target_scanline, int target_fuzz, + uint32_t *min, uint32_t *max, const int count) +{ + uint32_t dsl, dsl1 = 0, dsl2 = 0; + bool field1 = false, field2 = false; + uint32_t saved, surf = 0; + int i[2] = {}; + + dsl = dsl_reg(pipe); + surf = dspoffset_reg(devid, pipe); + + saved = read_reg(surf); + + while (!quit) { + while (!quit) { + dsl1 = read_reg(dsl); + field1 = dsl1 & 0x80000000; + dsl1 &= ~0x80000000; + if (dsl1 == target_scanline) + break; + } + + write_reg(surf, saved+256); + + while (!quit) { + dsl2 = read_reg(dsl); + field2 = dsl1 & 0x80000000; + dsl2 &= ~0x80000000; + if (dsl2 == target_scanline + target_fuzz) + break; + } + + write_reg(surf, saved); + + if (field1 != field2) + printf("fields are different (%u:%u -> %u:%u)\n", + field1, dsl1, field2, dsl2); + + min[field1*count+i[field1]] = dsl1; + max[field1*count+i[field1]] = dsl2; + if (++i[field1] >= count) + break; + } + + write_reg(surf, saved); +} + +static void poll_dsl_flip(uint32_t devid, int pipe, int target_scanline, int target_fuzz, + uint32_t *min, uint32_t *max, const int count) +{ + uint32_t dsl, dsl1 = 0, dsl2 = 0; + bool field1 = false, field2 = false; + uint32_t saved, surf = 0; + int i[2] = {}; + + dsl = dsl_reg(pipe); + surf = dspsurf_reg(devid, pipe); + + saved = read_reg(surf); + + while (!quit) { + while (!quit) { + dsl1 = read_reg(dsl); + field1 = dsl1 & 0x80000000; + dsl1 &= ~0x80000000; + if (dsl1 == target_scanline) + break; + } + + write_reg(surf, saved+4096); + + while (!quit) { + dsl2 = read_reg(dsl); + field2 = dsl1 & 0x80000000; + dsl2 &= ~0x80000000; + if (dsl2 == target_scanline + target_fuzz) + break; + } + + write_reg(surf, saved); + + if (field1 != field2) + printf("fields are different (%u:%u -> %u:%u)\n", + field1, dsl1, field2, dsl2); + + min[field1*count+i[field1]] = dsl1; + max[field1*count+i[field1]] = dsl2; + if (++i[field1] >= count) + break; + } + + write_reg(surf, saved); +} + +static void poll_dsl_surflive(uint32_t devid, int pipe, + uint32_t *min, uint32_t *max, const int count) +{ + uint32_t dsl, dsl1 = 0, dsl2 = 0, surf, surf1, surf2, surflive, surfl1 = 0, surfl2, saved, tmp; + bool field1 = false, field2 = false; + int i[2] = {}; + + switch (pipe) { + case 0: + surflive = DSPASURFLIVE; + break; + case 1: + surflive = DSPBSURFLIVE; + break; + case 2: + surflive = DSPCSURFLIVE; + break; + default: + return; + } + + dsl = dsl_reg(pipe); + surf = dspsurf_reg(devid, pipe); + + saved = read_reg(surf); + + surf1 = saved & ~0xfff; + surf2 = surf1 + 4096; + + while (!quit) { + write_reg(surf, surf2); + + while (!quit) { + dsl1 = read_reg(dsl); + surfl1 = read_reg(surflive) & ~0xfff; + surfl2 = read_reg(surflive) & ~0xfff; + dsl2 = read_reg(dsl); + + field1 = dsl1 & 0x80000000; + field2 = dsl2 & 0x80000000; + dsl1 &= ~0x80000000; + dsl2 &= ~0x80000000; + + if (surfl2 == surf2) + break; + } + + if (surfl1 != surf2) { + if (field1 != field2) + printf("fields are different (%u:%u -> %u:%u)\n", + field1, dsl1, field2, dsl2); + + min[field1*count+i[field1]] = dsl1; + max[field1*count+i[field1]] = dsl2; + if (++i[field1] >= count) + break; + } + + tmp = surf1; + surf1 = surf2; + surf2 = tmp; + } + + write_reg(surf, saved); +} + +static void poll_dsl_wrap(int pipe, uint32_t *min, uint32_t *max, const int count) +{ + uint32_t dsl, dsl1, dsl2; + bool field1, field2; + int i[2] = {}; + + dsl = dsl_reg(pipe); + + while (!quit) { + dsl1 = read_reg(dsl); + dsl2 = read_reg(dsl); + + field1 = dsl1 & 0x80000000; + field2 = dsl2 & 0x80000000; + dsl1 &= ~0x80000000; + dsl2 &= ~0x80000000; + + if (dsl2 >= dsl1) + continue; + + if (field1 != field2) + printf("fields are different (%u:%u -> %u:%u)\n", + field1, dsl1, field2, dsl2); + + min[field1*count+i[field1]] = dsl1; + max[field1*count+i[field1]] = dsl2; + if (++i[field1] >= count) + break; + } +} + +static void poll_dsl_field(int pipe, uint32_t *min, uint32_t *max, const int count) +{ + uint32_t dsl, dsl1, dsl2; + bool field1, field2; + int i[2] = {}; + + dsl = dsl_reg(pipe); + + while (!quit) { + dsl1 = read_reg(dsl); + dsl2 = read_reg(dsl); + + field1 = dsl1 & 0x80000000; + field2 = dsl2 & 0x80000000; + dsl1 &= ~0x80000000; + dsl2 &= ~0x80000000; + + if (field1 == field2) + continue; + + min[field1*count+i[field1]] = dsl1; + max[field1*count+i[field1]] = dsl2; + if (++i[field1] >= count) + break; + } +} + +static char pipe_name(int pipe) +{ + return pipe + 'A'; +} + +static const char *test_name(enum test test, int pipe, int bit, bool test_pixel_count) +{ + static char str[32]; + const char *type = test_pixel_count ? "pixel" : "dsl"; + + switch (test) { + case TEST_PIPESTAT: + snprintf(str, sizeof str, "%s / pipe %c / PIPESTAT[%d] (gmch)", type, pipe_name(pipe), bit); + return str; + case TEST_IIR_GEN2: + snprintf(str, sizeof str, "%s / pipe %c / IIR[%d] (gen2)", type, pipe_name(pipe), bit); + return str; + case TEST_IIR_GEN3: + snprintf(str, sizeof str, "%s / pipe %c / IIR[%d] (gen3+)", type, pipe_name(pipe), bit); + return str; + case TEST_DEIIR: + snprintf(str, sizeof str, "%s / pipe %c / DEIIR[%d] (pch)", type, pipe_name(pipe), bit); + return str; + case TEST_FRAMECOUNT_GEN3: + snprintf(str, sizeof str, "%s / pipe %c / Frame count (gen3/4)", type, pipe_name(pipe)); + return str; + case TEST_FRAMECOUNT_G4X: + snprintf(str, sizeof str, "%s / pipe %c / Frame count (g4x+)", type, pipe_name(pipe)); + return str; + case TEST_FLIPCOUNT: + snprintf(str, sizeof str, "%s / pipe %c / Flip count (g4x+)", type, pipe_name(pipe)); + return str; + case TEST_PAN: + snprintf(str, sizeof str, "%s / pipe %c / Pan", type, pipe_name(pipe)); + return str; + case TEST_FLIP: + snprintf(str, sizeof str, "%s / pipe %c / Flip", type, pipe_name(pipe)); + return str; + case TEST_SURFLIVE: + snprintf(str, sizeof str, "%s / pipe %c / Surflive", type, pipe_name(pipe)); + return str; + case TEST_WRAP: + snprintf(str, sizeof str, "%s / pipe %c / Wrap", type, pipe_name(pipe)); + return str; + case TEST_FIELD: + snprintf(str, sizeof str, "%s / pipe %c / Field", type, pipe_name(pipe)); + return str; + default: + return ""; + } +} + +static void usage(const char *name) +{ + fprintf(stderr, "Usage: %s [options]\n" + " -t,--test \n" + " -p,--pipe \n" + " -b,--bit \n" + " -l,--line \n" + " -f,--fuzz \n" + " -x,--pixel\n", + name); + exit(1); +} + +int main(int argc, char *argv[]) +{ + int fd, i; + int pipe = 0, bit = 0, target_scanline = 0, target_fuzz = 1; + bool test_pixelcount = false; + uint32_t devid; + uint32_t min[2*128] = {}; + uint32_t max[2*128] = {}; + uint32_t a, b; + enum test test = TEST_INVALID; + const int count = ARRAY_SIZE(min)/2; + + for (;;) { + static const struct option long_options[] = { + { .name = "test", .has_arg = required_argument, }, + { .name = "pipe", .has_arg = required_argument, }, + { .name = "bit", .has_arg = required_argument, }, + { .name = "line", .has_arg = required_argument, }, + { .name = "fuzz", .has_arg = required_argument, }, + { .name = "pixel", .has_arg = no_argument, }, + { }, + }; + + int opt = getopt_long(argc, argv, "t:p:b:l:f:x", long_options, NULL); + if (opt == -1) + break; + + switch (opt) { + case 't': + if (!strcmp(optarg, "pipestat")) + test = TEST_PIPESTAT; + else if (!strcmp(optarg, "iir")) + test = TEST_IIR; + else if (!strcmp(optarg, "framecount")) + test = TEST_FRAMECOUNT; + else if (!strcmp(optarg, "flipcount")) + test = TEST_FLIPCOUNT; + else if (!strcmp(optarg, "pan")) + test = TEST_PAN; + else if (!strcmp(optarg, "flip")) + test = TEST_FLIP; + else if (!strcmp(optarg, "surflive")) + test = TEST_SURFLIVE; + else if (!strcmp(optarg, "wrap")) + test = TEST_WRAP; + else if (!strcmp(optarg, "field")) + test = TEST_FIELD; + else + usage(argv[0]); + break; + case 'p': + pipe = atoi(optarg); + if (pipe < 0 || pipe > 2) + usage(argv[0]); + break; + case 'b': + bit = atoi(optarg); + if (bit < 0 || bit > 31) + usage(argv[0]); + break; + case 'l': + target_scanline = atoi(optarg); + if (target_scanline < 0) + usage(argv[0]); + break; + case 'f': + target_fuzz = atoi(optarg); + if (target_fuzz <= 0) + usage(argv[0]); + break; + case 'x': + test_pixelcount = true; + break; + } + } + + fd = drm_open_any(); + devid = intel_get_drm_devid(fd); + close(fd); + + /* + * check if the requires registers are + * avilable on the current platform. + */ + if (IS_GEN2(devid)) { + if (pipe > 1) + usage(argv[0]); + + if (test_pixelcount) + usage(argv[0]); + + switch (test) { + case TEST_IIR: + test = TEST_IIR_GEN2; + break; + case TEST_PIPESTAT: + case TEST_PAN: + break; + case TEST_FLIP: + test = TEST_PAN; + break; + default: + usage(argv[0]); + } + } else if (IS_GEN3(devid) || + (IS_GEN4(devid) && !IS_G4X(devid))) { + if (pipe > 1) + usage(argv[0]); + + switch (test) { + case TEST_IIR: + test = TEST_IIR_GEN3; + break; + case TEST_FRAMECOUNT: + test = TEST_FRAMECOUNT_GEN3; + break; + case TEST_PIPESTAT: + case TEST_PAN: + case TEST_WRAP: + case TEST_FIELD: + break; + case TEST_FLIP: + if (IS_GEN3(devid)) + test = TEST_PAN; + break; + default: + usage(argv[0]); + } + } else if (IS_G4X(devid) || IS_VALLEYVIEW(devid)) { + if (IS_VALLEYVIEW(devid)) + vlv_offset = 0x180000; + + if (pipe > 1) + usage(argv[0]); + + if (test_pixelcount) + usage(argv[0]); + + switch (test) { + case TEST_IIR: + test = TEST_IIR_GEN3; + break; + case TEST_FRAMECOUNT: + test = TEST_FRAMECOUNT_G4X; + break; + case TEST_FLIPCOUNT: + case TEST_PIPESTAT: + case TEST_PAN: + case TEST_FLIP: + case TEST_SURFLIVE: + case TEST_WRAP: + case TEST_FIELD: + break; + default: + usage(argv[0]); + } + } else if (HAS_PCH_SPLIT(devid) && + (IS_GEN5(devid) || IS_GEN6(devid) || IS_GEN7(devid))) { + if (pipe > 1 && + (IS_GEN5(devid) || IS_GEN6(devid))) + usage(argv[0]); + + if (test_pixelcount) + usage(argv[0]); + + switch (test) { + case TEST_IIR: + test = TEST_DEIIR; + break; + case TEST_FRAMECOUNT: + test = TEST_FRAMECOUNT_G4X; + break; + case TEST_FLIPCOUNT: + case TEST_PAN: + case TEST_FLIP: + case TEST_SURFLIVE: + case TEST_WRAP: + case TEST_FIELD: + break; + default: + usage(argv[0]); + } + } else if (IS_GEN8(devid)) { + if (test_pixelcount) + usage(argv[0]); + + switch (test) { + case TEST_IIR: + test = TEST_DEIIR; + break; + case TEST_FRAMECOUNT: + test = TEST_FRAMECOUNT_G4X; + break; + case TEST_FLIPCOUNT: + case TEST_PAN: + case TEST_FLIP: + case TEST_SURFLIVE: + case TEST_WRAP: + case TEST_FIELD: + break; + default: + usage(argv[0]); + } + } else { + usage(argv[0]); + } + + switch (test) { + case TEST_IIR: + case TEST_FRAMECOUNT: + /* should no longer have the generic tests here */ + assert(0); + default: + break; + } + + intel_register_access_init(intel_get_pci_device(), 0); + + printf("%s?\n", test_name(test, pipe, bit, test_pixelcount)); + + signal(SIGHUP, sighandler); + signal(SIGINT, sighandler); + signal(SIGTERM, sighandler); + + switch (test) { + case TEST_PIPESTAT: + if (test_pixelcount) + poll_pixel_pipestat(pipe, bit, min, max, count); + else + poll_dsl_pipestat(pipe, bit, min, max, count); + break; + case TEST_IIR_GEN2: + assert(!test_pixelcount); + poll_dsl_iir_gen2(pipe, bit, min, max, count); + break; + case TEST_IIR_GEN3: + if (test_pixelcount) + poll_pixel_iir_gen3(pipe, bit, min, max, count); + else + poll_dsl_iir_gen3(pipe, bit, min, max, count); + break; + case TEST_DEIIR: + assert(!test_pixelcount); + poll_dsl_deiir(devid, pipe, bit, min, max, count); + break; + case TEST_FRAMECOUNT_GEN3: + if (test_pixelcount) + poll_pixel_framecount_gen3(pipe, min, max, count); + else + poll_dsl_framecount_gen3(pipe, min, max, count); + break; + case TEST_FRAMECOUNT_G4X: + assert(!test_pixelcount); + poll_dsl_framecount_g4x(pipe, min, max, count); + break; + case TEST_FLIPCOUNT: + assert(!test_pixelcount); + poll_dsl_flipcount_g4x(devid, pipe, min, max, count); + break; + case TEST_PAN: + if (test_pixelcount) + poll_pixel_pan(devid, pipe, target_scanline, target_fuzz, + min, max, count); + else + poll_dsl_pan(devid, pipe, target_scanline, target_fuzz, + min, max, count); + break; + case TEST_FLIP: + if (test_pixelcount) + poll_pixel_flip(devid, pipe, target_scanline, target_fuzz, + min, max, count); + else + poll_dsl_flip(devid, pipe, target_scanline, target_fuzz, + min, max, count); + break; + case TEST_SURFLIVE: + poll_dsl_surflive(devid, pipe, min, max, count); + break; + case TEST_WRAP: + if (test_pixelcount) + poll_pixel_wrap(pipe, min, max, count); + else + poll_dsl_wrap(pipe, min, max, count); + break; + case TEST_FIELD: + poll_dsl_field(pipe, min, max, count); + break; + default: + assert(0); + } + + intel_register_access_fini(); + + if (quit) + return 0; + + for (i = 0; i < count; i++) { + if (min[0*count+i] == 0 && max[0*count+i] == 0) + break; + printf("[%u] %4u - %4u (%4u)\n", 0, min[0*count+i], max[0*count+i], + (min[0*count+i] + max[0*count+i] + 1) >> 1); + } + for (i = 0; i < count; i++) { + if (min[1*count+i] == 0 && max[1*count+i] == 0) + break; + printf("[%u] %4u - %4u (%4u)\n", 1, min[1*count+i], max[1*count+i], + (min[1*count+i] + max[1*count+i] + 1) >> 1); + } + + a = 0; + b = 0xffffffff; + for (i = 0; i < count; i++) { + if (min[0*count+i] == 0 && max[0*count+i] == 0) + break; + a = max(a, min[0*count+i]); + b = min(b, max[0*count+i]); + } + + printf("%s: [%u] %6u - %6u\n", test_name(test, pipe, bit, test_pixelcount), 0, a, b); + + a = 0; + b = 0xffffffff; + for (i = 0; i < count; i++) { + if (min[1*count+i] == 0 && max[1*count+i] == 0) + break; + a = max(a, min[1*count+i]); + b = min(b, max[1*count+i]); + } + + printf("%s: [%u] %6u - %6u\n", test_name(test, pipe, bit, test_pixelcount), 1, a, b); + + return 0; +} -- cgit v1.2.3