aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEric Anholt <eric@anholt.net>2015-12-30 15:25:44 -0500
committerEric Anholt <eric@anholt.net>2016-02-16 14:24:08 -0500
commitfc04023fafecf19ebd09278d8d67dc5ed1f68b46 (patch)
tree25acc41475384d9d364b6278d3cceea0139ac786
parentfe4cd8476928a66e109ab50a430362fcee8a5716 (diff)
drm/vc4: Add support for YUV planes.
This supports 420 and 422 subsampling with 2 or 3 planes, tested with modetest. It doesn't set up chroma subsampling position (which it appears KMS doesn't deal with yet). The LBM memory is overallocated in many cases, but apparently the docs aren't quite correct and I'll probably need to look at the hardware source to really figure it out. Signed-off-by: Eric Anholt <eric@anholt.net>
-rw-r--r--drivers/gpu/drm/vc4/vc4_plane.c256
-rw-r--r--drivers/gpu/drm/vc4/vc4_regs.h56
2 files changed, 253 insertions, 59 deletions
diff --git a/drivers/gpu/drm/vc4/vc4_plane.c b/drivers/gpu/drm/vc4/vc4_plane.c
index 013ebff60fb5..7b0c72ae02a0 100644
--- a/drivers/gpu/drm/vc4/vc4_plane.c
+++ b/drivers/gpu/drm/vc4/vc4_plane.c
@@ -54,15 +54,19 @@ struct vc4_plane_state {
54 /* Clipped coordinates of the plane on the display. */ 54 /* Clipped coordinates of the plane on the display. */
55 int crtc_x, crtc_y, crtc_w, crtc_h; 55 int crtc_x, crtc_y, crtc_w, crtc_h;
56 /* Clipped area being scanned from in the FB. */ 56 /* Clipped area being scanned from in the FB. */
57 u32 src_x, src_y, src_w, src_h; 57 u32 src_x, src_y;
58 58
59 enum vc4_scaling_mode x_scaling, y_scaling; 59 u32 src_w[2], src_h[2];
60
61 /* Scaling selection for the RGB/Y plane and the Cb/Cr planes. */
62 enum vc4_scaling_mode x_scaling[2], y_scaling[2];
60 bool is_unity; 63 bool is_unity;
64 bool is_yuv;
61 65
62 /* Offset to start scanning out from the start of the plane's 66 /* Offset to start scanning out from the start of the plane's
63 * BO. 67 * BO.
64 */ 68 */
65 u32 offset; 69 u32 offsets[3];
66 70
67 /* Our allocation in LBM for temporary storage during scaling. */ 71 /* Our allocation in LBM for temporary storage during scaling. */
68 struct drm_mm_node lbm; 72 struct drm_mm_node lbm;
@@ -79,6 +83,7 @@ static const struct hvs_format {
79 u32 hvs; /* HVS_FORMAT_* */ 83 u32 hvs; /* HVS_FORMAT_* */
80 u32 pixel_order; 84 u32 pixel_order;
81 bool has_alpha; 85 bool has_alpha;
86 bool flip_cbcr;
82} hvs_formats[] = { 87} hvs_formats[] = {
83 { 88 {
84 .drm = DRM_FORMAT_XRGB8888, .hvs = HVS_PIXEL_FORMAT_RGBA8888, 89 .drm = DRM_FORMAT_XRGB8888, .hvs = HVS_PIXEL_FORMAT_RGBA8888,
@@ -104,6 +109,32 @@ static const struct hvs_format {
104 .drm = DRM_FORMAT_XRGB1555, .hvs = HVS_PIXEL_FORMAT_RGBA5551, 109 .drm = DRM_FORMAT_XRGB1555, .hvs = HVS_PIXEL_FORMAT_RGBA5551,
105 .pixel_order = HVS_PIXEL_ORDER_ABGR, .has_alpha = false, 110 .pixel_order = HVS_PIXEL_ORDER_ABGR, .has_alpha = false,
106 }, 111 },
112 {
113 .drm = DRM_FORMAT_YUV422,
114 .hvs = HVS_PIXEL_FORMAT_YCBCR_YUV422_3PLANE,
115 },
116 {
117 .drm = DRM_FORMAT_YVU422,
118 .hvs = HVS_PIXEL_FORMAT_YCBCR_YUV422_3PLANE,
119 .flip_cbcr = true,
120 },
121 {
122 .drm = DRM_FORMAT_YUV420,
123 .hvs = HVS_PIXEL_FORMAT_YCBCR_YUV420_3PLANE,
124 },
125 {
126 .drm = DRM_FORMAT_YVU420,
127 .hvs = HVS_PIXEL_FORMAT_YCBCR_YUV420_3PLANE,
128 .flip_cbcr = true,
129 },
130 {
131 .drm = DRM_FORMAT_NV12,
132 .hvs = HVS_PIXEL_FORMAT_YCBCR_YUV420_2PLANE,
133 },
134 {
135 .drm = DRM_FORMAT_NV16,
136 .hvs = HVS_PIXEL_FORMAT_YCBCR_YUV422_2PLANE,
137 },
107}; 138};
108 139
109static const struct hvs_format *vc4_get_hvs_format(u32 drm_format) 140static const struct hvs_format *vc4_get_hvs_format(u32 drm_format)
@@ -219,11 +250,11 @@ static void vc4_dlist_write(struct vc4_plane_state *vc4_state, u32 val)
219 * 250 *
220 * This is a replication of a table from the spec. 251 * This is a replication of a table from the spec.
221 */ 252 */
222static u32 vc4_get_scl_field(struct drm_plane_state *state) 253static u32 vc4_get_scl_field(struct drm_plane_state *state, int plane)
223{ 254{
224 struct vc4_plane_state *vc4_state = to_vc4_plane_state(state); 255 struct vc4_plane_state *vc4_state = to_vc4_plane_state(state);
225 256
226 switch (vc4_state->x_scaling << 2 | vc4_state->y_scaling) { 257 switch (vc4_state->x_scaling[plane] << 2 | vc4_state->y_scaling[plane]) {
227 case VC4_SCALING_PPF << 2 | VC4_SCALING_PPF: 258 case VC4_SCALING_PPF << 2 | VC4_SCALING_PPF:
228 return SCALER_CTL0_SCL_H_PPF_V_PPF; 259 return SCALER_CTL0_SCL_H_PPF_V_PPF;
229 case VC4_SCALING_TPZ << 2 | VC4_SCALING_PPF: 260 case VC4_SCALING_TPZ << 2 | VC4_SCALING_PPF:
@@ -254,9 +285,16 @@ static int vc4_plane_setup_clipping_and_scaling(struct drm_plane_state *state)
254 struct drm_plane *plane = state->plane; 285 struct drm_plane *plane = state->plane;
255 struct vc4_plane_state *vc4_state = to_vc4_plane_state(state); 286 struct vc4_plane_state *vc4_state = to_vc4_plane_state(state);
256 struct drm_framebuffer *fb = state->fb; 287 struct drm_framebuffer *fb = state->fb;
288 struct drm_gem_cma_object *bo = drm_fb_cma_get_gem_obj(fb, 0);
257 u32 subpixel_src_mask = (1 << 16) - 1; 289 u32 subpixel_src_mask = (1 << 16) - 1;
290 u32 format = fb->pixel_format;
291 int num_planes = drm_format_num_planes(format);
292 u32 h_subsample = 1;
293 u32 v_subsample = 1;
294 int i;
258 295
259 vc4_state->offset = fb->offsets[0]; 296 for (i = 0; i < num_planes; i++)
297 vc4_state->offsets[i] = bo->paddr + fb->offsets[i];
260 298
261 /* We don't support subpixel source positioning for scaling. */ 299 /* We don't support subpixel source positioning for scaling. */
262 if ((state->src_x & subpixel_src_mask) || 300 if ((state->src_x & subpixel_src_mask) ||
@@ -268,20 +306,48 @@ static int vc4_plane_setup_clipping_and_scaling(struct drm_plane_state *state)
268 306
269 vc4_state->src_x = state->src_x >> 16; 307 vc4_state->src_x = state->src_x >> 16;
270 vc4_state->src_y = state->src_y >> 16; 308 vc4_state->src_y = state->src_y >> 16;
271 vc4_state->src_w = state->src_w >> 16; 309 vc4_state->src_w[0] = state->src_w >> 16;
272 vc4_state->src_h = state->src_h >> 16; 310 vc4_state->src_h[0] = state->src_h >> 16;
273 311
274 vc4_state->crtc_x = state->crtc_x; 312 vc4_state->crtc_x = state->crtc_x;
275 vc4_state->crtc_y = state->crtc_y; 313 vc4_state->crtc_y = state->crtc_y;
276 vc4_state->crtc_w = state->crtc_w; 314 vc4_state->crtc_w = state->crtc_w;
277 vc4_state->crtc_h = state->crtc_h; 315 vc4_state->crtc_h = state->crtc_h;
278 316
279 vc4_state->x_scaling = vc4_get_scaling_mode(vc4_state->src_w, 317 vc4_state->x_scaling[0] = vc4_get_scaling_mode(vc4_state->src_w[0],
280 vc4_state->crtc_w); 318 vc4_state->crtc_w);
281 vc4_state->y_scaling = vc4_get_scaling_mode(vc4_state->src_h, 319 vc4_state->y_scaling[0] = vc4_get_scaling_mode(vc4_state->src_h[0],
282 vc4_state->crtc_h); 320 vc4_state->crtc_h);
283 vc4_state->is_unity = (vc4_state->x_scaling == VC4_SCALING_NONE && 321
284 vc4_state->y_scaling == VC4_SCALING_NONE); 322 if (num_planes > 1) {
323 vc4_state->is_yuv = true;
324
325 h_subsample = drm_format_horz_chroma_subsampling(format);
326 v_subsample = drm_format_vert_chroma_subsampling(format);
327 vc4_state->src_w[1] = vc4_state->src_w[0] / h_subsample;
328 vc4_state->src_h[1] = vc4_state->src_h[0] / v_subsample;
329
330 vc4_state->x_scaling[1] =
331 vc4_get_scaling_mode(vc4_state->src_w[1],
332 vc4_state->crtc_w);
333 vc4_state->y_scaling[1] =
334 vc4_get_scaling_mode(vc4_state->src_h[1],
335 vc4_state->crtc_h);
336
337 /* YUV conversion requires that scaling be enabled,
338 * even on a plane that's otherwise 1:1. Choose TPZ
339 * for simplicity.
340 */
341 if (vc4_state->x_scaling[0] == VC4_SCALING_NONE)
342 vc4_state->x_scaling[0] = VC4_SCALING_TPZ;
343 if (vc4_state->y_scaling[0] == VC4_SCALING_NONE)
344 vc4_state->y_scaling[0] = VC4_SCALING_TPZ;
345 }
346
347 vc4_state->is_unity = (vc4_state->x_scaling[0] == VC4_SCALING_NONE &&
348 vc4_state->y_scaling[0] == VC4_SCALING_NONE &&
349 vc4_state->x_scaling[1] == VC4_SCALING_NONE &&
350 vc4_state->y_scaling[1] == VC4_SCALING_NONE);
285 351
286 /* No configuring scaling on the cursor plane, since it gets 352 /* No configuring scaling on the cursor plane, since it gets
287 non-vblank-synced updates, and scaling requires requires 353 non-vblank-synced updates, and scaling requires requires
@@ -294,16 +360,27 @@ static int vc4_plane_setup_clipping_and_scaling(struct drm_plane_state *state)
294 * support negative y, and negative x wastes bandwidth. 360 * support negative y, and negative x wastes bandwidth.
295 */ 361 */
296 if (vc4_state->crtc_x < 0) { 362 if (vc4_state->crtc_x < 0) {
297 vc4_state->offset += (drm_format_plane_cpp(fb->pixel_format, 363 for (i = 0; i < num_planes; i++) {
298 0) * 364 u32 cpp = drm_format_plane_cpp(fb->pixel_format, i);
299 -vc4_state->crtc_x); 365 u32 subs = ((i == 0) ? 1 : h_subsample);
300 vc4_state->src_w += vc4_state->crtc_x; 366
367 vc4_state->offsets[i] += (cpp *
368 (-vc4_state->crtc_x) / subs);
369 }
370 vc4_state->src_w[0] += vc4_state->crtc_x;
371 vc4_state->src_w[1] += vc4_state->crtc_x / h_subsample;
301 vc4_state->crtc_x = 0; 372 vc4_state->crtc_x = 0;
302 } 373 }
303