|
@@ -59,6 +59,23 @@ static inline struct tegra_dc_state *to_dc_state(struct drm_crtc_state *state)
|
|
|
return NULL;
|
|
return NULL;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+struct tegra_plane_state {
|
|
|
|
|
+ struct drm_plane_state base;
|
|
|
|
|
+
|
|
|
|
|
+ struct tegra_bo_tiling tiling;
|
|
|
|
|
+ u32 format;
|
|
|
|
|
+ u32 swap;
|
|
|
|
|
+};
|
|
|
|
|
+
|
|
|
|
|
+static inline struct tegra_plane_state *
|
|
|
|
|
+to_tegra_plane_state(struct drm_plane_state *state)
|
|
|
|
|
+{
|
|
|
|
|
+ if (state)
|
|
|
|
|
+ return container_of(state, struct tegra_plane_state, base);
|
|
|
|
|
+
|
|
|
|
|
+ return NULL;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
/*
|
|
/*
|
|
|
* Reads the active copy of a register. This takes the dc->lock spinlock to
|
|
* Reads the active copy of a register. This takes the dc->lock spinlock to
|
|
|
* prevent races with the VBLANK processing which also needs access to the
|
|
* prevent races with the VBLANK processing which also needs access to the
|
|
@@ -97,43 +114,49 @@ void tegra_dc_commit(struct tegra_dc *dc)
|
|
|
tegra_dc_writel(dc, GENERAL_ACT_REQ, DC_CMD_STATE_CONTROL);
|
|
tegra_dc_writel(dc, GENERAL_ACT_REQ, DC_CMD_STATE_CONTROL);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-static unsigned int tegra_dc_format(uint32_t format, uint32_t *swap)
|
|
|
|
|
|
|
+static int tegra_dc_format(u32 fourcc, u32 *format, u32 *swap)
|
|
|
{
|
|
{
|
|
|
/* assume no swapping of fetched data */
|
|
/* assume no swapping of fetched data */
|
|
|
if (swap)
|
|
if (swap)
|
|
|
*swap = BYTE_SWAP_NOSWAP;
|
|
*swap = BYTE_SWAP_NOSWAP;
|
|
|
|
|
|
|
|
- switch (format) {
|
|
|
|
|
|
|
+ switch (fourcc) {
|
|
|
case DRM_FORMAT_XBGR8888:
|
|
case DRM_FORMAT_XBGR8888:
|
|
|
- return WIN_COLOR_DEPTH_R8G8B8A8;
|
|
|
|
|
|
|
+ *format = WIN_COLOR_DEPTH_R8G8B8A8;
|
|
|
|
|
+ break;
|
|
|
|
|
|
|
|
case DRM_FORMAT_XRGB8888:
|
|
case DRM_FORMAT_XRGB8888:
|
|
|
- return WIN_COLOR_DEPTH_B8G8R8A8;
|
|
|
|
|
|
|
+ *format = WIN_COLOR_DEPTH_B8G8R8A8;
|
|
|
|
|
+ break;
|
|
|
|
|
|
|
|
case DRM_FORMAT_RGB565:
|
|
case DRM_FORMAT_RGB565:
|
|
|
- return WIN_COLOR_DEPTH_B5G6R5;
|
|
|
|
|
|
|
+ *format = WIN_COLOR_DEPTH_B5G6R5;
|
|
|
|
|
+ break;
|
|
|
|
|
|
|
|
case DRM_FORMAT_UYVY:
|
|
case DRM_FORMAT_UYVY:
|
|
|
- return WIN_COLOR_DEPTH_YCbCr422;
|
|
|
|
|
|
|
+ *format = WIN_COLOR_DEPTH_YCbCr422;
|
|
|
|
|
+ break;
|
|
|
|
|
|
|
|
case DRM_FORMAT_YUYV:
|
|
case DRM_FORMAT_YUYV:
|
|
|
if (swap)
|
|
if (swap)
|
|
|
*swap = BYTE_SWAP_SWAP2;
|
|
*swap = BYTE_SWAP_SWAP2;
|
|
|
|
|
|
|
|
- return WIN_COLOR_DEPTH_YCbCr422;
|
|
|
|
|
|
|
+ *format = WIN_COLOR_DEPTH_YCbCr422;
|
|
|
|
|
+ break;
|
|
|
|
|
|
|
|
case DRM_FORMAT_YUV420:
|
|
case DRM_FORMAT_YUV420:
|
|
|
- return WIN_COLOR_DEPTH_YCbCr420P;
|
|
|
|
|
|
|
+ *format = WIN_COLOR_DEPTH_YCbCr420P;
|
|
|
|
|
+ break;
|
|
|
|
|
|
|
|
case DRM_FORMAT_YUV422:
|
|
case DRM_FORMAT_YUV422:
|
|
|
- return WIN_COLOR_DEPTH_YCbCr422P;
|
|
|
|
|
|
|
+ *format = WIN_COLOR_DEPTH_YCbCr422P;
|
|
|
|
|
+ break;
|
|
|
|
|
|
|
|
default:
|
|
default:
|
|
|
- break;
|
|
|
|
|
|
|
+ return -EINVAL;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- WARN(1, "unsupported pixel format %u, using default\n", format);
|
|
|
|
|
- return WIN_COLOR_DEPTH_B8G8R8A8;
|
|
|
|
|
|
|
+ return 0;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
static bool tegra_dc_format_is_yuv(unsigned int format, bool *planar)
|
|
static bool tegra_dc_format_is_yuv(unsigned int format, bool *planar)
|
|
@@ -398,13 +421,54 @@ static void tegra_primary_plane_destroy(struct drm_plane *plane)
|
|
|
tegra_plane_destroy(plane);
|
|
tegra_plane_destroy(plane);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+static void tegra_plane_reset(struct drm_plane *plane)
|
|
|
|
|
+{
|
|
|
|
|
+ struct tegra_plane_state *state;
|
|
|
|
|
+
|
|
|
|
|
+ if (plane->state && plane->state->fb)
|
|
|
|
|
+ drm_framebuffer_unreference(plane->state->fb);
|
|
|
|
|
+
|
|
|
|
|
+ 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 = kmemdup(state, sizeof(*state), GFP_KERNEL);
|
|
|
|
|
+ if (!copy)
|
|
|
|
|
+ return NULL;
|
|
|
|
|
+
|
|
|
|
|
+ if (copy->base.fb)
|
|
|
|
|
+ drm_framebuffer_reference(copy->base.fb);
|
|
|
|
|
+
|
|
|
|
|
+ return ©->base;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+static void tegra_plane_atomic_destroy_state(struct drm_plane *plane,
|
|
|
|
|
+ struct drm_plane_state *state)
|
|
|
|
|
+{
|
|
|
|
|
+ if (state->fb)
|
|
|
|
|
+ drm_framebuffer_unreference(state->fb);
|
|
|
|
|
+
|
|
|
|
|
+ kfree(state);
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
static const struct drm_plane_funcs tegra_primary_plane_funcs = {
|
|
static const struct drm_plane_funcs tegra_primary_plane_funcs = {
|
|
|
.update_plane = drm_atomic_helper_update_plane,
|
|
.update_plane = drm_atomic_helper_update_plane,
|
|
|
.disable_plane = drm_atomic_helper_disable_plane,
|
|
.disable_plane = drm_atomic_helper_disable_plane,
|
|
|
.destroy = tegra_primary_plane_destroy,
|
|
.destroy = tegra_primary_plane_destroy,
|
|
|
- .reset = drm_atomic_helper_plane_reset,
|
|
|
|
|
- .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state,
|
|
|
|
|
- .atomic_destroy_state = drm_atomic_helper_plane_destroy_state,
|
|
|
|
|
|
|
+ .reset = tegra_plane_reset,
|
|
|
|
|
+ .atomic_duplicate_state = tegra_plane_atomic_duplicate_state,
|
|
|
|
|
+ .atomic_destroy_state = tegra_plane_atomic_destroy_state,
|
|
|
};
|
|
};
|
|
|
|
|
|
|
|
static int tegra_plane_prepare_fb(struct drm_plane *plane,
|
|
static int tegra_plane_prepare_fb(struct drm_plane *plane,
|
|
@@ -439,20 +503,26 @@ static int tegra_plane_state_add(struct tegra_plane *plane,
|
|
|
static int tegra_plane_atomic_check(struct drm_plane *plane,
|
|
static int tegra_plane_atomic_check(struct drm_plane *plane,
|
|
|
struct drm_plane_state *state)
|
|
struct drm_plane_state *state)
|
|
|
{
|
|
{
|
|
|
|
|
+ struct tegra_plane_state *plane_state = to_tegra_plane_state(state);
|
|
|
|
|
+ struct tegra_bo_tiling *tiling = &plane_state->tiling;
|
|
|
struct tegra_plane *tegra = to_tegra_plane(plane);
|
|
struct tegra_plane *tegra = to_tegra_plane(plane);
|
|
|
struct tegra_dc *dc = to_tegra_dc(state->crtc);
|
|
struct tegra_dc *dc = to_tegra_dc(state->crtc);
|
|
|
- struct tegra_bo_tiling tiling;
|
|
|
|
|
int err;
|
|
int err;
|
|
|
|
|
|
|
|
/* no need for further checks if the plane is being disabled */
|
|
/* no need for further checks if the plane is being disabled */
|
|
|
if (!state->crtc)
|
|
if (!state->crtc)
|
|
|
return 0;
|
|
return 0;
|
|
|
|
|
|
|
|
- err = tegra_fb_get_tiling(state->fb, &tiling);
|
|
|
|
|
|
|
+ err = tegra_dc_format(state->fb->pixel_format, &plane_state->format,
|
|
|
|
|
+ &plane_state->swap);
|
|
|
|
|
+ if (err < 0)
|
|
|
|
|
+ return err;
|
|
|
|
|
+
|
|
|
|
|
+ err = tegra_fb_get_tiling(state->fb, tiling);
|
|
|
if (err < 0)
|
|
if (err < 0)
|
|
|
return err;
|
|
return err;
|
|
|
|
|
|
|
|
- if (tiling.mode == TEGRA_BO_TILING_MODE_BLOCK &&
|
|
|
|
|
|
|
+ if (tiling->mode == TEGRA_BO_TILING_MODE_BLOCK &&
|
|
|
!dc->soc->supports_block_linear) {
|
|
!dc->soc->supports_block_linear) {
|
|
|
DRM_ERROR("hardware doesn't support block linear mode\n");
|
|
DRM_ERROR("hardware doesn't support block linear mode\n");
|
|
|
return -EINVAL;
|
|
return -EINVAL;
|
|
@@ -480,12 +550,12 @@ static int tegra_plane_atomic_check(struct drm_plane *plane,
|
|
|
static void tegra_plane_atomic_update(struct drm_plane *plane,
|
|
static void tegra_plane_atomic_update(struct drm_plane *plane,
|
|
|
struct drm_plane_state *old_state)
|
|
struct drm_plane_state *old_state)
|
|
|
{
|
|
{
|
|
|
|
|
+ struct tegra_plane_state *state = to_tegra_plane_state(plane->state);
|
|
|
struct tegra_dc *dc = to_tegra_dc(plane->state->crtc);
|
|
struct tegra_dc *dc = to_tegra_dc(plane->state->crtc);
|
|
|
struct drm_framebuffer *fb = plane->state->fb;
|
|
struct drm_framebuffer *fb = plane->state->fb;
|
|
|
struct tegra_plane *p = to_tegra_plane(plane);
|
|
struct tegra_plane *p = to_tegra_plane(plane);
|
|
|
struct tegra_dc_window window;
|
|
struct tegra_dc_window window;
|
|
|
unsigned int i;
|
|
unsigned int i;
|
|
|
- int err;
|
|
|
|
|
|
|
|
|
|
/* rien ne va plus */
|
|
/* rien ne va plus */
|
|
|
if (!plane->state->crtc || !plane->state->fb)
|
|
if (!plane->state->crtc || !plane->state->fb)
|
|
@@ -500,12 +570,13 @@ static void tegra_plane_atomic_update(struct drm_plane *plane,
|
|
|
window.dst.y = plane->state->crtc_y;
|
|
window.dst.y = plane->state->crtc_y;
|
|
|
window.dst.w = plane->state->crtc_w;
|
|
window.dst.w = plane->state->crtc_w;
|
|
|
window.dst.h = plane->state->crtc_h;
|
|
window.dst.h = plane->state->crtc_h;
|
|
|
- window.format = tegra_dc_format(fb->pixel_format, &window.swap);
|
|
|
|
|
window.bits_per_pixel = fb->bits_per_pixel;
|
|
window.bits_per_pixel = fb->bits_per_pixel;
|
|
|
window.bottom_up = tegra_fb_is_bottom_up(fb);
|
|
window.bottom_up = tegra_fb_is_bottom_up(fb);
|
|
|
|
|
|
|
|
- err = tegra_fb_get_tiling(fb, &window.tiling);
|
|
|
|
|
- WARN_ON(err < 0);
|
|
|
|
|
|
|
+ /* copy from state */
|
|
|
|
|
+ window.tiling = state->tiling;
|
|
|
|
|
+ window.format = state->format;
|
|
|
|
|
+ window.swap = state->swap;
|
|
|
|
|
|
|
|
for (i = 0; i < drm_format_num_planes(fb->pixel_format); i++) {
|
|
for (i = 0; i < drm_format_num_planes(fb->pixel_format); i++) {
|
|
|
struct tegra_bo *bo = tegra_fb_get_plane(fb, i);
|
|
struct tegra_bo *bo = tegra_fb_get_plane(fb, i);
|
|
@@ -710,9 +781,9 @@ static const struct drm_plane_funcs tegra_cursor_plane_funcs = {
|
|
|
.update_plane = drm_atomic_helper_update_plane,
|
|
.update_plane = drm_atomic_helper_update_plane,
|
|
|
.disable_plane = drm_atomic_helper_disable_plane,
|
|
.disable_plane = drm_atomic_helper_disable_plane,
|
|
|
.destroy = tegra_plane_destroy,
|
|
.destroy = tegra_plane_destroy,
|
|
|
- .reset = drm_atomic_helper_plane_reset,
|
|
|
|
|
- .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state,
|
|
|
|
|
- .atomic_destroy_state = drm_atomic_helper_plane_destroy_state,
|
|
|
|
|
|
|
+ .reset = tegra_plane_reset,
|
|
|
|
|
+ .atomic_duplicate_state = tegra_plane_atomic_duplicate_state,
|
|
|
|
|
+ .atomic_destroy_state = tegra_plane_atomic_destroy_state,
|
|
|
};
|
|
};
|
|
|
|
|
|
|
|
static const struct drm_plane_helper_funcs tegra_cursor_plane_helper_funcs = {
|
|
static const struct drm_plane_helper_funcs tegra_cursor_plane_helper_funcs = {
|
|
@@ -767,9 +838,9 @@ static const struct drm_plane_funcs tegra_overlay_plane_funcs = {
|
|
|
.update_plane = drm_atomic_helper_update_plane,
|
|
.update_plane = drm_atomic_helper_update_plane,
|
|
|
.disable_plane = drm_atomic_helper_disable_plane,
|
|
.disable_plane = drm_atomic_helper_disable_plane,
|
|
|
.destroy = tegra_overlay_plane_destroy,
|
|
.destroy = tegra_overlay_plane_destroy,
|
|
|
- .reset = drm_atomic_helper_plane_reset,
|
|
|
|
|
- .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state,
|
|
|
|
|
- .atomic_destroy_state = drm_atomic_helper_plane_destroy_state,
|
|
|
|
|
|
|
+ .reset = tegra_plane_reset,
|
|
|
|
|
+ .atomic_duplicate_state = tegra_plane_atomic_duplicate_state,
|
|
|
|
|
+ .atomic_destroy_state = tegra_plane_atomic_destroy_state,
|
|
|
};
|
|
};
|
|
|
|
|
|
|
|
static const uint32_t tegra_overlay_plane_formats[] = {
|
|
static const uint32_t tegra_overlay_plane_formats[] = {
|