[igt-dev] [PATCH i-g-t 3/6] HACK: tools/intel_scaler_coef: Test ilk/snb/ivb panel fitter programmable coefficients
Ville Syrjala
ville.syrjala at linux.intel.com
Tue Mar 10 14:18:27 UTC 2020
From: Ville Syrjälä <ville.syrjala at linux.intel.com>
ilk/snb/ivb panel fitters (only pf0 on ivb) have programmable
coefficients. Add some code to figure out how they work.
Signed-off-by: Ville Syrjälä <ville.syrjala at linux.intel.com>
---
tools/intel_scaler_coef.c | 262 +++++++++++++++++++++++++++++++++++++-
1 file changed, 260 insertions(+), 2 deletions(-)
diff --git a/tools/intel_scaler_coef.c b/tools/intel_scaler_coef.c
index a85af924fb6b..8565261099d0 100644
--- a/tools/intel_scaler_coef.c
+++ b/tools/intel_scaler_coef.c
@@ -35,6 +35,9 @@
#include "igt_aux.h"
#include "drmtest.h"
+#include "intel_io.h"
+#include "intel_chipset.h"
+
struct filter;
/*
@@ -432,7 +435,6 @@ static int hwtap_to_tap(const struct filter *f, int _t)
return -1;
}
-#if 0
static int tap_to_hwtap(const struct filter *f, int t)
{
if (!f->config.hwtaps)
@@ -440,7 +442,6 @@ static int tap_to_hwtap(const struct filter *f, int t)
return f->config.hwtaps[t];
}
-#endif
static const int ilk_pf_vert_3tap_hwtaps[] = { 0, 2, 4 };
static const int cnl_ps_hwtaps[] = { 6, 5, 4, 3, 2, 1, 0 };
@@ -949,6 +950,260 @@ static void usage(FILE *stream, const char *name)
fprintf(stream, "%s%c", filter_modes[i], i == MODE_INVALID - 1 ? '\n' : ',');
}
+struct rect {
+ int x, y, w, h;
+};
+
+#define _PIPE_REG(reg_a, pipe) ((reg_a) + (pipe) * 0x1000)
+#define HTOTAL(pipe) _PIPE_REG(0x60000, (pipe))
+#define VTOTAL(pipe) _PIPE_REG(0x6000c, (pipe))
+#define PIPECONF(pipe) _PIPE_REG(0x70008, (pipe))
+#define PIPECONF_ENABLE (1 << 31)
+#define PIPESRC(pipe) _PIPE_REG(0x6001C, (pipe))
+
+#define _PF_REG(reg_0, pf) ((reg_0) + (pf) * 0x800)
+#define PF_CTRL(pf) _PF_REG(0x68080, (pf)) /* aka. PF_CTRL1 */
+#define PF_ENABLE (1 << 31)
+#define PF_PIPE(pipe) ((pipe) << 29) /* ivb */
+#define PF_FILTER_PROG (0 << 23)
+#define PF_FILTER_MED (1 << 23)
+#define PF_FILTER_EDGE_ENH (2 << 23)
+#define PF_FILTER_EDGE_SOFT (3 << 23)
+#define PF_WIN_POS(pf) _PF_REG(0x68070, (pf))
+#define PF_WIN_SZ(pf) _PF_REG(0x68074, (pf))
+#define PF_HSCALE(pf) _PF_REG(0x68084, (pf)) /* aka. PF_CTRL2 */
+#define PF_VSCALE(pf) _PF_REG(0x68090, (pf)) /* aka. PF_CTRL4 */
+
+/* ilk/snb: both panel fitters */
+#define PF_HFILTL_COEF(pf, i) (_PF_REG(0x68100, (pf)) + 4 * (i))
+#define PF_HFILTC_COEF(pf, i) (_PF_REG(0x68200, (pf)) + 4 * (i))
+#define PF_VFILTL_COEF(pf, i) (_PF_REG(0x68300, (pf)) + 4 * (i))
+#define PF_VFILTC_COEF(pf, i) (_PF_REG(0x68400, (pf)) + 4 * (i))
+
+/* ivb: only pf0 (7x5 capable) */
+#define PF_HCOEF_INDEX 0x680a0
+#define PF_VCOEF_INDEX 0x680b0
+#define PF_COEF_AUTO_INCREMENT (1 << 15)
+#define PF_HCOEF_DATA 0x680a4
+#define PF_VCOEF_DATA 0x680b4
+
+static uint32_t I915_READ(uint32_t reg)
+{
+ uint32_t tmp = INREG(reg);
+ printf("0x%x = 0x%x\n", reg, tmp);
+ return tmp;
+}
+
+static void I915_WRITE(uint32_t reg, uint32_t value)
+{
+ OUTREG(reg, value);
+}
+
+static int ilk_coef_index(const struct filter *f, int p, int t)
+{
+ assert(f->config.nphases/2+1 == 17);
+ assert(f->config.ntaps == 7 ||
+ f->config.ntaps == 5 ||
+ f->config.ntaps == 3);
+
+ return nhwtaps(f) * p + tap_to_hwtap(f, t);
+}
+
+static void ilk_horz_coefs(struct filter *f, uint16_t hcoef[])
+{
+ f->config = configs[FORMAT_ILK_PF_HORZ];
+
+ generate_filter(f);
+ print_filter(f);
+ hw_print_filter(f);
+ update_filter(f);
+ print_filter(f);
+ hw_print_filter(f);
+ fixup_filter(f);
+ printf("ilk pf horz\n");
+ print_filter(f);
+ hw_print_filter(f);
+ print_c_filter(f);
+
+ for (int p = 0; p < f->config.nphases/2+1; p++) {
+ const double *coefs = f->phases[p].coefs;
+
+ for (int t = 0; t < f->config.ntaps; t++) {
+ union gen2_coef_reg r;
+ int i = ilk_coef_index(f, p, t);
+
+ gen2_coef_to_reg(f, t, coefs[t], &r);
+
+ hcoef[i] = r.reg;
+ }
+ }
+}
+
+static void ilk_vert_coefs(struct filter *f, uint16_t vcoef[], int src_w)
+{
+ /*
+ * The pfit automagically switches to three
+ * line mode when the source width is too big.
+ */
+ if (src_w > 2048)
+ f->config = configs[FORMAT_ILK_PF_VERT_3TAP];
+ else
+ f->config = configs[FORMAT_ILK_PF_VERT_5TAP];
+
+ generate_filter(f);
+ print_filter(f);
+ hw_print_filter(f);
+ update_filter(f);
+ print_filter(f);
+ hw_print_filter(f);
+ fixup_filter(f);
+ printf("ilk pf vert\n");
+ print_filter(f);
+ hw_print_filter(f);
+ print_c_filter(f);
+
+ for (int p = 0; p < f->config.nphases/2+1; p++) {
+ const double *coefs = f->phases[p].coefs;
+
+ for (int t = 0; t < f->config.ntaps; t++) {
+ union gen2_coef_reg r;
+ int i = ilk_coef_index(f, p, t);
+
+ gen2_coef_to_reg(f, t, coefs[t], &r);
+
+ vcoef[i] = r.reg;
+ }
+ }
+}
+
+static void ilk_program_hcoefs(int pf, const uint16_t hcoef[])
+{
+ for (int i = 0; i < 7 * 17; i += 2) {
+ uint32_t tmp = hcoef[i+1] << 16 | hcoef[i];
+
+ I915_WRITE(PF_HFILTL_COEF(pf, i/2), tmp);
+ I915_WRITE(PF_HFILTC_COEF(pf, i/2), tmp);
+ }
+}
+
+static void ilk_program_vcoefs(int pf, const uint16_t vcoef[])
+{
+ for (int i = 0; i < 5 * 17; i += 2) {
+ uint32_t tmp = vcoef[i+1] << 16 | vcoef[i];
+
+ I915_WRITE(PF_VFILTL_COEF(pf, i/2), tmp);
+ I915_WRITE(PF_VFILTC_COEF(pf, i/2), tmp);
+ }
+}
+
+static void ivb_program_hcoefs(const uint16_t hcoef[])
+{
+ I915_WRITE(PF_HCOEF_INDEX, PF_COEF_AUTO_INCREMENT);
+
+ /* twice for luma/R + chroma/G/B */
+ for (int j = 0; j < 2; j++) {
+ for (int i = 0; i < 7 * 17; i += 2) {
+ uint32_t tmp = hcoef[i+1] << 16 | hcoef[i];
+
+ I915_WRITE(PF_HCOEF_DATA, tmp);
+ }
+ }
+
+ I915_WRITE(PF_HCOEF_INDEX, 0);
+}
+
+static void ivb_program_vcoefs(const uint16_t vcoef[])
+{
+ I915_WRITE(PF_VCOEF_INDEX, PF_COEF_AUTO_INCREMENT);
+
+ /* twice for luma/R + chroma/G/B */
+ for (int j = 0; j < 2; j++) {
+ for (int i = 0; i < 5 * 17; i += 2) {
+ uint32_t tmp = vcoef[i+1] << 16 | vcoef[i];
+
+ I915_WRITE(PF_VCOEF_DATA, tmp);
+ }
+ }
+
+ I915_WRITE(PF_VCOEF_INDEX, 0);
+}
+
+static void ilk_program(struct filter *f, int pipe)
+{
+ struct intel_mmio_data mmio_data;
+ struct rect src = {};
+ struct rect dst = {};
+ uint16_t hcoef[7*17+1] = {};
+ uint16_t vcoef[5*17+1] = {};
+ uint32_t devid;
+ bool is_ivb;
+ int pf;
+
+ devid = intel_get_pci_device()->device_id;
+
+ if (!IS_IVYBRIDGE(devid) && !IS_GEN6(devid) && !IS_GEN5(devid))
+ return;
+
+ is_ivb = IS_IVYBRIDGE(devid);
+
+ intel_register_access_init(&mmio_data, intel_get_pci_device(), 0, -1);
+
+ if (!(I915_READ(PIPECONF(pipe)) & PIPECONF_ENABLE))
+ goto out;
+
+ /* On IVB only PF0 has programmable coefficients */
+ pf = is_ivb ? 0 : pipe;
+
+ dst.w = (I915_READ(HTOTAL(pipe)) & 0xffff) + 1;
+ dst.h = (I915_READ(VTOTAL(pipe)) & 0xffff) + 1;
+
+ dst.x = 64;
+ dst.y = 16;
+ dst.w -= 128;
+ dst.h -= 32;
+
+ src.w = ((I915_READ(PIPESRC(pipe)) >> 16) & 0xffff) + 1;
+ src.h = (I915_READ(PIPESRC(pipe)) & 0xffff) + 1;
+
+ ilk_horz_coefs(f, hcoef);
+ ilk_vert_coefs(f, vcoef, src.w);
+
+ if (is_ivb) {
+ ivb_program_hcoefs(hcoef);
+ ivb_program_vcoefs(vcoef);
+ } else {
+ ilk_program_hcoefs(pf, hcoef);
+ ilk_program_vcoefs(pf, vcoef);
+ }
+
+ I915_WRITE(PF_CTRL(pf),
+ PF_ENABLE |
+ (is_ivb ? PF_PIPE(pipe) : 0) |
+ PF_FILTER_PROG);
+
+ I915_WRITE(PF_WIN_POS(pf), dst.x << 16 | dst.y);
+ I915_WRITE(PF_WIN_SZ(pf), dst.w << 16 | dst.h);
+
+ printf("%dx%d%+d%+d -> %dx%d%+d%+d\n",
+ src.w, src.h, src.x, src.y,
+ dst.w, dst.h, dst.x, dst.y);
+ printf("sw: hscale 0x%x, vscale 0x%x\n",
+ (((src.w << 16) + 1) / dst.w) >> 1,
+ (((src.h << 16) + 1) / dst.h) >> 1);
+ printf("hw: hscale 0x%x, vscale 0x%x\n",
+ I915_READ(PF_HSCALE(pf)),
+ I915_READ(PF_VSCALE(pf)));
+
+ sleep(2);
+
+ I915_WRITE(PF_CTRL(pf), 0);
+ I915_WRITE(PF_WIN_POS(pf), 0);
+ I915_WRITE(PF_WIN_SZ(pf), 0);
+
+ out:
+ intel_register_access_fini(&mmio_data);
+}
+
int main(int argc, char *argv[])
{
const struct option opts[] = {
@@ -1109,5 +1364,8 @@ int main(int argc, char *argv[])
print_c_filter(&f);
+ if (1)
+ ilk_program(&f, 0);
+
return 0;
}
--
2.24.1
More information about the igt-dev
mailing list