Browse Source

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
Dave Airlie 8 years ago
parent
commit
020a0bbc0d

+ 12 - 2
drivers/gpu/drm/msm/dsi/dsi_host.c

@@ -139,6 +139,7 @@ struct msm_dsi_host {
 
 
 	u32 err_work_state;
 	u32 err_work_state;
 	struct work_struct err_work;
 	struct work_struct err_work;
+	struct work_struct hpd_work;
 	struct workqueue_struct *workqueue;
 	struct workqueue_struct *workqueue;
 
 
 	/* DSI 6G TX buffer*/
 	/* DSI 6G TX buffer*/
@@ -1294,6 +1295,14 @@ static void dsi_sw_reset_restore(struct msm_dsi_host *msm_host)
 	wmb();	/* make sure dsi controller enabled again */
 	wmb();	/* make sure dsi controller enabled again */
 }
 }
 
 
+static void dsi_hpd_worker(struct work_struct *work)
+{
+	struct msm_dsi_host *msm_host =
+		container_of(work, struct msm_dsi_host, hpd_work);
+
+	drm_helper_hpd_irq_event(msm_host->dev);
+}
+
 static void dsi_err_worker(struct work_struct *work)
 static void dsi_err_worker(struct work_struct *work)
 {
 {
 	struct msm_dsi_host *msm_host =
 	struct msm_dsi_host *msm_host =
@@ -1480,7 +1489,7 @@ static int dsi_host_attach(struct mipi_dsi_host *host,
 
 
 	DBG("id=%d", msm_host->id);
 	DBG("id=%d", msm_host->id);
 	if (msm_host->dev)
 	if (msm_host->dev)
-		drm_helper_hpd_irq_event(msm_host->dev);
+		queue_work(msm_host->workqueue, &msm_host->hpd_work);
 
 
 	return 0;
 	return 0;
 }
 }
@@ -1494,7 +1503,7 @@ static int dsi_host_detach(struct mipi_dsi_host *host,
 
 
 	DBG("id=%d", msm_host->id);
 	DBG("id=%d", msm_host->id);
 	if (msm_host->dev)
 	if (msm_host->dev)
-		drm_helper_hpd_irq_event(msm_host->dev);
+		queue_work(msm_host->workqueue, &msm_host->hpd_work);
 
 
 	return 0;
 	return 0;
 }
 }
@@ -1748,6 +1757,7 @@ int msm_dsi_host_init(struct msm_dsi *msm_dsi)
 	/* setup workqueue */
 	/* setup workqueue */
 	msm_host->workqueue = alloc_ordered_workqueue("dsi_drm_work", 0);
 	msm_host->workqueue = alloc_ordered_workqueue("dsi_drm_work", 0);
 	INIT_WORK(&msm_host->err_work, dsi_err_worker);
 	INIT_WORK(&msm_host->err_work, dsi_err_worker);
+	INIT_WORK(&msm_host->hpd_work, dsi_hpd_worker);
 
 
 	msm_dsi->host = &msm_host->base;
 	msm_dsi->host = &msm_host->base;
 	msm_dsi->id = msm_host->id;
 	msm_dsi->id = msm_host->id;

+ 1 - 0
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)
 		.parent_names = (const char *[]){ "xo" },
 		.parent_names = (const char *[]){ "xo" },
 		.num_parents = 1,
 		.num_parents = 1,
 		.name = vco_name,
 		.name = vco_name,
+		.flags = CLK_IGNORE_UNUSED,
 		.ops = &clk_ops_dsi_pll_28nm_vco,
 		.ops = &clk_ops_dsi_pll_28nm_vco,
 	};
 	};
 	struct device *dev = &pll_28nm->pdev->dev;
 	struct device *dev = &pll_28nm->pdev->dev;

+ 1 - 0
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)
 	struct clk_init_data vco_init = {
 	struct clk_init_data vco_init = {
 		.parent_names = (const char *[]){ "pxo" },
 		.parent_names = (const char *[]){ "pxo" },
 		.num_parents = 1,
 		.num_parents = 1,
+		.flags = CLK_IGNORE_UNUSED,
 		.ops = &clk_ops_dsi_pll_28nm_vco,
 		.ops = &clk_ops_dsi_pll_28nm_vco,
 	};
 	};
 	struct device *dev = &pll_28nm->pdev->dev;
 	struct device *dev = &pll_28nm->pdev->dev;

