mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-09-05 18:39:59 +00:00
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:
commit
5456248d66
4 changed files with 100 additions and 15 deletions
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue