aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorMihail Atanassov <mihail.atanassov@arm.com>2017-02-13 10:14:05 -0500
committerLiviu Dudau <Liviu.Dudau@arm.com>2017-04-24 08:28:08 -0400
commit28ce675b74742cae1c815970347267b45dc73a8a (patch)
tree5007564e6f4829a9b7e9964b37664959665dbf44 /drivers
parent50c7512fd7496129d774ccabf32537e9a45be186 (diff)
drm: mali-dp: Add plane upscaling support
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>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/gpu/drm/arm/malidp_crtc.c80
-rw-r--r--drivers/gpu/drm/arm/malidp_drv.c47
-rw-r--r--drivers/gpu/drm/arm/malidp_drv.h3
-rw-r--r--drivers/gpu/drm/arm/malidp_hw.c140
-rw-r--r--drivers/gpu/drm/arm/malidp_hw.h45
-rw-r--r--drivers/gpu/drm/arm/malidp_planes.c73
-rw-r--r--drivers/gpu/drm/arm/malidp_regs.h36
7 files changed, 407 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,
247 return 0; 247 return 0;
248} 248}
249 249
250static int malidp_crtc_atomic_check_scaling(struct drm_crtc *crtc,
251 struct drm_crtc_state *state)
252{
253 struct malidp_crtc_state *cs = to_malidp_crtc_state(state);
254 struct malidp_se_config *s = &cs->scaler_config;
255 struct drm_plane *plane;
256 const struct drm_plane_state *pstate;
257 u32 h_upscale_factor = 0; /* U16.16 */
258 u32 v_upscale_factor = 0; /* U16.16 */
259 u8 scaling = cs->scaled_planes_mask;
260
261 if (!scaling) {
262 s->scale_enable = false;
263 return 0;
264 }
265
266 /* The scaling engine can only handle one plane at a time. */
267 if (scaling & (scaling - 1))
268 return -EINVAL;
269
270 drm_atomic_crtc_state_for_each_plane_state(plane, pstate, state) {
271 struct malidp_plane *mp = to_malidp_plane(plane);
272 u64 crtc_w, crtc_h;
273 u32 phase;
274
275 if (!(mp->layer->id & scaling))
276 continue;
277
278 /*
279 * Convert crtc_[w|h] to U32.32, then divide by U16.16 src_[w|h]
280 * to get the U16.16 result.
281 */
282 crtc_w = (u64)pstate->crtc_w << 32;
283 crtc_h = (u64)pstate->crtc_h << 32;
284 h_upscale_factor = (u32)(crtc_w / pstate->src_w);
285 v_upscale_factor = (u32)(crtc_h / pstate->src_h);
286
287 /* Downscaling won't work when mclk == pxlclk. */
288 if (!(h_upscale_factor >> 16) || !(v_upscale_factor >> 16))
289 return -EINVAL;
290
291 s->input_w = pstate->src_w >> 16;
292 s->input_h = pstate->src_h >> 16;
293 s->output_w = pstate->crtc_w;
294 s->output_h = pstate->crtc_h;
295
296#define SE_N_PHASE 4
297#define SE_SHIFT_N_PHASE 12
298 /* Calculate initial_phase and delta_phase for horizontal. */
299 phase = s->input_w;
300 s->h_init_phase =
301 ((phase << SE_N_PHASE) / s->output_w + 1) / 2;
302
303 phase = s->input_w;
304 phase <<= (SE_SHIFT_N_PHASE + SE_N_PHASE);
305 s->h_delta_phase = phase / s->output_w;
306
307 /* Same for vertical. */
308 phase = s->input_h;
309 s->v_init_phase =
310 ((phase << SE_N_PHASE) / s->output_h + 1) / 2;
311
312 phase = s->input_h;
313 phase <<= (SE_SHIFT_N_PHASE + SE_N_PHASE);
314 s->v_delta_phase = phase / s->output_h;
315#undef SE_N_PHASE
316#undef SE_SHIFT_N_PHASE
317 s->plane_src_id = mp->layer->id;
318 }
319
320 s->scale_enable = true;
321 s->hcoeff = malidp_se_select_coeffs(h_upscale_factor);
322 s->vcoeff = malidp_se_select_coeffs(v_upscale_factor);
323 return 0;
324}
325
250static int malidp_crtc_atomic_check(struct drm_crtc *crtc, 326static int malidp_crtc_atomic_check(struct drm_crtc *crtc,
251 struct drm_crtc_state *state) 327 struct drm_crtc_state *state)
252{ 328{
@@ -325,6 +401,7 @@ static int malidp_crtc_atomic_check(struct drm_crtc *crtc,
325 401
326 ret = malidp_crtc_atomic_check_gamma(crtc, state); 402 ret = malidp_crtc_atomic_check_gamma(crtc, state);
327 ret = ret ? ret : malidp_crtc_atomic_check_ctm(crtc, state); 403 ret = ret ? ret : malidp_crtc_atomic_check_ctm(crtc, state);
404 ret = ret ? ret : malidp_crtc_atomic_check_scaling(crtc, state);
328 405
329 return ret; 406 return ret;
330} 407}
@@ -353,6 +430,9 @@ static struct drm_crtc_state *malidp_crtc_duplicate_state(struct drm_crtc *crtc)
353 sizeof(state->gamma_coeffs)); 430 sizeof(state->gamma_coeffs));
354 memcpy(state->coloradj_coeffs, old_state->coloradj_coeffs, 431 memcpy(state->coloradj_coeffs, old_state->coloradj_coeffs,
355 sizeof(state->coloradj_coeffs)); 432 sizeof(state->coloradj_coeffs));
433 memcpy(&state->scaler_config, &old_state->scaler_config,
434 sizeof(state->scaler_config));
435 state->scaled_planes_mask = 0;
356 436
357 return &state->base; 437 return &state->base;
358} 438}
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,
110 } 110 }
111} 111}
112 112
113static void malidp_atomic_commit_se_config(struct drm_crtc *crtc,
114 struct drm_crtc_state *old_state)
115{
116 struct malidp_crtc_state *cs = to_malidp_crtc_state(crtc->state);
117 struct malidp_crtc_state *old_cs = to_malidp_crtc_state(old_state);
118 struct malidp_drm *malidp = crtc_to_malidp_device(crtc);
119 struct malidp_hw_device *hwdev = malidp->dev;
120 struct malidp_se_config *s = &cs->scaler_config;
121 struct malidp_se_config *old_s = &old_cs->scaler_config;
122 u32 se_control = hwdev->map.se_base +
123 ((hwdev->map.features & MALIDP_REGMAP_HAS_CLEARIRQ) ?
124 0x10 : 0xC);
125 u32 layer_control = se_control + MALIDP_SE_LAYER_CONTROL;
126 u32 scr = se_control + MALIDP_SE_SCALING_CONTROL;
127 u32 val;
128
129 /* Set SE_CONTROL */
130 if (!s->scale_enable) {
131 val = malidp_hw_read(hwdev, se_control);
132 val &= ~MALIDP_SE_SCALING_EN;
133 malidp_hw_write(hwdev, val, se_control);
134 return;
135 }
136
137 hwdev->se_set_scaling_coeffs(hwdev, s, old_s);
138 val = malidp_hw_read(hwdev, se_control);
139 val |= MALIDP_SE_SCALING_EN | MALIDP_SE_ALPHA_EN;
140
141 val |= MALIDP_SE_RGBO_IF_EN;
142 malidp_hw_write(hwdev, val, se_control);
143
144 /* Set IN_SIZE & OUT_SIZE. */
145 val = MALIDP_SE_SET_V_SIZE(s->input_h) |
146 MALIDP_SE_SET_H_SIZE(s->input_w);
147 malidp_hw_write(hwdev, val, layer_control + MALIDP_SE_L0_IN_SIZE);
148 val = MALIDP_SE_SET_V_SIZE(s->output_h) |
149 MALIDP_SE_SET_H_SIZE(s->output_w);
150 malidp_hw_write(hwdev, val, layer_control + MALIDP_SE_L0_OUT_SIZE);
151
152 /* Set phase regs. */
153 malidp_hw_write(hwdev, s->h_init_phase, scr + MALIDP_SE_H_INIT_PH);
154 malidp_hw_write(hwdev, s->h_delta_phase, scr + MALIDP_SE_H_DELTA_PH);
155 malidp_hw_write(hwdev, s->v_init_phase, scr + MALIDP_SE_V_INIT_PH);
156 malidp_hw_write(hwdev, s->v_delta_phase, scr + MALIDP_SE_V_DELTA_PH);
157}
158
113/* 159/*
114 * set the "config valid" bit and wait until the hardware acts on it 160 * set the "config valid" bit and wait until the hardware acts on it
115 */ 161 */
@@ -179,6 +225,7 @@ static void malidp_atomic_commit_tail(struct drm_atomic_state *state)
179 for_each_crtc_in_state(state, crtc, old_crtc_state, i) { 225 for_each_crtc_in_state(state, crtc, old_crtc_state, i) {
180 malidp_atomic_commit_update_gamma(crtc, old_crtc_state); 226 malidp_atomic_commit_update_gamma(crtc, old_crtc_state);
181 malidp_atomic_commit_update_coloradj(crtc, old_crtc_state); 227 malidp_atomic_commit_update_coloradj(crtc, old_crtc_state);
228 malidp_atomic_commit_se_config(crtc, old_crtc_state);
182 } 229 }
183 230
184 drm_atomic_helper_commit_planes(drm, state, 0); 231 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 {
53 struct drm_crtc_state base; 53 struct drm_crtc_state base;
54 u32 gamma_coeffs[MALIDP_COEFFTAB_NUM_COEFFS]; 54 u32 gamma_coeffs[MALIDP_COEFFTAB_NUM_COEFFS];
55 u32 coloradj_coeffs[MALIDP_COLORADJ_NUM_COEFFS]; 55 u32 coloradj_coeffs[MALIDP_COLORADJ_NUM_COEFFS];
56 struct malidp_se_config scaler_config;
57 /* Bitfield of all the planes that have requested a scaled output. */
58 u8 scaled_planes_mask;
56}; 59};
57 60
58#define to_malidp_crtc_state(x) container_of(x, struct malidp_crtc_state, base) 61#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[] = {
86 { DE_SMART, MALIDP550_DE_LS_BASE, MALIDP550_DE_LS_PTR_BASE, MALIDP550_DE_LS_R1_STRIDE }, 86 { DE_SMART, MALIDP550_DE_LS_BASE, MALIDP550_DE_LS_PTR_BASE, MALIDP550_DE_LS_R1_STRIDE },
87}; 87};
88 88
89#define SE_N_SCALING_COEFFS 96
90static const u16 dp500_se_scaling_coeffs[][SE_N_SCALING_COEFFS] = {
91 [MALIDP_UPSCALING_COEFFS - 1] = {
92 0x0000, 0x0001, 0x0007, 0x0011, 0x001e, 0x002e, 0x003f, 0x0052,
93 0x0064, 0x0073, 0x007d, 0x0080, 0x007a, 0x006c, 0x0053, 0x002f,
94 0x0000, 0x3fc6, 0x3f83, 0x3f39, 0x3eea, 0x3e9b, 0x3e4f, 0x3e0a,
95 0x3dd4, 0x3db0, 0x3da2, 0x3db1, 0x3dde, 0x3e2f, 0x3ea5, 0x3f40,
96 0x0000, 0x00e5, 0x01ee, 0x0315, 0x0456, 0x05aa, 0x0709, 0x086c,
97 0x09c9, 0x0b15, 0x0c4a, 0x0d5d, 0x0e4a, 0x0f06, 0x0f91, 0x0fe5,
98 0x1000, 0x0fe5, 0x0f91, 0x0f06, 0x0e4a, 0x0d5d, 0x0c4a, 0x0b15,
99 0x09c9, 0x086c, 0x0709, 0x05aa, 0x0456, 0x0315, 0x01ee, 0x00e5,
100 0x0000, 0x3f40, 0x3ea5, 0x3e2f, 0x3dde, 0x3db1, 0x3da2, 0x3db0,
101 0x3dd4, 0x3e0a, 0x3e4f, 0x3e9b, 0x3eea, 0x3f39, 0x3f83, 0x3fc6,
102 0x0000, 0x002f, 0x0053, 0x006c, 0x007a, 0x0080, 0x007d, 0x0073,
103 0x0064, 0x0052, 0x003f, 0x002e, 0x001e, 0x0011, 0x0007, 0x0001
104 },
105 [MALIDP_DOWNSCALING_1_5_COEFFS - 1] = {
106 0x0059, 0x004f, 0x0041, 0x002e, 0x0016, 0x3ffb, 0x3fd9, 0x3fb4,
107 0x3f8c, 0x3f62, 0x3f36, 0x3f09, 0x3edd, 0x3eb3, 0x3e8d, 0x3e6c,
108 0x3e52, 0x3e3f, 0x3e35, 0x3e37, 0x3e46, 0x3e61, 0x3e8c, 0x3ec5,
109 0x3f0f, 0x3f68, 0x3fd1, 0x004a, 0x00d3, 0x0169, 0x020b, 0x02b8,
110 0x036e, 0x042d, 0x04f2, 0x05b9, 0x0681, 0x0745, 0x0803, 0x08ba,
111 0x0965, 0x0a03, 0x0a91, 0x0b0d, 0x0b75, 0x0bc6, 0x0c00, 0x0c20,
112 0x0c28, 0x0c20, 0x0c00, 0x0bc6, 0x0b75, 0x0b0d, 0x0a91, 0x0a03,
113 0x0965, 0x08ba, 0x0803, 0x0745, 0x0681, 0x05b9, 0x04f2, 0x042d,
114 0x036e, 0x02b8, 0x020b, 0x0169, 0x00d3, 0x004a, 0x3fd1, 0x3f68,
115 0x3f0f, 0x3ec5, 0x3e8c, 0x3e61, 0x3e46, 0x3e37, 0x3e35, 0x3e3f,
116 0x3e52, 0x3e6c, 0x3e8d, 0x3eb3, 0x3edd, 0x3f09, 0x3f36, 0x3f62,
117 0x3f8c, 0x3fb4, 0x3fd9, 0x3ffb, 0x0016, 0x002e, 0x0041, 0x004f
118 },
119 [MALIDP_DOWNSCALING_2_COEFFS - 1] = {
120 0x3f19, 0x3f03, 0x3ef0, 0x3edf, 0x3ed0, 0x3ec5, 0x3ebd, 0x3eb9,
121 0x3eb9, 0x3ebf, 0x3eca, 0x3ed9, 0x3eef, 0x3f0a, 0x3f2c, 0x3f52,
122 0x3f7f, 0x3fb0, 0x3fe8, 0x0026, 0x006a, 0x00b4, 0x0103, 0x0158,
123 0x01b1, 0x020d, 0x026c, 0x02cd, 0x032f, 0x0392, 0x03f4, 0x0455,
124 0x04b4, 0x051e, 0x0585, 0x05eb, 0x064c, 0x06a8, 0x06fe, 0x074e,
125 0x0796, 0x07d5, 0x080c, 0x0839, 0x085c, 0x0875, 0x0882, 0x0887,
126 0x0881, 0x0887, 0x0882, 0x0875, 0x085c, 0x0839, 0x080c, 0x07d5,
127 0x0796, 0x074e, 0x06fe, 0x06a8, 0x064c, 0x05eb, 0x0585, 0x051e,
128 0x04b4, 0x0455, 0x03f4, 0x0392, 0x032f, 0x02cd, 0x026c, 0x020d,
129 0x01b1, 0x0158, 0x0103, 0x00b4, 0x006a, 0x0026, 0x3fe8, 0x3fb0,
130 0x3f7f, 0x3f52, 0x3f2c, 0x3f0a, 0x3eef, 0x3ed9, 0x3eca, 0x3ebf,
131 0x3eb9, 0x3eb9, 0x3ebd, 0x3ec5, 0x3ed0, 0x3edf, 0x3ef0, 0x3f03
132 },
133 [MALIDP_DOWNSCALING_2_75_COEFFS - 1] = {
134 0x3f51, 0x3f60, 0x3f71, 0x3f84, 0x3f98, 0x3faf, 0x3fc8, 0x3fe3,
135 0x0000, 0x001f, 0x0040, 0x0064, 0x008a, 0x00b1, 0x00da, 0x0106,
136 0x0133, 0x0160, 0x018e, 0x01bd, 0x01ec, 0x021d, 0x024e, 0x0280,
137 0x02b2, 0x02e4, 0x0317, 0x0349, 0x037c, 0x03ad, 0x03df, 0x0410,
138 0x0440, 0x0468, 0x048f, 0x04b3, 0x04d6, 0x04f8, 0x0516, 0x0533,
139 0x054e, 0x0566, 0x057c, 0x0590, 0x05a0, 0x05ae, 0x05ba, 0x05c3,
140 0x05c9, 0x05c3, 0x05ba, 0x05ae, 0x05a0, 0x0590, 0x057c, 0x0566,
141 0x054e, 0x0533, 0x0516, 0x04f8, 0x04d6, 0x04b3, 0x048f, 0x0468,
142 0x0440, 0x0410, 0x03df, 0x03ad, 0x037c, 0x0349, 0x0317, 0x02e4,
143 0x02b2, 0x0280, 0x024e, 0x021d, 0x01ec, 0x01bd, 0x018e, 0x0160,
144 0x0133, 0x0106, 0x00da, 0x00b1, 0x008a, 0x0064, 0x0040, 0x001f,
145 0x0000, 0x3fe3, 0x3fc8, 0x3faf, 0x3f98, 0x3f84, 0x3f71, 0x3f60
146 },
147 [MALIDP_DOWNSCALING_4_COEFFS - 1] = {
148 0x0094, 0x00a9, 0x00be, 0x00d4, 0x00ea, 0x0101, 0x0118, 0x012f,
149 0x0148, 0x0160, 0x017a, 0x0193, 0x01ae, 0x01c8, 0x01e4, 0x01ff,
150 0x021c, 0x0233, 0x024a, 0x0261, 0x0278, 0x028f, 0x02a6, 0x02bd,
151 0x02d4, 0x02eb, 0x0302, 0x0319, 0x032f, 0x0346, 0x035d, 0x0374,
152 0x038a, 0x0397, 0x03a3, 0x03af, 0x03bb, 0x03c6, 0x03d1, 0x03db,
153 0x03e4, 0x03ed, 0x03f6, 0x03fe, 0x0406, 0x040d, 0x0414, 0x041a,
154 0x0420, 0x041a, 0x0414, 0x040d, 0x0406, 0x03fe, 0x03f6, 0x03ed,
155 0x03e4, 0x03db, 0x03d1, 0x03c6, 0x03bb, 0x03af, 0x03a3, 0x0397,
156 0x038a, 0x0374, 0x035d, 0x0346, 0x032f, 0x0319, 0x0302, 0x02eb,
157 0x02d4, 0x02bd, 0x02a6, 0x028f, 0x0278, 0x0261, 0x024a, 0x0233,
158 0x021c, 0x01ff, 0x01e4, 0x01c8, 0x01ae, 0x0193, 0x017a, 0x0160,
159 0x0148, 0x012f, 0x0118, 0x0101, 0x00ea, 0x00d4, 0x00be, 0x00a9
160 },
161};
162
89#define MALIDP_DE_DEFAULT_PREFETCH_START 5 163#define MALIDP_DE_DEFAULT_PREFETCH_START 5
90 164
91static int malidp500_query_hw(struct malidp_hw_device *hwdev) 165static 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
211 return w * drm_format_plane_cpp(fmt, 0) * 8; 285 return w * drm_format_plane_cpp(fmt, 0) * 8;
212} 286}
213 287
288static void malidp500_se_write_pp_coefftab(struct malidp_hw_device *hwdev,
289 u32 direction,
290 u16 addr,
291 u8 coeffs_id)
292{
293 int i;
294 u16 scaling_control = MALIDP500_SE_CONTROL + MALIDP_SE_SCALING_CONTROL;
295
296 malidp_hw_write(hwdev,
297 direction | (addr & MALIDP_SE_COEFFTAB_ADDR_MASK),
298 scaling_control + MALIDP_SE_COEFFTAB_ADDR);
299 for (i = 0; i < ARRAY_SIZE(dp500_se_scaling_coeffs); ++i)
300 malidp_hw_write(hwdev, MALIDP_SE_SET_COEFFTAB_DATA(
301 dp500_se_scaling_coeffs[coeffs_id][i]),
302 scaling_control + MALIDP_SE_COEFFTAB_DATA);
303}
304
305static int malidp500_se_set_scaling_coeffs(struct malidp_hw_device *hwdev,
306 struct malidp_se_config *se_config,
307 struct malidp_se_config *old_config)
308{
309 /* Get array indices into dp500_se_scaling_coeffs. */
310 u8 h = (u8)se_config->hcoeff - 1;
311 u8 v = (u8)se_config->vcoeff - 1;
312
313 if (WARN_ON(h >= ARRAY_SIZE(dp500_se_scaling_coeffs) ||
314 v >= ARRAY_SIZE(dp500_se_scaling_coeffs)))
315 return -EINVAL;
316
317 if ((h == v) && (se_config->hcoeff != old_config->hcoeff ||
318 se_config->vcoeff != old_config->vcoeff)) {
319 malidp500_se_write_pp_coefftab(hwdev,
320 (MALIDP_SE_V_COEFFTAB |
321 MALIDP_SE_H_COEFFTAB),
322 0, v);
323 } else {
324 if (se_config->vcoeff != old_config->vcoeff)
325 malidp500_se_write_pp_coefftab(hwdev,
326 MALIDP_SE_V_COEFFTAB,
327 0, v);
328 if (se_config->hcoeff != old_config->hcoeff)
329 malidp500_se_write_pp_coefftab(hwdev,
330 MALIDP_SE_H_COEFFTAB,
331 0, h);
332 }
333
334 return 0;
335}
336
214static int malidp550_query_hw(struct malidp_hw_device *hwdev) 337static int malidp550_query_hw(struct malidp_hw_device *hwdev)
215{ 338{
216 u32 conf = malidp_hw_read(hwdev, MALIDP550_CONFIG_ID); 339 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
384 return w * bytes_per_col; 507 return w * bytes_per_col;
385} 508}
386 509
510static int malidp550_se_set_scaling_coeffs(struct malidp_hw_device *hwdev,
511 struct malidp_se_config *se_config,
512 struct malidp_se_config *old_config)
513{
514 u32 mask = MALIDP550_SE_CTL_VCSEL(MALIDP550_SE_CTL_SEL_MASK) |
515 MALIDP550_SE_CTL_HCSEL(MALIDP550_SE_CTL_SEL_MASK);
516 u32 new_value = MALIDP550_SE_CTL_VCSEL(se_config->vcoeff) |
517 MALIDP550_SE_CTL_HCSEL(se_config->hcoeff);
518
519 malidp_hw_clearbits(hwdev, mask, MALIDP550_SE_CONTROL);
520 malidp_hw_setbits(hwdev, new_value, MALIDP550_SE_CONTROL);
521 return 0;
522}
523
387static int malidp650_query_hw(struct malidp_hw_device *hwdev) 524static int malidp650_query_hw(struct malidp_hw_device *hwdev)
388{ 525{
389 u32 conf = malidp_hw_read(hwdev, MALIDP550_CONFIG_ID); 526 u32 conf = malidp_hw_read(hwdev, MALIDP550_CONFIG_ID);
@@ -448,6 +585,7 @@ const struct malidp_hw_device malidp_device[MALIDP_MAX_DEVICES] = {
448 .set_config_valid = malidp500_set_config_valid, 585 .set_config_valid = malidp500_set_config_valid,
449 .modeset = malidp500_modeset, 586 .modeset = malidp500_modeset,
450 .rotmem_required = malidp500_rotmem_required, 587 .rotmem_required = malidp500_rotmem_required,
588 .se_set_scaling_coeffs = malidp500_se_set_scaling_coeffs,
451 .features = MALIDP_DEVICE_LV_HAS_3_STRIDES, 589 .features = MALIDP_DEVICE_LV_HAS_3_STRIDES,
452 }, 590 },
453 [MALIDP_550] = { 591 [MALIDP_550] = {
@@ -483,6 +621,7 @@ const struct malidp_hw_device malidp_device[MALIDP_MAX_DEVICES] = {
483 .set_config_valid = malidp550_set_config_valid, 621 .set_config_valid = malidp550_set_config_valid,
484 .modeset = malidp550_modeset, 622 .modeset = malidp550_modeset,
485 .rotmem_required = malidp550_rotmem_required, 623 .rotmem_required = malidp550_rotmem_required,
624 .se_set_scaling_coeffs = malidp550_se_set_scaling_coeffs,
486 .features = 0, 625 .features = 0,
487 }, 626 },
488 [MALIDP_650] = { 627 [MALIDP_650] = {
@@ -519,6 +658,7 @@ const struct malidp_hw_device malidp_device[MALIDP_MAX_DEVICES] = {
519 .set_config_valid = malidp550_set_config_valid, 658 .set_config_valid = malidp550_set_config_valid,
520 .modeset = malidp550_modeset, 659 .modeset = malidp550_modeset,
521 .rotmem_required = malidp550_rotmem_required, 660 .rotmem_required = malidp550_rotmem_required,
661 .se_set_scaling_coeffs = malidp550_se_set_scaling_coeffs,
522 .features = 0, 662 .features = 0,
523 }, 663 },
524}; 664};
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 {
61 u16 stride_offset; /* Offset to the first stride register. */ 61 u16 stride_offset; /* Offset to the first stride register. */
62}; 62};
63 63
64enum malidp_scaling_coeff_set {
65 MALIDP_UPSCALING_COEFFS = 1,
66 MALIDP_DOWNSCALING_1_5_COEFFS = 2,
67 MALIDP_DOWNSCALING_2_COEFFS = 3,
68 MALIDP_DOWNSCALING_2_75_COEFFS = 4,
69 MALIDP_DOWNSCALING_4_COEFFS = 5,
70};
71
72struct malidp_se_config {
73 u8 scale_enable : 1;
74 u8 hcoeff : 3;
75 u8 vcoeff : 3;
76 u8 plane_src_id;
77 u16 input_w, input_h;
78 u16 output_w, output_h;
79 u32 h_init_phase, h_delta_phase;
80 u32 v_init_phase, v_delta_phase;
81};
82
64/* regmap features */ 83/* regmap features */
65#define MALIDP_REGMAP_HAS_CLEARIRQ (1 << 0) 84#define MALIDP_REGMAP_HAS_CLEARIRQ (1 << 0)
66 85
@@ -153,6 +172,10 @@ struct malidp_hw_device {
153 */ 172 */
154 int (*rotmem_required)(struct malidp_hw_device *hwdev, u16 w, u16 h, u32 fmt); 173 int (*rotmem_required)(struct malidp_hw_device *hwdev, u16 w, u16 h, u32 fmt);
155 174
175 int (*se_set_scaling_coeffs)(struct malidp_hw_device *hwdev,
176 struct malidp_se_config *se_config,
177 struct malidp_se_config *old_config);
178
156 u8 features; 179 u8 features;
157 180
158 u8 min_line_size; 181 u8 min_line_size;
@@ -250,6 +273,28 @@ static inline bool malidp_hw_pitch_valid(struct malidp_hw_device *hwdev,
250 return !(pitch & (hwdev->map.bus_align_bytes - 1)); 273 return !(pitch & (hwdev->map.bus_align_bytes - 1));
251} 274}
252 275
276/* U16.16 */
277#define FP_1_00000 0x00010000 /* 1.0 */
278#define FP_0_66667 0x0000AAAA /* 0.6667 = 1/1.5 */
279#define FP_0_50000 0x00008000 /* 0.5 = 1/2 */
280#define FP_0_36363 0x00005D17 /* 0.36363 = 1/2.75 */
281#define FP_0_25000 0x00004000 /* 0.25 = 1/4 */
282
283static inline enum malidp_scaling_coeff_set
284malidp_se_select_coeffs(u32 upscale_factor)
285{
286 return (upscale_factor >= FP_1_00000) ? MALIDP_UPSCALING_COEFFS :
287 (upscale_factor >= FP_0_66667) ? MALIDP_DOWNSCALING_1_5_COEFFS :
288 (upscale_factor >= FP_0_50000) ? MALIDP_DOWNSCALING_2_COEFFS :
289 (upscale_factor >= FP_0_36363) ? MALIDP_DOWNSCALING_2_75_COEFFS :
290 MALIDP_DOWNSCALING_4_COEFFS;
291}
292
293#undef FP_0_25000
294#undef FP_0_36363
295#undef FP_0_50000
296#undef FP_0_66667
297#undef FP_1_00000
253/* 298/*
254 * background color components are defined as 12bits values, 299 * background color components are defined as 12bits values,
255 * they will be shifted right when stored on hardware that 300 * 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..814fda23cead 100644
--- a/drivers/gpu/drm/arm/malidp_planes.c
+++ b/drivers/gpu/drm/arm/malidp_planes.c
@@ -25,6 +25,9 @@
25#define MALIDP_LAYER_FORMAT 0x000 25#define MALIDP_LAYER_FORMAT 0x000
26#define MALIDP_LAYER_CONTROL 0x004 26#define MALIDP_LAYER_CONTROL 0x004
27#define LAYER_ENABLE (1 << 0) 27#define LAYER_ENABLE (1 << 0)
28#define LAYER_FLOWCFG_MASK 7
29#define LAYER_FLOWCFG(x) (((x) & LAYER_FLOWCFG_MASK) << 1)
30#define LAYER_FLOWCFG_SCALE_SE 3
28#define LAYER_ROT_OFFSET 8 31#define LAYER_ROT_OFFSET 8
29#define LAYER_H_FLIP (1 << 10) 32#define LAYER_H_FLIP (1 << 10)
30#define LAYER_V_FLIP (1 << 11) 33#define LAYER_V_FLIP (1 << 11)
@@ -133,16 +136,50 @@ static const struct drm_plane_funcs malidp_de_plane_funcs = {
133 .atomic_print_state = malidp_plane_atomic_print_state, 136 .atomic_print_state = malidp_plane_atomic_print_state,
134}; 137};
135 138
139static int malidp_se_check_scaling(struct malidp_plane *mp,
140 struct drm_plane_state *state)
141{
142 struct drm_crtc_state *crtc_state =
143 drm_atomic_get_existing_crtc_state(state->state, state->crtc);
144 struct malidp_crtc_state *mc;
145 struct drm_rect clip = { 0 };
146 u32 src_w, src_h;
147 int ret;
148
149 if (!crtc_state)
150 return -EINVAL;
151
152 clip.x2 = crtc_state->adjusted_mode.hdisplay;
153 clip.y2 = crtc_state->adjusted_mode.vdisplay;
154 ret = drm_plane_helper_check_state(state, &clip, 0, INT_MAX, true, true);
155 if (ret)
156 return ret;
157
158 src_w = state->src_w >> 16;
159 src_h = state->src_h >> 16;
160 if ((state->crtc_w == src_w) && (state->crtc_h == src_h)) {
161 /* Scaling not necessary for this plane. */
162 mc->scaled_planes_mask &= ~(mp->layer->id);
163 return 0;
164 }
165
166 if (mp->layer->id & (DE_SMART | DE_GRAPHICS2))
167 return -EINVAL;
168
169 mc = to_malidp_crtc_state(crtc_state);
170
171 mc->scaled_planes_mask |= mp->layer->id;
172 /* Defer scaling requirements calculation to the crtc check. */
173 return 0;
174}
175
136static int malidp_de_plane_check(struct drm_plane *plane, 176static int malidp_de_plane_check(struct drm_plane *plane,
137 struct drm_plane_state *state) 177 struct drm_plane_state *state)
138{ 178{
139 struct malidp_plane *mp = to_malidp_plane(plane); 179 struct malidp_plane *mp = to_malidp_plane(plane);
140 struct malidp_plane_state *ms = to_malidp_plane_state(state); 180 struct malidp_plane_state *ms = to_malidp_plane_state(state);
141 struct drm_crtc_state *crtc_state;
142 struct drm_framebuffer *fb; 181 struct drm_framebuffer *fb;
143 struct drm_rect clip = { 0 };
144 int i, ret; 182 int i, ret;
145 u32 src_w, src_h;
146 183
147 if (!state->crtc || !state->fb) 184 if (!state->crtc || !state->fb)
148 return 0; 185 return 0;
@@ -163,9 +200,6 @@ static int malidp_de_plane_check(struct drm_plane *plane,
163 } 200 }
164 } 201 }
165 202
166 src_w = state->src_w >> 16;
167 src_h = state->src_h >> 16;
168
169 if ((state->crtc_w > mp->hwdev->max_line_size) || 203 if ((state->crtc_w > mp->hwdev->max_line_size) ||
170 (state->crtc_h > mp->hwdev->max_line_size) || 204 (state->crtc_h > mp->hwdev->max_line_size) ||
171 (state->crtc_w < mp->hwdev->min_line_size) || 205 (state->crtc_w < mp->hwdev->min_line_size) ||
@@ -182,22 +216,16 @@ static int malidp_de_plane_check(struct drm_plane *plane,
182 (state->fb->pitches[1] != state->fb->pitches[2])) 216 (state->fb->pitches[1] != state->fb->pitches[2]))
183 return -EINVAL; 217 return -EINVAL;
184 218
219 ret = malidp_se_check_scaling(mp, state);
220 if (ret)
221 return ret;
222
185 /* packed RGB888 / BGR888 can't be rotated or flipped */ 223 /* packed RGB888 / BGR888 can't be rotated or flipped */
186 if (state->rotation != DRM_ROTATE_0 && 224 if (state->rotation != DRM_ROTATE_0 &&
187 (fb->format->format == DRM_FORMAT_RGB888 || 225 (fb->format->format == DRM_FORMAT_RGB888 ||
188 fb->format->format == DRM_FORMAT_BGR888)) 226 fb->format->format == DRM_FORMAT_BGR888))
189 return -EINVAL; 227 return -EINVAL;
190 228
191 crtc_state = drm_atomic_get_existing_crtc_state(state->state, state->crtc);
192 clip.x2 = crtc_state->adjusted_mode.hdisplay;
193 clip.y2 = crtc_state->adjusted_mode.vdisplay;
194 ret = drm_plane_helper_check_state(state, &clip,
195 DRM_PLANE_HELPER_NO_SCALING,
196 DRM_PLANE_HELPER_NO_SCALING,
197 true, true);
198 if (ret)
199 return ret;
200
201 ms->rotmem_size = 0; 229 ms->rotmem_size = 0;
202 if (state->rotation & MALIDP_ROTATED_MASK) { 230 if (state->rotation & MALIDP_ROTATED_MASK) {
203 int val; 231 int val;
@@ -302,6 +330,16 @@ static void malidp_de_plane_update(struct drm_plane *plane,
302 val &= ~LAYER_COMP_MASK; 330 val &= ~LAYER_COMP_MASK;
303 val |= LAYER_COMP_PIXEL; 331 val |= LAYER_COMP_PIXEL;
304 332
333 val &= ~LAYER_FLOWCFG(LAYER_FLOWCFG_MASK);
334 if (plane->state->crtc) {
335 struct malidp_crtc_state *m =
336 to_malidp_crtc_state(plane->state->crtc->state);
337
338 if (m->scaler_config.scale_enable &&
339 m->scaler_config.plane_src_id == mp->layer->id)
340 val |= LAYER_FLOWCFG(LAYER_FLOWCFG_SCALE_SE);
341 }
342
305 /* set the 'enable layer' bit */ 343 /* set the 'enable layer' bit */
306 val |= LAYER_ENABLE; 344 val |= LAYER_ENABLE;
307 345
@@ -314,7 +352,8 @@ static void malidp_de_plane_disable(struct drm_plane *plane,
314{ 352{
315 struct malidp_plane *mp = to_malidp_plane(plane); 353 struct malidp_plane *mp = to_malidp_plane(plane);
316 354
317 malidp_hw_clearbits(mp->hwdev, LAYER_ENABLE, 355 malidp_hw_clearbits(mp->hwdev,
356 LAYER_ENABLE | LAYER_FLOWCFG(LAYER_FLOWCFG_MASK),
318 mp->layer->base + MALIDP_LAYER_CONTROL); 357 mp->layer->base + MALIDP_LAYER_CONTROL);
319} 358}
320 359
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 @@
106#define MALIDP_COEF_TABLE_ADDR 0x00030 106#define MALIDP_COEF_TABLE_ADDR 0x00030
107#define MALIDP_COEF_TABLE_DATA 0x00034 107#define MALIDP_COEF_TABLE_DATA 0x00034
108 108
109/* Scaling engine registers and masks. */
110#define MALIDP_SE_SCALING_EN (1 << 0)
111#define MALIDP_SE_ALPHA_EN (1 << 1)
112#define MALIDP_SE_RGBO_IF_EN (1 << 4)
113#define MALIDP550_SE_CTL_SEL_MASK 7
114#define MALIDP550_SE_CTL_VCSEL(x) \
115 (((x) & MALIDP550_SE_CTL_SEL_MASK) << 20)
116#define MALIDP550_SE_CTL_HCSEL(x) \
117 (((x) & MALIDP550_SE_CTL_SEL_MASK) << 16)
118
119/* Blocks with offsets from SE_CONTROL register. */
120#define MALIDP_SE_LAYER_CONTROL 0x14
121#define MALIDP_SE_L0_IN_SIZE 0x00
122#define MALIDP_SE_L0_OUT_SIZE 0x04
123#define MALIDP_SE_SET_V_SIZE(x) (((x) & 0x1fff) << 16)
124#define MALIDP_SE_SET_H_SIZE(x) (((x) & 0x1fff) << 0)
125#define MALIDP_SE_SCALING_CONTROL 0x24
126#define MALIDP_SE_H_INIT_PH 0x00
127#define MALIDP_SE_H_DELTA_PH 0x04
128#define MALIDP_SE_V_INIT_PH 0x08
129#define MALIDP_SE_V_DELTA_PH 0x0c
130#define MALIDP_SE_COEFFTAB_ADDR 0x10
131#define MALIDP_SE_COEFFTAB_ADDR_MASK 0x7f
132#define MALIDP_SE_V_COEFFTAB (1 << 8)
133#define MALIDP_SE_H_COEFFTAB (1 << 9)
134#define MALIDP_SE_SET_V_COEFFTAB_ADDR(x) \
135 (MALIDP_SE_V_COEFFTAB | ((x) & MALIDP_SE_COEFFTAB_ADDR_MASK))
136#define MALIDP_SE_SET_H_COEFFTAB_ADDR(x) \
137 (MALIDP_SE_H_COEFFTAB | ((x) & MALIDP_SE_COEFFTAB_ADDR_MASK))
138#define MALIDP_SE_COEFFTAB_DATA 0x14
139#define MALIDP_SE_COEFFTAB_DATA_MASK 0x3fff
140#define MALIDP_SE_SET_COEFFTAB_DATA(x) \
141 ((x) & MALIDP_SE_COEFFTAB_DATA_MASK)
142
109/* register offsets and bits specific to DP500 */ 143/* register offsets and bits specific to DP500 */
110#define MALIDP500_ADDR_SPACE_SIZE 0x01000 144#define MALIDP500_ADDR_SPACE_SIZE 0x01000
111#define MALIDP500_DC_BASE 0x00000 145#define MALIDP500_DC_BASE 0x00000
@@ -146,6 +180,7 @@
146#define MALIDP500_DE_LG2_BASE 0x00300 180#define MALIDP500_DE_LG2_BASE 0x00300
147#define MALIDP500_DE_LG2_PTR_BASE 0x0031c 181#define MALIDP500_DE_LG2_PTR_BASE 0x0031c
148#define MALIDP500_SE_BASE 0x00c00 182#define MALIDP500_SE_BASE 0x00c00
183#define MALIDP500_SE_CONTROL 0x00c0c
149#define MALIDP500_SE_PTR_BASE 0x00e0c 184#define MALIDP500_SE_PTR_BASE 0x00e0c
150#define MALIDP500_DC_IRQ_BASE 0x00f00 185#define MALIDP500_DC_IRQ_BASE 0x00f00
151#define MALIDP500_CONFIG_VALID 0x00f00 186#define MALIDP500_CONFIG_VALID 0x00f00
@@ -175,6 +210,7 @@
175#define MALIDP550_DE_LS_PTR_BASE 0x0042c 210#define MALIDP550_DE_LS_PTR_BASE 0x0042c
176#define MALIDP550_DE_PERF_BASE 0x00500 211#define MALIDP550_DE_PERF_BASE 0x00500
177#define MALIDP550_SE_BASE 0x08000 212#define MALIDP550_SE_BASE 0x08000
213#define MALIDP550_SE_CONTROL 0x08010
178#define MALIDP550_DC_BASE 0x0c000 214#define MALIDP550_DC_BASE 0x0c000
179#define MALIDP550_DC_CONTROL 0x0c010 215#define MALIDP550_DC_CONTROL 0x0c010
180#define MALIDP550_DC_CONFIG_REQ (1 << 16) 216#define MALIDP550_DC_CONFIG_REQ (1 << 16)