[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