diff --git a/drivers/gpu/drm/vc4/vc4_drv.h b/drivers/gpu/drm/vc4/vc4_drv.h index 0ea174bfbeb5..04dd41925fe2 100644 --- a/drivers/gpu/drm/vc4/vc4_drv.h +++ b/drivers/gpu/drm/vc4/vc4_drv.h @@ -348,6 +348,7 @@ struct vc4_hvs { struct work_struct free_dlist_work; struct drm_mm_node mitchell_netravali_filter; + struct drm_mm_node nearest_neighbour_filter; struct debugfs_regset32 regset; diff --git a/drivers/gpu/drm/vc4/vc4_hvs.c b/drivers/gpu/drm/vc4/vc4_hvs.c index ea0db6e2f0f5..4c2af22345a1 100644 --- a/drivers/gpu/drm/vc4/vc4_hvs.c +++ b/drivers/gpu/drm/vc4/vc4_hvs.c @@ -412,6 +412,9 @@ static int vc4_hvs_debugfs_dlist_allocs(struct seq_file *m, void *data) static const u32 mitchell_netravali_1_3_1_3_kernel[] = VC4_LINEAR_PHASE_KERNEL(0, -2, -6, -8, -10, -8, -3, 2, 18, 50, 82, 119, 155, 187, 213, 227); +static const u32 nearest_neighbour_kernel[] = + VC4_LINEAR_PHASE_KERNEL(0, 0, 0, 0, 0, 0, 0, 0, + 1, 1, 1, 1, 255, 255, 255, 255); static int vc4_hvs_upload_linear_kernel(struct vc4_hvs *hvs, struct drm_mm_node *space, @@ -2067,14 +2070,19 @@ static int vc4_hvs_bind(struct device *dev, struct device *master, void *data) if (ret) return ret; - /* Upload filter kernels. We only have the one for now, so we - * keep it around for the lifetime of the driver. + /* Upload filter kernels. We only have the two for now, so we + * keep them around for the lifetime of the driver. */ ret = vc4_hvs_upload_linear_kernel(hvs, &hvs->mitchell_netravali_filter, mitchell_netravali_1_3_1_3_kernel); if (ret) return ret; + ret = vc4_hvs_upload_linear_kernel(hvs, + &hvs->nearest_neighbour_filter, + nearest_neighbour_kernel); + if (ret) + return ret; ret = vc4_hvs_cob_init(hvs); if (ret) @@ -2127,6 +2135,8 @@ static void vc4_hvs_unbind(struct device *dev, struct device *master, if (drm_mm_node_allocated(&vc4->hvs->mitchell_netravali_filter)) drm_mm_remove_node(&vc4->hvs->mitchell_netravali_filter); + if (drm_mm_node_allocated(&vc4->hvs->nearest_neighbour_filter)) + drm_mm_remove_node(&vc4->hvs->nearest_neighbour_filter); drm_mm_for_each_node_safe(node, next, &vc4->hvs->dlist_mm) drm_mm_remove_node(node); diff --git a/drivers/gpu/drm/vc4/vc4_plane.c b/drivers/gpu/drm/vc4/vc4_plane.c index 0081318310ea..a0808e93f2bf 100644 --- a/drivers/gpu/drm/vc4/vc4_plane.c +++ b/drivers/gpu/drm/vc4/vc4_plane.c @@ -597,7 +597,8 @@ static void vc4_write_tpz(struct vc4_plane_state *vc4_state, u32 src, u32 dst) #define PHASE_BITS 6 static void vc4_write_ppf(struct vc4_plane_state *vc4_state, u32 src, u32 dst, - u32 xy, int channel, int chroma_offset) + u32 xy, int channel, int chroma_offset, + bool no_interpolate) { struct vc4_dev *vc4 = to_vc4_dev(vc4_state->base.plane->dev); u32 scale = src / dst; @@ -649,6 +650,7 @@ static void vc4_write_ppf(struct vc4_plane_state *vc4_state, u32 src, u32 dst, phase &= SCALER_PPF_IPHASE_MASK; vc4_dlist_write(vc4_state, + (no_interpolate ? SCALER_PPF_NOINTERP : 0) | SCALER_PPF_AGC | VC4_SET_FIELD(scale, SCALER_PPF_SCALE) | /* @@ -844,14 +846,16 @@ static void vc4_write_scaling_parameters(struct drm_plane_state *state, if (vc4_state->x_scaling[channel] == VC4_SCALING_PPF) { vc4_write_ppf(vc4_state, vc4_state->src_w[channel], vc4_state->crtc_w, vc4_state->src_x, channel, - state->chroma_siting_h); + state->chroma_siting_h, + state->scaling_filter == DRM_SCALING_FILTER_NEAREST_NEIGHBOR); } /* Ch0 V-PPF Words 0-1: Scaling Parameters, Context */ if (vc4_state->y_scaling[channel] == VC4_SCALING_PPF) { vc4_write_ppf(vc4_state, vc4_state->src_h[channel], vc4_state->crtc_h, vc4_state->src_y, channel, - state->chroma_siting_v); + state->chroma_siting_v, + state->scaling_filter == DRM_SCALING_FILTER_NEAREST_NEIGHBOR); vc4_dlist_write(vc4_state, 0xc0c0c0c0); } @@ -1660,7 +1664,18 @@ static int vc4_plane_mode_set(struct drm_plane *plane, vc4_state->y_scaling[0] == VC4_SCALING_PPF || vc4_state->x_scaling[1] == VC4_SCALING_PPF || vc4_state->y_scaling[1] == VC4_SCALING_PPF) { - u32 kernel = VC4_SET_FIELD(vc4->hvs->mitchell_netravali_filter.start, + struct drm_mm_node *filter; + + switch (state->scaling_filter) { + case DRM_SCALING_FILTER_DEFAULT: + default: + filter = &vc4->hvs->mitchell_netravali_filter; + break; + case DRM_SCALING_FILTER_NEAREST_NEIGHBOR: + filter = &vc4->hvs->nearest_neighbour_filter; + break; + } + u32 kernel = VC4_SET_FIELD(filter->start, SCALER_PPF_KERNEL_OFFSET); /* HPPF plane 0 */ @@ -2072,9 +2087,19 @@ static int vc6_plane_mode_set(struct drm_plane *plane, vc4_state->y_scaling[0] == VC4_SCALING_PPF || vc4_state->x_scaling[1] == VC4_SCALING_PPF || vc4_state->y_scaling[1] == VC4_SCALING_PPF) { - u32 kernel = - VC4_SET_FIELD(vc4->hvs->mitchell_netravali_filter.start, - SCALER_PPF_KERNEL_OFFSET); + struct drm_mm_node *filter; + + switch (state->scaling_filter) { + case DRM_SCALING_FILTER_DEFAULT: + default: + filter = &vc4->hvs->mitchell_netravali_filter; + break; + case DRM_SCALING_FILTER_NEAREST_NEIGHBOR: + filter = &vc4->hvs->nearest_neighbour_filter; + break; + } + u32 kernel = VC4_SET_FIELD(filter->start, + SCALER_PPF_KERNEL_OFFSET); /* HPPF plane 0 */ vc4_dlist_write(vc4_state, kernel); @@ -2567,6 +2592,10 @@ struct drm_plane *vc4_plane_init(struct drm_device *dev, DRM_COLOR_YCBCR_BT709, DRM_COLOR_YCBCR_LIMITED_RANGE); + drm_plane_create_scaling_filter_property(plane, + BIT(DRM_SCALING_FILTER_DEFAULT) | + BIT(DRM_SCALING_FILTER_NEAREST_NEIGHBOR)); + drm_plane_create_chroma_siting_properties(plane, 0, 0); if (type == DRM_PLANE_TYPE_PRIMARY)