linux/drivers/gpu/drm/tegra/plane.c
Thierry Reding 7772fdaef9 drm/tegra: Support ARGB and ABGR formats
These formats can easily be supported on all generations of Tegra.

Note that the XRGB and XBGR formats that we supported were in fact using
the ARGB and ABGR Tegra formats. This happened to work in cases where no
alpha was being considered. This change is also a fix for those formats.

Signed-off-by: Thierry Reding <treding@nvidia.com>
2017-12-13 14:16:39 +01:00

189 lines
4.0 KiB
C

/*
* Copyright (C) 2017 NVIDIA CORPORATION. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <drm/drm_atomic.h>
#include <drm/drm_atomic_helper.h>
#include <drm/drm_plane_helper.h>
#include "dc.h"
#include "plane.h"
static void tegra_plane_destroy(struct drm_plane *plane)
{
struct tegra_plane *p = to_tegra_plane(plane);
drm_plane_cleanup(plane);
kfree(p);
}
static void tegra_plane_reset(struct drm_plane *plane)
{
struct tegra_plane_state *state;
if (plane->state)
__drm_atomic_helper_plane_destroy_state(plane->state);
kfree(plane->state);
plane->state = NULL;
state = kzalloc(sizeof(*state), GFP_KERNEL);
if (state) {
plane->state = &state->base;
plane->state->plane = plane;
}
}
static struct drm_plane_state *
tegra_plane_atomic_duplicate_state(struct drm_plane *plane)
{
struct tegra_plane_state *state = to_tegra_plane_state(plane->state);
struct tegra_plane_state *copy;
copy = kmalloc(sizeof(*copy), GFP_KERNEL);
if (!copy)
return NULL;
__drm_atomic_helper_plane_duplicate_state(plane, &copy->base);
copy->tiling = state->tiling;
copy->format = state->format;
copy->swap = state->swap;
return &copy->base;
}
static void tegra_plane_atomic_destroy_state(struct drm_plane *plane,
struct drm_plane_state *state)
{
__drm_atomic_helper_plane_destroy_state(state);
kfree(state);
}
const struct drm_plane_funcs tegra_plane_funcs = {
.update_plane = drm_atomic_helper_update_plane,
.disable_plane = drm_atomic_helper_disable_plane,
.destroy = tegra_plane_destroy,
.reset = tegra_plane_reset,
.atomic_duplicate_state = tegra_plane_atomic_duplicate_state,
.atomic_destroy_state = tegra_plane_atomic_destroy_state,
};
int tegra_plane_state_add(struct tegra_plane *plane,
struct drm_plane_state *state)
{
struct drm_crtc_state *crtc_state;
struct tegra_dc_state *tegra;
struct drm_rect clip;
int err;
/* Propagate errors from allocation or locking failures. */
crtc_state = drm_atomic_get_crtc_state(state->state, state->crtc);
if (IS_ERR(crtc_state))
return PTR_ERR(crtc_state);
clip.x1 = 0;
clip.y1 = 0;
clip.x2 = crtc_state->mode.hdisplay;
clip.y2 = crtc_state->mode.vdisplay;
/* Check plane state for visibility and calculate clipping bounds */
err = drm_atomic_helper_check_plane_state(state, crtc_state, &clip,
0, INT_MAX, true, true);
if (err < 0)
return err;
tegra = to_dc_state(crtc_state);
tegra->planes |= WIN_A_ACT_REQ << plane->index;
return 0;
}
int tegra_plane_format(u32 fourcc, u32 *format, u32 *swap)
{
/* assume no swapping of fetched data */
if (swap)
*swap = BYTE_SWAP_NOSWAP;
switch (fourcc) {
case DRM_FORMAT_XBGR8888:
*format = WIN_COLOR_DEPTH_R8G8B8X8;
break;
case DRM_FORMAT_ABGR8888:
*format = WIN_COLOR_DEPTH_R8G8B8A8;
break;
case DRM_FORMAT_XRGB8888:
*format = WIN_COLOR_DEPTH_B8G8R8X8;
break;
case DRM_FORMAT_ARGB8888:
*format = WIN_COLOR_DEPTH_B8G8R8A8;
break;
case DRM_FORMAT_RGB565:
*format = WIN_COLOR_DEPTH_B5G6R5;
break;
case DRM_FORMAT_UYVY:
*format = WIN_COLOR_DEPTH_YCbCr422;
break;
case DRM_FORMAT_YUYV:
if (!swap)
return -EINVAL;
*format = WIN_COLOR_DEPTH_YCbCr422;
*swap = BYTE_SWAP_SWAP2;
break;
case DRM_FORMAT_YUV420:
*format = WIN_COLOR_DEPTH_YCbCr420P;
break;
case DRM_FORMAT_YUV422:
*format = WIN_COLOR_DEPTH_YCbCr422P;
break;
default:
return -EINVAL;
}
return 0;
}
bool tegra_plane_format_is_yuv(unsigned int format, bool *planar)
{
switch (format) {
case WIN_COLOR_DEPTH_YCbCr422:
case WIN_COLOR_DEPTH_YUV422:
if (planar)
*planar = false;
return true;
case WIN_COLOR_DEPTH_YCbCr420P:
case WIN_COLOR_DEPTH_YUV420P:
case WIN_COLOR_DEPTH_YCbCr422P:
case WIN_COLOR_DEPTH_YUV422P:
case WIN_COLOR_DEPTH_YCbCr422R:
case WIN_COLOR_DEPTH_YUV422R:
case WIN_COLOR_DEPTH_YCbCr422RA:
case WIN_COLOR_DEPTH_YUV422RA:
if (planar)
*planar = true;
return true;
}
if (planar)
*planar = false;
return false;
}