Commit b4590047 authored by Dave Airlie's avatar Dave Airlie

Merge branch 'exynos-drm-next' of...

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
  ...
parents c0f3f90c df547bf7
...@@ -132,6 +132,7 @@ CONFIG_DRM_PARADE_PS8622=y ...@@ -132,6 +132,7 @@ CONFIG_DRM_PARADE_PS8622=y
CONFIG_DRM_EXYNOS=y CONFIG_DRM_EXYNOS=y
CONFIG_DRM_EXYNOS_FIMD=y CONFIG_DRM_EXYNOS_FIMD=y
CONFIG_DRM_EXYNOS_DSI=y CONFIG_DRM_EXYNOS_DSI=y
CONFIG_DRM_EXYNOS_MIXER=y
CONFIG_DRM_EXYNOS_HDMI=y CONFIG_DRM_EXYNOS_HDMI=y
CONFIG_DRM_PANEL_SIMPLE=y CONFIG_DRM_PANEL_SIMPLE=y
CONFIG_DRM_PANEL_SAMSUNG_S6E8AA0=y CONFIG_DRM_PANEL_SAMSUNG_S6E8AA0=y
......
...@@ -11,43 +11,59 @@ config DRM_EXYNOS ...@@ -11,43 +11,59 @@ config DRM_EXYNOS
Choose this option if you have a Samsung SoC EXYNOS chipset. Choose this option if you have a Samsung SoC EXYNOS chipset.
If M is selected the module will be called exynosdrm. If M is selected the module will be called exynosdrm.
if DRM_EXYNOS
config DRM_EXYNOS_IOMMU config DRM_EXYNOS_IOMMU
bool bool
depends on DRM_EXYNOS && EXYNOS_IOMMU && ARM_DMA_USE_IOMMU depends on EXYNOS_IOMMU && ARM_DMA_USE_IOMMU
default y default y
comment "CRTCs"
config DRM_EXYNOS_FIMD config DRM_EXYNOS_FIMD
bool "Exynos DRM FIMD" bool "FIMD"
depends on DRM_EXYNOS && !FB_S3C depends on !FB_S3C
select FB_MODE_HELPERS select FB_MODE_HELPERS
select MFD_SYSCON select MFD_SYSCON
help help
Choose this option if you want to use Exynos FIMD for DRM. Choose this option if you want to use Exynos FIMD for DRM.
config DRM_EXYNOS5433_DECON config DRM_EXYNOS5433_DECON
bool "Exynos5433 DRM DECON" bool "DECON on Exynos5433"
depends on DRM_EXYNOS
help help
Choose this option if you want to use Exynos5433 DECON for DRM. Choose this option if you want to use Exynos5433 DECON for DRM.
config DRM_EXYNOS7_DECON config DRM_EXYNOS7_DECON
bool "Exynos7 DRM DECON" bool "DECON on Exynos7"
depends on DRM_EXYNOS && !FB_S3C depends on !FB_S3C
select FB_MODE_HELPERS select FB_MODE_HELPERS
help help
Choose this option if you want to use Exynos DECON for DRM. 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 config DRM_EXYNOS_DPI
bool "EXYNOS DRM parallel output support" bool "Parallel output"
depends on DRM_EXYNOS && (DRM_EXYNOS_FIMD || DRM_EXYNOS7_DECON) depends on DRM_EXYNOS_FIMD
select DRM_PANEL select DRM_PANEL
default n default n
help help
This enables support for Exynos parallel output. This enables support for Exynos parallel output.
config DRM_EXYNOS_DSI config DRM_EXYNOS_DSI
bool "EXYNOS DRM MIPI-DSI driver support" bool "MIPI-DSI host"
depends on DRM_EXYNOS && (DRM_EXYNOS_FIMD || DRM_EXYNOS5433_DECON || DRM_EXYNOS7_DECON) depends on DRM_EXYNOS_FIMD || DRM_EXYNOS5433_DECON || DRM_EXYNOS7_DECON
select DRM_MIPI_DSI select DRM_MIPI_DSI
select DRM_PANEL select DRM_PANEL
default n default n
...@@ -55,58 +71,55 @@ config DRM_EXYNOS_DSI ...@@ -55,58 +71,55 @@ config DRM_EXYNOS_DSI
This enables support for Exynos MIPI-DSI device. This enables support for Exynos MIPI-DSI device.
config DRM_EXYNOS_DP config DRM_EXYNOS_DP
bool "EXYNOS DRM DP driver support" bool "Display Port"
depends on DRM_EXYNOS && (DRM_EXYNOS_FIMD || DRM_EXYNOS7_DECON) depends on DRM_EXYNOS_FIMD || DRM_EXYNOS7_DECON
default DRM_EXYNOS default DRM_EXYNOS
select DRM_PANEL select DRM_PANEL
help help
This enables support for DP device. This enables support for DP device.
config DRM_EXYNOS_HDMI config DRM_EXYNOS_HDMI
bool "Exynos DRM HDMI" bool "HDMI"
depends on DRM_EXYNOS && !VIDEO_SAMSUNG_S5P_TV depends on !VIDEO_SAMSUNG_S5P_TV && (DRM_EXYNOS_MIXER || DRM_EXYNOS5433_DECON)
help help
Choose this option if you want to use Exynos HDMI for DRM. Choose this option if you want to use Exynos HDMI for DRM.
config DRM_EXYNOS_VIDI config DRM_EXYNOS_MIC
bool "Exynos DRM Virtual Display" bool "Mobile Image Compressor"
depends on DRM_EXYNOS depends on DRM_EXYNOS5433_DECON
help 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 config DRM_EXYNOS_G2D
bool "Exynos DRM G2D" bool "G2D"
depends on DRM_EXYNOS && !VIDEO_SAMSUNG_S5P_G2D depends on !VIDEO_SAMSUNG_S5P_G2D
select FRAME_VECTOR select FRAME_VECTOR
help help
Choose this option if you want to use Exynos G2D for DRM. Choose this option if you want to use Exynos G2D for DRM.
config DRM_EXYNOS_IPP config DRM_EXYNOS_IPP
bool "Exynos DRM IPP" bool "Image Post Processor"
depends on DRM_EXYNOS
help help
Choose this option if you want to use IPP feature for DRM. Choose this option if you want to use IPP feature for DRM.
config DRM_EXYNOS_FIMC config DRM_EXYNOS_FIMC
bool "Exynos DRM FIMC" bool "FIMC"
depends on DRM_EXYNOS_IPP && MFD_SYSCON depends on DRM_EXYNOS_IPP && MFD_SYSCON
help help
Choose this option if you want to use Exynos FIMC for DRM. Choose this option if you want to use Exynos FIMC for DRM.
config DRM_EXYNOS_ROTATOR config DRM_EXYNOS_ROTATOR
bool "Exynos DRM Rotator" bool "Rotator"
depends on DRM_EXYNOS_IPP depends on DRM_EXYNOS_IPP
help help
Choose this option if you want to use Exynos Rotator for DRM. Choose this option if you want to use Exynos Rotator for DRM.
config DRM_EXYNOS_GSC config DRM_EXYNOS_GSC
bool "Exynos DRM GSC" bool "GScaler"
depends on DRM_EXYNOS_IPP && ARCH_EXYNOS5 && !ARCH_MULTIPLATFORM depends on DRM_EXYNOS_IPP && ARCH_EXYNOS5 && !ARCH_MULTIPLATFORM
help help
Choose this option if you want to use Exynos GSC for DRM. Choose this option if you want to use Exynos GSC for DRM.
config DRM_EXYNOS_MIC endif
bool "Exynos DRM MIC"
depends on (DRM_EXYNOS && DRM_EXYNOS5433_DECON)
help
Choose this option if you want to use Exynos MIC for DRM.
...@@ -14,7 +14,8 @@ exynosdrm-$(CONFIG_DRM_EXYNOS7_DECON) += exynos7_drm_decon.o ...@@ -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_DPI) += exynos_drm_dpi.o
exynosdrm-$(CONFIG_DRM_EXYNOS_DSI) += exynos_drm_dsi.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_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_VIDI) += exynos_drm_vidi.o
exynosdrm-$(CONFIG_DRM_EXYNOS_G2D) += exynos_drm_g2d.o exynosdrm-$(CONFIG_DRM_EXYNOS_G2D) += exynos_drm_g2d.o
exynosdrm-$(CONFIG_DRM_EXYNOS_IPP) += exynos_drm_ipp.o exynosdrm-$(CONFIG_DRM_EXYNOS_IPP) += exynos_drm_ipp.o
......
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/clk.h> #include <linux/clk.h>
#include <linux/component.h> #include <linux/component.h>
#include <linux/of_device.h>
#include <linux/of_gpio.h> #include <linux/of_gpio.h>
#include <linux/pm_runtime.h> #include <linux/pm_runtime.h>
...@@ -24,28 +25,11 @@ ...@@ -24,28 +25,11 @@
#include "exynos_drm_iommu.h" #include "exynos_drm_iommu.h"
#define WINDOWS_NR 3 #define WINDOWS_NR 3
#define CURSOR_WIN 2
#define MIN_FB_WIDTH_FOR_16WORD_BURST 128 #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[] = { static const char * const decon_clks_name[] = {
"pclk",
"aclk_decon", "aclk_decon",
"aclk_smmu_decon0x", "aclk_smmu_decon0x",
"aclk_xiu_decon0x", "aclk_xiu_decon0x",
...@@ -54,6 +38,32 @@ static const char * const decon_clks_name[] = { ...@@ -54,6 +38,32 @@ static const char * const decon_clks_name[] = {
"sclk_decon_eclk", "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[] = { static const uint32_t decon_formats[] = {
DRM_FORMAT_XRGB1555, DRM_FORMAT_XRGB1555,
DRM_FORMAT_RGB565, DRM_FORMAT_RGB565,
...@@ -61,17 +71,24 @@ static const uint32_t decon_formats[] = { ...@@ -61,17 +71,24 @@ static const uint32_t decon_formats[] = {
DRM_FORMAT_ARGB8888, 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) static int decon_enable_vblank(struct exynos_drm_crtc *crtc)
{ {
struct decon_context *ctx = crtc->ctx; struct decon_context *ctx = crtc->ctx;
u32 val; u32 val;
if (ctx->suspended) if (test_bit(BIT_SUSPENDED, &ctx->flags))
return -EPERM; return -EPERM;
if (test_and_set_bit(0, &ctx->irq_flags)) { if (test_and_set_bit(BIT_IRQS_ENABLED, &ctx->flags)) {
val = VIDINTCON0_INTEN; val = VIDINTCON0_INTEN;
if (ctx->i80_if) if (ctx->out_type == IFTYPE_I80)
val |= VIDINTCON0_FRAMEDONE; val |= VIDINTCON0_FRAMEDONE;
else else
val |= VIDINTCON0_INTFRMEN; val |= VIDINTCON0_INTFRMEN;
...@@ -86,79 +103,85 @@ static void decon_disable_vblank(struct exynos_drm_crtc *crtc) ...@@ -86,79 +103,85 @@ static void decon_disable_vblank(struct exynos_drm_crtc *crtc)
{ {
struct decon_context *ctx = crtc->ctx; struct decon_context *ctx = crtc->ctx;
if (ctx->suspended) if (test_bit(BIT_SUSPENDED, &ctx->flags))
return; 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); writel(0, ctx->addr + DECON_VIDINTCON0);
} }
static void decon_setup_trigger(struct decon_context *ctx) static void decon_setup_trigger(struct decon_context *ctx)
{ {
u32 val = TRIGCON_TRIGEN_PER_F | TRIGCON_TRIGEN_F | u32 val = (ctx->out_type != IFTYPE_HDMI)
TRIGCON_TE_AUTO_MASK | TRIGCON_SWTRIGEN; ? 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); writel(val, ctx->addr + DECON_TRIGCON);
} }
static void decon_commit(struct exynos_drm_crtc *crtc) static void decon_commit(struct exynos_drm_crtc *crtc)
{ {
struct decon_context *ctx = crtc->ctx; struct decon_context *ctx = crtc->ctx;
struct drm_display_mode *mode = &crtc->base.mode; struct drm_display_mode *m = &crtc->base.mode;
u32 val; u32 val;
if (ctx->suspended) if (test_bit(BIT_SUSPENDED, &ctx->flags))
return; 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 */ /* enable clock gate */
val = CMU_CLKGAGE_MODE_SFR_F | CMU_CLKGAGE_MODE_MEM_F; val = CMU_CLKGAGE_MODE_SFR_F | CMU_CLKGAGE_MODE_MEM_F;
writel(val, ctx->addr + DECON_CMU); writel(val, ctx->addr + DECON_CMU);
/* lcd on and use command if */ /* lcd on and use command if */
val = VIDOUT_LCD_ON; val = VIDOUT_LCD_ON;
if (ctx->i80_if) if (ctx->out_type == IFTYPE_I80)
val |= VIDOUT_COMMAND_IF; val |= VIDOUT_COMMAND_IF;
else else
val |= VIDOUT_RGB_IF; val |= VIDOUT_RGB_IF;
writel(val, ctx->addr + DECON_VIDOUTCON0); writel(val, ctx->addr + DECON_VIDOUTCON0);
val = VIDTCON2_LINEVAL(mode->vdisplay - 1) | val = VIDTCON2_LINEVAL(m->vdisplay - 1) |
VIDTCON2_HOZVAL(mode->hdisplay - 1); VIDTCON2_HOZVAL(m->hdisplay - 1);
writel(val, ctx->addr + DECON_VIDTCON2); writel(val, ctx->addr + DECON_VIDTCON2);
if (!ctx->i80_if) { if (ctx->out_type != IFTYPE_I80) {
val = VIDTCON00_VBPD_F( val = VIDTCON00_VBPD_F(
mode->crtc_vtotal - mode->crtc_vsync_end) | m->crtc_vtotal - m->crtc_vsync_end - 1) |
VIDTCON00_VFPD_F( VIDTCON00_VFPD_F(
mode->crtc_vsync_start - mode->crtc_vdisplay); m->crtc_vsync_start - m->crtc_vdisplay - 1);
writel(val, ctx->addr + DECON_VIDTCON00); writel(val, ctx->addr + DECON_VIDTCON00);
val = VIDTCON01_VSPW_F( 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); writel(val, ctx->addr + DECON_VIDTCON01);
val = VIDTCON10_HBPD_F( val = VIDTCON10_HBPD_F(
mode->crtc_htotal - mode->crtc_hsync_end) | m->crtc_htotal - m->crtc_hsync_end - 1) |
VIDTCON10_HFPD_F( VIDTCON10_HFPD_F(
mode->crtc_hsync_start - mode->crtc_hdisplay); m->crtc_hsync_start - m->crtc_hdisplay - 1);
writel(val, ctx->addr + DECON_VIDTCON10); writel(val, ctx->addr + DECON_VIDTCON10);
val = VIDTCON11_HSPW_F( 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); writel(val, ctx->addr + DECON_VIDTCON11);
} }
decon_setup_trigger(ctx); decon_setup_trigger(ctx);
/* enable output and display signal */ /* enable output and display signal */
val = VIDCON0_ENVID | VIDCON0_ENVID_F; decon_set_bits(ctx, DECON_VIDCON0, VIDCON0_ENVID | VIDCON0_ENVID_F, ~0);
writel(val, ctx->addr + DECON_VIDCON0);
} }
#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, static void decon_win_set_pixfmt(struct decon_context *ctx, unsigned int win,
struct drm_framebuffer *fb) struct drm_framebuffer *fb)
{ {
...@@ -214,16 +237,8 @@ static void decon_win_set_pixfmt(struct decon_context *ctx, unsigned int win, ...@@ -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, static void decon_shadow_protect_win(struct decon_context *ctx, int win,
bool protect) bool protect)
{ {
u32 val; decon_set_bits(ctx, DECON_SHADOWCON, SHADOWCON_Wx_PROTECT(win),
protect ? ~0 : 0);
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);
} }
static void decon_atomic_begin(struct exynos_drm_crtc *crtc, static void decon_atomic_begin(struct exynos_drm_crtc *crtc,
...@@ -231,12 +246,16 @@ 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; struct decon_context *ctx = crtc->ctx;
if (ctx->suspended) if (test_bit(BIT_SUSPENDED, &ctx->flags))
return; return;
decon_shadow_protect_win(ctx, plane->zpos, true); 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, static void decon_update_plane(struct exynos_drm_crtc *crtc,
struct exynos_drm_plane *plane) struct exynos_drm_plane *plane)
{ {
...@@ -247,7 +266,7 @@ static void decon_update_plane(struct exynos_drm_crtc *crtc, ...@@ -247,7 +266,7 @@ static void decon_update_plane(struct exynos_drm_crtc *crtc,
unsigned int pitch = state->fb->pitches[0]; unsigned int pitch = state->fb->pitches[0];
u32 val; u32 val;
if (ctx->suspended) if (test_bit(BIT_SUSPENDED, &ctx->flags))
return; return;
val = COORDINATE_X(plane->crtc_x) | COORDINATE_Y(plane->crtc_y); 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, ...@@ -270,21 +289,21 @@ static void decon_update_plane(struct exynos_drm_crtc *crtc,
val = plane->dma_addr[0] + pitch * plane->crtc_h; val = plane->dma_addr[0] + pitch * plane->crtc_h;
writel(val, ctx->addr + DECON_VIDW0xADD1B0(win)); writel(val, ctx->addr + DECON_VIDW0xADD1B0(win));
val = OFFSIZE(pitch - plane->crtc_w * bpp) if (ctx->out_type != IFTYPE_HDMI)
| PAGEWIDTH(plane->crtc_w * bpp); 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)); writel(val, ctx->addr + DECON_VIDW0xADD2(win));
decon_win_set_pixfmt(ctx, win, state->fb); decon_win_set_pixfmt(ctx, win, state->fb);
/* window enable */ /* window enable */
val = readl(ctx->addr + DECON_WINCONx(win)); decon_set_bits(ctx, DECON_WINCONx(win), WINCONx_ENWIN_F, ~0);
val |= WINCONx_ENWIN_F;
writel(val, ctx->addr + DECON_WINCONx(win));
/* standalone update */ /* standalone update */
val = readl(ctx->addr + DECON_UPDATE); decon_set_bits(ctx, DECON_UPDATE, STANDALONE_UPDATE_F, ~0);
val |= STANDALONE_UPDATE_F;
writel(val, ctx->addr + DECON_UPDATE);
} }
static void decon_disable_plane(struct exynos_drm_crtc *crtc, static void decon_disable_plane(struct exynos_drm_crtc *crtc,
...@@ -292,24 +311,19 @@ 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; struct decon_context *ctx = crtc->ctx;
unsigned int win = plane->zpos; unsigned int win = plane->zpos;
u32 val;
if (ctx->suspended) if (test_bit(BIT_SUSPENDED, &ctx->flags))
return; return;
decon_shadow_protect_win(ctx, win, true); decon_shadow_protect_win(ctx, win, true);
/* window disable */ /* window disable */
val = readl(ctx->addr + DECON_WINCONx(win)); decon_set_bits(ctx, DECON_WINCONx(win), WINCONx_ENWIN_F, 0);
val &= ~WINCONx_ENWIN_F;
writel(val, ctx->addr + DECON_WINCONx(win));
decon_shadow_protect_win(ctx, win, false); decon_shadow_protect_win(ctx, win, false);
/* standalone update */ /* standalone update */
val = readl(ctx->addr + DECON_UPDATE); decon_set_bits(ctx, DECON_UPDATE, STANDALONE_UPDATE_F, ~0);
val |= STANDALONE_UPDATE_F;
writel(val, ctx->addr + DECON_UPDATE);
} }
static void decon_atomic_flush(struct exynos_drm_crtc *crtc, static void decon_atomic_flush(struct exynos_drm_crtc *crtc,
...@@ -317,13 +331,13 @@ 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; struct decon_context *ctx = crtc->ctx;
if (ctx->suspended) if (test_bit(BIT_SUSPENDED, &ctx->flags))
return; return;
decon_shadow_protect_win(ctx, plane->zpos, false); decon_shadow_protect_win(ctx, plane->zpos, false);
if (ctx->i80_if) if (ctx->out_type == IFTYPE_I80)
atomic_set(&ctx->win_updated, 1); set_bit(BIT_WIN_UPDATED, &ctx->flags);
} }
static void decon_swreset(struct decon_context *ctx) static void decon_swreset(struct decon_context *ctx)
...@@ -347,6 +361,17 @@ 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"); 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) static void decon_enable(struct exynos_drm_crtc *crtc)
...@@ -355,11 +380,9 @@ 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 ret;
int i; int i;
if (!ctx->suspended) if (!test_and_clear_bit(BIT_SUSPENDED, &ctx->flags))
return; return;
ctx->suspended = false;
pm_runtime_get_sync(ctx->dev); pm_runtime_get_sync(ctx->dev);
for (i = 0; i < ARRAY_SIZE(decon_clks_name); i++) { for (i = 0; i < ARRAY_SIZE(decon_clks_name); i++) {
...@@ -368,10 +391,10 @@ static void decon_enable(struct exynos_drm_crtc *crtc) ...@@ -368,10 +391,10 @@ static void decon_enable(struct exynos_drm_crtc *crtc)
goto err; 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 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_enable_vblank(ctx->crtc);
decon_commit(ctx->crtc); decon_commit(ctx->crtc);
...@@ -381,7 +404,7 @@ static void decon_enable(struct exynos_drm_crtc *crtc) ...@@ -381,7 +404,7 @@ static void decon_enable(struct exynos_drm_crtc *crtc)
while (--i >= 0) while (--i >= 0)
clk_disable_unprepare(ctx->clks[i]); clk_disable_unprepare(ctx->clks[i]);
ctx->suspended = true; set_bit(BIT_SUSPENDED, &ctx->flags);
} }
static void decon_disable(struct exynos_drm_crtc *crtc) static void decon_disable(struct exynos_drm_crtc *crtc)
...@@ -389,7 +412,7 @@ 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; struct decon_context *ctx = crtc->ctx;
int i; int i;
if (ctx->suspended) if (test_bit(BIT_SUSPENDED, &ctx->flags))
return; return;
/* /*
...@@ -397,7 +420,7 @@ static void decon_disable(struct exynos_drm_crtc *crtc) ...@@ -397,7 +420,7 @@ static void decon_disable(struct exynos_drm_crtc *crtc)
* suspend that connector. Otherwise we might try to scan from * suspend that connector. Otherwise we might try to scan from
* a destroyed buffer later. * 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_disable_plane(crtc, &ctx->planes[i]);
decon_swreset(ctx); decon_swreset(ctx);
...@@ -405,27 +428,22 @@ static void decon_disable(struct exynos_drm_crtc *crtc) ...@@ -405,27 +428,22 @@ static void decon_disable(struct exynos_drm_crtc *crtc)
for (i = 0; i < ARRAY_SIZE(decon_clks_name); i++) for (i = 0; i < ARRAY_SIZE(decon_clks_name); i++)
clk_disable_unprepare(ctx->clks[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); 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) void decon_te_irq_handler(struct exynos_drm_crtc *crtc)
{ {
struct decon_context *ctx = crtc->ctx; 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; return;
if (atomic_add_unless(&ctx->win_updated, -1, 0)) { if (test_and_clear_bit(BIT_WIN_UPDATED, &ctx->flags))
/* trigger */ decon_set_bits(ctx, DECON_TRIGCON, TRIGCON_SWTRIGCMD, ~0);
val = readl(ctx->addr + DECON_TRIGCON);
val |= TRIGCON_SWTRIGCMD;
writel(val, ctx->addr + DECON_TRIGCON);
}
drm_crtc_handle_vblank(&ctx->crtc->base); drm_crtc_handle_vblank(&ctx->crtc->base);
} }
...@@ -434,7 +452,6 @@ static void decon_clear_channels(struct exynos_drm_crtc *crtc) ...@@ -434,7 +452,6 @@ static void decon_clear_channels(struct exynos_drm_crtc *crtc)
{ {
struct decon_context *ctx = crtc->ctx; struct decon_context *ctx = crtc->ctx;
int win, i, ret; int win, i, ret;
u32 val;
DRM_DEBUG_KMS("%s\n", __FILE__); DRM_DEBUG_KMS("%s\n", __FILE__);
...@@ -445,25 +462,10 @@ static void decon_clear_channels(struct exynos_drm_crtc *crtc) ...@@ -445,25 +462,10 @@ static void decon_clear_channels(struct exynos_drm_crtc *crtc)
} }
for (win = 0; win < WINDOWS_NR; win++) { for (win = 0; win < WINDOWS_NR; win++) {
/* shadow update disable */ decon_shadow_protect_win(ctx, win, true);
val = readl(ctx->addr + DECON_SHADOWCON); decon_set_bits(ctx, DECON_WINCONx(win), WINCONx_ENWIN_F, 0);
val |= SHADOWCON_Wx_PROTECT(win); decon_shadow_protect_win(ctx, win, false);
writel(val, ctx->addr + DECON_SHADOWCON); decon_set_bits(ctx, DECON_UPDATE, STANDALONE_UPDATE_F, ~0);
/* 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);
} }
/* TODO: wait for possible vsync */ /* TODO: wait for possible vsync */
msleep(50); msleep(50);
...@@ -479,7 +481,6 @@ static struct exynos_drm_crtc_ops decon_crtc_ops = { ...@@ -479,7 +481,6 @@ static struct exynos_drm_crtc_ops decon_crtc_ops = {
.commit = decon_commit, .commit = decon_commit,
.enable_vblank = decon_enable_vblank, .enable_vblank = decon_enable_vblank,
.disable_vblank = decon_disable_vblank, .disable_vblank = decon_disable_vblank,
.commit = decon_commit,
.atomic_begin = decon_atomic_begin, .atomic_begin = decon_atomic_begin,
.update_plane = decon_update_plane, .update_plane = decon_update_plane,
.disable_plane = decon_disable_plane, .disable_plane = decon_disable_plane,
...@@ -493,26 +494,30 @@ static int decon_bind(struct device *dev, struct device *master, void *data) ...@@ -493,26 +494,30 @@ static int decon_bind(struct device *dev, struct device *master, void *data)
struct drm_device *drm_dev = data; struct drm_device *drm_dev = data;
struct exynos_drm_private *priv = drm_dev->dev_private; struct exynos_drm_private *priv = drm_dev->dev_private;
struct exynos_drm_plane *exynos_plane; struct exynos_drm_plane *exynos_plane;
enum exynos_drm_output_type out_type;
enum drm_plane_type type; enum drm_plane_type type;
unsigned int zpos; unsigned int win;
int ret; int ret;
ctx->drm_dev = drm_dev; ctx->drm_dev = drm_dev;
ctx->pipe = priv->pipe++; ctx->pipe = priv->pipe++;
for (zpos = 0; zpos < WINDOWS_NR; zpos++) { for (win = ctx->first_win; win < WINDOWS_NR; win++) {
type = (zpos == ctx->default_win) ? DRM_PLANE_TYPE_PRIMARY : int tmp = (win == ctx->first_win) ? 0 : win;
DRM_PLANE_TYPE_OVERLAY;
ret = exynos_plane_init(drm_dev, &ctx->planes[zpos], type = exynos_plane_get_type(tmp, CURSOR_WIN);
ret = exynos_plane_init(drm_dev, &ctx->planes[win],
1 << ctx->pipe, type, decon_formats, 1 << ctx->pipe, type, decon_formats,
ARRAY_SIZE(decon_formats), zpos); ARRAY_SIZE(decon_formats), win);
if (ret) if (ret)
return 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->crtc = exynos_drm_crtc_create(drm_dev, &exynos_plane->base,
ctx->pipe, EXYNOS_DISPLAY_TYPE_LCD, ctx->pipe, out_type,
&decon_crtc_ops, ctx); &decon_crtc_ops, ctx);
if (IS_ERR(ctx->crtc)) { if (IS_ERR(ctx->crtc)) {
ret = PTR_ERR(ctx->crtc); ret = PTR_ERR(ctx->crtc);
...@@ -546,38 +551,20 @@ static const struct component_ops decon_component_ops = { ...@@ -546,38 +551,20 @@ static const struct component_ops decon_component_ops = {
.unbind = decon_unbind, .unbind = decon_unbind,
}; };
static irqreturn_t decon_vsync_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;
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)
{ {
struct decon_context *ctx = dev_id; struct decon_context *ctx = dev_id;
u32 val; u32 val;
int win; int win;
if (!test_bit(BIT_CLKS_ENABLED, &ctx->enabled)) if (!test_bit(BIT_CLKS_ENABLED, &ctx->flags))
goto out; goto out;
val = readl(ctx->addr + DECON_VIDINTCON1); val = readl(ctx->addr + DECON_VIDINTCON1);
if (val & VIDINTCON1_INTFRMDONEPEND) { val &= VIDINTCON1_INTFRMDONEPEND | VIDINTCON1_INTFRMPEND;
for (win = 0 ; win < WINDOWS_NR ; win++) {
if (val) {
for (win = ctx->first_win; win < WINDOWS_NR ; win++) {
struct exynos_drm_plane *plane = &ctx->planes[win]; struct exynos_drm_plane *plane = &ctx->planes[win];
if (!plane->pending_fb) if (!plane->pending_fb)
...@@ -587,16 +574,29 @@ static irqreturn_t decon_lcd_sys_irq_handler(int irq, void *dev_id) ...@@ -587,16 +574,29 @@ static irqreturn_t decon_lcd_sys_irq_handler(int irq, void *dev_id)
} }
/* clear */ /* clear */
writel(VIDINTCON1_INTFRMDONEPEND, writel(val, ctx->addr + DECON_VIDINTCON1);
ctx->addr + DECON_VIDINTCON1);
} }
out: out:
return IRQ_HANDLED; 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) static int exynos5433_decon_probe(struct platform_device *pdev)
{ {
const struct of_device_id *of_id;
struct device *dev = &pdev->dev; struct device *dev = &pdev->dev;
struct decon_context *ctx; struct decon_context *ctx;
struct resource *res; struct resource *res;
...@@ -607,11 +607,16 @@ static int exynos5433_decon_probe(struct platform_device *pdev) ...@@ -607,11 +607,16 @@ static int exynos5433_decon_probe(struct platform_device *pdev)
if (!ctx) if (!ctx)
return -ENOMEM; return -ENOMEM;
ctx->default_win = 0; __set_bit(BIT_SUSPENDED, &ctx->flags);
ctx->suspended = true;
ctx->dev = dev; 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++) { for (i = 0; i < ARRAY_SIZE(decon_clks_name); i++) {
struct clk *clk; struct clk *clk;
...@@ -636,14 +641,13 @@ static int exynos5433_decon_probe(struct platform_device *pdev) ...@@ -636,14 +641,13 @@ static int exynos5433_decon_probe(struct platform_device *pdev)
} }
res = platform_get_resource_byname(pdev, IORESOURCE_IRQ, res = platform_get_resource_byname(pdev, IORESOURCE_IRQ,
ctx->i80_if ? "lcd_sys" : "vsync"); (ctx->out_type == IFTYPE_I80) ? "lcd_sys" : "vsync");
if (!res) { if (!res) {
dev_err(dev, "cannot find IRQ resource\n"); dev_err(dev, "cannot find IRQ resource\n");
return -ENXIO; return -ENXIO;
} }
ret = devm_request_irq(dev, res->start, ctx->i80_if ? ret = devm_request_irq(dev, res->start, decon_irq_handler, 0,
decon_lcd_sys_irq_handler : decon_vsync_irq_handler, 0,
"drm_decon", ctx); "drm_decon", ctx);
if (ret < 0) { if (ret < 0) {
dev_err(dev, "lcd_sys irq request failed\n"); dev_err(dev, "lcd_sys irq request failed\n");
...@@ -675,12 +679,6 @@ static int exynos5433_decon_remove(struct platform_device *pdev) ...@@ -675,12 +679,6 @@ static int exynos5433_decon_remove(struct platform_device *pdev)
return 0; 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 = { struct platform_driver exynos5433_decon_driver = {
.probe = exynos5433_decon_probe, .probe = exynos5433_decon_probe,
.remove = exynos5433_decon_remove, .remove = exynos5433_decon_remove,
......
...@@ -40,6 +40,7 @@ ...@@ -40,6 +40,7 @@
#define MIN_FB_WIDTH_FOR_16WORD_BURST 128 #define MIN_FB_WIDTH_FOR_16WORD_BURST 128
#define WINDOWS_NR 2 #define WINDOWS_NR 2
#define CURSOR_WIN 1
struct decon_context { struct decon_context {
struct device *dev; struct device *dev;
...@@ -51,7 +52,6 @@ struct decon_context { ...@@ -51,7 +52,6 @@ struct decon_context {
struct clk *eclk; struct clk *eclk;
struct clk *vclk; struct clk *vclk;
void __iomem *regs; void __iomem *regs;
unsigned int default_win;
unsigned long irq_flags; unsigned long irq_flags;
bool i80_if; bool i80_if;
bool suspended; bool suspended;
...@@ -690,8 +690,7 @@ static int decon_bind(struct device *dev, struct device *master, void *data) ...@@ -690,8 +690,7 @@ static int decon_bind(struct device *dev, struct device *master, void *data)
} }
for (zpos = 0; zpos < WINDOWS_NR; zpos++) { for (zpos = 0; zpos < WINDOWS_NR; zpos++) {
type = (zpos == ctx->default_win) ? DRM_PLANE_TYPE_PRIMARY : type = exynos_plane_get_type(zpos, CURSOR_WIN);
DRM_PLANE_TYPE_OVERLAY;
ret = exynos_plane_init(drm_dev, &ctx->planes[zpos], ret = exynos_plane_init(drm_dev, &ctx->planes[zpos],
1 << ctx->pipe, type, decon_formats, 1 << ctx->pipe, type, decon_formats,
ARRAY_SIZE(decon_formats), zpos); ARRAY_SIZE(decon_formats), zpos);
...@@ -699,7 +698,7 @@ static int decon_bind(struct device *dev, struct device *master, void *data) ...@@ -699,7 +698,7 @@ static int decon_bind(struct device *dev, struct device *master, void *data)
return ret; return ret;
} }
exynos_plane = &ctx->planes[ctx->default_win]; exynos_plane = &ctx->planes[DEFAULT_WIN];
ctx->crtc = exynos_drm_crtc_create(drm_dev, &exynos_plane->base, ctx->crtc = exynos_drm_crtc_create(drm_dev, &exynos_plane->base,
ctx->pipe, EXYNOS_DISPLAY_TYPE_LCD, ctx->pipe, EXYNOS_DISPLAY_TYPE_LCD,
&decon_crtc_ops, ctx); &decon_crtc_ops, ctx);
......
...@@ -50,6 +50,17 @@ exynos_drm_crtc_mode_set_nofb(struct drm_crtc *crtc) ...@@ -50,6 +50,17 @@ exynos_drm_crtc_mode_set_nofb(struct drm_crtc *crtc)
exynos_crtc->ops->commit(exynos_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, static void exynos_crtc_atomic_begin(struct drm_crtc *crtc,
struct drm_crtc_state *old_crtc_state) struct drm_crtc_state *old_crtc_state)
{ {
...@@ -86,6 +97,7 @@ static struct drm_crtc_helper_funcs exynos_crtc_helper_funcs = { ...@@ -86,6 +97,7 @@ static struct drm_crtc_helper_funcs exynos_crtc_helper_funcs = {
.enable = exynos_drm_crtc_enable, .enable = exynos_drm_crtc_enable,
.disable = exynos_drm_crtc_disable, .disable = exynos_drm_crtc_disable,
.mode_set_nofb = exynos_drm_crtc_mode_set_nofb, .mode_set_nofb = exynos_drm_crtc_mode_set_nofb,
.atomic_check = exynos_crtc_atomic_check,
.atomic_begin = exynos_crtc_atomic_begin, .atomic_begin = exynos_crtc_atomic_begin,
.atomic_flush = exynos_crtc_atomic_flush, .atomic_flush = exynos_crtc_atomic_flush,
}; };
......
...@@ -529,8 +529,10 @@ static struct platform_driver *const exynos_drm_kms_drivers[] = { ...@@ -529,8 +529,10 @@ static struct platform_driver *const exynos_drm_kms_drivers[] = {
#ifdef CONFIG_DRM_EXYNOS_DSI #ifdef CONFIG_DRM_EXYNOS_DSI
&dsi_driver, &dsi_driver,
#endif #endif
#ifdef CONFIG_DRM_EXYNOS_HDMI #ifdef CONFIG_DRM_EXYNOS_MIXER
&mixer_driver, &mixer_driver,
#endif
#ifdef CONFIG_DRM_EXYNOS_HDMI
&hdmi_driver, &hdmi_driver,
#endif #endif
#ifdef CONFIG_DRM_EXYNOS_VIDI #ifdef CONFIG_DRM_EXYNOS_VIDI
......
...@@ -22,6 +22,8 @@ ...@@ -22,6 +22,8 @@
#define MAX_PLANE 5 #define MAX_PLANE 5
#define MAX_FB_BUFFER 4 #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_crtc(x) container_of(x, struct exynos_drm_crtc, base)
#define to_exynos_plane(x) container_of(x, struct exynos_drm_plane, base) #define to_exynos_plane(x) container_of(x, struct exynos_drm_plane, base)
...@@ -87,6 +89,7 @@ struct exynos_drm_plane { ...@@ -87,6 +89,7 @@ struct exynos_drm_plane {
* @disable_vblank: specific driver callback for disabling vblank interrupt. * @disable_vblank: specific driver callback for disabling vblank interrupt.
* @wait_for_vblank: wait for vblank interrupt to make sure that * @wait_for_vblank: wait for vblank interrupt to make sure that
* hardware overlay is updated. * hardware overlay is updated.
* @atomic_check: validate state
* @atomic_begin: prepare a window to receive a update * @atomic_begin: prepare a window to receive a update
* @atomic_flush: mark the end of a window update * @atomic_flush: mark the end of a window update
* @update_plane: apply hardware specific overlay data to registers. * @update_plane: apply hardware specific overlay data to registers.
...@@ -106,6 +109,8 @@ struct exynos_drm_crtc_ops { ...@@ -106,6 +109,8 @@ struct exynos_drm_crtc_ops {
int (*enable_vblank)(struct exynos_drm_crtc *crtc); int (*enable_vblank)(struct exynos_drm_crtc *crtc);
void (*disable_vblank)(struct exynos_drm_crtc *crtc); void (*disable_vblank)(struct exynos_drm_crtc *crtc);
void (*wait_for_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, void (*atomic_begin)(struct exynos_drm_crtc *crtc,
struct exynos_drm_plane *plane); struct exynos_drm_plane *plane);
void (*update_plane)(struct exynos_drm_crtc *crtc, void (*update_plane)(struct exynos_drm_crtc *crtc,
......
...@@ -32,15 +32,15 @@ ...@@ -32,15 +32,15 @@
* exynos specific framebuffer structure. * exynos specific framebuffer structure.
* *
* @fb: drm framebuffer obejct. * @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 exynos_drm_fb {
struct drm_framebuffer fb; struct drm_framebuffer fb;
struct exynos_drm_gem_obj *exynos_gem_obj[MAX_FB_BUFFER]; struct exynos_drm_gem *exynos_gem[MAX_FB_BUFFER];
}; };
static int check_fb_gem_memory_type(struct drm_device *drm_dev, 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; unsigned int flags;
...@@ -51,7 +51,7 @@ static int check_fb_gem_memory_type(struct drm_device *drm_dev, ...@@ -51,7 +51,7 @@ static int check_fb_gem_memory_type(struct drm_device *drm_dev,
if (is_drm_iommu_supported(drm_dev)) if (is_drm_iommu_supported(drm_dev))
return 0; return 0;
flags = exynos_gem_obj->flags; flags = exynos_gem->flags;
/* /*
* without iommu support, not support physically non-continuous memory * without iommu support, not support physically non-continuous memory
...@@ -75,13 +75,13 @@ static void exynos_drm_fb_destroy(struct drm_framebuffer *fb) ...@@ -75,13 +75,13 @@ static void exynos_drm_fb_destroy(struct drm_framebuffer *fb)
drm_framebuffer_cleanup(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; struct drm_gem_object *obj;
if (exynos_fb->exynos_gem_obj[i] == NULL) if (exynos_fb->exynos_gem[i] == NULL)
continue; continue;
obj = &exynos_fb->exynos_gem_obj[i]->base; obj = &exynos_fb->exynos_gem[i]->base;
drm_gem_object_unreference_unlocked(obj); drm_gem_object_unreference_unlocked(obj);
} }
...@@ -96,7 +96,7 @@ static int exynos_drm_fb_create_handle(struct drm_framebuffer *fb, ...@@ -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); struct exynos_drm_fb *exynos_fb = to_exynos_fb(fb);
return drm_gem_handle_create(file_priv, 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, static int exynos_drm_fb_dirty(struct drm_framebuffer *fb,
...@@ -118,7 +118,7 @@ static struct drm_framebuffer_funcs exynos_drm_fb_funcs = { ...@@ -118,7 +118,7 @@ static struct drm_framebuffer_funcs exynos_drm_fb_funcs = {
struct drm_framebuffer * struct drm_framebuffer *
exynos_drm_framebuffer_init(struct drm_device *dev, exynos_drm_framebuffer_init(struct drm_device *dev,
struct drm_mode_fb_cmd2 *mode_cmd, struct drm_mode_fb_cmd2 *mode_cmd,
struct exynos_drm_gem_obj **gem_obj, struct exynos_drm_gem **exynos_gem,
int count) int count)
{ {
struct exynos_drm_fb *exynos_fb; struct exynos_drm_fb *exynos_fb;
...@@ -130,11 +130,11 @@ exynos_drm_framebuffer_init(struct drm_device *dev, ...@@ -130,11 +130,11 @@ exynos_drm_framebuffer_init(struct drm_device *dev,
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
for (i = 0; i < count; i++) { 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) if (ret < 0)
goto err; 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); drm_helper_mode_fill_fb_struct(&exynos_fb->fb, mode_cmd);
...@@ -156,7 +156,7 @@ static struct drm_framebuffer * ...@@ -156,7 +156,7 @@ static struct drm_framebuffer *
exynos_user_fb_create(struct drm_device *dev, struct drm_file *file_priv, exynos_user_fb_create(struct drm_device *dev, struct drm_file *file_priv,
struct drm_mode_fb_cmd2 *mode_cmd) 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_gem_object *obj;
struct drm_framebuffer *fb; struct drm_framebuffer *fb;
int i; int i;
...@@ -171,10 +171,10 @@ exynos_user_fb_create(struct drm_device *dev, struct drm_file *file_priv, ...@@ -171,10 +171,10 @@ exynos_user_fb_create(struct drm_device *dev, struct drm_file *file_priv,
goto err; 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)) { if (IS_ERR(fb)) {
ret = PTR_ERR(fb); ret = PTR_ERR(fb);
goto err; goto err;
...@@ -184,27 +184,26 @@ exynos_user_fb_create(struct drm_device *dev, struct drm_file *file_priv, ...@@ -184,27 +184,26 @@ exynos_user_fb_create(struct drm_device *dev, struct drm_file *file_priv,
err: err:
while (i--) while (i--)
drm_gem_object_unreference_unlocked(&gem_objs[i]->base); drm_gem_object_unreference_unlocked(&exynos_gem[i]->base);
return ERR_PTR(ret); return ERR_PTR(ret);
} }
struct exynos_drm_gem_obj *exynos_drm_fb_gem_obj(struct drm_framebuffer *fb, struct exynos_drm_gem *exynos_drm_fb_gem(struct drm_framebuffer *fb, int index)
int index)
{ {
struct exynos_drm_fb *exynos_fb = to_exynos_fb(fb); 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) if (index >= MAX_FB_BUFFER)
return NULL; return NULL;
obj = exynos_fb->exynos_gem_obj[index]; exynos_gem = exynos_fb->exynos_gem[index];
if (!obj) if (!exynos_gem)
return NULL; 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) static void exynos_drm_output_poll_changed(struct drm_device *dev)
......
...@@ -19,12 +19,11 @@ ...@@ -19,12 +19,11 @@
struct drm_framebuffer * struct drm_framebuffer *
exynos_drm_framebuffer_init(struct drm_device *dev, exynos_drm_framebuffer_init(struct drm_device *dev,
struct drm_mode_fb_cmd2 *mode_cmd, struct drm_mode_fb_cmd2 *mode_cmd,
struct exynos_drm_gem_obj **gem_obj, struct exynos_drm_gem **exynos_gem,
int count); int count);
/* get gem object of a drm framebuffer */ /* get gem object of a drm framebuffer */
struct exynos_drm_gem_obj *exynos_drm_fb_gem_obj(struct drm_framebuffer *fb, struct exynos_drm_gem *exynos_drm_fb_gem(struct drm_framebuffer *fb, int index);
int index);
void exynos_drm_mode_config_init(struct drm_device *dev); void exynos_drm_mode_config_init(struct drm_device *dev);
......
...@@ -31,7 +31,7 @@ ...@@ -31,7 +31,7 @@
struct exynos_drm_fbdev { struct exynos_drm_fbdev {
struct drm_fb_helper drm_fb_helper; struct drm_fb_helper drm_fb_helper;
struct exynos_drm_gem_obj *obj; struct exynos_drm_gem *exynos_gem;
}; };
static int exynos_drm_fb_mmap(struct fb_info *info, static int exynos_drm_fb_mmap(struct fb_info *info,
...@@ -39,7 +39,7 @@ 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 drm_fb_helper *helper = info->par;
struct exynos_drm_fbdev *exynos_fbd = to_exynos_fbdev(helper); 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; unsigned long vm_size;
int ret; int ret;
...@@ -47,11 +47,12 @@ static int exynos_drm_fb_mmap(struct fb_info *info, ...@@ -47,11 +47,12 @@ static int exynos_drm_fb_mmap(struct fb_info *info,
vm_size = vma->vm_end - vma->vm_start; vm_size = vma->vm_end - vma->vm_start;
if (vm_size > obj->size) if (vm_size > exynos_gem->size)
return -EINVAL; return -EINVAL;
ret = dma_mmap_attrs(helper->dev->dev, vma, obj->pages, obj->dma_addr, ret = dma_mmap_attrs(helper->dev->dev, vma, exynos_gem->pages,
obj->size, &obj->dma_attrs); exynos_gem->dma_addr, exynos_gem->size,
&exynos_gem->dma_attrs);
if (ret < 0) { if (ret < 0) {
DRM_ERROR("failed to mmap.\n"); DRM_ERROR("failed to mmap.\n");
return ret; return ret;
...@@ -75,7 +76,7 @@ static struct fb_ops exynos_drm_fb_ops = { ...@@ -75,7 +76,7 @@ static struct fb_ops exynos_drm_fb_ops = {
static int exynos_drm_fbdev_update(struct drm_fb_helper *helper, static int exynos_drm_fbdev_update(struct drm_fb_helper *helper,
struct drm_fb_helper_surface_size *sizes, struct drm_fb_helper_surface_size *sizes,
struct exynos_drm_gem_obj *obj) struct exynos_drm_gem *exynos_gem)
{ {
struct fb_info *fbi; struct fb_info *fbi;
struct drm_framebuffer *fb = helper->fb; struct drm_framebuffer *fb = helper->fb;
...@@ -96,11 +97,11 @@ static int exynos_drm_fbdev_update(struct drm_fb_helper *helper, ...@@ -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_fix(fbi, fb->pitches[0], fb->depth);
drm_fb_helper_fill_var(fbi, helper, sizes->fb_width, sizes->fb_height); 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, exynos_gem->kvaddr = (void __iomem *) vmap(exynos_gem->pages, nr_pages,
pgprot_writecombine(PAGE_KERNEL)); VM_MAP, pgprot_writecombine(PAGE_KERNEL));
if (!obj->kvaddr) { if (!exynos_gem->kvaddr) {
DRM_ERROR("failed to map pages to kernel space.\n"); DRM_ERROR("failed to map pages to kernel space.\n");
drm_fb_helper_release_fbi(helper); drm_fb_helper_release_fbi(helper);
return -EIO; return -EIO;
...@@ -109,7 +110,7 @@ static int exynos_drm_fbdev_update(struct drm_fb_helper *helper, ...@@ -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.xoffset * (fb->bits_per_pixel >> 3);
offset += fbi->var.yoffset * fb->pitches[0]; 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->screen_size = size;
fbi->fix.smem_len = size; fbi->fix.smem_len = size;
...@@ -120,7 +121,7 @@ static int exynos_drm_fbdev_create(struct drm_fb_helper *helper, ...@@ -120,7 +121,7 @@ static int exynos_drm_fbdev_create(struct drm_fb_helper *helper,
struct drm_fb_helper_surface_size *sizes) struct drm_fb_helper_surface_size *sizes)
{ {
struct exynos_drm_fbdev *exynos_fbdev = to_exynos_fbdev(helper); 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_device *dev = helper->dev;
struct drm_mode_fb_cmd2 mode_cmd = { 0 }; struct drm_mode_fb_cmd2 mode_cmd = { 0 };
struct platform_device *pdev = dev->platformdev; struct platform_device *pdev = dev->platformdev;
...@@ -141,32 +142,34 @@ static int exynos_drm_fbdev_create(struct drm_fb_helper *helper, ...@@ -141,32 +142,34 @@ static int exynos_drm_fbdev_create(struct drm_fb_helper *helper,
size = mode_cmd.pitches[0] * mode_cmd.height; 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 * If physically contiguous memory allocation fails and if IOMMU is
* supported then try to get buffer from non physically contiguous * supported then try to get buffer from non physically contiguous
* memory area. * 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"); 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)) { if (IS_ERR(exynos_gem)) {
ret = PTR_ERR(obj); ret = PTR_ERR(exynos_gem);
goto out; 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)) { if (IS_ERR(helper->fb)) {
DRM_ERROR("failed to create drm framebuffer.\n"); DRM_ERROR("failed to create drm framebuffer.\n");
ret = PTR_ERR(helper->fb); ret = PTR_ERR(helper->fb);
goto err_destroy_gem; goto err_destroy_gem;
} }
ret = exynos_drm_fbdev_update(helper, sizes, obj); ret = exynos_drm_fbdev_update(helper, sizes, exynos_gem);
if (ret < 0) if (ret < 0)
goto err_destroy_framebuffer; goto err_destroy_framebuffer;
...@@ -176,7 +179,7 @@ static int exynos_drm_fbdev_create(struct drm_fb_helper *helper, ...@@ -176,7 +179,7 @@ static int exynos_drm_fbdev_create(struct drm_fb_helper *helper,
err_destroy_framebuffer: err_destroy_framebuffer:
drm_framebuffer_cleanup(helper->fb); drm_framebuffer_cleanup(helper->fb);
err_destroy_gem: err_destroy_gem:
exynos_drm_gem_destroy(obj); exynos_drm_gem_destroy(exynos_gem);
/* /*
* if failed, all resources allocated above would be released by * if failed, all resources allocated above would be released by
...@@ -269,11 +272,11 @@ static void exynos_drm_fbdev_destroy(struct drm_device *dev, ...@@ -269,11 +272,11 @@ static void exynos_drm_fbdev_destroy(struct drm_device *dev,
struct drm_fb_helper *fb_helper) struct drm_fb_helper *fb_helper)
{ {
struct exynos_drm_fbdev *exynos_fbd = to_exynos_fbdev(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; struct drm_framebuffer *fb;
if (obj->kvaddr) if (exynos_gem->kvaddr)
vunmap(obj->kvaddr); vunmap(exynos_gem->kvaddr);
/* release drm framebuffer and real buffer */ /* release drm framebuffer and real buffer */
if (fb_helper->fb && fb_helper->fb->funcs) { if (fb_helper->fb && fb_helper->fb->funcs) {
......
...@@ -466,7 +466,7 @@ static int fimc_src_set_fmt_order(struct fimc_context *ctx, u32 fmt) ...@@ -466,7 +466,7 @@ static int fimc_src_set_fmt_order(struct fimc_context *ctx, u32 fmt)
EXYNOS_MSCTRL_C_INT_IN_2PLANE); EXYNOS_MSCTRL_C_INT_IN_2PLANE);
break; break;
default: 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; return -EINVAL;
} }
...@@ -513,7 +513,7 @@ static int fimc_src_set_fmt(struct device *dev, u32 fmt) ...@@ -513,7 +513,7 @@ static int fimc_src_set_fmt(struct device *dev, u32 fmt)
cfg |= EXYNOS_MSCTRL_INFORMAT_YCBCR420; cfg |= EXYNOS_MSCTRL_INFORMAT_YCBCR420;
break; break;
default: 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; return -EINVAL;
} }
...@@ -578,7 +578,7 @@ static int fimc_src_set_transf(struct device *dev, ...@@ -578,7 +578,7 @@ static int fimc_src_set_transf(struct device *dev,
cfg1 &= ~EXYNOS_MSCTRL_FLIP_Y_MIRROR; cfg1 &= ~EXYNOS_MSCTRL_FLIP_Y_MIRROR;
break; break;
default: default:
dev_err(ippdrv->dev, "inavlid degree value %d.\n", degree); dev_err(ippdrv->dev, "invalid degree value %d.\n", degree);
return -EINVAL; return -EINVAL;
} }
...@@ -701,7 +701,7 @@ static int fimc_src_set_addr(struct device *dev, ...@@ -701,7 +701,7 @@ static int fimc_src_set_addr(struct device *dev,
property->prop_id, buf_id, buf_type); property->prop_id, buf_id, buf_type);
if (buf_id > FIMC_MAX_SRC) { 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; return -ENOMEM;
} }
...@@ -812,7 +812,7 @@ static int fimc_dst_set_fmt_order(struct fimc_context *ctx, u32 fmt) ...@@ -812,7 +812,7 @@ static int fimc_dst_set_fmt_order(struct fimc_context *ctx, u32 fmt)
cfg |= EXYNOS_CIOCTRL_YCBCR_2PLANE; cfg |= EXYNOS_CIOCTRL_YCBCR_2PLANE;
break; break;
default: 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; return -EINVAL;
} }
...@@ -865,7 +865,7 @@ static int fimc_dst_set_fmt(struct device *dev, u32 fmt) ...@@ -865,7 +865,7 @@ static int fimc_dst_set_fmt(struct device *dev, u32 fmt)
cfg |= EXYNOS_CITRGFMT_OUTFORMAT_YCBCR420; cfg |= EXYNOS_CITRGFMT_OUTFORMAT_YCBCR420;
break; break;
default: default:
dev_err(ippdrv->dev, "inavlid target format 0x%x.\n", dev_err(ippdrv->dev, "invalid target format 0x%x.\n",
fmt); fmt);
return -EINVAL; return -EINVAL;
} }
...@@ -929,7 +929,7 @@ static int fimc_dst_set_transf(struct device *dev, ...@@ -929,7 +929,7 @@ static int fimc_dst_set_transf(struct device *dev,
cfg &= ~EXYNOS_CITRGFMT_FLIP_Y_MIRROR; cfg &= ~EXYNOS_CITRGFMT_FLIP_Y_MIRROR;
break; break;
default: default:
dev_err(ippdrv->dev, "inavlid degree value %d.\n", degree); dev_err(ippdrv->dev, "invalid degree value %d.\n", degree);
return -EINVAL; return -EINVAL;
} }
...@@ -1160,7 +1160,7 @@ static int fimc_dst_set_addr(struct device *dev, ...@@ -1160,7 +1160,7 @@ static int fimc_dst_set_addr(struct device *dev,
property->prop_id, buf_id, buf_type); property->prop_id, buf_id, buf_type);
if (buf_id > FIMC_MAX_DST) { 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; return -ENOMEM;
} }
......
...@@ -87,6 +87,7 @@ ...@@ -87,6 +87,7 @@
/* FIMD has totally five hardware windows. */ /* FIMD has totally five hardware windows. */
#define WINDOWS_NR 5 #define WINDOWS_NR 5
#define CURSOR_WIN 4
struct fimd_driver_data { struct fimd_driver_data {
unsigned int timing_base; unsigned int timing_base;
...@@ -153,7 +154,6 @@ struct fimd_context { ...@@ -153,7 +154,6 @@ struct fimd_context {
struct clk *lcd_clk; struct clk *lcd_clk;
void __iomem *regs; void __iomem *regs;
struct regmap *sysreg; struct regmap *sysreg;
unsigned int default_win;
unsigned long irq_flags; unsigned long irq_flags;
u32 vidcon0; u32 vidcon0;
u32 vidcon1; u32 vidcon1;
...@@ -949,8 +949,7 @@ static int fimd_bind(struct device *dev, struct device *master, void *data) ...@@ -949,8 +949,7 @@ static int fimd_bind(struct device *dev, struct device *master, void *data)
ctx->pipe = priv->pipe++; ctx->pipe = priv->pipe++;
for (zpos = 0; zpos < WINDOWS_NR; zpos++) { for (zpos = 0; zpos < WINDOWS_NR; zpos++) {
type = (zpos == ctx->default_win) ? DRM_PLANE_TYPE_PRIMARY : type = exynos_plane_get_type(zpos, CURSOR_WIN);
DRM_PLANE_TYPE_OVERLAY;
ret = exynos_plane_init(drm_dev, &ctx->planes[zpos], ret = exynos_plane_init(drm_dev, &ctx->planes[zpos],
1 << ctx->pipe, type, fimd_formats, 1 << ctx->pipe, type, fimd_formats,
ARRAY_SIZE(fimd_formats), zpos); ARRAY_SIZE(fimd_formats), zpos);
...@@ -958,7 +957,7 @@ static int fimd_bind(struct device *dev, struct device *master, void *data) ...@@ -958,7 +957,7 @@ static int fimd_bind(struct device *dev, struct device *master, void *data)
return ret; return ret;
} }
exynos_plane = &ctx->planes[ctx->default_win]; exynos_plane = &ctx->planes[DEFAULT_WIN];
ctx->crtc = exynos_drm_crtc_create(drm_dev, &exynos_plane->base, ctx->crtc = exynos_drm_crtc_create(drm_dev, &exynos_plane->base,
ctx->pipe, EXYNOS_DISPLAY_TYPE_LCD, ctx->pipe, EXYNOS_DISPLAY_TYPE_LCD,
&fimd_crtc_ops, ctx); &fimd_crtc_ops, ctx);
......
...@@ -20,97 +20,108 @@ ...@@ -20,97 +20,108 @@
#include "exynos_drm_gem.h" #include "exynos_drm_gem.h"
#include "exynos_drm_iommu.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; enum dma_attr attr;
unsigned int nr_pages; 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"); DRM_DEBUG_KMS("already allocated.\n");
return 0; return 0;
} }
init_dma_attrs(&obj->dma_attrs); init_dma_attrs(&exynos_gem->dma_attrs);
/* /*
* if EXYNOS_BO_CONTIG, fully physically contiguous memory * if EXYNOS_BO_CONTIG, fully physically contiguous memory
* region will be allocated else physically contiguous * region will be allocated else physically contiguous
* as possible. * as possible.
*/ */
if (!(obj->flags & EXYNOS_BO_NONCONTIG)) if (!(exynos_gem->flags & EXYNOS_BO_NONCONTIG))
dma_set_attr(DMA_ATTR_FORCE_CONTIGUOUS, &obj->dma_attrs); dma_set_attr(DMA_ATTR_FORCE_CONTIGUOUS, &exynos_gem->dma_attrs);
/* /*
* if EXYNOS_BO_WC or EXYNOS_BO_NONCACHABLE, writecombine mapping * if EXYNOS_BO_WC or EXYNOS_BO_NONCACHABLE, writecombine mapping
* else cachable 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; attr = DMA_ATTR_WRITE_COMBINE;
else else
attr = DMA_ATTR_NON_CONSISTENT; attr = DMA_ATTR_NON_CONSISTENT;
dma_set_attr(attr, &obj->dma_attrs); dma_set_attr(attr, &exynos_gem->dma_attrs);
dma_set_attr(DMA_ATTR_NO_KERNEL_MAPPING, &obj->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)) { exynos_gem->pages = drm_calloc_large(nr_pages, sizeof(struct page *));
obj->pages = drm_calloc_large(nr_pages, sizeof(struct page *)); if (!exynos_gem->pages) {
if (!obj->pages) {
DRM_ERROR("failed to allocate pages.\n"); DRM_ERROR("failed to allocate pages.\n");
return -ENOMEM; return -ENOMEM;
} }
}
obj->cookie = dma_alloc_attrs(dev->dev, obj->size, &obj->dma_addr, exynos_gem->cookie = dma_alloc_attrs(dev->dev, exynos_gem->size,
GFP_KERNEL, &obj->dma_attrs); &exynos_gem->dma_addr, GFP_KERNEL,
if (!obj->cookie) { &exynos_gem->dma_attrs);
if (!exynos_gem->cookie) {
DRM_ERROR("failed to allocate buffer.\n"); DRM_ERROR("failed to allocate buffer.\n");
if (obj->pages) goto err_free;
drm_free_large(obj->pages);
return -ENOMEM;
} }
if (obj->pages) { ret = dma_get_sgtable_attrs(dev->dev, &sgt, exynos_gem->cookie,
dma_addr_t start_addr; exynos_gem->dma_addr, exynos_gem->size,
unsigned int i = 0; &exynos_gem->dma_attrs);
if (ret < 0) {
start_addr = obj->dma_addr; DRM_ERROR("failed to get sgtable.\n");
while (i < nr_pages) { goto err_dma_free;
obj->pages[i] = pfn_to_page(dma_to_pfn(dev->dev,
start_addr));
start_addr += PAGE_SIZE;
i++;
} }
} else {
obj->pages = obj->cookie; 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", DRM_DEBUG_KMS("dma_addr(0x%lx), size(0x%lx)\n",
(unsigned long)obj->dma_addr, (unsigned long)exynos_gem->dma_addr, exynos_gem->size);
obj->size);
return 0; 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"); DRM_DEBUG_KMS("dma_addr is invalid.\n");
return; return;
} }
DRM_DEBUG_KMS("dma_addr(0x%lx), size(0x%lx)\n", 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_free_attrs(dev->dev, exynos_gem->size, exynos_gem->cookie,
(dma_addr_t)obj->dma_addr, &obj->dma_attrs); (dma_addr_t)exynos_gem->dma_addr,
&exynos_gem->dma_attrs);
if (!is_drm_iommu_supported(dev)) drm_free_large(exynos_gem->pages);
drm_free_large(obj->pages);
} }
static int exynos_drm_gem_handle_create(struct drm_gem_object *obj, 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, ...@@ -135,9 +146,9 @@ static int exynos_drm_gem_handle_create(struct drm_gem_object *obj,
return 0; 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); 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) ...@@ -148,21 +159,21 @@ void exynos_drm_gem_destroy(struct exynos_drm_gem_obj *exynos_gem_obj)
* once dmabuf's refcount becomes 0. * once dmabuf's refcount becomes 0.
*/ */
if (obj->import_attach) if (obj->import_attach)
drm_prime_gem_destroy(obj, exynos_gem_obj->sgt); drm_prime_gem_destroy(obj, exynos_gem->sgt);
else else
exynos_drm_free_buf(exynos_gem_obj); exynos_drm_free_buf(exynos_gem);
/* release file pointer to gem object. */ /* release file pointer to gem object. */
drm_gem_object_release(obj); drm_gem_object_release(obj);
kfree(exynos_gem_obj); kfree(exynos_gem);
} }
unsigned long exynos_drm_gem_get_size(struct drm_device *dev, unsigned long exynos_drm_gem_get_size(struct drm_device *dev,
unsigned int gem_handle, unsigned int gem_handle,
struct drm_file *file_priv) struct drm_file *file_priv)
{ {
struct exynos_drm_gem_obj *exynos_gem_obj; struct exynos_drm_gem *exynos_gem;
struct drm_gem_object *obj; struct drm_gem_object *obj;
obj = drm_gem_object_lookup(dev, file_priv, gem_handle); 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, ...@@ -171,51 +182,51 @@ unsigned long exynos_drm_gem_get_size(struct drm_device *dev,
return 0; return 0;
} }
exynos_gem_obj = to_exynos_gem_obj(obj); exynos_gem = to_exynos_gem(obj);
drm_gem_object_unreference_unlocked(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, static struct exynos_drm_gem *exynos_drm_gem_init(struct drm_device *dev,
unsigned long size) unsigned long size)
{ {
struct exynos_drm_gem_obj *exynos_gem_obj; struct exynos_drm_gem *exynos_gem;
struct drm_gem_object *obj; struct drm_gem_object *obj;
int ret; int ret;
exynos_gem_obj = kzalloc(sizeof(*exynos_gem_obj), GFP_KERNEL); exynos_gem = kzalloc(sizeof(*exynos_gem), GFP_KERNEL);
if (!exynos_gem_obj) if (!exynos_gem)
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
exynos_gem_obj->size = size; exynos_gem->size = size;
obj = &exynos_gem_obj->base; obj = &exynos_gem->base;
ret = drm_gem_object_init(dev, obj, size); ret = drm_gem_object_init(dev, obj, size);
if (ret < 0) { if (ret < 0) {
DRM_ERROR("failed to initialize gem object\n"); DRM_ERROR("failed to initialize gem object\n");
kfree(exynos_gem_obj); kfree(exynos_gem);
return ERR_PTR(ret); return ERR_PTR(ret);
} }
ret = drm_gem_create_mmap_offset(obj); ret = drm_gem_create_mmap_offset(obj);
if (ret < 0) { if (ret < 0) {
drm_gem_object_release(obj); drm_gem_object_release(obj);
kfree(exynos_gem_obj); kfree(exynos_gem);
return ERR_PTR(ret); return ERR_PTR(ret);
} }
DRM_DEBUG_KMS("created file object = 0x%x\n", (unsigned int)obj->filp); 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, struct exynos_drm_gem *exynos_drm_gem_create(struct drm_device *dev,
unsigned int flags, unsigned int flags,
unsigned long size) unsigned long size)
{ {
struct exynos_drm_gem_obj *exynos_gem_obj; struct exynos_drm_gem *exynos_gem;
int ret; int ret;
if (flags & ~(EXYNOS_BO_MASK)) { if (flags & ~(EXYNOS_BO_MASK)) {
...@@ -230,38 +241,38 @@ struct exynos_drm_gem_obj *exynos_drm_gem_create(struct drm_device *dev, ...@@ -230,38 +241,38 @@ struct exynos_drm_gem_obj *exynos_drm_gem_create(struct drm_device *dev,
size = roundup(size, PAGE_SIZE); size = roundup(size, PAGE_SIZE);
exynos_gem_obj = exynos_drm_gem_init(dev, size); exynos_gem = exynos_drm_gem_init(dev, size);
if (IS_ERR(exynos_gem_obj)) if (IS_ERR(exynos_gem))
return exynos_gem_obj; return exynos_gem;
/* set memory type and cache attribute from user side. */ /* 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) { if (ret < 0) {
drm_gem_object_release(&exynos_gem_obj->base); drm_gem_object_release(&exynos_gem->base);
kfree(exynos_gem_obj); kfree(exynos_gem);
return ERR_PTR(ret); return ERR_PTR(ret);
} }
return exynos_gem_obj; return exynos_gem;
} }
int exynos_drm_gem_create_ioctl(struct drm_device *dev, void *data, int exynos_drm_gem_create_ioctl(struct drm_device *dev, void *data,
struct drm_file *file_priv) struct drm_file *file_priv)
{ {
struct drm_exynos_gem_create *args = data; struct drm_exynos_gem_create *args = data;
struct exynos_drm_gem_obj *exynos_gem_obj; struct exynos_drm_gem *exynos_gem;
int ret; int ret;
exynos_gem_obj = exynos_drm_gem_create(dev, args->flags, args->size); exynos_gem = exynos_drm_gem_create(dev, args->flags, args->size);
if (IS_ERR(exynos_gem_obj)) if (IS_ERR(exynos_gem))
return PTR_ERR(exynos_gem_obj); return PTR_ERR(exynos_gem);
ret = exynos_drm_gem_handle_create(&exynos_gem_obj->base, file_priv, ret = exynos_drm_gem_handle_create(&exynos_gem->base, file_priv,
&args->handle); &args->handle);
if (ret) { if (ret) {
exynos_drm_gem_destroy(exynos_gem_obj); exynos_drm_gem_destroy(exynos_gem);
return ret; return ret;
} }
...@@ -272,7 +283,7 @@ dma_addr_t *exynos_drm_gem_get_dma_addr(struct drm_device *dev, ...@@ -272,7 +283,7 @@ dma_addr_t *exynos_drm_gem_get_dma_addr(struct drm_device *dev,
unsigned int gem_handle, unsigned int gem_handle,
struct drm_file *filp) struct drm_file *filp)
{ {
struct exynos_drm_gem_obj *exynos_gem_obj; struct exynos_drm_gem *exynos_gem;
struct drm_gem_object *obj; struct drm_gem_object *obj;
obj = drm_gem_object_lookup(dev, filp, gem_handle); 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, ...@@ -281,9 +292,9 @@ dma_addr_t *exynos_drm_gem_get_dma_addr(struct drm_device *dev,
return ERR_PTR(-EINVAL); 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, 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, ...@@ -307,10 +318,10 @@ void exynos_drm_gem_put_dma_addr(struct drm_device *dev,
drm_gem_object_unreference_unlocked(obj); 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 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; unsigned long vm_size;
int ret; int ret;
...@@ -320,12 +331,12 @@ static int exynos_drm_gem_mmap_buffer(struct exynos_drm_gem_obj *exynos_gem_obj, ...@@ -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; vm_size = vma->vm_end - vma->vm_start;
/* check if user-requested size is valid. */ /* check if user-requested size is valid. */
if (vm_size > exynos_gem_obj->size) if (vm_size > exynos_gem->size)
return -EINVAL; return -EINVAL;
ret = dma_mmap_attrs(drm_dev->dev, vma, exynos_gem_obj->pages, ret = dma_mmap_attrs(drm_dev->dev, vma, exynos_gem->pages,
exynos_gem_obj->dma_addr, exynos_gem_obj->size, exynos_gem->dma_addr, exynos_gem->size,
&exynos_gem_obj->dma_attrs); &exynos_gem->dma_attrs);
if (ret < 0) { if (ret < 0) {
DRM_ERROR("failed to mmap.\n"); DRM_ERROR("failed to mmap.\n");
return ret; return ret;
...@@ -337,7 +348,7 @@ static int exynos_drm_gem_mmap_buffer(struct exynos_drm_gem_obj *exynos_gem_obj, ...@@ -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, int exynos_drm_gem_get_ioctl(struct drm_device *dev, void *data,
struct drm_file *file_priv) 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_exynos_gem_info *args = data;
struct drm_gem_object *obj; struct drm_gem_object *obj;
...@@ -350,10 +361,10 @@ int exynos_drm_gem_get_ioctl(struct drm_device *dev, void *data, ...@@ -350,10 +361,10 @@ int exynos_drm_gem_get_ioctl(struct drm_device *dev, void *data,
return -EINVAL; return -EINVAL;
} }
exynos_gem_obj = to_exynos_gem_obj(obj); exynos_gem = to_exynos_gem(obj);
args->flags = exynos_gem_obj->flags; args->flags = exynos_gem->flags;
args->size = exynos_gem_obj->size; args->size = exynos_gem->size;
drm_gem_object_unreference(obj); drm_gem_object_unreference(obj);
mutex_unlock(&dev->struct_mutex); mutex_unlock(&dev->struct_mutex);
...@@ -389,14 +400,14 @@ void exynos_gem_unmap_sgt_from_dma(struct drm_device *drm_dev, ...@@ -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) 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, int exynos_drm_gem_dumb_create(struct drm_file *file_priv,
struct drm_device *dev, struct drm_device *dev,
struct drm_mode_create_dumb *args) struct drm_mode_create_dumb *args)
{ {
struct exynos_drm_gem_obj *exynos_gem_obj; struct exynos_drm_gem *exynos_gem;
unsigned int flags; unsigned int flags;
int ret; int ret;
...@@ -414,16 +425,16 @@ int exynos_drm_gem_dumb_create(struct drm_file *file_priv, ...@@ -414,16 +425,16 @@ int exynos_drm_gem_dumb_create(struct drm_file *file_priv,
else else
flags = EXYNOS_BO_CONTIG | EXYNOS_BO_WC; flags = EXYNOS_BO_CONTIG | EXYNOS_BO_WC;
exynos_gem_obj = exynos_drm_gem_create(dev, flags, args->size); exynos_gem = exynos_drm_gem_create(dev, flags, args->size);
if (IS_ERR(exynos_gem_obj)) { if (IS_ERR(exynos_gem)) {
dev_warn(dev->dev, "FB allocation failed.\n"); 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, ret = exynos_drm_gem_handle_create(&exynos_gem->base, file_priv,
&args->handle); &args->handle);
if (ret) { if (ret) {
exynos_drm_gem_destroy(exynos_gem_obj); exynos_drm_gem_destroy(exynos_gem);
return ret; return ret;
} }
...@@ -464,7 +475,7 @@ int exynos_drm_gem_dumb_map_offset(struct drm_file *file_priv, ...@@ -464,7 +475,7 @@ int exynos_drm_gem_dumb_map_offset(struct drm_file *file_priv,
int exynos_drm_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf) int exynos_drm_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
{ {
struct drm_gem_object *obj = vma->vm_private_data; 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; unsigned long pfn;
pgoff_t page_offset; pgoff_t page_offset;
int ret; int ret;
...@@ -472,13 +483,13 @@ int exynos_drm_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf) ...@@ -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 - page_offset = ((unsigned long)vmf->virtual_address -
vma->vm_start) >> PAGE_SHIFT; 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"); DRM_ERROR("invalid page offset\n");
ret = -EINVAL; ret = -EINVAL;
goto out; 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); ret = vm_insert_mixed(vma, (unsigned long)vmf->virtual_address, pfn);
out: out:
...@@ -496,7 +507,7 @@ int exynos_drm_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf) ...@@ -496,7 +507,7 @@ int exynos_drm_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
int exynos_drm_gem_mmap(struct file *filp, struct vm_area_struct *vma) 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; struct drm_gem_object *obj;
int ret; int ret;
...@@ -508,21 +519,21 @@ int exynos_drm_gem_mmap(struct file *filp, struct vm_area_struct *vma) ...@@ -508,21 +519,21 @@ int exynos_drm_gem_mmap(struct file *filp, struct vm_area_struct *vma)
} }
obj = vma->vm_private_data; 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. */ /* 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); 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 = vma->vm_page_prot =
pgprot_writecombine(vm_get_page_prot(vma->vm_flags)); pgprot_writecombine(vm_get_page_prot(vma->vm_flags));
else else
vma->vm_page_prot = vma->vm_page_prot =
pgprot_noncached(vm_get_page_prot(vma->vm_flags)); 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) if (ret)
goto err_close_vm; goto err_close_vm;
...@@ -537,12 +548,12 @@ int exynos_drm_gem_mmap(struct file *filp, struct vm_area_struct *vma) ...@@ -537,12 +548,12 @@ int exynos_drm_gem_mmap(struct file *filp, struct vm_area_struct *vma)
/* low-level interface prime helpers */ /* low-level interface prime helpers */
struct sg_table *exynos_drm_gem_prime_get_sg_table(struct drm_gem_object *obj) 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; 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 * struct drm_gem_object *
...@@ -550,35 +561,35 @@ exynos_drm_gem_prime_import_sg_table(struct drm_device *dev, ...@@ -550,35 +561,35 @@ exynos_drm_gem_prime_import_sg_table(struct drm_device *dev,
struct dma_buf_attachment *attach, struct dma_buf_attachment *attach,
struct sg_table *sgt) struct sg_table *sgt)
{ {
struct exynos_drm_gem_obj *exynos_gem_obj; struct exynos_drm_gem *exynos_gem;
int npages; int npages;
int ret; int ret;
exynos_gem_obj = exynos_drm_gem_init(dev, attach->dmabuf->size); exynos_gem = exynos_drm_gem_init(dev, attach->dmabuf->size);
if (IS_ERR(exynos_gem_obj)) { if (IS_ERR(exynos_gem)) {
ret = PTR_ERR(exynos_gem_obj); ret = PTR_ERR(exynos_gem);
return ERR_PTR(ret); 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; npages = exynos_gem->size >> PAGE_SHIFT;
exynos_gem_obj->pages = drm_malloc_ab(npages, sizeof(struct page *)); exynos_gem->pages = drm_malloc_ab(npages, sizeof(struct page *));
if (!exynos_gem_obj->pages) { if (!exynos_gem->pages) {
ret = -ENOMEM; ret = -ENOMEM;
goto err; goto err;
} }
ret = drm_prime_sg_to_page_addr_arrays(sgt, exynos_gem_obj->pages, NULL, ret = drm_prime_sg_to_page_addr_arrays(sgt, exynos_gem->pages, NULL,
npages); npages);
if (ret < 0) if (ret < 0)
goto err_free_large; goto err_free_large;
exynos_gem_obj->sgt = sgt; exynos_gem->sgt = sgt;
if (sgt->nents == 1) { if (sgt->nents == 1) {
/* always physically continuous memory if sgt->nents is 1. */ /* always physically continuous memory if sgt->nents is 1. */
exynos_gem_obj->flags |= EXYNOS_BO_CONTIG; exynos_gem->flags |= EXYNOS_BO_CONTIG;
} else { } else {
/* /*
* this case could be CONTIG or NONCONTIG type but for now * 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, ...@@ -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 * TODO. we have to find a way that exporter can notify
* the type of its own buffer to importer. * 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: err_free_large:
drm_free_large(exynos_gem_obj->pages); drm_free_large(exynos_gem->pages);
err: err:
drm_gem_object_release(&exynos_gem_obj->base); drm_gem_object_release(&exynos_gem->base);
kfree(exynos_gem_obj); kfree(exynos_gem);
return ERR_PTR(ret); return ERR_PTR(ret);
} }
......
...@@ -14,8 +14,7 @@ ...@@ -14,8 +14,7 @@
#include <drm/drm_gem.h> #include <drm/drm_gem.h>
#define to_exynos_gem_obj(x) container_of(x,\ #define to_exynos_gem(x) container_of(x, struct exynos_drm_gem, base)
struct exynos_drm_gem_obj, base)
#define IS_NONCONTIG_BUFFER(f) (f & EXYNOS_BO_NONCONTIG) #define IS_NONCONTIG_BUFFER(f) (f & EXYNOS_BO_NONCONTIG)
...@@ -44,7 +43,7 @@ ...@@ -44,7 +43,7 @@
* P.S. this object would be transferred to user as kms_bo.handle so * P.S. this object would be transferred to user as kms_bo.handle so
* user can access the buffer through kms_bo.handle. * user can access the buffer through kms_bo.handle.
*/ */
struct exynos_drm_gem_obj { struct exynos_drm_gem {
struct drm_gem_object base; struct drm_gem_object base;
unsigned int flags; unsigned int flags;
unsigned long size; unsigned long size;
...@@ -59,10 +58,10 @@ struct exynos_drm_gem_obj { ...@@ -59,10 +58,10 @@ struct exynos_drm_gem_obj {
struct page **exynos_gem_get_pages(struct drm_gem_object *obj, gfp_t gfpmask); struct page **exynos_gem_get_pages(struct drm_gem_object *obj, gfp_t gfpmask);
/* destroy a buffer with gem object */ /* 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 */ /* create a new buffer with gem object */
struct exynos_drm_gem_obj *exynos_drm_gem_create(struct drm_device *dev, struct exynos_drm_gem *exynos_drm_gem_create(struct drm_device *dev,
unsigned int flags, unsigned int flags,
unsigned long size); unsigned long size);
...@@ -106,7 +105,7 @@ unsigned long exynos_drm_gem_get_size(struct drm_device *dev, ...@@ -106,7 +105,7 @@ unsigned long exynos_drm_gem_get_size(struct drm_device *dev,
struct drm_file *file_priv); struct drm_file *file_priv);
/* free gem object. */ /* 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. */ /* create memory region for drm framebuffer. */
int exynos_drm_gem_dumb_create(struct drm_file *file_priv, int exynos_drm_gem_dumb_create(struct drm_file *file_priv,
......
...@@ -543,7 +543,7 @@ static int gsc_src_set_fmt(struct device *dev, u32 fmt) ...@@ -543,7 +543,7 @@ static int gsc_src_set_fmt(struct device *dev, u32 fmt)
GSC_IN_YUV420_2P); GSC_IN_YUV420_2P);
break; break;
default: 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; return -EINVAL;
} }
...@@ -595,7 +595,7 @@ static int gsc_src_set_transf(struct device *dev, ...@@ -595,7 +595,7 @@ static int gsc_src_set_transf(struct device *dev,
cfg &= ~GSC_IN_ROT_YFLIP; cfg &= ~GSC_IN_ROT_YFLIP;
break; break;
default: default:
dev_err(ippdrv->dev, "inavlid degree value %d.\n", degree); dev_err(ippdrv->dev, "invalid degree value %d.\n", degree);
return -EINVAL; return -EINVAL;
} }
...@@ -721,7 +721,7 @@ static int gsc_src_set_addr(struct device *dev, ...@@ -721,7 +721,7 @@ static int gsc_src_set_addr(struct device *dev,
property->prop_id, buf_id, buf_type); property->prop_id, buf_id, buf_type);
if (buf_id > GSC_MAX_SRC) { 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; return -EINVAL;
} }
...@@ -814,7 +814,7 @@ static int gsc_dst_set_fmt(struct device *dev, u32 fmt) ...@@ -814,7 +814,7 @@ static int gsc_dst_set_fmt(struct device *dev, u32 fmt)
GSC_OUT_YUV420_2P); GSC_OUT_YUV420_2P);
break; break;
default: 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; return -EINVAL;
} }
...@@ -866,7 +866,7 @@ static int gsc_dst_set_transf(struct device *dev, ...@@ -866,7 +866,7 @@ static int gsc_dst_set_transf(struct device *dev,
cfg &= ~GSC_IN_ROT_YFLIP; cfg &= ~GSC_IN_ROT_YFLIP;
break; break;
default: default:
dev_err(ippdrv->dev, "inavlid degree value %d.\n", degree); dev_err(ippdrv->dev, "invalid degree value %d.\n", degree);
return -EINVAL; return -EINVAL;
} }
...@@ -1176,7 +1176,7 @@ static int gsc_dst_set_addr(struct device *dev, ...@@ -1176,7 +1176,7 @@ static int gsc_dst_set_addr(struct device *dev,
property->prop_id, buf_id, buf_type); property->prop_id, buf_id, buf_type);
if (buf_id > GSC_MAX_DST) { 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; return -EINVAL;
} }
......
...@@ -139,6 +139,5 @@ void drm_iommu_detach_device(struct drm_device *drm_dev, ...@@ -139,6 +139,5 @@ void drm_iommu_detach_device(struct drm_device *drm_dev,
if (!mapping || !mapping->domain) if (!mapping || !mapping->domain)
return; return;
iommu_detach_device(mapping->domain, subdrv_dev); arm_iommu_detach_device(subdrv_dev);
drm_release_iommu_mapping(drm_dev);
} }
...@@ -128,15 +128,14 @@ static int exynos_plane_atomic_check(struct drm_plane *plane, ...@@ -128,15 +128,14 @@ static int exynos_plane_atomic_check(struct drm_plane *plane,
nr = drm_format_num_planes(state->fb->pixel_format); nr = drm_format_num_planes(state->fb->pixel_format);
for (i = 0; i < nr; i++) { for (i = 0; i < nr; i++) {
struct exynos_drm_gem_obj *obj = struct exynos_drm_gem *exynos_gem =
exynos_drm_fb_gem_obj(state->fb, i); exynos_drm_fb_gem(state->fb, i);
if (!exynos_gem) {
if (!obj) {
DRM_DEBUG_KMS("gem object is null\n"); DRM_DEBUG_KMS("gem object is null\n");
return -EFAULT; return -EFAULT;
} }
exynos_plane->dma_addr[i] = obj->dma_addr + exynos_plane->dma_addr[i] = exynos_gem->dma_addr +
state->fb->offsets[i]; state->fb->offsets[i];
DRM_DEBUG_KMS("buffer: %d, dma_addr = 0x%lx\n", 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, ...@@ -208,6 +207,17 @@ static void exynos_plane_attach_zpos_property(struct drm_plane *plane,
drm_object_attach_property(&plane->base, prop, zpos); 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, int exynos_plane_init(struct drm_device *dev,
struct exynos_drm_plane *exynos_plane, struct exynos_drm_plane *exynos_plane,
unsigned long possible_crtcs, enum drm_plane_type type, unsigned long possible_crtcs, enum drm_plane_type type,
......
...@@ -9,6 +9,8 @@ ...@@ -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, int exynos_plane_init(struct drm_device *dev,
struct exynos_drm_plane *exynos_plane, struct exynos_drm_plane *exynos_plane,
unsigned long possible_crtcs, enum drm_plane_type type, unsigned long possible_crtcs, enum drm_plane_type type,
......
...@@ -29,6 +29,7 @@ ...@@ -29,6 +29,7 @@
/* vidi has totally three virtual windows. */ /* vidi has totally three virtual windows. */
#define WINDOWS_NR 3 #define WINDOWS_NR 3
#define CURSOR_WIN 2
#define ctx_from_connector(c) container_of(c, struct vidi_context, \ #define ctx_from_connector(c) container_of(c, struct vidi_context, \
connector) connector)
...@@ -42,7 +43,6 @@ struct vidi_context { ...@@ -42,7 +43,6 @@ struct vidi_context {
struct exynos_drm_plane planes[WINDOWS_NR]; struct exynos_drm_plane planes[WINDOWS_NR];
struct edid *raw_edid; struct edid *raw_edid;
unsigned int clkdiv; unsigned int clkdiv;
unsigned int default_win;
unsigned long irq_flags; unsigned long irq_flags;
unsigned int connected; unsigned int connected;
bool vblank_on; bool vblank_on;
...@@ -446,8 +446,7 @@ static int vidi_bind(struct device *dev, struct device *master, void *data) ...@@ -446,8 +446,7 @@ static int vidi_bind(struct device *dev, struct device *master, void *data)
vidi_ctx_initialize(ctx, drm_dev); vidi_ctx_initialize(ctx, drm_dev);
for (zpos = 0; zpos < WINDOWS_NR; zpos++) { for (zpos = 0; zpos < WINDOWS_NR; zpos++) {
type = (zpos == ctx->default_win) ? DRM_PLANE_TYPE_PRIMARY : type = exynos_plane_get_type(zpos, CURSOR_WIN);
DRM_PLANE_TYPE_OVERLAY;
ret = exynos_plane_init(drm_dev, &ctx->planes[zpos], ret = exynos_plane_init(drm_dev, &ctx->planes[zpos],
1 << ctx->pipe, type, formats, 1 << ctx->pipe, type, formats,
ARRAY_SIZE(formats), zpos); ARRAY_SIZE(formats), zpos);
...@@ -455,7 +454,7 @@ static int vidi_bind(struct device *dev, struct device *master, void *data) ...@@ -455,7 +454,7 @@ static int vidi_bind(struct device *dev, struct device *master, void *data)
return ret; return ret;
} }
exynos_plane = &ctx->planes[ctx->default_win]; exynos_plane = &ctx->planes[DEFAULT_WIN];
ctx->crtc = exynos_drm_crtc_create(drm_dev, &exynos_plane->base, ctx->crtc = exynos_drm_crtc_create(drm_dev, &exynos_plane->base,
ctx->pipe, EXYNOS_DISPLAY_TYPE_VIDI, ctx->pipe, EXYNOS_DISPLAY_TYPE_VIDI,
&vidi_crtc_ops, ctx); &vidi_crtc_ops, ctx);
...@@ -507,7 +506,6 @@ static int vidi_probe(struct platform_device *pdev) ...@@ -507,7 +506,6 @@ static int vidi_probe(struct platform_device *pdev)
if (!ctx) if (!ctx)
return -ENOMEM; return -ENOMEM;
ctx->default_win = 0;
ctx->pdev = pdev; ctx->pdev = pdev;
INIT_WORK(&ctx->work, vidi_fake_vblank_handler); INIT_WORK(&ctx->work, vidi_fake_vblank_handler);
......
...@@ -30,11 +30,11 @@ ...@@ -30,11 +30,11 @@
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/pm_runtime.h> #include <linux/pm_runtime.h>
#include <linux/clk.h> #include <linux/clk.h>
#include <linux/gpio/consumer.h>
#include <linux/regulator/consumer.h> #include <linux/regulator/consumer.h>
#include <linux/io.h> #include <linux/io.h>
#include <linux/of_address.h> #include <linux/of_address.h>
#include <linux/of_device.h> #include <linux/of_device.h>
#include <linux/of_gpio.h>
#include <linux/hdmi.h> #include <linux/hdmi.h>
#include <linux/component.h> #include <linux/component.h>
#include <linux/mfd/syscon.h> #include <linux/mfd/syscon.h>
...@@ -44,11 +44,6 @@ ...@@ -44,11 +44,6 @@
#include "exynos_drm_drv.h" #include "exynos_drm_drv.h"
#include "exynos_drm_crtc.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 #define HOTPLUG_DEBOUNCE_MS 1100
...@@ -66,6 +61,33 @@ ...@@ -66,6 +61,33 @@
enum hdmi_type { enum hdmi_type {
HDMI_TYPE13, HDMI_TYPE13,
HDMI_TYPE14, 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 { struct hdmi_driver_data {
...@@ -75,44 +97,32 @@ struct hdmi_driver_data { ...@@ -75,44 +97,32 @@ struct hdmi_driver_data {
unsigned int is_apb_phy:1; 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 hdmi_context {
struct drm_encoder encoder; struct drm_encoder encoder;
struct device *dev; struct device *dev;
struct drm_device *drm_dev; struct drm_device *drm_dev;
struct drm_connector connector; struct drm_connector connector;
bool hpd;
bool powered; bool powered;
bool dvi_mode; bool dvi_mode;
void __iomem *regs;
int irq;
struct delayed_work hotplug_work; 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; struct drm_display_mode current_mode;
u8 cea_video_id; u8 cea_video_id;
struct hdmi_resources res;
const struct hdmi_driver_data *drv_data; const struct hdmi_driver_data *drv_data;
int hpd_gpio; void __iomem *regs;
void __iomem *regs_hdmiphy; 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 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) 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) ...@@ -120,6 +130,11 @@ static inline struct hdmi_context *encoder_to_hdmi(struct drm_encoder *e)
return container_of(e, struct hdmi_context, encoder); 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 { struct hdmiphy_config {
int pixel_clock; int pixel_clock;
u8 conf[32]; u8 conf[32];
...@@ -133,7 +148,7 @@ static const struct hdmiphy_config hdmiphy_v13_configs[] = { ...@@ -133,7 +148,7 @@ static const struct hdmiphy_config hdmiphy_v13_configs[] = {
0x01, 0x05, 0x00, 0xD8, 0x10, 0x1C, 0x30, 0x40, 0x01, 0x05, 0x00, 0xD8, 0x10, 0x1C, 0x30, 0x40,
0x6B, 0x10, 0x02, 0x51, 0xDF, 0xF2, 0x54, 0x87, 0x6B, 0x10, 0x02, 0x51, 0xDF, 0xF2, 0x54, 0x87,
0x84, 0x00, 0x30, 0x38, 0x00, 0x08, 0x10, 0xE0, 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[] = { ...@@ -142,7 +157,7 @@ static const struct hdmiphy_config hdmiphy_v13_configs[] = {
0x01, 0x05, 0x00, 0xD4, 0x10, 0x9C, 0x09, 0x64, 0x01, 0x05, 0x00, 0xD4, 0x10, 0x9C, 0x09, 0x64,
0x6B, 0x10, 0x02, 0x51, 0xDF, 0xF2, 0x54, 0x87, 0x6B, 0x10, 0x02, 0x51, 0xDF, 0xF2, 0x54, 0x87,
0x84, 0x00, 0x30, 0x38, 0x00, 0x08, 0x10, 0xE0, 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[] = { ...@@ -151,7 +166,7 @@ static const struct hdmiphy_config hdmiphy_v13_configs[] = {
0x01, 0x05, 0x00, 0xD8, 0x10, 0x9C, 0xef, 0x5B, 0x01, 0x05, 0x00, 0xD8, 0x10, 0x9C, 0xef, 0x5B,
0x6D, 0x10, 0x01, 0x51, 0xef, 0xF3, 0x54, 0xb9, 0x6D, 0x10, 0x01, 0x51, 0xef, 0xF3, 0x54, 0xb9,
0x84, 0x00, 0x30, 0x38, 0x00, 0x08, 0x10, 0xE0, 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[] = { ...@@ -160,7 +175,7 @@ static const struct hdmiphy_config hdmiphy_v13_configs[] = {
0x01, 0x05, 0x00, 0xd8, 0x10, 0x9c, 0xf8, 0x40, 0x01, 0x05, 0x00, 0xd8, 0x10, 0x9c, 0xf8, 0x40,
0x6a, 0x10, 0x01, 0x51, 0xff, 0xf1, 0x54, 0xba, 0x6a, 0x10, 0x01, 0x51, 0xff, 0xf1, 0x54, 0xba,
0x84, 0x00, 0x10, 0x38, 0x00, 0x08, 0x10, 0xe0, 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[] = { ...@@ -169,7 +184,7 @@ static const struct hdmiphy_config hdmiphy_v13_configs[] = {
0x01, 0x05, 0x00, 0xD8, 0x10, 0x9C, 0xf8, 0x40, 0x01, 0x05, 0x00, 0xD8, 0x10, 0x9C, 0xf8, 0x40,
0x6A, 0x18, 0x00, 0x51, 0xff, 0xF1, 0x54, 0xba, 0x6A, 0x18, 0x00, 0x51, 0xff, 0xF1, 0x54, 0xba,
0x84, 0x00, 0x10, 0x38, 0x00, 0x08, 0x10, 0xE0, 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[] = { ...@@ -199,7 +214,7 @@ static const struct hdmiphy_config hdmiphy_v14_configs[] = {
0x01, 0xd1, 0x2d, 0x72, 0x40, 0x64, 0x12, 0x08, 0x01, 0xd1, 0x2d, 0x72, 0x40, 0x64, 0x12, 0x08,
0x43, 0xa0, 0x0e, 0xd9, 0x45, 0xa0, 0xac, 0x80, 0x43, 0xa0, 0x0e, 0xd9, 0x45, 0xa0, 0xac, 0x80,
0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86, 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[] = { ...@@ -262,7 +277,7 @@ static const struct hdmiphy_config hdmiphy_v14_configs[] = {
0x01, 0xd1, 0x1f, 0x10, 0x40, 0x40, 0xf8, 0x08, 0x01, 0xd1, 0x1f, 0x10, 0x40, 0x40, 0xf8, 0x08,
0x81, 0xa0, 0xba, 0xd8, 0x45, 0xa0, 0xac, 0x80, 0x81, 0xa0, 0xba, 0xd8, 0x45, 0xa0, 0xac, 0x80,
0x3c, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86, 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[] = { ...@@ -325,7 +340,7 @@ static const struct hdmiphy_config hdmiphy_v14_configs[] = {
0x01, 0xd1, 0x1f, 0x00, 0x40, 0x40, 0xf8, 0x08, 0x01, 0xd1, 0x1f, 0x00, 0x40, 0x40, 0xf8, 0x08,
0x81, 0xa0, 0xba, 0xd8, 0x45, 0xa0, 0xac, 0x80, 0x81, 0xa0, 0xba, 0xd8, 0x45, 0xa0, 0xac, 0x80,
0x3c, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86, 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 = { ...@@ -507,29 +522,31 @@ static struct hdmi_driver_data exynos4210_hdmi_driver_data = {
.is_apb_phy = 0, .is_apb_phy = 0,
}; };
static struct hdmi_driver_data exynos5_hdmi_driver_data = { static inline u32 hdmi_map_reg(struct hdmi_context *hdata, u32 reg_id)
.type = HDMI_TYPE14, {
.phy_confs = hdmiphy_v13_configs, if ((reg_id & 0xffff0000) == HDMI_MAPPED_BASE)
.phy_conf_count = ARRAY_SIZE(hdmiphy_v13_configs), return hdmi_reg_map[reg_id & 0xffff][hdata->drv_data->type];
.is_apb_phy = 0, return reg_id;
}; }
static inline u32 hdmi_reg_read(struct hdmi_context *hdata, u32 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, static inline void hdmi_reg_writeb(struct hdmi_context *hdata,
u32 reg_id, u8 value) 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, static inline void hdmi_reg_writev(struct hdmi_context *hdata, u32 reg_id,
int bytes, u32 val) int bytes, u32 val)
{ {
reg_id = hdmi_map_reg(hdata, reg_id);
while (--bytes >= 0) { while (--bytes >= 0) {
writeb(val & 0xff, hdata->regs + reg_id); writel(val & 0xff, hdata->regs + reg_id);
val >>= 8; val >>= 8;
reg_id += 4; reg_id += 4;
} }
...@@ -538,31 +555,14 @@ static inline void hdmi_reg_writev(struct hdmi_context *hdata, u32 reg_id, ...@@ -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, static inline void hdmi_reg_writemask(struct hdmi_context *hdata,
u32 reg_id, u32 value, u32 mask) 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); value = (value & mask) | (old & ~mask);
writel(value, hdata->regs + reg_id); 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, static int hdmiphy_reg_write_buf(struct hdmi_context *hdata,
u32 reg_offset, const u8 *buf, u32 len) u32 reg_offset, const u8 *buf, u32 len)
{ {
...@@ -579,7 +579,7 @@ static int hdmiphy_reg_write_buf(struct hdmi_context *hdata, ...@@ -579,7 +579,7 @@ static int hdmiphy_reg_write_buf(struct hdmi_context *hdata,
} else { } else {
int i; int i;
for (i = 0; i < len; i++) for (i = 0; i < len; i++)
writeb(buf[i], hdata->regs_hdmiphy + writel(buf[i], hdata->regs_hdmiphy +
((reg_offset + i)<<2)); ((reg_offset + i)<<2));
return 0; return 0;
} }
...@@ -689,7 +689,7 @@ static void hdmi_v14_regs_dump(struct hdmi_context *hdata, char *prefix) ...@@ -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_0);
DUMPREG(HDMI_PHY_STATUS_PLL); DUMPREG(HDMI_PHY_STATUS_PLL);
DUMPREG(HDMI_PHY_CON_0); DUMPREG(HDMI_PHY_CON_0);
DUMPREG(HDMI_PHY_RSTOUT); DUMPREG(HDMI_V14_PHY_RSTOUT);
DUMPREG(HDMI_PHY_VPLL); DUMPREG(HDMI_PHY_VPLL);
DUMPREG(HDMI_PHY_CMU); DUMPREG(HDMI_PHY_CMU);
DUMPREG(HDMI_CORE_RSTOUT); DUMPREG(HDMI_CORE_RSTOUT);
...@@ -942,9 +942,9 @@ static void hdmi_reg_infoframe(struct hdmi_context *hdata, ...@@ -942,9 +942,9 @@ static void hdmi_reg_infoframe(struct hdmi_context *hdata,
static enum drm_connector_status hdmi_detect(struct drm_connector *connector, static enum drm_connector_status hdmi_detect(struct drm_connector *connector,
bool force) 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_connected;
return connector_status_disconnected; return connector_status_disconnected;
...@@ -968,7 +968,7 @@ static struct drm_connector_funcs hdmi_connector_funcs = { ...@@ -968,7 +968,7 @@ static struct drm_connector_funcs hdmi_connector_funcs = {
static int hdmi_get_modes(struct drm_connector *connector) 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; struct edid *edid;
int ret; int ret;
...@@ -1008,7 +1008,7 @@ static int hdmi_find_phy_conf(struct hdmi_context *hdata, u32 pixel_clock) ...@@ -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, static int hdmi_mode_valid(struct drm_connector *connector,
struct drm_display_mode *mode) struct drm_display_mode *mode)
{ {
struct hdmi_context *hdata = ctx_from_connector(connector); struct hdmi_context *hdata = connector_to_hdmi(connector);
int ret; int ret;
DRM_DEBUG_KMS("xres=%d, yres=%d, refresh=%d, intl=%d clock=%d\n", 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, ...@@ -1016,10 +1016,6 @@ static int hdmi_mode_valid(struct drm_connector *connector,
(mode->flags & DRM_MODE_FLAG_INTERLACE) ? true : (mode->flags & DRM_MODE_FLAG_INTERLACE) ? true :
false, mode->clock * 1000); false, mode->clock * 1000);
ret = mixer_check_mode(mode);
if (ret)
return MODE_BAD;
ret = hdmi_find_phy_conf(hdata, mode->clock * 1000); ret = hdmi_find_phy_conf(hdata, mode->clock * 1000);
if (ret < 0) if (ret < 0)
return MODE_BAD; return MODE_BAD;
...@@ -1029,7 +1025,7 @@ static int hdmi_mode_valid(struct drm_connector *connector, ...@@ -1029,7 +1025,7 @@ static int hdmi_mode_valid(struct drm_connector *connector,
static struct drm_encoder *hdmi_best_encoder(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; return &hdata->encoder;
} }
...@@ -1110,69 +1106,16 @@ static bool hdmi_mode_fixup(struct drm_encoder *encoder, ...@@ -1110,69 +1106,16 @@ static bool hdmi_mode_fixup(struct drm_encoder *encoder,
return true; 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; u32 n, cts;
switch (freq) { cts = (freq % 9) ? 27000 : 30000;
case 32000: n = 128 * freq / (27000000 / cts);
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;
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_writev(hdata, HDMI_ACR_N0, 3, n);
hdmi_reg_writeb(hdata, HDMI_V13_ACR_CON, 4); hdmi_reg_writev(hdata, HDMI_ACR_MCTS0, 3, cts);
else hdmi_reg_writev(hdata, HDMI_ACR_CTS0, 3, cts);
hdmi_reg_writeb(hdata, HDMI_ACR_CON, 4); hdmi_reg_writeb(hdata, HDMI_ACR_CON, 4);
} }
...@@ -1181,7 +1124,6 @@ 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 sample_rate, bits_per_sample;
u32 data_num, bit_ch, sample_frq; u32 data_num, bit_ch, sample_frq;
u32 val; u32 val;
u8 acr[7];
sample_rate = 44100; sample_rate = 44100;
bits_per_sample = 16; bits_per_sample = 16;
...@@ -1201,8 +1143,7 @@ static void hdmi_audio_init(struct hdmi_context *hdata) ...@@ -1201,8 +1143,7 @@ static void hdmi_audio_init(struct hdmi_context *hdata)
break; break;
} }
hdmi_set_acr(sample_rate, acr); hdmi_reg_acr(hdata, sample_rate);
hdmi_reg_acr(hdata, acr);
hdmi_reg_writeb(hdata, HDMI_I2S_MUX_CON, HDMI_I2S_IN_DISABLE hdmi_reg_writeb(hdata, HDMI_I2S_MUX_CON, HDMI_I2S_IN_DISABLE
| HDMI_I2S_AUD_I2S | HDMI_I2S_CUV_I2S_ENABLE | HDMI_I2S_AUD_I2S | HDMI_I2S_CUV_I2S_ENABLE
...@@ -1335,11 +1276,27 @@ static void hdmi_conf_init(struct hdmi_context *hdata) ...@@ -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) static void hdmi_v13_mode_apply(struct hdmi_context *hdata)
{ {
struct drm_display_mode *m = &hdata->current_mode; struct drm_display_mode *m = &hdata->current_mode;
unsigned int val; unsigned int val;
int tries;
hdmi_reg_writev(hdata, HDMI_H_BLANK_0, 2, m->htotal - m->hdisplay); hdmi_reg_writev(hdata, HDMI_H_BLANK_0, 2, m->htotal - m->hdisplay);
hdmi_reg_writev(hdata, HDMI_V13_H_V_LINE_0, 3, 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) ...@@ -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_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_TOP_HDMI_L, 2, 0x1);
hdmi_reg_writev(hdata, HDMI_TG_FIELD_BOT_HDMI_L, 2, 0x233); 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) static void hdmi_v14_mode_apply(struct hdmi_context *hdata)
{ {
struct drm_display_mode *m = &hdata->current_mode; 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_H_BLANK_0, 2, m->htotal - m->hdisplay);
hdmi_reg_writev(hdata, HDMI_V_LINE_0, 2, m->vtotal); 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) ...@@ -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_VSYNC_TOP_HDMI_L, 2, 0x1);
hdmi_reg_writev(hdata, HDMI_TG_FIELD_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); 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) static void hdmi_mode_apply(struct hdmi_context *hdata)
...@@ -1590,74 +1506,26 @@ 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); hdmi_v13_mode_apply(hdata);
else else
hdmi_v14_mode_apply(hdata); hdmi_v14_mode_apply(hdata);
}
static void hdmiphy_conf_reset(struct hdmi_context *hdata) hdmiphy_wait_for_pll(hdata);
{
u32 reg;
clk_disable_unprepare(hdata->res.sclk_hdmi); clk_set_parent(hdata->mout_hdmi, hdata->sclk_hdmiphy);
clk_set_parent(hdata->res.mout_hdmi, hdata->res.sclk_pixel);
clk_prepare_enable(hdata->res.sclk_hdmi);
/* operation mode */ /* enable HDMI and timing generator */
hdmiphy_reg_writeb(hdata, HDMIPHY_MODE_SET_DONE, hdmi_start(hdata, true);
HDMI_PHY_ENABLE_MODE_SET); }
if (hdata->drv_data->type == HDMI_TYPE13) static void hdmiphy_conf_reset(struct hdmi_context *hdata)
reg = HDMI_V13_PHY_RSTOUT; {
else clk_set_parent(hdata->mout_hdmi, hdata->sclk_pixel);
reg = HDMI_PHY_RSTOUT;
/* reset hdmiphy */ /* 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); 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); 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) static void hdmiphy_conf_apply(struct hdmi_context *hdata)
{ {
int ret; int ret;
...@@ -1678,14 +1546,6 @@ static void hdmiphy_conf_apply(struct hdmi_context *hdata) ...@@ -1678,14 +1546,6 @@ static void hdmiphy_conf_apply(struct hdmi_context *hdata)
} }
usleep_range(10000, 12000); 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) static void hdmi_conf_apply(struct hdmi_context *hdata)
...@@ -1724,7 +1584,6 @@ static void hdmi_mode_set(struct drm_encoder *encoder, ...@@ -1724,7 +1584,6 @@ static void hdmi_mode_set(struct drm_encoder *encoder,
static void hdmi_enable(struct drm_encoder *encoder) static void hdmi_enable(struct drm_encoder *encoder)
{ {
struct hdmi_context *hdata = encoder_to_hdmi(encoder); struct hdmi_context *hdata = encoder_to_hdmi(encoder);
struct hdmi_resources *res = &hdata->res;
if (hdata->powered) if (hdata->powered)
return; return;
...@@ -1733,24 +1592,22 @@ static void hdmi_enable(struct drm_encoder *encoder) ...@@ -1733,24 +1592,22 @@ static void hdmi_enable(struct drm_encoder *encoder)
pm_runtime_get_sync(hdata->dev); 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"); DRM_DEBUG_KMS("failed to enable regulator bulk\n");
/* set pmu hdmiphy control bit to enable hdmiphy */ /* set pmu hdmiphy control bit to enable hdmiphy */
regmap_update_bits(hdata->pmureg, PMU_HDMI_PHY_CONTROL, regmap_update_bits(hdata->pmureg, PMU_HDMI_PHY_CONTROL,
PMU_HDMI_PHY_ENABLE_BIT, 1); PMU_HDMI_PHY_ENABLE_BIT, 1);
clk_prepare_enable(res->hdmi); clk_prepare_enable(hdata->hdmi);
clk_prepare_enable(res->sclk_hdmi); clk_prepare_enable(hdata->sclk_hdmi);
hdmiphy_poweron(hdata);
hdmi_conf_apply(hdata); hdmi_conf_apply(hdata);
} }
static void hdmi_disable(struct drm_encoder *encoder) static void hdmi_disable(struct drm_encoder *encoder)
{ {
struct hdmi_context *hdata = encoder_to_hdmi(encoder); struct hdmi_context *hdata = encoder_to_hdmi(encoder);
struct hdmi_resources *res = &hdata->res;
struct drm_crtc *crtc = encoder->crtc; struct drm_crtc *crtc = encoder->crtc;
const struct drm_crtc_helper_funcs *funcs = NULL; const struct drm_crtc_helper_funcs *funcs = NULL;
...@@ -1774,18 +1631,16 @@ static void hdmi_disable(struct drm_encoder *encoder) ...@@ -1774,18 +1631,16 @@ static void hdmi_disable(struct drm_encoder *encoder)
/* HDMI System Disable */ /* HDMI System Disable */
hdmi_reg_writemask(hdata, HDMI_CON_0, 0, HDMI_EN); hdmi_reg_writemask(hdata, HDMI_CON_0, 0, HDMI_EN);
hdmiphy_poweroff(hdata);
cancel_delayed_work(&hdata->hotplug_work); cancel_delayed_work(&hdata->hotplug_work);
clk_disable_unprepare(res->sclk_hdmi); clk_disable_unprepare(hdata->sclk_hdmi);
clk_disable_unprepare(res->hdmi); clk_disable_unprepare(hdata->hdmi);
/* reset pmu hdmiphy control bit to disable hdmiphy */ /* reset pmu hdmiphy control bit to disable hdmiphy */
regmap_update_bits(hdata->pmureg, PMU_HDMI_PHY_CONTROL, regmap_update_bits(hdata->pmureg, PMU_HDMI_PHY_CONTROL,
PMU_HDMI_PHY_ENABLE_BIT, 0); 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); pm_runtime_put_sync(hdata->dev);
...@@ -1826,80 +1681,76 @@ static irqreturn_t hdmi_irq_thread(int irq, void *arg) ...@@ -1826,80 +1681,76 @@ static irqreturn_t hdmi_irq_thread(int irq, void *arg)
static int hdmi_resources_init(struct hdmi_context *hdata) static int hdmi_resources_init(struct hdmi_context *hdata)
{ {
struct device *dev = hdata->dev; struct device *dev = hdata->dev;
struct hdmi_resources *res = &hdata->res;
static char *supply[] = {
"vdd",
"vdd_osc",
"vdd_pll",
};
int i, ret; int i, ret;
DRM_DEBUG_KMS("HDMI resource init\n"); 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 */ /* get clocks, power */
res->hdmi = devm_clk_get(dev, "hdmi"); hdata->hdmi = devm_clk_get(dev, "hdmi");
if (IS_ERR(res->hdmi)) { if (IS_ERR(hdata->hdmi)) {
DRM_ERROR("failed to get clock 'hdmi'\n"); DRM_ERROR("failed to get clock 'hdmi'\n");
ret = PTR_ERR(res->hdmi); ret = PTR_ERR(hdata->hdmi);
goto fail; goto fail;
} }
res->sclk_hdmi = devm_clk_get(dev, "sclk_hdmi"); hdata->sclk_hdmi = devm_clk_get(dev, "sclk_hdmi");
if (IS_ERR(res->sclk_hdmi)) { if (IS_ERR(hdata->sclk_hdmi)) {
DRM_ERROR("failed to get clock 'sclk_hdmi'\n"); DRM_ERROR("failed to get clock 'sclk_hdmi'\n");
ret = PTR_ERR(res->sclk_hdmi); ret = PTR_ERR(hdata->sclk_hdmi);
goto fail; goto fail;
} }
res->sclk_pixel = devm_clk_get(dev, "sclk_pixel"); hdata->sclk_pixel = devm_clk_get(dev, "sclk_pixel");
if (IS_ERR(res->sclk_pixel)) { if (IS_ERR(hdata->sclk_pixel)) {
DRM_ERROR("failed to get clock 'sclk_pixel'\n"); DRM_ERROR("failed to get clock 'sclk_pixel'\n");
ret = PTR_ERR(res->sclk_pixel); ret = PTR_ERR(hdata->sclk_pixel);
goto fail; goto fail;
} }
res->sclk_hdmiphy = devm_clk_get(dev, "sclk_hdmiphy"); hdata->sclk_hdmiphy = devm_clk_get(dev, "sclk_hdmiphy");
if (IS_ERR(res->sclk_hdmiphy)) { if (IS_ERR(hdata->sclk_hdmiphy)) {
DRM_ERROR("failed to get clock 'sclk_hdmiphy'\n"); DRM_ERROR("failed to get clock 'sclk_hdmiphy'\n");
ret = PTR_ERR(res->sclk_hdmiphy); ret = PTR_ERR(hdata->sclk_hdmiphy);
goto fail; goto fail;
} }
res->mout_hdmi = devm_clk_get(dev, "mout_hdmi"); hdata->mout_hdmi = devm_clk_get(dev, "mout_hdmi");
if (IS_ERR(res->mout_hdmi)) { if (IS_ERR(hdata->mout_hdmi)) {
DRM_ERROR("failed to get clock 'mout_hdmi'\n"); DRM_ERROR("failed to get clock 'mout_hdmi'\n");
ret = PTR_ERR(res->mout_hdmi); ret = PTR_ERR(hdata->mout_hdmi);
goto fail; 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) { for (i = 0; i < ARRAY_SIZE(supply); ++i) {
res->regul_bulk[i].supply = supply[i]; hdata->regul_bulk[i].supply = supply[i];
res->regul_bulk[i].consumer = NULL; 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) { if (ret) {
DRM_ERROR("failed to get regulators\n"); DRM_ERROR("failed to get regulators\n");
return ret; return ret;
} }
res->regul_count = ARRAY_SIZE(supply);
res->reg_hdmi_en = devm_regulator_get(dev, "hdmi-en"); hdata->reg_hdmi_en = devm_regulator_get_optional(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"); if (PTR_ERR(hdata->reg_hdmi_en) == -ENODEV)
return PTR_ERR(res->reg_hdmi_en); return 0;
}
if (!IS_ERR(res->reg_hdmi_en)) { if (IS_ERR(hdata->reg_hdmi_en))
ret = regulator_enable(res->reg_hdmi_en); return PTR_ERR(hdata->reg_hdmi_en);
if (ret) {
ret = regulator_enable(hdata->reg_hdmi_en);
if (ret)
DRM_ERROR("failed to enable hdmi-en regulator\n"); DRM_ERROR("failed to enable hdmi-en regulator\n");
return ret;
}
} else
res->reg_hdmi_en = NULL;
return ret; return ret;
fail: fail:
...@@ -1909,9 +1760,6 @@ static int hdmi_resources_init(struct hdmi_context *hdata) ...@@ -1909,9 +1760,6 @@ static int hdmi_resources_init(struct hdmi_context *hdata)
static struct of_device_id hdmi_match_types[] = { static struct of_device_id hdmi_match_types[] = {
{ {
.compatible = "samsung,exynos5-hdmi",
.data = &exynos5_hdmi_driver_data,
}, {
.compatible = "samsung,exynos4210-hdmi", .compatible = "samsung,exynos4210-hdmi",
.data = &exynos4210_hdmi_driver_data, .data = &exynos4210_hdmi_driver_data,
}, { }, {
...@@ -2009,11 +1857,6 @@ static int hdmi_probe(struct platform_device *pdev) ...@@ -2009,11 +1857,6 @@ static int hdmi_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, hdata); platform_set_drvdata(pdev, hdata);
hdata->dev = dev; 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); ret = hdmi_resources_init(hdata);
if (ret) { if (ret) {
...@@ -2028,12 +1871,6 @@ static int hdmi_probe(struct platform_device *pdev) ...@@ -2028,12 +1871,6 @@ static int hdmi_probe(struct platform_device *pdev)
return ret; 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); ddc_node = hdmi_legacy_ddc_dt_binding(dev);
if (ddc_node) if (ddc_node)
goto out_get_ddc_adpt; goto out_get_ddc_adpt;
...@@ -2081,13 +1918,6 @@ static int hdmi_probe(struct platform_device *pdev) ...@@ -2081,13 +1918,6 @@ static int hdmi_probe(struct platform_device *pdev)
} }
} }
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); INIT_DELAYED_WORK(&hdata->hotplug_work, hdmi_hotplug_work_func);
ret = devm_request_threaded_irq(dev, hdata->irq, NULL, ret = devm_request_threaded_irq(dev, hdata->irq, NULL,
...@@ -2133,15 +1963,17 @@ static int hdmi_remove(struct platform_device *pdev) ...@@ -2133,15 +1963,17 @@ static int hdmi_remove(struct platform_device *pdev)
cancel_delayed_work_sync(&hdata->hotplug_work); cancel_delayed_work_sync(&hdata->hotplug_work);
if (hdata->res.reg_hdmi_en) component_del(&pdev->dev, &hdmi_component_ops);
regulator_disable(hdata->res.reg_hdmi_en);
pm_runtime_disable(&pdev->dev);
if (!IS_ERR(hdata->reg_hdmi_en))
regulator_disable(hdata->reg_hdmi_en);
if (hdata->hdmiphy_port) if (hdata->hdmiphy_port)
put_device(&hdata->hdmiphy_port->dev); put_device(&hdata->hdmiphy_port->dev);
put_device(&hdata->ddc_adpt->dev);
pm_runtime_disable(&pdev->dev); put_device(&hdata->ddc_adpt->dev);
component_del(&pdev->dev, &hdmi_component_ops);
return 0; return 0;
} }
......
...@@ -39,11 +39,10 @@ ...@@ -39,11 +39,10 @@
#include "exynos_drm_crtc.h" #include "exynos_drm_crtc.h"
#include "exynos_drm_plane.h" #include "exynos_drm_plane.h"
#include "exynos_drm_iommu.h" #include "exynos_drm_iommu.h"
#include "exynos_mixer.h"
#define MIXER_WIN_NR 3 #define MIXER_WIN_NR 3
#define MIXER_DEFAULT_WIN 0
#define VP_DEFAULT_WIN 2 #define VP_DEFAULT_WIN 2
#define CURSOR_WIN 1
/* The pixelformats that are natively supported by the mixer. */ /* The pixelformats that are natively supported by the mixer. */
#define MXR_FORMAT_RGB565 4 #define MXR_FORMAT_RGB565 4
...@@ -600,7 +599,7 @@ static void mixer_graph_buffer(struct mixer_context *ctx, ...@@ -600,7 +599,7 @@ static void mixer_graph_buffer(struct mixer_context *ctx,
/* setup display size */ /* setup display size */
if (ctx->mxr_ver == MXR_VER_128_0_0_184 && 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_HEIGHT(mode->vdisplay);
val |= MXR_MXR_RES_WIDTH(mode->hdisplay); val |= MXR_MXR_RES_WIDTH(mode->hdisplay);
mixer_reg_write(res, MXR_RESOLUTION, val); mixer_reg_write(res, MXR_RESOLUTION, val);
...@@ -652,7 +651,7 @@ static void vp_win_reset(struct mixer_context *ctx) ...@@ -652,7 +651,7 @@ static void vp_win_reset(struct mixer_context *ctx)
/* waiting until VP_SRESET_PROCESSING is 0 */ /* waiting until VP_SRESET_PROCESSING is 0 */
if (~vp_reg_read(res, VP_SRESET) & VP_SRESET_PROCESSING) if (~vp_reg_read(res, VP_SRESET) & VP_SRESET_PROCESSING)
break; break;
usleep_range(10000, 12000); mdelay(10);
} }
WARN(tries == 0, "failed to reset Video Processor\n"); WARN(tries == 0, "failed to reset Video Processor\n");
} }
...@@ -1096,8 +1095,10 @@ static void mixer_disable(struct exynos_drm_crtc *crtc) ...@@ -1096,8 +1095,10 @@ static void mixer_disable(struct exynos_drm_crtc *crtc)
} }
/* Only valid for Mixer version 16.0.33.0 */ /* 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; u32 w, h;
w = mode->hdisplay; w = mode->hdisplay;
...@@ -1123,6 +1124,7 @@ static const struct exynos_drm_crtc_ops mixer_crtc_ops = { ...@@ -1123,6 +1124,7 @@ static const struct exynos_drm_crtc_ops mixer_crtc_ops = {
.wait_for_vblank = mixer_wait_for_vblank, .wait_for_vblank = mixer_wait_for_vblank,
.update_plane = mixer_update_plane, .update_plane = mixer_update_plane,
.disable_plane = mixer_disable_plane, .disable_plane = mixer_disable_plane,
.atomic_check = mixer_atomic_check,
}; };
static struct mixer_drv_data exynos5420_mxr_drv_data = { 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) ...@@ -1197,8 +1199,6 @@ static int mixer_bind(struct device *dev, struct device *manager, void *data)
const uint32_t *formats; const uint32_t *formats;
unsigned int fcount; unsigned int fcount;
type = (zpos == MIXER_DEFAULT_WIN) ? DRM_PLANE_TYPE_PRIMARY :
DRM_PLANE_TYPE_OVERLAY;
if (zpos < VP_DEFAULT_WIN) { if (zpos < VP_DEFAULT_WIN) {
formats = mixer_formats; formats = mixer_formats;
fcount = ARRAY_SIZE(mixer_formats); fcount = ARRAY_SIZE(mixer_formats);
...@@ -1207,6 +1207,7 @@ static int mixer_bind(struct device *dev, struct device *manager, void *data) ...@@ -1207,6 +1207,7 @@ static int mixer_bind(struct device *dev, struct device *manager, void *data)
fcount = ARRAY_SIZE(vp_formats); fcount = ARRAY_SIZE(vp_formats);
} }
type = exynos_plane_get_type(zpos, CURSOR_WIN);
ret = exynos_plane_init(drm_dev, &ctx->planes[zpos], ret = exynos_plane_init(drm_dev, &ctx->planes[zpos],
1 << ctx->pipe, type, formats, fcount, 1 << ctx->pipe, type, formats, fcount,
zpos); zpos);
...@@ -1214,7 +1215,7 @@ static int mixer_bind(struct device *dev, struct device *manager, void *data) ...@@ -1214,7 +1215,7 @@ static int mixer_bind(struct device *dev, struct device *manager, void *data)
return ret; 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->crtc = exynos_drm_crtc_create(drm_dev, &exynos_plane->base,
ctx->pipe, EXYNOS_DISPLAY_TYPE_HDMI, ctx->pipe, EXYNOS_DISPLAY_TYPE_HDMI,
&mixer_crtc_ops, ctx); &mixer_crtc_ops, ctx);
......
/*
* 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
...@@ -72,7 +72,6 @@ ...@@ -72,7 +72,6 @@
#define HDMI_V13_V_SYNC_GEN_3_0 HDMI_CORE_BASE(0x0150) #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_1 HDMI_CORE_BASE(0x0154)
#define HDMI_V13_V_SYNC_GEN_3_2 HDMI_CORE_BASE(0x0158) #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_CON HDMI_CORE_BASE(0x0300)
#define HDMI_V13_AVI_BYTE(n) HDMI_CORE_BASE(0x0320 + 4 * (n)) #define HDMI_V13_AVI_BYTE(n) HDMI_CORE_BASE(0x0320 + 4 * (n))
#define HDMI_V13_DC_CONTROL HDMI_CORE_BASE(0x05C0) #define HDMI_V13_DC_CONTROL HDMI_CORE_BASE(0x05C0)
...@@ -171,7 +170,7 @@ ...@@ -171,7 +170,7 @@
#define HDMI_HPD_ST HDMI_CTRL_BASE(0x0044) #define HDMI_HPD_ST HDMI_CTRL_BASE(0x0044)
#define HDMI_HPD_TH_X HDMI_CTRL_BASE(0x0050) #define HDMI_HPD_TH_X HDMI_CTRL_BASE(0x0050)
#define HDMI_AUDIO_CLKSEL HDMI_CTRL_BASE(0x0070) #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_VPLL HDMI_CTRL_BASE(0x0078)
#define HDMI_PHY_CMU HDMI_CTRL_BASE(0x007C) #define HDMI_PHY_CMU HDMI_CTRL_BASE(0x007C)
#define HDMI_CORE_RSTOUT HDMI_CTRL_BASE(0x0080) #define HDMI_CORE_RSTOUT HDMI_CTRL_BASE(0x0080)
...@@ -277,16 +276,26 @@ ...@@ -277,16 +276,26 @@
#define HDMI_ASP_CHCFG2 HDMI_CORE_BASE(0x0318) #define HDMI_ASP_CHCFG2 HDMI_CORE_BASE(0x0318)
#define HDMI_ASP_CHCFG3 HDMI_CORE_BASE(0x031C) #define HDMI_ASP_CHCFG3 HDMI_CORE_BASE(0x031C)
#define HDMI_ACR_CON HDMI_CORE_BASE(0x0400) #define HDMI_V13_ACR_CON HDMI_CORE_BASE(0x0180)
#define HDMI_ACR_MCTS0 HDMI_CORE_BASE(0x0410) #define HDMI_V13_ACR_MCTS0 HDMI_CORE_BASE(0x0184)
#define HDMI_ACR_MCTS1 HDMI_CORE_BASE(0x0414) #define HDMI_V13_ACR_MCTS1 HDMI_CORE_BASE(0x0188)
#define HDMI_ACR_MCTS2 HDMI_CORE_BASE(0x0418) #define HDMI_V13_ACR_MCTS2 HDMI_CORE_BASE(0x018C)
#define HDMI_ACR_CTS0 HDMI_CORE_BASE(0x0420) #define HDMI_V13_ACR_CTS0 HDMI_CORE_BASE(0x0190)
#define HDMI_ACR_CTS1 HDMI_CORE_BASE(0x0424) #define HDMI_V13_ACR_CTS1 HDMI_CORE_BASE(0x0194)
#define HDMI_ACR_CTS2 HDMI_CORE_BASE(0x0428) #define HDMI_V13_ACR_CTS2 HDMI_CORE_BASE(0x0198)
#define HDMI_ACR_N0 HDMI_CORE_BASE(0x0430) #define HDMI_V13_ACR_N0 HDMI_CORE_BASE(0x01A0)
#define HDMI_ACR_N1 HDMI_CORE_BASE(0x0434) #define HDMI_V13_ACR_N1 HDMI_CORE_BASE(0x01A4)
#define HDMI_ACR_N2 HDMI_CORE_BASE(0x0438) #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 */ /* Packet related registers */
#define HDMI_ACP_CON HDMI_CORE_BASE(0x0500) #define HDMI_ACP_CON HDMI_CORE_BASE(0x0500)
......
...@@ -82,6 +82,8 @@ ...@@ -82,6 +82,8 @@
/* VIDCON0 */ /* VIDCON0 */
#define VIDCON0_SWRESET (1 << 28) #define VIDCON0_SWRESET (1 << 28)
#define VIDCON0_CLKVALUP (1 << 14)
#define VIDCON0_VLCKFREE (1 << 5)
#define VIDCON0_STOP_STATUS (1 << 2) #define VIDCON0_STOP_STATUS (1 << 2)
#define VIDCON0_ENVID (1 << 1) #define VIDCON0_ENVID (1 << 1)
#define VIDCON0_ENVID_F (1 << 0) #define VIDCON0_ENVID_F (1 << 0)
...@@ -137,6 +139,13 @@ ...@@ -137,6 +139,13 @@
/* DECON_UPDATE */ /* DECON_UPDATE */
#define STANDALONE_UPDATE_F (1 << 0) #define STANDALONE_UPDATE_F (1 << 0)
/* DECON_VIDCON1 */
#define VIDCON1_VCLK_MASK (0x3 << 9)
#define VIDCON1_VCLK_RUN_VDEN_DISABLE (0x3 << 9)
#define VIDCON1_VCLK_HOLD (0x0 << 9)
#define VIDCON1_VCLK_RUN (0x1 << 9)
/* DECON_VIDTCON00 */ /* DECON_VIDTCON00 */
#define VIDTCON00_VBPD_F(x) (((x) & 0xfff) << 16) #define VIDTCON00_VBPD_F(x) (((x) & 0xfff) << 16)
#define VIDTCON00_VFPD_F(x) ((x) & 0xfff) #define VIDTCON00_VFPD_F(x) ((x) & 0xfff)
...@@ -159,7 +168,27 @@ ...@@ -159,7 +168,27 @@
#define TRIGCON_TRIGEN_PER_F (1 << 31) #define TRIGCON_TRIGEN_PER_F (1 << 31)
#define TRIGCON_TRIGEN_F (1 << 30) #define TRIGCON_TRIGEN_F (1 << 30)
#define TRIGCON_TE_AUTO_MASK (1 << 29) #define TRIGCON_TE_AUTO_MASK (1 << 29)
#define TRIGCON_WB_SWTRIGCMD (1 << 28)
#define TRIGCON_SWTRIGCMD_W4BUF (1 << 26)
#define TRIGCON_TRIGMODE_W4BUF (1 << 25)
#define TRIGCON_SWTRIGCMD_W3BUF (1 << 21)
#define TRIGCON_TRIGMODE_W3BUF (1 << 20)
#define TRIGCON_SWTRIGCMD_W2BUF (1 << 16)
#define TRIGCON_TRIGMODE_W2BUF (1 << 15)
#define TRIGCON_SWTRIGCMD_W1BUF (1 << 11)
#define TRIGCON_TRIGMODE_W1BUF (1 << 10)
#define TRIGCON_SWTRIGCMD_W0BUF (1 << 6)
#define TRIGCON_TRIGMODE_W0BUF (1 << 5)
#define TRIGCON_HWTRIGMASK_I80_RGB (1 << 4)
#define TRIGCON_HWTRIGEN_I80_RGB (1 << 3)
#define TRIGCON_HWTRIG_INV_I80_RGB (1 << 2)
#define TRIGCON_SWTRIGCMD (1 << 1) #define TRIGCON_SWTRIGCMD (1 << 1)
#define TRIGCON_SWTRIGEN (1 << 0) #define TRIGCON_SWTRIGEN (1 << 0)
/* DECON_CRCCTRL */
#define CRCCTRL_CRCCLKEN (0x1 << 2)
#define CRCCTRL_CRCSTART_F (0x1 << 1)
#define CRCCTRL_CRCEN (0x1 << 0)
#define CRCCTRL_MASK (0x7)
#endif /* EXYNOS_REGS_DECON_H */ #endif /* EXYNOS_REGS_DECON_H */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment