All of lore.kernel.org
 help / color / mirror / Atom feed
From: Liviu Dudau <Liviu.Dudau@arm.com>
To: Brian Starkey <brian.starkey@arm.com>
Cc: Mihail Atanassov <mihail.atanassov@arm.com>,
	Mali DP Maintainers <malidp@foss.arm.com>,
	DRI devel <dri-devel@lists.freedesktop.org>
Subject: [PATCH 10/12] drm: mali-dp: Add plane upscaling support
Date: Fri, 21 Apr 2017 10:18:46 +0100	[thread overview]
Message-ID: <20170421091848.4666-11-Liviu.Dudau@arm.com> (raw)
In-Reply-To: <20170421091848.4666-1-Liviu.Dudau@arm.com>

From: Mihail Atanassov <mihail.atanassov@arm.com>

Enable the scaling engine for upscaling a single plane using the polyphase
scaler. No image enhancement support or downscaling yet*, and composition
result scaling is not implemented.

* Downscaling a plane requires mclk > pxlclk.

Signed-off-by: Mihail Atanassov <mihail.atanassov@arm.com>
Signed-off-by: Liviu Dudau <Liviu.Dudau@arm.com>
---
 drivers/gpu/drm/arm/malidp_crtc.c   |  80 +++++++++++++++++++++
 drivers/gpu/drm/arm/malidp_drv.c    |  47 ++++++++++++
 drivers/gpu/drm/arm/malidp_drv.h    |   3 +
 drivers/gpu/drm/arm/malidp_hw.c     | 140 ++++++++++++++++++++++++++++++++++++
 drivers/gpu/drm/arm/malidp_hw.h     |  45 ++++++++++++
 drivers/gpu/drm/arm/malidp_planes.c |  75 ++++++++++++++-----
 drivers/gpu/drm/arm/malidp_regs.h   |  36 ++++++++++
 7 files changed, 409 insertions(+), 17 deletions(-)

diff --git a/drivers/gpu/drm/arm/malidp_crtc.c b/drivers/gpu/drm/arm/malidp_crtc.c
index 8f2e1ae51ba0..ceee2a77bfb4 100644
--- a/drivers/gpu/drm/arm/malidp_crtc.c
+++ b/drivers/gpu/drm/arm/malidp_crtc.c
@@ -247,6 +247,82 @@ static int malidp_crtc_atomic_check_ctm(struct drm_crtc *crtc,
 	return 0;
 }
 
+static int malidp_crtc_atomic_check_scaling(struct drm_crtc *crtc,
+					    struct drm_crtc_state *state)
+{
+	struct malidp_crtc_state *cs = to_malidp_crtc_state(state);
+	struct malidp_se_config *s = &cs->scaler_config;
+	struct drm_plane *plane;
+	const struct drm_plane_state *pstate;
+	u32 h_upscale_factor = 0; /* U16.16 */
+	u32 v_upscale_factor = 0; /* U16.16 */
+	u8 scaling = cs->scaled_planes_mask;
+
+	if (!scaling) {
+		s->scale_enable = false;
+		return 0;
+	}
+
+	/* The scaling engine can only handle one plane at a time. */
+	if (scaling & (scaling - 1))
+		return -EINVAL;
+
+	drm_atomic_crtc_state_for_each_plane_state(plane, pstate, state) {
+		struct malidp_plane *mp = to_malidp_plane(plane);
+		u64 crtc_w, crtc_h;
+		u32 phase;
+
+		if (!(mp->layer->id & scaling))
+			continue;
+
+		/*
+		 * Convert crtc_[w|h] to U32.32, then divide by U16.16 src_[w|h]
+		 * to get the U16.16 result.
+		 */
+		crtc_w = (u64)pstate->crtc_w << 32;
+		crtc_h = (u64)pstate->crtc_h << 32;
+		h_upscale_factor = (u32)(crtc_w / pstate->src_w);
+		v_upscale_factor = (u32)(crtc_h / pstate->src_h);
+
+		/* Downscaling won't work when mclk == pxlclk. */
+		if (!(h_upscale_factor >> 16) || !(v_upscale_factor >> 16))
+			return -EINVAL;
+
+		s->input_w = pstate->src_w >> 16;
+		s->input_h = pstate->src_h >> 16;
+		s->output_w = pstate->crtc_w;
+		s->output_h = pstate->crtc_h;
+
+#define SE_N_PHASE 4
+#define SE_SHIFT_N_PHASE 12
+		/* Calculate initial_phase and delta_phase for horizontal. */
+		phase = s->input_w;
+		s->h_init_phase =
+				((phase << SE_N_PHASE) / s->output_w + 1) / 2;
+
+		phase = s->input_w;
+		phase <<= (SE_SHIFT_N_PHASE + SE_N_PHASE);
+		s->h_delta_phase = phase / s->output_w;
+
+		/* Same for vertical. */
+		phase = s->input_h;
+		s->v_init_phase =
+				((phase << SE_N_PHASE) / s->output_h + 1) / 2;
+
+		phase = s->input_h;
+		phase <<= (SE_SHIFT_N_PHASE + SE_N_PHASE);
+		s->v_delta_phase = phase / s->output_h;
+#undef SE_N_PHASE
+#undef SE_SHIFT_N_PHASE
+		s->plane_src_id = mp->layer->id;
+	}
+
+	s->scale_enable = true;
+	s->hcoeff = malidp_se_select_coeffs(h_upscale_factor);
+	s->vcoeff = malidp_se_select_coeffs(v_upscale_factor);
+	return 0;
+}
+
 static int malidp_crtc_atomic_check(struct drm_crtc *crtc,
 				    struct drm_crtc_state *state)
 {
@@ -325,6 +401,7 @@ static int malidp_crtc_atomic_check(struct drm_crtc *crtc,
 
 	ret = malidp_crtc_atomic_check_gamma(crtc, state);
 	ret = ret ? ret : malidp_crtc_atomic_check_ctm(crtc, state);
+	ret = ret ? ret : malidp_crtc_atomic_check_scaling(crtc, state);
 
 	return ret;
 }
@@ -353,6 +430,9 @@ static struct drm_crtc_state *malidp_crtc_duplicate_state(struct drm_crtc *crtc)
 	       sizeof(state->gamma_coeffs));
 	memcpy(state->coloradj_coeffs, old_state->coloradj_coeffs,
 	       sizeof(state->coloradj_coeffs));
