diff options
author | Dave Airlie <airlied@redhat.com> | 2015-03-19 00:05:53 -0400 |
---|---|---|
committer | Dave Airlie <airlied@redhat.com> | 2015-03-19 00:05:53 -0400 |
commit | 6b94aea01d4f96235e947892f6c39f837045e741 (patch) | |
tree | f0597c10cae2e1102fad291336bc818214e98942 | |
parent | d79dc0a9baef6ba909ac9e8da095524046523d6a (diff) | |
parent | 1067219b27e29e925e7bdbb85b72c4c2bec0267e (diff) |
Merge branch 'drm_next' of https://github.com/markyzq/kernel-drm-rockchip into drm-next
rockchip fixes.
* 'drm_next' of https://github.com/markyzq/kernel-drm-rockchip:
drm/rockchip: vop: power off until vop standby take effect
drm/rockchip: vop: set vop enabled after enable iommu
drm/rockchip: vop use is_enabled instead of dpms mode
drm/rockchip: vop: fix vop vsync/hsync polarity
drm/rockchip: Only alloc a kmap for fbdev gem object
-rw-r--r-- | drivers/gpu/drm/rockchip/rockchip_drm_fbdev.c | 2 | ||||
-rw-r--r-- | drivers/gpu/drm/rockchip/rockchip_drm_gem.c | 17 | ||||
-rw-r--r-- | drivers/gpu/drm/rockchip/rockchip_drm_gem.h | 3 | ||||
-rw-r--r-- | drivers/gpu/drm/rockchip/rockchip_drm_vop.c | 118 |
4 files changed, 102 insertions, 38 deletions
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_fbdev.c b/drivers/gpu/drm/rockchip/rockchip_drm_fbdev.c index ff04877e837c..d5c1248916b2 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_fbdev.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_fbdev.c | |||
@@ -71,7 +71,7 @@ static int rockchip_drm_fbdev_create(struct drm_fb_helper *helper, | |||
71 | 71 | ||
72 | size = mode_cmd.pitches[0] * mode_cmd.height; | 72 | size = mode_cmd.pitches[0] * mode_cmd.height; |
73 | 73 | ||
74 | rk_obj = rockchip_gem_create_object(dev, size); | 74 | rk_obj = rockchip_gem_create_object(dev, size, true); |
75 | if (IS_ERR(rk_obj)) | 75 | if (IS_ERR(rk_obj)) |
76 | return -ENOMEM; | 76 | return -ENOMEM; |
77 | 77 | ||
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_gem.c b/drivers/gpu/drm/rockchip/rockchip_drm_gem.c index 7ca8799ef784..eb2282cc4a56 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_gem.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_gem.c | |||
@@ -22,7 +22,8 @@ | |||
22 | #include "rockchip_drm_drv.h" | 22 | #include "rockchip_drm_drv.h" |
23 | #include "rockchip_drm_gem.h" | 23 | #include "rockchip_drm_gem.h" |
24 | 24 | ||
25 | static int rockchip_gem_alloc_buf(struct rockchip_gem_object *rk_obj) | 25 | static int rockchip_gem_alloc_buf(struct rockchip_gem_object *rk_obj, |
26 | bool alloc_kmap) | ||
26 | { | 27 | { |
27 | struct drm_gem_object *obj = &rk_obj->base; | 28 | struct drm_gem_object *obj = &rk_obj->base; |
28 | struct drm_device *drm = obj->dev; | 29 | struct drm_device *drm = obj->dev; |
@@ -30,7 +31,9 @@ static int rockchip_gem_alloc_buf(struct rockchip_gem_object *rk_obj) | |||
30 | init_dma_attrs(&rk_obj->dma_attrs); | 31 | init_dma_attrs(&rk_obj->dma_attrs); |
31 | dma_set_attr(DMA_ATTR_WRITE_COMBINE, &rk_obj->dma_attrs); | 32 | dma_set_attr(DMA_ATTR_WRITE_COMBINE, &rk_obj->dma_attrs); |
32 | 33 | ||
33 | /* TODO(djkurtz): Use DMA_ATTR_NO_KERNEL_MAPPING except for fbdev */ | 34 | if (!alloc_kmap) |
35 | dma_set_attr(DMA_ATTR_NO_KERNEL_MAPPING, &rk_obj->dma_attrs); | ||
36 | |||
34 | rk_obj->kvaddr = dma_alloc_attrs(drm->dev, obj->size, | 37 | rk_obj->kvaddr = dma_alloc_attrs(drm->dev, obj->size, |
35 | &rk_obj->dma_addr, GFP_KERNEL, | 38 | &rk_obj->dma_addr, GFP_KERNEL, |
36 | &rk_obj->dma_attrs); | 39 | &rk_obj->dma_attrs); |
@@ -103,7 +106,8 @@ int rockchip_gem_mmap(struct file *filp, struct vm_area_struct *vma) | |||
103 | } | 106 | } |
104 | 107 | ||
105 | struct rockchip_gem_object * | 108 | struct rockchip_gem_object * |
106 | rockchip_gem_create_object(struct drm_device *drm, unsigned int size) | 109 | rockchip_gem_create_object(struct drm_device *drm, unsigned int size, |
110 | bool alloc_kmap) | ||
107 | { | 111 | { |
108 | struct rockchip_gem_object *rk_obj; | 112 | struct rockchip_gem_object *rk_obj; |
109 | struct drm_gem_object *obj; | 113 | struct drm_gem_object *obj; |
@@ -119,7 +123,7 @@ struct rockchip_gem_object * | |||
119 | 123 | ||
120 | drm_gem_private_object_init(drm, obj, size); | 124 | drm_gem_private_object_init(drm, obj, size); |
121 | 125 | ||
122 | ret = rockchip_gem_alloc_buf(rk_obj); | 126 | ret = rockchip_gem_alloc_buf(rk_obj, alloc_kmap); |
123 | if (ret) | 127 | if (ret) |
124 | goto err_free_rk_obj; | 128 | goto err_free_rk_obj; |
125 | 129 | ||
@@ -163,7 +167,7 @@ rockchip_gem_create_with_handle(struct drm_file *file_priv, | |||
163 | struct drm_gem_object *obj; | 167 | struct drm_gem_object *obj; |
164 | int ret; | 168 | int ret; |
165 | 169 | ||
166 | rk_obj = rockchip_gem_create_object(drm, size); | 170 | rk_obj = rockchip_gem_create_object(drm, size, false); |
167 | if (IS_ERR(rk_obj)) | 171 | if (IS_ERR(rk_obj)) |
168 | return ERR_CAST(rk_obj); | 172 | return ERR_CAST(rk_obj); |
169 | 173 | ||
@@ -282,6 +286,9 @@ void *rockchip_gem_prime_vmap(struct drm_gem_object *obj) | |||
282 | { | 286 | { |
283 | struct rockchip_gem_object *rk_obj = to_rockchip_obj(obj); | 287 | struct rockchip_gem_object *rk_obj = to_rockchip_obj(obj); |
284 | 288 | ||
289 | if (dma_get_attr(DMA_ATTR_NO_KERNEL_MAPPING, &rk_obj->dma_attrs)) | ||
290 | return NULL; | ||
291 | |||
285 | return rk_obj->kvaddr; | 292 | return rk_obj->kvaddr; |
286 | } | 293 | } |
287 | 294 | ||
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_gem.h b/drivers/gpu/drm/rockchip/rockchip_drm_gem.h index 67bcebe90003..ad22618473a4 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_gem.h +++ b/drivers/gpu/drm/rockchip/rockchip_drm_gem.h | |||
@@ -41,7 +41,8 @@ int rockchip_gem_mmap_buf(struct drm_gem_object *obj, | |||
41 | struct vm_area_struct *vma); | 41 | struct vm_area_struct *vma); |
42 | 42 | ||
43 | struct rockchip_gem_object * | 43 | struct rockchip_gem_object * |
44 | rockchip_gem_create_object(struct drm_device *drm, unsigned int size); | 44 | rockchip_gem_create_object(struct drm_device *drm, unsigned int size, |
45 | bool alloc_kmap); | ||
45 | 46 | ||
46 | void rockchip_gem_free_object(struct drm_gem_object *obj); | 47 | void rockchip_gem_free_object(struct drm_gem_object *obj); |
47 | 48 | ||
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c index 9a5c571b95fc..d041921b3bb9 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c | |||
@@ -81,7 +81,7 @@ struct vop { | |||
81 | struct drm_crtc crtc; | 81 | struct drm_crtc crtc; |
82 | struct device *dev; | 82 | struct device *dev; |
83 | struct drm_device *drm_dev; | 83 | struct drm_device *drm_dev; |
84 | unsigned int dpms; | 84 | bool is_enabled; |
85 | 85 | ||
86 | int connector_type; | 86 | int connector_type; |
87 | int connector_out_mode; | 87 | int connector_out_mode; |
@@ -89,6 +89,7 @@ struct vop { | |||
89 | /* mutex vsync_ work */ | 89 | /* mutex vsync_ work */ |
90 | struct mutex vsync_mutex; | 90 | struct mutex vsync_mutex; |
91 | bool vsync_work_pending; | 91 | bool vsync_work_pending; |
92 | struct completion dsp_hold_completion; | ||
92 | 93 | ||
93 | const struct vop_data *data; | 94 | const struct vop_data *data; |
94 | 95 | ||
@@ -382,11 +383,44 @@ static bool is_alpha_support(uint32_t format) | |||
382 | } | 383 | } |
383 | } | 384 | } |
384 | 385 | ||
386 | static void vop_dsp_hold_valid_irq_enable(struct vop *vop) | ||
387 | { | ||
388 | unsigned long flags; | ||
389 | |||
390 | if (WARN_ON(!vop->is_enabled)) | ||
391 | return; | ||
392 | |||
393 | spin_lock_irqsave(&vop->irq_lock, flags); | ||
394 | |||
395 | vop_mask_write(vop, INTR_CTRL0, DSP_HOLD_VALID_INTR_MASK, | ||
396 | DSP_HOLD_VALID_INTR_EN(1)); | ||
397 | |||
398 | spin_unlock_irqrestore(&vop->irq_lock, flags); | ||
399 | } | ||
400 | |||
401 | static void vop_dsp_hold_valid_irq_disable(struct vop *vop) | ||
402 | { | ||
403 | unsigned long flags; | ||
404 | |||
405 | if (WARN_ON(!vop->is_enabled)) | ||
406 | return; | ||
407 | |||
408 | spin_lock_irqsave(&vop->irq_lock, flags); | ||
409 | |||
410 | vop_mask_write(vop, INTR_CTRL0, DSP_HOLD_VALID_INTR_MASK, | ||
411 | DSP_HOLD_VALID_INTR_EN(0)); | ||
412 | |||
413 | spin_unlock_irqrestore(&vop->irq_lock, flags); | ||
414 | } | ||
415 | |||
385 | static void vop_enable(struct drm_crtc *crtc) | 416 | static void vop_enable(struct drm_crtc *crtc) |
386 | { | 417 | { |
387 | struct vop *vop = to_vop(crtc); | 418 | struct vop *vop = to_vop(crtc); |
388 | int ret; | 419 | int ret; |
389 | 420 | ||
421 | if (vop->is_enabled) | ||
422 | return; | ||
423 | |||
390 | ret = clk_enable(vop->hclk); | 424 | ret = clk_enable(vop->hclk); |
391 | if (ret < 0) { | 425 | if (ret < 0) { |
392 | dev_err(vop->dev, "failed to enable hclk - %d\n", ret); | 426 | dev_err(vop->dev, "failed to enable hclk - %d\n", ret); |
@@ -417,6 +451,11 @@ static void vop_enable(struct drm_crtc *crtc) | |||
417 | goto err_disable_aclk; | 451 | goto err_disable_aclk; |
418 | } | 452 | } |
419 | 453 | ||
454 | /* | ||
455 | * At here, vop clock & iommu is enable, R/W vop regs would be safe. | ||
456 | */ | ||
457 | vop->is_enabled = true; | ||
458 | |||
420 | spin_lock(&vop->reg_lock); | 459 | spin_lock(&vop->reg_lock); |
421 | 460 | ||
422 | VOP_CTRL_SET(vop, standby, 0); | 461 | VOP_CTRL_SET(vop, standby, 0); |
@@ -441,26 +480,41 @@ static void vop_disable(struct drm_crtc *crtc) | |||
441 | { | 480 | { |
442 | struct vop *vop = to_vop(crtc); | 481 | struct vop *vop = to_vop(crtc); |
443 | 482 | ||
444 | drm_vblank_off(crtc->dev, vop->pipe); | 483 | if (!vop->is_enabled) |
484 | return; | ||
445 | 485 | ||
446 | disable_irq(vop->irq); | 486 | drm_vblank_off(crtc->dev, vop->pipe); |
447 | 487 | ||
448 | /* | 488 | /* |
449 | * TODO: Since standby doesn't take effect until the next vblank, | 489 | * Vop standby will take effect at end of current frame, |
450 | * when we turn off dclk below, the vop is probably still active. | 490 | * if dsp hold valid irq happen, it means standby complete. |
491 | * | ||
492 | * we must wait standby complete when we want to disable aclk, | ||
493 | * if not, memory bus maybe dead. | ||
451 | */ | 494 | */ |
495 | reinit_completion(&vop->dsp_hold_completion); | ||
496 | vop_dsp_hold_valid_irq_enable(vop); | ||
497 | |||
452 | spin_lock(&vop->reg_lock); | 498 | spin_lock(&vop->reg_lock); |
453 | 499 | ||
454 | VOP_CTRL_SET(vop, standby, 1); | 500 | VOP_CTRL_SET(vop, standby, 1); |
455 | 501 | ||
456 | spin_unlock(&vop->reg_lock); | 502 | spin_unlock(&vop->reg_lock); |
503 | |||
504 | wait_for_completion(&vop->dsp_hold_completion); | ||
505 | |||
506 | vop_dsp_hold_valid_irq_disable(vop); | ||
507 | |||
508 | disable_irq(vop->irq); | ||
509 | |||
510 | vop->is_enabled = false; | ||
511 | |||
457 | /* | 512 | /* |
458 | * disable dclk to stop frame scan, so we can safely detach iommu, | 513 | * vop standby complete, so iommu detach is safe. |
459 | */ | 514 | */ |
460 | clk_disable(vop->dclk); | ||
461 | |||
462 | rockchip_drm_dma_detach_device(vop->drm_dev, vop->dev); | 515 | rockchip_drm_dma_detach_device(vop->drm_dev, vop->dev); |
463 | 516 | ||
517 | clk_disable(vop->dclk); | ||
464 | clk_disable(vop->aclk); | 518 | clk_disable(vop->aclk); |
465 | clk_disable(vop->hclk); | 519 | clk_disable(vop->hclk); |
466 | } | 520 | } |
@@ -742,7 +796,7 @@ static int vop_crtc_enable_vblank(struct drm_crtc *crtc) | |||
742 | struct vop *vop = to_vop(crtc); | 796 | struct vop *vop = to_vop(crtc); |
743 | unsigned long flags; | 797 | unsigned long flags; |
744 | 798 | ||
745 | if (vop->dpms != DRM_MODE_DPMS_ON) | 799 | if (!vop->is_enabled) |
746 | return -EPERM; | 800 | return -EPERM; |
747 | 801 | ||
748 | spin_lock_irqsave(&vop->irq_lock, flags); | 802 | spin_lock_irqsave(&vop->irq_lock, flags); |
@@ -759,8 +813,9 @@ static void vop_crtc_disable_vblank(struct drm_crtc *crtc) | |||
759 | struct vop *vop = to_vop(crtc); | 813 | struct vop *vop = to_vop(crtc); |
760 | unsigned long flags; | 814 | unsigned long flags; |
761 | 815 | ||
762 | if (vop->dpms != DRM_MODE_DPMS_ON) | 816 | if (!vop->is_enabled) |
763 | return; | 817 | return; |
818 | |||
764 | spin_lock_irqsave(&vop->irq_lock, flags); | 819 | spin_lock_irqsave(&vop->irq_lock, flags); |
765 | vop_mask_write(vop, INTR_CTRL0, FS_INTR_MASK, FS_INTR_EN(0)); | 820 | vop_mask_write(vop, INTR_CTRL0, FS_INTR_MASK, FS_INTR_EN(0)); |
766 | spin_unlock_irqrestore(&vop->irq_lock, flags); | 821 | spin_unlock_irqrestore(&vop->irq_lock, flags); |
@@ -773,15 +828,8 @@ static const struct rockchip_crtc_funcs private_crtc_funcs = { | |||
773 | 828 | ||
774 | static void vop_crtc_dpms(struct drm_crtc *crtc, int mode) | 829 | static void vop_crtc_dpms(struct drm_crtc *crtc, int mode) |
775 | { | 830 | { |
776 | struct vop *vop = to_vop(crtc); | ||
777 | |||
778 | DRM_DEBUG_KMS("crtc[%d] mode[%d]\n", crtc->base.id, mode); | 831 | DRM_DEBUG_KMS("crtc[%d] mode[%d]\n", crtc->base.id, mode); |
779 | 832 | ||
780 | if (vop->dpms == mode) { | ||
781 | DRM_DEBUG_KMS("desired dpms mode is same as previous one.\n"); | ||
782 | return; | ||
783 | } | ||
784 | |||
785 | switch (mode) { | 833 | switch (mode) { |
786 | case DRM_MODE_DPMS_ON: | 834 | case DRM_MODE_DPMS_ON: |
787 | vop_enable(crtc); | 835 | vop_enable(crtc); |
@@ -795,8 +843,6 @@ static void vop_crtc_dpms(struct drm_crtc *crtc, int mode) | |||
795 | DRM_DEBUG_KMS("unspecified mode %d\n", mode); | 843 | DRM_DEBUG_KMS("unspecified mode %d\n", mode); |
796 | break; | 844 | break; |
797 | } | 845 | } |
798 | |||
799 | vop->dpms = mode; | ||
800 | } | 846 | } |
801 | 847 | ||
802 | static void vop_crtc_prepare(struct drm_crtc *crtc) | 848 | static void vop_crtc_prepare(struct drm_crtc *crtc) |
@@ -874,8 +920,8 @@ static int vop_crtc_mode_set(struct drm_crtc *crtc, | |||
874 | VOP_CTRL_SET(vop, out_mode, vop->connector_out_mode); | 920 | VOP_CTRL_SET(vop, out_mode, vop->connector_out_mode); |
875 | 921 | ||
876 | val = 0x8; | 922 | val = 0x8; |
877 | val |= (adjusted_mode->flags & DRM_MODE_FLAG_NHSYNC) ? 1 : 0; | 923 | val |= (adjusted_mode->flags & DRM_MODE_FLAG_NHSYNC) ? 0 : 1; |
878 | val |= (adjusted_mode->flags & DRM_MODE_FLAG_NVSYNC) ? (1 << 1) : 0; | 924 | val |= (adjusted_mode->flags & DRM_MODE_FLAG_NVSYNC) ? 0 : (1 << 1); |
879 | VOP_CTRL_SET(vop, pin_pol, val); | 925 | VOP_CTRL_SET(vop, pin_pol, val); |
880 | 926 | ||
881 | VOP_CTRL_SET(vop, htotal_pw, (htotal << 16) | hsync_len); | 927 | VOP_CTRL_SET(vop, htotal_pw, (htotal << 16) | hsync_len); |
@@ -934,9 +980,9 @@ static int vop_crtc_page_flip(struct drm_crtc *crtc, | |||
934 | struct drm_framebuffer *old_fb = crtc->primary->fb; | 980 | struct drm_framebuffer *old_fb = crtc->primary->fb; |
935 | int ret; | 981 | int ret; |
936 | 982 | ||
937 | /* when the page flip is requested, crtc's dpms should be on */ | 983 | /* when the page flip is requested, crtc should be on */ |
938 | if (vop->dpms > DRM_MODE_DPMS_ON) { | 984 | if (!vop->is_enabled) { |
939 | DRM_DEBUG("failed page flip request at dpms[%d].\n", vop->dpms); | 985 | DRM_DEBUG("page flip request rejected because crtc is off.\n"); |
940 | return 0; | 986 | return 0; |
941 | } | 987 | } |
942 | 988 | ||
@@ -1081,6 +1127,7 @@ static irqreturn_t vop_isr(int irq, void *data) | |||
1081 | struct vop *vop = data; | 1127 | struct vop *vop = data; |
1082 | uint32_t intr0_reg, active_irqs; | 1128 | uint32_t intr0_reg, active_irqs; |
1083 | unsigned long flags; | 1129 | unsigned long flags; |
1130 | int ret = IRQ_NONE; | ||
1084 | 1131 | ||
1085 | /* | 1132 | /* |
1086 | * INTR_CTRL0 register has interrupt status, enable and clear bits, we | 1133 | * INTR_CTRL0 register has interrupt status, enable and clear bits, we |
@@ -1099,15 +1146,23 @@ static irqreturn_t vop_isr(int irq, void *data) | |||
1099 | if (!active_irqs) | 1146 | if (!active_irqs) |
1100 | return IRQ_NONE; | 1147 | return IRQ_NONE; |
1101 | 1148 | ||
1102 | /* Only Frame Start Interrupt is enabled; other irqs are spurious. */ | 1149 | if (active_irqs & DSP_HOLD_VALID_INTR) { |
1103 | if (!(active_irqs & FS_INTR)) { | 1150 | complete(&vop->dsp_hold_completion); |
1104 | DRM_ERROR("Unknown VOP IRQs: %#02x\n", active_irqs); | 1151 | active_irqs &= ~DSP_HOLD_VALID_INTR; |
1105 | return IRQ_NONE; | 1152 | ret = IRQ_HANDLED; |
1106 | } | 1153 | } |
1107 | 1154 | ||
1108 | drm_handle_vblank(vop->drm_dev, vop->pipe); | 1155 | if (active_irqs & FS_INTR) { |
1156 | drm_handle_vblank(vop->drm_dev, vop->pipe); | ||
1157 | active_irqs &= ~FS_INTR; | ||
1158 | ret = (vop->vsync_work_pending) ? IRQ_WAKE_THREAD : IRQ_HANDLED; | ||
1159 | } | ||
1109 | 1160 | ||
1110 | return (vop->vsync_work_pending) ? IRQ_WAKE_THREAD : IRQ_HANDLED; | 1161 | /* Unhandled irqs are spurious. */ |
1162 | if (active_irqs) | ||
1163 | DRM_ERROR("Unknown VOP IRQs: %#02x\n", active_irqs); | ||
1164 | |||
1165 | return ret; | ||
1111 | } | 1166 | } |
1112 | 1167 | ||
1113 | static int vop_create_crtc(struct vop *vop) | 1168 | static int vop_create_crtc(struct vop *vop) |
@@ -1189,6 +1244,7 @@ static int vop_create_crtc(struct vop *vop) | |||
1189 | goto err_cleanup_crtc; | 1244 | goto err_cleanup_crtc; |
1190 | } | 1245 | } |
1191 | 1246 | ||
1247 | init_completion(&vop->dsp_hold_completion); | ||
1192 | crtc->port = port; | 1248 | crtc->port = port; |
1193 | vop->pipe = drm_crtc_index(crtc); | 1249 | vop->pipe = drm_crtc_index(crtc); |
1194 | rockchip_register_crtc_funcs(drm_dev, &private_crtc_funcs, vop->pipe); | 1250 | rockchip_register_crtc_funcs(drm_dev, &private_crtc_funcs, vop->pipe); |
@@ -1302,7 +1358,7 @@ static int vop_initial(struct vop *vop) | |||
1302 | 1358 | ||
1303 | clk_disable(vop->hclk); | 1359 | clk_disable(vop->hclk); |
1304 | 1360 | ||
1305 | vop->dpms = DRM_MODE_DPMS_OFF; | 1361 | vop->is_enabled = false; |
1306 | 1362 | ||
1307 | return 0; | 1363 | return 0; |
1308 | 1364 | ||