summaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/exynos
diff options
context:
space:
mode:
authorMauro Carvalho Chehab <mchehab@s-opensource.com>2017-03-06 10:49:34 +0100
committerMauro Carvalho Chehab <mchehab@s-opensource.com>2017-03-06 10:49:34 +0100
commit700ea5e0e0dd70420a04e703ff264cc133834cba (patch)
treed217b0d90d014953ea10ab7d88809660d2da8a64 /drivers/gpu/drm/exynos
parent[media] media: ti-vpe: vpe: allow use of user specified stride (diff)
parentLinux 4.11-rc1 (diff)
downloadlinux-700ea5e0e0dd70420a04e703ff264cc133834cba.tar.xz
linux-700ea5e0e0dd70420a04e703ff264cc133834cba.zip
Merge tag 'v4.11-rc1' into patchwork
Linux 4.11-rc1 * tag 'v4.11-rc1': (10730 commits) Linux 4.11-rc1 strparser: destroy workqueue on module exit Documentation/sphinx: fix primary_domain configuration docs: Fix htmldocs build failure doc/ko_KR/memory-barriers: Update control-dependencies section pcieaer doc: update the link Documentation: Update path to sysrq.txt sfc: fix IPID endianness in TSOv2 sfc: avoid max() in array size rds: remove unnecessary returned value check rxrpc: Fix potential NULL-pointer exception nfp: correct DMA direction in XDP DMA sync nfp: don't tell FW about the reserved buffer space net: ethernet: bgmac: mac address change bug net: ethernet: bgmac: init sequence bug xen-netback: don't vfree() queues under spinlock xen-netback: keep a local pointer for vif in backend_disconnect() netfilter: nf_tables: don't call nfnetlink_set_err() if nfnetlink_send() fails netfilter: nft_set_rbtree: incorrect assumption on lower interval lookups netfilter: nf_conntrack_sip: fix wrong memory initialisation ...
Diffstat (limited to 'drivers/gpu/drm/exynos')
-rw-r--r--drivers/gpu/drm/exynos/Kconfig2
-rw-r--r--drivers/gpu/drm/exynos/exynos5433_drm_decon.c100
-rw-r--r--drivers/gpu/drm/exynos/exynos7_drm_decon.c8
-rw-r--r--drivers/gpu/drm/exynos/exynos_dp.c5
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_crtc.c34
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_crtc.h4
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_drv.c118
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_drv.h10
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_dsi.c6
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_fb.c34
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_fbdev.c15
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_fimd.c6
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_g2d.c19
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_gem.c3
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_gem.h2
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_mic.c126
-rw-r--r--drivers/gpu/drm/exynos/exynos_hdmi.c80
-rw-r--r--drivers/gpu/drm/exynos/exynos_mixer.c14
18 files changed, 296 insertions, 290 deletions
diff --git a/drivers/gpu/drm/exynos/Kconfig b/drivers/gpu/drm/exynos/Kconfig
index d706ca4e2f02..1d185347c64c 100644
--- a/drivers/gpu/drm/exynos/Kconfig
+++ b/drivers/gpu/drm/exynos/Kconfig
@@ -19,7 +19,6 @@ comment "CRTCs"
config DRM_EXYNOS_FIMD
bool "FIMD"
depends on !FB_S3C
- select FB_MODE_HELPERS
select MFD_SYSCON
help
Choose this option if you want to use Exynos FIMD for DRM.
@@ -32,7 +31,6 @@ config DRM_EXYNOS5433_DECON
config DRM_EXYNOS7_DECON
bool "DECON on Exynos7"
depends on !FB_S3C
- select FB_MODE_HELPERS
help
Choose this option if you want to use Exynos DECON for DRM.
diff --git a/drivers/gpu/drm/exynos/exynos5433_drm_decon.c b/drivers/gpu/drm/exynos/exynos5433_drm_decon.c
index 75eeb831ed6a..0fd6f7a18364 100644
--- a/drivers/gpu/drm/exynos/exynos5433_drm_decon.c
+++ b/drivers/gpu/drm/exynos/exynos5433_drm_decon.c
@@ -13,9 +13,11 @@
#include <linux/platform_device.h>
#include <linux/clk.h>
#include <linux/component.h>
+#include <linux/mfd/syscon.h>
#include <linux/of_device.h>
#include <linux/of_gpio.h>
#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
#include <video/exynos5433_decon.h>
@@ -25,6 +27,9 @@
#include "exynos_drm_plane.h"
#include "exynos_drm_iommu.h"
+#define DSD_CFG_MUX 0x1004
+#define DSD_CFG_MUX_TE_UNMASK_GLOBAL BIT(13)
+
#define WINDOWS_NR 3
#define MIN_FB_WIDTH_FOR_16WORD_BURST 128
@@ -57,6 +62,7 @@ struct decon_context {
struct exynos_drm_plane planes[WINDOWS_NR];
struct exynos_drm_plane_config configs[WINDOWS_NR];
void __iomem *addr;
+ struct regmap *sysreg;
struct clk *clks[ARRAY_SIZE(decon_clks_name)];
int pipe;
unsigned long flags;
@@ -118,18 +124,29 @@ static void decon_disable_vblank(struct exynos_drm_crtc *crtc)
static void decon_setup_trigger(struct decon_context *ctx)
{
- u32 val = !(ctx->out_type & I80_HW_TRG)
- ? TRIGCON_TRIGEN_PER_F | TRIGCON_TRIGEN_F |
- TRIGCON_TE_AUTO_MASK | TRIGCON_SWTRIGEN
- : TRIGCON_TRIGEN_PER_F | TRIGCON_TRIGEN_F |
- TRIGCON_HWTRIGMASK | TRIGCON_HWTRIGEN;
- writel(val, ctx->addr + DECON_TRIGCON);
+ if (!(ctx->out_type & (IFTYPE_I80 | I80_HW_TRG)))
+ return;
+
+ if (!(ctx->out_type & I80_HW_TRG)) {
+ writel(TRIGCON_TE_AUTO_MASK | TRIGCON_SWTRIGEN
+ | TRIGCON_TE_AUTO_MASK | TRIGCON_SWTRIGEN,
+ ctx->addr + DECON_TRIGCON);
+ return;
+ }
+
+ writel(TRIGCON_TRIGEN_PER_F | TRIGCON_TRIGEN_F | TRIGCON_HWTRIGMASK
+ | TRIGCON_HWTRIGEN, ctx->addr + DECON_TRIGCON);
+
+ if (regmap_update_bits(ctx->sysreg, DSD_CFG_MUX,
+ DSD_CFG_MUX_TE_UNMASK_GLOBAL, ~0))
+ DRM_ERROR("Cannot update sysreg.\n");
}
static void decon_commit(struct exynos_drm_crtc *crtc)
{
struct decon_context *ctx = crtc->ctx;
struct drm_display_mode *m = &crtc->base.mode;
+ bool interlaced = false;
u32 val;
if (test_bit(BIT_SUSPENDED, &ctx->flags))
@@ -140,13 +157,16 @@ static void decon_commit(struct exynos_drm_crtc *crtc)
m->crtc_hsync_end = m->crtc_htotal - 92;
m->crtc_vsync_start = m->crtc_vdisplay + 1;
m->crtc_vsync_end = m->crtc_vsync_start + 1;
+ if (m->flags & DRM_MODE_FLAG_INTERLACE)
+ interlaced = true;
}
- if (ctx->out_type & (IFTYPE_I80 | I80_HW_TRG))
- decon_setup_trigger(ctx);
+ decon_setup_trigger(ctx);
/* lcd on and use command if */
val = VIDOUT_LCD_ON;
+ if (interlaced)
+ val |= VIDOUT_INTERLACE_EN_F;
if (ctx->out_type & IFTYPE_I80) {
val |= VIDOUT_COMMAND_IF;
} else {
@@ -155,15 +175,21 @@ static void decon_commit(struct exynos_drm_crtc *crtc)
writel(val, ctx->addr + DECON_VIDOUTCON0);
- val = VIDTCON2_LINEVAL(m->vdisplay - 1) |
- VIDTCON2_HOZVAL(m->hdisplay - 1);
+ if (interlaced)
+ val = VIDTCON2_LINEVAL(m->vdisplay / 2 - 1) |
+ VIDTCON2_HOZVAL(m->hdisplay - 1);
+ else
+ val = VIDTCON2_LINEVAL(m->vdisplay - 1) |
+ VIDTCON2_HOZVAL(m->hdisplay - 1);
writel(val, ctx->addr + DECON_VIDTCON2);
if (!(ctx->out_type & IFTYPE_I80)) {
- val = VIDTCON00_VBPD_F(
- m->crtc_vtotal - m->crtc_vsync_end - 1) |
- VIDTCON00_VFPD_F(
- m->crtc_vsync_start - m->crtc_vdisplay - 1);
+ int vbp = m->crtc_vtotal - m->crtc_vsync_end;
+ int vfp = m->crtc_vsync_start - m->crtc_vdisplay;
+
+ if (interlaced)
+ vbp = vbp / 2 - 1;
+ val = VIDTCON00_VBPD_F(vbp - 1) | VIDTCON00_VFPD_F(vfp - 1);
writel(val, ctx->addr + DECON_VIDTCON00);
val = VIDTCON01_VSPW_F(
@@ -195,7 +221,7 @@ static void decon_win_set_pixfmt(struct decon_context *ctx, unsigned int win,
val = readl(ctx->addr + DECON_WINCONx(win));
val &= ~WINCONx_BPPMODE_MASK;
- switch (fb->pixel_format) {
+ switch (fb->format->format) {
case DRM_FORMAT_XRGB1555:
val |= WINCONx_BPPMODE_16BPP_I1555;
val |= WINCONx_HAWSWP_F;
@@ -221,7 +247,7 @@ static void decon_win_set_pixfmt(struct decon_context *ctx, unsigned int win,
return;
}
- DRM_DEBUG_KMS("bpp = %u\n", fb->bits_per_pixel);
+ DRM_DEBUG_KMS("bpp = %u\n", fb->format->cpp[0] * 8);
/*
* In case of exynos, setting dma-burst to 16Word causes permanent
@@ -270,7 +296,7 @@ static void decon_update_plane(struct exynos_drm_crtc *crtc,
struct decon_context *ctx = crtc->ctx;
struct drm_framebuffer *fb = state->base.fb;
unsigned int win = plane->index;
- unsigned int bpp = fb->bits_per_pixel >> 3;
+ unsigned int bpp = fb->format->cpp[0];
unsigned int pitch = fb->pitches[0];
dma_addr_t dma_addr = exynos_drm_fb_dma_addr(fb, 0);
u32 val;
@@ -278,12 +304,22 @@ static void decon_update_plane(struct exynos_drm_crtc *crtc,
if (test_bit(BIT_SUSPENDED, &ctx->flags))
return;
- val = COORDINATE_X(state->crtc.x) | COORDINATE_Y(state->crtc.y);
- writel(val, ctx->addr + DECON_VIDOSDxA(win));
+ if (crtc->base.mode.flags & DRM_MODE_FLAG_INTERLACE) {
+ val = COORDINATE_X(state->crtc.x) |
+ COORDINATE_Y(state->crtc.y / 2);
+ writel(val, ctx->addr + DECON_VIDOSDxA(win));
+
+ val = COORDINATE_X(state->crtc.x + state->crtc.w - 1) |
+ COORDINATE_Y((state->crtc.y + state->crtc.h) / 2 - 1);
+ writel(val, ctx->addr + DECON_VIDOSDxB(win));
+ } else {
+ val = COORDINATE_X(state->crtc.x) | COORDINATE_Y(state->crtc.y);
+ writel(val, ctx->addr + DECON_VIDOSDxA(win));
- val = COORDINATE_X(state->crtc.x + state->crtc.w - 1) |
- COORDINATE_Y(state->crtc.y + state->crtc.h - 1);
- writel(val, ctx->addr + DECON_VIDOSDxB(win));
+ val = COORDINATE_X(state->crtc.x + state->crtc.w - 1) |
+ COORDINATE_Y(state->crtc.y + state->crtc.h - 1);
+ writel(val, ctx->addr + DECON_VIDOSDxB(win));
+ }
val = VIDOSD_Wx_ALPHA_R_F(0x0) | VIDOSD_Wx_ALPHA_G_F(0x0) |
VIDOSD_Wx_ALPHA_B_F(0x0);
@@ -355,8 +391,6 @@ static void decon_swreset(struct decon_context *ctx)
udelay(10);
}
- WARN(tries == 0, "failed to disable DECON\n");
-
writel(VIDCON0_SWRESET, ctx->addr + DECON_VIDCON0);
for (tries = 2000; tries; --tries) {
if (~readl(ctx->addr + DECON_VIDCON0) & VIDCON0_SWRESET)
@@ -467,7 +501,7 @@ err:
clk_disable_unprepare(ctx->clks[i]);
}
-static struct exynos_drm_crtc_ops decon_crtc_ops = {
+static const struct exynos_drm_crtc_ops decon_crtc_ops = {
.enable = decon_enable,
.disable = decon_disable,
.enable_vblank = decon_enable_vblank,
@@ -557,6 +591,13 @@ static irqreturn_t decon_irq_handler(int irq, void *dev_id)
if (val) {
writel(val, ctx->addr + DECON_VIDINTCON1);
+ if (ctx->out_type & IFTYPE_HDMI) {
+ val = readl(ctx->addr + DECON_VIDOUTCON0);
+ val &= VIDOUT_INTERLACE_EN_F | VIDOUT_INTERLACE_FIELD_F;
+ if (val ==
+ (VIDOUT_INTERLACE_EN_F | VIDOUT_INTERLACE_FIELD_F))
+ return IRQ_HANDLED;
+ }
drm_crtc_handle_vblank(&ctx->crtc->base);
}
@@ -637,6 +678,15 @@ static int exynos5433_decon_probe(struct platform_device *pdev)
ctx->out_type |= IFTYPE_I80;
}
+ if (ctx->out_type | I80_HW_TRG) {
+ ctx->sysreg = syscon_regmap_lookup_by_phandle(dev->of_node,
+ "samsung,disp-sysreg");
+ if (IS_ERR(ctx->sysreg)) {
+ dev_err(dev, "failed to get system register\n");
+ return PTR_ERR(ctx->sysreg);
+ }
+ }
+
for (i = 0; i < ARRAY_SIZE(decon_clks_name); i++) {
struct clk *clk;
diff --git a/drivers/gpu/drm/exynos/exynos7_drm_decon.c b/drivers/gpu/drm/exynos/exynos7_drm_decon.c
index f4d5a2133777..f9ab19e205e2 100644
--- a/drivers/gpu/drm/exynos/exynos7_drm_decon.c
+++ b/drivers/gpu/drm/exynos/exynos7_drm_decon.c
@@ -281,7 +281,7 @@ static void decon_win_set_pixfmt(struct decon_context *ctx, unsigned int win,
val = readl(ctx->regs + WINCON(win));
val &= ~WINCONx_BPPMODE_MASK;
- switch (fb->pixel_format) {
+ switch (fb->format->format) {
case DRM_FORMAT_RGB565:
val |= WINCONx_BPPMODE_16BPP_565;
val |= WINCONx_BURSTLEN_16WORD;
@@ -330,7 +330,7 @@ static void decon_win_set_pixfmt(struct decon_context *ctx, unsigned int win,
break;
}
- DRM_DEBUG_KMS("bpp = %d\n", fb->bits_per_pixel);
+ DRM_DEBUG_KMS("bpp = %d\n", fb->format->cpp[0] * 8);
/*
* In case of exynos, setting dma-burst to 16Word causes permanent
@@ -340,7 +340,7 @@ static void decon_win_set_pixfmt(struct decon_context *ctx, unsigned int win,
* movement causes unstable DMA which results into iommu crash/tear.
*/
- padding = (fb->pitches[0] / (fb->bits_per_pixel >> 3)) - fb->width;
+ padding = (fb->pitches[0] / fb->format->cpp[0]) - fb->width;
if (fb->width + padding < MIN_FB_WIDTH_FOR_16WORD_BURST) {
val &= ~WINCONx_BURSTLEN_MASK;
val |= WINCONx_BURSTLEN_8WORD;
@@ -407,7 +407,7 @@ static void decon_update_plane(struct exynos_drm_crtc *crtc,
unsigned int last_x;
unsigned int last_y;
unsigned int win = plane->index;
- unsigned int bpp = fb->bits_per_pixel >> 3;
+ unsigned int bpp = fb->format->cpp[0];
unsigned int pitch = fb->pitches[0];
if (ctx->suspended)
diff --git a/drivers/gpu/drm/exynos/exynos_dp.c b/drivers/gpu/drm/exynos/exynos_dp.c
index 528229faffe4..1ef0be338b85 100644
--- a/drivers/gpu/drm/exynos/exynos_dp.c
+++ b/drivers/gpu/drm/exynos/exynos_dp.c
@@ -99,7 +99,6 @@ static int exynos_dp_bridge_attach(struct analogix_dp_plat_data *plat_data,
struct drm_connector *connector)
{
struct exynos_dp_device *dp = to_dp(plat_data);
- struct drm_encoder *encoder = &dp->encoder;
int ret;
drm_connector_register(connector);
@@ -107,9 +106,7 @@ static int exynos_dp_bridge_attach(struct analogix_dp_plat_data *plat_data,
/* Pre-empt DP connector creation if there's a bridge */
if (dp->ptn_bridge) {
- bridge->next = dp->ptn_bridge;
- dp->ptn_bridge->encoder = encoder;
- ret = drm_bridge_attach(encoder->dev, dp->ptn_bridge);
+ ret = drm_bridge_attach(&dp->encoder, dp->ptn_bridge, bridge);
if (ret) {
DRM_ERROR("Failed to attach bridge to drm\n");
bridge->next = NULL;
diff --git a/drivers/gpu/drm/exynos/exynos_drm_crtc.c b/drivers/gpu/drm/exynos/exynos_drm_crtc.c
index 2530bf57716a..5367b6664fe3 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_crtc.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_crtc.c
@@ -39,6 +39,14 @@ static void exynos_drm_crtc_disable(struct drm_crtc *crtc)
if (exynos_crtc->ops->disable)
exynos_crtc->ops->disable(exynos_crtc);
+
+ if (crtc->state->event && !crtc->state->active) {
+ spin_lock_irq(&crtc->dev->event_lock);
+ drm_crtc_send_vblank_event(crtc, crtc->state->event);
+ spin_unlock_irq(&crtc->dev->event_lock);
+
+ crtc->state->event = NULL;
+ }
}
static void
@@ -109,9 +117,6 @@ static const struct drm_crtc_helper_funcs exynos_crtc_helper_funcs = {
static void exynos_drm_crtc_destroy(struct drm_crtc *crtc)
{
struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc);
- struct exynos_drm_private *private = crtc->dev->dev_private;
-
- private->crtc[exynos_crtc->pipe] = NULL;
drm_crtc_cleanup(crtc);
kfree(exynos_crtc);
@@ -134,7 +139,6 @@ struct exynos_drm_crtc *exynos_drm_crtc_create(struct drm_device *drm_dev,
void *ctx)
{
struct exynos_drm_crtc *exynos_crtc;
- struct exynos_drm_private *private = drm_dev->dev_private;
struct drm_crtc *crtc;
int ret;
@@ -149,8 +153,6 @@ struct exynos_drm_crtc *exynos_drm_crtc_create(struct drm_device *drm_dev,
crtc = &exynos_crtc->base;
- private->crtc[pipe] = crtc;
-
ret = drm_crtc_init_with_planes(drm_dev, crtc, plane, NULL,
&exynos_crtc_funcs, NULL);
if (ret < 0)
@@ -209,23 +211,3 @@ void exynos_drm_crtc_te_handler(struct drm_crtc *crtc)
if (exynos_crtc->ops->te_handler)
exynos_crtc->ops->te_handler(exynos_crtc);
}
-
-void exynos_drm_crtc_cancel_page_flip(struct drm_crtc *crtc,
- struct drm_file *file)
-{
- struct drm_pending_vblank_event *e;
- unsigned long flags;
-
- spin_lock_irqsave(&crtc->dev->event_lock, flags);
-
- e = crtc->state->event;
- if (e && e->base.file_priv == file)
- crtc->state->event = NULL;
- else
- e = NULL;
-
- spin_unlock_irqrestore(&crtc->dev->event_lock, flags);
-
- if (e)
- drm_event_cancel_free(crtc->dev, &e->base);
-}
diff --git a/drivers/gpu/drm/exynos/exynos_drm_crtc.h b/drivers/gpu/drm/exynos/exynos_drm_crtc.h
index cfdcf3e4eb1b..6a581a8af465 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_crtc.h
+++ b/drivers/gpu/drm/exynos/exynos_drm_crtc.h
@@ -40,8 +40,4 @@ int exynos_drm_crtc_get_pipe_from_type(struct drm_device *drm_dev,
*/
void exynos_drm_crtc_te_handler(struct drm_crtc *crtc);
-/* This function cancels a page flip request. */
-void exynos_drm_crtc_cancel_page_flip(struct drm_crtc *crtc,
- struct drm_file *file);
-
#endif
diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.c b/drivers/gpu/drm/exynos/exynos_drm_drv.c
index 739180ac3da5..035d02ecffcd 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_drv.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_drv.c
@@ -38,56 +38,6 @@
#define DRIVER_MAJOR 1
#define DRIVER_MINOR 0
-struct exynos_atomic_commit {
- struct work_struct work;
- struct drm_device *dev;
- struct drm_atomic_state *state;
- u32 crtcs;
-};
-
-static void exynos_atomic_commit_complete(struct exynos_atomic_commit *commit)
-{
- struct drm_device *dev = commit->dev;
- struct exynos_drm_private *priv = dev->dev_private;
- struct drm_atomic_state *state = commit->state;
-
- drm_atomic_helper_commit_modeset_disables(dev, state);
-
- drm_atomic_helper_commit_modeset_enables(dev, state);
-
- /*
- * Exynos can't update planes with CRTCs and encoders disabled,
- * its updates routines, specially for FIMD, requires the clocks
- * to be enabled. So it is necessary to handle the modeset operations
- * *before* the commit_planes() step, this way it will always
- * have the relevant clocks enabled to perform the update.
- */
-
- drm_atomic_helper_commit_planes(dev, state, 0);
-
- drm_atomic_helper_wait_for_vblanks(dev, state);
-
- drm_atomic_helper_cleanup_planes(dev, state);
-
- drm_atomic_state_put(state);
-
- spin_lock(&priv->lock);
- priv->pending &= ~commit->crtcs;
- spin_unlock(&priv->lock);
-
- wake_up_all(&priv->wait);
-
- kfree(commit);
-}
-
-static void exynos_drm_atomic_work(struct work_struct *work)
-{
- struct exynos_atomic_commit *commit = container_of(work,
- struct exynos_atomic_commit, work);
-
- exynos_atomic_commit_complete(commit);
-}
-
static struct device *exynos_drm_get_dma_device(void);
static int exynos_drm_load(struct drm_device *dev, unsigned long flags)
@@ -186,7 +136,7 @@ err_free_private:
return ret;
}
-static int exynos_drm_unload(struct drm_device *dev)
+static void exynos_drm_unload(struct drm_device *dev)
{
exynos_drm_device_subdrv_remove(dev);
@@ -200,67 +150,6 @@ static int exynos_drm_unload(struct drm_device *dev)
kfree(dev->dev_private);
dev->dev_private = NULL;
-
- return 0;
-}
-
-static int commit_is_pending(struct exynos_drm_private *priv, u32 crtcs)
-{
- bool pending;
-
- spin_lock(&priv->lock);
- pending = priv->pending & crtcs;
- spin_unlock(&priv->lock);
-
- return pending;
-}
-
-int exynos_atomic_commit(struct drm_device *dev, struct drm_atomic_state *state,
- bool nonblock)
-{
- struct exynos_drm_private *priv = dev->dev_private;
- struct exynos_atomic_commit *commit;
- struct drm_crtc *crtc;
- struct drm_crtc_state *crtc_state;
- int i, ret;
-
- commit = kzalloc(sizeof(*commit), GFP_KERNEL);
- if (!commit)
- return -ENOMEM;
-
- ret = drm_atomic_helper_prepare_planes(dev, state);
- if (ret) {
- kfree(commit);
- return ret;
- }
-
- /* This is the point of no return */
-
- INIT_WORK(&commit->work, exynos_drm_atomic_work);
- commit->dev = dev;
- commit->state = state;
-
- /* Wait until all affected CRTCs have completed previous commits and
- * mark them as pending.
- */
- for_each_crtc_in_state(state, crtc, crtc_state, i)
- commit->crtcs |= drm_crtc_mask(crtc);
-
- wait_event(priv->wait, !commit_is_pending(priv, commit->crtcs));
-
- spin_lock(&priv->lock);
- priv->pending |= commit->crtcs;
- spin_unlock(&priv->lock);
-
- drm_atomic_helper_swap_state(state, true);
-
- drm_atomic_state_get(state);
- if (nonblock)
- schedule_work(&commit->work);
- else
- exynos_atomic_commit_complete(commit);
-
- return 0;
}
int exynos_atomic_check(struct drm_device *dev,
@@ -309,12 +198,7 @@ err_file_priv_free:
static void exynos_drm_preclose(struct drm_device *dev,
struct drm_file *file)
{
- struct drm_crtc *crtc;
-
exynos_drm_subdrv_close(dev, file);
-
- list_for_each_entry(crtc, &dev->mode_config.crtc_list, head)
- exynos_drm_crtc_cancel_page_flip(crtc, file);
}
static void exynos_drm_postclose(struct drm_device *dev, struct drm_file *file)
diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.h b/drivers/gpu/drm/exynos/exynos_drm_drv.h
index 80c4d5b81689..cf6e08cb35a7 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_drv.h
+++ b/drivers/gpu/drm/exynos/exynos_drm_drv.h
@@ -211,12 +211,6 @@ struct drm_exynos_file_private {
struct exynos_drm_private {
struct drm_fb_helper *fb_helper;
- /*
- * created crtc object would be contained at this array and
- * this array is used to be aware of which crtc did it request vblank.
- */
- struct drm_crtc *crtc[MAX_CRTC];
-
struct device *dma_dev;
void *mapping;
@@ -231,9 +225,9 @@ struct exynos_drm_private {
static inline struct exynos_drm_crtc *
exynos_drm_crtc_from_pipe(struct drm_device *dev, int pipe)
{
- struct exynos_drm_private *private = dev->dev_private;
+ struct drm_crtc *crtc = drm_crtc_from_index(dev, pipe);
- return to_exynos_crtc(private->crtc[pipe]);
+ return to_exynos_crtc(crtc);
}
static inline struct device *to_dma_dev(struct drm_device *dev)
diff --git a/drivers/gpu/drm/exynos/exynos_drm_dsi.c b/drivers/gpu/drm/exynos/exynos_drm_dsi.c
index e07cb1fe4860..812e2ec0761d 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_dsi.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_dsi.c
@@ -1718,10 +1718,8 @@ static int exynos_dsi_bind(struct device *dev, struct device *master,
}
bridge = of_drm_find_bridge(dsi->bridge_node);
- if (bridge) {
- encoder->bridge = bridge;
- drm_bridge_attach(drm_dev, bridge);
- }
+ if (bridge)
+ drm_bridge_attach(encoder, bridge, NULL);
return mipi_dsi_host_register(&dsi->dsi_host);
}
diff --git a/drivers/gpu/drm/exynos/exynos_drm_fb.c b/drivers/gpu/drm/exynos/exynos_drm_fb.c
index 23cce0a3f5fc..c77a5aced81a 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_fb.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_fb.c
@@ -126,7 +126,7 @@ exynos_drm_framebuffer_init(struct drm_device *dev,
+ mode_cmd->offsets[i];
}
- drm_helper_mode_fill_fb_struct(&exynos_fb->fb, mode_cmd);
+ drm_helper_mode_fill_fb_struct(dev, &exynos_fb->fb, mode_cmd);
ret = drm_framebuffer_init(dev, &exynos_fb->fb, &exynos_drm_fb_funcs);
if (ret < 0) {
@@ -187,11 +187,40 @@ dma_addr_t exynos_drm_fb_dma_addr(struct drm_framebuffer *fb, int index)
return exynos_fb->dma_addr[index];
}
+static void exynos_drm_atomic_commit_tail(struct drm_atomic_state *state)
+{
+ struct drm_device *dev = state->dev;
+
+ drm_atomic_helper_commit_modeset_disables(dev, state);
+
+ drm_atomic_helper_commit_modeset_enables(dev, state);
+
+ /*
+ * Exynos can't update planes with CRTCs and encoders disabled,
+ * its updates routines, specially for FIMD, requires the clocks
+ * to be enabled. So it is necessary to handle the modeset operations
+ * *before* the commit_planes() step, this way it will always
+ * have the relevant clocks enabled to perform the update.
+ */
+ drm_atomic_helper_commit_planes(dev, state,
+ DRM_PLANE_COMMIT_ACTIVE_ONLY);
+
+ drm_atomic_helper_commit_hw_done(state);
+
+ drm_atomic_helper_wait_for_vblanks(dev, state);
+
+ drm_atomic_helper_cleanup_planes(dev, state);
+}
+
+static struct drm_mode_config_helper_funcs exynos_drm_mode_config_helpers = {
+ .atomic_commit_tail = exynos_drm_atomic_commit_tail,
+};
+
static const struct drm_mode_config_funcs exynos_drm_mode_config_funcs = {
.fb_create = exynos_user_fb_create,
.output_poll_changed = exynos_drm_output_poll_changed,
.atomic_check = exynos_atomic_check,
- .atomic_commit = exynos_atomic_commit,
+ .atomic_commit = drm_atomic_helper_commit,
};
void exynos_drm_mode_config_init(struct drm_device *dev)
@@ -208,4 +237,5 @@ void exynos_drm_mode_config_init(struct drm_device *dev)
dev->mode_config.max_height = 4096;
dev->mode_config.funcs = &exynos_drm_mode_config_funcs;
+ dev->mode_config.helper_private = &exynos_drm_mode_config_helpers;
}
diff --git a/drivers/gpu/drm/exynos/exynos_drm_fbdev.c b/drivers/gpu/drm/exynos/exynos_drm_fbdev.c
index 9f35deb56170..bcdb2720b68e 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_fbdev.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_fbdev.c
@@ -76,7 +76,7 @@ static int exynos_drm_fbdev_update(struct drm_fb_helper *helper,
{
struct fb_info *fbi;
struct drm_framebuffer *fb = helper->fb;
- unsigned int size = fb->width * fb->height * (fb->bits_per_pixel >> 3);
+ unsigned int size = fb->width * fb->height * fb->format->cpp[0];
unsigned int nr_pages;
unsigned long offset;
@@ -90,7 +90,7 @@ static int exynos_drm_fbdev_update(struct drm_fb_helper *helper,
fbi->flags = FBINFO_FLAG_DEFAULT;
fbi->fbops = &exynos_drm_fb_ops;
- drm_fb_helper_fill_fix(fbi, fb->pitches[0], fb->depth);
+ drm_fb_helper_fill_fix(fbi, fb->pitches[0], fb->format->depth);
drm_fb_helper_fill_var(fbi, helper, sizes->fb_width, sizes->fb_height);
nr_pages = exynos_gem->size >> PAGE_SHIFT;
@@ -103,7 +103,7 @@ static int exynos_drm_fbdev_update(struct drm_fb_helper *helper,
return -EIO;
}
- offset = fbi->var.xoffset * (fb->bits_per_pixel >> 3);
+ offset = fbi->var.xoffset * fb->format->cpp[0];
offset += fbi->var.yoffset * fb->pitches[0];
fbi->screen_base = exynos_gem->kvaddr + offset;
@@ -208,7 +208,6 @@ int exynos_drm_fbdev_init(struct drm_device *dev)
struct exynos_drm_fbdev *fbdev;
struct exynos_drm_private *private = dev->dev_private;
struct drm_fb_helper *helper;
- unsigned int num_crtc;
int ret;
if (!dev->mode_config.num_crtc || !dev->mode_config.num_connector)
@@ -225,9 +224,7 @@ int exynos_drm_fbdev_init(struct drm_device *dev)
drm_fb_helper_prepare(dev, helper, &exynos_drm_fb_helper_funcs);
- num_crtc = dev->mode_config.num_crtc;
-
- ret = drm_fb_helper_init(dev, helper, num_crtc, MAX_CONNECTOR);
+ ret = drm_fb_helper_init(dev, helper, MAX_CONNECTOR);
if (ret < 0) {
DRM_ERROR("failed to initialize drm fb helper.\n");
goto err_init;
@@ -270,10 +267,8 @@ static void exynos_drm_fbdev_destroy(struct drm_device *dev,
/* release drm framebuffer and real buffer */
if (fb_helper->fb && fb_helper->fb->funcs) {
fb = fb_helper->fb;
- if (fb) {
- drm_framebuffer_unregister_private(fb);
+ if (fb)
drm_framebuffer_remove(fb);
- }
}
drm_fb_helper_unregister_fbi(fb_helper);
diff --git a/drivers/gpu/drm/exynos/exynos_drm_fimd.c b/drivers/gpu/drm/exynos/exynos_drm_fimd.c
index e2e405170d35..a9fa444c6053 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_fimd.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_fimd.c
@@ -125,10 +125,8 @@ static struct fimd_driver_data exynos3_fimd_driver_data = {
.timing_base = 0x20000,
.lcdblk_offset = 0x210,
.lcdblk_bypass_shift = 1,
- .trg_type = I80_HW_TRG,
.has_shadowcon = 1,
.has_vidoutcon = 1,
- .has_trigger_per_te = 1,
};
static struct fimd_driver_data exynos4_fimd_driver_data = {
@@ -738,7 +736,7 @@ static void fimd_update_plane(struct exynos_drm_crtc *crtc,
unsigned long val, size, offset;
unsigned int last_x, last_y, buf_offsize, line_size;
unsigned int win = plane->index;
- unsigned int bpp = fb->bits_per_pixel >> 3;
+ unsigned int bpp = fb->format->cpp[0];
unsigned int pitch = fb->pitches[0];
if (ctx->suspended)
@@ -804,7 +802,7 @@ static void fimd_update_plane(struct exynos_drm_crtc *crtc,
DRM_DEBUG_KMS("osd size = 0x%x\n", (unsigned int)val);
}
- fimd_win_set_pixfmt(ctx, win, fb->pixel_format, state->src.w);
+ fimd_win_set_pixfmt(ctx, win, fb->format->format, state->src.w);
/* hardware window 0 doesn't support color key. */
if (win != 0)
diff --git a/drivers/gpu/drm/exynos/exynos_drm_g2d.c b/drivers/gpu/drm/exynos/exynos_drm_g2d.c
index fbd13fabdf2d..2b8bf2dd6387 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_g2d.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_g2d.c
@@ -1193,6 +1193,17 @@ int exynos_g2d_set_cmdlist_ioctl(struct drm_device *drm_dev, void *data,
if (!node)
return -ENOMEM;
+ /*
+ * To avoid an integer overflow for the later size computations, we
+ * enforce a maximum number of submitted commands here. This limit is
+ * sufficient for all conceivable usage cases of the G2D.
+ */
+ if (req->cmd_nr > G2D_CMDLIST_DATA_NUM ||
+ req->cmd_buf_nr > G2D_CMDLIST_DATA_NUM) {
+ dev_err(dev, "number of submitted G2D commands exceeds limit\n");
+ return -EINVAL;
+ }
+
node->event = NULL;
if (req->event_type != G2D_EVENT_NOT) {
@@ -1250,7 +1261,11 @@ int exynos_g2d_set_cmdlist_ioctl(struct drm_device *drm_dev, void *data,
cmdlist->data[cmdlist->last++] = G2D_INTEN_ACF;
}
- /* Check size of cmdlist: last 2 is about G2D_BITBLT_START */
+ /*
+ * Check the size of cmdlist. The 2 that is added last comes from
+ * the implicit G2D_BITBLT_START that is appended once we have
+ * checked all the submitted commands.
+ */
size = cmdlist->last + req->cmd_nr * 2 + req->cmd_buf_nr * 2 + 2;
if (size > G2D_CMDLIST_DATA_NUM) {
dev_err(dev, "cmdlist size is too big\n");
@@ -1668,7 +1683,7 @@ struct platform_driver g2d_driver = {
.probe = g2d_probe,
.remove = g2d_remove,
.driver = {
- .name = "s5p-g2d",
+ .name = "exynos-drm-g2d",
.owner = THIS_MODULE,
.pm = &g2d_pm_ops,
.of_match_table = exynos_g2d_match,
diff --git a/drivers/gpu/drm/exynos/exynos_drm_gem.c b/drivers/gpu/drm/exynos/exynos_drm_gem.c
index 57b81460fec8..4c28f7ffcc4d 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_gem.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_gem.c
@@ -447,8 +447,9 @@ int exynos_drm_gem_dumb_map_offset(struct drm_file *file_priv,
return ret;
}
-int exynos_drm_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
+int exynos_drm_gem_fault(struct vm_fault *vmf)
{
+ struct vm_area_struct *vma = vmf->vma;
struct drm_gem_object *obj = vma->vm_private_data;
struct exynos_drm_gem *exynos_gem = to_exynos_gem(obj);
unsigned long pfn;
diff --git a/drivers/gpu/drm/exynos/exynos_drm_gem.h b/drivers/gpu/drm/exynos/exynos_drm_gem.h
index df7c543d6558..85457255fcd1 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_gem.h
+++ b/drivers/gpu/drm/exynos/exynos_drm_gem.h
@@ -116,7 +116,7 @@ int exynos_drm_gem_dumb_map_offset(struct drm_file *file_priv,
uint64_t *offset);
/* page fault handler and mmap fault address(virtual) to physical memory. */
-int exynos_drm_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf);
+int exynos_drm_gem_fault(struct vm_fault *vmf);
/* set vm_flags and we can change the vm attribute to other one at here. */
int exynos_drm_gem_mmap(struct file *filp, struct vm_area_struct *vma);
diff --git a/drivers/gpu/drm/exynos/exynos_drm_mic.c b/drivers/gpu/drm/exynos/exynos_drm_mic.c
index a0def0be6d65..2ef43d403eaa 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_mic.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_mic.c
@@ -19,6 +19,7 @@
#include <linux/of_graph.h>
#include <linux/clk.h>
#include <linux/component.h>
+#include <linux/pm_runtime.h>
#include <drm/drmP.h>
#include <linux/mfd/syscon.h>
#include <linux/regmap.h>
@@ -269,35 +270,9 @@ static int parse_dt(struct exynos_mic *mic)
}
nodes[j++] = remote_node;
- switch (i) {
- case ENDPOINT_DECON_NODE:
- /* decon node */
- if (of_get_child_by_name(remote_node,
- "i80-if-timings"))
- mic->i80_mode = 1;
-
- break;
- case ENDPOINT_DSI_NODE:
- /* panel node */
- remote_node = get_remote_node(remote_node, 1);
- if (!remote_node) {
- ret = -EPIPE;
- goto exit;
- }
- nodes[j++] = remote_node;
-
- ret = of_get_videomode(remote_node,
- &mic->vm, 0);
- if (ret) {
- DRM_ERROR("mic: failed to get videomode");
- goto exit;
- }
-
- break;
- default:
- DRM_ERROR("mic: Unknown endpoint from MIC");
- break;
- }
+ if (i == ENDPOINT_DECON_NODE &&
+ of_get_child_by_name(remote_node, "i80-if-timings"))
+ mic->i80_mode = 1;
}
exit:
@@ -312,7 +287,6 @@ static void mic_disable(struct drm_bridge *bridge) { }
static void mic_post_disable(struct drm_bridge *bridge)
{
struct exynos_mic *mic = bridge->driver_private;
- int i;
mutex_lock(&mic_mutex);
if (!mic->enabled)
@@ -320,39 +294,43 @@ static void mic_post_disable(struct drm_bridge *bridge)
mic_set_path(mic, 0);
- for (i = NUM_CLKS - 1; i > -1; i--)
- clk_disable_unprepare(mic->clks[i]);
-
+ pm_runtime_put(mic->dev);
mic->enabled = 0;
already_disabled:
mutex_unlock(&mic_mutex);
}
+static void mic_mode_set(struct drm_bridge *bridge,
+ struct drm_display_mode *mode,
+ struct drm_display_mode *adjusted_mode)
+{
+ struct exynos_mic *mic = bridge->driver_private;
+
+ mutex_lock(&mic_mutex);
+ drm_display_mode_to_videomode(mode, &mic->vm);
+ mutex_unlock(&mic_mutex);
+}
+
static void mic_pre_enable(struct drm_bridge *bridge)
{
struct exynos_mic *mic = bridge->driver_private;
- int ret, i;
+ int ret;
mutex_lock(&mic_mutex);
if (mic->enabled)
- goto already_enabled;
+ goto unlock;
- for (i = 0; i < NUM_CLKS; i++) {
- ret = clk_prepare_enable(mic->clks[i]);
- if (ret < 0) {
- DRM_ERROR("Failed to enable clock (%s)\n",
- clk_names[i]);
- goto turn_off_clks;
- }
- }
+ ret = pm_runtime_get_sync(mic->dev);
+ if (ret < 0)
+ goto unlock;
mic_set_path(mic, 1);
ret = mic_sw_reset(mic);
if (ret) {
DRM_ERROR("Failed to reset\n");
- goto turn_off_clks;
+ goto turn_off;
}
if (!mic->i80_mode)
@@ -365,10 +343,9 @@ static void mic_pre_enable(struct drm_bridge *bridge)
return;
-turn_off_clks:
- while (--i > -1)
- clk_disable_unprepare(mic->clks[i]);
-already_enabled:
+turn_off:
+ pm_runtime_put(mic->dev);
+unlock:
mutex_unlock(&mic_mutex);
}
@@ -377,6 +354,7 @@ static void mic_enable(struct drm_bridge *bridge) { }
static const struct drm_bridge_funcs mic_bridge_funcs = {
.disable = mic_disable,
.post_disable = mic_post_disable,
+ .mode_set = mic_mode_set,
.pre_enable = mic_pre_enable,
.enable = mic_enable,
};
@@ -401,14 +379,12 @@ static void exynos_mic_unbind(struct device *dev, struct device *master,
void *data)
{
struct exynos_mic *mic = dev_get_drvdata(dev);
- int i;
mutex_lock(&mic_mutex);
if (!mic->enabled)
goto already_disabled;
- for (i = NUM_CLKS - 1; i > -1; i--)
- clk_disable_unprepare(mic->clks[i]);
+ pm_runtime_put(mic->dev);
already_disabled:
mutex_unlock(&mic_mutex);
@@ -421,6 +397,41 @@ static const struct component_ops exynos_mic_component_ops = {
.unbind = exynos_mic_unbind,
};
+#ifdef CONFIG_PM
+static int exynos_mic_suspend(struct device *dev)
+{
+ struct exynos_mic *mic = dev_get_drvdata(dev);
+ int i;
+
+ for (i = NUM_CLKS - 1; i > -1; i--)
+ clk_disable_unprepare(mic->clks[i]);
+
+ return 0;
+}
+
+static int exynos_mic_resume(struct device *dev)
+{
+ struct exynos_mic *mic = dev_get_drvdata(dev);
+ int ret, i;
+
+ for (i = 0; i < NUM_CLKS; i++) {
+ ret = clk_prepare_enable(mic->clks[i]);
+ if (ret < 0) {
+ DRM_ERROR("Failed to enable clock (%s)\n",
+ clk_names[i]);
+ while (--i > -1)
+ clk_disable_unprepare(mic->clks[i]);
+ return ret;
+ }
+ }
+ return 0;
+}
+#endif
+
+static const struct dev_pm_ops exynos_mic_pm_ops = {
+ SET_RUNTIME_PM_OPS(exynos_mic_suspend, exynos_mic_resume, NULL)
+};
+
static int exynos_mic_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
@@ -473,9 +484,18 @@ static int exynos_mic_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, mic);
+ pm_runtime_enable(dev);
+
+ ret = component_add(dev, &exynos_mic_component_ops);
+ if (ret)
+ goto err_pm;
+
DRM_DEBUG_KMS("MIC has been probed\n");
- return component_add(dev, &exynos_mic_component_ops);
+ return 0;
+
+err_pm:
+ pm_runtime_disable(dev);
err:
return ret;
}
@@ -483,6 +503,7 @@ err:
static int exynos_mic_remove(struct platform_device *pdev)
{
component_del(&pdev->dev, &exynos_mic_component_ops);
+ pm_runtime_disable(&pdev->dev);
return 0;
}
@@ -497,6 +518,7 @@ struct platform_driver mic_driver = {
.remove = exynos_mic_remove,
.driver = {
.name = "exynos-mic",
+ .pm = &exynos_mic_pm_ops,
.owner = THIS_MODULE,
.of_match_table = exynos_mic_of_match,
},
diff --git a/drivers/gpu/drm/exynos/exynos_hdmi.c b/drivers/gpu/drm/exynos/exynos_hdmi.c
index 5ed8b1effe71..88ccc0469316 100644
--- a/drivers/gpu/drm/exynos/exynos_hdmi.c
+++ b/drivers/gpu/drm/exynos/exynos_hdmi.c
@@ -35,6 +35,7 @@
#include <linux/io.h>
#include <linux/of_address.h>
#include <linux/of_device.h>
+#include <linux/of_graph.h>
#include <linux/hdmi.h>
#include <linux/component.h>
#include <linux/mfd/syscon.h>
@@ -133,6 +134,7 @@ struct hdmi_context {
struct regulator_bulk_data regul_bulk[ARRAY_SIZE(supply)];
struct regulator *reg_hdmi_en;
struct exynos_drm_clk phy_clk;
+ struct drm_bridge *bridge;
};
static inline struct hdmi_context *encoder_to_hdmi(struct drm_encoder *e)
@@ -509,9 +511,9 @@ static const struct hdmiphy_config hdmiphy_5433_configs[] = {
{
.pixel_clock = 27000000,
.conf = {
- 0x01, 0x51, 0x22, 0x51, 0x08, 0xfc, 0x88, 0x46,
- 0x72, 0x50, 0x24, 0x0c, 0x24, 0x0f, 0x7c, 0xa5,
- 0xd4, 0x2b, 0x87, 0x00, 0x00, 0x04, 0x00, 0x30,
+ 0x01, 0x51, 0x2d, 0x75, 0x01, 0x00, 0x88, 0x02,
+ 0x72, 0x50, 0x44, 0x8c, 0x27, 0x00, 0x7c, 0xac,
+ 0xd6, 0x2b, 0x67, 0x00, 0x00, 0x04, 0x00, 0x30,
0x08, 0x10, 0x01, 0x01, 0x48, 0x40, 0x00, 0x40,
},
},
@@ -519,9 +521,9 @@ static const struct hdmiphy_config hdmiphy_5433_configs[] = {
.pixel_clock = 27027000,
.conf = {
0x01, 0x51, 0x2d, 0x72, 0x64, 0x09, 0x88, 0xc3,
- 0x71, 0x50, 0x24, 0x14, 0x24, 0x0f, 0x7c, 0xa5,
- 0xd4, 0x2b, 0x87, 0x00, 0x00, 0x04, 0x00, 0x30,
- 0x28, 0x10, 0x01, 0x01, 0x48, 0x40, 0x00, 0x40,
+ 0x71, 0x50, 0x44, 0x8c, 0x27, 0x00, 0x7c, 0xac,
+ 0xd6, 0x2b, 0x67, 0x00, 0x00, 0x04, 0x00, 0x30,
+ 0x08, 0x10, 0x01, 0x01, 0x48, 0x40, 0x00, 0x40,
},
},
{
@@ -587,6 +589,15 @@ static const struct hdmiphy_config hdmiphy_5433_configs[] = {
0x08, 0x10, 0x01, 0x01, 0x48, 0x4a, 0x00, 0x40,
},
},
+ {
+ .pixel_clock = 297000000,
+ .conf = {
+ 0x01, 0x51, 0x3E, 0x05, 0x40, 0xF0, 0x88, 0xC2,
+ 0x52, 0x53, 0x44, 0x8C, 0x27, 0x00, 0x7C, 0xAC,
+ 0xD6, 0x2B, 0x67, 0x00, 0x00, 0x04, 0x00, 0x30,
+ 0x08, 0x10, 0x01, 0x01, 0x48, 0x40, 0x00, 0x40,
+ },
+ },
};
static const char * const hdmi_clk_gates4[] = {
@@ -788,7 +799,8 @@ static void hdmi_reg_infoframes(struct hdmi_context *hdata)
sizeof(buf));
if (ret > 0) {
hdmi_reg_writeb(hdata, HDMI_VSI_CON, HDMI_VSI_CON_EVERY_VSYNC);
- hdmi_reg_write_buf(hdata, HDMI_VSI_HEADER0, buf, ret);
+ hdmi_reg_write_buf(hdata, HDMI_VSI_HEADER0, buf, 3);
+ hdmi_reg_write_buf(hdata, HDMI_VSI_DATA(0), buf + 3, ret - 3);
}
ret = hdmi_audio_infoframe_init(&frm.audio);
@@ -912,7 +924,15 @@ static int hdmi_create_connector(struct drm_encoder *encoder)
drm_connector_register(connector);
drm_mode_connector_attach_encoder(connector, encoder);
- return 0;
+ if (hdata->bridge) {
+ encoder->bridge = hdata->bridge;
+ hdata->bridge->encoder = encoder;
+ ret = drm_bridge_attach(encoder, hdata->bridge, NULL);
+ if (ret)
+ DRM_ERROR("Failed to attach bridge\n");
+ }
+
+ return ret;
}
static bool hdmi_mode_fixup(struct drm_encoder *encoder,
@@ -1581,6 +1601,31 @@ static void hdmiphy_clk_enable(struct exynos_drm_clk *clk, bool enable)
hdmiphy_disable(hdata);
}
+static int hdmi_bridge_init(struct hdmi_context *hdata)
+{
+ struct device *dev = hdata->dev;
+ struct device_node *ep, *np;
+
+ ep = of_graph_get_endpoint_by_regs(dev->of_node, 1, -1);
+ if (!ep)
+ return 0;
+
+ np = of_graph_get_remote_port_parent(ep);
+ of_node_put(ep);
+ if (!np) {
+ DRM_ERROR("failed to get remote port parent");
+ return -EINVAL;
+ }
+
+ hdata->bridge = of_drm_find_bridge(np);
+ of_node_put(np);
+
+ if (!hdata->bridge)
+ return -EPROBE_DEFER;
+
+ return 0;
+}
+
static int hdmi_resources_init(struct hdmi_context *hdata)
{
struct device *dev = hdata->dev;
@@ -1620,17 +1665,18 @@ static int hdmi_resources_init(struct hdmi_context *hdata)
hdata->reg_hdmi_en = devm_regulator_get_optional(dev, "hdmi-en");
- if (PTR_ERR(hdata->reg_hdmi_en) == -ENODEV)
- return 0;
+ if (PTR_ERR(hdata->reg_hdmi_en) != -ENODEV) {
+ if (IS_ERR(hdata->reg_hdmi_en))
+ return PTR_ERR(hdata->reg_hdmi_en);
- if (IS_ERR(hdata->reg_hdmi_en))
- return PTR_ERR(hdata->reg_hdmi_en);
-
- ret = regulator_enable(hdata->reg_hdmi_en);
- if (ret)
- DRM_ERROR("failed to enable hdmi-en regulator\n");
+ ret = regulator_enable(hdata->reg_hdmi_en);
+ if (ret) {
+ DRM_ERROR("failed to enable hdmi-en regulator\n");
+ return ret;
+ }
+ }
- return ret;
+ return hdmi_bridge_init(hdata);
}
static struct of_device_id hdmi_match_types[] = {
diff --git a/drivers/gpu/drm/exynos/exynos_mixer.c b/drivers/gpu/drm/exynos/exynos_mixer.c
index edb20a34c66c..72143ac10525 100644
--- a/drivers/gpu/drm/exynos/exynos_mixer.c
+++ b/drivers/gpu/drm/exynos/exynos_mixer.c
@@ -485,7 +485,7 @@ static void vp_video_buffer(struct mixer_context *ctx,
bool crcb_mode = false;
u32 val;
- switch (fb->pixel_format) {
+ switch (fb->format->format) {
case DRM_FORMAT_NV12:
crcb_mode = false;
break;
@@ -494,7 +494,7 @@ static void vp_video_buffer(struct mixer_context *ctx,
break;
default:
DRM_ERROR("pixel format for vp is wrong [%d].\n",
- fb->pixel_format);
+ fb->format->format);
return;
}
@@ -597,7 +597,7 @@ static void mixer_graph_buffer(struct mixer_context *ctx,
unsigned int fmt;
u32 val;
- switch (fb->pixel_format) {
+ switch (fb->format->format) {
case DRM_FORMAT_XRGB4444:
case DRM_FORMAT_ARGB4444:
fmt = MXR_FORMAT_ARGB4444;
@@ -631,7 +631,7 @@ static void mixer_graph_buffer(struct mixer_context *ctx,
/* converting dma address base and source offset */
dma_addr = exynos_drm_fb_dma_addr(fb, 0)
- + (state->src.x * fb->bits_per_pixel >> 3)
+ + (state->src.x * fb->format->cpp[0])
+ (state->src.y * fb->pitches[0]);
src_x_offset = 0;
src_y_offset = 0;
@@ -649,7 +649,7 @@ static void mixer_graph_buffer(struct mixer_context *ctx,
/* setup geometry */
mixer_reg_write(res, MXR_GRAPHIC_SPAN(win),
- fb->pitches[0] / (fb->bits_per_pixel >> 3));
+ fb->pitches[0] / fb->format->cpp[0]);
/* setup display size */
if (ctx->mxr_ver == MXR_VER_128_0_0_184 &&
@@ -681,7 +681,7 @@ static void mixer_graph_buffer(struct mixer_context *ctx,
mixer_cfg_scan(ctx, mode->vdisplay);
mixer_cfg_rgb_fmt(ctx, mode->vdisplay);
mixer_cfg_layer(ctx, win, priority, true);
- mixer_cfg_gfx_blend(ctx, win, is_alpha_format(fb->pixel_format));
+ mixer_cfg_gfx_blend(ctx, win, is_alpha_format(fb->format->format));
/* layer update mandatory for mixer 16.0.33.0 */
if (ctx->mxr_ver == MXR_VER_16_0_33_0 ||
@@ -701,7 +701,7 @@ static void vp_win_reset(struct mixer_context *ctx)
unsigned int tries = 100;
vp_reg_write(res, VP_SRESET, VP_SRESET_PROCESSING);
- while (tries--) {
+ while (--tries) {
/* waiting until VP_SRESET_PROCESSING is 0 */
if (~vp_reg_read(res, VP_SRESET) & VP_SRESET_PROCESSING)
break;