drm/vc4: Add support for per plane scaling filter selection

Seeing as the HVS can be configured with regard the scaling filter,
and DRM now supports selecting scaling filters at a per CRTC or
per plane level, we can implement it.

Default remains as the Mitchell/Netravali filter, but nearest
neighbour is now also implemented.

Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
This commit is contained in:
Dave Stevenson
2024-07-25 15:42:41 +01:00
committed by Phil Elwell
parent e4c2a7731e
commit d6a3a3f106
3 changed files with 52 additions and 11 deletions

View File

@@ -358,6 +358,7 @@ struct vc4_hvs {
struct work_struct free_dlist_work; struct work_struct free_dlist_work;
struct drm_mm_node mitchell_netravali_filter; struct drm_mm_node mitchell_netravali_filter;
struct drm_mm_node nearest_neighbour_filter;
struct debugfs_regset32 regset; struct debugfs_regset32 regset;

View File

@@ -469,6 +469,9 @@ static int vc4_hvs_debugfs_dlist_allocs(struct seq_file *m, void *data)
static const u32 mitchell_netravali_1_3_1_3_kernel[] = static const u32 mitchell_netravali_1_3_1_3_kernel[] =
VC4_LINEAR_PHASE_KERNEL(0, -2, -6, -8, -10, -8, -3, 2, 18, VC4_LINEAR_PHASE_KERNEL(0, -2, -6, -8, -10, -8, -3, 2, 18,
50, 82, 119, 155, 187, 213, 227); 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, static int vc4_hvs_upload_linear_kernel(struct vc4_hvs *hvs,
struct drm_mm_node *space, struct drm_mm_node *space,
@@ -2300,14 +2303,19 @@ static int vc4_hvs_bind(struct device *dev, struct device *master, void *data)
if (ret) if (ret)
return ret; return ret;
/* Upload filter kernels. We only have the one for now, so we /* Upload filter kernels. We only have the two for now, so we
* keep it around for the lifetime of the driver. * keep them around for the lifetime of the driver.
*/ */
ret = vc4_hvs_upload_linear_kernel(hvs, ret = vc4_hvs_upload_linear_kernel(hvs,
&hvs->mitchell_netravali_filter, &hvs->mitchell_netravali_filter,
mitchell_netravali_1_3_1_3_kernel); mitchell_netravali_1_3_1_3_kernel);
if (ret) if (ret)
return 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); ret = vc4_hvs_cob_init(hvs);
if (ret) if (ret)
@@ -2333,6 +2341,8 @@ static void vc4_hvs_unbind(struct device *dev, struct device *master,
if (drm_mm_node_allocated(&vc4->hvs->mitchell_netravali_filter)) if (drm_mm_node_allocated(&vc4->hvs->mitchell_netravali_filter))
drm_mm_remove_node(&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_for_each_node_safe(node, next, &vc4->hvs->dlist_mm)
drm_mm_remove_node(node); drm_mm_remove_node(node);

View File

@@ -573,7 +573,9 @@ static void vc4_write_tpz(struct vc4_plane_state *vc4_state, u32 src, u32 dst)
/* phase magnitude bits */ /* phase magnitude bits */
#define PHASE_BITS 6 #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) static void vc4_write_ppf(struct vc4_plane_state *vc4_state, u32 src, u32 dst,
u32 xy, int channel, int chroma_offset,
bool no_interpolate)
{ {
struct vc4_dev *vc4 = to_vc4_dev(vc4_state->base.plane->dev); struct vc4_dev *vc4 = to_vc4_dev(vc4_state->base.plane->dev);
u32 scale = src / dst; u32 scale = src / dst;
@@ -612,6 +614,7 @@ static void vc4_write_ppf(struct vc4_plane_state *vc4_state, u32 src, u32 dst, u
phase &= SCALER_PPF_IPHASE_MASK; phase &= SCALER_PPF_IPHASE_MASK;
vc4_dlist_write(vc4_state, vc4_dlist_write(vc4_state,
no_interpolate ? SCALER_PPF_NOINTERP : 0 |
SCALER_PPF_AGC | SCALER_PPF_AGC |
VC4_SET_FIELD(scale, SCALER_PPF_SCALE) | VC4_SET_FIELD(scale, SCALER_PPF_SCALE) |
/* /*
@@ -806,15 +809,17 @@ static void vc4_write_scaling_parameters(struct drm_plane_state *state,
/* Ch0 H-PPF Word 0: Scaling Parameters */ /* Ch0 H-PPF Word 0: Scaling Parameters */
if (vc4_state->x_scaling[channel] == VC4_SCALING_PPF) { if (vc4_state->x_scaling[channel] == VC4_SCALING_PPF) {
vc4_write_ppf(vc4_state, vc4_write_ppf(vc4_state,
vc4_state->src_w[channel], vc4_state->crtc_w, vc4_state->src_x, channel, vc4_state->src_w[channel], vc4_state->crtc_w, vc4_state->src_x,
state->chroma_siting_h); channel, state->chroma_siting_h,
state->scaling_filter == DRM_SCALING_FILTER_NEAREST_NEIGHBOR);
} }
/* Ch0 V-PPF Words 0-1: Scaling Parameters, Context */ /* Ch0 V-PPF Words 0-1: Scaling Parameters, Context */
if (vc4_state->y_scaling[channel] == VC4_SCALING_PPF) { if (vc4_state->y_scaling[channel] == VC4_SCALING_PPF) {
vc4_write_ppf(vc4_state, vc4_write_ppf(vc4_state,
vc4_state->src_h[channel], vc4_state->crtc_h, vc4_state->src_y, channel, vc4_state->src_h[channel], vc4_state->crtc_h, vc4_state->src_y,
state->chroma_siting_v); channel, state->chroma_siting_v,
state->scaling_filter == DRM_SCALING_FILTER_NEAREST_NEIGHBOR);
vc4_dlist_write(vc4_state, 0xc0c0c0c0); vc4_dlist_write(vc4_state, 0xc0c0c0c0);
} }
@@ -1547,7 +1552,18 @@ static int vc4_plane_mode_set(struct drm_plane *plane,
vc4_state->y_scaling[0] == VC4_SCALING_PPF || vc4_state->y_scaling[0] == VC4_SCALING_PPF ||
vc4_state->x_scaling[1] == VC4_SCALING_PPF || vc4_state->x_scaling[1] == VC4_SCALING_PPF ||
vc4_state->y_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); SCALER_PPF_KERNEL_OFFSET);
/* HPPF plane 0 */ /* HPPF plane 0 */
@@ -1958,8 +1974,18 @@ static int vc6_plane_mode_set(struct drm_plane *plane,
vc4_state->y_scaling[0] == VC4_SCALING_PPF || vc4_state->y_scaling[0] == VC4_SCALING_PPF ||
vc4_state->x_scaling[1] == VC4_SCALING_PPF || vc4_state->x_scaling[1] == VC4_SCALING_PPF ||
vc4_state->y_scaling[1] == VC4_SCALING_PPF) { vc4_state->y_scaling[1] == VC4_SCALING_PPF) {
u32 kernel = struct drm_mm_node *filter;
VC4_SET_FIELD(vc4->hvs->mitchell_netravali_filter.start,
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); SCALER_PPF_KERNEL_OFFSET);
/* HPPF plane 0 */ /* HPPF plane 0 */
@@ -2442,6 +2468,10 @@ struct drm_plane *vc4_plane_init(struct drm_device *dev,
DRM_COLOR_YCBCR_BT709, DRM_COLOR_YCBCR_BT709,
DRM_COLOR_YCBCR_LIMITED_RANGE); 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); drm_plane_create_chroma_siting_properties(plane, 0, 0);
if (type == DRM_PLANE_TYPE_PRIMARY) if (type == DRM_PLANE_TYPE_PRIMARY)