1 From fd317c55c0a5d9f8950b49d1efe32166a378cb26 Mon Sep 17 00:00:00 2001
2 From: Dave Stevenson <dave.stevenson@raspberrypi.com>
3 Date: Wed, 15 Dec 2021 10:17:38 +0100
4 Subject: [PATCH] drm/vc4: plane: Add support for DRM_FORMAT_P030
6 The P030 format, used with the DRM_FORMAT_MOD_BROADCOM_SAND128 modifier,
7 is a format output by the video decoder on the BCM2711.
9 Add native support to the KMS planes for that format.
11 Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
12 Signed-off-by: Maxime Ripard <maxime@cerno.tech>
13 Acked-by: Thomas Zimmermann <tzimmermann@suse.de>
14 Link: https://lore.kernel.org/r/20211215091739.135042-3-maxime@cerno.tech
16 drivers/gpu/drm/vc4/vc4_plane.c | 127 ++++++++++++++++++++++++--------
17 1 file changed, 96 insertions(+), 31 deletions(-)
19 --- a/drivers/gpu/drm/vc4/vc4_plane.c
20 +++ b/drivers/gpu/drm/vc4/vc4_plane.c
21 @@ -33,6 +33,7 @@ static const struct hvs_format {
22 u32 hvs; /* HVS_FORMAT_* */
28 .drm = DRM_FORMAT_XRGB8888,
29 @@ -128,6 +129,12 @@ static const struct hvs_format {
30 .hvs = HVS_PIXEL_FORMAT_YCBCR_YUV422_2PLANE,
31 .pixel_order = HVS_PIXEL_ORDER_XYCRCB,
34 + .drm = DRM_FORMAT_P030,
35 + .hvs = HVS_PIXEL_FORMAT_YCBCR_10BIT,
36 + .pixel_order = HVS_PIXEL_ORDER_XYCBCR,
41 static const struct hvs_format *vc4_get_hvs_format(u32 drm_format)
42 @@ -762,47 +769,90 @@ static int vc4_plane_mode_set(struct drm
43 case DRM_FORMAT_MOD_BROADCOM_SAND128:
44 case DRM_FORMAT_MOD_BROADCOM_SAND256: {
45 uint32_t param = fourcc_mod_broadcom_param(fb->modifier);
46 - u32 tile_w, tile, x_off, pix_per_tile;
48 - hvs_format = HVS_PIXEL_FORMAT_H264;
50 - switch (base_format_mod) {
51 - case DRM_FORMAT_MOD_BROADCOM_SAND64:
52 - tiling = SCALER_CTL0_TILING_64B;
55 - case DRM_FORMAT_MOD_BROADCOM_SAND128:
56 - tiling = SCALER_CTL0_TILING_128B;
59 - case DRM_FORMAT_MOD_BROADCOM_SAND256:
60 - tiling = SCALER_CTL0_TILING_256B_OR_T;
67 if (param > SCALER_TILE_HEIGHT_MASK) {
68 - DRM_DEBUG_KMS("SAND height too large (%d)\n", param);
69 + DRM_DEBUG_KMS("SAND height too large (%d)\n",
74 - pix_per_tile = tile_w / fb->format->cpp[0];
75 - tile = vc4_state->src_x / pix_per_tile;
76 - x_off = vc4_state->src_x % pix_per_tile;
77 + if (fb->format->format == DRM_FORMAT_P030) {
78 + hvs_format = HVS_PIXEL_FORMAT_YCBCR_10BIT;
79 + tiling = SCALER_CTL0_TILING_128B;
81 + hvs_format = HVS_PIXEL_FORMAT_H264;
83 + switch (base_format_mod) {
84 + case DRM_FORMAT_MOD_BROADCOM_SAND64:
85 + tiling = SCALER_CTL0_TILING_64B;
87 + case DRM_FORMAT_MOD_BROADCOM_SAND128:
88 + tiling = SCALER_CTL0_TILING_128B;
90 + case DRM_FORMAT_MOD_BROADCOM_SAND256:
91 + tiling = SCALER_CTL0_TILING_256B_OR_T;
98 /* Adjust the base pointer to the first pixel to be scanned
101 + * For P030, y_ptr [31:4] is the 128bit word for the start pixel
102 + * y_ptr [3:0] is the pixel (0-11) contained within that 128bit
103 + * word that should be taken as the first pixel.
104 + * Ditto uv_ptr [31:4] vs [3:0], however [3:0] contains the
105 + * element within the 128bit word, eg for pixel 3 the value
108 for (i = 0; i < num_planes; i++) {
109 + u32 tile_w, tile, x_off, pix_per_tile;
111 + if (fb->format->format == DRM_FORMAT_P030) {
113 + * Spec says: bits [31:4] of the given address
114 + * should point to the 128-bit word containing
115 + * the desired starting pixel, and bits[3:0]
116 + * should be between 0 and 11, indicating which
117 + * of the 12-pixels in that 128-bit word is the
118 + * first pixel to be used
120 + u32 remaining_pixels = vc4_state->src_x % 96;
121 + u32 aligned = remaining_pixels / 12;
122 + u32 last_bits = remaining_pixels % 12;
124 + x_off = aligned * 16 + last_bits;
128 + switch (base_format_mod) {
129 + case DRM_FORMAT_MOD_BROADCOM_SAND64:
132 + case DRM_FORMAT_MOD_BROADCOM_SAND128:
135 + case DRM_FORMAT_MOD_BROADCOM_SAND256:
141 + pix_per_tile = tile_w / fb->format->cpp[0];
142 + x_off = (vc4_state->src_x % pix_per_tile) /
143 + (i ? h_subsample : 1) *
144 + fb->format->cpp[i];
147 + tile = vc4_state->src_x / pix_per_tile;
149 vc4_state->offsets[i] += param * tile_w * tile;
150 vc4_state->offsets[i] += src_y /
151 (i ? v_subsample : 1) *
153 - vc4_state->offsets[i] += x_off /
154 - (i ? h_subsample : 1) *
155 - fb->format->cpp[i];
156 + vc4_state->offsets[i] += x_off & ~(i ? 1 : 0);
159 pitch0 = VC4_SET_FIELD(param, SCALER_TILE_HEIGHT);
160 @@ -955,7 +1005,8 @@ static int vc4_plane_mode_set(struct drm
163 for (i = 1; i < num_planes; i++) {
164 - if (hvs_format != HVS_PIXEL_FORMAT_H264) {
165 + if (hvs_format != HVS_PIXEL_FORMAT_H264 &&
166 + hvs_format != HVS_PIXEL_FORMAT_YCBCR_10BIT) {
167 vc4_dlist_write(vc4_state,
168 VC4_SET_FIELD(fb->pitches[i],
170 @@ -1315,6 +1366,13 @@ static bool vc4_format_mod_supported(str
174 + case DRM_FORMAT_P030:
175 + switch (fourcc_mod_broadcom_mod(modifier)) {
176 + case DRM_FORMAT_MOD_BROADCOM_SAND128:
181 case DRM_FORMAT_RGBX1010102:
182 case DRM_FORMAT_BGRX1010102:
183 case DRM_FORMAT_RGBA1010102:
184 @@ -1347,8 +1405,11 @@ struct drm_plane *vc4_plane_init(struct
185 struct drm_plane *plane = NULL;
186 struct vc4_plane *vc4_plane;
187 u32 formats[ARRAY_SIZE(hvs_formats)];
188 + int num_formats = 0;
191 + bool hvs5 = of_device_is_compatible(dev->dev->of_node,
192 + "brcm,bcm2711-vc5");
193 static const uint64_t modifiers[] = {
194 DRM_FORMAT_MOD_BROADCOM_VC4_T_TILED,
195 DRM_FORMAT_MOD_BROADCOM_SAND128,
196 @@ -1363,13 +1424,17 @@ struct drm_plane *vc4_plane_init(struct
198 return ERR_PTR(-ENOMEM);
200 - for (i = 0; i < ARRAY_SIZE(hvs_formats); i++)
201 - formats[i] = hvs_formats[i].drm;
202 + for (i = 0; i < ARRAY_SIZE(hvs_formats); i++) {
203 + if (!hvs_formats[i].hvs5_only || hvs5) {
204 + formats[num_formats] = hvs_formats[i].drm;
209 plane = &vc4_plane->base;
210 ret = drm_universal_plane_init(dev, plane, 0,
212 - formats, ARRAY_SIZE(formats),
213 + formats, num_formats,
214 modifiers, type, NULL);