diff options
| -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) |
