aboutsummaryrefslogtreecommitdiff
path: root/drivers/gpu
diff options
context:
space:
mode:
authorDave Airlie2015-11-03 15:42:10 +1000
committerDave Airlie2015-11-03 15:42:10 +1000
commitb4590047966ba35a626f947c3fee2c4ed7081685 (patch)
tree9b510c09baabcdfa53810f911a7eb23393a83eb0 /drivers/gpu
parentc0f3f90cf454dd845dcc443afa4f0e312a8eaee0 (diff)
parentdf547bf7735a623500eedff9cc6716ac1d82b95d (diff)
Merge branch 'exynos-drm-next' of git://git.kernel.org/pub/scm/linux/kernel/git/daeinki/drm-exynos into drm-next
This pull request includes comprehensive cleanups to HDMI part and several fixups. In addition, this pull request includes also a defconfig patch which enables mixer driver as default. For this, I got already Acked-by from Krzysztof Kozlowski who is a Exynos SoC maintainer. * 'exynos-drm-next' of git://git.kernel.org/pub/scm/linux/kernel/git/daeinki/drm-exynos: (34 commits) drm/exynos/gem: remove DMA-mapping hacks used for constructing page array ARM: exynos_defconfig: enable Exynos DRM Mixer driver drm/exynos: simplify Kconfig component names drm/exynos: re-arrange Kconfig entries drm/exynos: abstract out common dependency drm/exynos: separate Mixer and HDMI drivers drm/exynos/mixer: replace direct cross-driver call with drm mode validation drm/exynos: add atomic_check callback to exynos_crtc drm/exynos/decon5433: add support for DECON-TV drm/exynos/decon5433: remove duplicated initialization drm/exynos/decon5433: merge different flag fields drm/exynos/decon5433: add function to set particular register bits drm/exynos/decon5433: fix timing registers writes drm/exynos/decon5433: add PCLK clock drm/exynos: cleanup name of gem object for exynos_drm drm/exynos: fix to detach device of iommu drm/exynos: add cursor plane support drm/exynos: add global macro for the default primary plane drm/exynos: fix spelling errors drm: exynos: mixer: fix using usleep() in atomic context ...
Diffstat (limited to 'drivers/gpu')
-rw-r--r--drivers/gpu/drm/exynos/Kconfig75
-rw-r--r--drivers/gpu/drm/exynos/Makefile3
-rw-r--r--drivers/gpu/drm/exynos/exynos5433_drm_decon.c324
-rw-r--r--drivers/gpu/drm/exynos/exynos7_drm_decon.c7
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_crtc.c12
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_drv.c4
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_drv.h5
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_fb.c45
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_fb.h5
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_fbdev.c53
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_fimc.c16
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_fimd.c7
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_gem.c275
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_gem.h15
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_gsc.c12
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_iommu.c3
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_plane.c20
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_plane.h2
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_vidi.c8
-rw-r--r--drivers/gpu/drm/exynos/exynos_hdmi.c496
-rw-r--r--drivers/gpu/drm/exynos/exynos_mixer.c17
-rw-r--r--drivers/gpu/drm/exynos/exynos_mixer.h20
-rw-r--r--drivers/gpu/drm/exynos/regs-hdmi.h33
23 files changed, 664 insertions, 793 deletions
diff --git a/drivers/gpu/drm/exynos/Kconfig b/drivers/gpu/drm/exynos/Kconfig
index bd1a4156f647..96e86cf4455b 100644
--- a/drivers/gpu/drm/exynos/Kconfig
+++ b/drivers/gpu/drm/exynos/Kconfig
@@ -11,43 +11,59 @@ config DRM_EXYNOS
Choose this option if you have a Samsung SoC EXYNOS chipset.
If M is selected the module will be called exynosdrm.
+if DRM_EXYNOS
+
config DRM_EXYNOS_IOMMU
bool
- depends on DRM_EXYNOS && EXYNOS_IOMMU && ARM_DMA_USE_IOMMU
+ depends on EXYNOS_IOMMU && ARM_DMA_USE_IOMMU
default y
+comment "CRTCs"
+
config DRM_EXYNOS_FIMD
- bool "Exynos DRM FIMD"
- depends on DRM_EXYNOS && !FB_S3C
+ 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.
config DRM_EXYNOS5433_DECON
- bool "Exynos5433 DRM DECON"
- depends on DRM_EXYNOS
+ bool "DECON on Exynos5433"
help
Choose this option if you want to use Exynos5433 DECON for DRM.
config DRM_EXYNOS7_DECON
- bool "Exynos7 DRM DECON"
- depends on DRM_EXYNOS && !FB_S3C
+ 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.
+config DRM_EXYNOS_MIXER
+ bool "Mixer"
+ depends on !VIDEO_SAMSUNG_S5P_TV
+ help
+ Choose this option if you want to use Exynos Mixer for DRM.
+
+config DRM_EXYNOS_VIDI
+ bool "Virtual Display"
+ help
+ Choose this option if you want to use Exynos VIDI for DRM.
+
+comment "Encoders and Bridges"
+
config DRM_EXYNOS_DPI
- bool "EXYNOS DRM parallel output support"
- depends on DRM_EXYNOS && (DRM_EXYNOS_FIMD || DRM_EXYNOS7_DECON)
+ bool "Parallel output"
+ depends on DRM_EXYNOS_FIMD
select DRM_PANEL
default n
help
This enables support for Exynos parallel output.
config DRM_EXYNOS_DSI
- bool "EXYNOS DRM MIPI-DSI driver support"
- depends on DRM_EXYNOS && (DRM_EXYNOS_FIMD || DRM_EXYNOS5433_DECON || DRM_EXYNOS7_DECON)
+ bool "MIPI-DSI host"
+ depends on DRM_EXYNOS_FIMD || DRM_EXYNOS5433_DECON || DRM_EXYNOS7_DECON
select DRM_MIPI_DSI
select DRM_PANEL
default n
@@ -55,58 +71,55 @@ config DRM_EXYNOS_DSI
This enables support for Exynos MIPI-DSI device.
config DRM_EXYNOS_DP
- bool "EXYNOS DRM DP driver support"
- depends on DRM_EXYNOS && (DRM_EXYNOS_FIMD || DRM_EXYNOS7_DECON)
+ bool "Display Port"
+ depends on DRM_EXYNOS_FIMD || DRM_EXYNOS7_DECON
default DRM_EXYNOS
select DRM_PANEL
help
This enables support for DP device.
config DRM_EXYNOS_HDMI
- bool "Exynos DRM HDMI"
- depends on DRM_EXYNOS && !VIDEO_SAMSUNG_S5P_TV
+ bool "HDMI"
+ depends on !VIDEO_SAMSUNG_S5P_TV && (DRM_EXYNOS_MIXER || DRM_EXYNOS5433_DECON)
help
Choose this option if you want to use Exynos HDMI for DRM.
-config DRM_EXYNOS_VIDI
- bool "Exynos DRM Virtual Display"
- depends on DRM_EXYNOS
+config DRM_EXYNOS_MIC
+ bool "Mobile Image Compressor"
+ depends on DRM_EXYNOS5433_DECON
help
- Choose this option if you want to use Exynos VIDI for DRM.
+ Choose this option if you want to use Exynos MIC for DRM.
+
+comment "Sub-drivers"
config DRM_EXYNOS_G2D
- bool "Exynos DRM G2D"
- depends on DRM_EXYNOS && !VIDEO_SAMSUNG_S5P_G2D
+ bool "G2D"
+ depends on !VIDEO_SAMSUNG_S5P_G2D
select FRAME_VECTOR
help
Choose this option if you want to use Exynos G2D for DRM.
config DRM_EXYNOS_IPP
- bool "Exynos DRM IPP"
- depends on DRM_EXYNOS
+ bool "Image Post Processor"
help
Choose this option if you want to use IPP feature for DRM.
config DRM_EXYNOS_FIMC
- bool "Exynos DRM FIMC"
+ bool "FIMC"
depends on DRM_EXYNOS_IPP && MFD_SYSCON
help
Choose this option if you want to use Exynos FIMC for DRM.
config DRM_EXYNOS_ROTATOR
- bool "Exynos DRM Rotator"
+ bool "Rotator"
depends on DRM_EXYNOS_IPP
help
Choose this option if you want to use Exynos Rotator for DRM.
config DRM_EXYNOS_GSC
- bool "Exynos DRM GSC"
+ bool "GScaler"
depends on DRM_EXYNOS_IPP && ARCH_EXYNOS5 && !ARCH_MULTIPLATFORM
help
Choose this option if you want to use Exynos GSC for DRM.
-config DRM_EXYNOS_MIC
- bool "Exynos DRM MIC"
- depends on (DRM_EXYNOS && DRM_EXYNOS5433_DECON)
- help
- Choose this option if you want to use Exynos MIC for DRM.
+endif
diff --git a/drivers/gpu/drm/exynos/Makefile b/drivers/gpu/drm/exynos/Makefile
index 02aecfed6354..6496532aaa91 100644
--- a/drivers/gpu/drm/exynos/Makefile
+++ b/drivers/gpu/drm/exynos/Makefile
@@ -14,7 +14,8 @@ exynosdrm-$(CONFIG_DRM_EXYNOS7_DECON) += exynos7_drm_decon.o
exynosdrm-$(CONFIG_DRM_EXYNOS_DPI) += exynos_drm_dpi.o
exynosdrm-$(CONFIG_DRM_EXYNOS_DSI) += exynos_drm_dsi.o
exynosdrm-$(CONFIG_DRM_EXYNOS_DP) += exynos_dp_core.o exynos_dp_reg.o
-exynosdrm-$(CONFIG_DRM_EXYNOS_HDMI) += exynos_hdmi.o exynos_mixer.o
+exynosdrm-$(CONFIG_DRM_EXYNOS_MIXER) += exynos_mixer.o
+exynosdrm-$(CONFIG_DRM_EXYNOS_HDMI) += exynos_hdmi.o
exynosdrm-$(CONFIG_DRM_EXYNOS_VIDI) += exynos_drm_vidi.o
exynosdrm-$(CONFIG_DRM_EXYNOS_G2D) += exynos_drm_g2d.o
exynosdrm-$(CONFIG_DRM_EXYNOS_IPP) += exynos_drm_ipp.o
diff --git a/drivers/gpu/drm/exynos/exynos5433_drm_decon.c b/drivers/gpu/drm/exynos/exynos5433_drm_decon.c
index b3c730770b0f..fbe1b3174f75 100644
--- a/drivers/gpu/drm/exynos/exynos5433_drm_decon.c
+++ b/drivers/gpu/drm/exynos/exynos5433_drm_decon.c
@@ -13,6 +13,7 @@
#include <linux/platform_device.h>
#include <linux/clk.h>
#include <linux/component.h>
+#include <linux/of_device.h>
#include <linux/of_gpio.h>
#include <linux/pm_runtime.h>
@@ -24,28 +25,11 @@
#include "exynos_drm_iommu.h"
#define WINDOWS_NR 3
+#define CURSOR_WIN 2
#define MIN_FB_WIDTH_FOR_16WORD_BURST 128
-struct decon_context {
- struct device *dev;
- struct drm_device *drm_dev;
- struct exynos_drm_crtc *crtc;
- struct exynos_drm_plane planes[WINDOWS_NR];
- void __iomem *addr;
- struct clk *clks[6];
- unsigned int default_win;
- unsigned long irq_flags;
- int pipe;
- bool suspended;
-
-#define BIT_CLKS_ENABLED 0
-#define BIT_IRQS_ENABLED 1
- unsigned long enabled;
- bool i80_if;
- atomic_t win_updated;
-};
-
static const char * const decon_clks_name[] = {
+ "pclk",
"aclk_decon",
"aclk_smmu_decon0x",
"aclk_xiu_decon0x",
@@ -54,6 +38,32 @@ static const char * const decon_clks_name[] = {
"sclk_decon_eclk",
};
+enum decon_iftype {
+ IFTYPE_RGB,
+ IFTYPE_I80,
+ IFTYPE_HDMI
+};
+
+enum decon_flag_bits {
+ BIT_CLKS_ENABLED,
+ BIT_IRQS_ENABLED,
+ BIT_WIN_UPDATED,
+ BIT_SUSPENDED
+};
+
+struct decon_context {
+ struct device *dev;
+ struct drm_device *drm_dev;
+ struct exynos_drm_crtc *crtc;
+ struct exynos_drm_plane planes[WINDOWS_NR];
+ void __iomem *addr;
+ struct clk *clks[ARRAY_SIZE(decon_clks_name)];
+ int pipe;
+ unsigned long flags;
+ enum decon_iftype out_type;
+ int first_win;
+};
+
static const uint32_t decon_formats[] = {
DRM_FORMAT_XRGB1555,
DRM_FORMAT_RGB565,
@@ -61,17 +71,24 @@ static const uint32_t decon_formats[] = {
DRM_FORMAT_ARGB8888,
};
+static inline void decon_set_bits(struct decon_context *ctx, u32 reg, u32 mask,
+ u32 val)
+{
+ val = (val & mask) | (readl(ctx->addr + reg) & ~mask);
+ writel(val, ctx->addr + reg);
+}
+
static int decon_enable_vblank(struct exynos_drm_crtc *crtc)
{
struct decon_context *ctx = crtc->ctx;
u32 val;
- if (ctx->suspended)
+ if (test_bit(BIT_SUSPENDED, &ctx->flags))
return -EPERM;
- if (test_and_set_bit(0, &ctx->irq_flags)) {
+ if (test_and_set_bit(BIT_IRQS_ENABLED, &ctx->flags)) {
val = VIDINTCON0_INTEN;
- if (ctx->i80_if)
+ if (ctx->out_type == IFTYPE_I80)
val |= VIDINTCON0_FRAMEDONE;
else
val |= VIDINTCON0_INTFRMEN;
@@ -86,79 +103,85 @@ static void decon_disable_vblank(struct exynos_drm_crtc *crtc)
{
struct decon_context *ctx = crtc->ctx;
- if (ctx->suspended)
+ if (test_bit(BIT_SUSPENDED, &ctx->flags))
return;
- if (test_and_clear_bit(0, &ctx->irq_flags))
+ if (test_and_clear_bit(BIT_IRQS_ENABLED, &ctx->flags))
writel(0, ctx->addr + DECON_VIDINTCON0);
}
static void decon_setup_trigger(struct decon_context *ctx)
{
- u32 val = TRIGCON_TRIGEN_PER_F | TRIGCON_TRIGEN_F |
- TRIGCON_TE_AUTO_MASK | TRIGCON_SWTRIGEN;
+ u32 val = (ctx->out_type != IFTYPE_HDMI)
+ ? TRIGCON_TRIGEN_PER_F | TRIGCON_TRIGEN_F |
+ TRIGCON_TE_AUTO_MASK | TRIGCON_SWTRIGEN
+ : TRIGCON_TRIGEN_PER_F | TRIGCON_TRIGEN_F |
+ TRIGCON_HWTRIGMASK_I80_RGB | TRIGCON_HWTRIGEN_I80_RGB;
writel(val, ctx->addr + DECON_TRIGCON);
}
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 *m = &crtc->base.mode;
u32 val;
- if (ctx->suspended)
+ if (test_bit(BIT_SUSPENDED, &ctx->flags))
return;
+ if (ctx->out_type == IFTYPE_HDMI) {
+ m->crtc_hsync_start = m->crtc_hdisplay + 10;
+ 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;
+ }
+
+ decon_set_bits(ctx, DECON_VIDCON0, VIDCON0_ENVID, 0);
+
/* enable clock gate */
val = CMU_CLKGAGE_MODE_SFR_F | CMU_CLKGAGE_MODE_MEM_F;
writel(val, ctx->addr + DECON_CMU);
/* lcd on and use command if */
val = VIDOUT_LCD_ON;
- if (ctx->i80_if)
+ if (ctx->out_type == IFTYPE_I80)
val |= VIDOUT_COMMAND_IF;
else
val |= VIDOUT_RGB_IF;
writel(val, ctx->addr + DECON_VIDOUTCON0);
- val = VIDTCON2_LINEVAL(mode->vdisplay - 1) |
- VIDTCON2_HOZVAL(mode->hdisplay - 1);
+ val = VIDTCON2_LINEVAL(m->vdisplay - 1) |
+ VIDTCON2_HOZVAL(m->hdisplay - 1);
writel(val, ctx->addr + DECON_VIDTCON2);
- if (!ctx->i80_if) {
+ if (ctx->out_type != IFTYPE_I80) {
val = VIDTCON00_VBPD_F(
- mode->crtc_vtotal - mode->crtc_vsync_end) |
+ m->crtc_vtotal - m->crtc_vsync_end - 1) |
VIDTCON00_VFPD_F(
- mode->crtc_vsync_start - mode->crtc_vdisplay);
+ m->crtc_vsync_start - m->crtc_vdisplay - 1);
writel(val, ctx->addr + DECON_VIDTCON00);
val = VIDTCON01_VSPW_F(
- mode->crtc_vsync_end - mode->crtc_vsync_start);
+ m->crtc_vsync_end - m->crtc_vsync_start - 1);
writel(val, ctx->addr + DECON_VIDTCON01);
val = VIDTCON10_HBPD_F(
- mode->crtc_htotal - mode->crtc_hsync_end) |
+ m->crtc_htotal - m->crtc_hsync_end - 1) |
VIDTCON10_HFPD_F(
- mode->crtc_hsync_start - mode->crtc_hdisplay);
+ m->crtc_hsync_start - m->crtc_hdisplay - 1);
writel(val, ctx->addr + DECON_VIDTCON10);
val = VIDTCON11_HSPW_F(
- mode->crtc_hsync_end - mode->crtc_hsync_start);
+ m->crtc_hsync_end - m->crtc_hsync_start - 1);
writel(val, ctx->addr + DECON_VIDTCON11);
}
decon_setup_trigger(ctx);
/* enable output and display signal */
- val = VIDCON0_ENVID | VIDCON0_ENVID_F;
- writel(val, ctx->addr + DECON_VIDCON0);
+ decon_set_bits(ctx, DECON_VIDCON0, VIDCON0_ENVID | VIDCON0_ENVID_F, ~0);
}
-#define COORDINATE_X(x) (((x) & 0xfff) << 12)
-#define COORDINATE_Y(x) ((x) & 0xfff)
-#define OFFSIZE(x) (((x) & 0x3fff) << 14)
-#define PAGEWIDTH(x) ((x) & 0x3fff)
-
static void decon_win_set_pixfmt(struct decon_context *ctx, unsigned int win,
struct drm_framebuffer *fb)
{
@@ -214,16 +237,8 @@ static void decon_win_set_pixfmt(struct decon_context *ctx, unsigned int win,
static void decon_shadow_protect_win(struct decon_context *ctx, int win,
bool protect)
{
- u32 val;
-
- val = readl(ctx->addr + DECON_SHADOWCON);
-
- if (protect)
- val |= SHADOWCON_Wx_PROTECT(win);
- else
- val &= ~SHADOWCON_Wx_PROTECT(win);
-
- writel(val, ctx->addr + DECON_SHADOWCON);
+ decon_set_bits(ctx, DECON_SHADOWCON, SHADOWCON_Wx_PROTECT(win),
+ protect ? ~0 : 0);
}
static void decon_atomic_begin(struct exynos_drm_crtc *crtc,
@@ -231,12 +246,16 @@ static void decon_atomic_begin(struct exynos_drm_crtc *crtc,
{
struct decon_context *ctx = crtc->ctx;
- if (ctx->suspended)
+ if (test_bit(BIT_SUSPENDED, &ctx->flags))
return;
decon_shadow_protect_win(ctx, plane->zpos, true);
}
+#define BIT_VAL(x, e, s) (((x) & ((1 << ((e) - (s) + 1)) - 1)) << (s))
+#define COORDINATE_X(x) BIT_VAL((x), 23, 12)
+#define COORDINATE_Y(x) BIT_VAL((x), 11, 0)
+
static void decon_update_plane(struct exynos_drm_crtc *crtc,
struct exynos_drm_plane *plane)
{
@@ -247,7 +266,7 @@ static void decon_update_plane(struct exynos_drm_crtc *crtc,
unsigned int pitch = state->fb->pitches[0];
u32 val;
- if (ctx->suspended)
+ if (test_bit(BIT_SUSPENDED, &ctx->flags))
return;
val = COORDINATE_X(plane->crtc_x) | COORDINATE_Y(plane->crtc_y);
@@ -270,21 +289,21 @@ static void decon_update_plane(struct exynos_drm_crtc *crtc,
val = plane->dma_addr[0] + pitch * plane->crtc_h;
writel(val, ctx->addr + DECON_VIDW0xADD1B0(win));
- val = OFFSIZE(pitch - plane->crtc_w * bpp)
- | PAGEWIDTH(plane->crtc_w * bpp);
+ if (ctx->out_type != IFTYPE_HDMI)
+ val = BIT_VAL(pitch - plane->crtc_w * bpp, 27, 14)
+ | BIT_VAL(plane->crtc_w * bpp, 13, 0);
+ else
+ val = BIT_VAL(pitch - plane->crtc_w * bpp, 29, 15)
+ | BIT_VAL(plane->crtc_w * bpp, 14, 0);
writel(val, ctx->addr + DECON_VIDW0xADD2(win));
decon_win_set_pixfmt(ctx, win, state->fb);
/* window enable */
- val = readl(ctx->addr + DECON_WINCONx(win));
- val |= WINCONx_ENWIN_F;
- writel(val, ctx->addr + DECON_WINCONx(win));
+ decon_set_bits(ctx, DECON_WINCONx(win), WINCONx_ENWIN_F, ~0);
/* standalone update */
- val = readl(ctx->addr + DECON_UPDATE);
- val |= STANDALONE_UPDATE_F;
- writel(val, ctx->addr + DECON_UPDATE);
+ decon_set_bits(ctx, DECON_UPDATE, STANDALONE_UPDATE_F, ~0);
}
static void decon_disable_plane(struct exynos_drm_crtc *crtc,
@@ -292,24 +311,19 @@ static void decon_disable_plane(struct exynos_drm_crtc *crtc,
{
struct decon_context *ctx = crtc->ctx;
unsigned int win = plane->zpos;
- u32 val;
- if (ctx->suspended)
+ if (test_bit(BIT_SUSPENDED, &ctx->flags))
return;
decon_shadow_protect_win(ctx, win, true);
/* window disable */
- val = readl(ctx->addr + DECON_WINCONx(win));
- val &= ~WINCONx_ENWIN_F;
- writel(val, ctx->addr + DECON_WINCONx(win));
+ decon_set_bits(ctx, DECON_WINCONx(win), WINCONx_ENWIN_F, 0);
decon_shadow_protect_win(ctx, win, false);
/* standalone update */
- val = readl(ctx->addr + DECON_UPDATE);
- val |= STANDALONE_UPDATE_F;
- writel(val, ctx->addr + DECON_UPDATE);
+ decon_set_bits(ctx, DECON_UPDATE, STANDALONE_UPDATE_F, ~0);
}
static void decon_atomic_flush(struct exynos_drm_crtc *crtc,
@@ -317,13 +331,13 @@ static void decon_atomic_flush(struct exynos_drm_crtc *crtc,
{
struct decon_context *ctx = crtc->ctx;
- if (ctx->suspended)
+ if (test_bit(BIT_SUSPENDED, &ctx->flags))
return;
decon_shadow_protect_win(ctx, plane->zpos, false);
- if (ctx->i80_if)
- atomic_set(&ctx->win_updated, 1);
+ if (ctx->out_type == IFTYPE_I80)
+ set_bit(BIT_WIN_UPDATED, &ctx->flags);
}
static void decon_swreset(struct decon_context *ctx)
@@ -347,6 +361,17 @@ static void decon_swreset(struct decon_context *ctx)
}
WARN(tries == 0, "failed to software reset DECON\n");
+
+ if (ctx->out_type != IFTYPE_HDMI)
+ return;
+
+ writel(VIDCON0_CLKVALUP | VIDCON0_VLCKFREE, ctx->addr + DECON_VIDCON0);
+ decon_set_bits(ctx, DECON_CMU,
+ CMU_CLKGAGE_MODE_SFR_F | CMU_CLKGAGE_MODE_MEM_F, ~0);
+ writel(VIDCON1_VCLK_RUN_VDEN_DISABLE, ctx->addr + DECON_VIDCON1);
+ writel(CRCCTRL_CRCEN | CRCCTRL_CRCSTART_F | CRCCTRL_CRCCLKEN,
+ ctx->addr + DECON_CRCCTRL);
+ decon_setup_trigger(ctx);
}
static void decon_enable(struct exynos_drm_crtc *crtc)
@@ -355,11 +380,9 @@ static void decon_enable(struct exynos_drm_crtc *crtc)
int ret;
int i;
- if (!ctx->suspended)
+ if (!test_and_clear_bit(BIT_SUSPENDED, &ctx->flags))
return;
- ctx->suspended = false;
-
pm_runtime_get_sync(ctx->dev);
for (i = 0; i < ARRAY_SIZE(decon_clks_name); i++) {
@@ -368,10 +391,10 @@ static void decon_enable(struct exynos_drm_crtc *crtc)
goto err;
}
- set_bit(BIT_CLKS_ENABLED, &ctx->enabled);
+ set_bit(BIT_CLKS_ENABLED, &ctx->flags);
/* if vblank was enabled status, enable it again. */
- if (test_and_clear_bit(0, &ctx->irq_flags))
+ if (test_and_clear_bit(BIT_IRQS_ENABLED, &ctx->flags))
decon_enable_vblank(ctx->crtc);
decon_commit(ctx->crtc);
@@ -381,7 +404,7 @@ err:
while (--i >= 0)
clk_disable_unprepare(ctx->clks[i]);
- ctx->suspended = true;
+ set_bit(BIT_SUSPENDED, &ctx->flags);
}
static void decon_disable(struct exynos_drm_crtc *crtc)
@@ -389,7 +412,7 @@ static void decon_disable(struct exynos_drm_crtc *crtc)
struct decon_context *ctx = crtc->ctx;
int i;
- if (ctx->suspended)
+ if (test_bit(BIT_SUSPENDED, &ctx->flags))
return;
/*
@@ -397,7 +420,7 @@ static void decon_disable(struct exynos_drm_crtc *crtc)
* suspend that connector. Otherwise we might try to scan from
* a destroyed buffer later.
*/
- for (i = 0; i < WINDOWS_NR; i++)
+ for (i = ctx->first_win; i < WINDOWS_NR; i++)
decon_disable_plane(crtc, &ctx->planes[i]);
decon_swreset(ctx);
@@ -405,27 +428,22 @@ static void decon_disable(struct exynos_drm_crtc *crtc)
for (i = 0; i < ARRAY_SIZE(decon_clks_name); i++)
clk_disable_unprepare(ctx->clks[i]);
- clear_bit(BIT_CLKS_ENABLED, &ctx->enabled);
+ clear_bit(BIT_CLKS_ENABLED, &ctx->flags);
pm_runtime_put_sync(ctx->dev);
- ctx->suspended = true;
+ set_bit(BIT_SUSPENDED, &ctx->flags);
}
void decon_te_irq_handler(struct exynos_drm_crtc *crtc)
{
struct decon_context *ctx = crtc->ctx;
- u32 val;
- if (!test_bit(BIT_CLKS_ENABLED, &ctx->enabled))
+ if (!test_bit(BIT_CLKS_ENABLED, &ctx->flags))
return;
- if (atomic_add_unless(&ctx->win_updated, -1, 0)) {
- /* trigger */
- val = readl(ctx->addr + DECON_TRIGCON);
- val |= TRIGCON_SWTRIGCMD;
- writel(val, ctx->addr + DECON_TRIGCON);
- }
+ if (test_and_clear_bit(BIT_WIN_UPDATED, &ctx->flags))
+ decon_set_bits(ctx, DECON_TRIGCON, TRIGCON_SWTRIGCMD, ~0);
drm_crtc_handle_vblank(&ctx->crtc->base);
}
@@ -434,7 +452,6 @@ static void decon_clear_channels(struct exynos_drm_crtc *crtc)
{
struct decon_context *ctx = crtc->ctx;
int win, i, ret;
- u32 val;
DRM_DEBUG_KMS("%s\n", __FILE__);
@@ -445,25 +462,10 @@ static void decon_clear_channels(struct exynos_drm_crtc *crtc)
}
for (win = 0; win < WINDOWS_NR; win++) {
- /* shadow update disable */
- val = readl(ctx->addr + DECON_SHADOWCON);
- val |= SHADOWCON_Wx_PROTECT(win);
- writel(val, ctx->addr + DECON_SHADOWCON);
-
- /* window disable */
- val = readl(ctx->addr + DECON_WINCONx(win));
- val &= ~WINCONx_ENWIN_F;
- writel(val, ctx->addr + DECON_WINCONx(win));
-
- /* shadow update enable */
- val = readl(ctx->addr + DECON_SHADOWCON);
- val &= ~SHADOWCON_Wx_PROTECT(win);
- writel(val, ctx->addr + DECON_SHADOWCON);
-
- /* standalone update */
- val = readl(ctx->addr + DECON_UPDATE);
- val |= STANDALONE_UPDATE_F;
- writel(val, ctx->addr + DECON_UPDATE);
+ decon_shadow_protect_win(ctx, win, true);
+ decon_set_bits(ctx, DECON_WINCONx(win), WINCONx_ENWIN_F, 0);
+ decon_shadow_protect_win(ctx, win, false);
+ decon_set_bits(ctx, DECON_UPDATE, STANDALONE_UPDATE_F, ~0);
}
/* TODO: wait for possible vsync */
msleep(50);
@@ -479,7 +481,6 @@ static struct exynos_drm_crtc_ops decon_crtc_ops = {
.commit = decon_commit,
.enable_vblank = decon_enable_vblank,
.disable_vblank = decon_disable_vblank,
- .commit = decon_commit,
.atomic_begin = decon_atomic_begin,
.update_plane = decon_update_plane,
.disable_plane = decon_disable_plane,
@@ -493,26 +494,30 @@ static int decon_bind(struct device *dev, struct device *master, void *data)
struct drm_device *drm_dev = data;
struct exynos_drm_private *priv = drm_dev->dev_private;
struct exynos_drm_plane *exynos_plane;
+ enum exynos_drm_output_type out_type;
enum drm_plane_type type;
- unsigned int zpos;
+ unsigned int win;
int ret;
ctx->drm_dev = drm_dev;
ctx->pipe = priv->pipe++;
- for (zpos = 0; zpos < WINDOWS_NR; zpos++) {
- type = (zpos == ctx->default_win) ? DRM_PLANE_TYPE_PRIMARY :
- DRM_PLANE_TYPE_OVERLAY;
- ret = exynos_plane_init(drm_dev, &ctx->planes[zpos],
+ for (win = ctx->first_win; win < WINDOWS_NR; win++) {
+ int tmp = (win == ctx->first_win) ? 0 : win;
+
+ type = exynos_plane_get_type(tmp, CURSOR_WIN);
+ ret = exynos_plane_init(drm_dev, &ctx->planes[win],
1 << ctx->pipe, type, decon_formats,
- ARRAY_SIZE(decon_formats), zpos);
+ ARRAY_SIZE(decon_formats), win);
if (ret)
return ret;
}
- exynos_plane = &ctx->planes[ctx->default_win];
+ exynos_plane = &ctx->planes[ctx->first_win];
+ out_type = (ctx->out_type == IFTYPE_HDMI) ? EXYNOS_DISPLAY_TYPE_HDMI
+ : EXYNOS_DISPLAY_TYPE_LCD;
ctx->crtc = exynos_drm_crtc_create(drm_dev, &exynos_plane->base,
- ctx->pipe, EXYNOS_DISPLAY_TYPE_LCD,
+ ctx->pipe, out_type,
&decon_crtc_ops, ctx);
if (IS_ERR(ctx->crtc)) {
ret = PTR_ERR(ctx->crtc);
@@ -546,38 +551,20 @@ static const struct component_ops decon_component_ops = {
.unbind = decon_unbind,
};
-static irqreturn_t decon_vsync_irq_handler(int irq, void *dev_id)
-{
- struct decon_context *ctx = dev_id;
- u32 val;
-
- if (!test_bit(BIT_CLKS_ENABLED, &ctx->enabled))
- goto out;
-
- val = readl(ctx->addr + DECON_VIDINTCON1);
- if (val & VIDINTCON1_INTFRMPEND) {
- drm_crtc_handle_vblank(&ctx->crtc->base);
-
- /* clear */
- writel(VIDINTCON1_INTFRMPEND, ctx->addr + DECON_VIDINTCON1);
- }
-
-out:
- return IRQ_HANDLED;
-}
-
-static irqreturn_t decon_lcd_sys_irq_handler(int irq, void *dev_id)
+static irqreturn_t decon_irq_handler(int irq, void *dev_id)
{
struct decon_context *ctx = dev_id;
u32 val;
int win;
- if (!test_bit(BIT_CLKS_ENABLED, &ctx->enabled))
+ if (!test_bit(BIT_CLKS_ENABLED, &ctx->flags))
goto out;
val = readl(ctx->addr + DECON_VIDINTCON1);
- if (val & VIDINTCON1_INTFRMDONEPEND) {
- for (win = 0 ; win < WINDOWS_NR ; win++) {
+ val &= VIDINTCON1_INTFRMDONEPEND | VIDINTCON1_INTFRMPEND;
+
+ if (val) {
+ for (win = ctx->first_win; win < WINDOWS_NR ; win++) {
struct exynos_drm_plane *plane = &ctx->planes[win];
if (!plane->pending_fb)
@@ -587,16 +574,29 @@ static irqreturn_t decon_lcd_sys_irq_handler(int irq, void *dev_id)
}
/* clear */
- writel(VIDINTCON1_INTFRMDONEPEND,
- ctx->addr + DECON_VIDINTCON1);
+ writel(val, ctx->addr + DECON_VIDINTCON1);
}
out:
return IRQ_HANDLED;
}
+static const struct of_device_id exynos5433_decon_driver_dt_match[] = {
+ {
+ .compatible = "samsung,exynos5433-decon",
+ .data = (void *)IFTYPE_RGB
+ },
+ {
+ .compatible = "samsung,exynos5433-decon-tv",
+ .data = (void *)IFTYPE_HDMI
+ },
+ {},
+};
+MODULE_DEVICE_TABLE(of, exynos5433_decon_driver_dt_match);
+
static int exynos5433_decon_probe(struct platform_device *pdev)
{
+ const struct of_device_id *of_id;
struct device *dev = &pdev->dev;
struct decon_context *ctx;
struct resource *res;
@@ -607,11 +607,16 @@ static int exynos5433_decon_probe(struct platform_device *pdev)
if (!ctx)
return -ENOMEM;
- ctx->default_win = 0;
- ctx->suspended = true;
+ __set_bit(BIT_SUSPENDED, &ctx->flags);
ctx->dev = dev;
- if (of_get_child_by_name(dev->of_node, "i80-if-timings"))
- ctx->i80_if = true;
+
+ of_id = of_match_device(exynos5433_decon_driver_dt_match, &pdev->dev);
+ ctx->out_type = (enum decon_iftype)of_id->data;
+
+ if (ctx->out_type == IFTYPE_HDMI)
+ ctx->first_win = 1;
+ else if (of_get_child_by_name(dev->of_node, "i80-if-timings"))
+ ctx->out_type = IFTYPE_I80;
for (i = 0; i < ARRAY_SIZE(decon_clks_name); i++) {
struct clk *clk;
@@ -636,15 +641,14 @@ static int exynos5433_decon_probe(struct platform_device *pdev)
}
res = platform_get_resource_byname(pdev, IORESOURCE_IRQ,
- ctx->i80_if ? "lcd_sys" : "vsync");
+ (ctx->out_type == IFTYPE_I80) ? "lcd_sys" : "vsync");
if (!res) {
dev_err(dev, "cannot find IRQ resource\n");
return -ENXIO;
}
- ret = devm_request_irq(dev, res->start, ctx->i80_if ?
- decon_lcd_sys_irq_handler : decon_vsync_irq_handler, 0,
- "drm_decon", ctx);
+ ret = devm_request_irq(dev, res->start, decon_irq_handler, 0,
+ "drm_decon", ctx);
if (ret < 0) {
dev_err(dev, "lcd_sys irq request failed\n");
return ret;
@@ -675,12 +679,6 @@ static int exynos5433_decon_remove(struct platform_device *pdev)
return 0;
}
-static const struct of_device_id exynos5433_decon_driver_dt_match[] = {
- { .compatible = "samsung,exynos5433-decon" },
- {},
-};
-MODULE_DEVICE_TABLE(of, exynos5433_decon_driver_dt_match);
-
struct platform_driver exynos5433_decon_driver = {
.probe = exynos5433_decon_probe,
.remove = exynos5433_decon_remove,
diff --git a/drivers/gpu/drm/exynos/exynos7_drm_decon.c b/drivers/gpu/drm/exynos/exynos7_drm_decon.c
index e6cbaca821a4..ead2b16e237d 100644
--- a/drivers/gpu/drm/exynos/exynos7_drm_decon.c
+++ b/drivers/gpu/drm/exynos/exynos7_drm_decon.c
@@ -40,6 +40,7 @@
#define MIN_FB_WIDTH_FOR_16WORD_BURST 128
#define WINDOWS_NR 2
+#define CURSOR_WIN 1
struct decon_context {
struct device *dev;
@@ -51,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;
@@ -690,8 +690,7 @@ 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, decon_formats,
ARRAY_SIZE(decon_formats), zpos);
@@ -699,7 +698,7 @@ static int decon_bind(struct device *dev, struct device *master, void *data)
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);
diff --git a/drivers/gpu/drm/exynos/exynos_drm_crtc.c b/drivers/gpu/drm/exynos/exynos_drm_crtc.c
index 50dec0df160f..b3ba27fd9a6b 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_crtc.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_crtc.c
@@ -50,6 +50,17 @@ exynos_drm_crtc_mode_set_nofb(struct drm_crtc *crtc)
exynos_crtc->ops->commit(exynos_crtc);
}
+static int exynos_crtc_atomic_check(struct drm_crtc *crtc,
+ struct drm_crtc_state *state)
+{
+ struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc);
+
+ if (exynos_crtc->ops->atomic_check)
+ return exynos_crtc->ops->atomic_check(exynos_crtc, state);
+
+ return 0;
+}
+
static void exynos_crtc_atomic_begin(struct drm_crtc *crtc,
struct drm_crtc_state *old_crtc_state)
{
@@ -86,6 +97,7 @@ static struct drm_crtc_helper_funcs exynos_crtc_helper_funcs = {
.enable = exynos_drm_crtc_enable,
.disable = exynos_drm_crtc_disable,
.mode_set_nofb = exynos_drm_crtc_mode_set_nofb,
+ .atomic_check = exynos_crtc_atomic_check,
.atomic_begin = exynos_crtc_atomic_begin,
.atomic_flush = exynos_crtc_atomic_flush,
};
diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.c b/drivers/gpu/drm/exynos/exynos_drm_drv.c
index 09c4c6af8cd1..2c6019d6a205 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_drv.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_drv.c
@@ -529,8 +529,10 @@ static struct platform_driver *const exynos_drm_kms_drivers[] = {
#ifdef CONFIG_DRM_EXYNOS_DSI
&dsi_driver,
#endif
-#ifdef CONFIG_DRM_EXYNOS_HDMI
+#ifdef CONFIG_DRM_EXYNOS_MIXER
&mixer_driver,
+#endif
+#ifdef CONFIG_DRM_EXYNOS_HDMI
&hdmi_driver,
#endif
#ifdef CONFIG_DRM_EXYNOS_VIDI
diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.h b/drivers/gpu/drm/exynos/exynos_drm_drv.h
index 6c717ba672db..f1eda7fa4e3c 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_drv.h
+++ b/drivers/gpu/drm/exynos/exynos_drm_drv.h
@@ -22,6 +22,8 @@
#define MAX_PLANE 5
#define MAX_FB_BUFFER 4
+#define DEFAULT_WIN 0
+
#define to_exynos_crtc(x) container_of(x, struct exynos_drm_crtc, base)
#define to_exynos_plane(x) container_of(x, struct exynos_drm_plane, base)
@@ -87,6 +89,7 @@ struct exynos_drm_plane {
* @disable_vblank: specific driver callback for disabling vblank interrupt.
* @wait_for_vblank: wait for vblank interrupt to make sure that
* hardware overlay is updated.
+ * @atomic_check: validate state
* @atomic_begin: prepare a window to receive a update
* @atomic_flush: mark the end of a window update
* @update_plane: apply hardware specific overlay data to registers.
@@ -106,6 +109,8 @@ struct exynos_drm_crtc_ops {
int (*enable_vblank)(struct exynos_drm_crtc *crtc);
void (*disable_vblank)(struct exynos_drm_crtc *crtc);
void (*wait_for_vblank)(struct exynos_drm_crtc *crtc);
+ int (*atomic_check)(struct exynos_drm_crtc *crtc,
+ struct drm_crtc_state *state);
void (*atomic_begin)(struct exynos_drm_crtc *crtc,
struct exynos_drm_plane *plane);
void (*update_plane)(struct exynos_drm_crtc *crtc,
diff --git a/drivers/gpu/drm/exynos/exynos_drm_fb.c b/drivers/gpu/drm/exynos/exynos_drm_fb.c
index 084280859589..fcea28bdbc42 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_fb.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_fb.c
@@ -32,15 +32,15 @@
* exynos specific framebuffer structure.
*
* @fb: drm framebuffer obejct.
- * @exynos_gem_obj: array of exynos specific gem object containing a gem object.
+ * @exynos_gem: array of exynos specific gem object containing a gem object.
*/
struct exynos_drm_fb {
- struct drm_framebuffer fb;
- struct exynos_drm_gem_obj *exynos_gem_obj[MAX_FB_BUFFER];
+ struct drm_framebuffer fb;
+ struct exynos_drm_gem *exynos_gem[MAX_FB_BUFFER];
};
static int check_fb_gem_memory_type(struct drm_device *drm_dev,
- struct exynos_drm_gem_obj *exynos_gem_obj)
+ struct exynos_drm_gem *exynos_gem)
{
unsigned int flags;
@@ -51,7 +51,7 @@ static int check_fb_gem_memory_type(struct drm_device *drm_dev,
if (is_drm_iommu_supported(drm_dev))
return 0;
- flags = exynos_gem_obj->flags;
+ flags = exynos_gem->flags;
/*
* without iommu support, not support physically non-continuous memory
@@ -75,13 +75,13 @@ static void exynos_drm_fb_destroy(struct drm_framebuffer *fb)
drm_framebuffer_cleanup(fb);
- for (i = 0; i < ARRAY_SIZE(exynos_fb->exynos_gem_obj); i++) {
+ for (i = 0; i < ARRAY_SIZE(exynos_fb->exynos_gem); i++) {
struct drm_gem_object *obj;
- if (exynos_fb->exynos_gem_obj[i] == NULL)
+ if (exynos_fb->exynos_gem[i] == NULL)
continue;
- obj = &exynos_fb->exynos_gem_obj[i]->base;
+ obj = &exynos_fb->exynos_gem[i]->base;
drm_gem_object_unreference_unlocked(obj);
}
@@ -96,7 +96,7 @@ static int exynos_drm_fb_create_handle(struct drm_framebuffer *fb,
struct exynos_drm_fb *exynos_fb = to_exynos_fb(fb);
return drm_gem_handle_create(file_priv,
- &exynos_fb->exynos_gem_obj[0]->base, handle);
+ &exynos_fb->exynos_gem[0]->base, handle);
}
static int exynos_drm_fb_dirty(struct drm_framebuffer *fb,
@@ -118,7 +118,7 @@ static struct drm_framebuffer_funcs exynos_drm_fb_funcs = {
struct drm_framebuffer *
exynos_drm_framebuffer_init(struct drm_device *dev,
struct drm_mode_fb_cmd2 *mode_cmd,
- struct exynos_drm_gem_obj **gem_obj,
+ struct exynos_drm_gem **exynos_gem,
int count)
{
struct exynos_drm_fb *exynos_fb;
@@ -130,11 +130,11 @@ exynos_drm_framebuffer_init(struct drm_device *dev,
return ERR_PTR(-ENOMEM);
for (i = 0; i < count; i++) {
- ret = check_fb_gem_memory_type(dev, gem_obj[i]);
+ ret = check_fb_gem_memory_type(dev, exynos_gem[i]);
if (ret < 0)
goto err;
- exynos_fb->exynos_gem_obj[i] = gem_obj[i];
+ exynos_fb->exynos_gem[i] = exynos_gem[i];
}
drm_helper_mode_fill_fb_struct(&exynos_fb->fb, mode_cmd);
@@ -156,7 +156,7 @@ static struct drm_framebuffer *
exynos_user_fb_create(struct drm_device *dev, struct drm_file *file_priv,
struct drm_mode_fb_cmd2 *mode_cmd)
{
- struct exynos_drm_gem_obj *gem_objs[MAX_FB_BUFFER];
+ struct exynos_drm_gem *exynos_gem[MAX_FB_BUFFER];
struct drm_gem_object *obj;
struct drm_framebuffer *fb;
int i;
@@ -171,10 +171,10 @@ exynos_user_fb_create(struct drm_device *dev, struct drm_file *file_priv,
goto err;
}
- gem_objs[i] = to_exynos_gem_obj(obj);
+ exynos_gem[i] = to_exynos_gem(obj);
}
- fb = exynos_drm_framebuffer_init(dev, mode_cmd, gem_objs, i);
+ fb = exynos_drm_framebuffer_init(dev, mode_cmd, exynos_gem, i);
if (IS_ERR(fb)) {
ret = PTR_ERR(fb);
goto err;
@@ -184,27 +184,26 @@ exynos_user_fb_create(struct drm_device *dev, struct drm_file *file_priv,
err:
while (i--)
- drm_gem_object_unreference_unlocked(&gem_objs[i]->base);
+ drm_gem_object_unreference_unlocked(&exynos_gem[i]->base);
return ERR_PTR(ret);
}
-struct exynos_drm_gem_obj *exynos_drm_fb_gem_obj(struct drm_framebuffer *fb,
- int index)
+struct exynos_drm_gem *exynos_drm_fb_gem(struct drm_framebuffer *fb, int index)
{
struct exynos_drm_fb *exynos_fb = to_exynos_fb(fb);
- struct exynos_drm_gem_obj *obj;
+ struct exynos_drm_gem *exynos_gem;
if (index >= MAX_FB_BUFFER)
return NULL;
- obj = exynos_fb->exynos_gem_obj[index];
- if (!obj)
+ exynos_gem = exynos_fb->exynos_gem[index];
+ if (!exynos_gem)
return NULL;
- DRM_DEBUG_KMS("dma_addr = 0x%lx\n", (unsigned long)obj->dma_addr);
+ DRM_DEBUG_KMS("dma_addr: 0x%lx\n", (unsigned long)exynos_gem->dma_addr);
- return obj;
+ return exynos_gem;
}
static void exynos_drm_output_poll_changed(struct drm_device *dev)
diff --git a/drivers/gpu/drm/exynos/exynos_drm_fb.h b/drivers/gpu/drm/exynos/exynos_drm_fb.h
index 85e4445b920e..726a2d44371f 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_fb.h
+++ b/drivers/gpu/drm/exynos/exynos_drm_fb.h
@@ -19,12 +19,11 @@
struct drm_framebuffer *
exynos_drm_framebuffer_init(struct drm_device *dev,
struct drm_mode_fb_cmd2 *mode_cmd,
- struct exynos_drm_gem_obj **gem_obj,
+ struct exynos_drm_gem **exynos_gem,
int count);
/* get gem object of a drm framebuffer */
-struct exynos_drm_gem_obj *exynos_drm_fb_gem_obj(struct drm_framebuffer *fb,
- int index);
+struct exynos_drm_gem *exynos_drm_fb_gem(struct drm_framebuffer *fb, int index);
void exynos_drm_mode_config_init(struct drm_device *dev);
diff --git a/drivers/gpu/drm/exynos/exynos_drm_fbdev.c b/drivers/gpu/drm/exynos/exynos_drm_fbdev.c
index a221f753ad9c..f6118baa8e3e 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_fbdev.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_fbdev.c
@@ -30,8 +30,8 @@
drm_fb_helper)
struct exynos_drm_fbdev {
- struct drm_fb_helper drm_fb_helper;
- struct exynos_drm_gem_obj *obj;
+ struct drm_fb_helper drm_fb_helper;
+ struct exynos_drm_gem *exynos_gem;
};
static int exynos_drm_fb_mmap(struct fb_info *info,
@@ -39,7 +39,7 @@ static int exynos_drm_fb_mmap(struct fb_info *info,
{
struct drm_fb_helper *helper = info->par;
struct exynos_drm_fbdev *exynos_fbd = to_exynos_fbdev(helper);
- struct exynos_drm_gem_obj *obj = exynos_fbd->obj;
+ struct exynos_drm_gem *exynos_gem = exynos_fbd->exynos_gem;
unsigned long vm_size;
int ret;
@@ -47,11 +47,12 @@ static int exynos_drm_fb_mmap(struct fb_info *info,
vm_size = vma->vm_end - vma->vm_start;
- if (vm_size > obj->size)
+ if (vm_size > exynos_gem->size)
return -EINVAL;
- ret = dma_mmap_attrs(helper->dev->dev, vma, obj->pages, obj->dma_addr,
- obj->size, &obj->dma_attrs);
+ ret = dma_mmap_attrs(helper->dev->dev, vma, exynos_gem->pages,
+ exynos_gem->dma_addr, exynos_gem->size,
+ &exynos_gem->dma_attrs);
if (ret < 0) {
DRM_ERROR("failed to mmap.\n");
return ret;
@@ -75,7 +76,7 @@ static struct fb_ops exynos_drm_fb_ops = {
static int exynos_drm_fbdev_update(struct drm_fb_helper *helper,
struct drm_fb_helper_surface_size *sizes,
- struct exynos_drm_gem_obj *obj)
+ struct exynos_drm_gem *exynos_gem)
{
struct fb_info *fbi;
struct drm_framebuffer *fb = helper->fb;
@@ -96,11 +97,11 @@ static int exynos_drm_fbdev_update(struct drm_fb_helper *helper,
drm_fb_helper_fill_fix(fbi, fb->pitches[0], fb->depth);
drm_fb_helper_fill_var(fbi, helper, sizes->fb_width, sizes->fb_height);
- nr_pages = obj->size >> PAGE_SHIFT;
+ nr_pages = exynos_gem->size >> PAGE_SHIFT;
- obj->kvaddr = (void __iomem *) vmap(obj->pages, nr_pages, VM_MAP,
- pgprot_writecombine(PAGE_KERNEL));
- if (!obj->kvaddr) {
+ exynos_gem->kvaddr = (void __iomem *) vmap(exynos_gem->pages, nr_pages,
+ VM_MAP, pgprot_writecombine(PAGE_KERNEL));
+ if (!exynos_gem->kvaddr) {
DRM_ERROR("failed to map pages to kernel space.\n");
drm_fb_helper_release_fbi(helper);
return -EIO;
@@ -109,7 +110,7 @@ static int exynos_drm_fbdev_update(struct drm_fb_helper *helper,
offset = fbi->var.xoffset * (fb->bits_per_pixel >> 3);
offset += fbi->var.yoffset * fb->pitches[0];
- fbi->screen_base = obj->kvaddr + offset;
+ fbi->screen_base = exynos_gem->kvaddr + offset;
fbi->screen_size = size;
fbi->fix.smem_len = size;
@@ -120,7 +121,7 @@ static int exynos_drm_fbdev_create(struct drm_fb_helper *helper,
struct drm_fb_helper_surface_size *sizes)
{
struct exynos_drm_fbdev *exynos_fbdev = to_exynos_fbdev(helper);
- struct exynos_drm_gem_obj *obj;
+ struct exynos_drm_gem *exynos_gem;
struct drm_device *dev = helper->dev;
struct drm_mode_fb_cmd2 mode_cmd = { 0 };
struct platform_device *pdev = dev->platformdev;
@@ -141,32 +142,34 @@ static int exynos_drm_fbdev_create(struct drm_fb_helper *helper,
size = mode_cmd.pitches[0] * mode_cmd.height;
- obj = exynos_drm_gem_create(dev, EXYNOS_BO_CONTIG, size);
+ exynos_gem = exynos_drm_gem_create(dev, EXYNOS_BO_CONTIG, size);
/*
* If physically contiguous memory allocation fails and if IOMMU is
* supported then try to get buffer from non physically contiguous
* memory area.
*/
- if (IS_ERR(obj) && is_drm_iommu_supported(dev)) {
+ if (IS_ERR(exynos_gem) && is_drm_iommu_supported(dev)) {
dev_warn(&pdev->dev, "contiguous FB allocation failed, falling back to non-contiguous\n");
- obj = exynos_drm_gem_create(dev, EXYNOS_BO_NONCONTIG, size);
+ exynos_gem = exynos_drm_gem_create(dev, EXYNOS_BO_NONCONTIG,
+ size);
}
- if (IS_ERR(obj)) {
- ret = PTR_ERR(obj);
+ if (IS_ERR(exynos_gem)) {
+ ret = PTR_ERR(exynos_gem);
goto out;
}
- exynos_fbdev->obj = obj;
+ exynos_fbdev->exynos_gem = exynos_gem;
- helper->fb = exynos_drm_framebuffer_init(dev, &mode_cmd, &obj, 1);
+ helper->fb =
+ exynos_drm_framebuffer_init(dev, &mode_cmd, &exynos_gem, 1);
if (IS_ERR(helper->fb)) {
DRM_ERROR("failed to create drm framebuffer.\n");
ret = PTR_ERR(helper->fb);
goto err_destroy_gem;
}
- ret = exynos_drm_fbdev_update(helper, sizes, obj);
+ ret = exynos_drm_fbdev_update(helper, sizes, exynos_gem);
if (ret < 0)
goto err_destroy_framebuffer;
@@ -176,7 +179,7 @@ static int exynos_drm_fbdev_create(struct drm_fb_helper *helper,
err_destroy_framebuffer:
drm_framebuffer_cleanup(helper->fb);
err_destroy_gem:
- exynos_drm_gem_destroy(obj);
+ exynos_drm_gem_destroy(exynos_gem);
/*
* if failed, all resources allocated above would be released by
@@ -269,11 +272,11 @@ static void exynos_drm_fbdev_destroy(struct drm_device *dev,
struct drm_fb_helper *fb_helper)
{
struct exynos_drm_fbdev *exynos_fbd = to_exynos_fbdev(fb_helper);
- struct exynos_drm_gem_obj *obj = exynos_fbd->obj;
+ struct exynos_drm_gem *exynos_gem = exynos_fbd->exynos_gem;
struct drm_framebuffer *fb;
- if (obj->kvaddr)
- vunmap(obj->kvaddr);
+ if (exynos_gem->kvaddr)
+ vunmap(exynos_gem->kvaddr);
/* release drm framebuffer and real buffer */
if (fb_helper->fb && fb_helper->fb->funcs) {
diff --git a/drivers/gpu/drm/exynos/exynos_drm_fimc.c b/drivers/gpu/drm/exynos/exynos_drm_fimc.c
index dd3a5e6d58c8..c747824f3c98 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_fimc.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_fimc.c
@@ -466,7 +466,7 @@ static int fimc_src_set_fmt_order(struct fimc_context *ctx, u32 fmt)
EXYNOS_MSCTRL_C_INT_IN_2PLANE);
break;
default:
- dev_err(ippdrv->dev, "inavlid source yuv order 0x%x.\n", fmt);
+ dev_err(ippdrv->dev, "invalid source yuv order 0x%x.\n", fmt);
return -EINVAL;
}
@@ -513,7 +513,7 @@ static int fimc_src_set_fmt(struct device *dev, u32 fmt)
cfg |= EXYNOS_MSCTRL_INFORMAT_YCBCR420;
break;
default:
- dev_err(ippdrv->dev, "inavlid source format 0x%x.\n", fmt);
+ dev_err(ippdrv->dev, "invalid source format 0x%x.\n", fmt);
return -EINVAL;
}
@@ -578,7 +578,7 @@ static int fimc_src_set_transf(struct device *dev,
cfg1 &= ~EXYNOS_MSCTRL_FLIP_Y_MIRROR;
break;
default:
- dev_err(ippdrv->dev, "inavlid degree value %d.\n", degree);
+ dev_err(ippdrv->dev, "invalid degree value %d.\n", degree);
return -EINVAL;
}
@@ -701,7 +701,7 @@ static int fimc_src_set_addr(struct device *dev,
property->prop_id, buf_id, buf_type);
if (buf_id > FIMC_MAX_SRC) {
- dev_info(ippdrv->dev, "inavlid buf_id %d.\n", buf_id);
+ dev_info(ippdrv->dev, "invalid buf_id %d.\n", buf_id);
return -ENOMEM;
}
@@ -812,7 +812,7 @@ static int fimc_dst_set_fmt_order(struct fimc_context *ctx, u32 fmt)
cfg |= EXYNOS_CIOCTRL_YCBCR_2PLANE;
break;
default:
- dev_err(ippdrv->dev, "inavlid target yuv order 0x%x.\n", fmt);
+ dev_err(ippdrv->dev, "invalid target yuv order 0x%x.\n", fmt);
return -EINVAL;
}
@@ -865,7 +865,7 @@ static int fimc_dst_set_fmt(struct device *dev, u32 fmt)
cfg |= EXYNOS_CITRGFMT_OUTFORMAT_YCBCR420;
break;
default:
- dev_err(ippdrv->dev, "inavlid target format 0x%x.\n",
+ dev_err(ippdrv->dev, "invalid target format 0x%x.\n",
fmt);
return -EINVAL;
}
@@ -929,7 +929,7 @@ static int fimc_dst_set_transf(struct device *dev,
cfg &= ~EXYNOS_CITRGFMT_FLIP_Y_MIRROR;
break;
default:
- dev_err(ippdrv->dev, "inavlid degree value %d.\n", degree);
+ dev_err(ippdrv->dev, "invalid degree value %d.\n", degree);
return -EINVAL;
}
@@ -1160,7 +1160,7 @@ static int fimc_dst_set_addr(struct device *dev,
property->prop_id, buf_id, buf_type);
if (buf_id > FIMC_MAX_DST) {
- dev_info(ippdrv->dev, "inavlid buf_id %d.\n", buf_id);
+ dev_info(ippdrv->dev, "invalid buf_id %d.\n", buf_id);
return -ENOMEM;
}
diff --git a/drivers/gpu/drm/exynos/exynos_drm_fimd.c b/drivers/gpu/drm/exynos/exynos_drm_fimd.c
index 3d1aba67758b..bd75c1531cac 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_fimd.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_fimd.c
@@ -87,6 +87,7 @@
/* FIMD has totally five hardware windows. */
#define WINDOWS_NR 5
+#define CURSOR_WIN 4
struct fimd_driver_data {
unsigned int timing_base;
@@ -153,7 +154,6 @@ struct fimd_context {
struct clk *lcd_clk;
void __iomem *regs;
struct regmap *sysreg;
- unsigned int default_win;
unsigned long irq_flags;
u32 vidcon0;
u32 vidcon1;
@@ -949,8 +949,7 @@ static int fimd_bind(struct device *dev, struct device *master, void *data)
ctx->pipe = priv->pipe++;
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, fimd_formats,
ARRAY_SIZE(fimd_formats), zpos);
@@ -958,7 +957,7 @@ static int fimd_bind(struct device *dev, struct device *master, void *data)
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,
&fimd_crtc_ops, ctx);
diff --git a/drivers/gpu/drm/exynos/exynos_drm_gem.c b/drivers/gpu/drm/exynos/exynos_drm_gem.c
index 407afedb6003..252eb301470c 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_gem.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_gem.c
@@ -20,97 +20,108 @@
#include "exynos_drm_gem.h"
#include "exynos_drm_iommu.h"
-static int exynos_drm_alloc_buf(struct exynos_drm_gem_obj *obj)
+static int exynos_drm_alloc_buf(struct exynos_drm_gem *exynos_gem)
{
- struct drm_device *dev = obj->base.dev;
+ struct drm_device *dev = exynos_gem->base.dev;
enum dma_attr attr;
unsigned int nr_pages;
+ struct sg_table sgt;
+ int ret = -ENOMEM;
- if (obj->dma_addr) {
+ if (exynos_gem->dma_addr) {
DRM_DEBUG_KMS("already allocated.\n");
return 0;
}
- init_dma_attrs(&obj->dma_attrs);
+ init_dma_attrs(&exynos_gem->dma_attrs);
/*
* if EXYNOS_BO_CONTIG, fully physically contiguous memory
* region will be allocated else physically contiguous
* as possible.
*/
- if (!(obj->flags & EXYNOS_BO_NONCONTIG))
- dma_set_attr(DMA_ATTR_FORCE_CONTIGUOUS, &obj->dma_attrs);
+ if (!(exynos_gem->flags & EXYNOS_BO_NONCONTIG))
+ dma_set_attr(DMA_ATTR_FORCE_CONTIGUOUS, &exynos_gem->dma_attrs);
/*
* if EXYNOS_BO_WC or EXYNOS_BO_NONCACHABLE, writecombine mapping
* else cachable mapping.
*/
- if (obj->flags & EXYNOS_BO_WC || !(obj->flags & EXYNOS_BO_CACHABLE))
+ if (exynos_gem->flags & EXYNOS_BO_WC ||
+ !(exynos_gem->flags & EXYNOS_BO_CACHABLE))
attr = DMA_ATTR_WRITE_COMBINE;
else
attr = DMA_ATTR_NON_CONSISTENT;
- dma_set_attr(attr, &obj->dma_attrs);
- dma_set_attr(DMA_ATTR_NO_KERNEL_MAPPING, &obj->dma_attrs);
+ dma_set_attr(attr, &exynos_gem->dma_attrs);
+ dma_set_attr(DMA_ATTR_NO_KERNEL_MAPPING, &exynos_gem->dma_attrs);
- nr_pages = obj->size >> PAGE_SHIFT;
+ nr_pages = exynos_gem->size >> PAGE_SHIFT;
- if (!is_drm_iommu_supported(dev)) {
- obj->pages = drm_calloc_large(nr_pages, sizeof(struct page *));
- if (!obj->pages) {
- DRM_ERROR("failed to allocate pages.\n");
- return -ENOMEM;
- }
+ exynos_gem->pages = drm_calloc_large(nr_pages, sizeof(struct page *));
+ if (!exynos_gem->pages) {
+ DRM_ERROR("failed to allocate pages.\n");
+ return -ENOMEM;
}
- obj->cookie = dma_alloc_attrs(dev->dev, obj->size, &obj->dma_addr,
- GFP_KERNEL, &obj->dma_attrs);
- if (!obj->cookie) {
+ exynos_gem->cookie = dma_alloc_attrs(dev->dev, exynos_gem->size,
+ &exynos_gem->dma_addr, GFP_KERNEL,
+ &exynos_gem->dma_attrs);
+ if (!exynos_gem->cookie) {
DRM_ERROR("failed to allocate buffer.\n");
- if (obj->pages)
- drm_free_large(obj->pages);
- return -ENOMEM;
+ goto err_free;
}
- if (obj->pages) {
- dma_addr_t start_addr;
- unsigned int i = 0;
-
- start_addr = obj->dma_addr;
- while (i < nr_pages) {
- obj->pages[i] = pfn_to_page(dma_to_pfn(dev->dev,
- start_addr));
- start_addr += PAGE_SIZE;
- i++;
- }
- } else {
- obj->pages = obj->cookie;
+ ret = dma_get_sgtable_attrs(dev->dev, &sgt, exynos_gem->cookie,
+ exynos_gem->dma_addr, exynos_gem->size,
+ &exynos_gem->dma_attrs);
+ if (ret < 0) {
+ DRM_ERROR("failed to get sgtable.\n");
+ goto err_dma_free;
}
+ if (drm_prime_sg_to_page_addr_arrays(&sgt, exynos_gem->pages, NULL,
+ nr_pages)) {
+ DRM_ERROR("invalid sgtable.\n");
+ ret = -EINVAL;
+ goto err_sgt_free;
+ }
+
+ sg_free_table(&sgt);
+
DRM_DEBUG_KMS("dma_addr(0x%lx), size(0x%lx)\n",
- (unsigned long)obj->dma_addr,
- obj->size);
+ (unsigned long)exynos_gem->dma_addr, exynos_gem->size);
return 0;
+
+err_sgt_free:
+ sg_free_table(&sgt);
+err_dma_free:
+ dma_free_attrs(dev->dev, exynos_gem->size, exynos_gem->cookie,
+ exynos_gem->dma_addr, &exynos_gem->dma_attrs);
+err_free:
+ drm_free_large(exynos_gem->pages);
+
+ return ret;
}
-static void exynos_drm_free_buf(struct exynos_drm_gem_obj *obj)
+static void exynos_drm_free_buf(struct exynos_drm_gem *exynos_gem)
{
- struct drm_device *dev = obj->base.dev;
+ struct drm_device *dev = exynos_gem->base.dev;
- if (!obj->dma_addr) {
+ if (!exynos_gem->dma_addr) {
DRM_DEBUG_KMS("dma_addr is invalid.\n");
return;
}
DRM_DEBUG_KMS("dma_addr(0x%lx), size(0x%lx)\n",
- (unsigned long)obj->dma_addr, obj->size);
+ (unsigned long)exynos_gem->dma_addr, exynos_gem->size);
- dma_free_attrs(dev->dev, obj->size, obj->cookie,
- (dma_addr_t)obj->dma_addr, &obj->dma_attrs);
+ dma_free_attrs(dev->dev, exynos_gem->size, exynos_gem->cookie,
+ (dma_addr_t)exynos_gem->dma_addr,
+ &exynos_gem->dma_attrs);
- if (!is_drm_iommu_supported(dev))
- drm_free_large(obj->pages);
+ drm_free_large(exynos_gem->pages);
}
static int exynos_drm_gem_handle_create(struct drm_gem_object *obj,
@@ -135,9 +146,9 @@ static int exynos_drm_gem_handle_create(struct drm_gem_object *obj,
return 0;
}
-void exynos_drm_gem_destroy(struct exynos_drm_gem_obj *exynos_gem_obj)
+void exynos_drm_gem_destroy(struct exynos_drm_gem *exynos_gem)
{
- struct drm_gem_object *obj = &exynos_gem_obj->base;
+ struct drm_gem_object *obj = &exynos_gem->base;
DRM_DEBUG_KMS("handle count = %d\n", obj->handle_count);
@@ -148,21 +159,21 @@ void exynos_drm_gem_destroy(struct exynos_drm_gem_obj *exynos_gem_obj)
* once dmabuf's refcount becomes 0.
*/
if (obj->import_attach)
- drm_prime_gem_destroy(obj, exynos_gem_obj->sgt);
+ drm_prime_gem_destroy(obj, exynos_gem->sgt);
else
- exynos_drm_free_buf(exynos_gem_obj);
+ exynos_drm_free_buf(exynos_gem);
/* release file pointer to gem object. */
drm_gem_object_release(obj);
- kfree(exynos_gem_obj);
+ kfree(exynos_gem);
}
unsigned long exynos_drm_gem_get_size(struct drm_device *dev,
unsigned int gem_handle,
struct drm_file *file_priv)
{
- struct exynos_drm_gem_obj *exynos_gem_obj;
+ struct exynos_drm_gem *exynos_gem;
struct drm_gem_object *obj;
obj = drm_gem_object_lookup(dev, file_priv, gem_handle);
@@ -171,51 +182,51 @@ unsigned long exynos_drm_gem_get_size(struct drm_device *dev,
return 0;
}
- exynos_gem_obj = to_exynos_gem_obj(obj);
+ exynos_gem = to_exynos_gem(obj);
drm_gem_object_unreference_unlocked(obj);
- return exynos_gem_obj->size;
+ return exynos_gem->size;
}
-static struct exynos_drm_gem_obj *exynos_drm_gem_init(struct drm_device *dev,
- unsigned long size)
+static struct exynos_drm_gem *exynos_drm_gem_init(struct drm_device *dev,
+ unsigned long size)
{
- struct exynos_drm_gem_obj *exynos_gem_obj;
+ struct exynos_drm_gem *exynos_gem;
struct drm_gem_object *obj;
int ret;
- exynos_gem_obj = kzalloc(sizeof(*exynos_gem_obj), GFP_KERNEL);
- if (!exynos_gem_obj)
+ exynos_gem = kzalloc(sizeof(*exynos_gem), GFP_KERNEL);
+ if (!exynos_gem)
return ERR_PTR(-ENOMEM);
- exynos_gem_obj->size = size;
- obj = &exynos_gem_obj->base;
+ exynos_gem->size = size;
+ obj = &exynos_gem->base;
ret = drm_gem_object_init(dev, obj, size);
if (ret < 0) {
DRM_ERROR("failed to initialize gem object\n");
- kfree(exynos_gem_obj);
+ kfree(exynos_gem);
return ERR_PTR(ret);
}
ret = drm_gem_create_mmap_offset(obj);
if (ret < 0) {
drm_gem_object_release(obj);
- kfree(exynos_gem_obj);
+ kfree(exynos_gem);
return ERR_PTR(ret);
}
DRM_DEBUG_KMS("created file object = 0x%x\n", (unsigned int)obj->filp);
- return exynos_gem_obj;
+ return exynos_gem;
}
-struct exynos_drm_gem_obj *exynos_drm_gem_create(struct drm_device *dev,
- unsigned int flags,
- unsigned long size)
+struct exynos_drm_gem *exynos_drm_gem_create(struct drm_device *dev,
+ unsigned int flags,
+ unsigned long size)
{
- struct exynos_drm_gem_obj *exynos_gem_obj;
+ struct exynos_drm_gem *exynos_gem;
int ret;
if (flags & ~(EXYNOS_BO_MASK)) {
@@ -230,38 +241,38 @@ struct exynos_drm_gem_obj *exynos_drm_gem_create(struct drm_device *dev,
size = roundup(size, PAGE_SIZE);
- exynos_gem_obj = exynos_drm_gem_init(dev, size);
- if (IS_ERR(exynos_gem_obj))
- return exynos_gem_obj;
+ exynos_gem = exynos_drm_gem_init(dev, size);
+ if (IS_ERR(exynos_gem))
+ return exynos_gem;
/* set memory type and cache attribute from user side. */
- exynos_gem_obj->flags = flags;
+ exynos_gem->flags = flags;
- ret = exynos_drm_alloc_buf(exynos_gem_obj);
+ ret = exynos_drm_alloc_buf(exynos_gem);
if (ret < 0) {
- drm_gem_object_release(&exynos_gem_obj->base);
- kfree(exynos_gem_obj);
+ drm_gem_object_release(&exynos_gem->base);
+ kfree(exynos_gem);
return ERR_PTR(ret);
}
- return exynos_gem_obj;
+ return exynos_gem;
}
int exynos_drm_gem_create_ioctl(struct drm_device *dev, void *data,
struct drm_file *file_priv)
{
struct drm_exynos_gem_create *args = data;
- struct exynos_drm_gem_obj *exynos_gem_obj;
+ struct exynos_drm_gem *exynos_gem;
int ret;
- exynos_gem_obj = exynos_drm_gem_create(dev, args->flags, args->size);
- if (IS_ERR(exynos_gem_obj))
- return PTR_ERR(exynos_gem_obj);
+ exynos_gem = exynos_drm_gem_create(dev, args->flags, args->size);
+ if (IS_ERR(exynos_gem))
+ return PTR_ERR(exynos_gem);
- ret = exynos_drm_gem_handle_create(&exynos_gem_obj->base, file_priv,
- &args->handle);
+ ret = exynos_drm_gem_handle_create(&exynos_gem->base, file_priv,
+ &args->handle);
if (ret) {
- exynos_drm_gem_destroy(exynos_gem_obj);
+ exynos_drm_gem_destroy(exynos_gem);
return ret;
}
@@ -272,7 +283,7 @@ dma_addr_t *exynos_drm_gem_get_dma_addr(struct drm_device *dev,
unsigned int gem_handle,
struct drm_file *filp)
{
- struct exynos_drm_gem_obj *exynos_gem_obj;
+ struct exynos_drm_gem *exynos_gem;
struct drm_gem_object *obj;
obj = drm_gem_object_lookup(dev, filp, gem_handle);
@@ -281,9 +292,9 @@ dma_addr_t *exynos_drm_gem_get_dma_addr(struct drm_device *dev,
return ERR_PTR(-EINVAL);
}
- exynos_gem_obj = to_exynos_gem_obj(obj);
+ exynos_gem = to_exynos_gem(obj);
- return &exynos_gem_obj->dma_addr;
+ return &exynos_gem->dma_addr;
}
void exynos_drm_gem_put_dma_addr(struct drm_device *dev,
@@ -307,10 +318,10 @@ void exynos_drm_gem_put_dma_addr(struct drm_device *dev,
drm_gem_object_unreference_unlocked(obj);
}
-static int exynos_drm_gem_mmap_buffer(struct exynos_drm_gem_obj *exynos_gem_obj,
+static int exynos_drm_gem_mmap_buffer(struct exynos_drm_gem *exynos_gem,
struct vm_area_struct *vma)
{
- struct drm_device *drm_dev = exynos_gem_obj->base.dev;
+ struct drm_device *drm_dev = exynos_gem->base.dev;
unsigned long vm_size;
int ret;
@@ -320,12 +331,12 @@ static int exynos_drm_gem_mmap_buffer(struct exynos_drm_gem_obj *exynos_gem_obj,
vm_size = vma->vm_end - vma->vm_start;
/* check if user-requested size is valid. */
- if (vm_size > exynos_gem_obj->size)
+ if (vm_size > exynos_gem->size)
return -EINVAL;
- ret = dma_mmap_attrs(drm_dev->dev, vma, exynos_gem_obj->pages,
- exynos_gem_obj->dma_addr, exynos_gem_obj->size,
- &exynos_gem_obj->dma_attrs);
+ ret = dma_mmap_attrs(drm_dev->dev, vma, exynos_gem->pages,
+ exynos_gem->dma_addr, exynos_gem->size,
+ &exynos_gem->dma_attrs);
if (ret < 0) {
DRM_ERROR("failed to mmap.\n");
return ret;
@@ -337,7 +348,7 @@ static int exynos_drm_gem_mmap_buffer(struct exynos_drm_gem_obj *exynos_gem_obj,
int exynos_drm_gem_get_ioctl(struct drm_device *dev, void *data,
struct drm_file *file_priv)
{
- struct exynos_drm_gem_obj *exynos_gem_obj;
+ struct exynos_drm_gem *exynos_gem;
struct drm_exynos_gem_info *args = data;
struct drm_gem_object *obj;
@@ -350,10 +361,10 @@ int exynos_drm_gem_get_ioctl(struct drm_device *dev, void *data,
return -EINVAL;
}
- exynos_gem_obj = to_exynos_gem_obj(obj);
+ exynos_gem = to_exynos_gem(obj);
- args->flags = exynos_gem_obj->flags;
- args->size = exynos_gem_obj->size;
+ args->flags = exynos_gem->flags;
+ args->size = exynos_gem->size;
drm_gem_object_unreference(obj);
mutex_unlock(&dev->struct_mutex);
@@ -389,14 +400,14 @@ void exynos_gem_unmap_sgt_from_dma(struct drm_device *drm_dev,
void exynos_drm_gem_free_object(struct drm_gem_object *obj)
{
- exynos_drm_gem_destroy(to_exynos_gem_obj(obj));
+ exynos_drm_gem_destroy(to_exynos_gem(obj));
}
int exynos_drm_gem_dumb_create(struct drm_file *file_priv,
struct drm_device *dev,
struct drm_mode_create_dumb *args)
{
- struct exynos_drm_gem_obj *exynos_gem_obj;
+ struct exynos_drm_gem *exynos_gem;
unsigned int flags;
int ret;
@@ -414,16 +425,16 @@ int exynos_drm_gem_dumb_create(struct drm_file *file_priv,
else
flags = EXYNOS_BO_CONTIG | EXYNOS_BO_WC;
- exynos_gem_obj = exynos_drm_gem_create(dev, flags, args->size);
- if (IS_ERR(exynos_gem_obj)) {
+ exynos_gem = exynos_drm_gem_create(dev, flags, args->size);
+ if (IS_ERR(exynos_gem)) {
dev_warn(dev->dev, "FB allocation failed.\n");
- return PTR_ERR(exynos_gem_obj);
+ return PTR_ERR(exynos_gem);
}
- ret = exynos_drm_gem_handle_create(&exynos_gem_obj->base, file_priv,
- &args->handle);
+ ret = exynos_drm_gem_handle_create(&exynos_gem->base, file_priv,
+ &args->handle);
if (ret) {
- exynos_drm_gem_destroy(exynos_gem_obj);
+ exynos_drm_gem_destroy(exynos_gem);
return ret;
}
@@ -464,7 +475,7 @@ unlock:
int exynos_drm_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
{
struct drm_gem_object *obj = vma->vm_private_data;
- struct exynos_drm_gem_obj *exynos_gem_obj = to_exynos_gem_obj(obj);
+ struct exynos_drm_gem *exynos_gem = to_exynos_gem(obj);
unsigned long pfn;
pgoff_t page_offset;
int ret;
@@ -472,13 +483,13 @@ int exynos_drm_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
page_offset = ((unsigned long)vmf->virtual_address -
vma->vm_start) >> PAGE_SHIFT;
- if (page_offset >= (exynos_gem_obj->size >> PAGE_SHIFT)) {
+ if (page_offset >= (exynos_gem->size >> PAGE_SHIFT)) {
DRM_ERROR("invalid page offset\n");
ret = -EINVAL;
goto out;
}
- pfn = page_to_pfn(exynos_gem_obj->pages[page_offset]);
+ pfn = page_to_pfn(exynos_gem->pages[page_offset]);
ret = vm_insert_mixed(vma, (unsigned long)vmf->virtual_address, pfn);
out:
@@ -496,7 +507,7 @@ out:
int exynos_drm_gem_mmap(struct file *filp, struct vm_area_struct *vma)
{
- struct exynos_drm_gem_obj *exynos_gem_obj;
+ struct exynos_drm_gem *exynos_gem;
struct drm_gem_object *obj;
int ret;
@@ -508,21 +519,21 @@ int exynos_drm_gem_mmap(struct file *filp, struct vm_area_struct *vma)
}
obj = vma->vm_private_data;
- exynos_gem_obj = to_exynos_gem_obj(obj);
+ exynos_gem = to_exynos_gem(obj);
- DRM_DEBUG_KMS("flags = 0x%x\n", exynos_gem_obj->flags);
+ DRM_DEBUG_KMS("flags = 0x%x\n", exynos_gem->flags);
/* non-cachable as default. */
- if (exynos_gem_obj->flags & EXYNOS_BO_CACHABLE)
+ if (exynos_gem->flags & EXYNOS_BO_CACHABLE)
vma->vm_page_prot = vm_get_page_prot(vma->vm_flags);
- else if (exynos_gem_obj->flags & EXYNOS_BO_WC)
+ else if (exynos_gem->flags & EXYNOS_BO_WC)
vma->vm_page_prot =
pgprot_writecombine(vm_get_page_prot(vma->vm_flags));
else
vma->vm_page_prot =
pgprot_noncached(vm_get_page_prot(vma->vm_flags));
- ret = exynos_drm_gem_mmap_buffer(exynos_gem_obj, vma);
+ ret = exynos_drm_gem_mmap_buffer(exynos_gem, vma);
if (ret)
goto err_close_vm;
@@ -537,12 +548,12 @@ err_close_vm:
/* low-level interface prime helpers */
struct sg_table *exynos_drm_gem_prime_get_sg_table(struct drm_gem_object *obj)
{
- struct exynos_drm_gem_obj *exynos_gem_obj = to_exynos_gem_obj(obj);
+ struct exynos_drm_gem *exynos_gem = to_exynos_gem(obj);
int npages;
- npages = exynos_gem_obj->size >> PAGE_SHIFT;
+ npages = exynos_gem->size >> PAGE_SHIFT;
- return drm_prime_pages_to_sg(exynos_gem_obj->pages, npages);
+ return drm_prime_pages_to_sg(exynos_gem->pages, npages);
}
struct drm_gem_object *
@@ -550,35 +561,35 @@ exynos_drm_gem_prime_import_sg_table(struct drm_device *dev,
struct dma_buf_attachment *attach,
struct sg_table *sgt)
{
- struct exynos_drm_gem_obj *exynos_gem_obj;
+ struct exynos_drm_gem *exynos_gem;
int npages;
int ret;
- exynos_gem_obj = exynos_drm_gem_init(dev, attach->dmabuf->size);
- if (IS_ERR(exynos_gem_obj)) {
- ret = PTR_ERR(exynos_gem_obj);
+ exynos_gem = exynos_drm_gem_init(dev, attach->dmabuf->size);
+ if (IS_ERR(exynos_gem)) {
+ ret = PTR_ERR(exynos_gem);
return ERR_PTR(ret);
}
- exynos_gem_obj->dma_addr = sg_dma_address(sgt->sgl);
+ exynos_gem->dma_addr = sg_dma_address(sgt->sgl);
- npages = exynos_gem_obj->size >> PAGE_SHIFT;
- exynos_gem_obj->pages = drm_malloc_ab(npages, sizeof(struct page *));
- if (!exynos_gem_obj->pages) {
+ npages = exynos_gem->size >> PAGE_SHIFT;
+ exynos_gem->pages = drm_malloc_ab(npages, sizeof(struct page *));
+ if (!exynos_gem->pages) {
ret = -ENOMEM;
goto err;
}
- ret = drm_prime_sg_to_page_addr_arrays(sgt, exynos_gem_obj->pages, NULL,
- npages);
+ ret = drm_prime_sg_to_page_addr_arrays(sgt, exynos_gem->pages, NULL,
+ npages);
if (ret < 0)
goto err_free_large;
- exynos_gem_obj->sgt = sgt;
+ exynos_gem->sgt = sgt;
if (sgt->nents == 1) {
/* always physically continuous memory if sgt->nents is 1. */
- exynos_gem_obj->flags |= EXYNOS_BO_CONTIG;
+ exynos_gem->flags |= EXYNOS_BO_CONTIG;
} else {
/*
* this case could be CONTIG or NONCONTIG type but for now
@@ -586,16 +597,16 @@ exynos_drm_gem_prime_import_sg_table(struct drm_device *dev,
* TODO. we have to find a way that exporter can notify
* the type of its own buffer to importer.
*/
- exynos_gem_obj->flags |= EXYNOS_BO_NONCONTIG;
+ exynos_gem->flags |= EXYNOS_BO_NONCONTIG;
}
- return &exynos_gem_obj->base;
+ return &exynos_gem->base;
err_free_large:
- drm_free_large(exynos_gem_obj->pages);
+ drm_free_large(exynos_gem->pages);
err:
- drm_gem_object_release(&exynos_gem_obj->base);
- kfree(exynos_gem_obj);
+ drm_gem_object_release(&exynos_gem->base);
+ kfree(exynos_gem);
return ERR_PTR(ret);
}
diff --git a/drivers/gpu/drm/exynos/exynos_drm_gem.h b/drivers/gpu/drm/exynos/exynos_drm_gem.h
index b62d1007c0e0..37ab8b282db6 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_gem.h
+++ b/drivers/gpu/drm/exynos/exynos_drm_gem.h
@@ -14,8 +14,7 @@
#include <drm/drm_gem.h>
-#define to_exynos_gem_obj(x) container_of(x,\
- struct exynos_drm_gem_obj, base)
+#define to_exynos_gem(x) container_of(x, struct exynos_drm_gem, base)
#define IS_NONCONTIG_BUFFER(f) (f & EXYNOS_BO_NONCONTIG)
@@ -44,7 +43,7 @@
* P.S. this object would be transferred to user as kms_bo.handle so
* user can access the buffer through kms_bo.handle.
*/
-struct exynos_drm_gem_obj {
+struct exynos_drm_gem {
struct drm_gem_object base;
unsigned int flags;
unsigned long size;
@@ -59,12 +58,12 @@ struct exynos_drm_gem_obj {
struct page **exynos_gem_get_pages(struct drm_gem_object *obj, gfp_t gfpmask);
/* destroy a buffer with gem object */
-void exynos_drm_gem_destroy(struct exynos_drm_gem_obj *exynos_gem_obj);
+void exynos_drm_gem_destroy(struct exynos_drm_gem *exynos_gem);
/* create a new buffer with gem object */
-struct exynos_drm_gem_obj *exynos_drm_gem_create(struct drm_device *dev,
- unsigned int flags,
- unsigned long size);
+struct exynos_drm_gem *exynos_drm_gem_create(struct drm_device *dev,
+ unsigned int flags,
+ unsigned long size);
/*
* request gem object creation and buffer allocation as the size
@@ -106,7 +105,7 @@ unsigned long exynos_drm_gem_get_size(struct drm_device *dev,
struct drm_file *file_priv);
/* free gem object. */
-void exynos_drm_gem_free_object(struct drm_gem_object *gem_obj);
+void exynos_drm_gem_free_object(struct drm_gem_object *obj);
/* create memory region for drm framebuffer. */
int exynos_drm_gem_dumb_create(struct drm_file *file_priv,
diff --git a/drivers/gpu/drm/exynos/exynos_drm_gsc.c b/drivers/gpu/drm/exynos/exynos_drm_gsc.c
index 808a0a013780..11b87d2a7913 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_gsc.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_gsc.c
@@ -543,7 +543,7 @@ static int gsc_src_set_fmt(struct device *dev, u32 fmt)
GSC_IN_YUV420_2P);
break;
default:
- dev_err(ippdrv->dev, "inavlid target yuv order 0x%x.\n", fmt);
+ dev_err(ippdrv->dev, "invalid target yuv order 0x%x.\n", fmt);
return -EINVAL;
}
@@ -595,7 +595,7 @@ static int gsc_src_set_transf(struct device *dev,
cfg &= ~GSC_IN_ROT_YFLIP;
break;
default:
- dev_err(ippdrv->dev, "inavlid degree value %d.\n", degree);
+ dev_err(ippdrv->dev, "invalid degree value %d.\n", degree);
return -EINVAL;
}
@@ -721,7 +721,7 @@ static int gsc_src_set_addr(struct device *dev,
property->prop_id, buf_id, buf_type);
if (buf_id > GSC_MAX_SRC) {
- dev_info(ippdrv->dev, "inavlid buf_id %d.\n", buf_id);
+ dev_info(ippdrv->dev, "invalid buf_id %d.\n", buf_id);
return -EINVAL;
}
@@ -814,7 +814,7 @@ static int gsc_dst_set_fmt(struct device *dev, u32 fmt)
GSC_OUT_YUV420_2P);
break;
default:
- dev_err(ippdrv->dev, "inavlid target yuv order 0x%x.\n", fmt);
+ dev_err(ippdrv->dev, "invalid target yuv order 0x%x.\n", fmt);
return -EINVAL;
}
@@ -866,7 +866,7 @@ static int gsc_dst_set_transf(struct device *dev,
cfg &= ~GSC_IN_ROT_YFLIP;
break;
default:
- dev_err(ippdrv->dev, "inavlid degree value %d.\n", degree);
+ dev_err(ippdrv->dev, "invalid degree value %d.\n", degree);
return -EINVAL;
}
@@ -1176,7 +1176,7 @@ static int gsc_dst_set_addr(struct device *dev,
property->prop_id, buf_id, buf_type);
if (buf_id > GSC_MAX_DST) {
- dev_info(ippdrv->dev, "inavlid buf_id %d.\n", buf_id);
+ dev_info(ippdrv->dev, "invalid buf_id %d.\n", buf_id);
return -EINVAL;
}
diff --git a/drivers/gpu/drm/exynos/exynos_drm_iommu.c b/drivers/gpu/drm/exynos/exynos_drm_iommu.c
index 055e8ec2ef21..d73b9ad35b7a 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_iommu.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_iommu.c
@@ -139,6 +139,5 @@ void drm_iommu_detach_device(struct drm_device *drm_dev,
if (!mapping || !mapping->domain)
return;
- iommu_detach_device(mapping->domain, subdrv_dev);
- drm_release_iommu_mapping(drm_dev);
+ arm_iommu_detach_device(subdrv_dev);
}
diff --git a/drivers/gpu/drm/exynos/exynos_drm_plane.c b/drivers/gpu/drm/exynos/exynos_drm_plane.c
index 714822441467..179311760bb7 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_plane.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_plane.c
@@ -128,15 +128,14 @@ static int exynos_plane_atomic_check(struct drm_plane *plane,
nr = drm_format_num_planes(state->fb->pixel_format);
for (i = 0; i < nr; i++) {
- struct exynos_drm_gem_obj *obj =
- exynos_drm_fb_gem_obj(state->fb, i);
-
- if (!obj) {
+ struct exynos_drm_gem *exynos_gem =
+ exynos_drm_fb_gem(state->fb, i);
+ if (!exynos_gem) {
DRM_DEBUG_KMS("gem object is null\n");
return -EFAULT;
}
- exynos_plane->dma_addr[i] = obj->dma_addr +
+ exynos_plane->dma_addr[i] = exynos_gem->dma_addr +
state->fb->offsets[i];
DRM_DEBUG_KMS("buffer: %d, dma_addr = 0x%lx\n",
@@ -208,6 +207,17 @@ static void exynos_plane_attach_zpos_property(struct drm_plane *plane,
drm_object_attach_property(&plane->base, prop, zpos);
}
+enum drm_plane_type exynos_plane_get_type(unsigned int zpos,
+ unsigned int cursor_win)
+{
+ if (zpos == DEFAULT_WIN)
+ return DRM_PLANE_TYPE_PRIMARY;
+ else if (zpos == cursor_win)
+ return DRM_PLANE_TYPE_CURSOR;
+ else
+ return DRM_PLANE_TYPE_OVERLAY;
+}
+
int exynos_plane_init(struct drm_device *dev,
struct exynos_drm_plane *exynos_plane,
unsigned long possible_crtcs, enum drm_plane_type type,
diff --git a/drivers/gpu/drm/exynos/exynos_drm_plane.h b/drivers/gpu/drm/exynos/exynos_drm_plane.h
index 476c9340b591..abb641e64c23 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_plane.h
+++ b/drivers/gpu/drm/exynos/exynos_drm_plane.h
@@ -9,6 +9,8 @@
*
*/
+enum drm_plane_type exynos_plane_get_type(unsigned int zpos,
+ unsigned int cursor_win);
int exynos_plane_init(struct drm_device *dev,
struct exynos_drm_plane *exynos_plane,
unsigned long possible_crtcs, enum drm_plane_type type,
diff --git a/drivers/gpu/drm/exynos/exynos_drm_vidi.c b/drivers/gpu/drm/exynos/exynos_drm_vidi.c
index 75718e1bc3dd..669362c53f49 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_vidi.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_vidi.c
@@ -29,6 +29,7 @@
/* vidi has totally three virtual windows. */
#define WINDOWS_NR 3
+#define CURSOR_WIN 2
#define ctx_from_connector(c) container_of(c, struct vidi_context, \
connector)
@@ -42,7 +43,6 @@ struct vidi_context {
struct exynos_drm_plane planes[WINDOWS_NR];
struct edid *raw_edid;
unsigned int clkdiv;
- unsigned int default_win;
unsigned long irq_flags;
unsigned int connected;
bool vblank_on;
@@ -446,8 +446,7 @@ static int vidi_bind(struct device *dev, struct device *master, void *data)
vidi_ctx_initialize(ctx, drm_dev);
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, formats,
ARRAY_SIZE(formats), zpos);
@@ -455,7 +454,7 @@ static int vidi_bind(struct device *dev, struct device *master, void *data)
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_VIDI,
&vidi_crtc_ops, ctx);
@@ -507,7 +506,6 @@ static int vidi_probe(struct platform_device *pdev)
if (!ctx)
return -ENOMEM;
- ctx->default_win = 0;
ctx->pdev = pdev;
INIT_WORK(&ctx->work, vidi_fake_vblank_handler);
diff --git a/drivers/gpu/drm/exynos/exynos_hdmi.c b/drivers/gpu/drm/exynos/exynos_hdmi.c
index 932f7fa240f8..57b675563e94 100644
--- a/drivers/gpu/drm/exynos/exynos_hdmi.c
+++ b/drivers/gpu/drm/exynos/exynos_hdmi.c
@@ -30,11 +30,11 @@
#include <linux/delay.h>
#include <linux/pm_runtime.h>
#include <linux/clk.h>
+#include <linux/gpio/consumer.h>
#include <linux/regulator/consumer.h>
#include <linux/io.h>
#include <linux/of_address.h>
#include <linux/of_device.h>
-#include <linux/of_gpio.h>
#include <linux/hdmi.h>
#include <linux/component.h>
#include <linux/mfd/syscon.h>
@@ -44,11 +44,6 @@
#include "exynos_drm_drv.h"
#include "exynos_drm_crtc.h"
-#include "exynos_mixer.h"
-
-#include <linux/gpio.h>
-
-#define ctx_from_connector(c) container_of(c, struct hdmi_context, connector)
#define HOTPLUG_DEBOUNCE_MS 1100
@@ -66,6 +61,33 @@
enum hdmi_type {
HDMI_TYPE13,
HDMI_TYPE14,
+ HDMI_TYPE_COUNT
+};
+
+#define HDMI_MAPPED_BASE 0xffff0000
+
+enum hdmi_mapped_regs {
+ HDMI_PHY_STATUS = HDMI_MAPPED_BASE,
+ HDMI_PHY_RSTOUT,
+ HDMI_ACR_CON,
+ HDMI_ACR_MCTS0,
+ HDMI_ACR_CTS0,
+ HDMI_ACR_N0
+};
+
+static const u32 hdmi_reg_map[][HDMI_TYPE_COUNT] = {
+ { HDMI_V13_PHY_STATUS, HDMI_PHY_STATUS_0 },
+ { HDMI_V13_PHY_RSTOUT, HDMI_V14_PHY_RSTOUT },
+ { HDMI_V13_ACR_CON, HDMI_V14_ACR_CON },
+ { HDMI_V13_ACR_MCTS0, HDMI_V14_ACR_MCTS0 },
+ { HDMI_V13_ACR_CTS0, HDMI_V14_ACR_CTS0 },
+ { HDMI_V13_ACR_N0, HDMI_V14_ACR_N0 },
+};
+
+static const char * const supply[] = {
+ "vdd",
+ "vdd_osc",
+ "vdd_pll",
};
struct hdmi_driver_data {
@@ -75,44 +97,32 @@ struct hdmi_driver_data {
unsigned int is_apb_phy:1;
};
-struct hdmi_resources {
- struct clk *hdmi;
- struct clk *sclk_hdmi;
- struct clk *sclk_pixel;
- struct clk *sclk_hdmiphy;
- struct clk *mout_hdmi;
- struct regulator_bulk_data *regul_bulk;
- struct regulator *reg_hdmi_en;
- int regul_count;
-};
-
struct hdmi_context {
struct drm_encoder encoder;
struct device *dev;
struct drm_device *drm_dev;
struct drm_connector connector;
- bool hpd;
bool powered;
bool dvi_mode;
-
- void __iomem *regs;
- int irq;
struct delayed_work hotplug_work;
-
- struct i2c_adapter *ddc_adpt;
- struct i2c_client *hdmiphy_port;
-
- /* current hdmiphy conf regs */
struct drm_display_mode current_mode;
u8 cea_video_id;
-
- struct hdmi_resources res;
const struct hdmi_driver_data *drv_data;
- int hpd_gpio;
+ void __iomem *regs;
void __iomem *regs_hdmiphy;
-
+ struct i2c_client *hdmiphy_port;
+ struct i2c_adapter *ddc_adpt;
+ struct gpio_desc *hpd_gpio;
+ int irq;
struct regmap *pmureg;
+ struct clk *hdmi;
+ struct clk *sclk_hdmi;
+ struct clk *sclk_pixel;
+ struct clk *sclk_hdmiphy;
+ struct clk *mout_hdmi;
+ struct regulator_bulk_data regul_bulk[ARRAY_SIZE(supply)];
+ struct regulator *reg_hdmi_en;
};
static inline struct hdmi_context *encoder_to_hdmi(struct drm_encoder *e)
@@ -120,6 +130,11 @@ static inline struct hdmi_context *encoder_to_hdmi(struct drm_encoder *e)
return container_of(e, struct hdmi_context, encoder);
}
+static inline struct hdmi_context *connector_to_hdmi(struct drm_connector *c)
+{
+ return container_of(c, struct hdmi_context, connector);
+}
+
struct hdmiphy_config {
int pixel_clock;
u8 conf[32];
@@ -133,7 +148,7 @@ static const struct hdmiphy_config hdmiphy_v13_configs[] = {
0x01, 0x05, 0x00, 0xD8, 0x10, 0x1C, 0x30, 0x40,
0x6B, 0x10, 0x02, 0x51, 0xDF, 0xF2, 0x54, 0x87,
0x84, 0x00, 0x30, 0x38, 0x00, 0x08, 0x10, 0xE0,
- 0x22, 0x40, 0xE3, 0x26, 0x00, 0x00, 0x00, 0x00,
+ 0x22, 0x40, 0xE3, 0x26, 0x00, 0x00, 0x00, 0x80,
},
},
{
@@ -142,7 +157,7 @@ static const struct hdmiphy_config hdmiphy_v13_configs[] = {
0x01, 0x05, 0x00, 0xD4, 0x10, 0x9C, 0x09, 0x64,
0x6B, 0x10, 0x02, 0x51, 0xDF, 0xF2, 0x54, 0x87,
0x84, 0x00, 0x30, 0x38, 0x00, 0x08, 0x10, 0xE0,
- 0x22, 0x40, 0xE3, 0x26, 0x00, 0x00, 0x00, 0x00,
+ 0x22, 0x40, 0xE3, 0x26, 0x00, 0x00, 0x00, 0x80,
},
},
{
@@ -151,7 +166,7 @@ static const struct hdmiphy_config hdmiphy_v13_configs[] = {
0x01, 0x05, 0x00, 0xD8, 0x10, 0x9C, 0xef, 0x5B,
0x6D, 0x10, 0x01, 0x51, 0xef, 0xF3, 0x54, 0xb9,
0x84, 0x00, 0x30, 0x38, 0x00, 0x08, 0x10, 0xE0,
- 0x22, 0x40, 0xa5, 0x26, 0x01, 0x00, 0x00, 0x00,
+ 0x22, 0x40, 0xa5, 0x26, 0x01, 0x00, 0x00, 0x80,
},
},
{
@@ -160,7 +175,7 @@ static const struct hdmiphy_config hdmiphy_v13_configs[] = {
0x01, 0x05, 0x00, 0xd8, 0x10, 0x9c, 0xf8, 0x40,
0x6a, 0x10, 0x01, 0x51, 0xff, 0xf1, 0x54, 0xba,
0x84, 0x00, 0x10, 0x38, 0x00, 0x08, 0x10, 0xe0,
- 0x22, 0x40, 0xa4, 0x26, 0x01, 0x00, 0x00, 0x00,
+ 0x22, 0x40, 0xa4, 0x26, 0x01, 0x00, 0x00, 0x80,
},
},
{
@@ -169,7 +184,7 @@ static const struct hdmiphy_config hdmiphy_v13_configs[] = {
0x01, 0x05, 0x00, 0xD8, 0x10, 0x9C, 0xf8, 0x40,
0x6A, 0x18, 0x00, 0x51, 0xff, 0xF1, 0x54, 0xba,
0x84, 0x00, 0x10, 0x38, 0x00, 0x08, 0x10, 0xE0,
- 0x22, 0x40, 0xa4, 0x26, 0x02, 0x00, 0x00, 0x00,
+ 0x22, 0x40, 0xa4, 0x26, 0x02, 0x00, 0x00, 0x80,
},
},
};
@@ -199,7 +214,7 @@ static const struct hdmiphy_config hdmiphy_v14_configs[] = {
0x01, 0xd1, 0x2d, 0x72, 0x40, 0x64, 0x12, 0x08,
0x43, 0xa0, 0x0e, 0xd9, 0x45, 0xa0, 0xac, 0x80,
0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
- 0x54, 0xe3, 0x24, 0x00, 0x00, 0x00, 0x01, 0x00,
+ 0x54, 0xe3, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
},
},
{
@@ -262,7 +277,7 @@ static const struct hdmiphy_config hdmiphy_v14_configs[] = {
0x01, 0xd1, 0x1f, 0x10, 0x40, 0x40, 0xf8, 0x08,
0x81, 0xa0, 0xba, 0xd8, 0x45, 0xa0, 0xac, 0x80,
0x3c, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
- 0x54, 0xa5, 0x24, 0x01, 0x00, 0x00, 0x01, 0x00,
+ 0x54, 0xa5, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
},
},
{
@@ -325,7 +340,7 @@ static const struct hdmiphy_config hdmiphy_v14_configs[] = {
0x01, 0xd1, 0x1f, 0x00, 0x40, 0x40, 0xf8, 0x08,
0x81, 0xa0, 0xba, 0xd8, 0x45, 0xa0, 0xac, 0x80,
0x3c, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
- 0x54, 0x4b, 0x25, 0x03, 0x00, 0x00, 0x01, 0x00,
+ 0x54, 0x4b, 0x25, 0x03, 0x00, 0x00, 0x01, 0x80,
},
},
};
@@ -507,29 +522,31 @@ static struct hdmi_driver_data exynos4210_hdmi_driver_data = {
.is_apb_phy = 0,
};
-static struct hdmi_driver_data exynos5_hdmi_driver_data = {
- .type = HDMI_TYPE14,
- .phy_confs = hdmiphy_v13_configs,
- .phy_conf_count = ARRAY_SIZE(hdmiphy_v13_configs),
- .is_apb_phy = 0,
-};
+static inline u32 hdmi_map_reg(struct hdmi_context *hdata, u32 reg_id)
+{
+ if ((reg_id & 0xffff0000) == HDMI_MAPPED_BASE)
+ return hdmi_reg_map[reg_id & 0xffff][hdata->drv_data->type];
+ return reg_id;
+}
static inline u32 hdmi_reg_read(struct hdmi_context *hdata, u32 reg_id)
{
- return readl(hdata->regs + reg_id);
+ return readl(hdata->regs + hdmi_map_reg(hdata, reg_id));
}
static inline void hdmi_reg_writeb(struct hdmi_context *hdata,
u32 reg_id, u8 value)
{
- writeb(value, hdata->regs + reg_id);
+ writel(value, hdata->regs + hdmi_map_reg(hdata, reg_id));
}
static inline void hdmi_reg_writev(struct hdmi_context *hdata, u32 reg_id,
int bytes, u32 val)
{
+ reg_id = hdmi_map_reg(hdata, reg_id);
+
while (--bytes >= 0) {
- writeb(val & 0xff, hdata->regs + reg_id);
+ writel(val & 0xff, hdata->regs + reg_id);
val >>= 8;
reg_id += 4;
}
@@ -538,31 +555,14 @@ static inline void hdmi_reg_writev(struct hdmi_context *hdata, u32 reg_id,
static inline void hdmi_reg_writemask(struct hdmi_context *hdata,
u32 reg_id, u32 value, u32 mask)
{
- u32 old = readl(hdata->regs + reg_id);
+ u32 old;
+
+ reg_id = hdmi_map_reg(hdata, reg_id);
+ old = readl(hdata->regs + reg_id);
value = (value & mask) | (old & ~mask);
writel(value, hdata->regs + reg_id);
}
-static int hdmiphy_reg_writeb(struct hdmi_context *hdata,
- u32 reg_offset, u8 value)
-{
- if (hdata->hdmiphy_port) {
- u8 buffer[2];
- int ret;
-
- buffer[0] = reg_offset;
- buffer[1] = value;
-
- ret = i2c_master_send(hdata->hdmiphy_port, buffer, 2);
- if (ret == 2)
- return 0;
- return ret;
- } else {
- writeb(value, hdata->regs_hdmiphy + (reg_offset<<2));
- return 0;
- }
-}
-
static int hdmiphy_reg_write_buf(struct hdmi_context *hdata,
u32 reg_offset, const u8 *buf, u32 len)
{
@@ -579,7 +579,7 @@ static int hdmiphy_reg_write_buf(struct hdmi_context *hdata,
} else {
int i;
for (i = 0; i < len; i++)
- writeb(buf[i], hdata->regs_hdmiphy +
+ writel(buf[i], hdata->regs_hdmiphy +
((reg_offset + i)<<2));
return 0;
}
@@ -689,7 +689,7 @@ static void hdmi_v14_regs_dump(struct hdmi_context *hdata, char *prefix)
DUMPREG(HDMI_PHY_STATUS_0);
DUMPREG(HDMI_PHY_STATUS_PLL);
DUMPREG(HDMI_PHY_CON_0);
- DUMPREG(HDMI_PHY_RSTOUT);
+ DUMPREG(HDMI_V14_PHY_RSTOUT);
DUMPREG(HDMI_PHY_VPLL);
DUMPREG(HDMI_PHY_CMU);
DUMPREG(HDMI_CORE_RSTOUT);
@@ -942,9 +942,9 @@ static void hdmi_reg_infoframe(struct hdmi_context *hdata,
static enum drm_connector_status hdmi_detect(struct drm_connector *connector,
bool force)
{
- struct hdmi_context *hdata = ctx_from_connector(connector);
+ struct hdmi_context *hdata = connector_to_hdmi(connector);
- if (gpio_get_value(hdata->hpd_gpio))
+ if (gpiod_get_value(hdata->hpd_gpio))
return connector_status_connected;
return connector_status_disconnected;
@@ -968,7 +968,7 @@ static struct drm_connector_funcs hdmi_connector_funcs = {
static int hdmi_get_modes(struct drm_connector *connector)
{
- struct hdmi_context *hdata = ctx_from_connector(connector);
+ struct hdmi_context *hdata = connector_to_hdmi(connector);
struct edid *edid;
int ret;
@@ -1008,7 +1008,7 @@ static int hdmi_find_phy_conf(struct hdmi_context *hdata, u32 pixel_clock)
static int hdmi_mode_valid(struct drm_connector *connector,
struct drm_display_mode *mode)
{
- struct hdmi_context *hdata = ctx_from_connector(connector);
+ struct hdmi_context *hdata = connector_to_hdmi(connector);
int ret;
DRM_DEBUG_KMS("xres=%d, yres=%d, refresh=%d, intl=%d clock=%d\n",
@@ -1016,10 +1016,6 @@ static int hdmi_mode_valid(struct drm_connector *connector,
(mode->flags & DRM_MODE_FLAG_INTERLACE) ? true :
false, mode->clock * 1000);
- ret = mixer_check_mode(mode);
- if (ret)
- return MODE_BAD;
-
ret = hdmi_find_phy_conf(hdata, mode->clock * 1000);
if (ret < 0)
return MODE_BAD;
@@ -1029,7 +1025,7 @@ static int hdmi_mode_valid(struct drm_connector *connector,
static struct drm_encoder *hdmi_best_encoder(struct drm_connector *connector)
{
- struct hdmi_context *hdata = ctx_from_connector(connector);
+ struct hdmi_context *hdata = connector_to_hdmi(connector);
return &hdata->encoder;
}
@@ -1110,70 +1106,17 @@ static bool hdmi_mode_fixup(struct drm_encoder *encoder,
return true;
}
-static void hdmi_set_acr(u32 freq, u8 *acr)
+static void hdmi_reg_acr(struct hdmi_context *hdata, u32 freq)
{
u32 n, cts;
- switch (freq) {
- case 32000:
- n = 4096;
- cts = 27000;
- break;
- case 44100:
- n = 6272;
- cts = 30000;
- break;
- case 88200:
- n = 12544;
- cts = 30000;
- break;
- case 176400:
- n = 25088;
- cts = 30000;
- break;
- case 48000:
- n = 6144;
- cts = 27000;
- break;
- case 96000:
- n = 12288;
- cts = 27000;
- break;
- case 192000:
- n = 24576;
- cts = 27000;
- break;
- default:
- n = 0;
- cts = 0;
- break;
- }
-
- acr[1] = cts >> 16;
- acr[2] = cts >> 8 & 0xff;
- acr[3] = cts & 0xff;
+ cts = (freq % 9) ? 27000 : 30000;
+ n = 128 * freq / (27000000 / cts);
- acr[4] = n >> 16;
- acr[5] = n >> 8 & 0xff;
- acr[6] = n & 0xff;
-}
-
-static void hdmi_reg_acr(struct hdmi_context *hdata, u8 *acr)
-{
- hdmi_reg_writeb(hdata, HDMI_ACR_N0, acr[6]);
- hdmi_reg_writeb(hdata, HDMI_ACR_N1, acr[5]);
- hdmi_reg_writeb(hdata, HDMI_ACR_N2, acr[4]);
- hdmi_reg_writeb(hdata, HDMI_ACR_MCTS0, acr[3]);
- hdmi_reg_writeb(hdata, HDMI_ACR_MCTS1, acr[2]);
- hdmi_reg_writeb(hdata, HDMI_ACR_MCTS2, acr[1]);
- hdmi_reg_writeb(hdata, HDMI_ACR_CTS0, acr[3]);
- hdmi_reg_writeb(hdata, HDMI_ACR_CTS1, acr[2]);
- hdmi_reg_writeb(hdata, HDMI_ACR_CTS2, acr[1]);
-
- if (hdata->drv_data->type == HDMI_TYPE13)
- hdmi_reg_writeb(hdata, HDMI_V13_ACR_CON, 4);
- else
- hdmi_reg_writeb(hdata, HDMI_ACR_CON, 4);
+ hdmi_reg_writev(hdata, HDMI_ACR_N0, 3, n);
+ hdmi_reg_writev(hdata, HDMI_ACR_MCTS0, 3, cts);
+ hdmi_reg_writev(hdata, HDMI_ACR_CTS0, 3, cts);
+ hdmi_reg_writeb(hdata, HDMI_ACR_CON, 4);
}
static void hdmi_audio_init(struct hdmi_context *hdata)
@@ -1181,7 +1124,6 @@ static void hdmi_audio_init(struct hdmi_context *hdata)
u32 sample_rate, bits_per_sample;
u32 data_num, bit_ch, sample_frq;
u32 val;
- u8 acr[7];
sample_rate = 44100;
bits_per_sample = 16;
@@ -1201,8 +1143,7 @@ static void hdmi_audio_init(struct hdmi_context *hdata)
break;
}
- hdmi_set_acr(sample_rate, acr);
- hdmi_reg_acr(hdata, acr);
+ hdmi_reg_acr(hdata, sample_rate);
hdmi_reg_writeb(hdata, HDMI_I2S_MUX_CON, HDMI_I2S_IN_DISABLE
| HDMI_I2S_AUD_I2S | HDMI_I2S_CUV_I2S_ENABLE
@@ -1335,11 +1276,27 @@ static void hdmi_conf_init(struct hdmi_context *hdata)
}
}
+static void hdmiphy_wait_for_pll(struct hdmi_context *hdata)
+{
+ int tries;
+
+ for (tries = 0; tries < 10; ++tries) {
+ u32 val = hdmi_reg_read(hdata, HDMI_PHY_STATUS);
+
+ if (val & HDMI_PHY_STATUS_READY) {
+ DRM_DEBUG_KMS("PLL stabilized after %d tries\n", tries);
+ return;
+ }
+ usleep_range(10, 20);
+ }
+
+ DRM_ERROR("PLL could not reach steady state\n");
+}
+
static void hdmi_v13_mode_apply(struct hdmi_context *hdata)
{
struct drm_display_mode *m = &hdata->current_mode;
unsigned int val;
- int tries;
hdmi_reg_writev(hdata, HDMI_H_BLANK_0, 2, m->htotal - m->hdisplay);
hdmi_reg_writev(hdata, HDMI_V13_H_V_LINE_0, 3,
@@ -1425,32 +1382,11 @@ static void hdmi_v13_mode_apply(struct hdmi_context *hdata)
hdmi_reg_writev(hdata, HDMI_TG_VSYNC_BOT_HDMI_L, 2, 0x233);
hdmi_reg_writev(hdata, HDMI_TG_FIELD_TOP_HDMI_L, 2, 0x1);
hdmi_reg_writev(hdata, HDMI_TG_FIELD_BOT_HDMI_L, 2, 0x233);
-
- /* waiting for HDMIPHY's PLL to get to steady state */
- for (tries = 100; tries; --tries) {
- u32 val = hdmi_reg_read(hdata, HDMI_V13_PHY_STATUS);
- if (val & HDMI_PHY_STATUS_READY)
- break;
- usleep_range(1000, 2000);
- }
- /* steady state not achieved */
- if (tries == 0) {
- DRM_ERROR("hdmiphy's pll could not reach steady state.\n");
- hdmi_regs_dump(hdata, "timing apply");
- }
-
- clk_disable_unprepare(hdata->res.sclk_hdmi);
- clk_set_parent(hdata->res.mout_hdmi, hdata->res.sclk_hdmiphy);
- clk_prepare_enable(hdata->res.sclk_hdmi);
-
- /* enable HDMI and timing generator */
- hdmi_start(hdata, true);
}
static void hdmi_v14_mode_apply(struct hdmi_context *hdata)
{
struct drm_display_mode *m = &hdata->current_mode;
- int tries;
hdmi_reg_writev(hdata, HDMI_H_BLANK_0, 2, m->htotal - m->hdisplay);
hdmi_reg_writev(hdata, HDMI_V_LINE_0, 2, m->vtotal);
@@ -1562,26 +1498,6 @@ static void hdmi_v14_mode_apply(struct hdmi_context *hdata)
hdmi_reg_writev(hdata, HDMI_TG_VSYNC_TOP_HDMI_L, 2, 0x1);
hdmi_reg_writev(hdata, HDMI_TG_FIELD_TOP_HDMI_L, 2, 0x1);
hdmi_reg_writev(hdata, HDMI_TG_3D, 1, 0x0);
-
- /* waiting for HDMIPHY's PLL to get to steady state */
- for (tries = 100; tries; --tries) {
- u32 val = hdmi_reg_read(hdata, HDMI_PHY_STATUS_0);
- if (val & HDMI_PHY_STATUS_READY)
- break;
- usleep_range(1000, 2000);
- }
- /* steady state not achieved */
- if (tries == 0) {
- DRM_ERROR("hdmiphy's pll could not reach steady state.\n");
- hdmi_regs_dump(hdata, "timing apply");
- }
-
- clk_disable_unprepare(hdata->res.sclk_hdmi);
- clk_set_parent(hdata->res.mout_hdmi, hdata->res.sclk_hdmiphy);
- clk_prepare_enable(hdata->res.sclk_hdmi);
-
- /* enable HDMI and timing generator */
- hdmi_start(hdata, true);
}
static void hdmi_mode_apply(struct hdmi_context *hdata)
@@ -1590,74 +1506,26 @@ static void hdmi_mode_apply(struct hdmi_context *hdata)
hdmi_v13_mode_apply(hdata);
else
hdmi_v14_mode_apply(hdata);
-}
-static void hdmiphy_conf_reset(struct hdmi_context *hdata)
-{
- u32 reg;
+ hdmiphy_wait_for_pll(hdata);
- clk_disable_unprepare(hdata->res.sclk_hdmi);
- clk_set_parent(hdata->res.mout_hdmi, hdata->res.sclk_pixel);
- clk_prepare_enable(hdata->res.sclk_hdmi);
+ clk_set_parent(hdata->mout_hdmi, hdata->sclk_hdmiphy);
- /* operation mode */
- hdmiphy_reg_writeb(hdata, HDMIPHY_MODE_SET_DONE,
- HDMI_PHY_ENABLE_MODE_SET);
+ /* enable HDMI and timing generator */
+ hdmi_start(hdata, true);
+}
- if (hdata->drv_data->type == HDMI_TYPE13)
- reg = HDMI_V13_PHY_RSTOUT;
- else
- reg = HDMI_PHY_RSTOUT;
+static void hdmiphy_conf_reset(struct hdmi_context *hdata)
+{
+ clk_set_parent(hdata->mout_hdmi, hdata->sclk_pixel);
/* reset hdmiphy */
- hdmi_reg_writemask(hdata, reg, ~0, HDMI_PHY_SW_RSTOUT);
+ hdmi_reg_writemask(hdata, HDMI_PHY_RSTOUT, ~0, HDMI_PHY_SW_RSTOUT);
usleep_range(10000, 12000);
- hdmi_reg_writemask(hdata, reg, 0, HDMI_PHY_SW_RSTOUT);
+ hdmi_reg_writemask(hdata, HDMI_PHY_RSTOUT, 0, HDMI_PHY_SW_RSTOUT);
usleep_range(10000, 12000);
}
-static void hdmiphy_poweron(struct hdmi_context *hdata)
-{
- if (hdata->drv_data->type != HDMI_TYPE14)
- return;
-
- DRM_DEBUG_KMS("\n");
-
- /* For PHY Mode Setting */
- hdmiphy_reg_writeb(hdata, HDMIPHY_MODE_SET_DONE,
- HDMI_PHY_ENABLE_MODE_SET);
- /* Phy Power On */
- hdmiphy_reg_writeb(hdata, HDMIPHY_POWER,
- HDMI_PHY_POWER_ON);
- /* For PHY Mode Setting */
- hdmiphy_reg_writeb(hdata, HDMIPHY_MODE_SET_DONE,
- HDMI_PHY_DISABLE_MODE_SET);
- /* PHY SW Reset */
- hdmiphy_conf_reset(hdata);
-}
-
-static void hdmiphy_poweroff(struct hdmi_context *hdata)
-{
- if (hdata->drv_data->type != HDMI_TYPE14)
- return;
-
- DRM_DEBUG_KMS("\n");
-
- /* PHY SW Reset */
- hdmiphy_conf_reset(hdata);
- /* For PHY Mode Setting */
- hdmiphy_reg_writeb(hdata, HDMIPHY_MODE_SET_DONE,
- HDMI_PHY_ENABLE_MODE_SET);
-
- /* PHY Power Off */
- hdmiphy_reg_writeb(hdata, HDMIPHY_POWER,
- HDMI_PHY_POWER_OFF);
-
- /* For PHY Mode Setting */
- hdmiphy_reg_writeb(hdata, HDMIPHY_MODE_SET_DONE,
- HDMI_PHY_DISABLE_MODE_SET);
-}
-
static void hdmiphy_conf_apply(struct hdmi_context *hdata)
{
int ret;
@@ -1678,14 +1546,6 @@ static void hdmiphy_conf_apply(struct hdmi_context *hdata)
}
usleep_range(10000, 12000);
-
- ret = hdmiphy_reg_writeb(hdata, HDMIPHY_MODE_SET_DONE,
- HDMI_PHY_DISABLE_MODE_SET);
- if (ret) {
- DRM_ERROR("failed to enable hdmiphy\n");
- return;
- }
-
}
static void hdmi_conf_apply(struct hdmi_context *hdata)
@@ -1724,7 +1584,6 @@ static void hdmi_mode_set(struct drm_encoder *encoder,
static void hdmi_enable(struct drm_encoder *encoder)
{
struct hdmi_context *hdata = encoder_to_hdmi(encoder);
- struct hdmi_resources *res = &hdata->res;
if (hdata->powered)
return;
@@ -1733,24 +1592,22 @@ static void hdmi_enable(struct drm_encoder *encoder)
pm_runtime_get_sync(hdata->dev);
- if (regulator_bulk_enable(res->regul_count, res->regul_bulk))
+ if (regulator_bulk_enable(ARRAY_SIZE(supply), hdata->regul_bulk))
DRM_DEBUG_KMS("failed to enable regulator bulk\n");
/* set pmu hdmiphy control bit to enable hdmiphy */
regmap_update_bits(hdata->pmureg, PMU_HDMI_PHY_CONTROL,
PMU_HDMI_PHY_ENABLE_BIT, 1);
- clk_prepare_enable(res->hdmi);
- clk_prepare_enable(res->sclk_hdmi);
+ clk_prepare_enable(hdata->hdmi);
+ clk_prepare_enable(hdata->sclk_hdmi);
- hdmiphy_poweron(hdata);
hdmi_conf_apply(hdata);
}
static void hdmi_disable(struct drm_encoder *encoder)
{
struct hdmi_context *hdata = encoder_to_hdmi(encoder);
- struct hdmi_resources *res = &hdata->res;
struct drm_crtc *crtc = encoder->crtc;
const struct drm_crtc_helper_funcs *funcs = NULL;
@@ -1774,18 +1631,16 @@ static void hdmi_disable(struct drm_encoder *encoder)
/* HDMI System Disable */
hdmi_reg_writemask(hdata, HDMI_CON_0, 0, HDMI_EN);
- hdmiphy_poweroff(hdata);
-
cancel_delayed_work(&hdata->hotplug_work);
- clk_disable_unprepare(res->sclk_hdmi);
- clk_disable_unprepare(res->hdmi);
+ clk_disable_unprepare(hdata->sclk_hdmi);
+ clk_disable_unprepare(hdata->hdmi);
/* reset pmu hdmiphy control bit to disable hdmiphy */
regmap_update_bits(hdata->pmureg, PMU_HDMI_PHY_CONTROL,
PMU_HDMI_PHY_ENABLE_BIT, 0);
- regulator_bulk_disable(res->regul_count, res->regul_bulk);
+ regulator_bulk_disable(ARRAY_SIZE(supply), hdata->regul_bulk);
pm_runtime_put_sync(hdata->dev);
@@ -1826,80 +1681,76 @@ static irqreturn_t hdmi_irq_thread(int irq, void *arg)
static int hdmi_resources_init(struct hdmi_context *hdata)
{
struct device *dev = hdata->dev;
- struct hdmi_resources *res = &hdata->res;
- static char *supply[] = {
- "vdd",
- "vdd_osc",
- "vdd_pll",
- };
int i, ret;
DRM_DEBUG_KMS("HDMI resource init\n");
+ hdata->hpd_gpio = devm_gpiod_get(dev, "hpd", GPIOD_IN);
+ if (IS_ERR(hdata->hpd_gpio)) {
+ DRM_ERROR("cannot get hpd gpio property\n");
+ return PTR_ERR(hdata->hpd_gpio);
+ }
+
+ hdata->irq = gpiod_to_irq(hdata->hpd_gpio);
+ if (hdata->irq < 0) {
+ DRM_ERROR("failed to get GPIO irq\n");
+ return hdata->irq;
+ }
/* get clocks, power */
- res->hdmi = devm_clk_get(dev, "hdmi");
- if (IS_ERR(res->hdmi)) {
+ hdata->hdmi = devm_clk_get(dev, "hdmi");
+ if (IS_ERR(hdata->hdmi)) {
DRM_ERROR("failed to get clock 'hdmi'\n");
- ret = PTR_ERR(res->hdmi);
+ ret = PTR_ERR(hdata->hdmi);
goto fail;
}
- res->sclk_hdmi = devm_clk_get(dev, "sclk_hdmi");
- if (IS_ERR(res->sclk_hdmi)) {
+ hdata->sclk_hdmi = devm_clk_get(dev, "sclk_hdmi");
+ if (IS_ERR(hdata->sclk_hdmi)) {
DRM_ERROR("failed to get clock 'sclk_hdmi'\n");
- ret = PTR_ERR(res->sclk_hdmi);
+ ret = PTR_ERR(hdata->sclk_hdmi);
goto fail;
}
- res->sclk_pixel = devm_clk_get(dev, "sclk_pixel");
- if (IS_ERR(res->sclk_pixel)) {
+ hdata->sclk_pixel = devm_clk_get(dev, "sclk_pixel");
+ if (IS_ERR(hdata->sclk_pixel)) {
DRM_ERROR("failed to get clock 'sclk_pixel'\n");
- ret = PTR_ERR(res->sclk_pixel);
+ ret = PTR_ERR(hdata->sclk_pixel);
goto fail;
}
- res->sclk_hdmiphy = devm_clk_get(dev, "sclk_hdmiphy");
- if (IS_ERR(res->sclk_hdmiphy)) {
+ hdata->sclk_hdmiphy = devm_clk_get(dev, "sclk_hdmiphy");
+ if (IS_ERR(hdata->sclk_hdmiphy)) {
DRM_ERROR("failed to get clock 'sclk_hdmiphy'\n");
- ret = PTR_ERR(res->sclk_hdmiphy);
+ ret = PTR_ERR(hdata->sclk_hdmiphy);
goto fail;
}
- res->mout_hdmi = devm_clk_get(dev, "mout_hdmi");
- if (IS_ERR(res->mout_hdmi)) {
+ hdata->mout_hdmi = devm_clk_get(dev, "mout_hdmi");
+ if (IS_ERR(hdata->mout_hdmi)) {
DRM_ERROR("failed to get clock 'mout_hdmi'\n");
- ret = PTR_ERR(res->mout_hdmi);
+ ret = PTR_ERR(hdata->mout_hdmi);
goto fail;
}
- clk_set_parent(res->mout_hdmi, res->sclk_pixel);
+ clk_set_parent(hdata->mout_hdmi, hdata->sclk_pixel);
- res->regul_bulk = devm_kzalloc(dev, ARRAY_SIZE(supply) *
- sizeof(res->regul_bulk[0]), GFP_KERNEL);
- if (!res->regul_bulk) {
- ret = -ENOMEM;
- goto fail;
- }
for (i = 0; i < ARRAY_SIZE(supply); ++i) {
- res->regul_bulk[i].supply = supply[i];
- res->regul_bulk[i].consumer = NULL;
+ hdata->regul_bulk[i].supply = supply[i];
+ hdata->regul_bulk[i].consumer = NULL;
}
- ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(supply), res->regul_bulk);
+ ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(supply), hdata->regul_bulk);
if (ret) {
DRM_ERROR("failed to get regulators\n");
return ret;
}
- res->regul_count = ARRAY_SIZE(supply);
- res->reg_hdmi_en = devm_regulator_get(dev, "hdmi-en");
- if (IS_ERR(res->reg_hdmi_en) && PTR_ERR(res->reg_hdmi_en) != -ENOENT) {
- DRM_ERROR("failed to get hdmi-en regulator\n");
- return PTR_ERR(res->reg_hdmi_en);
- }
- if (!IS_ERR(res->reg_hdmi_en)) {
- ret = regulator_enable(res->reg_hdmi_en);
- if (ret) {
- DRM_ERROR("failed to enable hdmi-en regulator\n");
- return ret;
- }
- } else
- res->reg_hdmi_en = NULL;
+ hdata->reg_hdmi_en = devm_regulator_get_optional(dev, "hdmi-en");
+
+ if (PTR_ERR(hdata->reg_hdmi_en) == -ENODEV)
+ return 0;
+
+ 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");
return ret;
fail:
@@ -1909,9 +1760,6 @@ fail:
static struct of_device_id hdmi_match_types[] = {
{
- .compatible = "samsung,exynos5-hdmi",
- .data = &exynos5_hdmi_driver_data,
- }, {
.compatible = "samsung,exynos4210-hdmi",
.data = &exynos4210_hdmi_driver_data,
}, {
@@ -2009,11 +1857,6 @@ static int hdmi_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, hdata);
hdata->dev = dev;
- hdata->hpd_gpio = of_get_named_gpio(dev->of_node, "hpd-gpio", 0);
- if (hdata->hpd_gpio < 0) {
- DRM_ERROR("cannot get hpd gpio property\n");
- return hdata->hpd_gpio;
- }
ret = hdmi_resources_init(hdata);
if (ret) {
@@ -2028,12 +1871,6 @@ static int hdmi_probe(struct platform_device *pdev)
return ret;
}
- ret = devm_gpio_request(dev, hdata->hpd_gpio, "HPD");
- if (ret) {
- DRM_ERROR("failed to request HPD gpio\n");
- return ret;
- }
-
ddc_node = hdmi_legacy_ddc_dt_binding(dev);
if (ddc_node)
goto out_get_ddc_adpt;
@@ -2081,13 +1918,6 @@ out_get_phy_port:
}
}
- hdata->irq = gpio_to_irq(hdata->hpd_gpio);
- if (hdata->irq < 0) {
- DRM_ERROR("failed to get GPIO irq\n");
- ret = hdata->irq;
- goto err_hdmiphy;
- }
-
INIT_DELAYED_WORK(&hdata->hotplug_work, hdmi_hotplug_work_func);
ret = devm_request_threaded_irq(dev, hdata->irq, NULL,
@@ -2133,15 +1963,17 @@ static int hdmi_remove(struct platform_device *pdev)
cancel_delayed_work_sync(&hdata->hotplug_work);
- if (hdata->res.reg_hdmi_en)
- regulator_disable(hdata->res.reg_hdmi_en);
+ component_del(&pdev->dev, &hdmi_component_ops);
+
+ pm_runtime_disable(&pdev->dev);
+
+ if (!IS_ERR(hdata->reg_hdmi_en))
+ regulator_disable(hdata->reg_hdmi_en);
if (hdata->hdmiphy_port)
put_device(&hdata->hdmiphy_port->dev);
- put_device(&hdata->ddc_adpt->dev);
- pm_runtime_disable(&pdev->dev);
- component_del(&pdev->dev, &hdmi_component_ops);
+ put_device(&hdata->ddc_adpt->dev);
return 0;
}
diff --git a/drivers/gpu/drm/exynos/exynos_mixer.c b/drivers/gpu/drm/exynos/exynos_mixer.c
index 7f81cce966d4..d09f8f9a8939 100644
--- a/drivers/gpu/drm/exynos/exynos_mixer.c
+++ b/drivers/gpu/drm/exynos/exynos_mixer.c
@@ -39,11 +39,10 @@
#include "exynos_drm_crtc.h"
#include "exynos_drm_plane.h"
#include "exynos_drm_iommu.h"
-#include "exynos_mixer.h"
#define MIXER_WIN_NR 3
-#define MIXER_DEFAULT_WIN 0
#define VP_DEFAULT_WIN 2
+#define CURSOR_WIN 1
/* The pixelformats that are natively supported by the mixer. */
#define MXR_FORMAT_RGB565 4
@@ -600,7 +599,7 @@ static void mixer_graph_buffer(struct mixer_context *ctx,
/* setup display size */
if (ctx->mxr_ver == MXR_VER_128_0_0_184 &&
- win == MIXER_DEFAULT_WIN) {
+ win == DEFAULT_WIN) {
val = MXR_MXR_RES_HEIGHT(mode->vdisplay);
val |= MXR_MXR_RES_WIDTH(mode->hdisplay);
mixer_reg_write(res, MXR_RESOLUTION, val);
@@ -652,7 +651,7 @@ static void vp_win_reset(struct mixer_context *ctx)
/* waiting until VP_SRESET_PROCESSING is 0 */
if (~vp_reg_read(res, VP_SRESET) & VP_SRESET_PROCESSING)
break;
- usleep_range(10000, 12000);
+ mdelay(10);
}
WARN(tries == 0, "failed to reset Video Processor\n");
}
@@ -1096,8 +1095,10 @@ static void mixer_disable(struct exynos_drm_crtc *crtc)
}
/* Only valid for Mixer version 16.0.33.0 */
-int mixer_check_mode(struct drm_display_mode *mode)
+static int mixer_atomic_check(struct exynos_drm_crtc *crtc,
+ struct drm_crtc_state *state)
{
+ struct drm_display_mode *mode = &state->adjusted_mode;
u32 w, h;
w = mode->hdisplay;
@@ -1123,6 +1124,7 @@ static const struct exynos_drm_crtc_ops mixer_crtc_ops = {
.wait_for_vblank = mixer_wait_for_vblank,
.update_plane = mixer_update_plane,
.disable_plane = mixer_disable_plane,
+ .atomic_check = mixer_atomic_check,
};
static struct mixer_drv_data exynos5420_mxr_drv_data = {
@@ -1197,8 +1199,6 @@ static int mixer_bind(struct device *dev, struct device *manager, void *data)
const uint32_t *formats;
unsigned int fcount;
- type = (zpos == MIXER_DEFAULT_WIN) ? DRM_PLANE_TYPE_PRIMARY :
- DRM_PLANE_TYPE_OVERLAY;
if (zpos < VP_DEFAULT_WIN) {
formats = mixer_formats;
fcount = ARRAY_SIZE(mixer_formats);
@@ -1207,6 +1207,7 @@ static int mixer_bind(struct device *dev, struct device *manager, void *data)
fcount = ARRAY_SIZE(vp_formats);
}
+ type = exynos_plane_get_type(zpos, CURSOR_WIN);
ret = exynos_plane_init(drm_dev, &ctx->planes[zpos],
1 << ctx->pipe, type, formats, fcount,
zpos);
@@ -1214,7 +1215,7 @@ static int mixer_bind(struct device *dev, struct device *manager, void *data)
return ret;
}
- exynos_plane = &ctx->planes[MIXER_DEFAULT_WIN];
+ exynos_plane = &ctx->planes[DEFAULT_WIN];
ctx->crtc = exynos_drm_crtc_create(drm_dev, &exynos_plane->base,
ctx->pipe, EXYNOS_DISPLAY_TYPE_HDMI,
&mixer_crtc_ops, ctx);
diff --git a/drivers/gpu/drm/exynos/exynos_mixer.h b/drivers/gpu/drm/exynos/exynos_mixer.h
deleted file mode 100644
index 3811e417f0e9..000000000000
--- a/drivers/gpu/drm/exynos/exynos_mixer.h
+++ /dev/null
@@ -1,20 +0,0 @@
-/*
- * Copyright (C) 2013 Google, Inc.
- *
- * This software is licensed under the terms of the GNU General Public
- * License version 2, as published by the Free Software Foundation, and
- * may be copied, distributed, and modified under those terms.
- *
- * 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.
- */
-
-#ifndef _EXYNOS_MIXER_H_
-#define _EXYNOS_MIXER_H_
-
-/* This function returns 0 if the given timing is valid for the mixer */
-int mixer_check_mode(struct drm_display_mode *mode);
-
-#endif
diff --git a/drivers/gpu/drm/exynos/regs-hdmi.h b/drivers/gpu/drm/exynos/regs-hdmi.h
index 3f35ac6d8a47..8c891e59be21 100644
--- a/drivers/gpu/drm/exynos/regs-hdmi.h
+++ b/drivers/gpu/drm/exynos/regs-hdmi.h
@@ -72,7 +72,6 @@
#define HDMI_V13_V_SYNC_GEN_3_0 HDMI_CORE_BASE(0x0150)
#define HDMI_V13_V_SYNC_GEN_3_1 HDMI_CORE_BASE(0x0154)
#define HDMI_V13_V_SYNC_GEN_3_2 HDMI_CORE_BASE(0x0158)
-#define HDMI_V13_ACR_CON HDMI_CORE_BASE(0x0180)
#define HDMI_V13_AVI_CON HDMI_CORE_BASE(0x0300)
#define HDMI_V13_AVI_BYTE(n) HDMI_CORE_BASE(0x0320 + 4 * (n))
#define HDMI_V13_DC_CONTROL HDMI_CORE_BASE(0x05C0)
@@ -171,7 +170,7 @@
#define HDMI_HPD_ST HDMI_CTRL_BASE(0x0044)
#define HDMI_HPD_TH_X HDMI_CTRL_BASE(0x0050)
#define HDMI_AUDIO_CLKSEL HDMI_CTRL_BASE(0x0070)
-#define HDMI_PHY_RSTOUT HDMI_CTRL_BASE(0x0074)
+#define HDMI_V14_PHY_RSTOUT HDMI_CTRL_BASE(0x0074)
#define HDMI_PHY_VPLL HDMI_CTRL_BASE(0x0078)
#define HDMI_PHY_CMU HDMI_CTRL_BASE(0x007C)
#define HDMI_CORE_RSTOUT HDMI_CTRL_BASE(0x0080)
@@ -277,16 +276,26 @@
#define HDMI_ASP_CHCFG2 HDMI_CORE_BASE(0x0318)
#define HDMI_ASP_CHCFG3 HDMI_CORE_BASE(0x031C)
-#define HDMI_ACR_CON HDMI_CORE_BASE(0x0400)
-#define HDMI_ACR_MCTS0 HDMI_CORE_BASE(0x0410)
-#define HDMI_ACR_MCTS1 HDMI_CORE_BASE(0x0414)
-#define HDMI_ACR_MCTS2 HDMI_CORE_BASE(0x0418)
-#define HDMI_ACR_CTS0 HDMI_CORE_BASE(0x0420)
-#define HDMI_ACR_CTS1 HDMI_CORE_BASE(0x0424)
-#define HDMI_ACR_CTS2 HDMI_CORE_BASE(0x0428)
-#define HDMI_ACR_N0 HDMI_CORE_BASE(0x0430)
-#define HDMI_ACR_N1 HDMI_CORE_BASE(0x0434)
-#define HDMI_ACR_N2 HDMI_CORE_BASE(0x0438)
+#define HDMI_V13_ACR_CON HDMI_CORE_BASE(0x0180)
+#define HDMI_V13_ACR_MCTS0 HDMI_CORE_BASE(0x0184)
+#define HDMI_V13_ACR_MCTS1 HDMI_CORE_BASE(0x0188)
+#define HDMI_V13_ACR_MCTS2 HDMI_CORE_BASE(0x018C)
+#define HDMI_V13_ACR_CTS0 HDMI_CORE_BASE(0x0190)
+#define HDMI_V13_ACR_CTS1 HDMI_CORE_BASE(0x0194)
+#define HDMI_V13_ACR_CTS2 HDMI_CORE_BASE(0x0198)
+#define HDMI_V13_ACR_N0 HDMI_CORE_BASE(0x01A0)
+#define HDMI_V13_ACR_N1 HDMI_CORE_BASE(0x01A4)
+#define HDMI_V13_ACR_N2 HDMI_CORE_BASE(0x01A8)
+#define HDMI_V14_ACR_CON HDMI_CORE_BASE(0x0400)
+#define HDMI_V14_ACR_MCTS0 HDMI_CORE_BASE(0x0410)
+#define HDMI_V14_ACR_MCTS1 HDMI_CORE_BASE(0x0414)
+#define HDMI_V14_ACR_MCTS2 HDMI_CORE_BASE(0x0418)
+#define HDMI_V14_ACR_CTS0 HDMI_CORE_BASE(0x0420)
+#define HDMI_V14_ACR_CTS1 HDMI_CORE_BASE(0x0424)
+#define HDMI_V14_ACR_CTS2 HDMI_CORE_BASE(0x0428)
+#define HDMI_V14_ACR_N0 HDMI_CORE_BASE(0x0430)
+#define HDMI_V14_ACR_N1 HDMI_CORE_BASE(0x0434)
+#define HDMI_V14_ACR_N2 HDMI_CORE_BASE(0x0438)
/* Packet related registers */
#define HDMI_ACP_CON HDMI_CORE_BASE(0x0500)