mirror of
https://github.com/AuxXxilium/linux_dsm_epyc7002.git
synced 2024-12-14 10:36:49 +07:00
0e4faf679e
Replace the use of drm_plane_helper_check_update() with drm_plane_helper_check_state() since we have a plane state. This also eliminates the double clipping the driver was doing in both check and commit phases). And it should fix src coordinate addr adjustement. Previously the driver was expecting negative dst coordinates after clipping, which is not going happen, so any clipping induced addr adjustment simply didn't happen. Neither did the driver respect any user configured src coordinates, so panning and such would have been totally broken. It should be all good now. Cc: CK Hu <ck.hu@mediatek.com> Cc: linux-mediatek@lists.infradead.org Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Reviewed-by: Bibby Hsieh <bibby.hsieh@mediatek.com> Tested-by: Bibby Hsieh <bibby.hsieh@mediatek.com> Acked-by: CK Hu <ck.hu@mediatek.com> Signed-off-by: Sean Paul <seanpaul@chromium.org> Link: http://patchwork.freedesktop.org/patch/msgid/1469549224-1860-9-git-send-email-ville.syrjala@linux.intel.com
210 lines
5.4 KiB
C
210 lines
5.4 KiB
C
/*
|
|
* Copyright (c) 2015 MediaTek Inc.
|
|
* Author: CK Hu <ck.hu@mediatek.com>
|
|
*
|
|
* 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.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*/
|
|
|
|
#include <drm/drmP.h>
|
|
#include <drm/drm_atomic.h>
|
|
#include <drm/drm_atomic_helper.h>
|
|
#include <drm/drm_plane_helper.h>
|
|
|
|
#include "mtk_drm_crtc.h"
|
|
#include "mtk_drm_ddp_comp.h"
|
|
#include "mtk_drm_drv.h"
|
|
#include "mtk_drm_fb.h"
|
|
#include "mtk_drm_gem.h"
|
|
#include "mtk_drm_plane.h"
|
|
|
|
static const u32 formats[] = {
|
|
DRM_FORMAT_XRGB8888,
|
|
DRM_FORMAT_ARGB8888,
|
|
DRM_FORMAT_RGB565,
|
|
};
|
|
|
|
static void mtk_plane_enable(struct mtk_drm_plane *mtk_plane,
|
|
dma_addr_t addr)
|
|
{
|
|
struct drm_plane *plane = &mtk_plane->base;
|
|
struct mtk_plane_state *state = to_mtk_plane_state(plane->state);
|
|
unsigned int pitch, format;
|
|
bool enable;
|
|
|
|
if (WARN_ON(!plane->state))
|
|
return;
|
|
|
|
enable = state->base.visible;
|
|
|
|
if (WARN_ON(enable && !plane->state->fb))
|
|
return;
|
|
|
|
if (plane->state->fb) {
|
|
pitch = plane->state->fb->pitches[0];
|
|
format = plane->state->fb->pixel_format;
|
|
} else {
|
|
pitch = 0;
|
|
format = DRM_FORMAT_RGBA8888;
|
|
}
|
|
|
|
addr += (state->base.src.x1 >> 16) * 4;
|
|
addr += (state->base.src.y1 >> 16) * pitch;
|
|
|
|
state->pending.enable = enable;
|
|
state->pending.pitch = pitch;
|
|
state->pending.format = format;
|
|
state->pending.addr = addr;
|
|
state->pending.x = state->base.dst.x1;
|
|
state->pending.y = state->base.dst.y1;
|
|
state->pending.width = drm_rect_width(&state->base.dst);
|
|
state->pending.height = drm_rect_height(&state->base.dst);
|
|
wmb(); /* Make sure the above parameters are set before update */
|
|
state->pending.dirty = true;
|
|
}
|
|
|
|
static void mtk_plane_reset(struct drm_plane *plane)
|
|
{
|
|
struct mtk_plane_state *state;
|
|
|
|
if (plane->state) {
|
|
if (plane->state->fb)
|
|
drm_framebuffer_unreference(plane->state->fb);
|
|
|
|
state = to_mtk_plane_state(plane->state);
|
|
memset(state, 0, sizeof(*state));
|
|
} else {
|
|
state = kzalloc(sizeof(*state), GFP_KERNEL);
|
|
if (!state)
|
|
return;
|
|
plane->state = &state->base;
|
|
}
|
|
|
|
state->base.plane = plane;
|
|
state->pending.format = DRM_FORMAT_RGB565;
|
|
}
|
|
|
|
static struct drm_plane_state *mtk_plane_duplicate_state(struct drm_plane *plane)
|
|
{
|
|
struct mtk_plane_state *old_state = to_mtk_plane_state(plane->state);
|
|
struct mtk_plane_state *state;
|
|
|
|
state = kzalloc(sizeof(*state), GFP_KERNEL);
|
|
if (!state)
|
|
return NULL;
|
|
|
|
__drm_atomic_helper_plane_duplicate_state(plane, &state->base);
|
|
|
|
WARN_ON(state->base.plane != plane);
|
|
|
|
state->pending = old_state->pending;
|
|
|
|
return &state->base;
|
|
}
|
|
|
|
static void mtk_drm_plane_destroy_state(struct drm_plane *plane,
|
|
struct drm_plane_state *state)
|
|
{
|
|
__drm_atomic_helper_plane_destroy_state(state);
|
|
kfree(to_mtk_plane_state(state));
|
|
}
|
|
|
|
static const struct drm_plane_funcs mtk_plane_funcs = {
|
|
.update_plane = drm_atomic_helper_update_plane,
|
|
.disable_plane = drm_atomic_helper_disable_plane,
|
|
.destroy = drm_plane_cleanup,
|
|
.reset = mtk_plane_reset,
|
|
.atomic_duplicate_state = mtk_plane_duplicate_state,
|
|
.atomic_destroy_state = mtk_drm_plane_destroy_state,
|
|
};
|
|
|
|
static int mtk_plane_atomic_check(struct drm_plane *plane,
|
|
struct drm_plane_state *state)
|
|
{
|
|
struct drm_framebuffer *fb = state->fb;
|
|
struct drm_crtc_state *crtc_state;
|
|
struct drm_rect clip = { 0, };
|
|
|
|
if (!fb)
|
|
return 0;
|
|
|
|
if (!mtk_fb_get_gem_obj(fb)) {
|
|
DRM_DEBUG_KMS("buffer is null\n");
|
|
return -EFAULT;
|
|
}
|
|
|
|
if (!state->crtc)
|
|
return 0;
|
|
|
|
crtc_state = drm_atomic_get_crtc_state(state->state, state->crtc);
|
|
if (IS_ERR(crtc_state))
|
|
return PTR_ERR(crtc_state);
|
|
|
|
clip.x2 = crtc_state->mode.hdisplay;
|
|
clip.y2 = crtc_state->mode.vdisplay;
|
|
|
|
return drm_plane_helper_check_state(state, &clip,
|
|
DRM_PLANE_HELPER_NO_SCALING,
|
|
DRM_PLANE_HELPER_NO_SCALING,
|
|
true, true);
|
|
}
|
|
|
|
static void mtk_plane_atomic_update(struct drm_plane *plane,
|
|
struct drm_plane_state *old_state)
|
|
{
|
|
struct mtk_plane_state *state = to_mtk_plane_state(plane->state);
|
|
struct drm_crtc *crtc = state->base.crtc;
|
|
struct drm_gem_object *gem;
|
|
struct mtk_drm_gem_obj *mtk_gem;
|
|
struct mtk_drm_plane *mtk_plane = to_mtk_plane(plane);
|
|
|
|
if (!crtc)
|
|
return;
|
|
|
|
gem = mtk_fb_get_gem_obj(state->base.fb);
|
|
mtk_gem = to_mtk_gem_obj(gem);
|
|
mtk_plane_enable(mtk_plane, mtk_gem->dma_addr);
|
|
}
|
|
|
|
static void mtk_plane_atomic_disable(struct drm_plane *plane,
|
|
struct drm_plane_state *old_state)
|
|
{
|
|
struct mtk_plane_state *state = to_mtk_plane_state(plane->state);
|
|
|
|
state->pending.enable = false;
|
|
wmb(); /* Make sure the above parameter is set before update */
|
|
state->pending.dirty = true;
|
|
}
|
|
|
|
static const struct drm_plane_helper_funcs mtk_plane_helper_funcs = {
|
|
.atomic_check = mtk_plane_atomic_check,
|
|
.atomic_update = mtk_plane_atomic_update,
|
|
.atomic_disable = mtk_plane_atomic_disable,
|
|
};
|
|
|
|
int mtk_plane_init(struct drm_device *dev, struct mtk_drm_plane *mtk_plane,
|
|
unsigned long possible_crtcs, enum drm_plane_type type,
|
|
unsigned int zpos)
|
|
{
|
|
int err;
|
|
|
|
err = drm_universal_plane_init(dev, &mtk_plane->base, possible_crtcs,
|
|
&mtk_plane_funcs, formats,
|
|
ARRAY_SIZE(formats), type, NULL);
|
|
if (err) {
|
|
DRM_ERROR("failed to initialize plane\n");
|
|
return err;
|
|
}
|
|
|
|
drm_plane_helper_add(&mtk_plane->base, &mtk_plane_helper_funcs);
|
|
mtk_plane->idx = zpos;
|
|
|
|
return 0;
|
|
}
|