diff options
| author | Dave Airlie <airlied@redhat.com> | 2015-08-17 01:33:23 -0400 |
|---|---|---|
| committer | Dave Airlie <airlied@redhat.com> | 2015-08-17 01:33:23 -0400 |
| commit | 3ff8e5090c337a4eb26952d68587f450e012bd72 (patch) | |
| tree | 5e21297fd91d72be8f65636b8d2e85cabdc522d4 /drivers/gpu | |
| parent | 3be66711b6adefad2a95c108161607d79729ea05 (diff) | |
| parent | 2a8cb48945408984cd04c850b293f467b32ec5af (diff) | |
Merge branch 'exynos-drm-next' of git://git.kernel.org/pub/scm/linux/kernel/git/daeinki/drm-exynos into drm-next
Summary:
- Clean up HDMI and MIXER parts
- Clean up legacy structures specific to Exynos DRM
. This patch series removes existing exyons_drm_display and
exynos_drm_encoder structures specific to Exynos DRM, and
makes them to replace with common drm_encoder structure.
With cleanup patch, we removes exynos_drm_encoder module.
- Clean up gem, dmabuf and buffer modules
. This patch series replaces existing Exynos DRM dmabuf codes
with common drm prime ones, and embeds all codes of exynos_drm_buf
into exynos_drm_gem module.
With cleanup patch, we removes exynos_drm_buf and exynos_drm_dmabuf
modules.
- And some fixups.
* 'exynos-drm-next' of git://git.kernel.org/pub/scm/linux/kernel/git/daeinki/drm-exynos: (53 commits)
drm/exynos: merge exynos_drm_buf.c to exynos_drm_gem.c
drm/exynos: use prime helpers
drm/exynos: remove function roundup_gem_size
drm/exynos: remove function update_vm_cache_attr
drm/exynos: remove function check_gem_flags
drm/exynos: use ERR_PTR instead of NULL in exynos_drm_gem_init
drm/exynos: remove unused fields of struct exynos_drm_gem_buf
drm/exynos: stop copying sg table
drm/exynos: remove function exynos_drm_gem_map_buf
drm/exynos: remove mutex locking in pagefault handler
drm/exynos: remove function convert_to_vm_err_msg
drm/exynos: stop using sgtable in page fault handler
drm/exynos: remove struct exynos_drm_encoder layer
drm/exynos: fold encoder setup into exynos_drm_load()
drm/exynos: remove exynos_drm_create_enc_conn()
drm/exynos: remove exynos_encoder's .commit() op
drm/exynos: remove extra call to exynos_dp_commit()
drm/exynos: remove extra call to hdmi_commit()
drm/exynos: remove struct exynos_drm_display
drm/exynos: simplify calculation of possible CRTCs
...
Diffstat (limited to 'drivers/gpu')
33 files changed, 1139 insertions, 2301 deletions
diff --git a/drivers/gpu/drm/exynos/Makefile b/drivers/gpu/drm/exynos/Makefile index 7de0b1084fcd..02aecfed6354 100644 --- a/drivers/gpu/drm/exynos/Makefile +++ b/drivers/gpu/drm/exynos/Makefile | |||
| @@ -3,10 +3,9 @@ | |||
| 3 | # Direct Rendering Infrastructure (DRI) in XFree86 4.1.0 and higher. | 3 | # Direct Rendering Infrastructure (DRI) in XFree86 4.1.0 and higher. |
| 4 | 4 | ||
| 5 | ccflags-y := -Iinclude/drm -Idrivers/gpu/drm/exynos | 5 | ccflags-y := -Iinclude/drm -Idrivers/gpu/drm/exynos |
| 6 | exynosdrm-y := exynos_drm_drv.o exynos_drm_encoder.o \ | 6 | exynosdrm-y := exynos_drm_drv.o exynos_drm_crtc.o exynos_drm_fbdev.o \ |
| 7 | exynos_drm_crtc.o exynos_drm_fbdev.o exynos_drm_fb.o \ | 7 | exynos_drm_fb.o exynos_drm_gem.o exynos_drm_core.o \ |
| 8 | exynos_drm_buf.o exynos_drm_gem.o exynos_drm_core.o \ | 8 | exynos_drm_plane.o |
| 9 | exynos_drm_plane.o exynos_drm_dmabuf.o | ||
| 10 | 9 | ||
| 11 | exynosdrm-$(CONFIG_DRM_EXYNOS_IOMMU) += exynos_drm_iommu.o | 10 | exynosdrm-$(CONFIG_DRM_EXYNOS_IOMMU) += exynos_drm_iommu.o |
| 12 | exynosdrm-$(CONFIG_DRM_EXYNOS_FIMD) += exynos_drm_fimd.o | 11 | exynosdrm-$(CONFIG_DRM_EXYNOS_FIMD) += exynos_drm_fimd.o |
diff --git a/drivers/gpu/drm/exynos/exynos5433_drm_decon.c b/drivers/gpu/drm/exynos/exynos5433_drm_decon.c index 8b1225f245fc..484e312e0a22 100644 --- a/drivers/gpu/drm/exynos/exynos5433_drm_decon.c +++ b/drivers/gpu/drm/exynos/exynos5433_drm_decon.c | |||
| @@ -152,15 +152,15 @@ static void decon_commit(struct exynos_drm_crtc *crtc) | |||
| 152 | #define OFFSIZE(x) (((x) & 0x3fff) << 14) | 152 | #define OFFSIZE(x) (((x) & 0x3fff) << 14) |
| 153 | #define PAGEWIDTH(x) ((x) & 0x3fff) | 153 | #define PAGEWIDTH(x) ((x) & 0x3fff) |
| 154 | 154 | ||
| 155 | static void decon_win_set_pixfmt(struct decon_context *ctx, unsigned int win) | 155 | static void decon_win_set_pixfmt(struct decon_context *ctx, unsigned int win, |
| 156 | struct drm_framebuffer *fb) | ||
| 156 | { | 157 | { |
| 157 | struct exynos_drm_plane *plane = &ctx->planes[win]; | ||
| 158 | unsigned long val; | 158 | unsigned long val; |
| 159 | 159 | ||
| 160 | val = readl(ctx->addr + DECON_WINCONx(win)); | 160 | val = readl(ctx->addr + DECON_WINCONx(win)); |
| 161 | val &= ~WINCONx_BPPMODE_MASK; | 161 | val &= ~WINCONx_BPPMODE_MASK; |
| 162 | 162 | ||
| 163 | switch (plane->pixel_format) { | 163 | switch (fb->pixel_format) { |
| 164 | case DRM_FORMAT_XRGB1555: | 164 | case DRM_FORMAT_XRGB1555: |
| 165 | val |= WINCONx_BPPMODE_16BPP_I1555; | 165 | val |= WINCONx_BPPMODE_16BPP_I1555; |
| 166 | val |= WINCONx_HAWSWP_F; | 166 | val |= WINCONx_HAWSWP_F; |
| @@ -186,7 +186,7 @@ static void decon_win_set_pixfmt(struct decon_context *ctx, unsigned int win) | |||
| 186 | return; | 186 | return; |
| 187 | } | 187 | } |
| 188 | 188 | ||
| 189 | DRM_DEBUG_KMS("bpp = %u\n", plane->bpp); | 189 | DRM_DEBUG_KMS("bpp = %u\n", fb->bits_per_pixel); |
| 190 | 190 | ||
| 191 | /* | 191 | /* |
| 192 | * In case of exynos, setting dma-burst to 16Word causes permanent | 192 | * In case of exynos, setting dma-burst to 16Word causes permanent |
| @@ -196,7 +196,7 @@ static void decon_win_set_pixfmt(struct decon_context *ctx, unsigned int win) | |||
| 196 | * movement causes unstable DMA which results into iommu crash/tear. | 196 | * movement causes unstable DMA which results into iommu crash/tear. |
| 197 | */ | 197 | */ |
| 198 | 198 | ||
| 199 | if (plane->fb_width < MIN_FB_WIDTH_FOR_16WORD_BURST) { | 199 | if (fb->width < MIN_FB_WIDTH_FOR_16WORD_BURST) { |
| 200 | val &= ~WINCONx_BURSTLEN_MASK; | 200 | val &= ~WINCONx_BURSTLEN_MASK; |
| 201 | val |= WINCONx_BURSTLEN_8WORD; | 201 | val |= WINCONx_BURSTLEN_8WORD; |
| 202 | } | 202 | } |
| @@ -219,17 +219,16 @@ static void decon_shadow_protect_win(struct decon_context *ctx, int win, | |||
| 219 | writel(val, ctx->addr + DECON_SHADOWCON); | 219 | writel(val, ctx->addr + DECON_SHADOWCON); |
| 220 | } | 220 | } |
| 221 | 221 | ||
| 222 | static void decon_win_commit(struct exynos_drm_crtc *crtc, unsigned int win) | 222 | static void decon_update_plane(struct exynos_drm_crtc *crtc, |
| 223 | struct exynos_drm_plane *plane) | ||
| 223 | { | 224 | { |
| 224 | struct decon_context *ctx = crtc->ctx; | 225 | struct decon_context *ctx = crtc->ctx; |
| 225 | struct exynos_drm_plane *plane; | 226 | struct drm_plane_state *state = plane->base.state; |
| 227 | unsigned int win = plane->zpos; | ||
| 228 | unsigned int bpp = state->fb->bits_per_pixel >> 3; | ||
| 229 | unsigned int pitch = state->fb->pitches[0]; | ||
| 226 | u32 val; | 230 | u32 val; |
| 227 | 231 | ||
| 228 | if (win < 0 || win >= WINDOWS_NR) | ||
| 229 | return; | ||
| 230 | |||
| 231 | plane = &ctx->planes[win]; | ||
| 232 | |||
| 233 | if (ctx->suspended) | 232 | if (ctx->suspended) |
| 234 | return; | 233 | return; |
| 235 | 234 | ||
| @@ -238,8 +237,8 @@ static void decon_win_commit(struct exynos_drm_crtc *crtc, unsigned int win) | |||
| 238 | val = COORDINATE_X(plane->crtc_x) | COORDINATE_Y(plane->crtc_y); | 237 | val = COORDINATE_X(plane->crtc_x) | COORDINATE_Y(plane->crtc_y); |
| 239 | writel(val, ctx->addr + DECON_VIDOSDxA(win)); | 238 | writel(val, ctx->addr + DECON_VIDOSDxA(win)); |
| 240 | 239 | ||
| 241 | val = COORDINATE_X(plane->crtc_x + plane->crtc_width - 1) | | 240 | val = COORDINATE_X(plane->crtc_x + plane->crtc_w - 1) | |
| 242 | COORDINATE_Y(plane->crtc_y + plane->crtc_height - 1); | 241 | COORDINATE_Y(plane->crtc_y + plane->crtc_h - 1); |
| 243 | writel(val, ctx->addr + DECON_VIDOSDxB(win)); | 242 | writel(val, ctx->addr + DECON_VIDOSDxB(win)); |
| 244 | 243 | ||
| 245 | val = VIDOSD_Wx_ALPHA_R_F(0x0) | VIDOSD_Wx_ALPHA_G_F(0x0) | | 244 | val = VIDOSD_Wx_ALPHA_R_F(0x0) | VIDOSD_Wx_ALPHA_G_F(0x0) | |
| @@ -252,14 +251,14 @@ static void decon_win_commit(struct exynos_drm_crtc *crtc, unsigned int win) | |||
| 252 | 251 | ||
| 253 | writel(plane->dma_addr[0], ctx->addr + DECON_VIDW0xADD0B0(win)); | 252 | writel(plane->dma_addr[0], ctx->addr + DECON_VIDW0xADD0B0(win)); |
| 254 | 253 | ||
| 255 | val = plane->dma_addr[0] + plane->pitch * plane->crtc_height; | 254 | val = plane->dma_addr[0] + pitch * plane->crtc_h; |
| 256 | writel(val, ctx->addr + DECON_VIDW0xADD1B0(win)); | 255 | writel(val, ctx->addr + DECON_VIDW0xADD1B0(win)); |
| 257 | 256 | ||
| 258 | val = OFFSIZE(plane->pitch - plane->crtc_width * (plane->bpp >> 3)) | 257 | val = OFFSIZE(pitch - plane->crtc_w * bpp) |
| 259 | | PAGEWIDTH(plane->crtc_width * (plane->bpp >> 3)); | 258 | | PAGEWIDTH(plane->crtc_w * bpp); |
| 260 | writel(val, ctx->addr + DECON_VIDW0xADD2(win)); | 259 | writel(val, ctx->addr + DECON_VIDW0xADD2(win)); |
| 261 | 260 | ||
| 262 | decon_win_set_pixfmt(ctx, win); | 261 | decon_win_set_pixfmt(ctx, win, state->fb); |
| 263 | 262 | ||
| 264 | /* window enable */ | 263 | /* window enable */ |
| 265 | val = readl(ctx->addr + DECON_WINCONx(win)); | 264 | val = readl(ctx->addr + DECON_WINCONx(win)); |
| @@ -277,17 +276,13 @@ static void decon_win_commit(struct exynos_drm_crtc *crtc, unsigned int win) | |||
| 277 | atomic_set(&ctx->win_updated, 1); | 276 | atomic_set(&ctx->win_updated, 1); |
| 278 | } | 277 | } |
| 279 | 278 | ||
| 280 | static void decon_win_disable(struct exynos_drm_crtc *crtc, unsigned int win) | 279 | static void decon_disable_plane(struct exynos_drm_crtc *crtc, |
| 280 | struct exynos_drm_plane *plane) | ||
| 281 | { | 281 | { |
| 282 | struct decon_context *ctx = crtc->ctx; | 282 | struct decon_context *ctx = crtc->ctx; |
| 283 | struct exynos_drm_plane *plane; | 283 | unsigned int win = plane->zpos; |
| 284 | u32 val; | 284 | u32 val; |
| 285 | 285 | ||
| 286 | if (win < 0 || win >= WINDOWS_NR) | ||
| 287 | return; | ||
| 288 | |||
| 289 | plane = &ctx->planes[win]; | ||
| 290 | |||
| 291 | if (ctx->suspended) | 286 | if (ctx->suspended) |
| 292 | return; | 287 | return; |
| 293 | 288 | ||
| @@ -378,7 +373,7 @@ static void decon_disable(struct exynos_drm_crtc *crtc) | |||
| 378 | * a destroyed buffer later. | 373 | * a destroyed buffer later. |
| 379 | */ | 374 | */ |
| 380 | for (i = 0; i < WINDOWS_NR; i++) | 375 | for (i = 0; i < WINDOWS_NR; i++) |
| 381 | decon_win_disable(crtc, i); | 376 | decon_disable_plane(crtc, &ctx->planes[i]); |
| 382 | 377 | ||
| 383 | decon_swreset(ctx); | 378 | decon_swreset(ctx); |
| 384 | 379 | ||
| @@ -407,7 +402,7 @@ void decon_te_irq_handler(struct exynos_drm_crtc *crtc) | |||
| 407 | writel(val, ctx->addr + DECON_TRIGCON); | 402 | writel(val, ctx->addr + DECON_TRIGCON); |
| 408 | } | 403 | } |
| 409 | 404 | ||
| 410 | drm_handle_vblank(ctx->drm_dev, ctx->pipe); | 405 | drm_crtc_handle_vblank(&ctx->crtc->base); |
| 411 | } | 406 | } |
| 412 | 407 | ||
| 413 | static void decon_clear_channels(struct exynos_drm_crtc *crtc) | 408 | static void decon_clear_channels(struct exynos_drm_crtc *crtc) |
| @@ -460,10 +455,9 @@ static struct exynos_drm_crtc_ops decon_crtc_ops = { | |||
| 460 | .enable_vblank = decon_enable_vblank, | 455 | .enable_vblank = decon_enable_vblank, |
| 461 | .disable_vblank = decon_disable_vblank, | 456 | .disable_vblank = decon_disable_vblank, |
| 462 | .commit = decon_commit, | 457 | .commit = decon_commit, |
| 463 | .win_commit = decon_win_commit, | 458 | .update_plane = decon_update_plane, |
| 464 | .win_disable = decon_win_disable, | 459 | .disable_plane = decon_disable_plane, |
| 465 | .te_handler = decon_te_irq_handler, | 460 | .te_handler = decon_te_irq_handler, |
| 466 | .clear_channels = decon_clear_channels, | ||
| 467 | }; | 461 | }; |
| 468 | 462 | ||
| 469 | static int decon_bind(struct device *dev, struct device *master, void *data) | 463 | static int decon_bind(struct device *dev, struct device *master, void *data) |
| @@ -497,7 +491,9 @@ static int decon_bind(struct device *dev, struct device *master, void *data) | |||
| 497 | goto err; | 491 | goto err; |
| 498 | } | 492 | } |
| 499 | 493 | ||
| 500 | ret = drm_iommu_attach_device_if_possible(ctx->crtc, drm_dev, dev); | 494 | decon_clear_channels(ctx->crtc); |
| 495 | |||
| 496 | ret = drm_iommu_attach_device(drm_dev, dev); | ||
| 501 | if (ret) | 497 | if (ret) |
| 502 | goto err; | 498 | goto err; |
| 503 | 499 | ||
| @@ -514,8 +510,7 @@ static void decon_unbind(struct device *dev, struct device *master, void *data) | |||
| 514 | decon_disable(ctx->crtc); | 510 | decon_disable(ctx->crtc); |
| 515 | 511 | ||
| 516 | /* detach this sub driver from iommu mapping if supported. */ | 512 | /* detach this sub driver from iommu mapping if supported. */ |
| 517 | if (is_drm_iommu_supported(ctx->drm_dev)) | 513 | drm_iommu_detach_device(ctx->drm_dev, ctx->dev); |
| 518 | drm_iommu_detach_device(ctx->drm_dev, ctx->dev); | ||
| 519 | } | 514 | } |
| 520 | 515 | ||
| 521 | static const struct component_ops decon_component_ops = { | 516 | static const struct component_ops decon_component_ops = { |
| @@ -533,7 +528,7 @@ static irqreturn_t decon_vsync_irq_handler(int irq, void *dev_id) | |||
| 533 | 528 | ||
| 534 | val = readl(ctx->addr + DECON_VIDINTCON1); | 529 | val = readl(ctx->addr + DECON_VIDINTCON1); |
| 535 | if (val & VIDINTCON1_INTFRMPEND) { | 530 | if (val & VIDINTCON1_INTFRMPEND) { |
| 536 | drm_handle_vblank(ctx->drm_dev, ctx->pipe); | 531 | drm_crtc_handle_vblank(&ctx->crtc->base); |
| 537 | 532 | ||
| 538 | /* clear */ | 533 | /* clear */ |
| 539 | writel(VIDINTCON1_INTFRMPEND, ctx->addr + DECON_VIDINTCON1); | 534 | writel(VIDINTCON1_INTFRMPEND, ctx->addr + DECON_VIDINTCON1); |
| @@ -553,7 +548,7 @@ static irqreturn_t decon_lcd_sys_irq_handler(int irq, void *dev_id) | |||
| 553 | 548 | ||
| 554 | val = readl(ctx->addr + DECON_VIDINTCON1); | 549 | val = readl(ctx->addr + DECON_VIDINTCON1); |
| 555 | if (val & VIDINTCON1_INTFRMDONEPEND) { | 550 | if (val & VIDINTCON1_INTFRMDONEPEND) { |
| 556 | exynos_drm_crtc_finish_pageflip(ctx->drm_dev, ctx->pipe); | 551 | exynos_drm_crtc_finish_pageflip(ctx->crtc); |
| 557 | 552 | ||
| 558 | /* clear */ | 553 | /* clear */ |
| 559 | writel(VIDINTCON1_INTFRMDONEPEND, | 554 | writel(VIDINTCON1_INTFRMDONEPEND, |
diff --git a/drivers/gpu/drm/exynos/exynos7_drm_decon.c b/drivers/gpu/drm/exynos/exynos7_drm_decon.c index 362532afd1a5..07926547c94f 100644 --- a/drivers/gpu/drm/exynos/exynos7_drm_decon.c +++ b/drivers/gpu/drm/exynos/exynos7_drm_decon.c | |||
| @@ -61,7 +61,7 @@ struct decon_context { | |||
| 61 | atomic_t wait_vsync_event; | 61 | atomic_t wait_vsync_event; |
| 62 | 62 | ||
| 63 | struct exynos_drm_panel_info panel; | 63 | struct exynos_drm_panel_info panel; |
| 64 | struct exynos_drm_display *display; | 64 | struct drm_encoder *encoder; |
| 65 | }; | 65 | }; |
| 66 | 66 | ||
| 67 | static const struct of_device_id decon_driver_dt_match[] = { | 67 | static const struct of_device_id decon_driver_dt_match[] = { |
| @@ -126,7 +126,9 @@ static int decon_ctx_initialize(struct decon_context *ctx, | |||
| 126 | ctx->drm_dev = drm_dev; | 126 | ctx->drm_dev = drm_dev; |
| 127 | ctx->pipe = priv->pipe++; | 127 | ctx->pipe = priv->pipe++; |
| 128 | 128 | ||
| 129 | ret = drm_iommu_attach_device_if_possible(ctx->crtc, drm_dev, ctx->dev); | 129 | decon_clear_channels(ctx->crtc); |
| 130 | |||
| 131 | ret = drm_iommu_attach_device(drm_dev, ctx->dev); | ||
| 130 | if (ret) | 132 | if (ret) |
| 131 | priv->pipe--; | 133 | priv->pipe--; |
| 132 | 134 | ||
| @@ -136,8 +138,7 @@ static int decon_ctx_initialize(struct decon_context *ctx, | |||
| 136 | static void decon_ctx_remove(struct decon_context *ctx) | 138 | static void decon_ctx_remove(struct decon_context *ctx) |
| 137 | { | 139 | { |
| 138 | /* detach this sub driver from iommu mapping if supported. */ | 140 | /* detach this sub driver from iommu mapping if supported. */ |
| 139 | if (is_drm_iommu_supported(ctx->drm_dev)) | 141 | drm_iommu_detach_device(ctx->drm_dev, ctx->dev); |
| 140 | drm_iommu_detach_device(ctx->drm_dev, ctx->dev); | ||
| 141 | } | 142 | } |
| 142 | 143 | ||
| 143 | static u32 decon_calc_clkdiv(struct decon_context *ctx, | 144 | static u32 decon_calc_clkdiv(struct decon_context *ctx, |
| @@ -271,16 +272,16 @@ static void decon_disable_vblank(struct exynos_drm_crtc *crtc) | |||
| 271 | } | 272 | } |
| 272 | } | 273 | } |
| 273 | 274 | ||
| 274 | static void decon_win_set_pixfmt(struct decon_context *ctx, unsigned int win) | 275 | static void decon_win_set_pixfmt(struct decon_context *ctx, unsigned int win, |
| 276 | struct drm_framebuffer *fb) | ||
| 275 | { | 277 | { |
| 276 | struct exynos_drm_plane *plane = &ctx->planes[win]; | ||
| 277 | unsigned long val; | 278 | unsigned long val; |
| 278 | int padding; | 279 | int padding; |
| 279 | 280 | ||
| 280 | val = readl(ctx->regs + WINCON(win)); | 281 | val = readl(ctx->regs + WINCON(win)); |
| 281 | val &= ~WINCONx_BPPMODE_MASK; | 282 | val &= ~WINCONx_BPPMODE_MASK; |
| 282 | 283 | ||
| 283 | switch (plane->pixel_format) { | 284 | switch (fb->pixel_format) { |
| 284 | case DRM_FORMAT_RGB565: | 285 | case DRM_FORMAT_RGB565: |
| 285 | val |= WINCONx_BPPMODE_16BPP_565; | 286 | val |= WINCONx_BPPMODE_16BPP_565; |
| 286 | val |= WINCONx_BURSTLEN_16WORD; | 287 | val |= WINCONx_BURSTLEN_16WORD; |
| @@ -329,7 +330,7 @@ static void decon_win_set_pixfmt(struct decon_context *ctx, unsigned int win) | |||
| 329 | break; | 330 | break; |
| 330 | } | 331 | } |
| 331 | 332 | ||
| 332 | DRM_DEBUG_KMS("bpp = %d\n", plane->bpp); | 333 | DRM_DEBUG_KMS("bpp = %d\n", fb->bits_per_pixel); |
| 333 | 334 | ||
| 334 | /* | 335 | /* |
| 335 | * In case of exynos, setting dma-burst to 16Word causes permanent | 336 | * In case of exynos, setting dma-burst to 16Word causes permanent |
| @@ -339,8 +340,8 @@ static void decon_win_set_pixfmt(struct decon_context *ctx, unsigned int win) | |||
| 339 | * movement causes unstable DMA which results into iommu crash/tear. | 340 | * movement causes unstable DMA which results into iommu crash/tear. |
| 340 | */ | 341 | */ |
| 341 | 342 | ||
| 342 | padding = (plane->pitch / (plane->bpp >> 3)) - plane->fb_width; | 343 | padding = (fb->pitches[0] / (fb->bits_per_pixel >> 3)) - fb->width; |
| 343 | if (plane->fb_width + padding < MIN_FB_WIDTH_FOR_16WORD_BURST) { | 344 | if (fb->width + padding < MIN_FB_WIDTH_FOR_16WORD_BURST) { |
| 344 | val &= ~WINCONx_BURSTLEN_MASK; | 345 | val &= ~WINCONx_BURSTLEN_MASK; |
| 345 | val |= WINCONx_BURSTLEN_8WORD; | 346 | val |= WINCONx_BURSTLEN_8WORD; |
| 346 | } | 347 | } |
| @@ -382,23 +383,19 @@ static void decon_shadow_protect_win(struct decon_context *ctx, | |||
| 382 | writel(val, ctx->regs + SHADOWCON); | 383 | writel(val, ctx->regs + SHADOWCON); |
| 383 | } | 384 | } |
| 384 | 385 | ||
| 385 | static void decon_win_commit(struct exynos_drm_crtc *crtc, unsigned int win) | 386 | static void decon_update_plane(struct exynos_drm_crtc *crtc, |
| 387 | struct exynos_drm_plane *plane) | ||
| 386 | { | 388 | { |
| 387 | struct decon_context *ctx = crtc->ctx; | 389 | struct decon_context *ctx = crtc->ctx; |
| 388 | struct drm_display_mode *mode = &crtc->base.state->adjusted_mode; | 390 | struct drm_display_mode *mode = &crtc->base.state->adjusted_mode; |
| 389 | struct exynos_drm_plane *plane; | 391 | struct drm_plane_state *state = plane->base.state; |
| 390 | int padding; | 392 | int padding; |
| 391 | unsigned long val, alpha; | 393 | unsigned long val, alpha; |
| 392 | unsigned int last_x; | 394 | unsigned int last_x; |
| 393 | unsigned int last_y; | 395 | unsigned int last_y; |
| 394 | 396 | unsigned int win = plane->zpos; | |
| 395 | if (ctx->suspended) | 397 | unsigned int bpp = state->fb->bits_per_pixel >> 3; |
| 396 | return; | 398 | unsigned int pitch = state->fb->pitches[0]; |
| 397 | |||
| 398 | if (win < 0 || win >= WINDOWS_NR) | ||
| 399 | return; | ||
| 400 | |||
| 401 | plane = &ctx->planes[win]; | ||
| 402 | 399 | ||
| 403 | if (ctx->suspended) | 400 | if (ctx->suspended) |
| 404 | return; | 401 | return; |
| @@ -420,11 +417,11 @@ static void decon_win_commit(struct exynos_drm_crtc *crtc, unsigned int win) | |||
| 420 | val = (unsigned long)plane->dma_addr[0]; | 417 | val = (unsigned long)plane->dma_addr[0]; |
| 421 | writel(val, ctx->regs + VIDW_BUF_START(win)); | 418 | writel(val, ctx->regs + VIDW_BUF_START(win)); |
| 422 | 419 | ||
| 423 | padding = (plane->pitch / (plane->bpp >> 3)) - plane->fb_width; | 420 | padding = (pitch / bpp) - state->fb->width; |
| 424 | 421 | ||
| 425 | /* buffer size */ | 422 | /* buffer size */ |
| 426 | writel(plane->fb_width + padding, ctx->regs + VIDW_WHOLE_X(win)); | 423 | writel(state->fb->width + padding, ctx->regs + VIDW_WHOLE_X(win)); |
| 427 | writel(plane->fb_height, ctx->regs + VIDW_WHOLE_Y(win)); | 424 | writel(state->fb->height, ctx->regs + VIDW_WHOLE_Y(win)); |
| 428 | 425 | ||
| 429 | /* offset from the start of the buffer to read */ | 426 | /* offset from the start of the buffer to read */ |
| 430 | writel(plane->src_x, ctx->regs + VIDW_OFFSET_X(win)); | 427 | writel(plane->src_x, ctx->regs + VIDW_OFFSET_X(win)); |
| @@ -433,25 +430,25 @@ static void decon_win_commit(struct exynos_drm_crtc *crtc, unsigned int win) | |||
| 433 | DRM_DEBUG_KMS("start addr = 0x%lx\n", | 430 | DRM_DEBUG_KMS("start addr = 0x%lx\n", |
| 434 | (unsigned long)val); | 431 | (unsigned long)val); |
| 435 | DRM_DEBUG_KMS("ovl_width = %d, ovl_height = %d\n", | 432 | DRM_DEBUG_KMS("ovl_width = %d, ovl_height = %d\n", |
| 436 | plane->crtc_width, plane->crtc_height); | 433 | plane->crtc_w, plane->crtc_h); |
| 437 | 434 | ||
| 438 | /* | 435 | /* |
| 439 | * OSD position. | 436 | * OSD position. |
| 440 | * In case the window layout goes of LCD layout, DECON fails. | 437 | * In case the window layout goes of LCD layout, DECON fails. |
| 441 | */ | 438 | */ |
| 442 | if ((plane->crtc_x + plane->crtc_width) > mode->hdisplay) | 439 | if ((plane->crtc_x + plane->crtc_w) > mode->hdisplay) |
| 443 | plane->crtc_x = mode->hdisplay - plane->crtc_width; | 440 | plane->crtc_x = mode->hdisplay - plane->crtc_w; |
| 444 | if ((plane->crtc_y + plane->crtc_height) > mode->vdisplay) | 441 | if ((plane->crtc_y + plane->crtc_h) > mode->vdisplay) |
| 445 | plane->crtc_y = mode->vdisplay - plane->crtc_height; | 442 | plane->crtc_y = mode->vdisplay - plane->crtc_h; |
| 446 | 443 | ||
| 447 | val = VIDOSDxA_TOPLEFT_X(plane->crtc_x) | | 444 | val = VIDOSDxA_TOPLEFT_X(plane->crtc_x) | |
| 448 | VIDOSDxA_TOPLEFT_Y(plane->crtc_y); | 445 | VIDOSDxA_TOPLEFT_Y(plane->crtc_y); |
| 449 | writel(val, ctx->regs + VIDOSD_A(win)); | 446 | writel(val, ctx->regs + VIDOSD_A(win)); |
| 450 | 447 | ||
| 451 | last_x = plane->crtc_x + plane->crtc_width; | 448 | last_x = plane->crtc_x + plane->crtc_w; |
| 452 | if (last_x) | 449 | if (last_x) |
| 453 | last_x--; | 450 | last_x--; |
| 454 | last_y = plane->crtc_y + plane->crtc_height; | 451 | last_y = plane->crtc_y + plane->crtc_h; |
| 455 | if (last_y) | 452 | if (last_y) |
| 456 | last_y--; | 453 | last_y--; |
| 457 | 454 | ||
| @@ -475,7 +472,7 @@ static void decon_win_commit(struct exynos_drm_crtc *crtc, unsigned int win) | |||
| 475 | 472 | ||
| 476 | writel(alpha, ctx->regs + VIDOSD_D(win)); | 473 | writel(alpha, ctx->regs + VIDOSD_D(win)); |
| 477 | 474 | ||
| 478 | decon_win_set_pixfmt(ctx, win); | 475 | decon_win_set_pixfmt(ctx, win, state->fb); |
| 479 | 476 | ||
| 480 | /* hardware window 0 doesn't support color key. */ | 477 | /* hardware window 0 doesn't support color key. */ |
| 481 | if (win != 0) | 478 | if (win != 0) |
| @@ -495,17 +492,13 @@ static void decon_win_commit(struct exynos_drm_crtc *crtc, unsigned int win) | |||
| 495 | writel(val, ctx->regs + DECON_UPDATE); | 492 | writel(val, ctx->regs + DECON_UPDATE); |
| 496 | } | 493 | } |
| 497 | 494 | ||
| 498 | static void decon_win_disable(struct exynos_drm_crtc *crtc, unsigned int win) | 495 | static void decon_disable_plane(struct exynos_drm_crtc *crtc, |
| 496 | struct exynos_drm_plane *plane) | ||
| 499 | { | 497 | { |
| 500 | struct decon_context *ctx = crtc->ctx; | 498 | struct decon_context *ctx = crtc->ctx; |
| 501 | struct exynos_drm_plane *plane; | 499 | unsigned int win = plane->zpos; |
| 502 | u32 val; | 500 | u32 val; |
| 503 | 501 | ||
| 504 | if (win < 0 || win >= WINDOWS_NR) | ||
| 505 | return; | ||
| 506 | |||
| 507 | plane = &ctx->planes[win]; | ||
| 508 | |||
| 509 | if (ctx->suspended) | 502 | if (ctx->suspended) |
| 510 | return; | 503 | return; |
| 511 | 504 | ||
| @@ -601,7 +594,7 @@ static void decon_disable(struct exynos_drm_crtc *crtc) | |||
| 601 | * a destroyed buffer later. | 594 | * a destroyed buffer later. |
| 602 | */ | 595 | */ |
| 603 | for (i = 0; i < WINDOWS_NR; i++) | 596 | for (i = 0; i < WINDOWS_NR; i++) |
| 604 | decon_win_disable(crtc, i); | 597 | decon_disable_plane(crtc, &ctx->planes[i]); |
| 605 | 598 | ||
| 606 | clk_disable_unprepare(ctx->vclk); | 599 | clk_disable_unprepare(ctx->vclk); |
| 607 | clk_disable_unprepare(ctx->eclk); | 600 | clk_disable_unprepare(ctx->eclk); |
| @@ -621,9 +614,8 @@ static const struct exynos_drm_crtc_ops decon_crtc_ops = { | |||
| 621 | .enable_vblank = decon_enable_vblank, | 614 | .enable_vblank = decon_enable_vblank, |
| 622 | .disable_vblank = decon_disable_vblank, | 615 | .disable_vblank = decon_disable_vblank, |
| 623 | .wait_for_vblank = decon_wait_for_vblank, | 616 | .wait_for_vblank = decon_wait_for_vblank, |
| 624 | .win_commit = decon_win_commit, | 617 | .update_plane = decon_update_plane, |
| 625 | .win_disable = decon_win_disable, | 618 | .disable_plane = decon_disable_plane, |
| 626 | .clear_channels = decon_clear_channels, | ||
| 627 | }; | 619 | }; |
| 628 | 620 | ||
| 629 | 621 | ||
| @@ -643,8 +635,8 @@ static irqreturn_t decon_irq_handler(int irq, void *dev_id) | |||
| 643 | goto out; | 635 | goto out; |
| 644 | 636 | ||
| 645 | if (!ctx->i80_if) { | 637 | if (!ctx->i80_if) { |
| 646 | drm_handle_vblank(ctx->drm_dev, ctx->pipe); | 638 | drm_crtc_handle_vblank(&ctx->crtc->base); |
| 647 | exynos_drm_crtc_finish_pageflip(ctx->drm_dev, ctx->pipe); | 639 | exynos_drm_crtc_finish_pageflip(ctx->crtc); |
| 648 | 640 | ||
| 649 | /* set wait vsync event to zero and wake up queue. */ | 641 | /* set wait vsync event to zero and wake up queue. */ |
| 650 | if (atomic_read(&ctx->wait_vsync_event)) { | 642 | if (atomic_read(&ctx->wait_vsync_event)) { |
| @@ -689,8 +681,8 @@ static int decon_bind(struct device *dev, struct device *master, void *data) | |||
| 689 | return PTR_ERR(ctx->crtc); | 681 | return PTR_ERR(ctx->crtc); |
| 690 | } | 682 | } |
| 691 | 683 | ||
| 692 | if (ctx->display) | 684 | if (ctx->encoder) |
| 693 | exynos_drm_create_enc_conn(drm_dev, ctx->display); | 685 | exynos_dpi_bind(drm_dev, ctx->encoder); |
| 694 | 686 | ||
| 695 | return 0; | 687 | return 0; |
| 696 | 688 | ||
| @@ -703,8 +695,8 @@ static void decon_unbind(struct device *dev, struct device *master, | |||
| 703 | 695 | ||
| 704 | decon_disable(ctx->crtc); | 696 | decon_disable(ctx->crtc); |
| 705 | 697 | ||
| 706 | if (ctx->display) | 698 | if (ctx->encoder) |
| 707 | exynos_dpi_remove(ctx->display); | 699 | exynos_dpi_remove(ctx->encoder); |
| 708 | 700 | ||
| 709 | decon_ctx_remove(ctx); | 701 | decon_ctx_remove(ctx); |
| 710 | } | 702 | } |
| @@ -789,9 +781,9 @@ static int decon_probe(struct platform_device *pdev) | |||
| 789 | 781 | ||
| 790 | platform_set_drvdata(pdev, ctx); | 782 | platform_set_drvdata(pdev, ctx); |
| 791 | 783 | ||
| 792 | ctx->display = exynos_dpi_probe(dev); | 784 | ctx->encoder = exynos_dpi_probe(dev); |
| 793 | if (IS_ERR(ctx->display)) { | 785 | if (IS_ERR(ctx->encoder)) { |
| 794 | ret = PTR_ERR(ctx->display); | 786 | ret = PTR_ERR(ctx->encoder); |
| 795 | goto err_iounmap; | 787 | goto err_iounmap; |
| 796 | } | 788 | } |
| 797 | 789 | ||
diff --git a/drivers/gpu/drm/exynos/exynos_dp_core.c b/drivers/gpu/drm/exynos/exynos_dp_core.c index 172b8002a2c8..d66ade0efac8 100644 --- a/drivers/gpu/drm/exynos/exynos_dp_core.c +++ b/drivers/gpu/drm/exynos/exynos_dp_core.c | |||
| @@ -32,19 +32,20 @@ | |||
| 32 | #include <drm/drm_panel.h> | 32 | #include <drm/drm_panel.h> |
| 33 | 33 | ||
| 34 | #include "exynos_dp_core.h" | 34 | #include "exynos_dp_core.h" |
| 35 | #include "exynos_drm_crtc.h" | ||
| 35 | 36 | ||
| 36 | #define ctx_from_connector(c) container_of(c, struct exynos_dp_device, \ | 37 | #define ctx_from_connector(c) container_of(c, struct exynos_dp_device, \ |
| 37 | connector) | 38 | connector) |
| 38 | 39 | ||
| 39 | static inline struct exynos_drm_crtc *dp_to_crtc(struct exynos_dp_device *dp) | 40 | static inline struct exynos_drm_crtc *dp_to_crtc(struct exynos_dp_device *dp) |
| 40 | { | 41 | { |
| 41 | return to_exynos_crtc(dp->encoder->crtc); | 42 | return to_exynos_crtc(dp->encoder.crtc); |
| 42 | } | 43 | } |
| 43 | 44 | ||
| 44 | static inline struct exynos_dp_device * | 45 | static inline struct exynos_dp_device *encoder_to_dp( |
| 45 | display_to_dp(struct exynos_drm_display *d) | 46 | struct drm_encoder *e) |
| 46 | { | 47 | { |
| 47 | return container_of(d, struct exynos_dp_device, display); | 48 | return container_of(e, struct exynos_dp_device, encoder); |
| 48 | } | 49 | } |
| 49 | 50 | ||
| 50 | struct bridge_init { | 51 | struct bridge_init { |
| @@ -795,9 +796,6 @@ static int exynos_dp_config_video(struct exynos_dp_device *dp) | |||
| 795 | /* Configure video slave mode */ | 796 | /* Configure video slave mode */ |
| 796 | exynos_dp_enable_video_master(dp, 0); | 797 | exynos_dp_enable_video_master(dp, 0); |
| 797 | 798 | ||
| 798 | /* Enable video */ | ||
| 799 | exynos_dp_start_video(dp); | ||
| 800 | |||
| 801 | timeout_loop = 0; | 799 | timeout_loop = 0; |
| 802 | 800 | ||
| 803 | for (;;) { | 801 | for (;;) { |
| @@ -891,9 +889,9 @@ static void exynos_dp_hotplug(struct work_struct *work) | |||
| 891 | drm_helper_hpd_irq_event(dp->drm_dev); | 889 | drm_helper_hpd_irq_event(dp->drm_dev); |
| 892 | } | 890 | } |
| 893 | 891 | ||
| 894 | static void exynos_dp_commit(struct exynos_drm_display *display) | 892 | static void exynos_dp_commit(struct drm_encoder *encoder) |
| 895 | { | 893 | { |
| 896 | struct exynos_dp_device *dp = display_to_dp(display); | 894 | struct exynos_dp_device *dp = encoder_to_dp(encoder); |
| 897 | int ret; | 895 | int ret; |
| 898 | 896 | ||
| 899 | /* Keep the panel disabled while we configure video */ | 897 | /* Keep the panel disabled while we configure video */ |
| @@ -938,6 +936,9 @@ static void exynos_dp_commit(struct exynos_drm_display *display) | |||
| 938 | if (drm_panel_enable(dp->panel)) | 936 | if (drm_panel_enable(dp->panel)) |
| 939 | DRM_ERROR("failed to enable the panel\n"); | 937 | DRM_ERROR("failed to enable the panel\n"); |
| 940 | } | 938 | } |
| 939 | |||
| 940 | /* Enable video */ | ||
| 941 | exynos_dp_start_video(dp); | ||
| 941 | } | 942 | } |
| 942 | 943 | ||
| 943 | static enum drm_connector_status exynos_dp_detect( | 944 | static enum drm_connector_status exynos_dp_detect( |
| @@ -994,7 +995,7 @@ static struct drm_encoder *exynos_dp_best_encoder( | |||
| 994 | { | 995 | { |
| 995 | struct exynos_dp_device *dp = ctx_from_connector(connector); | 996 | struct exynos_dp_device *dp = ctx_from_connector(connector); |
| 996 | 997 | ||
| 997 | return dp->encoder; | 998 | return &dp->encoder; |
| 998 | } | 999 | } |
| 999 | 1000 | ||
| 1000 | static struct drm_connector_helper_funcs exynos_dp_connector_helper_funcs = { | 1001 | static struct drm_connector_helper_funcs exynos_dp_connector_helper_funcs = { |
| @@ -1019,15 +1020,12 @@ static int exynos_drm_attach_lcd_bridge(struct exynos_dp_device *dp, | |||
| 1019 | return 0; | 1020 | return 0; |
| 1020 | } | 1021 | } |
| 1021 | 1022 | ||
| 1022 | static int exynos_dp_create_connector(struct exynos_drm_display *display, | 1023 | static int exynos_dp_create_connector(struct drm_encoder *encoder) |
| 1023 | struct drm_encoder *encoder) | ||
| 1024 | { | 1024 | { |
| 1025 | struct exynos_dp_device *dp = display_to_dp(display); | 1025 | struct exynos_dp_device *dp = encoder_to_dp(encoder); |
| 1026 | struct drm_connector *connector = &dp->connector; | 1026 | struct drm_connector *connector = &dp->connector; |
| 1027 | int ret; | 1027 | int ret; |
| 1028 | 1028 | ||
| 1029 | dp->encoder = encoder; | ||
| 1030 | |||
| 1031 | /* Pre-empt DP connector creation if there's a bridge */ | 1029 | /* Pre-empt DP connector creation if there's a bridge */ |
| 1032 | if (dp->bridge) { | 1030 | if (dp->bridge) { |
| 1033 | ret = exynos_drm_attach_lcd_bridge(dp, encoder); | 1031 | ret = exynos_drm_attach_lcd_bridge(dp, encoder); |
| @@ -1054,20 +1052,22 @@ static int exynos_dp_create_connector(struct exynos_drm_display *display, | |||
| 1054 | return ret; | 1052 | return ret; |
| 1055 | } | 1053 | } |
| 1056 | 1054 | ||
| 1057 | static void exynos_dp_phy_init(struct exynos_dp_device *dp) | 1055 | static bool exynos_dp_mode_fixup(struct drm_encoder *encoder, |
| 1056 | const struct drm_display_mode *mode, | ||
| 1057 | struct drm_display_mode *adjusted_mode) | ||
| 1058 | { | 1058 | { |
| 1059 | if (dp->phy) | 1059 | return true; |
| 1060 | phy_power_on(dp->phy); | ||
| 1061 | } | 1060 | } |
| 1062 | 1061 | ||
| 1063 | static void exynos_dp_phy_exit(struct exynos_dp_device *dp) | 1062 | static void exynos_dp_mode_set(struct drm_encoder *encoder, |
| 1063 | struct drm_display_mode *mode, | ||
| 1064 | struct drm_display_mode *adjusted_mode) | ||
| 1064 | { | 1065 | { |
| 1065 | if (dp->phy) | ||
| 1066 | phy_power_off(dp->phy); | ||
| 1067 | } | 1066 | } |
| 1068 | 1067 | ||
| 1069 | static void exynos_dp_poweron(struct exynos_dp_device *dp) | 1068 | static void exynos_dp_enable(struct drm_encoder *encoder) |
| 1070 | { | 1069 | { |
| 1070 | struct exynos_dp_device *dp = encoder_to_dp(encoder); | ||
| 1071 | struct exynos_drm_crtc *crtc = dp_to_crtc(dp); | 1071 | struct exynos_drm_crtc *crtc = dp_to_crtc(dp); |
| 1072 | 1072 | ||
| 1073 | if (dp->dpms_mode == DRM_MODE_DPMS_ON) | 1073 | if (dp->dpms_mode == DRM_MODE_DPMS_ON) |
| @@ -1084,14 +1084,17 @@ static void exynos_dp_poweron(struct exynos_dp_device *dp) | |||
| 1084 | crtc->ops->clock_enable(dp_to_crtc(dp), true); | 1084 | crtc->ops->clock_enable(dp_to_crtc(dp), true); |
| 1085 | 1085 | ||
| 1086 | clk_prepare_enable(dp->clock); | 1086 | clk_prepare_enable(dp->clock); |
| 1087 | exynos_dp_phy_init(dp); | 1087 | phy_power_on(dp->phy); |
| 1088 | exynos_dp_init_dp(dp); | 1088 | exynos_dp_init_dp(dp); |
| 1089 | enable_irq(dp->irq); | 1089 | enable_irq(dp->irq); |
| 1090 | exynos_dp_commit(&dp->display); | 1090 | exynos_dp_commit(&dp->encoder); |
| 1091 | |||
| 1092 | dp->dpms_mode = DRM_MODE_DPMS_ON; | ||
| 1091 | } | 1093 | } |
| 1092 | 1094 | ||
| 1093 | static void exynos_dp_poweroff(struct exynos_dp_device *dp) | 1095 | static void exynos_dp_disable(struct drm_encoder *encoder) |
| 1094 | { | 1096 | { |
| 1097 | struct exynos_dp_device *dp = encoder_to_dp(encoder); | ||
| 1095 | struct exynos_drm_crtc *crtc = dp_to_crtc(dp); | 1098 | struct exynos_drm_crtc *crtc = dp_to_crtc(dp); |
| 1096 | 1099 | ||
| 1097 | if (dp->dpms_mode != DRM_MODE_DPMS_ON) | 1100 | if (dp->dpms_mode != DRM_MODE_DPMS_ON) |
| @@ -1106,7 +1109,7 @@ static void exynos_dp_poweroff(struct exynos_dp_device *dp) | |||
| 1106 | 1109 | ||
| 1107 | disable_irq(dp->irq); | 1110 | disable_irq(dp->irq); |
| 1108 | flush_work(&dp->hotplug_work); | 1111 | flush_work(&dp->hotplug_work); |
| 1109 | exynos_dp_phy_exit(dp); | 1112 | phy_power_off(dp->phy); |
| 1110 | clk_disable_unprepare(dp->clock); | 1113 | clk_disable_unprepare(dp->clock); |
| 1111 | 1114 | ||
| 1112 | if (crtc->ops->clock_enable) | 1115 | if (crtc->ops->clock_enable) |
| @@ -1116,31 +1119,19 @@ static void exynos_dp_poweroff(struct exynos_dp_device *dp) | |||
| 1116 | if (drm_panel_unprepare(dp->panel)) | 1119 | if (drm_panel_unprepare(dp->panel)) |
| 1117 | DRM_ERROR("failed to turnoff the panel\n"); | 1120 | DRM_ERROR("failed to turnoff the panel\n"); |
| 1118 | } | 1121 | } |
| 1119 | } | ||
| 1120 | |||
| 1121 | static void exynos_dp_dpms(struct exynos_drm_display *display, int mode) | ||
| 1122 | { | ||
| 1123 | struct exynos_dp_device *dp = display_to_dp(display); | ||
| 1124 | 1122 | ||
| 1125 | switch (mode) { | 1123 | dp->dpms_mode = DRM_MODE_DPMS_OFF; |
| 1126 | case DRM_MODE_DPMS_ON: | ||
| 1127 | exynos_dp_poweron(dp); | ||
| 1128 | break; | ||
| 1129 | case DRM_MODE_DPMS_STANDBY: | ||
| 1130 | case DRM_MODE_DPMS_SUSPEND: | ||
| 1131 | case DRM_MODE_DPMS_OFF: | ||
| 1132 | exynos_dp_poweroff(dp); | ||
| 1133 | break; | ||
| 1134 | default: | ||
| 1135 | break; | ||
| 1136 | } | ||
| 1137 | dp->dpms_mode = mode; | ||
| 1138 | } | 1124 | } |
| 1139 | 1125 | ||
| 1140 | static struct exynos_drm_display_ops exynos_dp_display_ops = { | 1126 | static struct drm_encoder_helper_funcs exynos_dp_encoder_helper_funcs = { |
| 1141 | .create_connector = exynos_dp_create_connector, | 1127 | .mode_fixup = exynos_dp_mode_fixup, |
| 1142 | .dpms = exynos_dp_dpms, | 1128 | .mode_set = exynos_dp_mode_set, |
| 1143 | .commit = exynos_dp_commit, | 1129 | .enable = exynos_dp_enable, |
| 1130 | .disable = exynos_dp_disable, | ||
| 1131 | }; | ||
| 1132 | |||
| 1133 | static struct drm_encoder_funcs exynos_dp_encoder_funcs = { | ||
| 1134 | .destroy = drm_encoder_cleanup, | ||
| 1144 | }; | 1135 | }; |
| 1145 | 1136 | ||
| 1146 | static struct video_info *exynos_dp_dt_parse_pdata(struct device *dev) | 1137 | static struct video_info *exynos_dp_dt_parse_pdata(struct device *dev) |
| @@ -1219,9 +1210,10 @@ static int exynos_dp_bind(struct device *dev, struct device *master, void *data) | |||
| 1219 | struct exynos_dp_device *dp = dev_get_drvdata(dev); | 1210 | struct exynos_dp_device *dp = dev_get_drvdata(dev); |
| 1220 | struct platform_device *pdev = to_platform_device(dev); | 1211 | struct platform_device *pdev = to_platform_device(dev); |
| 1221 | struct drm_device *drm_dev = data; | 1212 | struct drm_device *drm_dev = data; |
| 1213 | struct drm_encoder *encoder = &dp->encoder; | ||
| 1222 | struct resource *res; | 1214 | struct resource *res; |
| 1223 | unsigned int irq_flags; | 1215 | unsigned int irq_flags; |
| 1224 | int ret = 0; | 1216 | int pipe, ret = 0; |
| 1225 | 1217 | ||
| 1226 | dp->dev = &pdev->dev; | 1218 | dp->dev = &pdev->dev; |
| 1227 | dp->dpms_mode = DRM_MODE_DPMS_OFF; | 1219 | dp->dpms_mode = DRM_MODE_DPMS_OFF; |
| @@ -1297,7 +1289,7 @@ static int exynos_dp_bind(struct device *dev, struct device *master, void *data) | |||
| 1297 | 1289 | ||
| 1298 | INIT_WORK(&dp->hotplug_work, exynos_dp_hotplug); | 1290 | INIT_WORK(&dp->hotplug_work, exynos_dp_hotplug); |
| 1299 | 1291 | ||
| 1300 | exynos_dp_phy_init(dp); | 1292 | phy_power_on(dp->phy); |
| 1301 | 1293 | ||
| 1302 | exynos_dp_init_dp(dp); | 1294 | exynos_dp_init_dp(dp); |
| 1303 | 1295 | ||
| @@ -1311,7 +1303,28 @@ static int exynos_dp_bind(struct device *dev, struct device *master, void *data) | |||
| 1311 | 1303 | ||
| 1312 | dp->drm_dev = drm_dev; | 1304 | dp->drm_dev = drm_dev; |
| 1313 | 1305 | ||
| 1314 | return exynos_drm_create_enc_conn(drm_dev, &dp->display); | 1306 | pipe = exynos_drm_crtc_get_pipe_from_type(drm_dev, |
| 1307 | EXYNOS_DISPLAY_TYPE_LCD); | ||
| 1308 | if (pipe < 0) | ||
| 1309 | return pipe; | ||
| 1310 | |||
| 1311 | encoder->possible_crtcs = 1 << pipe; | ||
| 1312 | |||
| 1313 | DRM_DEBUG_KMS("possible_crtcs = 0x%x\n", encoder->possible_crtcs); | ||
| 1314 | |||
| 1315 | drm_encoder_init(drm_dev, encoder, &exynos_dp_encoder_funcs, | ||
| 1316 | DRM_MODE_ENCODER_TMDS); | ||
| 1317 | |||
| 1318 | drm_encoder_helper_add(encoder, &exynos_dp_encoder_helper_funcs); | ||
| 1319 | |||
| 1320 | ret = exynos_dp_create_connector(encoder); | ||
| 1321 | if (ret) { | ||
| 1322 | DRM_ERROR("failed to create connector ret = %d\n", ret); | ||
| 1323 | drm_encoder_cleanup(encoder); | ||
| 1324 | return ret; | ||
| 1325 | } | ||
| 1326 | |||
| 1327 | return 0; | ||
| 1315 | } | 1328 | } |
| 1316 | 1329 | ||
| 1317 | static void exynos_dp_unbind(struct device *dev, struct device *master, | 1330 | static void exynos_dp_unbind(struct device *dev, struct device *master, |
| @@ -1319,7 +1332,7 @@ static void exynos_dp_unbind(struct device *dev, struct device *master, | |||
| 1319 | { | 1332 | { |
| 1320 | struct exynos_dp_device *dp = dev_get_drvdata(dev); | 1333 | struct exynos_dp_device *dp = dev_get_drvdata(dev); |
| 1321 | 1334 | ||
| 1322 | exynos_dp_dpms(&dp->display, DRM_MODE_DPMS_OFF); | 1335 | exynos_dp_disable(&dp->encoder); |
| 1323 | } | 1336 | } |
| 1324 | 1337 | ||
| 1325 | static const struct component_ops exynos_dp_ops = { | 1338 | static const struct component_ops exynos_dp_ops = { |
| @@ -1338,8 +1351,6 @@ static int exynos_dp_probe(struct platform_device *pdev) | |||
| 1338 | if (!dp) | 1351 | if (!dp) |
| 1339 | return -ENOMEM; | 1352 | return -ENOMEM; |
| 1340 | 1353 | ||
| 1341 | dp->display.type = EXYNOS_DISPLAY_TYPE_LCD; | ||
| 1342 | dp->display.ops = &exynos_dp_display_ops; | ||
| 1343 | platform_set_drvdata(pdev, dp); | 1354 | platform_set_drvdata(pdev, dp); |
| 1344 | 1355 | ||
| 1345 | panel_node = of_parse_phandle(dev->of_node, "panel", 0); | 1356 | panel_node = of_parse_phandle(dev->of_node, "panel", 0); |
| @@ -1377,7 +1388,7 @@ static int exynos_dp_suspend(struct device *dev) | |||
| 1377 | { | 1388 | { |
| 1378 | struct exynos_dp_device *dp = dev_get_drvdata(dev); | 1389 | struct exynos_dp_device *dp = dev_get_drvdata(dev); |
| 1379 | 1390 | ||
| 1380 | exynos_dp_dpms(&dp->display, DRM_MODE_DPMS_OFF); | 1391 | exynos_dp_disable(&dp->encoder); |
| 1381 | return 0; | 1392 | return 0; |
| 1382 | } | 1393 | } |
| 1383 | 1394 | ||
| @@ -1385,7 +1396,7 @@ static int exynos_dp_resume(struct device *dev) | |||
| 1385 | { | 1396 | { |
| 1386 | struct exynos_dp_device *dp = dev_get_drvdata(dev); | 1397 | struct exynos_dp_device *dp = dev_get_drvdata(dev); |
| 1387 | 1398 | ||
| 1388 | exynos_dp_dpms(&dp->display, DRM_MODE_DPMS_ON); | 1399 | exynos_dp_enable(&dp->encoder); |
| 1389 | return 0; | 1400 | return 0; |
| 1390 | } | 1401 | } |
| 1391 | #endif | 1402 | #endif |
diff --git a/drivers/gpu/drm/exynos/exynos_dp_core.h b/drivers/gpu/drm/exynos/exynos_dp_core.h index a4e799679669..e413b6f7b0e7 100644 --- a/drivers/gpu/drm/exynos/exynos_dp_core.h +++ b/drivers/gpu/drm/exynos/exynos_dp_core.h | |||
| @@ -147,11 +147,10 @@ struct link_train { | |||
| 147 | }; | 147 | }; |
| 148 | 148 | ||
| 149 | struct exynos_dp_device { | 149 | struct exynos_dp_device { |
| 150 | struct exynos_drm_display display; | 150 | struct drm_encoder encoder; |
| 151 | struct device *dev; | 151 | struct device *dev; |
| 152 | struct drm_device *drm_dev; | 152 | struct drm_device *drm_dev; |
| 153 | struct drm_connector connector; | 153 | struct drm_connector connector; |
| 154 | struct drm_encoder *encoder; | ||
| 155 | struct drm_panel *panel; | 154 | struct drm_panel *panel; |
| 156 | struct drm_bridge *bridge; | 155 | struct drm_bridge *bridge; |
| 157 | struct clk *clock; | 156 | struct clk *clock; |
diff --git a/drivers/gpu/drm/exynos/exynos_drm_buf.c b/drivers/gpu/drm/exynos/exynos_drm_buf.c deleted file mode 100644 index 24994ba10e28..000000000000 --- a/drivers/gpu/drm/exynos/exynos_drm_buf.c +++ /dev/null | |||
| @@ -1,186 +0,0 @@ | |||
| 1 | /* exynos_drm_buf.c | ||
| 2 | * | ||
| 3 | * Copyright (c) 2011 Samsung Electronics Co., Ltd. | ||
| 4 | * Author: Inki Dae <inki.dae@samsung.com> | ||
| 5 | * | ||
| 6 | * This program is free software; you can redistribute it and/or modify it | ||
| 7 | * under the terms of the GNU General Public License as published by the | ||
| 8 | * Free Software Foundation; either version 2 of the License, or (at your | ||
| 9 | * option) any later version. | ||
| 10 | */ | ||
| 11 | |||
| 12 | #include <drm/drmP.h> | ||
| 13 | #include <drm/exynos_drm.h> | ||
| 14 | |||
| 15 | #include "exynos_drm_drv.h" | ||
| 16 | #include "exynos_drm_gem.h" | ||
| 17 | #include "exynos_drm_buf.h" | ||
| 18 | #include "exynos_drm_iommu.h" | ||
| 19 | |||
| 20 | static int lowlevel_buffer_allocate(struct drm_device *dev, | ||
| 21 | unsigned int flags, struct exynos_drm_gem_buf *buf) | ||
| 22 | { | ||
| 23 | int ret = 0; | ||
| 24 | enum dma_attr attr; | ||
| 25 | unsigned int nr_pages; | ||
| 26 | |||
| 27 | if (buf->dma_addr) { | ||
| 28 | DRM_DEBUG_KMS("already allocated.\n"); | ||
| 29 | return 0; | ||
| 30 | } | ||
| 31 | |||
| 32 | init_dma_attrs(&buf->dma_attrs); | ||
| 33 | |||
| 34 | /* | ||
| 35 | * if EXYNOS_BO_CONTIG, fully physically contiguous memory | ||
| 36 | * region will be allocated else physically contiguous | ||
| 37 | * as possible. | ||
| 38 | */ | ||
| 39 | if (!(flags & EXYNOS_BO_NONCONTIG)) | ||
| 40 | dma_set_attr(DMA_ATTR_FORCE_CONTIGUOUS, &buf->dma_attrs); | ||
| 41 | |||
| 42 | /* | ||
| 43 | * if EXYNOS_BO_WC or EXYNOS_BO_NONCACHABLE, writecombine mapping | ||
| 44 | * else cachable mapping. | ||
| 45 | */ | ||
| 46 | if (flags & EXYNOS_BO_WC || !(flags & EXYNOS_BO_CACHABLE)) | ||
| 47 | attr = DMA_ATTR_WRITE_COMBINE; | ||
| 48 | else | ||
| 49 | attr = DMA_ATTR_NON_CONSISTENT; | ||
| 50 | |||
| 51 | dma_set_attr(attr, &buf->dma_attrs); | ||
| 52 | dma_set_attr(DMA_ATTR_NO_KERNEL_MAPPING, &buf->dma_attrs); | ||
| 53 | |||
| 54 | nr_pages = buf->size >> PAGE_SHIFT; | ||
| 55 | |||
| 56 | if (!is_drm_iommu_supported(dev)) { | ||
| 57 | dma_addr_t start_addr; | ||
| 58 | unsigned int i = 0; | ||
| 59 | |||
| 60 | buf->pages = drm_calloc_large(nr_pages, sizeof(struct page *)); | ||
| 61 | if (!buf->pages) { | ||
| 62 | DRM_ERROR("failed to allocate pages.\n"); | ||
| 63 | return -ENOMEM; | ||
| 64 | } | ||
| 65 | |||
| 66 | buf->cookie = dma_alloc_attrs(dev->dev, | ||
| 67 | buf->size, | ||
| 68 | &buf->dma_addr, GFP_KERNEL, | ||
| 69 | &buf->dma_attrs); | ||
| 70 | if (!buf->cookie) { | ||
| 71 | DRM_ERROR("failed to allocate buffer.\n"); | ||
| 72 | ret = -ENOMEM; | ||
| 73 | goto err_free; | ||
| 74 | } | ||
| 75 | |||
| 76 | start_addr = buf->dma_addr; | ||
| 77 | while (i < nr_pages) { | ||
| 78 | buf->pages[i] = phys_to_page(start_addr); | ||
| 79 | start_addr += PAGE_SIZE; | ||
| 80 | i++; | ||
| 81 | } | ||
| 82 | } else { | ||
| 83 | |||
| 84 | buf->pages = dma_alloc_attrs(dev->dev, buf->size, | ||
| 85 | &buf->dma_addr, GFP_KERNEL, | ||
| 86 | &buf->dma_attrs); | ||
| 87 | if (!buf->pages) { | ||
| 88 | DRM_ERROR("failed to allocate buffer.\n"); | ||
| 89 | return -ENOMEM; | ||
| 90 | } | ||
| 91 | } | ||
| 92 | |||
| 93 | buf->sgt = drm_prime_pages_to_sg(buf->pages, nr_pages); | ||
| 94 | if (IS_ERR(buf->sgt)) { | ||
| 95 | DRM_ERROR("failed to get sg table.\n"); | ||
| 96 | ret = PTR_ERR(buf->sgt); | ||
| 97 | goto err_free_attrs; | ||
| 98 | } | ||
| 99 | |||
| 100 | DRM_DEBUG_KMS("dma_addr(0x%lx), size(0x%lx)\n", | ||
| 101 | (unsigned long)buf->dma_addr, | ||
| 102 | buf->size); | ||
| 103 | |||
| 104 | return ret; | ||
| 105 | |||
| 106 | err_free_attrs: | ||
| 107 | dma_free_attrs(dev->dev, buf->size, buf->pages, | ||
| 108 | (dma_addr_t)buf->dma_addr, &buf->dma_attrs); | ||
| 109 | buf->dma_addr = (dma_addr_t)NULL; | ||
| 110 | err_free: | ||
| 111 | if (!is_drm_iommu_supported(dev)) | ||
| 112 | drm_free_large(buf->pages); | ||
| 113 | |||
| 114 | return ret; | ||
| 115 | } | ||
| 116 | |||
| 117 | static void lowlevel_buffer_deallocate(struct drm_device *dev, | ||
| 118 | unsigned int flags, struct exynos_drm_gem_buf *buf) | ||
| 119 | { | ||
| 120 | if (!buf->dma_addr) { | ||
| 121 | DRM_DEBUG_KMS("dma_addr is invalid.\n"); | ||
| 122 | return; | ||
| 123 | } | ||
| 124 | |||
| 125 | DRM_DEBUG_KMS("dma_addr(0x%lx), size(0x%lx)\n", | ||
| 126 | (unsigned long)buf->dma_addr, | ||
| 127 | buf->size); | ||
| 128 | |||
| 129 | sg_free_table(buf->sgt); | ||
| 130 | |||
| 131 | kfree(buf->sgt); | ||
| 132 | buf->sgt = NULL; | ||
| 133 | |||
| 134 | if (!is_drm_iommu_supported(dev)) { | ||
| 135 | dma_free_attrs(dev->dev, buf->size, buf->cookie, | ||
| 136 | (dma_addr_t)buf->dma_addr, &buf->dma_attrs); | ||
| 137 | drm_free_large(buf->pages); | ||
| 138 | } else | ||
| 139 | dma_free_attrs(dev->dev, buf->size, buf->pages, | ||
| 140 | (dma_addr_t)buf->dma_addr, &buf->dma_attrs); | ||
| 141 | |||
| 142 | buf->dma_addr = (dma_addr_t)NULL; | ||
| 143 | } | ||
| 144 | |||
| 145 | struct exynos_drm_gem_buf *exynos_drm_init_buf(struct drm_device *dev, | ||
| 146 | unsigned int size) | ||
| 147 | { | ||
| 148 | struct exynos_drm_gem_buf *buffer; | ||
| 149 | |||
| 150 | DRM_DEBUG_KMS("desired size = 0x%x\n", size); | ||
| 151 | |||
| 152 | buffer = kzalloc(sizeof(*buffer), GFP_KERNEL); | ||
| 153 | if (!buffer) | ||
| 154 | return NULL; | ||
| 155 | |||
| 156 | buffer->size = size; | ||
| 157 | return buffer; | ||
| 158 | } | ||
| 159 | |||
| 160 | void exynos_drm_fini_buf(struct drm_device *dev, | ||
| 161 | struct exynos_drm_gem_buf *buffer) | ||
| 162 | { | ||
| 163 | kfree(buffer); | ||
| 164 | buffer = NULL; | ||
| 165 | } | ||
| 166 | |||
| 167 | int exynos_drm_alloc_buf(struct drm_device *dev, | ||
| 168 | struct exynos_drm_gem_buf *buf, unsigned int flags) | ||
| 169 | { | ||
| 170 | |||
| 171 | /* | ||
| 172 | * allocate memory region and set the memory information | ||
| 173 | * to vaddr and dma_addr of a buffer object. | ||
| 174 | */ | ||
| 175 | if (lowlevel_buffer_allocate(dev, flags, buf) < 0) | ||
| 176 | return -ENOMEM; | ||
| 177 | |||
| 178 | return 0; | ||
| 179 | } | ||
| 180 | |||
| 181 | void exynos_drm_free_buf(struct drm_device *dev, | ||
| 182 | unsigned int flags, struct exynos_drm_gem_buf *buffer) | ||
| 183 | { | ||
| 184 | |||
| 185 | lowlevel_buffer_deallocate(dev, flags, buffer); | ||
| 186 | } | ||
diff --git a/drivers/gpu/drm/exynos/exynos_drm_buf.h b/drivers/gpu/drm/exynos/exynos_drm_buf.h deleted file mode 100644 index a6412f19673c..000000000000 --- a/drivers/gpu/drm/exynos/exynos_drm_buf.h +++ /dev/null | |||
| @@ -1,33 +0,0 @@ | |||
| 1 | /* exynos_drm_buf.h | ||
| 2 | * | ||
| 3 | * Copyright (c) 2011 Samsung Electronics Co., Ltd. | ||
| 4 | * Author: Inki Dae <inki.dae@samsung.com> | ||
| 5 | * | ||
| 6 | * This program is free software; you can redistribute it and/or modify it | ||
| 7 | * under the terms of the GNU General Public License as published by the | ||
| 8 | * Free Software Foundation; either version 2 of the License, or (at your | ||
| 9 | * option) any later version. | ||
| 10 | */ | ||
| 11 | |||
| 12 | #ifndef _EXYNOS_DRM_BUF_H_ | ||
| 13 | #define _EXYNOS_DRM_BUF_H_ | ||
| 14 | |||
| 15 | /* create and initialize buffer object. */ | ||
| 16 | struct exynos_drm_gem_buf *exynos_drm_init_buf(struct drm_device *dev, | ||
| 17 | unsigned int size); | ||
| 18 | |||
| 19 | /* destroy buffer object. */ | ||
| 20 | void exynos_drm_fini_buf(struct drm_device *dev, | ||
| 21 | struct exynos_drm_gem_buf *buffer); | ||
| 22 | |||
| 23 | /* allocate physical memory region and setup sgt. */ | ||
| 24 | int exynos_drm_alloc_buf(struct drm_device *dev, | ||
| 25 | struct exynos_drm_gem_buf *buf, | ||
| 26 | unsigned int flags); | ||
| 27 | |||
| 28 | /* release physical memory region, and sgt. */ | ||
| 29 | void exynos_drm_free_buf(struct drm_device *dev, | ||
| 30 | unsigned int flags, | ||
| 31 | struct exynos_drm_gem_buf *buffer); | ||
| 32 | |||
| 33 | #endif | ||
diff --git a/drivers/gpu/drm/exynos/exynos_drm_core.c b/drivers/gpu/drm/exynos/exynos_drm_core.c index 4c9f972eaa07..c68a6a2a9b57 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_core.c +++ b/drivers/gpu/drm/exynos/exynos_drm_core.c | |||
| @@ -15,46 +15,10 @@ | |||
| 15 | #include <drm/drmP.h> | 15 | #include <drm/drmP.h> |
| 16 | #include "exynos_drm_drv.h" | 16 | #include "exynos_drm_drv.h" |
| 17 | #include "exynos_drm_crtc.h" | 17 | #include "exynos_drm_crtc.h" |
| 18 | #include "exynos_drm_encoder.h" | ||
| 19 | #include "exynos_drm_fbdev.h" | 18 | #include "exynos_drm_fbdev.h" |
| 20 | 19 | ||
| 21 | static LIST_HEAD(exynos_drm_subdrv_list); | 20 | static LIST_HEAD(exynos_drm_subdrv_list); |
| 22 | 21 | ||
| 23 | int exynos_drm_create_enc_conn(struct drm_device *dev, | ||
| 24 | struct exynos_drm_display *display) | ||
| 25 | { | ||
| 26 | struct drm_encoder *encoder; | ||
| 27 | int ret; | ||
| 28 | unsigned long possible_crtcs = 0; | ||
| 29 | |||
| 30 | ret = exynos_drm_crtc_get_pipe_from_type(dev, display->type); | ||
| 31 | if (ret < 0) | ||
| 32 | return ret; | ||
| 33 | |||
| 34 | possible_crtcs |= 1 << ret; | ||
| 35 | |||
| 36 | /* create and initialize a encoder for this sub driver. */ | ||
| 37 | encoder = exynos_drm_encoder_create(dev, display, possible_crtcs); | ||
| 38 | if (!encoder) { | ||
| 39 | DRM_ERROR("failed to create encoder\n"); | ||
| 40 | return -EFAULT; | ||
| 41 | } | ||
| 42 | |||
| 43 | display->encoder = encoder; | ||
| 44 | |||
| 45 | ret = display->ops->create_connector(display, encoder); | ||
| 46 | if (ret) { | ||
| 47 | DRM_ERROR("failed to create connector ret = %d\n", ret); | ||
| 48 | goto err_destroy_encoder; | ||
| 49 | } | ||
| 50 | |||
| 51 | return 0; | ||
| 52 | |||
| 53 | err_destroy_encoder: | ||
| 54 | encoder->funcs->destroy(encoder); | ||
| 55 | return ret; | ||
| 56 | } | ||
| 57 | |||
| 58 | int exynos_drm_subdrv_register(struct exynos_drm_subdrv *subdrv) | 22 | int exynos_drm_subdrv_register(struct exynos_drm_subdrv *subdrv) |
| 59 | { | 23 | { |
| 60 | if (!subdrv) | 24 | if (!subdrv) |
diff --git a/drivers/gpu/drm/exynos/exynos_drm_crtc.c b/drivers/gpu/drm/exynos/exynos_drm_crtc.c index 1610757230a5..c47899738eb4 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_crtc.c +++ b/drivers/gpu/drm/exynos/exynos_drm_crtc.c | |||
| @@ -19,7 +19,6 @@ | |||
| 19 | 19 | ||
| 20 | #include "exynos_drm_crtc.h" | 20 | #include "exynos_drm_crtc.h" |
| 21 | #include "exynos_drm_drv.h" | 21 | #include "exynos_drm_drv.h" |
| 22 | #include "exynos_drm_encoder.h" | ||
| 23 | #include "exynos_drm_plane.h" | 22 | #include "exynos_drm_plane.h" |
| 24 | 23 | ||
| 25 | static void exynos_drm_crtc_enable(struct drm_crtc *crtc) | 24 | static void exynos_drm_crtc_enable(struct drm_crtc *crtc) |
| @@ -177,7 +176,7 @@ int exynos_drm_crtc_enable_vblank(struct drm_device *dev, int pipe) | |||
| 177 | return -EPERM; | 176 | return -EPERM; |
| 178 | 177 | ||
| 179 | if (exynos_crtc->ops->enable_vblank) | 178 | if (exynos_crtc->ops->enable_vblank) |
| 180 | exynos_crtc->ops->enable_vblank(exynos_crtc); | 179 | return exynos_crtc->ops->enable_vblank(exynos_crtc); |
| 181 | 180 | ||
| 182 | return 0; | 181 | return 0; |
| 183 | } | 182 | } |
| @@ -195,24 +194,22 @@ void exynos_drm_crtc_disable_vblank(struct drm_device *dev, int pipe) | |||
| 195 | exynos_crtc->ops->disable_vblank(exynos_crtc); | 194 | exynos_crtc->ops->disable_vblank(exynos_crtc); |
| 196 | } | 195 | } |
| 197 | 196 | ||
| 198 | void exynos_drm_crtc_finish_pageflip(struct drm_device *dev, int pipe) | 197 | void exynos_drm_crtc_finish_pageflip(struct exynos_drm_crtc *exynos_crtc) |
| 199 | { | 198 | { |
| 200 | struct exynos_drm_private *dev_priv = dev->dev_private; | 199 | struct drm_crtc *crtc = &exynos_crtc->base; |
| 201 | struct drm_crtc *drm_crtc = dev_priv->crtc[pipe]; | ||
| 202 | struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(drm_crtc); | ||
| 203 | unsigned long flags; | 200 | unsigned long flags; |
| 204 | 201 | ||
| 205 | spin_lock_irqsave(&dev->event_lock, flags); | 202 | spin_lock_irqsave(&crtc->dev->event_lock, flags); |
| 206 | if (exynos_crtc->event) { | 203 | if (exynos_crtc->event) { |
| 207 | 204 | ||
| 208 | drm_send_vblank_event(dev, -1, exynos_crtc->event); | 205 | drm_crtc_send_vblank_event(crtc, exynos_crtc->event); |
| 209 | drm_vblank_put(dev, pipe); | 206 | drm_crtc_vblank_put(crtc); |
| 210 | wake_up(&exynos_crtc->pending_flip_queue); | 207 | wake_up(&exynos_crtc->pending_flip_queue); |
| 211 | 208 | ||
| 212 | } | 209 | } |
| 213 | 210 | ||
| 214 | exynos_crtc->event = NULL; | 211 | exynos_crtc->event = NULL; |
| 215 | spin_unlock_irqrestore(&dev->event_lock, flags); | 212 | spin_unlock_irqrestore(&crtc->dev->event_lock, flags); |
| 216 | } | 213 | } |
| 217 | 214 | ||
| 218 | void exynos_drm_crtc_complete_scanout(struct drm_framebuffer *fb) | 215 | void exynos_drm_crtc_complete_scanout(struct drm_framebuffer *fb) |
| @@ -239,7 +236,7 @@ void exynos_drm_crtc_complete_scanout(struct drm_framebuffer *fb) | |||
| 239 | } | 236 | } |
| 240 | 237 | ||
| 241 | int exynos_drm_crtc_get_pipe_from_type(struct drm_device *drm_dev, | 238 | int exynos_drm_crtc_get_pipe_from_type(struct drm_device *drm_dev, |
| 242 | unsigned int out_type) | 239 | enum exynos_drm_output_type out_type) |
| 243 | { | 240 | { |
| 244 | struct drm_crtc *crtc; | 241 | struct drm_crtc *crtc; |
| 245 | 242 | ||
diff --git a/drivers/gpu/drm/exynos/exynos_drm_crtc.h b/drivers/gpu/drm/exynos/exynos_drm_crtc.h index 0f3aa70818e3..9e7027d6c2f6 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_crtc.h +++ b/drivers/gpu/drm/exynos/exynos_drm_crtc.h | |||
| @@ -25,12 +25,12 @@ struct exynos_drm_crtc *exynos_drm_crtc_create(struct drm_device *drm_dev, | |||
| 25 | void *context); | 25 | void *context); |
| 26 | int exynos_drm_crtc_enable_vblank(struct drm_device *dev, int pipe); | 26 | int exynos_drm_crtc_enable_vblank(struct drm_device *dev, int pipe); |
| 27 | void exynos_drm_crtc_disable_vblank(struct drm_device *dev, int pipe); | 27 | void exynos_drm_crtc_disable_vblank(struct drm_device *dev, int pipe); |
| 28 | void exynos_drm_crtc_finish_pageflip(struct drm_device *dev, int pipe); | 28 | void exynos_drm_crtc_finish_pageflip(struct exynos_drm_crtc *exynos_crtc); |
| 29 | void exynos_drm_crtc_complete_scanout(struct drm_framebuffer *fb); | 29 | void exynos_drm_crtc_complete_scanout(struct drm_framebuffer *fb); |
| 30 | 30 | ||
| 31 | /* This function gets pipe value to crtc device matched with out_type. */ | 31 | /* This function gets pipe value to crtc device matched with out_type. */ |
| 32 | int exynos_drm_crtc_get_pipe_from_type(struct drm_device *drm_dev, | 32 | int exynos_drm_crtc_get_pipe_from_type(struct drm_device *drm_dev, |
| 33 | unsigned int out_type); | 33 | enum exynos_drm_output_type out_type); |
| 34 | 34 | ||
| 35 | /* | 35 | /* |
| 36 | * This function calls the crtc device(manager)'s te_handler() callback | 36 | * This function calls the crtc device(manager)'s te_handler() callback |
diff --git a/drivers/gpu/drm/exynos/exynos_drm_dmabuf.c b/drivers/gpu/drm/exynos/exynos_drm_dmabuf.c deleted file mode 100644 index cd485c091b30..000000000000 --- a/drivers/gpu/drm/exynos/exynos_drm_dmabuf.c +++ /dev/null | |||
| @@ -1,286 +0,0 @@ | |||
| 1 | /* exynos_drm_dmabuf.c | ||
| 2 | * | ||
| 3 | * Copyright (c) 2012 Samsung Electronics Co., Ltd. | ||
| 4 | * Author: Inki Dae <inki.dae@samsung.com> | ||
| 5 | * | ||
| 6 | * This program is free software; you can redistribute it and/or modify it | ||
| 7 | * under the terms of the GNU General Public License as published by the | ||
| 8 | * Free Software Foundation; either version 2 of the License, or (at your | ||
| 9 | * option) any later version. | ||
| 10 | */ | ||
| 11 | |||
| 12 | #include <drm/drmP.h> | ||
| 13 | #include <drm/exynos_drm.h> | ||
| 14 | #include "exynos_drm_dmabuf.h" | ||
| 15 | #include "exynos_drm_drv.h" | ||
| 16 | #include "exynos_drm_gem.h" | ||
| 17 | |||
| 18 | #include <linux/dma-buf.h> | ||
| 19 | |||
| 20 | struct exynos_drm_dmabuf_attachment { | ||
| 21 | struct sg_table sgt; | ||
| 22 | enum dma_data_direction dir; | ||
| 23 | bool is_mapped; | ||
| 24 | }; | ||
| 25 | |||
| 26 | static struct exynos_drm_gem_obj *dma_buf_to_obj(struct dma_buf *buf) | ||
| 27 | { | ||
| 28 | return to_exynos_gem_obj(buf->priv); | ||
| 29 | } | ||
| 30 | |||
| 31 | static int exynos_gem_attach_dma_buf(struct dma_buf *dmabuf, | ||
| 32 | struct device *dev, | ||
| 33 | struct dma_buf_attachment *attach) | ||
| 34 | { | ||
| 35 | struct exynos_drm_dmabuf_attachment *exynos_attach; | ||
| 36 | |||
| 37 | exynos_attach = kzalloc(sizeof(*exynos_attach), GFP_KERNEL); | ||
| 38 | if (!exynos_attach) | ||
| 39 | return -ENOMEM; | ||
| 40 | |||
| 41 | exynos_attach->dir = DMA_NONE; | ||
| 42 | attach->priv = exynos_attach; | ||
| 43 | |||
| 44 | return 0; | ||
| 45 | } | ||
| 46 | |||
| 47 | static void exynos_gem_detach_dma_buf(struct dma_buf *dmabuf, | ||
| 48 | struct dma_buf_attachment *attach) | ||
| 49 | { | ||
| 50 | struct exynos_drm_dmabuf_attachment *exynos_attach = attach->priv; | ||
| 51 | struct sg_table *sgt; | ||
| 52 | |||
| 53 | if (!exynos_attach) | ||
| 54 | return; | ||
| 55 | |||
| 56 | sgt = &exynos_attach->sgt; | ||
| 57 | |||
| 58 | if (exynos_attach->dir != DMA_NONE) | ||
| 59 | dma_unmap_sg(attach->dev, sgt->sgl, sgt->nents, | ||
| 60 | exynos_attach->dir); | ||
| 61 | |||
| 62 | sg_free_table(sgt); | ||
| 63 | kfree(exynos_attach); | ||
| 64 | attach->priv = NULL; | ||
| 65 | } | ||
| 66 | |||
| 67 | static struct sg_table * | ||
| 68 | exynos_gem_map_dma_buf(struct dma_buf_attachment *attach, | ||
| 69 | enum dma_data_direction dir) | ||
| 70 | { | ||
| 71 | struct exynos_drm_dmabuf_attachment *exynos_attach = attach->priv; | ||
| 72 | struct exynos_drm_gem_obj *gem_obj = dma_buf_to_obj(attach->dmabuf); | ||
| 73 | struct drm_device *dev = gem_obj->base.dev; | ||
| 74 | struct exynos_drm_gem_buf *buf; | ||
| 75 | struct scatterlist *rd, *wr; | ||
| 76 | struct sg_table *sgt = NULL; | ||
| 77 | unsigned int i; | ||
| 78 | int nents, ret; | ||
| 79 | |||
| 80 | /* just return current sgt if already requested. */ | ||
| 81 | if (exynos_attach->dir == dir && exynos_attach->is_mapped) | ||
| 82 | return &exynos_attach->sgt; | ||
| 83 | |||
| 84 | buf = gem_obj->buffer; | ||
| 85 | if (!buf) { | ||
| 86 | DRM_ERROR("buffer is null.\n"); | ||
| 87 | return ERR_PTR(-ENOMEM); | ||
| 88 | } | ||
| 89 | |||
| 90 | sgt = &exynos_attach->sgt; | ||
| 91 | |||
| 92 | ret = sg_alloc_table(sgt, buf->sgt->orig_nents, GFP_KERNEL); | ||
| 93 | if (ret) { | ||
| 94 | DRM_ERROR("failed to alloc sgt.\n"); | ||
| 95 | return ERR_PTR(-ENOMEM); | ||
| 96 | } | ||
| 97 | |||
| 98 | mutex_lock(&dev->struct_mutex); | ||
| 99 | |||
| 100 | rd = buf->sgt->sgl; | ||
| 101 | wr = sgt->sgl; | ||
| 102 | for (i = 0; i < sgt->orig_nents; ++i) { | ||
| 103 | sg_set_page(wr, sg_page(rd), rd->length, rd->offset); | ||
| 104 | rd = sg_next(rd); | ||
| 105 | wr = sg_next(wr); | ||
| 106 | } | ||
| 107 | |||
| 108 | if (dir != DMA_NONE) { | ||
| 109 | nents = dma_map_sg(attach->dev, sgt->sgl, sgt->orig_nents, dir); | ||
| 110 | if (!nents) { | ||
| 111 | DRM_ERROR("failed to map sgl with iommu.\n"); | ||
| 112 | sg_free_table(sgt); | ||
| 113 | sgt = ERR_PTR(-EIO); | ||
| 114 | goto err_unlock; | ||
| 115 | } | ||
| 116 | } | ||
| 117 | |||
| 118 | exynos_attach->is_mapped = true; | ||
| 119 | exynos_attach->dir = dir; | ||
| 120 | attach->priv = exynos_attach; | ||
| 121 | |||
| 122 | DRM_DEBUG_PRIME("buffer size = 0x%lx\n", buf->size); | ||
| 123 | |||
| 124 | err_unlock: | ||
| 125 | mutex_unlock(&dev->struct_mutex); | ||
| 126 | return sgt; | ||
| 127 | } | ||
| 128 | |||
| 129 | static void exynos_gem_unmap_dma_buf(struct dma_buf_attachment *attach, | ||
| 130 | struct sg_table *sgt, | ||
| 131 | enum dma_data_direction dir) | ||
| 132 | { | ||
| 133 | /* Nothing to do. */ | ||
| 134 | } | ||
| 135 | |||
| 136 | static void *exynos_gem_dmabuf_kmap_atomic(struct dma_buf *dma_buf, | ||
| 137 | unsigned long page_num) | ||
| 138 | { | ||
| 139 | /* TODO */ | ||
| 140 | |||
| 141 | return NULL; | ||
| 142 | } | ||
| 143 | |||
| 144 | static void exynos_gem_dmabuf_kunmap_atomic(struct dma_buf *dma_buf, | ||
| 145 | unsigned long page_num, | ||
| 146 | void *addr) | ||
| 147 | { | ||
| 148 | /* TODO */ | ||
| 149 | } | ||
| 150 | |||
| 151 | static void *exynos_gem_dmabuf_kmap(struct dma_buf *dma_buf, | ||
| 152 | unsigned long page_num) | ||
| 153 | { | ||
| 154 | /* TODO */ | ||
| 155 | |||
| 156 | return NULL; | ||
| 157 | } | ||
| 158 | |||
| 159 | static void exynos_gem_dmabuf_kunmap(struct dma_buf *dma_buf, | ||
| 160 | unsigned long page_num, void *addr) | ||
| 161 | { | ||
| 162 | /* TODO */ | ||
| 163 | } | ||
| 164 | |||
| 165 | static int exynos_gem_dmabuf_mmap(struct dma_buf *dma_buf, | ||
| 166 | struct vm_area_struct *vma) | ||
| 167 | { | ||
| 168 | return -ENOTTY; | ||
| 169 | } | ||
| 170 | |||
| 171 | static struct dma_buf_ops exynos_dmabuf_ops = { | ||
| 172 | .attach = exynos_gem_attach_dma_buf, | ||
| 173 | .detach = exynos_gem_detach_dma_buf, | ||
| 174 | .map_dma_buf = exynos_gem_map_dma_buf, | ||
| 175 | .unmap_dma_buf = exynos_gem_unmap_dma_buf, | ||
| 176 | .kmap = exynos_gem_dmabuf_kmap, | ||
| 177 | .kmap_atomic = exynos_gem_dmabuf_kmap_atomic, | ||
| 178 | .kunmap = exynos_gem_dmabuf_kunmap, | ||
| 179 | .kunmap_atomic = exynos_gem_dmabuf_kunmap_atomic, | ||
| 180 | .mmap = exynos_gem_dmabuf_mmap, | ||
| 181 | .release = drm_gem_dmabuf_release, | ||
| 182 | }; | ||
| 183 | |||
| 184 | struct dma_buf *exynos_dmabuf_prime_export(struct drm_device *drm_dev, | ||
| 185 | struct drm_gem_object *obj, int flags) | ||
| 186 | { | ||
| 187 | struct exynos_drm_gem_obj *exynos_gem_obj = to_exynos_gem_obj(obj); | ||
| 188 | DEFINE_DMA_BUF_EXPORT_INFO(exp_info); | ||
| 189 | |||
| 190 | exp_info.ops = &exynos_dmabuf_ops; | ||
| 191 | exp_info.size = exynos_gem_obj->base.size; | ||
| 192 | exp_info.flags = flags; | ||
| 193 | exp_info.priv = obj; | ||
| 194 | |||
| 195 | return dma_buf_export(&exp_info); | ||
| 196 | } | ||
| 197 | |||
| 198 | struct drm_gem_object *exynos_dmabuf_prime_import(struct drm_device *drm_dev, | ||
| 199 | struct dma_buf *dma_buf) | ||
| 200 | { | ||
| 201 | struct dma_buf_attachment *attach; | ||
| 202 | struct sg_table *sgt; | ||
| 203 | struct scatterlist *sgl; | ||
| 204 | struct exynos_drm_gem_obj *exynos_gem_obj; | ||
| 205 | struct exynos_drm_gem_buf *buffer; | ||
| 206 | int ret; | ||
| 207 | |||
| 208 | /* is this one of own objects? */ | ||
| 209 | if (dma_buf->ops == &exynos_dmabuf_ops) { | ||
| 210 | struct drm_gem_object *obj; | ||
| 211 | |||
| 212 | obj = dma_buf->priv; | ||
| 213 | |||
| 214 | /* is it from our device? */ | ||
| 215 | if (obj->dev == drm_dev) { | ||
| 216 | /* | ||
| 217 | * Importing dmabuf exported from out own gem increases | ||
| 218 | * refcount on gem itself instead of f_count of dmabuf. | ||
| 219 | */ | ||
| 220 | drm_gem_object_reference(obj); | ||
| 221 | return obj; | ||
| 222 | } | ||
| 223 | } | ||
| 224 | |||
| 225 | attach = dma_buf_attach(dma_buf, drm_dev->dev); | ||
| 226 | if (IS_ERR(attach)) | ||
| 227 | return ERR_PTR(-EINVAL); | ||
| 228 | |||
| 229 | get_dma_buf(dma_buf); | ||
| 230 | |||
| 231 | sgt = dma_buf_map_attachment(attach, DMA_BIDIRECTIONAL); | ||
| 232 | if (IS_ERR(sgt)) { | ||
| 233 | ret = PTR_ERR(sgt); | ||
| 234 | goto err_buf_detach; | ||
| 235 | } | ||
| 236 | |||
| 237 | buffer = kzalloc(sizeof(*buffer), GFP_KERNEL); | ||
| 238 | if (!buffer) { | ||
| 239 | ret = -ENOMEM; | ||
| 240 | goto err_unmap_attach; | ||
| 241 | } | ||
| 242 | |||
| 243 | exynos_gem_obj = exynos_drm_gem_init(drm_dev, dma_buf->size); | ||
| 244 | if (!exynos_gem_obj) { | ||
| 245 | ret = -ENOMEM; | ||
| 246 | goto err_free_buffer; | ||
| 247 | } | ||
| 248 | |||
| 249 | sgl = sgt->sgl; | ||
| 250 | |||
| 251 | buffer->size = dma_buf->size; | ||
| 252 | buffer->dma_addr = sg_dma_address(sgl); | ||
| 253 | |||
| 254 | if (sgt->nents == 1) { | ||
| 255 | /* always physically continuous memory if sgt->nents is 1. */ | ||
| 256 | exynos_gem_obj->flags |= EXYNOS_BO_CONTIG; | ||
| 257 | } else { | ||
| 258 | /* | ||
| 259 | * this case could be CONTIG or NONCONTIG type but for now | ||
| 260 | * sets NONCONTIG. | ||
| 261 | * TODO. we have to find a way that exporter can notify | ||
| 262 | * the type of its own buffer to importer. | ||
| 263 | */ | ||
| 264 | exynos_gem_obj->flags |= EXYNOS_BO_NONCONTIG; | ||
| 265 | } | ||
| 266 | |||
| 267 | exynos_gem_obj->buffer = buffer; | ||
| 268 | buffer->sgt = sgt; | ||
| 269 | exynos_gem_obj->base.import_attach = attach; | ||
| 270 | |||
| 271 | DRM_DEBUG_PRIME("dma_addr = %pad, size = 0x%lx\n", &buffer->dma_addr, | ||
| 272 | buffer->size); | ||
| 273 | |||
| 274 | return &exynos_gem_obj->base; | ||
| 275 | |||
| 276 | err_free_buffer: | ||
| 277 | kfree(buffer); | ||
| 278 | buffer = NULL; | ||
| 279 | err_unmap_attach: | ||
| 280 | dma_buf_unmap_attachment(attach, sgt, DMA_BIDIRECTIONAL); | ||
| 281 | err_buf_detach: | ||
| 282 | dma_buf_detach(dma_buf, attach); | ||
| 283 | dma_buf_put(dma_buf); | ||
| 284 | |||
| 285 | return ERR_PTR(ret); | ||
| 286 | } | ||
diff --git a/drivers/gpu/drm/exynos/exynos_drm_dmabuf.h b/drivers/gpu/drm/exynos/exynos_drm_dmabuf.h deleted file mode 100644 index 886de9ff484d..000000000000 --- a/drivers/gpu/drm/exynos/exynos_drm_dmabuf.h +++ /dev/null | |||
| @@ -1,20 +0,0 @@ | |||
| 1 | /* exynos_drm_dmabuf.h | ||
| 2 | * | ||
| 3 | * Copyright (c) 2012 Samsung Electronics Co., Ltd. | ||
| 4 | * Author: Inki Dae <inki.dae@samsung.com> | ||
| 5 | * | ||
| 6 | * This program is free software; you can redistribute it and/or modify it | ||
| 7 | * under the terms of the GNU General Public License as published by the | ||
| 8 | * Free Software Foundation; either version 2 of the License, or (at your | ||
| 9 | * option) any later version. | ||
| 10 | */ | ||
| 11 | |||
| 12 | #ifndef _EXYNOS_DRM_DMABUF_H_ | ||
| 13 | #define _EXYNOS_DRM_DMABUF_H_ | ||
| 14 | |||
| 15 | struct dma_buf *exynos_dmabuf_prime_export(struct drm_device *drm_dev, | ||
| 16 | struct drm_gem_object *obj, int flags); | ||
| 17 | |||
| 18 | struct drm_gem_object *exynos_dmabuf_prime_import(struct drm_device *drm_dev, | ||
| 19 | struct dma_buf *dma_buf); | ||
| 20 | #endif | ||
diff --git a/drivers/gpu/drm/exynos/exynos_drm_dpi.c b/drivers/gpu/drm/exynos/exynos_drm_dpi.c index 7cb6595c1894..c748b8790de3 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_dpi.c +++ b/drivers/gpu/drm/exynos/exynos_drm_dpi.c | |||
| @@ -20,26 +20,24 @@ | |||
| 20 | #include <video/of_videomode.h> | 20 | #include <video/of_videomode.h> |
| 21 | #include <video/videomode.h> | 21 | #include <video/videomode.h> |
| 22 | 22 | ||
| 23 | #include "exynos_drm_drv.h" | 23 | #include "exynos_drm_crtc.h" |
| 24 | 24 | ||
| 25 | struct exynos_dpi { | 25 | struct exynos_dpi { |
| 26 | struct exynos_drm_display display; | 26 | struct drm_encoder encoder; |
| 27 | struct device *dev; | 27 | struct device *dev; |
| 28 | struct device_node *panel_node; | 28 | struct device_node *panel_node; |
| 29 | 29 | ||
| 30 | struct drm_panel *panel; | 30 | struct drm_panel *panel; |
| 31 | struct drm_connector connector; | 31 | struct drm_connector connector; |
| 32 | struct drm_encoder *encoder; | ||
| 33 | 32 | ||
| 34 | struct videomode *vm; | 33 | struct videomode *vm; |
| 35 | int dpms_mode; | ||
| 36 | }; | 34 | }; |
| 37 | 35 | ||
| 38 | #define connector_to_dpi(c) container_of(c, struct exynos_dpi, connector) | 36 | #define connector_to_dpi(c) container_of(c, struct exynos_dpi, connector) |
| 39 | 37 | ||
| 40 | static inline struct exynos_dpi *display_to_dpi(struct exynos_drm_display *d) | 38 | static inline struct exynos_dpi *encoder_to_dpi(struct drm_encoder *e) |
| 41 | { | 39 | { |
| 42 | return container_of(d, struct exynos_dpi, display); | 40 | return container_of(e, struct exynos_dpi, encoder); |
| 43 | } | 41 | } |
| 44 | 42 | ||
| 45 | static enum drm_connector_status | 43 | static enum drm_connector_status |
| @@ -99,7 +97,7 @@ exynos_dpi_best_encoder(struct drm_connector *connector) | |||
| 99 | { | 97 | { |
| 100 | struct exynos_dpi *ctx = connector_to_dpi(connector); | 98 | struct exynos_dpi *ctx = connector_to_dpi(connector); |
| 101 | 99 | ||
| 102 | return ctx->encoder; | 100 | return &ctx->encoder; |
| 103 | } | 101 | } |
| 104 | 102 | ||
| 105 | static struct drm_connector_helper_funcs exynos_dpi_connector_helper_funcs = { | 103 | static struct drm_connector_helper_funcs exynos_dpi_connector_helper_funcs = { |
| @@ -107,15 +105,12 @@ static struct drm_connector_helper_funcs exynos_dpi_connector_helper_funcs = { | |||
| 107 | .best_encoder = exynos_dpi_best_encoder, | 105 | .best_encoder = exynos_dpi_best_encoder, |
| 108 | }; | 106 | }; |
| 109 | 107 | ||
| 110 | static int exynos_dpi_create_connector(struct exynos_drm_display *display, | 108 | static int exynos_dpi_create_connector(struct drm_encoder *encoder) |
| 111 | struct drm_encoder *encoder) | ||
| 112 | { | 109 | { |
| 113 | struct exynos_dpi *ctx = display_to_dpi(display); | 110 | struct exynos_dpi *ctx = encoder_to_dpi(encoder); |
| 114 | struct drm_connector *connector = &ctx->connector; | 111 | struct drm_connector *connector = &ctx->connector; |
| 115 | int ret; | 112 | int ret; |
| 116 | 113 | ||
| 117 | ctx->encoder = encoder; | ||
| 118 | |||
| 119 | connector->polled = DRM_CONNECTOR_POLL_HPD; | 114 | connector->polled = DRM_CONNECTOR_POLL_HPD; |
| 120 | 115 | ||
| 121 | ret = drm_connector_init(encoder->dev, connector, | 116 | ret = drm_connector_init(encoder->dev, connector, |
| @@ -133,46 +128,48 @@ static int exynos_dpi_create_connector(struct exynos_drm_display *display, | |||
| 133 | return 0; | 128 | return 0; |
| 134 | } | 129 | } |
| 135 | 130 | ||
| 136 | static void exynos_dpi_poweron(struct exynos_dpi *ctx) | 131 | static bool exynos_dpi_mode_fixup(struct drm_encoder *encoder, |
| 132 | const struct drm_display_mode *mode, | ||
| 133 | struct drm_display_mode *adjusted_mode) | ||
| 134 | { | ||
| 135 | return true; | ||
| 136 | } | ||
| 137 | |||
| 138 | static void exynos_dpi_mode_set(struct drm_encoder *encoder, | ||
| 139 | struct drm_display_mode *mode, | ||
| 140 | struct drm_display_mode *adjusted_mode) | ||
| 137 | { | 141 | { |
| 142 | } | ||
| 143 | |||
| 144 | static void exynos_dpi_enable(struct drm_encoder *encoder) | ||
| 145 | { | ||
| 146 | struct exynos_dpi *ctx = encoder_to_dpi(encoder); | ||
| 147 | |||
| 138 | if (ctx->panel) { | 148 | if (ctx->panel) { |
| 139 | drm_panel_prepare(ctx->panel); | 149 | drm_panel_prepare(ctx->panel); |
| 140 | drm_panel_enable(ctx->panel); | 150 | drm_panel_enable(ctx->panel); |
| 141 | } | 151 | } |
| 142 | } | 152 | } |
| 143 | 153 | ||
| 144 | static void exynos_dpi_poweroff(struct exynos_dpi *ctx) | 154 | static void exynos_dpi_disable(struct drm_encoder *encoder) |
| 145 | { | 155 | { |
| 156 | struct exynos_dpi *ctx = encoder_to_dpi(encoder); | ||
| 157 | |||
| 146 | if (ctx->panel) { | 158 | if (ctx->panel) { |
| 147 | drm_panel_disable(ctx->panel); | 159 | drm_panel_disable(ctx->panel); |
| 148 | drm_panel_unprepare(ctx->panel); | 160 | drm_panel_unprepare(ctx->panel); |
| 149 | } | 161 | } |
| 150 | } | 162 | } |
| 151 | 163 | ||
| 152 | static void exynos_dpi_dpms(struct exynos_drm_display *display, int mode) | 164 | static struct drm_encoder_helper_funcs exynos_dpi_encoder_helper_funcs = { |
| 153 | { | 165 | .mode_fixup = exynos_dpi_mode_fixup, |
| 154 | struct exynos_dpi *ctx = display_to_dpi(display); | 166 | .mode_set = exynos_dpi_mode_set, |
| 155 | 167 | .enable = exynos_dpi_enable, | |
| 156 | switch (mode) { | 168 | .disable = exynos_dpi_disable, |
| 157 | case DRM_MODE_DPMS_ON: | 169 | }; |
| 158 | if (ctx->dpms_mode != DRM_MODE_DPMS_ON) | ||
| 159 | exynos_dpi_poweron(ctx); | ||
| 160 | break; | ||
| 161 | case DRM_MODE_DPMS_STANDBY: | ||
| 162 | case DRM_MODE_DPMS_SUSPEND: | ||
| 163 | case DRM_MODE_DPMS_OFF: | ||
| 164 | if (ctx->dpms_mode == DRM_MODE_DPMS_ON) | ||
| 165 | exynos_dpi_poweroff(ctx); | ||
| 166 | break; | ||
| 167 | default: | ||
| 168 | break; | ||
| 169 | } | ||
| 170 | ctx->dpms_mode = mode; | ||
| 171 | } | ||
| 172 | 170 | ||
| 173 | static struct exynos_drm_display_ops exynos_dpi_display_ops = { | 171 | static struct drm_encoder_funcs exynos_dpi_encoder_funcs = { |
| 174 | .create_connector = exynos_dpi_create_connector, | 172 | .destroy = drm_encoder_cleanup, |
| 175 | .dpms = exynos_dpi_dpms | ||
| 176 | }; | 173 | }; |
| 177 | 174 | ||
| 178 | /* of_* functions will be removed after merge of of_graph patches */ | 175 | /* of_* functions will be removed after merge of of_graph patches */ |
| @@ -299,7 +296,34 @@ static int exynos_dpi_parse_dt(struct exynos_dpi *ctx) | |||
| 299 | return 0; | 296 | return 0; |
| 300 | } | 297 | } |
| 301 | 298 | ||
| 302 | struct exynos_drm_display *exynos_dpi_probe(struct device *dev) | 299 | int exynos_dpi_bind(struct drm_device *dev, struct drm_encoder *encoder) |
| 300 | { | ||
| 301 | int ret; | ||
| 302 | |||
| 303 | ret = exynos_drm_crtc_get_pipe_from_type(dev, EXYNOS_DISPLAY_TYPE_LCD); | ||
| 304 | if (ret < 0) | ||
| 305 | return ret; | ||
| 306 | |||
| 307 | encoder->possible_crtcs = 1 << ret; | ||
| 308 | |||
| 309 | DRM_DEBUG_KMS("possible_crtcs = 0x%x\n", encoder->possible_crtcs); | ||
| 310 | |||
| 311 | drm_encoder_init(dev, encoder, &exynos_dpi_encoder_funcs, | ||
| 312 | DRM_MODE_ENCODER_TMDS); | ||
| 313 | |||
| 314 | drm_encoder_helper_add(encoder, &exynos_dpi_encoder_helper_funcs); | ||
| 315 | |||
| 316 | ret = exynos_dpi_create_connector(encoder); | ||
| 317 | if (ret) { | ||
| 318 | DRM_ERROR("failed to create connector ret = %d\n", ret); | ||
| 319 | drm_encoder_cleanup(encoder); | ||
| 320 | return ret; | ||
| 321 | } | ||
| 322 | |||
| 323 | return 0; | ||
| 324 | } | ||
| 325 | |||
| 326 | struct drm_encoder *exynos_dpi_probe(struct device *dev) | ||
| 303 | { | 327 | { |
| 304 | struct exynos_dpi *ctx; | 328 | struct exynos_dpi *ctx; |
| 305 | int ret; | 329 | int ret; |
| @@ -308,10 +332,7 @@ struct exynos_drm_display *exynos_dpi_probe(struct device *dev) | |||
| 308 | if (!ctx) | 332 | if (!ctx) |
| 309 | return ERR_PTR(-ENOMEM); | 333 | return ERR_PTR(-ENOMEM); |
| 310 | 334 | ||
| 311 | ctx->display.type = EXYNOS_DISPLAY_TYPE_LCD; | ||
| 312 | ctx->display.ops = &exynos_dpi_display_ops; | ||
| 313 | ctx->dev = dev; | 335 | ctx->dev = dev; |
| 314 | ctx->dpms_mode = DRM_MODE_DPMS_OFF; | ||
| 315 | 336 | ||
| 316 | ret = exynos_dpi_parse_dt(ctx); | 337 | ret = exynos_dpi_parse_dt(ctx); |
| 317 | if (ret < 0) { | 338 | if (ret < 0) { |
| @@ -325,14 +346,14 @@ struct exynos_drm_display *exynos_dpi_probe(struct device *dev) | |||
| 325 | return ERR_PTR(-EPROBE_DEFER); | 346 | return ERR_PTR(-EPROBE_DEFER); |
| 326 | } | 347 | } |
| 327 | 348 | ||
| 328 | return &ctx->display; | 349 | return &ctx->encoder; |
| 329 | } | 350 | } |
| 330 | 351 | ||
| 331 | int exynos_dpi_remove(struct exynos_drm_display *display) | 352 | int exynos_dpi_remove(struct drm_encoder *encoder) |
| 332 | { | 353 | { |
| 333 | struct exynos_dpi *ctx = display_to_dpi(display); | 354 | struct exynos_dpi *ctx = encoder_to_dpi(encoder); |
| 334 | 355 | ||
| 335 | exynos_dpi_dpms(&ctx->display, DRM_MODE_DPMS_OFF); | 356 | exynos_dpi_disable(&ctx->encoder); |
| 336 | 357 | ||
| 337 | if (ctx->panel) | 358 | if (ctx->panel) |
| 338 | drm_panel_detach(ctx->panel); | 359 | drm_panel_detach(ctx->panel); |
diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.c b/drivers/gpu/drm/exynos/exynos_drm_drv.c index 63a68c60a353..fa5194caf259 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_drv.c +++ b/drivers/gpu/drm/exynos/exynos_drm_drv.c | |||
| @@ -21,13 +21,11 @@ | |||
| 21 | 21 | ||
| 22 | #include "exynos_drm_drv.h" | 22 | #include "exynos_drm_drv.h" |
| 23 | #include "exynos_drm_crtc.h" | 23 | #include "exynos_drm_crtc.h" |
| 24 | #include "exynos_drm_encoder.h" | ||
| 25 | #include "exynos_drm_fbdev.h" | 24 | #include "exynos_drm_fbdev.h" |
| 26 | #include "exynos_drm_fb.h" | 25 | #include "exynos_drm_fb.h" |
| 27 | #include "exynos_drm_gem.h" | 26 | #include "exynos_drm_gem.h" |
| 28 | #include "exynos_drm_plane.h" | 27 | #include "exynos_drm_plane.h" |
| 29 | #include "exynos_drm_vidi.h" | 28 | #include "exynos_drm_vidi.h" |
| 30 | #include "exynos_drm_dmabuf.h" | ||
| 31 | #include "exynos_drm_g2d.h" | 29 | #include "exynos_drm_g2d.h" |
| 32 | #include "exynos_drm_ipp.h" | 30 | #include "exynos_drm_ipp.h" |
| 33 | #include "exynos_drm_iommu.h" | 31 | #include "exynos_drm_iommu.h" |
| @@ -41,7 +39,9 @@ | |||
| 41 | static int exynos_drm_load(struct drm_device *dev, unsigned long flags) | 39 | static int exynos_drm_load(struct drm_device *dev, unsigned long flags) |
| 42 | { | 40 | { |
| 43 | struct exynos_drm_private *private; | 41 | struct exynos_drm_private *private; |
| 44 | int ret; | 42 | struct drm_encoder *encoder; |
| 43 | unsigned int clone_mask; | ||
| 44 | int cnt, ret; | ||
| 45 | 45 | ||
| 46 | private = kzalloc(sizeof(struct exynos_drm_private), GFP_KERNEL); | 46 | private = kzalloc(sizeof(struct exynos_drm_private), GFP_KERNEL); |
| 47 | if (!private) | 47 | if (!private) |
| @@ -67,7 +67,13 @@ static int exynos_drm_load(struct drm_device *dev, unsigned long flags) | |||
| 67 | exynos_drm_mode_config_init(dev); | 67 | exynos_drm_mode_config_init(dev); |
| 68 | 68 | ||
| 69 | /* setup possible_clones. */ | 69 | /* setup possible_clones. */ |
| 70 | exynos_drm_encoder_setup(dev); | 70 | cnt = 0; |
| 71 | clone_mask = 0; | ||
| 72 | list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) | ||
| 73 | clone_mask |= (1 << (cnt++)); | ||
| 74 | |||
| 75 | list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) | ||
| 76 | encoder->possible_clones = clone_mask; | ||
| 71 | 77 | ||
| 72 | platform_set_drvdata(dev->platformdev, dev); | 78 | platform_set_drvdata(dev->platformdev, dev); |
| 73 | 79 | ||
| @@ -297,8 +303,12 @@ static struct drm_driver exynos_drm_driver = { | |||
| 297 | .dumb_destroy = drm_gem_dumb_destroy, | 303 | .dumb_destroy = drm_gem_dumb_destroy, |
| 298 | .prime_handle_to_fd = drm_gem_prime_handle_to_fd, | 304 | .prime_handle_to_fd = drm_gem_prime_handle_to_fd, |
| 299 | .prime_fd_to_handle = drm_gem_prime_fd_to_handle, | 305 | .prime_fd_to_handle = drm_gem_prime_fd_to_handle, |
| 300 | .gem_prime_export = exynos_dmabuf_prime_export, | 306 | .gem_prime_export = drm_gem_prime_export, |
| 301 | .gem_prime_import = exynos_dmabuf_prime_import, | 307 | .gem_prime_import = drm_gem_prime_import, |
| 308 | .gem_prime_get_sg_table = exynos_drm_gem_prime_get_sg_table, | ||
| 309 | .gem_prime_import_sg_table = exynos_drm_gem_prime_import_sg_table, | ||
| 310 | .gem_prime_vmap = exynos_drm_gem_prime_vmap, | ||
| 311 | .gem_prime_vunmap = exynos_drm_gem_prime_vunmap, | ||
| 302 | .ioctls = exynos_ioctls, | 312 | .ioctls = exynos_ioctls, |
| 303 | .num_ioctls = ARRAY_SIZE(exynos_ioctls), | 313 | .num_ioctls = ARRAY_SIZE(exynos_ioctls), |
| 304 | .fops = &exynos_drm_driver_fops, | 314 | .fops = &exynos_drm_driver_fops, |
| @@ -345,9 +355,6 @@ static struct platform_driver exynos_drm_platform_driver; | |||
| 345 | * because connector requires pipe number of its crtc during initialization. | 355 | * because connector requires pipe number of its crtc during initialization. |
| 346 | */ | 356 | */ |
| 347 | static struct platform_driver *const exynos_drm_kms_drivers[] = { | 357 | static struct platform_driver *const exynos_drm_kms_drivers[] = { |
| 348 | #ifdef CONFIG_DRM_EXYNOS_VIDI | ||
| 349 | &vidi_driver, | ||
| 350 | #endif | ||
| 351 | #ifdef CONFIG_DRM_EXYNOS_FIMD | 358 | #ifdef CONFIG_DRM_EXYNOS_FIMD |
| 352 | &fimd_driver, | 359 | &fimd_driver, |
| 353 | #endif | 360 | #endif |
| @@ -370,6 +377,9 @@ static struct platform_driver *const exynos_drm_kms_drivers[] = { | |||
| 370 | &mixer_driver, | 377 | &mixer_driver, |
| 371 | &hdmi_driver, | 378 | &hdmi_driver, |
| 372 | #endif | 379 | #endif |
| 380 | #ifdef CONFIG_DRM_EXYNOS_VIDI | ||
| 381 | &vidi_driver, | ||
| 382 | #endif | ||
| 373 | }; | 383 | }; |
| 374 | 384 | ||
| 375 | static struct platform_driver *const exynos_drm_non_kms_drivers[] = { | 385 | static struct platform_driver *const exynos_drm_non_kms_drivers[] = { |
diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.h b/drivers/gpu/drm/exynos/exynos_drm_drv.h index dd00f160c1e5..6b8a30f23473 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_drv.h +++ b/drivers/gpu/drm/exynos/exynos_drm_drv.h | |||
| @@ -44,23 +44,14 @@ enum exynos_drm_output_type { | |||
| 44 | * - the unit is screen coordinates. | 44 | * - the unit is screen coordinates. |
| 45 | * @src_y: offset y on a framebuffer to be displayed. | 45 | * @src_y: offset y on a framebuffer to be displayed. |
| 46 | * - the unit is screen coordinates. | 46 | * - the unit is screen coordinates. |
| 47 | * @src_width: width of a partial image to be displayed from framebuffer. | 47 | * @src_w: width of a partial image to be displayed from framebuffer. |
| 48 | * @src_height: height of a partial image to be displayed from framebuffer. | 48 | * @src_h: height of a partial image to be displayed from framebuffer. |
| 49 | * @fb_width: width of a framebuffer. | ||
| 50 | * @fb_height: height of a framebuffer. | ||
| 51 | * @crtc_x: offset x on hardware screen. | 49 | * @crtc_x: offset x on hardware screen. |
| 52 | * @crtc_y: offset y on hardware screen. | 50 | * @crtc_y: offset y on hardware screen. |
| 53 | * @crtc_width: window width to be displayed (hardware screen). | 51 | * @crtc_w: window width to be displayed (hardware screen). |
| 54 | * @crtc_height: window height to be displayed (hardware screen). | 52 | * @crtc_h: window height to be displayed (hardware screen). |
| 55 | * @mode_width: width of screen mode. | ||
| 56 | * @mode_height: height of screen mode. | ||
| 57 | * @h_ratio: horizontal scaling ratio, 16.16 fixed point | 53 | * @h_ratio: horizontal scaling ratio, 16.16 fixed point |
| 58 | * @v_ratio: vertical scaling ratio, 16.16 fixed point | 54 | * @v_ratio: vertical scaling ratio, 16.16 fixed point |
| 59 | * @refresh: refresh rate. | ||
| 60 | * @scan_flag: interlace or progressive way. | ||
| 61 | * (it could be DRM_MODE_FLAG_*) | ||
| 62 | * @bpp: pixel size.(in bit) | ||
| 63 | * @pixel_format: fourcc pixel format of this overlay | ||
| 64 | * @dma_addr: array of bus(accessed by dma) address to the memory region | 55 | * @dma_addr: array of bus(accessed by dma) address to the memory region |
| 65 | * allocated for a overlay. | 56 | * allocated for a overlay. |
| 66 | * @zpos: order of overlay layer(z position). | 57 | * @zpos: order of overlay layer(z position). |
| @@ -73,76 +64,19 @@ struct exynos_drm_plane { | |||
| 73 | struct drm_plane base; | 64 | struct drm_plane base; |
| 74 | unsigned int src_x; | 65 | unsigned int src_x; |
| 75 | unsigned int src_y; | 66 | unsigned int src_y; |
| 76 | unsigned int src_width; | 67 | unsigned int src_w; |
| 77 | unsigned int src_height; | 68 | unsigned int src_h; |
| 78 | unsigned int fb_width; | ||
| 79 | unsigned int fb_height; | ||
| 80 | unsigned int crtc_x; | 69 | unsigned int crtc_x; |
| 81 | unsigned int crtc_y; | 70 | unsigned int crtc_y; |
| 82 | unsigned int crtc_width; | 71 | unsigned int crtc_w; |
| 83 | unsigned int crtc_height; | 72 | unsigned int crtc_h; |
| 84 | unsigned int mode_width; | ||
| 85 | unsigned int mode_height; | ||
| 86 | unsigned int h_ratio; | 73 | unsigned int h_ratio; |
| 87 | unsigned int v_ratio; | 74 | unsigned int v_ratio; |
| 88 | unsigned int refresh; | ||
| 89 | unsigned int scan_flag; | ||
| 90 | unsigned int bpp; | ||
| 91 | unsigned int pitch; | ||
| 92 | uint32_t pixel_format; | ||
| 93 | dma_addr_t dma_addr[MAX_FB_BUFFER]; | 75 | dma_addr_t dma_addr[MAX_FB_BUFFER]; |
| 94 | unsigned int zpos; | 76 | unsigned int zpos; |
| 95 | }; | 77 | }; |
| 96 | 78 | ||
| 97 | /* | 79 | /* |
| 98 | * Exynos DRM Display Structure. | ||
| 99 | * - this structure is common to analog tv, digital tv and lcd panel. | ||
| 100 | * | ||
| 101 | * @create_connector: initialize and register a new connector | ||
| 102 | * @remove: cleans up the display for removal | ||
| 103 | * @mode_fixup: fix mode data comparing to hw specific display mode. | ||
| 104 | * @mode_set: convert drm_display_mode to hw specific display mode and | ||
| 105 | * would be called by encoder->mode_set(). | ||
| 106 | * @check_mode: check if mode is valid or not. | ||
| 107 | * @dpms: display device on or off. | ||
| 108 | * @commit: apply changes to hw | ||
| 109 | */ | ||
| 110 | struct exynos_drm_display; | ||
| 111 | struct exynos_drm_display_ops { | ||
| 112 | int (*create_connector)(struct exynos_drm_display *display, | ||
| 113 | struct drm_encoder *encoder); | ||
| 114 | void (*remove)(struct exynos_drm_display *display); | ||
| 115 | void (*mode_fixup)(struct exynos_drm_display *display, | ||
| 116 | struct drm_connector *connector, | ||
| 117 | const struct drm_display_mode *mode, | ||
| 118 | struct drm_display_mode *adjusted_mode); | ||
| 119 | void (*mode_set)(struct exynos_drm_display *display, | ||
| 120 | struct drm_display_mode *mode); | ||
| 121 | int (*check_mode)(struct exynos_drm_display *display, | ||
| 122 | struct drm_display_mode *mode); | ||
| 123 | void (*dpms)(struct exynos_drm_display *display, int mode); | ||
| 124 | void (*commit)(struct exynos_drm_display *display); | ||
| 125 | }; | ||
| 126 | |||
| 127 | /* | ||
| 128 | * Exynos drm display structure, maps 1:1 with an encoder/connector | ||
| 129 | * | ||
| 130 | * @list: the list entry for this manager | ||
| 131 | * @type: one of EXYNOS_DISPLAY_TYPE_LCD and HDMI. | ||
| 132 | * @encoder: encoder object this display maps to | ||
| 133 | * @connector: connector object this display maps to | ||
| 134 | * @ops: pointer to callbacks for exynos drm specific functionality | ||
| 135 | * @ctx: A pointer to the display's implementation specific context | ||
| 136 | */ | ||
| 137 | struct exynos_drm_display { | ||
| 138 | struct list_head list; | ||
| 139 | enum exynos_drm_output_type type; | ||
| 140 | struct drm_encoder *encoder; | ||
| 141 | struct drm_connector *connector; | ||
| 142 | struct exynos_drm_display_ops *ops; | ||
| 143 | }; | ||
| 144 | |||
| 145 | /* | ||
| 146 | * Exynos drm crtc ops | 80 | * Exynos drm crtc ops |
| 147 | * | 81 | * |
| 148 | * @enable: enable the device | 82 | * @enable: enable the device |
| @@ -153,8 +87,8 @@ struct exynos_drm_display { | |||
| 153 | * @disable_vblank: specific driver callback for disabling vblank interrupt. | 87 | * @disable_vblank: specific driver callback for disabling vblank interrupt. |
| 154 | * @wait_for_vblank: wait for vblank interrupt to make sure that | 88 | * @wait_for_vblank: wait for vblank interrupt to make sure that |
| 155 | * hardware overlay is updated. | 89 | * hardware overlay is updated. |
| 156 | * @win_commit: apply hardware specific overlay data to registers. | 90 | * @update_plane: apply hardware specific overlay data to registers. |
| 157 | * @win_disable: disable hardware specific overlay. | 91 | * @disable_plane: disable hardware specific overlay. |
| 158 | * @te_handler: trigger to transfer video image at the tearing effect | 92 | * @te_handler: trigger to transfer video image at the tearing effect |
| 159 | * synchronization signal if there is a page flip request. | 93 | * synchronization signal if there is a page flip request. |
| 160 | * @clock_enable: optional function enabling/disabling display domain clock, | 94 | * @clock_enable: optional function enabling/disabling display domain clock, |
| @@ -173,11 +107,12 @@ struct exynos_drm_crtc_ops { | |||
| 173 | int (*enable_vblank)(struct exynos_drm_crtc *crtc); | 107 | int (*enable_vblank)(struct exynos_drm_crtc *crtc); |
| 174 | void (*disable_vblank)(struct exynos_drm_crtc *crtc); | 108 | void (*disable_vblank)(struct exynos_drm_crtc *crtc); |
| 175 | void (*wait_for_vblank)(struct exynos_drm_crtc *crtc); | 109 | void (*wait_for_vblank)(struct exynos_drm_crtc *crtc); |
| 176 | void (*win_commit)(struct exynos_drm_crtc *crtc, unsigned int zpos); | 110 | void (*update_plane)(struct exynos_drm_crtc *crtc, |
| 177 | void (*win_disable)(struct exynos_drm_crtc *crtc, unsigned int zpos); | 111 | struct exynos_drm_plane *plane); |
| 112 | void (*disable_plane)(struct exynos_drm_crtc *crtc, | ||
| 113 | struct exynos_drm_plane *plane); | ||
| 178 | void (*te_handler)(struct exynos_drm_crtc *crtc); | 114 | void (*te_handler)(struct exynos_drm_crtc *crtc); |
| 179 | void (*clock_enable)(struct exynos_drm_crtc *crtc, bool enable); | 115 | void (*clock_enable)(struct exynos_drm_crtc *crtc, bool enable); |
| 180 | void (*clear_channels)(struct exynos_drm_crtc *crtc); | ||
| 181 | }; | 116 | }; |
| 182 | 117 | ||
| 183 | /* | 118 | /* |
| @@ -285,20 +220,23 @@ int exynos_drm_subdrv_open(struct drm_device *dev, struct drm_file *file); | |||
| 285 | void exynos_drm_subdrv_close(struct drm_device *dev, struct drm_file *file); | 220 | void exynos_drm_subdrv_close(struct drm_device *dev, struct drm_file *file); |
| 286 | 221 | ||
| 287 | #ifdef CONFIG_DRM_EXYNOS_DPI | 222 | #ifdef CONFIG_DRM_EXYNOS_DPI |
| 288 | struct exynos_drm_display * exynos_dpi_probe(struct device *dev); | 223 | struct drm_encoder *exynos_dpi_probe(struct device *dev); |
| 289 | int exynos_dpi_remove(struct exynos_drm_display *display); | 224 | int exynos_dpi_remove(struct drm_encoder *encoder); |
| 225 | int exynos_dpi_bind(struct drm_device *dev, struct drm_encoder *encoder); | ||
| 290 | #else | 226 | #else |
| 291 | static inline struct exynos_drm_display * | 227 | static inline struct drm_encoder * |
| 292 | exynos_dpi_probe(struct device *dev) { return NULL; } | 228 | exynos_dpi_probe(struct device *dev) { return NULL; } |
| 293 | static inline int exynos_dpi_remove(struct exynos_drm_display *display) | 229 | static inline int exynos_dpi_remove(struct drm_encoder *encoder) |
| 230 | { | ||
| 231 | return 0; | ||
| 232 | } | ||
| 233 | static inline int exynos_dpi_bind(struct drm_device *dev, | ||
| 234 | struct drm_encoder *encoder) | ||
| 294 | { | 235 | { |
| 295 | return 0; | 236 | return 0; |
| 296 | } | 237 | } |
| 297 | #endif | 238 | #endif |
| 298 | 239 | ||
| 299 | /* This function creates a encoder and a connector, and initializes them. */ | ||
| 300 | int exynos_drm_create_enc_conn(struct drm_device *dev, | ||
| 301 | struct exynos_drm_display *display); | ||
| 302 | 240 | ||
| 303 | extern struct platform_driver fimd_driver; | 241 | extern struct platform_driver fimd_driver; |
| 304 | extern struct platform_driver exynos5433_decon_driver; | 242 | extern struct platform_driver exynos5433_decon_driver; |
diff --git a/drivers/gpu/drm/exynos/exynos_drm_dsi.c b/drivers/gpu/drm/exynos/exynos_drm_dsi.c index 0e58b36cb8c2..12b03b364703 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_dsi.c +++ b/drivers/gpu/drm/exynos/exynos_drm_dsi.c | |||
| @@ -259,7 +259,7 @@ struct exynos_dsi_driver_data { | |||
| 259 | }; | 259 | }; |
| 260 | 260 | ||
| 261 | struct exynos_dsi { | 261 | struct exynos_dsi { |
| 262 | struct exynos_drm_display display; | 262 | struct drm_encoder encoder; |
| 263 | struct mipi_dsi_host dsi_host; | 263 | struct mipi_dsi_host dsi_host; |
| 264 | struct drm_connector connector; | 264 | struct drm_connector connector; |
| 265 | struct device_node *panel_node; | 265 | struct device_node *panel_node; |
| @@ -295,9 +295,9 @@ struct exynos_dsi { | |||
| 295 | #define host_to_dsi(host) container_of(host, struct exynos_dsi, dsi_host) | 295 | #define host_to_dsi(host) container_of(host, struct exynos_dsi, dsi_host) |
| 296 | #define connector_to_dsi(c) container_of(c, struct exynos_dsi, connector) | 296 | #define connector_to_dsi(c) container_of(c, struct exynos_dsi, connector) |
| 297 | 297 | ||
| 298 | static inline struct exynos_dsi *display_to_dsi(struct exynos_drm_display *d) | 298 | static inline struct exynos_dsi *encoder_to_dsi(struct drm_encoder *e) |
| 299 | { | 299 | { |
| 300 | return container_of(d, struct exynos_dsi, display); | 300 | return container_of(e, struct exynos_dsi, encoder); |
| 301 | } | 301 | } |
| 302 | 302 | ||
| 303 | enum reg_idx { | 303 | enum reg_idx { |
| @@ -1272,7 +1272,7 @@ static irqreturn_t exynos_dsi_irq(int irq, void *dev_id) | |||
| 1272 | static irqreturn_t exynos_dsi_te_irq_handler(int irq, void *dev_id) | 1272 | static irqreturn_t exynos_dsi_te_irq_handler(int irq, void *dev_id) |
| 1273 | { | 1273 | { |
| 1274 | struct exynos_dsi *dsi = (struct exynos_dsi *)dev_id; | 1274 | struct exynos_dsi *dsi = (struct exynos_dsi *)dev_id; |
| 1275 | struct drm_encoder *encoder = dsi->display.encoder; | 1275 | struct drm_encoder *encoder = &dsi->encoder; |
| 1276 | 1276 | ||
| 1277 | if (dsi->state & DSIM_STATE_VIDOUT_AVAILABLE) | 1277 | if (dsi->state & DSIM_STATE_VIDOUT_AVAILABLE) |
| 1278 | exynos_drm_crtc_te_handler(encoder->crtc); | 1278 | exynos_drm_crtc_te_handler(encoder->crtc); |
| @@ -1518,16 +1518,17 @@ static void exynos_dsi_poweroff(struct exynos_dsi *dsi) | |||
| 1518 | dev_err(dsi->dev, "cannot disable regulators %d\n", ret); | 1518 | dev_err(dsi->dev, "cannot disable regulators %d\n", ret); |
| 1519 | } | 1519 | } |
| 1520 | 1520 | ||
| 1521 | static int exynos_dsi_enable(struct exynos_dsi *dsi) | 1521 | static void exynos_dsi_enable(struct drm_encoder *encoder) |
| 1522 | { | 1522 | { |
| 1523 | struct exynos_dsi *dsi = encoder_to_dsi(encoder); | ||
| 1523 | int ret; | 1524 | int ret; |
| 1524 | 1525 | ||
| 1525 | if (dsi->state & DSIM_STATE_ENABLED) | 1526 | if (dsi->state & DSIM_STATE_ENABLED) |
| 1526 | return 0; | 1527 | return; |
| 1527 | 1528 | ||
| 1528 | ret = exynos_dsi_poweron(dsi); | 1529 | ret = exynos_dsi_poweron(dsi); |
| 1529 | if (ret < 0) | 1530 | if (ret < 0) |
| 1530 | return ret; | 1531 | return; |
| 1531 | 1532 | ||
| 1532 | dsi->state |= DSIM_STATE_ENABLED; | 1533 | dsi->state |= DSIM_STATE_ENABLED; |
| 1533 | 1534 | ||
| @@ -1535,7 +1536,7 @@ static int exynos_dsi_enable(struct exynos_dsi *dsi) | |||
| 1535 | if (ret < 0) { | 1536 | if (ret < 0) { |
| 1536 | dsi->state &= ~DSIM_STATE_ENABLED; | 1537 | dsi->state &= ~DSIM_STATE_ENABLED; |
| 1537 | exynos_dsi_poweroff(dsi); | 1538 | exynos_dsi_poweroff(dsi); |
| 1538 | return ret; | 1539 | return; |
| 1539 | } | 1540 | } |
| 1540 | 1541 | ||
| 1541 | exynos_dsi_set_display_mode(dsi); | 1542 | exynos_dsi_set_display_mode(dsi); |
| @@ -1547,16 +1548,16 @@ static int exynos_dsi_enable(struct exynos_dsi *dsi) | |||
| 1547 | exynos_dsi_set_display_enable(dsi, false); | 1548 | exynos_dsi_set_display_enable(dsi, false); |
| 1548 | drm_panel_unprepare(dsi->panel); | 1549 | drm_panel_unprepare(dsi->panel); |
| 1549 | exynos_dsi_poweroff(dsi); | 1550 | exynos_dsi_poweroff(dsi); |
| 1550 | return ret; | 1551 | return; |
| 1551 | } | 1552 | } |
| 1552 | 1553 | ||
| 1553 | dsi->state |= DSIM_STATE_VIDOUT_AVAILABLE; | 1554 | dsi->state |= DSIM_STATE_VIDOUT_AVAILABLE; |
| 1554 | |||
| 1555 | return 0; | ||
| 1556 | } | 1555 | } |
| 1557 | 1556 | ||
| 1558 | static void exynos_dsi_disable(struct exynos_dsi *dsi) | 1557 | static void exynos_dsi_disable(struct drm_encoder *encoder) |
| 1559 | { | 1558 | { |
| 1559 | struct exynos_dsi *dsi = encoder_to_dsi(encoder); | ||
| 1560 | |||
| 1560 | if (!(dsi->state & DSIM_STATE_ENABLED)) | 1561 | if (!(dsi->state & DSIM_STATE_ENABLED)) |
| 1561 | return; | 1562 | return; |
| 1562 | 1563 | ||
| @@ -1571,26 +1572,6 @@ static void exynos_dsi_disable(struct exynos_dsi *dsi) | |||
| 1571 | exynos_dsi_poweroff(dsi); | 1572 | exynos_dsi_poweroff(dsi); |
| 1572 | } | 1573 | } |
| 1573 | 1574 | ||
| 1574 | static void exynos_dsi_dpms(struct exynos_drm_display *display, int mode) | ||
| 1575 | { | ||
| 1576 | struct exynos_dsi *dsi = display_to_dsi(display); | ||
| 1577 | |||
| 1578 | if (dsi->panel) { | ||
| 1579 | switch (mode) { | ||
| 1580 | case DRM_MODE_DPMS_ON: | ||
| 1581 | exynos_dsi_enable(dsi); | ||
| 1582 | break; | ||
| 1583 | case DRM_MODE_DPMS_STANDBY: | ||
| 1584 | case DRM_MODE_DPMS_SUSPEND: | ||
| 1585 | case DRM_MODE_DPMS_OFF: | ||
| 1586 | exynos_dsi_disable(dsi); | ||
| 1587 | break; | ||
| 1588 | default: | ||
| 1589 | break; | ||
| 1590 | } | ||
| 1591 | } | ||
| 1592 | } | ||
| 1593 | |||
| 1594 | static enum drm_connector_status | 1575 | static enum drm_connector_status |
| 1595 | exynos_dsi_detect(struct drm_connector *connector, bool force) | 1576 | exynos_dsi_detect(struct drm_connector *connector, bool force) |
| 1596 | { | 1577 | { |
| @@ -1601,10 +1582,10 @@ exynos_dsi_detect(struct drm_connector *connector, bool force) | |||
| 1601 | if (dsi->panel) | 1582 | if (dsi->panel) |
| 1602 | drm_panel_attach(dsi->panel, &dsi->connector); | 1583 | drm_panel_attach(dsi->panel, &dsi->connector); |
| 1603 | } else if (!dsi->panel_node) { | 1584 | } else if (!dsi->panel_node) { |
| 1604 | struct exynos_drm_display *display; | 1585 | struct drm_encoder *encoder; |
| 1605 | 1586 | ||
| 1606 | display = platform_get_drvdata(to_platform_device(dsi->dev)); | 1587 | encoder = platform_get_drvdata(to_platform_device(dsi->dev)); |
| 1607 | exynos_dsi_dpms(display, DRM_MODE_DPMS_OFF); | 1588 | exynos_dsi_disable(encoder); |
| 1608 | drm_panel_detach(dsi->panel); | 1589 | drm_panel_detach(dsi->panel); |
| 1609 | dsi->panel = NULL; | 1590 | dsi->panel = NULL; |
| 1610 | } | 1591 | } |
| @@ -1647,7 +1628,7 @@ exynos_dsi_best_encoder(struct drm_connector *connector) | |||
| 1647 | { | 1628 | { |
| 1648 | struct exynos_dsi *dsi = connector_to_dsi(connector); | 1629 | struct exynos_dsi *dsi = connector_to_dsi(connector); |
| 1649 | 1630 | ||
| 1650 | return dsi->display.encoder; | 1631 | return &dsi->encoder; |
| 1651 | } | 1632 | } |
| 1652 | 1633 | ||
| 1653 | static struct drm_connector_helper_funcs exynos_dsi_connector_helper_funcs = { | 1634 | static struct drm_connector_helper_funcs exynos_dsi_connector_helper_funcs = { |
| @@ -1655,10 +1636,9 @@ static struct drm_connector_helper_funcs exynos_dsi_connector_helper_funcs = { | |||
| 1655 | .best_encoder = exynos_dsi_best_encoder, | 1636 | .best_encoder = exynos_dsi_best_encoder, |
| 1656 | }; | 1637 | }; |
| 1657 | 1638 | ||
| 1658 | static int exynos_dsi_create_connector(struct exynos_drm_display *display, | 1639 | static int exynos_dsi_create_connector(struct drm_encoder *encoder) |
| 1659 | struct drm_encoder *encoder) | ||
| 1660 | { | 1640 | { |
| 1661 | struct exynos_dsi *dsi = display_to_dsi(display); | 1641 | struct exynos_dsi *dsi = encoder_to_dsi(encoder); |
| 1662 | struct drm_connector *connector = &dsi->connector; | 1642 | struct drm_connector *connector = &dsi->connector; |
| 1663 | int ret; | 1643 | int ret; |
| 1664 | 1644 | ||
| @@ -1679,26 +1659,40 @@ static int exynos_dsi_create_connector(struct exynos_drm_display *display, | |||
| 1679 | return 0; | 1659 | return 0; |
| 1680 | } | 1660 | } |
| 1681 | 1661 | ||
| 1682 | static void exynos_dsi_mode_set(struct exynos_drm_display *display, | 1662 | static bool exynos_dsi_mode_fixup(struct drm_encoder *encoder, |
| 1683 | struct drm_display_mode *mode) | 1663 | const struct drm_display_mode *mode, |
| 1664 | struct drm_display_mode *adjusted_mode) | ||
| 1684 | { | 1665 | { |
| 1685 | struct exynos_dsi *dsi = display_to_dsi(display); | 1666 | return true; |
| 1686 | struct videomode *vm = &dsi->vm; | 1667 | } |
| 1687 | 1668 | ||
| 1688 | vm->hactive = mode->hdisplay; | 1669 | static void exynos_dsi_mode_set(struct drm_encoder *encoder, |
| 1689 | vm->vactive = mode->vdisplay; | 1670 | struct drm_display_mode *mode, |
| 1690 | vm->vfront_porch = mode->vsync_start - mode->vdisplay; | 1671 | struct drm_display_mode *adjusted_mode) |
| 1691 | vm->vback_porch = mode->vtotal - mode->vsync_end; | 1672 | { |
| 1692 | vm->vsync_len = mode->vsync_end - mode->vsync_start; | 1673 | struct exynos_dsi *dsi = encoder_to_dsi(encoder); |
| 1693 | vm->hfront_porch = mode->hsync_start - mode->hdisplay; | 1674 | struct videomode *vm = &dsi->vm; |
| 1694 | vm->hback_porch = mode->htotal - mode->hsync_end; | 1675 | struct drm_display_mode *m = adjusted_mode; |
| 1695 | vm->hsync_len = mode->hsync_end - mode->hsync_start; | 1676 | |
| 1677 | vm->hactive = m->hdisplay; | ||
| 1678 | vm->vactive = m->vdisplay; | ||
| 1679 | vm->vfront_porch = m->vsync_start - m->vdisplay; | ||
| 1680 | vm->vback_porch = m->vtotal - m->vsync_end; | ||
| 1681 | vm->vsync_len = m->vsync_end - m->vsync_start; | ||
| 1682 | vm->hfront_porch = m->hsync_start - m->hdisplay; | ||
| 1683 | vm->hback_porch = m->htotal - m->hsync_end; | ||
| 1684 | vm->hsync_len = m->hsync_end - m->hsync_start; | ||
| 1696 | } | 1685 | } |
| 1697 | 1686 | ||
| 1698 | static struct exynos_drm_display_ops exynos_dsi_display_ops = { | 1687 | static struct drm_encoder_helper_funcs exynos_dsi_encoder_helper_funcs = { |
| 1699 | .create_connector = exynos_dsi_create_connector, | 1688 | .mode_fixup = exynos_dsi_mode_fixup, |
| 1700 | .mode_set = exynos_dsi_mode_set, | 1689 | .mode_set = exynos_dsi_mode_set, |
| 1701 | .dpms = exynos_dsi_dpms | 1690 | .enable = exynos_dsi_enable, |
| 1691 | .disable = exynos_dsi_disable, | ||
| 1692 | }; | ||
| 1693 | |||
| 1694 | static struct drm_encoder_funcs exynos_dsi_encoder_funcs = { | ||
| 1695 | .destroy = drm_encoder_cleanup, | ||
| 1702 | }; | 1696 | }; |
| 1703 | 1697 | ||
| 1704 | MODULE_DEVICE_TABLE(of, exynos_dsi_of_match); | 1698 | MODULE_DEVICE_TABLE(of, exynos_dsi_of_match); |
| @@ -1821,22 +1815,35 @@ end: | |||
| 1821 | static int exynos_dsi_bind(struct device *dev, struct device *master, | 1815 | static int exynos_dsi_bind(struct device *dev, struct device *master, |
| 1822 | void *data) | 1816 | void *data) |
| 1823 | { | 1817 | { |
| 1824 | struct exynos_drm_display *display = dev_get_drvdata(dev); | 1818 | struct drm_encoder *encoder = dev_get_drvdata(dev); |
| 1825 | struct exynos_dsi *dsi = display_to_dsi(display); | 1819 | struct exynos_dsi *dsi = encoder_to_dsi(encoder); |
| 1826 | struct drm_device *drm_dev = data; | 1820 | struct drm_device *drm_dev = data; |
| 1827 | struct drm_bridge *bridge; | 1821 | struct drm_bridge *bridge; |
| 1828 | int ret; | 1822 | int ret; |
| 1829 | 1823 | ||
| 1830 | ret = exynos_drm_create_enc_conn(drm_dev, display); | 1824 | ret = exynos_drm_crtc_get_pipe_from_type(drm_dev, |
| 1825 | EXYNOS_DISPLAY_TYPE_LCD); | ||
| 1826 | if (ret < 0) | ||
| 1827 | return ret; | ||
| 1828 | |||
| 1829 | encoder->possible_crtcs = 1 << ret; | ||
| 1830 | |||
| 1831 | DRM_DEBUG_KMS("possible_crtcs = 0x%x\n", encoder->possible_crtcs); | ||
| 1832 | |||
| 1833 | drm_encoder_init(drm_dev, encoder, &exynos_dsi_encoder_funcs, | ||
| 1834 | DRM_MODE_ENCODER_TMDS); | ||
| 1835 | |||
| 1836 | drm_encoder_helper_add(encoder, &exynos_dsi_encoder_helper_funcs); | ||
| 1837 | |||
| 1838 | ret = exynos_dsi_create_connector(encoder); | ||
| 1831 | if (ret) { | 1839 | if (ret) { |
| 1832 | DRM_ERROR("Encoder create [%d] failed with %d\n", | 1840 | DRM_ERROR("failed to create connector ret = %d\n", ret); |
| 1833 | display->type, ret); | 1841 | drm_encoder_cleanup(encoder); |
| 1834 | return ret; | 1842 | return ret; |
| 1835 | } | 1843 | } |
| 1836 | 1844 | ||
| 1837 | bridge = of_drm_find_bridge(dsi->bridge_node); | 1845 | bridge = of_drm_find_bridge(dsi->bridge_node); |
| 1838 | if (bridge) { | 1846 | if (bridge) { |
| 1839 | display->encoder->bridge = bridge; | ||
| 1840 | drm_bridge_attach(drm_dev, bridge); | 1847 | drm_bridge_attach(drm_dev, bridge); |
| 1841 | } | 1848 | } |
| 1842 | 1849 | ||
| @@ -1846,10 +1853,10 @@ static int exynos_dsi_bind(struct device *dev, struct device *master, | |||
| 1846 | static void exynos_dsi_unbind(struct device *dev, struct device *master, | 1853 | static void exynos_dsi_unbind(struct device *dev, struct device *master, |
| 1847 | void *data) | 1854 | void *data) |
| 1848 | { | 1855 | { |
| 1849 | struct exynos_drm_display *display = dev_get_drvdata(dev); | 1856 | struct drm_encoder *encoder = dev_get_drvdata(dev); |
| 1850 | struct exynos_dsi *dsi = display_to_dsi(display); | 1857 | struct exynos_dsi *dsi = encoder_to_dsi(encoder); |
| 1851 | 1858 | ||
| 1852 | exynos_dsi_dpms(display, DRM_MODE_DPMS_OFF); | 1859 | exynos_dsi_disable(encoder); |
| 1853 | 1860 | ||
| 1854 | mipi_dsi_host_unregister(&dsi->dsi_host); | 1861 | mipi_dsi_host_unregister(&dsi->dsi_host); |
| 1855 | } | 1862 | } |
| @@ -1870,9 +1877,6 @@ static int exynos_dsi_probe(struct platform_device *pdev) | |||
| 1870 | if (!dsi) | 1877 | if (!dsi) |
| 1871 | return -ENOMEM; | 1878 | return -ENOMEM; |
| 1872 | 1879 | ||
| 1873 | dsi->display.type = EXYNOS_DISPLAY_TYPE_LCD; | ||
| 1874 | dsi->display.ops = &exynos_dsi_display_ops; | ||
| 1875 | |||
| 1876 | /* To be checked as invalid one */ | 1880 | /* To be checked as invalid one */ |
| 1877 | dsi->te_gpio = -ENOENT; | 1881 | dsi->te_gpio = -ENOENT; |
| 1878 | 1882 | ||
| @@ -1948,7 +1952,7 @@ static int exynos_dsi_probe(struct platform_device *pdev) | |||
| 1948 | return ret; | 1952 | return ret; |
| 1949 | } | 1953 | } |
| 1950 | 1954 | ||
| 1951 | platform_set_drvdata(pdev, &dsi->display); | 1955 | platform_set_drvdata(pdev, &dsi->encoder); |
| 1952 | 1956 | ||
| 1953 | return component_add(dev, &exynos_dsi_component_ops); | 1957 | return component_add(dev, &exynos_dsi_component_ops); |
| 1954 | } | 1958 | } |
diff --git a/drivers/gpu/drm/exynos/exynos_drm_encoder.c b/drivers/gpu/drm/exynos/exynos_drm_encoder.c deleted file mode 100644 index 7b89fd520e45..000000000000 --- a/drivers/gpu/drm/exynos/exynos_drm_encoder.c +++ /dev/null | |||
| @@ -1,174 +0,0 @@ | |||
| 1 | /* exynos_drm_encoder.c | ||
| 2 | * | ||
| 3 | * Copyright (c) 2011 Samsung Electronics Co., Ltd. | ||
| 4 | * Authors: | ||
| 5 | * Inki Dae <inki.dae@samsung.com> | ||
| 6 | * Joonyoung Shim <jy0922.shim@samsung.com> | ||
| 7 | * Seung-Woo Kim <sw0312.kim@samsung.com> | ||
| 8 | * | ||
| 9 | * This program is free software; you can redistribute it and/or modify it | ||
| 10 | * under the terms of the GNU General Public License as published by the | ||
| 11 | * Free Software Foundation; either version 2 of the License, or (at your | ||
| 12 | * option) any later version. | ||
| 13 | */ | ||
| 14 | |||
| 15 | #include <drm/drmP.h> | ||
| 16 | #include <drm/drm_crtc_helper.h> | ||
| 17 | |||
| 18 | #include "exynos_drm_drv.h" | ||
| 19 | #include "exynos_drm_encoder.h" | ||
| 20 | |||
| 21 | #define to_exynos_encoder(x) container_of(x, struct exynos_drm_encoder,\ | ||
| 22 | drm_encoder) | ||
| 23 | |||
| 24 | /* | ||
| 25 | * exynos specific encoder structure. | ||
| 26 | * | ||
| 27 | * @drm_encoder: encoder object. | ||
| 28 | * @display: the display structure that maps to this encoder | ||
| 29 | */ | ||
| 30 | struct exynos_drm_encoder { | ||
| 31 | struct drm_encoder drm_encoder; | ||
| 32 | struct exynos_drm_display *display; | ||
| 33 | }; | ||
| 34 | |||
| 35 | static bool | ||
| 36 | exynos_drm_encoder_mode_fixup(struct drm_encoder *encoder, | ||
| 37 | const struct drm_display_mode *mode, | ||
| 38 | struct drm_display_mode *adjusted_mode) | ||
| 39 | { | ||
| 40 | struct drm_device *dev = encoder->dev; | ||
| 41 | struct exynos_drm_encoder *exynos_encoder = to_exynos_encoder(encoder); | ||
| 42 | struct exynos_drm_display *display = exynos_encoder->display; | ||
| 43 | struct drm_connector *connector; | ||
| 44 | |||
| 45 | list_for_each_entry(connector, &dev->mode_config.connector_list, head) { | ||
| 46 | if (connector->encoder != encoder) | ||
| 47 | continue; | ||
| 48 | |||
| 49 | if (display->ops->mode_fixup) | ||
| 50 | display->ops->mode_fixup(display, connector, mode, | ||
| 51 | adjusted_mode); | ||
| 52 | } | ||
| 53 | |||
| 54 | return true; | ||
| 55 | } | ||
| 56 | |||
| 57 | static void exynos_drm_encoder_mode_set(struct drm_encoder *encoder, | ||
| 58 | struct drm_display_mode *mode, | ||
| 59 | struct drm_display_mode *adjusted_mode) | ||
| 60 | { | ||
| 61 | struct exynos_drm_encoder *exynos_encoder = to_exynos_encoder(encoder); | ||
| 62 | struct exynos_drm_display *display = exynos_encoder->display; | ||
| 63 | |||
| 64 | if (display->ops->mode_set) | ||
| 65 | display->ops->mode_set(display, adjusted_mode); | ||
| 66 | } | ||
| 67 | |||
| 68 | static void exynos_drm_encoder_enable(struct drm_encoder *encoder) | ||
| 69 | { | ||
| 70 | struct exynos_drm_encoder *exynos_encoder = to_exynos_encoder(encoder); | ||
| 71 | struct exynos_drm_display *display = exynos_encoder->display; | ||
| 72 | |||
| 73 | if (display->ops->dpms) | ||
| 74 | display->ops->dpms(display, DRM_MODE_DPMS_ON); | ||
| 75 | |||
| 76 | if (display->ops->commit) | ||
| 77 | display->ops->commit(display); | ||
| 78 | } | ||
| 79 | |||
| 80 | static void exynos_drm_encoder_disable(struct drm_encoder *encoder) | ||
| 81 | { | ||
| 82 | struct exynos_drm_encoder *exynos_encoder = to_exynos_encoder(encoder); | ||
| 83 | struct exynos_drm_display *display = exynos_encoder->display; | ||
| 84 | |||
| 85 | if (display->ops->dpms) | ||
| 86 | display->ops->dpms(display, DRM_MODE_DPMS_OFF); | ||
| 87 | } | ||
| 88 | |||
| 89 | static struct drm_encoder_helper_funcs exynos_encoder_helper_funcs = { | ||
| 90 | .mode_fixup = exynos_drm_encoder_mode_fixup, | ||
| 91 | .mode_set = exynos_drm_encoder_mode_set, | ||
| 92 | .enable = exynos_drm_encoder_enable, | ||
| 93 | .disable = exynos_drm_encoder_disable, | ||
| 94 | }; | ||
| 95 | |||
| 96 | static void exynos_drm_encoder_destroy(struct drm_encoder *encoder) | ||
| 97 | { | ||
| 98 | struct exynos_drm_encoder *exynos_encoder = to_exynos_encoder(encoder); | ||
| 99 | |||
| 100 | drm_encoder_cleanup(encoder); | ||
| 101 | kfree(exynos_encoder); | ||
| 102 | } | ||
| 103 | |||
| 104 | static struct drm_encoder_funcs exynos_encoder_funcs = { | ||
| 105 | .destroy = exynos_drm_encoder_destroy, | ||
| 106 | }; | ||
| 107 | |||
| 108 | static unsigned int exynos_drm_encoder_clones(struct drm_encoder *encoder) | ||
| 109 | { | ||
| 110 | struct drm_encoder *clone; | ||
| 111 | struct drm_device *dev = encoder->dev; | ||
| 112 | struct exynos_drm_encoder *exynos_encoder = to_exynos_encoder(encoder); | ||
| 113 | struct exynos_drm_display *display = exynos_encoder->display; | ||
| 114 | unsigned int clone_mask = 0; | ||
| 115 | int cnt = 0; | ||
| 116 | |||
| 117 | list_for_each_entry(clone, &dev->mode_config.encoder_list, head) { | ||
| 118 | switch (display->type) { | ||
| 119 | case EXYNOS_DISPLAY_TYPE_LCD: | ||
| 120 | case EXYNOS_DISPLAY_TYPE_HDMI: | ||
| 121 | case EXYNOS_DISPLAY_TYPE_VIDI: | ||
| 122 | clone_mask |= (1 << (cnt++)); | ||
| 123 | break; | ||
| 124 | default: | ||
| 125 | continue; | ||
| 126 | } | ||
| 127 | } | ||
| 128 | |||
| 129 | return clone_mask; | ||
| 130 | } | ||
| 131 | |||
| 132 | void exynos_drm_encoder_setup(struct drm_device *dev) | ||
| 133 | { | ||
| 134 | struct drm_encoder *encoder; | ||
| 135 | |||
| 136 | list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) | ||
| 137 | encoder->possible_clones = exynos_drm_encoder_clones(encoder); | ||
| 138 | } | ||
| 139 | |||
| 140 | struct drm_encoder * | ||
| 141 | exynos_drm_encoder_create(struct drm_device *dev, | ||
| 142 | struct exynos_drm_display *display, | ||
| 143 | unsigned long possible_crtcs) | ||
| 144 | { | ||
| 145 | struct drm_encoder *encoder; | ||
| 146 | struct exynos_drm_encoder *exynos_encoder; | ||
| 147 | |||
| 148 | if (!possible_crtcs) | ||
| 149 | return NULL; | ||
| 150 | |||
| 151 | exynos_encoder = kzalloc(sizeof(*exynos_encoder), GFP_KERNEL); | ||
| 152 | if (!exynos_encoder) | ||
| 153 | return NULL; | ||
| 154 | |||
| 155 | exynos_encoder->display = display; | ||
| 156 | encoder = &exynos_encoder->drm_encoder; | ||
| 157 | encoder->possible_crtcs = possible_crtcs; | ||
| 158 | |||
| 159 | DRM_DEBUG_KMS("possible_crtcs = 0x%x\n", encoder->possible_crtcs); | ||
| 160 | |||
| 161 | drm_encoder_init(dev, encoder, &exynos_encoder_funcs, | ||
| 162 | DRM_MODE_ENCODER_TMDS); | ||
| 163 | |||
| 164 | drm_encoder_helper_add(encoder, &exynos_encoder_helper_funcs); | ||
| 165 | |||
| 166 | DRM_DEBUG_KMS("encoder has been created\n"); | ||
| 167 | |||
| 168 | return encoder; | ||
| 169 | } | ||
| 170 | |||
| 171 | struct exynos_drm_display *exynos_drm_get_display(struct drm_encoder *encoder) | ||
| 172 | { | ||
| 173 | return to_exynos_encoder(encoder)->display; | ||
| 174 | } | ||
diff --git a/drivers/gpu/drm/exynos/exynos_drm_encoder.h b/drivers/gpu/drm/exynos/exynos_drm_encoder.h deleted file mode 100644 index 26305d8dd93a..000000000000 --- a/drivers/gpu/drm/exynos/exynos_drm_encoder.h +++ /dev/null | |||
| @@ -1,23 +0,0 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (c) 2011 Samsung Electronics Co., Ltd. | ||
| 3 | * Authors: | ||
| 4 | * Inki Dae <inki.dae@samsung.com> | ||
| 5 | * Joonyoung Shim <jy0922.shim@samsung.com> | ||
| 6 | * Seung-Woo Kim <sw0312.kim@samsung.com> | ||
| 7 | * | ||
| 8 | * This program is free software; you can redistribute it and/or modify it | ||
| 9 | * under the terms of the GNU General Public License as published by the | ||
| 10 | * Free Software Foundation; either version 2 of the License, or (at your | ||
| 11 | * option) any later version. | ||
| 12 | */ | ||
| 13 | |||
| 14 | #ifndef _EXYNOS_DRM_ENCODER_H_ | ||
| 15 | #define _EXYNOS_DRM_ENCODER_H_ | ||
| 16 | |||
| 17 | void exynos_drm_encoder_setup(struct drm_device *dev); | ||
| 18 | struct drm_encoder *exynos_drm_encoder_create(struct drm_device *dev, | ||
| 19 | struct exynos_drm_display *mgr, | ||
| 20 | unsigned long possible_crtcs); | ||
| 21 | struct exynos_drm_display *exynos_drm_get_display(struct drm_encoder *encoder); | ||
| 22 | |||
| 23 | #endif | ||
diff --git a/drivers/gpu/drm/exynos/exynos_drm_fb.c b/drivers/gpu/drm/exynos/exynos_drm_fb.c index 2b6320e6eae2..9738f4e0c6eb 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_fb.c +++ b/drivers/gpu/drm/exynos/exynos_drm_fb.c | |||
| @@ -238,22 +238,22 @@ err_free: | |||
| 238 | return ERR_PTR(ret); | 238 | return ERR_PTR(ret); |
| 239 | } | 239 | } |
| 240 | 240 | ||
| 241 | struct exynos_drm_gem_buf *exynos_drm_fb_buffer(struct drm_framebuffer *fb, | 241 | struct exynos_drm_gem_obj *exynos_drm_fb_gem_obj(struct drm_framebuffer *fb, |
| 242 | int index) | 242 | int index) |
| 243 | { | 243 | { |
| 244 | struct exynos_drm_fb *exynos_fb = to_exynos_fb(fb); | 244 | struct exynos_drm_fb *exynos_fb = to_exynos_fb(fb); |
| 245 | struct exynos_drm_gem_buf *buffer; | 245 | struct exynos_drm_gem_obj *obj; |
| 246 | 246 | ||
| 247 | if (index >= MAX_FB_BUFFER) | 247 | if (index >= MAX_FB_BUFFER) |
| 248 | return NULL; | 248 | return NULL; |
| 249 | 249 | ||
| 250 | buffer = exynos_fb->exynos_gem_obj[index]->buffer; | 250 | obj = exynos_fb->exynos_gem_obj[index]; |
| 251 | if (!buffer) | 251 | if (!obj) |
| 252 | return NULL; | 252 | return NULL; |
| 253 | 253 | ||
| 254 | DRM_DEBUG_KMS("dma_addr = 0x%lx\n", (unsigned long)buffer->dma_addr); | 254 | DRM_DEBUG_KMS("dma_addr = 0x%lx\n", (unsigned long)obj->dma_addr); |
| 255 | 255 | ||
| 256 | return buffer; | 256 | return obj; |
| 257 | } | 257 | } |
| 258 | 258 | ||
| 259 | static void exynos_drm_output_poll_changed(struct drm_device *dev) | 259 | 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 517471b37566..1c9e27c32cd1 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_fb.h +++ b/drivers/gpu/drm/exynos/exynos_drm_fb.h | |||
| @@ -19,8 +19,8 @@ exynos_drm_framebuffer_init(struct drm_device *dev, | |||
| 19 | struct drm_mode_fb_cmd2 *mode_cmd, | 19 | struct drm_mode_fb_cmd2 *mode_cmd, |
| 20 | struct drm_gem_object *obj); | 20 | struct drm_gem_object *obj); |
| 21 | 21 | ||
| 22 | /* get memory information of a drm framebuffer */ | 22 | /* get gem object of a drm framebuffer */ |
| 23 | struct exynos_drm_gem_buf *exynos_drm_fb_buffer(struct drm_framebuffer *fb, | 23 | struct exynos_drm_gem_obj *exynos_drm_fb_gem_obj(struct drm_framebuffer *fb, |
| 24 | int index); | 24 | int index); |
| 25 | 25 | ||
| 26 | void exynos_drm_mode_config_init(struct drm_device *dev); | 26 | 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 dd64bc04ffbb..624595afbce0 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_fbdev.c +++ b/drivers/gpu/drm/exynos/exynos_drm_fbdev.c | |||
| @@ -40,8 +40,7 @@ static int exynos_drm_fb_mmap(struct fb_info *info, | |||
| 40 | { | 40 | { |
| 41 | struct drm_fb_helper *helper = info->par; | 41 | struct drm_fb_helper *helper = info->par; |
| 42 | struct exynos_drm_fbdev *exynos_fbd = to_exynos_fbdev(helper); | 42 | struct exynos_drm_fbdev *exynos_fbd = to_exynos_fbdev(helper); |
| 43 | struct exynos_drm_gem_obj *exynos_gem_obj = exynos_fbd->exynos_gem_obj; | 43 | struct exynos_drm_gem_obj *obj = exynos_fbd->exynos_gem_obj; |
| 44 | struct exynos_drm_gem_buf *buffer = exynos_gem_obj->buffer; | ||
| 45 | unsigned long vm_size; | 44 | unsigned long vm_size; |
| 46 | int ret; | 45 | int ret; |
| 47 | 46 | ||
| @@ -49,11 +48,11 @@ static int exynos_drm_fb_mmap(struct fb_info *info, | |||
| 49 | 48 | ||
| 50 | vm_size = vma->vm_end - vma->vm_start; | 49 | vm_size = vma->vm_end - vma->vm_start; |
| 51 | 50 | ||
| 52 | if (vm_size > buffer->size) | 51 | if (vm_size > obj->size) |
| 53 | return -EINVAL; | 52 | return -EINVAL; |
| 54 | 53 | ||
| 55 | ret = dma_mmap_attrs(helper->dev->dev, vma, buffer->pages, | 54 | ret = dma_mmap_attrs(helper->dev->dev, vma, obj->pages, obj->dma_addr, |
| 56 | buffer->dma_addr, buffer->size, &buffer->dma_attrs); | 55 | obj->size, &obj->dma_attrs); |
| 57 | if (ret < 0) { | 56 | if (ret < 0) { |
| 58 | DRM_ERROR("failed to mmap.\n"); | 57 | DRM_ERROR("failed to mmap.\n"); |
| 59 | return ret; | 58 | return ret; |
| @@ -80,7 +79,7 @@ static int exynos_drm_fbdev_update(struct drm_fb_helper *helper, | |||
| 80 | struct drm_framebuffer *fb) | 79 | struct drm_framebuffer *fb) |
| 81 | { | 80 | { |
| 82 | struct fb_info *fbi = helper->fbdev; | 81 | struct fb_info *fbi = helper->fbdev; |
| 83 | struct exynos_drm_gem_buf *buffer; | 82 | struct exynos_drm_gem_obj *obj; |
| 84 | unsigned int size = fb->width * fb->height * (fb->bits_per_pixel >> 3); | 83 | unsigned int size = fb->width * fb->height * (fb->bits_per_pixel >> 3); |
| 85 | unsigned int nr_pages; | 84 | unsigned int nr_pages; |
| 86 | unsigned long offset; | 85 | unsigned long offset; |
| @@ -89,18 +88,17 @@ static int exynos_drm_fbdev_update(struct drm_fb_helper *helper, | |||
| 89 | drm_fb_helper_fill_var(fbi, helper, sizes->fb_width, sizes->fb_height); | 88 | drm_fb_helper_fill_var(fbi, helper, sizes->fb_width, sizes->fb_height); |
| 90 | 89 | ||
| 91 | /* RGB formats use only one buffer */ | 90 | /* RGB formats use only one buffer */ |
| 92 | buffer = exynos_drm_fb_buffer(fb, 0); | 91 | obj = exynos_drm_fb_gem_obj(fb, 0); |
| 93 | if (!buffer) { | 92 | if (!obj) { |
| 94 | DRM_DEBUG_KMS("buffer is null.\n"); | 93 | DRM_DEBUG_KMS("gem object is null.\n"); |
| 95 | return -EFAULT; | 94 | return -EFAULT; |
| 96 | } | 95 | } |
| 97 | 96 | ||
| 98 | nr_pages = buffer->size >> PAGE_SHIFT; | 97 | nr_pages = obj->size >> PAGE_SHIFT; |
| 99 | 98 | ||
| 100 | buffer->kvaddr = (void __iomem *) vmap(buffer->pages, | 99 | obj->kvaddr = (void __iomem *) vmap(obj->pages, nr_pages, VM_MAP, |
| 101 | nr_pages, VM_MAP, | ||
| 102 | pgprot_writecombine(PAGE_KERNEL)); | 100 | pgprot_writecombine(PAGE_KERNEL)); |
| 103 | if (!buffer->kvaddr) { | 101 | if (!obj->kvaddr) { |
| 104 | DRM_ERROR("failed to map pages to kernel space.\n"); | 102 | DRM_ERROR("failed to map pages to kernel space.\n"); |
| 105 | return -EIO; | 103 | return -EIO; |
| 106 | } | 104 | } |
| @@ -111,7 +109,7 @@ static int exynos_drm_fbdev_update(struct drm_fb_helper *helper, | |||
| 111 | offset = fbi->var.xoffset * (fb->bits_per_pixel >> 3); | 109 | offset = fbi->var.xoffset * (fb->bits_per_pixel >> 3); |
| 112 | offset += fbi->var.yoffset * fb->pitches[0]; | 110 | offset += fbi->var.yoffset * fb->pitches[0]; |
| 113 | 111 | ||
| 114 | fbi->screen_base = buffer->kvaddr + offset; | 112 | fbi->screen_base = obj->kvaddr + offset; |
| 115 | fbi->screen_size = size; | 113 | fbi->screen_size = size; |
| 116 | fbi->fix.smem_len = size; | 114 | fbi->fix.smem_len = size; |
| 117 | 115 | ||
| @@ -290,8 +288,8 @@ static void exynos_drm_fbdev_destroy(struct drm_device *dev, | |||
| 290 | struct exynos_drm_gem_obj *exynos_gem_obj = exynos_fbd->exynos_gem_obj; | 288 | struct exynos_drm_gem_obj *exynos_gem_obj = exynos_fbd->exynos_gem_obj; |
| 291 | struct drm_framebuffer *fb; | 289 | struct drm_framebuffer *fb; |
| 292 | 290 | ||
| 293 | if (exynos_gem_obj->buffer->kvaddr) | 291 | if (exynos_gem_obj->kvaddr) |
| 294 | vunmap(exynos_gem_obj->buffer->kvaddr); | 292 | vunmap(exynos_gem_obj->kvaddr); |
| 295 | 293 | ||
| 296 | /* release drm framebuffer and real buffer */ | 294 | /* release drm framebuffer and real buffer */ |
| 297 | if (fb_helper->fb && fb_helper->fb->funcs) { | 295 | if (fb_helper->fb && fb_helper->fb->funcs) { |
diff --git a/drivers/gpu/drm/exynos/exynos_drm_fimd.c b/drivers/gpu/drm/exynos/exynos_drm_fimd.c index 794e56c8798e..5def6bc073eb 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_fimd.c +++ b/drivers/gpu/drm/exynos/exynos_drm_fimd.c | |||
| @@ -169,7 +169,7 @@ struct fimd_context { | |||
| 169 | 169 | ||
| 170 | struct exynos_drm_panel_info panel; | 170 | struct exynos_drm_panel_info panel; |
| 171 | struct fimd_driver_data *driver_data; | 171 | struct fimd_driver_data *driver_data; |
| 172 | struct exynos_drm_display *display; | 172 | struct drm_encoder *encoder; |
| 173 | }; | 173 | }; |
| 174 | 174 | ||
| 175 | static const struct of_device_id fimd_driver_dt_match[] = { | 175 | static const struct of_device_id fimd_driver_dt_match[] = { |
| @@ -348,13 +348,6 @@ static void fimd_clear_channels(struct exynos_drm_crtc *crtc) | |||
| 348 | pm_runtime_put(ctx->dev); | 348 | pm_runtime_put(ctx->dev); |
| 349 | } | 349 | } |
| 350 | 350 | ||
| 351 | static void fimd_iommu_detach_devices(struct fimd_context *ctx) | ||
| 352 | { | ||
| 353 | /* detach this sub driver from iommu mapping if supported. */ | ||
| 354 | if (is_drm_iommu_supported(ctx->drm_dev)) | ||
| 355 | drm_iommu_detach_device(ctx->drm_dev, ctx->dev); | ||
| 356 | } | ||
| 357 | |||
| 358 | static u32 fimd_calc_clkdiv(struct fimd_context *ctx, | 351 | static u32 fimd_calc_clkdiv(struct fimd_context *ctx, |
| 359 | const struct drm_display_mode *mode) | 352 | const struct drm_display_mode *mode) |
| 360 | { | 353 | { |
| @@ -486,9 +479,9 @@ static void fimd_commit(struct exynos_drm_crtc *crtc) | |||
| 486 | } | 479 | } |
| 487 | 480 | ||
| 488 | 481 | ||
| 489 | static void fimd_win_set_pixfmt(struct fimd_context *ctx, unsigned int win) | 482 | static void fimd_win_set_pixfmt(struct fimd_context *ctx, unsigned int win, |
| 483 | struct drm_framebuffer *fb) | ||
| 490 | { | 484 | { |
| 491 | struct exynos_drm_plane *plane = &ctx->planes[win]; | ||
| 492 | unsigned long val; | 485 | unsigned long val; |
| 493 | 486 | ||
| 494 | val = WINCONx_ENWIN; | 487 | val = WINCONx_ENWIN; |
| @@ -498,11 +491,11 @@ static void fimd_win_set_pixfmt(struct fimd_context *ctx, unsigned int win) | |||
| 498 | * So the request format is ARGB8888 then change it to XRGB8888. | 491 | * So the request format is ARGB8888 then change it to XRGB8888. |
| 499 | */ | 492 | */ |
| 500 | if (ctx->driver_data->has_limited_fmt && !win) { | 493 | if (ctx->driver_data->has_limited_fmt && !win) { |
| 501 | if (plane->pixel_format == DRM_FORMAT_ARGB8888) | 494 | if (fb->pixel_format == DRM_FORMAT_ARGB8888) |
| 502 | plane->pixel_format = DRM_FORMAT_XRGB8888; | 495 | fb->pixel_format = DRM_FORMAT_XRGB8888; |
| 503 | } | 496 | } |
| 504 | 497 | ||
| 505 | switch (plane->pixel_format) { | 498 | switch (fb->pixel_format) { |
| 506 | case DRM_FORMAT_C8: | 499 | case DRM_FORMAT_C8: |
| 507 | val |= WINCON0_BPPMODE_8BPP_PALETTE; | 500 | val |= WINCON0_BPPMODE_8BPP_PALETTE; |
| 508 | val |= WINCONx_BURSTLEN_8WORD; | 501 | val |= WINCONx_BURSTLEN_8WORD; |
| @@ -538,7 +531,7 @@ static void fimd_win_set_pixfmt(struct fimd_context *ctx, unsigned int win) | |||
| 538 | break; | 531 | break; |
| 539 | } | 532 | } |
| 540 | 533 | ||
| 541 | DRM_DEBUG_KMS("bpp = %d\n", plane->bpp); | 534 | DRM_DEBUG_KMS("bpp = %d\n", fb->bits_per_pixel); |
| 542 | 535 | ||
| 543 | /* | 536 | /* |
| 544 | * In case of exynos, setting dma-burst to 16Word causes permanent | 537 | * In case of exynos, setting dma-burst to 16Word causes permanent |
| @@ -548,7 +541,7 @@ static void fimd_win_set_pixfmt(struct fimd_context *ctx, unsigned int win) | |||
| 548 | * movement causes unstable DMA which results into iommu crash/tear. | 541 | * movement causes unstable DMA which results into iommu crash/tear. |
| 549 | */ | 542 | */ |
| 550 | 543 | ||
| 551 | if (plane->fb_width < MIN_FB_WIDTH_FOR_16WORD_BURST) { | 544 | if (fb->width < MIN_FB_WIDTH_FOR_16WORD_BURST) { |
| 552 | val &= ~WINCONx_BURSTLEN_MASK; | 545 | val &= ~WINCONx_BURSTLEN_MASK; |
| 553 | val |= WINCONx_BURSTLEN_4WORD; | 546 | val |= WINCONx_BURSTLEN_4WORD; |
| 554 | } | 547 | } |
| @@ -614,21 +607,17 @@ static void fimd_shadow_protect_win(struct fimd_context *ctx, | |||
| 614 | writel(val, ctx->regs + reg); | 607 | writel(val, ctx->regs + reg); |
| 615 | } | 608 | } |
| 616 | 609 | ||
| 617 | static void fimd_win_commit(struct exynos_drm_crtc *crtc, unsigned int win) | 610 | static void fimd_update_plane(struct exynos_drm_crtc *crtc, |
| 611 | struct exynos_drm_plane *plane) | ||
| 618 | { | 612 | { |
| 619 | struct fimd_context *ctx = crtc->ctx; | 613 | struct fimd_context *ctx = crtc->ctx; |
| 620 | struct exynos_drm_plane *plane; | 614 | struct drm_plane_state *state = plane->base.state; |
| 621 | dma_addr_t dma_addr; | 615 | dma_addr_t dma_addr; |
| 622 | unsigned long val, size, offset; | 616 | unsigned long val, size, offset; |
| 623 | unsigned int last_x, last_y, buf_offsize, line_size; | 617 | unsigned int last_x, last_y, buf_offsize, line_size; |
| 624 | 618 | unsigned int win = plane->zpos; | |
| 625 | if (ctx->suspended) | 619 | unsigned int bpp = state->fb->bits_per_pixel >> 3; |
| 626 | return; | 620 | unsigned int pitch = state->fb->pitches[0]; |
| 627 | |||
| 628 | if (win < 0 || win >= WINDOWS_NR) | ||
| 629 | return; | ||
| 630 | |||
| 631 | plane = &ctx->planes[win]; | ||
| 632 | 621 | ||
| 633 | if (ctx->suspended) | 622 | if (ctx->suspended) |
| 634 | return; | 623 | return; |
| @@ -647,8 +636,8 @@ static void fimd_win_commit(struct exynos_drm_crtc *crtc, unsigned int win) | |||
| 647 | fimd_shadow_protect_win(ctx, win, true); | 636 | fimd_shadow_protect_win(ctx, win, true); |
| 648 | 637 | ||
| 649 | 638 | ||
| 650 | offset = plane->src_x * (plane->bpp >> 3); | 639 | offset = plane->src_x * bpp; |
| 651 | offset += plane->src_y * plane->pitch; | 640 | offset += plane->src_y * pitch; |
| 652 | 641 | ||
| 653 | /* buffer start address */ | 642 | /* buffer start address */ |
| 654 | dma_addr = plane->dma_addr[0] + offset; | 643 | dma_addr = plane->dma_addr[0] + offset; |
| @@ -656,18 +645,18 @@ static void fimd_win_commit(struct exynos_drm_crtc *crtc, unsigned int win) | |||
| 656 | writel(val, ctx->regs + VIDWx_BUF_START(win, 0)); | 645 | writel(val, ctx->regs + VIDWx_BUF_START(win, 0)); |
| 657 | 646 | ||
| 658 | /* buffer end address */ | 647 | /* buffer end address */ |
| 659 | size = plane->pitch * plane->crtc_height; | 648 | size = pitch * plane->crtc_h; |
| 660 | val = (unsigned long)(dma_addr + size); | 649 | val = (unsigned long)(dma_addr + size); |
| 661 | writel(val, ctx->regs + VIDWx_BUF_END(win, 0)); | 650 | writel(val, ctx->regs + VIDWx_BUF_END(win, 0)); |
| 662 | 651 | ||
| 663 | DRM_DEBUG_KMS("start addr = 0x%lx, end addr = 0x%lx, size = 0x%lx\n", | 652 | DRM_DEBUG_KMS("start addr = 0x%lx, end addr = 0x%lx, size = 0x%lx\n", |
| 664 | (unsigned long)dma_addr, val, size); | 653 | (unsigned long)dma_addr, val, size); |
| 665 | DRM_DEBUG_KMS("ovl_width = %d, ovl_height = %d\n", | 654 | DRM_DEBUG_KMS("ovl_width = %d, ovl_height = %d\n", |
| 666 | plane->crtc_width, plane->crtc_height); | 655 | plane->crtc_w, plane->crtc_h); |
| 667 | 656 | ||
| 668 | /* buffer size */ | 657 | /* buffer size */ |
| 669 | buf_offsize = plane->pitch - (plane->crtc_width * (plane->bpp >> 3)); | 658 | buf_offsize = pitch - (plane->crtc_w * bpp); |
| 670 | line_size = plane->crtc_width * (plane->bpp >> 3); | 659 | line_size = plane->crtc_w * bpp; |
| 671 | val = VIDW_BUF_SIZE_OFFSET(buf_offsize) | | 660 | val = VIDW_BUF_SIZE_OFFSET(buf_offsize) | |
| 672 | VIDW_BUF_SIZE_PAGEWIDTH(line_size) | | 661 | VIDW_BUF_SIZE_PAGEWIDTH(line_size) | |
| 673 | VIDW_BUF_SIZE_OFFSET_E(buf_offsize) | | 662 | VIDW_BUF_SIZE_OFFSET_E(buf_offsize) | |
| @@ -681,10 +670,10 @@ static void fimd_win_commit(struct exynos_drm_crtc *crtc, unsigned int win) | |||
| 681 | VIDOSDxA_TOPLEFT_Y_E(plane->crtc_y); | 670 | VIDOSDxA_TOPLEFT_Y_E(plane->crtc_y); |
| 682 | writel(val, ctx->regs + VIDOSD_A(win)); | 671 | writel(val, ctx->regs + VIDOSD_A(win)); |
| 683 | 672 | ||
| 684 | last_x = plane->crtc_x + plane->crtc_width; | 673 | last_x = plane->crtc_x + plane->crtc_w; |
| 685 | if (last_x) | 674 | if (last_x) |
| 686 | last_x--; | 675 | last_x--; |
| 687 | last_y = plane->crtc_y + plane->crtc_height; | 676 | last_y = plane->crtc_y + plane->crtc_h; |
| 688 | if (last_y) | 677 | if (last_y) |
| 689 | last_y--; | 678 | last_y--; |
| 690 | 679 | ||
| @@ -701,13 +690,13 @@ static void fimd_win_commit(struct exynos_drm_crtc *crtc, unsigned int win) | |||
| 701 | u32 offset = VIDOSD_D(win); | 690 | u32 offset = VIDOSD_D(win); |
| 702 | if (win == 0) | 691 | if (win == 0) |
| 703 | offset = VIDOSD_C(win); | 692 | offset = VIDOSD_C(win); |
| 704 | val = plane->crtc_width * plane->crtc_height; | 693 | val = plane->crtc_w * plane->crtc_h; |
| 705 | writel(val, ctx->regs + offset); | 694 | writel(val, ctx->regs + offset); |
| 706 | 695 | ||
| 707 | DRM_DEBUG_KMS("osd size = 0x%x\n", (unsigned int)val); | 696 | DRM_DEBUG_KMS("osd size = 0x%x\n", (unsigned int)val); |
| 708 | } | 697 | } |
| 709 | 698 | ||
| 710 | fimd_win_set_pixfmt(ctx, win); | 699 | fimd_win_set_pixfmt(ctx, win, state->fb); |
| 711 | 700 | ||
| 712 | /* hardware window 0 doesn't support color key. */ | 701 | /* hardware window 0 doesn't support color key. */ |
| 713 | if (win != 0) | 702 | if (win != 0) |
| @@ -725,15 +714,11 @@ static void fimd_win_commit(struct exynos_drm_crtc *crtc, unsigned int win) | |||
| 725 | atomic_set(&ctx->win_updated, 1); | 714 | atomic_set(&ctx->win_updated, 1); |
| 726 | } | 715 | } |
| 727 | 716 | ||
| 728 | static void fimd_win_disable(struct exynos_drm_crtc *crtc, unsigned int win) | 717 | static void fimd_disable_plane(struct exynos_drm_crtc *crtc, |
| 718 | struct exynos_drm_plane *plane) | ||
| 729 | { | 719 | { |
| 730 | struct fimd_context *ctx = crtc->ctx; | 720 | struct fimd_context *ctx = crtc->ctx; |
| 731 | struct exynos_drm_plane *plane; | 721 | unsigned int win = plane->zpos; |
| 732 | |||
| 733 | if (win < 0 || win >= WINDOWS_NR) | ||
| 734 | return; | ||
| 735 | |||
| 736 | plane = &ctx->planes[win]; | ||
| 737 | 722 | ||
| 738 | if (ctx->suspended) | 723 | if (ctx->suspended) |
| 739 | return; | 724 | return; |
| @@ -795,7 +780,7 @@ static void fimd_disable(struct exynos_drm_crtc *crtc) | |||
| 795 | * a destroyed buffer later. | 780 | * a destroyed buffer later. |
| 796 | */ | 781 | */ |
| 797 | for (i = 0; i < WINDOWS_NR; i++) | 782 | for (i = 0; i < WINDOWS_NR; i++) |
| 798 | fimd_win_disable(crtc, i); | 783 | fimd_disable_plane(crtc, &ctx->planes[i]); |
| 799 | 784 | ||
| 800 | fimd_enable_vblank(crtc); | 785 | fimd_enable_vblank(crtc); |
| 801 | fimd_wait_for_vblank(crtc); | 786 | fimd_wait_for_vblank(crtc); |
| @@ -862,7 +847,7 @@ static void fimd_te_handler(struct exynos_drm_crtc *crtc) | |||
| 862 | } | 847 | } |
| 863 | 848 | ||
| 864 | if (test_bit(0, &ctx->irq_flags)) | 849 | if (test_bit(0, &ctx->irq_flags)) |
| 865 | drm_handle_vblank(ctx->drm_dev, ctx->pipe); | 850 | drm_crtc_handle_vblank(&ctx->crtc->base); |
| 866 | } | 851 | } |
| 867 | 852 | ||
| 868 | static void fimd_dp_clock_enable(struct exynos_drm_crtc *crtc, bool enable) | 853 | static void fimd_dp_clock_enable(struct exynos_drm_crtc *crtc, bool enable) |
| @@ -890,11 +875,10 @@ static const struct exynos_drm_crtc_ops fimd_crtc_ops = { | |||
| 890 | .enable_vblank = fimd_enable_vblank, | 875 | .enable_vblank = fimd_enable_vblank, |
| 891 | .disable_vblank = fimd_disable_vblank, | 876 | .disable_vblank = fimd_disable_vblank, |
| 892 | .wait_for_vblank = fimd_wait_for_vblank, | 877 | .wait_for_vblank = fimd_wait_for_vblank, |
| 893 | .win_commit = fimd_win_commit, | 878 | .update_plane = fimd_update_plane, |
| 894 | .win_disable = fimd_win_disable, | 879 | .disable_plane = fimd_disable_plane, |
| 895 | .te_handler = fimd_te_handler, | 880 | .te_handler = fimd_te_handler, |
| 896 | .clock_enable = fimd_dp_clock_enable, | 881 | .clock_enable = fimd_dp_clock_enable, |
| 897 | .clear_channels = fimd_clear_channels, | ||
| 898 | }; | 882 | }; |
| 899 | 883 | ||
| 900 | static irqreturn_t fimd_irq_handler(int irq, void *dev_id) | 884 | static irqreturn_t fimd_irq_handler(int irq, void *dev_id) |
| @@ -913,13 +897,13 @@ static irqreturn_t fimd_irq_handler(int irq, void *dev_id) | |||
| 913 | goto out; | 897 | goto out; |
| 914 | 898 | ||
| 915 | if (ctx->i80_if) { | 899 | if (ctx->i80_if) { |
| 916 | exynos_drm_crtc_finish_pageflip(ctx->drm_dev, ctx->pipe); | 900 | exynos_drm_crtc_finish_pageflip(ctx->crtc); |
| 917 | 901 | ||
| 918 | /* Exits triggering mode */ | 902 | /* Exits triggering mode */ |
| 919 | atomic_set(&ctx->triggering, 0); | 903 | atomic_set(&ctx->triggering, 0); |
| 920 | } else { | 904 | } else { |
| 921 | drm_handle_vblank(ctx->drm_dev, ctx->pipe); | 905 | drm_crtc_handle_vblank(&ctx->crtc->base); |
| 922 | exynos_drm_crtc_finish_pageflip(ctx->drm_dev, ctx->pipe); | 906 | exynos_drm_crtc_finish_pageflip(ctx->crtc); |
| 923 | 907 | ||
| 924 | /* set wait vsync event to zero and wake up queue. */ | 908 | /* set wait vsync event to zero and wake up queue. */ |
| 925 | if (atomic_read(&ctx->wait_vsync_event)) { | 909 | if (atomic_read(&ctx->wait_vsync_event)) { |
| @@ -961,10 +945,13 @@ static int fimd_bind(struct device *dev, struct device *master, void *data) | |||
| 961 | if (IS_ERR(ctx->crtc)) | 945 | if (IS_ERR(ctx->crtc)) |
| 962 | return PTR_ERR(ctx->crtc); | 946 | return PTR_ERR(ctx->crtc); |
| 963 | 947 | ||
| 964 | if (ctx->display) | 948 | if (ctx->encoder) |
| 965 | exynos_drm_create_enc_conn(drm_dev, ctx->display); | 949 | exynos_dpi_bind(drm_dev, ctx->encoder); |
| 950 | |||
| 951 | if (is_drm_iommu_supported(drm_dev)) | ||
| 952 | fimd_clear_channels(ctx->crtc); | ||
| 966 | 953 | ||
| 967 | ret = drm_iommu_attach_device_if_possible(ctx->crtc, drm_dev, dev); | 954 | ret = drm_iommu_attach_device(drm_dev, dev); |
| 968 | if (ret) | 955 | if (ret) |
| 969 | priv->pipe--; | 956 | priv->pipe--; |
| 970 | 957 | ||
| @@ -978,10 +965,10 @@ static void fimd_unbind(struct device *dev, struct device *master, | |||
| 978 | 965 | ||
| 979 | fimd_disable(ctx->crtc); | 966 | fimd_disable(ctx->crtc); |
| 980 | 967 | ||
| 981 | fimd_iommu_detach_devices(ctx); | 968 | drm_iommu_detach_device(ctx->drm_dev, ctx->dev); |
| 982 | 969 | ||
| 983 | if (ctx->display) | 970 | if (ctx->encoder) |
| 984 | exynos_dpi_remove(ctx->display); | 971 | exynos_dpi_remove(ctx->encoder); |
| 985 | } | 972 | } |
| 986 | 973 | ||
| 987 | static const struct component_ops fimd_component_ops = { | 974 | static const struct component_ops fimd_component_ops = { |
| @@ -1088,10 +1075,9 @@ static int fimd_probe(struct platform_device *pdev) | |||
| 1088 | 1075 | ||
| 1089 | platform_set_drvdata(pdev, ctx); | 1076 | platform_set_drvdata(pdev, ctx); |
| 1090 | 1077 | ||
| 1091 | ctx->display = exynos_dpi_probe(dev); | 1078 | ctx->encoder = exynos_dpi_probe(dev); |
| 1092 | if (IS_ERR(ctx->display)) { | 1079 | if (IS_ERR(ctx->encoder)) |
| 1093 | return PTR_ERR(ctx->display); | 1080 | return PTR_ERR(ctx->encoder); |
| 1094 | } | ||
| 1095 | 1081 | ||
| 1096 | pm_runtime_enable(dev); | 1082 | pm_runtime_enable(dev); |
| 1097 | 1083 | ||
diff --git a/drivers/gpu/drm/exynos/exynos_drm_g2d.c b/drivers/gpu/drm/exynos/exynos_drm_g2d.c index 81a250830808..ba008391a2fc 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_g2d.c +++ b/drivers/gpu/drm/exynos/exynos_drm_g2d.c | |||
| @@ -1319,9 +1319,6 @@ static int g2d_subdrv_probe(struct drm_device *drm_dev, struct device *dev) | |||
| 1319 | return ret; | 1319 | return ret; |
| 1320 | } | 1320 | } |
| 1321 | 1321 | ||
| 1322 | if (!is_drm_iommu_supported(drm_dev)) | ||
| 1323 | return 0; | ||
| 1324 | |||
| 1325 | ret = drm_iommu_attach_device(drm_dev, dev); | 1322 | ret = drm_iommu_attach_device(drm_dev, dev); |
| 1326 | if (ret < 0) { | 1323 | if (ret < 0) { |
| 1327 | dev_err(dev, "failed to enable iommu.\n"); | 1324 | dev_err(dev, "failed to enable iommu.\n"); |
| @@ -1334,9 +1331,6 @@ static int g2d_subdrv_probe(struct drm_device *drm_dev, struct device *dev) | |||
| 1334 | 1331 | ||
| 1335 | static void g2d_subdrv_remove(struct drm_device *drm_dev, struct device *dev) | 1332 | static void g2d_subdrv_remove(struct drm_device *drm_dev, struct device *dev) |
| 1336 | { | 1333 | { |
| 1337 | if (!is_drm_iommu_supported(drm_dev)) | ||
| 1338 | return; | ||
| 1339 | |||
| 1340 | drm_iommu_detach_device(drm_dev, dev); | 1334 | drm_iommu_detach_device(drm_dev, dev); |
| 1341 | } | 1335 | } |
| 1342 | 1336 | ||
diff --git a/drivers/gpu/drm/exynos/exynos_drm_gem.c b/drivers/gpu/drm/exynos/exynos_drm_gem.c index 0d5b9698d384..67461b77f040 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_gem.c +++ b/drivers/gpu/drm/exynos/exynos_drm_gem.c | |||
| @@ -13,98 +13,112 @@ | |||
| 13 | #include <drm/drm_vma_manager.h> | 13 | #include <drm/drm_vma_manager.h> |
| 14 | 14 | ||
| 15 | #include <linux/shmem_fs.h> | 15 | #include <linux/shmem_fs.h> |
| 16 | #include <linux/dma-buf.h> | ||
| 16 | #include <drm/exynos_drm.h> | 17 | #include <drm/exynos_drm.h> |
| 17 | 18 | ||
| 18 | #include "exynos_drm_drv.h" | 19 | #include "exynos_drm_drv.h" |
| 19 | #include "exynos_drm_gem.h" | 20 | #include "exynos_drm_gem.h" |
| 20 | #include "exynos_drm_buf.h" | ||
| 21 | #include "exynos_drm_iommu.h" | 21 | #include "exynos_drm_iommu.h" |
| 22 | 22 | ||
| 23 | static unsigned int convert_to_vm_err_msg(int msg) | 23 | static int exynos_drm_alloc_buf(struct exynos_drm_gem_obj *obj) |
| 24 | { | 24 | { |
| 25 | unsigned int out_msg; | 25 | struct drm_device *dev = obj->base.dev; |
| 26 | enum dma_attr attr; | ||
| 27 | unsigned int nr_pages; | ||
| 26 | 28 | ||
| 27 | switch (msg) { | 29 | if (obj->dma_addr) { |
| 28 | case 0: | 30 | DRM_DEBUG_KMS("already allocated.\n"); |
| 29 | case -ERESTARTSYS: | 31 | return 0; |
| 30 | case -EINTR: | 32 | } |
| 31 | out_msg = VM_FAULT_NOPAGE; | ||
| 32 | break; | ||
| 33 | 33 | ||
| 34 | case -ENOMEM: | 34 | init_dma_attrs(&obj->dma_attrs); |
| 35 | out_msg = VM_FAULT_OOM; | ||
| 36 | break; | ||
| 37 | 35 | ||
| 38 | default: | 36 | /* |
| 39 | out_msg = VM_FAULT_SIGBUS; | 37 | * if EXYNOS_BO_CONTIG, fully physically contiguous memory |
| 40 | break; | 38 | * region will be allocated else physically contiguous |
| 41 | } | 39 | * as possible. |
| 40 | */ | ||
| 41 | if (!(obj->flags & EXYNOS_BO_NONCONTIG)) | ||
| 42 | dma_set_attr(DMA_ATTR_FORCE_CONTIGUOUS, &obj->dma_attrs); | ||
| 42 | 43 | ||
| 43 | return out_msg; | 44 | /* |
| 44 | } | 45 | * if EXYNOS_BO_WC or EXYNOS_BO_NONCACHABLE, writecombine mapping |
| 46 | * else cachable mapping. | ||
| 47 | */ | ||
| 48 | if (obj->flags & EXYNOS_BO_WC || !(obj->flags & EXYNOS_BO_CACHABLE)) | ||
| 49 | attr = DMA_ATTR_WRITE_COMBINE; | ||
| 50 | else | ||
| 51 | attr = DMA_ATTR_NON_CONSISTENT; | ||
| 45 | 52 | ||
| 46 | static int check_gem_flags(unsigned int flags) | 53 | dma_set_attr(attr, &obj->dma_attrs); |
| 47 | { | 54 | dma_set_attr(DMA_ATTR_NO_KERNEL_MAPPING, &obj->dma_attrs); |
| 48 | if (flags & ~(EXYNOS_BO_MASK)) { | ||
| 49 | DRM_ERROR("invalid flags.\n"); | ||
| 50 | return -EINVAL; | ||
| 51 | } | ||
| 52 | 55 | ||
| 53 | return 0; | 56 | nr_pages = obj->size >> PAGE_SHIFT; |
| 54 | } | ||
| 55 | 57 | ||
| 56 | static void update_vm_cache_attr(struct exynos_drm_gem_obj *obj, | 58 | if (!is_drm_iommu_supported(dev)) { |
| 57 | struct vm_area_struct *vma) | 59 | dma_addr_t start_addr; |
| 58 | { | 60 | unsigned int i = 0; |
| 59 | DRM_DEBUG_KMS("flags = 0x%x\n", obj->flags); | ||
| 60 | 61 | ||
| 61 | /* non-cachable as default. */ | 62 | obj->pages = drm_calloc_large(nr_pages, sizeof(struct page *)); |
| 62 | if (obj->flags & EXYNOS_BO_CACHABLE) | 63 | if (!obj->pages) { |
| 63 | vma->vm_page_prot = vm_get_page_prot(vma->vm_flags); | 64 | DRM_ERROR("failed to allocate pages.\n"); |
| 64 | else if (obj->flags & EXYNOS_BO_WC) | 65 | return -ENOMEM; |
| 65 | vma->vm_page_prot = | 66 | } |
| 66 | pgprot_writecombine(vm_get_page_prot(vma->vm_flags)); | ||
| 67 | else | ||
| 68 | vma->vm_page_prot = | ||
| 69 | pgprot_noncached(vm_get_page_prot(vma->vm_flags)); | ||
| 70 | } | ||
| 71 | 67 | ||
| 72 | static unsigned long roundup_gem_size(unsigned long size, unsigned int flags) | 68 | obj->cookie = dma_alloc_attrs(dev->dev, |
| 73 | { | 69 | obj->size, |
| 74 | /* TODO */ | 70 | &obj->dma_addr, GFP_KERNEL, |
| 71 | &obj->dma_attrs); | ||
| 72 | if (!obj->cookie) { | ||
| 73 | DRM_ERROR("failed to allocate buffer.\n"); | ||
| 74 | drm_free_large(obj->pages); | ||
| 75 | return -ENOMEM; | ||
| 76 | } | ||
| 77 | |||
| 78 | start_addr = obj->dma_addr; | ||
| 79 | while (i < nr_pages) { | ||
| 80 | obj->pages[i] = phys_to_page(start_addr); | ||
| 81 | start_addr += PAGE_SIZE; | ||
| 82 | i++; | ||
| 83 | } | ||
| 84 | } else { | ||
| 85 | obj->pages = dma_alloc_attrs(dev->dev, obj->size, | ||
| 86 | &obj->dma_addr, GFP_KERNEL, | ||
| 87 | &obj->dma_attrs); | ||
| 88 | if (!obj->pages) { | ||
| 89 | DRM_ERROR("failed to allocate buffer.\n"); | ||
| 90 | return -ENOMEM; | ||
| 91 | } | ||
| 92 | } | ||
| 93 | |||
| 94 | DRM_DEBUG_KMS("dma_addr(0x%lx), size(0x%lx)\n", | ||
| 95 | (unsigned long)obj->dma_addr, | ||
| 96 | obj->size); | ||
| 75 | 97 | ||
| 76 | return roundup(size, PAGE_SIZE); | 98 | return 0; |
| 77 | } | 99 | } |
| 78 | 100 | ||
| 79 | static int exynos_drm_gem_map_buf(struct drm_gem_object *obj, | 101 | static void exynos_drm_free_buf(struct exynos_drm_gem_obj *obj) |
| 80 | struct vm_area_struct *vma, | ||
| 81 | unsigned long f_vaddr, | ||
| 82 | pgoff_t page_offset) | ||
| 83 | { | 102 | { |
| 84 | struct exynos_drm_gem_obj *exynos_gem_obj = to_exynos_gem_obj(obj); | 103 | struct drm_device *dev = obj->base.dev; |
| 85 | struct exynos_drm_gem_buf *buf = exynos_gem_obj->buffer; | ||
| 86 | struct scatterlist *sgl; | ||
| 87 | unsigned long pfn; | ||
| 88 | int i; | ||
| 89 | |||
| 90 | if (!buf->sgt) | ||
| 91 | return -EINTR; | ||
| 92 | 104 | ||
| 93 | if (page_offset >= (buf->size >> PAGE_SHIFT)) { | 105 | if (!obj->dma_addr) { |
| 94 | DRM_ERROR("invalid page offset\n"); | 106 | DRM_DEBUG_KMS("dma_addr is invalid.\n"); |
| 95 | return -EINVAL; | 107 | return; |
| 96 | } | 108 | } |
| 97 | 109 | ||
| 98 | sgl = buf->sgt->sgl; | 110 | DRM_DEBUG_KMS("dma_addr(0x%lx), size(0x%lx)\n", |
| 99 | for_each_sg(buf->sgt->sgl, sgl, buf->sgt->nents, i) { | 111 | (unsigned long)obj->dma_addr, obj->size); |
| 100 | if (page_offset < (sgl->length >> PAGE_SHIFT)) | ||
| 101 | break; | ||
| 102 | page_offset -= (sgl->length >> PAGE_SHIFT); | ||
| 103 | } | ||
| 104 | 112 | ||
| 105 | pfn = __phys_to_pfn(sg_phys(sgl)) + page_offset; | 113 | if (!is_drm_iommu_supported(dev)) { |
| 114 | dma_free_attrs(dev->dev, obj->size, obj->cookie, | ||
| 115 | (dma_addr_t)obj->dma_addr, &obj->dma_attrs); | ||
| 116 | drm_free_large(obj->pages); | ||
| 117 | } else | ||
| 118 | dma_free_attrs(dev->dev, obj->size, obj->pages, | ||
| 119 | (dma_addr_t)obj->dma_addr, &obj->dma_attrs); | ||
| 106 | 120 | ||
| 107 | return vm_insert_mixed(vma, f_vaddr, pfn); | 121 | obj->dma_addr = (dma_addr_t)NULL; |
| 108 | } | 122 | } |
| 109 | 123 | ||
| 110 | static int exynos_drm_gem_handle_create(struct drm_gem_object *obj, | 124 | static int exynos_drm_gem_handle_create(struct drm_gem_object *obj, |
| @@ -131,11 +145,7 @@ static int exynos_drm_gem_handle_create(struct drm_gem_object *obj, | |||
| 131 | 145 | ||
| 132 | void exynos_drm_gem_destroy(struct exynos_drm_gem_obj *exynos_gem_obj) | 146 | void exynos_drm_gem_destroy(struct exynos_drm_gem_obj *exynos_gem_obj) |
| 133 | { | 147 | { |
| 134 | struct drm_gem_object *obj; | 148 | struct drm_gem_object *obj = &exynos_gem_obj->base; |
| 135 | struct exynos_drm_gem_buf *buf; | ||
| 136 | |||
| 137 | obj = &exynos_gem_obj->base; | ||
| 138 | buf = exynos_gem_obj->buffer; | ||
| 139 | 149 | ||
| 140 | DRM_DEBUG_KMS("handle count = %d\n", obj->handle_count); | 150 | DRM_DEBUG_KMS("handle count = %d\n", obj->handle_count); |
| 141 | 151 | ||
| @@ -148,12 +158,9 @@ void exynos_drm_gem_destroy(struct exynos_drm_gem_obj *exynos_gem_obj) | |||
| 148 | if (obj->import_attach) | 158 | if (obj->import_attach) |
| 149 | goto out; | 159 | goto out; |
| 150 | 160 | ||
| 151 | exynos_drm_free_buf(obj->dev, exynos_gem_obj->flags, buf); | 161 | exynos_drm_free_buf(exynos_gem_obj); |
| 152 | 162 | ||
| 153 | out: | 163 | out: |
| 154 | exynos_drm_fini_buf(obj->dev, buf); | ||
| 155 | exynos_gem_obj->buffer = NULL; | ||
| 156 | |||
| 157 | drm_gem_free_mmap_offset(obj); | 164 | drm_gem_free_mmap_offset(obj); |
| 158 | 165 | ||
| 159 | /* release file pointer to gem object. */ | 166 | /* release file pointer to gem object. */ |
| @@ -180,7 +187,7 @@ unsigned long exynos_drm_gem_get_size(struct drm_device *dev, | |||
| 180 | 187 | ||
| 181 | drm_gem_object_unreference_unlocked(obj); | 188 | drm_gem_object_unreference_unlocked(obj); |
| 182 | 189 | ||
| 183 | return exynos_gem_obj->buffer->size; | 190 | return exynos_gem_obj->size; |
| 184 | } | 191 | } |
| 185 | 192 | ||
| 186 | 193 | ||
| @@ -193,7 +200,7 @@ struct exynos_drm_gem_obj *exynos_drm_gem_init(struct drm_device *dev, | |||
| 193 | 200 | ||
| 194 | exynos_gem_obj = kzalloc(sizeof(*exynos_gem_obj), GFP_KERNEL); | 201 | exynos_gem_obj = kzalloc(sizeof(*exynos_gem_obj), GFP_KERNEL); |
| 195 | if (!exynos_gem_obj) | 202 | if (!exynos_gem_obj) |
| 196 | return NULL; | 203 | return ERR_PTR(-ENOMEM); |
| 197 | 204 | ||
| 198 | exynos_gem_obj->size = size; | 205 | exynos_gem_obj->size = size; |
| 199 | obj = &exynos_gem_obj->base; | 206 | obj = &exynos_gem_obj->base; |
| @@ -202,7 +209,7 @@ struct exynos_drm_gem_obj *exynos_drm_gem_init(struct drm_device *dev, | |||
| 202 | if (ret < 0) { | 209 | if (ret < 0) { |
| 203 | DRM_ERROR("failed to initialize gem object\n"); | 210 | DRM_ERROR("failed to initialize gem object\n"); |
| 204 | kfree(exynos_gem_obj); | 211 | kfree(exynos_gem_obj); |
| 205 | return NULL; | 212 | return ERR_PTR(ret); |
| 206 | } | 213 | } |
| 207 | 214 | ||
| 208 | DRM_DEBUG_KMS("created file object = 0x%x\n", (unsigned int)obj->filp); | 215 | DRM_DEBUG_KMS("created file object = 0x%x\n", (unsigned int)obj->filp); |
| @@ -215,47 +222,35 @@ struct exynos_drm_gem_obj *exynos_drm_gem_create(struct drm_device *dev, | |||
| 215 | unsigned long size) | 222 | unsigned long size) |
| 216 | { | 223 | { |
| 217 | struct exynos_drm_gem_obj *exynos_gem_obj; | 224 | struct exynos_drm_gem_obj *exynos_gem_obj; |
| 218 | struct exynos_drm_gem_buf *buf; | ||
| 219 | int ret; | 225 | int ret; |
| 220 | 226 | ||
| 227 | if (flags & ~(EXYNOS_BO_MASK)) { | ||
| 228 | DRM_ERROR("invalid flags.\n"); | ||
| 229 | return ERR_PTR(-EINVAL); | ||
| 230 | } | ||
| 231 | |||
| 221 | if (!size) { | 232 | if (!size) { |
| 222 | DRM_ERROR("invalid size.\n"); | 233 | DRM_ERROR("invalid size.\n"); |
| 223 | return ERR_PTR(-EINVAL); | 234 | return ERR_PTR(-EINVAL); |
| 224 | } | 235 | } |
| 225 | 236 | ||
| 226 | size = roundup_gem_size(size, flags); | 237 | size = roundup(size, PAGE_SIZE); |
| 227 | |||
| 228 | ret = check_gem_flags(flags); | ||
| 229 | if (ret) | ||
| 230 | return ERR_PTR(ret); | ||
| 231 | |||
| 232 | buf = exynos_drm_init_buf(dev, size); | ||
| 233 | if (!buf) | ||
| 234 | return ERR_PTR(-ENOMEM); | ||
| 235 | 238 | ||
| 236 | exynos_gem_obj = exynos_drm_gem_init(dev, size); | 239 | exynos_gem_obj = exynos_drm_gem_init(dev, size); |
| 237 | if (!exynos_gem_obj) { | 240 | if (IS_ERR(exynos_gem_obj)) |
| 238 | ret = -ENOMEM; | 241 | return exynos_gem_obj; |
| 239 | goto err_fini_buf; | ||
| 240 | } | ||
| 241 | |||
| 242 | exynos_gem_obj->buffer = buf; | ||
| 243 | 242 | ||
| 244 | /* set memory type and cache attribute from user side. */ | 243 | /* set memory type and cache attribute from user side. */ |
| 245 | exynos_gem_obj->flags = flags; | 244 | exynos_gem_obj->flags = flags; |
| 246 | 245 | ||
| 247 | ret = exynos_drm_alloc_buf(dev, buf, flags); | 246 | ret = exynos_drm_alloc_buf(exynos_gem_obj); |
| 248 | if (ret < 0) | 247 | if (ret < 0) { |
| 249 | goto err_gem_fini; | 248 | drm_gem_object_release(&exynos_gem_obj->base); |
| 249 | kfree(exynos_gem_obj); | ||
| 250 | return ERR_PTR(ret); | ||
| 251 | } | ||
| 250 | 252 | ||
| 251 | return exynos_gem_obj; | 253 | return exynos_gem_obj; |
| 252 | |||
| 253 | err_gem_fini: | ||
| 254 | drm_gem_object_release(&exynos_gem_obj->base); | ||
| 255 | kfree(exynos_gem_obj); | ||
| 256 | err_fini_buf: | ||
| 257 | exynos_drm_fini_buf(dev, buf); | ||
| 258 | return ERR_PTR(ret); | ||
| 259 | } | 254 | } |
| 260 | 255 | ||
| 261 | int exynos_drm_gem_create_ioctl(struct drm_device *dev, void *data, | 256 | int exynos_drm_gem_create_ioctl(struct drm_device *dev, void *data, |
| @@ -294,7 +289,7 @@ dma_addr_t *exynos_drm_gem_get_dma_addr(struct drm_device *dev, | |||
| 294 | 289 | ||
| 295 | exynos_gem_obj = to_exynos_gem_obj(obj); | 290 | exynos_gem_obj = to_exynos_gem_obj(obj); |
| 296 | 291 | ||
| 297 | return &exynos_gem_obj->buffer->dma_addr; | 292 | return &exynos_gem_obj->dma_addr; |
| 298 | } | 293 | } |
| 299 | 294 | ||
| 300 | void exynos_drm_gem_put_dma_addr(struct drm_device *dev, | 295 | void exynos_drm_gem_put_dma_addr(struct drm_device *dev, |
| @@ -322,7 +317,6 @@ int exynos_drm_gem_mmap_buffer(struct exynos_drm_gem_obj *exynos_gem_obj, | |||
| 322 | struct vm_area_struct *vma) | 317 | struct vm_area_struct *vma) |
| 323 | { | 318 | { |
| 324 | struct drm_device *drm_dev = exynos_gem_obj->base.dev; | 319 | struct drm_device *drm_dev = exynos_gem_obj->base.dev; |
| 325 | struct exynos_drm_gem_buf *buffer; | ||
| 326 | unsigned long vm_size; | 320 | unsigned long vm_size; |
| 327 | int ret; | 321 | int ret; |
| 328 | 322 | ||
| @@ -331,19 +325,13 @@ int exynos_drm_gem_mmap_buffer(struct exynos_drm_gem_obj *exynos_gem_obj, | |||
| 331 | 325 | ||
| 332 | vm_size = vma->vm_end - vma->vm_start; | 326 | vm_size = vma->vm_end - vma->vm_start; |
| 333 | 327 | ||
| 334 | /* | ||
| 335 | * a buffer contains information to physically continuous memory | ||
| 336 | * allocated by user request or at framebuffer creation. | ||
| 337 | */ | ||
| 338 | buffer = exynos_gem_obj->buffer; | ||
| 339 | |||
| 340 | /* check if user-requested size is valid. */ | 328 | /* check if user-requested size is valid. */ |
| 341 | if (vm_size > buffer->size) | 329 | if (vm_size > exynos_gem_obj->size) |
| 342 | return -EINVAL; | 330 | return -EINVAL; |
| 343 | 331 | ||
| 344 | ret = dma_mmap_attrs(drm_dev->dev, vma, buffer->pages, | 332 | ret = dma_mmap_attrs(drm_dev->dev, vma, exynos_gem_obj->pages, |
| 345 | buffer->dma_addr, buffer->size, | 333 | exynos_gem_obj->dma_addr, exynos_gem_obj->size, |
| 346 | &buffer->dma_attrs); | 334 | &exynos_gem_obj->dma_attrs); |
| 347 | if (ret < 0) { | 335 | if (ret < 0) { |
| 348 | DRM_ERROR("failed to mmap.\n"); | 336 | DRM_ERROR("failed to mmap.\n"); |
| 349 | return ret; | 337 | return ret; |
| @@ -503,15 +491,6 @@ void exynos_gem_unmap_sgt_from_dma(struct drm_device *drm_dev, | |||
| 503 | 491 | ||
| 504 | void exynos_drm_gem_free_object(struct drm_gem_object *obj) | 492 | void exynos_drm_gem_free_object(struct drm_gem_object *obj) |
| 505 | { | 493 | { |
| 506 | struct exynos_drm_gem_obj *exynos_gem_obj; | ||
| 507 | struct exynos_drm_gem_buf *buf; | ||
| 508 | |||
| 509 | exynos_gem_obj = to_exynos_gem_obj(obj); | ||
| 510 | buf = exynos_gem_obj->buffer; | ||
| 511 | |||
| 512 | if (obj->import_attach) | ||
| 513 | drm_prime_gem_destroy(obj, buf->sgt); | ||
| 514 | |||
| 515 | exynos_drm_gem_destroy(to_exynos_gem_obj(obj)); | 494 | exynos_drm_gem_destroy(to_exynos_gem_obj(obj)); |
| 516 | } | 495 | } |
| 517 | 496 | ||
| @@ -595,24 +574,34 @@ unlock: | |||
| 595 | int exynos_drm_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf) | 574 | int exynos_drm_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf) |
| 596 | { | 575 | { |
| 597 | struct drm_gem_object *obj = vma->vm_private_data; | 576 | struct drm_gem_object *obj = vma->vm_private_data; |
| 598 | struct drm_device *dev = obj->dev; | 577 | struct exynos_drm_gem_obj *exynos_gem_obj = to_exynos_gem_obj(obj); |
| 599 | unsigned long f_vaddr; | 578 | unsigned long pfn; |
| 600 | pgoff_t page_offset; | 579 | pgoff_t page_offset; |
| 601 | int ret; | 580 | int ret; |
| 602 | 581 | ||
| 603 | page_offset = ((unsigned long)vmf->virtual_address - | 582 | page_offset = ((unsigned long)vmf->virtual_address - |
| 604 | vma->vm_start) >> PAGE_SHIFT; | 583 | vma->vm_start) >> PAGE_SHIFT; |
| 605 | f_vaddr = (unsigned long)vmf->virtual_address; | ||
| 606 | |||
| 607 | mutex_lock(&dev->struct_mutex); | ||
| 608 | 584 | ||
| 609 | ret = exynos_drm_gem_map_buf(obj, vma, f_vaddr, page_offset); | 585 | if (page_offset >= (exynos_gem_obj->size >> PAGE_SHIFT)) { |
| 610 | if (ret < 0) | 586 | DRM_ERROR("invalid page offset\n"); |
| 611 | DRM_ERROR("failed to map a buffer with user.\n"); | 587 | ret = -EINVAL; |
| 588 | goto out; | ||
| 589 | } | ||
| 612 | 590 | ||
| 613 | mutex_unlock(&dev->struct_mutex); | 591 | pfn = page_to_pfn(exynos_gem_obj->pages[page_offset]); |
| 592 | ret = vm_insert_mixed(vma, (unsigned long)vmf->virtual_address, pfn); | ||
| 614 | 593 | ||
| 615 | return convert_to_vm_err_msg(ret); | 594 | out: |
| 595 | switch (ret) { | ||
| 596 | case 0: | ||
| 597 | case -ERESTARTSYS: | ||
| 598 | case -EINTR: | ||
| 599 | return VM_FAULT_NOPAGE; | ||
| 600 | case -ENOMEM: | ||
| 601 | return VM_FAULT_OOM; | ||
| 602 | default: | ||
| 603 | return VM_FAULT_SIGBUS; | ||
| 604 | } | ||
| 616 | } | 605 | } |
| 617 | 606 | ||
| 618 | int exynos_drm_gem_mmap(struct file *filp, struct vm_area_struct *vma) | 607 | int exynos_drm_gem_mmap(struct file *filp, struct vm_area_struct *vma) |
| @@ -631,11 +620,17 @@ int exynos_drm_gem_mmap(struct file *filp, struct vm_area_struct *vma) | |||
| 631 | obj = vma->vm_private_data; | 620 | obj = vma->vm_private_data; |
| 632 | exynos_gem_obj = to_exynos_gem_obj(obj); | 621 | exynos_gem_obj = to_exynos_gem_obj(obj); |
| 633 | 622 | ||
| 634 | ret = check_gem_flags(exynos_gem_obj->flags); | 623 | DRM_DEBUG_KMS("flags = 0x%x\n", exynos_gem_obj->flags); |
| 635 | if (ret) | ||
| 636 | goto err_close_vm; | ||
| 637 | 624 | ||
| 638 | update_vm_cache_attr(exynos_gem_obj, vma); | 625 | /* non-cachable as default. */ |
| 626 | if (exynos_gem_obj->flags & EXYNOS_BO_CACHABLE) | ||
| 627 | vma->vm_page_prot = vm_get_page_prot(vma->vm_flags); | ||
| 628 | else if (exynos_gem_obj->flags & EXYNOS_BO_WC) | ||
| 629 | vma->vm_page_prot = | ||
| 630 | pgprot_writecombine(vm_get_page_prot(vma->vm_flags)); | ||
| 631 | else | ||
| 632 | vma->vm_page_prot = | ||
| 633 | pgprot_noncached(vm_get_page_prot(vma->vm_flags)); | ||
| 639 | 634 | ||
| 640 | ret = exynos_drm_gem_mmap_buffer(exynos_gem_obj, vma); | 635 | ret = exynos_drm_gem_mmap_buffer(exynos_gem_obj, vma); |
| 641 | if (ret) | 636 | if (ret) |
| @@ -649,3 +644,76 @@ err_close_vm: | |||
| 649 | 644 | ||
| 650 | return ret; | 645 | return ret; |
| 651 | } | 646 | } |
| 647 | |||
| 648 | /* low-level interface prime helpers */ | ||
| 649 | struct sg_table *exynos_drm_gem_prime_get_sg_table(struct drm_gem_object *obj) | ||
| 650 | { | ||
| 651 | struct exynos_drm_gem_obj *exynos_gem_obj = to_exynos_gem_obj(obj); | ||
| 652 | int npages; | ||
| 653 | |||
| 654 | npages = exynos_gem_obj->size >> PAGE_SHIFT; | ||
| 655 | |||
| 656 | return drm_prime_pages_to_sg(exynos_gem_obj->pages, npages); | ||
| 657 | } | ||
| 658 | |||
| 659 | struct drm_gem_object * | ||
| 660 | exynos_drm_gem_prime_import_sg_table(struct drm_device *dev, | ||
| 661 | struct dma_buf_attachment *attach, | ||
| 662 | struct sg_table *sgt) | ||
| 663 | { | ||
| 664 | struct exynos_drm_gem_obj *exynos_gem_obj; | ||
| 665 | int npages; | ||
| 666 | int ret; | ||
| 667 | |||
| 668 | exynos_gem_obj = exynos_drm_gem_init(dev, attach->dmabuf->size); | ||
| 669 | if (IS_ERR(exynos_gem_obj)) { | ||
| 670 | ret = PTR_ERR(exynos_gem_obj); | ||
| 671 | goto err; | ||
| 672 | } | ||
| 673 | |||
| 674 | exynos_gem_obj->dma_addr = sg_dma_address(sgt->sgl); | ||
| 675 | |||
| 676 | npages = exynos_gem_obj->size >> PAGE_SHIFT; | ||
| 677 | exynos_gem_obj->pages = drm_malloc_ab(npages, sizeof(struct page *)); | ||
| 678 | if (!exynos_gem_obj->pages) { | ||
| 679 | ret = -ENOMEM; | ||
| 680 | goto err; | ||
| 681 | } | ||
| 682 | |||
| 683 | ret = drm_prime_sg_to_page_addr_arrays(sgt, exynos_gem_obj->pages, NULL, | ||
| 684 | npages); | ||
| 685 | if (ret < 0) | ||
| 686 | goto err_free_large; | ||
| 687 | |||
| 688 | if (sgt->nents == 1) { | ||
| 689 | /* always physically continuous memory if sgt->nents is 1. */ | ||
| 690 | exynos_gem_obj->flags |= EXYNOS_BO_CONTIG; | ||
| 691 | } else { | ||
| 692 | /* | ||
| 693 | * this case could be CONTIG or NONCONTIG type but for now | ||
| 694 | * sets NONCONTIG. | ||
| 695 | * TODO. we have to find a way that exporter can notify | ||
| 696 | * the type of its own buffer to importer. | ||
| 697 | */ | ||
| 698 | exynos_gem_obj->flags |= EXYNOS_BO_NONCONTIG; | ||
| 699 | } | ||
| 700 | |||
| 701 | return &exynos_gem_obj->base; | ||
| 702 | |||
| 703 | err_free_large: | ||
| 704 | drm_free_large(exynos_gem_obj->pages); | ||
| 705 | err: | ||
| 706 | drm_gem_object_release(&exynos_gem_obj->base); | ||
| 707 | kfree(exynos_gem_obj); | ||
| 708 | return ERR_PTR(ret); | ||
| 709 | } | ||
| 710 | |||
| 711 | void *exynos_drm_gem_prime_vmap(struct drm_gem_object *obj) | ||
| 712 | { | ||
| 713 | return NULL; | ||
| 714 | } | ||
| 715 | |||
| 716 | void exynos_drm_gem_prime_vunmap(struct drm_gem_object *obj, void *vaddr) | ||
| 717 | { | ||
| 718 | /* Nothing to do */ | ||
| 719 | } | ||
diff --git a/drivers/gpu/drm/exynos/exynos_drm_gem.h b/drivers/gpu/drm/exynos/exynos_drm_gem.h index 6f42e2248288..cd62f8410d1e 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_gem.h +++ b/drivers/gpu/drm/exynos/exynos_drm_gem.h | |||
| @@ -20,35 +20,6 @@ | |||
| 20 | #define IS_NONCONTIG_BUFFER(f) (f & EXYNOS_BO_NONCONTIG) | 20 | #define IS_NONCONTIG_BUFFER(f) (f & EXYNOS_BO_NONCONTIG) |
| 21 | 21 | ||
| 22 | /* | 22 | /* |
| 23 | * exynos drm gem buffer structure. | ||
| 24 | * | ||
| 25 | * @cookie: cookie returned by dma_alloc_attrs | ||
| 26 | * @kvaddr: kernel virtual address to allocated memory region. | ||
| 27 | * *userptr: user space address. | ||
| 28 | * @dma_addr: bus address(accessed by dma) to allocated memory region. | ||
| 29 | * - this address could be physical address without IOMMU and | ||
| 30 | * device address with IOMMU. | ||
| 31 | * @write: whether pages will be written to by the caller. | ||
| 32 | * @pages: Array of backing pages. | ||
| 33 | * @sgt: sg table to transfer page data. | ||
| 34 | * @size: size of allocated memory region. | ||
| 35 | * @pfnmap: indicate whether memory region from userptr is mmaped with | ||
| 36 | * VM_PFNMAP or not. | ||
| 37 | */ | ||
| 38 | struct exynos_drm_gem_buf { | ||
| 39 | void *cookie; | ||
| 40 | void __iomem *kvaddr; | ||
| 41 | unsigned long userptr; | ||
| 42 | dma_addr_t dma_addr; | ||
| 43 | struct dma_attrs dma_attrs; | ||
| 44 | unsigned int write; | ||
| 45 | struct page **pages; | ||
| 46 | struct sg_table *sgt; | ||
| 47 | unsigned long size; | ||
| 48 | bool pfnmap; | ||
| 49 | }; | ||
| 50 | |||
| 51 | /* | ||
| 52 | * exynos drm buffer structure. | 23 | * exynos drm buffer structure. |
| 53 | * | 24 | * |
| 54 | * @base: a gem object. | 25 | * @base: a gem object. |
| @@ -59,18 +30,28 @@ struct exynos_drm_gem_buf { | |||
| 59 | * by user request or at framebuffer creation. | 30 | * by user request or at framebuffer creation. |
| 60 | * continuous memory region allocated by user request | 31 | * continuous memory region allocated by user request |
| 61 | * or at framebuffer creation. | 32 | * or at framebuffer creation. |
| 33 | * @flags: indicate memory type to allocated buffer and cache attruibute. | ||
| 62 | * @size: size requested from user, in bytes and this size is aligned | 34 | * @size: size requested from user, in bytes and this size is aligned |
| 63 | * in page unit. | 35 | * in page unit. |
| 64 | * @flags: indicate memory type to allocated buffer and cache attruibute. | 36 | * @cookie: cookie returned by dma_alloc_attrs |
| 37 | * @kvaddr: kernel virtual address to allocated memory region. | ||
| 38 | * @dma_addr: bus address(accessed by dma) to allocated memory region. | ||
| 39 | * - this address could be physical address without IOMMU and | ||
| 40 | * device address with IOMMU. | ||
| 41 | * @pages: Array of backing pages. | ||
| 65 | * | 42 | * |
| 66 | * P.S. this object would be transferred to user as kms_bo.handle so | 43 | * P.S. this object would be transferred to user as kms_bo.handle so |
| 67 | * user can access the buffer through kms_bo.handle. | 44 | * user can access the buffer through kms_bo.handle. |
| 68 | */ | 45 | */ |
| 69 | struct exynos_drm_gem_obj { | 46 | struct exynos_drm_gem_obj { |
| 70 | struct drm_gem_object base; | 47 | struct drm_gem_object base; |
| 71 | struct exynos_drm_gem_buf *buffer; | 48 | unsigned int flags; |
| 72 | unsigned long size; | 49 | unsigned long size; |
| 73 | unsigned int flags; | 50 | void *cookie; |
| 51 | void __iomem *kvaddr; | ||
| 52 | dma_addr_t dma_addr; | ||
| 53 | struct dma_attrs dma_attrs; | ||
| 54 | struct page **pages; | ||
| 74 | }; | 55 | }; |
| 75 | 56 | ||
| 76 | struct page **exynos_gem_get_pages(struct drm_gem_object *obj, gfp_t gfpmask); | 57 | struct page **exynos_gem_get_pages(struct drm_gem_object *obj, gfp_t gfpmask); |
| @@ -177,4 +158,13 @@ void exynos_gem_unmap_sgt_from_dma(struct drm_device *drm_dev, | |||
| 177 | struct sg_table *sgt, | 158 | struct sg_table *sgt, |
| 178 | enum dma_data_direction dir); | 159 | enum dma_data_direction dir); |
| 179 | 160 | ||
| 161 | /* low-level interface prime helpers */ | ||
| 162 | struct sg_table *exynos_drm_gem_prime_get_sg_table(struct drm_gem_object *obj); | ||
| 163 | struct drm_gem_object * | ||
| 164 | exynos_drm_gem_prime_import_sg_table(struct drm_device *dev, | ||
| 165 | struct dma_buf_attachment *attach, | ||
| 166 | struct sg_table *sgt); | ||
| 167 | void *exynos_drm_gem_prime_vmap(struct drm_gem_object *obj); | ||
| 168 | void exynos_drm_gem_prime_vunmap(struct drm_gem_object *obj, void *vaddr); | ||
| 169 | |||
| 180 | #endif | 170 | #endif |
diff --git a/drivers/gpu/drm/exynos/exynos_drm_gsc.c b/drivers/gpu/drm/exynos/exynos_drm_gsc.c index f1c6b76c127f..808a0a013780 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_gsc.c +++ b/drivers/gpu/drm/exynos/exynos_drm_gsc.c | |||
| @@ -582,9 +582,17 @@ static int gsc_src_set_transf(struct device *dev, | |||
| 582 | break; | 582 | break; |
| 583 | case EXYNOS_DRM_DEGREE_180: | 583 | case EXYNOS_DRM_DEGREE_180: |
| 584 | cfg |= GSC_IN_ROT_180; | 584 | cfg |= GSC_IN_ROT_180; |
| 585 | if (flip & EXYNOS_DRM_FLIP_VERTICAL) | ||
| 586 | cfg &= ~GSC_IN_ROT_XFLIP; | ||
| 587 | if (flip & EXYNOS_DRM_FLIP_HORIZONTAL) | ||
| 588 | cfg &= ~GSC_IN_ROT_YFLIP; | ||
| 585 | break; | 589 | break; |
| 586 | case EXYNOS_DRM_DEGREE_270: | 590 | case EXYNOS_DRM_DEGREE_270: |
| 587 | cfg |= GSC_IN_ROT_270; | 591 | cfg |= GSC_IN_ROT_270; |
| 592 | if (flip & EXYNOS_DRM_FLIP_VERTICAL) | ||
| 593 | cfg &= ~GSC_IN_ROT_XFLIP; | ||
| 594 | if (flip & EXYNOS_DRM_FLIP_HORIZONTAL) | ||
| 595 | cfg &= ~GSC_IN_ROT_YFLIP; | ||
| 588 | break; | 596 | break; |
| 589 | default: | 597 | default: |
| 590 | dev_err(ippdrv->dev, "inavlid degree value %d.\n", degree); | 598 | dev_err(ippdrv->dev, "inavlid degree value %d.\n", degree); |
| @@ -845,9 +853,17 @@ static int gsc_dst_set_transf(struct device *dev, | |||
| 845 | break; | 853 | break; |
| 846 | case EXYNOS_DRM_DEGREE_180: | 854 | case EXYNOS_DRM_DEGREE_180: |
| 847 | cfg |= GSC_IN_ROT_180; | 855 | cfg |= GSC_IN_ROT_180; |
| 856 | if (flip & EXYNOS_DRM_FLIP_VERTICAL) | ||
| 857 | cfg &= ~GSC_IN_ROT_XFLIP; | ||
| 858 | if (flip & EXYNOS_DRM_FLIP_HORIZONTAL) | ||
| 859 | cfg &= ~GSC_IN_ROT_YFLIP; | ||
| 848 | break; | 860 | break; |
| 849 | case EXYNOS_DRM_DEGREE_270: | 861 | case EXYNOS_DRM_DEGREE_270: |
| 850 | cfg |= GSC_IN_ROT_270; | 862 | cfg |= GSC_IN_ROT_270; |
| 863 | if (flip & EXYNOS_DRM_FLIP_VERTICAL) | ||
| 864 | cfg &= ~GSC_IN_ROT_XFLIP; | ||
| 865 | if (flip & EXYNOS_DRM_FLIP_HORIZONTAL) | ||
| 866 | cfg &= ~GSC_IN_ROT_YFLIP; | ||
| 851 | break; | 867 | break; |
| 852 | default: | 868 | default: |
| 853 | dev_err(ippdrv->dev, "inavlid degree value %d.\n", degree); | 869 | dev_err(ippdrv->dev, "inavlid degree value %d.\n", degree); |
diff --git a/drivers/gpu/drm/exynos/exynos_drm_iommu.c b/drivers/gpu/drm/exynos/exynos_drm_iommu.c index d4ec7465e9cc..055e8ec2ef21 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_iommu.c +++ b/drivers/gpu/drm/exynos/exynos_drm_iommu.c | |||
| @@ -87,10 +87,8 @@ int drm_iommu_attach_device(struct drm_device *drm_dev, | |||
| 87 | struct device *dev = drm_dev->dev; | 87 | struct device *dev = drm_dev->dev; |
| 88 | int ret; | 88 | int ret; |
| 89 | 89 | ||
| 90 | if (!dev->archdata.mapping) { | 90 | if (!dev->archdata.mapping) |
| 91 | DRM_ERROR("iommu_mapping is null.\n"); | 91 | return 0; |
| 92 | return -EFAULT; | ||
| 93 | } | ||
| 94 | 92 | ||
| 95 | subdrv_dev->dma_parms = devm_kzalloc(subdrv_dev, | 93 | subdrv_dev->dma_parms = devm_kzalloc(subdrv_dev, |
| 96 | sizeof(*subdrv_dev->dma_parms), | 94 | sizeof(*subdrv_dev->dma_parms), |
| @@ -144,17 +142,3 @@ void drm_iommu_detach_device(struct drm_device *drm_dev, | |||
| 144 | iommu_detach_device(mapping->domain, subdrv_dev); | 142 | iommu_detach_device(mapping->domain, subdrv_dev); |
| 145 | drm_release_iommu_mapping(drm_dev); | 143 | drm_release_iommu_mapping(drm_dev); |
| 146 | } | 144 | } |
| 147 | |||
| 148 | int drm_iommu_attach_device_if_possible(struct exynos_drm_crtc *exynos_crtc, | ||
| 149 | struct drm_device *drm_dev, struct device *subdrv_dev) | ||
| 150 | { | ||
| 151 | int ret = 0; | ||
| 152 | |||
| 153 | if (is_drm_iommu_supported(drm_dev)) { | ||
| 154 | if (exynos_crtc->ops->clear_channels) | ||
| 155 | exynos_crtc->ops->clear_channels(exynos_crtc); | ||
| 156 | return drm_iommu_attach_device(drm_dev, subdrv_dev); | ||
| 157 | } | ||
| 158 | |||
| 159 | return ret; | ||
| 160 | } | ||
diff --git a/drivers/gpu/drm/exynos/exynos_drm_iommu.h b/drivers/gpu/drm/exynos/exynos_drm_iommu.h index 8341c7a475b4..dc1b5441f491 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_iommu.h +++ b/drivers/gpu/drm/exynos/exynos_drm_iommu.h | |||
| @@ -29,19 +29,11 @@ void drm_iommu_detach_device(struct drm_device *dev_dev, | |||
| 29 | 29 | ||
| 30 | static inline bool is_drm_iommu_supported(struct drm_device *drm_dev) | 30 | static inline bool is_drm_iommu_supported(struct drm_device *drm_dev) |
| 31 | { | 31 | { |
| 32 | #ifdef CONFIG_ARM_DMA_USE_IOMMU | ||
| 33 | struct device *dev = drm_dev->dev; | 32 | struct device *dev = drm_dev->dev; |
| 34 | 33 | ||
| 35 | return dev->archdata.mapping ? true : false; | 34 | return dev->archdata.mapping ? true : false; |
| 36 | #else | ||
| 37 | return false; | ||
| 38 | #endif | ||
| 39 | } | 35 | } |
| 40 | 36 | ||
| 41 | int drm_iommu_attach_device_if_possible( | ||
| 42 | struct exynos_drm_crtc *exynos_crtc, struct drm_device *drm_dev, | ||
| 43 | struct device *subdrv_dev); | ||
| 44 | |||
| 45 | #else | 37 | #else |
| 46 | 38 | ||
| 47 | static inline int drm_create_iommu_mapping(struct drm_device *drm_dev) | 39 | static inline int drm_create_iommu_mapping(struct drm_device *drm_dev) |
| @@ -69,12 +61,5 @@ static inline bool is_drm_iommu_supported(struct drm_device *drm_dev) | |||
| 69 | return false; | 61 | return false; |
| 70 | } | 62 | } |
| 71 | 63 | ||
| 72 | static inline int drm_iommu_attach_device_if_possible( | ||
| 73 | struct exynos_drm_crtc *exynos_crtc, struct drm_device *drm_dev, | ||
| 74 | struct device *subdrv_dev) | ||
| 75 | { | ||
| 76 | return 0; | ||
| 77 | } | ||
| 78 | |||
| 79 | #endif | 64 | #endif |
| 80 | #endif | 65 | #endif |
diff --git a/drivers/gpu/drm/exynos/exynos_drm_ipp.c b/drivers/gpu/drm/exynos/exynos_drm_ipp.c index 67e5451e066f..67d24236e745 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_ipp.c +++ b/drivers/gpu/drm/exynos/exynos_drm_ipp.c | |||
| @@ -1622,12 +1622,10 @@ static int ipp_subdrv_probe(struct drm_device *drm_dev, struct device *dev) | |||
| 1622 | INIT_LIST_HEAD(&ippdrv->cmd_list); | 1622 | INIT_LIST_HEAD(&ippdrv->cmd_list); |
| 1623 | mutex_init(&ippdrv->cmd_lock); | 1623 | mutex_init(&ippdrv->cmd_lock); |
| 1624 | 1624 | ||
| 1625 | if (is_drm_iommu_supported(drm_dev)) { | 1625 | ret = drm_iommu_attach_device(drm_dev, ippdrv->dev); |
| 1626 | ret = drm_iommu_attach_device(drm_dev, ippdrv->dev); | 1626 | if (ret) { |
| 1627 | if (ret) { | 1627 | DRM_ERROR("failed to activate iommu\n"); |
| 1628 | DRM_ERROR("failed to activate iommu\n"); | 1628 | goto err; |
| 1629 | goto err; | ||
| 1630 | } | ||
| 1631 | } | 1629 | } |
| 1632 | } | 1630 | } |
| 1633 | 1631 | ||
| @@ -1637,8 +1635,7 @@ err: | |||
| 1637 | /* get ipp driver entry */ | 1635 | /* get ipp driver entry */ |
| 1638 | list_for_each_entry_continue_reverse(ippdrv, &exynos_drm_ippdrv_list, | 1636 | list_for_each_entry_continue_reverse(ippdrv, &exynos_drm_ippdrv_list, |
| 1639 | drv_list) { | 1637 | drv_list) { |
| 1640 | if (is_drm_iommu_supported(drm_dev)) | 1638 | drm_iommu_detach_device(drm_dev, ippdrv->dev); |
| 1641 | drm_iommu_detach_device(drm_dev, ippdrv->dev); | ||
| 1642 | 1639 | ||
| 1643 | ipp_remove_id(&ctx->ipp_idr, &ctx->ipp_lock, | 1640 | ipp_remove_id(&ctx->ipp_idr, &ctx->ipp_lock, |
| 1644 | ippdrv->prop_list.ipp_id); | 1641 | ippdrv->prop_list.ipp_id); |
| @@ -1654,8 +1651,7 @@ static void ipp_subdrv_remove(struct drm_device *drm_dev, struct device *dev) | |||
| 1654 | 1651 | ||
| 1655 | /* get ipp driver entry */ | 1652 | /* get ipp driver entry */ |
| 1656 | list_for_each_entry_safe(ippdrv, t, &exynos_drm_ippdrv_list, drv_list) { | 1653 | list_for_each_entry_safe(ippdrv, t, &exynos_drm_ippdrv_list, drv_list) { |
| 1657 | if (is_drm_iommu_supported(drm_dev)) | 1654 | drm_iommu_detach_device(drm_dev, ippdrv->dev); |
| 1658 | drm_iommu_detach_device(drm_dev, ippdrv->dev); | ||
| 1659 | 1655 | ||
| 1660 | ipp_remove_id(&ctx->ipp_idr, &ctx->ipp_lock, | 1656 | ipp_remove_id(&ctx->ipp_idr, &ctx->ipp_lock, |
| 1661 | ippdrv->prop_list.ipp_id); | 1657 | ippdrv->prop_list.ipp_id); |
diff --git a/drivers/gpu/drm/exynos/exynos_drm_plane.c b/drivers/gpu/drm/exynos/exynos_drm_plane.c index a729980d3c2f..d9a68fd83120 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_plane.c +++ b/drivers/gpu/drm/exynos/exynos_drm_plane.c | |||
| @@ -97,29 +97,18 @@ static void exynos_plane_mode_set(struct drm_plane *plane, | |||
| 97 | /* set drm framebuffer data. */ | 97 | /* set drm framebuffer data. */ |
| 98 | exynos_plane->src_x = src_x; | 98 | exynos_plane->src_x = src_x; |
| 99 | exynos_plane->src_y = src_y; | 99 | exynos_plane->src_y = src_y; |
| 100 | exynos_plane->src_width = (actual_w * exynos_plane->h_ratio) >> 16; | 100 | exynos_plane->src_w = (actual_w * exynos_plane->h_ratio) >> 16; |
| 101 | exynos_plane->src_height = (actual_h * exynos_plane->v_ratio) >> 16; | 101 | exynos_plane->src_h = (actual_h * exynos_plane->v_ratio) >> 16; |
| 102 | exynos_plane->fb_width = fb->width; | ||
| 103 | exynos_plane->fb_height = fb->height; | ||
| 104 | exynos_plane->bpp = fb->bits_per_pixel; | ||
| 105 | exynos_plane->pitch = fb->pitches[0]; | ||
| 106 | exynos_plane->pixel_format = fb->pixel_format; | ||
| 107 | 102 | ||
| 108 | /* set plane range to be displayed. */ | 103 | /* set plane range to be displayed. */ |
| 109 | exynos_plane->crtc_x = crtc_x; | 104 | exynos_plane->crtc_x = crtc_x; |
| 110 | exynos_plane->crtc_y = crtc_y; | 105 | exynos_plane->crtc_y = crtc_y; |
| 111 | exynos_plane->crtc_width = actual_w; | 106 | exynos_plane->crtc_w = actual_w; |
| 112 | exynos_plane->crtc_height = actual_h; | 107 | exynos_plane->crtc_h = actual_h; |
| 113 | |||
| 114 | /* set drm mode data. */ | ||
| 115 | exynos_plane->mode_width = mode->hdisplay; | ||
| 116 | exynos_plane->mode_height = mode->vdisplay; | ||
| 117 | exynos_plane->refresh = mode->vrefresh; | ||
| 118 | exynos_plane->scan_flag = mode->flags; | ||
| 119 | 108 | ||
| 120 | DRM_DEBUG_KMS("plane : offset_x/y(%d,%d), width/height(%d,%d)", | 109 | DRM_DEBUG_KMS("plane : offset_x/y(%d,%d), width/height(%d,%d)", |
| 121 | exynos_plane->crtc_x, exynos_plane->crtc_y, | 110 | exynos_plane->crtc_x, exynos_plane->crtc_y, |
| 122 | exynos_plane->crtc_width, exynos_plane->crtc_height); | 111 | exynos_plane->crtc_w, exynos_plane->crtc_h); |
| 123 | 112 | ||
| 124 | plane->crtc = crtc; | 113 | plane->crtc = crtc; |
| 125 | } | 114 | } |
| @@ -145,15 +134,15 @@ static int exynos_plane_atomic_check(struct drm_plane *plane, | |||
| 145 | 134 | ||
| 146 | nr = exynos_drm_fb_get_buf_cnt(state->fb); | 135 | nr = exynos_drm_fb_get_buf_cnt(state->fb); |
| 147 | for (i = 0; i < nr; i++) { | 136 | for (i = 0; i < nr; i++) { |
| 148 | struct exynos_drm_gem_buf *buffer = | 137 | struct exynos_drm_gem_obj *obj = |
| 149 | exynos_drm_fb_buffer(state->fb, i); | 138 | exynos_drm_fb_gem_obj(state->fb, i); |
| 150 | 139 | ||
| 151 | if (!buffer) { | 140 | if (!obj) { |
| 152 | DRM_DEBUG_KMS("buffer is null\n"); | 141 | DRM_DEBUG_KMS("gem object is null\n"); |
| 153 | return -EFAULT; | 142 | return -EFAULT; |
| 154 | } | 143 | } |
| 155 | 144 | ||
| 156 | exynos_plane->dma_addr[i] = buffer->dma_addr + | 145 | exynos_plane->dma_addr[i] = obj->dma_addr + |
| 157 | state->fb->offsets[i]; | 146 | state->fb->offsets[i]; |
| 158 | 147 | ||
| 159 | DRM_DEBUG_KMS("buffer: %d, dma_addr = 0x%lx\n", | 148 | DRM_DEBUG_KMS("buffer: %d, dma_addr = 0x%lx\n", |
| @@ -179,8 +168,8 @@ static void exynos_plane_atomic_update(struct drm_plane *plane, | |||
| 179 | state->src_x >> 16, state->src_y >> 16, | 168 | state->src_x >> 16, state->src_y >> 16, |
| 180 | state->src_w >> 16, state->src_h >> 16); | 169 | state->src_w >> 16, state->src_h >> 16); |
| 181 | 170 | ||
| 182 | if (exynos_crtc->ops->win_commit) | 171 | if (exynos_crtc->ops->update_plane) |
| 183 | exynos_crtc->ops->win_commit(exynos_crtc, exynos_plane->zpos); | 172 | exynos_crtc->ops->update_plane(exynos_crtc, exynos_plane); |
| 184 | } | 173 | } |
| 185 | 174 | ||
| 186 | static void exynos_plane_atomic_disable(struct drm_plane *plane, | 175 | static void exynos_plane_atomic_disable(struct drm_plane *plane, |
| @@ -192,9 +181,9 @@ static void exynos_plane_atomic_disable(struct drm_plane *plane, | |||
| 192 | if (!old_state->crtc) | 181 | if (!old_state->crtc) |
| 193 | return; | 182 | return; |
| 194 | 183 | ||
| 195 | if (exynos_crtc->ops->win_disable) | 184 | if (exynos_crtc->ops->disable_plane) |
| 196 | exynos_crtc->ops->win_disable(exynos_crtc, | 185 | exynos_crtc->ops->disable_plane(exynos_crtc, |
| 197 | exynos_plane->zpos); | 186 | exynos_plane); |
| 198 | } | 187 | } |
| 199 | 188 | ||
| 200 | static const struct drm_plane_helper_funcs plane_helper_funcs = { | 189 | static const struct drm_plane_helper_funcs plane_helper_funcs = { |
diff --git a/drivers/gpu/drm/exynos/exynos_drm_vidi.c b/drivers/gpu/drm/exynos/exynos_drm_vidi.c index 3413393d8a16..581af35861a6 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_vidi.c +++ b/drivers/gpu/drm/exynos/exynos_drm_vidi.c | |||
| @@ -25,7 +25,6 @@ | |||
| 25 | #include "exynos_drm_drv.h" | 25 | #include "exynos_drm_drv.h" |
| 26 | #include "exynos_drm_crtc.h" | 26 | #include "exynos_drm_crtc.h" |
| 27 | #include "exynos_drm_plane.h" | 27 | #include "exynos_drm_plane.h" |
| 28 | #include "exynos_drm_encoder.h" | ||
| 29 | #include "exynos_drm_vidi.h" | 28 | #include "exynos_drm_vidi.h" |
| 30 | 29 | ||
| 31 | /* vidi has totally three virtual windows. */ | 30 | /* vidi has totally three virtual windows. */ |
| @@ -35,11 +34,10 @@ | |||
| 35 | connector) | 34 | connector) |
| 36 | 35 | ||
| 37 | struct vidi_context { | 36 | struct vidi_context { |
| 38 | struct exynos_drm_display display; | 37 | struct drm_encoder encoder; |
| 39 | struct platform_device *pdev; | 38 | struct platform_device *pdev; |
| 40 | struct drm_device *drm_dev; | 39 | struct drm_device *drm_dev; |
| 41 | struct exynos_drm_crtc *crtc; | 40 | struct exynos_drm_crtc *crtc; |
| 42 | struct drm_encoder *encoder; | ||
| 43 | struct drm_connector connector; | 41 | struct drm_connector connector; |
| 44 | struct exynos_drm_plane planes[WINDOWS_NR]; | 42 | struct exynos_drm_plane planes[WINDOWS_NR]; |
| 45 | struct edid *raw_edid; | 43 | struct edid *raw_edid; |
| @@ -55,9 +53,9 @@ struct vidi_context { | |||
| 55 | int pipe; | 53 | int pipe; |
| 56 | }; | 54 | }; |
| 57 | 55 | ||
| 58 | static inline struct vidi_context *display_to_vidi(struct exynos_drm_display *d) | 56 | static inline struct vidi_context *encoder_to_vidi(struct drm_encoder *e) |
| 59 | { | 57 | { |
| 60 | return container_of(d, struct vidi_context, display); | 58 | return container_of(e, struct vidi_context, encoder); |
| 61 | } | 59 | } |
| 62 | 60 | ||
| 63 | static const char fake_edid_info[] = { | 61 | static const char fake_edid_info[] = { |
| @@ -100,7 +98,7 @@ static int vidi_enable_vblank(struct exynos_drm_crtc *crtc) | |||
| 100 | /* | 98 | /* |
| 101 | * in case of page flip request, vidi_finish_pageflip function | 99 | * in case of page flip request, vidi_finish_pageflip function |
| 102 | * will not be called because direct_vblank is true and then | 100 | * will not be called because direct_vblank is true and then |
| 103 | * that function will be called by crtc_ops->win_commit callback | 101 | * that function will be called by crtc_ops->update_plane callback |
| 104 | */ | 102 | */ |
| 105 | schedule_work(&ctx->work); | 103 | schedule_work(&ctx->work); |
| 106 | 104 | ||
| @@ -118,19 +116,14 @@ static void vidi_disable_vblank(struct exynos_drm_crtc *crtc) | |||
| 118 | ctx->vblank_on = false; | 116 | ctx->vblank_on = false; |
| 119 | } | 117 | } |
| 120 | 118 | ||
| 121 | static void vidi_win_commit(struct exynos_drm_crtc *crtc, unsigned int win) | 119 | static void vidi_update_plane(struct exynos_drm_crtc *crtc, |
| 120 | struct exynos_drm_plane *plane) | ||
| 122 | { | 121 | { |
| 123 | struct vidi_context *ctx = crtc->ctx; | 122 | struct vidi_context *ctx = crtc->ctx; |
| 124 | struct exynos_drm_plane *plane; | ||
| 125 | 123 | ||
| 126 | if (ctx->suspended) | 124 | if (ctx->suspended) |
| 127 | return; | 125 | return; |
| 128 | 126 | ||
| 129 | if (win < 0 || win >= WINDOWS_NR) | ||
| 130 | return; | ||
| 131 | |||
| 132 | plane = &ctx->planes[win]; | ||
| 133 | |||
| 134 | DRM_DEBUG_KMS("dma_addr = %pad\n", plane->dma_addr); | 127 | DRM_DEBUG_KMS("dma_addr = %pad\n", plane->dma_addr); |
| 135 | 128 | ||
| 136 | if (ctx->vblank_on) | 129 | if (ctx->vblank_on) |
| @@ -179,7 +172,7 @@ static const struct exynos_drm_crtc_ops vidi_crtc_ops = { | |||
| 179 | .disable = vidi_disable, | 172 | .disable = vidi_disable, |
| 180 | .enable_vblank = vidi_enable_vblank, | 173 | .enable_vblank = vidi_enable_vblank, |
| 181 | .disable_vblank = vidi_disable_vblank, | 174 | .disable_vblank = vidi_disable_vblank, |
| 182 | .win_commit = vidi_win_commit, | 175 | .update_plane = vidi_update_plane, |
| 183 | }; | 176 | }; |
| 184 | 177 | ||
| 185 | static void vidi_fake_vblank_handler(struct work_struct *work) | 178 | static void vidi_fake_vblank_handler(struct work_struct *work) |
| @@ -196,7 +189,7 @@ static void vidi_fake_vblank_handler(struct work_struct *work) | |||
| 196 | mutex_lock(&ctx->lock); | 189 | mutex_lock(&ctx->lock); |
| 197 | 190 | ||
| 198 | if (ctx->direct_vblank) { | 191 | if (ctx->direct_vblank) { |
| 199 | drm_handle_vblank(ctx->drm_dev, ctx->pipe); | 192 | drm_crtc_handle_vblank(&ctx->crtc->base); |
| 200 | ctx->direct_vblank = false; | 193 | ctx->direct_vblank = false; |
| 201 | mutex_unlock(&ctx->lock); | 194 | mutex_unlock(&ctx->lock); |
| 202 | return; | 195 | return; |
| @@ -204,7 +197,7 @@ static void vidi_fake_vblank_handler(struct work_struct *work) | |||
| 204 | 197 | ||
| 205 | mutex_unlock(&ctx->lock); | 198 | mutex_unlock(&ctx->lock); |
| 206 | 199 | ||
| 207 | exynos_drm_crtc_finish_pageflip(ctx->drm_dev, ctx->pipe); | 200 | exynos_drm_crtc_finish_pageflip(ctx->crtc); |
| 208 | } | 201 | } |
| 209 | 202 | ||
| 210 | static int vidi_show_connection(struct device *dev, | 203 | static int vidi_show_connection(struct device *dev, |
| @@ -259,9 +252,7 @@ static DEVICE_ATTR(connection, 0644, vidi_show_connection, | |||
| 259 | int vidi_connection_ioctl(struct drm_device *drm_dev, void *data, | 252 | int vidi_connection_ioctl(struct drm_device *drm_dev, void *data, |
| 260 | struct drm_file *file_priv) | 253 | struct drm_file *file_priv) |
| 261 | { | 254 | { |
| 262 | struct vidi_context *ctx = NULL; | 255 | struct vidi_context *ctx = dev_get_drvdata(drm_dev->dev); |
| 263 | struct drm_encoder *encoder; | ||
| 264 | struct exynos_drm_display *display; | ||
| 265 | struct drm_exynos_vidi_connection *vidi = data; | 256 | struct drm_exynos_vidi_connection *vidi = data; |
| 266 | 257 | ||
| 267 | if (!vidi) { | 258 | if (!vidi) { |
| @@ -274,21 +265,6 @@ int vidi_connection_ioctl(struct drm_device *drm_dev, void *data, | |||
| 274 | return -EINVAL; | 265 | return -EINVAL; |
| 275 | } | 266 | } |
| 276 | 267 | ||
| 277 | list_for_each_entry(encoder, &drm_dev->mode_config.encoder_list, | ||
| 278 | head) { | ||
| 279 | display = exynos_drm_get_display(encoder); | ||
| 280 | |||
| 281 | if (display->type == EXYNOS_DISPLAY_TYPE_VIDI) { | ||
| 282 | ctx = display_to_vidi(display); | ||
| 283 | break; | ||
| 284 | } | ||
| 285 | } | ||
| 286 | |||
| 287 | if (!ctx) { | ||
| 288 | DRM_DEBUG_KMS("not found virtual device type encoder.\n"); | ||
| 289 | return -EINVAL; | ||
| 290 | } | ||
| 291 | |||
| 292 | if (ctx->connected == vidi->connection) { | 268 | if (ctx->connected == vidi->connection) { |
| 293 | DRM_DEBUG_KMS("same connection request.\n"); | 269 | DRM_DEBUG_KMS("same connection request.\n"); |
| 294 | return -EINVAL; | 270 | return -EINVAL; |
| @@ -381,7 +357,7 @@ static struct drm_encoder *vidi_best_encoder(struct drm_connector *connector) | |||
| 381 | { | 357 | { |
| 382 | struct vidi_context *ctx = ctx_from_connector(connector); | 358 | struct vidi_context *ctx = ctx_from_connector(connector); |
| 383 | 359 | ||
| 384 | return ctx->encoder; | 360 | return &ctx->encoder; |
| 385 | } | 361 | } |
| 386 | 362 | ||
| 387 | static struct drm_connector_helper_funcs vidi_connector_helper_funcs = { | 363 | static struct drm_connector_helper_funcs vidi_connector_helper_funcs = { |
| @@ -389,14 +365,12 @@ static struct drm_connector_helper_funcs vidi_connector_helper_funcs = { | |||
| 389 | .best_encoder = vidi_best_encoder, | 365 | .best_encoder = vidi_best_encoder, |
| 390 | }; | 366 | }; |
| 391 | 367 | ||
| 392 | static int vidi_create_connector(struct exynos_drm_display *display, | 368 | static int vidi_create_connector(struct drm_encoder *encoder) |
| 393 | struct drm_encoder *encoder) | ||
| 394 | { | 369 | { |
| 395 | struct vidi_context *ctx = display_to_vidi(display); | 370 | struct vidi_context *ctx = encoder_to_vidi(encoder); |
| 396 | struct drm_connector *connector = &ctx->connector; | 371 | struct drm_connector *connector = &ctx->connector; |
| 397 | int ret; | 372 | int ret; |
| 398 | 373 | ||
| 399 | ctx->encoder = encoder; | ||
| 400 | connector->polled = DRM_CONNECTOR_POLL_HPD; | 374 | connector->polled = DRM_CONNECTOR_POLL_HPD; |
| 401 | 375 | ||
| 402 | ret = drm_connector_init(ctx->drm_dev, connector, | 376 | ret = drm_connector_init(ctx->drm_dev, connector, |
| @@ -413,19 +387,47 @@ static int vidi_create_connector(struct exynos_drm_display *display, | |||
| 413 | return 0; | 387 | return 0; |
| 414 | } | 388 | } |
| 415 | 389 | ||
| 390 | static bool exynos_vidi_mode_fixup(struct drm_encoder *encoder, | ||
| 391 | const struct drm_display_mode *mode, | ||
| 392 | struct drm_display_mode *adjusted_mode) | ||
| 393 | { | ||
| 394 | return true; | ||
| 395 | } | ||
| 396 | |||
| 397 | static void exynos_vidi_mode_set(struct drm_encoder *encoder, | ||
| 398 | struct drm_display_mode *mode, | ||
| 399 | struct drm_display_mode *adjusted_mode) | ||
| 400 | { | ||
| 401 | } | ||
| 416 | 402 | ||
| 417 | static struct exynos_drm_display_ops vidi_display_ops = { | 403 | static void exynos_vidi_enable(struct drm_encoder *encoder) |
| 418 | .create_connector = vidi_create_connector, | 404 | { |
| 405 | } | ||
| 406 | |||
| 407 | static void exynos_vidi_disable(struct drm_encoder *encoder) | ||
| 408 | { | ||
| 409 | } | ||
| 410 | |||
| 411 | static struct drm_encoder_helper_funcs exynos_vidi_encoder_helper_funcs = { | ||
| 412 | .mode_fixup = exynos_vidi_mode_fixup, | ||
| 413 | .mode_set = exynos_vidi_mode_set, | ||
| 414 | .enable = exynos_vidi_enable, | ||
| 415 | .disable = exynos_vidi_disable, | ||
| 416 | }; | ||
| 417 | |||
| 418 | static struct drm_encoder_funcs exynos_vidi_encoder_funcs = { | ||
| 419 | .destroy = drm_encoder_cleanup, | ||
| 419 | }; | 420 | }; |
| 420 | 421 | ||
| 421 | static int vidi_bind(struct device *dev, struct device *master, void *data) | 422 | static int vidi_bind(struct device *dev, struct device *master, void *data) |
| 422 | { | 423 | { |
| 423 | struct vidi_context *ctx = dev_get_drvdata(dev); | 424 | struct vidi_context *ctx = dev_get_drvdata(dev); |
| 424 | struct drm_device *drm_dev = data; | 425 | struct drm_device *drm_dev = data; |
| 426 | struct drm_encoder *encoder = &ctx->encoder; | ||
| 425 | struct exynos_drm_plane *exynos_plane; | 427 | struct exynos_drm_plane *exynos_plane; |
| 426 | enum drm_plane_type type; | 428 | enum drm_plane_type type; |
| 427 | unsigned int zpos; | 429 | unsigned int zpos; |
| 428 | int ret; | 430 | int pipe, ret; |
| 429 | 431 | ||
| 430 | vidi_ctx_initialize(ctx, drm_dev); | 432 | vidi_ctx_initialize(ctx, drm_dev); |
| 431 | 433 | ||
| @@ -447,9 +449,24 @@ static int vidi_bind(struct device *dev, struct device *master, void *data) | |||
| 447 | return PTR_ERR(ctx->crtc); | 449 | return PTR_ERR(ctx->crtc); |
| 448 | } | 450 | } |
| 449 | 451 | ||
| 450 | ret = exynos_drm_create_enc_conn(drm_dev, &ctx->display); | 452 | pipe = exynos_drm_crtc_get_pipe_from_type(drm_dev, |
| 453 | EXYNOS_DISPLAY_TYPE_VIDI); | ||
| 454 | if (pipe < 0) | ||
| 455 | return pipe; | ||
| 456 | |||
| 457 | encoder->possible_crtcs = 1 << pipe; | ||
| 458 | |||
| 459 | DRM_DEBUG_KMS("possible_crtcs = 0x%x\n", encoder->possible_crtcs); | ||
| 460 | |||
| 461 | drm_encoder_init(drm_dev, encoder, &exynos_vidi_encoder_funcs, | ||
| 462 | DRM_MODE_ENCODER_TMDS); | ||
| 463 | |||
| 464 | drm_encoder_helper_add(encoder, &exynos_vidi_encoder_helper_funcs); | ||
| 465 | |||
| 466 | ret = vidi_create_connector(encoder); | ||
| 451 | if (ret) { | 467 | if (ret) { |
| 452 | ctx->crtc->base.funcs->destroy(&ctx->crtc->base); | 468 | DRM_ERROR("failed to create connector ret = %d\n", ret); |
| 469 | drm_encoder_cleanup(encoder); | ||
| 453 | return ret; | 470 | return ret; |
| 454 | } | 471 | } |
| 455 | 472 | ||
| @@ -475,8 +492,6 @@ static int vidi_probe(struct platform_device *pdev) | |||
| 475 | if (!ctx) | 492 | if (!ctx) |
| 476 | return -ENOMEM; | 493 | return -ENOMEM; |
| 477 | 494 | ||
| 478 | ctx->display.type = EXYNOS_DISPLAY_TYPE_VIDI; | ||
| 479 | ctx->display.ops = &vidi_display_ops; | ||
| 480 | ctx->default_win = 0; | 495 | ctx->default_win = 0; |
| 481 | ctx->pdev = pdev; | 496 | ctx->pdev = pdev; |
| 482 | 497 | ||
diff --git a/drivers/gpu/drm/exynos/exynos_hdmi.c b/drivers/gpu/drm/exynos/exynos_hdmi.c index 4a00990e4ae4..932f7fa240f8 100644 --- a/drivers/gpu/drm/exynos/exynos_hdmi.c +++ b/drivers/gpu/drm/exynos/exynos_hdmi.c | |||
| @@ -22,7 +22,6 @@ | |||
| 22 | #include "regs-hdmi.h" | 22 | #include "regs-hdmi.h" |
| 23 | 23 | ||
| 24 | #include <linux/kernel.h> | 24 | #include <linux/kernel.h> |
| 25 | #include <linux/spinlock.h> | ||
| 26 | #include <linux/wait.h> | 25 | #include <linux/wait.h> |
| 27 | #include <linux/i2c.h> | 26 | #include <linux/i2c.h> |
| 28 | #include <linux/platform_device.h> | 27 | #include <linux/platform_device.h> |
| @@ -33,8 +32,8 @@ | |||
| 33 | #include <linux/clk.h> | 32 | #include <linux/clk.h> |
| 34 | #include <linux/regulator/consumer.h> | 33 | #include <linux/regulator/consumer.h> |
| 35 | #include <linux/io.h> | 34 | #include <linux/io.h> |
| 36 | #include <linux/of.h> | ||
| 37 | #include <linux/of_address.h> | 35 | #include <linux/of_address.h> |
| 36 | #include <linux/of_device.h> | ||
| 38 | #include <linux/of_gpio.h> | 37 | #include <linux/of_gpio.h> |
| 39 | #include <linux/hdmi.h> | 38 | #include <linux/hdmi.h> |
| 40 | #include <linux/component.h> | 39 | #include <linux/component.h> |
| @@ -48,7 +47,6 @@ | |||
| 48 | #include "exynos_mixer.h" | 47 | #include "exynos_mixer.h" |
| 49 | 48 | ||
| 50 | #include <linux/gpio.h> | 49 | #include <linux/gpio.h> |
| 51 | #include <media/s5p_hdmi.h> | ||
| 52 | 50 | ||
| 53 | #define ctx_from_connector(c) container_of(c, struct hdmi_context, connector) | 51 | #define ctx_from_connector(c) container_of(c, struct hdmi_context, connector) |
| 54 | 52 | ||
| @@ -88,109 +86,14 @@ struct hdmi_resources { | |||
| 88 | int regul_count; | 86 | int regul_count; |
| 89 | }; | 87 | }; |
| 90 | 88 | ||
| 91 | struct hdmi_tg_regs { | ||
| 92 | u8 cmd[1]; | ||
| 93 | u8 h_fsz[2]; | ||
| 94 | u8 hact_st[2]; | ||
| 95 | u8 hact_sz[2]; | ||
| 96 | u8 v_fsz[2]; | ||
| 97 | u8 vsync[2]; | ||
| 98 | u8 vsync2[2]; | ||
| 99 | u8 vact_st[2]; | ||
| 100 | u8 vact_sz[2]; | ||
| 101 | u8 field_chg[2]; | ||
| 102 | u8 vact_st2[2]; | ||
| 103 | u8 vact_st3[2]; | ||
| 104 | u8 vact_st4[2]; | ||
| 105 | u8 vsync_top_hdmi[2]; | ||
| 106 | u8 vsync_bot_hdmi[2]; | ||
| 107 | u8 field_top_hdmi[2]; | ||
| 108 | u8 field_bot_hdmi[2]; | ||
| 109 | u8 tg_3d[1]; | ||
| 110 | }; | ||
| 111 | |||
| 112 | struct hdmi_v13_core_regs { | ||
| 113 | u8 h_blank[2]; | ||
| 114 | u8 v_blank[3]; | ||
| 115 | u8 h_v_line[3]; | ||
| 116 | u8 vsync_pol[1]; | ||
| 117 | u8 int_pro_mode[1]; | ||
| 118 | u8 v_blank_f[3]; | ||
| 119 | u8 h_sync_gen[3]; | ||
| 120 | u8 v_sync_gen1[3]; | ||
| 121 | u8 v_sync_gen2[3]; | ||
| 122 | u8 v_sync_gen3[3]; | ||
| 123 | }; | ||
| 124 | |||
| 125 | struct hdmi_v14_core_regs { | ||
| 126 | u8 h_blank[2]; | ||
| 127 | u8 v2_blank[2]; | ||
| 128 | u8 v1_blank[2]; | ||
| 129 | u8 v_line[2]; | ||
| 130 | u8 h_line[2]; | ||
| 131 | u8 hsync_pol[1]; | ||
| 132 | u8 vsync_pol[1]; | ||
| 133 | u8 int_pro_mode[1]; | ||
| 134 | u8 v_blank_f0[2]; | ||
| 135 | u8 v_blank_f1[2]; | ||
| 136 | u8 h_sync_start[2]; | ||
| 137 | u8 h_sync_end[2]; | ||
| 138 | u8 v_sync_line_bef_2[2]; | ||
| 139 | u8 v_sync_line_bef_1[2]; | ||
| 140 | u8 v_sync_line_aft_2[2]; | ||
| 141 | u8 v_sync_line_aft_1[2]; | ||
| 142 | u8 v_sync_line_aft_pxl_2[2]; | ||
| 143 | u8 v_sync_line_aft_pxl_1[2]; | ||
| 144 | u8 v_blank_f2[2]; /* for 3D mode */ | ||
| 145 | u8 v_blank_f3[2]; /* for 3D mode */ | ||
| 146 | u8 v_blank_f4[2]; /* for 3D mode */ | ||
| 147 | u8 v_blank_f5[2]; /* for 3D mode */ | ||
| 148 | u8 v_sync_line_aft_3[2]; | ||
| 149 | u8 v_sync_line_aft_4[2]; | ||
| 150 | u8 v_sync_line_aft_5[2]; | ||
| 151 | u8 v_sync_line_aft_6[2]; | ||
| 152 | u8 v_sync_line_aft_pxl_3[2]; | ||
| 153 | u8 v_sync_line_aft_pxl_4[2]; | ||
| 154 | u8 v_sync_line_aft_pxl_5[2]; | ||
| 155 | u8 v_sync_line_aft_pxl_6[2]; | ||
| 156 | u8 vact_space_1[2]; | ||
| 157 | u8 vact_space_2[2]; | ||
| 158 | u8 vact_space_3[2]; | ||
| 159 | u8 vact_space_4[2]; | ||
| 160 | u8 vact_space_5[2]; | ||
| 161 | u8 vact_space_6[2]; | ||
| 162 | }; | ||
| 163 | |||
| 164 | struct hdmi_v13_conf { | ||
| 165 | struct hdmi_v13_core_regs core; | ||
| 166 | struct hdmi_tg_regs tg; | ||
| 167 | }; | ||
| 168 | |||
| 169 | struct hdmi_v14_conf { | ||
| 170 | struct hdmi_v14_core_regs core; | ||
| 171 | struct hdmi_tg_regs tg; | ||
| 172 | }; | ||
| 173 | |||
| 174 | struct hdmi_conf_regs { | ||
| 175 | int pixel_clock; | ||
| 176 | int cea_video_id; | ||
| 177 | enum hdmi_picture_aspect aspect_ratio; | ||
| 178 | union { | ||
| 179 | struct hdmi_v13_conf v13_conf; | ||
| 180 | struct hdmi_v14_conf v14_conf; | ||
| 181 | } conf; | ||
| 182 | }; | ||
| 183 | |||
| 184 | struct hdmi_context { | 89 | struct hdmi_context { |
| 185 | struct exynos_drm_display display; | 90 | struct drm_encoder encoder; |
| 186 | struct device *dev; | 91 | struct device *dev; |
| 187 | struct drm_device *drm_dev; | 92 | struct drm_device *drm_dev; |
| 188 | struct drm_connector connector; | 93 | struct drm_connector connector; |
| 189 | struct drm_encoder *encoder; | ||
| 190 | bool hpd; | 94 | bool hpd; |
| 191 | bool powered; | 95 | bool powered; |
| 192 | bool dvi_mode; | 96 | bool dvi_mode; |
| 193 | struct mutex hdmi_mutex; | ||
| 194 | 97 | ||
| 195 | void __iomem *regs; | 98 | void __iomem *regs; |
| 196 | int irq; | 99 | int irq; |
| @@ -201,22 +104,20 @@ struct hdmi_context { | |||
| 201 | 104 | ||
| 202 | /* current hdmiphy conf regs */ | 105 | /* current hdmiphy conf regs */ |
| 203 | struct drm_display_mode current_mode; | 106 | struct drm_display_mode current_mode; |
| 204 | struct hdmi_conf_regs mode_conf; | 107 | u8 cea_video_id; |
| 205 | 108 | ||
| 206 | struct hdmi_resources res; | 109 | struct hdmi_resources res; |
| 110 | const struct hdmi_driver_data *drv_data; | ||
| 207 | 111 | ||
| 208 | int hpd_gpio; | 112 | int hpd_gpio; |
| 209 | void __iomem *regs_hdmiphy; | 113 | void __iomem *regs_hdmiphy; |
| 210 | const struct hdmiphy_config *phy_confs; | ||
| 211 | unsigned int phy_conf_count; | ||
| 212 | 114 | ||
| 213 | struct regmap *pmureg; | 115 | struct regmap *pmureg; |
| 214 | enum hdmi_type type; | ||
| 215 | }; | 116 | }; |
| 216 | 117 | ||
| 217 | static inline struct hdmi_context *display_to_hdmi(struct exynos_drm_display *d) | 118 | static inline struct hdmi_context *encoder_to_hdmi(struct drm_encoder *e) |
| 218 | { | 119 | { |
| 219 | return container_of(d, struct hdmi_context, display); | 120 | return container_of(e, struct hdmi_context, encoder); |
| 220 | } | 121 | } |
| 221 | 122 | ||
| 222 | struct hdmiphy_config { | 123 | struct hdmiphy_config { |
| @@ -624,6 +525,16 @@ static inline void hdmi_reg_writeb(struct hdmi_context *hdata, | |||
| 624 | writeb(value, hdata->regs + reg_id); | 525 | writeb(value, hdata->regs + reg_id); |
| 625 | } | 526 | } |
| 626 | 527 | ||
| 528 | static inline void hdmi_reg_writev(struct hdmi_context *hdata, u32 reg_id, | ||
| 529 | int bytes, u32 val) | ||
| 530 | { | ||
| 531 | while (--bytes >= 0) { | ||
| 532 | writeb(val & 0xff, hdata->regs + reg_id); | ||
| 533 | val >>= 8; | ||
| 534 | reg_id += 4; | ||
| 535 | } | ||
| 536 | } | ||
| 537 | |||
| 627 | static inline void hdmi_reg_writemask(struct hdmi_context *hdata, | 538 | static inline void hdmi_reg_writemask(struct hdmi_context *hdata, |
| 628 | u32 reg_id, u32 value, u32 mask) | 539 | u32 reg_id, u32 value, u32 mask) |
| 629 | { | 540 | { |
| @@ -930,7 +841,7 @@ static void hdmi_v14_regs_dump(struct hdmi_context *hdata, char *prefix) | |||
| 930 | 841 | ||
| 931 | static void hdmi_regs_dump(struct hdmi_context *hdata, char *prefix) | 842 | static void hdmi_regs_dump(struct hdmi_context *hdata, char *prefix) |
| 932 | { | 843 | { |
| 933 | if (hdata->type == HDMI_TYPE13) | 844 | if (hdata->drv_data->type == HDMI_TYPE13) |
| 934 | hdmi_v13_regs_dump(hdata, prefix); | 845 | hdmi_v13_regs_dump(hdata, prefix); |
| 935 | else | 846 | else |
| 936 | hdmi_v14_regs_dump(hdata, prefix); | 847 | hdmi_v14_regs_dump(hdata, prefix); |
| @@ -957,7 +868,7 @@ static void hdmi_reg_infoframe(struct hdmi_context *hdata, | |||
| 957 | u32 hdr_sum; | 868 | u32 hdr_sum; |
| 958 | u8 chksum; | 869 | u8 chksum; |
| 959 | u32 mod; | 870 | u32 mod; |
| 960 | u32 vic; | 871 | u8 ar; |
| 961 | 872 | ||
| 962 | mod = hdmi_reg_read(hdata, HDMI_MODE_SEL); | 873 | mod = hdmi_reg_read(hdata, HDMI_MODE_SEL); |
| 963 | if (hdata->dvi_mode) { | 874 | if (hdata->dvi_mode) { |
| @@ -988,27 +899,22 @@ static void hdmi_reg_infoframe(struct hdmi_context *hdata, | |||
| 988 | * Set the aspect ratio as per the mode, mentioned in | 899 | * Set the aspect ratio as per the mode, mentioned in |
| 989 | * Table 9 AVI InfoFrame Data Byte 2 of CEA-861-D Standard | 900 | * Table 9 AVI InfoFrame Data Byte 2 of CEA-861-D Standard |
| 990 | */ | 901 | */ |
| 991 | switch (hdata->mode_conf.aspect_ratio) { | 902 | ar = hdata->current_mode.picture_aspect_ratio; |
| 903 | switch (ar) { | ||
| 992 | case HDMI_PICTURE_ASPECT_4_3: | 904 | case HDMI_PICTURE_ASPECT_4_3: |
| 993 | hdmi_reg_writeb(hdata, HDMI_AVI_BYTE(2), | 905 | ar |= AVI_4_3_CENTER_RATIO; |
| 994 | hdata->mode_conf.aspect_ratio | | ||
| 995 | AVI_4_3_CENTER_RATIO); | ||
| 996 | break; | 906 | break; |
| 997 | case HDMI_PICTURE_ASPECT_16_9: | 907 | case HDMI_PICTURE_ASPECT_16_9: |
| 998 | hdmi_reg_writeb(hdata, HDMI_AVI_BYTE(2), | 908 | ar |= AVI_16_9_CENTER_RATIO; |
| 999 | hdata->mode_conf.aspect_ratio | | ||
| 1000 | AVI_16_9_CENTER_RATIO); | ||
| 1001 | break; | 909 | break; |
| 1002 | case HDMI_PICTURE_ASPECT_NONE: | 910 | case HDMI_PICTURE_ASPECT_NONE: |
| 1003 | default: | 911 | default: |
| 1004 | hdmi_reg_writeb(hdata, HDMI_AVI_BYTE(2), | 912 | ar |= AVI_SAME_AS_PIC_ASPECT_RATIO; |
| 1005 | hdata->mode_conf.aspect_ratio | | ||
| 1006 | AVI_SAME_AS_PIC_ASPECT_RATIO); | ||
| 1007 | break; | 913 | break; |
| 1008 | } | 914 | } |
| 915 | hdmi_reg_writeb(hdata, HDMI_AVI_BYTE(2), ar); | ||
| 1009 | 916 | ||
| 1010 | vic = hdata->mode_conf.cea_video_id; | 917 | hdmi_reg_writeb(hdata, HDMI_AVI_BYTE(4), hdata->cea_video_id); |
| 1011 | hdmi_reg_writeb(hdata, HDMI_AVI_BYTE(4), vic); | ||
| 1012 | 918 | ||
| 1013 | chksum = hdmi_chksum(hdata, HDMI_AVI_BYTE(1), | 919 | chksum = hdmi_chksum(hdata, HDMI_AVI_BYTE(1), |
| 1014 | infoframe->any.length, hdr_sum); | 920 | infoframe->any.length, hdr_sum); |
| @@ -1038,10 +944,10 @@ static enum drm_connector_status hdmi_detect(struct drm_connector *connector, | |||
| 1038 | { | 944 | { |
| 1039 | struct hdmi_context *hdata = ctx_from_connector(connector); | 945 | struct hdmi_context *hdata = ctx_from_connector(connector); |
| 1040 | 946 | ||
| 1041 | hdata->hpd = gpio_get_value(hdata->hpd_gpio); | 947 | if (gpio_get_value(hdata->hpd_gpio)) |
| 948 | return connector_status_connected; | ||
| 1042 | 949 | ||
| 1043 | return hdata->hpd ? connector_status_connected : | 950 | return connector_status_disconnected; |
| 1044 | connector_status_disconnected; | ||
| 1045 | } | 951 | } |
| 1046 | 952 | ||
| 1047 | static void hdmi_connector_destroy(struct drm_connector *connector) | 953 | static void hdmi_connector_destroy(struct drm_connector *connector) |
| @@ -1091,8 +997,8 @@ static int hdmi_find_phy_conf(struct hdmi_context *hdata, u32 pixel_clock) | |||
| 1091 | { | 997 | { |
| 1092 | int i; | 998 | int i; |
| 1093 | 999 | ||
| 1094 | for (i = 0; i < hdata->phy_conf_count; i++) | 1000 | for (i = 0; i < hdata->drv_data->phy_conf_count; i++) |
| 1095 | if (hdata->phy_confs[i].pixel_clock == pixel_clock) | 1001 | if (hdata->drv_data->phy_confs[i].pixel_clock == pixel_clock) |
| 1096 | return i; | 1002 | return i; |
| 1097 | 1003 | ||
| 1098 | DRM_DEBUG_KMS("Could not find phy config for %d\n", pixel_clock); | 1004 | DRM_DEBUG_KMS("Could not find phy config for %d\n", pixel_clock); |
| @@ -1125,7 +1031,7 @@ static struct drm_encoder *hdmi_best_encoder(struct drm_connector *connector) | |||
| 1125 | { | 1031 | { |
| 1126 | struct hdmi_context *hdata = ctx_from_connector(connector); | 1032 | struct hdmi_context *hdata = ctx_from_connector(connector); |
| 1127 | 1033 | ||
| 1128 | return hdata->encoder; | 1034 | return &hdata->encoder; |
| 1129 | } | 1035 | } |
| 1130 | 1036 | ||
| 1131 | static struct drm_connector_helper_funcs hdmi_connector_helper_funcs = { | 1037 | static struct drm_connector_helper_funcs hdmi_connector_helper_funcs = { |
| @@ -1134,14 +1040,12 @@ static struct drm_connector_helper_funcs hdmi_connector_helper_funcs = { | |||
| 1134 | .best_encoder = hdmi_best_encoder, | 1040 | .best_encoder = hdmi_best_encoder, |
| 1135 | }; | 1041 | }; |
| 1136 | 1042 | ||
| 1137 | static int hdmi_create_connector(struct exynos_drm_display *display, | 1043 | static int hdmi_create_connector(struct drm_encoder *encoder) |
| 1138 | struct drm_encoder *encoder) | ||
| 1139 | { | 1044 | { |
| 1140 | struct hdmi_context *hdata = display_to_hdmi(display); | 1045 | struct hdmi_context *hdata = encoder_to_hdmi(encoder); |
| 1141 | struct drm_connector *connector = &hdata->connector; | 1046 | struct drm_connector *connector = &hdata->connector; |
| 1142 | int ret; | 1047 | int ret; |
| 1143 | 1048 | ||
| 1144 | hdata->encoder = encoder; | ||
| 1145 | connector->interlace_allowed = true; | 1049 | connector->interlace_allowed = true; |
| 1146 | connector->polled = DRM_CONNECTOR_POLL_HPD; | 1050 | connector->polled = DRM_CONNECTOR_POLL_HPD; |
| 1147 | 1051 | ||
| @@ -1159,23 +1063,30 @@ static int hdmi_create_connector(struct exynos_drm_display *display, | |||
| 1159 | return 0; | 1063 | return 0; |
| 1160 | } | 1064 | } |
| 1161 | 1065 | ||
| 1162 | static void hdmi_mode_fixup(struct exynos_drm_display *display, | 1066 | static bool hdmi_mode_fixup(struct drm_encoder *encoder, |
| 1163 | struct drm_connector *connector, | 1067 | const struct drm_display_mode *mode, |
| 1164 | const struct drm_display_mode *mode, | 1068 | struct drm_display_mode *adjusted_mode) |
| 1165 | struct drm_display_mode *adjusted_mode) | ||
| 1166 | { | 1069 | { |
| 1070 | struct drm_device *dev = encoder->dev; | ||
| 1071 | struct drm_connector *connector; | ||
| 1167 | struct drm_display_mode *m; | 1072 | struct drm_display_mode *m; |
| 1168 | int mode_ok; | 1073 | int mode_ok; |
| 1169 | 1074 | ||
| 1170 | DRM_DEBUG_KMS("%s\n", __FILE__); | ||
| 1171 | |||
| 1172 | drm_mode_set_crtcinfo(adjusted_mode, 0); | 1075 | drm_mode_set_crtcinfo(adjusted_mode, 0); |
| 1173 | 1076 | ||
| 1077 | list_for_each_entry(connector, &dev->mode_config.connector_list, head) { | ||
| 1078 | if (connector->encoder == encoder) | ||
| 1079 | break; | ||
| 1080 | } | ||
| 1081 | |||
| 1082 | if (connector->encoder != encoder) | ||
| 1083 | return true; | ||
| 1084 | |||
| 1174 | mode_ok = hdmi_mode_valid(connector, adjusted_mode); | 1085 | mode_ok = hdmi_mode_valid(connector, adjusted_mode); |
| 1175 | 1086 | ||
| 1176 | /* just return if user desired mode exists. */ | 1087 | /* just return if user desired mode exists. */ |
| 1177 | if (mode_ok == MODE_OK) | 1088 | if (mode_ok == MODE_OK) |
| 1178 | return; | 1089 | return true; |
| 1179 | 1090 | ||
| 1180 | /* | 1091 | /* |
| 1181 | * otherwise, find the most suitable mode among modes and change it | 1092 | * otherwise, find the most suitable mode among modes and change it |
| @@ -1195,6 +1106,8 @@ static void hdmi_mode_fixup(struct exynos_drm_display *display, | |||
| 1195 | break; | 1106 | break; |
| 1196 | } | 1107 | } |
| 1197 | } | 1108 | } |
| 1109 | |||
| 1110 | return true; | ||
| 1198 | } | 1111 | } |
| 1199 | 1112 | ||
| 1200 | static void hdmi_set_acr(u32 freq, u8 *acr) | 1113 | static void hdmi_set_acr(u32 freq, u8 *acr) |
| @@ -1257,7 +1170,7 @@ static void hdmi_reg_acr(struct hdmi_context *hdata, u8 *acr) | |||
| 1257 | hdmi_reg_writeb(hdata, HDMI_ACR_CTS1, acr[2]); | 1170 | hdmi_reg_writeb(hdata, HDMI_ACR_CTS1, acr[2]); |
| 1258 | hdmi_reg_writeb(hdata, HDMI_ACR_CTS2, acr[1]); | 1171 | hdmi_reg_writeb(hdata, HDMI_ACR_CTS2, acr[1]); |
| 1259 | 1172 | ||
| 1260 | if (hdata->type == HDMI_TYPE13) | 1173 | if (hdata->drv_data->type == HDMI_TYPE13) |
| 1261 | hdmi_reg_writeb(hdata, HDMI_V13_ACR_CON, 4); | 1174 | hdmi_reg_writeb(hdata, HDMI_V13_ACR_CON, 4); |
| 1262 | else | 1175 | else |
| 1263 | hdmi_reg_writeb(hdata, HDMI_ACR_CON, 4); | 1176 | hdmi_reg_writeb(hdata, HDMI_ACR_CON, 4); |
| @@ -1391,7 +1304,7 @@ static void hdmi_conf_init(struct hdmi_context *hdata) | |||
| 1391 | HDMI_VID_PREAMBLE_DIS | HDMI_GUARD_BAND_DIS); | 1304 | HDMI_VID_PREAMBLE_DIS | HDMI_GUARD_BAND_DIS); |
| 1392 | } | 1305 | } |
| 1393 | 1306 | ||
| 1394 | if (hdata->type == HDMI_TYPE13) { | 1307 | if (hdata->drv_data->type == HDMI_TYPE13) { |
| 1395 | /* choose bluescreen (fecal) color */ | 1308 | /* choose bluescreen (fecal) color */ |
| 1396 | hdmi_reg_writeb(hdata, HDMI_V13_BLUE_SCREEN_0, 0x12); | 1309 | hdmi_reg_writeb(hdata, HDMI_V13_BLUE_SCREEN_0, 0x12); |
| 1397 | hdmi_reg_writeb(hdata, HDMI_V13_BLUE_SCREEN_1, 0x34); | 1310 | hdmi_reg_writeb(hdata, HDMI_V13_BLUE_SCREEN_1, 0x34); |
| @@ -1424,66 +1337,94 @@ static void hdmi_conf_init(struct hdmi_context *hdata) | |||
| 1424 | 1337 | ||
| 1425 | static void hdmi_v13_mode_apply(struct hdmi_context *hdata) | 1338 | static void hdmi_v13_mode_apply(struct hdmi_context *hdata) |
| 1426 | { | 1339 | { |
| 1427 | const struct hdmi_tg_regs *tg = &hdata->mode_conf.conf.v13_conf.tg; | 1340 | struct drm_display_mode *m = &hdata->current_mode; |
| 1428 | const struct hdmi_v13_core_regs *core = | 1341 | unsigned int val; |
| 1429 | &hdata->mode_conf.conf.v13_conf.core; | ||
| 1430 | int tries; | 1342 | int tries; |
| 1431 | 1343 | ||
| 1432 | /* setting core registers */ | 1344 | hdmi_reg_writev(hdata, HDMI_H_BLANK_0, 2, m->htotal - m->hdisplay); |
| 1433 | hdmi_reg_writeb(hdata, HDMI_H_BLANK_0, core->h_blank[0]); | 1345 | hdmi_reg_writev(hdata, HDMI_V13_H_V_LINE_0, 3, |
| 1434 | hdmi_reg_writeb(hdata, HDMI_H_BLANK_1, core->h_blank[1]); | 1346 | (m->htotal << 12) | m->vtotal); |
| 1435 | hdmi_reg_writeb(hdata, HDMI_V13_V_BLANK_0, core->v_blank[0]); | 1347 | |
| 1436 | hdmi_reg_writeb(hdata, HDMI_V13_V_BLANK_1, core->v_blank[1]); | 1348 | val = (m->flags & DRM_MODE_FLAG_NVSYNC) ? 1 : 0; |
| 1437 | hdmi_reg_writeb(hdata, HDMI_V13_V_BLANK_2, core->v_blank[2]); | 1349 | hdmi_reg_writev(hdata, HDMI_VSYNC_POL, 1, val); |
| 1438 | hdmi_reg_writeb(hdata, HDMI_V13_H_V_LINE_0, core->h_v_line[0]); | 1350 | |
| 1439 | hdmi_reg_writeb(hdata, HDMI_V13_H_V_LINE_1, core->h_v_line[1]); | 1351 | val = (m->flags & DRM_MODE_FLAG_INTERLACE) ? 1 : 0; |
| 1440 | hdmi_reg_writeb(hdata, HDMI_V13_H_V_LINE_2, core->h_v_line[2]); | 1352 | hdmi_reg_writev(hdata, HDMI_INT_PRO_MODE, 1, val); |
| 1441 | hdmi_reg_writeb(hdata, HDMI_VSYNC_POL, core->vsync_pol[0]); | 1353 | |
| 1442 | hdmi_reg_writeb(hdata, HDMI_INT_PRO_MODE, core->int_pro_mode[0]); | 1354 | val = (m->hsync_start - m->hdisplay - 2); |
| 1443 | hdmi_reg_writeb(hdata, HDMI_V13_V_BLANK_F_0, core->v_blank_f[0]); | 1355 | val |= ((m->hsync_end - m->hdisplay - 2) << 10); |
| 1444 | hdmi_reg_writeb(hdata, HDMI_V13_V_BLANK_F_1, core->v_blank_f[1]); | 1356 | val |= ((m->flags & DRM_MODE_FLAG_NHSYNC) ? 1 : 0)<<20; |
| 1445 | hdmi_reg_writeb(hdata, HDMI_V13_V_BLANK_F_2, core->v_blank_f[2]); | 1357 | hdmi_reg_writev(hdata, HDMI_V13_H_SYNC_GEN_0, 3, val); |
| 1446 | hdmi_reg_writeb(hdata, HDMI_V13_H_SYNC_GEN_0, core->h_sync_gen[0]); | 1358 | |
| 1447 | hdmi_reg_writeb(hdata, HDMI_V13_H_SYNC_GEN_1, core->h_sync_gen[1]); | 1359 | /* |
| 1448 | hdmi_reg_writeb(hdata, HDMI_V13_H_SYNC_GEN_2, core->h_sync_gen[2]); | 1360 | * Quirk requirement for exynos HDMI IP design, |
| 1449 | hdmi_reg_writeb(hdata, HDMI_V13_V_SYNC_GEN_1_0, core->v_sync_gen1[0]); | 1361 | * 2 pixels less than the actual calculation for hsync_start |
| 1450 | hdmi_reg_writeb(hdata, HDMI_V13_V_SYNC_GEN_1_1, core->v_sync_gen1[1]); | 1362 | * and end. |
| 1451 | hdmi_reg_writeb(hdata, HDMI_V13_V_SYNC_GEN_1_2, core->v_sync_gen1[2]); | 1363 | */ |
| 1452 | hdmi_reg_writeb(hdata, HDMI_V13_V_SYNC_GEN_2_0, core->v_sync_gen2[0]); | 1364 | |
| 1453 | hdmi_reg_writeb(hdata, HDMI_V13_V_SYNC_GEN_2_1, core->v_sync_gen2[1]); | 1365 | /* Following values & calculations differ for different type of modes */ |
| 1454 | hdmi_reg_writeb(hdata, HDMI_V13_V_SYNC_GEN_2_2, core->v_sync_gen2[2]); | 1366 | if (m->flags & DRM_MODE_FLAG_INTERLACE) { |
| 1455 | hdmi_reg_writeb(hdata, HDMI_V13_V_SYNC_GEN_3_0, core->v_sync_gen3[0]); | 1367 | /* Interlaced Mode */ |
| 1456 | hdmi_reg_writeb(hdata, HDMI_V13_V_SYNC_GEN_3_1, core->v_sync_gen3[1]); | 1368 | val = ((m->vsync_end - m->vdisplay) / 2); |
| 1457 | hdmi_reg_writeb(hdata, HDMI_V13_V_SYNC_GEN_3_2, core->v_sync_gen3[2]); | 1369 | val |= ((m->vsync_start - m->vdisplay) / 2) << 12; |
| 1370 | hdmi_reg_writev(hdata, HDMI_V13_V_SYNC_GEN_1_0, 3, val); | ||
| 1371 | |||
| 1372 | val = m->vtotal / 2; | ||
| 1373 | val |= ((m->vtotal - m->vdisplay) / 2) << 11; | ||
| 1374 | hdmi_reg_writev(hdata, HDMI_V13_V_BLANK_0, 3, val); | ||
| 1375 | |||
| 1376 | val = (m->vtotal + | ||
| 1377 | ((m->vsync_end - m->vsync_start) * 4) + 5) / 2; | ||
| 1378 | val |= m->vtotal << 11; | ||
| 1379 | hdmi_reg_writev(hdata, HDMI_V13_V_BLANK_F_0, 3, val); | ||
| 1380 | |||
| 1381 | val = ((m->vtotal / 2) + 7); | ||
| 1382 | val |= ((m->vtotal / 2) + 2) << 12; | ||
| 1383 | hdmi_reg_writev(hdata, HDMI_V13_V_SYNC_GEN_2_0, 3, val); | ||
| 1384 | |||
| 1385 | val = ((m->htotal / 2) + (m->hsync_start - m->hdisplay)); | ||
| 1386 | val |= ((m->htotal / 2) + | ||
| 1387 | (m->hsync_start - m->hdisplay)) << 12; | ||
| 1388 | hdmi_reg_writev(hdata, HDMI_V13_V_SYNC_GEN_3_0, 3, val); | ||
| 1389 | |||
| 1390 | hdmi_reg_writev(hdata, HDMI_TG_VACT_ST_L, 2, | ||
| 1391 | (m->vtotal - m->vdisplay) / 2); | ||
| 1392 | hdmi_reg_writev(hdata, HDMI_TG_VACT_SZ_L, 2, m->vdisplay / 2); | ||
| 1393 | |||
| 1394 | hdmi_reg_writev(hdata, HDMI_TG_VACT_ST2_L, 2, 0x249); | ||
| 1395 | } else { | ||
| 1396 | /* Progressive Mode */ | ||
| 1397 | |||
| 1398 | val = m->vtotal; | ||
| 1399 | val |= (m->vtotal - m->vdisplay) << 11; | ||
| 1400 | hdmi_reg_writev(hdata, HDMI_V13_V_BLANK_0, 3, val); | ||
| 1401 | |||
| 1402 | hdmi_reg_writev(hdata, HDMI_V13_V_BLANK_F_0, 3, 0); | ||
| 1403 | |||
| 1404 | val = (m->vsync_end - m->vdisplay); | ||
| 1405 | val |= ((m->vsync_start - m->vdisplay) << 12); | ||
| 1406 | hdmi_reg_writev(hdata, HDMI_V13_V_SYNC_GEN_1_0, 3, val); | ||
| 1407 | |||
| 1408 | hdmi_reg_writev(hdata, HDMI_V13_V_SYNC_GEN_2_0, 3, 0x1001); | ||
| 1409 | hdmi_reg_writev(hdata, HDMI_V13_V_SYNC_GEN_3_0, 3, 0x1001); | ||
| 1410 | hdmi_reg_writev(hdata, HDMI_TG_VACT_ST_L, 2, | ||
| 1411 | m->vtotal - m->vdisplay); | ||
| 1412 | hdmi_reg_writev(hdata, HDMI_TG_VACT_SZ_L, 2, m->vdisplay); | ||
| 1413 | hdmi_reg_writev(hdata, HDMI_TG_VACT_ST2_L, 2, 0x248); | ||
| 1414 | } | ||
| 1415 | |||
| 1458 | /* Timing generator registers */ | 1416 | /* Timing generator registers */ |
| 1459 | hdmi_reg_writeb(hdata, HDMI_TG_H_FSZ_L, tg->h_fsz[0]); | 1417 | hdmi_reg_writev(hdata, HDMI_TG_H_FSZ_L, 2, m->htotal); |
| 1460 | hdmi_reg_writeb(hdata, HDMI_TG_H_FSZ_H, tg->h_fsz[1]); | 1418 | hdmi_reg_writev(hdata, HDMI_TG_HACT_ST_L, 2, m->htotal - m->hdisplay); |
| 1461 | hdmi_reg_writeb(hdata, HDMI_TG_HACT_ST_L, tg->hact_st[0]); | 1419 | hdmi_reg_writev(hdata, HDMI_TG_HACT_SZ_L, 2, m->hdisplay); |
| 1462 | hdmi_reg_writeb(hdata, HDMI_TG_HACT_ST_H, tg->hact_st[1]); | 1420 | hdmi_reg_writev(hdata, HDMI_TG_V_FSZ_L, 2, m->vtotal); |
| 1463 | hdmi_reg_writeb(hdata, HDMI_TG_HACT_SZ_L, tg->hact_sz[0]); | 1421 | hdmi_reg_writev(hdata, HDMI_TG_VSYNC_L, 2, 0x1); |
| 1464 | hdmi_reg_writeb(hdata, HDMI_TG_HACT_SZ_H, tg->hact_sz[1]); | 1422 | hdmi_reg_writev(hdata, HDMI_TG_VSYNC2_L, 2, 0x233); |
| 1465 | hdmi_reg_writeb(hdata, HDMI_TG_V_FSZ_L, tg->v_fsz[0]); | 1423 | hdmi_reg_writev(hdata, HDMI_TG_FIELD_CHG_L, 2, 0x233); |
| 1466 | hdmi_reg_writeb(hdata, HDMI_TG_V_FSZ_H, tg->v_fsz[1]); | 1424 | hdmi_reg_writev(hdata, HDMI_TG_VSYNC_TOP_HDMI_L, 2, 0x1); |
| 1467 | hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_L, tg->vsync[0]); | 1425 | hdmi_reg_writev(hdata, HDMI_TG_VSYNC_BOT_HDMI_L, 2, 0x233); |
| 1468 | hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_H, tg->vsync[1]); | 1426 | hdmi_reg_writev(hdata, HDMI_TG_FIELD_TOP_HDMI_L, 2, 0x1); |
| 1469 | hdmi_reg_writeb(hdata, HDMI_TG_VSYNC2_L, tg->vsync2[0]); | 1427 | hdmi_reg_writev(hdata, HDMI_TG_FIELD_BOT_HDMI_L, 2, 0x233); |
| 1470 | hdmi_reg_writeb(hdata, HDMI_TG_VSYNC2_H, tg->vsync2[1]); | ||
| 1471 | hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST_L, tg->vact_st[0]); | ||
| 1472 | hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST_H, tg->vact_st[1]); | ||
| 1473 | hdmi_reg_writeb(hdata, HDMI_TG_VACT_SZ_L, tg->vact_sz[0]); | ||
| 1474 | hdmi_reg_writeb(hdata, HDMI_TG_VACT_SZ_H, tg->vact_sz[1]); | ||
| 1475 | hdmi_reg_writeb(hdata, HDMI_TG_FIELD_CHG_L, tg->field_chg[0]); | ||
| 1476 | hdmi_reg_writeb(hdata, HDMI_TG_FIELD_CHG_H, tg->field_chg[1]); | ||
| 1477 | hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST2_L, tg->vact_st2[0]); | ||
| 1478 | hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST2_H, tg->vact_st2[1]); | ||
| 1479 | hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_TOP_HDMI_L, tg->vsync_top_hdmi[0]); | ||
| 1480 | hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_TOP_HDMI_H, tg->vsync_top_hdmi[1]); | ||
| 1481 | hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_BOT_HDMI_L, tg->vsync_bot_hdmi[0]); | ||
| 1482 | hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_BOT_HDMI_H, tg->vsync_bot_hdmi[1]); | ||
| 1483 | hdmi_reg_writeb(hdata, HDMI_TG_FIELD_TOP_HDMI_L, tg->field_top_hdmi[0]); | ||
| 1484 | hdmi_reg_writeb(hdata, HDMI_TG_FIELD_TOP_HDMI_H, tg->field_top_hdmi[1]); | ||
| 1485 | hdmi_reg_writeb(hdata, HDMI_TG_FIELD_BOT_HDMI_L, tg->field_bot_hdmi[0]); | ||
| 1486 | hdmi_reg_writeb(hdata, HDMI_TG_FIELD_BOT_HDMI_H, tg->field_bot_hdmi[1]); | ||
| 1487 | 1428 | ||
| 1488 | /* waiting for HDMIPHY's PLL to get to steady state */ | 1429 | /* waiting for HDMIPHY's PLL to get to steady state */ |
| 1489 | for (tries = 100; tries; --tries) { | 1430 | for (tries = 100; tries; --tries) { |
| @@ -1508,144 +1449,119 @@ static void hdmi_v13_mode_apply(struct hdmi_context *hdata) | |||
| 1508 | 1449 | ||
| 1509 | static void hdmi_v14_mode_apply(struct hdmi_context *hdata) | 1450 | static void hdmi_v14_mode_apply(struct hdmi_context *hdata) |
| 1510 | { | 1451 | { |
| 1511 | const struct hdmi_tg_regs *tg = &hdata->mode_conf.conf.v14_conf.tg; | 1452 | struct drm_display_mode *m = &hdata->current_mode; |
| 1512 | const struct hdmi_v14_core_regs *core = | ||
| 1513 | &hdata->mode_conf.conf.v14_conf.core; | ||
| 1514 | int tries; | 1453 | int tries; |
| 1515 | 1454 | ||
| 1516 | /* setting core registers */ | 1455 | hdmi_reg_writev(hdata, HDMI_H_BLANK_0, 2, m->htotal - m->hdisplay); |
| 1517 | hdmi_reg_writeb(hdata, HDMI_H_BLANK_0, core->h_blank[0]); | 1456 | hdmi_reg_writev(hdata, HDMI_V_LINE_0, 2, m->vtotal); |
| 1518 | hdmi_reg_writeb(hdata, HDMI_H_BLANK_1, core->h_blank[1]); | 1457 | hdmi_reg_writev(hdata, HDMI_H_LINE_0, 2, m->htotal); |
| 1519 | hdmi_reg_writeb(hdata, HDMI_V2_BLANK_0, core->v2_blank[0]); | 1458 | hdmi_reg_writev(hdata, HDMI_HSYNC_POL, 1, |
| 1520 | hdmi_reg_writeb(hdata, HDMI_V2_BLANK_1, core->v2_blank[1]); | 1459 | (m->flags & DRM_MODE_FLAG_NHSYNC) ? 1 : 0); |
| 1521 | hdmi_reg_writeb(hdata, HDMI_V1_BLANK_0, core->v1_blank[0]); | 1460 | hdmi_reg_writev(hdata, HDMI_VSYNC_POL, 1, |
| 1522 | hdmi_reg_writeb(hdata, HDMI_V1_BLANK_1, core->v1_blank[1]); | 1461 | (m->flags & DRM_MODE_FLAG_NVSYNC) ? 1 : 0); |
| 1523 | hdmi_reg_writeb(hdata, HDMI_V_LINE_0, core->v_line[0]); | 1462 | hdmi_reg_writev(hdata, HDMI_INT_PRO_MODE, 1, |
| 1524 | hdmi_reg_writeb(hdata, HDMI_V_LINE_1, core->v_line[1]); | 1463 | (m->flags & DRM_MODE_FLAG_INTERLACE) ? 1 : 0); |
| 1525 | hdmi_reg_writeb(hdata, HDMI_H_LINE_0, core->h_line[0]); | 1464 | |
| 1526 | hdmi_reg_writeb(hdata, HDMI_H_LINE_1, core->h_line[1]); | 1465 | /* |
| 1527 | hdmi_reg_writeb(hdata, HDMI_HSYNC_POL, core->hsync_pol[0]); | 1466 | * Quirk requirement for exynos 5 HDMI IP design, |
| 1528 | hdmi_reg_writeb(hdata, HDMI_VSYNC_POL, core->vsync_pol[0]); | 1467 | * 2 pixels less than the actual calculation for hsync_start |
| 1529 | hdmi_reg_writeb(hdata, HDMI_INT_PRO_MODE, core->int_pro_mode[0]); | 1468 | * and end. |
| 1530 | hdmi_reg_writeb(hdata, HDMI_V_BLANK_F0_0, core->v_blank_f0[0]); | 1469 | */ |
| 1531 | hdmi_reg_writeb(hdata, HDMI_V_BLANK_F0_1, core->v_blank_f0[1]); | 1470 | |
| 1532 | hdmi_reg_writeb(hdata, HDMI_V_BLANK_F1_0, core->v_blank_f1[0]); | 1471 | /* Following values & calculations differ for different type of modes */ |
| 1533 | hdmi_reg_writeb(hdata, HDMI_V_BLANK_F1_1, core->v_blank_f1[1]); | 1472 | if (m->flags & DRM_MODE_FLAG_INTERLACE) { |
| 1534 | hdmi_reg_writeb(hdata, HDMI_H_SYNC_START_0, core->h_sync_start[0]); | 1473 | /* Interlaced Mode */ |
| 1535 | hdmi_reg_writeb(hdata, HDMI_H_SYNC_START_1, core->h_sync_start[1]); | 1474 | hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_BEF_2_0, 2, |
| 1536 | hdmi_reg_writeb(hdata, HDMI_H_SYNC_END_0, core->h_sync_end[0]); | 1475 | (m->vsync_end - m->vdisplay) / 2); |
| 1537 | hdmi_reg_writeb(hdata, HDMI_H_SYNC_END_1, core->h_sync_end[1]); | 1476 | hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_BEF_1_0, 2, |
| 1538 | hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_BEF_2_0, | 1477 | (m->vsync_start - m->vdisplay) / 2); |
| 1539 | core->v_sync_line_bef_2[0]); | 1478 | hdmi_reg_writev(hdata, HDMI_V2_BLANK_0, 2, m->vtotal / 2); |
| 1540 | hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_BEF_2_1, | 1479 | hdmi_reg_writev(hdata, HDMI_V1_BLANK_0, 2, |
| 1541 | core->v_sync_line_bef_2[1]); | 1480 | (m->vtotal - m->vdisplay) / 2); |
| 1542 | hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_BEF_1_0, | 1481 | hdmi_reg_writev(hdata, HDMI_V_BLANK_F0_0, 2, |
| 1543 | core->v_sync_line_bef_1[0]); | 1482 | m->vtotal - m->vdisplay / 2); |
| 1544 | hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_BEF_1_1, | 1483 | hdmi_reg_writev(hdata, HDMI_V_BLANK_F1_0, 2, m->vtotal); |
| 1545 | core->v_sync_line_bef_1[1]); | 1484 | hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_2_0, 2, |
| 1546 | hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_2_0, | 1485 | (m->vtotal / 2) + 7); |
| 1547 | core->v_sync_line_aft_2[0]); | 1486 | hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_1_0, 2, |
| 1548 | hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_2_1, | 1487 | (m->vtotal / 2) + 2); |
| 1549 | core->v_sync_line_aft_2[1]); | 1488 | hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_PXL_2_0, 2, |
| 1550 | hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_1_0, | 1489 | (m->htotal / 2) + (m->hsync_start - m->hdisplay)); |
| 1551 | core->v_sync_line_aft_1[0]); | 1490 | hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_PXL_1_0, 2, |
| 1552 | hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_1_1, | 1491 | (m->htotal / 2) + (m->hsync_start - m->hdisplay)); |
| 1553 | core->v_sync_line_aft_1[1]); | 1492 | hdmi_reg_writev(hdata, HDMI_TG_VACT_ST_L, 2, |
| 1554 | hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_2_0, | 1493 | (m->vtotal - m->vdisplay) / 2); |
| 1555 | core->v_sync_line_aft_pxl_2[0]); | 1494 | hdmi_reg_writev(hdata, HDMI_TG_VACT_SZ_L, 2, m->vdisplay / 2); |
| 1556 | hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_2_1, | 1495 | hdmi_reg_writev(hdata, HDMI_TG_VACT_ST2_L, 2, |
| 1557 | core->v_sync_line_aft_pxl_2[1]); | 1496 | m->vtotal - m->vdisplay / 2); |
| 1558 | hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_1_0, | 1497 | hdmi_reg_writev(hdata, HDMI_TG_VSYNC2_L, 2, |
| 1559 | core->v_sync_line_aft_pxl_1[0]); | 1498 | (m->vtotal / 2) + 1); |
| 1560 | hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_1_1, | 1499 | hdmi_reg_writev(hdata, HDMI_TG_VSYNC_BOT_HDMI_L, 2, |
| 1561 | core->v_sync_line_aft_pxl_1[1]); | 1500 | (m->vtotal / 2) + 1); |
| 1562 | hdmi_reg_writeb(hdata, HDMI_V_BLANK_F2_0, core->v_blank_f2[0]); | 1501 | hdmi_reg_writev(hdata, HDMI_TG_FIELD_BOT_HDMI_L, 2, |
| 1563 | hdmi_reg_writeb(hdata, HDMI_V_BLANK_F2_1, core->v_blank_f2[1]); | 1502 | (m->vtotal / 2) + 1); |
| 1564 | hdmi_reg_writeb(hdata, HDMI_V_BLANK_F3_0, core->v_blank_f3[0]); | 1503 | hdmi_reg_writev(hdata, HDMI_TG_VACT_ST3_L, 2, 0x0); |
| 1565 | hdmi_reg_writeb(hdata, HDMI_V_BLANK_F3_1, core->v_blank_f3[1]); | 1504 | hdmi_reg_writev(hdata, HDMI_TG_VACT_ST4_L, 2, 0x0); |
| 1566 | hdmi_reg_writeb(hdata, HDMI_V_BLANK_F4_0, core->v_blank_f4[0]); | 1505 | } else { |
| 1567 | hdmi_reg_writeb(hdata, HDMI_V_BLANK_F4_1, core->v_blank_f4[1]); | 1506 | /* Progressive Mode */ |
| 1568 | hdmi_reg_writeb(hdata, HDMI_V_BLANK_F5_0, core->v_blank_f5[0]); | 1507 | hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_BEF_2_0, 2, |
| 1569 | hdmi_reg_writeb(hdata, HDMI_V_BLANK_F5_1, core->v_blank_f5[1]); | 1508 | m->vsync_end - m->vdisplay); |
| 1570 | hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_3_0, | 1509 | hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_BEF_1_0, 2, |
| 1571 | core->v_sync_line_aft_3[0]); | 1510 | m->vsync_start - m->vdisplay); |
| 1572 | hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_3_1, | 1511 | hdmi_reg_writev(hdata, HDMI_V2_BLANK_0, 2, m->vtotal); |
| 1573 | core->v_sync_line_aft_3[1]); | 1512 | hdmi_reg_writev(hdata, HDMI_V1_BLANK_0, 2, |
| 1574 | hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_4_0, | 1513 | m->vtotal - m->vdisplay); |
| 1575 | core->v_sync_line_aft_4[0]); | 1514 | hdmi_reg_writev(hdata, HDMI_V_BLANK_F0_0, 2, 0xffff); |
| 1576 | hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_4_1, | 1515 | hdmi_reg_writev(hdata, HDMI_V_BLANK_F1_0, 2, 0xffff); |
| 1577 | core->v_sync_line_aft_4[1]); | 1516 | hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_2_0, 2, 0xffff); |
| 1578 | hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_5_0, | 1517 | hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_1_0, 2, 0xffff); |
| 1579 | core->v_sync_line_aft_5[0]); | 1518 | hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_PXL_2_0, 2, 0xffff); |
| 1580 | hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_5_1, | 1519 | hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_PXL_1_0, 2, 0xffff); |
| 1581 | core->v_sync_line_aft_5[1]); | 1520 | hdmi_reg_writev(hdata, HDMI_TG_VACT_ST_L, 2, |
| 1582 | hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_6_0, | 1521 | m->vtotal - m->vdisplay); |
| 1583 | core->v_sync_line_aft_6[0]); | 1522 | hdmi_reg_writev(hdata, HDMI_TG_VACT_SZ_L, 2, m->vdisplay); |
| 1584 | hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_6_1, | 1523 | hdmi_reg_writev(hdata, HDMI_TG_VACT_ST2_L, 2, 0x248); |
| 1585 | core->v_sync_line_aft_6[1]); | 1524 | hdmi_reg_writev(hdata, HDMI_TG_VACT_ST3_L, 2, 0x47b); |
| 1586 | hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_3_0, | 1525 | hdmi_reg_writev(hdata, HDMI_TG_VACT_ST4_L, 2, 0x6ae); |
| 1587 | core->v_sync_line_aft_pxl_3[0]); | 1526 | hdmi_reg_writev(hdata, HDMI_TG_VSYNC2_L, 2, 0x233); |
| 1588 | hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_3_1, | 1527 | hdmi_reg_writev(hdata, HDMI_TG_VSYNC_BOT_HDMI_L, 2, 0x233); |
| 1589 | core->v_sync_line_aft_pxl_3[1]); | 1528 | hdmi_reg_writev(hdata, HDMI_TG_FIELD_BOT_HDMI_L, 2, 0x233); |
| 1590 | hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_4_0, | 1529 | } |
| 1591 | core->v_sync_line_aft_pxl_4[0]); | 1530 | |
| 1592 | hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_4_1, | 1531 | /* Following values & calculations are same irrespective of mode type */ |
| 1593 | core->v_sync_line_aft_pxl_4[1]); | 1532 | hdmi_reg_writev(hdata, HDMI_H_SYNC_START_0, 2, |
| 1594 | hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_5_0, | 1533 | m->hsync_start - m->hdisplay - 2); |
| 1595 | core->v_sync_line_aft_pxl_5[0]); | 1534 | hdmi_reg_writev(hdata, HDMI_H_SYNC_END_0, 2, |
| 1596 | hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_5_1, | 1535 | m->hsync_end - m->hdisplay - 2); |
| 1597 | core->v_sync_line_aft_pxl_5[1]); | 1536 | hdmi_reg_writev(hdata, HDMI_VACT_SPACE_1_0, 2, 0xffff); |
| 1598 | hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_6_0, | 1537 | hdmi_reg_writev(hdata, HDMI_VACT_SPACE_2_0, 2, 0xffff); |
| 1599 | core->v_sync_line_aft_pxl_6[0]); | 1538 | hdmi_reg_writev(hdata, HDMI_VACT_SPACE_3_0, 2, 0xffff); |
| 1600 | hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_6_1, | 1539 | hdmi_reg_writev(hdata, HDMI_VACT_SPACE_4_0, 2, 0xffff); |
| 1601 | core->v_sync_line_aft_pxl_6[1]); | 1540 | hdmi_reg_writev(hdata, HDMI_VACT_SPACE_5_0, 2, 0xffff); |
| 1602 | hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_1_0, core->vact_space_1[0]); | 1541 | hdmi_reg_writev(hdata, HDMI_VACT_SPACE_6_0, 2, 0xffff); |
| 1603 | hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_1_1, core->vact_space_1[1]); | 1542 | hdmi_reg_writev(hdata, HDMI_V_BLANK_F2_0, 2, 0xffff); |
| 1604 | hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_2_0, core->vact_space_2[0]); | 1543 | hdmi_reg_writev(hdata, HDMI_V_BLANK_F3_0, 2, 0xffff); |
| 1605 | hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_2_1, core->vact_space_2[1]); | 1544 | hdmi_reg_writev(hdata, HDMI_V_BLANK_F4_0, 2, 0xffff); |
| 1606 | hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_3_0, core->vact_space_3[0]); | 1545 | hdmi_reg_writev(hdata, HDMI_V_BLANK_F5_0, 2, 0xffff); |
| 1607 | hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_3_1, core->vact_space_3[1]); | 1546 | hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_3_0, 2, 0xffff); |
| 1608 | hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_4_0, core->vact_space_4[0]); | 1547 | hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_4_0, 2, 0xffff); |
| 1609 | hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_4_1, core->vact_space_4[1]); | 1548 | hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_5_0, 2, 0xffff); |
| 1610 | hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_5_0, core->vact_space_5[0]); | 1549 | hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_6_0, 2, 0xffff); |
| 1611 | hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_5_1, core->vact_space_5[1]); | 1550 | hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_PXL_3_0, 2, 0xffff); |
| 1612 | hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_6_0, core->vact_space_6[0]); | 1551 | hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_PXL_4_0, 2, 0xffff); |
| 1613 | hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_6_1, core->vact_space_6[1]); | 1552 | hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_PXL_5_0, 2, 0xffff); |
| 1553 | hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_PXL_6_0, 2, 0xffff); | ||
| 1614 | 1554 | ||
| 1615 | /* Timing generator registers */ | 1555 | /* Timing generator registers */ |
| 1616 | hdmi_reg_writeb(hdata, HDMI_TG_H_FSZ_L, tg->h_fsz[0]); | 1556 | hdmi_reg_writev(hdata, HDMI_TG_H_FSZ_L, 2, m->htotal); |
| 1617 | hdmi_reg_writeb(hdata, HDMI_TG_H_FSZ_H, tg->h_fsz[1]); | 1557 | hdmi_reg_writev(hdata, HDMI_TG_HACT_ST_L, 2, m->htotal - m->hdisplay); |
| 1618 | hdmi_reg_writeb(hdata, HDMI_TG_HACT_ST_L, tg->hact_st[0]); | 1558 | hdmi_reg_writev(hdata, HDMI_TG_HACT_SZ_L, 2, m->hdisplay); |
| 1619 | hdmi_reg_writeb(hdata, HDMI_TG_HACT_ST_H, tg->hact_st[1]); | 1559 | hdmi_reg_writev(hdata, HDMI_TG_V_FSZ_L, 2, m->vtotal); |
| 1620 | hdmi_reg_writeb(hdata, HDMI_TG_HACT_SZ_L, tg->hact_sz[0]); | 1560 | hdmi_reg_writev(hdata, HDMI_TG_VSYNC_L, 2, 0x1); |
| 1621 | hdmi_reg_writeb(hdata, HDMI_TG_HACT_SZ_H, tg->hact_sz[1]); | 1561 | hdmi_reg_writev(hdata, HDMI_TG_FIELD_CHG_L, 2, 0x233); |
| 1622 | hdmi_reg_writeb(hdata, HDMI_TG_V_FSZ_L, tg->v_fsz[0]); | 1562 | hdmi_reg_writev(hdata, HDMI_TG_VSYNC_TOP_HDMI_L, 2, 0x1); |
| 1623 | hdmi_reg_writeb(hdata, HDMI_TG_V_FSZ_H, tg->v_fsz[1]); | 1563 | hdmi_reg_writev(hdata, HDMI_TG_FIELD_TOP_HDMI_L, 2, 0x1); |
| 1624 | hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_L, tg->vsync[0]); | 1564 | hdmi_reg_writev(hdata, HDMI_TG_3D, 1, 0x0); |
| 1625 | hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_H, tg->vsync[1]); | ||
| 1626 | hdmi_reg_writeb(hdata, HDMI_TG_VSYNC2_L, tg->vsync2[0]); | ||
| 1627 | hdmi_reg_writeb(hdata, HDMI_TG_VSYNC2_H, tg->vsync2[1]); | ||
| 1628 | hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST_L, tg->vact_st[0]); | ||
| 1629 | hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST_H, tg->vact_st[1]); | ||
| 1630 | hdmi_reg_writeb(hdata, HDMI_TG_VACT_SZ_L, tg->vact_sz[0]); | ||
| 1631 | hdmi_reg_writeb(hdata, HDMI_TG_VACT_SZ_H, tg->vact_sz[1]); | ||
| 1632 | hdmi_reg_writeb(hdata, HDMI_TG_FIELD_CHG_L, tg->field_chg[0]); | ||
| 1633 | hdmi_reg_writeb(hdata, HDMI_TG_FIELD_CHG_H, tg->field_chg[1]); | ||
| 1634 | hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST2_L, tg->vact_st2[0]); | ||
| 1635 | hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST2_H, tg->vact_st2[1]); | ||
| 1636 | hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST3_L, tg->vact_st3[0]); | ||
| 1637 | hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST3_H, tg->vact_st3[1]); | ||
| 1638 | hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST4_L, tg->vact_st4[0]); | ||
| 1639 | hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST4_H, tg->vact_st4[1]); | ||
| 1640 | hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_TOP_HDMI_L, tg->vsync_top_hdmi[0]); | ||
| 1641 | hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_TOP_HDMI_H, tg->vsync_top_hdmi[1]); | ||
| 1642 | hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_BOT_HDMI_L, tg->vsync_bot_hdmi[0]); | ||
| 1643 | hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_BOT_HDMI_H, tg->vsync_bot_hdmi[1]); | ||
| 1644 | hdmi_reg_writeb(hdata, HDMI_TG_FIELD_TOP_HDMI_L, tg->field_top_hdmi[0]); | ||
| 1645 | hdmi_reg_writeb(hdata, HDMI_TG_FIELD_TOP_HDMI_H, tg->field_top_hdmi[1]); | ||
| 1646 | hdmi_reg_writeb(hdata, HDMI_TG_FIELD_BOT_HDMI_L, tg->field_bot_hdmi[0]); | ||
| 1647 | hdmi_reg_writeb(hdata, HDMI_TG_FIELD_BOT_HDMI_H, tg->field_bot_hdmi[1]); | ||
| 1648 | hdmi_reg_writeb(hdata, HDMI_TG_3D, tg->tg_3d[0]); | ||
| 1649 | 1565 | ||
| 1650 | /* waiting for HDMIPHY's PLL to get to steady state */ | 1566 | /* waiting for HDMIPHY's PLL to get to steady state */ |
| 1651 | for (tries = 100; tries; --tries) { | 1567 | for (tries = 100; tries; --tries) { |
| @@ -1670,7 +1586,7 @@ static void hdmi_v14_mode_apply(struct hdmi_context *hdata) | |||
| 1670 | 1586 | ||
| 1671 | static void hdmi_mode_apply(struct hdmi_context *hdata) | 1587 | static void hdmi_mode_apply(struct hdmi_context *hdata) |
| 1672 | { | 1588 | { |
| 1673 | if (hdata->type == HDMI_TYPE13) | 1589 | if (hdata->drv_data->type == HDMI_TYPE13) |
| 1674 | hdmi_v13_mode_apply(hdata); | 1590 | hdmi_v13_mode_apply(hdata); |
| 1675 | else | 1591 | else |
| 1676 | hdmi_v14_mode_apply(hdata); | 1592 | hdmi_v14_mode_apply(hdata); |
| @@ -1688,7 +1604,7 @@ static void hdmiphy_conf_reset(struct hdmi_context *hdata) | |||
| 1688 | hdmiphy_reg_writeb(hdata, HDMIPHY_MODE_SET_DONE, | 1604 | hdmiphy_reg_writeb(hdata, HDMIPHY_MODE_SET_DONE, |
| 1689 | HDMI_PHY_ENABLE_MODE_SET); | 1605 | HDMI_PHY_ENABLE_MODE_SET); |
| 1690 | 1606 | ||
| 1691 | if (hdata->type == HDMI_TYPE13) | 1607 | if (hdata->drv_data->type == HDMI_TYPE13) |
| 1692 | reg = HDMI_V13_PHY_RSTOUT; | 1608 | reg = HDMI_V13_PHY_RSTOUT; |
| 1693 | else | 1609 | else |
| 1694 | reg = HDMI_PHY_RSTOUT; | 1610 | reg = HDMI_PHY_RSTOUT; |
| @@ -1702,7 +1618,7 @@ static void hdmiphy_conf_reset(struct hdmi_context *hdata) | |||
| 1702 | 1618 | ||
| 1703 | static void hdmiphy_poweron(struct hdmi_context *hdata) | 1619 | static void hdmiphy_poweron(struct hdmi_context *hdata) |
| 1704 | { | 1620 | { |
| 1705 | if (hdata->type != HDMI_TYPE14) | 1621 | if (hdata->drv_data->type != HDMI_TYPE14) |
| 1706 | return; | 1622 | return; |
| 1707 | 1623 | ||
| 1708 | DRM_DEBUG_KMS("\n"); | 1624 | DRM_DEBUG_KMS("\n"); |
| @@ -1722,7 +1638,7 @@ static void hdmiphy_poweron(struct hdmi_context *hdata) | |||
| 1722 | 1638 | ||
| 1723 | static void hdmiphy_poweroff(struct hdmi_context *hdata) | 1639 | static void hdmiphy_poweroff(struct hdmi_context *hdata) |
| 1724 | { | 1640 | { |
| 1725 | if (hdata->type != HDMI_TYPE14) | 1641 | if (hdata->drv_data->type != HDMI_TYPE14) |
| 1726 | return; | 1642 | return; |
| 1727 | 1643 | ||
| 1728 | DRM_DEBUG_KMS("\n"); | 1644 | DRM_DEBUG_KMS("\n"); |
| @@ -1748,13 +1664,14 @@ static void hdmiphy_conf_apply(struct hdmi_context *hdata) | |||
| 1748 | int i; | 1664 | int i; |
| 1749 | 1665 | ||
| 1750 | /* pixel clock */ | 1666 | /* pixel clock */ |
| 1751 | i = hdmi_find_phy_conf(hdata, hdata->mode_conf.pixel_clock); | 1667 | i = hdmi_find_phy_conf(hdata, hdata->current_mode.clock * 1000); |
| 1752 | if (i < 0) { | 1668 | if (i < 0) { |
| 1753 | DRM_ERROR("failed to find hdmiphy conf\n"); | 1669 | DRM_ERROR("failed to find hdmiphy conf\n"); |
| 1754 | return; | 1670 | return; |
| 1755 | } | 1671 | } |
| 1756 | 1672 | ||
| 1757 | ret = hdmiphy_reg_write_buf(hdata, 0, hdata->phy_confs[i].conf, 32); | 1673 | ret = hdmiphy_reg_write_buf(hdata, 0, |
| 1674 | hdata->drv_data->phy_confs[i].conf, 32); | ||
| 1758 | if (ret) { | 1675 | if (ret) { |
| 1759 | DRM_ERROR("failed to configure hdmiphy\n"); | 1676 | DRM_ERROR("failed to configure hdmiphy\n"); |
| 1760 | return; | 1677 | return; |
| @@ -1776,10 +1693,8 @@ static void hdmi_conf_apply(struct hdmi_context *hdata) | |||
| 1776 | hdmiphy_conf_reset(hdata); | 1693 | hdmiphy_conf_reset(hdata); |
| 1777 | hdmiphy_conf_apply(hdata); | 1694 | hdmiphy_conf_apply(hdata); |
| 1778 | 1695 | ||
| 1779 | mutex_lock(&hdata->hdmi_mutex); | ||
| 1780 | hdmi_start(hdata, false); | 1696 | hdmi_start(hdata, false); |
| 1781 | hdmi_conf_init(hdata); | 1697 | hdmi_conf_init(hdata); |
| 1782 | mutex_unlock(&hdata->hdmi_mutex); | ||
| 1783 | 1698 | ||
| 1784 | hdmi_audio_init(hdata); | 1699 | hdmi_audio_init(hdata); |
| 1785 | 1700 | ||
| @@ -1790,271 +1705,32 @@ static void hdmi_conf_apply(struct hdmi_context *hdata) | |||
| 1790 | hdmi_regs_dump(hdata, "start"); | 1705 | hdmi_regs_dump(hdata, "start"); |
| 1791 | } | 1706 | } |
| 1792 | 1707 | ||
| 1793 | static void hdmi_set_reg(u8 *reg_pair, int num_bytes, u32 value) | 1708 | static void hdmi_mode_set(struct drm_encoder *encoder, |
| 1794 | { | 1709 | struct drm_display_mode *mode, |
| 1795 | int i; | 1710 | struct drm_display_mode *adjusted_mode) |
| 1796 | BUG_ON(num_bytes > 4); | ||
| 1797 | for (i = 0; i < num_bytes; i++) | ||
| 1798 | reg_pair[i] = (value >> (8 * i)) & 0xff; | ||
| 1799 | } | ||
| 1800 | |||
| 1801 | static void hdmi_v13_mode_set(struct hdmi_context *hdata, | ||
| 1802 | struct drm_display_mode *m) | ||
| 1803 | { | 1711 | { |
| 1804 | struct hdmi_v13_core_regs *core = &hdata->mode_conf.conf.v13_conf.core; | 1712 | struct hdmi_context *hdata = encoder_to_hdmi(encoder); |
| 1805 | struct hdmi_tg_regs *tg = &hdata->mode_conf.conf.v13_conf.tg; | 1713 | struct drm_display_mode *m = adjusted_mode; |
| 1806 | unsigned int val; | ||
| 1807 | |||
| 1808 | hdata->mode_conf.cea_video_id = | ||
| 1809 | drm_match_cea_mode((struct drm_display_mode *)m); | ||
| 1810 | hdata->mode_conf.pixel_clock = m->clock * 1000; | ||
| 1811 | hdata->mode_conf.aspect_ratio = m->picture_aspect_ratio; | ||
| 1812 | |||
| 1813 | hdmi_set_reg(core->h_blank, 2, m->htotal - m->hdisplay); | ||
| 1814 | hdmi_set_reg(core->h_v_line, 3, (m->htotal << 12) | m->vtotal); | ||
| 1815 | |||
| 1816 | val = (m->flags & DRM_MODE_FLAG_NVSYNC) ? 1 : 0; | ||
| 1817 | hdmi_set_reg(core->vsync_pol, 1, val); | ||
| 1818 | |||
| 1819 | val = (m->flags & DRM_MODE_FLAG_INTERLACE) ? 1 : 0; | ||
| 1820 | hdmi_set_reg(core->int_pro_mode, 1, val); | ||
| 1821 | |||
| 1822 | val = (m->hsync_start - m->hdisplay - 2); | ||
| 1823 | val |= ((m->hsync_end - m->hdisplay - 2) << 10); | ||
| 1824 | val |= ((m->flags & DRM_MODE_FLAG_NHSYNC) ? 1 : 0)<<20; | ||
| 1825 | hdmi_set_reg(core->h_sync_gen, 3, val); | ||
| 1826 | |||
| 1827 | /* | ||
| 1828 | * Quirk requirement for exynos HDMI IP design, | ||
| 1829 | * 2 pixels less than the actual calculation for hsync_start | ||
| 1830 | * and end. | ||
| 1831 | */ | ||
| 1832 | |||
| 1833 | /* Following values & calculations differ for different type of modes */ | ||
| 1834 | if (m->flags & DRM_MODE_FLAG_INTERLACE) { | ||
| 1835 | /* Interlaced Mode */ | ||
| 1836 | val = ((m->vsync_end - m->vdisplay) / 2); | ||
| 1837 | val |= ((m->vsync_start - m->vdisplay) / 2) << 12; | ||
| 1838 | hdmi_set_reg(core->v_sync_gen1, 3, val); | ||
| 1839 | |||
| 1840 | val = m->vtotal / 2; | ||
| 1841 | val |= ((m->vtotal - m->vdisplay) / 2) << 11; | ||
| 1842 | hdmi_set_reg(core->v_blank, 3, val); | ||
| 1843 | |||
| 1844 | val = (m->vtotal + | ||
| 1845 | ((m->vsync_end - m->vsync_start) * 4) + 5) / 2; | ||
| 1846 | val |= m->vtotal << 11; | ||
| 1847 | hdmi_set_reg(core->v_blank_f, 3, val); | ||
| 1848 | |||
| 1849 | val = ((m->vtotal / 2) + 7); | ||
| 1850 | val |= ((m->vtotal / 2) + 2) << 12; | ||
| 1851 | hdmi_set_reg(core->v_sync_gen2, 3, val); | ||
| 1852 | |||
| 1853 | val = ((m->htotal / 2) + (m->hsync_start - m->hdisplay)); | ||
| 1854 | val |= ((m->htotal / 2) + | ||
| 1855 | (m->hsync_start - m->hdisplay)) << 12; | ||
| 1856 | hdmi_set_reg(core->v_sync_gen3, 3, val); | ||
| 1857 | |||
| 1858 | hdmi_set_reg(tg->vact_st, 2, (m->vtotal - m->vdisplay) / 2); | ||
| 1859 | hdmi_set_reg(tg->vact_sz, 2, m->vdisplay / 2); | ||
| 1860 | |||
| 1861 | hdmi_set_reg(tg->vact_st2, 2, 0x249);/* Reset value + 1*/ | ||
| 1862 | } else { | ||
| 1863 | /* Progressive Mode */ | ||
| 1864 | |||
| 1865 | val = m->vtotal; | ||
| 1866 | val |= (m->vtotal - m->vdisplay) << 11; | ||
| 1867 | hdmi_set_reg(core->v_blank, 3, val); | ||
| 1868 | |||
| 1869 | hdmi_set_reg(core->v_blank_f, 3, 0); | ||
| 1870 | |||
| 1871 | val = (m->vsync_end - m->vdisplay); | ||
| 1872 | val |= ((m->vsync_start - m->vdisplay) << 12); | ||
| 1873 | hdmi_set_reg(core->v_sync_gen1, 3, val); | ||
| 1874 | |||
| 1875 | hdmi_set_reg(core->v_sync_gen2, 3, 0x1001);/* Reset value */ | ||
| 1876 | hdmi_set_reg(core->v_sync_gen3, 3, 0x1001);/* Reset value */ | ||
| 1877 | hdmi_set_reg(tg->vact_st, 2, m->vtotal - m->vdisplay); | ||
| 1878 | hdmi_set_reg(tg->vact_sz, 2, m->vdisplay); | ||
| 1879 | hdmi_set_reg(tg->vact_st2, 2, 0x248); /* Reset value */ | ||
| 1880 | } | ||
| 1881 | |||
| 1882 | /* Timing generator registers */ | ||
| 1883 | hdmi_set_reg(tg->cmd, 1, 0x0); | ||
| 1884 | hdmi_set_reg(tg->h_fsz, 2, m->htotal); | ||
| 1885 | hdmi_set_reg(tg->hact_st, 2, m->htotal - m->hdisplay); | ||
| 1886 | hdmi_set_reg(tg->hact_sz, 2, m->hdisplay); | ||
| 1887 | hdmi_set_reg(tg->v_fsz, 2, m->vtotal); | ||
| 1888 | hdmi_set_reg(tg->vsync, 2, 0x1); | ||
| 1889 | hdmi_set_reg(tg->vsync2, 2, 0x233); /* Reset value */ | ||
| 1890 | hdmi_set_reg(tg->field_chg, 2, 0x233); /* Reset value */ | ||
| 1891 | hdmi_set_reg(tg->vsync_top_hdmi, 2, 0x1); /* Reset value */ | ||
| 1892 | hdmi_set_reg(tg->vsync_bot_hdmi, 2, 0x233); /* Reset value */ | ||
| 1893 | hdmi_set_reg(tg->field_top_hdmi, 2, 0x1); /* Reset value */ | ||
| 1894 | hdmi_set_reg(tg->field_bot_hdmi, 2, 0x233); /* Reset value */ | ||
| 1895 | hdmi_set_reg(tg->tg_3d, 1, 0x0); /* Not used */ | ||
| 1896 | } | ||
| 1897 | |||
| 1898 | static void hdmi_v14_mode_set(struct hdmi_context *hdata, | ||
| 1899 | struct drm_display_mode *m) | ||
| 1900 | { | ||
| 1901 | struct hdmi_tg_regs *tg = &hdata->mode_conf.conf.v14_conf.tg; | ||
| 1902 | struct hdmi_v14_core_regs *core = | ||
| 1903 | &hdata->mode_conf.conf.v14_conf.core; | ||
| 1904 | |||
| 1905 | hdata->mode_conf.cea_video_id = | ||
| 1906 | drm_match_cea_mode((struct drm_display_mode *)m); | ||
| 1907 | hdata->mode_conf.pixel_clock = m->clock * 1000; | ||
| 1908 | hdata->mode_conf.aspect_ratio = m->picture_aspect_ratio; | ||
| 1909 | |||
| 1910 | hdmi_set_reg(core->h_blank, 2, m->htotal - m->hdisplay); | ||
| 1911 | hdmi_set_reg(core->v_line, 2, m->vtotal); | ||
| 1912 | hdmi_set_reg(core->h_line, 2, m->htotal); | ||
| 1913 | hdmi_set_reg(core->hsync_pol, 1, | ||
| 1914 | (m->flags & DRM_MODE_FLAG_NHSYNC) ? 1 : 0); | ||
| 1915 | hdmi_set_reg(core->vsync_pol, 1, | ||
| 1916 | (m->flags & DRM_MODE_FLAG_NVSYNC) ? 1 : 0); | ||
| 1917 | hdmi_set_reg(core->int_pro_mode, 1, | ||
| 1918 | (m->flags & DRM_MODE_FLAG_INTERLACE) ? 1 : 0); | ||
| 1919 | |||
| 1920 | /* | ||
| 1921 | * Quirk requirement for exynos 5 HDMI IP design, | ||
| 1922 | * 2 pixels less than the actual calculation for hsync_start | ||
| 1923 | * and end. | ||
| 1924 | */ | ||
| 1925 | |||
| 1926 | /* Following values & calculations differ for different type of modes */ | ||
| 1927 | if (m->flags & DRM_MODE_FLAG_INTERLACE) { | ||
| 1928 | /* Interlaced Mode */ | ||
| 1929 | hdmi_set_reg(core->v_sync_line_bef_2, 2, | ||
| 1930 | (m->vsync_end - m->vdisplay) / 2); | ||
| 1931 | hdmi_set_reg(core->v_sync_line_bef_1, 2, | ||
| 1932 | (m->vsync_start - m->vdisplay) / 2); | ||
| 1933 | hdmi_set_reg(core->v2_blank, 2, m->vtotal / 2); | ||
| 1934 | hdmi_set_reg(core->v1_blank, 2, (m->vtotal - m->vdisplay) / 2); | ||
| 1935 | hdmi_set_reg(core->v_blank_f0, 2, m->vtotal - m->vdisplay / 2); | ||
| 1936 | hdmi_set_reg(core->v_blank_f1, 2, m->vtotal); | ||
| 1937 | hdmi_set_reg(core->v_sync_line_aft_2, 2, (m->vtotal / 2) + 7); | ||
| 1938 | hdmi_set_reg(core->v_sync_line_aft_1, 2, (m->vtotal / 2) + 2); | ||
| 1939 | hdmi_set_reg(core->v_sync_line_aft_pxl_2, 2, | ||
| 1940 | (m->htotal / 2) + (m->hsync_start - m->hdisplay)); | ||
| 1941 | hdmi_set_reg(core->v_sync_line_aft_pxl_1, 2, | ||
| 1942 | (m->htotal / 2) + (m->hsync_start - m->hdisplay)); | ||
| 1943 | hdmi_set_reg(tg->vact_st, 2, (m->vtotal - m->vdisplay) / 2); | ||
| 1944 | hdmi_set_reg(tg->vact_sz, 2, m->vdisplay / 2); | ||
| 1945 | hdmi_set_reg(tg->vact_st2, 2, m->vtotal - m->vdisplay / 2); | ||
| 1946 | hdmi_set_reg(tg->vsync2, 2, (m->vtotal / 2) + 1); | ||
| 1947 | hdmi_set_reg(tg->vsync_bot_hdmi, 2, (m->vtotal / 2) + 1); | ||
| 1948 | hdmi_set_reg(tg->field_bot_hdmi, 2, (m->vtotal / 2) + 1); | ||
| 1949 | hdmi_set_reg(tg->vact_st3, 2, 0x0); | ||
| 1950 | hdmi_set_reg(tg->vact_st4, 2, 0x0); | ||
| 1951 | } else { | ||
| 1952 | /* Progressive Mode */ | ||
| 1953 | hdmi_set_reg(core->v_sync_line_bef_2, 2, | ||
| 1954 | m->vsync_end - m->vdisplay); | ||
| 1955 | hdmi_set_reg(core->v_sync_line_bef_1, 2, | ||
| 1956 | m->vsync_start - m->vdisplay); | ||
| 1957 | hdmi_set_reg(core->v2_blank, 2, m->vtotal); | ||
| 1958 | hdmi_set_reg(core->v1_blank, 2, m->vtotal - m->vdisplay); | ||
| 1959 | hdmi_set_reg(core->v_blank_f0, 2, 0xffff); | ||
| 1960 | hdmi_set_reg(core->v_blank_f1, 2, 0xffff); | ||
| 1961 | hdmi_set_reg(core->v_sync_line_aft_2, 2, 0xffff); | ||
| 1962 | hdmi_set_reg(core->v_sync_line_aft_1, 2, 0xffff); | ||
| 1963 | hdmi_set_reg(core->v_sync_line_aft_pxl_2, 2, 0xffff); | ||
| 1964 | hdmi_set_reg(core->v_sync_line_aft_pxl_1, 2, 0xffff); | ||
| 1965 | hdmi_set_reg(tg->vact_st, 2, m->vtotal - m->vdisplay); | ||
| 1966 | hdmi_set_reg(tg->vact_sz, 2, m->vdisplay); | ||
| 1967 | hdmi_set_reg(tg->vact_st2, 2, 0x248); /* Reset value */ | ||
| 1968 | hdmi_set_reg(tg->vact_st3, 2, 0x47b); /* Reset value */ | ||
| 1969 | hdmi_set_reg(tg->vact_st4, 2, 0x6ae); /* Reset value */ | ||
| 1970 | hdmi_set_reg(tg->vsync2, 2, 0x233); /* Reset value */ | ||
| 1971 | hdmi_set_reg(tg->vsync_bot_hdmi, 2, 0x233); /* Reset value */ | ||
| 1972 | hdmi_set_reg(tg->field_bot_hdmi, 2, 0x233); /* Reset value */ | ||
| 1973 | } | ||
| 1974 | |||
| 1975 | /* Following values & calculations are same irrespective of mode type */ | ||
| 1976 | hdmi_set_reg(core->h_sync_start, 2, m->hsync_start - m->hdisplay - 2); | ||
| 1977 | hdmi_set_reg(core->h_sync_end, 2, m->hsync_end - m->hdisplay - 2); | ||
| 1978 | hdmi_set_reg(core->vact_space_1, 2, 0xffff); | ||
| 1979 | hdmi_set_reg(core->vact_space_2, 2, 0xffff); | ||
| 1980 | hdmi_set_reg(core->vact_space_3, 2, 0xffff); | ||
| 1981 | hdmi_set_reg(core->vact_space_4, 2, 0xffff); | ||
| 1982 | hdmi_set_reg(core->vact_space_5, 2, 0xffff); | ||
| 1983 | hdmi_set_reg(core->vact_space_6, 2, 0xffff); | ||
| 1984 | hdmi_set_reg(core->v_blank_f2, 2, 0xffff); | ||
| 1985 | hdmi_set_reg(core->v_blank_f3, 2, 0xffff); | ||
| 1986 | hdmi_set_reg(core->v_blank_f4, 2, 0xffff); | ||
| 1987 | hdmi_set_reg(core->v_blank_f5, 2, 0xffff); | ||
| 1988 | hdmi_set_reg(core->v_sync_line_aft_3, 2, 0xffff); | ||
| 1989 | hdmi_set_reg(core->v_sync_line_aft_4, 2, 0xffff); | ||
| 1990 | hdmi_set_reg(core->v_sync_line_aft_5, 2, 0xffff); | ||
| 1991 | hdmi_set_reg(core->v_sync_line_aft_6, 2, 0xffff); | ||
| 1992 | hdmi_set_reg(core->v_sync_line_aft_pxl_3, 2, 0xffff); | ||
| 1993 | hdmi_set_reg(core->v_sync_line_aft_pxl_4, 2, 0xffff); | ||
| 1994 | hdmi_set_reg(core->v_sync_line_aft_pxl_5, 2, 0xffff); | ||
| 1995 | hdmi_set_reg(core->v_sync_line_aft_pxl_6, 2, 0xffff); | ||
| 1996 | |||
| 1997 | /* Timing generator registers */ | ||
| 1998 | hdmi_set_reg(tg->cmd, 1, 0x0); | ||
| 1999 | hdmi_set_reg(tg->h_fsz, 2, m->htotal); | ||
| 2000 | hdmi_set_reg(tg->hact_st, 2, m->htotal - m->hdisplay); | ||
| 2001 | hdmi_set_reg(tg->hact_sz, 2, m->hdisplay); | ||
| 2002 | hdmi_set_reg(tg->v_fsz, 2, m->vtotal); | ||
| 2003 | hdmi_set_reg(tg->vsync, 2, 0x1); | ||
| 2004 | hdmi_set_reg(tg->field_chg, 2, 0x233); /* Reset value */ | ||
| 2005 | hdmi_set_reg(tg->vsync_top_hdmi, 2, 0x1); /* Reset value */ | ||
| 2006 | hdmi_set_reg(tg->field_top_hdmi, 2, 0x1); /* Reset value */ | ||
| 2007 | hdmi_set_reg(tg->tg_3d, 1, 0x0); | ||
| 2008 | } | ||
| 2009 | |||
| 2010 | static void hdmi_mode_set(struct exynos_drm_display *display, | ||
| 2011 | struct drm_display_mode *mode) | ||
| 2012 | { | ||
| 2013 | struct hdmi_context *hdata = display_to_hdmi(display); | ||
| 2014 | struct drm_display_mode *m = mode; | ||
| 2015 | 1714 | ||
| 2016 | DRM_DEBUG_KMS("xres=%d, yres=%d, refresh=%d, intl=%s\n", | 1715 | DRM_DEBUG_KMS("xres=%d, yres=%d, refresh=%d, intl=%s\n", |
| 2017 | m->hdisplay, m->vdisplay, | 1716 | m->hdisplay, m->vdisplay, |
| 2018 | m->vrefresh, (m->flags & DRM_MODE_FLAG_INTERLACE) ? | 1717 | m->vrefresh, (m->flags & DRM_MODE_FLAG_INTERLACE) ? |
| 2019 | "INTERLACED" : "PROGRESSIVE"); | 1718 | "INTERLACED" : "PROGRESSIVE"); |
| 2020 | 1719 | ||
| 2021 | /* preserve mode information for later use. */ | 1720 | drm_mode_copy(&hdata->current_mode, m); |
| 2022 | drm_mode_copy(&hdata->current_mode, mode); | 1721 | hdata->cea_video_id = drm_match_cea_mode(mode); |
| 2023 | |||
| 2024 | if (hdata->type == HDMI_TYPE13) | ||
| 2025 | hdmi_v13_mode_set(hdata, mode); | ||
| 2026 | else | ||
| 2027 | hdmi_v14_mode_set(hdata, mode); | ||
| 2028 | } | ||
| 2029 | |||
| 2030 | static void hdmi_commit(struct exynos_drm_display *display) | ||
| 2031 | { | ||
| 2032 | struct hdmi_context *hdata = display_to_hdmi(display); | ||
| 2033 | |||
| 2034 | mutex_lock(&hdata->hdmi_mutex); | ||
| 2035 | if (!hdata->powered) { | ||
| 2036 | mutex_unlock(&hdata->hdmi_mutex); | ||
| 2037 | return; | ||
| 2038 | } | ||
| 2039 | mutex_unlock(&hdata->hdmi_mutex); | ||
| 2040 | |||
| 2041 | hdmi_conf_apply(hdata); | ||
| 2042 | } | 1722 | } |
| 2043 | 1723 | ||
| 2044 | static void hdmi_poweron(struct hdmi_context *hdata) | 1724 | static void hdmi_enable(struct drm_encoder *encoder) |
| 2045 | { | 1725 | { |
| 1726 | struct hdmi_context *hdata = encoder_to_hdmi(encoder); | ||
| 2046 | struct hdmi_resources *res = &hdata->res; | 1727 | struct hdmi_resources *res = &hdata->res; |
| 2047 | 1728 | ||
| 2048 | mutex_lock(&hdata->hdmi_mutex); | 1729 | if (hdata->powered) |
| 2049 | if (hdata->powered) { | ||
| 2050 | mutex_unlock(&hdata->hdmi_mutex); | ||
| 2051 | return; | 1730 | return; |
| 2052 | } | ||
| 2053 | 1731 | ||
| 2054 | hdata->powered = true; | 1732 | hdata->powered = true; |
| 2055 | 1733 | ||
| 2056 | mutex_unlock(&hdata->hdmi_mutex); | ||
| 2057 | |||
| 2058 | pm_runtime_get_sync(hdata->dev); | 1734 | pm_runtime_get_sync(hdata->dev); |
| 2059 | 1735 | ||
| 2060 | if (regulator_bulk_enable(res->regul_count, res->regul_bulk)) | 1736 | if (regulator_bulk_enable(res->regul_count, res->regul_bulk)) |
| @@ -2068,17 +1744,32 @@ static void hdmi_poweron(struct hdmi_context *hdata) | |||
| 2068 | clk_prepare_enable(res->sclk_hdmi); | 1744 | clk_prepare_enable(res->sclk_hdmi); |
| 2069 | 1745 | ||
| 2070 | hdmiphy_poweron(hdata); | 1746 | hdmiphy_poweron(hdata); |
| 2071 | hdmi_commit(&hdata->display); | 1747 | hdmi_conf_apply(hdata); |
| 2072 | } | 1748 | } |
| 2073 | 1749 | ||
| 2074 | static void hdmi_poweroff(struct hdmi_context *hdata) | 1750 | static void hdmi_disable(struct drm_encoder *encoder) |
| 2075 | { | 1751 | { |
| 1752 | struct hdmi_context *hdata = encoder_to_hdmi(encoder); | ||
| 2076 | struct hdmi_resources *res = &hdata->res; | 1753 | struct hdmi_resources *res = &hdata->res; |
| 1754 | struct drm_crtc *crtc = encoder->crtc; | ||
| 1755 | const struct drm_crtc_helper_funcs *funcs = NULL; | ||
| 2077 | 1756 | ||
| 2078 | mutex_lock(&hdata->hdmi_mutex); | ||
| 2079 | if (!hdata->powered) | 1757 | if (!hdata->powered) |
| 2080 | goto out; | 1758 | return; |
| 2081 | mutex_unlock(&hdata->hdmi_mutex); | 1759 | |
| 1760 | /* | ||
| 1761 | * The SFRs of VP and Mixer are updated by Vertical Sync of | ||
| 1762 | * Timing generator which is a part of HDMI so the sequence | ||
| 1763 | * to disable TV Subsystem should be as following, | ||
| 1764 | * VP -> Mixer -> HDMI | ||
| 1765 | * | ||
| 1766 | * Below codes will try to disable Mixer and VP(if used) | ||
| 1767 | * prior to disabling HDMI. | ||
| 1768 | */ | ||
| 1769 | if (crtc) | ||
| 1770 | funcs = crtc->helper_private; | ||
| 1771 | if (funcs && funcs->disable) | ||
| 1772 | (*funcs->disable)(crtc); | ||
| 2082 | 1773 | ||
| 2083 | /* HDMI System Disable */ | 1774 | /* HDMI System Disable */ |
| 2084 | hdmi_reg_writemask(hdata, HDMI_CON_0, 0, HDMI_EN); | 1775 | hdmi_reg_writemask(hdata, HDMI_CON_0, 0, HDMI_EN); |
| @@ -2098,57 +1789,18 @@ static void hdmi_poweroff(struct hdmi_context *hdata) | |||
| 2098 | 1789 | ||
| 2099 | pm_runtime_put_sync(hdata->dev); | 1790 | pm_runtime_put_sync(hdata->dev); |
| 2100 | 1791 | ||
| 2101 | mutex_lock(&hdata->hdmi_mutex); | ||
| 2102 | hdata->powered = false; | 1792 | hdata->powered = false; |
| 2103 | |||
| 2104 | out: | ||
| 2105 | mutex_unlock(&hdata->hdmi_mutex); | ||
| 2106 | } | ||
| 2107 | |||
| 2108 | static void hdmi_dpms(struct exynos_drm_display *display, int mode) | ||
| 2109 | { | ||
| 2110 | struct hdmi_context *hdata = display_to_hdmi(display); | ||
| 2111 | struct drm_encoder *encoder = hdata->encoder; | ||
| 2112 | struct drm_crtc *crtc = encoder->crtc; | ||
| 2113 | const struct drm_crtc_helper_funcs *funcs = NULL; | ||
| 2114 | |||
| 2115 | DRM_DEBUG_KMS("mode %d\n", mode); | ||
| 2116 | |||
| 2117 | switch (mode) { | ||
| 2118 | case DRM_MODE_DPMS_ON: | ||
| 2119 | hdmi_poweron(hdata); | ||
| 2120 | break; | ||
| 2121 | case DRM_MODE_DPMS_STANDBY: | ||
| 2122 | case DRM_MODE_DPMS_SUSPEND: | ||
| 2123 | case DRM_MODE_DPMS_OFF: | ||
| 2124 | /* | ||
| 2125 | * The SFRs of VP and Mixer are updated by Vertical Sync of | ||
| 2126 | * Timing generator which is a part of HDMI so the sequence | ||
| 2127 | * to disable TV Subsystem should be as following, | ||
| 2128 | * VP -> Mixer -> HDMI | ||
| 2129 | * | ||
| 2130 | * Below codes will try to disable Mixer and VP(if used) | ||
| 2131 | * prior to disabling HDMI. | ||
| 2132 | */ | ||
| 2133 | if (crtc) | ||
| 2134 | funcs = crtc->helper_private; | ||
| 2135 | if (funcs && funcs->disable) | ||
| 2136 | (*funcs->disable)(crtc); | ||
| 2137 | |||
| 2138 | hdmi_poweroff(hdata); | ||
| 2139 | break; | ||
| 2140 | default: | ||
| 2141 | DRM_DEBUG_KMS("unknown dpms mode: %d\n", mode); | ||
| 2142 | break; | ||
| 2143 | } | ||
| 2144 | } | 1793 | } |
| 2145 | 1794 | ||
| 2146 | static struct exynos_drm_display_ops hdmi_display_ops = { | 1795 | static struct drm_encoder_helper_funcs exynos_hdmi_encoder_helper_funcs = { |
| 2147 | .create_connector = hdmi_create_connector, | ||
| 2148 | .mode_fixup = hdmi_mode_fixup, | 1796 | .mode_fixup = hdmi_mode_fixup, |
| 2149 | .mode_set = hdmi_mode_set, | 1797 | .mode_set = hdmi_mode_set, |
| 2150 | .dpms = hdmi_dpms, | 1798 | .enable = hdmi_enable, |
| 2151 | .commit = hdmi_commit, | 1799 | .disable = hdmi_disable, |
| 1800 | }; | ||
| 1801 | |||
| 1802 | static struct drm_encoder_funcs exynos_hdmi_encoder_funcs = { | ||
| 1803 | .destroy = drm_encoder_cleanup, | ||
| 2152 | }; | 1804 | }; |
| 2153 | 1805 | ||
| 2154 | static void hdmi_hotplug_work_func(struct work_struct *work) | 1806 | static void hdmi_hotplug_work_func(struct work_struct *work) |
| @@ -2157,10 +1809,6 @@ static void hdmi_hotplug_work_func(struct work_struct *work) | |||
| 2157 | 1809 | ||
| 2158 | hdata = container_of(work, struct hdmi_context, hotplug_work.work); | 1810 | hdata = container_of(work, struct hdmi_context, hotplug_work.work); |
| 2159 | 1811 | ||
| 2160 | mutex_lock(&hdata->hdmi_mutex); | ||
| 2161 | hdata->hpd = gpio_get_value(hdata->hpd_gpio); | ||
| 2162 | mutex_unlock(&hdata->hdmi_mutex); | ||
| 2163 | |||
| 2164 | if (hdata->drm_dev) | 1812 | if (hdata->drm_dev) |
| 2165 | drm_helper_hpd_irq_event(hdata->drm_dev); | 1813 | drm_helper_hpd_irq_event(hdata->drm_dev); |
| 2166 | } | 1814 | } |
| @@ -2259,30 +1907,6 @@ fail: | |||
| 2259 | return ret; | 1907 | return ret; |
| 2260 | } | 1908 | } |
| 2261 | 1909 | ||
| 2262 | static struct s5p_hdmi_platform_data *drm_hdmi_dt_parse_pdata | ||
| 2263 | (struct device *dev) | ||
| 2264 | { | ||
| 2265 | struct device_node *np = dev->of_node; | ||
| 2266 | struct s5p_hdmi_platform_data *pd; | ||
| 2267 | u32 value; | ||
| 2268 | |||
| 2269 | pd = devm_kzalloc(dev, sizeof(*pd), GFP_KERNEL); | ||
| 2270 | if (!pd) | ||
| 2271 | goto err_data; | ||
| 2272 | |||
| 2273 | if (!of_find_property(np, "hpd-gpio", &value)) { | ||
| 2274 | DRM_ERROR("no hpd gpio property found\n"); | ||
| 2275 | goto err_data; | ||
| 2276 | } | ||
| 2277 | |||
| 2278 | pd->hpd_gpio = of_get_named_gpio(np, "hpd-gpio", 0); | ||
| 2279 | |||
| 2280 | return pd; | ||
| 2281 | |||
| 2282 | err_data: | ||
| 2283 | return NULL; | ||
| 2284 | } | ||
| 2285 | |||
| 2286 | static struct of_device_id hdmi_match_types[] = { | 1910 | static struct of_device_id hdmi_match_types[] = { |
| 2287 | { | 1911 | { |
| 2288 | .compatible = "samsung,exynos5-hdmi", | 1912 | .compatible = "samsung,exynos5-hdmi", |
| @@ -2306,10 +1930,33 @@ static int hdmi_bind(struct device *dev, struct device *master, void *data) | |||
| 2306 | { | 1930 | { |
| 2307 | struct drm_device *drm_dev = data; | 1931 | struct drm_device *drm_dev = data; |
| 2308 | struct hdmi_context *hdata = dev_get_drvdata(dev); | 1932 | struct hdmi_context *hdata = dev_get_drvdata(dev); |
| 1933 | struct drm_encoder *encoder = &hdata->encoder; | ||
| 1934 | int ret, pipe; | ||
| 2309 | 1935 | ||
| 2310 | hdata->drm_dev = drm_dev; | 1936 | hdata->drm_dev = drm_dev; |
| 2311 | 1937 | ||
| 2312 | return exynos_drm_create_enc_conn(drm_dev, &hdata->display); | 1938 | pipe = exynos_drm_crtc_get_pipe_from_type(drm_dev, |
| 1939 | EXYNOS_DISPLAY_TYPE_HDMI); | ||
| 1940 | if (pipe < 0) | ||
| 1941 | return pipe; | ||
| 1942 | |||
| 1943 | encoder->possible_crtcs = 1 << pipe; | ||
| 1944 | |||
| 1945 | DRM_DEBUG_KMS("possible_crtcs = 0x%x\n", encoder->possible_crtcs); | ||
| 1946 | |||
| 1947 | drm_encoder_init(drm_dev, encoder, &exynos_hdmi_encoder_funcs, | ||
| 1948 | DRM_MODE_ENCODER_TMDS); | ||
| 1949 | |||
| 1950 | drm_encoder_helper_add(encoder, &exynos_hdmi_encoder_helper_funcs); | ||
| 1951 | |||
| 1952 | ret = hdmi_create_connector(encoder); | ||
| 1953 | if (ret) { | ||
| 1954 | DRM_ERROR("failed to create connector ret = %d\n", ret); | ||
| 1955 | drm_encoder_cleanup(encoder); | ||
| 1956 | return ret; | ||
| 1957 | } | ||
| 1958 | |||
| 1959 | return 0; | ||
| 2313 | } | 1960 | } |
| 2314 | 1961 | ||
| 2315 | static void hdmi_unbind(struct device *dev, struct device *master, void *data) | 1962 | static void hdmi_unbind(struct device *dev, struct device *master, void *data) |
| @@ -2343,43 +1990,30 @@ static struct device_node *hdmi_legacy_phy_dt_binding(struct device *dev) | |||
| 2343 | static int hdmi_probe(struct platform_device *pdev) | 1990 | static int hdmi_probe(struct platform_device *pdev) |
| 2344 | { | 1991 | { |
| 2345 | struct device_node *ddc_node, *phy_node; | 1992 | struct device_node *ddc_node, *phy_node; |
| 2346 | struct s5p_hdmi_platform_data *pdata; | ||
| 2347 | struct hdmi_driver_data *drv_data; | ||
| 2348 | const struct of_device_id *match; | 1993 | const struct of_device_id *match; |
| 2349 | struct device *dev = &pdev->dev; | 1994 | struct device *dev = &pdev->dev; |
| 2350 | struct hdmi_context *hdata; | 1995 | struct hdmi_context *hdata; |
| 2351 | struct resource *res; | 1996 | struct resource *res; |
| 2352 | int ret; | 1997 | int ret; |
| 2353 | 1998 | ||
| 2354 | if (!dev->of_node) | ||
| 2355 | return -ENODEV; | ||
| 2356 | |||
| 2357 | pdata = drm_hdmi_dt_parse_pdata(dev); | ||
| 2358 | if (!pdata) | ||
| 2359 | return -EINVAL; | ||
| 2360 | |||
| 2361 | hdata = devm_kzalloc(dev, sizeof(struct hdmi_context), GFP_KERNEL); | 1999 | hdata = devm_kzalloc(dev, sizeof(struct hdmi_context), GFP_KERNEL); |
| 2362 | if (!hdata) | 2000 | if (!hdata) |
| 2363 | return -ENOMEM; | 2001 | return -ENOMEM; |
| 2364 | 2002 | ||
| 2365 | hdata->display.type = EXYNOS_DISPLAY_TYPE_HDMI; | 2003 | match = of_match_device(hdmi_match_types, dev); |
| 2366 | hdata->display.ops = &hdmi_display_ops; | ||
| 2367 | |||
| 2368 | mutex_init(&hdata->hdmi_mutex); | ||
| 2369 | |||
| 2370 | platform_set_drvdata(pdev, hdata); | ||
| 2371 | |||
| 2372 | match = of_match_node(hdmi_match_types, dev->of_node); | ||
| 2373 | if (!match) | 2004 | if (!match) |
| 2374 | return -ENODEV; | 2005 | return -ENODEV; |
| 2375 | 2006 | ||
| 2376 | drv_data = (struct hdmi_driver_data *)match->data; | 2007 | hdata->drv_data = match->data; |
| 2377 | hdata->type = drv_data->type; | 2008 | |
| 2378 | hdata->phy_confs = drv_data->phy_confs; | 2009 | platform_set_drvdata(pdev, hdata); |
| 2379 | hdata->phy_conf_count = drv_data->phy_conf_count; | ||
| 2380 | 2010 | ||
| 2381 | hdata->hpd_gpio = pdata->hpd_gpio; | ||
| 2382 | hdata->dev = dev; | 2011 | hdata->dev = dev; |
| 2012 | hdata->hpd_gpio = of_get_named_gpio(dev->of_node, "hpd-gpio", 0); | ||
| 2013 | if (hdata->hpd_gpio < 0) { | ||
| 2014 | DRM_ERROR("cannot get hpd gpio property\n"); | ||
| 2015 | return hdata->hpd_gpio; | ||
| 2016 | } | ||
| 2383 | 2017 | ||
| 2384 | ret = hdmi_resources_init(hdata); | 2018 | ret = hdmi_resources_init(hdata); |
| 2385 | if (ret) { | 2019 | if (ret) { |
| @@ -2431,7 +2065,7 @@ out_get_ddc_adpt: | |||
| 2431 | } | 2065 | } |
| 2432 | 2066 | ||
| 2433 | out_get_phy_port: | 2067 | out_get_phy_port: |
| 2434 | if (drv_data->is_apb_phy) { | 2068 | if (hdata->drv_data->is_apb_phy) { |
| 2435 | hdata->regs_hdmiphy = of_iomap(phy_node, 0); | 2069 | hdata->regs_hdmiphy = of_iomap(phy_node, 0); |
| 2436 | if (!hdata->regs_hdmiphy) { | 2070 | if (!hdata->regs_hdmiphy) { |
| 2437 | DRM_ERROR("failed to ioremap hdmi phy\n"); | 2071 | DRM_ERROR("failed to ioremap hdmi phy\n"); |
| @@ -2454,8 +2088,6 @@ out_get_phy_port: | |||
| 2454 | goto err_hdmiphy; | 2088 | goto err_hdmiphy; |
| 2455 | } | 2089 | } |
| 2456 | 2090 | ||
| 2457 | hdata->hpd = gpio_get_value(hdata->hpd_gpio); | ||
| 2458 | |||
| 2459 | INIT_DELAYED_WORK(&hdata->hotplug_work, hdmi_hotplug_work_func); | 2091 | INIT_DELAYED_WORK(&hdata->hotplug_work, hdmi_hotplug_work_func); |
| 2460 | 2092 | ||
| 2461 | ret = devm_request_threaded_irq(dev, hdata->irq, NULL, | 2093 | ret = devm_request_threaded_irq(dev, hdata->irq, NULL, |
diff --git a/drivers/gpu/drm/exynos/exynos_mixer.c b/drivers/gpu/drm/exynos/exynos_mixer.c index 4706b56902b4..e68340c77676 100644 --- a/drivers/gpu/drm/exynos/exynos_mixer.c +++ b/drivers/gpu/drm/exynos/exynos_mixer.c | |||
| @@ -69,6 +69,11 @@ enum mixer_version_id { | |||
| 69 | MXR_VER_128_0_0_184, | 69 | MXR_VER_128_0_0_184, |
| 70 | }; | 70 | }; |
| 71 | 71 | ||
| 72 | enum mixer_flag_bits { | ||
| 73 | MXR_BIT_POWERED, | ||
| 74 | MXR_BIT_VSYNC, | ||
| 75 | }; | ||
| 76 | |||
| 72 | struct mixer_context { | 77 | struct mixer_context { |
| 73 | struct platform_device *pdev; | 78 | struct platform_device *pdev; |
| 74 | struct device *dev; | 79 | struct device *dev; |
| @@ -76,13 +81,11 @@ struct mixer_context { | |||
| 76 | struct exynos_drm_crtc *crtc; | 81 | struct exynos_drm_crtc *crtc; |
| 77 | struct exynos_drm_plane planes[MIXER_WIN_NR]; | 82 | struct exynos_drm_plane planes[MIXER_WIN_NR]; |
| 78 | int pipe; | 83 | int pipe; |
| 84 | unsigned long flags; | ||
| 79 | bool interlace; | 85 | bool interlace; |
| 80 | bool powered; | ||
| 81 | bool vp_enabled; | 86 | bool vp_enabled; |
| 82 | bool has_sclk; | 87 | bool has_sclk; |
| 83 | u32 int_en; | ||
| 84 | 88 | ||
| 85 | struct mutex mixer_mutex; | ||
| 86 | struct mixer_resources mixer_res; | 89 | struct mixer_resources mixer_res; |
| 87 | enum mixer_version_id mxr_ver; | 90 | enum mixer_version_id mxr_ver; |
| 88 | wait_queue_head_t wait_vsync_queue; | 91 | wait_queue_head_t wait_vsync_queue; |
| @@ -380,19 +383,20 @@ static void mixer_stop(struct mixer_context *ctx) | |||
| 380 | usleep_range(10000, 12000); | 383 | usleep_range(10000, 12000); |
| 381 | } | 384 | } |
| 382 | 385 | ||
| 383 | static void vp_video_buffer(struct mixer_context *ctx, unsigned int win) | 386 | static void vp_video_buffer(struct mixer_context *ctx, |
| 387 | struct exynos_drm_plane *plane) | ||
| 384 | { | 388 | { |
| 385 | struct mixer_resources *res = &ctx->mixer_res; | 389 | struct mixer_resources *res = &ctx->mixer_res; |
| 390 | struct drm_plane_state *state = plane->base.state; | ||
| 391 | struct drm_framebuffer *fb = state->fb; | ||
| 392 | struct drm_display_mode *mode = &state->crtc->mode; | ||
| 386 | unsigned long flags; | 393 | unsigned long flags; |
| 387 | struct exynos_drm_plane *plane; | ||
| 388 | dma_addr_t luma_addr[2], chroma_addr[2]; | 394 | dma_addr_t luma_addr[2], chroma_addr[2]; |
| 389 | bool tiled_mode = false; | 395 | bool tiled_mode = false; |
| 390 | bool crcb_mode = false; | 396 | bool crcb_mode = false; |
| 391 | u32 val; | 397 | u32 val; |
| 392 | 398 | ||
| 393 | plane = &ctx->planes[win]; | 399 | switch (fb->pixel_format) { |
| 394 | |||
| 395 | switch (plane->pixel_format) { | ||
| 396 | case DRM_FORMAT_NV12: | 400 | case DRM_FORMAT_NV12: |
| 397 | crcb_mode = false; | 401 | crcb_mode = false; |
| 398 | break; | 402 | break; |
| @@ -401,21 +405,21 @@ static void vp_video_buffer(struct mixer_context *ctx, unsigned int win) | |||
| 401 | break; | 405 | break; |
| 402 | default: | 406 | default: |
| 403 | DRM_ERROR("pixel format for vp is wrong [%d].\n", | 407 | DRM_ERROR("pixel format for vp is wrong [%d].\n", |
| 404 | plane->pixel_format); | 408 | fb->pixel_format); |
| 405 | return; | 409 | return; |
| 406 | } | 410 | } |
| 407 | 411 | ||
| 408 | luma_addr[0] = plane->dma_addr[0]; | 412 | luma_addr[0] = plane->dma_addr[0]; |
| 409 | chroma_addr[0] = plane->dma_addr[1]; | 413 | chroma_addr[0] = plane->dma_addr[1]; |
| 410 | 414 | ||
| 411 | if (plane->scan_flag & DRM_MODE_FLAG_INTERLACE) { | 415 | if (mode->flags & DRM_MODE_FLAG_INTERLACE) { |
| 412 | ctx->interlace = true; | 416 | ctx->interlace = true; |
| 413 | if (tiled_mode) { | 417 | if (tiled_mode) { |
| 414 | luma_addr[1] = luma_addr[0] + 0x40; | 418 | luma_addr[1] = luma_addr[0] + 0x40; |
| 415 | chroma_addr[1] = chroma_addr[0] + 0x40; | 419 | chroma_addr[1] = chroma_addr[0] + 0x40; |
| 416 | } else { | 420 | } else { |
| 417 | luma_addr[1] = luma_addr[0] + plane->pitch; | 421 | luma_addr[1] = luma_addr[0] + fb->pitches[0]; |
| 418 | chroma_addr[1] = chroma_addr[0] + plane->pitch; | 422 | chroma_addr[1] = chroma_addr[0] + fb->pitches[0]; |
| 419 | } | 423 | } |
| 420 | } else { | 424 | } else { |
| 421 | ctx->interlace = false; | 425 | ctx->interlace = false; |
| @@ -436,25 +440,25 @@ static void vp_video_buffer(struct mixer_context *ctx, unsigned int win) | |||
| 436 | vp_reg_writemask(res, VP_MODE, val, VP_MODE_FMT_MASK); | 440 | vp_reg_writemask(res, VP_MODE, val, VP_MODE_FMT_MASK); |
| 437 | 441 | ||
| 438 | /* setting size of input image */ | 442 | /* setting size of input image */ |
| 439 | vp_reg_write(res, VP_IMG_SIZE_Y, VP_IMG_HSIZE(plane->pitch) | | 443 | vp_reg_write(res, VP_IMG_SIZE_Y, VP_IMG_HSIZE(fb->pitches[0]) | |
| 440 | VP_IMG_VSIZE(plane->fb_height)); | 444 | VP_IMG_VSIZE(fb->height)); |
| 441 | /* chroma height has to reduced by 2 to avoid chroma distorions */ | 445 | /* chroma height has to reduced by 2 to avoid chroma distorions */ |
| 442 | vp_reg_write(res, VP_IMG_SIZE_C, VP_IMG_HSIZE(plane->pitch) | | 446 | vp_reg_write(res, VP_IMG_SIZE_C, VP_IMG_HSIZE(fb->pitches[0]) | |
| 443 | VP_IMG_VSIZE(plane->fb_height / 2)); | 447 | VP_IMG_VSIZE(fb->height / 2)); |
| 444 | 448 | ||
| 445 | vp_reg_write(res, VP_SRC_WIDTH, plane->src_width); | 449 | vp_reg_write(res, VP_SRC_WIDTH, plane->src_w); |
| 446 | vp_reg_write(res, VP_SRC_HEIGHT, plane->src_height); | 450 | vp_reg_write(res, VP_SRC_HEIGHT, plane->src_h); |
| 447 | vp_reg_write(res, VP_SRC_H_POSITION, | 451 | vp_reg_write(res, VP_SRC_H_POSITION, |
| 448 | VP_SRC_H_POSITION_VAL(plane->src_x)); | 452 | VP_SRC_H_POSITION_VAL(plane->src_x)); |
| 449 | vp_reg_write(res, VP_SRC_V_POSITION, plane->src_y); | 453 | vp_reg_write(res, VP_SRC_V_POSITION, plane->src_y); |
| 450 | 454 | ||
| 451 | vp_reg_write(res, VP_DST_WIDTH, plane->crtc_width); | 455 | vp_reg_write(res, VP_DST_WIDTH, plane->crtc_w); |
| 452 | vp_reg_write(res, VP_DST_H_POSITION, plane->crtc_x); | 456 | vp_reg_write(res, VP_DST_H_POSITION, plane->crtc_x); |
| 453 | if (ctx->interlace) { | 457 | if (ctx->interlace) { |
| 454 | vp_reg_write(res, VP_DST_HEIGHT, plane->crtc_height / 2); | 458 | vp_reg_write(res, VP_DST_HEIGHT, plane->crtc_h / 2); |
| 455 | vp_reg_write(res, VP_DST_V_POSITION, plane->crtc_y / 2); | 459 | vp_reg_write(res, VP_DST_V_POSITION, plane->crtc_y / 2); |
| 456 | } else { | 460 | } else { |
| 457 | vp_reg_write(res, VP_DST_HEIGHT, plane->crtc_height); | 461 | vp_reg_write(res, VP_DST_HEIGHT, plane->crtc_h); |
| 458 | vp_reg_write(res, VP_DST_V_POSITION, plane->crtc_y); | 462 | vp_reg_write(res, VP_DST_V_POSITION, plane->crtc_y); |
| 459 | } | 463 | } |
| 460 | 464 | ||
| @@ -469,9 +473,9 @@ static void vp_video_buffer(struct mixer_context *ctx, unsigned int win) | |||
| 469 | vp_reg_write(res, VP_TOP_C_PTR, chroma_addr[0]); | 473 | vp_reg_write(res, VP_TOP_C_PTR, chroma_addr[0]); |
| 470 | vp_reg_write(res, VP_BOT_C_PTR, chroma_addr[1]); | 474 | vp_reg_write(res, VP_BOT_C_PTR, chroma_addr[1]); |
| 471 | 475 | ||
| 472 | mixer_cfg_scan(ctx, plane->mode_height); | 476 | mixer_cfg_scan(ctx, mode->vdisplay); |
| 473 | mixer_cfg_rgb_fmt(ctx, plane->mode_height); | 477 | mixer_cfg_rgb_fmt(ctx, mode->vdisplay); |
| 474 | mixer_cfg_layer(ctx, win, true); | 478 | mixer_cfg_layer(ctx, plane->zpos, true); |
| 475 | mixer_run(ctx); | 479 | mixer_run(ctx); |
| 476 | 480 | ||
| 477 | mixer_vsync_set_update(ctx, true); | 481 | mixer_vsync_set_update(ctx, true); |
| @@ -491,15 +495,15 @@ static void mixer_layer_update(struct mixer_context *ctx) | |||
| 491 | static int mixer_setup_scale(const struct exynos_drm_plane *plane, | 495 | static int mixer_setup_scale(const struct exynos_drm_plane *plane, |
| 492 | unsigned int *x_ratio, unsigned int *y_ratio) | 496 | unsigned int *x_ratio, unsigned int *y_ratio) |
| 493 | { | 497 | { |
| 494 | if (plane->crtc_width != plane->src_width) { | 498 | if (plane->crtc_w != plane->src_w) { |
| 495 | if (plane->crtc_width == 2 * plane->src_width) | 499 | if (plane->crtc_w == 2 * plane->src_w) |
| 496 | *x_ratio = 1; | 500 | *x_ratio = 1; |
| 497 | else | 501 | else |
| 498 | goto fail; | 502 | goto fail; |
| 499 | } | 503 | } |
| 500 | 504 | ||
| 501 | if (plane->crtc_height != plane->src_height) { | 505 | if (plane->crtc_h != plane->src_h) { |
| 502 | if (plane->crtc_height == 2 * plane->src_height) | 506 | if (plane->crtc_h == 2 * plane->src_h) |
| 503 | *y_ratio = 1; | 507 | *y_ratio = 1; |
| 504 | else | 508 | else |
| 505 | goto fail; | 509 | goto fail; |
| @@ -512,20 +516,22 @@ fail: | |||
| 512 | return -ENOTSUPP; | 516 | return -ENOTSUPP; |
| 513 | } | 517 | } |
| 514 | 518 | ||
| 515 | static void mixer_graph_buffer(struct mixer_context *ctx, unsigned int win) | 519 | static void mixer_graph_buffer(struct mixer_context *ctx, |
| 520 | struct exynos_drm_plane *plane) | ||
| 516 | { | 521 | { |
| 517 | struct mixer_resources *res = &ctx->mixer_res; | 522 | struct mixer_resources *res = &ctx->mixer_res; |
| 523 | struct drm_plane_state *state = plane->base.state; | ||
| 524 | struct drm_framebuffer *fb = state->fb; | ||
| 525 | struct drm_display_mode *mode = &state->crtc->mode; | ||
| 518 | unsigned long flags; | 526 | unsigned long flags; |
| 519 | struct exynos_drm_plane *plane; | 527 | unsigned int win = plane->zpos; |
| 520 | unsigned int x_ratio = 0, y_ratio = 0; | 528 | unsigned int x_ratio = 0, y_ratio = 0; |
| 521 | unsigned int src_x_offset, src_y_offset, dst_x_offset, dst_y_offset; | 529 | unsigned int src_x_offset, src_y_offset, dst_x_offset, dst_y_offset; |
| 522 | dma_addr_t dma_addr; | 530 | dma_addr_t dma_addr; |
| 523 | unsigned int fmt; | 531 | unsigned int fmt; |
| 524 | u32 val; | 532 | u32 val; |
| 525 | 533 | ||
| 526 | plane = &ctx->planes[win]; | 534 | switch (fb->pixel_format) { |
| 527 | |||
| 528 | switch (plane->pixel_format) { | ||
| 529 | case DRM_FORMAT_XRGB4444: | 535 | case DRM_FORMAT_XRGB4444: |
| 530 | fmt = MXR_FORMAT_ARGB4444; | 536 | fmt = MXR_FORMAT_ARGB4444; |
| 531 | break; | 537 | break; |
| @@ -557,12 +563,12 @@ static void mixer_graph_buffer(struct mixer_context *ctx, unsigned int win) | |||
| 557 | 563 | ||
| 558 | /* converting dma address base and source offset */ | 564 | /* converting dma address base and source offset */ |
| 559 | dma_addr = plane->dma_addr[0] | 565 | dma_addr = plane->dma_addr[0] |
| 560 | + (plane->src_x * plane->bpp >> 3) | 566 | + (plane->src_x * fb->bits_per_pixel >> 3) |
| 561 | + (plane->src_y * plane->pitch); | 567 | + (plane->src_y * fb->pitches[0]); |
| 562 | src_x_offset = 0; | 568 | src_x_offset = 0; |
| 563 | src_y_offset = 0; | 569 | src_y_offset = 0; |
| 564 | 570 | ||
| 565 | if (plane->scan_flag & DRM_MODE_FLAG_INTERLACE) | 571 | if (mode->flags & DRM_MODE_FLAG_INTERLACE) |
| 566 | ctx->interlace = true; | 572 | ctx->interlace = true; |
| 567 | else | 573 | else |
| 568 | ctx->interlace = false; | 574 | ctx->interlace = false; |
| @@ -576,18 +582,18 @@ static void mixer_graph_buffer(struct mixer_context *ctx, unsigned int win) | |||
| 576 | 582 | ||
| 577 | /* setup geometry */ | 583 | /* setup geometry */ |
| 578 | mixer_reg_write(res, MXR_GRAPHIC_SPAN(win), | 584 | mixer_reg_write(res, MXR_GRAPHIC_SPAN(win), |
| 579 | plane->pitch / (plane->bpp >> 3)); | 585 | fb->pitches[0] / (fb->bits_per_pixel >> 3)); |
| 580 | 586 | ||
| 581 | /* setup display size */ | 587 | /* setup display size */ |
| 582 | if (ctx->mxr_ver == MXR_VER_128_0_0_184 && | 588 | if (ctx->mxr_ver == MXR_VER_128_0_0_184 && |
| 583 | win == MIXER_DEFAULT_WIN) { | 589 | win == MIXER_DEFAULT_WIN) { |
| 584 | val = MXR_MXR_RES_HEIGHT(plane->mode_height); | 590 | val = MXR_MXR_RES_HEIGHT(mode->vdisplay); |
| 585 | val |= MXR_MXR_RES_WIDTH(plane->mode_width); | 591 | val |= MXR_MXR_RES_WIDTH(mode->hdisplay); |
| 586 | mixer_reg_write(res, MXR_RESOLUTION, val); | 592 | mixer_reg_write(res, MXR_RESOLUTION, val); |
| 587 | } | 593 | } |
| 588 | 594 | ||
| 589 | val = MXR_GRP_WH_WIDTH(plane->src_width); | 595 | val = MXR_GRP_WH_WIDTH(plane->src_w); |
| 590 | val |= MXR_GRP_WH_HEIGHT(plane->src_height); | 596 | val |= MXR_GRP_WH_HEIGHT(plane->src_h); |
| 591 | val |= MXR_GRP_WH_H_SCALE(x_ratio); | 597 | val |= MXR_GRP_WH_H_SCALE(x_ratio); |
| 592 | val |= MXR_GRP_WH_V_SCALE(y_ratio); | 598 | val |= MXR_GRP_WH_V_SCALE(y_ratio); |
| 593 | mixer_reg_write(res, MXR_GRAPHIC_WH(win), val); | 599 | mixer_reg_write(res, MXR_GRAPHIC_WH(win), val); |
| @@ -605,8 +611,8 @@ static void mixer_graph_buffer(struct mixer_context *ctx, unsigned int win) | |||
| 605 | /* set buffer address to mixer */ | 611 | /* set buffer address to mixer */ |
| 606 | mixer_reg_write(res, MXR_GRAPHIC_BASE(win), dma_addr); | 612 | mixer_reg_write(res, MXR_GRAPHIC_BASE(win), dma_addr); |
| 607 | 613 | ||
| 608 | mixer_cfg_scan(ctx, plane->mode_height); | 614 | mixer_cfg_scan(ctx, mode->vdisplay); |
| 609 | mixer_cfg_rgb_fmt(ctx, plane->mode_height); | 615 | mixer_cfg_rgb_fmt(ctx, mode->vdisplay); |
| 610 | mixer_cfg_layer(ctx, win, true); | 616 | mixer_cfg_layer(ctx, win, true); |
| 611 | 617 | ||
| 612 | /* layer update mandatory for mixer 16.0.33.0 */ | 618 | /* layer update mandatory for mixer 16.0.33.0 */ |
| @@ -735,8 +741,8 @@ static irqreturn_t mixer_irq_handler(int irq, void *arg) | |||
| 735 | goto out; | 741 | goto out; |
| 736 | } | 742 | } |
| 737 | 743 | ||
| 738 | drm_handle_vblank(ctx->drm_dev, ctx->pipe); | 744 | drm_crtc_handle_vblank(&ctx->crtc->base); |
| 739 | exynos_drm_crtc_finish_pageflip(ctx->drm_dev, ctx->pipe); | 745 | exynos_drm_crtc_finish_pageflip(ctx->crtc); |
| 740 | 746 | ||
| 741 | /* set wait vsync event to zero and wake up queue. */ | 747 | /* set wait vsync event to zero and wake up queue. */ |
| 742 | if (atomic_read(&ctx->wait_vsync_event)) { | 748 | if (atomic_read(&ctx->wait_vsync_event)) { |
| @@ -881,8 +887,7 @@ static int mixer_initialize(struct mixer_context *mixer_ctx, | |||
| 881 | } | 887 | } |
| 882 | } | 888 | } |
| 883 | 889 | ||
| 884 | ret = drm_iommu_attach_device_if_possible(mixer_ctx->crtc, drm_dev, | 890 | ret = drm_iommu_attach_device(drm_dev, mixer_ctx->dev); |
| 885 | mixer_ctx->dev); | ||
| 886 | if (ret) | 891 | if (ret) |
| 887 | priv->pipe--; | 892 | priv->pipe--; |
| 888 | 893 | ||
| @@ -891,8 +896,7 @@ static int mixer_initialize(struct mixer_context *mixer_ctx, | |||
| 891 | 896 | ||
| 892 | static void mixer_ctx_remove(struct mixer_context *mixer_ctx) | 897 | static void mixer_ctx_remove(struct mixer_context *mixer_ctx) |
| 893 | { | 898 | { |
| 894 | if (is_drm_iommu_supported(mixer_ctx->drm_dev)) | 899 | drm_iommu_detach_device(mixer_ctx->drm_dev, mixer_ctx->dev); |
| 895 | drm_iommu_detach_device(mixer_ctx->drm_dev, mixer_ctx->dev); | ||
| 896 | } | 900 | } |
| 897 | 901 | ||
| 898 | static int mixer_enable_vblank(struct exynos_drm_crtc *crtc) | 902 | static int mixer_enable_vblank(struct exynos_drm_crtc *crtc) |
| @@ -900,10 +904,9 @@ static int mixer_enable_vblank(struct exynos_drm_crtc *crtc) | |||
| 900 | struct mixer_context *mixer_ctx = crtc->ctx; | 904 | struct mixer_context *mixer_ctx = crtc->ctx; |
| 901 | struct mixer_resources *res = &mixer_ctx->mixer_res; | 905 | struct mixer_resources *res = &mixer_ctx->mixer_res; |
| 902 | 906 | ||
| 903 | if (!mixer_ctx->powered) { | 907 | __set_bit(MXR_BIT_VSYNC, &mixer_ctx->flags); |
| 904 | mixer_ctx->int_en |= MXR_INT_EN_VSYNC; | 908 | if (!test_bit(MXR_BIT_POWERED, &mixer_ctx->flags)) |
| 905 | return 0; | 909 | return 0; |
| 906 | } | ||
| 907 | 910 | ||
| 908 | /* enable vsync interrupt */ | 911 | /* enable vsync interrupt */ |
| 909 | mixer_reg_writemask(res, MXR_INT_STATUS, ~0, MXR_INT_CLEAR_VSYNC); | 912 | mixer_reg_writemask(res, MXR_INT_STATUS, ~0, MXR_INT_CLEAR_VSYNC); |
| @@ -917,54 +920,48 @@ static void mixer_disable_vblank(struct exynos_drm_crtc *crtc) | |||
| 917 | struct mixer_context *mixer_ctx = crtc->ctx; | 920 | struct mixer_context *mixer_ctx = crtc->ctx; |
| 918 | struct mixer_resources *res = &mixer_ctx->mixer_res; | 921 | struct mixer_resources *res = &mixer_ctx->mixer_res; |
| 919 | 922 | ||
| 920 | if (!mixer_ctx->powered) { | 923 | __clear_bit(MXR_BIT_VSYNC, &mixer_ctx->flags); |
| 921 | mixer_ctx->int_en &= MXR_INT_EN_VSYNC; | 924 | |
| 925 | if (!test_bit(MXR_BIT_POWERED, &mixer_ctx->flags)) | ||
| 922 | return; | 926 | return; |
| 923 | } | ||
| 924 | 927 | ||
| 925 | /* disable vsync interrupt */ | 928 | /* disable vsync interrupt */ |
| 926 | mixer_reg_writemask(res, MXR_INT_STATUS, ~0, MXR_INT_CLEAR_VSYNC); | 929 | mixer_reg_writemask(res, MXR_INT_STATUS, ~0, MXR_INT_CLEAR_VSYNC); |
| 927 | mixer_reg_writemask(res, MXR_INT_EN, 0, MXR_INT_EN_VSYNC); | 930 | mixer_reg_writemask(res, MXR_INT_EN, 0, MXR_INT_EN_VSYNC); |
| 928 | } | 931 | } |
| 929 | 932 | ||
| 930 | static void mixer_win_commit(struct exynos_drm_crtc *crtc, unsigned int win) | 933 | static void mixer_update_plane(struct exynos_drm_crtc *crtc, |
| 934 | struct exynos_drm_plane *plane) | ||
| 931 | { | 935 | { |
| 932 | struct mixer_context *mixer_ctx = crtc->ctx; | 936 | struct mixer_context *mixer_ctx = crtc->ctx; |
| 933 | 937 | ||
| 934 | DRM_DEBUG_KMS("win: %d\n", win); | 938 | DRM_DEBUG_KMS("win: %d\n", plane->zpos); |
| 935 | 939 | ||
| 936 | mutex_lock(&mixer_ctx->mixer_mutex); | 940 | if (!test_bit(MXR_BIT_POWERED, &mixer_ctx->flags)) |
| 937 | if (!mixer_ctx->powered) { | ||
| 938 | mutex_unlock(&mixer_ctx->mixer_mutex); | ||
| 939 | return; | 941 | return; |
| 940 | } | ||
| 941 | mutex_unlock(&mixer_ctx->mixer_mutex); | ||
| 942 | 942 | ||
| 943 | if (win > 1 && mixer_ctx->vp_enabled) | 943 | if (plane->zpos > 1 && mixer_ctx->vp_enabled) |
| 944 | vp_video_buffer(mixer_ctx, win); | 944 | vp_video_buffer(mixer_ctx, plane); |
| 945 | else | 945 | else |
| 946 | mixer_graph_buffer(mixer_ctx, win); | 946 | mixer_graph_buffer(mixer_ctx, plane); |
| 947 | } | 947 | } |
| 948 | 948 | ||
| 949 | static void mixer_win_disable(struct exynos_drm_crtc *crtc, unsigned int win) | 949 | static void mixer_disable_plane(struct exynos_drm_crtc *crtc, |
| 950 | struct exynos_drm_plane *plane) | ||
| 950 | { | 951 | { |
| 951 | struct mixer_context *mixer_ctx = crtc->ctx; | 952 | struct mixer_context *mixer_ctx = crtc->ctx; |
| 952 | struct mixer_resources *res = &mixer_ctx->mixer_res; | 953 | struct mixer_resources *res = &mixer_ctx->mixer_res; |
| 953 | unsigned long flags; | 954 | unsigned long flags; |
| 954 | 955 | ||
| 955 | DRM_DEBUG_KMS("win: %d\n", win); | 956 | DRM_DEBUG_KMS("win: %d\n", plane->zpos); |
| 956 | 957 | ||
| 957 | mutex_lock(&mixer_ctx->mixer_mutex); | 958 | if (!test_bit(MXR_BIT_POWERED, &mixer_ctx->flags)) |
| 958 | if (!mixer_ctx->powered) { | ||
| 959 | mutex_unlock(&mixer_ctx->mixer_mutex); | ||
| 960 | return; | 959 | return; |
| 961 | } | ||
| 962 | mutex_unlock(&mixer_ctx->mixer_mutex); | ||
| 963 | 960 | ||
| 964 | spin_lock_irqsave(&res->reg_slock, flags); | 961 | spin_lock_irqsave(&res->reg_slock, flags); |
| 965 | mixer_vsync_set_update(mixer_ctx, false); | 962 | mixer_vsync_set_update(mixer_ctx, false); |
| 966 | 963 | ||
| 967 | mixer_cfg_layer(mixer_ctx, win, false); | 964 | mixer_cfg_layer(mixer_ctx, plane->zpos, false); |
| 968 | 965 | ||
| 969 | mixer_vsync_set_update(mixer_ctx, true); | 966 | mixer_vsync_set_update(mixer_ctx, true); |
| 970 | spin_unlock_irqrestore(&res->reg_slock, flags); | 967 | spin_unlock_irqrestore(&res->reg_slock, flags); |
| @@ -975,12 +972,8 @@ static void mixer_wait_for_vblank(struct exynos_drm_crtc *crtc) | |||
| 975 | struct mixer_context *mixer_ctx = crtc->ctx; | 972 | struct mixer_context *mixer_ctx = crtc->ctx; |
| 976 | int err; | 973 | int err; |
| 977 | 974 | ||
| 978 | mutex_lock(&mixer_ctx->mixer_mutex); | 975 | if (!test_bit(MXR_BIT_POWERED, &mixer_ctx->flags)) |
| 979 | if (!mixer_ctx->powered) { | ||
| 980 | mutex_unlock(&mixer_ctx->mixer_mutex); | ||
| 981 | return; | 976 | return; |
| 982 | } | ||
| 983 | mutex_unlock(&mixer_ctx->mixer_mutex); | ||
| 984 | 977 | ||
| 985 | err = drm_vblank_get(mixer_ctx->drm_dev, mixer_ctx->pipe); | 978 | err = drm_vblank_get(mixer_ctx->drm_dev, mixer_ctx->pipe); |
| 986 | if (err < 0) { | 979 | if (err < 0) { |
| @@ -1008,13 +1001,8 @@ static void mixer_enable(struct exynos_drm_crtc *crtc) | |||
| 1008 | struct mixer_resources *res = &ctx->mixer_res; | 1001 | struct mixer_resources *res = &ctx->mixer_res; |
| 1009 | int ret; | 1002 | int ret; |
| 1010 | 1003 | ||
| 1011 | mutex_lock(&ctx->mixer_mutex); | 1004 | if (test_bit(MXR_BIT_POWERED, &ctx->flags)) |
| 1012 | if (ctx->powered) { | ||
| 1013 | mutex_unlock(&ctx->mixer_mutex); | ||
| 1014 | return; | 1005 | return; |
| 1015 | } | ||
| 1016 | |||
| 1017 | mutex_unlock(&ctx->mixer_mutex); | ||
| 1018 | 1006 | ||
| 1019 | pm_runtime_get_sync(ctx->dev); | 1007 | pm_runtime_get_sync(ctx->dev); |
| 1020 | 1008 | ||
| @@ -1046,15 +1034,14 @@ static void mixer_enable(struct exynos_drm_crtc *crtc) | |||
| 1046 | } | 1034 | } |
| 1047 | } | 1035 | } |
| 1048 | 1036 | ||
| 1049 | mutex_lock(&ctx->mixer_mutex); | 1037 | set_bit(MXR_BIT_POWERED, &ctx->flags); |
| 1050 | ctx->powered = true; | ||
| 1051 | mutex_unlock(&ctx->mixer_mutex); | ||
| 1052 | 1038 | ||
| 1053 | mixer_reg_writemask(res, MXR_STATUS, ~0, MXR_STATUS_SOFT_RESET); | 1039 | mixer_reg_writemask(res, MXR_STATUS, ~0, MXR_STATUS_SOFT_RESET); |
| 1054 | 1040 | ||
| 1055 | if (ctx->int_en & MXR_INT_EN_VSYNC) | 1041 | if (test_bit(MXR_BIT_VSYNC, &ctx->flags)) { |
| 1056 | mixer_reg_writemask(res, MXR_INT_STATUS, ~0, MXR_INT_CLEAR_VSYNC); | 1042 | mixer_reg_writemask(res, MXR_INT_STATUS, ~0, MXR_INT_CLEAR_VSYNC); |
| 1057 | mixer_reg_write(res, MXR_INT_EN, ctx->int_en); | 1043 | mixer_reg_writemask(res, MXR_INT_EN, ~0, MXR_INT_EN_VSYNC); |
| 1044 | } | ||
| 1058 | mixer_win_reset(ctx); | 1045 | mixer_win_reset(ctx); |
| 1059 | } | 1046 | } |
| 1060 | 1047 | ||
| @@ -1064,24 +1051,16 @@ static void mixer_disable(struct exynos_drm_crtc *crtc) | |||
| 1064 | struct mixer_resources *res = &ctx->mixer_res; | 1051 | struct mixer_resources *res = &ctx->mixer_res; |
| 1065 | int i; | 1052 | int i; |
| 1066 | 1053 | ||
| 1067 | mutex_lock(&ctx->mixer_mutex); | 1054 | if (!test_bit(MXR_BIT_POWERED, &ctx->flags)) |
| 1068 | if (!ctx->powered) { | ||
| 1069 | mutex_unlock(&ctx->mixer_mutex); | ||
| 1070 | return; | 1055 | return; |
| 1071 | } | ||
| 1072 | mutex_unlock(&ctx->mixer_mutex); | ||
| 1073 | 1056 | ||
| 1074 | mixer_stop(ctx); | 1057 | mixer_stop(ctx); |
| 1075 | mixer_regs_dump(ctx); | 1058 | mixer_regs_dump(ctx); |
| 1076 | 1059 | ||
| 1077 | for (i = 0; i < MIXER_WIN_NR; i++) | 1060 | for (i = 0; i < MIXER_WIN_NR; i++) |
| 1078 | mixer_win_disable(crtc, i); | 1061 | mixer_disable_plane(crtc, &ctx->planes[i]); |
| 1079 | 1062 | ||
| 1080 | ctx->int_en = mixer_reg_read(res, MXR_INT_EN); | 1063 | clear_bit(MXR_BIT_POWERED, &ctx->flags); |
| 1081 | |||
| 1082 | mutex_lock(&ctx->mixer_mutex); | ||
| 1083 | ctx->powered = false; | ||
| 1084 | mutex_unlock(&ctx->mixer_mutex); | ||
| 1085 | 1064 | ||
| 1086 | clk_disable_unprepare(res->hdmi); | 1065 | clk_disable_unprepare(res->hdmi); |
| 1087 | clk_disable_unprepare(res->mixer); | 1066 | clk_disable_unprepare(res->mixer); |
| @@ -1120,8 +1099,8 @@ static const struct exynos_drm_crtc_ops mixer_crtc_ops = { | |||
| 1120 | .enable_vblank = mixer_enable_vblank, | 1099 | .enable_vblank = mixer_enable_vblank, |
| 1121 | .disable_vblank = mixer_disable_vblank, | 1100 | .disable_vblank = mixer_disable_vblank, |
| 1122 | .wait_for_vblank = mixer_wait_for_vblank, | 1101 | .wait_for_vblank = mixer_wait_for_vblank, |
| 1123 | .win_commit = mixer_win_commit, | 1102 | .update_plane = mixer_update_plane, |
| 1124 | .win_disable = mixer_win_disable, | 1103 | .disable_plane = mixer_disable_plane, |
| 1125 | }; | 1104 | }; |
| 1126 | 1105 | ||
| 1127 | static struct mixer_drv_data exynos5420_mxr_drv_data = { | 1106 | static struct mixer_drv_data exynos5420_mxr_drv_data = { |
| @@ -1243,8 +1222,6 @@ static int mixer_probe(struct platform_device *pdev) | |||
| 1243 | return -ENOMEM; | 1222 | return -ENOMEM; |
| 1244 | } | 1223 | } |
| 1245 | 1224 | ||
| 1246 | mutex_init(&ctx->mixer_mutex); | ||
| 1247 | |||
| 1248 | if (dev->of_node) { | 1225 | if (dev->of_node) { |
| 1249 | const struct of_device_id *match; | 1226 | const struct of_device_id *match; |
| 1250 | 1227 | ||