+	memcpy(&state->scaler_config, &old_state->scaler_config,
+	       sizeof(state->scaler_config));
+	state->scaled_planes_mask = 0;
 
 	return &state->base;
 }
diff --git a/drivers/gpu/drm/arm/malidp_drv.c b/drivers/gpu/drm/arm/malidp_drv.c
index 24bc96f9e91c..baca2dce1b92 100644
--- a/drivers/gpu/drm/arm/malidp_drv.c
+++ b/drivers/gpu/drm/arm/malidp_drv.c
@@ -110,6 +110,52 @@ void malidp_atomic_commit_update_coloradj(struct drm_crtc *crtc,
 	}
 }
 
+static void malidp_atomic_commit_se_config(struct drm_crtc *crtc,
+					   struct drm_crtc_state *old_state)
+{
+	struct malidp_crtc_state *cs = to_malidp_crtc_state(crtc->state);
+	struct malidp_crtc_state *old_cs = to_malidp_crtc_state(old_state);
+	struct malidp_drm *malidp = crtc_to_malidp_device(crtc);
+	struct malidp_hw_device *hwdev = malidp->dev;
+	struct malidp_se_config *s = &cs->scaler_config;
+	struct malidp_se_config *old_s = &old_cs->scaler_config;
+	u32 se_control = hwdev->map.se_base +
+			 ((hwdev->map.features & MALIDP_REGMAP_HAS_CLEARIRQ) ?
+			 0x10 : 0xC);
+	u32 layer_control = se_control + MALIDP_SE_LAYER_CONTROL;
+	u32 scr = se_control + MALIDP_SE_SCALING_CONTROL;
+	u32 val;
+
+	/* Set SE_CONTROL */
+	if (!s->scale_enable) {
+		val = malidp_hw_read(hwdev, se_control);
+		val &= ~MALIDP_SE_SCALING_EN;
+		malidp_hw_write(hwdev, val, se_control);
+		return;
+	}
+
+	hwdev->se_set_scaling_coeffs(hwdev, s, old_s);
+	val = malidp_hw_read(hwdev, se_control);
+	val |= MALIDP_SE_SCALING_EN | MALIDP_SE_ALPHA_EN;
+
+	val |= MALIDP_SE_RGBO_IF_EN;
+	malidp_hw_write(hwdev, val, se_control);
+
+	/* Set IN_SIZE & OUT_SIZE. */
+	val = MALIDP_SE_SET_V_SIZE(s->input_h) |
+	      MALIDP_SE_SET_H_SIZE(s->input_w);
+	malidp_hw_write(hwdev, val, layer_control + MALIDP_SE_L0_IN_SIZE);
+	val = MALIDP_SE_SET_V_SIZE(s->output_h) |
+	      MALIDP_SE_SET_H_SIZE(s->output_w);
+	malidp_hw_write(hwdev, val, layer_control + MALIDP_SE_L0_OUT_SIZE);
+
+	/* Set phase regs. */
+	malidp_hw_write(hwdev, s->h_init_phase, scr + MALIDP_SE_H_INIT_PH);
+	malidp_hw_write(hwdev, s->h_delta_phase, scr + MALIDP_SE_H_DELTA_PH);
+	malidp_hw_write(hwdev, s->v_init_phase, scr + MALIDP_SE_V_INIT_PH);
+	malidp_hw_write(hwdev, s->v_delta_phase, scr + MALIDP_SE_V_DELTA_PH);
+}
+
 /*
  * set the "config valid" bit and wait until the hardware acts on it
  */
@@ -179,6 +225,7 @@ static void malidp_atomic_commit_tail(struct drm_atomic_state *state)
 	for_each_crtc_in_state(state, crtc, old_crtc_state, i) {
 		malidp_atomic_commit_update_gamma(crtc, old_crtc_state);
 		malidp_atomic_commit_update_coloradj(crtc, old_crtc_state);
+		malidp_atomic_commit_se_config(crtc, old_crtc_state);
 	}
 
 	drm_atomic_helper_commit_planes(drm, state, 0);
