diff options
Diffstat (limited to 'drivers/gpu/drm/arm')
-rw-r--r-- | drivers/gpu/drm/arm/malidp_crtc.c | 23 | ||||
-rw-r--r-- | drivers/gpu/drm/arm/malidp_hw.c | 70 | ||||
-rw-r--r-- | drivers/gpu/drm/arm/malidp_hw.h | 4 |
3 files changed, 85 insertions, 12 deletions
diff --git a/drivers/gpu/drm/arm/malidp_crtc.c b/drivers/gpu/drm/arm/malidp_crtc.c index b0f0365efd23..19f1f3b34691 100644 --- a/drivers/gpu/drm/arm/malidp_crtc.c +++ b/drivers/gpu/drm/arm/malidp_crtc.c @@ -36,13 +36,6 @@ static bool malidp_crtc_mode_fixup(struct drm_crtc *crtc, long rate, req_rate = mode->crtc_clock * 1000; if (req_rate) { - rate = clk_round_rate(hwdev->mclk, req_rate); - if (rate < req_rate) { - DRM_DEBUG_DRIVER("mclk clock unable to reach %d kHz\n", - mode->crtc_clock); - return false; - } - rate = clk_round_rate(hwdev->pxlclk, req_rate); if (rate != req_rate) { DRM_DEBUG_DRIVER("pxlclk doesn't support %ld Hz\n", @@ -250,17 +243,21 @@ static int malidp_crtc_atomic_check_ctm(struct drm_crtc *crtc, static int malidp_crtc_atomic_check_scaling(struct drm_crtc *crtc, struct drm_crtc_state *state) { + struct malidp_drm *malidp = crtc_to_malidp_device(crtc); + struct malidp_hw_device *hwdev = malidp->dev; struct malidp_crtc_state *cs = to_malidp_crtc_state(state); struct malidp_se_config *s = &cs->scaler_config; struct drm_plane *plane; + struct videomode vm; 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; + int ret; if (!scaling) { s->scale_enable = false; - return 0; + goto mclk_calc; } /* The scaling engine can only handle one plane at a time. */ @@ -284,10 +281,6 @@ static int malidp_crtc_atomic_check_scaling(struct drm_crtc *crtc, 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->enhancer_enable = ((h_upscale_factor >> 16) >= 2 || (v_upscale_factor >> 16) >= 2); @@ -323,6 +316,12 @@ static int malidp_crtc_atomic_check_scaling(struct drm_crtc *crtc, s->scale_enable = true; s->hcoeff = malidp_se_select_coeffs(h_upscale_factor); s->vcoeff = malidp_se_select_coeffs(v_upscale_factor); + +mclk_calc: + drm_display_mode_to_videomode(&state->adjusted_mode, &vm); + ret = hwdev->se_calc_mclk(hwdev, s, &vm); + if (ret < 0) + return -EINVAL; return 0; } diff --git a/drivers/gpu/drm/arm/malidp_hw.c b/drivers/gpu/drm/arm/malidp_hw.c index e444c23a8261..28360b8542f7 100644 --- a/drivers/gpu/drm/arm/malidp_hw.c +++ b/drivers/gpu/drm/arm/malidp_hw.c @@ -12,6 +12,7 @@ * in an attempt to provide to the rest of the driver code a unified view */ +#include <linux/clk.h> #include <linux/types.h> #include <linux/io.h> #include <drm/drmP.h> @@ -334,6 +335,39 @@ static int malidp500_se_set_scaling_coeffs(struct malidp_hw_device *hwdev, return 0; } +static long malidp500_se_calc_mclk(struct malidp_hw_device *hwdev, + struct malidp_se_config *se_config, + struct videomode *vm) +{ + unsigned long mclk; + unsigned long pxlclk = vm->pixelclock; /* Hz */ + unsigned long htotal = vm->hactive + vm->hfront_porch + + vm->hback_porch + vm->hsync_len; + unsigned long input_size = se_config->input_w * se_config->input_h; + unsigned long a = 10; + long ret; + + /* + * mclk = max(a, 1.5) * pxlclk + * + * To avoid float calculaiton, using 15 instead of 1.5 and div by + * 10 to get mclk. + */ + if (se_config->scale_enable) { + a = 15 * input_size / (htotal * se_config->output_h); + if (a < 15) + a = 15; + } + mclk = a * pxlclk / 10; + ret = clk_get_rate(hwdev->mclk); + if (ret < mclk) { + DRM_DEBUG_DRIVER("mclk requirement of %lu kHz can't be met.\n", + mclk / 1000); + return -EINVAL; + } + return ret; +} + static int malidp550_query_hw(struct malidp_hw_device *hwdev) { u32 conf = malidp_hw_read(hwdev, MALIDP550_CONFIG_ID); @@ -521,6 +555,39 @@ static int malidp550_se_set_scaling_coeffs(struct malidp_hw_device *hwdev, return 0; } +static long malidp550_se_calc_mclk(struct malidp_hw_device *hwdev, + struct malidp_se_config *se_config, + struct videomode *vm) +{ + unsigned long mclk; + unsigned long pxlclk = vm->pixelclock; + unsigned long htotal = vm->hactive + vm->hfront_porch + + vm->hback_porch + vm->hsync_len; + unsigned long numerator = 1, denominator = 1; + long ret; + + if (se_config->scale_enable) { + numerator = max(se_config->input_w, se_config->output_w) * + se_config->input_h; + numerator += se_config->output_w * + (se_config->output_h - + min(se_config->input_h, se_config->output_h)); + denominator = (htotal - 2) * se_config->output_h; + } + + /* mclk can't be slower than pxlclk. */ + if (numerator < denominator) + numerator = denominator = 1; + mclk = (pxlclk * numerator) / denominator; + ret = clk_get_rate(hwdev->mclk); + if (ret < mclk) { + DRM_DEBUG_DRIVER("mclk requirement of %lu kHz can't be met.\n", + mclk / 1000); + return -EINVAL; + } + return ret; +} + static int malidp650_query_hw(struct malidp_hw_device *hwdev) { u32 conf = malidp_hw_read(hwdev, MALIDP550_CONFIG_ID); @@ -586,6 +653,7 @@ const struct malidp_hw_device malidp_device[MALIDP_MAX_DEVICES] = { .modeset = malidp500_modeset, .rotmem_required = malidp500_rotmem_required, .se_set_scaling_coeffs = malidp500_se_set_scaling_coeffs, + .se_calc_mclk = malidp500_se_calc_mclk, .features = MALIDP_DEVICE_LV_HAS_3_STRIDES, }, [MALIDP_550] = { @@ -622,6 +690,7 @@ const struct malidp_hw_device malidp_device[MALIDP_MAX_DEVICES] = { .modeset = malidp550_modeset, .rotmem_required = malidp550_rotmem_required, .se_set_scaling_coeffs = malidp550_se_set_scaling_coeffs, + .se_calc_mclk = malidp550_se_calc_mclk, .features = 0, }, [MALIDP_650] = { @@ -659,6 +728,7 @@ const struct malidp_hw_device malidp_device[MALIDP_MAX_DEVICES] = { .modeset = malidp550_modeset, .rotmem_required = malidp550_rotmem_required, .se_set_scaling_coeffs = malidp550_se_set_scaling_coeffs, + .se_calc_mclk = malidp550_se_calc_mclk, .features = 0, }, }; diff --git a/drivers/gpu/drm/arm/malidp_hw.h b/drivers/gpu/drm/arm/malidp_hw.h index a93ae0a951a3..849ad9a30c3a 100644 --- a/drivers/gpu/drm/arm/malidp_hw.h +++ b/drivers/gpu/drm/arm/malidp_hw.h @@ -177,6 +177,10 @@ struct malidp_hw_device { struct malidp_se_config *se_config, struct malidp_se_config *old_config); + long (*se_calc_mclk)(struct malidp_hw_device *hwdev, + struct malidp_se_config *se_config, + struct videomode *vm); + u8 features; u8 min_line_size; |