+ 1 - 0
drivers/gpu/drm/msm/hdmi/hdmi_phy_8996.c

@@ -702,6 +702,7 @@ static struct clk_init_data pll_init = {
 	.ops = &hdmi_8996_pll_ops,
 	.ops = &hdmi_8996_pll_ops,
 	.parent_names = hdmi_pll_parents,
 	.parent_names = hdmi_pll_parents,
 	.num_parents = ARRAY_SIZE(hdmi_pll_parents),
 	.num_parents = ARRAY_SIZE(hdmi_pll_parents),
+	.flags = CLK_IGNORE_UNUSED,
 };
 };
 
 
 int msm_hdmi_pll_8996_init(struct platform_device *pdev)
 int msm_hdmi_pll_8996_init(struct platform_device *pdev)

+ 1 - 0
drivers/gpu/drm/msm/hdmi/hdmi_pll_8960.c

@@ -424,6 +424,7 @@ static struct clk_init_data pll_init = {
 	.ops = &hdmi_pll_ops,
 	.ops = &hdmi_pll_ops,
 	.parent_names = hdmi_pll_parents,
 	.parent_names = hdmi_pll_parents,
 	.num_parents = ARRAY_SIZE(hdmi_pll_parents),
 	.num_parents = ARRAY_SIZE(hdmi_pll_parents),
+	.flags = CLK_IGNORE_UNUSED,
 };
 };
 
 
 int msm_hdmi_pll_8960_init(struct platform_device *pdev)
 int msm_hdmi_pll_8960_init(struct platform_device *pdev)

+ 2 - 2
drivers/gpu/drm/msm/mdp/mdp5/mdp5_cfg.c

@@ -272,7 +272,7 @@ const struct mdp5_cfg_hw msm8x16_config = {
 		.count = 2,
 		.count = 2,
 		.base = { 0x14000, 0x16000 },
 		.base = { 0x14000, 0x16000 },
 		.caps = MDP_PIPE_CAP_HFLIP | MDP_PIPE_CAP_VFLIP |
 		.caps = MDP_PIPE_CAP_HFLIP | MDP_PIPE_CAP_VFLIP |
-				MDP_PIPE_CAP_SCALE | MDP_PIPE_CAP_DECIMATION,
+				MDP_PIPE_CAP_DECIMATION,
 	},
 	},
 	.pipe_dma = {
 	.pipe_dma = {
 		.count = 1,
 		.count = 1,
@@ -282,7 +282,7 @@ const struct mdp5_cfg_hw msm8x16_config = {
 	.lm = {
 	.lm = {
 		.count = 2, /* LM0 and LM3 */
 		.count = 2, /* LM0 and LM3 */
 		.base = { 0x44000, 0x47000 },
 		.base = { 0x44000, 0x47000 },
-		.nb_stages = 5,
+		.nb_stages = 8,
 		.max_width = 2048,
 		.max_width = 2048,
 		.max_height = 0xFFFF,
 		.max_height = 0xFFFF,
 	},
 	},

+ 28 - 18
drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c

@@ -223,12 +223,7 @@ static void blend_setup(struct drm_crtc *crtc)
 		plane_cnt++;
 		plane_cnt++;
 	}
 	}
 
 
-	/*
-	* If there is no base layer, enable border color.
-	* Although it's not possbile in current blend logic,
-	* put it here as a reminder.
-	*/
-	if (!pstates[STAGE_BASE] && plane_cnt) {
+	if (!pstates[STAGE_BASE]) {
 		ctl_blend_flags |= MDP5_CTL_BLEND_OP_FLAG_BORDER_OUT;
 		ctl_blend_flags |= MDP5_CTL_BLEND_OP_FLAG_BORDER_OUT;
 		DBG("Border Color is enabled");
 		DBG("Border Color is enabled");
 	}
 	}
@@ -365,6 +360,15 @@ static int pstate_cmp(const void *a, const void *b)
 	return pa->state->zpos - pb->state->zpos;
 	return pa->state->zpos - pb->state->zpos;
 }
 }
 
 
