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