diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2016-04-01 08:21:18 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2016-04-01 08:21:18 -0400 |
commit | 6ddf37da05cd71bf9e43349d607e810b43c9008a (patch) | |
tree | d326ef95a7cb8e67242d22abac2b8af4fb3a51c2 | |
parent | 52bef0cb107d0cc801bbdb931de97d3e501ebf2c (diff) | |
parent | 72b9ff0612ad8fc969b910cd00ac16b57a1a9ba4 (diff) |
Merge branch 'drm-fixes' of git://people.freedesktop.org/~airlied/linux
Pull drm fixes from Dave Airlie:
"Nothing too crazy in here: a bunch of AMD fixes/quirks, two msm fixes,
some rockchip fixes, and a udl warning fix, along with one locking fix
for displayport that seems to fix some dodgy monitors"
* 'drm-fixes' of git://people.freedesktop.org/~airlied/linux:
drm/udl: Use unlocked gem unreferencing
drm/dp: move hw_mutex up the call stack
drm/amdgpu: Don't move pinned BOs
drm/radeon: Don't move pinned BOs
drm/radeon: add a dpm quirk for all R7 370 parts
drm/radeon: add another R7 370 quirk
drm/rockchip: dw_hdmi: Don't call platform_set_drvdata()
drm/rockchip: vop: Fix vop crtc cleanup
drm/rockchip: dw_hdmi: Call drm_encoder_cleanup() in error path
drm/rockchip: vop: Disable planes when disabling CRTC
drm/rockchip: vop: Don't reject empty modesets
drm/rockchip: cancel pending vblanks on close
drm/rockchip: vop: fix crtc size in plane check
drm/radeon: add a dpm quirk for sapphire Dual-X R7 370 2G D5
drm/amd: Beef up ACP Kconfig menu text
drm/msm: fix typo in the !COMMON_CLK case
drm/msm: fix bug after preclose removal
-rw-r--r-- | drivers/gpu/drm/amd/acp/Kconfig | 8 | ||||
-rw-r--r-- | drivers/gpu/drm/amd/amdgpu/amdgpu_object.c | 4 | ||||
-rw-r--r-- | drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c | 6 | ||||
-rw-r--r-- | drivers/gpu/drm/drm_dp_helper.c | 27 | ||||
-rw-r--r-- | drivers/gpu/drm/msm/hdmi/hdmi.h | 2 | ||||
-rw-r--r-- | drivers/gpu/drm/msm/msm_drv.c | 3 | ||||
-rw-r--r-- | drivers/gpu/drm/msm/msm_kms.h | 1 | ||||
-rw-r--r-- | drivers/gpu/drm/radeon/radeon_object.c | 4 | ||||
-rw-r--r-- | drivers/gpu/drm/radeon/radeon_ttm.c | 6 | ||||
-rw-r--r-- | drivers/gpu/drm/radeon/si_dpm.c | 6 | ||||
-rw-r--r-- | drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c | 13 | ||||
-rw-r--r-- | drivers/gpu/drm/rockchip/rockchip_drm_drv.c | 22 | ||||
-rw-r--r-- | drivers/gpu/drm/rockchip/rockchip_drm_drv.h | 1 | ||||
-rw-r--r-- | drivers/gpu/drm/rockchip/rockchip_drm_vop.c | 79 | ||||
-rw-r--r-- | drivers/gpu/drm/udl/udl_fb.c | 2 | ||||
-rw-r--r-- | drivers/gpu/drm/udl/udl_gem.c | 2 |
16 files changed, 152 insertions, 34 deletions
diff --git a/drivers/gpu/drm/amd/acp/Kconfig b/drivers/gpu/drm/amd/acp/Kconfig index 0f734ee05274..ca77ec10147c 100644 --- a/drivers/gpu/drm/amd/acp/Kconfig +++ b/drivers/gpu/drm/amd/acp/Kconfig | |||
@@ -1,10 +1,14 @@ | |||
1 | menu "ACP Configuration" | 1 | menu "ACP (Audio CoProcessor) Configuration" |
2 | 2 | ||
3 | config DRM_AMD_ACP | 3 | config DRM_AMD_ACP |
4 | bool "Enable ACP IP support" | 4 | bool "Enable AMD Audio CoProcessor IP support" |
5 | select MFD_CORE | 5 | select MFD_CORE |
6 | select PM_GENERIC_DOMAINS if PM | 6 | select PM_GENERIC_DOMAINS if PM |
7 | help | 7 | help |
8 | Choose this option to enable ACP IP support for AMD SOCs. | 8 | Choose this option to enable ACP IP support for AMD SOCs. |
9 | This adds the ACP (Audio CoProcessor) IP driver and wires | ||
10 | it up into the amdgpu driver. The ACP block provides the DMA | ||
11 | engine for the i2s-based ALSA driver. It is required for audio | ||
12 | on APUs which utilize an i2s codec. | ||
9 | 13 | ||
10 | endmenu | 14 | endmenu |
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c index 151a2d42c639..56d1458393cc 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c | |||
@@ -608,6 +608,10 @@ int amdgpu_bo_fault_reserve_notify(struct ttm_buffer_object *bo) | |||
608 | if ((offset + size) <= adev->mc.visible_vram_size) | 608 | if ((offset + size) <= adev->mc.visible_vram_size) |
609 | return 0; | 609 | return 0; |
610 | 610 | ||
611 | /* Can't move a pinned BO to visible VRAM */ | ||
612 | if (abo->pin_count > 0) | ||
613 | return -EINVAL; | ||
614 | |||
611 | /* hurrah the memory is not visible ! */ | 615 | /* hurrah the memory is not visible ! */ |
612 | amdgpu_ttm_placement_from_domain(abo, AMDGPU_GEM_DOMAIN_VRAM); | 616 | amdgpu_ttm_placement_from_domain(abo, AMDGPU_GEM_DOMAIN_VRAM); |
613 | lpfn = adev->mc.visible_vram_size >> PAGE_SHIFT; | 617 | lpfn = adev->mc.visible_vram_size >> PAGE_SHIFT; |
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c index ab34190859a8..f1a55d1888cb 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c | |||
@@ -384,9 +384,15 @@ static int amdgpu_bo_move(struct ttm_buffer_object *bo, | |||
384 | struct ttm_mem_reg *new_mem) | 384 | struct ttm_mem_reg *new_mem) |
385 | { | 385 | { |
386 | struct amdgpu_device *adev; | 386 | struct amdgpu_device *adev; |
387 | struct amdgpu_bo *abo; | ||
387 | struct ttm_mem_reg *old_mem = &bo->mem; | 388 | struct ttm_mem_reg *old_mem = &bo->mem; |
388 | int r; | 389 | int r; |
389 | 390 | ||
391 | /* Can't move a pinned BO */ | ||
392 | abo = container_of(bo, struct amdgpu_bo, tbo); | ||
393 | if (WARN_ON_ONCE(abo->pin_count > 0)) | ||
394 | return -EINVAL; | ||
395 | |||
390 | adev = amdgpu_get_adev(bo->bdev); | 396 | adev = amdgpu_get_adev(bo->bdev); |
391 | if (old_mem->mem_type == TTM_PL_SYSTEM && bo->ttm == NULL) { | 397 | if (old_mem->mem_type == TTM_PL_SYSTEM && bo->ttm == NULL) { |
392 | amdgpu_move_null(bo, new_mem); | 398 | amdgpu_move_null(bo, new_mem); |
diff --git a/drivers/gpu/drm/drm_dp_helper.c b/drivers/gpu/drm/drm_dp_helper.c index 7d58f594cffe..df64ed1c0139 100644 --- a/drivers/gpu/drm/drm_dp_helper.c +++ b/drivers/gpu/drm/drm_dp_helper.c | |||
@@ -179,7 +179,7 @@ static int drm_dp_dpcd_access(struct drm_dp_aux *aux, u8 request, | |||
179 | { | 179 | { |
180 | struct drm_dp_aux_msg msg; | 180 | struct drm_dp_aux_msg msg; |
181 | unsigned int retry; | 181 | unsigned int retry; |
182 | int err; | 182 | int err = 0; |
183 | 183 | ||
184 | memset(&msg, 0, sizeof(msg)); | 184 | memset(&msg, 0, sizeof(msg)); |
185 | msg.address = offset; | 185 | msg.address = offset; |
@@ -187,6 +187,8 @@ static int drm_dp_dpcd_access(struct drm_dp_aux *aux, u8 request, | |||
187 | msg.buffer = buffer; | 187 | msg.buffer = buffer; |
188 | msg.size = size; | 188 | msg.size = size; |
189 | 189 | ||
190 | mutex_lock(&aux->hw_mutex); | ||
191 | |||
190 | /* | 192 | /* |
191 | * The specification doesn't give any recommendation on how often to | 193 | * The specification doesn't give any recommendation on how often to |
192 | * retry native transactions. We used to retry 7 times like for | 194 | * retry native transactions. We used to retry 7 times like for |
@@ -195,25 +197,24 @@ static int drm_dp_dpcd_access(struct drm_dp_aux *aux, u8 request, | |||
195 | */ | 197 | */ |
196 | for (retry = 0; retry < 32; retry++) { | 198 | for (retry = 0; retry < 32; retry++) { |
197 | 199 | ||
198 | mutex_lock(&aux->hw_mutex); | ||
199 | err = aux->transfer(aux, &msg); | 200 | err = aux->transfer(aux, &msg); |
200 | mutex_unlock(&aux->hw_mutex); | ||
201 | if (err < 0) { | 201 | if (err < 0) { |
202 | if (err == -EBUSY) | 202 | if (err == -EBUSY) |
203 | continue; | 203 | continue; |
204 | 204 | ||
205 | return err; | 205 | goto unlock; |
206 | } | 206 | } |
207 | 207 | ||
208 | 208 | ||
209 | switch (msg.reply & DP_AUX_NATIVE_REPLY_MASK) { | 209 | switch (msg.reply & DP_AUX_NATIVE_REPLY_MASK) { |
210 | case DP_AUX_NATIVE_REPLY_ACK: | 210 | case DP_AUX_NATIVE_REPLY_ACK: |
211 | if (err < size) | 211 | if (err < size) |
212 | return -EPROTO; | 212 | err = -EPROTO; |
213 | return err; | 213 | goto unlock; |
214 | 214 | ||
215 | case DP_AUX_NATIVE_REPLY_NACK: | 215 | case DP_AUX_NATIVE_REPLY_NACK: |
216 | return -EIO; | 216 | err = -EIO; |
217 | goto unlock; | ||
217 | 218 | ||
218 | case DP_AUX_NATIVE_REPLY_DEFER: | 219 | case DP_AUX_NATIVE_REPLY_DEFER: |
219 | usleep_range(AUX_RETRY_INTERVAL, AUX_RETRY_INTERVAL + 100); | 220 | usleep_range(AUX_RETRY_INTERVAL, AUX_RETRY_INTERVAL + 100); |
@@ -222,7 +223,11 @@ static int drm_dp_dpcd_access(struct drm_dp_aux *aux, u8 request, | |||
222 | } | 223 | } |
223 | 224 | ||
224 | DRM_DEBUG_KMS("too many retries, giving up\n"); | 225 | DRM_DEBUG_KMS("too many retries, giving up\n"); |
225 | return -EIO; | 226 | err = -EIO; |
227 | |||
228 | unlock: | ||
229 | mutex_unlock(&aux->hw_mutex); | ||
230 | return err; | ||
226 | } | 231 | } |
227 | 232 | ||
228 | /** | 233 | /** |
@@ -544,9 +549,7 @@ static int drm_dp_i2c_do_msg(struct drm_dp_aux *aux, struct drm_dp_aux_msg *msg) | |||
544 | int max_retries = max(7, drm_dp_i2c_retry_count(msg, dp_aux_i2c_speed_khz)); | 549 | int max_retries = max(7, drm_dp_i2c_retry_count(msg, dp_aux_i2c_speed_khz)); |
545 | 550 | ||
546 | for (retry = 0, defer_i2c = 0; retry < (max_retries + defer_i2c); retry++) { | 551 | for (retry = 0, defer_i2c = 0; retry < (max_retries + defer_i2c); retry++) { |
547 | mutex_lock(&aux->hw_mutex); | ||
548 | ret = aux->transfer(aux, msg); | 552 | ret = aux->transfer(aux, msg); |
549 | mutex_unlock(&aux->hw_mutex); | ||
550 | if (ret < 0) { | 553 | if (ret < 0) { |
551 | if (ret == -EBUSY) | 554 | if (ret == -EBUSY) |
552 | continue; | 555 | continue; |
@@ -685,6 +688,8 @@ static int drm_dp_i2c_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs, | |||
685 | 688 | ||
686 | memset(&msg, 0, sizeof(msg)); | 689 | memset(&msg, 0, sizeof(msg)); |
687 | 690 | ||
691 | mutex_lock(&aux->hw_mutex); | ||
692 | |||
688 | for (i = 0; i < num; i++) { | 693 | for (i = 0; i < num; i++) { |
689 | msg.address = msgs[i].addr; | 694 | msg.address = msgs[i].addr; |
690 | drm_dp_i2c_msg_set_request(&msg, &msgs[i]); | 695 | drm_dp_i2c_msg_set_request(&msg, &msgs[i]); |
@@ -739,6 +744,8 @@ static int drm_dp_i2c_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs, | |||
739 | msg.size = 0; | 744 | msg.size = 0; |
740 | (void)drm_dp_i2c_do_msg(aux, &msg); | 745 | (void)drm_dp_i2c_do_msg(aux, &msg); |
741 | 746 | ||
747 | mutex_unlock(&aux->hw_mutex); | ||
748 | |||
742 | return err; | 749 | return err; |
743 | } | 750 | } |
744 | 751 | ||
diff --git a/drivers/gpu/drm/msm/hdmi/hdmi.h b/drivers/gpu/drm/msm/hdmi/hdmi.h index b04a64664673..65428cf233ce 100644 --- a/drivers/gpu/drm/msm/hdmi/hdmi.h +++ b/drivers/gpu/drm/msm/hdmi/hdmi.h | |||
@@ -196,7 +196,7 @@ void __exit msm_hdmi_phy_driver_unregister(void); | |||
196 | int msm_hdmi_pll_8960_init(struct platform_device *pdev); | 196 | int msm_hdmi_pll_8960_init(struct platform_device *pdev); |
197 | int msm_hdmi_pll_8996_init(struct platform_device *pdev); | 197 | int msm_hdmi_pll_8996_init(struct platform_device *pdev); |
198 | #else | 198 | #else |
199 | static inline int msm_hdmi_pll_8960_init(struct platform_device *pdev); | 199 | static inline int msm_hdmi_pll_8960_init(struct platform_device *pdev) |
200 | { | 200 | { |
201 | return -ENODEV; | 201 | return -ENODEV; |
202 | } | 202 | } |
diff --git a/drivers/gpu/drm/msm/msm_drv.c b/drivers/gpu/drm/msm/msm_drv.c index d52910e2c26c..c03b96709179 100644 --- a/drivers/gpu/drm/msm/msm_drv.c +++ b/drivers/gpu/drm/msm/msm_drv.c | |||
@@ -467,9 +467,6 @@ static void msm_preclose(struct drm_device *dev, struct drm_file *file) | |||
467 | struct msm_file_private *ctx = file->driver_priv; | 467 | struct msm_file_private *ctx = file->driver_priv; |
468 | struct msm_kms *kms = priv->kms; | 468 | struct msm_kms *kms = priv->kms; |
469 | 469 | ||
470 | if (kms) | ||
471 | kms->funcs->preclose(kms, file); | ||
472 | |||
473 | mutex_lock(&dev->struct_mutex); | 470 | mutex_lock(&dev->struct_mutex); |
474 | if (ctx == priv->lastctx) | 471 | if (ctx == priv->lastctx) |
475 | priv->lastctx = NULL; | 472 | priv->lastctx = NULL; |
diff --git a/drivers/gpu/drm/msm/msm_kms.h b/drivers/gpu/drm/msm/msm_kms.h index 9bcabaada179..e32222c3d44f 100644 --- a/drivers/gpu/drm/msm/msm_kms.h +++ b/drivers/gpu/drm/msm/msm_kms.h | |||
@@ -55,7 +55,6 @@ struct msm_kms_funcs { | |||
55 | struct drm_encoder *slave_encoder, | 55 | struct drm_encoder *slave_encoder, |
56 | bool is_cmd_mode); | 56 | bool is_cmd_mode); |
57 | /* cleanup: */ | 57 | /* cleanup: */ |
58 | void (*preclose)(struct msm_kms *kms, struct drm_file *file); | ||
59 | void (*destroy)(struct msm_kms *kms); | 58 | void (*destroy)(struct msm_kms *kms); |
60 | }; | 59 | }; |
61 | 60 | ||
diff --git a/drivers/gpu/drm/radeon/radeon_object.c b/drivers/gpu/drm/radeon/radeon_object.c index dd46c38676db..2d901bf28a94 100644 --- a/drivers/gpu/drm/radeon/radeon_object.c +++ b/drivers/gpu/drm/radeon/radeon_object.c | |||
@@ -799,6 +799,10 @@ int radeon_bo_fault_reserve_notify(struct ttm_buffer_object *bo) | |||
799 | if ((offset + size) <= rdev->mc.visible_vram_size) | 799 | if ((offset + size) <= rdev->mc.visible_vram_size) |
800 | return 0; | 800 | return 0; |
801 | 801 | ||
802 | /* Can't move a pinned BO to visible VRAM */ | ||
803 | if (rbo->pin_count > 0) | ||
804 | return -EINVAL; | ||
805 | |||
802 | /* hurrah the memory is not visible ! */ | 806 | /* hurrah the memory is not visible ! */ |
803 | radeon_ttm_placement_from_domain(rbo, RADEON_GEM_DOMAIN_VRAM); | 807 | radeon_ttm_placement_from_domain(rbo, RADEON_GEM_DOMAIN_VRAM); |
804 | lpfn = rdev->mc.visible_vram_size >> PAGE_SHIFT; | 808 | lpfn = rdev->mc.visible_vram_size >> PAGE_SHIFT; |
diff --git a/drivers/gpu/drm/radeon/radeon_ttm.c b/drivers/gpu/drm/radeon/radeon_ttm.c index 6d8c32377c6f..c008312e1bcd 100644 --- a/drivers/gpu/drm/radeon/radeon_ttm.c +++ b/drivers/gpu/drm/radeon/radeon_ttm.c | |||
@@ -397,9 +397,15 @@ static int radeon_bo_move(struct ttm_buffer_object *bo, | |||
397 | struct ttm_mem_reg *new_mem) | 397 | struct ttm_mem_reg *new_mem) |
398 | { | 398 | { |
399 | struct radeon_device *rdev; | 399 | struct radeon_device *rdev; |
400 | struct radeon_bo *rbo; | ||
400 | struct ttm_mem_reg *old_mem = &bo->mem; | 401 | struct ttm_mem_reg *old_mem = &bo->mem; |
401 | int r; | 402 | int r; |
402 | 403 | ||
404 | /* Can't move a pinned BO */ | ||
405 | rbo = container_of(bo, struct radeon_bo, tbo); | ||
406 | if (WARN_ON_ONCE(rbo->pin_count > 0)) | ||
407 | return -EINVAL; | ||
408 | |||
403 | rdev = radeon_get_rdev(bo->bdev); | 409 | rdev = radeon_get_rdev(bo->bdev); |
404 | if (old_mem->mem_type == TTM_PL_SYSTEM && bo->ttm == NULL) { | 410 | if (old_mem->mem_type == TTM_PL_SYSTEM && bo->ttm == NULL) { |
405 | radeon_move_null(bo, new_mem); | 411 | radeon_move_null(bo, new_mem); |
diff --git a/drivers/gpu/drm/radeon/si_dpm.c b/drivers/gpu/drm/radeon/si_dpm.c index cb75ab72098a..af4df81c4e0c 100644 --- a/drivers/gpu/drm/radeon/si_dpm.c +++ b/drivers/gpu/drm/radeon/si_dpm.c | |||
@@ -2926,9 +2926,11 @@ static struct si_dpm_quirk si_dpm_quirk_list[] = { | |||
2926 | /* PITCAIRN - https://bugs.freedesktop.org/show_bug.cgi?id=76490 */ | 2926 | /* PITCAIRN - https://bugs.freedesktop.org/show_bug.cgi?id=76490 */ |
2927 | { PCI_VENDOR_ID_ATI, 0x6810, 0x1462, 0x3036, 0, 120000 }, | 2927 | { PCI_VENDOR_ID_ATI, 0x6810, 0x1462, 0x3036, 0, 120000 }, |
2928 | { PCI_VENDOR_ID_ATI, 0x6811, 0x174b, 0xe271, 0, 120000 }, | 2928 | { PCI_VENDOR_ID_ATI, 0x6811, 0x174b, 0xe271, 0, 120000 }, |
2929 | { PCI_VENDOR_ID_ATI, 0x6811, 0x174b, 0x2015, 0, 120000 }, | ||
2929 | { PCI_VENDOR_ID_ATI, 0x6810, 0x174b, 0xe271, 85000, 90000 }, | 2930 | { PCI_VENDOR_ID_ATI, 0x6810, 0x174b, 0xe271, 85000, 90000 }, |
2930 | { PCI_VENDOR_ID_ATI, 0x6811, 0x1462, 0x2015, 0, 120000 }, | 2931 | { PCI_VENDOR_ID_ATI, 0x6811, 0x1462, 0x2015, 0, 120000 }, |
2931 | { PCI_VENDOR_ID_ATI, 0x6811, 0x1043, 0x2015, 0, 120000 }, | 2932 | { PCI_VENDOR_ID_ATI, 0x6811, 0x1043, 0x2015, 0, 120000 }, |
2933 | { PCI_VENDOR_ID_ATI, 0x6811, 0x148c, 0x2015, 0, 120000 }, | ||
2932 | { 0, 0, 0, 0 }, | 2934 | { 0, 0, 0, 0 }, |
2933 | }; | 2935 | }; |
2934 | 2936 | ||
@@ -3008,6 +3010,10 @@ static void si_apply_state_adjust_rules(struct radeon_device *rdev, | |||
3008 | } | 3010 | } |
3009 | ++p; | 3011 | ++p; |
3010 | } | 3012 | } |
3013 | /* limit mclk on all R7 370 parts for stability */ | ||
3014 | if (rdev->pdev->device == 0x6811 && | ||
3015 | rdev->pdev->revision == 0x81) | ||
3016 | max_mclk = 120000; | ||
3011 | 3017 | ||
3012 | if (rps->vce_active) { | 3018 | if (rps->vce_active) { |
3013 | rps->evclk = rdev->pm.dpm.vce_states[rdev->pm.dpm.vce_level].evclk; | 3019 | rps->evclk = rdev->pm.dpm.vce_states[rdev->pm.dpm.vce_level].evclk; |
diff --git a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c index 3d3cf2f8891e..d5cfef75fc80 100644 --- a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c +++ b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c | |||
@@ -271,8 +271,6 @@ static int dw_hdmi_rockchip_bind(struct device *dev, struct device *master, | |||
271 | if (!iores) | 271 | if (!iores) |
272 | return -ENXIO; | 272 | return -ENXIO; |
273 | 273 | ||
274 | platform_set_drvdata(pdev, hdmi); | ||
275 | |||
276 | encoder->possible_crtcs = drm_of_find_possible_crtcs(drm, dev->of_node); | 274 | encoder->possible_crtcs = drm_of_find_possible_crtcs(drm, dev->of_node); |
277 | /* | 275 | /* |
278 | * If we failed to find the CRTC(s) which this encoder is | 276 | * If we failed to find the CRTC(s) which this encoder is |
@@ -293,7 +291,16 @@ static int dw_hdmi_rockchip_bind(struct device *dev, struct device *master, | |||
293 | drm_encoder_init(drm, encoder, &dw_hdmi_rockchip_encoder_funcs, | 291 | drm_encoder_init(drm, encoder, &dw_hdmi_rockchip_encoder_funcs, |
294 | DRM_MODE_ENCODER_TMDS, NULL); | 292 | DRM_MODE_ENCODER_TMDS, NULL); |
295 | 293 | ||
296 | return dw_hdmi_bind(dev, master, data, encoder, iores, irq, plat_data); | 294 | ret = dw_hdmi_bind(dev, master, data, encoder, iores, irq, plat_data); |
295 | |||
296 | /* | ||
297 | * If dw_hdmi_bind() fails we'll never call dw_hdmi_unbind(), | ||
298 | * which would have called the encoder cleanup. Do it manually. | ||
299 | */ | ||
300 | if (ret) | ||
301 | drm_encoder_cleanup(encoder); | ||
302 | |||
303 | return ret; | ||
297 | } | 304 | } |
298 | 305 | ||
299 | static void dw_hdmi_rockchip_unbind(struct device *dev, struct device *master, | 306 | static void dw_hdmi_rockchip_unbind(struct device *dev, struct device *master, |
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_drv.c b/drivers/gpu/drm/rockchip/rockchip_drm_drv.c index 896da09e49ee..f556a8f4fde6 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_drv.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.c | |||
@@ -251,6 +251,27 @@ static int rockchip_drm_unload(struct drm_device *drm_dev) | |||
251 | return 0; | 251 | return 0; |
252 | } | 252 | } |
253 | 253 | ||
254 | static void rockchip_drm_crtc_cancel_pending_vblank(struct drm_crtc *crtc, | ||
255 | struct drm_file *file_priv) | ||
256 | { | ||
257 | struct rockchip_drm_private *priv = crtc->dev->dev_private; | ||
258 | int pipe = drm_crtc_index(crtc); | ||
259 | |||
260 | if (pipe < ROCKCHIP_MAX_CRTC && | ||
261 | priv->crtc_funcs[pipe] && | ||
262 | priv->crtc_funcs[pipe]->cancel_pending_vblank) | ||
263 | priv->crtc_funcs[pipe]->cancel_pending_vblank(crtc, file_priv); | ||
264 | } | ||
265 | |||
266 | static void rockchip_drm_preclose(struct drm_device *dev, | ||
267 | struct drm_file *file_priv) | ||
268 | { | ||
269 | struct drm_crtc *crtc; | ||
270 | |||
271 | list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) | ||
272 | rockchip_drm_crtc_cancel_pending_vblank(crtc, file_priv); | ||
273 | } | ||
274 | |||
254 | void rockchip_drm_lastclose(struct drm_device *dev) | 275 | void rockchip_drm_lastclose(struct drm_device *dev) |
255 | { | 276 | { |
256 | struct rockchip_drm_private *priv = dev->dev_private; | 277 | struct rockchip_drm_private *priv = dev->dev_private; |
@@ -281,6 +302,7 @@ static struct drm_driver rockchip_drm_driver = { | |||
281 | DRIVER_PRIME | DRIVER_ATOMIC, | 302 | DRIVER_PRIME | DRIVER_ATOMIC, |
282 | .load = rockchip_drm_load, | 303 | .load = rockchip_drm_load, |
283 | .unload = rockchip_drm_unload, | 304 | .unload = rockchip_drm_unload, |
305 | .preclose = rockchip_drm_preclose, | ||
284 | .lastclose = rockchip_drm_lastclose, | 306 | .lastclose = rockchip_drm_lastclose, |
285 | .get_vblank_counter = drm_vblank_no_hw_counter, | 307 | .get_vblank_counter = drm_vblank_no_hw_counter, |
286 | .enable_vblank = rockchip_drm_crtc_enable_vblank, | 308 | .enable_vblank = rockchip_drm_crtc_enable_vblank, |
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_drv.h b/drivers/gpu/drm/rockchip/rockchip_drm_drv.h index 3529f692edb8..00d17d71aa4c 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_drv.h +++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.h | |||
@@ -40,6 +40,7 @@ struct rockchip_crtc_funcs { | |||
40 | int (*enable_vblank)(struct drm_crtc *crtc); | 40 | int (*enable_vblank)(struct drm_crtc *crtc); |
41 | void (*disable_vblank)(struct drm_crtc *crtc); | 41 | void (*disable_vblank)(struct drm_crtc *crtc); |
42 | void (*wait_for_update)(struct drm_crtc *crtc); | 42 | void (*wait_for_update)(struct drm_crtc *crtc); |
43 | void (*cancel_pending_vblank)(struct drm_crtc *crtc, struct drm_file *file_priv); | ||
43 | }; | 44 | }; |
44 | 45 | ||
45 | struct rockchip_atomic_commit { | 46 | struct rockchip_atomic_commit { |
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c index fd370548d7d7..a619f120f801 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c | |||
@@ -499,10 +499,25 @@ err_disable_hclk: | |||
499 | static void vop_crtc_disable(struct drm_crtc *crtc) | 499 | static void vop_crtc_disable(struct drm_crtc *crtc) |
500 | { | 500 | { |
501 | struct vop *vop = to_vop(crtc); | 501 | struct vop *vop = to_vop(crtc); |
502 | int i; | ||
502 | 503 | ||
503 | if (!vop->is_enabled) | 504 | if (!vop->is_enabled) |
504 | return; | 505 | return; |
505 | 506 | ||
507 | /* | ||
508 | * We need to make sure that all windows are disabled before we | ||
509 | * disable that crtc. Otherwise we might try to scan from a destroyed | ||
510 | * buffer later. | ||
511 | */ | ||
512 | for (i = 0; i < vop->data->win_size; i++) { | ||
513 | struct vop_win *vop_win = &vop->win[i]; | ||
514 | const struct vop_win_data *win = vop_win->data; | ||
515 | |||
516 | spin_lock(&vop->reg_lock); | ||
517 | VOP_WIN_SET(vop, win, enable, 0); | ||
518 | spin_unlock(&vop->reg_lock); | ||
519 | } | ||
520 | |||
506 | drm_crtc_vblank_off(crtc); | 521 | drm_crtc_vblank_off(crtc); |
507 | 522 | ||
508 | /* | 523 | /* |
@@ -549,6 +564,7 @@ static int vop_plane_atomic_check(struct drm_plane *plane, | |||
549 | struct drm_plane_state *state) | 564 | struct drm_plane_state *state) |
550 | { | 565 | { |
551 | struct drm_crtc *crtc = state->crtc; | 566 | struct drm_crtc *crtc = state->crtc; |
567 | struct drm_crtc_state *crtc_state; | ||
552 | struct drm_framebuffer *fb = state->fb; | 568 | struct drm_framebuffer *fb = state->fb; |
553 | struct vop_win *vop_win = to_vop_win(plane); | 569 | struct vop_win *vop_win = to_vop_win(plane); |
554 | struct vop_plane_state *vop_plane_state = to_vop_plane_state(state); | 570 | struct vop_plane_state *vop_plane_state = to_vop_plane_state(state); |
@@ -563,12 +579,13 @@ static int vop_plane_atomic_check(struct drm_plane *plane, | |||
563 | int max_scale = win->phy->scl ? FRAC_16_16(8, 1) : | 579 | int max_scale = win->phy->scl ? FRAC_16_16(8, 1) : |
564 | DRM_PLANE_HELPER_NO_SCALING; | 580 | DRM_PLANE_HELPER_NO_SCALING; |
565 | 581 | ||
566 | crtc = crtc ? crtc : plane->state->crtc; | ||
567 | /* | ||
568 | * Both crtc or plane->state->crtc can be null. | ||
569 | */ | ||
570 | if (!crtc || !fb) | 582 | if (!crtc || !fb) |
571 | goto out_disable; | 583 | goto out_disable; |
584 | |||
585 | crtc_state = drm_atomic_get_existing_crtc_state(state->state, crtc); | ||
586 | if (WARN_ON(!crtc_state)) | ||
587 | return -EINVAL; | ||
588 | |||
572 | src->x1 = state->src_x; | 589 | src->x1 = state->src_x; |
573 | src->y1 = state->src_y; | 590 | src->y1 = state->src_y; |
574 | src->x2 = state->src_x + state->src_w; | 591 | src->x2 = state->src_x + state->src_w; |
@@ -580,8 +597,8 @@ static int vop_plane_atomic_check(struct drm_plane *plane, | |||
580 | 597 | ||
581 | clip.x1 = 0; | 598 | clip.x1 = 0; |
582 | clip.y1 = 0; | 599 | clip.y1 = 0; |
583 | clip.x2 = crtc->mode.hdisplay; | 600 | clip.x2 = crtc_state->adjusted_mode.hdisplay; |
584 | clip.y2 = crtc->mode.vdisplay; | 601 | clip.y2 = crtc_state->adjusted_mode.vdisplay; |
585 | 602 | ||
586 | ret = drm_plane_helper_check_update(plane, crtc, state->fb, | 603 | ret = drm_plane_helper_check_update(plane, crtc, state->fb, |
587 | src, dest, &clip, | 604 | src, dest, &clip, |
@@ -873,10 +890,30 @@ static void vop_crtc_wait_for_update(struct drm_crtc *crtc) | |||
873 | WARN_ON(!wait_for_completion_timeout(&vop->wait_update_complete, 100)); | 890 | WARN_ON(!wait_for_completion_timeout(&vop->wait_update_complete, 100)); |
874 | } | 891 | } |
875 | 892 | ||
893 | static void vop_crtc_cancel_pending_vblank(struct drm_crtc *crtc, | ||
894 | struct drm_file *file_priv) | ||
895 | { | ||
896 | struct drm_device *drm = crtc->dev; | ||
897 | struct vop *vop = to_vop(crtc); | ||
898 | struct drm_pending_vblank_event *e; | ||
899 | unsigned long flags; | ||
900 | |||
901 | spin_lock_irqsave(&drm->event_lock, flags); | ||
902 | e = vop->event; | ||
903 | if (e && e->base.file_priv == file_priv) { | ||
904 | vop->event = NULL; | ||
905 | |||
906 | e->base.destroy(&e->base); | ||
907 | file_priv->event_space += sizeof(e->event); | ||
908 | } | ||
909 | spin_unlock_irqrestore(&drm->event_lock, flags); | ||
910 | } | ||
911 | |||
876 | static const struct rockchip_crtc_funcs private_crtc_funcs = { | 912 | static const struct rockchip_crtc_funcs private_crtc_funcs = { |
877 | .enable_vblank = vop_crtc_enable_vblank, | 913 | .enable_vblank = vop_crtc_enable_vblank, |
878 | .disable_vblank = vop_crtc_disable_vblank, | 914 | .disable_vblank = vop_crtc_disable_vblank, |
879 | .wait_for_update = vop_crtc_wait_for_update, | 915 | .wait_for_update = vop_crtc_wait_for_update, |
916 | .cancel_pending_vblank = vop_crtc_cancel_pending_vblank, | ||
880 | }; | 917 | }; |
881 | 918 | ||
882 | static bool vop_crtc_mode_fixup(struct drm_crtc *crtc, | 919 | static bool vop_crtc_mode_fixup(struct drm_crtc *crtc, |
@@ -885,9 +922,6 @@ static bool vop_crtc_mode_fixup(struct drm_crtc *crtc, | |||
885 | { | 922 | { |
886 | struct vop *vop = to_vop(crtc); | 923 | struct vop *vop = to_vop(crtc); |
887 | 924 | ||
888 | if (adjusted_mode->htotal == 0 || adjusted_mode->vtotal == 0) | ||
889 | return false; | ||
890 | |||
891 | adjusted_mode->clock = | 925 | adjusted_mode->clock = |
892 | clk_round_rate(vop->dclk, mode->clock * 1000) / 1000; | 926 | clk_round_rate(vop->dclk, mode->clock * 1000) / 1000; |
893 | 927 | ||
@@ -1108,7 +1142,7 @@ static int vop_create_crtc(struct vop *vop) | |||
1108 | const struct vop_data *vop_data = vop->data; | 1142 | const struct vop_data *vop_data = vop->data; |
1109 | struct device *dev = vop->dev; | 1143 | struct device *dev = vop->dev; |
1110 | struct drm_device *drm_dev = vop->drm_dev; | 1144 | struct drm_device *drm_dev = vop->drm_dev; |
1111 | struct drm_plane *primary = NULL, *cursor = NULL, *plane; | 1145 | struct drm_plane *primary = NULL, *cursor = NULL, *plane, *tmp; |
1112 | struct drm_crtc *crtc = &vop->crtc; | 1146 | struct drm_crtc *crtc = &vop->crtc; |
1113 | struct device_node *port; | 1147 | struct device_node *port; |
1114 | int ret; | 1148 | int ret; |
@@ -1148,7 +1182,7 @@ static int vop_create_crtc(struct vop *vop) | |||
1148 | ret = drm_crtc_init_with_planes(drm_dev, crtc, primary, cursor, | 1182 | ret = drm_crtc_init_with_planes(drm_dev, crtc, primary, cursor, |
1149 | &vop_crtc_funcs, NULL); | 1183 | &vop_crtc_funcs, NULL); |
1150 | if (ret) | 1184 | if (ret) |
1151 | return ret; | 1185 | goto err_cleanup_planes; |
1152 | 1186 | ||
1153 | drm_crtc_helper_add(crtc, &vop_crtc_helper_funcs); | 1187 | drm_crtc_helper_add(crtc, &vop_crtc_helper_funcs); |
1154 | 1188 | ||
@@ -1181,6 +1215,7 @@ static int vop_create_crtc(struct vop *vop) | |||
1181 | if (!port) { | 1215 | if (!port) { |
1182 | DRM_ERROR("no port node found in %s\n", | 1216 | DRM_ERROR("no port node found in %s\n", |
1183 | dev->of_node->full_name); | 1217 | dev->of_node->full_name); |
1218 | ret = -ENOENT; | ||
1184 | goto err_cleanup_crtc; | 1219 | goto err_cleanup_crtc; |
1185 | } | 1220 | } |
1186 | 1221 | ||
@@ -1194,7 +1229,8 @@ static int vop_create_crtc(struct vop *vop) | |||
1194 | err_cleanup_crtc: | 1229 | err_cleanup_crtc: |
1195 | drm_crtc_cleanup(crtc); | 1230 | drm_crtc_cleanup(crtc); |
1196 | err_cleanup_planes: | 1231 | err_cleanup_planes: |
1197 | list_for_each_entry(plane, &drm_dev->mode_config.plane_list, head) | 1232 | list_for_each_entry_safe(plane, tmp, &drm_dev->mode_config.plane_list, |
1233 | head) | ||
1198 | drm_plane_cleanup(plane); | 1234 | drm_plane_cleanup(plane); |
1199 | return ret; | 1235 | return ret; |
1200 | } | 1236 | } |
@@ -1202,9 +1238,28 @@ err_cleanup_planes: | |||
1202 | static void vop_destroy_crtc(struct vop *vop) | 1238 | static void vop_destroy_crtc(struct vop *vop) |
1203 | { | 1239 | { |
1204 | struct drm_crtc *crtc = &vop->crtc; | 1240 | struct drm_crtc *crtc = &vop->crtc; |
1241 | struct drm_device *drm_dev = vop->drm_dev; | ||
1242 | struct drm_plane *plane, *tmp; | ||
1205 | 1243 | ||
1206 | rockchip_unregister_crtc_funcs(crtc); | 1244 | rockchip_unregister_crtc_funcs(crtc); |
1207 | of_node_put(crtc->port); | 1245 | of_node_put(crtc->port); |
1246 | |||
1247 | /* | ||
1248 | * We need to cleanup the planes now. Why? | ||
1249 | * | ||
1250 | * The planes are "&vop->win[i].base". That means the memory is | ||
1251 | * all part of the big "struct vop" chunk of memory. That memory | ||
1252 | * was devm allocated and associated with this component. We need to | ||
1253 | * free it ourselves before vop_unbind() finishes. | ||
1254 | */ | ||
1255 | list_for_each_entry_safe(plane, tmp, &drm_dev->mode_config.plane_list, | ||
1256 | head) | ||
1257 | vop_plane_destroy(plane); | ||
1258 | |||
1259 | /* | ||
1260 | * Destroy CRTC after vop_plane_destroy() since vop_disable_plane() | ||
1261 | * references the CRTC. | ||
1262 | */ | ||
1208 | drm_crtc_cleanup(crtc); | 1263 | drm_crtc_cleanup(crtc); |
1209 | } | 1264 | } |
1210 | 1265 | ||
diff --git a/drivers/gpu/drm/udl/udl_fb.c b/drivers/gpu/drm/udl/udl_fb.c index 33239a2b264a..fd1eb9d03f0b 100644 --- a/drivers/gpu/drm/udl/udl_fb.c +++ b/drivers/gpu/drm/udl/udl_fb.c | |||
@@ -536,7 +536,7 @@ static int udlfb_create(struct drm_fb_helper *helper, | |||
536 | out_destroy_fbi: | 536 | out_destroy_fbi: |
537 | drm_fb_helper_release_fbi(helper); | 537 | drm_fb_helper_release_fbi(helper); |
538 | out_gfree: | 538 | out_gfree: |
539 | drm_gem_object_unreference(&ufbdev->ufb.obj->base); | 539 | drm_gem_object_unreference_unlocked(&ufbdev->ufb.obj->base); |
540 | out: | 540 | out: |
541 | return ret; | 541 | return ret; |
542 | } | 542 | } |
diff --git a/drivers/gpu/drm/udl/udl_gem.c b/drivers/gpu/drm/udl/udl_gem.c index 2a0a784ab6ee..d7528e0d8442 100644 --- a/drivers/gpu/drm/udl/udl_gem.c +++ b/drivers/gpu/drm/udl/udl_gem.c | |||
@@ -52,7 +52,7 @@ udl_gem_create(struct drm_file *file, | |||
52 | return ret; | 52 | return ret; |
53 | } | 53 | } |
54 | 54 | ||
55 | drm_gem_object_unreference(&obj->base); | 55 | drm_gem_object_unreference_unlocked(&obj->base); |
56 | *handle_p = handle; | 56 | *handle_p = handle; |
57 | return 0; | 57 | return 0; |
58 | } | 58 | } |