+/* is there a helper for this? */
+static bool is_fullscreen(struct drm_crtc_state *cstate,
+		struct drm_plane_state *pstate)
+{
+	return (pstate->crtc_x <= 0) && (pstate->crtc_y <= 0) &&
+		((pstate->crtc_x + pstate->crtc_w) >= cstate->mode.hdisplay) &&
+		((pstate->crtc_y + pstate->crtc_h) >= cstate->mode.vdisplay);
+}
+
 static int mdp5_crtc_atomic_check(struct drm_crtc *crtc,
 static int mdp5_crtc_atomic_check(struct drm_crtc *crtc,
 		struct drm_crtc_state *state)
 		struct drm_crtc_state *state)
 {
 {
@@ -375,21 +379,11 @@ static int mdp5_crtc_atomic_check(struct drm_crtc *crtc,
 	struct plane_state pstates[STAGE_MAX + 1];
 	struct plane_state pstates[STAGE_MAX + 1];
 	const struct mdp5_cfg_hw *hw_cfg;
 	const struct mdp5_cfg_hw *hw_cfg;
 	const struct drm_plane_state *pstate;
 	const struct drm_plane_state *pstate;
-	int cnt = 0, i;
+	int cnt = 0, base = 0, i;
 
 
 	DBG("%s: check", mdp5_crtc->name);
 	DBG("%s: check", mdp5_crtc->name);
 
 
-	/* verify that there are not too many planes attached to crtc
-	 * and that we don't have conflicting mixer stages:
-	 */
-	hw_cfg = mdp5_cfg_get_hw_config(mdp5_kms->cfg);
 	drm_atomic_crtc_state_for_each_plane_state(plane, pstate, state) {
 	drm_atomic_crtc_state_for_each_plane_state(plane, pstate, state) {
-		if (cnt >= (hw_cfg->lm.nb_stages)) {
-			dev_err(dev->dev, "too many planes!\n");
-			return -EINVAL;
-		}
-
-
 		pstates[cnt].plane = plane;
 		pstates[cnt].plane = plane;
 		pstates[cnt].state = to_mdp5_plane_state(pstate);
 		pstates[cnt].state = to_mdp5_plane_state(pstate);
 
 
@@ -399,8 +393,24 @@ static int mdp5_crtc_atomic_check(struct drm_crtc *crtc,
 	/* assign a stage based on sorted zpos property */
 	/* assign a stage based on sorted zpos property */
 	sort(pstates, cnt, sizeof(pstates[0]), pstate_cmp, NULL);
 	sort(pstates, cnt, sizeof(pstates[0]), pstate_cmp, NULL);
 
 
+	/* if the bottom-most layer is not fullscreen, we need to use
+	 * it for solid-color:
+	 */
+	if ((cnt > 0) && !is_fullscreen(state, &pstates[0].state->base))
+		base++;
+
+	/* verify that there are not too many planes attached to crtc
+	 * and that we don't have conflicting mixer stages:
+	 */
+	hw_cfg = mdp5_cfg_get_hw_config(mdp5_kms->cfg);
+
+	if ((cnt + base) >= hw_cfg->lm.nb_stages) {
+		dev_err(dev->dev, "too many planes!\n");
+		return -EINVAL;
+	}
+
 	for (i = 0; i < cnt; i++) {
 	for (i = 0; i < cnt; i++) {
-		pstates[i].state->stage = STAGE_BASE + i;
+		pstates[i].state->stage = STAGE_BASE + i + base;
 		DBG("%s: assign pipe %s on stage=%d", mdp5_crtc->name,
 		DBG("%s: assign pipe %s on stage=%d", mdp5_crtc->name,
 				pipe2name(mdp5_plane_pipe(pstates[i].plane)),
 				pipe2name(mdp5_plane_pipe(pstates[i].plane)),
 				pstates[i].state->stage);
 				pstates[i].state->stage);

+ 3 - 6
drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c

@@ -292,8 +292,7 @@ static int mdp5_plane_atomic_check(struct drm_plane *plane,
 		format = to_mdp_format(msm_framebuffer_format(state->fb));
 		format = to_mdp_format(msm_framebuffer_format(state->fb));
 		if (MDP_FORMAT_IS_YUV(format) &&
 		if (MDP_FORMAT_IS_YUV(format) &&
 			!pipe_supports_yuv(mdp5_plane->caps)) {
 			!pipe_supports_yuv(mdp5_plane->caps)) {
-			dev_err(plane->dev->dev,
-				"Pipe doesn't support YUV\n");
+			DBG("Pipe doesn't support YUV\n");
 
 
 			return -EINVAL;
 			return -EINVAL;
 		}
 		}
@@ -301,8 +300,7 @@ static int mdp5_plane_atomic_check(struct drm_plane *plane,
 		if (!(mdp5_plane->caps & MDP_PIPE_CAP_SCALE) &&
 		if (!(mdp5_plane->caps & MDP_PIPE_CAP_SCALE) &&
 			(((state->src_w >> 16) != state->crtc_w) ||
 			(((state->src_w >> 16) != state->crtc_w) ||
 			((state->src_h >> 16) != state->crtc_h))) {
 			((state->src_h >> 16) != state->crtc_h))) {
-			dev_err(plane->dev->dev,
-				"Pipe doesn't support scaling (%dx%d -> %dx%d)\n",
+			DBG("Pipe doesn't support scaling (%dx%d -> %dx%d)\n",
 				state->src_w >> 16, state->src_h >> 16,
 				state->src_w >> 16, state->src_h >> 16,
 				state->crtc_w, state->crtc_h);
 				state->crtc_w, state->crtc_h);
 
 
@@ -313,8 +311,7 @@ static int mdp5_plane_atomic_check(struct drm_plane *plane,
 		vflip = !!(state->rotation & DRM_REFLECT_Y);
 		vflip = !!(state->rotation & DRM_REFLECT_Y);
 		if ((vflip && !(mdp5_plane->caps & MDP_PIPE_CAP_VFLIP)) ||
 		if ((vflip && !(mdp5_plane->caps & MDP_PIPE_CAP_VFLIP)) ||
 			(hflip && !(mdp5_plane->caps & MDP_PIPE_CAP_HFLIP))) {
 			(hflip && !(mdp5_plane->caps & MDP_PIPE_CAP_HFLIP))) {
-			dev_err(plane->dev->dev,
-				"Pipe doesn't support flip\n");
+			DBG("Pipe doesn't support flip\n");
 
 
 			return -EINVAL;
 			return -EINVAL;
 		}
 		}

+ 1 - 1
drivers/gpu/drm/msm/msm_drv.c

@@ -228,7 +228,7 @@ static int msm_drm_uninit(struct device *dev)
 	flush_workqueue(priv->atomic_wq);
 	flush_workqueue(priv->atomic_wq);
 	destroy_workqueue(priv->atomic_wq);
 	destroy_workqueue(priv->atomic_wq);
 
 
-	if (kms)
+	if (kms && kms->funcs)
 		kms->funcs->destroy(kms);
 		kms->funcs->destroy(kms);
 
 
 	if (gpu) {
 	if (gpu) {

+ 5 - 2
drivers/gpu/drm/msm/msm_gem_shrinker.c

@@ -163,6 +163,9 @@ void msm_gem_shrinker_init(struct drm_device *dev)
 void msm_gem_shrinker_cleanup(struct drm_device *dev)
 void msm_gem_shrinker_cleanup(struct drm_device *dev)
 {
 {
 	struct msm_drm_private *priv = dev->dev_private;
 	struct msm_drm_private *priv = dev->dev_private;
-	WARN_ON(unregister_vmap_purge_notifier(&priv->vmap_notifier));
-	unregister_shrinker(&priv->shrinker);
+
+	if (priv->shrinker.nr_deferred) {
+		WARN_ON(unregister_vmap_purge_notifier(&priv->vmap_notifier));
+		unregister_shrinker(&priv->shrinker);
+	}
 }
 }