summaryrefslogtreecommitdiffstats
path: root/kernel/drivers/gpu/drm/exynos/exynos7_drm_decon.c
diff options
context:
space:
mode:
authorJosé Pekkarinen <jose.pekkarinen@nokia.com>2016-04-11 10:41:07 +0300
committerJosé Pekkarinen <jose.pekkarinen@nokia.com>2016-04-13 08:17:18 +0300
commite09b41010ba33a20a87472ee821fa407a5b8da36 (patch)
treed10dc367189862e7ca5c592f033dc3726e1df4e3 /kernel/drivers/gpu/drm/exynos/exynos7_drm_decon.c
parentf93b97fd65072de626c074dbe099a1fff05ce060 (diff)
These changes are the raw update to linux-4.4.6-rt14. Kernel sources
are taken from kernel.org, and rt patch from the rt wiki download page. During the rebasing, the following patch collided: Force tick interrupt and get rid of softirq magic(I70131fb85). Collisions have been removed because its logic was found on the source already. Change-Id: I7f57a4081d9deaa0d9ccfc41a6c8daccdee3b769 Signed-off-by: José Pekkarinen <jose.pekkarinen@nokia.com>
Diffstat (limited to 'kernel/drivers/gpu/drm/exynos/exynos7_drm_decon.c')
-rw-r--r--kernel/drivers/gpu/drm/exynos/exynos7_drm_decon.c321
1 files changed, 117 insertions, 204 deletions
diff --git a/kernel/drivers/gpu/drm/exynos/exynos7_drm_decon.c b/kernel/drivers/gpu/drm/exynos/exynos7_drm_decon.c
index 6714e5b19..ead2b16e2 100644
--- a/kernel/drivers/gpu/drm/exynos/exynos7_drm_decon.c
+++ b/kernel/drivers/gpu/drm/exynos/exynos7_drm_decon.c
@@ -37,10 +37,10 @@
* DECON stands for Display and Enhancement controller.
*/
-#define DECON_DEFAULT_FRAMERATE 60
#define MIN_FB_WIDTH_FOR_16WORD_BURST 128
#define WINDOWS_NR 2
+#define CURSOR_WIN 1
struct decon_context {
struct device *dev;
@@ -52,7 +52,6 @@ struct decon_context {
struct clk *eclk;
struct clk *vclk;
void __iomem *regs;
- unsigned int default_win;
unsigned long irq_flags;
bool i80_if;
bool suspended;
@@ -61,7 +60,7 @@ struct decon_context {
atomic_t wait_vsync_event;
struct exynos_drm_panel_info panel;
- struct exynos_drm_display *display;
+ struct drm_encoder *encoder;
};
static const struct of_device_id decon_driver_dt_match[] = {
@@ -70,6 +69,18 @@ static const struct of_device_id decon_driver_dt_match[] = {
};
MODULE_DEVICE_TABLE(of, decon_driver_dt_match);
+static const uint32_t decon_formats[] = {
+ DRM_FORMAT_RGB565,
+ DRM_FORMAT_XRGB8888,
+ DRM_FORMAT_XBGR8888,
+ DRM_FORMAT_RGBX8888,
+ DRM_FORMAT_BGRX8888,
+ DRM_FORMAT_ARGB8888,
+ DRM_FORMAT_ABGR8888,
+ DRM_FORMAT_RGBA8888,
+ DRM_FORMAT_BGRA8888,
+};
+
static void decon_wait_for_vblank(struct exynos_drm_crtc *crtc)
{
struct decon_context *ctx = crtc->ctx;
@@ -89,8 +100,9 @@ static void decon_wait_for_vblank(struct exynos_drm_crtc *crtc)
DRM_DEBUG_KMS("vblank wait timed out.\n");
}
-static void decon_clear_channel(struct decon_context *ctx)
+static void decon_clear_channels(struct exynos_drm_crtc *crtc)
{
+ struct decon_context *ctx = crtc->ctx;
unsigned int win, ch_enabled = 0;
DRM_DEBUG_KMS("%s\n", __FILE__);
@@ -120,34 +132,24 @@ static int decon_ctx_initialize(struct decon_context *ctx,
struct drm_device *drm_dev)
{
struct exynos_drm_private *priv = drm_dev->dev_private;
+ int ret;
ctx->drm_dev = drm_dev;
ctx->pipe = priv->pipe++;
- /* attach this sub driver to iommu mapping if supported. */
- if (is_drm_iommu_supported(ctx->drm_dev)) {
- int ret;
-
- /*
- * If any channel is already active, iommu will throw
- * a PAGE FAULT when enabled. So clear any channel if enabled.
- */
- decon_clear_channel(ctx);
- ret = drm_iommu_attach_device(ctx->drm_dev, ctx->dev);
- if (ret) {
- DRM_ERROR("drm_iommu_attach failed.\n");
- return ret;
- }
- }
+ decon_clear_channels(ctx->crtc);
- return 0;
+ ret = drm_iommu_attach_device(drm_dev, ctx->dev);
+ if (ret)
+ priv->pipe--;
+
+ return ret;
}
static void decon_ctx_remove(struct decon_context *ctx)
{
/* detach this sub driver from iommu mapping if supported. */
- if (is_drm_iommu_supported(ctx->drm_dev))
- drm_iommu_detach_device(ctx->drm_dev, ctx->dev);
+ drm_iommu_detach_device(ctx->drm_dev, ctx->dev);
}
static u32 decon_calc_clkdiv(struct decon_context *ctx,
@@ -162,20 +164,10 @@ static u32 decon_calc_clkdiv(struct decon_context *ctx,
return (clkdiv < 0x100) ? clkdiv : 0xff;
}
-static bool decon_mode_fixup(struct exynos_drm_crtc *crtc,
- const struct drm_display_mode *mode,
- struct drm_display_mode *adjusted_mode)
-{
- if (adjusted_mode->vrefresh == 0)
- adjusted_mode->vrefresh = DECON_DEFAULT_FRAMERATE;
-
- return true;
-}
-
static void decon_commit(struct exynos_drm_crtc *crtc)
{
struct decon_context *ctx = crtc->ctx;
- struct drm_display_mode *mode = &crtc->base.mode;
+ struct drm_display_mode *mode = &crtc->base.state->adjusted_mode;
u32 val, clkdiv;
if (ctx->suspended)
@@ -281,16 +273,16 @@ static void decon_disable_vblank(struct exynos_drm_crtc *crtc)
}
}
-static void decon_win_set_pixfmt(struct decon_context *ctx, unsigned int win)
+static void decon_win_set_pixfmt(struct decon_context *ctx, unsigned int win,
+ struct drm_framebuffer *fb)
{
- struct exynos_drm_plane *plane = &ctx->planes[win];
unsigned long val;
int padding;
val = readl(ctx->regs + WINCON(win));
val &= ~WINCONx_BPPMODE_MASK;
- switch (plane->pixel_format) {
+ switch (fb->pixel_format) {
case DRM_FORMAT_RGB565:
val |= WINCONx_BPPMODE_16BPP_565;
val |= WINCONx_BURSTLEN_16WORD;
@@ -339,7 +331,7 @@ static void decon_win_set_pixfmt(struct decon_context *ctx, unsigned int win)
break;
}
- DRM_DEBUG_KMS("bpp = %d\n", plane->bpp);
+ DRM_DEBUG_KMS("bpp = %d\n", fb->bits_per_pixel);
/*
* In case of exynos, setting dma-burst to 16Word causes permanent
@@ -349,8 +341,8 @@ static void decon_win_set_pixfmt(struct decon_context *ctx, unsigned int win)
* movement causes unstable DMA which results into iommu crash/tear.
*/
- padding = (plane->pitch / (plane->bpp >> 3)) - plane->fb_width;
- if (plane->fb_width + padding < MIN_FB_WIDTH_FOR_16WORD_BURST) {
+ padding = (fb->pitches[0] / (fb->bits_per_pixel >> 3)) - fb->width;
+ if (fb->width + padding < MIN_FB_WIDTH_FOR_16WORD_BURST) {
val &= ~WINCONx_BURSTLEN_MASK;
val |= WINCONx_BURSTLEN_8WORD;
}
@@ -392,29 +384,33 @@ static void decon_shadow_protect_win(struct decon_context *ctx,
writel(val, ctx->regs + SHADOWCON);
}
-static void decon_win_commit(struct exynos_drm_crtc *crtc, unsigned int win)
+static void decon_atomic_begin(struct exynos_drm_crtc *crtc,
+ struct exynos_drm_plane *plane)
{
struct decon_context *ctx = crtc->ctx;
- struct drm_display_mode *mode = &crtc->base.mode;
- struct exynos_drm_plane *plane;
- int padding;
- unsigned long val, alpha;
- unsigned int last_x;
- unsigned int last_y;
if (ctx->suspended)
return;
- if (win < 0 || win >= WINDOWS_NR)
- return;
+ decon_shadow_protect_win(ctx, plane->zpos, true);
+}
- plane = &ctx->planes[win];
+static void decon_update_plane(struct exynos_drm_crtc *crtc,
+ struct exynos_drm_plane *plane)
+{
+ struct decon_context *ctx = crtc->ctx;
+ struct drm_display_mode *mode = &crtc->base.state->adjusted_mode;
+ struct drm_plane_state *state = plane->base.state;
+ int padding;
+ unsigned long val, alpha;
+ unsigned int last_x;
+ unsigned int last_y;
+ unsigned int win = plane->zpos;
+ unsigned int bpp = state->fb->bits_per_pixel >> 3;
+ unsigned int pitch = state->fb->pitches[0];
- /* If suspended, enable this on resume */
- if (ctx->suspended) {
- plane->resume = true;
+ if (ctx->suspended)
return;
- }
/*
* SHADOWCON/PRTCON register is used for enabling timing.
@@ -426,18 +422,15 @@ static void decon_win_commit(struct exynos_drm_crtc *crtc, unsigned int win)
* is set.
*/
- /* protect windows */
- decon_shadow_protect_win(ctx, win, true);
-
/* buffer start address */
val = (unsigned long)plane->dma_addr[0];
writel(val, ctx->regs + VIDW_BUF_START(win));
- padding = (plane->pitch / (plane->bpp >> 3)) - plane->fb_width;
+ padding = (pitch / bpp) - state->fb->width;
/* buffer size */
- writel(plane->fb_width + padding, ctx->regs + VIDW_WHOLE_X(win));
- writel(plane->fb_height, ctx->regs + VIDW_WHOLE_Y(win));
+ writel(state->fb->width + padding, ctx->regs + VIDW_WHOLE_X(win));
+ writel(state->fb->height, ctx->regs + VIDW_WHOLE_Y(win));
/* offset from the start of the buffer to read */
writel(plane->src_x, ctx->regs + VIDW_OFFSET_X(win));
@@ -446,25 +439,25 @@ static void decon_win_commit(struct exynos_drm_crtc *crtc, unsigned int win)
DRM_DEBUG_KMS("start addr = 0x%lx\n",
(unsigned long)val);
DRM_DEBUG_KMS("ovl_width = %d, ovl_height = %d\n",
- plane->crtc_width, plane->crtc_height);
+ plane->crtc_w, plane->crtc_h);
/*
* OSD position.
* In case the window layout goes of LCD layout, DECON fails.
*/
- if ((plane->crtc_x + plane->crtc_width) > mode->hdisplay)
- plane->crtc_x = mode->hdisplay - plane->crtc_width;
- if ((plane->crtc_y + plane->crtc_height) > mode->vdisplay)
- plane->crtc_y = mode->vdisplay - plane->crtc_height;
+ if ((plane->crtc_x + plane->crtc_w) > mode->hdisplay)
+ plane->crtc_x = mode->hdisplay - plane->crtc_w;
+ if ((plane->crtc_y + plane->crtc_h) > mode->vdisplay)
+ plane->crtc_y = mode->vdisplay - plane->crtc_h;
val = VIDOSDxA_TOPLEFT_X(plane->crtc_x) |
VIDOSDxA_TOPLEFT_Y(plane->crtc_y);
writel(val, ctx->regs + VIDOSD_A(win));
- last_x = plane->crtc_x + plane->crtc_width;
+ last_x = plane->crtc_x + plane->crtc_w;
if (last_x)
last_x--;
- last_y = plane->crtc_y + plane->crtc_height;
+ last_y = plane->crtc_y + plane->crtc_h;
if (last_y)
last_y--;
@@ -488,7 +481,7 @@ static void decon_win_commit(struct exynos_drm_crtc *crtc, unsigned int win)
writel(alpha, ctx->regs + VIDOSD_D(win));
- decon_win_set_pixfmt(ctx, win);
+ decon_win_set_pixfmt(ctx, win, state->fb);
/* hardware window 0 doesn't support color key. */
if (win != 0)
@@ -506,26 +499,17 @@ static void decon_win_commit(struct exynos_drm_crtc *crtc, unsigned int win)
val = readl(ctx->regs + DECON_UPDATE);
val |= DECON_UPDATE_STANDALONE_F;
writel(val, ctx->regs + DECON_UPDATE);
-
- plane->enabled = true;
}
-static void decon_win_disable(struct exynos_drm_crtc *crtc, unsigned int win)
+static void decon_disable_plane(struct exynos_drm_crtc *crtc,
+ struct exynos_drm_plane *plane)
{
struct decon_context *ctx = crtc->ctx;
- struct exynos_drm_plane *plane;
+ unsigned int win = plane->zpos;
u32 val;
- if (win < 0 || win >= WINDOWS_NR)
- return;
-
- plane = &ctx->planes[win];
-
- if (ctx->suspended) {
- /* do not resume this window*/
- plane->resume = false;
+ if (ctx->suspended)
return;
- }
/* protect windows */
decon_shadow_protect_win(ctx, win, true);
@@ -535,55 +519,20 @@ static void decon_win_disable(struct exynos_drm_crtc *crtc, unsigned int win)
val &= ~WINCONx_ENWIN;
writel(val, ctx->regs + WINCON(win));
- /* unprotect windows */
- decon_shadow_protect_win(ctx, win, false);
-
val = readl(ctx->regs + DECON_UPDATE);
val |= DECON_UPDATE_STANDALONE_F;
writel(val, ctx->regs + DECON_UPDATE);
-
- plane->enabled = false;
-}
-
-static void decon_window_suspend(struct decon_context *ctx)
-{
- struct exynos_drm_plane *plane;
- int i;
-
- for (i = 0; i < WINDOWS_NR; i++) {
- plane = &ctx->planes[i];
- plane->resume = plane->enabled;
- if (plane->enabled)
- decon_win_disable(ctx->crtc, i);
- }
}
-static void decon_window_resume(struct decon_context *ctx)
+static void decon_atomic_flush(struct exynos_drm_crtc *crtc,
+ struct exynos_drm_plane *plane)
{
- struct exynos_drm_plane *plane;
- int i;
-
- for (i = 0; i < WINDOWS_NR; i++) {
- plane = &ctx->planes[i];
- plane->enabled = plane->resume;
- plane->resume = false;
- }
-}
-
-static void decon_apply(struct decon_context *ctx)
-{
- struct exynos_drm_plane *plane;
- int i;
+ struct decon_context *ctx = crtc->ctx;
- for (i = 0; i < WINDOWS_NR; i++) {
- plane = &ctx->planes[i];
- if (plane->enabled)
- decon_win_commit(ctx->crtc, i);
- else
- decon_win_disable(ctx->crtc, i);
- }
+ if (ctx->suspended)
+ return;
- decon_commit(ctx->crtc);
+ decon_shadow_protect_win(ctx, plane->zpos, false);
}
static void decon_init(struct decon_context *ctx)
@@ -603,12 +552,13 @@ static void decon_init(struct decon_context *ctx)
writel(VIDCON1_VCLK_HOLD, ctx->regs + VIDCON1(0));
}
-static int decon_poweron(struct decon_context *ctx)
+static void decon_enable(struct exynos_drm_crtc *crtc)
{
+ struct decon_context *ctx = crtc->ctx;
int ret;
if (!ctx->suspended)
- return 0;
+ return;
ctx->suspended = false;
@@ -617,68 +567,51 @@ static int decon_poweron(struct decon_context *ctx)
ret = clk_prepare_enable(ctx->pclk);
if (ret < 0) {
DRM_ERROR("Failed to prepare_enable the pclk [%d]\n", ret);
- goto pclk_err;
+ return;
}
ret = clk_prepare_enable(ctx->aclk);
if (ret < 0) {
DRM_ERROR("Failed to prepare_enable the aclk [%d]\n", ret);
- goto aclk_err;
+ return;
}
ret = clk_prepare_enable(ctx->eclk);
if (ret < 0) {
DRM_ERROR("Failed to prepare_enable the eclk [%d]\n", ret);
- goto eclk_err;
+ return;
}
ret = clk_prepare_enable(ctx->vclk);
if (ret < 0) {
DRM_ERROR("Failed to prepare_enable the vclk [%d]\n", ret);
- goto vclk_err;
+ return;
}
decon_init(ctx);
/* if vblank was enabled status, enable it again. */
- if (test_and_clear_bit(0, &ctx->irq_flags)) {
- ret = decon_enable_vblank(ctx->crtc);
- if (ret) {
- DRM_ERROR("Failed to re-enable vblank [%d]\n", ret);
- goto err;
- }
- }
-
- decon_window_resume(ctx);
-
- decon_apply(ctx);
+ if (test_and_clear_bit(0, &ctx->irq_flags))
+ decon_enable_vblank(ctx->crtc);
- return 0;
-
-err:
- clk_disable_unprepare(ctx->vclk);
-vclk_err:
- clk_disable_unprepare(ctx->eclk);
-eclk_err:
- clk_disable_unprepare(ctx->aclk);
-aclk_err:
- clk_disable_unprepare(ctx->pclk);
-pclk_err:
- ctx->suspended = true;
- return ret;
+ decon_commit(ctx->crtc);
}
-static int decon_poweroff(struct decon_context *ctx)
+static void decon_disable(struct exynos_drm_crtc *crtc)
{
+ struct decon_context *ctx = crtc->ctx;
+ int i;
+
if (ctx->suspended)
- return 0;
+ return;
/*
* We need to make sure that all windows are disabled before we
* suspend that connector. Otherwise we might try to scan from
* a destroyed buffer later.
*/
- decon_window_suspend(ctx);
+ for (i = 0; i < WINDOWS_NR; i++)
+ decon_disable_plane(crtc, &ctx->planes[i]);
clk_disable_unprepare(ctx->vclk);
clk_disable_unprepare(ctx->eclk);
@@ -688,37 +621,19 @@ static int decon_poweroff(struct decon_context *ctx)
pm_runtime_put_sync(ctx->dev);
ctx->suspended = true;
- return 0;
-}
-
-static void decon_dpms(struct exynos_drm_crtc *crtc, int mode)
-{
- DRM_DEBUG_KMS("%s, %d\n", __FILE__, mode);
-
- switch (mode) {
- case DRM_MODE_DPMS_ON:
- decon_poweron(crtc->ctx);
- break;
- case DRM_MODE_DPMS_STANDBY:
- case DRM_MODE_DPMS_SUSPEND:
- case DRM_MODE_DPMS_OFF:
- decon_poweroff(crtc->ctx);
- break;
- default:
- DRM_DEBUG_KMS("unspecified mode %d\n", mode);
- break;
- }
}
static const struct exynos_drm_crtc_ops decon_crtc_ops = {
- .dpms = decon_dpms,
- .mode_fixup = decon_mode_fixup,
+ .enable = decon_enable,
+ .disable = decon_disable,
.commit = decon_commit,
.enable_vblank = decon_enable_vblank,
.disable_vblank = decon_disable_vblank,
.wait_for_vblank = decon_wait_for_vblank,
- .win_commit = decon_win_commit,
- .win_disable = decon_win_disable,
+ .atomic_begin = decon_atomic_begin,
+ .update_plane = decon_update_plane,
+ .disable_plane = decon_disable_plane,
+ .atomic_flush = decon_atomic_flush,
};
@@ -726,6 +641,7 @@ static irqreturn_t decon_irq_handler(int irq, void *dev_id)
{
struct decon_context *ctx = (struct decon_context *)dev_id;
u32 val, clear_bit;
+ int win;
val = readl(ctx->regs + VIDINTCON1);
@@ -738,8 +654,15 @@ static irqreturn_t decon_irq_handler(int irq, void *dev_id)
goto out;
if (!ctx->i80_if) {
- drm_handle_vblank(ctx->drm_dev, ctx->pipe);
- exynos_drm_crtc_finish_pageflip(ctx->drm_dev, ctx->pipe);
+ drm_crtc_handle_vblank(&ctx->crtc->base);
+ for (win = 0 ; win < WINDOWS_NR ; win++) {
+ struct exynos_drm_plane *plane = &ctx->planes[win];
+
+ if (!plane->pending_fb)
+ continue;
+
+ exynos_drm_crtc_finish_update(ctx->crtc, plane);
+ }
/* set wait vsync event to zero and wake up queue. */
if (atomic_read(&ctx->wait_vsync_event)) {
@@ -767,15 +690,15 @@ static int decon_bind(struct device *dev, struct device *master, void *data)
}
for (zpos = 0; zpos < WINDOWS_NR; zpos++) {
- type = (zpos == ctx->default_win) ? DRM_PLANE_TYPE_PRIMARY :
- DRM_PLANE_TYPE_OVERLAY;
+ type = exynos_plane_get_type(zpos, CURSOR_WIN);
ret = exynos_plane_init(drm_dev, &ctx->planes[zpos],
- 1 << ctx->pipe, type, zpos);
+ 1 << ctx->pipe, type, decon_formats,
+ ARRAY_SIZE(decon_formats), zpos);
if (ret)
return ret;
}
- exynos_plane = &ctx->planes[ctx->default_win];
+ exynos_plane = &ctx->planes[DEFAULT_WIN];
ctx->crtc = exynos_drm_crtc_create(drm_dev, &exynos_plane->base,
ctx->pipe, EXYNOS_DISPLAY_TYPE_LCD,
&decon_crtc_ops, ctx);
@@ -784,8 +707,8 @@ static int decon_bind(struct device *dev, struct device *master, void *data)
return PTR_ERR(ctx->crtc);
}
- if (ctx->display)
- exynos_drm_create_enc_conn(drm_dev, ctx->display);
+ if (ctx->encoder)
+ exynos_dpi_bind(drm_dev, ctx->encoder);
return 0;
@@ -796,10 +719,10 @@ static void decon_unbind(struct device *dev, struct device *master,
{
struct decon_context *ctx = dev_get_drvdata(dev);
- decon_dpms(ctx->crtc, DRM_MODE_DPMS_OFF);
+ decon_disable(ctx->crtc);
- if (ctx->display)
- exynos_dpi_remove(ctx->display);
+ if (ctx->encoder)
+ exynos_dpi_remove(ctx->encoder);
decon_ctx_remove(ctx);
}
@@ -824,11 +747,6 @@ static int decon_probe(struct platform_device *pdev)
if (!ctx)
return -ENOMEM;
- ret = exynos_drm_component_add(dev, EXYNOS_DEVICE_TYPE_CRTC,
- EXYNOS_DISPLAY_TYPE_LCD);
- if (ret)
- return ret;
-
ctx->dev = dev;
ctx->suspended = true;
@@ -838,10 +756,8 @@ static int decon_probe(struct platform_device *pdev)
of_node_put(i80_if_timings);
ctx->regs = of_iomap(dev->of_node, 0);
- if (!ctx->regs) {
- ret = -ENOMEM;
- goto err_del_component;
- }
+ if (!ctx->regs)
+ return -ENOMEM;
ctx->pclk = devm_clk_get(dev, "pclk_decon0");
if (IS_ERR(ctx->pclk)) {
@@ -891,9 +807,9 @@ static int decon_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, ctx);
- ctx->display = exynos_dpi_probe(dev);
- if (IS_ERR(ctx->display)) {
- ret = PTR_ERR(ctx->display);
+ ctx->encoder = exynos_dpi_probe(dev);
+ if (IS_ERR(ctx->encoder)) {
+ ret = PTR_ERR(ctx->encoder);
goto err_iounmap;
}
@@ -911,8 +827,6 @@ err_disable_pm_runtime:
err_iounmap:
iounmap(ctx->regs);
-err_del_component:
- exynos_drm_component_del(dev, EXYNOS_DEVICE_TYPE_CRTC);
return ret;
}
@@ -925,7 +839,6 @@ static int decon_remove(struct platform_device *pdev)
iounmap(ctx->regs);
component_del(&pdev->dev, &decon_component_ops);
- exynos_drm_component_del(&pdev->dev, EXYNOS_DEVICE_TYPE_CRTC);
return 0;
}