Commit 00c1beab 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

Summary:
 - Support for pipeline clock between KMS drivers.
   . Exynos SoC is required to control clocks across KMS drivers
     according to Exynos SoC version. So this patch refactos
     some relevant codes and provides generic solution for it.
 - Add Exynos5433 SoC support to HDMI parts - HDMI and DECON-TV.
 - Add HW trigger mode support to CRTC drivers.
   . In case of using i80 Panel, some Exynos SoC supports HW trigger
     mode so this patch makes trigger mode - HW or SW trigger - to be
     set according to SoC version properly.
 - And some cleanups and regression fixups.

* 'exynos-drm-next' of git://git.kernel.org/pub/scm/linux/kernel/git/daeinki/drm-exynos: (39 commits)
  drm/exynos: clean up register definions for fimd and decon
  drm/exynos: decon: clean up interface type
  drm/exynos: fimd: add HW trigger support
  drm/exynos: clean up wait_for_vblank
  drm/exynos: mixer: use generic of_device_get_match_data helper
  drm/exynos: mixer: remove support for non-dt platforms
  drm/exynos: hdmi: use generic of_device_get_match_data helper
  drm/exynos: rotator: use generic of_device_get_match_data helper
  drm/exynos: fimd: use generic of_device_get_match_data helper
  drm/exynos: dsi: use generic of_device_get_match_data helper
  drm/exynos: exynos5433_decon: use generic of_device_get_match_data helper
  drm/exynos: convert clock_enable crtc callback to pipeline clock
  drm/exynos/mixer: enable HDMI-PHY before configuring MIXER
  drm/exynos/decon5433: enable HDMI-PHY before configuring DECON
  drm/exynos: add support for pipeline clock to the framework
  drm/exynos: add helper to get crtc from pipe
  drm/exynos/decon5433: do not protect window in plane disable
  drm/exynos/decon5433: reset decon on start
  drm/exynos/decon5433: fix DECON standalone update
  drm/exynos/hdmi: remove registry dump
  ...
