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