diff options
author | Dave Airlie <airlied@redhat.com> | 2017-04-28 15:48:45 -0400 |
---|---|---|
committer | Dave Airlie <airlied@redhat.com> | 2017-04-28 15:48:45 -0400 |
commit | 97643d75b053cd2aa7b23a93a474ed3690e34384 (patch) | |
tree | ea546747872e054429aab11defc21a0987ccd898 /drivers/gpu/drm | |
parent | 6b1462700b4a6a1244c018cdd2fa97ded43090a0 (diff) | |
parent | 763656d30b3d220a52e4b2bd1fc174a4cd6c0f43 (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.c | 341 | ||||
-rw-r--r-- | drivers/gpu/drm/arm/malidp_drv.c | 307 | ||||
-rw-r--r-- | drivers/gpu/drm/arm/malidp_drv.h | 13 | ||||
-rw-r--r-- | drivers/gpu/drm/arm/malidp_hw.c | 213 | ||||
-rw-r--r-- | drivers/gpu/drm/arm/malidp_hw.h | 81 | ||||
-rw-r--r-- | drivers/gpu/drm/arm/malidp_planes.c | 108 | ||||
-rw-r--r-- | drivers/gpu/drm/arm/malidp_regs.h | 72 |
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 | |||
89 | static 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 | |||
120 | static 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 | */ | ||
144 | static 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 | */ | ||
198 | static 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 | |||
243 | static 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 | |||
319 | mclk_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 | ||
84 | static int malidp_crtc_atomic_check(struct drm_crtc *crtc, | 327 | static 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 | ||
162 | static const struct drm_crtc_helper_funcs malidp_crtc_helper_funcs = { | 410 | static 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 | ||
417 | static 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 | |||
441 | static 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 | |||
458 | static 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 | |||
169 | static int malidp_crtc_enable_vblank(struct drm_crtc *crtc) | 471 | static 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 | ||
188 | static const struct drm_crtc_funcs malidp_crtc_funcs = { | 490 | static 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 | ||
232 | crtc_cleanup_planes: | 541 | crtc_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 | ||
37 | static 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 | |||
56 | static 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 | |||
82 | static | ||
83 | void 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 | |||
113 | static 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) | |||
88 | static void malidp_atomic_commit_tail(struct drm_atomic_state *state) | 217 | static 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 | ||
424 | static 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 | |||
433 | DEVICE_ATTR_RO(core_id); | ||
434 | |||
435 | static 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 | |||
445 | static 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 | ||
452 | static 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 | |||
469 | static 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 | |||
282 | static int malidp_bind(struct device *dev) | 483 | static 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); | ||
444 | fbdev_fail: | 653 | fbdev_fail: |
654 | pm_runtime_get_sync(dev); | ||
445 | drm_vblank_cleanup(drm); | 655 | drm_vblank_cleanup(drm); |
446 | vblank_fail: | 656 | vblank_fail: |
447 | malidp_se_irq_fini(drm); | 657 | malidp_se_irq_fini(drm); |
@@ -452,14 +662,17 @@ irq_init_fail: | |||
452 | bind_fail: | 662 | bind_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); | ||
456 | init_fail: | 665 | init_fail: |
666 | malidp_fini_sysfs(dev); | ||
667 | malidp_fini(drm); | ||
668 | query_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); |
459 | query_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); |
464 | alloc_fail: | 677 | alloc_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 | ||
752 | static 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 | |||
773 | static 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 | |||
787 | static 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 | |||
536 | static struct platform_driver malidp_platform_driver = { | 792 | static 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 | ||
52 | struct 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 | |||
50 | int malidp_de_planes_init(struct drm_device *drm); | 63 | int malidp_de_planes_init(struct drm_device *drm); |
51 | void malidp_de_planes_destroy(struct drm_device *drm); | 64 | void malidp_de_planes_destroy(struct drm_device *drm); |
52 | int malidp_crtc_init(struct drm_device *drm); | 65 | int 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 | ||
91 | static 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 | ||
91 | static int malidp500_query_hw(struct malidp_hw_device *hwdev) | 166 | static 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 | ||
289 | static 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 | |||
306 | static 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 | |||
338 | static 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 | |||
214 | static int malidp550_query_hw(struct malidp_hw_device *hwdev) | 371 | static 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 | ||
544 | static 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 | |||
558 | static 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 | |||
387 | static int malidp650_query_hw(struct malidp_hw_device *hwdev) | 591 | static 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) | |||
415 | const struct malidp_hw_device malidp_device[MALIDP_MAX_DEVICES] = { | 619 | const 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 | ||
64 | enum 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 | |||
72 | struct 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 | ||
67 | struct malidp_hw_regmap { | 87 | struct 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 | ||
174 | static inline u32 malidp_hw_read(struct malidp_hw_device *hwdev, u32 reg) | 207 | static 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 | ||
179 | static inline void malidp_hw_write(struct malidp_hw_device *hwdev, | 213 | static 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 | |||
288 | static inline enum malidp_scaling_coeff_set | ||
289 | malidp_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 | |||
304 | static 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 | */ | ||
72 | static 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 | |||
63 | static struct | 88 | static struct |
64 | drm_plane_state *malidp_duplicate_plane_state(struct drm_plane *plane) | 89 | drm_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 | ||
118 | static 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 | |||
93 | static const struct drm_plane_funcs malidp_de_plane_funcs = { | 128 | static 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 | ||
139 | static 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 | |||
103 | static int malidp_de_plane_check(struct drm_plane *plane, | 176 | static 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) |