diff options
author | Dave Airlie <airlied@redhat.com> | 2016-11-06 18:41:10 -0500 |
---|---|---|
committer | Dave Airlie <airlied@redhat.com> | 2016-11-06 18:41:10 -0500 |
commit | 020a0bbc0d89c15693e69ed2063584ef7ec2d811 (patch) | |
tree | 7ae26a678e3829475009e6263007e5b0ec043050 | |
parent | 672c98915891285b04b97ea6112c7db507903595 (diff) | |
parent | 16976085a114ae293c6fa7a463d74600ffcfeb4b (diff) |
Merge branch 'msm-fixes-4.9' of git://people.freedesktop.org/~robclark/linux into drm-fixes
Fixes for some msm issues
* 'msm-fixes-4.9' of git://people.freedesktop.org/~robclark/linux:
drm/msm: Fix error handling crashes seen when VRAM allocation fails
drm/msm/mdp5: 8x16 actually has 8 mixer stages
drm/msm/mdp5: no scaling support on RGBn pipes for 8x16
drm/msm/mdp5: handle non-fullscreen base plane case
drm/msm: Set CLK_IGNORE_UNUSED flag for PLL clocks
drm/msm/dsi: Queue HPD helper work in attach/detach callbacks
-rw-r--r-- | drivers/gpu/drm/msm/dsi/dsi_host.c | 14 | ||||
-rw-r--r-- | drivers/gpu/drm/msm/dsi/pll/dsi_pll_28nm.c | 1 | ||||
-rw-r--r-- | drivers/gpu/drm/msm/dsi/pll/dsi_pll_28nm_8960.c | 1 | ||||
-rw-r--r-- | drivers/gpu/drm/msm/hdmi/hdmi_phy_8996.c | 1 | ||||
-rw-r--r-- | drivers/gpu/drm/msm/hdmi/hdmi_pll_8960.c | 1 | ||||
-rw-r--r-- | drivers/gpu/drm/msm/mdp/mdp5/mdp5_cfg.c | 4 | ||||
-rw-r--r-- | drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c | 46 | ||||
-rw-r--r-- | drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c | 9 | ||||
-rw-r--r-- | drivers/gpu/drm/msm/msm_drv.c | 2 | ||||
-rw-r--r-- | drivers/gpu/drm/msm/msm_gem_shrinker.c | 7 |
10 files changed, 55 insertions, 31 deletions
diff --git a/drivers/gpu/drm/msm/dsi/dsi_host.c b/drivers/gpu/drm/msm/dsi/dsi_host.c index f05ed0e1f3d6..6f240021705b 100644 --- a/drivers/gpu/drm/msm/dsi/dsi_host.c +++ b/drivers/gpu/drm/msm/dsi/dsi_host.c | |||
@@ -139,6 +139,7 @@ struct msm_dsi_host { | |||
139 | 139 | ||
140 | u32 err_work_state; | 140 | u32 err_work_state; |
141 | struct work_struct err_work; | 141 | struct work_struct err_work; |
142 | struct work_struct hpd_work; | ||
142 | struct workqueue_struct *workqueue; | 143 | struct workqueue_struct *workqueue; |
143 | 144 | ||
144 | /* DSI 6G TX buffer*/ | 145 | /* DSI 6G TX buffer*/ |
@@ -1294,6 +1295,14 @@ static void dsi_sw_reset_restore(struct msm_dsi_host *msm_host) | |||
1294 | wmb(); /* make sure dsi controller enabled again */ | 1295 | wmb(); /* make sure dsi controller enabled again */ |
1295 | } | 1296 | } |
1296 | 1297 | ||
1298 | static void dsi_hpd_worker(struct work_struct *work) | ||
1299 | { | ||
1300 | struct msm_dsi_host *msm_host = | ||
1301 | container_of(work, struct msm_dsi_host, hpd_work); | ||
1302 | |||
1303 | drm_helper_hpd_irq_event(msm_host->dev); | ||
1304 | } | ||
1305 | |||
1297 | static void dsi_err_worker(struct work_struct *work) | 1306 | static void dsi_err_worker(struct work_struct *work) |
1298 | { | 1307 | { |
1299 | struct msm_dsi_host *msm_host = | 1308 | struct msm_dsi_host *msm_host = |
@@ -1480,7 +1489,7 @@ static int dsi_host_attach(struct mipi_dsi_host *host, | |||
1480 | 1489 | ||
1481 | DBG("id=%d", msm_host->id); | 1490 | DBG("id=%d", msm_host->id); |
1482 | if (msm_host->dev) | 1491 | if (msm_host->dev) |
1483 | drm_helper_hpd_irq_event(msm_host->dev); | 1492 | queue_work(msm_host->workqueue, &msm_host->hpd_work); |
1484 | 1493 | ||
1485 | return 0; | 1494 | return 0; |
1486 | } | 1495 | } |
@@ -1494,7 +1503,7 @@ static int dsi_host_detach(struct mipi_dsi_host *host, | |||
1494 | 1503 | ||
1495 | DBG("id=%d", msm_host->id); | 1504 | DBG("id=%d", msm_host->id); |
1496 | if (msm_host->dev) | 1505 | if (msm_host->dev) |
1497 | drm_helper_hpd_irq_event(msm_host->dev); | 1506 | queue_work(msm_host->workqueue, &msm_host->hpd_work); |
1498 | 1507 | ||
1499 | return 0; | 1508 | return 0; |
1500 | } | 1509 | } |
@@ -1748,6 +1757,7 @@ int msm_dsi_host_init(struct msm_dsi *msm_dsi) | |||
1748 | /* setup workqueue */ | 1757 | /* setup workqueue */ |
1749 | msm_host->workqueue = alloc_ordered_workqueue("dsi_drm_work", 0); | 1758 | msm_host->workqueue = alloc_ordered_workqueue("dsi_drm_work", 0); |
1750 | INIT_WORK(&msm_host->err_work, dsi_err_worker); | 1759 | INIT_WORK(&msm_host->err_work, dsi_err_worker); |
1760 | INIT_WORK(&msm_host->hpd_work, dsi_hpd_worker); | ||
1751 | 1761 | ||
1752 | msm_dsi->host = &msm_host->base; | 1762 | msm_dsi->host = &msm_host->base; |
1753 | msm_dsi->id = msm_host->id; | 1763 | msm_dsi->id = msm_host->id; |
diff --git a/drivers/gpu/drm/msm/dsi/pll/dsi_pll_28nm.c b/drivers/gpu/drm/msm/dsi/pll/dsi_pll_28nm.c index 598fdaff0a41..26e3a01a99c2 100644 --- a/drivers/gpu/drm/msm/dsi/pll/dsi_pll_28nm.c +++ b/drivers/gpu/drm/msm/dsi/pll/dsi_pll_28nm.c | |||
@@ -521,6 +521,7 @@ static int pll_28nm_register(struct dsi_pll_28nm *pll_28nm) | |||
521 | .parent_names = (const char *[]){ "xo" }, | 521 | .parent_names = (const char *[]){ "xo" }, |
522 | .num_parents = 1, | 522 | .num_parents = 1, |
523 | .name = vco_name, | 523 | .name = vco_name, |
524 | .flags = CLK_IGNORE_UNUSED, | ||
524 | .ops = &clk_ops_dsi_pll_28nm_vco, | 525 | .ops = &clk_ops_dsi_pll_28nm_vco, |
525 | }; | 526 | }; |
526 | struct device *dev = &pll_28nm->pdev->dev; | 527 | struct device *dev = &pll_28nm->pdev->dev; |
diff --git a/drivers/gpu/drm/msm/dsi/pll/dsi_pll_28nm_8960.c b/drivers/gpu/drm/msm/dsi/pll/dsi_pll_28nm_8960.c index 38c90e1eb002..49008451085b 100644 --- a/drivers/gpu/drm/msm/dsi/pll/dsi_pll_28nm_8960.c +++ b/drivers/gpu/drm/msm/dsi/pll/dsi_pll_28nm_8960.c | |||
@@ -412,6 +412,7 @@ static int pll_28nm_register(struct dsi_pll_28nm *pll_28nm) | |||
412 | struct clk_init_data vco_init = { | 412 | struct clk_init_data vco_init = { |
413 | .parent_names = (const char *[]){ "pxo" }, | 413 | .parent_names = (const char *[]){ "pxo" }, |
414 | .num_parents = 1, | 414 | .num_parents = 1, |
415 | .flags = CLK_IGNORE_UNUSED, | ||
415 | .ops = &clk_ops_dsi_pll_28nm_vco, | 416 | .ops = &clk_ops_dsi_pll_28nm_vco, |
416 | }; | 417 | }; |
417 | struct device *dev = &pll_28nm->pdev->dev; | 418 | struct device *dev = &pll_28nm->pdev->dev; |
diff --git a/drivers/gpu/drm/msm/hdmi/hdmi_phy_8996.c b/drivers/gpu/drm/msm/hdmi/hdmi_phy_8996.c index aa94a553794f..143eab46ba68 100644 --- a/drivers/gpu/drm/msm/hdmi/hdmi_phy_8996.c +++ b/drivers/gpu/drm/msm/hdmi/hdmi_phy_8996.c | |||
@@ -702,6 +702,7 @@ static struct clk_init_data pll_init = { | |||
702 | .ops = &hdmi_8996_pll_ops, | 702 | .ops = &hdmi_8996_pll_ops, |
703 | .parent_names = hdmi_pll_parents, | 703 | .parent_names = hdmi_pll_parents, |
704 | .num_parents = ARRAY_SIZE(hdmi_pll_parents), | 704 | .num_parents = ARRAY_SIZE(hdmi_pll_parents), |
705 | .flags = CLK_IGNORE_UNUSED, | ||
705 | }; | 706 | }; |
706 | 707 | ||
707 | int msm_hdmi_pll_8996_init(struct platform_device *pdev) | 708 | int msm_hdmi_pll_8996_init(struct platform_device *pdev) |
diff --git a/drivers/gpu/drm/msm/hdmi/hdmi_pll_8960.c b/drivers/gpu/drm/msm/hdmi/hdmi_pll_8960.c index 92da69aa6187..99590758c68b 100644 --- a/drivers/gpu/drm/msm/hdmi/hdmi_pll_8960.c +++ b/drivers/gpu/drm/msm/hdmi/hdmi_pll_8960.c | |||
@@ -424,6 +424,7 @@ static struct clk_init_data pll_init = { | |||
424 | .ops = &hdmi_pll_ops, | 424 | .ops = &hdmi_pll_ops, |
425 | .parent_names = hdmi_pll_parents, | 425 | .parent_names = hdmi_pll_parents, |
426 | .num_parents = ARRAY_SIZE(hdmi_pll_parents), | 426 | .num_parents = ARRAY_SIZE(hdmi_pll_parents), |
427 | .flags = CLK_IGNORE_UNUSED, | ||
427 | }; | 428 | }; |
428 | 429 | ||
429 | int msm_hdmi_pll_8960_init(struct platform_device *pdev) | 430 | int msm_hdmi_pll_8960_init(struct platform_device *pdev) |
diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_cfg.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_cfg.c index ac9e4cde1380..8b4e3004f451 100644 --- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_cfg.c +++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_cfg.c | |||
@@ -272,7 +272,7 @@ const struct mdp5_cfg_hw msm8x16_config = { | |||
272 | .count = 2, | 272 | .count = 2, |
273 | .base = { 0x14000, 0x16000 }, | 273 | .base = { 0x14000, 0x16000 }, |
274 | .caps = MDP_PIPE_CAP_HFLIP | MDP_PIPE_CAP_VFLIP | | 274 | .caps = MDP_PIPE_CAP_HFLIP | MDP_PIPE_CAP_VFLIP | |
275 | MDP_PIPE_CAP_SCALE | MDP_PIPE_CAP_DECIMATION, | 275 | MDP_PIPE_CAP_DECIMATION, |
276 | }, | 276 | }, |
277 | .pipe_dma = { | 277 | .pipe_dma = { |
278 | .count = 1, | 278 | .count = 1, |
@@ -282,7 +282,7 @@ const struct mdp5_cfg_hw msm8x16_config = { | |||
282 | .lm = { | 282 | .lm = { |
283 | .count = 2, /* LM0 and LM3 */ | 283 | .count = 2, /* LM0 and LM3 */ |
284 | .base = { 0x44000, 0x47000 }, | 284 | .base = { 0x44000, 0x47000 }, |
285 | .nb_stages = 5, | 285 | .nb_stages = 8, |
286 | .max_width = 2048, | 286 | .max_width = 2048, |
287 | .max_height = 0xFFFF, | 287 | .max_height = 0xFFFF, |
288 | }, | 288 | }, |
diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c index fa2be7ce9468..c205c360e16d 100644 --- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c +++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c | |||
@@ -223,12 +223,7 @@ static void blend_setup(struct drm_crtc *crtc) | |||
223 | plane_cnt++; | 223 | plane_cnt++; |
224 | } | 224 | } |
225 | 225 | ||
226 | /* | 226 | if (!pstates[STAGE_BASE]) { |
227 | * If there is no base layer, enable border color. | ||
228 | * Although it's not possbile in current blend logic, | ||
229 | * put it here as a reminder. | ||
230 | */ | ||
231 | if (!pstates[STAGE_BASE] && plane_cnt) { | ||
232 | ctl_blend_flags |= MDP5_CTL_BLEND_OP_FLAG_BORDER_OUT; | 227 | ctl_blend_flags |= MDP5_CTL_BLEND_OP_FLAG_BORDER_OUT; |
233 | DBG("Border Color is enabled"); | 228 | DBG("Border Color is enabled"); |
234 | } | 229 | } |
@@ -365,6 +360,15 @@ static int pstate_cmp(const void *a, const void *b) | |||
365 | return pa->state->zpos - pb->state->zpos; | 360 | return pa->state->zpos - pb->state->zpos; |
366 | } | 361 | } |
367 | 362 | ||
363 | /* is there a helper for this? */ | ||
364 | static bool is_fullscreen(struct drm_crtc_state *cstate, | ||
365 | struct drm_plane_state *pstate) | ||
366 | { | ||
367 | return (pstate->crtc_x <= 0) && (pstate->crtc_y <= 0) && | ||
368 | ((pstate->crtc_x + pstate->crtc_w) >= cstate->mode.hdisplay) && | ||
369 | ((pstate->crtc_y + pstate->crtc_h) >= cstate->mode.vdisplay); | ||
370 | } | ||
371 | |||
368 | static int mdp5_crtc_atomic_check(struct drm_crtc *crtc, | 372 | static int mdp5_crtc_atomic_check(struct drm_crtc *crtc, |
369 | struct drm_crtc_state *state) | 373 | struct drm_crtc_state *state) |
370 | { | 374 | { |
@@ -375,21 +379,11 @@ static int mdp5_crtc_atomic_check(struct drm_crtc *crtc, | |||
375 | struct plane_state pstates[STAGE_MAX + 1]; | 379 | struct plane_state pstates[STAGE_MAX + 1]; |
376 | const struct mdp5_cfg_hw *hw_cfg; | 380 | const struct mdp5_cfg_hw *hw_cfg; |
377 | const struct drm_plane_state *pstate; | 381 | const struct drm_plane_state *pstate; |
378 | int cnt = 0, i; | 382 | int cnt = 0, base = 0, i; |
379 | 383 | ||
380 | DBG("%s: check", mdp5_crtc->name); | 384 | DBG("%s: check", mdp5_crtc->name); |
381 | 385 | ||
382 | /* verify that there are not too many planes attached to crtc | ||
383 | * and that we don't have conflicting mixer stages: | ||
384 | */ | ||
385 | hw_cfg = mdp5_cfg_get_hw_config(mdp5_kms->cfg); | ||
386 | drm_atomic_crtc_state_for_each_plane_state(plane, pstate, state) { | 386 | drm_atomic_crtc_state_for_each_plane_state(plane, pstate, state) { |
387 | if (cnt >= (hw_cfg->lm.nb_stages)) { | ||
388 | dev_err(dev->dev, "too many planes!\n"); | ||
389 | return -EINVAL; | ||
390 | } | ||
391 | |||
392 | |||
393 | pstates[cnt].plane = plane; | 387 | pstates[cnt].plane = plane; |
394 | pstates[cnt].state = to_mdp5_plane_state(pstate); | 388 | pstates[cnt].state = to_mdp5_plane_state(pstate); |
395 | 389 | ||
@@ -399,8 +393,24 @@ static int mdp5_crtc_atomic_check(struct drm_crtc *crtc, | |||
399 | /* assign a stage based on sorted zpos property */ | 393 | /* assign a stage based on sorted zpos property */ |
400 | sort(pstates, cnt, sizeof(pstates[0]), pstate_cmp, NULL); | 394 | sort(pstates, cnt, sizeof(pstates[0]), pstate_cmp, NULL); |
401 | 395 | ||
396 | /* if the bottom-most layer is not fullscreen, we need to use | ||
397 | * it for solid-color: | ||
398 | */ | ||
399 | if ((cnt > 0) && !is_fullscreen(state, &pstates[0].state->base)) | ||
400 | base++; | ||
401 | |||
402 | /* verify that there are not too many planes attached to crtc | ||
403 | * and that we don't have conflicting mixer stages: | ||
404 | */ | ||
405 | hw_cfg = mdp5_cfg_get_hw_config(mdp5_kms->cfg); | ||
406 | |||
407 | if ((cnt + base) >= hw_cfg->lm.nb_stages) { | ||
408 | dev_err(dev->dev, "too many planes!\n"); | ||
409 | return -EINVAL; | ||
410 | } | ||
411 | |||
402 | for (i = 0; i < cnt; i++) { | 412 | for (i = 0; i < cnt; i++) { |
403 | pstates[i].state->stage = STAGE_BASE + i; | 413 | pstates[i].state->stage = STAGE_BASE + i + base; |
404 | DBG("%s: assign pipe %s on stage=%d", mdp5_crtc->name, | 414 | DBG("%s: assign pipe %s on stage=%d", mdp5_crtc->name, |
405 | pipe2name(mdp5_plane_pipe(pstates[i].plane)), | 415 | pipe2name(mdp5_plane_pipe(pstates[i].plane)), |
406 | pstates[i].state->stage); | 416 | pstates[i].state->stage); |
diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c index 951c002b05df..83bf997dda03 100644 --- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c +++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c | |||
@@ -292,8 +292,7 @@ static int mdp5_plane_atomic_check(struct drm_plane *plane, | |||
292 | format = to_mdp_format(msm_framebuffer_format(state->fb)); | 292 | format = to_mdp_format(msm_framebuffer_format(state->fb)); |
293 | if (MDP_FORMAT_IS_YUV(format) && | 293 | if (MDP_FORMAT_IS_YUV(format) && |
294 | !pipe_supports_yuv(mdp5_plane->caps)) { | 294 | !pipe_supports_yuv(mdp5_plane->caps)) { |
295 | dev_err(plane->dev->dev, | 295 | DBG("Pipe doesn't support YUV\n"); |
296 | "Pipe doesn't support YUV\n"); | ||
297 | 296 | ||
298 | return -EINVAL; | 297 | return -EINVAL; |
299 | } | 298 | } |
@@ -301,8 +300,7 @@ static int mdp5_plane_atomic_check(struct drm_plane *plane, | |||
301 | if (!(mdp5_plane->caps & MDP_PIPE_CAP_SCALE) && | 300 | if (!(mdp5_plane->caps & MDP_PIPE_CAP_SCALE) && |
302 | (((state->src_w >> 16) != state->crtc_w) || | 301 | (((state->src_w >> 16) != state->crtc_w) || |
303 | ((state->src_h >> 16) != state->crtc_h))) { | 302 | ((state->src_h >> 16) != state->crtc_h))) { |
304 | dev_err(plane->dev->dev, | 303 | DBG("Pipe doesn't support scaling (%dx%d -> %dx%d)\n", |
305 | "Pipe doesn't support scaling (%dx%d -> %dx%d)\n", | ||
306 | state->src_w >> 16, state->src_h >> 16, | 304 | state->src_w >> 16, state->src_h >> 16, |
307 | state->crtc_w, state->crtc_h); | 305 | state->crtc_w, state->crtc_h); |
308 | 306 | ||
@@ -313,8 +311,7 @@ static int mdp5_plane_atomic_check(struct drm_plane *plane, | |||
313 | vflip = !!(state->rotation & DRM_REFLECT_Y); | 311 | vflip = !!(state->rotation & DRM_REFLECT_Y); |
314 | if ((vflip && !(mdp5_plane->caps & MDP_PIPE_CAP_VFLIP)) || | 312 | if ((vflip && !(mdp5_plane->caps & MDP_PIPE_CAP_VFLIP)) || |
315 | (hflip && !(mdp5_plane->caps & MDP_PIPE_CAP_HFLIP))) { | 313 | (hflip && !(mdp5_plane->caps & MDP_PIPE_CAP_HFLIP))) { |
316 | dev_err(plane->dev->dev, | 314 | DBG("Pipe doesn't support flip\n"); |
317 | "Pipe doesn't support flip\n"); | ||
318 | 315 | ||
319 | return -EINVAL; | 316 | return -EINVAL; |
320 | } | 317 | } |
diff --git a/drivers/gpu/drm/msm/msm_drv.c b/drivers/gpu/drm/msm/msm_drv.c index fb5c0b0a7594..46568fc80848 100644 --- a/drivers/gpu/drm/msm/msm_drv.c +++ b/drivers/gpu/drm/msm/msm_drv.c | |||
@@ -228,7 +228,7 @@ static int msm_drm_uninit(struct device *dev) | |||
228 | flush_workqueue(priv->atomic_wq); | 228 | flush_workqueue(priv->atomic_wq); |
229 | destroy_workqueue(priv->atomic_wq); | 229 | destroy_workqueue(priv->atomic_wq); |
230 | 230 | ||
231 | if (kms) | 231 | if (kms && kms->funcs) |
232 | kms->funcs->destroy(kms); | 232 | kms->funcs->destroy(kms); |
233 | 233 | ||
234 | if (gpu) { | 234 | if (gpu) { |
diff --git a/drivers/gpu/drm/msm/msm_gem_shrinker.c b/drivers/gpu/drm/msm/msm_gem_shrinker.c index 283d2841ba58..192b2d3a79cb 100644 --- a/drivers/gpu/drm/msm/msm_gem_shrinker.c +++ b/drivers/gpu/drm/msm/msm_gem_shrinker.c | |||
@@ -163,6 +163,9 @@ void msm_gem_shrinker_init(struct drm_device *dev) | |||
163 | void msm_gem_shrinker_cleanup(struct drm_device *dev) | 163 | void msm_gem_shrinker_cleanup(struct drm_device *dev) |
164 | { | 164 | { |
165 | struct msm_drm_private *priv = dev->dev_private; | 165 | struct msm_drm_private *priv = dev->dev_private; |
166 | WARN_ON(unregister_vmap_purge_notifier(&priv->vmap_notifier)); | 166 | |
167 | unregister_shrinker(&priv->shrinker); | 167 | if (priv->shrinker.nr_deferred) { |
168 | WARN_ON(unregister_vmap_purge_notifier(&priv->vmap_notifier)); | ||
169 | unregister_shrinker(&priv->shrinker); | ||
170 | } | ||
168 | } | 171 | } |