parents acff058f b5bf0f1e
...@@ -5,7 +5,8 @@ Exynos series of SoCs which transfers the image data from a video memory ...@@ -5,7 +5,8 @@ Exynos series of SoCs which transfers the image data from a video memory
buffer to an external LCD interface. buffer to an external LCD interface.
Required properties: Required properties:
- compatible: value should be "samsung,exynos5433-decon"; - compatible: value should be one of:
"samsung,exynos5433-decon", "samsung,exynos5433-decon-tv";
- reg: physical base address and length of the DECON registers set. - reg: physical base address and length of the DECON registers set.
- interrupts: should contain a list of all DECON IP block interrupts in the - interrupts: should contain a list of all DECON IP block interrupts in the
order: VSYNC, LCD_SYSTEM. The interrupt specifier format order: VSYNC, LCD_SYSTEM. The interrupt specifier format
...@@ -16,7 +17,7 @@ Required properties: ...@@ -16,7 +17,7 @@ Required properties:
- clocks: must include clock specifiers corresponding to entries in the - clocks: must include clock specifiers corresponding to entries in the
clock-names property. clock-names property.
- clock-names: list of clock names sorted in the same order as the clocks - clock-names: list of clock names sorted in the same order as the clocks
property. Must contain "aclk_decon", "aclk_smmu_decon0x", property. Must contain "pclk", "aclk_decon", "aclk_smmu_decon0x",
"aclk_xiu_decon0x", "pclk_smmu_decon0x", clk_decon_vclk", "aclk_xiu_decon0x", "pclk_smmu_decon0x", clk_decon_vclk",
"sclk_decon_eclk" "sclk_decon_eclk"
- ports: contains a port which is connected to mic node. address-cells and - ports: contains a port which is connected to mic node. address-cells and
......
...@@ -5,6 +5,7 @@ Required properties: ...@@ -5,6 +5,7 @@ Required properties:
1) "samsung,exynos4210-hdmi" 1) "samsung,exynos4210-hdmi"
2) "samsung,exynos4212-hdmi" 2) "samsung,exynos4212-hdmi"
3) "samsung,exynos5420-hdmi" 3) "samsung,exynos5420-hdmi"
4) "samsung,exynos5433-hdmi"
- reg: physical base address of the hdmi and length of memory mapped - reg: physical base address of the hdmi and length of memory mapped
region. region.
- interrupts: interrupt number to the cpu. - interrupts: interrupt number to the cpu.
...@@ -12,6 +13,11 @@ Required properties: ...@@ -12,6 +13,11 @@ Required properties:
a) phandle of the gpio controller node. a) phandle of the gpio controller node.
b) pin number within the gpio controller. b) pin number within the gpio controller.
c) optional flags and pull up/down. c) optional flags and pull up/down.
- ddc: phandle to the hdmi ddc node
- phy: phandle to the hdmi phy node
- samsung,syscon-phandle: phandle for system controller node for PMU.
Required properties for Exynos 4210, 4212, 5420 and 5433:
- clocks: list of clock IDs from SoC clock driver. - clocks: list of clock IDs from SoC clock driver.
a) hdmi: Gate of HDMI IP bus clock. a) hdmi: Gate of HDMI IP bus clock.
b) sclk_hdmi: Gate of HDMI special clock. b) sclk_hdmi: Gate of HDMI special clock.
...@@ -25,9 +31,24 @@ Required properties: ...@@ -25,9 +31,24 @@ Required properties:
sclk_pixel. sclk_pixel.
- clock-names: aliases as per driver requirements for above clock IDs: - clock-names: aliases as per driver requirements for above clock IDs:
"hdmi", "sclk_hdmi", "sclk_pixel", "sclk_hdmiphy" and "mout_hdmi". "hdmi", "sclk_hdmi", "sclk_pixel", "sclk_hdmiphy" and "mout_hdmi".
- ddc: phandle to the hdmi ddc node
- phy: phandle to the hdmi phy node Required properties for Exynos 5433:
- samsung,syscon-phandle: phandle for system controller node for PMU. - clocks: list of clock specifiers according to common clock bindings.
a) hdmi_pclk: Gate of HDMI IP APB bus.
b) hdmi_i_pclk: Gate of HDMI-PHY IP APB bus.
d) i_tmds_clk: Gate of HDMI TMDS clock.
e) i_pixel_clk: Gate of HDMI pixel clock.
f) i_spdif_clk: Gate of HDMI SPDIF clock.
g) oscclk: Oscillator clock, used as parent of following *_user clocks
in case HDMI-PHY is not operational.
h) tmds_clko: TMDS clock generated by HDMI-PHY.
i) tmds_clko_user: MUX used to switch between oscclk and tmds_clko,
respectively if HDMI-PHY is off and operational.
j) pixel_clko: Pixel clock generated by HDMI-PHY.
k) pixel_clko_user: MUX used to switch between oscclk and pixel_clko,
respectively if HDMI-PHY is off and operational.
- clock-names: aliases for above clock specfiers.
- samsung,sysreg: handle to syscon used to control the system registers.
Example: Example:
......
...@@ -95,7 +95,7 @@ comment "Sub-drivers" ...@@ -95,7 +95,7 @@ comment "Sub-drivers"
config DRM_EXYNOS_G2D config DRM_EXYNOS_G2D
bool "G2D" bool "G2D"
depends on !VIDEO_SAMSUNG_S5P_G2D depends on VIDEO_SAMSUNG_S5P_G2D=n
select FRAME_VECTOR select FRAME_VECTOR
help help
Choose this option if you want to use Exynos G2D for DRM. Choose this option if you want to use Exynos G2D for DRM.
......
...@@ -2,10 +2,10 @@ ...@@ -2,10 +2,10 @@
# Makefile for the drm device driver. This driver provides support for the # Makefile for the drm device driver. This driver provides support for the
# Direct Rendering Infrastructure (DRI) in XFree86 4.1.0 and higher. # Direct Rendering Infrastructure (DRI) in XFree86 4.1.0 and higher.
exynosdrm-y := exynos_drm_drv.o exynos_drm_crtc.o exynos_drm_fbdev.o \ exynosdrm-y := exynos_drm_drv.o exynos_drm_crtc.o exynos_drm_fb.o \
exynos_drm_fb.o exynos_drm_gem.o exynos_drm_core.o \ exynos_drm_gem.o exynos_drm_core.o exynos_drm_plane.o
exynos_drm_plane.o
exynosdrm-$(CONFIG_DRM_FBDEV_EMULATION) += exynos_drm_fbdev.o
exynosdrm-$(CONFIG_DRM_EXYNOS_IOMMU) += exynos_drm_iommu.o exynosdrm-$(CONFIG_DRM_EXYNOS_IOMMU) += exynos_drm_iommu.o
exynosdrm-$(CONFIG_DRM_EXYNOS_FIMD) += exynos_drm_fimd.o exynosdrm-$(CONFIG_DRM_EXYNOS_FIMD) += exynos_drm_fimd.o
exynosdrm-$(CONFIG_DRM_EXYNOS5433_DECON) += exynos5433_drm_decon.o exynosdrm-$(CONFIG_DRM_EXYNOS5433_DECON) += exynos5433_drm_decon.o
......
...@@ -28,6 +28,10 @@ ...@@ -28,6 +28,10 @@
#define WINDOWS_NR 3 #define WINDOWS_NR 3
#define MIN_FB_WIDTH_FOR_16WORD_BURST 128 #define MIN_FB_WIDTH_FOR_16WORD_BURST 128
#define IFTYPE_I80 (1 << 0)
#define I80_HW_TRG (1 << 1)
#define IFTYPE_HDMI (1 << 2)
static const char * const decon_clks_name[] = { static const char * const decon_clks_name[] = {
"pclk", "pclk",
"aclk_decon", "aclk_decon",
...@@ -38,12 +42,6 @@ static const char * const decon_clks_name[] = { ...@@ -38,12 +42,6 @@ static const char * const decon_clks_name[] = {
"sclk_decon_eclk", "sclk_decon_eclk",
}; };
enum decon_iftype {
IFTYPE_RGB,
IFTYPE_I80,
IFTYPE_HDMI
};
enum decon_flag_bits { enum decon_flag_bits {
BIT_CLKS_ENABLED, BIT_CLKS_ENABLED,
BIT_IRQS_ENABLED, BIT_IRQS_ENABLED,
...@@ -61,7 +59,7 @@ struct decon_context { ...@@ -61,7 +59,7 @@ struct decon_context {
struct clk *clks[ARRAY_SIZE(decon_clks_name)]; struct clk *clks[ARRAY_SIZE(decon_clks_name)];
int pipe; int pipe;
unsigned long flags; unsigned long flags;
enum decon_iftype out_type; unsigned long out_type;
int first_win; int first_win;
}; };
...@@ -95,7 +93,7 @@ static int decon_enable_vblank(struct exynos_drm_crtc *crtc) ...@@ -95,7 +93,7 @@ static int decon_enable_vblank(struct exynos_drm_crtc *crtc)
if (!test_and_set_bit(BIT_IRQS_ENABLED, &ctx->flags)) { if (!test_and_set_bit(BIT_IRQS_ENABLED, &ctx->flags)) {
val = VIDINTCON0_INTEN; val = VIDINTCON0_INTEN;
if (ctx->out_type == IFTYPE_I80) if (ctx->out_type & IFTYPE_I80)
val |= VIDINTCON0_FRAMEDONE; val |= VIDINTCON0_FRAMEDONE;
else else
val |= VIDINTCON0_INTFRMEN; val |= VIDINTCON0_INTFRMEN;
...@@ -119,11 +117,11 @@ static void decon_disable_vblank(struct exynos_drm_crtc *crtc) ...@@ -119,11 +117,11 @@ static void decon_disable_vblank(struct exynos_drm_crtc *crtc)
static void decon_setup_trigger(struct decon_context *ctx) static void decon_setup_trigger(struct decon_context *ctx)
{ {
u32 val = (ctx->out_type != IFTYPE_HDMI) u32 val = !(ctx->out_type & I80_HW_TRG)
? TRIGCON_TRIGEN_PER_F | TRIGCON_TRIGEN_F | ? TRIGCON_TRIGEN_PER_F | TRIGCON_TRIGEN_F |
TRIGCON_TE_AUTO_MASK | TRIGCON_SWTRIGEN TRIGCON_TE_AUTO_MASK | TRIGCON_SWTRIGEN
: TRIGCON_TRIGEN_PER_F | TRIGCON_TRIGEN_F | : TRIGCON_TRIGEN_PER_F | TRIGCON_TRIGEN_F |
TRIGCON_HWTRIGMASK_I80_RGB | TRIGCON_HWTRIGEN_I80_RGB; TRIGCON_HWTRIGMASK | TRIGCON_HWTRIGEN;
writel(val, ctx->addr + DECON_TRIGCON); writel(val, ctx->addr + DECON_TRIGCON);
} }
...@@ -136,7 +134,7 @@ static void decon_commit(struct exynos_drm_crtc *crtc) ...@@ -136,7 +134,7 @@ static void decon_commit(struct exynos_drm_crtc *crtc)
if (test_bit(BIT_SUSPENDED, &ctx->flags)) if (test_bit(BIT_SUSPENDED, &ctx->flags))
return; return;
if (ctx->out_type == IFTYPE_HDMI) { if (ctx->out_type & IFTYPE_HDMI) {
m->crtc_hsync_start = m->crtc_hdisplay + 10; m->crtc_hsync_start = m->crtc_hdisplay + 10;
m->crtc_hsync_end = m->crtc_htotal - 92; m->crtc_hsync_end = m->crtc_htotal - 92;
m->crtc_vsync_start = m->crtc_vdisplay + 1; m->crtc_vsync_start = m->crtc_vdisplay + 1;
...@@ -151,17 +149,20 @@ static void decon_commit(struct exynos_drm_crtc *crtc) ...@@ -151,17 +149,20 @@ static void decon_commit(struct exynos_drm_crtc *crtc)
/* lcd on and use command if */ /* lcd on and use command if */
val = VIDOUT_LCD_ON; val = VIDOUT_LCD_ON;
if (ctx->out_type == IFTYPE_I80) if (ctx->out_type & IFTYPE_I80) {
val |= VIDOUT_COMMAND_IF; val |= VIDOUT_COMMAND_IF;
else decon_setup_trigger(ctx);
} else {
val |= VIDOUT_RGB_IF; val |= VIDOUT_RGB_IF;
}
writel(val, ctx->addr + DECON_VIDOUTCON0); writel(val, ctx->addr + DECON_VIDOUTCON0);
val = VIDTCON2_LINEVAL(m->vdisplay - 1) | val = VIDTCON2_LINEVAL(m->vdisplay - 1) |
VIDTCON2_HOZVAL(m->hdisplay - 1); VIDTCON2_HOZVAL(m->hdisplay - 1);
writel(val, ctx->addr + DECON_VIDTCON2); writel(val, ctx->addr + DECON_VIDTCON2);
if (ctx->out_type != IFTYPE_I80) { if (!(ctx->out_type & IFTYPE_I80)) {
val = VIDTCON00_VBPD_F( val = VIDTCON00_VBPD_F(
m->crtc_vtotal - m->crtc_vsync_end - 1) | m->crtc_vtotal - m->crtc_vsync_end - 1) |
VIDTCON00_VFPD_F( VIDTCON00_VFPD_F(
...@@ -183,10 +184,10 @@ static void decon_commit(struct exynos_drm_crtc *crtc) ...@@ -183,10 +184,10 @@ static void decon_commit(struct exynos_drm_crtc *crtc)
writel(val, ctx->addr + DECON_VIDTCON11); writel(val, ctx->addr + DECON_VIDTCON11);
} }
decon_setup_trigger(ctx);
/* enable output and display signal */ /* enable output and display signal */
decon_set_bits(ctx, DECON_VIDCON0, VIDCON0_ENVID | VIDCON0_ENVID_F, ~0); decon_set_bits(ctx, DECON_VIDCON0, VIDCON0_ENVID | VIDCON0_ENVID_F, ~0);
decon_set_bits(ctx, DECON_UPDATE, STANDALONE_UPDATE_F, ~0);
} }
static void decon_win_set_pixfmt(struct decon_context *ctx, unsigned int win, static void decon_win_set_pixfmt(struct decon_context *ctx, unsigned int win,
...@@ -300,7 +301,7 @@ static void decon_update_plane(struct exynos_drm_crtc *crtc, ...@@ -300,7 +301,7 @@ static void decon_update_plane(struct exynos_drm_crtc *crtc,
val = dma_addr + pitch * state->src.h; val = dma_addr + pitch * state->src.h;
writel(val, ctx->addr + DECON_VIDW0xADD1B0(win)); writel(val, ctx->addr + DECON_VIDW0xADD1B0(win));
if (ctx->out_type != IFTYPE_HDMI) if (!(ctx->out_type & IFTYPE_HDMI))
val = BIT_VAL(pitch - state->crtc.w * bpp, 27, 14) val = BIT_VAL(pitch - state->crtc.w * bpp, 27, 14)
| BIT_VAL(state->crtc.w * bpp, 13, 0); | BIT_VAL(state->crtc.w * bpp, 13, 0);
else else
...@@ -312,9 +313,6 @@ static void decon_update_plane(struct exynos_drm_crtc *crtc, ...@@ -312,9 +313,6 @@ static void decon_update_plane(struct exynos_drm_crtc *crtc,
/* window enable */ /* window enable */
decon_set_bits(ctx, DECON_WINCONx(win), WINCONx_ENWIN_F, ~0); decon_set_bits(ctx, DECON_WINCONx(win), WINCONx_ENWIN_F, ~0);
/* standalone update */
decon_set_bits(ctx, DECON_UPDATE, STANDALONE_UPDATE_F, ~0);
} }
static void decon_disable_plane(struct exynos_drm_crtc *crtc, static void decon_disable_plane(struct exynos_drm_crtc *crtc,
...@@ -326,15 +324,7 @@ static void decon_disable_plane(struct exynos_drm_crtc *crtc, ...@@ -326,15 +324,7 @@ static void decon_disable_plane(struct exynos_drm_crtc *crtc,
if (test_bit(BIT_SUSPENDED, &ctx->flags)) if (test_bit(BIT_SUSPENDED, &ctx->flags))
return; return;
decon_shadow_protect_win(ctx, win, true);
/* window disable */
decon_set_bits(ctx, DECON_WINCONx(win), WINCONx_ENWIN_F, 0); decon_set_bits(ctx, DECON_WINCONx(win), WINCONx_ENWIN_F, 0);
decon_shadow_protect_win(ctx, win, false);
/* standalone update */
decon_set_bits(ctx, DECON_UPDATE, STANDALONE_UPDATE_F, ~0);
} }
static void decon_atomic_flush(struct exynos_drm_crtc *crtc) static void decon_atomic_flush(struct exynos_drm_crtc *crtc)
...@@ -348,7 +338,10 @@ static void decon_atomic_flush(struct exynos_drm_crtc *crtc) ...@@ -348,7 +338,10 @@ static void decon_atomic_flush(struct exynos_drm_crtc *crtc)
for (i = ctx->first_win; i < WINDOWS_NR; i++) for (i = ctx->first_win; i < WINDOWS_NR; i++)
decon_shadow_protect_win(ctx, i, false); decon_shadow_protect_win(ctx, i, false);
if (ctx->out_type == IFTYPE_I80) /* standalone update */
decon_set_bits(ctx, DECON_UPDATE, STANDALONE_UPDATE_F, ~0);
if (ctx->out_type & IFTYPE_I80)
set_bit(BIT_WIN_UPDATED, &ctx->flags); set_bit(BIT_WIN_UPDATED, &ctx->flags);
} }
...@@ -374,7 +367,7 @@ static void decon_swreset(struct decon_context *ctx) ...@@ -374,7 +367,7 @@ static void decon_swreset(struct decon_context *ctx)
WARN(tries == 0, "failed to software reset DECON\n"); WARN(tries == 0, "failed to software reset DECON\n");
if (ctx->out_type != IFTYPE_HDMI) if (!(ctx->out_type & IFTYPE_HDMI))
return; return;
writel(VIDCON0_CLKVALUP | VIDCON0_VLCKFREE, ctx->addr + DECON_VIDCON0); writel(VIDCON0_CLKVALUP | VIDCON0_VLCKFREE, ctx->addr + DECON_VIDCON0);
...@@ -383,7 +376,9 @@ static void decon_swreset(struct decon_context *ctx) ...@@ -383,7 +376,9 @@ static void decon_swreset(struct decon_context *ctx)
writel(VIDCON1_VCLK_RUN_VDEN_DISABLE, ctx->addr + DECON_VIDCON1); writel(VIDCON1_VCLK_RUN_VDEN_DISABLE, ctx->addr + DECON_VIDCON1);
writel(CRCCTRL_CRCEN | CRCCTRL_CRCSTART_F | CRCCTRL_CRCCLKEN, writel(CRCCTRL_CRCEN | CRCCTRL_CRCSTART_F | CRCCTRL_CRCCLKEN,
ctx->addr + DECON_CRCCTRL); ctx->addr + DECON_CRCCTRL);
decon_setup_trigger(ctx);
if (ctx->out_type & IFTYPE_I80)
decon_setup_trigger(ctx);
} }
static void decon_enable(struct exynos_drm_crtc *crtc) static void decon_enable(struct exynos_drm_crtc *crtc)
...@@ -395,8 +390,12 @@ static void decon_enable(struct exynos_drm_crtc *crtc) ...@@ -395,8 +390,12 @@ static void decon_enable(struct exynos_drm_crtc *crtc)
pm_runtime_get_sync(ctx->dev); pm_runtime_get_sync(ctx->dev);
exynos_drm_pipe_clk_enable(crtc, true);
set_bit(BIT_CLKS_ENABLED, &ctx->flags); set_bit(BIT_CLKS_ENABLED, &ctx->flags);
decon_swreset(ctx);
/* if vblank was enabled status, enable it again. */ /* if vblank was enabled status, enable it again. */
if (test_and_clear_bit(BIT_IRQS_ENABLED, &ctx->flags)) if (test_and_clear_bit(BIT_IRQS_ENABLED, &ctx->flags))
decon_enable_vblank(ctx->crtc); decon_enable_vblank(ctx->crtc);
...@@ -424,6 +423,8 @@ static void decon_disable(struct exynos_drm_crtc *crtc) ...@@ -424,6 +423,8 @@ static void decon_disable(struct exynos_drm_crtc *crtc)
clear_bit(BIT_CLKS_ENABLED, &ctx->flags); clear_bit(BIT_CLKS_ENABLED, &ctx->flags);
exynos_drm_pipe_clk_enable(crtc, false);
pm_runtime_put_sync(ctx->dev); pm_runtime_put_sync(ctx->dev);
set_bit(BIT_SUSPENDED, &ctx->flags); set_bit(BIT_SUSPENDED, &ctx->flags);
...@@ -459,8 +460,10 @@ static void decon_clear_channels(struct exynos_drm_crtc *crtc) ...@@ -459,8 +460,10 @@ static void decon_clear_channels(struct exynos_drm_crtc *crtc)
decon_shadow_protect_win(ctx, win, true); decon_shadow_protect_win(ctx, win, true);
decon_set_bits(ctx, DECON_WINCONx(win), WINCONx_ENWIN_F, 0); decon_set_bits(ctx, DECON_WINCONx(win), WINCONx_ENWIN_F, 0);
decon_shadow_protect_win(ctx, win, false); decon_shadow_protect_win(ctx, win, false);
decon_set_bits(ctx, DECON_UPDATE, STANDALONE_UPDATE_F, ~0);
} }
decon_set_bits(ctx, DECON_UPDATE, STANDALONE_UPDATE_F, ~0);
/* TODO: wait for possible vsync */ /* TODO: wait for possible vsync */
msleep(50); msleep(50);
...@@ -509,7 +512,7 @@ static int decon_bind(struct device *dev, struct device *master, void *data) ...@@ -509,7 +512,7 @@ static int decon_bind(struct device *dev, struct device *master, void *data)
} }
exynos_plane = &ctx->planes[ctx->first_win]; exynos_plane = &ctx->planes[ctx->first_win];
out_type = (ctx->out_type == IFTYPE_HDMI) ? EXYNOS_DISPLAY_TYPE_HDMI out_type = (ctx->out_type & IFTYPE_HDMI) ? EXYNOS_DISPLAY_TYPE_HDMI
: EXYNOS_DISPLAY_TYPE_LCD; : EXYNOS_DISPLAY_TYPE_LCD;
ctx->crtc = exynos_drm_crtc_create(drm_dev, &exynos_plane->base, ctx->crtc = exynos_drm_crtc_create(drm_dev, &exynos_plane->base,
ctx->pipe, out_type, ctx->pipe, out_type,
...@@ -617,11 +620,11 @@ static const struct dev_pm_ops exynos5433_decon_pm_ops = { ...@@ -617,11 +620,11 @@ static const struct dev_pm_ops exynos5433_decon_pm_ops = {
static const struct of_device_id exynos5433_decon_driver_dt_match[] = { static const struct of_device_id exynos5433_decon_driver_dt_match[] = {
{ {
.compatible = "samsung,exynos5433-decon", .compatible = "samsung,exynos5433-decon",
.data = (void *)IFTYPE_RGB .data = (void *)I80_HW_TRG
}, },
{ {
.compatible = "samsung,exynos5433-decon-tv", .compatible = "samsung,exynos5433-decon-tv",
.data = (void *)IFTYPE_HDMI .data = (void *)(I80_HW_TRG | IFTYPE_HDMI)
}, },
{}, {},
}; };
...@@ -629,7 +632,6 @@ MODULE_DEVICE_TABLE(of, exynos5433_decon_driver_dt_match); ...@@ -629,7 +632,6 @@ MODULE_DEVICE_TABLE(of, exynos5433_decon_driver_dt_match);
static int exynos5433_decon_probe(struct platform_device *pdev) static int exynos5433_decon_probe(struct platform_device *pdev)
{ {
const struct of_device_id *of_id;
struct device *dev = &pdev->dev; struct device *dev = &pdev->dev;
struct decon_context *ctx; struct decon_context *ctx;
struct resource *res; struct resource *res;
...@@ -642,14 +644,14 @@ static int exynos5433_decon_probe(struct platform_device *pdev) ...@@ -642,14 +644,14 @@ static int exynos5433_decon_probe(struct platform_device *pdev)
__set_bit(BIT_SUSPENDED, &ctx->flags); __set_bit(BIT_SUSPENDED, &ctx->flags);
ctx->dev = dev; ctx->dev = dev;
ctx->out_type = (unsigned long)of_device_get_match_data(dev);
of_id = of_match_device(exynos5433_decon_driver_dt_match, &pdev->dev); if (ctx->out_type & IFTYPE_HDMI) {
ctx->out_type = (enum decon_iftype)of_id->data;
if (ctx->out_type == IFTYPE_HDMI)
ctx->first_win = 1; ctx->first_win = 1;
else if (of_get_child_by_name(dev->of_node, "i80-if-timings"))
ctx->out_type = IFTYPE_I80; ctx->out_type = IFTYPE_I80;
} else if (of_get_child_by_name(dev->of_node, "i80-if-timings")) {
ctx->out_type = IFTYPE_I80;
}
for (i = 0; i < ARRAY_SIZE(decon_clks_name); i++) { for (i = 0; i < ARRAY_SIZE(decon_clks_name); i++) {
struct clk *clk; struct clk *clk;
...@@ -674,7 +676,7 @@ static int exynos5433_decon_probe(struct platform_device *pdev) ...@@ -674,7 +676,7 @@ static int exynos5433_decon_probe(struct platform_device *pdev)
} }
res = platform_get_resource_byname(pdev, IORESOURCE_IRQ, res = platform_get_resource_byname(pdev, IORESOURCE_IRQ,
(ctx->out_type == IFTYPE_I80) ? "lcd_sys" : "vsync"); (ctx->out_type & IFTYPE_I80) ? "lcd_sys" : "vsync");
if (!res) { if (!res) {
dev_err(dev, "cannot find IRQ resource\n"); dev_err(dev, "cannot find IRQ resource\n");
return -ENXIO; return -ENXIO;
......
...@@ -593,7 +593,6 @@ static const struct exynos_drm_crtc_ops decon_crtc_ops = { ...@@ -593,7 +593,6 @@ static const struct exynos_drm_crtc_ops decon_crtc_ops = {
.commit = decon_commit, .commit = decon_commit,
.enable_vblank = decon_enable_vblank, .enable_vblank = decon_enable_vblank,
.disable_vblank = decon_disable_vblank, .disable_vblank = decon_disable_vblank,
.wait_for_vblank = decon_wait_for_vblank,
.atomic_begin = decon_atomic_begin, .atomic_begin = decon_atomic_begin,
.update_plane = decon_update_plane, .update_plane = decon_update_plane,
.disable_plane = decon_disable_plane, .disable_plane = decon_disable_plane,
......
...@@ -48,14 +48,11 @@ int exynos_dp_crtc_clock_enable(struct analogix_dp_plat_data *plat_data, ...@@ -48,14 +48,11 @@ int exynos_dp_crtc_clock_enable(struct analogix_dp_plat_data *plat_data,
{ {
struct exynos_dp_device *dp = to_dp(plat_data); struct exynos_dp_device *dp = to_dp(plat_data);
struct drm_encoder *encoder = &dp->encoder; struct drm_encoder *encoder = &dp->encoder;
struct exynos_drm_crtc *crtc;
if (!encoder) if (!encoder->crtc)
return -1; return -EPERM;
crtc = to_exynos_crtc(encoder->crtc); exynos_drm_pipe_clk_enable(to_exynos_crtc(encoder->crtc), enable);
if (crtc && crtc->ops && crtc->ops->clock_enable)
crtc->ops->clock_enable(crtc, enable);
return 0; return 0;
} }
......
...@@ -101,7 +101,7 @@ int exynos_drm_subdrv_open(struct drm_device *dev, struct drm_file *file) ...@@ -101,7 +101,7 @@ int exynos_drm_subdrv_open(struct drm_device *dev, struct drm_file *file)
return 0; return 0;
err: err:
list_for_each_entry_reverse(subdrv, &subdrv->list, list) { list_for_each_entry_continue_reverse(subdrv, &exynos_drm_subdrv_list, list) {
if (subdrv->close) if (subdrv->close)
subdrv->close(dev, subdrv->dev, file); subdrv->close(dev, subdrv->dev, file);
} }
......
...@@ -157,9 +157,8 @@ struct exynos_drm_crtc *exynos_drm_crtc_create(struct drm_device *drm_dev, ...@@ -157,9 +157,8 @@ struct exynos_drm_crtc *exynos_drm_crtc_create(struct drm_device *drm_dev,
int exynos_drm_crtc_enable_vblank(struct drm_device *dev, unsigned int pipe) int exynos_drm_crtc_enable_vblank(struct drm_device *dev, unsigned int pipe)
{ {
struct exynos_drm_private *private = dev->dev_private; struct exynos_drm_crtc *exynos_crtc = exynos_drm_crtc_from_pipe(dev,
struct exynos_drm_crtc *exynos_crtc = pipe);
to_exynos_crtc(private->crtc[pipe]);
if (exynos_crtc->ops->enable_vblank) if (exynos_crtc->ops->enable_vblank)
return exynos_crtc->ops->enable_vblank(exynos_crtc); return exynos_crtc->ops->enable_vblank(exynos_crtc);
...@@ -169,9 +168,8 @@ int exynos_drm_crtc_enable_vblank(struct drm_device *dev, unsigned int pipe) ...@@ -169,9 +168,8 @@ int exynos_drm_crtc_enable_vblank(struct drm_device *dev, unsigned int pipe)
void exynos_drm_crtc_disable_vblank(struct drm_device *dev, unsigned int pipe) void exynos_drm_crtc_disable_vblank(struct drm_device *dev, unsigned int pipe)
{ {
struct exynos_drm_private *private = dev->dev_private; struct exynos_drm_crtc *exynos_crtc = exynos_drm_crtc_from_pipe(dev,
struct exynos_drm_crtc *exynos_crtc = pipe);
to_exynos_crtc(private->crtc[pipe]);
if (exynos_crtc->ops->disable_vblank) if (exynos_crtc->ops->disable_vblank)
exynos_crtc->ops->disable_vblank(exynos_crtc); exynos_crtc->ops->disable_vblank(exynos_crtc);
......
...@@ -120,8 +120,6 @@ struct exynos_drm_plane_config { ...@@ -120,8 +120,6 @@ struct exynos_drm_plane_config {
* @commit: set current hw specific display mode to hw. * @commit: set current hw specific display mode to hw.
* @enable_vblank: specific driver callback for enabling vblank interrupt. * @enable_vblank: specific driver callback for enabling vblank interrupt.
* @disable_vblank: specific driver callback for disabling vblank interrupt. * @disable_vblank: specific driver callback for disabling vblank interrupt.
* @wait_for_vblank: wait for vblank interrupt to make sure that
* hardware overlay is updated.
* @atomic_check: validate state * @atomic_check: validate state
* @atomic_begin: prepare device to receive an update * @atomic_begin: prepare device to receive an update
* @atomic_flush: mark the end of device update * @atomic_flush: mark the end of device update
...@@ -129,10 +127,6 @@ struct exynos_drm_plane_config { ...@@ -129,10 +127,6 @@ struct exynos_drm_plane_config {
* @disable_plane: disable hardware specific overlay. * @disable_plane: disable hardware specific overlay.
* @te_handler: trigger to transfer video image at the tearing effect * @te_handler: trigger to transfer video image at the tearing effect
* synchronization signal if there is a page flip request. * synchronization signal if there is a page flip request.
* @clock_enable: optional function enabling/disabling display domain clock,
* called from exynos-dp driver before powering up (with
* 'enable' argument as true) and after powering down (with
* 'enable' as false).
*/ */
struct exynos_drm_crtc; struct exynos_drm_crtc;
struct exynos_drm_crtc_ops { struct exynos_drm_crtc_ops {
...@@ -141,7 +135,6 @@ struct exynos_drm_crtc_ops { ...@@ -141,7 +135,6 @@ struct exynos_drm_crtc_ops {
void (*commit)(struct exynos_drm_crtc *crtc); void (*commit)(struct exynos_drm_crtc *crtc);
int (*enable_vblank)(struct exynos_drm_crtc *crtc); int (*enable_vblank)(struct exynos_drm_crtc *crtc);
void (*disable_vblank)(struct exynos_drm_crtc *crtc); void (*disable_vblank)(struct exynos_drm_crtc *crtc);
void (*wait_for_vblank)(struct exynos_drm_crtc *crtc);
int (*atomic_check)(struct exynos_drm_crtc *crtc, int (*atomic_check)(struct exynos_drm_crtc *crtc,
struct drm_crtc_state *state); struct drm_crtc_state *state);
void (*atomic_begin)(struct exynos_drm_crtc *crtc); void (*atomic_begin)(struct exynos_drm_crtc *crtc);
...@@ -151,7 +144,10 @@ struct exynos_drm_crtc_ops { ...@@ -151,7 +144,10 @@ struct exynos_drm_crtc_ops {
struct exynos_drm_plane *plane); struct exynos_drm_plane *plane);
void (*atomic_flush)(struct exynos_drm_crtc *crtc); void (*atomic_flush)(struct exynos_drm_crtc *crtc);
void (*te_handler)(struct exynos_drm_crtc *crtc); void (*te_handler)(struct exynos_drm_crtc *crtc);
void (*clock_enable)(struct exynos_drm_crtc *crtc, bool enable); };
struct exynos_drm_clk {
void (*enable)(struct exynos_drm_clk *clk, bool enable);
}; };
/* /*
...@@ -182,8 +178,16 @@ struct exynos_drm_crtc { ...@@ -182,8 +178,16 @@ struct exynos_drm_crtc {
atomic_t pending_update; atomic_t pending_update;
const struct exynos_drm_crtc_ops *ops; const struct exynos_drm_crtc_ops *ops;
void *ctx; void *ctx;
struct exynos_drm_clk *pipe_clk;
}; };
static inline void exynos_drm_pipe_clk_enable(struct exynos_drm_crtc *crtc,
bool enable)
{
if (crtc->pipe_clk)
crtc->pipe_clk->enable(crtc->pipe_clk, enable);
}
struct exynos_drm_g2d_private { struct exynos_drm_g2d_private {
struct device *dev; struct device *dev;
struct list_head inuse_cmdlist; struct list_head inuse_cmdlist;
...@@ -232,6 +236,14 @@ struct exynos_drm_private { ...@@ -232,6 +236,14 @@ struct exynos_drm_private {
wait_queue_head_t wait; wait_queue_head_t wait;
}; };
static inline struct exynos_drm_crtc *
exynos_drm_crtc_from_pipe(struct drm_device *dev, int pipe)
{
struct exynos_drm_private *private = dev->dev_private;
return to_exynos_crtc(private->crtc[pipe]);
}
static inline struct device *to_dma_dev(struct drm_device *dev) static inline struct device *to_dma_dev(struct drm_device *dev)
{ {
struct exynos_drm_private *priv = dev->dev_private; struct exynos_drm_private *priv = dev->dev_private;
......
...@@ -280,7 +280,7 @@ struct exynos_dsi { ...@@ -280,7 +280,7 @@ struct exynos_dsi {
spinlock_t transfer_lock; /* protects transfer_list */ spinlock_t transfer_lock; /* protects transfer_list */
struct list_head transfer_list; struct list_head transfer_list;
struct exynos_dsi_driver_data *driver_data; const struct exynos_dsi_driver_data *driver_data;
struct device_node *bridge_node; struct device_node *bridge_node;
}; };
...@@ -532,15 +532,6 @@ static const struct of_device_id exynos_dsi_of_match[] = { ...@@ -532,15 +532,6 @@ static const struct of_device_id exynos_dsi_of_match[] = {
{ } { }
}; };
static inline struct exynos_dsi_driver_data *exynos_dsi_get_driver_data(
struct platform_device *pdev)
{
const struct of_device_id *of_id =
of_match_device(exynos_dsi_of_match, &pdev->dev);
return (struct exynos_dsi_driver_data *)of_id->data;
}
static void exynos_dsi_wait_for_reset(struct exynos_dsi *dsi) static void exynos_dsi_wait_for_reset(struct exynos_dsi *dsi)
{ {
if (wait_for_completion_timeout(&dsi->completed, msecs_to_jiffies(300))) if (wait_for_completion_timeout(&dsi->completed, msecs_to_jiffies(300)))
...@@ -564,7 +555,7 @@ static void exynos_dsi_reset(struct exynos_dsi *dsi) ...@@ -564,7 +555,7 @@ static void exynos_dsi_reset(struct exynos_dsi *dsi)
static unsigned long exynos_dsi_pll_find_pms(struct exynos_dsi *dsi, static unsigned long exynos_dsi_pll_find_pms(struct exynos_dsi *dsi,
unsigned long fin, unsigned long fout, u8 *p, u16 *m, u8 *s) unsigned long fin, unsigned long fout, u8 *p, u16 *m, u8 *s)
{ {
struct exynos_dsi_driver_data *driver_data = dsi->driver_data; const struct exynos_dsi_driver_data *driver_data = dsi->driver_data;
unsigned long best_freq = 0; unsigned long best_freq = 0;
u32 min_delta = 0xffffffff; u32 min_delta = 0xffffffff;
u8 p_min, p_max; u8 p_min, p_max;
...@@ -618,7 +609,7 @@ static unsigned long exynos_dsi_pll_find_pms(struct exynos_dsi *dsi, ...@@ -618,7 +609,7 @@ static unsigned long exynos_dsi_pll_find_pms(struct exynos_dsi *dsi,
static unsigned long exynos_dsi_set_pll(struct exynos_dsi *dsi, static unsigned long exynos_dsi_set_pll(struct exynos_dsi *dsi,
unsigned long freq) unsigned long freq)
{ {
struct exynos_dsi_driver_data *driver_data = dsi->driver_data; const struct exynos_dsi_driver_data *driver_data = dsi->driver_data;
unsigned long fin, fout; unsigned long fin, fout;
int timeout; int timeout;
u8 p, s; u8 p, s;
...@@ -712,7 +703,7 @@ static int exynos_dsi_enable_clock(struct exynos_dsi *dsi) ...@@ -712,7 +703,7 @@ static int exynos_dsi_enable_clock(struct exynos_dsi *dsi)
static void exynos_dsi_set_phy_ctrl(struct exynos_dsi *dsi) static void exynos_dsi_set_phy_ctrl(struct exynos_dsi *dsi)
{ {
struct exynos_dsi_driver_data *driver_data = dsi->driver_data; const struct exynos_dsi_driver_data *driver_data = dsi->driver_data;
const unsigned int *reg_values = driver_data->reg_values; const unsigned int *reg_values = driver_data->reg_values;
u32 reg; u32 reg;
...@@ -790,7 +781,7 @@ static void exynos_dsi_enable_lane(struct exynos_dsi *dsi, u32 lane) ...@@ -790,7 +781,7 @@ static void exynos_dsi_enable_lane(struct exynos_dsi *dsi, u32 lane)
static int exynos_dsi_init_link(struct exynos_dsi *dsi) static int exynos_dsi_init_link(struct exynos_dsi *dsi)
{ {
struct exynos_dsi_driver_data *driver_data = dsi->driver_data; const struct exynos_dsi_driver_data *driver_data = dsi->driver_data;
int timeout; int timeout;
u32 reg; u32 reg;
u32 lanes_mask; u32 lanes_mask;
...@@ -1334,7 +1325,7 @@ static void exynos_dsi_disable_irq(struct exynos_dsi *dsi) ...@@ -1334,7 +1325,7 @@ static void exynos_dsi_disable_irq(struct exynos_dsi *dsi)
static int exynos_dsi_init(struct exynos_dsi *dsi) static int exynos_dsi_init(struct exynos_dsi *dsi)
{ {
struct exynos_dsi_driver_data *driver_data = dsi->driver_data; const struct exynos_dsi_driver_data *driver_data = dsi->driver_data;
exynos_dsi_reset(dsi); exynos_dsi_reset(dsi);
exynos_dsi_enable_irq(dsi); exynos_dsi_enable_irq(dsi);
...@@ -1833,7 +1824,7 @@ static int exynos_dsi_probe(struct platform_device *pdev) ...@@ -1833,7 +1824,7 @@ static int exynos_dsi_probe(struct platform_device *pdev)
dsi->dsi_host.dev = dev; dsi->dsi_host.dev = dev;
dsi->dev = dev; dsi->dev = dev;
dsi->driver_data = exynos_dsi_get_driver_data(pdev); dsi->driver_data = of_device_get_match_data(dev);
ret = exynos_dsi_parse_dt(dsi); ret = exynos_dsi_parse_dt(dsi);
if (ret) if (ret)
...@@ -1917,7 +1908,7 @@ static int __maybe_unused exynos_dsi_suspend(struct device *dev) ...@@ -1917,7 +1908,7 @@ static int __maybe_unused exynos_dsi_suspend(struct device *dev)
{ {
struct drm_encoder *encoder = dev_get_drvdata(dev); struct drm_encoder *encoder = dev_get_drvdata(dev);
struct exynos_dsi *dsi = encoder_to_dsi(encoder); struct exynos_dsi *dsi = encoder_to_dsi(encoder);
struct exynos_dsi_driver_data *driver_data = dsi->driver_data; const struct exynos_dsi_driver_data *driver_data = dsi->driver_data;
int ret, i; int ret, i;
usleep_range(10000, 20000); usleep_range(10000, 20000);
...@@ -1948,7 +1939,7 @@ static int __maybe_unused exynos_dsi_resume(struct device *dev) ...@@ -1948,7 +1939,7 @@ static int __maybe_unused exynos_dsi_resume(struct device *dev)
{ {
struct drm_encoder *encoder = dev_get_drvdata(dev); struct drm_encoder *encoder = dev_get_drvdata(dev);
struct exynos_dsi *dsi = encoder_to_dsi(encoder); struct exynos_dsi *dsi = encoder_to_dsi(encoder);
struct exynos_dsi_driver_data *driver_data = dsi->driver_data; const struct exynos_dsi_driver_data *driver_data = dsi->driver_data;
int ret, i; int ret, i;
ret = regulator_bulk_enable(ARRAY_SIZE(dsi->supplies), dsi->supplies); ret = regulator_bulk_enable(ARRAY_SIZE(dsi->supplies), dsi->supplies);
......
...@@ -199,17 +199,6 @@ dma_addr_t exynos_drm_fb_dma_addr(struct drm_framebuffer *fb, int index) ...@@ -199,17 +199,6 @@ dma_addr_t exynos_drm_fb_dma_addr(struct drm_framebuffer *fb, int index)
return exynos_fb->dma_addr[index]; return exynos_fb->dma_addr[index];
} }
static void exynos_drm_output_poll_changed(struct drm_device *dev)
{
struct exynos_drm_private *private = dev->dev_private;
struct drm_fb_helper *fb_helper = private->fb_helper;
if (fb_helper)
drm_fb_helper_hotplug_event(fb_helper);
else
exynos_drm_fbdev_init(dev);
}
static const struct drm_mode_config_funcs exynos_drm_mode_config_funcs = { static const struct drm_mode_config_funcs exynos_drm_mode_config_funcs = {
.fb_create = exynos_user_fb_create, .fb_create = exynos_user_fb_create,
.output_poll_changed = exynos_drm_output_poll_changed, .output_poll_changed = exynos_drm_output_poll_changed,
......
...@@ -311,3 +311,14 @@ void exynos_drm_fbdev_restore_mode(struct drm_device *dev) ...@@ -311,3 +311,14 @@ void exynos_drm_fbdev_restore_mode(struct drm_device *dev)
drm_fb_helper_restore_fbdev_mode_unlocked(private->fb_helper); drm_fb_helper_restore_fbdev_mode_unlocked(private->fb_helper);
} }
void exynos_drm_output_poll_changed(struct drm_device *dev)
{
struct exynos_drm_private *private = dev->dev_private;
struct drm_fb_helper *fb_helper = private->fb_helper;
if (fb_helper)
drm_fb_helper_hotplug_event(fb_helper);
else
exynos_drm_fbdev_init(dev);
}
...@@ -15,9 +15,30 @@ ...@@ -15,9 +15,30 @@
#ifndef _EXYNOS_DRM_FBDEV_H_ #ifndef _EXYNOS_DRM_FBDEV_H_
#define _EXYNOS_DRM_FBDEV_H_ #define _EXYNOS_DRM_FBDEV_H_
#ifdef CONFIG_DRM_FBDEV_EMULATION
int exynos_drm_fbdev_init(struct drm_device *dev); int exynos_drm_fbdev_init(struct drm_device *dev);
int exynos_drm_fbdev_reinit(struct drm_device *dev);
void exynos_drm_fbdev_fini(struct drm_device *dev); void exynos_drm_fbdev_fini(struct drm_device *dev);
void exynos_drm_fbdev_restore_mode(struct drm_device *dev); void exynos_drm_fbdev_restore_mode(struct drm_device *dev);
void exynos_drm_output_poll_changed(struct drm_device *dev);
#else
static inline int exynos_drm_fbdev_init(struct drm_device *dev)
{
return 0;
}
static inline void exynos_drm_fbdev_fini(struct drm_device *dev)
{
}
static inline void exynos_drm_fbdev_restore_mode(struct drm_device *dev)
{
}
#define exynos_drm_output_poll_changed (NULL)
#endif
#endif #endif
...@@ -68,10 +68,15 @@ ...@@ -68,10 +68,15 @@
/* color key value register for hardware window 1 ~ 4. */ /* color key value register for hardware window 1 ~ 4. */
#define WKEYCON1_BASE(x) ((WKEYCON1 + 0x140) + ((x - 1) * 8)) #define WKEYCON1_BASE(x) ((WKEYCON1 + 0x140) + ((x - 1) * 8))
/* I80 / RGB trigger control register */ /* I80 trigger control register */
#define TRIGCON 0x1A4 #define TRIGCON 0x1A4
#define TRGMODE_I80_RGB_ENABLE_I80 (1 << 0) #define TRGMODE_ENABLE (1 << 0)
#define SWTRGCMD_I80_RGB_ENABLE (1 << 1) #define SWTRGCMD_ENABLE (1 << 1)
/* Exynos3250, 3472, 4415, 5260 5410, 5420 and 5422 only supported. */
#define HWTRGEN_ENABLE (1 << 3)
#define HWTRGMASK_ENABLE (1 << 4)
/* Exynos3250, 3472, 4415, 5260, 5420 and 5422 only supported. */
#define HWTRIGEN_PER_ENABLE (1 << 31)
/* display mode change control register except exynos4 */ /* display mode change control register except exynos4 */
#define VIDOUT_CON 0x000 #define VIDOUT_CON 0x000
...@@ -89,12 +94,16 @@ ...@@ -89,12 +94,16 @@
/* FIMD has totally five hardware windows. */ /* FIMD has totally five hardware windows. */
#define WINDOWS_NR 5 #define WINDOWS_NR 5
/* HW trigger flag on i80 panel. */
#define I80_HW_TRG (1 << 1)
struct fimd_driver_data { struct fimd_driver_data {
unsigned int timing_base; unsigned int timing_base;
unsigned int lcdblk_offset; unsigned int lcdblk_offset;
unsigned int lcdblk_vt_shift; unsigned int lcdblk_vt_shift;
unsigned int lcdblk_bypass_shift; unsigned int lcdblk_bypass_shift;
unsigned int lcdblk_mic_bypass_shift; unsigned int lcdblk_mic_bypass_shift;
unsigned int trg_type;
unsigned int has_shadowcon:1; unsigned int has_shadowcon:1;
unsigned int has_clksel:1; unsigned int has_clksel:1;
...@@ -102,20 +111,26 @@ struct fimd_driver_data { ...@@ -102,20 +111,26 @@ struct fimd_driver_data {
unsigned int has_vidoutcon:1; unsigned int has_vidoutcon:1;
unsigned int has_vtsel:1; unsigned int has_vtsel:1;
unsigned int has_mic_bypass:1; unsigned int has_mic_bypass:1;
unsigned int has_dp_clk:1;
unsigned int has_hw_trigger:1;
unsigned int has_trigger_per_te:1;
}; };
static struct fimd_driver_data s3c64xx_fimd_driver_data = { static struct fimd_driver_data s3c64xx_fimd_driver_data = {
.timing_base = 0x0, .timing_base = 0x0,
.has_clksel = 1, .has_clksel = 1,
.has_limited_fmt = 1, .has_limited_fmt = 1,
.has_hw_trigger = 1,
}; };
static struct fimd_driver_data exynos3_fimd_driver_data = { static struct fimd_driver_data exynos3_fimd_driver_data = {
.timing_base = 0x20000, .timing_base = 0x20000,
.lcdblk_offset = 0x210, .lcdblk_offset = 0x210,
.lcdblk_bypass_shift = 1, .lcdblk_bypass_shift = 1,
.trg_type = I80_HW_TRG,
.has_shadowcon = 1, .has_shadowcon = 1,
.has_vidoutcon = 1, .has_vidoutcon = 1,
.has_trigger_per_te = 1,
}; };
static struct fimd_driver_data exynos4_fimd_driver_data = { static struct fimd_driver_data exynos4_fimd_driver_data = {
...@@ -132,9 +147,11 @@ static struct fimd_driver_data exynos4415_fimd_driver_data = { ...@@ -132,9 +147,11 @@ static struct fimd_driver_data exynos4415_fimd_driver_data = {
.lcdblk_offset = 0x210, .lcdblk_offset = 0x210,
.lcdblk_vt_shift = 10, .lcdblk_vt_shift = 10,
.lcdblk_bypass_shift = 1, .lcdblk_bypass_shift = 1,
.trg_type = I80_HW_TRG,
.has_shadowcon = 1, .has_shadowcon = 1,
.has_vidoutcon = 1, .has_vidoutcon = 1,
.has_vtsel = 1, .has_vtsel = 1,
.has_trigger_per_te = 1,
}; };
static struct fimd_driver_data exynos5_fimd_driver_data = { static struct fimd_driver_data exynos5_fimd_driver_data = {
...@@ -145,6 +162,7 @@ static struct fimd_driver_data exynos5_fimd_driver_data = { ...@@ -145,6 +162,7 @@ static struct fimd_driver_data exynos5_fimd_driver_data = {
.has_shadowcon = 1, .has_shadowcon = 1,
.has_vidoutcon = 1, .has_vidoutcon = 1,
.has_vtsel = 1, .has_vtsel = 1,
.has_dp_clk = 1,
}; };
static struct fimd_driver_data exynos5420_fimd_driver_data = { static struct fimd_driver_data exynos5420_fimd_driver_data = {
...@@ -153,10 +171,14 @@ static struct fimd_driver_data exynos5420_fimd_driver_data = { ...@@ -153,10 +171,14 @@ static struct fimd_driver_data exynos5420_fimd_driver_data = {
.lcdblk_vt_shift = 24, .lcdblk_vt_shift = 24,
.lcdblk_bypass_shift = 15, .lcdblk_bypass_shift = 15,
.lcdblk_mic_bypass_shift = 11, .lcdblk_mic_bypass_shift = 11,
.trg_type = I80_HW_TRG,
.has_shadowcon = 1, .has_shadowcon = 1,
.has_vidoutcon = 1, .has_vidoutcon = 1,
.has_vtsel = 1, .has_vtsel = 1,
.has_mic_bypass = 1, .has_mic_bypass = 1,
.has_dp_clk = 1,
.has_hw_trigger = 1,
.has_trigger_per_te = 1,
}; };
struct fimd_context { struct fimd_context {
...@@ -182,8 +204,9 @@ struct fimd_context { ...@@ -182,8 +204,9 @@ struct fimd_context {
atomic_t win_updated; atomic_t win_updated;
atomic_t triggering; atomic_t triggering;
struct fimd_driver_data *driver_data; const struct fimd_driver_data *driver_data;
struct drm_encoder *encoder; struct drm_encoder *encoder;
struct exynos_drm_clk dp_clk;
}; };
static const struct of_device_id fimd_driver_dt_match[] = { static const struct of_device_id fimd_driver_dt_match[] = {
...@@ -219,15 +242,6 @@ static const uint32_t fimd_formats[] = { ...@@ -219,15 +242,6 @@ static const uint32_t fimd_formats[] = {
DRM_FORMAT_ARGB8888, DRM_FORMAT_ARGB8888,
}; };
static inline struct fimd_driver_data *drm_fimd_get_driver_data(
struct platform_device *pdev)
{
const struct of_device_id *of_id =
of_match_device(fimd_driver_dt_match, &pdev->dev);
return (struct fimd_driver_data *)of_id->data;
}
static int fimd_enable_vblank(struct exynos_drm_crtc *crtc) static int fimd_enable_vblank(struct exynos_drm_crtc *crtc)
{ {
struct fimd_context *ctx = crtc->ctx; struct fimd_context *ctx = crtc->ctx;
...@@ -400,11 +414,31 @@ static u32 fimd_calc_clkdiv(struct fimd_context *ctx, ...@@ -400,11 +414,31 @@ static u32 fimd_calc_clkdiv(struct fimd_context *ctx,
return (clkdiv < 0x100) ? clkdiv : 0xff; return (clkdiv < 0x100) ? clkdiv : 0xff;
} }
static void fimd_setup_trigger(struct fimd_context *ctx)
{
void __iomem *timing_base = ctx->regs + ctx->driver_data->timing_base;
u32 trg_type = ctx->driver_data->trg_type;
u32 val = readl(timing_base + TRIGCON);
val &= ~(TRGMODE_ENABLE);
if (trg_type == I80_HW_TRG) {
if (ctx->driver_data->has_hw_trigger)
val |= HWTRGEN_ENABLE | HWTRGMASK_ENABLE;
if (ctx->driver_data->has_trigger_per_te)
val |= HWTRIGEN_PER_ENABLE;
} else {
val |= TRGMODE_ENABLE;
}
writel(val, timing_base + TRIGCON);
}
static void fimd_commit(struct exynos_drm_crtc *crtc) static void fimd_commit(struct exynos_drm_crtc *crtc)
{ {
struct fimd_context *ctx = crtc->ctx; struct fimd_context *ctx = crtc->ctx;
struct drm_display_mode *mode = &crtc->base.state->adjusted_mode; struct drm_display_mode *mode = &crtc->base.state->adjusted_mode;
struct fimd_driver_data *driver_data = ctx->driver_data; const struct fimd_driver_data *driver_data = ctx->driver_data;
void *timing_base = ctx->regs + driver_data->timing_base; void *timing_base = ctx->regs + driver_data->timing_base;
u32 val, clkdiv; u32 val, clkdiv;
...@@ -495,6 +529,8 @@ static void fimd_commit(struct exynos_drm_crtc *crtc) ...@@ -495,6 +529,8 @@ static void fimd_commit(struct exynos_drm_crtc *crtc)
VIDTCON2_HOZVAL_E(mode->hdisplay - 1); VIDTCON2_HOZVAL_E(mode->hdisplay - 1);
writel(val, ctx->regs + driver_data->timing_base + VIDTCON2); writel(val, ctx->regs + driver_data->timing_base + VIDTCON2);
fimd_setup_trigger(ctx);
/* /*
* fields of register with prefix '_F' would be updated * fields of register with prefix '_F' would be updated
* at vsync(same as dma start) * at vsync(same as dma start)
...@@ -827,7 +863,7 @@ static void fimd_disable(struct exynos_drm_crtc *crtc) ...@@ -827,7 +863,7 @@ static void fimd_disable(struct exynos_drm_crtc *crtc)
static void fimd_trigger(struct device *dev) static void fimd_trigger(struct device *dev)
{ {
struct fimd_context *ctx = dev_get_drvdata(dev); struct fimd_context *ctx = dev_get_drvdata(dev);
struct fimd_driver_data *driver_data = ctx->driver_data; const struct fimd_driver_data *driver_data = ctx->driver_data;
void *timing_base = ctx->regs + driver_data->timing_base; void *timing_base = ctx->regs + driver_data->timing_base;
u32 reg; u32 reg;
...@@ -842,7 +878,7 @@ static void fimd_trigger(struct device *dev) ...@@ -842,7 +878,7 @@ static void fimd_trigger(struct device *dev)
atomic_set(&ctx->triggering, 1); atomic_set(&ctx->triggering, 1);
reg = readl(timing_base + TRIGCON); reg = readl(timing_base + TRIGCON);
reg |= (TRGMODE_I80_RGB_ENABLE_I80 | SWTRGCMD_I80_RGB_ENABLE); reg |= (TRGMODE_ENABLE | SWTRGCMD_ENABLE);
writel(reg, timing_base + TRIGCON); writel(reg, timing_base + TRIGCON);
/* /*
...@@ -856,11 +892,15 @@ static void fimd_trigger(struct device *dev) ...@@ -856,11 +892,15 @@ static void fimd_trigger(struct device *dev)
static void fimd_te_handler(struct exynos_drm_crtc *crtc) static void fimd_te_handler(struct exynos_drm_crtc *crtc)
{ {
struct fimd_context *ctx = crtc->ctx; struct fimd_context *ctx = crtc->ctx;
u32 trg_type = ctx->driver_data->trg_type;
/* Checks the crtc is detached already from encoder */ /* Checks the crtc is detached already from encoder */
if (ctx->pipe < 0 || !ctx->drm_dev) if (ctx->pipe < 0 || !ctx->drm_dev)
return; return;
if (trg_type == I80_HW_TRG)
goto out;
/* /*
* If there is a page flip request, triggers and handles the page flip * If there is a page flip request, triggers and handles the page flip
* event so that current fb can be updated into panel GRAM. * event so that current fb can be updated into panel GRAM.
...@@ -868,6 +908,7 @@ static void fimd_te_handler(struct exynos_drm_crtc *crtc) ...@@ -868,6 +908,7 @@ static void fimd_te_handler(struct exynos_drm_crtc *crtc)
if (atomic_add_unless(&ctx->win_updated, -1, 0)) if (atomic_add_unless(&ctx->win_updated, -1, 0))
fimd_trigger(ctx->dev); fimd_trigger(ctx->dev);
out:
/* Wakes up vsync event queue */ /* Wakes up vsync event queue */
if (atomic_read(&ctx->wait_vsync_event)) { if (atomic_read(&ctx->wait_vsync_event)) {
atomic_set(&ctx->wait_vsync_event, 0); atomic_set(&ctx->wait_vsync_event, 0);
...@@ -878,21 +919,12 @@ static void fimd_te_handler(struct exynos_drm_crtc *crtc) ...@@ -878,21 +919,12 @@ static void fimd_te_handler(struct exynos_drm_crtc *crtc)
drm_crtc_handle_vblank(&ctx->crtc->base); drm_crtc_handle_vblank(&ctx->crtc->base);
} }
static void fimd_dp_clock_enable(struct exynos_drm_crtc *crtc, bool enable) static void fimd_dp_clock_enable(struct exynos_drm_clk *clk, bool enable)
{ {
struct fimd_context *ctx = crtc->ctx; struct fimd_context *ctx = container_of(clk, struct fimd_context,
u32 val; dp_clk);
u32 val = enable ? DP_MIE_CLK_DP_ENABLE : DP_MIE_CLK_DISABLE;
/*
* Only Exynos 5250, 5260, 5410 and 542x requires enabling DP/MIE
* clock. On these SoCs the bootloader may enable it but any
* power domain off/on will reset it to disable state.
*/
if (ctx->driver_data != &exynos5_fimd_driver_data ||
ctx->driver_data != &exynos5420_fimd_driver_data)
return;
val = enable ? DP_MIE_CLK_DP_ENABLE : DP_MIE_CLK_DISABLE;
writel(val, ctx->regs + DP_MIE_CLKCON); writel(val, ctx->regs + DP_MIE_CLKCON);
} }
...@@ -902,13 +934,11 @@ static const struct exynos_drm_crtc_ops fimd_crtc_ops = { ...@@ -902,13 +934,11 @@ static const struct exynos_drm_crtc_ops fimd_crtc_ops = {
.commit = fimd_commit, .commit = fimd_commit,
.enable_vblank = fimd_enable_vblank, .enable_vblank = fimd_enable_vblank,
.disable_vblank = fimd_disable_vblank, .disable_vblank = fimd_disable_vblank,
.wait_for_vblank = fimd_wait_for_vblank,
.atomic_begin = fimd_atomic_begin, .atomic_begin = fimd_atomic_begin,
.update_plane = fimd_update_plane, .update_plane = fimd_update_plane,
.disable_plane = fimd_disable_plane, .disable_plane = fimd_disable_plane,
.atomic_flush = fimd_atomic_flush, .atomic_flush = fimd_atomic_flush,
.te_handler = fimd_te_handler, .te_handler = fimd_te_handler,
.clock_enable = fimd_dp_clock_enable,
}; };
static irqreturn_t fimd_irq_handler(int irq, void *dev_id) static irqreturn_t fimd_irq_handler(int irq, void *dev_id)
...@@ -987,6 +1017,11 @@ static int fimd_bind(struct device *dev, struct device *master, void *data) ...@@ -987,6 +1017,11 @@ static int fimd_bind(struct device *dev, struct device *master, void *data)
if (IS_ERR(ctx->crtc)) if (IS_ERR(ctx->crtc))
return PTR_ERR(ctx->crtc); return PTR_ERR(ctx->crtc);
if (ctx->driver_data->has_dp_clk) {
ctx->dp_clk.enable = fimd_dp_clock_enable;
ctx->crtc->pipe_clk = &ctx->dp_clk;
}
if (ctx->encoder) if (ctx->encoder)
exynos_dpi_bind(drm_dev, ctx->encoder); exynos_dpi_bind(drm_dev, ctx->encoder);
...@@ -1035,7 +1070,7 @@ static int fimd_probe(struct platform_device *pdev) ...@@ -1035,7 +1070,7 @@ static int fimd_probe(struct platform_device *pdev)
ctx->dev = dev; ctx->dev = dev;
ctx->suspended = true; ctx->suspended = true;
ctx->driver_data = drm_fimd_get_driver_data(pdev); ctx->driver_data = of_device_get_match_data(dev);
if (of_property_read_bool(dev->of_node, "samsung,invert-vden")) if (of_property_read_bool(dev->of_node, "samsung,invert-vden"))
ctx->vidcon1 |= VIDCON1_INV_VDEN; ctx->vidcon1 |= VIDCON1_INV_VDEN;
......
...@@ -129,7 +129,7 @@ static void mic_set_path(struct exynos_mic *mic, bool enable) ...@@ -129,7 +129,7 @@ static void mic_set_path(struct exynos_mic *mic, bool enable)
} else } else
val &= ~(MIC0_RGB_MUX | MIC0_I80_MUX | MIC0_ON_MUX); val &= ~(MIC0_RGB_MUX | MIC0_I80_MUX | MIC0_ON_MUX);
regmap_write(mic->sysreg, DSD_CFG_MUX, val); ret = regmap_write(mic->sysreg, DSD_CFG_MUX, val);
if (ret) if (ret)
DRM_ERROR("mic: Failed to read system register\n"); DRM_ERROR("mic: Failed to read system register\n");
} }
...@@ -457,6 +457,7 @@ static int exynos_mic_probe(struct platform_device *pdev) ...@@ -457,6 +457,7 @@ static int exynos_mic_probe(struct platform_device *pdev)
"samsung,disp-syscon"); "samsung,disp-syscon");
if (IS_ERR(mic->sysreg)) { if (IS_ERR(mic->sysreg)) {
DRM_ERROR("mic: Failed to get system register.\n"); DRM_ERROR("mic: Failed to get system register.\n");
ret = PTR_ERR(mic->sysreg);
goto err; goto err;
} }
......
...@@ -11,9 +11,10 @@ ...@@ -11,9 +11,10 @@
#include <drm/drmP.h> #include <drm/drmP.h>
#include <drm/exynos_drm.h> #include <drm/drm_atomic.h>
#include <drm/drm_plane_helper.h>
#include <drm/drm_atomic_helper.h> #include <drm/drm_atomic_helper.h>
#include <drm/drm_plane_helper.h>
#include <drm/exynos_drm.h>
#include "exynos_drm_drv.h" #include "exynos_drm_drv.h"
#include "exynos_drm_crtc.h" #include "exynos_drm_crtc.h"
#include "exynos_drm_fb.h" #include "exynos_drm_fb.h"
...@@ -57,11 +58,12 @@ static int exynos_plane_get_size(int start, unsigned length, unsigned last) ...@@ -57,11 +58,12 @@ static int exynos_plane_get_size(int start, unsigned length, unsigned last)
} }
static void exynos_plane_mode_set(struct exynos_drm_plane_state *exynos_state) static void exynos_plane_mode_set(struct exynos_drm_plane_state *exynos_state)
{ {
struct drm_plane_state *state = &exynos_state->base; struct drm_plane_state *state = &exynos_state->base;
struct drm_crtc *crtc = exynos_state->base.crtc; struct drm_crtc *crtc = state->crtc;
struct drm_display_mode *mode = &crtc->state->adjusted_mode; struct drm_crtc_state *crtc_state =
drm_atomic_get_existing_crtc_state(state->state, crtc);
struct drm_display_mode *mode = &crtc_state->adjusted_mode;
int crtc_x, crtc_y; int crtc_x, crtc_y;
unsigned int crtc_w, crtc_h; unsigned int crtc_w, crtc_h;
unsigned int src_x, src_y; unsigned int src_x, src_y;
......
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
#include <linux/io.h> #include <linux/io.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/clk.h> #include <linux/clk.h>
#include <linux/of_device.h>
#include <linux/pm_runtime.h> #include <linux/pm_runtime.h>
#include <drm/drmP.h> #include <drm/drmP.h>
...@@ -696,7 +697,6 @@ static int rotator_probe(struct platform_device *pdev) ...@@ -696,7 +697,6 @@ static int rotator_probe(struct platform_device *pdev)
struct device *dev = &pdev->dev; struct device *dev = &pdev->dev;
struct rot_context *rot; struct rot_context *rot;
struct exynos_drm_ippdrv *ippdrv; struct exynos_drm_ippdrv *ippdrv;
const struct of_device_id *match;
int ret; int ret;
if (!dev->of_node) { if (!dev->of_node) {
...@@ -708,13 +708,8 @@ static int rotator_probe(struct platform_device *pdev) ...@@ -708,13 +708,8 @@ static int rotator_probe(struct platform_device *pdev)
if (!rot) if (!rot)
return -ENOMEM; return -ENOMEM;
match = of_match_node(exynos_rotator_match, dev->of_node); rot->limit_tbl = (struct rot_limit_table *)
if (!match) { of_device_get_match_data(dev);
dev_err(dev, "failed to match node\n");
return -ENODEV;
}
rot->limit_tbl = (struct rot_limit_table *)match->data;
rot->regs_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); rot->regs_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
rot->regs = devm_ioremap_resource(dev, rot->regs_res); rot->regs = devm_ioremap_resource(dev, rot->regs_res);
if (IS_ERR(rot->regs)) if (IS_ERR(rot->regs))
......
...@@ -7,9 +7,9 @@ ...@@ -7,9 +7,9 @@
* *
* Based on drivers/media/video/s5p-tv/hdmi_drv.c * Based on drivers/media/video/s5p-tv/hdmi_drv.c
* *
* This program is free software; you can redistribute it and/or modify it * This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the * under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your * Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. * option) any later version.
* *
*/ */
...@@ -49,14 +49,16 @@ ...@@ -49,14 +49,16 @@
/* AVI header and aspect ratio */ /* AVI header and aspect ratio */
#define HDMI_AVI_VERSION 0x02 #define HDMI_AVI_VERSION 0x02
#define HDMI_AVI_LENGTH 0x0D #define HDMI_AVI_LENGTH 0x0d
/* AUI header info */ /* AUI header info */
#define HDMI_AUI_VERSION 0x01 #define HDMI_AUI_VERSION 0x01
#define HDMI_AUI_LENGTH 0x0A #define HDMI_AUI_LENGTH 0x0a
#define AVI_SAME_AS_PIC_ASPECT_RATIO 0x8
#define AVI_4_3_CENTER_RATIO 0x9 /* AVI active format aspect ratio */
#define AVI_16_9_CENTER_RATIO 0xa #define AVI_SAME_AS_PIC_ASPECT_RATIO 0x08
#define AVI_4_3_CENTER_RATIO 0x09
#define AVI_16_9_CENTER_RATIO 0x0a
enum hdmi_type { enum hdmi_type {
HDMI_TYPE13, HDMI_TYPE13,
...@@ -90,11 +92,34 @@ static const char * const supply[] = { ...@@ -90,11 +92,34 @@ static const char * const supply[] = {
"vdd_pll", "vdd_pll",
}; };
struct hdmiphy_config {
int pixel_clock;
u8 conf[32];
};
struct hdmiphy_configs {
int count;
const struct hdmiphy_config *data;
};
struct string_array_spec {
int count;
const char * const *data;
};
#define INIT_ARRAY_SPEC(a) { .count = ARRAY_SIZE(a), .data = a }
struct hdmi_driver_data { struct hdmi_driver_data {
unsigned int type; unsigned int type;
const struct hdmiphy_config *phy_confs;
unsigned int phy_conf_count;
unsigned int is_apb_phy:1; unsigned int is_apb_phy:1;
unsigned int has_sysreg:1;
struct hdmiphy_configs phy_confs;
struct string_array_spec clk_gates;
/*
* Array of triplets (p_off, p_on, clock), where p_off and p_on are
* required parents of clock when HDMI-PHY is respectively off or on.
*/
struct string_array_spec clk_muxes;
}; };
struct hdmi_context { struct hdmi_context {
...@@ -116,11 +141,9 @@ struct hdmi_context { ...@@ -116,11 +141,9 @@ struct hdmi_context {
struct gpio_desc *hpd_gpio; struct gpio_desc *hpd_gpio;
int irq; int irq;
struct regmap *pmureg; struct regmap *pmureg;
struct clk *hdmi; struct regmap *sysreg;
struct clk *sclk_hdmi; struct clk **clk_gates;
struct clk *sclk_pixel; struct clk **clk_muxes;
struct clk *sclk_hdmiphy;
struct clk *mout_hdmi;
struct regulator_bulk_data regul_bulk[ARRAY_SIZE(supply)]; struct regulator_bulk_data regul_bulk[ARRAY_SIZE(supply)];
struct regulator *reg_hdmi_en; struct regulator *reg_hdmi_en;
}; };
...@@ -135,12 +158,6 @@ static inline struct hdmi_context *connector_to_hdmi(struct drm_connector *c) ...@@ -135,12 +158,6 @@ static inline struct hdmi_context *connector_to_hdmi(struct drm_connector *c)
return container_of(c, struct hdmi_context, connector); return container_of(c, struct hdmi_context, connector);
} }
struct hdmiphy_config {
int pixel_clock;
u8 conf[32];
};
/* list of phy config settings */
static const struct hdmiphy_config hdmiphy_v13_configs[] = { static const struct hdmiphy_config hdmiphy_v13_configs[] = {
{ {
.pixel_clock = 27000000, .pixel_clock = 27000000,
...@@ -501,25 +518,136 @@ static const struct hdmiphy_config hdmiphy_5420_configs[] = { ...@@ -501,25 +518,136 @@ static const struct hdmiphy_config hdmiphy_5420_configs[] = {
}, },
}; };
static struct hdmi_driver_data exynos5420_hdmi_driver_data = { static const struct hdmiphy_config hdmiphy_5433_configs[] = {
{
.pixel_clock = 27000000,
.conf = {
0x01, 0x51, 0x22, 0x51, 0x08, 0xfc, 0x88, 0x46,
0x72, 0x50, 0x24, 0x0c, 0x24, 0x0f, 0x7c, 0xa5,
0xd4, 0x2b, 0x87, 0x00, 0x00, 0x04, 0x00, 0x30,
0x08, 0x10, 0x01, 0x01, 0x48, 0x40, 0x00, 0x40,
},
},
{
.pixel_clock = 27027000,
.conf = {
0x01, 0x51, 0x2d, 0x72, 0x64, 0x09, 0x88, 0xc3,
0x71, 0x50, 0x24, 0x14, 0x24, 0x0f, 0x7c, 0xa5,
0xd4, 0x2b, 0x87, 0x00, 0x00, 0x04, 0x00, 0x30,
0x28, 0x10, 0x01, 0x01, 0x48, 0x40, 0x00, 0x40,
},
},
{
.pixel_clock = 40000000,
.conf = {
0x01, 0x51, 0x32, 0x55, 0x01, 0x00, 0x88, 0x02,
0x4d, 0x50, 0x44, 0x8C, 0x27, 0x00, 0x7C, 0xAC,
0xD6, 0x2B, 0x67, 0x00, 0x00, 0x04, 0x00, 0x30,
0x08, 0x10, 0x01, 0x01, 0x48, 0x40, 0x00, 0x40,
},
},
{
.pixel_clock = 50000000,
.conf = {
0x01, 0x51, 0x34, 0x40, 0x64, 0x09, 0x88, 0xc3,
0x3d, 0x50, 0x44, 0x8C, 0x27, 0x00, 0x7C, 0xAC,
0xD6, 0x2B, 0x67, 0x00, 0x00, 0x04, 0x00, 0x30,
0x08, 0x10, 0x01, 0x01, 0x48, 0x40, 0x00, 0x40,
},
},
{
.pixel_clock = 65000000,
.conf = {
0x01, 0x51, 0x36, 0x31, 0x40, 0x10, 0x04, 0xc6,
0x2e, 0xe8, 0x44, 0x8C, 0x27, 0x00, 0x7C, 0xAC,
0xD6, 0x2B, 0x67, 0x00, 0x00, 0x04, 0x00, 0x30,
0x08, 0x10, 0x01, 0x01, 0x48, 0x40, 0x00, 0x40,
},
},
{
.pixel_clock = 74176000,
.conf = {
0x01, 0x51, 0x3E, 0x35, 0x5B, 0xDE, 0x88, 0x42,
0x53, 0x51, 0x44, 0x8C, 0x27, 0x00, 0x7C, 0xAC,
0xD6, 0x2B, 0x67, 0x00, 0x00, 0x04, 0x00, 0x30,
0x08, 0x10, 0x01, 0x01, 0x48, 0x40, 0x00, 0x40,
},
},
{
.pixel_clock = 74250000,
.conf = {
0x01, 0x51, 0x3E, 0x35, 0x40, 0xF0, 0x88, 0xC2,
0x52, 0x51, 0x44, 0x8C, 0x27, 0x00, 0x7C, 0xAC,
0xD6, 0x2B, 0x67, 0x00, 0x00, 0x04, 0x00, 0x30,
0x08, 0x10, 0x01, 0x01, 0x48, 0x40, 0x00, 0x40,
},
},
{
.pixel_clock = 108000000,
.conf = {
0x01, 0x51, 0x2d, 0x15, 0x01, 0x00, 0x88, 0x02,
0x72, 0x52, 0x44, 0x8C, 0x27, 0x00, 0x7C, 0xAC,
0xD6, 0x2B, 0x67, 0x00, 0x00, 0x04, 0x00, 0x30,
0x08, 0x10, 0x01, 0x01, 0x48, 0x40, 0x00, 0x40,
},
},
{
.pixel_clock = 148500000,
.conf = {
0x01, 0x51, 0x1f, 0x00, 0x40, 0xf8, 0x88, 0xc1,
0x52, 0x52, 0x24, 0x0c, 0x24, 0x0f, 0x7c, 0xa5,
0xd4, 0x2b, 0x87, 0x00, 0x00, 0x04, 0x00, 0x30,
0x08, 0x10, 0x01, 0x01, 0x48, 0x4a, 0x00, 0x40,
},
},
};
static const char * const hdmi_clk_gates4[] = {
"hdmi", "sclk_hdmi"
};
static const char * const hdmi_clk_muxes4[] = {
"sclk_pixel", "sclk_hdmiphy", "mout_hdmi"
};
static const char * const hdmi_clk_gates5433[] = {
"hdmi_pclk", "hdmi_i_pclk", "i_tmds_clk", "i_pixel_clk", "i_spdif_clk"
};
static const char * const hdmi_clk_muxes5433[] = {
"oscclk", "tmds_clko", "tmds_clko_user",
"oscclk", "pixel_clko", "pixel_clko_user"
};
static const struct hdmi_driver_data exynos4210_hdmi_driver_data = {
.type = HDMI_TYPE13,
.phy_confs = INIT_ARRAY_SPEC(hdmiphy_v13_configs),
.clk_gates = INIT_ARRAY_SPEC(hdmi_clk_gates4),
.clk_muxes = INIT_ARRAY_SPEC(hdmi_clk_muxes4),
};
static const struct hdmi_driver_data exynos4212_hdmi_driver_data = {
.type = HDMI_TYPE14, .type = HDMI_TYPE14,
.phy_confs = hdmiphy_5420_configs, .phy_confs = INIT_ARRAY_SPEC(hdmiphy_v14_configs),
.phy_conf_count = ARRAY_SIZE(hdmiphy_5420_configs), .clk_gates = INIT_ARRAY_SPEC(hdmi_clk_gates4),
.is_apb_phy = 1, .clk_muxes = INIT_ARRAY_SPEC(hdmi_clk_muxes4),
}; };
static struct hdmi_driver_data exynos4212_hdmi_driver_data = { static const struct hdmi_driver_data exynos5420_hdmi_driver_data = {
.type = HDMI_TYPE14, .type = HDMI_TYPE14,
.phy_confs = hdmiphy_v14_configs, .is_apb_phy = 1,
.phy_conf_count = ARRAY_SIZE(hdmiphy_v14_configs), .phy_confs = INIT_ARRAY_SPEC(hdmiphy_5420_configs),
.is_apb_phy = 0, .clk_gates = INIT_ARRAY_SPEC(hdmi_clk_gates4),
.clk_muxes = INIT_ARRAY_SPEC(hdmi_clk_muxes4),
}; };
static struct hdmi_driver_data exynos4210_hdmi_driver_data = { static const struct hdmi_driver_data exynos5433_hdmi_driver_data = {
.type = HDMI_TYPE13, .type = HDMI_TYPE14,
.phy_confs = hdmiphy_v13_configs, .is_apb_phy = 1,
.phy_conf_count = ARRAY_SIZE(hdmiphy_v13_configs), .has_sysreg = 1,
.is_apb_phy = 0, .phy_confs = INIT_ARRAY_SPEC(hdmiphy_5433_configs),
.clk_gates = INIT_ARRAY_SPEC(hdmi_clk_gates5433),
.clk_muxes = INIT_ARRAY_SPEC(hdmi_clk_muxes5433),
}; };
static inline u32 hdmi_map_reg(struct hdmi_context *hdata, u32 reg_id) static inline u32 hdmi_map_reg(struct hdmi_context *hdata, u32 reg_id)
...@@ -585,266 +713,52 @@ static int hdmiphy_reg_write_buf(struct hdmi_context *hdata, ...@@ -585,266 +713,52 @@ static int hdmiphy_reg_write_buf(struct hdmi_context *hdata,
} }
} }
static void hdmi_v13_regs_dump(struct hdmi_context *hdata, char *prefix) static int hdmi_clk_enable_gates(struct hdmi_context *hdata)
{ {
#define DUMPREG(reg_id) \ int i, ret;
DRM_DEBUG_KMS("%s:" #reg_id " = %08x\n", prefix, \
readl(hdata->regs + reg_id)) for (i = 0; i < hdata->drv_data->clk_gates.count; ++i) {
DRM_DEBUG_KMS("%s: ---- CONTROL REGISTERS ----\n", prefix); ret = clk_prepare_enable(hdata->clk_gates[i]);
DUMPREG(HDMI_INTC_FLAG); if (!ret)
DUMPREG(HDMI_INTC_CON); continue;
DUMPREG(HDMI_HPD_STATUS);
DUMPREG(HDMI_V13_PHY_RSTOUT); dev_err(hdata->dev, "Cannot enable clock '%s', %d\n",
DUMPREG(HDMI_V13_PHY_VPLL); hdata->drv_data->clk_gates.data[i], ret);
DUMPREG(HDMI_V13_PHY_CMU); while (i--)
DUMPREG(HDMI_V13_CORE_RSTOUT); clk_disable_unprepare(hdata->clk_gates[i]);
return ret;
DRM_DEBUG_KMS("%s: ---- CORE REGISTERS ----\n", prefix); }
DUMPREG(HDMI_CON_0);
DUMPREG(HDMI_CON_1); return 0;
DUMPREG(HDMI_CON_2);
DUMPREG(HDMI_SYS_STATUS);
DUMPREG(HDMI_V13_PHY_STATUS);
DUMPREG(HDMI_STATUS_EN);
DUMPREG(HDMI_HPD);
DUMPREG(HDMI_MODE_SEL);
DUMPREG(HDMI_V13_HPD_GEN);
DUMPREG(HDMI_V13_DC_CONTROL);
DUMPREG(HDMI_V13_VIDEO_PATTERN_GEN);
DRM_DEBUG_KMS("%s: ---- CORE SYNC REGISTERS ----\n", prefix);
DUMPREG(HDMI_H_BLANK_0);
DUMPREG(HDMI_H_BLANK_1);
DUMPREG(HDMI_V13_V_BLANK_0);
DUMPREG(HDMI_V13_V_BLANK_1);
DUMPREG(HDMI_V13_V_BLANK_2);
DUMPREG(HDMI_V13_H_V_LINE_0);
DUMPREG(HDMI_V13_H_V_LINE_1);
DUMPREG(HDMI_V13_H_V_LINE_2);
DUMPREG(HDMI_VSYNC_POL);
DUMPREG(HDMI_INT_PRO_MODE);
DUMPREG(HDMI_V13_V_BLANK_F_0);
DUMPREG(HDMI_V13_V_BLANK_F_1);
DUMPREG(HDMI_V13_V_BLANK_F_2);
DUMPREG(HDMI_V13_H_SYNC_GEN_0);
DUMPREG(HDMI_V13_H_SYNC_GEN_1);
DUMPREG(HDMI_V13_H_SYNC_GEN_2);
DUMPREG(HDMI_V13_V_SYNC_GEN_1_0);
DUMPREG(HDMI_V13_V_SYNC_GEN_1_1);
DUMPREG(HDMI_V13_V_SYNC_GEN_1_2);
DUMPREG(HDMI_V13_V_SYNC_GEN_2_0);
DUMPREG(HDMI_V13_V_SYNC_GEN_2_1);
DUMPREG(HDMI_V13_V_SYNC_GEN_2_2);
DUMPREG(HDMI_V13_V_SYNC_GEN_3_0);
DUMPREG(HDMI_V13_V_SYNC_GEN_3_1);
DUMPREG(HDMI_V13_V_SYNC_GEN_3_2);
DRM_DEBUG_KMS("%s: ---- TG REGISTERS ----\n", prefix);
DUMPREG(HDMI_TG_CMD);
DUMPREG(HDMI_TG_H_FSZ_L);
DUMPREG(HDMI_TG_H_FSZ_H);
DUMPREG(HDMI_TG_HACT_ST_L);
DUMPREG(HDMI_TG_HACT_ST_H);
DUMPREG(HDMI_TG_HACT_SZ_L);
DUMPREG(HDMI_TG_HACT_SZ_H);
DUMPREG(HDMI_TG_V_FSZ_L);
DUMPREG(HDMI_TG_V_FSZ_H);
DUMPREG(HDMI_TG_VSYNC_L);
DUMPREG(HDMI_TG_VSYNC_H);
DUMPREG(HDMI_TG_VSYNC2_L);
DUMPREG(HDMI_TG_VSYNC2_H);
DUMPREG(HDMI_TG_VACT_ST_L);
DUMPREG(HDMI_TG_VACT_ST_H);
DUMPREG(HDMI_TG_VACT_SZ_L);
DUMPREG(HDMI_TG_VACT_SZ_H);
DUMPREG(HDMI_TG_FIELD_CHG_L);
DUMPREG(HDMI_TG_FIELD_CHG_H);
DUMPREG(HDMI_TG_VACT_ST2_L);
DUMPREG(HDMI_TG_VACT_ST2_H);
DUMPREG(HDMI_TG_VSYNC_TOP_HDMI_L);
DUMPREG(HDMI_TG_VSYNC_TOP_HDMI_H);
DUMPREG(HDMI_TG_VSYNC_BOT_HDMI_L);
DUMPREG(HDMI_TG_VSYNC_BOT_HDMI_H);
DUMPREG(HDMI_TG_FIELD_TOP_HDMI_L);
DUMPREG(HDMI_TG_FIELD_TOP_HDMI_H);
DUMPREG(HDMI_TG_FIELD_BOT_HDMI_L);
DUMPREG(HDMI_TG_FIELD_BOT_HDMI_H);
#undef DUMPREG
} }
static void hdmi_v14_regs_dump(struct hdmi_context *hdata, char *prefix) static void hdmi_clk_disable_gates(struct hdmi_context *hdata)
{ {
int i; int i = hdata->drv_data->clk_gates.count;
#define DUMPREG(reg_id) \ while (i--)
DRM_DEBUG_KMS("%s:" #reg_id " = %08x\n", prefix, \ clk_disable_unprepare(hdata->clk_gates[i]);
readl(hdata->regs + reg_id))
DRM_DEBUG_KMS("%s: ---- CONTROL REGISTERS ----\n", prefix);
DUMPREG(HDMI_INTC_CON);
DUMPREG(HDMI_INTC_FLAG);
DUMPREG(HDMI_HPD_STATUS);
DUMPREG(HDMI_INTC_CON_1);
DUMPREG(HDMI_INTC_FLAG_1);
DUMPREG(HDMI_PHY_STATUS_0);
DUMPREG(HDMI_PHY_STATUS_PLL);
DUMPREG(HDMI_PHY_CON_0);
DUMPREG(HDMI_V14_PHY_RSTOUT);
DUMPREG(HDMI_PHY_VPLL);
DUMPREG(HDMI_PHY_CMU);
DUMPREG(HDMI_CORE_RSTOUT);
DRM_DEBUG_KMS("%s: ---- CORE REGISTERS ----\n", prefix);
DUMPREG(HDMI_CON_0);
DUMPREG(HDMI_CON_1);
DUMPREG(HDMI_CON_2);
DUMPREG(HDMI_SYS_STATUS);
DUMPREG(HDMI_PHY_STATUS_0);
DUMPREG(HDMI_STATUS_EN);
DUMPREG(HDMI_HPD);
DUMPREG(HDMI_MODE_SEL);
DUMPREG(HDMI_ENC_EN);
DUMPREG(HDMI_DC_CONTROL);
DUMPREG(HDMI_VIDEO_PATTERN_GEN);
DRM_DEBUG_KMS("%s: ---- CORE SYNC REGISTERS ----\n", prefix);
DUMPREG(HDMI_H_BLANK_0);
DUMPREG(HDMI_H_BLANK_1);
DUMPREG(HDMI_V2_BLANK_0);
DUMPREG(HDMI_V2_BLANK_1);
DUMPREG(HDMI_V1_BLANK_0);
DUMPREG(HDMI_V1_BLANK_1);
DUMPREG(HDMI_V_LINE_0);
DUMPREG(HDMI_V_LINE_1);
DUMPREG(HDMI_H_LINE_0);
DUMPREG(HDMI_H_LINE_1);
DUMPREG(HDMI_HSYNC_POL);
DUMPREG(HDMI_VSYNC_POL);
DUMPREG(HDMI_INT_PRO_MODE);
DUMPREG(HDMI_V_BLANK_F0_0);
DUMPREG(HDMI_V_BLANK_F0_1);
DUMPREG(HDMI_V_BLANK_F1_0);
DUMPREG(HDMI_V_BLANK_F1_1);
DUMPREG(HDMI_H_SYNC_START_0);
DUMPREG(HDMI_H_SYNC_START_1);
DUMPREG(HDMI_H_SYNC_END_0);
DUMPREG(HDMI_H_SYNC_END_1);
DUMPREG(HDMI_V_SYNC_LINE_BEF_2_0);
DUMPREG(HDMI_V_SYNC_LINE_BEF_2_1);
DUMPREG(HDMI_V_SYNC_LINE_BEF_1_0);
DUMPREG(HDMI_V_SYNC_LINE_BEF_1_1);
DUMPREG(HDMI_V_SYNC_LINE_AFT_2_0);
DUMPREG(HDMI_V_SYNC_LINE_AFT_2_1);
DUMPREG(HDMI_V_SYNC_LINE_AFT_1_0);
DUMPREG(HDMI_V_SYNC_LINE_AFT_1_1);
DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_2_0);
DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_2_1);
DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_1_0);
DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_1_1);
DUMPREG(HDMI_V_BLANK_F2_0);
DUMPREG(HDMI_V_BLANK_F2_1);
DUMPREG(HDMI_V_BLANK_F3_0);
DUMPREG(HDMI_V_BLANK_F3_1);
DUMPREG(HDMI_V_BLANK_F4_0);
DUMPREG(HDMI_V_BLANK_F4_1);
DUMPREG(HDMI_V_BLANK_F5_0);
DUMPREG(HDMI_V_BLANK_F5_1);
DUMPREG(HDMI_V_SYNC_LINE_AFT_3_0);
DUMPREG(HDMI_V_SYNC_LINE_AFT_3_1);
DUMPREG(HDMI_V_SYNC_LINE_AFT_4_0);
DUMPREG(HDMI_V_SYNC_LINE_AFT_4_1);
DUMPREG(HDMI_V_SYNC_LINE_AFT_5_0);
DUMPREG(HDMI_V_SYNC_LINE_AFT_5_1);
DUMPREG(HDMI_V_SYNC_LINE_AFT_6_0);
DUMPREG(HDMI_V_SYNC_LINE_AFT_6_1);
DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_3_0);
DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_3_1);
DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_4_0);
DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_4_1);
DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_5_0);
DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_5_1);
DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_6_0);
DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_6_1);
DUMPREG(HDMI_VACT_SPACE_1_0);
DUMPREG(HDMI_VACT_SPACE_1_1);
DUMPREG(HDMI_VACT_SPACE_2_0);
DUMPREG(HDMI_VACT_SPACE_2_1);
DUMPREG(HDMI_VACT_SPACE_3_0);
DUMPREG(HDMI_VACT_SPACE_3_1);
DUMPREG(HDMI_VACT_SPACE_4_0);
DUMPREG(HDMI_VACT_SPACE_4_1);
DUMPREG(HDMI_VACT_SPACE_5_0);
DUMPREG(HDMI_VACT_SPACE_5_1);
DUMPREG(HDMI_VACT_SPACE_6_0);
DUMPREG(HDMI_VACT_SPACE_6_1);
DRM_DEBUG_KMS("%s: ---- TG REGISTERS ----\n", prefix);
DUMPREG(HDMI_TG_CMD);
DUMPREG(HDMI_TG_H_FSZ_L);
DUMPREG(HDMI_TG_H_FSZ_H);
DUMPREG(HDMI_TG_HACT_ST_L);
DUMPREG(HDMI_TG_HACT_ST_H);
DUMPREG(HDMI_TG_HACT_SZ_L);
DUMPREG(HDMI_TG_HACT_SZ_H);
DUMPREG(HDMI_TG_V_FSZ_L);
DUMPREG(HDMI_TG_V_FSZ_H);
DUMPREG(HDMI_TG_VSYNC_L);
DUMPREG(HDMI_TG_VSYNC_H);
DUMPREG(HDMI_TG_VSYNC2_L);
DUMPREG(HDMI_TG_VSYNC2_H);
DUMPREG(HDMI_TG_VACT_ST_L);
DUMPREG(HDMI_TG_VACT_ST_H);
DUMPREG(HDMI_TG_VACT_SZ_L);
DUMPREG(HDMI_TG_VACT_SZ_H);
DUMPREG(HDMI_TG_FIELD_CHG_L);
DUMPREG(HDMI_TG_FIELD_CHG_H);
DUMPREG(HDMI_TG_VACT_ST2_L);
DUMPREG(HDMI_TG_VACT_ST2_H);
DUMPREG(HDMI_TG_VACT_ST3_L);
DUMPREG(HDMI_TG_VACT_ST3_H);
DUMPREG(HDMI_TG_VACT_ST4_L);
DUMPREG(HDMI_TG_VACT_ST4_H);
DUMPREG(HDMI_TG_VSYNC_TOP_HDMI_L);
DUMPREG(HDMI_TG_VSYNC_TOP_HDMI_H);
DUMPREG(HDMI_TG_VSYNC_BOT_HDMI_L);
DUMPREG(HDMI_TG_VSYNC_BOT_HDMI_H);
DUMPREG(HDMI_TG_FIELD_TOP_HDMI_L);
DUMPREG(HDMI_TG_FIELD_TOP_HDMI_H);
DUMPREG(HDMI_TG_FIELD_BOT_HDMI_L);
DUMPREG(HDMI_TG_FIELD_BOT_HDMI_H);
DUMPREG(HDMI_TG_3D);
DRM_DEBUG_KMS("%s: ---- PACKET REGISTERS ----\n", prefix);
DUMPREG(HDMI_AVI_CON);
DUMPREG(HDMI_AVI_HEADER0);
DUMPREG(HDMI_AVI_HEADER1);
DUMPREG(HDMI_AVI_HEADER2);
DUMPREG(HDMI_AVI_CHECK_SUM);
DUMPREG(HDMI_VSI_CON);
DUMPREG(HDMI_VSI_HEADER0);
DUMPREG(HDMI_VSI_HEADER1);
DUMPREG(HDMI_VSI_HEADER2);
for (i = 0; i < 7; ++i)
DUMPREG(HDMI_VSI_DATA(i));
#undef DUMPREG
} }
static void hdmi_regs_dump(struct hdmi_context *hdata, char *prefix) static int hdmi_clk_set_parents(struct hdmi_context *hdata, bool to_phy)
{ {
if (hdata->drv_data->type == HDMI_TYPE13) struct device *dev = hdata->dev;
hdmi_v13_regs_dump(hdata, prefix); int ret = 0;
else int i;
hdmi_v14_regs_dump(hdata, prefix);
for (i = 0; i < hdata->drv_data->clk_muxes.count; i += 3) {
struct clk **c = &hdata->clk_muxes[i];
ret = clk_set_parent(c[2], c[to_phy]);
if (!ret)
continue;
dev_err(dev, "Cannot set clock parent of '%s' to '%s', %d\n",
hdata->drv_data->clk_muxes.data[i + 2],
hdata->drv_data->clk_muxes.data[i + to_phy], ret);
}
return ret;
} }
static u8 hdmi_chksum(struct hdmi_context *hdata, static u8 hdmi_chksum(struct hdmi_context *hdata,
...@@ -993,10 +907,11 @@ static int hdmi_get_modes(struct drm_connector *connector) ...@@ -993,10 +907,11 @@ static int hdmi_get_modes(struct drm_connector *connector)
static int hdmi_find_phy_conf(struct hdmi_context *hdata, u32 pixel_clock) static int hdmi_find_phy_conf(struct hdmi_context *hdata, u32 pixel_clock)
{ {
const struct hdmiphy_configs *confs = &hdata->drv_data->phy_confs;
int i; int i;
for (i = 0; i < hdata->drv_data->phy_conf_count; i++) for (i = 0; i < confs->count; i++)
if (hdata->drv_data->phy_confs[i].pixel_clock == pixel_clock) if (confs->data[i].pixel_clock == pixel_clock)
return i; return i;
DRM_DEBUG_KMS("Could not find phy config for %d\n", pixel_clock); DRM_DEBUG_KMS("Could not find phy config for %d\n", pixel_clock);
...@@ -1078,13 +993,11 @@ static bool hdmi_mode_fixup(struct drm_encoder *encoder, ...@@ -1078,13 +993,11 @@ static bool hdmi_mode_fixup(struct drm_encoder *encoder,
mode_ok = hdmi_mode_valid(connector, adjusted_mode); mode_ok = hdmi_mode_valid(connector, adjusted_mode);
/* just return if user desired mode exists. */
if (mode_ok == MODE_OK) if (mode_ok == MODE_OK)
return true; return true;
/* /*
* otherwise, find the most suitable mode among modes and change it * Find the most suitable mode and copy it to adjusted_mode.
* to adjusted_mode.
*/ */
list_for_each_entry(m, &connector->modes, head) { list_for_each_entry(m, &connector->modes, head) {
mode_ok = hdmi_mode_valid(connector, m); mode_ok = hdmi_mode_valid(connector, m);
...@@ -1129,15 +1042,15 @@ static void hdmi_audio_init(struct hdmi_context *hdata) ...@@ -1129,15 +1042,15 @@ static void hdmi_audio_init(struct hdmi_context *hdata)
switch (bits_per_sample) { switch (bits_per_sample) {
case 20: case 20:
data_num = 2; data_num = 2;
bit_ch = 1; bit_ch = 1;
break; break;
case 24: case 24:
data_num = 3; data_num = 3;
bit_ch = 1; bit_ch = 1;
break; break;
default: default:
data_num = 1; data_num = 1;
bit_ch = 0; bit_ch = 0;
break; break;
} }
...@@ -1230,13 +1143,12 @@ static void hdmi_conf_init(struct hdmi_context *hdata) ...@@ -1230,13 +1143,12 @@ static void hdmi_conf_init(struct hdmi_context *hdata)
/* choose HDMI mode */ /* choose HDMI mode */
hdmi_reg_writemask(hdata, HDMI_MODE_SEL, hdmi_reg_writemask(hdata, HDMI_MODE_SEL,
HDMI_MODE_HDMI_EN, HDMI_MODE_MASK); HDMI_MODE_HDMI_EN, HDMI_MODE_MASK);
/* Apply Video preable and Guard band in HDMI mode only */ /* apply video pre-amble and guard band in HDMI mode only */
hdmi_reg_writeb(hdata, HDMI_CON_2, 0); hdmi_reg_writeb(hdata, HDMI_CON_2, 0);
/* disable bluescreen */ /* disable bluescreen */
hdmi_reg_writemask(hdata, HDMI_CON_0, 0, HDMI_BLUE_SCR_EN); hdmi_reg_writemask(hdata, HDMI_CON_0, 0, HDMI_BLUE_SCR_EN);
if (hdata->dvi_mode) { if (hdata->dvi_mode) {
/* choose DVI mode */
hdmi_reg_writemask(hdata, HDMI_MODE_SEL, hdmi_reg_writemask(hdata, HDMI_MODE_SEL,
HDMI_MODE_DVI_EN, HDMI_MODE_MASK); HDMI_MODE_DVI_EN, HDMI_MODE_MASK);
hdmi_reg_writeb(hdata, HDMI_CON_2, hdmi_reg_writeb(hdata, HDMI_CON_2,
...@@ -1308,7 +1220,7 @@ static void hdmi_v13_mode_apply(struct hdmi_context *hdata) ...@@ -1308,7 +1220,7 @@ static void hdmi_v13_mode_apply(struct hdmi_context *hdata)
val = (m->hsync_start - m->hdisplay - 2); val = (m->hsync_start - m->hdisplay - 2);
val |= ((m->hsync_end - m->hdisplay - 2) << 10); val |= ((m->hsync_end - m->hdisplay - 2) << 10);
val |= ((m->flags & DRM_MODE_FLAG_NHSYNC) ? 1 : 0)<<20; val |= ((m->flags & DRM_MODE_FLAG_NHSYNC) ? 1 : 0)<<20;
hdmi_reg_writev(hdata, HDMI_V13_H_SYNC_GEN_0, 3, val); hdmi_reg_writev(hdata, HDMI_V13_H_SYNC_GEN_0, 3, val);
/* /*
...@@ -1319,7 +1231,6 @@ static void hdmi_v13_mode_apply(struct hdmi_context *hdata) ...@@ -1319,7 +1231,6 @@ static void hdmi_v13_mode_apply(struct hdmi_context *hdata)
/* Following values & calculations differ for different type of modes */ /* Following values & calculations differ for different type of modes */
if (m->flags & DRM_MODE_FLAG_INTERLACE) { if (m->flags & DRM_MODE_FLAG_INTERLACE) {
/* Interlaced Mode */
val = ((m->vsync_end - m->vdisplay) / 2); val = ((m->vsync_end - m->vdisplay) / 2);
val |= ((m->vsync_start - m->vdisplay) / 2) << 12; val |= ((m->vsync_start - m->vdisplay) / 2) << 12;
hdmi_reg_writev(hdata, HDMI_V13_V_SYNC_GEN_1_0, 3, val); hdmi_reg_writev(hdata, HDMI_V13_V_SYNC_GEN_1_0, 3, val);
...@@ -1348,8 +1259,6 @@ static void hdmi_v13_mode_apply(struct hdmi_context *hdata) ...@@ -1348,8 +1259,6 @@ static void hdmi_v13_mode_apply(struct hdmi_context *hdata)
hdmi_reg_writev(hdata, HDMI_TG_VACT_ST2_L, 2, 0x249); hdmi_reg_writev(hdata, HDMI_TG_VACT_ST2_L, 2, 0x249);
} else { } else {
/* Progressive Mode */
val = m->vtotal; val = m->vtotal;
val |= (m->vtotal - m->vdisplay) << 11; val |= (m->vtotal - m->vdisplay) << 11;
hdmi_reg_writev(hdata, HDMI_V13_V_BLANK_0, 3, val); hdmi_reg_writev(hdata, HDMI_V13_V_BLANK_0, 3, val);
...@@ -1365,21 +1274,12 @@ static void hdmi_v13_mode_apply(struct hdmi_context *hdata) ...@@ -1365,21 +1274,12 @@ static void hdmi_v13_mode_apply(struct hdmi_context *hdata)
hdmi_reg_writev(hdata, HDMI_TG_VACT_ST_L, 2, hdmi_reg_writev(hdata, HDMI_TG_VACT_ST_L, 2,
m->vtotal - m->vdisplay); m->vtotal - m->vdisplay);
hdmi_reg_writev(hdata, HDMI_TG_VACT_SZ_L, 2, m->vdisplay); hdmi_reg_writev(hdata, HDMI_TG_VACT_SZ_L, 2, m->vdisplay);
hdmi_reg_writev(hdata, HDMI_TG_VACT_ST2_L, 2, 0x248);
} }
/* Timing generator registers */
hdmi_reg_writev(hdata, HDMI_TG_H_FSZ_L, 2, m->htotal); hdmi_reg_writev(hdata, HDMI_TG_H_FSZ_L, 2, m->htotal);
hdmi_reg_writev(hdata, HDMI_TG_HACT_ST_L, 2, m->htotal - m->hdisplay); hdmi_reg_writev(hdata, HDMI_TG_HACT_ST_L, 2, m->htotal - m->hdisplay);
hdmi_reg_writev(hdata, HDMI_TG_HACT_SZ_L, 2, m->hdisplay); hdmi_reg_writev(hdata, HDMI_TG_HACT_SZ_L, 2, m->hdisplay);
hdmi_reg_writev(hdata, HDMI_TG_V_FSZ_L, 2, m->vtotal); hdmi_reg_writev(hdata, HDMI_TG_V_FSZ_L, 2, m->vtotal);
hdmi_reg_writev(hdata, HDMI_TG_VSYNC_L, 2, 0x1);
hdmi_reg_writev(hdata, HDMI_TG_VSYNC2_L, 2, 0x233);
hdmi_reg_writev(hdata, HDMI_TG_FIELD_CHG_L, 2, 0x233);
hdmi_reg_writev(hdata, HDMI_TG_VSYNC_TOP_HDMI_L, 2, 0x1);
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);
} }
static void hdmi_v14_mode_apply(struct hdmi_context *hdata) static void hdmi_v14_mode_apply(struct hdmi_context *hdata)
...@@ -1390,7 +1290,7 @@ static void hdmi_v14_mode_apply(struct hdmi_context *hdata) ...@@ -1390,7 +1290,7 @@ static void hdmi_v14_mode_apply(struct hdmi_context *hdata)
hdmi_reg_writev(hdata, HDMI_V_LINE_0, 2, m->vtotal); hdmi_reg_writev(hdata, HDMI_V_LINE_0, 2, m->vtotal);
hdmi_reg_writev(hdata, HDMI_H_LINE_0, 2, m->htotal); hdmi_reg_writev(hdata, HDMI_H_LINE_0, 2, m->htotal);
hdmi_reg_writev(hdata, HDMI_HSYNC_POL, 1, hdmi_reg_writev(hdata, HDMI_HSYNC_POL, 1,
(m->flags & DRM_MODE_FLAG_NHSYNC) ? 1 : 0); (m->flags & DRM_MODE_FLAG_NHSYNC) ? 1 : 0);
hdmi_reg_writev(hdata, HDMI_VSYNC_POL, 1, hdmi_reg_writev(hdata, HDMI_VSYNC_POL, 1,
(m->flags & DRM_MODE_FLAG_NVSYNC) ? 1 : 0); (m->flags & DRM_MODE_FLAG_NVSYNC) ? 1 : 0);
hdmi_reg_writev(hdata, HDMI_INT_PRO_MODE, 1, hdmi_reg_writev(hdata, HDMI_INT_PRO_MODE, 1,
...@@ -1404,7 +1304,6 @@ static void hdmi_v14_mode_apply(struct hdmi_context *hdata) ...@@ -1404,7 +1304,6 @@ static void hdmi_v14_mode_apply(struct hdmi_context *hdata)
/* Following values & calculations differ for different type of modes */ /* Following values & calculations differ for different type of modes */
if (m->flags & DRM_MODE_FLAG_INTERLACE) { if (m->flags & DRM_MODE_FLAG_INTERLACE) {
/* Interlaced Mode */
hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_BEF_2_0, 2, hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_BEF_2_0, 2,
(m->vsync_end - m->vdisplay) / 2); (m->vsync_end - m->vdisplay) / 2);
hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_BEF_1_0, 2, hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_BEF_1_0, 2,
...@@ -1437,7 +1336,6 @@ static void hdmi_v14_mode_apply(struct hdmi_context *hdata) ...@@ -1437,7 +1336,6 @@ static void hdmi_v14_mode_apply(struct hdmi_context *hdata)
hdmi_reg_writev(hdata, HDMI_TG_VACT_ST3_L, 2, 0x0); hdmi_reg_writev(hdata, HDMI_TG_VACT_ST3_L, 2, 0x0);
hdmi_reg_writev(hdata, HDMI_TG_VACT_ST4_L, 2, 0x0); hdmi_reg_writev(hdata, HDMI_TG_VACT_ST4_L, 2, 0x0);
} else { } else {
/* Progressive Mode */
hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_BEF_2_0, 2, hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_BEF_2_0, 2,
m->vsync_end - m->vdisplay); m->vsync_end - m->vdisplay);
hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_BEF_1_0, 2, hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_BEF_1_0, 2,
...@@ -1454,15 +1352,8 @@ static void hdmi_v14_mode_apply(struct hdmi_context *hdata) ...@@ -1454,15 +1352,8 @@ static void hdmi_v14_mode_apply(struct hdmi_context *hdata)
hdmi_reg_writev(hdata, HDMI_TG_VACT_ST_L, 2, hdmi_reg_writev(hdata, HDMI_TG_VACT_ST_L, 2,
m->vtotal - m->vdisplay); m->vtotal - m->vdisplay);
hdmi_reg_writev(hdata, HDMI_TG_VACT_SZ_L, 2, m->vdisplay); hdmi_reg_writev(hdata, HDMI_TG_VACT_SZ_L, 2, m->vdisplay);
hdmi_reg_writev(hdata, HDMI_TG_VACT_ST2_L, 2, 0x248);
hdmi_reg_writev(hdata, HDMI_TG_VACT_ST3_L, 2, 0x47b);
hdmi_reg_writev(hdata, HDMI_TG_VACT_ST4_L, 2, 0x6ae);
hdmi_reg_writev(hdata, HDMI_TG_VSYNC2_L, 2, 0x233);
hdmi_reg_writev(hdata, HDMI_TG_VSYNC_BOT_HDMI_L, 2, 0x233);
hdmi_reg_writev(hdata, HDMI_TG_FIELD_BOT_HDMI_L, 2, 0x233);
} }
/* Following values & calculations are same irrespective of mode type */
hdmi_reg_writev(hdata, HDMI_H_SYNC_START_0, 2, hdmi_reg_writev(hdata, HDMI_H_SYNC_START_0, 2,
m->hsync_start - m->hdisplay - 2); m->hsync_start - m->hdisplay - 2);
hdmi_reg_writev(hdata, HDMI_H_SYNC_END_0, 2, hdmi_reg_writev(hdata, HDMI_H_SYNC_END_0, 2,
...@@ -1486,16 +1377,12 @@ static void hdmi_v14_mode_apply(struct hdmi_context *hdata) ...@@ -1486,16 +1377,12 @@ static void hdmi_v14_mode_apply(struct hdmi_context *hdata)
hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_PXL_5_0, 2, 0xffff); hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_PXL_5_0, 2, 0xffff);
hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_PXL_6_0, 2, 0xffff); hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_PXL_6_0, 2, 0xffff);
/* Timing generator registers */
hdmi_reg_writev(hdata, HDMI_TG_H_FSZ_L, 2, m->htotal); hdmi_reg_writev(hdata, HDMI_TG_H_FSZ_L, 2, m->htotal);
hdmi_reg_writev(hdata, HDMI_TG_HACT_ST_L, 2, m->htotal - m->hdisplay); hdmi_reg_writev(hdata, HDMI_TG_HACT_ST_L, 2, m->htotal - m->hdisplay);
hdmi_reg_writev(hdata, HDMI_TG_HACT_SZ_L, 2, m->hdisplay); hdmi_reg_writev(hdata, HDMI_TG_HACT_SZ_L, 2, m->hdisplay);
hdmi_reg_writev(hdata, HDMI_TG_V_FSZ_L, 2, m->vtotal); hdmi_reg_writev(hdata, HDMI_TG_V_FSZ_L, 2, m->vtotal);
hdmi_reg_writev(hdata, HDMI_TG_VSYNC_L, 2, 0x1); if (hdata->drv_data == &exynos5433_hdmi_driver_data)
hdmi_reg_writev(hdata, HDMI_TG_FIELD_CHG_L, 2, 0x233); hdmi_reg_writeb(hdata, HDMI_TG_DECON_EN, 1);
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);
} }
static void hdmi_mode_apply(struct hdmi_context *hdata) static void hdmi_mode_apply(struct hdmi_context *hdata)
...@@ -1505,62 +1392,65 @@ static void hdmi_mode_apply(struct hdmi_context *hdata) ...@@ -1505,62 +1392,65 @@ static void hdmi_mode_apply(struct hdmi_context *hdata)
else else
hdmi_v14_mode_apply(hdata); hdmi_v14_mode_apply(hdata);
hdmiphy_wait_for_pll(hdata);
clk_set_parent(hdata->mout_hdmi, hdata->sclk_hdmiphy);
/* enable HDMI and timing generator */
hdmi_start(hdata, true); hdmi_start(hdata, true);
} }
static void hdmiphy_conf_reset(struct hdmi_context *hdata) static void hdmiphy_conf_reset(struct hdmi_context *hdata)
{ {
clk_set_parent(hdata->mout_hdmi, hdata->sclk_pixel); hdmi_reg_writemask(hdata, HDMI_CORE_RSTOUT, 0, 1);
usleep_range(10000, 12000);
/* reset hdmiphy */ hdmi_reg_writemask(hdata, HDMI_CORE_RSTOUT, ~0, 1);
usleep_range(10000, 12000);
hdmi_reg_writemask(hdata, HDMI_PHY_RSTOUT, ~0, HDMI_PHY_SW_RSTOUT); hdmi_reg_writemask(hdata, HDMI_PHY_RSTOUT, ~0, HDMI_PHY_SW_RSTOUT);
usleep_range(10000, 12000); usleep_range(10000, 12000);
hdmi_reg_writemask(hdata, HDMI_PHY_RSTOUT, 0, HDMI_PHY_SW_RSTOUT); hdmi_reg_writemask(hdata, HDMI_PHY_RSTOUT, 0, HDMI_PHY_SW_RSTOUT);
usleep_range(10000, 12000); usleep_range(10000, 12000);
} }
static void hdmiphy_enable_mode_set(struct hdmi_context *hdata, bool enable)
{
u8 v = enable ? HDMI_PHY_ENABLE_MODE_SET : HDMI_PHY_DISABLE_MODE_SET;
if (hdata->drv_data == &exynos5433_hdmi_driver_data)
writel(v, hdata->regs_hdmiphy + HDMIPHY5433_MODE_SET_DONE);
}
static void hdmiphy_conf_apply(struct hdmi_context *hdata) static void hdmiphy_conf_apply(struct hdmi_context *hdata)
{ {
int ret; int ret;
int i; const u8 *phy_conf;
/* pixel clock */ ret = hdmi_find_phy_conf(hdata, hdata->current_mode.clock * 1000);
i = hdmi_find_phy_conf(hdata, hdata->current_mode.clock * 1000); if (ret < 0) {
if (i < 0) {
DRM_ERROR("failed to find hdmiphy conf\n"); DRM_ERROR("failed to find hdmiphy conf\n");
return; return;
} }
phy_conf = hdata->drv_data->phy_confs.data[ret].conf;
hdmi_clk_set_parents(hdata, false);
hdmiphy_conf_reset(hdata);
ret = hdmiphy_reg_write_buf(hdata, 0, hdmiphy_enable_mode_set(hdata, true);
hdata->drv_data->phy_confs[i].conf, 32); ret = hdmiphy_reg_write_buf(hdata, 0, phy_conf, 32);
if (ret) { if (ret) {
DRM_ERROR("failed to configure hdmiphy\n"); DRM_ERROR("failed to configure hdmiphy\n");
return; return;
} }
hdmiphy_enable_mode_set(hdata, false);
hdmi_clk_set_parents(hdata, true);
usleep_range(10000, 12000); usleep_range(10000, 12000);
hdmiphy_wait_for_pll(hdata);
} }
static void hdmi_conf_apply(struct hdmi_context *hdata) static void hdmi_conf_apply(struct hdmi_context *hdata)
{ {
hdmiphy_conf_reset(hdata);
hdmiphy_conf_apply(hdata); hdmiphy_conf_apply(hdata);
hdmi_start(hdata, false); hdmi_start(hdata, false);
hdmi_conf_init(hdata); hdmi_conf_init(hdata);
hdmi_audio_init(hdata); hdmi_audio_init(hdata);
/* setting core registers */
hdmi_mode_apply(hdata); hdmi_mode_apply(hdata);
hdmi_audio_control(hdata, true); hdmi_audio_control(hdata, true);
hdmi_regs_dump(hdata, "start");
} }
static void hdmi_mode_set(struct drm_encoder *encoder, static void hdmi_mode_set(struct drm_encoder *encoder,
...@@ -1579,6 +1469,15 @@ static void hdmi_mode_set(struct drm_encoder *encoder, ...@@ -1579,6 +1469,15 @@ static void hdmi_mode_set(struct drm_encoder *encoder,
hdata->cea_video_id = drm_match_cea_mode(mode); hdata->cea_video_id = drm_match_cea_mode(mode);
} }
static void hdmi_set_refclk(struct hdmi_context *hdata, bool on)
{
if (!hdata->sysreg)
return;
regmap_update_bits(hdata->sysreg, EXYNOS5433_SYSREG_DISP_HDMI_PHY,
SYSREG_HDMI_REFCLK_INT_CLK, on ? ~0 : 0);
}
static void hdmi_enable(struct drm_encoder *encoder) static void hdmi_enable(struct drm_encoder *encoder)
{ {
struct hdmi_context *hdata = encoder_to_hdmi(encoder); struct hdmi_context *hdata = encoder_to_hdmi(encoder);
...@@ -1591,10 +1490,13 @@ static void hdmi_enable(struct drm_encoder *encoder) ...@@ -1591,10 +1490,13 @@ static void hdmi_enable(struct drm_encoder *encoder)
if (regulator_bulk_enable(ARRAY_SIZE(supply), hdata->regul_bulk)) if (regulator_bulk_enable(ARRAY_SIZE(supply), hdata->regul_bulk))
DRM_DEBUG_KMS("failed to enable regulator bulk\n"); DRM_DEBUG_KMS("failed to enable regulator bulk\n");
/* set pmu hdmiphy control bit to enable hdmiphy */
regmap_update_bits(hdata->pmureg, PMU_HDMI_PHY_CONTROL, regmap_update_bits(hdata->pmureg, PMU_HDMI_PHY_CONTROL,
PMU_HDMI_PHY_ENABLE_BIT, 1); PMU_HDMI_PHY_ENABLE_BIT, 1);
hdmi_set_refclk(hdata, true);
hdmi_reg_writemask(hdata, HDMI_PHY_CON_0, 0, HDMI_PHY_POWER_OFF_EN);
hdmi_conf_apply(hdata); hdmi_conf_apply(hdata);
hdata->powered = true; hdata->powered = true;
...@@ -1623,12 +1525,14 @@ static void hdmi_disable(struct drm_encoder *encoder) ...@@ -1623,12 +1525,14 @@ static void hdmi_disable(struct drm_encoder *encoder)
if (funcs && funcs->disable) if (funcs && funcs->disable)
(*funcs->disable)(crtc); (*funcs->disable)(crtc);
/* HDMI System Disable */
hdmi_reg_writemask(hdata, HDMI_CON_0, 0, HDMI_EN); hdmi_reg_writemask(hdata, HDMI_CON_0, 0, HDMI_EN);
cancel_delayed_work(&hdata->hotplug_work); cancel_delayed_work(&hdata->hotplug_work);
/* reset pmu hdmiphy control bit to disable hdmiphy */ hdmi_reg_writemask(hdata, HDMI_PHY_CON_0, ~0, HDMI_PHY_POWER_OFF_EN);
hdmi_set_refclk(hdata, false);
regmap_update_bits(hdata->pmureg, PMU_HDMI_PHY_CONTROL, regmap_update_bits(hdata->pmureg, PMU_HDMI_PHY_CONTROL,
PMU_HDMI_PHY_ENABLE_BIT, 0); PMU_HDMI_PHY_ENABLE_BIT, 0);
...@@ -1670,6 +1574,57 @@ static irqreturn_t hdmi_irq_thread(int irq, void *arg) ...@@ -1670,6 +1574,57 @@ static irqreturn_t hdmi_irq_thread(int irq, void *arg)
return IRQ_HANDLED; return IRQ_HANDLED;
} }
static int hdmi_clks_get(struct hdmi_context *hdata,
const struct string_array_spec *names,
struct clk **clks)
{
struct device *dev = hdata->dev;
int i;
for (i = 0; i < names->count; ++i) {
struct clk *clk = devm_clk_get(dev, names->data[i]);
if (IS_ERR(clk)) {
int ret = PTR_ERR(clk);
dev_err(dev, "Cannot get clock %s, %d\n",
names->data[i], ret);
return ret;
}
clks[i] = clk;
}
return 0;
}
static int hdmi_clk_init(struct hdmi_context *hdata)
{
const struct hdmi_driver_data *drv_data = hdata->drv_data;
int count = drv_data->clk_gates.count + drv_data->clk_muxes.count;
struct device *dev = hdata->dev;
struct clk **clks;
int ret;
if (!count)
return 0;
clks = devm_kzalloc(dev, sizeof(*clks) * count, GFP_KERNEL);
if (!clks)
return -ENOMEM;
hdata->clk_gates = clks;
hdata->clk_muxes = clks + drv_data->clk_gates.count;
ret = hdmi_clks_get(hdata, &drv_data->clk_gates, hdata->clk_gates);
if (ret)
return ret;
return hdmi_clks_get(hdata, &drv_data->clk_muxes, hdata->clk_muxes);
}
static int hdmi_resources_init(struct hdmi_context *hdata) static int hdmi_resources_init(struct hdmi_context *hdata)
{ {
struct device *dev = hdata->dev; struct device *dev = hdata->dev;
...@@ -1688,39 +1643,14 @@ static int hdmi_resources_init(struct hdmi_context *hdata) ...@@ -1688,39 +1643,14 @@ static int hdmi_resources_init(struct hdmi_context *hdata)
DRM_ERROR("failed to get GPIO irq\n"); DRM_ERROR("failed to get GPIO irq\n");
return hdata->irq; return hdata->irq;
} }
/* get clocks, power */
hdata->hdmi = devm_clk_get(dev, "hdmi");
if (IS_ERR(hdata->hdmi)) {
DRM_ERROR("failed to get clock 'hdmi'\n");
ret = PTR_ERR(hdata->hdmi);
goto fail;
}
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(hdata->sclk_hdmi);
goto fail;
}
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(hdata->sclk_pixel);
goto fail;
}
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(hdata->sclk_hdmiphy);
goto fail;
}
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(hdata->mout_hdmi);
goto fail;
}
clk_set_parent(hdata->mout_hdmi, hdata->sclk_pixel); ret = hdmi_clk_init(hdata);
if (ret)
return ret;
ret = hdmi_clk_set_parents(hdata, false);
if (ret)
return ret;
for (i = 0; i < ARRAY_SIZE(supply); ++i) { for (i = 0; i < ARRAY_SIZE(supply); ++i) {
hdata->regul_bulk[i].supply = supply[i]; hdata->regul_bulk[i].supply = supply[i];
...@@ -1745,9 +1675,6 @@ static int hdmi_resources_init(struct hdmi_context *hdata) ...@@ -1745,9 +1675,6 @@ static int hdmi_resources_init(struct hdmi_context *hdata)
DRM_ERROR("failed to enable hdmi-en regulator\n"); DRM_ERROR("failed to enable hdmi-en regulator\n");
return ret; return ret;
fail:
DRM_ERROR("HDMI resource init - failed\n");
return ret;
} }
static struct of_device_id hdmi_match_types[] = { static struct of_device_id hdmi_match_types[] = {
...@@ -1760,6 +1687,9 @@ static struct of_device_id hdmi_match_types[] = { ...@@ -1760,6 +1687,9 @@ static struct of_device_id hdmi_match_types[] = {
}, { }, {
.compatible = "samsung,exynos5420-hdmi", .compatible = "samsung,exynos5420-hdmi",
.data = &exynos5420_hdmi_driver_data, .data = &exynos5420_hdmi_driver_data,
}, {
.compatible = "samsung,exynos5433-hdmi",
.data = &exynos5433_hdmi_driver_data,
}, { }, {
/* end node */ /* end node */
} }
...@@ -1830,7 +1760,6 @@ static struct device_node *hdmi_legacy_phy_dt_binding(struct device *dev) ...@@ -1830,7 +1760,6 @@ static struct device_node *hdmi_legacy_phy_dt_binding(struct device *dev)
static int hdmi_probe(struct platform_device *pdev) static int hdmi_probe(struct platform_device *pdev)
{ {
struct device_node *ddc_node, *phy_node; struct device_node *ddc_node, *phy_node;
const struct of_device_id *match;
struct device *dev = &pdev->dev; struct device *dev = &pdev->dev;
struct hdmi_context *hdata; struct hdmi_context *hdata;
struct resource *res; struct resource *res;
...@@ -1840,11 +1769,7 @@ static int hdmi_probe(struct platform_device *pdev) ...@@ -1840,11 +1769,7 @@ static int hdmi_probe(struct platform_device *pdev)
if (!hdata) if (!hdata)
return -ENOMEM; return -ENOMEM;
match = of_match_device(hdmi_match_types, dev); hdata->drv_data = of_device_get_match_data(dev);
if (!match)
return -ENODEV;
hdata->drv_data = match->data;
platform_set_drvdata(pdev, hdata); platform_set_drvdata(pdev, hdata);
...@@ -1867,7 +1792,6 @@ static int hdmi_probe(struct platform_device *pdev) ...@@ -1867,7 +1792,6 @@ static int hdmi_probe(struct platform_device *pdev)
if (ddc_node) if (ddc_node)
goto out_get_ddc_adpt; goto out_get_ddc_adpt;
/* DDC i2c driver */
ddc_node = of_parse_phandle(dev->of_node, "ddc", 0); ddc_node = of_parse_phandle(dev->of_node, "ddc", 0);
if (!ddc_node) { if (!ddc_node) {
DRM_ERROR("Failed to find ddc node in device tree\n"); DRM_ERROR("Failed to find ddc node in device tree\n");
...@@ -1885,7 +1809,6 @@ static int hdmi_probe(struct platform_device *pdev) ...@@ -1885,7 +1809,6 @@ static int hdmi_probe(struct platform_device *pdev)
if (phy_node) if (phy_node)
goto out_get_phy_port; goto out_get_phy_port;
/* hdmiphy i2c driver */
phy_node = of_parse_phandle(dev->of_node, "phy", 0); phy_node = of_parse_phandle(dev->of_node, "phy", 0);
if (!phy_node) { if (!phy_node) {
DRM_ERROR("Failed to find hdmiphy node in device tree\n"); DRM_ERROR("Failed to find hdmiphy node in device tree\n");
...@@ -1929,6 +1852,16 @@ static int hdmi_probe(struct platform_device *pdev) ...@@ -1929,6 +1852,16 @@ static int hdmi_probe(struct platform_device *pdev)
goto err_hdmiphy; goto err_hdmiphy;
} }
if (hdata->drv_data->has_sysreg) {
hdata->sysreg = syscon_regmap_lookup_by_phandle(dev->of_node,
"samsung,sysreg-phandle");
if (IS_ERR(hdata->sysreg)) {
DRM_ERROR("sysreg regmap lookup failed.\n");
ret = -EPROBE_DEFER;
goto err_hdmiphy;
}
}
pm_runtime_enable(dev); pm_runtime_enable(dev);
ret = component_add(&pdev->dev, &hdmi_component_ops); ret = component_add(&pdev->dev, &hdmi_component_ops);
...@@ -1975,8 +1908,7 @@ static int exynos_hdmi_suspend(struct device *dev) ...@@ -1975,8 +1908,7 @@ static int exynos_hdmi_suspend(struct device *dev)
{ {
struct hdmi_context *hdata = dev_get_drvdata(dev); struct hdmi_context *hdata = dev_get_drvdata(dev);
clk_disable_unprepare(hdata->sclk_hdmi); hdmi_clk_disable_gates(hdata);
clk_disable_unprepare(hdata->hdmi);
return 0; return 0;
} }
...@@ -1986,17 +1918,9 @@ static int exynos_hdmi_resume(struct device *dev) ...@@ -1986,17 +1918,9 @@ static int exynos_hdmi_resume(struct device *dev)
struct hdmi_context *hdata = dev_get_drvdata(dev); struct hdmi_context *hdata = dev_get_drvdata(dev);
int ret; int ret;
ret = clk_prepare_enable(hdata->hdmi); ret = hdmi_clk_enable_gates(hdata);
if (ret < 0) { if (ret < 0)
DRM_ERROR("Failed to prepare_enable the hdmi clk [%d]\n", ret);
return ret;
}
ret = clk_prepare_enable(hdata->sclk_hdmi);
if (ret < 0) {
DRM_ERROR("Failed to prepare_enable the sclk_mixer clk [%d]\n",
ret);
return ret; return ret;
}
return 0; return 0;
} }
......
...@@ -31,6 +31,7 @@ ...@@ -31,6 +31,7 @@
#include <linux/clk.h> #include <linux/clk.h>
#include <linux/regulator/consumer.h> #include <linux/regulator/consumer.h>
#include <linux/of.h> #include <linux/of.h>
#include <linux/of_device.h>
#include <linux/component.h> #include <linux/component.h>
#include <drm/exynos_drm.h> #include <drm/exynos_drm.h>
...@@ -103,8 +104,6 @@ struct mixer_context { ...@@ -103,8 +104,6 @@ struct mixer_context {
struct mixer_resources mixer_res; struct mixer_resources mixer_res;
enum mixer_version_id mxr_ver; enum mixer_version_id mxr_ver;
wait_queue_head_t wait_vsync_queue;
atomic_t wait_vsync_event;
}; };
struct mixer_drv_data { struct mixer_drv_data {
...@@ -787,12 +786,6 @@ static irqreturn_t mixer_irq_handler(int irq, void *arg) ...@@ -787,12 +786,6 @@ static irqreturn_t mixer_irq_handler(int irq, void *arg)
exynos_drm_crtc_finish_update(ctx->crtc, plane); exynos_drm_crtc_finish_update(ctx->crtc, plane);
} }
/* set wait vsync event to zero and wake up queue. */
if (atomic_read(&ctx->wait_vsync_event)) {
atomic_set(&ctx->wait_vsync_event, 0);
wake_up(&ctx->wait_vsync_queue);
}
} }
out: out:
...@@ -1027,34 +1020,6 @@ static void mixer_atomic_flush(struct exynos_drm_crtc *crtc) ...@@ -1027,34 +1020,6 @@ static void mixer_atomic_flush(struct exynos_drm_crtc *crtc)
mixer_vsync_set_update(mixer_ctx, true); mixer_vsync_set_update(mixer_ctx, true);
} }
static void mixer_wait_for_vblank(struct exynos_drm_crtc *crtc)
{
struct mixer_context *mixer_ctx = crtc->ctx;
int err;
if (!test_bit(MXR_BIT_POWERED, &mixer_ctx->flags))
return;
err = drm_vblank_get(mixer_ctx->drm_dev, mixer_ctx->pipe);
if (err < 0) {
DRM_DEBUG_KMS("failed to acquire vblank counter\n");
return;
}
atomic_set(&mixer_ctx->wait_vsync_event, 1);
/*
* wait for MIXER to signal VSYNC interrupt or return after
* timeout which is set to 50ms (refresh rate of 20).
*/
if (!wait_event_timeout(mixer_ctx->wait_vsync_queue,
!atomic_read(&mixer_ctx->wait_vsync_event),
HZ/20))
DRM_DEBUG_KMS("vblank wait timed out.\n");
drm_vblank_put(mixer_ctx->drm_dev, mixer_ctx->pipe);
}
static void mixer_enable(struct exynos_drm_crtc *crtc) static void mixer_enable(struct exynos_drm_crtc *crtc)
{ {
struct mixer_context *ctx = crtc->ctx; struct mixer_context *ctx = crtc->ctx;
...@@ -1065,6 +1030,8 @@ static void mixer_enable(struct exynos_drm_crtc *crtc) ...@@ -1065,6 +1030,8 @@ static void mixer_enable(struct exynos_drm_crtc *crtc)
pm_runtime_get_sync(ctx->dev); pm_runtime_get_sync(ctx->dev);
exynos_drm_pipe_clk_enable(crtc, true);
mixer_vsync_set_update(ctx, false); mixer_vsync_set_update(ctx, false);
mixer_reg_writemask(res, MXR_STATUS, ~0, MXR_STATUS_SOFT_RESET); mixer_reg_writemask(res, MXR_STATUS, ~0, MXR_STATUS_SOFT_RESET);
...@@ -1094,6 +1061,8 @@ static void mixer_disable(struct exynos_drm_crtc *crtc) ...@@ -1094,6 +1061,8 @@ static void mixer_disable(struct exynos_drm_crtc *crtc)
for (i = 0; i < MIXER_WIN_NR; i++) for (i = 0; i < MIXER_WIN_NR; i++)
mixer_disable_plane(crtc, &ctx->planes[i]); mixer_disable_plane(crtc, &ctx->planes[i]);
exynos_drm_pipe_clk_enable(crtc, false);
pm_runtime_put(ctx->dev); pm_runtime_put(ctx->dev);
clear_bit(MXR_BIT_POWERED, &ctx->flags); clear_bit(MXR_BIT_POWERED, &ctx->flags);
...@@ -1126,7 +1095,6 @@ static const struct exynos_drm_crtc_ops mixer_crtc_ops = { ...@@ -1126,7 +1095,6 @@ static const struct exynos_drm_crtc_ops mixer_crtc_ops = {
.disable = mixer_disable, .disable = mixer_disable,
.enable_vblank = mixer_enable_vblank, .enable_vblank = mixer_enable_vblank,
.disable_vblank = mixer_disable_vblank, .disable_vblank = mixer_disable_vblank,
.wait_for_vblank = mixer_wait_for_vblank,
.atomic_begin = mixer_atomic_begin, .atomic_begin = mixer_atomic_begin,
.update_plane = mixer_update_plane, .update_plane = mixer_update_plane,
.disable_plane = mixer_disable_plane, .disable_plane = mixer_disable_plane,
...@@ -1155,18 +1123,6 @@ static struct mixer_drv_data exynos4210_mxr_drv_data = { ...@@ -1155,18 +1123,6 @@ static struct mixer_drv_data exynos4210_mxr_drv_data = {
.has_sclk = 1, .has_sclk = 1,
}; };
static const struct platform_device_id mixer_driver_types[] = {
{
.name = "s5p-mixer",
.driver_data = (unsigned long)&exynos4210_mxr_drv_data,
}, {
.name = "exynos5-mixer",
.driver_data = (unsigned long)&exynos5250_mxr_drv_data,
}, {
/* end node */
}
};
static struct of_device_id mixer_match_types[] = { static struct of_device_id mixer_match_types[] = {
{ {
.compatible = "samsung,exynos4210-mixer", .compatible = "samsung,exynos4210-mixer",
...@@ -1243,7 +1199,7 @@ static const struct component_ops mixer_component_ops = { ...@@ -1243,7 +1199,7 @@ static const struct component_ops mixer_component_ops = {
static int mixer_probe(struct platform_device *pdev) static int mixer_probe(struct platform_device *pdev)
{ {
struct device *dev = &pdev->dev; struct device *dev = &pdev->dev;
struct mixer_drv_data *drv; const struct mixer_drv_data *drv;
struct mixer_context *ctx; struct mixer_context *ctx;
int ret; int ret;
...@@ -1253,23 +1209,13 @@ static int mixer_probe(struct platform_device *pdev) ...@@ -1253,23 +1209,13 @@ static int mixer_probe(struct platform_device *pdev)
return -ENOMEM; return -ENOMEM;
} }
if (dev->of_node) { drv = of_device_get_match_data(dev);
const struct of_device_id *match;
match = of_match_node(mixer_match_types, dev->of_node);
drv = (struct mixer_drv_data *)match->data;
} else {
drv = (struct mixer_drv_data *)
platform_get_device_id(pdev)->driver_data;
}
ctx->pdev = pdev; ctx->pdev = pdev;
ctx->dev = dev; ctx->dev = dev;
ctx->vp_enabled = drv->is_vp_enabled; ctx->vp_enabled = drv->is_vp_enabled;
ctx->has_sclk = drv->has_sclk; ctx->has_sclk = drv->has_sclk;
ctx->mxr_ver = drv->version; ctx->mxr_ver = drv->version;
init_waitqueue_head(&ctx->wait_vsync_queue);
atomic_set(&ctx->wait_vsync_event, 0);
platform_set_drvdata(pdev, ctx); platform_set_drvdata(pdev, ctx);
...@@ -1355,5 +1301,4 @@ struct platform_driver mixer_driver = { ...@@ -1355,5 +1301,4 @@ struct platform_driver mixer_driver = {
}, },
.probe = mixer_probe, .probe = mixer_probe,
.remove = mixer_remove, .remove = mixer_remove,
.id_table = mixer_driver_types,
}; };
...@@ -586,10 +586,12 @@ ...@@ -586,10 +586,12 @@
#define HDMI_TG_VACT_ST4_L HDMI_TG_BASE(0x0070) #define HDMI_TG_VACT_ST4_L HDMI_TG_BASE(0x0070)
#define HDMI_TG_VACT_ST4_H HDMI_TG_BASE(0x0074) #define HDMI_TG_VACT_ST4_H HDMI_TG_BASE(0x0074)
#define HDMI_TG_3D HDMI_TG_BASE(0x00F0) #define HDMI_TG_3D HDMI_TG_BASE(0x00F0)
#define HDMI_TG_DECON_EN HDMI_TG_BASE(0x01e0)
/* HDMI PHY Registers Offsets*/ /* HDMI PHY Registers Offsets*/
#define HDMIPHY_POWER (0x74 >> 2) #define HDMIPHY_POWER 0x74
#define HDMIPHY_MODE_SET_DONE (0x7c >> 2) #define HDMIPHY_MODE_SET_DONE 0x7c
#define HDMIPHY5433_MODE_SET_DONE 0x84
/* HDMI PHY Values */ /* HDMI PHY Values */
#define HDMI_PHY_POWER_ON 0x80 #define HDMI_PHY_POWER_ON 0x80
...@@ -603,4 +605,7 @@ ...@@ -603,4 +605,7 @@
#define PMU_HDMI_PHY_CONTROL 0x700 #define PMU_HDMI_PHY_CONTROL 0x700
#define PMU_HDMI_PHY_ENABLE_BIT BIT(0) #define PMU_HDMI_PHY_ENABLE_BIT BIT(0)
#define EXYNOS5433_SYSREG_DISP_HDMI_PHY 0x1008
#define SYSREG_HDMI_REFCLK_INT_CLK 1
#endif /* SAMSUNG_REGS_HDMI_H */ #endif /* SAMSUNG_REGS_HDMI_H */
...@@ -179,9 +179,9 @@ ...@@ -179,9 +179,9 @@
#define TRIGCON_TRIGMODE_W1BUF (1 << 10) #define TRIGCON_TRIGMODE_W1BUF (1 << 10)
#define TRIGCON_SWTRIGCMD_W0BUF (1 << 6) #define TRIGCON_SWTRIGCMD_W0BUF (1 << 6)
#define TRIGCON_TRIGMODE_W0BUF (1 << 5) #define TRIGCON_TRIGMODE_W0BUF (1 << 5)
#define TRIGCON_HWTRIGMASK_I80_RGB (1 << 4) #define TRIGCON_HWTRIGMASK (1 << 4)
#define TRIGCON_HWTRIGEN_I80_RGB (1 << 3) #define TRIGCON_HWTRIGEN (1 << 3)
#define TRIGCON_HWTRIG_INV_I80_RGB (1 << 2) #define TRIGCON_HWTRIG_INV (1 << 2)
#define TRIGCON_SWTRIGCMD (1 << 1) #define TRIGCON_SWTRIGCMD (1 << 1)
#define TRIGCON_SWTRIGEN (1 << 0) #define TRIGCON_SWTRIGEN (1 << 0)
......
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