diff options
author | Mihail Atanassov <mihail.atanassov@arm.com> | 2017-02-13 18:14:05 +0300 |
---|---|---|
committer | Liviu Dudau <Liviu.Dudau@arm.com> | 2017-04-24 15:28:08 +0300 |
commit | 28ce675b74742cae1c815970347267b45dc73a8a (patch) | |
tree | 5007564e6f4829a9b7e9964b37664959665dbf44 /drivers/gpu/drm/arm/malidp_crtc.c | |
parent | 50c7512fd7496129d774ccabf32537e9a45be186 (diff) | |
download | linux-28ce675b74742cae1c815970347267b45dc73a8a.tar.xz |
drm: mali-dp: Add plane upscaling support
Enable the scaling engine for upscaling a single plane using the polyphase
scaler. No image enhancement support or downscaling yet*, and composition
result scaling is not implemented.
* Downscaling a plane requires mclk > pxlclk.
Signed-off-by: Mihail Atanassov <mihail.atanassov@arm.com>
Signed-off-by: Liviu Dudau <Liviu.Dudau@arm.com>
Diffstat (limited to 'drivers/gpu/drm/arm/malidp_crtc.c')
-rw-r--r-- | drivers/gpu/drm/arm/malidp_crtc.c | 80 |
1 files changed, 80 insertions, 0 deletions
diff --git a/drivers/gpu/drm/arm/malidp_crtc.c b/drivers/gpu/drm/arm/malidp_crtc.c index 8f2e1ae51ba0..ceee2a77bfb4 100644 --- a/drivers/gpu/drm/arm/malidp_crtc.c +++ b/drivers/gpu/drm/arm/malidp_crtc.c @@ -247,6 +247,82 @@ static int malidp_crtc_atomic_check_ctm(struct drm_crtc *crtc, return 0; } +static int malidp_crtc_atomic_check_scaling(struct drm_crtc *crtc, + struct drm_crtc_state *state) +{ + struct malidp_crtc_state *cs = to_malidp_crtc_state(state); + struct malidp_se_config *s = &cs->scaler_config; + struct drm_plane *plane; + const struct drm_plane_state *pstate; + u32 h_upscale_factor = 0; /* U16.16 */ + u32 v_upscale_factor = 0; /* U16.16 */ + u8 scaling = cs->scaled_planes_mask; + + if (!scaling) { + s->scale_enable = false; + return 0; + } + + /* The scaling engine can only handle one plane at a time. */ + if (scaling & (scaling - 1)) + return -EINVAL; + + drm_atomic_crtc_state_for_each_plane_state(plane, pstate, state) { + struct malidp_plane *mp = to_malidp_plane(plane); + u64 crtc_w, crtc_h; + u32 phase; + + if (!(mp->layer->id & scaling)) + continue; + + /* + * Convert crtc_[w|h] to U32.32, then divide by U16.16 src_[w|h] + * to get the U16.16 result. + */ + crtc_w = (u64)pstate->crtc_w << 32; + crtc_h = (u64)pstate->crtc_h << 32; + h_upscale_factor = (u32)(crtc_w / pstate->src_w); + v_upscale_factor = (u32)(crtc_h / pstate->src_h); + + /* Downscaling won't work when mclk == pxlclk. */ + if (!(h_upscale_factor >> 16) || !(v_upscale_factor >> 16)) + return -EINVAL; + + s->input_w = pstate->src_w >> 16; + s->input_h = pstate->src_h >> 16; + s->output_w = pstate->crtc_w; + s->output_h = pstate->crtc_h; + +#define SE_N_PHASE 4 +#define SE_SHIFT_N_PHASE 12 + /* Calculate initial_phase and delta_phase for horizontal. */ + phase = s->input_w; + s->h_init_phase = + ((phase << SE_N_PHASE) / s->output_w + 1) / 2; + + phase = s->input_w; + phase <<= (SE_SHIFT_N_PHASE + SE_N_PHASE); + s->h_delta_phase = phase / s->output_w; + + /* Same for vertical. */ + phase = s->input_h; + s->v_init_phase = + ((phase << SE_N_PHASE) / s->output_h + 1) / 2; + + phase = s->input_h; + phase <<= (SE_SHIFT_N_PHASE + SE_N_PHASE); + s->v_delta_phase = phase / s->output_h; +#undef SE_N_PHASE +#undef SE_SHIFT_N_PHASE + s->plane_src_id = mp->layer->id; + } + + s->scale_enable = true; + s->hcoeff = malidp_se_select_coeffs(h_upscale_factor); + s->vcoeff = malidp_se_select_coeffs(v_upscale_factor); + return 0; +} + static int malidp_crtc_atomic_check(struct drm_crtc *crtc, struct drm_crtc_state *state) { @@ -325,6 +401,7 @@ static int malidp_crtc_atomic_check(struct drm_crtc *crtc, ret = malidp_crtc_atomic_check_gamma(crtc, state); ret = ret ? ret : malidp_crtc_atomic_check_ctm(crtc, state); + ret = ret ? ret : malidp_crtc_atomic_check_scaling(crtc, state); return ret; } @@ -353,6 +430,9 @@ static struct drm_crtc_state *malidp_crtc_duplicate_state(struct drm_crtc *crtc) sizeof(state->gamma_coeffs)); memcpy(state->coloradj_coeffs, old_state->coloradj_coeffs, sizeof(state->coloradj_coeffs)); + memcpy(&state->scaler_config, &old_state->scaler_config, + sizeof(state->scaler_config)); + state->scaled_planes_mask = 0; return &state->base; } |