From: Mihail Atanassov Date: Mon, 13 Feb 2017 15:14:05 +0000 (+0000) Subject: drm: mali-dp: Add plane upscaling support X-Git-Url: https://git.stricted.de/?a=commitdiff_plain;h=28ce675b74742cae1c815970347267b45dc73a8a;p=GitHub%2FLineageOS%2Fandroid_kernel_motorola_exynos9610.git 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 Signed-off-by: Liviu Dudau --- 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; } diff --git a/drivers/gpu/drm/arm/malidp_drv.c b/drivers/gpu/drm/arm/malidp_drv.c index 24bc96f9e91c..baca2dce1b92 100644 --- a/drivers/gpu/drm/arm/malidp_drv.c +++ b/drivers/gpu/drm/arm/malidp_drv.c @@ -110,6 +110,52 @@ void malidp_atomic_commit_update_coloradj(struct drm_crtc *crtc, } } +static void malidp_atomic_commit_se_config(struct drm_crtc *crtc, + struct drm_crtc_state *old_state) +{ + struct malidp_crtc_state *cs = to_malidp_crtc_state(crtc->state); + struct malidp_crtc_state *old_cs = to_malidp_crtc_state(old_state); + struct malidp_drm *malidp = crtc_to_malidp_device(crtc); + struct malidp_hw_device *hwdev = malidp->dev; + struct malidp_se_config *s = &cs->scaler_config; + struct malidp_se_config *old_s = &old_cs->scaler_config; + u32 se_control = hwdev->map.se_base + + ((hwdev->map.features & MALIDP_REGMAP_HAS_CLEARIRQ) ? + 0x10 : 0xC); + u32 layer_control = se_control + MALIDP_SE_LAYER_CONTROL; + u32 scr = se_control + MALIDP_SE_SCALING_CONTROL; + u32 val; + + /* Set SE_CONTROL */ + if (!s->scale_enable) { + val = malidp_hw_read(hwdev, se_control); + val &= ~MALIDP_SE_SCALING_EN; + malidp_hw_write(hwdev, val, se_control); + return; + } + + hwdev->se_set_scaling_coeffs(hwdev, s, old_s); + val = malidp_hw_read(hwdev, se_control); + val |= MALIDP_SE_SCALING_EN | MALIDP_SE_ALPHA_EN; + + val |= MALIDP_SE_RGBO_IF_EN; + malidp_hw_write(hwdev, val, se_control); + + /* Set IN_SIZE & OUT_SIZE. */ + val = MALIDP_SE_SET_V_SIZE(s->input_h) | + MALIDP_SE_SET_H_SIZE(s->input_w); + malidp_hw_write(hwdev, val, layer_control + MALIDP_SE_L0_IN_SIZE); + val = MALIDP_SE_SET_V_SIZE(s->output_h) | + MALIDP_SE_SET_H_SIZE(s->output_w); + malidp_hw_write(hwdev, val, layer_control + MALIDP_SE_L0_OUT_SIZE); + + /* Set phase regs. */ + malidp_hw_write(hwdev, s->h_init_phase, scr + MALIDP_SE_H_INIT_PH); + malidp_hw_write(hwdev, s->h_delta_phase, scr + MALIDP_SE_H_DELTA_PH); + malidp_hw_write(hwdev, s->v_init_phase, scr + MALIDP_SE_V_INIT_PH); + malidp_hw_write(hwdev, s->v_delta_phase, scr + MALIDP_SE_V_DELTA_PH); +} + /* * set the "config valid" bit and wait until the hardware acts on it */ @@ -179,6 +225,7 @@ static void malidp_atomic_commit_tail(struct drm_atomic_state *state) for_each_crtc_in_state(state, crtc, old_crtc_state, i) { malidp_atomic_commit_update_gamma(crtc, old_crtc_state); malidp_atomic_commit_update_coloradj(crtc, old_crtc_state); + malidp_atomic_commit_se_config(crtc, old_crtc_state); } drm_atomic_helper_commit_planes(drm, state, 0); diff --git a/drivers/gpu/drm/arm/malidp_drv.h b/drivers/gpu/drm/arm/malidp_drv.h index 75070efda2fc..040311ffcaec 100644 --- a/drivers/gpu/drm/arm/malidp_drv.h +++ b/drivers/gpu/drm/arm/malidp_drv.h @@ -53,6 +53,9 @@ struct malidp_crtc_state { struct drm_crtc_state base; u32 gamma_coeffs[MALIDP_COEFFTAB_NUM_COEFFS]; u32 coloradj_coeffs[MALIDP_COLORADJ_NUM_COEFFS]; + struct malidp_se_config scaler_config; + /* Bitfield of all the planes that have requested a scaled output. */ + u8 scaled_planes_mask; }; #define to_malidp_crtc_state(x) container_of(x, struct malidp_crtc_state, base) diff --git a/drivers/gpu/drm/arm/malidp_hw.c b/drivers/gpu/drm/arm/malidp_hw.c index b8025b7c1aca..e444c23a8261 100644 --- a/drivers/gpu/drm/arm/malidp_hw.c +++ b/drivers/gpu/drm/arm/malidp_hw.c @@ -86,6 +86,80 @@ static const struct malidp_layer malidp550_layers[] = { { DE_SMART, MALIDP550_DE_LS_BASE, MALIDP550_DE_LS_PTR_BASE, MALIDP550_DE_LS_R1_STRIDE }, }; +#define SE_N_SCALING_COEFFS 96 +static const u16 dp500_se_scaling_coeffs[][SE_N_SCALING_COEFFS] = { + [MALIDP_UPSCALING_COEFFS - 1] = { + 0x0000, 0x0001, 0x0007, 0x0011, 0x001e, 0x002e, 0x003f, 0x0052, + 0x0064, 0x0073, 0x007d, 0x0080, 0x007a, 0x006c, 0x0053, 0x002f, + 0x0000, 0x3fc6, 0x3f83, 0x3f39, 0x3eea, 0x3e9b, 0x3e4f, 0x3e0a, + 0x3dd4, 0x3db0, 0x3da2, 0x3db1, 0x3dde, 0x3e2f, 0x3ea5, 0x3f40, + 0x0000, 0x00e5, 0x01ee, 0x0315, 0x0456, 0x05aa, 0x0709, 0x086c, + 0x09c9, 0x0b15, 0x0c4a, 0x0d5d, 0x0e4a, 0x0f06, 0x0f91, 0x0fe5, + 0x1000, 0x0fe5, 0x0f91, 0x0f06, 0x0e4a, 0x0d5d, 0x0c4a, 0x0b15, + 0x09c9, 0x086c, 0x0709, 0x05aa, 0x0456, 0x0315, 0x01ee, 0x00e5, + 0x0000, 0x3f40, 0x3ea5, 0x3e2f, 0x3dde, 0x3db1, 0x3da2, 0x3db0, + 0x3dd4, 0x3e0a, 0x3e4f, 0x3e9b, 0x3eea, 0x3f39, 0x3f83, 0x3fc6, + 0x0000, 0x002f, 0x0053, 0x006c, 0x007a, 0x0080, 0x007d, 0x0073, + 0x0064, 0x0052, 0x003f, 0x002e, 0x001e, 0x0011, 0x0007, 0x0001 + }, + [MALIDP_DOWNSCALING_1_5_COEFFS - 1] = { + 0x0059, 0x004f, 0x0041, 0x002e, 0x0016, 0x3ffb, 0x3fd9, 0x3fb4, + 0x3f8c, 0x3f62, 0x3f36, 0x3f09, 0x3edd, 0x3eb3, 0x3e8d, 0x3e6c, + 0x3e52, 0x3e3f, 0x3e35, 0x3e37, 0x3e46, 0x3e61, 0x3e8c, 0x3ec5, + 0x3f0f, 0x3f68, 0x3fd1, 0x004a, 0x00d3, 0x0169, 0x020b, 0x02b8, + 0x036e, 0x042d, 0x04f2, 0x05b9, 0x0681, 0x0745, 0x0803, 0x08ba, + 0x0965, 0x0a03, 0x0a91, 0x0b0d, 0x0b75, 0x0bc6, 0x0c00, 0x0c20, + 0x0c28, 0x0c20, 0x0c00, 0x0bc6, 0x0b75, 0x0b0d, 0x0a91, 0x0a03, + 0x0965, 0x08ba, 0x0803, 0x0745, 0x0681, 0x05b9, 0x04f2, 0x042d, + 0x036e, 0x02b8, 0x020b, 0x0169, 0x00d3, 0x004a, 0x3fd1, 0x3f68, + 0x3f0f, 0x3ec5, 0x3e8c, 0x3e61, 0x3e46, 0x3e37, 0x3e35, 0x3e3f, + 0x3e52, 0x3e6c, 0x3e8d, 0x3eb3, 0x3edd, 0x3f09, 0x3f36, 0x3f62, + 0x3f8c, 0x3fb4, 0x3fd9, 0x3ffb, 0x0016, 0x002e, 0x0041, 0x004f + }, + [MALIDP_DOWNSCALING_2_COEFFS - 1] = { + 0x3f19, 0x3f03, 0x3ef0, 0x3edf, 0x3ed0, 0x3ec5, 0x3ebd, 0x3eb9, + 0x3eb9, 0x3ebf, 0x3eca, 0x3ed9, 0x3eef, 0x3f0a, 0x3f2c, 0x3f52, + 0x3f7f, 0x3fb0, 0x3fe8, 0x0026, 0x006a, 0x00b4, 0x0103, 0x0158, + 0x01b1, 0x020d, 0x026c, 0x02cd, 0x032f, 0x0392, 0x03f4, 0x0455, + 0x04b4, 0x051e, 0x0585, 0x05eb, 0x064c, 0x06a8, 0x06fe, 0x074e, + 0x0796, 0x07d5, 0x080c, 0x0839, 0x085c, 0x0875, 0x0882, 0x0887, + 0x0881, 0x0887, 0x0882, 0x0875, 0x085c, 0x0839, 0x080c, 0x07d5, + 0x0796, 0x074e, 0x06fe, 0x06a8, 0x064c, 0x05eb, 0x0585, 0x051e, + 0x04b4, 0x0455, 0x03f4, 0x0392, 0x032f, 0x02cd, 0x026c, 0x020d, + 0x01b1, 0x0158, 0x0103, 0x00b4, 0x006a, 0x0026, 0x3fe8, 0x3fb0, + 0x3f7f, 0x3f52, 0x3f2c, 0x3f0a, 0x3eef, 0x3ed9, 0x3eca, 0x3ebf, + 0x3eb9, 0x3eb9, 0x3ebd, 0x3ec5, 0x3ed0, 0x3edf, 0x3ef0, 0x3f03 + }, + [MALIDP_DOWNSCALING_2_75_COEFFS - 1] = { + 0x3f51, 0x3f60, 0x3f71, 0x3f84, 0x3f98, 0x3faf, 0x3fc8, 0x3fe3, + 0x0000, 0x001f, 0x0040, 0x0064, 0x008a, 0x00b1, 0x00da, 0x0106, + 0x0133, 0x0160, 0x018e, 0x01bd, 0x01ec, 0x021d, 0x024e, 0x0280, + 0x02b2, 0x02e4, 0x0317, 0x0349, 0x037c, 0x03ad, 0x03df, 0x0410, + 0x0440, 0x0468, 0x048f, 0x04b3, 0x04d6, 0x04f8, 0x0516, 0x0533, + 0x054e, 0x0566, 0x057c, 0x0590, 0x05a0, 0x05ae, 0x05ba, 0x05c3, + 0x05c9, 0x05c3, 0x05ba, 0x05ae, 0x05a0, 0x0590, 0x057c, 0x0566, + 0x054e, 0x0533, 0x0516, 0x04f8, 0x04d6, 0x04b3, 0x048f, 0x0468, + 0x0440, 0x0410, 0x03df, 0x03ad, 0x037c, 0x0349, 0x0317, 0x02e4, + 0x02b2, 0x0280, 0x024e, 0x021d, 0x01ec, 0x01bd, 0x018e, 0x0160, + 0x0133, 0x0106, 0x00da, 0x00b1, 0x008a, 0x0064, 0x0040, 0x001f, + 0x0000, 0x3fe3, 0x3fc8, 0x3faf, 0x3f98, 0x3f84, 0x3f71, 0x3f60 + }, + [MALIDP_DOWNSCALING_4_COEFFS - 1] = { + 0x0094, 0x00a9, 0x00be, 0x00d4, 0x00ea, 0x0101, 0x0118, 0x012f, + 0x0148, 0x0160, 0x017a, 0x0193, 0x01ae, 0x01c8, 0x01e4, 0x01ff, + 0x021c, 0x0233, 0x024a, 0x0261, 0x0278, 0x028f, 0x02a6, 0x02bd, + 0x02d4, 0x02eb, 0x0302, 0x0319, 0x032f, 0x0346, 0x035d, 0x0374, + 0x038a, 0x0397, 0x03a3, 0x03af, 0x03bb, 0x03c6, 0x03d1, 0x03db, + 0x03e4, 0x03ed, 0x03f6, 0x03fe, 0x0406, 0x040d, 0x0414, 0x041a, + 0x0420, 0x041a, 0x0414, 0x040d, 0x0406, 0x03fe, 0x03f6, 0x03ed, + 0x03e4, 0x03db, 0x03d1, 0x03c6, 0x03bb, 0x03af, 0x03a3, 0x0397, + 0x038a, 0x0374, 0x035d, 0x0346, 0x032f, 0x0319, 0x0302, 0x02eb, + 0x02d4, 0x02bd, 0x02a6, 0x028f, 0x0278, 0x0261, 0x024a, 0x0233, + 0x021c, 0x01ff, 0x01e4, 0x01c8, 0x01ae, 0x0193, 0x017a, 0x0160, + 0x0148, 0x012f, 0x0118, 0x0101, 0x00ea, 0x00d4, 0x00be, 0x00a9 + }, +}; + #define MALIDP_DE_DEFAULT_PREFETCH_START 5 static int malidp500_query_hw(struct malidp_hw_device *hwdev) @@ -211,6 +285,55 @@ static int malidp500_rotmem_required(struct malidp_hw_device *hwdev, u16 w, u16 return w * drm_format_plane_cpp(fmt, 0) * 8; } +static void malidp500_se_write_pp_coefftab(struct malidp_hw_device *hwdev, + u32 direction, + u16 addr, + u8 coeffs_id) +{ + int i; + u16 scaling_control = MALIDP500_SE_CONTROL + MALIDP_SE_SCALING_CONTROL; + + malidp_hw_write(hwdev, + direction | (addr & MALIDP_SE_COEFFTAB_ADDR_MASK), + scaling_control + MALIDP_SE_COEFFTAB_ADDR); + for (i = 0; i < ARRAY_SIZE(dp500_se_scaling_coeffs); ++i) + malidp_hw_write(hwdev, MALIDP_SE_SET_COEFFTAB_DATA( + dp500_se_scaling_coeffs[coeffs_id][i]), + scaling_control + MALIDP_SE_COEFFTAB_DATA); +} + +static int malidp500_se_set_scaling_coeffs(struct malidp_hw_device *hwdev, + struct malidp_se_config *se_config, + struct malidp_se_config *old_config) +{ + /* Get array indices into dp500_se_scaling_coeffs. */ + u8 h = (u8)se_config->hcoeff - 1; + u8 v = (u8)se_config->vcoeff - 1; + + if (WARN_ON(h >= ARRAY_SIZE(dp500_se_scaling_coeffs) || + v >= ARRAY_SIZE(dp500_se_scaling_coeffs))) + return -EINVAL; + + if ((h == v) && (se_config->hcoeff != old_config->hcoeff || + se_config->vcoeff != old_config->vcoeff)) { + malidp500_se_write_pp_coefftab(hwdev, + (MALIDP_SE_V_COEFFTAB | + MALIDP_SE_H_COEFFTAB), + 0, v); + } else { + if (se_config->vcoeff != old_config->vcoeff) + malidp500_se_write_pp_coefftab(hwdev, + MALIDP_SE_V_COEFFTAB, + 0, v); + if (se_config->hcoeff != old_config->hcoeff) + malidp500_se_write_pp_coefftab(hwdev, + MALIDP_SE_H_COEFFTAB, + 0, h); + } + + return 0; +} + static int malidp550_query_hw(struct malidp_hw_device *hwdev) { u32 conf = malidp_hw_read(hwdev, MALIDP550_CONFIG_ID); @@ -384,6 +507,20 @@ static int malidp550_rotmem_required(struct malidp_hw_device *hwdev, u16 w, u16 return w * bytes_per_col; } +static int malidp550_se_set_scaling_coeffs(struct malidp_hw_device *hwdev, + struct malidp_se_config *se_config, + struct malidp_se_config *old_config) +{ + u32 mask = MALIDP550_SE_CTL_VCSEL(MALIDP550_SE_CTL_SEL_MASK) | + MALIDP550_SE_CTL_HCSEL(MALIDP550_SE_CTL_SEL_MASK); + u32 new_value = MALIDP550_SE_CTL_VCSEL(se_config->vcoeff) | + MALIDP550_SE_CTL_HCSEL(se_config->hcoeff); + + malidp_hw_clearbits(hwdev, mask, MALIDP550_SE_CONTROL); + malidp_hw_setbits(hwdev, new_value, MALIDP550_SE_CONTROL); + return 0; +} + static int malidp650_query_hw(struct malidp_hw_device *hwdev) { u32 conf = malidp_hw_read(hwdev, MALIDP550_CONFIG_ID); @@ -448,6 +585,7 @@ const struct malidp_hw_device malidp_device[MALIDP_MAX_DEVICES] = { .set_config_valid = malidp500_set_config_valid, .modeset = malidp500_modeset, .rotmem_required = malidp500_rotmem_required, + .se_set_scaling_coeffs = malidp500_se_set_scaling_coeffs, .features = MALIDP_DEVICE_LV_HAS_3_STRIDES, }, [MALIDP_550] = { @@ -483,6 +621,7 @@ const struct malidp_hw_device malidp_device[MALIDP_MAX_DEVICES] = { .set_config_valid = malidp550_set_config_valid, .modeset = malidp550_modeset, .rotmem_required = malidp550_rotmem_required, + .se_set_scaling_coeffs = malidp550_se_set_scaling_coeffs, .features = 0, }, [MALIDP_650] = { @@ -519,6 +658,7 @@ const struct malidp_hw_device malidp_device[MALIDP_MAX_DEVICES] = { .set_config_valid = malidp550_set_config_valid, .modeset = malidp550_modeset, .rotmem_required = malidp550_rotmem_required, + .se_set_scaling_coeffs = malidp550_se_set_scaling_coeffs, .features = 0, }, }; diff --git a/drivers/gpu/drm/arm/malidp_hw.h b/drivers/gpu/drm/arm/malidp_hw.h index 470fe71724a3..52a65a8a056f 100644 --- a/drivers/gpu/drm/arm/malidp_hw.h +++ b/drivers/gpu/drm/arm/malidp_hw.h @@ -61,6 +61,25 @@ struct malidp_layer { u16 stride_offset; /* Offset to the first stride register. */ }; +enum malidp_scaling_coeff_set { + MALIDP_UPSCALING_COEFFS = 1, + MALIDP_DOWNSCALING_1_5_COEFFS = 2, + MALIDP_DOWNSCALING_2_COEFFS = 3, + MALIDP_DOWNSCALING_2_75_COEFFS = 4, + MALIDP_DOWNSCALING_4_COEFFS = 5, +}; + +struct malidp_se_config { + u8 scale_enable : 1; + u8 hcoeff : 3; + u8 vcoeff : 3; + u8 plane_src_id; + u16 input_w, input_h; + u16 output_w, output_h; + u32 h_init_phase, h_delta_phase; + u32 v_init_phase, v_delta_phase; +}; + /* regmap features */ #define MALIDP_REGMAP_HAS_CLEARIRQ (1 << 0) @@ -153,6 +172,10 @@ struct malidp_hw_device { */ int (*rotmem_required)(struct malidp_hw_device *hwdev, u16 w, u16 h, u32 fmt); + int (*se_set_scaling_coeffs)(struct malidp_hw_device *hwdev, + struct malidp_se_config *se_config, + struct malidp_se_config *old_config); + u8 features; u8 min_line_size; @@ -250,6 +273,28 @@ static inline bool malidp_hw_pitch_valid(struct malidp_hw_device *hwdev, return !(pitch & (hwdev->map.bus_align_bytes - 1)); } +/* U16.16 */ +#define FP_1_00000 0x00010000 /* 1.0 */ +#define FP_0_66667 0x0000AAAA /* 0.6667 = 1/1.5 */ +#define FP_0_50000 0x00008000 /* 0.5 = 1/2 */ +#define FP_0_36363 0x00005D17 /* 0.36363 = 1/2.75 */ +#define FP_0_25000 0x00004000 /* 0.25 = 1/4 */ + +static inline enum malidp_scaling_coeff_set +malidp_se_select_coeffs(u32 upscale_factor) +{ + return (upscale_factor >= FP_1_00000) ? MALIDP_UPSCALING_COEFFS : + (upscale_factor >= FP_0_66667) ? MALIDP_DOWNSCALING_1_5_COEFFS : + (upscale_factor >= FP_0_50000) ? MALIDP_DOWNSCALING_2_COEFFS : + (upscale_factor >= FP_0_36363) ? MALIDP_DOWNSCALING_2_75_COEFFS : + MALIDP_DOWNSCALING_4_COEFFS; +} + +#undef FP_0_25000 +#undef FP_0_36363 +#undef FP_0_50000 +#undef FP_0_66667 +#undef FP_1_00000 /* * background color components are defined as 12bits values, * they will be shifted right when stored on hardware that diff --git a/drivers/gpu/drm/arm/malidp_planes.c b/drivers/gpu/drm/arm/malidp_planes.c index 8106e22f9349..814fda23cead 100644 --- a/drivers/gpu/drm/arm/malidp_planes.c +++ b/drivers/gpu/drm/arm/malidp_planes.c @@ -25,6 +25,9 @@ #define MALIDP_LAYER_FORMAT 0x000 #define MALIDP_LAYER_CONTROL 0x004 #define LAYER_ENABLE (1 << 0) +#define LAYER_FLOWCFG_MASK 7 +#define LAYER_FLOWCFG(x) (((x) & LAYER_FLOWCFG_MASK) << 1) +#define LAYER_FLOWCFG_SCALE_SE 3 #define LAYER_ROT_OFFSET 8 #define LAYER_H_FLIP (1 << 10) #define LAYER_V_FLIP (1 << 11) @@ -133,16 +136,50 @@ static const struct drm_plane_funcs malidp_de_plane_funcs = { .atomic_print_state = malidp_plane_atomic_print_state, }; +static int malidp_se_check_scaling(struct malidp_plane *mp, + struct drm_plane_state *state) +{ + struct drm_crtc_state *crtc_state = + drm_atomic_get_existing_crtc_state(state->state, state->crtc); + struct malidp_crtc_state *mc; + struct drm_rect clip = { 0 }; + u32 src_w, src_h; + int ret; + + if (!crtc_state) + return -EINVAL; + + clip.x2 = crtc_state->adjusted_mode.hdisplay; + clip.y2 = crtc_state->adjusted_mode.vdisplay; + ret = drm_plane_helper_check_state(state, &clip, 0, INT_MAX, true, true); + if (ret) + return ret; + + src_w = state->src_w >> 16; + src_h = state->src_h >> 16; + if ((state->crtc_w == src_w) && (state->crtc_h == src_h)) { + /* Scaling not necessary for this plane. */ + mc->scaled_planes_mask &= ~(mp->layer->id); + return 0; + } + + if (mp->layer->id & (DE_SMART | DE_GRAPHICS2)) + return -EINVAL; + + mc = to_malidp_crtc_state(crtc_state); + + mc->scaled_planes_mask |= mp->layer->id; + /* Defer scaling requirements calculation to the crtc check. */ + return 0; +} + static int malidp_de_plane_check(struct drm_plane *plane, struct drm_plane_state *state) { struct malidp_plane *mp = to_malidp_plane(plane); struct malidp_plane_state *ms = to_malidp_plane_state(state); - struct drm_crtc_state *crtc_state; struct drm_framebuffer *fb; - struct drm_rect clip = { 0 }; int i, ret; - u32 src_w, src_h; if (!state->crtc || !state->fb) return 0; @@ -163,9 +200,6 @@ static int malidp_de_plane_check(struct drm_plane *plane, } } - src_w = state->src_w >> 16; - src_h = state->src_h >> 16; - if ((state->crtc_w > mp->hwdev->max_line_size) || (state->crtc_h > mp->hwdev->max_line_size) || (state->crtc_w < mp->hwdev->min_line_size) || @@ -182,22 +216,16 @@ static int malidp_de_plane_check(struct drm_plane *plane, (state->fb->pitches[1] != state->fb->pitches[2])) return -EINVAL; + ret = malidp_se_check_scaling(mp, state); + if (ret) + return ret; + /* packed RGB888 / BGR888 can't be rotated or flipped */ if (state->rotation != DRM_ROTATE_0 && (fb->format->format == DRM_FORMAT_RGB888 || fb->format->format == DRM_FORMAT_BGR888)) return -EINVAL; - crtc_state = drm_atomic_get_existing_crtc_state(state->state, state->crtc); - clip.x2 = crtc_state->adjusted_mode.hdisplay; - clip.y2 = crtc_state->adjusted_mode.vdisplay; - ret = drm_plane_helper_check_state(state, &clip, - DRM_PLANE_HELPER_NO_SCALING, - DRM_PLANE_HELPER_NO_SCALING, - true, true); - if (ret) - return ret; - ms->rotmem_size = 0; if (state->rotation & MALIDP_ROTATED_MASK) { int val; @@ -302,6 +330,16 @@ static void malidp_de_plane_update(struct drm_plane *plane, val &= ~LAYER_COMP_MASK; val |= LAYER_COMP_PIXEL; + val &= ~LAYER_FLOWCFG(LAYER_FLOWCFG_MASK); + if (plane->state->crtc) { + struct malidp_crtc_state *m = + to_malidp_crtc_state(plane->state->crtc->state); + + if (m->scaler_config.scale_enable && + m->scaler_config.plane_src_id == mp->layer->id) + val |= LAYER_FLOWCFG(LAYER_FLOWCFG_SCALE_SE); + } + /* set the 'enable layer' bit */ val |= LAYER_ENABLE; @@ -314,7 +352,8 @@ static void malidp_de_plane_disable(struct drm_plane *plane, { struct malidp_plane *mp = to_malidp_plane(plane); - malidp_hw_clearbits(mp->hwdev, LAYER_ENABLE, + malidp_hw_clearbits(mp->hwdev, + LAYER_ENABLE | LAYER_FLOWCFG(LAYER_FLOWCFG_MASK), mp->layer->base + MALIDP_LAYER_CONTROL); } diff --git a/drivers/gpu/drm/arm/malidp_regs.h b/drivers/gpu/drm/arm/malidp_regs.h index 4bf338d4172e..91d2ba5729bf 100644 --- a/drivers/gpu/drm/arm/malidp_regs.h +++ b/drivers/gpu/drm/arm/malidp_regs.h @@ -106,6 +106,40 @@ #define MALIDP_COEF_TABLE_ADDR 0x00030 #define MALIDP_COEF_TABLE_DATA 0x00034 +/* Scaling engine registers and masks. */ +#define MALIDP_SE_SCALING_EN (1 << 0) +#define MALIDP_SE_ALPHA_EN (1 << 1) +#define MALIDP_SE_RGBO_IF_EN (1 << 4) +#define MALIDP550_SE_CTL_SEL_MASK 7 +#define MALIDP550_SE_CTL_VCSEL(x) \ + (((x) & MALIDP550_SE_CTL_SEL_MASK) << 20) +#define MALIDP550_SE_CTL_HCSEL(x) \ + (((x) & MALIDP550_SE_CTL_SEL_MASK) << 16) + +/* Blocks with offsets from SE_CONTROL register. */ +#define MALIDP_SE_LAYER_CONTROL 0x14 +#define MALIDP_SE_L0_IN_SIZE 0x00 +#define MALIDP_SE_L0_OUT_SIZE 0x04 +#define MALIDP_SE_SET_V_SIZE(x) (((x) & 0x1fff) << 16) +#define MALIDP_SE_SET_H_SIZE(x) (((x) & 0x1fff) << 0) +#define MALIDP_SE_SCALING_CONTROL 0x24 +#define MALIDP_SE_H_INIT_PH 0x00 +#define MALIDP_SE_H_DELTA_PH 0x04 +#define MALIDP_SE_V_INIT_PH 0x08 +#define MALIDP_SE_V_DELTA_PH 0x0c +#define MALIDP_SE_COEFFTAB_ADDR 0x10 +#define MALIDP_SE_COEFFTAB_ADDR_MASK 0x7f +#define MALIDP_SE_V_COEFFTAB (1 << 8) +#define MALIDP_SE_H_COEFFTAB (1 << 9) +#define MALIDP_SE_SET_V_COEFFTAB_ADDR(x) \ + (MALIDP_SE_V_COEFFTAB | ((x) & MALIDP_SE_COEFFTAB_ADDR_MASK)) +#define MALIDP_SE_SET_H_COEFFTAB_ADDR(x) \ + (MALIDP_SE_H_COEFFTAB | ((x) & MALIDP_SE_COEFFTAB_ADDR_MASK)) +#define MALIDP_SE_COEFFTAB_DATA 0x14 +#define MALIDP_SE_COEFFTAB_DATA_MASK 0x3fff +#define MALIDP_SE_SET_COEFFTAB_DATA(x) \ + ((x) & MALIDP_SE_COEFFTAB_DATA_MASK) + /* register offsets and bits specific to DP500 */ #define MALIDP500_ADDR_SPACE_SIZE 0x01000 #define MALIDP500_DC_BASE 0x00000 @@ -146,6 +180,7 @@ #define MALIDP500_DE_LG2_BASE 0x00300 #define MALIDP500_DE_LG2_PTR_BASE 0x0031c #define MALIDP500_SE_BASE 0x00c00 +#define MALIDP500_SE_CONTROL 0x00c0c #define MALIDP500_SE_PTR_BASE 0x00e0c #define MALIDP500_DC_IRQ_BASE 0x00f00 #define MALIDP500_CONFIG_VALID 0x00f00 @@ -175,6 +210,7 @@ #define MALIDP550_DE_LS_PTR_BASE 0x0042c #define MALIDP550_DE_PERF_BASE 0x00500 #define MALIDP550_SE_BASE 0x08000 +#define MALIDP550_SE_CONTROL 0x08010 #define MALIDP550_DC_BASE 0x0c000 #define MALIDP550_DC_CONTROL 0x0c010 #define MALIDP550_DC_CONFIG_REQ (1 << 16)