Commit 05faf155 authored by Laurentiu Palcu's avatar Laurentiu Palcu Committed by Lucas Stach

drm/imx/dcss: allow using nearest neighbor interpolation scaling

This patch adds support for using NN interpolation scaling by setting the
SCALING_FILTER plane property to 1. Otherwise, the default method is used.
Signed-off-by: default avatarLaurentiu Palcu <laurentiu.palcu@oss.nxp.com>
Reviewed-by: default avatarLucas Stach <l.stach@pengutronix.de>
Signed-off-by: default avatarLucas Stach <l.stach@pengutronix.de>
Link: https://patchwork.freedesktop.org/patch/msgid/20201105145018.27255-1-laurentiu.palcu@oss.nxp.com
parent 594486b5
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
#define __DCSS_PRV_H__ #define __DCSS_PRV_H__
#include <drm/drm_fourcc.h> #include <drm/drm_fourcc.h>
#include <drm/drm_plane.h>
#include <linux/io.h> #include <linux/io.h>
#include <video/videomode.h> #include <video/videomode.h>
...@@ -165,6 +166,8 @@ void dcss_ss_sync_set(struct dcss_ss *ss, struct videomode *vm, ...@@ -165,6 +166,8 @@ void dcss_ss_sync_set(struct dcss_ss *ss, struct videomode *vm,
/* SCALER */ /* SCALER */
int dcss_scaler_init(struct dcss_dev *dcss, unsigned long scaler_base); int dcss_scaler_init(struct dcss_dev *dcss, unsigned long scaler_base);
void dcss_scaler_exit(struct dcss_scaler *scl); void dcss_scaler_exit(struct dcss_scaler *scl);
void dcss_scaler_set_filter(struct dcss_scaler *scl, int ch_num,
enum drm_scaling_filter scaling_filter);
void dcss_scaler_setup(struct dcss_scaler *scl, int ch_num, void dcss_scaler_setup(struct dcss_scaler *scl, int ch_num,
const struct drm_format_info *format, const struct drm_format_info *format,
int src_xres, int src_yres, int dst_xres, int dst_yres, int src_xres, int src_yres, int dst_xres, int dst_yres,
......
...@@ -257,7 +257,8 @@ static bool dcss_plane_needs_setup(struct drm_plane_state *state, ...@@ -257,7 +257,8 @@ static bool dcss_plane_needs_setup(struct drm_plane_state *state,
state->src_h != old_state->src_h || state->src_h != old_state->src_h ||
fb->format->format != old_fb->format->format || fb->format->format != old_fb->format->format ||
fb->modifier != old_fb->modifier || fb->modifier != old_fb->modifier ||
state->rotation != old_state->rotation; state->rotation != old_state->rotation ||
state->scaling_filter != old_state->scaling_filter;
} }
static void dcss_plane_atomic_update(struct drm_plane *plane, static void dcss_plane_atomic_update(struct drm_plane *plane,
...@@ -313,6 +314,9 @@ static void dcss_plane_atomic_update(struct drm_plane *plane, ...@@ -313,6 +314,9 @@ static void dcss_plane_atomic_update(struct drm_plane *plane,
is_rotation_90_or_270 = state->rotation & (DRM_MODE_ROTATE_90 | is_rotation_90_or_270 = state->rotation & (DRM_MODE_ROTATE_90 |
DRM_MODE_ROTATE_270); DRM_MODE_ROTATE_270);
dcss_scaler_set_filter(dcss->scaler, dcss_plane->ch_num,
state->scaling_filter);
dcss_scaler_setup(dcss->scaler, dcss_plane->ch_num, dcss_scaler_setup(dcss->scaler, dcss_plane->ch_num,
state->fb->format, state->fb->format,
is_rotation_90_or_270 ? src_h : src_w, is_rotation_90_or_270 ? src_h : src_w,
...@@ -394,6 +398,10 @@ struct dcss_plane *dcss_plane_init(struct drm_device *drm, ...@@ -394,6 +398,10 @@ struct dcss_plane *dcss_plane_init(struct drm_device *drm,
if (ret) if (ret)
return ERR_PTR(ret); return ERR_PTR(ret);
drm_plane_create_scaling_filter_property(&dcss_plane->base,
BIT(DRM_SCALING_FILTER_DEFAULT) |
BIT(DRM_SCALING_FILTER_NEAREST_NEIGHBOR));
drm_plane_create_rotation_property(&dcss_plane->base, drm_plane_create_rotation_property(&dcss_plane->base,
DRM_MODE_ROTATE_0, DRM_MODE_ROTATE_0,
DRM_MODE_ROTATE_0 | DRM_MODE_ROTATE_0 |
......
...@@ -77,6 +77,8 @@ struct dcss_scaler_ch { ...@@ -77,6 +77,8 @@ struct dcss_scaler_ch {
u32 c_vstart; u32 c_vstart;
u32 c_hstart; u32 c_hstart;
bool use_nn_interpolation;
}; };
struct dcss_scaler { struct dcss_scaler {
...@@ -243,6 +245,17 @@ static void dcss_scaler_gaussian_filter(int fc_q, bool use_5_taps, ...@@ -243,6 +245,17 @@ static void dcss_scaler_gaussian_filter(int fc_q, bool use_5_taps,
} }
} }
static void dcss_scaler_nearest_neighbor_filter(bool use_5_taps,
int coef[][PSC_NUM_TAPS])
{
int i, j;
for (i = 0; i < PSC_STORED_PHASES; i++)
for (j = 0; j < PSC_NUM_TAPS; j++)
coef[i][j] = j == PSC_NUM_TAPS >> 1 ?
(1 << PSC_COEFF_PRECISION) : 0;
}
/** /**
* dcss_scaler_filter_design() - Compute filter coefficients using * dcss_scaler_filter_design() - Compute filter coefficients using
* Gaussian filter. * Gaussian filter.
...@@ -253,7 +266,8 @@ static void dcss_scaler_gaussian_filter(int fc_q, bool use_5_taps, ...@@ -253,7 +266,8 @@ static void dcss_scaler_gaussian_filter(int fc_q, bool use_5_taps,
*/ */
static void dcss_scaler_filter_design(int src_length, int dst_length, static void dcss_scaler_filter_design(int src_length, int dst_length,
bool use_5_taps, bool phase0_identity, bool use_5_taps, bool phase0_identity,
int coef[][PSC_NUM_TAPS]) int coef[][PSC_NUM_TAPS],
bool nn_interpolation)
{ {
int fc_q; int fc_q;
...@@ -263,8 +277,11 @@ static void dcss_scaler_filter_design(int src_length, int dst_length, ...@@ -263,8 +277,11 @@ static void dcss_scaler_filter_design(int src_length, int dst_length,
else else
fc_q = div_q(dst_length, src_length * PSC_NUM_PHASES); fc_q = div_q(dst_length, src_length * PSC_NUM_PHASES);
/* compute gaussian filter coefficients */ if (nn_interpolation)
dcss_scaler_gaussian_filter(fc_q, use_5_taps, phase0_identity, coef); dcss_scaler_nearest_neighbor_filter(use_5_taps, coef);
else
/* compute gaussian filter coefficients */
dcss_scaler_gaussian_filter(fc_q, use_5_taps, phase0_identity, coef);
} }
static void dcss_scaler_write(struct dcss_scaler_ch *ch, u32 val, u32 ofs) static void dcss_scaler_write(struct dcss_scaler_ch *ch, u32 val, u32 ofs)
...@@ -653,12 +670,14 @@ static void dcss_scaler_yuv_coef_set(struct dcss_scaler_ch *ch, ...@@ -653,12 +670,14 @@ static void dcss_scaler_yuv_coef_set(struct dcss_scaler_ch *ch,
/* horizontal luma */ /* horizontal luma */
dcss_scaler_filter_design(src_xres, dst_xres, false, dcss_scaler_filter_design(src_xres, dst_xres, false,
src_xres == dst_xres, coef); src_xres == dst_xres, coef,
ch->use_nn_interpolation);
dcss_scaler_program_7_coef_set(ch, DCSS_SCALER_COEF_HLUM, coef); dcss_scaler_program_7_coef_set(ch, DCSS_SCALER_COEF_HLUM, coef);
/* vertical luma */ /* vertical luma */
dcss_scaler_filter_design(src_yres, dst_yres, program_5_taps, dcss_scaler_filter_design(src_yres, dst_yres, program_5_taps,
src_yres == dst_yres, coef); src_yres == dst_yres, coef,
ch->use_nn_interpolation);
if (program_5_taps) if (program_5_taps)
dcss_scaler_program_5_coef_set(ch, DCSS_SCALER_COEF_VLUM, coef); dcss_scaler_program_5_coef_set(ch, DCSS_SCALER_COEF_VLUM, coef);
...@@ -678,14 +697,14 @@ static void dcss_scaler_yuv_coef_set(struct dcss_scaler_ch *ch, ...@@ -678,14 +697,14 @@ static void dcss_scaler_yuv_coef_set(struct dcss_scaler_ch *ch,
/* horizontal chroma */ /* horizontal chroma */
dcss_scaler_filter_design(src_xres, dst_xres, false, dcss_scaler_filter_design(src_xres, dst_xres, false,
(src_xres == dst_xres) && (ch->c_hstart == 0), (src_xres == dst_xres) && (ch->c_hstart == 0),
coef); coef, ch->use_nn_interpolation);
dcss_scaler_program_7_coef_set(ch, DCSS_SCALER_COEF_HCHR, coef); dcss_scaler_program_7_coef_set(ch, DCSS_SCALER_COEF_HCHR, coef);
/* vertical chroma */ /* vertical chroma */
dcss_scaler_filter_design(src_yres, dst_yres, program_5_taps, dcss_scaler_filter_design(src_yres, dst_yres, program_5_taps,
(src_yres == dst_yres) && (ch->c_vstart == 0), (src_yres == dst_yres) && (ch->c_vstart == 0),
coef); coef, ch->use_nn_interpolation);
if (program_5_taps) if (program_5_taps)
dcss_scaler_program_5_coef_set(ch, DCSS_SCALER_COEF_VCHR, coef); dcss_scaler_program_5_coef_set(ch, DCSS_SCALER_COEF_VCHR, coef);
else else
...@@ -700,12 +719,14 @@ static void dcss_scaler_rgb_coef_set(struct dcss_scaler_ch *ch, ...@@ -700,12 +719,14 @@ static void dcss_scaler_rgb_coef_set(struct dcss_scaler_ch *ch,
/* horizontal RGB */ /* horizontal RGB */
dcss_scaler_filter_design(src_xres, dst_xres, false, dcss_scaler_filter_design(src_xres, dst_xres, false,
src_xres == dst_xres, coef); src_xres == dst_xres, coef,
ch->use_nn_interpolation);
dcss_scaler_program_7_coef_set(ch, DCSS_SCALER_COEF_HLUM, coef); dcss_scaler_program_7_coef_set(ch, DCSS_SCALER_COEF_HLUM, coef);
/* vertical RGB */ /* vertical RGB */
dcss_scaler_filter_design(src_yres, dst_yres, false, dcss_scaler_filter_design(src_yres, dst_yres, false,
src_yres == dst_yres, coef); src_yres == dst_yres, coef,
ch->use_nn_interpolation);
dcss_scaler_program_7_coef_set(ch, DCSS_SCALER_COEF_VLUM, coef); dcss_scaler_program_7_coef_set(ch, DCSS_SCALER_COEF_VLUM, coef);
} }
...@@ -751,6 +772,14 @@ static void dcss_scaler_set_rgb10_order(struct dcss_scaler_ch *ch, ...@@ -751,6 +772,14 @@ static void dcss_scaler_set_rgb10_order(struct dcss_scaler_ch *ch,
ch->sdata_ctrl |= a2r10g10b10_format << A2R10G10B10_FORMAT_POS; ch->sdata_ctrl |= a2r10g10b10_format << A2R10G10B10_FORMAT_POS;
} }
void dcss_scaler_set_filter(struct dcss_scaler *scl, int ch_num,
enum drm_scaling_filter scaling_filter)
{
struct dcss_scaler_ch *ch = &scl->ch[ch_num];
ch->use_nn_interpolation = scaling_filter == DRM_SCALING_FILTER_NEAREST_NEIGHBOR;
}
void dcss_scaler_setup(struct dcss_scaler *scl, int ch_num, void dcss_scaler_setup(struct dcss_scaler *scl, int ch_num,
const struct drm_format_info *format, const struct drm_format_info *format,
int src_xres, int src_yres, int dst_xres, int dst_yres, int src_xres, int src_yres, int dst_xres, int dst_yres,
......
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