diff options
Diffstat (limited to 'drivers/gpu/drm/sun4i/sun4i_backend.c')
-rw-r--r-- | drivers/gpu/drm/sun4i/sun4i_backend.c | 106 |
1 files changed, 94 insertions, 12 deletions
diff --git a/drivers/gpu/drm/sun4i/sun4i_backend.c b/drivers/gpu/drm/sun4i/sun4i_backend.c index bf49c55b0f2c..9e9255ee59cd 100644 --- a/drivers/gpu/drm/sun4i/sun4i_backend.c +++ b/drivers/gpu/drm/sun4i/sun4i_backend.c @@ -48,8 +48,12 @@ static const u32 sunxi_rgb2yuv_coef[12] = { /* * These coefficients are taken from the A33 BSP from Allwinner. * - * The formula is for each component, each coefficient being multiplied by - * 1024 and each constant being multiplied by 16: + * The first three values of each row are coded as 13-bit signed fixed-point + * numbers, with 10 bits for the fractional part. The fourth value is a + * constant coded as a 14-bit signed fixed-point number with 4 bits for the + * fractional part. + * + * The values in table order give the following colorspace translation: * G = 1.164 * Y - 0.391 * U - 0.813 * V + 135 * R = 1.164 * Y + 1.596 * V - 222 * B = 1.164 * Y + 2.018 * U + 276 @@ -155,6 +159,36 @@ static int sun4i_backend_drm_format_to_layer(u32 format, u32 *mode) return 0; } +static const uint32_t sun4i_backend_formats[] = { + DRM_FORMAT_ARGB1555, + DRM_FORMAT_ARGB4444, + DRM_FORMAT_ARGB8888, + DRM_FORMAT_BGRX8888, + DRM_FORMAT_RGB565, + DRM_FORMAT_RGB888, + DRM_FORMAT_RGBA4444, + DRM_FORMAT_RGBA5551, + DRM_FORMAT_UYVY, + DRM_FORMAT_VYUY, + DRM_FORMAT_XRGB8888, + DRM_FORMAT_YUYV, + DRM_FORMAT_YVYU, +}; + +bool sun4i_backend_format_is_supported(uint32_t fmt, uint64_t modifier) +{ + unsigned int i; + + if (modifier != DRM_FORMAT_MOD_LINEAR) + return false; + + for (i = 0; i < ARRAY_SIZE(sun4i_backend_formats); i++) + if (sun4i_backend_formats[i] == fmt) + return true; + + return false; +} + int sun4i_backend_update_layer_coord(struct sun4i_backend *backend, int layer, struct drm_plane *plane) { @@ -395,6 +429,15 @@ int sun4i_backend_update_layer_zpos(struct sun4i_backend *backend, int layer, return 0; } +void sun4i_backend_cleanup_layer(struct sun4i_backend *backend, + int layer) +{ + regmap_update_bits(backend->engine.regs, + SUN4I_BACKEND_ATTCTL_REG0(layer), + SUN4I_BACKEND_ATTCTL_REG0_LAY_VDOEN | + SUN4I_BACKEND_ATTCTL_REG0_LAY_YUVEN, 0); +} + static bool sun4i_backend_plane_uses_scaler(struct drm_plane_state *state) { u16 src_h = state->src_h >> 16; @@ -413,11 +456,50 @@ static bool sun4i_backend_plane_uses_frontend(struct drm_plane_state *state) { struct sun4i_layer *layer = plane_to_sun4i_layer(state->plane); struct sun4i_backend *backend = layer->backend; + uint32_t format = state->fb->format->format; + uint64_t modifier = state->fb->modifier; if (IS_ERR(backend->frontend)) return false; - return sun4i_backend_plane_uses_scaler(state); + if (!sun4i_frontend_format_is_supported(format, modifier)) + return false; + + if (!sun4i_backend_format_is_supported(format, modifier)) + return true; + + /* + * TODO: The backend alone allows 2x and 4x integer scaling, including + * support for an alpha component (which the frontend doesn't support). + * Use the backend directly instead of the frontend in this case, with + * another test to return false. + */ + + if (sun4i_backend_plane_uses_scaler(state)) + return true; + + /* + * Here the format is supported by both the frontend and the backend + * and no frontend scaling is required, so use the backend directly. + */ + return false; +} + +static bool sun4i_backend_plane_is_supported(struct drm_plane_state *state, + bool *uses_frontend) +{ + if (sun4i_backend_plane_uses_frontend(state)) { + *uses_frontend = true; + return true; + } + + *uses_frontend = false; + + /* Scaling is not supported without the frontend. */ + if (sun4i_backend_plane_uses_scaler(state)) + return false; + + return true; } static void sun4i_backend_atomic_begin(struct sunxi_engine *engine, @@ -460,14 +542,19 @@ static int sun4i_backend_atomic_check(struct sunxi_engine *engine, struct drm_framebuffer *fb = plane_state->fb; struct drm_format_name_buf format_name; - if (sun4i_backend_plane_uses_frontend(plane_state)) { + if (!sun4i_backend_plane_is_supported(plane_state, + &layer_state->uses_frontend)) + return -EINVAL; + + if (layer_state->uses_frontend) { DRM_DEBUG_DRIVER("Using the frontend for plane %d\n", plane->index); - - layer_state->uses_frontend = true; num_frontend_planes++; } else { - layer_state->uses_frontend = false; + if (fb->format->is_yuv) { + DRM_DEBUG_DRIVER("Plane FB format is YUV\n"); + num_yuv_planes++; + } } DRM_DEBUG_DRIVER("Plane FB format is %s\n", @@ -476,11 +563,6 @@ static int sun4i_backend_atomic_check(struct sunxi_engine *engine, if (fb->format->has_alpha || (plane_state->alpha != DRM_BLEND_ALPHA_OPAQUE)) num_alpha_planes++; - if (fb->format->is_yuv) { - DRM_DEBUG_DRIVER("Plane FB format is YUV\n"); - num_yuv_planes++; - } - DRM_DEBUG_DRIVER("Plane zpos is %d\n", plane_state->normalized_zpos); |