Merge branch 'drm-rockchip-next-fixes-2016-03-28' of https://github.com/markyzq/kernel-drm-rockchip into drm-fixes

bunch of rockchip fixes.

* 'drm-rockchip-next-fixes-2016-03-28' of https://github.com/markyzq/kernel-drm-rockchip:
  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
This commit is contained in:
Dave Airlie 2016-04-01 13:14:24 +10:00
commit 5456248d66
4 changed files with 100 additions and 15 deletions

View File

@ -271,8 +271,6 @@ static int dw_hdmi_rockchip_bind(struct device *dev, struct device *master,
if (!iores)
return -ENXIO;
platform_set_drvdata(pdev, hdmi);
encoder->possible_crtcs = drm_of_find_possible_crtcs(drm, dev->of_node);
/*
* 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,
drm_encoder_init(drm, encoder, &dw_hdmi_rockchip_encoder_funcs,
DRM_MODE_ENCODER_TMDS, NULL);
return dw_hdmi_bind(dev, master, data, encoder, iores, irq, plat_data);
ret = dw_hdmi_bind(dev, master, data, encoder, iores, irq, plat_data);
/*
* If dw_hdmi_bind() fails we'll never call dw_hdmi_unbind(),
* which would have called the encoder cleanup. Do it manually.
*/
if (ret)
drm_encoder_cleanup(encoder);
return ret;
}
static void dw_hdmi_rockchip_unbind(struct device *dev, struct device *master,

View File

@ -251,6 +251,27 @@ static int rockchip_drm_unload(struct drm_device *drm_dev)
return 0;
}
static void rockchip_drm_crtc_cancel_pending_vblank(struct drm_crtc *crtc,
struct drm_file *file_priv)
{
struct rockchip_drm_private *priv = crtc->dev->dev_private;
int pipe = drm_crtc_index(crtc);
if (pipe < ROCKCHIP_MAX_CRTC &&
priv->crtc_funcs[pipe] &&
priv->crtc_funcs[pipe]->cancel_pending_vblank)
priv->crtc_funcs[pipe]->cancel_pending_vblank(crtc, file_priv);
}
static void rockchip_drm_preclose(struct drm_device *dev,
struct drm_file *file_priv)
{
struct drm_crtc *crtc;
list_for_each_entry(crtc, &dev->mode_config.crtc_list, head)
rockchip_drm_crtc_cancel_pending_vblank(crtc, file_priv);
}
void rockchip_drm_lastclose(struct drm_device *dev)
{
struct rockchip_drm_private *priv = dev->dev_private;
@ -281,6 +302,7 @@ static struct drm_driver rockchip_drm_driver = {
DRIVER_PRIME | DRIVER_ATOMIC,
.load = rockchip_drm_load,
.unload = rockchip_drm_unload,
.preclose = rockchip_drm_preclose,
.lastclose = rockchip_drm_lastclose,
.get_vblank_counter = drm_vblank_no_hw_counter,
.enable_vblank = rockchip_drm_crtc_enable_vblank,

View File

@ -40,6 +40,7 @@ struct rockchip_crtc_funcs {
int (*enable_vblank)(struct drm_crtc *crtc);
void (*disable_vblank)(struct drm_crtc *crtc);
void (*wait_for_update)(struct drm_crtc *crtc);
void (*cancel_pending_vblank)(struct drm_crtc *crtc, struct drm_file *file_priv);
};
struct rockchip_atomic_commit {

View File

@ -499,10 +499,25 @@ static void vop_enable(struct drm_crtc *crtc)
static void vop_crtc_disable(struct drm_crtc *crtc)
{
struct vop *vop = to_vop(crtc);
int i;
if (!vop->is_enabled)
return;
/*
* We need to make sure that all windows are disabled before we
* disable that crtc. Otherwise we might try to scan from a destroyed
* buffer later.
*/
for (i = 0; i < vop->data->win_size; i++) {
struct vop_win *vop_win = &vop->win[i];
const struct vop_win_data *win = vop_win->data;
spin_lock(&vop->reg_lock);
VOP_WIN_SET(vop, win, enable, 0);
spin_unlock(&vop->reg_lock);
}
drm_crtc_vblank_off(crtc);
/*
@ -549,6 +564,7 @@ static int vop_plane_atomic_check(struct drm_plane *plane,
struct drm_plane_state *state)
{
struct drm_crtc *crtc = state->crtc;
struct drm_crtc_state *crtc_state;
struct drm_framebuffer *fb = state->fb;
struct vop_win *vop_win = to_vop_win(plane);
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,
int max_scale = win->phy->scl ? FRAC_16_16(8, 1) :
DRM_PLANE_HELPER_NO_SCALING;
crtc = crtc ? crtc : plane->state->crtc;
/*
* Both crtc or plane->state->crtc can be null.
*/
if (!crtc || !fb)
goto out_disable;
crtc_state = drm_atomic_get_existing_crtc_state(state->state, crtc);
if (WARN_ON(!crtc_state))
return -EINVAL;
src->x1 = state->src_x;
src->y1 = state->src_y;
src->x2 = state->src_x + state->src_w;
@ -580,8 +597,8 @@ static int vop_plane_atomic_check(struct drm_plane *plane,
clip.x1 = 0;
clip.y1 = 0;
clip.x2 = crtc->mode.hdisplay;
clip.y2 = crtc->mode.vdisplay;
clip.x2 = crtc_state->adjusted_mode.hdisplay;
clip.y2 = crtc_state->adjusted_mode.vdisplay;
ret = drm_plane_helper_check_update(plane, crtc, state->fb,
src, dest, &clip,
@ -873,10 +890,30 @@ static void vop_crtc_wait_for_update(struct drm_crtc *crtc)
WARN_ON(!wait_for_completion_timeout(&vop->wait_update_complete, 100));
}
static void vop_crtc_cancel_pending_vblank(struct drm_crtc *crtc,
struct drm_file *file_priv)
{
struct drm_device *drm = crtc->dev;
struct vop *vop = to_vop(crtc);
struct drm_pending_vblank_event *e;
unsigned long flags;
spin_lock_irqsave(&drm->event_lock, flags);
e = vop->event;
if (e && e->base.file_priv == file_priv) {
vop->event = NULL;
e->base.destroy(&e->base);
file_priv->event_space += sizeof(e->event);
}
spin_unlock_irqrestore(&drm->event_lock, flags);
}
static const struct rockchip_crtc_funcs private_crtc_funcs = {
.enable_vblank = vop_crtc_enable_vblank,
.disable_vblank = vop_crtc_disable_vblank,
.wait_for_update = vop_crtc_wait_for_update,
.cancel_pending_vblank = vop_crtc_cancel_pending_vblank,
};
static bool vop_crtc_mode_fixup(struct drm_crtc *crtc,
@ -885,9 +922,6 @@ static bool vop_crtc_mode_fixup(struct drm_crtc *crtc,
{
struct vop *vop = to_vop(crtc);
if (adjusted_mode->htotal == 0 || adjusted_mode->vtotal == 0)
return false;
adjusted_mode->clock =
clk_round_rate(vop->dclk, mode->clock * 1000) / 1000;
@ -1108,7 +1142,7 @@ static int vop_create_crtc(struct vop *vop)
const struct vop_data *vop_data = vop->data;
struct device *dev = vop->dev;
struct drm_device *drm_dev = vop->drm_dev;
struct drm_plane *primary = NULL, *cursor = NULL, *plane;
struct drm_plane *primary = NULL, *cursor = NULL, *plane, *tmp;
struct drm_crtc *crtc = &vop->crtc;
struct device_node *port;
int ret;
@ -1148,7 +1182,7 @@ static int vop_create_crtc(struct vop *vop)
ret = drm_crtc_init_with_planes(drm_dev, crtc, primary, cursor,
&vop_crtc_funcs, NULL);
if (ret)
return ret;
goto err_cleanup_planes;
drm_crtc_helper_add(crtc, &vop_crtc_helper_funcs);
@ -1181,6 +1215,7 @@ static int vop_create_crtc(struct vop *vop)
if (!port) {
DRM_ERROR("no port node found in %s\n",
dev->of_node->full_name);
ret = -ENOENT;
goto err_cleanup_crtc;
}
@ -1194,7 +1229,8 @@ static int vop_create_crtc(struct vop *vop)
err_cleanup_crtc:
drm_crtc_cleanup(crtc);
err_cleanup_planes:
list_for_each_entry(plane, &drm_dev->mode_config.plane_list, head)
list_for_each_entry_safe(plane, tmp, &drm_dev->mode_config.plane_list,
head)
drm_plane_cleanup(plane);
return ret;
}
@ -1202,9 +1238,28 @@ static int vop_create_crtc(struct vop *vop)
static void vop_destroy_crtc(struct vop *vop)
{
struct drm_crtc *crtc = &vop->crtc;
struct drm_device *drm_dev = vop->drm_dev;
struct drm_plane *plane, *tmp;
rockchip_unregister_crtc_funcs(crtc);
of_node_put(crtc->port);
/*
* We need to cleanup the planes now. Why?
*
* The planes are "&vop->win[i].base". That means the memory is
* all part of the big "struct vop" chunk of memory. That memory
* was devm allocated and associated with this component. We need to
* free it ourselves before vop_unbind() finishes.
*/
list_for_each_entry_safe(plane, tmp, &drm_dev->mode_config.plane_list,
head)
vop_plane_destroy(plane);
/*
* Destroy CRTC after vop_plane_destroy() since vop_disable_plane()
* references the CRTC.
*/
drm_crtc_cleanup(crtc);
}