diff options
Diffstat (limited to 'drivers/gpu/drm/exynos/exynos_drm_fimd.c')
-rw-r--r-- | drivers/gpu/drm/exynos/exynos_drm_fimd.c | 71 |
1 files changed, 53 insertions, 18 deletions
diff --git a/drivers/gpu/drm/exynos/exynos_drm_fimd.c b/drivers/gpu/drm/exynos/exynos_drm_fimd.c index 4659c88cdd9..db3b3d9e731 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_fimd.c +++ b/drivers/gpu/drm/exynos/exynos_drm_fimd.c | |||
@@ -64,7 +64,7 @@ struct fimd_win_data { | |||
64 | unsigned int fb_width; | 64 | unsigned int fb_width; |
65 | unsigned int fb_height; | 65 | unsigned int fb_height; |
66 | unsigned int bpp; | 66 | unsigned int bpp; |
67 | dma_addr_t paddr; | 67 | dma_addr_t dma_addr; |
68 | void __iomem *vaddr; | 68 | void __iomem *vaddr; |
69 | unsigned int buf_offsize; | 69 | unsigned int buf_offsize; |
70 | unsigned int line_size; /* bytes */ | 70 | unsigned int line_size; /* bytes */ |
@@ -124,7 +124,7 @@ static int fimd_display_power_on(struct device *dev, int mode) | |||
124 | return 0; | 124 | return 0; |
125 | } | 125 | } |
126 | 126 | ||
127 | static struct exynos_drm_display fimd_display = { | 127 | static struct exynos_drm_display_ops fimd_display_ops = { |
128 | .type = EXYNOS_DISPLAY_TYPE_LCD, | 128 | .type = EXYNOS_DISPLAY_TYPE_LCD, |
129 | .is_connected = fimd_display_is_connected, | 129 | .is_connected = fimd_display_is_connected, |
130 | .get_timing = fimd_get_timing, | 130 | .get_timing = fimd_get_timing, |
@@ -177,6 +177,40 @@ static void fimd_commit(struct device *dev) | |||
177 | writel(val, ctx->regs + VIDCON0); | 177 | writel(val, ctx->regs + VIDCON0); |
178 | } | 178 | } |
179 | 179 | ||
180 | static void fimd_disable(struct device *dev) | ||
181 | { | ||
182 | struct fimd_context *ctx = get_fimd_context(dev); | ||
183 | struct exynos_drm_subdrv *subdrv = &ctx->subdrv; | ||
184 | struct drm_device *drm_dev = subdrv->drm_dev; | ||
185 | struct exynos_drm_manager *manager = &subdrv->manager; | ||
186 | u32 val; | ||
187 | |||
188 | DRM_DEBUG_KMS("%s\n", __FILE__); | ||
189 | |||
190 | /* fimd dma off */ | ||
191 | val = readl(ctx->regs + VIDCON0); | ||
192 | val &= ~(VIDCON0_ENVID | VIDCON0_ENVID_F); | ||
193 | writel(val, ctx->regs + VIDCON0); | ||
194 | |||
195 | /* | ||
196 | * if vblank is enabled status with dma off then | ||
197 | * it disables vsync interrupt. | ||
198 | */ | ||
199 | if (drm_dev->vblank_enabled[manager->pipe] && | ||
200 | atomic_read(&drm_dev->vblank_refcount[manager->pipe])) { | ||
201 | drm_vblank_put(drm_dev, manager->pipe); | ||
202 | |||
203 | /* | ||
204 | * if vblank_disable_allowed is 0 then disable | ||
205 | * vsync interrupt right now else the vsync interrupt | ||
206 | * would be disabled by drm timer once a current process | ||
207 | * gives up ownershop of vblank event. | ||
208 | */ | ||
209 | if (!drm_dev->vblank_disable_allowed) | ||
210 | drm_vblank_off(drm_dev, manager->pipe); | ||
211 | } | ||
212 | } | ||
213 | |||
180 | static int fimd_enable_vblank(struct device *dev) | 214 | static int fimd_enable_vblank(struct device *dev) |
181 | { | 215 | { |
182 | struct fimd_context *ctx = get_fimd_context(dev); | 216 | struct fimd_context *ctx = get_fimd_context(dev); |
@@ -220,6 +254,7 @@ static void fimd_disable_vblank(struct device *dev) | |||
220 | 254 | ||
221 | static struct exynos_drm_manager_ops fimd_manager_ops = { | 255 | static struct exynos_drm_manager_ops fimd_manager_ops = { |
222 | .commit = fimd_commit, | 256 | .commit = fimd_commit, |
257 | .disable = fimd_disable, | ||
223 | .enable_vblank = fimd_enable_vblank, | 258 | .enable_vblank = fimd_enable_vblank, |
224 | .disable_vblank = fimd_disable_vblank, | 259 | .disable_vblank = fimd_disable_vblank, |
225 | }; | 260 | }; |
@@ -251,7 +286,7 @@ static void fimd_win_mode_set(struct device *dev, | |||
251 | win_data->ovl_height = overlay->crtc_height; | 286 | win_data->ovl_height = overlay->crtc_height; |
252 | win_data->fb_width = overlay->fb_width; | 287 | win_data->fb_width = overlay->fb_width; |
253 | win_data->fb_height = overlay->fb_height; | 288 | win_data->fb_height = overlay->fb_height; |
254 | win_data->paddr = overlay->paddr + offset; | 289 | win_data->dma_addr = overlay->dma_addr + offset; |
255 | win_data->vaddr = overlay->vaddr + offset; | 290 | win_data->vaddr = overlay->vaddr + offset; |
256 | win_data->bpp = overlay->bpp; | 291 | win_data->bpp = overlay->bpp; |
257 | win_data->buf_offsize = (overlay->fb_width - overlay->crtc_width) * | 292 | win_data->buf_offsize = (overlay->fb_width - overlay->crtc_width) * |
@@ -263,7 +298,7 @@ static void fimd_win_mode_set(struct device *dev, | |||
263 | DRM_DEBUG_KMS("ovl_width = %d, ovl_height = %d\n", | 298 | DRM_DEBUG_KMS("ovl_width = %d, ovl_height = %d\n", |
264 | win_data->ovl_width, win_data->ovl_height); | 299 | win_data->ovl_width, win_data->ovl_height); |
265 | DRM_DEBUG_KMS("paddr = 0x%lx, vaddr = 0x%lx\n", | 300 | DRM_DEBUG_KMS("paddr = 0x%lx, vaddr = 0x%lx\n", |
266 | (unsigned long)win_data->paddr, | 301 | (unsigned long)win_data->dma_addr, |
267 | (unsigned long)win_data->vaddr); | 302 | (unsigned long)win_data->vaddr); |
268 | DRM_DEBUG_KMS("fb_width = %d, crtc_width = %d\n", | 303 | DRM_DEBUG_KMS("fb_width = %d, crtc_width = %d\n", |
269 | overlay->fb_width, overlay->crtc_width); | 304 | overlay->fb_width, overlay->crtc_width); |
@@ -376,16 +411,16 @@ static void fimd_win_commit(struct device *dev) | |||
376 | writel(val, ctx->regs + SHADOWCON); | 411 | writel(val, ctx->regs + SHADOWCON); |
377 | 412 | ||
378 | /* buffer start address */ | 413 | /* buffer start address */ |
379 | val = win_data->paddr; | 414 | val = (unsigned long)win_data->dma_addr; |
380 | writel(val, ctx->regs + VIDWx_BUF_START(win, 0)); | 415 | writel(val, ctx->regs + VIDWx_BUF_START(win, 0)); |
381 | 416 | ||
382 | /* buffer end address */ | 417 | /* buffer end address */ |
383 | size = win_data->fb_width * win_data->ovl_height * (win_data->bpp >> 3); | 418 | size = win_data->fb_width * win_data->ovl_height * (win_data->bpp >> 3); |
384 | val = win_data->paddr + size; | 419 | val = (unsigned long)(win_data->dma_addr + size); |
385 | writel(val, ctx->regs + VIDWx_BUF_END(win, 0)); | 420 | writel(val, ctx->regs + VIDWx_BUF_END(win, 0)); |
386 | 421 | ||
387 | DRM_DEBUG_KMS("start addr = 0x%lx, end addr = 0x%lx, size = 0x%lx\n", | 422 | DRM_DEBUG_KMS("start addr = 0x%lx, end addr = 0x%lx, size = 0x%lx\n", |
388 | (unsigned long)win_data->paddr, val, size); | 423 | (unsigned long)win_data->dma_addr, val, size); |
389 | DRM_DEBUG_KMS("ovl_width = %d, ovl_height = %d\n", | 424 | DRM_DEBUG_KMS("ovl_width = %d, ovl_height = %d\n", |
390 | win_data->ovl_width, win_data->ovl_height); | 425 | win_data->ovl_width, win_data->ovl_height); |
391 | 426 | ||
@@ -447,7 +482,6 @@ static void fimd_win_commit(struct device *dev) | |||
447 | static void fimd_win_disable(struct device *dev) | 482 | static void fimd_win_disable(struct device *dev) |
448 | { | 483 | { |
449 | struct fimd_context *ctx = get_fimd_context(dev); | 484 | struct fimd_context *ctx = get_fimd_context(dev); |
450 | struct fimd_win_data *win_data; | ||
451 | int win = ctx->default_win; | 485 | int win = ctx->default_win; |
452 | u32 val; | 486 | u32 val; |
453 | 487 | ||
@@ -456,8 +490,6 @@ static void fimd_win_disable(struct device *dev) | |||
456 | if (win < 0 || win > WINDOWS_NR) | 490 | if (win < 0 || win > WINDOWS_NR) |
457 | return; | 491 | return; |
458 | 492 | ||
459 | win_data = &ctx->win_data[win]; | ||
460 | |||
461 | /* protect windows */ | 493 | /* protect windows */ |
462 | val = readl(ctx->regs + SHADOWCON); | 494 | val = readl(ctx->regs + SHADOWCON); |
463 | val |= SHADOWCON_WINx_PROTECT(win); | 495 | val |= SHADOWCON_WINx_PROTECT(win); |
@@ -528,6 +560,16 @@ static irqreturn_t fimd_irq_handler(int irq, void *dev_id) | |||
528 | /* VSYNC interrupt */ | 560 | /* VSYNC interrupt */ |
529 | writel(VIDINTCON1_INT_FRAME, ctx->regs + VIDINTCON1); | 561 | writel(VIDINTCON1_INT_FRAME, ctx->regs + VIDINTCON1); |
530 | 562 | ||
563 | /* | ||
564 | * in case that vblank_disable_allowed is 1, it could induce | ||
565 | * the problem that manager->pipe could be -1 because with | ||
566 | * disable callback, vsync interrupt isn't disabled and at this moment, | ||
567 | * vsync interrupt could occur. the vsync interrupt would be disabled | ||
568 | * by timer handler later. | ||
569 | */ | ||
570 | if (manager->pipe == -1) | ||
571 | return IRQ_HANDLED; | ||
572 | |||
531 | drm_handle_vblank(drm_dev, manager->pipe); | 573 | drm_handle_vblank(drm_dev, manager->pipe); |
532 | fimd_finish_pageflip(drm_dev, manager->pipe); | 574 | fimd_finish_pageflip(drm_dev, manager->pipe); |
533 | 575 | ||
@@ -548,13 +590,6 @@ static int fimd_subdrv_probe(struct drm_device *drm_dev, struct device *dev) | |||
548 | */ | 590 | */ |
549 | drm_dev->irq_enabled = 1; | 591 | drm_dev->irq_enabled = 1; |
550 | 592 | ||
551 | /* | ||
552 | * with vblank_disable_allowed = 1, vblank interrupt will be disabled | ||
553 | * by drm timer once a current process gives up ownership of | ||
554 | * vblank event.(drm_vblank_put function was called) | ||
555 | */ | ||
556 | drm_dev->vblank_disable_allowed = 1; | ||
557 | |||
558 | return 0; | 593 | return 0; |
559 | } | 594 | } |
560 | 595 | ||
@@ -731,7 +766,7 @@ static int __devinit fimd_probe(struct platform_device *pdev) | |||
731 | subdrv->manager.pipe = -1; | 766 | subdrv->manager.pipe = -1; |
732 | subdrv->manager.ops = &fimd_manager_ops; | 767 | subdrv->manager.ops = &fimd_manager_ops; |
733 | subdrv->manager.overlay_ops = &fimd_overlay_ops; | 768 | subdrv->manager.overlay_ops = &fimd_overlay_ops; |
734 | subdrv->manager.display = &fimd_display; | 769 | subdrv->manager.display_ops = &fimd_display_ops; |
735 | subdrv->manager.dev = dev; | 770 | subdrv->manager.dev = dev; |
736 | 771 | ||
737 | platform_set_drvdata(pdev, ctx); | 772 | platform_set_drvdata(pdev, ctx); |