Skip to content

Commit

Permalink
drm/vc4: Add support for per plane scaling filter selection
Browse files Browse the repository at this point in the history
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 <[email protected]>
  • Loading branch information
6by9 authored and pelwell committed Sep 11, 2024
1 parent e4c2a77 commit d6a3a3f
Show file tree
Hide file tree
Showing 3 changed files with 52 additions and 11 deletions.
1 change: 1 addition & 0 deletions drivers/gpu/drm/vc4/vc4_drv.h
Original file line number Diff line number Diff line change
Expand Up @@ -358,6 +358,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;

Expand Down
14 changes: 12 additions & 2 deletions drivers/gpu/drm/vc4/vc4_hvs.c
Original file line number Diff line number Diff line change
Expand Up @@ -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[] =
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,
Expand Down Expand Up @@ -2300,14 +2303,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)
Expand All @@ -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))
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);
Expand Down
48 changes: 39 additions & 9 deletions drivers/gpu/drm/vc4/vc4_plane.c
Original file line number Diff line number Diff line change
Expand Up @@ -573,7 +573,9 @@ static void vc4_write_tpz(struct vc4_plane_state *vc4_state, u32 src, u32 dst)
/* phase magnitude bits */
#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);
u32 scale = src / dst;
Expand Down Expand Up @@ -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;

vc4_dlist_write(vc4_state,
no_interpolate ? SCALER_PPF_NOINTERP : 0 |
SCALER_PPF_AGC |
VC4_SET_FIELD(scale, SCALER_PPF_SCALE) |
/*
Expand Down Expand Up @@ -806,15 +809,17 @@ static void vc4_write_scaling_parameters(struct drm_plane_state *state,
/* Ch0 H-PPF Word 0: Scaling Parameters */
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);
vc4_state->src_w[channel], vc4_state->crtc_w, vc4_state->src_x,
channel, 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);
vc4_state->src_h[channel], vc4_state->crtc_h, vc4_state->src_y,
channel, state->chroma_siting_v,
state->scaling_filter == DRM_SCALING_FILTER_NEAREST_NEIGHBOR);
vc4_dlist_write(vc4_state, 0xc0c0c0c0);
}

Expand Down Expand Up @@ -1547,7 +1552,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 */
Expand Down Expand Up @@ -1958,9 +1974,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);
Expand Down Expand Up @@ -2442,6 +2468,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)
Expand Down

0 comments on commit d6a3a3f

Please sign in to comment.