Commit c2e7f82d authored by Mihail Atanassov's avatar Mihail Atanassov Committed by Liviu Dudau

drm: mali-dp: Check the mclk rate and allow up/down scaling

When downscaling, mclk needs to be sufficiently higher than pxlclk in
order to be able to fetch the higher-resolution data and produce output
pixels. When not scaling, or when upscaling, mclk can be equal to
pxlclk. Since the driver doesn't control mclk, just ensure that the
requirement is satisfied with the current clock rate.
Signed-off-by: default avatarMihail Atanassov <mihail.atanassov@arm.com>
Signed-off-by: default avatarLiviu Dudau <Liviu.Dudau@arm.com>
parent 0274e6a0
......@@ -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;
}
......
......@@ -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,
},
};
......
......@@ -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;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment