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

Commit 6b94aea0 authored by Dave Airlie's avatar Dave Airlie
Browse files

Merge branch 'drm_next' of https://github.com/markyzq/kernel-drm-rockchip into drm-next

rockchip fixes.

* 'drm_next' of https://github.com/markyzq/kernel-drm-rockchip:
  drm/rockchip: vop: power off until vop standby take effect
  drm/rockchip: vop: set vop enabled after enable iommu
  drm/rockchip: vop use is_enabled instead of dpms mode
  drm/rockchip: vop: fix vop vsync/hsync polarity
  drm/rockchip: Only alloc a kmap for fbdev gem object
parents d79dc0a9 1067219b
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -71,7 +71,7 @@ static int rockchip_drm_fbdev_create(struct drm_fb_helper *helper,

	size = mode_cmd.pitches[0] * mode_cmd.height;

	rk_obj = rockchip_gem_create_object(dev, size);
	rk_obj = rockchip_gem_create_object(dev, size, true);
	if (IS_ERR(rk_obj))
		return -ENOMEM;

+12 −5
Original line number Diff line number Diff line
@@ -22,7 +22,8 @@
#include "rockchip_drm_drv.h"
#include "rockchip_drm_gem.h"

static int rockchip_gem_alloc_buf(struct rockchip_gem_object *rk_obj)
static int rockchip_gem_alloc_buf(struct rockchip_gem_object *rk_obj,
				  bool alloc_kmap)
{
	struct drm_gem_object *obj = &rk_obj->base;
	struct drm_device *drm = obj->dev;
@@ -30,7 +31,9 @@ static int rockchip_gem_alloc_buf(struct rockchip_gem_object *rk_obj)
	init_dma_attrs(&rk_obj->dma_attrs);
	dma_set_attr(DMA_ATTR_WRITE_COMBINE, &rk_obj->dma_attrs);

	/* TODO(djkurtz): Use DMA_ATTR_NO_KERNEL_MAPPING except for fbdev */
	if (!alloc_kmap)
		dma_set_attr(DMA_ATTR_NO_KERNEL_MAPPING, &rk_obj->dma_attrs);

	rk_obj->kvaddr = dma_alloc_attrs(drm->dev, obj->size,
					 &rk_obj->dma_addr, GFP_KERNEL,
					 &rk_obj->dma_attrs);
@@ -103,7 +106,8 @@ int rockchip_gem_mmap(struct file *filp, struct vm_area_struct *vma)
}

struct rockchip_gem_object *
	rockchip_gem_create_object(struct drm_device *drm, unsigned int size)
	rockchip_gem_create_object(struct drm_device *drm, unsigned int size,
				   bool alloc_kmap)
{
	struct rockchip_gem_object *rk_obj;
	struct drm_gem_object *obj;
@@ -119,7 +123,7 @@ struct rockchip_gem_object *

	drm_gem_private_object_init(drm, obj, size);

	ret = rockchip_gem_alloc_buf(rk_obj);
	ret = rockchip_gem_alloc_buf(rk_obj, alloc_kmap);
	if (ret)
		goto err_free_rk_obj;

@@ -163,7 +167,7 @@ rockchip_gem_create_with_handle(struct drm_file *file_priv,
	struct drm_gem_object *obj;
	int ret;

	rk_obj = rockchip_gem_create_object(drm, size);
	rk_obj = rockchip_gem_create_object(drm, size, false);
	if (IS_ERR(rk_obj))
		return ERR_CAST(rk_obj);

@@ -282,6 +286,9 @@ void *rockchip_gem_prime_vmap(struct drm_gem_object *obj)
{
	struct rockchip_gem_object *rk_obj = to_rockchip_obj(obj);

	if (dma_get_attr(DMA_ATTR_NO_KERNEL_MAPPING, &rk_obj->dma_attrs))
		return NULL;

	return rk_obj->kvaddr;
}

+2 −1
Original line number Diff line number Diff line
@@ -41,7 +41,8 @@ int rockchip_gem_mmap_buf(struct drm_gem_object *obj,
			  struct vm_area_struct *vma);

struct rockchip_gem_object *
	rockchip_gem_create_object(struct drm_device *drm, unsigned int size);
	rockchip_gem_create_object(struct drm_device *drm, unsigned int size,
				   bool alloc_kmap);

void rockchip_gem_free_object(struct drm_gem_object *obj);

+87 −31
Original line number Diff line number Diff line
@@ -81,7 +81,7 @@ struct vop {
	struct drm_crtc crtc;
	struct device *dev;
	struct drm_device *drm_dev;
	unsigned int dpms;
	bool is_enabled;

	int connector_type;
	int connector_out_mode;
@@ -89,6 +89,7 @@ struct vop {
	/* mutex vsync_ work */
	struct mutex vsync_mutex;
	bool vsync_work_pending;
	struct completion dsp_hold_completion;

	const struct vop_data *data;

@@ -382,11 +383,44 @@ static bool is_alpha_support(uint32_t format)
	}
}

static void vop_dsp_hold_valid_irq_enable(struct vop *vop)
{
	unsigned long flags;

	if (WARN_ON(!vop->is_enabled))
		return;

	spin_lock_irqsave(&vop->irq_lock, flags);

	vop_mask_write(vop, INTR_CTRL0, DSP_HOLD_VALID_INTR_MASK,
		       DSP_HOLD_VALID_INTR_EN(1));

	spin_unlock_irqrestore(&vop->irq_lock, flags);
}

static void vop_dsp_hold_valid_irq_disable(struct vop *vop)
{
	unsigned long flags;

	if (WARN_ON(!vop->is_enabled))
		return;

	spin_lock_irqsave(&vop->irq_lock, flags);

	vop_mask_write(vop, INTR_CTRL0, DSP_HOLD_VALID_INTR_MASK,
		       DSP_HOLD_VALID_INTR_EN(0));

	spin_unlock_irqrestore(&vop->irq_lock, flags);
}

static void vop_enable(struct drm_crtc *crtc)
{
	struct vop *vop = to_vop(crtc);
	int ret;

	if (vop->is_enabled)
		return;

	ret = clk_enable(vop->hclk);
	if (ret < 0) {
		dev_err(vop->dev, "failed to enable hclk - %d\n", ret);
@@ -417,6 +451,11 @@ static void vop_enable(struct drm_crtc *crtc)
		goto err_disable_aclk;
	}

	/*
	 * At here, vop clock & iommu is enable, R/W vop regs would be safe.
	 */
	vop->is_enabled = true;

	spin_lock(&vop->reg_lock);

	VOP_CTRL_SET(vop, standby, 0);
@@ -441,26 +480,41 @@ static void vop_disable(struct drm_crtc *crtc)
{
	struct vop *vop = to_vop(crtc);

	drm_vblank_off(crtc->dev, vop->pipe);
	if (!vop->is_enabled)
		return;

	disable_irq(vop->irq);
	drm_vblank_off(crtc->dev, vop->pipe);

	/*
	 * TODO: Since standby doesn't take effect until the next vblank,
	 * when we turn off dclk below, the vop is probably still active.
	 * Vop standby will take effect at end of current frame,
	 * if dsp hold valid irq happen, it means standby complete.
	 *
	 * we must wait standby complete when we want to disable aclk,
	 * if not, memory bus maybe dead.
	 */
	reinit_completion(&vop->dsp_hold_completion);
	vop_dsp_hold_valid_irq_enable(vop);

	spin_lock(&vop->reg_lock);

	VOP_CTRL_SET(vop, standby, 1);

	spin_unlock(&vop->reg_lock);

	wait_for_completion(&vop->dsp_hold_completion);

	vop_dsp_hold_valid_irq_disable(vop);

	disable_irq(vop->irq);

	vop->is_enabled = false;

	/*
	 * disable dclk to stop frame scan, so we can safely detach iommu,
	 * vop standby complete, so iommu detach is safe.
	 */
	clk_disable(vop->dclk);

	rockchip_drm_dma_detach_device(vop->drm_dev, vop->dev);

	clk_disable(vop->dclk);
	clk_disable(vop->aclk);
	clk_disable(vop->hclk);
}
@@ -742,7 +796,7 @@ static int vop_crtc_enable_vblank(struct drm_crtc *crtc)
	struct vop *vop = to_vop(crtc);
	unsigned long flags;

	if (vop->dpms != DRM_MODE_DPMS_ON)
	if (!vop->is_enabled)
		return -EPERM;

	spin_lock_irqsave(&vop->irq_lock, flags);
@@ -759,8 +813,9 @@ static void vop_crtc_disable_vblank(struct drm_crtc *crtc)
	struct vop *vop = to_vop(crtc);
	unsigned long flags;

	if (vop->dpms != DRM_MODE_DPMS_ON)
	if (!vop->is_enabled)
		return;

	spin_lock_irqsave(&vop->irq_lock, flags);
	vop_mask_write(vop, INTR_CTRL0, FS_INTR_MASK, FS_INTR_EN(0));
	spin_unlock_irqrestore(&vop->irq_lock, flags);
@@ -773,15 +828,8 @@ static const struct rockchip_crtc_funcs private_crtc_funcs = {

static void vop_crtc_dpms(struct drm_crtc *crtc, int mode)
{
	struct vop *vop = to_vop(crtc);

	DRM_DEBUG_KMS("crtc[%d] mode[%d]\n", crtc->base.id, mode);

	if (vop->dpms == mode) {
		DRM_DEBUG_KMS("desired dpms mode is same as previous one.\n");
		return;
	}

	switch (mode) {
	case DRM_MODE_DPMS_ON:
		vop_enable(crtc);
@@ -795,8 +843,6 @@ static void vop_crtc_dpms(struct drm_crtc *crtc, int mode)
		DRM_DEBUG_KMS("unspecified mode %d\n", mode);
		break;
	}

	vop->dpms = mode;
}

static void vop_crtc_prepare(struct drm_crtc *crtc)
@@ -874,8 +920,8 @@ static int vop_crtc_mode_set(struct drm_crtc *crtc,
	VOP_CTRL_SET(vop, out_mode, vop->connector_out_mode);

	val = 0x8;
	val |= (adjusted_mode->flags & DRM_MODE_FLAG_NHSYNC) ? 1 : 0;
	val |= (adjusted_mode->flags & DRM_MODE_FLAG_NVSYNC) ? (1 << 1) : 0;
	val |= (adjusted_mode->flags & DRM_MODE_FLAG_NHSYNC) ? 0 : 1;
	val |= (adjusted_mode->flags & DRM_MODE_FLAG_NVSYNC) ? 0 : (1 << 1);
	VOP_CTRL_SET(vop, pin_pol, val);

	VOP_CTRL_SET(vop, htotal_pw, (htotal << 16) | hsync_len);
@@ -934,9 +980,9 @@ static int vop_crtc_page_flip(struct drm_crtc *crtc,
	struct drm_framebuffer *old_fb = crtc->primary->fb;
	int ret;

	/* when the page flip is requested, crtc's dpms should be on */
	if (vop->dpms > DRM_MODE_DPMS_ON) {
		DRM_DEBUG("failed page flip request at dpms[%d].\n", vop->dpms);
	/* when the page flip is requested, crtc should be on */
	if (!vop->is_enabled) {
		DRM_DEBUG("page flip request rejected because crtc is off.\n");
		return 0;
	}

@@ -1081,6 +1127,7 @@ static irqreturn_t vop_isr(int irq, void *data)
	struct vop *vop = data;
	uint32_t intr0_reg, active_irqs;
	unsigned long flags;
	int ret = IRQ_NONE;

	/*
	 * INTR_CTRL0 register has interrupt status, enable and clear bits, we
@@ -1099,15 +1146,23 @@ static irqreturn_t vop_isr(int irq, void *data)
	if (!active_irqs)
		return IRQ_NONE;

	/* Only Frame Start Interrupt is enabled; other irqs are spurious. */
	if (!(active_irqs & FS_INTR)) {
		DRM_ERROR("Unknown VOP IRQs: %#02x\n", active_irqs);
		return IRQ_NONE;
	if (active_irqs & DSP_HOLD_VALID_INTR) {
		complete(&vop->dsp_hold_completion);
		active_irqs &= ~DSP_HOLD_VALID_INTR;
		ret = IRQ_HANDLED;
	}

	if (active_irqs & FS_INTR) {
		drm_handle_vblank(vop->drm_dev, vop->pipe);
		active_irqs &= ~FS_INTR;
		ret = (vop->vsync_work_pending) ? IRQ_WAKE_THREAD : IRQ_HANDLED;
	}

	return (vop->vsync_work_pending) ? IRQ_WAKE_THREAD : IRQ_HANDLED;
	/* Unhandled irqs are spurious. */
	if (active_irqs)
		DRM_ERROR("Unknown VOP IRQs: %#02x\n", active_irqs);

	return ret;
}

static int vop_create_crtc(struct vop *vop)
@@ -1189,6 +1244,7 @@ static int vop_create_crtc(struct vop *vop)
		goto err_cleanup_crtc;
	}

	init_completion(&vop->dsp_hold_completion);
	crtc->port = port;
	vop->pipe = drm_crtc_index(crtc);
	rockchip_register_crtc_funcs(drm_dev, &private_crtc_funcs, vop->pipe);
@@ -1302,7 +1358,7 @@ static int vop_initial(struct vop *vop)

	clk_disable(vop->hclk);

	vop->dpms = DRM_MODE_DPMS_OFF;
	vop->is_enabled = false;

	return 0;