Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 5456248d authored by Dave Airlie's avatar Dave Airlie
Browse files

Merge branch 'drm-rockchip-next-fixes-2016-03-28' of...

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
parents 90516d89 06b898ec
Loading
Loading
Loading
Loading
+10 −3
Original line number Diff line number Diff line
@@ -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,
+22 −0
Original line number Diff line number Diff line
@@ -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,
+1 −0
Original line number Diff line number Diff line
@@ -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 {
+67 −12
Original line number Diff line number Diff line
@@ -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);
}