diff --git a/drivers/gpu/drm/arm/malidp_drv.h b/drivers/gpu/drm/arm/malidp_drv.h
index 75070efda2fc..040311ffcaec 100644
--- a/drivers/gpu/drm/arm/malidp_drv.h
+++ b/drivers/gpu/drm/arm/malidp_drv.h
@@ -53,6 +53,9 @@ struct malidp_crtc_state {
 	struct drm_crtc_state base;
 	u32 gamma_coeffs[MALIDP_COEFFTAB_NUM_COEFFS];
 	u32 coloradj_coeffs[MALIDP_COLORADJ_NUM_COEFFS];
+	struct malidp_se_config scaler_config;
+	/* Bitfield of all the planes that have requested a scaled output. */
+	u8 scaled_planes_mask;
 };
 
 #define to_malidp_crtc_state(x) container_of(x, struct malidp_crtc_state, base)
diff --git a/drivers/gpu/drm/arm/malidp_hw.c b/drivers/gpu/drm/arm/malidp_hw.c
index b8025b7c1aca..e444c23a8261 100644
--- a/drivers/gpu/drm/arm/malidp_hw.c
+++ b/drivers/gpu/drm/arm/malidp_hw.c
@@ -86,6 +86,80 @@ static const struct malidp_layer malidp550_layers[] = {
 	{ DE_SMART, MALIDP550_DE_LS_BASE, MALIDP550_DE_LS_PTR_BASE, MALIDP550_DE_LS_R1_STRIDE },
 };
 
+#define SE_N_SCALING_COEFFS	96
+static const u16 dp500_se_scaling_coeffs[][SE_N_SCALING_COEFFS] = {
+	[MALIDP_UPSCALING_COEFFS - 1] = {
+		0x0000, 0x0001, 0x0007, 0x0011, 0x001e, 0x002e, 0x003f, 0x0052,
+		0x0064, 0x0073, 0x007d, 0x0080, 0x007a, 0x006c, 0x0053, 0x002f,
+		0x0000, 0x3fc6, 0x3f83, 0x3f39, 0x3eea, 0x3e9b, 0x3e4f, 0x3e0a,
+		0x3dd4, 0x3db0, 0x3da2, 0x3db1, 0x3dde, 0x3e2f, 0x3ea5, 0x3f40,
+		0x0000, 0x00e5, 0x01ee, 0x0315, 0x0456, 0x05aa, 0x0709, 0x086c,
+		0x09c9, 0x0b15, 0x0c4a, 0x0d5d, 0x0e4a, 0x0f06, 0x0f91, 0x0fe5,
+		0x1000, 0x0fe5, 0x0f91, 0x0f06, 0x0e4a, 0x0d5d, 0x0c4a, 0x0b15,
+		0x09c9, 0x086c, 0x0709, 0x05aa, 0x0456, 0x0315, 0x01ee, 0x00e5,
+		0x0000, 0x3f40, 0x3ea5, 0x3e2f, 0x3dde, 0x3db1, 0x3da2, 0x3db0,
+		0x3dd4, 0x3e0a, 0x3e4f, 0x3e9b, 0x3eea, 0x3f39, 0x3f83, 0x3fc6,
+		0x0000, 0x002f, 0x0053, 0x006c, 0x007a, 0x0080, 0x007d, 0x0073,
+		0x0064, 0x0052, 0x003f, 0x002e, 0x001e, 0x0011, 0x0007, 0x0001
+	},
+	[MALIDP_DOWNSCALING_1_5_COEFFS - 1] = {
+		0x0059, 0x004f, 0x0041, 0x002e, 0x0016, 0x3ffb, 0x3fd9, 0x3fb4,
+		0x3f8c, 0x3f62, 0x3f36, 0x3f09, 0x3edd, 0x3eb3, 0x3e8d, 0x3e6c,
+		0x3e52, 0x3e3f, 0x3e35, 0x3e37, 0x3e46, 0x3e61, 0x3e8c, 0x3ec5,
+		0x3f0f, 0x3f68, 0x3fd1, 0x004a, 0x00d3, 0x0169, 0x020b, 0x02b8,
+		0x036e, 0x042d, 0x04f2, 0x05b9, 0x0681, 0x0745, 0x0803, 0x08ba,
+		0x0965, 0x0a03, 0x0a91, 0x0b0d, 0x0b75, 0x0bc6, 0x0c00, 0x0c20,
+		0x0c28, 0x0c20, 0x0c00, 0x0bc6, 0x0b75, 0x0b0d, 0x0a91, 0x0a03,
+		0x0965, 0x08ba, 0x0803, 0x0745, 0x0681, 0x05b9, 0x04f2, 0x042d,
+		0x036e, 0x02b8, 0x020b, 0x0169, 0x00d3, 0x004a, 0x3fd1, 0x3f68,
+		0x3f0f, 0x3ec5, 0x3e8c, 0x3e61, 0x3e46, 0x3e37, 0x3e35, 0x3e3f,
+		0x3e52, 0x3e6c, 0x3e8d, 0x3eb3, 0x3edd, 0x3f09, 0x3f36, 0x3f62,
+		0x3f8c, 0x3fb4, 0x3fd9, 0x3ffb, 0x0016, 0x002e, 0x0041, 0x004f
+	},
+	[MALIDP_DOWNSCALING_2_COEFFS - 1] = {
+		0x3f19, 0x3f03, 0x3ef0, 0x3edf, 0x3ed0, 0x3ec5, 0x3ebd, 0x3eb9,
+		0x3eb9, 0x3ebf, 0x3eca, 0x3ed9, 0x3eef, 0x3f0a, 0x3f2c, 0x3f52,
+		0x3f7f, 0x3fb0, 0x3fe8, 0x0026, 0x006a, 0x00b4, 0x0103, 0x0158,
+		0x01b1, 0x020d, 0x026c, 0x02cd, 0x032f, 0x0392, 0x03f4, 0x0455,
+		0x04b4, 0x051e, 0x0585, 0x05eb, 0x064c, 0x06a8, 0x06fe, 0x074e,
+		0x0796, 0x07d5, 0x080c, 0x0839, 0x085c, 0x0875, 0x0882, 0x0887,
+		0x0881, 0x0887, 0x0882, 0x0875, 0x085c, 0x0839, 0x080c, 0x07d5,
+		0x0796, 0x074e, 0x06fe, 0x06a8, 0x064c, 0x05eb, 0x0585, 0x051e,
+		0x04b4, 0x0455, 0x03f4, 0x0392, 0x032f, 0x02cd, 0x026c, 0x020d,
+		0x01b1, 0x0158, 0x0103, 0x00b4, 0x006a, 0x0026, 0x3fe8, 0x3fb0,
+		0x3f7f, 0x3f52, 0x3f2c, 0x3f0a, 0x3eef, 0x3ed9, 0x3eca, 0x3ebf,
+		0x3eb9, 0x3eb9, 0x3ebd, 0x3ec5, 0x3ed0, 0x3edf, 0x3ef0, 0x3f03
+	},
+	[MALIDP_DOWNSCALING_2_75_COEFFS - 1] = {
+		0x3f51, 0x3f60, 0x3f71, 0x3f84, 0x3f98, 0x3faf, 0x3fc8, 0x3fe3,
+		0x0000, 0x001f, 0x0040, 0x0064, 0x008a, 0x00b1, 0x00da, 0x0106,
+		0x0133, 0x0160, 0x018e, 0x01bd, 0x01ec, 0x021d, 0x024e, 0x0280,
+		0x02b2, 0x02e4, 0x0317, 0x0349, 0x037c, 0x03ad, 0x03df, 0x0410,
+		0x0440, 0x0468, 0x048f, 0x04b3, 0x04d6, 0x04f8, 0x0516, 0x0533,
+		0x054e, 0x0566, 0x057c, 0x0590, 0x05a0, 0x05ae, 0x05ba, 0x05c3,
+		0x05c9, 0x05c3, 0x05ba, 0x05ae, 0x05a0, 0x0590, 0x057c, 0x0566,
+		0x054e, 0x0533, 0x0516, 0x04f8, 0x04d6, 0x04b3, 0x048f, 0x0468,
+		0x0440, 0x0410, 0x03df, 0x03ad, 0x037c, 0x0349, 0x0317, 0x02e4,
+		0x02b2, 0x0280, 0x024e, 0x021d, 0x01ec, 0x01bd, 0x018e, 0x0160,
+		0x0133, 0x0106, 0x00da, 0x00b1, 0x008a, 0x0064, 0x0040, 0x001f,
+		0x0000, 0x3fe3, 0x3fc8, 0x3faf, 0x3f98, 0x3f84, 0x3f71, 0x3f60
+	},
+	[MALIDP_DOWNSCALING_4_COEFFS - 1] = {
+		0x0094, 0x00a9, 0x00be, 0x00d4, 0x00ea, 0x0101, 0x0118, 0x012f,
+		0x0148, 0x0160, 0x017a, 0x0193, 0x01ae, 0x01c8, 0x01e4, 0x01ff,
+		0x021c, 0x0233, 0x024a, 0x0261, 0x0278, 0x028f, 0x02a6, 0x02bd,
+		0x02d4, 0x02eb, 0x0302, 0x0319, 0x032f, 0x0346, 0x035d, 0x0374,
+		0x038a, 0x0397, 0x03a3, 0x03af, 0x03bb, 0x03c6, 0x03d1, 0x03db,
+		0x03e4, 0x03ed, 0x03f6, 0x03fe, 0x0406, 0x040d, 0x0414, 0x041a,
+		0x0420, 0x041a, 0x0414, 0x040d, 0x0406, 0x03fe, 0x03f6, 0x03ed,
+		0x03e4, 0x03db, 0x03d1, 0x03c6, 0x03bb, 0x03af, 0x03a3, 0x0397,
+		0x038a, 0x0374, 0x035d, 0x0346, 0x032f, 0x0319, 0x0302, 0x02eb,
+		0x02d4, 0x02bd, 0x02a6, 0x028f, 0x0278, 0x0261, 0x024a, 0x0233,
+		0x021c, 0x01ff, 0x01e4, 0x01c8, 0x01ae, 0x0193, 0x017a, 0x0160,
+		0x0148, 0x012f, 0x0118, 0x0101, 0x00ea, 0x00d4, 0x00be, 0x00a9
+	},
+};
+
 #define MALIDP_DE_DEFAULT_PREFETCH_START	5
 
 static int malidp500_query_hw(struct malidp_hw_device *hwdev)
