1 From d6a3a3f106010d9576a700148220842cac4c5739 Mon Sep 17 00:00:00 2001
2 From: Dave Stevenson <dave.stevenson@raspberrypi.com>
3 Date: Thu, 25 Jul 2024 15:42:41 +0100
4 Subject: [PATCH 1257/1350] drm/vc4: Add support for per plane scaling filter
7 Seeing as the HVS can be configured with regard the scaling filter,
8 and DRM now supports selecting scaling filters at a per CRTC or
9 per plane level, we can implement it.
11 Default remains as the Mitchell/Netravali filter, but nearest
12 neighbour is now also implemented.
14 Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
16 drivers/gpu/drm/vc4/vc4_drv.h | 1 +
17 drivers/gpu/drm/vc4/vc4_hvs.c | 14 ++++++++--
18 drivers/gpu/drm/vc4/vc4_plane.c | 48 ++++++++++++++++++++++++++-------
19 3 files changed, 52 insertions(+), 11 deletions(-)
21 --- a/drivers/gpu/drm/vc4/vc4_drv.h
22 +++ b/drivers/gpu/drm/vc4/vc4_drv.h
23 @@ -358,6 +358,7 @@ struct vc4_hvs {
24 struct work_struct free_dlist_work;
26 struct drm_mm_node mitchell_netravali_filter;
27 + struct drm_mm_node nearest_neighbour_filter;
29 struct debugfs_regset32 regset;
31 --- a/drivers/gpu/drm/vc4/vc4_hvs.c
32 +++ b/drivers/gpu/drm/vc4/vc4_hvs.c
33 @@ -469,6 +469,9 @@ static int vc4_hvs_debugfs_dlist_allocs(
34 static const u32 mitchell_netravali_1_3_1_3_kernel[] =
35 VC4_LINEAR_PHASE_KERNEL(0, -2, -6, -8, -10, -8, -3, 2, 18,
36 50, 82, 119, 155, 187, 213, 227);
37 +static const u32 nearest_neighbour_kernel[] =
38 + VC4_LINEAR_PHASE_KERNEL(0, 0, 0, 0, 0, 0, 0, 0,
39 + 1, 1, 1, 1, 255, 255, 255, 255);
41 static int vc4_hvs_upload_linear_kernel(struct vc4_hvs *hvs,
42 struct drm_mm_node *space,
43 @@ -2259,14 +2262,19 @@ static int vc4_hvs_bind(struct device *d
47 - /* Upload filter kernels. We only have the one for now, so we
48 - * keep it around for the lifetime of the driver.
49 + /* Upload filter kernels. We only have the two for now, so we
50 + * keep them around for the lifetime of the driver.
52 ret = vc4_hvs_upload_linear_kernel(hvs,
53 &hvs->mitchell_netravali_filter,
54 mitchell_netravali_1_3_1_3_kernel);
57 + ret = vc4_hvs_upload_linear_kernel(hvs,
58 + &hvs->nearest_neighbour_filter,
59 + nearest_neighbour_kernel);
63 ret = vc4_hvs_cob_init(hvs);
65 @@ -2292,6 +2300,8 @@ static void vc4_hvs_unbind(struct device
67 if (drm_mm_node_allocated(&vc4->hvs->mitchell_netravali_filter))
68 drm_mm_remove_node(&vc4->hvs->mitchell_netravali_filter);
69 + if (drm_mm_node_allocated(&vc4->hvs->nearest_neighbour_filter))
70 + drm_mm_remove_node(&vc4->hvs->nearest_neighbour_filter);
72 drm_mm_for_each_node_safe(node, next, &vc4->hvs->dlist_mm)
73 drm_mm_remove_node(node);
74 --- a/drivers/gpu/drm/vc4/vc4_plane.c
75 +++ b/drivers/gpu/drm/vc4/vc4_plane.c
76 @@ -582,7 +582,9 @@ static void vc4_write_tpz(struct vc4_pla
77 /* phase magnitude bits */
80 -static void vc4_write_ppf(struct vc4_plane_state *vc4_state, u32 src, u32 dst, u32 xy, int channel, int chroma_offset)
81 +static void vc4_write_ppf(struct vc4_plane_state *vc4_state, u32 src, u32 dst,
82 + u32 xy, int channel, int chroma_offset,
83 + bool no_interpolate)
85 struct vc4_dev *vc4 = to_vc4_dev(vc4_state->base.plane->dev);
86 u32 scale = src / dst;
87 @@ -621,6 +623,7 @@ static void vc4_write_ppf(struct vc4_pla
88 phase &= SCALER_PPF_IPHASE_MASK;
90 vc4_dlist_write(vc4_state,
91 + no_interpolate ? SCALER_PPF_NOINTERP : 0 |
93 VC4_SET_FIELD(scale, SCALER_PPF_SCALE) |
95 @@ -815,15 +818,17 @@ static void vc4_write_scaling_parameters
96 /* Ch0 H-PPF Word 0: Scaling Parameters */
97 if (vc4_state->x_scaling[channel] == VC4_SCALING_PPF) {
98 vc4_write_ppf(vc4_state,
99 - vc4_state->src_w[channel], vc4_state->crtc_w, vc4_state->src_x, channel,
100 - state->chroma_siting_h);
101 + vc4_state->src_w[channel], vc4_state->crtc_w, vc4_state->src_x,
102 + channel, state->chroma_siting_h,
103 + state->scaling_filter == DRM_SCALING_FILTER_NEAREST_NEIGHBOR);
106 /* Ch0 V-PPF Words 0-1: Scaling Parameters, Context */
107 if (vc4_state->y_scaling[channel] == VC4_SCALING_PPF) {
108 vc4_write_ppf(vc4_state,
109 - vc4_state->src_h[channel], vc4_state->crtc_h, vc4_state->src_y, channel,
110 - state->chroma_siting_v);
111 + vc4_state->src_h[channel], vc4_state->crtc_h, vc4_state->src_y,
112 + channel, state->chroma_siting_v,
113 + state->scaling_filter == DRM_SCALING_FILTER_NEAREST_NEIGHBOR);
114 vc4_dlist_write(vc4_state, 0xc0c0c0c0);
117 @@ -1573,7 +1578,18 @@ static int vc4_plane_mode_set(struct drm
118 vc4_state->y_scaling[0] == VC4_SCALING_PPF ||
119 vc4_state->x_scaling[1] == VC4_SCALING_PPF ||
120 vc4_state->y_scaling[1] == VC4_SCALING_PPF) {
121 - u32 kernel = VC4_SET_FIELD(vc4->hvs->mitchell_netravali_filter.start,
122 + struct drm_mm_node *filter;
124 + switch (state->scaling_filter) {
125 + case DRM_SCALING_FILTER_DEFAULT:
127 + filter = &vc4->hvs->mitchell_netravali_filter;
129 + case DRM_SCALING_FILTER_NEAREST_NEIGHBOR:
130 + filter = &vc4->hvs->nearest_neighbour_filter;
133 + u32 kernel = VC4_SET_FIELD(filter->start,
134 SCALER_PPF_KERNEL_OFFSET);
137 @@ -1984,9 +2000,19 @@ static int vc6_plane_mode_set(struct drm
138 vc4_state->y_scaling[0] == VC4_SCALING_PPF ||
139 vc4_state->x_scaling[1] == VC4_SCALING_PPF ||
140 vc4_state->y_scaling[1] == VC4_SCALING_PPF) {
142 - VC4_SET_FIELD(vc4->hvs->mitchell_netravali_filter.start,
143 - SCALER_PPF_KERNEL_OFFSET);
144 + struct drm_mm_node *filter;
146 + switch (state->scaling_filter) {
147 + case DRM_SCALING_FILTER_DEFAULT:
149 + filter = &vc4->hvs->mitchell_netravali_filter;
151 + case DRM_SCALING_FILTER_NEAREST_NEIGHBOR:
152 + filter = &vc4->hvs->nearest_neighbour_filter;
155 + u32 kernel = VC4_SET_FIELD(filter->start,
156 + SCALER_PPF_KERNEL_OFFSET);
159 vc4_dlist_write(vc4_state, kernel);
160 @@ -2468,6 +2494,10 @@ struct drm_plane *vc4_plane_init(struct
161 DRM_COLOR_YCBCR_BT709,
162 DRM_COLOR_YCBCR_LIMITED_RANGE);
164 + drm_plane_create_scaling_filter_property(plane,
165 + BIT(DRM_SCALING_FILTER_DEFAULT) |
166 + BIT(DRM_SCALING_FILTER_NEAREST_NEIGHBOR));
168 drm_plane_create_chroma_siting_properties(plane, 0, 0);
170 if (type == DRM_PLANE_TYPE_PRIMARY)