Commit 020a0bbc authored by Dave Airlie's avatar Dave Airlie

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
parents 672c9891 16976085
...@@ -139,6 +139,7 @@ struct msm_dsi_host { ...@@ -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) ...@@ -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, ...@@ -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, ...@@ -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) ...@@ -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;
......
...@@ -521,6 +521,7 @@ static int pll_28nm_register(struct dsi_pll_28nm *pll_28nm) ...@@ -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;
......
...@@ -412,6 +412,7 @@ static int pll_28nm_register(struct dsi_pll_28nm *pll_28nm) ...@@ -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;
......
...@@ -702,6 +702,7 @@ static struct clk_init_data pll_init = { ...@@ -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)
......
...@@ -424,6 +424,7 @@ static struct clk_init_data pll_init = { ...@@ -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)
......
...@@ -272,7 +272,7 @@ const struct mdp5_cfg_hw msm8x16_config = { ...@@ -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 = { ...@@ -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,
}, },
......
...@@ -223,12 +223,7 @@ static void blend_setup(struct drm_crtc *crtc) ...@@ -223,12 +223,7 @@ static void blend_setup(struct drm_crtc *crtc)
plane_cnt++; plane_cnt++;
} }
/* if (!pstates[STAGE_BASE]) {
* 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) {
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) ...@@ -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, ...@@ -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, ...@@ -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);
......
...@@ -292,8 +292,7 @@ static int mdp5_plane_atomic_check(struct drm_plane *plane, ...@@ -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, DBG("Pipe doesn't support YUV\n");
"Pipe doesn't support YUV\n");
return -EINVAL; return -EINVAL;
} }
...@@ -301,8 +300,7 @@ static int mdp5_plane_atomic_check(struct drm_plane *plane, ...@@ -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, DBG("Pipe doesn't support scaling (%dx%d -> %dx%d)\n",
"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, ...@@ -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, DBG("Pipe doesn't support flip\n");
"Pipe doesn't support flip\n");
return -EINVAL; return -EINVAL;
} }
......
...@@ -228,7 +228,7 @@ static int msm_drm_uninit(struct device *dev) ...@@ -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) {
......
...@@ -163,6 +163,9 @@ void msm_gem_shrinker_init(struct drm_device *dev) ...@@ -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);
}
} }
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment