aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm
diff options
context:
space:
mode:
authorDave Airlie <airlied@redhat.com>2017-04-28 15:48:45 -0400
committerDave Airlie <airlied@redhat.com>2017-04-28 15:48:45 -0400
commit97643d75b053cd2aa7b23a93a474ed3690e34384 (patch)
treeea546747872e054429aab11defc21a0987ccd898 /drivers/gpu/drm
parent6b1462700b4a6a1244c018cdd2fa97ded43090a0 (diff)
parent763656d30b3d220a52e4b2bd1fc174a4cd6c0f43 (diff)
Merge branch 'for-upstream/mali-dp' of git://linux-arm.org/linux-ld into drm-next
Latest updates on Mali DP, adding support for colour management, plane scaling and power management. (these have been in -next for a while). * 'for-upstream/mali-dp' of git://linux-arm.org/linux-ld: drm: mali-dp: use div_u64 for expensive 64-bit divisions drm: mali-dp: Check the mclk rate and allow up/down scaling drm: mali-dp: Enable image enhancement when scaling drm: mali-dp: Add plane upscaling support drm/mali-dp: Add core_id file to the sysfs interface drm: mali-dp: Add CTM support drm: mali-dp: enable gamma support drm: mali-dp: add malidp_crtc_state struct drm: mali-dp: add custom reset hook for planes drm: mali-dp: remove unused variable drm: mali-dp: add atomic_print_state for planes drm: mali-dp: Enable power management for the device. drm: mali-dp: Update the state of all planes before re-enabling active CRTCs.
Diffstat (limited to 'drivers/gpu/drm')
-rw-r--r--drivers/gpu/drm/arm/malidp_crtc.c341
-rw-r--r--drivers/gpu/drm/arm/malidp_drv.c307
-rw-r--r--drivers/gpu/drm/arm/malidp_drv.h13
-rw-r--r--drivers/gpu/drm/arm/malidp_hw.c213
-rw-r--r--drivers/gpu/drm/arm/malidp_hw.h81
-rw-r--r--drivers/gpu/drm/arm/malidp_planes.c108
-rw-r--r--drivers/gpu/drm/arm/malidp_regs.h72
7 files changed, 1073 insertions, 62 deletions
diff --git a/drivers/gpu/drm/arm/malidp_crtc.c b/drivers/gpu/drm/arm/malidp_crtc.c
index f9d665550d3e..9446a673d469 100644
--- a/drivers/gpu/drm/arm/malidp_crtc.c
+++ b/drivers/gpu/drm/arm/malidp_crtc.c
@@ -16,6 +16,7 @@
16#include <drm/drm_crtc.h> 16#include <drm/drm_crtc.h>
17#include <drm/drm_crtc_helper.h> 17#include <drm/drm_crtc_helper.h>
18#include <linux/clk.h> 18#include <linux/clk.h>
19#include <linux/pm_runtime.h>
19#include <video/videomode.h> 20#include <video/videomode.h>
20 21
21#include "malidp_drv.h" 22#include "malidp_drv.h"
@@ -35,13 +36,6 @@ static bool malidp_crtc_mode_fixup(struct drm_crtc *crtc,
35 long rate, req_rate = mode->crtc_clock * 1000; 36 long rate, req_rate = mode->crtc_clock * 1000;
36 37
37 if (req_rate) { 38 if (req_rate) {
38 rate = clk_round_rate(hwdev->mclk, req_rate);
39 if (rate < req_rate) {
40 DRM_DEBUG_DRIVER("mclk clock unable to reach %d kHz\n",
41 mode->crtc_clock);
42 return false;
43 }
44
45 rate = clk_round_rate(hwdev->pxlclk, req_rate); 39 rate = clk_round_rate(hwdev->pxlclk, req_rate);
46 if (rate != req_rate) { 40 if (rate != req_rate) {
47 DRM_DEBUG_DRIVER("pxlclk doesn't support %ld Hz\n", 41 DRM_DEBUG_DRIVER("pxlclk doesn't support %ld Hz\n",
@@ -58,9 +52,14 @@ static void malidp_crtc_enable(struct drm_crtc *crtc)
58 struct malidp_drm *malidp = crtc_to_malidp_device(crtc); 52 struct malidp_drm *malidp = crtc_to_malidp_device(crtc);
59 struct malidp_hw_device *hwdev = malidp->dev; 53 struct malidp_hw_device *hwdev = malidp->dev;
60 struct videomode vm; 54 struct videomode vm;
55 int err = pm_runtime_get_sync(crtc->dev->dev);
61 56
62 drm_display_mode_to_videomode(&crtc->state->adjusted_mode, &vm); 57 if (err < 0) {
58 DRM_DEBUG_DRIVER("Failed to enable runtime power management: %d\n", err);
59 return;
60 }
63 61
62 drm_display_mode_to_videomode(&crtc->state->adjusted_mode, &vm);
64 clk_prepare_enable(hwdev->pxlclk); 63 clk_prepare_enable(hwdev->pxlclk);
65 64
66 /* We rely on firmware to set mclk to a sensible level. */ 65 /* We rely on firmware to set mclk to a sensible level. */
@@ -75,10 +74,254 @@ static void malidp_crtc_disable(struct drm_crtc *crtc)
75{ 74{
76 struct malidp_drm *malidp = crtc_to_malidp_device(crtc); 75 struct malidp_drm *malidp = crtc_to_malidp_device(crtc);
77 struct malidp_hw_device *hwdev = malidp->dev; 76 struct malidp_hw_device *hwdev = malidp->dev;
77 int err;
78 78
79 drm_crtc_vblank_off(crtc); 79 drm_crtc_vblank_off(crtc);
80 hwdev->enter_config_mode(hwdev); 80 hwdev->enter_config_mode(hwdev);
81 clk_disable_unprepare(hwdev->pxlclk); 81 clk_disable_unprepare(hwdev->pxlclk);
82
83 err = pm_runtime_put(crtc->dev->dev);
84 if (err < 0) {
85 DRM_DEBUG_DRIVER("Failed to disable runtime power management: %d\n", err);
86 }
87}
88
89static const struct gamma_curve_segment {
90 u16 start;
91 u16 end;
92} segments[MALIDP_COEFFTAB_NUM_COEFFS] = {
93 /* sector 0 */
94 { 0, 0 }, { 1, 1 }, { 2, 2 }, { 3, 3 },
95 { 4, 4 }, { 5, 5 }, { 6, 6 }, { 7, 7 },
96 { 8, 8 }, { 9, 9 }, { 10, 10 }, { 11, 11 },
97 { 12, 12 }, { 13, 13 }, { 14, 14 }, { 15, 15 },
98 /* sector 1 */
99 { 16, 19 }, { 20, 23 }, { 24, 27 }, { 28, 31 },
100 /* sector 2 */
101 { 32, 39 }, { 40, 47 }, { 48, 55 }, { 56, 63 },
102 /* sector 3 */
103 { 64, 79 }, { 80, 95 }, { 96, 111 }, { 112, 127 },
104 /* sector 4 */
105 { 128, 159 }, { 160, 191 }, { 192, 223 }, { 224, 255 },
106 /* sector 5 */
107 { 256, 319 }, { 320, 383 }, { 384, 447 }, { 448, 511 },
108 /* sector 6 */
109 { 512, 639 }, { 640, 767 }, { 768, 895 }, { 896, 1023 },
110 { 1024, 1151 }, { 1152, 1279 }, { 1280, 1407 }, { 1408, 1535 },
111 { 1536, 1663 }, { 1664, 1791 }, { 1792, 1919 }, { 1920, 2047 },
112 { 2048, 2175 }, { 2176, 2303 }, { 2304, 2431 }, { 2432, 2559 },
113 { 2560, 2687 }, { 2688, 2815 }, { 2816, 2943 }, { 2944, 3071 },
114 { 3072, 3199 }, { 3200, 3327 }, { 3328, 3455 }, { 3456, 3583 },
115 { 3584, 3711 }, { 3712, 3839 }, { 3840, 3967 }, { 3968, 4095 },
116};
117
118#define DE_COEFTAB_DATA(a, b) ((((a) & 0xfff) << 16) | (((b) & 0xfff)))
119
120static void malidp_generate_gamma_table(struct drm_property_blob *lut_blob,
121 u32 coeffs[MALIDP_COEFFTAB_NUM_COEFFS])
122{
123 struct drm_color_lut *lut = (struct drm_color_lut *)lut_blob->data;
124 int i;
125
126 for (i = 0; i < MALIDP_COEFFTAB_NUM_COEFFS; ++i) {
127 u32 a, b, delta_in, out_start, out_end;
128
129 delta_in = segments[i].end - segments[i].start;
130 /* DP has 12-bit internal precision for its LUTs. */
131 out_start = drm_color_lut_extract(lut[segments[i].start].green,
132 12);
133 out_end = drm_color_lut_extract(lut[segments[i].end].green, 12);
134 a = (delta_in == 0) ? 0 : ((out_end - out_start) * 256) / delta_in;
135 b = out_start;
136 coeffs[i] = DE_COEFTAB_DATA(a, b);
137 }
138}
139
140/*
141 * Check if there is a new gamma LUT and if it is of an acceptable size. Also,
142 * reject any LUTs that use distinct red, green, and blue curves.
143 */
144static int malidp_crtc_atomic_check_gamma(struct drm_crtc *crtc,
145 struct drm_crtc_state *state)
146{
147 struct malidp_crtc_state *mc = to_malidp_crtc_state(state);
148 struct drm_color_lut *lut;
149 size_t lut_size;
150 int i;
151
152 if (!state->color_mgmt_changed || !state->gamma_lut)
153 return 0;
154
155 if (crtc->state->gamma_lut &&
156 (crtc->state->gamma_lut->base.id == state->gamma_lut->base.id))
157 return 0;
158
159 if (state->gamma_lut->length % sizeof(struct drm_color_lut))
160 return -EINVAL;
161
162 lut_size = state->gamma_lut->length / sizeof(struct drm_color_lut);
163 if (lut_size != MALIDP_GAMMA_LUT_SIZE)
164 return -EINVAL;
165
166 lut = (struct drm_color_lut *)state->gamma_lut->data;
167 for (i = 0; i < lut_size; ++i)
168 if (!((lut[i].red == lut[i].green) &&
169 (lut[i].red == lut[i].blue)))
170 return -EINVAL;
171
172 if (!state->mode_changed) {
173 int ret;
174
175 state->mode_changed = true;
176 /*
177 * Kerneldoc for drm_atomic_helper_check_modeset mandates that
178 * it be invoked when the driver sets ->mode_changed. Since
179 * changing the gamma LUT doesn't depend on any external
180 * resources, it is safe to call it only once.
181 */
182 ret = drm_atomic_helper_check_modeset(crtc->dev, state->state);
183 if (ret)
184 return ret;
185 }
186
187 malidp_generate_gamma_table(state->gamma_lut, mc->gamma_coeffs);
188 return 0;
189}
190
191/*
192 * Check if there is a new CTM and if it contains valid input. Valid here means
193 * that the number is inside the representable range for a Q3.12 number,
194 * excluding truncating the fractional part of the input data.
195 *
196 * The COLORADJ registers can be changed atomically.
197 */
198static int malidp_crtc_atomic_check_ctm(struct drm_crtc *crtc,
199 struct drm_crtc_state *state)
200{
201 struct malidp_crtc_state *mc = to_malidp_crtc_state(state);
202 struct drm_color_ctm *ctm;
203 int i;
204
205 if (!state->color_mgmt_changed)
206 return 0;
207
208 if (!state->ctm)
209 return 0;
210
211 if (crtc->state->ctm && (crtc->state->ctm->base.id ==
212 state->ctm->base.id))
213 return 0;
214
215 /*
216 * The size of the ctm is checked in
217 * drm_atomic_replace_property_blob_from_id.
218 */
219 ctm = (struct drm_color_ctm *)state->ctm->data;
220 for (i = 0; i < ARRAY_SIZE(ctm->matrix); ++i) {
221 /* Convert from S31.32 to Q3.12. */
222 s64 val = ctm->matrix[i];
223 u32 mag = ((((u64)val) & ~BIT_ULL(63)) >> 20) &
224 GENMASK_ULL(14, 0);
225
226 /*
227 * Convert to 2s complement and check the destination's top bit
228 * for overflow. NB: Can't check before converting or it'd
229 * incorrectly reject the case:
230 * sign == 1
231 * mag == 0x2000
232 */
233 if (val & BIT_ULL(63))
234 mag = ~mag + 1;
235 if (!!(val & BIT_ULL(63)) != !!(mag & BIT(14)))
236 return -EINVAL;
237 mc->coloradj_coeffs[i] = mag;
238 }
239
240 return 0;
241}
242
243static int malidp_crtc_atomic_check_scaling(struct drm_crtc *crtc,
244 struct drm_crtc_state *state)
245{
246 struct malidp_drm *malidp = crtc_to_malidp_device(crtc);
247 struct malidp_hw_device *hwdev = malidp->dev;
248 struct malidp_crtc_state *cs = to_malidp_crtc_state(state);
249 struct malidp_se_config *s = &cs->scaler_config;
250 struct drm_plane *plane;
251 struct videomode vm;
252 const struct drm_plane_state *pstate;
253 u32 h_upscale_factor = 0; /* U16.16 */
254 u32 v_upscale_factor = 0; /* U16.16 */
255 u8 scaling = cs->scaled_planes_mask;
256 int ret;
257
258 if (!scaling) {
259 s->scale_enable = false;
260 goto mclk_calc;
261 }
262
263 /* The scaling engine can only handle one plane at a time. */
264 if (scaling & (scaling - 1))
265 return -EINVAL;
266
267 drm_atomic_crtc_state_for_each_plane_state(plane, pstate, state) {
268 struct malidp_plane *mp = to_malidp_plane(plane);
269 u32 phase;
270
271 if (!(mp->layer->id & scaling))
272 continue;
273
274 /*
275 * Convert crtc_[w|h] to U32.32, then divide by U16.16 src_[w|h]
276 * to get the U16.16 result.
277 */
278 h_upscale_factor = div_u64((u64)pstate->crtc_w << 32,
279 pstate->src_w);
280 v_upscale_factor = div_u64((u64)pstate->crtc_h << 32,
281 pstate->src_h);
282
283 s->enhancer_enable = ((h_upscale_factor >> 16) >= 2 ||
284 (v_upscale_factor >> 16) >= 2);
285
286 s->input_w = pstate->src_w >> 16;
287 s->input_h = pstate->src_h >> 16;
288 s->output_w = pstate->crtc_w;
289 s->output_h = pstate->crtc_h;
290
291#define SE_N_PHASE 4
292#define SE_SHIFT_N_PHASE 12
293 /* Calculate initial_phase and delta_phase for horizontal. */
294 phase = s->input_w;
295 s->h_init_phase =
296 ((phase << SE_N_PHASE) / s->output_w + 1) / 2;
297
298 phase = s->input_w;
299 phase <<= (SE_SHIFT_N_PHASE + SE_N_PHASE);
300 s->h_delta_phase = phase / s->output_w;
301
302 /* Same for vertical. */
303 phase = s->input_h;
304 s->v_init_phase =
305 ((phase << SE_N_PHASE) / s->output_h + 1) / 2;
306
307 phase = s->input_h;
308 phase <<= (SE_SHIFT_N_PHASE + SE_N_PHASE);
309 s->v_delta_phase = phase / s->output_h;
310#undef SE_N_PHASE
311#undef SE_SHIFT_N_PHASE
312 s->plane_src_id = mp->layer->id;
313 }
314
315 s->scale_enable = true;
316 s->hcoeff = malidp_se_select_coeffs(h_upscale_factor);
317 s->vcoeff = malidp_se_select_coeffs(v_upscale_factor);
318
319mclk_calc:
320 drm_display_mode_to_videomode(&state->adjusted_mode, &vm);
321 ret = hwdev->se_calc_mclk(hwdev, s, &vm);
322 if (ret < 0)
323 return -EINVAL;
324 return 0;
82} 325}
83 326
84static int malidp_crtc_atomic_check(struct drm_crtc *crtc, 327static int malidp_crtc_atomic_check(struct drm_crtc *crtc,
@@ -90,6 +333,7 @@ static int malidp_crtc_atomic_check(struct drm_crtc *crtc,
90 const struct drm_plane_state *pstate; 333 const struct drm_plane_state *pstate;
91 u32 rot_mem_free, rot_mem_usable; 334 u32 rot_mem_free, rot_mem_usable;
92 int rotated_planes = 0; 335 int rotated_planes = 0;
336 int ret;
93 337
94 /* 338 /*
95 * check if there is enough rotation memory available for planes 339 * check if there is enough rotation memory available for planes
@@ -156,7 +400,11 @@ static int malidp_crtc_atomic_check(struct drm_crtc *crtc,
156 } 400 }
157 } 401 }
158 402
159 return 0; 403 ret = malidp_crtc_atomic_check_gamma(crtc, state);
404 ret = ret ? ret : malidp_crtc_atomic_check_ctm(crtc, state);
405 ret = ret ? ret : malidp_crtc_atomic_check_scaling(crtc, state);
406
407 return ret;
160} 408}
161 409
162static const struct drm_crtc_helper_funcs malidp_crtc_helper_funcs = { 410static const struct drm_crtc_helper_funcs malidp_crtc_helper_funcs = {
@@ -166,6 +414,60 @@ static const struct drm_crtc_helper_funcs malidp_crtc_helper_funcs = {
166 .atomic_check = malidp_crtc_atomic_check, 414 .atomic_check = malidp_crtc_atomic_check,
167}; 415};
168 416
417static struct drm_crtc_state *malidp_crtc_duplicate_state(struct drm_crtc *crtc)
418{
419 struct malidp_crtc_state *state, *old_state;
420
421 if (WARN_ON(!crtc->state))
422 return NULL;
423
424 old_state = to_malidp_crtc_state(crtc->state);
425 state = kmalloc(sizeof(*state), GFP_KERNEL);
426 if (!state)
427 return NULL;
428
429 __drm_atomic_helper_crtc_duplicate_state(crtc, &state->base);
430 memcpy(state->gamma_coeffs, old_state->gamma_coeffs,
431 sizeof(state->gamma_coeffs));
432 memcpy(state->coloradj_coeffs, old_state->coloradj_coeffs,
433 sizeof(state->coloradj_coeffs));
434 memcpy(&state->scaler_config, &old_state->scaler_config,
435 sizeof(state->scaler_config));
436 state->scaled_planes_mask = 0;
437
438 return &state->base;
439}
440
441static void malidp_crtc_reset(struct drm_crtc *crtc)
442{
443 struct malidp_crtc_state *state = NULL;
444
445 if (crtc->state) {
446 state = to_malidp_crtc_state(crtc->state);
447 __drm_atomic_helper_crtc_destroy_state(crtc->state);
448 }
449
450 kfree(state);
451 state = kzalloc(sizeof(*state), GFP_KERNEL);
452 if (state) {
453 crtc->state = &state->base;
454 crtc->state->crtc = crtc;
455 }
456}
457
458static void malidp_crtc_destroy_state(struct drm_crtc *crtc,
459 struct drm_crtc_state *state)
460{
461 struct malidp_crtc_state *mali_state = NULL;
462
463 if (state) {
464 mali_state = to_malidp_crtc_state(state);
465 __drm_atomic_helper_crtc_destroy_state(state);
466 }
467
468 kfree(mali_state);
469}
470
169static int malidp_crtc_enable_vblank(struct drm_crtc *crtc) 471static int malidp_crtc_enable_vblank(struct drm_crtc *crtc)
170{ 472{
171 struct malidp_drm *malidp = crtc_to_malidp_device(crtc); 473 struct malidp_drm *malidp = crtc_to_malidp_device(crtc);
@@ -186,12 +488,13 @@ static void malidp_crtc_disable_vblank(struct drm_crtc *crtc)
186} 488}
187 489
188static const struct drm_crtc_funcs malidp_crtc_funcs = { 490static const struct drm_crtc_funcs malidp_crtc_funcs = {
491 .gamma_set = drm_atomic_helper_legacy_gamma_set,
189 .destroy = drm_crtc_cleanup, 492 .destroy = drm_crtc_cleanup,
190 .set_config = drm_atomic_helper_set_config, 493 .set_config = drm_atomic_helper_set_config,
191 .page_flip = drm_atomic_helper_page_flip, 494 .page_flip = drm_atomic_helper_page_flip,
192 .reset = drm_atomic_helper_crtc_reset, 495 .reset = malidp_crtc_reset,
193 .atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state, 496 .atomic_duplicate_state = malidp_crtc_duplicate_state,
194 .atomic_destroy_state = drm_atomic_helper_crtc_destroy_state, 497 .atomic_destroy_state = malidp_crtc_destroy_state,
195 .enable_vblank = malidp_crtc_enable_vblank, 498 .enable_vblank = malidp_crtc_enable_vblank,
196 .disable_vblank = malidp_crtc_disable_vblank, 499 .disable_vblank = malidp_crtc_disable_vblank,
197}; 500};
@@ -223,11 +526,17 @@ int malidp_crtc_init(struct drm_device *drm)
223 526
224 ret = drm_crtc_init_with_planes(drm, &malidp->crtc, primary, NULL, 527 ret = drm_crtc_init_with_planes(drm, &malidp->crtc, primary, NULL,
225 &malidp_crtc_funcs, NULL); 528 &malidp_crtc_funcs, NULL);
529 if (ret)
530 goto crtc_cleanup_planes;
226 531
227 if (!ret) { 532 drm_crtc_helper_add(&malidp->crtc, &malidp_crtc_helper_funcs);
228 drm_crtc_helper_add(&malidp->crtc, &malidp_crtc_helper_funcs); 533 drm_mode_crtc_set_gamma_size(&malidp->crtc, MALIDP_GAMMA_LUT_SIZE);
229 return 0; 534 /* No inverse-gamma: it is per-plane. */
230 } 535 drm_crtc_enable_color_mgmt(&malidp->crtc, 0, true, MALIDP_GAMMA_LUT_SIZE);
536
537 malidp_se_set_enh_coeffs(malidp->dev);
538
539 return 0;
231 540
232crtc_cleanup_planes: 541crtc_cleanup_planes:
233 malidp_de_planes_destroy(drm); 542 malidp_de_planes_destroy(drm);
diff --git a/drivers/gpu/drm/arm/malidp_drv.c b/drivers/gpu/drm/arm/malidp_drv.c
index 898c2b58e73d..0d3eb537d08b 100644
--- a/drivers/gpu/drm/arm/malidp_drv.c
+++ b/drivers/gpu/drm/arm/malidp_drv.c
@@ -13,9 +13,11 @@
13#include <linux/module.h> 13#include <linux/module.h>
14#include <linux/clk.h> 14#include <linux/clk.h>
15#include <linux/component.h> 15#include <linux/component.h>
16#include <linux/console.h>
16#include <linux/of_device.h> 17#include <linux/of_device.h>
17#include <linux/of_graph.h> 18#include <linux/of_graph.h>
18#include <linux/of_reserved_mem.h> 19#include <linux/of_reserved_mem.h>
20#include <linux/pm_runtime.h>
19 21
20#include <drm/drmP.h> 22#include <drm/drmP.h>
21#include <drm/drm_atomic.h> 23#include <drm/drm_atomic.h>
@@ -32,6 +34,131 @@
32 34
33#define MALIDP_CONF_VALID_TIMEOUT 250 35#define MALIDP_CONF_VALID_TIMEOUT 250
34 36
37static void malidp_write_gamma_table(struct malidp_hw_device *hwdev,
38 u32 data[MALIDP_COEFFTAB_NUM_COEFFS])
39{
40 int i;
41 /* Update all channels with a single gamma curve. */
42 const u32 gamma_write_mask = GENMASK(18, 16);
43 /*
44 * Always write an entire table, so the address field in
45 * DE_COEFFTAB_ADDR is 0 and we can use the gamma_write_mask bitmask
46 * directly.
47 */
48 malidp_hw_write(hwdev, gamma_write_mask,
49 hwdev->map.coeffs_base + MALIDP_COEF_TABLE_ADDR);
50 for (i = 0; i < MALIDP_COEFFTAB_NUM_COEFFS; ++i)
51 malidp_hw_write(hwdev, data[i],
52 hwdev->map.coeffs_base +
53 MALIDP_COEF_TABLE_DATA);
54}
55
56static void malidp_atomic_commit_update_gamma(struct drm_crtc *crtc,
57 struct drm_crtc_state *old_state)
58{
59 struct malidp_drm *malidp = crtc_to_malidp_device(crtc);
60 struct malidp_hw_device *hwdev = malidp->dev;
61
62 if (!crtc->state->color_mgmt_changed)
63 return;
64
65 if (!crtc->state->gamma_lut) {
66 malidp_hw_clearbits(hwdev,
67 MALIDP_DISP_FUNC_GAMMA,
68 MALIDP_DE_DISPLAY_FUNC);
69 } else {
70 struct malidp_crtc_state *mc =
71 to_malidp_crtc_state(crtc->state);
72
73 if (!old_state->gamma_lut || (crtc->state->gamma_lut->base.id !=
74 old_state->gamma_lut->base.id))
75 malidp_write_gamma_table(hwdev, mc->gamma_coeffs);
76
77 malidp_hw_setbits(hwdev, MALIDP_DISP_FUNC_GAMMA,
78 MALIDP_DE_DISPLAY_FUNC);
79 }
80}
81
82static
83void malidp_atomic_commit_update_coloradj(struct drm_crtc *crtc,
84 struct drm_crtc_state *old_state)
85{
86 struct malidp_drm *malidp = crtc_to_malidp_device(crtc);
87 struct malidp_hw_device *hwdev = malidp->dev;
88 int i;
89
90 if (!crtc->state->color_mgmt_changed)
91 return;
92
93 if (!crtc->state->ctm) {
94 malidp_hw_clearbits(hwdev, MALIDP_DISP_FUNC_CADJ,
95 MALIDP_DE_DISPLAY_FUNC);
96 } else {
97 struct malidp_crtc_state *mc =
98 to_malidp_crtc_state(crtc->state);
99
100 if (!old_state->ctm || (crtc->state->ctm->base.id !=
101 old_state->ctm->base.id))
102 for (i = 0; i < MALIDP_COLORADJ_NUM_COEFFS; ++i)
103 malidp_hw_write(hwdev,
104 mc->coloradj_coeffs[i],
105 hwdev->map.coeffs_base +
106 MALIDP_COLOR_ADJ_COEF + 4 * i);
107
108 malidp_hw_setbits(hwdev, MALIDP_DISP_FUNC_CADJ,
109 MALIDP_DE_DISPLAY_FUNC);
110 }
111}
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_ENH(MALIDP_SE_ENH_MASK);
142 val |= s->enhancer_enable ? MALIDP_SE_ENH(3) : 0;
143
144 val |= MALIDP_SE_RGBO_IF_EN;
145 malidp_hw_write(hwdev, val, se_control);
146
147 /* Set IN_SIZE & OUT_SIZE. */
148 val = MALIDP_SE_SET_V_SIZE(s->input_h) |
149 MALIDP_SE_SET_H_SIZE(s->input_w);
150 malidp_hw_write(hwdev, val, layer_control + MALIDP_SE_L0_IN_SIZE);
151 val = MALIDP_SE_SET_V_SIZE(s->output_h) |
152 MALIDP_SE_SET_H_SIZE(s->output_w);
153 malidp_hw_write(hwdev, val, layer_control + MALIDP_SE_L0_OUT_SIZE);
154
155 /* Set phase regs. */
156 malidp_hw_write(hwdev, s->h_init_phase, scr + MALIDP_SE_H_INIT_PH);
157 malidp_hw_write(hwdev, s->h_delta_phase, scr + MALIDP_SE_H_DELTA_PH);
158 malidp_hw_write(hwdev, s->v_init_phase, scr + MALIDP_SE_V_INIT_PH);
159 malidp_hw_write(hwdev, s->v_delta_phase, scr + MALIDP_SE_V_DELTA_PH);
160}
161
35/* 162/*
36 * set the "config valid" bit and wait until the hardware acts on it 163 * set the "config valid" bit and wait until the hardware acts on it
37 */ 164 */
@@ -66,10 +193,12 @@ static void malidp_atomic_commit_hw_done(struct drm_atomic_state *state)
66 struct drm_pending_vblank_event *event; 193 struct drm_pending_vblank_event *event;
67 struct drm_device *drm = state->dev; 194 struct drm_device *drm = state->dev;
68 struct malidp_drm *malidp = drm->dev_private; 195 struct malidp_drm *malidp = drm->dev_private;
69 int ret = malidp_set_and_wait_config_valid(drm);
70 196
71 if (ret) 197 if (malidp->crtc.enabled) {
72 DRM_DEBUG_DRIVER("timed out waiting for updated configuration\n"); 198 /* only set config_valid if the CRTC is enabled */
199 if (malidp_set_and_wait_config_valid(drm))
200 DRM_DEBUG_DRIVER("timed out waiting for updated configuration\n");
201 }
73 202
74 event = malidp->crtc.state->event; 203 event = malidp->crtc.state->event;
75 if (event) { 204 if (event) {
@@ -88,15 +217,30 @@ static void malidp_atomic_commit_hw_done(struct drm_atomic_state *state)
88static void malidp_atomic_commit_tail(struct drm_atomic_state *state) 217static void malidp_atomic_commit_tail(struct drm_atomic_state *state)
89{ 218{
90 struct drm_device *drm = state->dev; 219 struct drm_device *drm = state->dev;
220 struct drm_crtc *crtc;
221 struct drm_crtc_state *old_crtc_state;
222 int i;
223
224 pm_runtime_get_sync(drm->dev);
91 225
92 drm_atomic_helper_commit_modeset_disables(drm, state); 226 drm_atomic_helper_commit_modeset_disables(drm, state);
93 drm_atomic_helper_commit_modeset_enables(drm, state); 227
228 for_each_crtc_in_state(state, crtc, old_crtc_state, i) {
229 malidp_atomic_commit_update_gamma(crtc, old_crtc_state);
230 malidp_atomic_commit_update_coloradj(crtc, old_crtc_state);
231 malidp_atomic_commit_se_config(crtc, old_crtc_state);
232 }
233
94 drm_atomic_helper_commit_planes(drm, state, 0); 234 drm_atomic_helper_commit_planes(drm, state, 0);
95 235
236 drm_atomic_helper_commit_modeset_enables(drm, state);
237
96 malidp_atomic_commit_hw_done(state); 238 malidp_atomic_commit_hw_done(state);
97 239
98 drm_atomic_helper_wait_for_vblanks(drm, state); 240 drm_atomic_helper_wait_for_vblanks(drm, state);
99 241
242 pm_runtime_put(drm->dev);
243
100 drm_atomic_helper_cleanup_planes(drm, state); 244 drm_atomic_helper_cleanup_planes(drm, state);
101} 245}
102 246
@@ -277,8 +421,65 @@ static bool malidp_has_sufficient_address_space(const struct resource *res,
277 return true; 421 return true;
278} 422}
279 423
424static ssize_t core_id_show(struct device *dev, struct device_attribute *attr,
425 char *buf)
426{
427 struct drm_device *drm = dev_get_drvdata(dev);
428 struct malidp_drm *malidp = drm->dev_private;
429
430 return snprintf(buf, PAGE_SIZE, "%08x\n", malidp->core_id);
431}
432
433DEVICE_ATTR_RO(core_id);
434
435static int malidp_init_sysfs(struct device *dev)
436{
437 int ret = device_create_file(dev, &dev_attr_core_id);
438
439 if (ret)
440 DRM_ERROR("failed to create device file for core_id\n");
441
442 return ret;
443}
444
445static void malidp_fini_sysfs(struct device *dev)
446{
447 device_remove_file(dev, &dev_attr_core_id);
448}
449
280#define MAX_OUTPUT_CHANNELS 3 450#define MAX_OUTPUT_CHANNELS 3
281 451
452static int malidp_runtime_pm_suspend(struct device *dev)
453{
454 struct drm_device *drm = dev_get_drvdata(dev);
455 struct malidp_drm *malidp = drm->dev_private;
456 struct malidp_hw_device *hwdev = malidp->dev;
457
458 /* we can only suspend if the hardware is in config mode */
459 WARN_ON(!hwdev->in_config_mode(hwdev));
460
461 hwdev->pm_suspended = true;
462 clk_disable_unprepare(hwdev->mclk);
463 clk_disable_unprepare(hwdev->aclk);
464 clk_disable_unprepare(hwdev->pclk);
465
466 return 0;
467}
468
469static int malidp_runtime_pm_resume(struct device *dev)
470{
471 struct drm_device *drm = dev_get_drvdata(dev);
472 struct malidp_drm *malidp = drm->dev_private;
473 struct malidp_hw_device *hwdev = malidp->dev;
474
475 clk_prepare_enable(hwdev->pclk);
476 clk_prepare_enable(hwdev->aclk);
477 clk_prepare_enable(hwdev->mclk);
478 hwdev->pm_suspended = false;
479
480 return 0;
481}
482
282static int malidp_bind(struct device *dev) 483static int malidp_bind(struct device *dev)
283{ 484{
284 struct resource *res; 485 struct resource *res;
@@ -307,7 +508,6 @@ static int malidp_bind(struct device *dev)
307 memcpy(hwdev, of_device_get_match_data(dev), sizeof(*hwdev)); 508 memcpy(hwdev, of_device_get_match_data(dev), sizeof(*hwdev));
308 malidp->dev = hwdev; 509 malidp->dev = hwdev;
309 510
310
311 res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 511 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
312 hwdev->regs = devm_ioremap_resource(dev, res); 512 hwdev->regs = devm_ioremap_resource(dev, res);
313 if (IS_ERR(hwdev->regs)) 513 if (IS_ERR(hwdev->regs))
@@ -340,14 +540,17 @@ static int malidp_bind(struct device *dev)
340 goto alloc_fail; 540 goto alloc_fail;
341 } 541 }
342 542
343 /* Enable APB clock in order to get access to the registers */ 543 drm->dev_private = malidp;
344 clk_prepare_enable(hwdev->pclk); 544 dev_set_drvdata(dev, drm);
345 /* 545
346 * Enable AXI clock and main clock so that prefetch can start once 546 /* Enable power management */
347 * the registers are set 547 pm_runtime_enable(dev);
348 */ 548
349 clk_prepare_enable(hwdev->aclk); 549 /* Resume device to enable the clocks */
350 clk_prepare_enable(hwdev->mclk); 550 if (pm_runtime_enabled(dev))
551 pm_runtime_get_sync(dev);
552 else
553 malidp_runtime_pm_resume(dev);
351 554
352 dev_id = of_match_device(malidp_drm_of_match, dev); 555 dev_id = of_match_device(malidp_drm_of_match, dev);
353 if (!dev_id) { 556 if (!dev_id) {
@@ -376,6 +579,8 @@ static int malidp_bind(struct device *dev)
376 DRM_INFO("found ARM Mali-DP%3x version r%dp%d\n", version >> 16, 579 DRM_INFO("found ARM Mali-DP%3x version r%dp%d\n", version >> 16,
377 (version >> 12) & 0xf, (version >> 8) & 0xf); 580 (version >> 12) & 0xf, (version >> 8) & 0xf);
378 581
582 malidp->core_id = version;
583
379 /* set the number of lines used for output of RGB data */ 584 /* set the number of lines used for output of RGB data */
380 ret = of_property_read_u8_array(dev->of_node, 585 ret = of_property_read_u8_array(dev->of_node,
381 "arm,malidp-output-port-lines", 586 "arm,malidp-output-port-lines",
@@ -387,13 +592,15 @@ static int malidp_bind(struct device *dev)
387 out_depth = (out_depth << 8) | (output_width[i] & 0xf); 592 out_depth = (out_depth << 8) | (output_width[i] & 0xf);
388 malidp_hw_write(hwdev, out_depth, hwdev->map.out_depth_base); 593 malidp_hw_write(hwdev, out_depth, hwdev->map.out_depth_base);
389 594
390 drm->dev_private = malidp;
391 dev_set_drvdata(dev, drm);
392 atomic_set(&malidp->config_valid, 0); 595 atomic_set(&malidp->config_valid, 0);
393 init_waitqueue_head(&malidp->wq); 596 init_waitqueue_head(&malidp->wq);
394 597
395 ret = malidp_init(drm); 598 ret = malidp_init(drm);
396 if (ret < 0) 599 if (ret < 0)
600 goto query_hw_fail;
601
602 ret = malidp_init_sysfs(dev);
603 if (ret)
397 goto init_fail; 604 goto init_fail;
398 605
399 /* Set the CRTC's port so that the encoder component can find it */ 606 /* Set the CRTC's port so that the encoder component can find it */
@@ -416,6 +623,7 @@ static int malidp_bind(struct device *dev)
416 DRM_ERROR("failed to initialise vblank\n"); 623 DRM_ERROR("failed to initialise vblank\n");
417 goto vblank_fail; 624 goto vblank_fail;
418 } 625 }
626 pm_runtime_put(dev);
419 627
420 drm_mode_config_reset(drm); 628 drm_mode_config_reset(drm);
421 629
@@ -441,7 +649,9 @@ register_fail:
441 drm_fbdev_cma_fini(malidp->fbdev); 649 drm_fbdev_cma_fini(malidp->fbdev);
442 malidp->fbdev = NULL; 650 malidp->fbdev = NULL;
443 } 651 }
652 drm_kms_helper_poll_fini(drm);
444fbdev_fail: 653fbdev_fail:
654 pm_runtime_get_sync(dev);
445 drm_vblank_cleanup(drm); 655 drm_vblank_cleanup(drm);
446vblank_fail: 656vblank_fail:
447 malidp_se_irq_fini(drm); 657 malidp_se_irq_fini(drm);
@@ -452,14 +662,17 @@ irq_init_fail:
452bind_fail: 662bind_fail:
453 of_node_put(malidp->crtc.port); 663 of_node_put(malidp->crtc.port);
454 malidp->crtc.port = NULL; 664 malidp->crtc.port = NULL;
455 malidp_fini(drm);
456init_fail: 665init_fail:
666 malidp_fini_sysfs(dev);
667 malidp_fini(drm);
668query_hw_fail:
669 pm_runtime_put(dev);
670 if (pm_runtime_enabled(dev))
671 pm_runtime_disable(dev);
672 else
673 malidp_runtime_pm_suspend(dev);
457 drm->dev_private = NULL; 674 drm->dev_private = NULL;
458 dev_set_drvdata(dev, NULL); 675 dev_set_drvdata(dev, NULL);
459query_hw_fail:
460 clk_disable_unprepare(hwdev->mclk);
461 clk_disable_unprepare(hwdev->aclk);
462 clk_disable_unprepare(hwdev->pclk);
463 drm_dev_unref(drm); 676 drm_dev_unref(drm);
464alloc_fail: 677alloc_fail:
465 of_reserved_mem_device_release(dev); 678 of_reserved_mem_device_release(dev);
@@ -471,7 +684,6 @@ static void malidp_unbind(struct device *dev)
471{ 684{
472 struct drm_device *drm = dev_get_drvdata(dev); 685 struct drm_device *drm = dev_get_drvdata(dev);
473 struct malidp_drm *malidp = drm->dev_private; 686 struct malidp_drm *malidp = drm->dev_private;
474 struct malidp_hw_device *hwdev = malidp->dev;
475 687
476 drm_dev_unregister(drm); 688 drm_dev_unregister(drm);
477 if (malidp->fbdev) { 689 if (malidp->fbdev) {
@@ -479,18 +691,22 @@ static void malidp_unbind(struct device *dev)
479 malidp->fbdev = NULL; 691 malidp->fbdev = NULL;
480 } 692 }
481 drm_kms_helper_poll_fini(drm); 693 drm_kms_helper_poll_fini(drm);
694 pm_runtime_get_sync(dev);
695 drm_vblank_cleanup(drm);
482 malidp_se_irq_fini(drm); 696 malidp_se_irq_fini(drm);
483 malidp_de_irq_fini(drm); 697 malidp_de_irq_fini(drm);
484 drm_vblank_cleanup(drm);
485 component_unbind_all(dev, drm); 698 component_unbind_all(dev, drm);
486 of_node_put(malidp->crtc.port); 699 of_node_put(malidp->crtc.port);
487 malidp->crtc.port = NULL; 700 malidp->crtc.port = NULL;
701 malidp_fini_sysfs(dev);
488 malidp_fini(drm); 702 malidp_fini(drm);
703 pm_runtime_put(dev);
704 if (pm_runtime_enabled(dev))
705 pm_runtime_disable(dev);
706 else
707 malidp_runtime_pm_suspend(dev);
489 drm->dev_private = NULL; 708 drm->dev_private = NULL;
490 dev_set_drvdata(dev, NULL); 709 dev_set_drvdata(dev, NULL);
491 clk_disable_unprepare(hwdev->mclk);
492 clk_disable_unprepare(hwdev->aclk);
493 clk_disable_unprepare(hwdev->pclk);
494 drm_dev_unref(drm); 710 drm_dev_unref(drm);
495 of_reserved_mem_device_release(dev); 711 of_reserved_mem_device_release(dev);
496} 712}
@@ -533,11 +749,52 @@ static int malidp_platform_remove(struct platform_device *pdev)
533 return 0; 749 return 0;
534} 750}
535 751
752static int __maybe_unused malidp_pm_suspend(struct device *dev)
753{
754 struct drm_device *drm = dev_get_drvdata(dev);
755 struct malidp_drm *malidp = drm->dev_private;
756
757 drm_kms_helper_poll_disable(drm);
758 console_lock();
759 drm_fbdev_cma_set_suspend(malidp->fbdev, 1);
760 console_unlock();
761 malidp->pm_state = drm_atomic_helper_suspend(drm);
762 if (IS_ERR(malidp->pm_state)) {
763 console_lock();
764 drm_fbdev_cma_set_suspend(malidp->fbdev, 0);
765 console_unlock();
766 drm_kms_helper_poll_enable(drm);
767 return PTR_ERR(malidp->pm_state);
768 }
769
770 return 0;
771}
772
773static int __maybe_unused malidp_pm_resume(struct device *dev)
774{
775 struct drm_device *drm = dev_get_drvdata(dev);
776 struct malidp_drm *malidp = drm->dev_private;
777
778 drm_atomic_helper_resume(drm, malidp->pm_state);
779 console_lock();
780 drm_fbdev_cma_set_suspend(malidp->fbdev, 0);
781 console_unlock();
782 drm_kms_helper_poll_enable(drm);
783
784 return 0;
785}
786
787static const struct dev_pm_ops malidp_pm_ops = {
788 SET_SYSTEM_SLEEP_PM_OPS(malidp_pm_suspend, malidp_pm_resume) \
789 SET_RUNTIME_PM_OPS(malidp_runtime_pm_suspend, malidp_runtime_pm_resume, NULL)
790};
791
536static struct platform_driver malidp_platform_driver = { 792static struct platform_driver malidp_platform_driver = {
537 .probe = malidp_platform_probe, 793 .probe = malidp_platform_probe,
538 .remove = malidp_platform_remove, 794 .remove = malidp_platform_remove,
539 .driver = { 795 .driver = {
540 .name = "mali-dp", 796 .name = "mali-dp",
797 .pm = &malidp_pm_ops,
541 .of_match_table = malidp_drm_of_match, 798 .of_match_table = malidp_drm_of_match,
542 }, 799 },
543}; 800};
diff --git a/drivers/gpu/drm/arm/malidp_drv.h b/drivers/gpu/drm/arm/malidp_drv.h
index dbc617c6e4ef..040311ffcaec 100644
--- a/drivers/gpu/drm/arm/malidp_drv.h
+++ b/drivers/gpu/drm/arm/malidp_drv.h
@@ -24,6 +24,8 @@ struct malidp_drm {
24 struct drm_crtc crtc; 24 struct drm_crtc crtc;
25 wait_queue_head_t wq; 25 wait_queue_head_t wq;
26 atomic_t config_valid; 26 atomic_t config_valid;
27 struct drm_atomic_state *pm_state;
28 u32 core_id;
27}; 29};
28 30
29#define crtc_to_malidp_device(x) container_of(x, struct malidp_drm, crtc) 31#define crtc_to_malidp_device(x) container_of(x, struct malidp_drm, crtc)
@@ -47,6 +49,17 @@ struct malidp_plane_state {
47#define to_malidp_plane(x) container_of(x, struct malidp_plane, base) 49#define to_malidp_plane(x) container_of(x, struct malidp_plane, base)
48#define to_malidp_plane_state(x) container_of(x, struct malidp_plane_state, base) 50#define to_malidp_plane_state(x) container_of(x, struct malidp_plane_state, base)
49 51
52struct malidp_crtc_state {
53 struct drm_crtc_state base;
54 u32 gamma_coeffs[MALIDP_COEFFTAB_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;
59};
60
61#define to_malidp_crtc_state(x) container_of(x, struct malidp_crtc_state, base)
62
50int malidp_de_planes_init(struct drm_device *drm); 63int malidp_de_planes_init(struct drm_device *drm);
51void malidp_de_planes_destroy(struct drm_device *drm); 64void malidp_de_planes_destroy(struct drm_device *drm);
52int malidp_crtc_init(struct drm_device *drm); 65int malidp_crtc_init(struct drm_device *drm);
diff --git a/drivers/gpu/drm/arm/malidp_hw.c b/drivers/gpu/drm/arm/malidp_hw.c
index 9f5513006eee..28360b8542f7 100644
--- a/drivers/gpu/drm/arm/malidp_hw.c
+++ b/drivers/gpu/drm/arm/malidp_hw.c
@@ -12,6 +12,7 @@
12 * in an attempt to provide to the rest of the driver code a unified view 12 * in an attempt to provide to the rest of the driver code a unified view
13 */ 13 */
14 14
15#include <linux/clk.h>
15#include <linux/types.h> 16#include <linux/types.h>
16#include <linux/io.h> 17#include <linux/io.h>
17#include <drm/drmP.h> 18#include <drm/drmP.h>
@@ -86,6 +87,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 }, 87 { DE_SMART, MALIDP550_DE_LS_BASE, MALIDP550_DE_LS_PTR_BASE, MALIDP550_DE_LS_R1_STRIDE },
87}; 88};
88 89
90#define SE_N_SCALING_COEFFS 96
91static const u16 dp500_se_scaling_coeffs[][SE_N_SCALING_COEFFS] = {
92 [MALIDP_UPSCALING_COEFFS - 1] = {
93 0x0000, 0x0001, 0x0007, 0x0011, 0x001e, 0x002e, 0x003f, 0x0052,
94 0x0064, 0x0073, 0x007d, 0x0080, 0x007a, 0x006c, 0x0053, 0x002f,
95 0x0000, 0x3fc6, 0x3f83, 0x3f39, 0x3eea, 0x3e9b, 0x3e4f, 0x3e0a,
96 0x3dd4, 0x3db0, 0x3da2, 0x3db1, 0x3dde, 0x3e2f, 0x3ea5, 0x3f40,
97 0x0000, 0x00e5, 0x01ee, 0x0315, 0x0456, 0x05aa, 0x0709, 0x086c,
98 0x09c9, 0x0b15, 0x0c4a, 0x0d5d, 0x0e4a, 0x0f06, 0x0f91, 0x0fe5,
99 0x1000, 0x0fe5, 0x0f91, 0x0f06, 0x0e4a, 0x0d5d, 0x0c4a, 0x0b15,
100 0x09c9, 0x086c, 0x0709, 0x05aa, 0x0456, 0x0315, 0x01ee, 0x00e5,
101 0x0000, 0x3f40, 0x3ea5, 0x3e2f, 0x3dde, 0x3db1, 0x3da2, 0x3db0,
102 0x3dd4, 0x3e0a, 0x3e4f, 0x3e9b, 0x3eea, 0x3f39, 0x3f83, 0x3fc6,
103 0x0000, 0x002f, 0x0053, 0x006c, 0x007a, 0x0080, 0x007d, 0x0073,
104 0x0064, 0x0052, 0x003f, 0x002e, 0x001e, 0x0011, 0x0007, 0x0001
105 },
106 [MALIDP_DOWNSCALING_1_5_COEFFS - 1] = {
107 0x0059, 0x004f, 0x0041, 0x002e, 0x0016, 0x3ffb, 0x3fd9, 0x3fb4,
108 0x3f8c, 0x3f62, 0x3f36, 0x3f09, 0x3edd, 0x3eb3, 0x3e8d, 0x3e6c,
109 0x3e52, 0x3e3f, 0x3e35, 0x3e37, 0x3e46, 0x3e61, 0x3e8c, 0x3ec5,
110 0x3f0f, 0x3f68, 0x3fd1, 0x004a, 0x00d3, 0x0169, 0x020b, 0x02b8,
111 0x036e, 0x042d, 0x04f2, 0x05b9, 0x0681, 0x0745, 0x0803, 0x08ba,
112 0x0965, 0x0a03, 0x0a91, 0x0b0d, 0x0b75, 0x0bc6, 0x0c00, 0x0c20,
113 0x0c28, 0x0c20, 0x0c00, 0x0bc6, 0x0b75, 0x0b0d, 0x0a91, 0x0a03,
114 0x0965, 0x08ba, 0x0803, 0x0745, 0x0681, 0x05b9, 0x04f2, 0x042d,
115 0x036e, 0x02b8, 0x020b, 0x0169, 0x00d3, 0x004a, 0x3fd1, 0x3f68,
116 0x3f0f, 0x3ec5, 0x3e8c, 0x3e61, 0x3e46, 0x3e37, 0x3e35, 0x3e3f,
117 0x3e52, 0x3e6c, 0x3e8d, 0x3eb3, 0x3edd, 0x3f09, 0x3f36, 0x3f62,
118 0x3f8c, 0x3fb4, 0x3fd9, 0x3ffb, 0x0016, 0x002e, 0x0041, 0x004f
119 },
120 [MALIDP_DOWNSCALING_2_COEFFS - 1] = {
121 0x3f19, 0x3f03, 0x3ef0, 0x3edf, 0x3ed0, 0x3ec5, 0x3ebd, 0x3eb9,
122 0x3eb9, 0x3ebf, 0x3eca, 0x3ed9, 0x3eef, 0x3f0a, 0x3f2c, 0x3f52,
123 0x3f7f, 0x3fb0, 0x3fe8, 0x0026, 0x006a, 0x00b4, 0x0103, 0x0158,
124 0x01b1, 0x020d, 0x026c, 0x02cd, 0x032f, 0x0392, 0x03f4, 0x0455,
125 0x04b4, 0x051e, 0x0585, 0x05eb, 0x064c, 0x06a8, 0x06fe, 0x074e,
126 0x0796, 0x07d5, 0x080c, 0x0839, 0x085c, 0x0875, 0x0882, 0x0887,
127 0x0881, 0x0887, 0x0882, 0x0875, 0x085c, 0x0839, 0x080c, 0x07d5,
128 0x0796, 0x074e, 0x06fe, 0x06a8, 0x064c, 0x05eb, 0x0585, 0x051e,
129 0x04b4, 0x0455, 0x03f4, 0x0392, 0x032f, 0x02cd, 0x026c, 0x020d,
130 0x01b1, 0x0158, 0x0103, 0x00b4, 0x006a, 0x0026, 0x3fe8, 0x3fb0,
131 0x3f7f, 0x3f52, 0x3f2c, 0x3f0a, 0x3eef, 0x3ed9, 0x3eca, 0x3ebf,
132 0x3eb9, 0x3eb9, 0x3ebd, 0x3ec5, 0x3ed0, 0x3edf, 0x3ef0, 0x3f03
133 },
134 [MALIDP_DOWNSCALING_2_75_COEFFS - 1] = {
135 0x3f51, 0x3f60, 0x3f71, 0x3f84, 0x3f98, 0x3faf, 0x3fc8, 0x3fe3,
136 0x0000, 0x001f, 0x0040, 0x0064, 0x008a, 0x00b1, 0x00da, 0x0106,
137 0x0133, 0x0160, 0x018e, 0x01bd, 0x01ec, 0x021d, 0x024e, 0x0280,
138 0x02b2, 0x02e4, 0x0317, 0x0349, 0x037c, 0x03ad, 0x03df, 0x0410,
139 0x0440, 0x0468, 0x048f, 0x04b3, 0x04d6, 0x04f8, 0x0516, 0x0533,
140 0x054e, 0x0566, 0x057c, 0x0590, 0x05a0, 0x05ae, 0x05ba, 0x05c3,
141 0x05c9, 0x05c3, 0x05ba, 0x05ae, 0x05a0, 0x0590, 0x057c, 0x0566,
142 0x054e, 0x0533, 0x0516, 0x04f8, 0x04d6, 0x04b3, 0x048f, 0x0468,
143 0x0440, 0x0410, 0x03df, 0x03ad, 0x037c, 0x0349, 0x0317, 0x02e4,
144 0x02b2, 0x0280, 0x024e, 0x021d, 0x01ec, 0x01bd, 0x018e, 0x0160,
145 0x0133, 0x0106, 0x00da, 0x00b1, 0x008a, 0x0064, 0x0040, 0x001f,
146 0x0000, 0x3fe3, 0x3fc8, 0x3faf, 0x3f98, 0x3f84, 0x3f71, 0x3f60
147 },
148 [MALIDP_DOWNSCALING_4_COEFFS - 1] = {
149 0x0094, 0x00a9, 0x00be, 0x00d4, 0x00ea, 0x0101, 0x0118, 0x012f,
150 0x0148, 0x0160, 0x017a, 0x0193, 0x01ae, 0x01c8, 0x01e4, 0x01ff,
151 0x021c, 0x0233, 0x024a, 0x0261, 0x0278, 0x028f, 0x02a6, 0x02bd,
152 0x02d4, 0x02eb, 0x0302, 0x0319, 0x032f, 0x0346, 0x035d, 0x0374,
153 0x038a, 0x0397, 0x03a3, 0x03af, 0x03bb, 0x03c6, 0x03d1, 0x03db,
154 0x03e4, 0x03ed, 0x03f6, 0x03fe, 0x0406, 0x040d, 0x0414, 0x041a,
155 0x0420, 0x041a, 0x0414, 0x040d, 0x0406, 0x03fe, 0x03f6, 0x03ed,
156 0x03e4, 0x03db, 0x03d1, 0x03c6, 0x03bb, 0x03af, 0x03a3, 0x0397,
157 0x038a, 0x0374, 0x035d, 0x0346, 0x032f, 0x0319, 0x0302, 0x02eb,
158 0x02d4, 0x02bd, 0x02a6, 0x028f, 0x0278, 0x0261, 0x024a, 0x0233,
159 0x021c, 0x01ff, 0x01e4, 0x01c8, 0x01ae, 0x0193, 0x017a, 0x0160,
160 0x0148, 0x012f, 0x0118, 0x0101, 0x00ea, 0x00d4, 0x00be, 0x00a9
161 },
162};
163
89#define MALIDP_DE_DEFAULT_PREFETCH_START 5 164#define MALIDP_DE_DEFAULT_PREFETCH_START 5
90 165
91static int malidp500_query_hw(struct malidp_hw_device *hwdev) 166static int malidp500_query_hw(struct malidp_hw_device *hwdev)
@@ -211,6 +286,88 @@ static int malidp500_rotmem_required(struct malidp_hw_device *hwdev, u16 w, u16
211 return w * drm_format_plane_cpp(fmt, 0) * 8; 286 return w * drm_format_plane_cpp(fmt, 0) * 8;
212} 287}
213 288
289static void malidp500_se_write_pp_coefftab(struct malidp_hw_device *hwdev,
290 u32 direction,
291 u16 addr,
292 u8 coeffs_id)
293{
294 int i;
295 u16 scaling_control = MALIDP500_SE_CONTROL + MALIDP_SE_SCALING_CONTROL;
296
297 malidp_hw_write(hwdev,
298 direction | (addr & MALIDP_SE_COEFFTAB_ADDR_MASK),
299 scaling_control + MALIDP_SE_COEFFTAB_ADDR);
300 for (i = 0; i < ARRAY_SIZE(dp500_se_scaling_coeffs); ++i)
301 malidp_hw_write(hwdev, MALIDP_SE_SET_COEFFTAB_DATA(
302 dp500_se_scaling_coeffs[coeffs_id][i]),
303 scaling_control + MALIDP_SE_COEFFTAB_DATA);
304}
305
306static int malidp500_se_set_scaling_coeffs(struct malidp_hw_device *hwdev,
307 struct malidp_se_config *se_config,
308 struct malidp_se_config *old_config)
309{
310 /* Get array indices into dp500_se_scaling_coeffs. */
311 u8 h = (u8)se_config->hcoeff - 1;
312 u8 v = (u8)se_config->vcoeff - 1;
313
314 if (WARN_ON(h >= ARRAY_SIZE(dp500_se_scaling_coeffs) ||
315 v >= ARRAY_SIZE(dp500_se_scaling_coeffs)))
316 return -EINVAL;
317
318 if ((h == v) && (se_config->hcoeff != old_config->hcoeff ||
319 se_config->vcoeff != old_config->vcoeff)) {
320 malidp500_se_write_pp_coefftab(hwdev,
321 (MALIDP_SE_V_COEFFTAB |
322 MALIDP_SE_H_COEFFTAB),
323 0, v);
324 } else {
325 if (se_config->vcoeff != old_config->vcoeff)
326 malidp500_se_write_pp_coefftab(hwdev,
327 MALIDP_SE_V_COEFFTAB,
328 0, v);
329 if (se_config->hcoeff != old_config->hcoeff)
330 malidp500_se_write_pp_coefftab(hwdev,
331 MALIDP_SE_H_COEFFTAB,
332 0, h);
333 }
334
335 return 0;
336}
337
338static long malidp500_se_calc_mclk(struct malidp_hw_device *hwdev,
339 struct malidp_se_config *se_config,
340 struct videomode *vm)
341{
342 unsigned long mclk;
343 unsigned long pxlclk = vm->pixelclock; /* Hz */
344 unsigned long htotal = vm->hactive + vm->hfront_porch +
345 vm->hback_porch + vm->hsync_len;
346 unsigned long input_size = se_config->input_w * se_config->input_h;
347 unsigned long a = 10;
348 long ret;
349
350 /*
351 * mclk = max(a, 1.5) * pxlclk
352 *
353 * To avoid float calculaiton, using 15 instead of 1.5 and div by
354 * 10 to get mclk.
355 */
356 if (se_config->scale_enable) {
357 a = 15 * input_size / (htotal * se_config->output_h);
358 if (a < 15)
359 a = 15;
360 }
361 mclk = a * pxlclk / 10;
362 ret = clk_get_rate(hwdev->mclk);
363 if (ret < mclk) {
364 DRM_DEBUG_DRIVER("mclk requirement of %lu kHz can't be met.\n",
365 mclk / 1000);
366 return -EINVAL;
367 }
368 return ret;
369}
370
214static int malidp550_query_hw(struct malidp_hw_device *hwdev) 371static int malidp550_query_hw(struct malidp_hw_device *hwdev)
215{ 372{
216 u32 conf = malidp_hw_read(hwdev, MALIDP550_CONFIG_ID); 373 u32 conf = malidp_hw_read(hwdev, MALIDP550_CONFIG_ID);
@@ -384,6 +541,53 @@ static int malidp550_rotmem_required(struct malidp_hw_device *hwdev, u16 w, u16
384 return w * bytes_per_col; 541 return w * bytes_per_col;
385} 542}
386 543
544static int malidp550_se_set_scaling_coeffs(struct malidp_hw_device *hwdev,
545 struct malidp_se_config *se_config,
546 struct malidp_se_config *old_config)
547{
548 u32 mask = MALIDP550_SE_CTL_VCSEL(MALIDP550_SE_CTL_SEL_MASK) |
549 MALIDP550_SE_CTL_HCSEL(MALIDP550_SE_CTL_SEL_MASK);
550 u32 new_value = MALIDP550_SE_CTL_VCSEL(se_config->vcoeff) |
551 MALIDP550_SE_CTL_HCSEL(se_config->hcoeff);
552
553 malidp_hw_clearbits(hwdev, mask, MALIDP550_SE_CONTROL);
554 malidp_hw_setbits(hwdev, new_value, MALIDP550_SE_CONTROL);
555 return 0;
556}
557
558static long malidp550_se_calc_mclk(struct malidp_hw_device *hwdev,
559 struct malidp_se_config *se_config,
560 struct videomode *vm)
561{
562 unsigned long mclk;
563 unsigned long pxlclk = vm->pixelclock;
564 unsigned long htotal = vm->hactive + vm->hfront_porch +
565 vm->hback_porch + vm->hsync_len;
566 unsigned long numerator = 1, denominator = 1;
567 long ret;
568
569 if (se_config->scale_enable) {
570 numerator = max(se_config->input_w, se_config->output_w) *
571 se_config->input_h;
572 numerator += se_config->output_w *
573 (se_config->output_h -
574 min(se_config->input_h, se_config->output_h));
575 denominator = (htotal - 2) * se_config->output_h;
576 }
577
578 /* mclk can't be slower than pxlclk. */
579 if (numerator < denominator)
580 numerator = denominator = 1;
581 mclk = (pxlclk * numerator) / denominator;
582 ret = clk_get_rate(hwdev->mclk);
583 if (ret < mclk) {
584 DRM_DEBUG_DRIVER("mclk requirement of %lu kHz can't be met.\n",
585 mclk / 1000);
586 return -EINVAL;
587 }
588 return ret;
589}
590
387static int malidp650_query_hw(struct malidp_hw_device *hwdev) 591static int malidp650_query_hw(struct malidp_hw_device *hwdev)
388{ 592{
389 u32 conf = malidp_hw_read(hwdev, MALIDP550_CONFIG_ID); 593 u32 conf = malidp_hw_read(hwdev, MALIDP550_CONFIG_ID);
@@ -415,6 +619,7 @@ static int malidp650_query_hw(struct malidp_hw_device *hwdev)
415const struct malidp_hw_device malidp_device[MALIDP_MAX_DEVICES] = { 619const struct malidp_hw_device malidp_device[MALIDP_MAX_DEVICES] = {
416 [MALIDP_500] = { 620 [MALIDP_500] = {
417 .map = { 621 .map = {
622 .coeffs_base = MALIDP500_COEFFS_BASE,
418 .se_base = MALIDP500_SE_BASE, 623 .se_base = MALIDP500_SE_BASE,
419 .dc_base = MALIDP500_DC_BASE, 624 .dc_base = MALIDP500_DC_BASE,
420 .out_depth_base = MALIDP500_OUTPUT_DEPTH, 625 .out_depth_base = MALIDP500_OUTPUT_DEPTH,
@@ -447,10 +652,13 @@ const struct malidp_hw_device malidp_device[MALIDP_MAX_DEVICES] = {
447 .set_config_valid = malidp500_set_config_valid, 652 .set_config_valid = malidp500_set_config_valid,
448 .modeset = malidp500_modeset, 653 .modeset = malidp500_modeset,
449 .rotmem_required = malidp500_rotmem_required, 654 .rotmem_required = malidp500_rotmem_required,
655 .se_set_scaling_coeffs = malidp500_se_set_scaling_coeffs,
656 .se_calc_mclk = malidp500_se_calc_mclk,
450 .features = MALIDP_DEVICE_LV_HAS_3_STRIDES, 657 .features = MALIDP_DEVICE_LV_HAS_3_STRIDES,
451 }, 658 },
452 [MALIDP_550] = { 659 [MALIDP_550] = {
453 .map = { 660 .map = {
661 .coeffs_base = MALIDP550_COEFFS_BASE,
454 .se_base = MALIDP550_SE_BASE, 662 .se_base = MALIDP550_SE_BASE,
455 .dc_base = MALIDP550_DC_BASE, 663 .dc_base = MALIDP550_DC_BASE,
456 .out_depth_base = MALIDP550_DE_OUTPUT_DEPTH, 664 .out_depth_base = MALIDP550_DE_OUTPUT_DEPTH,
@@ -481,10 +689,13 @@ const struct malidp_hw_device malidp_device[MALIDP_MAX_DEVICES] = {
481 .set_config_valid = malidp550_set_config_valid, 689 .set_config_valid = malidp550_set_config_valid,
482 .modeset = malidp550_modeset, 690 .modeset = malidp550_modeset,
483 .rotmem_required = malidp550_rotmem_required, 691 .rotmem_required = malidp550_rotmem_required,
692 .se_set_scaling_coeffs = malidp550_se_set_scaling_coeffs,
693 .se_calc_mclk = malidp550_se_calc_mclk,
484 .features = 0, 694 .features = 0,
485 }, 695 },
486 [MALIDP_650] = { 696 [MALIDP_650] = {
487 .map = { 697 .map = {
698 .coeffs_base = MALIDP550_COEFFS_BASE,
488 .se_base = MALIDP550_SE_BASE, 699 .se_base = MALIDP550_SE_BASE,
489 .dc_base = MALIDP550_DC_BASE, 700 .dc_base = MALIDP550_DC_BASE,
490 .out_depth_base = MALIDP550_DE_OUTPUT_DEPTH, 701 .out_depth_base = MALIDP550_DE_OUTPUT_DEPTH,
@@ -516,6 +727,8 @@ const struct malidp_hw_device malidp_device[MALIDP_MAX_DEVICES] = {
516 .set_config_valid = malidp550_set_config_valid, 727 .set_config_valid = malidp550_set_config_valid,
517 .modeset = malidp550_modeset, 728 .modeset = malidp550_modeset,
518 .rotmem_required = malidp550_rotmem_required, 729 .rotmem_required = malidp550_rotmem_required,
730 .se_set_scaling_coeffs = malidp550_se_set_scaling_coeffs,
731 .se_calc_mclk = malidp550_se_calc_mclk,
519 .features = 0, 732 .features = 0,
520 }, 733 },
521}; 734};
diff --git a/drivers/gpu/drm/arm/malidp_hw.h b/drivers/gpu/drm/arm/malidp_hw.h
index 00974b59407d..849ad9a30c3a 100644
--- a/drivers/gpu/drm/arm/malidp_hw.h
+++ b/drivers/gpu/drm/arm/malidp_hw.h
@@ -61,12 +61,34 @@ 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 enhancer_enable : 1;
75 u8 hcoeff : 3;
76 u8 vcoeff : 3;
77 u8 plane_src_id;
78 u16 input_w, input_h;
79 u16 output_w, output_h;
80 u32 h_init_phase, h_delta_phase;
81 u32 v_init_phase, v_delta_phase;
82};
83
64/* regmap features */ 84/* regmap features */
65#define MALIDP_REGMAP_HAS_CLEARIRQ (1 << 0) 85#define MALIDP_REGMAP_HAS_CLEARIRQ (1 << 0)
66 86
67struct malidp_hw_regmap { 87struct malidp_hw_regmap {
68 /* address offset of the DE register bank */ 88 /* address offset of the DE register bank */
69 /* is always 0x0000 */ 89 /* is always 0x0000 */
90 /* address offset of the DE coefficients registers */
91 const u16 coeffs_base;
70 /* address offset of the SE registers bank */ 92 /* address offset of the SE registers bank */
71 const u16 se_base; 93 const u16 se_base;
72 /* address offset of the DC registers bank */ 94 /* address offset of the DC registers bank */
@@ -151,11 +173,22 @@ struct malidp_hw_device {
151 */ 173 */
152 int (*rotmem_required)(struct malidp_hw_device *hwdev, u16 w, u16 h, u32 fmt); 174 int (*rotmem_required)(struct malidp_hw_device *hwdev, u16 w, u16 h, u32 fmt);
153 175
176 int (*se_set_scaling_coeffs)(struct malidp_hw_device *hwdev,
177 struct malidp_se_config *se_config,
178 struct malidp_se_config *old_config);
179
180 long (*se_calc_mclk)(struct malidp_hw_device *hwdev,
181 struct malidp_se_config *se_config,
182 struct videomode *vm);
183
154 u8 features; 184 u8 features;
155 185
156 u8 min_line_size; 186 u8 min_line_size;
157 u16 max_line_size; 187 u16 max_line_size;
158 188
189 /* track the device PM state */
190 bool pm_suspended;
191
159 /* size of memory used for rotating layers, up to two banks available */ 192 /* size of memory used for rotating layers, up to two banks available */
160 u32 rotation_memory[2]; 193 u32 rotation_memory[2];
161}; 194};
@@ -173,12 +206,14 @@ extern const struct malidp_hw_device malidp_device[MALIDP_MAX_DEVICES];
173 206
174static inline u32 malidp_hw_read(struct malidp_hw_device *hwdev, u32 reg) 207static inline u32 malidp_hw_read(struct malidp_hw_device *hwdev, u32 reg)
175{ 208{
209 WARN_ON(hwdev->pm_suspended);
176 return readl(hwdev->regs + reg); 210 return readl(hwdev->regs + reg);
177} 211}
178 212
179static inline void malidp_hw_write(struct malidp_hw_device *hwdev, 213static inline void malidp_hw_write(struct malidp_hw_device *hwdev,
180 u32 value, u32 reg) 214 u32 value, u32 reg)
181{ 215{
216 WARN_ON(hwdev->pm_suspended);
182 writel(value, hwdev->regs + reg); 217 writel(value, hwdev->regs + reg);
183} 218}
184 219
@@ -243,6 +278,47 @@ static inline bool malidp_hw_pitch_valid(struct malidp_hw_device *hwdev,
243 return !(pitch & (hwdev->map.bus_align_bytes - 1)); 278 return !(pitch & (hwdev->map.bus_align_bytes - 1));
244} 279}
245 280
281/* U16.16 */
282#define FP_1_00000 0x00010000 /* 1.0 */
283#define FP_0_66667 0x0000AAAA /* 0.6667 = 1/1.5 */
284#define FP_0_50000 0x00008000 /* 0.5 = 1/2 */
285#define FP_0_36363 0x00005D17 /* 0.36363 = 1/2.75 */
286#define FP_0_25000 0x00004000 /* 0.25 = 1/4 */
287
288static inline enum malidp_scaling_coeff_set
289malidp_se_select_coeffs(u32 upscale_factor)
290{
291 return (upscale_factor >= FP_1_00000) ? MALIDP_UPSCALING_COEFFS :
292 (upscale_factor >= FP_0_66667) ? MALIDP_DOWNSCALING_1_5_COEFFS :
293 (upscale_factor >= FP_0_50000) ? MALIDP_DOWNSCALING_2_COEFFS :
294 (upscale_factor >= FP_0_36363) ? MALIDP_DOWNSCALING_2_75_COEFFS :
295 MALIDP_DOWNSCALING_4_COEFFS;
296}
297
298#undef FP_0_25000
299#undef FP_0_36363
300#undef FP_0_50000
301#undef FP_0_66667
302#undef FP_1_00000
303
304static inline void malidp_se_set_enh_coeffs(struct malidp_hw_device *hwdev)
305{
306 static const s32 enhancer_coeffs[] = {
307 -8, -8, -8, -8, 128, -8, -8, -8, -8
308 };
309 u32 val = MALIDP_SE_SET_ENH_LIMIT_LOW(MALIDP_SE_ENH_LOW_LEVEL) |
310 MALIDP_SE_SET_ENH_LIMIT_HIGH(MALIDP_SE_ENH_HIGH_LEVEL);
311 u32 image_enh = hwdev->map.se_base +
312 ((hwdev->map.features & MALIDP_REGMAP_HAS_CLEARIRQ) ?
313 0x10 : 0xC) + MALIDP_SE_IMAGE_ENH;
314 u32 enh_coeffs = image_enh + MALIDP_SE_ENH_COEFF0;
315 int i;
316
317 malidp_hw_write(hwdev, val, image_enh);
318 for (i = 0; i < ARRAY_SIZE(enhancer_coeffs); ++i)
319 malidp_hw_write(hwdev, enhancer_coeffs[i], enh_coeffs + i * 4);
320}
321
246/* 322/*
247 * background color components are defined as 12bits values, 323 * background color components are defined as 12bits values,
248 * they will be shifted right when stored on hardware that 324 * they will be shifted right when stored on hardware that
@@ -252,4 +328,9 @@ static inline bool malidp_hw_pitch_valid(struct malidp_hw_device *hwdev,
252#define MALIDP_BGND_COLOR_G 0x000 328#define MALIDP_BGND_COLOR_G 0x000
253#define MALIDP_BGND_COLOR_B 0x000 329#define MALIDP_BGND_COLOR_B 0x000
254 330
331#define MALIDP_COLORADJ_NUM_COEFFS 12
332#define MALIDP_COEFFTAB_NUM_COEFFS 64
333
334#define MALIDP_GAMMA_LUT_SIZE 4096
335
255#endif /* __MALIDP_HW_H__ */ 336#endif /* __MALIDP_HW_H__ */
diff --git a/drivers/gpu/drm/arm/malidp_planes.c b/drivers/gpu/drm/arm/malidp_planes.c
index d5aec082294c..814fda23cead 100644
--- a/drivers/gpu/drm/arm/malidp_planes.c
+++ b/drivers/gpu/drm/arm/malidp_planes.c
@@ -16,6 +16,7 @@
16#include <drm/drm_fb_cma_helper.h> 16#include <drm/drm_fb_cma_helper.h>
17#include <drm/drm_gem_cma_helper.h> 17#include <drm/drm_gem_cma_helper.h>
18#include <drm/drm_plane_helper.h> 18#include <drm/drm_plane_helper.h>
19#include <drm/drm_print.h>
19 20
20#include "malidp_hw.h" 21#include "malidp_hw.h"
21#include "malidp_drv.h" 22#include "malidp_drv.h"
@@ -24,6 +25,9 @@
24#define MALIDP_LAYER_FORMAT 0x000 25#define MALIDP_LAYER_FORMAT 0x000
25#define MALIDP_LAYER_CONTROL 0x004 26#define MALIDP_LAYER_CONTROL 0x004
26#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
27#define LAYER_ROT_OFFSET 8 31#define LAYER_ROT_OFFSET 8
28#define LAYER_H_FLIP (1 << 10) 32#define LAYER_H_FLIP (1 << 10)
29#define LAYER_V_FLIP (1 << 11) 33#define LAYER_V_FLIP (1 << 11)
@@ -60,6 +64,27 @@ static void malidp_de_plane_destroy(struct drm_plane *plane)
60 devm_kfree(plane->dev->dev, mp); 64 devm_kfree(plane->dev->dev, mp);
61} 65}
62 66
67/*
68 * Replicate what the default ->reset hook does: free the state pointer and
69 * allocate a new empty object. We just need enough space to store
70 * a malidp_plane_state instead of a drm_plane_state.
71 */
72static void malidp_plane_reset(struct drm_plane *plane)
73{
74 struct malidp_plane_state *state = to_malidp_plane_state(plane->state);
75
76 if (state)
77 __drm_atomic_helper_plane_destroy_state(&state->base);
78 kfree(state);
79 plane->state = NULL;
80 state = kzalloc(sizeof(*state), GFP_KERNEL);
81 if (state) {
82 state->base.plane = plane;
83 state->base.rotation = DRM_ROTATE_0;
84 plane->state = &state->base;
85 }
86}
87
63static struct 88static struct
64drm_plane_state *malidp_duplicate_plane_state(struct drm_plane *plane) 89drm_plane_state *malidp_duplicate_plane_state(struct drm_plane *plane)
65{ 90{
@@ -90,26 +115,71 @@ static void malidp_destroy_plane_state(struct drm_plane *plane,
90 kfree(m_state); 115 kfree(m_state);
91} 116}
92 117
118static void malidp_plane_atomic_print_state(struct drm_printer *p,
119 const struct drm_plane_state *state)
120{
121 struct malidp_plane_state *ms = to_malidp_plane_state(state);
122
123 drm_printf(p, "\trotmem_size=%u\n", ms->rotmem_size);
124 drm_printf(p, "\tformat_id=%u\n", ms->format);
125 drm_printf(p, "\tn_planes=%u\n", ms->n_planes);
126}
127
93static const struct drm_plane_funcs malidp_de_plane_funcs = { 128static const struct drm_plane_funcs malidp_de_plane_funcs = {
94 .update_plane = drm_atomic_helper_update_plane, 129 .update_plane = drm_atomic_helper_update_plane,
95 .disable_plane = drm_atomic_helper_disable_plane, 130 .disable_plane = drm_atomic_helper_disable_plane,
96 .set_property = drm_atomic_helper_plane_set_property, 131 .set_property = drm_atomic_helper_plane_set_property,
97 .destroy = malidp_de_plane_destroy, 132 .destroy = malidp_de_plane_destroy,
98 .reset = drm_atomic_helper_plane_reset, 133 .reset = malidp_plane_reset,
99 .atomic_duplicate_state = malidp_duplicate_plane_state, 134 .atomic_duplicate_state = malidp_duplicate_plane_state,
100 .atomic_destroy_state = malidp_destroy_plane_state, 135 .atomic_destroy_state = malidp_destroy_plane_state,
136 .atomic_print_state = malidp_plane_atomic_print_state,
101}; 137};
102 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
103static int malidp_de_plane_check(struct drm_plane *plane, 176static int malidp_de_plane_check(struct drm_plane *plane,
104 struct drm_plane_state *state) 177 struct drm_plane_state *state)
105{ 178{
106 struct malidp_plane *mp = to_malidp_plane(plane); 179 struct malidp_plane *mp = to_malidp_plane(plane);
107 struct malidp_plane_state *ms = to_malidp_plane_state(state); 180 struct malidp_plane_state *ms = to_malidp_plane_state(state);
108 struct drm_crtc_state *crtc_state;
109 struct drm_framebuffer *fb; 181 struct drm_framebuffer *fb;
110 struct drm_rect clip = { 0 };
111 int i, ret; 182 int i, ret;
112 u32 src_w, src_h;
113 183
114 if (!state->crtc || !state->fb) 184 if (!state->crtc || !state->fb)
115 return 0; 185 return 0;
@@ -130,9 +200,6 @@ static int malidp_de_plane_check(struct drm_plane *plane,
130 } 200 }
131 } 201 }
132 202
133 src_w = state->src_w >> 16;
134 src_h = state->src_h >> 16;
135
136 if ((state->crtc_w > mp->hwdev->max_line_size) || 203 if ((state->crtc_w > mp->hwdev->max_line_size) ||
137 (state->crtc_h > mp->hwdev->max_line_size) || 204 (state->crtc_h > mp->hwdev->max_line_size) ||
138 (state->crtc_w < mp->hwdev->min_line_size) || 205 (state->crtc_w < mp->hwdev->min_line_size) ||
@@ -149,22 +216,16 @@ static int malidp_de_plane_check(struct drm_plane *plane,
149 (state->fb->pitches[1] != state->fb->pitches[2])) 216 (state->fb->pitches[1] != state->fb->pitches[2]))
150 return -EINVAL; 217 return -EINVAL;
151 218
219 ret = malidp_se_check_scaling(mp, state);
220 if (ret)
221 return ret;
222
152 /* packed RGB888 / BGR888 can't be rotated or flipped */ 223 /* packed RGB888 / BGR888 can't be rotated or flipped */
153 if (state->rotation != DRM_ROTATE_0 && 224 if (state->rotation != DRM_ROTATE_0 &&
154 (fb->format->format == DRM_FORMAT_RGB888 || 225 (fb->format->format == DRM_FORMAT_RGB888 ||
155 fb->format->format == DRM_FORMAT_BGR888)) 226 fb->format->format == DRM_FORMAT_BGR888))
156 return -EINVAL; 227 return -EINVAL;
157 228
158 crtc_state = drm_atomic_get_existing_crtc_state(state->state, state->crtc);
159 clip.x2 = crtc_state->adjusted_mode.hdisplay;
160 clip.y2 = crtc_state->adjusted_mode.vdisplay;
161 ret = drm_plane_helper_check_state(state, &clip,
162 DRM_PLANE_HELPER_NO_SCALING,
163 DRM_PLANE_HELPER_NO_SCALING,
164 true, true);
165 if (ret)
166 return ret;
167
168 ms->rotmem_size = 0; 229 ms->rotmem_size = 0;
169 if (state->rotation & MALIDP_ROTATED_MASK) { 230 if (state->rotation & MALIDP_ROTATED_MASK) {
170 int val; 231 int val;
@@ -269,6 +330,16 @@ static void malidp_de_plane_update(struct drm_plane *plane,
269 val &= ~LAYER_COMP_MASK; 330 val &= ~LAYER_COMP_MASK;
270 val |= LAYER_COMP_PIXEL; 331 val |= LAYER_COMP_PIXEL;
271 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
272 /* set the 'enable layer' bit */ 343 /* set the 'enable layer' bit */
273 val |= LAYER_ENABLE; 344 val |= LAYER_ENABLE;
274 345
@@ -281,7 +352,8 @@ static void malidp_de_plane_disable(struct drm_plane *plane,
281{ 352{
282 struct malidp_plane *mp = to_malidp_plane(plane); 353 struct malidp_plane *mp = to_malidp_plane(plane);
283 354
284 malidp_hw_clearbits(mp->hwdev, LAYER_ENABLE, 355 malidp_hw_clearbits(mp->hwdev,
356 LAYER_ENABLE | LAYER_FLOWCFG(LAYER_FLOWCFG_MASK),
285 mp->layer->base + MALIDP_LAYER_CONTROL); 357 mp->layer->base + MALIDP_LAYER_CONTROL);
286} 358}
287 359
diff --git a/drivers/gpu/drm/arm/malidp_regs.h b/drivers/gpu/drm/arm/malidp_regs.h
index b816067a65c5..2039f857f77d 100644
--- a/drivers/gpu/drm/arm/malidp_regs.h
+++ b/drivers/gpu/drm/arm/malidp_regs.h
@@ -63,6 +63,8 @@
63 63
64/* bit masks that are common between products */ 64/* bit masks that are common between products */
65#define MALIDP_CFG_VALID (1 << 0) 65#define MALIDP_CFG_VALID (1 << 0)
66#define MALIDP_DISP_FUNC_GAMMA (1 << 0)
67#define MALIDP_DISP_FUNC_CADJ (1 << 4)
66#define MALIDP_DISP_FUNC_ILACED (1 << 8) 68#define MALIDP_DISP_FUNC_ILACED (1 << 8)
67 69
68/* register offsets for IRQ management */ 70/* register offsets for IRQ management */
@@ -99,6 +101,58 @@
99 101
100#define MALIDP_PRODUCT_ID(__core_id) ((u32)(__core_id) >> 16) 102#define MALIDP_PRODUCT_ID(__core_id) ((u32)(__core_id) >> 16)
101 103
104/* register offsets relative to MALIDP5x0_COEFFS_BASE */
105#define MALIDP_COLOR_ADJ_COEF 0x00000
106#define MALIDP_COEF_TABLE_ADDR 0x00030
107#define MALIDP_COEF_TABLE_DATA 0x00034
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_ENH_MASK 3
113#define MALIDP_SE_ENH(x) (((x) & MALIDP_SE_ENH_MASK) << 2)
114#define MALIDP_SE_RGBO_IF_EN (1 << 4)
115#define MALIDP550_SE_CTL_SEL_MASK 7
116#define MALIDP550_SE_CTL_VCSEL(x) \
117 (((x) & MALIDP550_SE_CTL_SEL_MASK) << 20)
118#define MALIDP550_SE_CTL_HCSEL(x) \
119 (((x) & MALIDP550_SE_CTL_SEL_MASK) << 16)
120
121/* Blocks with offsets from SE_CONTROL register. */
122#define MALIDP_SE_LAYER_CONTROL 0x14
123#define MALIDP_SE_L0_IN_SIZE 0x00
124#define MALIDP_SE_L0_OUT_SIZE 0x04
125#define MALIDP_SE_SET_V_SIZE(x) (((x) & 0x1fff) << 16)
126#define MALIDP_SE_SET_H_SIZE(x) (((x) & 0x1fff) << 0)
127#define MALIDP_SE_SCALING_CONTROL 0x24
128#define MALIDP_SE_H_INIT_PH 0x00
129#define MALIDP_SE_H_DELTA_PH 0x04
130#define MALIDP_SE_V_INIT_PH 0x08
131#define MALIDP_SE_V_DELTA_PH 0x0c
132#define MALIDP_SE_COEFFTAB_ADDR 0x10
133#define MALIDP_SE_COEFFTAB_ADDR_MASK 0x7f
134#define MALIDP_SE_V_COEFFTAB (1 << 8)
135#define MALIDP_SE_H_COEFFTAB (1 << 9)
136#define MALIDP_SE_SET_V_COEFFTAB_ADDR(x) \
137 (MALIDP_SE_V_COEFFTAB | ((x) & MALIDP_SE_COEFFTAB_ADDR_MASK))
138#define MALIDP_SE_SET_H_COEFFTAB_ADDR(x) \
139 (MALIDP_SE_H_COEFFTAB | ((x) & MALIDP_SE_COEFFTAB_ADDR_MASK))
140#define MALIDP_SE_COEFFTAB_DATA 0x14
141#define MALIDP_SE_COEFFTAB_DATA_MASK 0x3fff
142#define MALIDP_SE_SET_COEFFTAB_DATA(x) \
143 ((x) & MALIDP_SE_COEFFTAB_DATA_MASK)
144/* Enhance coeffents reigster offset */
145#define MALIDP_SE_IMAGE_ENH 0x3C
146/* ENH_LIMITS offset 0x0 */
147#define MALIDP_SE_ENH_LOW_LEVEL 24
148#define MALIDP_SE_ENH_HIGH_LEVEL 63
149#define MALIDP_SE_ENH_LIMIT_MASK 0xfff
150#define MALIDP_SE_SET_ENH_LIMIT_LOW(x) \
151 ((x) & MALIDP_SE_ENH_LIMIT_MASK)
152#define MALIDP_SE_SET_ENH_LIMIT_HIGH(x) \
153 (((x) & MALIDP_SE_ENH_LIMIT_MASK) << 16)
154#define MALIDP_SE_ENH_COEFF0 0x04
155
102/* register offsets and bits specific to DP500 */ 156/* register offsets and bits specific to DP500 */
103#define MALIDP500_ADDR_SPACE_SIZE 0x01000 157#define MALIDP500_ADDR_SPACE_SIZE 0x01000
104#define MALIDP500_DC_BASE 0x00000 158#define MALIDP500_DC_BASE 0x00000
@@ -120,6 +174,18 @@
120#define MALIDP500_COLOR_ADJ_COEF 0x00078 174#define MALIDP500_COLOR_ADJ_COEF 0x00078
121#define MALIDP500_COEF_TABLE_ADDR 0x000a8 175#define MALIDP500_COEF_TABLE_ADDR 0x000a8
122#define MALIDP500_COEF_TABLE_DATA 0x000ac 176#define MALIDP500_COEF_TABLE_DATA 0x000ac
177
178/*
179 * The YUV2RGB coefficients on the DP500 are not in the video layer's register
180 * block. They belong in a separate block above the layer's registers, hence
181 * the negative offset.
182 */
183#define MALIDP500_LV_YUV2RGB ((s16)(-0xB8))
184/*
185 * To match DP550/650, the start of the coeffs registers is
186 * at COLORADJ_COEFF0 instead of at YUV_RGB_COEF1.
187 */
188#define MALIDP500_COEFFS_BASE 0x00078
123#define MALIDP500_DE_LV_BASE 0x00100 189#define MALIDP500_DE_LV_BASE 0x00100
124#define MALIDP500_DE_LV_PTR_BASE 0x00124 190#define MALIDP500_DE_LV_PTR_BASE 0x00124
125#define MALIDP500_DE_LG1_BASE 0x00200 191#define MALIDP500_DE_LG1_BASE 0x00200
@@ -127,6 +193,7 @@
127#define MALIDP500_DE_LG2_BASE 0x00300 193#define MALIDP500_DE_LG2_BASE 0x00300
128#define MALIDP500_DE_LG2_PTR_BASE 0x0031c 194#define MALIDP500_DE_LG2_PTR_BASE 0x0031c
129#define MALIDP500_SE_BASE 0x00c00 195#define MALIDP500_SE_BASE 0x00c00
196#define MALIDP500_SE_CONTROL 0x00c0c
130#define MALIDP500_SE_PTR_BASE 0x00e0c 197#define MALIDP500_SE_PTR_BASE 0x00e0c
131#define MALIDP500_DC_IRQ_BASE 0x00f00 198#define MALIDP500_DC_IRQ_BASE 0x00f00
132#define MALIDP500_CONFIG_VALID 0x00f00 199#define MALIDP500_CONFIG_VALID 0x00f00
@@ -145,9 +212,7 @@
145#define MALIDP550_DE_DISP_SIDEBAND 0x00040 212#define MALIDP550_DE_DISP_SIDEBAND 0x00040
146#define MALIDP550_DE_BGND_COLOR 0x00044 213#define MALIDP550_DE_BGND_COLOR 0x00044
147#define MALIDP550_DE_OUTPUT_DEPTH 0x0004c 214#define MALIDP550_DE_OUTPUT_DEPTH 0x0004c
148#define MALIDP550_DE_COLOR_COEF 0x00050 215#define MALIDP550_COEFFS_BASE 0x00050
149#define MALIDP550_DE_COEF_TABLE_ADDR 0x00080
150#define MALIDP550_DE_COEF_TABLE_DATA 0x00084
151#define MALIDP550_DE_LV1_BASE 0x00100 216#define MALIDP550_DE_LV1_BASE 0x00100
152#define MALIDP550_DE_LV1_PTR_BASE 0x00124 217#define MALIDP550_DE_LV1_PTR_BASE 0x00124
153#define MALIDP550_DE_LV2_BASE 0x00200 218#define MALIDP550_DE_LV2_BASE 0x00200
@@ -158,6 +223,7 @@
158#define MALIDP550_DE_LS_PTR_BASE 0x0042c 223#define MALIDP550_DE_LS_PTR_BASE 0x0042c
159#define MALIDP550_DE_PERF_BASE 0x00500 224#define MALIDP550_DE_PERF_BASE 0x00500
160#define MALIDP550_SE_BASE 0x08000 225#define MALIDP550_SE_BASE 0x08000
226#define MALIDP550_SE_CONTROL 0x08010
161#define MALIDP550_DC_BASE 0x0c000 227#define MALIDP550_DC_BASE 0x0c000
162#define MALIDP550_DC_CONTROL 0x0c010 228#define MALIDP550_DC_CONTROL 0x0c010
163#define MALIDP550_DC_CONFIG_REQ (1 << 16) 229#define MALIDP550_DC_CONFIG_REQ (1 << 16)