@@ -211,6 +285,55 @@ static int malidp500_rotmem_required(struct malidp_hw_device *hwdev, u16 w, u16
 	return w * drm_format_plane_cpp(fmt, 0) * 8;
 }
 
+static void malidp500_se_write_pp_coefftab(struct malidp_hw_device *hwdev,
+					   u32 direction,
+					   u16 addr,
+					   u8 coeffs_id)
+{
+	int i;
+	u16 scaling_control = MALIDP500_SE_CONTROL + MALIDP_SE_SCALING_CONTROL;
+
+	malidp_hw_write(hwdev,
+			direction | (addr & MALIDP_SE_COEFFTAB_ADDR_MASK),
+			scaling_control + MALIDP_SE_COEFFTAB_ADDR);
+	for (i = 0; i < ARRAY_SIZE(dp500_se_scaling_coeffs); ++i)
+		malidp_hw_write(hwdev, MALIDP_SE_SET_COEFFTAB_DATA(
+				dp500_se_scaling_coeffs[coeffs_id][i]),
+				scaling_control + MALIDP_SE_COEFFTAB_DATA);
+}
+
+static int malidp500_se_set_scaling_coeffs(struct malidp_hw_device *hwdev,
+					   struct malidp_se_config *se_config,
+					   struct malidp_se_config *old_config)
+{
+	/* Get array indices into dp500_se_scaling_coeffs. */
+	u8 h = (u8)se_config->hcoeff - 1;
+	u8 v = (u8)se_config->vcoeff - 1;
+
+	if (WARN_ON(h >= ARRAY_SIZE(dp500_se_scaling_coeffs) ||
+		    v >= ARRAY_SIZE(dp500_se_scaling_coeffs)))
+		return -EINVAL;
+
+	if ((h == v) && (se_config->hcoeff != old_config->hcoeff ||
+			 se_config->vcoeff != old_config->vcoeff)) {
+		malidp500_se_write_pp_coefftab(hwdev,
+					       (MALIDP_SE_V_COEFFTAB |
+						MALIDP_SE_H_COEFFTAB),
+					       0, v);
+	} else {
+		if (se_config->vcoeff != old_config->vcoeff)
+			malidp500_se_write_pp_coefftab(hwdev,
+						       MALIDP_SE_V_COEFFTAB,
+						       0, v);
+		if (se_config->hcoeff != old_config->hcoeff)
+			malidp500_se_write_pp_coefftab(hwdev,
+						       MALIDP_SE_H_COEFFTAB,
+						       0, h);
+	}
+
+	return 0;
+}
+
 static int malidp550_query_hw(struct malidp_hw_device *hwdev)
 {
 	u32 conf = malidp_hw_read(hwdev, MALIDP550_CONFIG_ID);
@@ -384,6 +507,20 @@ static int malidp550_rotmem_required(struct malidp_hw_device *hwdev, u16 w, u16
 	return w * bytes_per_col;
 }
 
+static int malidp550_se_set_scaling_coeffs(struct malidp_hw_device *hwdev,
+					   struct malidp_se_config *se_config,
+					   struct malidp_se_config *old_config)
+{
+	u32 mask = MALIDP550_SE_CTL_VCSEL(MALIDP550_SE_CTL_SEL_MASK) |
+		   MALIDP550_SE_CTL_HCSEL(MALIDP550_SE_CTL_SEL_MASK);
+	u32 new_value = MALIDP550_SE_CTL_VCSEL(se_config->vcoeff) |
+			MALIDP550_SE_CTL_HCSEL(se_config->hcoeff);
+
+	malidp_hw_clearbits(hwdev, mask, MALIDP550_SE_CONTROL);
+	malidp_hw_setbits(hwdev, new_value, MALIDP550_SE_CONTROL);
+	return 0;
+}
+
 static int malidp650_query_hw(struct malidp_hw_device *hwdev)
 {
 	u32 conf = malidp_hw_read(hwdev, MALIDP550_CONFIG_ID);
@@ -448,6 +585,7 @@ const struct malidp_hw_device malidp_device[MALIDP_MAX_DEVICES] = {
 		.set_config_valid = malidp500_set_config_valid,
 		.modeset = malidp500_modeset,
 		.rotmem_required = malidp500_rotmem_required,
+		.se_set_scaling_coeffs = malidp500_se_set_scaling_coeffs,
 		.features = MALIDP_DEVICE_LV_HAS_3_STRIDES,
 	},
 	[MALIDP_550] = {
@@ -483,6 +621,7 @@ const struct malidp_hw_device malidp_device[MALIDP_MAX_DEVICES] = {
 		.set_config_valid = malidp550_set_config_valid,
 		.modeset = malidp550_modeset,
 		.rotmem_required = malidp550_rotmem_required,
+		.se_set_scaling_coeffs = malidp550_se_set_scaling_coeffs,
 		.features = 0,
 	},
 	[MALIDP_650] = {
@@ -519,6 +658,7 @@ const struct malidp_hw_device malidp_device[MALIDP_MAX_DEVICES] = {
 		.set_config_valid = malidp550_set_config_valid,
 		.modeset = malidp550_modeset,
 		.rotmem_required = malidp550_rotmem_required,
+		.se_set_scaling_coeffs = malidp550_se_set_scaling_coeffs,
 		.features = 0,
 	},
 };
diff --git a/drivers/gpu/drm/arm/malidp_hw.h b/drivers/gpu/drm/arm/malidp_hw.h
index 470fe71724a3..52a65a8a056f 100644
--- a/drivers/gpu/drm/arm/malidp_hw.h
+++ b/drivers/gpu/drm/arm/malidp_hw.h
@@ -61,6 +61,25 @@ struct malidp_layer {
 	u16 stride_offset;	/* Offset to the first stride register. */
 };
 
+enum malidp_scaling_coeff_set {
+	MALIDP_UPSCALING_COEFFS = 1,
+	MALIDP_DOWNSCALING_1_5_COEFFS = 2,
+	MALIDP_DOWNSCALING_2_COEFFS = 3,
+	MALIDP_DOWNSCALING_2_75_COEFFS = 4,
+	MALIDP_DOWNSCALING_4_COEFFS = 5,
+};
+
+struct malidp_se_config {
+	u8 scale_enable : 1;
+	u8 hcoeff : 3;
+	u8 vcoeff : 3;
+	u8 plane_src_id;
+	u16 input_w, input_h;
+	u16 output_w, output_h;
+	u32 h_init_phase, h_delta_phase;
+	u32 v_init_phase, v_delta_phase;
+};
+
 /* regmap features */
 #define MALIDP_REGMAP_HAS_CLEARIRQ	(1 << 0)
 
@@ -153,6 +172,10 @@ struct malidp_hw_device {
 	 */
 	int (*rotmem_required)(struct malidp_hw_device *hwdev, u16 w, u16 h, u32 fmt);
 
+	int (*se_set_scaling_coeffs)(struct malidp_hw_device *hwdev,
+				     struct malidp_se_config *se_config,
+				     struct malidp_se_config *old_config);
+
 	u8 features;
 
 	u8 min_line_size;
@@ -250,6 +273,28 @@ static inline bool malidp_hw_pitch_valid(struct malidp_hw_device *hwdev,
 	return !(pitch & (hwdev->map.bus_align_bytes - 1));
 }
 
+/* U16.16 */
+#define FP_1_00000	0x00010000	/* 1.0 */
+#define FP_0_66667	0x0000AAAA	/* 0.6667 = 1/1.5 */
+#define FP_0_50000	0x00008000	/* 0.5 = 1/2 */
+#define FP_0_36363	0x00005D17	/* 0.36363 = 1/2.75 */
+#define FP_0_25000	0x00004000	/* 0.25 = 1/4 */
+
+static inline enum malidp_scaling_coeff_set
+malidp_se_select_coeffs(u32 upscale_factor)
+{
+	return (upscale_factor >= FP_1_00000) ? MALIDP_UPSCALING_COEFFS :
+	       (upscale_factor >= FP_0_66667) ? MALIDP_DOWNSCALING_1_5_COEFFS :
+	       (upscale_factor >= FP_0_50000) ? MALIDP_DOWNSCALING_2_COEFFS :
+	       (upscale_factor >= FP_0_36363) ? MALIDP_DOWNSCALING_2_75_COEFFS :
+	       MALIDP_DOWNSCALING_4_COEFFS;
+}
+
+#undef FP_0_25000
+#undef FP_0_36363
+#undef FP_0_50000
+#undef FP_0_66667
+#undef FP_1_00000
 /*
  * background color components are defined as 12bits values,
  * they will be shifted right when stored on hardware that
diff --git a/drivers/gpu/drm/arm/malidp_planes.c b/drivers/gpu/drm/arm/malidp_planes.c
index 8106e22f9349..e5f4ecde2602 100644
--- a/drivers/gpu/drm/arm/malidp_planes.c
+++ b/drivers/gpu/drm/arm/malidp_planes.c
@@ -25,6 +25,9 @@
 #define MALIDP_LAYER_FORMAT		0x000
 #define MALIDP_LAYER_CONTROL		0x004
 #define   LAYER_ENABLE			(1 << 0)
+#define   LAYER_FLOWCFG_MASK		7
+#define   LAYER_FLOWCFG(x)		(((x) & LAYER_FLOWCFG_MASK) << 1)
+#define     LAYER_FLOWCFG_SCALE_SE	3
 #define   LAYER_ROT_OFFSET		8
 #define   LAYER_H_FLIP			(1 << 10)
 #define   LAYER_V_FLIP			(1 << 11)
@@ -133,16 +136,52 @@ static const struct drm_plane_funcs malidp_de_plane_funcs = {
 	.atomic_print_state = malidp_plane_atomic_print_state,
 };
 
+static int malidp_se_check_scaling(struct malidp_plane *mp,
+				   struct drm_plane_state *state)
+{
+	struct drm_crtc_state *crtc_state =
+		drm_atomic_get_existing_crtc_state(state->state, state->crtc);
+	struct malidp_crtc_state *mc;
+	struct drm_rect clip = { 0 };
+	u32 src_w, src_h;
+	int ret;
+
+	if (!crtc_state)
+		return -EINVAL;
+
+	clip.x2 = crtc_state->adjusted_mode.hdisplay;
+	clip.y2 = crtc_state->adjusted_mode.vdisplay;
+	ret = drm_plane_helper_check_state(state, &clip,
+					   0, INT_MAX,
+					   true, true);
+	if (ret)
+		return ret;
+
+	src_w = state->src_w >> 16;
+	src_h = state->src_h >> 16;
+	if ((state->crtc_w == src_w) && (state->crtc_h == src_h)) {
+		/* Scaling not necessary for this plane. */
+		mc->scaled_planes_mask &= ~(mp->layer->id);
+		return 0;
+	}
+
+	if (mp->layer->id & (DE_SMART | DE_GRAPHICS2))
+		return -EINVAL;
+
+	mc = to_malidp_crtc_state(crtc_state);
+
+	mc->scaled_planes_mask |= mp->layer->id;
+	/* Defer scaling requirements calculation to the crtc check. */
+	return 0;
+}
+
 static int malidp_de_plane_check(struct drm_plane *plane,
 				 struct drm_plane_state *state)
 {
 	struct malidp_plane *mp = to_malidp_plane(plane);
 	struct malidp_plane_state *ms = to_malidp_plane_state(state);
-	struct drm_crtc_state *crtc_state;
 	struct drm_framebuffer *fb;
-	struct drm_rect clip = { 0 };
 	int i, ret;
-	u32 src_w, src_h;
 
 	if (!state->crtc || !state->fb)
 		return 0;
@@ -163,9 +202,6 @@ static int malidp_de_plane_check(struct drm_plane *plane,
 		}
 	}
 
-	src_w = state->src_w >> 16;
-	src_h = state->src_h >> 16;
-
 	if ((state->crtc_w > mp->hwdev->max_line_size) ||
 	    (state->crtc_h > mp->hwdev->max_line_size) ||
 	    (state->crtc_w < mp->hwdev->min_line_size) ||
@@ -182,22 +218,16 @@ static int malidp_de_plane_check(struct drm_plane *plane,
 	    (state->fb->pitches[1] != state->fb->pitches[2]))
 		return -EINVAL;
 
+	ret = malidp_se_check_scaling(mp, state);
+	if (ret)
+		return ret;
+
 	/* packed RGB888 / BGR888 can't be rotated or flipped */
 	if (state->rotation != DRM_ROTATE_0 &&
 	    (fb->format->format == DRM_FORMAT_RGB888 ||
 	     fb->format->format == DRM_FORMAT_BGR888))
 		return -EINVAL;
 
-	crtc_state = drm_atomic_get_existing_crtc_state(state->state, state->crtc);
-	clip.x2 = crtc_state->adjusted_mode.hdisplay;
-	clip.y2 = crtc_state->adjusted_mode.vdisplay;
-	ret = drm_plane_helper_check_state(state, &clip,
-					   DRM_PLANE_HELPER_NO_SCALING,
-					   DRM_PLANE_HELPER_NO_SCALING,
-					   true, true);
-	if (ret)
-		return ret;
-
 	ms->rotmem_size = 0;
 	if (state->rotation & MALIDP_ROTATED_MASK) {
 		int val;
@@ -302,6 +332,16 @@ static void malidp_de_plane_update(struct drm_plane *plane,
 	val &= ~LAYER_COMP_MASK;
 	val |= LAYER_COMP_PIXEL;
 
+	val &= ~LAYER_FLOWCFG(LAYER_FLOWCFG_MASK);
+	if (plane->state->crtc) {
+		struct malidp_crtc_state *m =
+			to_malidp_crtc_state(plane->state->crtc->state);
+
+		if (m->scaler_config.scale_enable &&
+		    m->scaler_config.plane_src_id == mp->layer->id)
+			val |= LAYER_FLOWCFG(LAYER_FLOWCFG_SCALE_SE);
+	}
+
 	/* set the 'enable layer' bit */
 	val |= LAYER_ENABLE;
 
@@ -314,7 +354,8 @@ static void malidp_de_plane_disable(struct drm_plane *plane,
 {
 	struct malidp_plane *mp = to_malidp_plane(plane);
 
-	malidp_hw_clearbits(mp->hwdev, LAYER_ENABLE,
+	malidp_hw_clearbits(mp->hwdev,
+			    LAYER_ENABLE | LAYER_FLOWCFG(LAYER_FLOWCFG_MASK),
 			    mp->layer->base + MALIDP_LAYER_CONTROL);
 }
 
diff --git a/drivers/gpu/drm/arm/malidp_regs.h b/drivers/gpu/drm/arm/malidp_regs.h
index 4bf338d4172e..91d2ba5729bf 100644
--- a/drivers/gpu/drm/arm/malidp_regs.h
+++ b/drivers/gpu/drm/arm/malidp_regs.h
@@ -106,6 +106,40 @@
 #define MALIDP_COEF_TABLE_ADDR		0x00030
 #define MALIDP_COEF_TABLE_DATA		0x00034
 
+/* Scaling engine registers and masks. */
+#define   MALIDP_SE_SCALING_EN			(1 << 0)
+#define   MALIDP_SE_ALPHA_EN			(1 << 1)
+#define   MALIDP_SE_RGBO_IF_EN			(1 << 4)
+#define   MALIDP550_SE_CTL_SEL_MASK		7
+#define   MALIDP550_SE_CTL_VCSEL(x) \
+		(((x) & MALIDP550_SE_CTL_SEL_MASK) << 20)
+#define   MALIDP550_SE_CTL_HCSEL(x) \
+		(((x) & MALIDP550_SE_CTL_SEL_MASK) << 16)
+
+/* Blocks with offsets from SE_CONTROL register. */
+#define MALIDP_SE_LAYER_CONTROL			0x14
+#define   MALIDP_SE_L0_IN_SIZE			0x00
+#define   MALIDP_SE_L0_OUT_SIZE			0x04
+#define   MALIDP_SE_SET_V_SIZE(x)		(((x) & 0x1fff) << 16)
+#define   MALIDP_SE_SET_H_SIZE(x)		(((x) & 0x1fff) << 0)
+#define MALIDP_SE_SCALING_CONTROL		0x24
+#define   MALIDP_SE_H_INIT_PH			0x00
+#define   MALIDP_SE_H_DELTA_PH			0x04
+#define   MALIDP_SE_V_INIT_PH			0x08
+#define   MALIDP_SE_V_DELTA_PH			0x0c
+#define   MALIDP_SE_COEFFTAB_ADDR		0x10
+#define     MALIDP_SE_COEFFTAB_ADDR_MASK	0x7f
+#define     MALIDP_SE_V_COEFFTAB		(1 << 8)
+#define     MALIDP_SE_H_COEFFTAB		(1 << 9)
+#define     MALIDP_SE_SET_V_COEFFTAB_ADDR(x) \
+		(MALIDP_SE_V_COEFFTAB | ((x) & MALIDP_SE_COEFFTAB_ADDR_MASK))
+#define     MALIDP_SE_SET_H_COEFFTAB_ADDR(x) \
+		(MALIDP_SE_H_COEFFTAB | ((x) & MALIDP_SE_COEFFTAB_ADDR_MASK))
+#define   MALIDP_SE_COEFFTAB_DATA		0x14
+#define     MALIDP_SE_COEFFTAB_DATA_MASK	0x3fff
+#define     MALIDP_SE_SET_COEFFTAB_DATA(x) \
+		((x) & MALIDP_SE_COEFFTAB_DATA_MASK)
+
 /* register offsets and bits specific to DP500 */
 #define MALIDP500_ADDR_SPACE_SIZE	0x01000
 #define MALIDP500_DC_BASE		0x00000
@@ -146,6 +180,7 @@
 #define MALIDP500_DE_LG2_BASE		0x00300
 #define MALIDP500_DE_LG2_PTR_BASE	0x0031c
 #define MALIDP500_SE_BASE		0x00c00
+#define MALIDP500_SE_CONTROL		0x00c0c
 #define MALIDP500_SE_PTR_BASE		0x00e0c
 #define MALIDP500_DC_IRQ_BASE		0x00f00
 #define MALIDP500_CONFIG_VALID		0x00f00
@@ -175,6 +210,7 @@
 #define MALIDP550_DE_LS_PTR_BASE	0x0042c
 #define MALIDP550_DE_PERF_BASE		0x00500
 #define MALIDP550_SE_BASE		0x08000
+#define MALIDP550_SE_CONTROL		0x08010
 #define MALIDP550_DC_BASE		0x0c000
 #define MALIDP550_DC_CONTROL		0x0c010
 #define   MALIDP550_DC_CONFIG_REQ	(1 << 16)
-- 
2.12.0

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

  parent reply	other threads:[~2017-04-21  9:18 UTC|newest]

Thread overview: 13+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2017-04-21  9:18 [PATCH 00/12] drm/mali-dp: Collate the pending patches in a series Liviu Dudau
2017-04-21  9:18 ` [PATCH 01/12] drm: mali-dp: Update the state of all planes before re-enabling active CRTCs Liviu Dudau
2017-04-21  9:18 ` [PATCH 02/12] drm: mali-dp: Enable power management for the device Liviu Dudau
2017-04-21  9:18 ` [PATCH 03/12] drm: mali-dp: add atomic_print_state for planes Liviu Dudau
2017-04-21  9:18 ` [PATCH 04/12] drm: mali-dp: remove unused variable Liviu Dudau
2017-04-21  9:18 ` [PATCH 05/12] drm: mali-dp: add custom reset hook for planes Liviu Dudau
2017-04-21  9:18 ` [PATCH 06/12] drm: mali-dp: add malidp_crtc_state struct Liviu Dudau
2017-04-21  9:18 ` [PATCH 07/12] drm: mali-dp: enable gamma support Liviu Dudau
2017-04-21  9:18 ` [PATCH 08/12] drm: mali-dp: Add CTM support Liviu Dudau
2017-04-21  9:18 ` [PATCH 09/12] drm/mali-dp: Add core_id file to the sysfs interface Liviu Dudau
2017-04-21  9:18 ` Liviu Dudau [this message]
2017-04-21  9:18 ` [PATCH 11/12] drm: mali-dp: Enable image enhancement when scaling Liviu Dudau
2017-04-21  9:18 ` [PATCH 12/12] drm: mali-dp: Check the mclk rate and allow up/down scaling Liviu Dudau

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20170421091848.4666-11-Liviu.Dudau@arm.com \
    --to=liviu.dudau@arm.com \
    --cc=brian.starkey@arm.com \
    --cc=dri-devel@lists.freedesktop.org \
    --cc=malidp@foss.arm.com \
    --cc=mihail.atanassov@arm.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.