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

Commit bbbe29d8 authored by Dave Airlie's avatar Dave Airlie
Browse files

Merge branch 'drm-armada-devel' of git://ftp.arm.linux.org.uk/~rmk/linux-arm into drm-next

* remove support for the non-component support from the Armada DRM driver,
  switching it to component-only mode.
* create a "armada plane" to allow the primary and overlay planes to share
  some code.
* increase efficiency by using inherently atomic operations, rather than
  spinlocking to achieve atomicity.  Eg, if we want to exchange a value,
  using xchg().
* increase PM savings by stopping the external pixel clock when we're in
  DPMS mode.

* 'drm-armada-devel' of git://ftp.arm.linux.org.uk/~rmk/linux-arm:
  drm/armada: move frame wait wakeup into plane work
  drm/armada: convert overlay plane vbl worker to a armada plane worker
  drm/armada: move CRTC flip work to primary plane work
  drm/armada: move frame wait into armada_frame
  drm/armada: move the locking for armada_drm_vbl_event_remove()
  drm/armada: move the update of dplane->ctrl0 out of spinlock
  drm/armada: move write to dma_ctrl0 to armada_drm_crtc_plane_disable()
  drm/armada: provide a common helper to disable a plane
  drm/armada: allocate primary plane ourselves
  drm/armada: add primary plane creation
  drm/armada: introduce generic armada_plane struct
  drm/armada: update armada overlay to use drm_universal_plane_init()
  drm/armada: use xchg() to atomically update dplane->old_fb
  drm/armada: factor out retirement of old fb
  drm/armada: rename overlay identifiers
  drm/armada: redo locking and atomics for armada_drm_crtc_complete_frame_work()
  drm/armada: disable CRTC clock during DPMS
  drm/armada: use drm_plane_force_disable() to disable the overlay plane
  drm/armada: move vbl code into armada_crtc
  drm/armada: remove non-component support
parents d4070ff7 7cb410cd
Loading
Loading
Loading
Loading
+0 −9
Original line number Original line Diff line number Diff line
@@ -14,12 +14,3 @@ config DRM_ARMADA
	  This driver provides no built-in acceleration; acceleration is
	  This driver provides no built-in acceleration; acceleration is
	  performed by other IP found on the SoC.  This driver provides
	  performed by other IP found on the SoC.  This driver provides
	  kernel mode setting and buffer management to userspace.
	  kernel mode setting and buffer management to userspace.

config DRM_ARMADA_TDA1998X
	bool "Support TDA1998X HDMI output"
	depends on DRM_ARMADA != n
	depends on I2C && DRM_I2C_NXP_TDA998X = y
	default y
	help
	  Support the TDA1998x HDMI output device found on the Solid-Run
	  CuBox.
+1 −2
Original line number Original line Diff line number Diff line
armada-y	:= armada_crtc.o armada_drv.o armada_fb.o armada_fbdev.o \
armada-y	:= armada_crtc.o armada_drv.o armada_fb.o armada_fbdev.o \
		   armada_gem.o armada_output.o armada_overlay.o \
		   armada_gem.o armada_overlay.o
		   armada_slave.o
armada-y	+= armada_510.o
armada-y	+= armada_510.o
armada-$(CONFIG_DEBUG_FS) += armada_debugfs.o
armada-$(CONFIG_DEBUG_FS) += armada_debugfs.o


+185 −73
Original line number Original line Diff line number Diff line
@@ -20,6 +20,7 @@
#include "armada_hw.h"
#include "armada_hw.h"


struct armada_frame_work {
struct armada_frame_work {
	struct armada_plane_work work;
	struct drm_pending_vblank_event *event;
	struct drm_pending_vblank_event *event;
	struct armada_regs regs[4];
	struct armada_regs regs[4];
	struct drm_framebuffer *old_fb;
	struct drm_framebuffer *old_fb;
@@ -33,6 +34,23 @@ enum csc_mode {
	CSC_RGB_STUDIO = 2,
	CSC_RGB_STUDIO = 2,
};
};


static const uint32_t armada_primary_formats[] = {
	DRM_FORMAT_UYVY,
	DRM_FORMAT_YUYV,
	DRM_FORMAT_VYUY,
	DRM_FORMAT_YVYU,
	DRM_FORMAT_ARGB8888,
	DRM_FORMAT_ABGR8888,
	DRM_FORMAT_XRGB8888,
	DRM_FORMAT_XBGR8888,
	DRM_FORMAT_RGB888,
	DRM_FORMAT_BGR888,
	DRM_FORMAT_ARGB1555,
	DRM_FORMAT_ABGR1555,
	DRM_FORMAT_RGB565,
	DRM_FORMAT_BGR565,
};

/*
/*
 * A note about interlacing.  Let's consider HDMI 1920x1080i.
 * A note about interlacing.  Let's consider HDMI 1920x1080i.
 * The timing parameters we have from X are:
 * The timing parameters we have from X are:
@@ -173,49 +191,82 @@ static unsigned armada_drm_crtc_calc_fb(struct drm_framebuffer *fb,
	return i;
	return i;
}
}


static int armada_drm_crtc_queue_frame_work(struct armada_crtc *dcrtc,
static void armada_drm_plane_work_run(struct armada_crtc *dcrtc,
	struct armada_frame_work *work)
	struct armada_plane *plane)
{
	struct armada_plane_work *work = xchg(&plane->work, NULL);

	/* Handle any pending frame work. */
	if (work) {
		work->fn(dcrtc, plane, work);
		drm_vblank_put(dcrtc->crtc.dev, dcrtc->num);
	}

	wake_up(&plane->frame_wait);
}

int armada_drm_plane_work_queue(struct armada_crtc *dcrtc,
	struct armada_plane *plane, struct armada_plane_work *work)
{
{
	struct drm_device *dev = dcrtc->crtc.dev;
	unsigned long flags;
	int ret;
	int ret;


	ret = drm_vblank_get(dev, dcrtc->num);
	ret = drm_vblank_get(dcrtc->crtc.dev, dcrtc->num);
	if (ret) {
	if (ret) {
		DRM_ERROR("failed to acquire vblank counter\n");
		DRM_ERROR("failed to acquire vblank counter\n");
		return ret;
		return ret;
	}
	}


	spin_lock_irqsave(&dev->event_lock, flags);
	ret = cmpxchg(&plane->work, NULL, work) ? -EBUSY : 0;
	if (!dcrtc->frame_work)
		dcrtc->frame_work = work;
	else
		ret = -EBUSY;
	spin_unlock_irqrestore(&dev->event_lock, flags);

	if (ret)
	if (ret)
		drm_vblank_put(dev, dcrtc->num);
		drm_vblank_put(dcrtc->crtc.dev, dcrtc->num);


	return ret;
	return ret;
}
}


static void armada_drm_crtc_complete_frame_work(struct armada_crtc *dcrtc)
int armada_drm_plane_work_wait(struct armada_plane *plane, long timeout)
{
{
	struct drm_device *dev = dcrtc->crtc.dev;
	return wait_event_timeout(plane->frame_wait, !plane->work, timeout);
	struct armada_frame_work *work = dcrtc->frame_work;
}

struct armada_plane_work *armada_drm_plane_work_cancel(
	struct armada_crtc *dcrtc, struct armada_plane *plane)
{
	struct armada_plane_work *work = xchg(&plane->work, NULL);

	if (work)
		drm_vblank_put(dcrtc->crtc.dev, dcrtc->num);


	dcrtc->frame_work = NULL;
	return work;
}


	armada_drm_crtc_update_regs(dcrtc, work->regs);
static int armada_drm_crtc_queue_frame_work(struct armada_crtc *dcrtc,
	struct armada_frame_work *work)
{
	struct armada_plane *plane = drm_to_armada_plane(dcrtc->crtc.primary);


	if (work->event)
	return armada_drm_plane_work_queue(dcrtc, plane, &work->work);
		drm_send_vblank_event(dev, dcrtc->num, work->event);
}


	drm_vblank_put(dev, dcrtc->num);
static void armada_drm_crtc_complete_frame_work(struct armada_crtc *dcrtc,
	struct armada_plane *plane, struct armada_plane_work *work)
{
	struct armada_frame_work *fwork = container_of(work, struct armada_frame_work, work);
	struct drm_device *dev = dcrtc->crtc.dev;
	unsigned long flags;

	spin_lock_irqsave(&dcrtc->irq_lock, flags);
	armada_drm_crtc_update_regs(dcrtc, fwork->regs);
	spin_unlock_irqrestore(&dcrtc->irq_lock, flags);

	if (fwork->event) {
		spin_lock_irqsave(&dev->event_lock, flags);
		drm_send_vblank_event(dev, dcrtc->num, fwork->event);
		spin_unlock_irqrestore(&dev->event_lock, flags);
	}


	/* Finally, queue the process-half of the cleanup. */
	/* Finally, queue the process-half of the cleanup. */
	__armada_drm_queue_unref_work(dcrtc->crtc.dev, work->old_fb);
	__armada_drm_queue_unref_work(dcrtc->crtc.dev, fwork->old_fb);
	kfree(work);
	kfree(fwork);
}
}


static void armada_drm_crtc_finish_fb(struct armada_crtc *dcrtc,
static void armada_drm_crtc_finish_fb(struct armada_crtc *dcrtc,
@@ -235,6 +286,7 @@ static void armada_drm_crtc_finish_fb(struct armada_crtc *dcrtc,
	work = kmalloc(sizeof(*work), GFP_KERNEL);
	work = kmalloc(sizeof(*work), GFP_KERNEL);
	if (work) {
	if (work) {
		int i = 0;
		int i = 0;
		work->work.fn = armada_drm_crtc_complete_frame_work;
		work->event = NULL;
		work->event = NULL;
		work->old_fb = fb;
		work->old_fb = fb;
		armada_reg_queue_end(work->regs, i);
		armada_reg_queue_end(work->regs, i);
@@ -255,19 +307,14 @@ static void armada_drm_crtc_finish_fb(struct armada_crtc *dcrtc,


static void armada_drm_vblank_off(struct armada_crtc *dcrtc)
static void armada_drm_vblank_off(struct armada_crtc *dcrtc)
{
{
	struct drm_device *dev = dcrtc->crtc.dev;
	struct armada_plane *plane = drm_to_armada_plane(dcrtc->crtc.primary);


	/*
	/*
	 * Tell the DRM core that vblank IRQs aren't going to happen for
	 * Tell the DRM core that vblank IRQs aren't going to happen for
	 * a while.  This cleans up any pending vblank events for us.
	 * a while.  This cleans up any pending vblank events for us.
	 */
	 */
	drm_crtc_vblank_off(&dcrtc->crtc);
	drm_crtc_vblank_off(&dcrtc->crtc);

	armada_drm_plane_work_run(dcrtc, plane);
	/* Handle any pending flip event. */
	spin_lock_irq(&dev->event_lock);
	if (dcrtc->frame_work)
		armada_drm_crtc_complete_frame_work(dcrtc);
	spin_unlock_irq(&dev->event_lock);
}
}


void armada_drm_crtc_gamma_set(struct drm_crtc *crtc, u16 r, u16 g, u16 b,
void armada_drm_crtc_gamma_set(struct drm_crtc *crtc, u16 r, u16 g, u16 b,
@@ -287,7 +334,11 @@ static void armada_drm_crtc_dpms(struct drm_crtc *crtc, int dpms)


	if (dcrtc->dpms != dpms) {
	if (dcrtc->dpms != dpms) {
		dcrtc->dpms = dpms;
		dcrtc->dpms = dpms;
		if (!IS_ERR(dcrtc->clk) && !dpms_blanked(dpms))
			WARN_ON(clk_prepare_enable(dcrtc->clk));
		armada_drm_crtc_update(dcrtc);
		armada_drm_crtc_update(dcrtc);
		if (!IS_ERR(dcrtc->clk) && dpms_blanked(dpms))
			clk_disable_unprepare(dcrtc->clk);
		if (dpms_blanked(dpms))
		if (dpms_blanked(dpms))
			armada_drm_vblank_off(dcrtc);
			armada_drm_vblank_off(dcrtc);
		else
		else
@@ -310,17 +361,11 @@ static void armada_drm_crtc_prepare(struct drm_crtc *crtc)
	/*
	/*
	 * If we have an overlay plane associated with this CRTC, disable
	 * If we have an overlay plane associated with this CRTC, disable
	 * it before the modeset to avoid its coordinates being outside
	 * it before the modeset to avoid its coordinates being outside
	 * the new mode parameters.  DRM doesn't provide help with this.
	 * the new mode parameters.
	 */
	 */
	plane = dcrtc->plane;
	plane = dcrtc->plane;
	if (plane) {
	if (plane)
		struct drm_framebuffer *fb = plane->fb;
		drm_plane_force_disable(plane);

		plane->funcs->disable_plane(plane);
		plane->fb = NULL;
		plane->crtc = NULL;
		drm_framebuffer_unreference(fb);
	}
}
}


/* The mode_config.mutex will be held for this call */
/* The mode_config.mutex will be held for this call */
@@ -356,8 +401,8 @@ static bool armada_drm_crtc_mode_fixup(struct drm_crtc *crtc,


static void armada_drm_crtc_irq(struct armada_crtc *dcrtc, u32 stat)
static void armada_drm_crtc_irq(struct armada_crtc *dcrtc, u32 stat)
{
{
	struct armada_vbl_event *e, *n;
	void __iomem *base = dcrtc->base;
	void __iomem *base = dcrtc->base;
	struct drm_plane *ovl_plane;


	if (stat & DMA_FF_UNDERFLOW)
	if (stat & DMA_FF_UNDERFLOW)
		DRM_ERROR("video underflow on crtc %u\n", dcrtc->num);
		DRM_ERROR("video underflow on crtc %u\n", dcrtc->num);
@@ -368,11 +413,10 @@ static void armada_drm_crtc_irq(struct armada_crtc *dcrtc, u32 stat)
		drm_handle_vblank(dcrtc->crtc.dev, dcrtc->num);
		drm_handle_vblank(dcrtc->crtc.dev, dcrtc->num);


	spin_lock(&dcrtc->irq_lock);
	spin_lock(&dcrtc->irq_lock);

	ovl_plane = dcrtc->plane;
	list_for_each_entry_safe(e, n, &dcrtc->vbl_list, node) {
	if (ovl_plane) {
		list_del_init(&e->node);
		struct armada_plane *plane = drm_to_armada_plane(ovl_plane);
		drm_vblank_put(dcrtc->crtc.dev, dcrtc->num);
		armada_drm_plane_work_run(dcrtc, plane);
		e->fn(dcrtc, e->data);
	}
	}


	if (stat & GRA_FRAME_IRQ && dcrtc->interlaced) {
	if (stat & GRA_FRAME_IRQ && dcrtc->interlaced) {
@@ -404,14 +448,8 @@ static void armada_drm_crtc_irq(struct armada_crtc *dcrtc, u32 stat)
	spin_unlock(&dcrtc->irq_lock);
	spin_unlock(&dcrtc->irq_lock);


	if (stat & GRA_FRAME_IRQ) {
	if (stat & GRA_FRAME_IRQ) {
		struct drm_device *dev = dcrtc->crtc.dev;
		struct armada_plane *plane = drm_to_armada_plane(dcrtc->crtc.primary);

		armada_drm_plane_work_run(dcrtc, plane);
		spin_lock(&dev->event_lock);
		if (dcrtc->frame_work)
			armada_drm_crtc_complete_frame_work(dcrtc);
		spin_unlock(&dev->event_lock);

		wake_up(&dcrtc->frame_wait);
	}
	}
}
}


@@ -527,7 +565,8 @@ static int armada_drm_crtc_mode_set(struct drm_crtc *crtc,
		adj->crtc_vtotal, tm, bm);
		adj->crtc_vtotal, tm, bm);


	/* Wait for pending flips to complete */
	/* Wait for pending flips to complete */
	wait_event(dcrtc->frame_wait, !dcrtc->frame_work);
	armada_drm_plane_work_wait(drm_to_armada_plane(dcrtc->crtc.primary),
				   MAX_SCHEDULE_TIMEOUT);


	drm_crtc_vblank_off(crtc);
	drm_crtc_vblank_off(crtc);


@@ -537,6 +576,13 @@ static int armada_drm_crtc_mode_set(struct drm_crtc *crtc,
		writel_relaxed(val, dcrtc->base + LCD_SPU_DUMB_CTRL);
		writel_relaxed(val, dcrtc->base + LCD_SPU_DUMB_CTRL);
	}
	}


	/*
	 * If we are blanked, we would have disabled the clock.  Re-enable
	 * it so that compute_clock() does the right thing.
	 */
	if (!IS_ERR(dcrtc->clk) && dpms_blanked(dcrtc->dpms))
		WARN_ON(clk_prepare_enable(dcrtc->clk));

	/* Now compute the divider for real */
	/* Now compute the divider for real */
	dcrtc->variant->compute_clock(dcrtc, adj, &sclk);
	dcrtc->variant->compute_clock(dcrtc, adj, &sclk);


@@ -637,7 +683,8 @@ static int armada_drm_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y,
	armada_reg_queue_end(regs, i);
	armada_reg_queue_end(regs, i);


	/* Wait for pending flips to complete */
	/* Wait for pending flips to complete */
	wait_event(dcrtc->frame_wait, !dcrtc->frame_work);
	armada_drm_plane_work_wait(drm_to_armada_plane(dcrtc->crtc.primary),
				   MAX_SCHEDULE_TIMEOUT);


	/* Take a reference to the new fb as we're using it */
	/* Take a reference to the new fb as we're using it */
	drm_framebuffer_reference(crtc->primary->fb);
	drm_framebuffer_reference(crtc->primary->fb);
@@ -651,18 +698,47 @@ static int armada_drm_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y,
	return 0;
	return 0;
}
}


void armada_drm_crtc_plane_disable(struct armada_crtc *dcrtc,
	struct drm_plane *plane)
{
	u32 sram_para1, dma_ctrl0_mask;

	/*
	 * Drop our reference on any framebuffer attached to this plane.
	 * We don't need to NULL this out as drm_plane_force_disable(),
	 * and __setplane_internal() will do so for an overlay plane, and
	 * __drm_helper_disable_unused_functions() will do so for the
	 * primary plane.
	 */
	if (plane->fb)
		drm_framebuffer_unreference(plane->fb);

	/* Power down the Y/U/V FIFOs */
	sram_para1 = CFG_PDWN16x66 | CFG_PDWN32x66;

	/* Power down most RAMs and FIFOs if this is the primary plane */
	if (plane->type == DRM_PLANE_TYPE_PRIMARY) {
		sram_para1 |= CFG_PDWN256x32 | CFG_PDWN256x24 | CFG_PDWN256x8 |
			      CFG_PDWN32x32 | CFG_PDWN64x66;
		dma_ctrl0_mask = CFG_GRA_ENA;
	} else {
		dma_ctrl0_mask = CFG_DMA_ENA;
	}

	spin_lock_irq(&dcrtc->irq_lock);
	armada_updatel(0, dma_ctrl0_mask, dcrtc->base + LCD_SPU_DMA_CTRL0);
	spin_unlock_irq(&dcrtc->irq_lock);

	armada_updatel(sram_para1, 0, dcrtc->base + LCD_SPU_SRAM_PARA1);
}

/* The mode_config.mutex will be held for this call */
/* The mode_config.mutex will be held for this call */
static void armada_drm_crtc_disable(struct drm_crtc *crtc)
static void armada_drm_crtc_disable(struct drm_crtc *crtc)
{
{
	struct armada_crtc *dcrtc = drm_to_armada_crtc(crtc);
	struct armada_crtc *dcrtc = drm_to_armada_crtc(crtc);


	armada_drm_crtc_dpms(crtc, DRM_MODE_DPMS_OFF);
	armada_drm_crtc_dpms(crtc, DRM_MODE_DPMS_OFF);
	armada_drm_crtc_finish_fb(dcrtc, crtc->primary->fb, true);
	armada_drm_crtc_plane_disable(dcrtc, crtc->primary);

	/* Power down most RAMs and FIFOs */
	writel_relaxed(CFG_PDWN256x32 | CFG_PDWN256x24 | CFG_PDWN256x8 |
		       CFG_PDWN32x32 | CFG_PDWN16x66 | CFG_PDWN32x66 |
		       CFG_PDWN64x66, dcrtc->base + LCD_SPU_SRAM_PARA1);
}
}


static const struct drm_crtc_helper_funcs armada_crtc_helper_funcs = {
static const struct drm_crtc_helper_funcs armada_crtc_helper_funcs = {
@@ -920,8 +996,6 @@ static int armada_drm_crtc_page_flip(struct drm_crtc *crtc,
{
{
	struct armada_crtc *dcrtc = drm_to_armada_crtc(crtc);
	struct armada_crtc *dcrtc = drm_to_armada_crtc(crtc);
	struct armada_frame_work *work;
	struct armada_frame_work *work;
	struct drm_device *dev = crtc->dev;
	unsigned long flags;
	unsigned i;
	unsigned i;
	int ret;
	int ret;


@@ -933,6 +1007,7 @@ static int armada_drm_crtc_page_flip(struct drm_crtc *crtc,
	if (!work)
	if (!work)
		return -ENOMEM;
		return -ENOMEM;


	work->work.fn = armada_drm_crtc_complete_frame_work;
	work->event = event;
	work->event = event;
	work->old_fb = dcrtc->crtc.primary->fb;
	work->old_fb = dcrtc->crtc.primary->fb;


@@ -966,12 +1041,8 @@ static int armada_drm_crtc_page_flip(struct drm_crtc *crtc,
	 * Finally, if the display is blanked, we won't receive an
	 * Finally, if the display is blanked, we won't receive an
	 * interrupt, so complete it now.
	 * interrupt, so complete it now.
	 */
	 */
	if (dpms_blanked(dcrtc->dpms)) {
	if (dpms_blanked(dcrtc->dpms))
		spin_lock_irqsave(&dev->event_lock, flags);
		armada_drm_plane_work_run(dcrtc, drm_to_armada_plane(dcrtc->crtc.primary));
		if (dcrtc->frame_work)
			armada_drm_crtc_complete_frame_work(dcrtc);
		spin_unlock_irqrestore(&dev->event_lock, flags);
	}


	return 0;
	return 0;
}
}
@@ -1012,6 +1083,19 @@ static struct drm_crtc_funcs armada_crtc_funcs = {
	.set_property	= armada_drm_crtc_set_property,
	.set_property	= armada_drm_crtc_set_property,
};
};


static const struct drm_plane_funcs armada_primary_plane_funcs = {
	.update_plane	= drm_primary_helper_update,
	.disable_plane	= drm_primary_helper_disable,
	.destroy	= drm_primary_helper_destroy,
};

int armada_drm_plane_init(struct armada_plane *plane)
{
	init_waitqueue_head(&plane->frame_wait);

	return 0;
}

static struct drm_prop_enum_list armada_drm_csc_yuv_enum_list[] = {
static struct drm_prop_enum_list armada_drm_csc_yuv_enum_list[] = {
	{ CSC_AUTO,        "Auto" },
	{ CSC_AUTO,        "Auto" },
	{ CSC_YUV_CCIR601, "CCIR601" },
	{ CSC_YUV_CCIR601, "CCIR601" },
@@ -1044,12 +1128,13 @@ static int armada_drm_crtc_create_properties(struct drm_device *dev)
	return 0;
	return 0;
}
}


int armada_drm_crtc_create(struct drm_device *drm, struct device *dev,
static int armada_drm_crtc_create(struct drm_device *drm, struct device *dev,
	struct resource *res, int irq, const struct armada_variant *variant,
	struct resource *res, int irq, const struct armada_variant *variant,
	struct device_node *port)
	struct device_node *port)
{
{
	struct armada_private *priv = drm->dev_private;
	struct armada_private *priv = drm->dev_private;
	struct armada_crtc *dcrtc;
	struct armada_crtc *dcrtc;
	struct armada_plane *primary;
	void __iomem *base;
	void __iomem *base;
	int ret;
	int ret;


@@ -1080,8 +1165,6 @@ int armada_drm_crtc_create(struct drm_device *drm, struct device *dev,
	dcrtc->spu_iopad_ctrl = CFG_VSCALE_LN_EN | CFG_IOPAD_DUMB24;
	dcrtc->spu_iopad_ctrl = CFG_VSCALE_LN_EN | CFG_IOPAD_DUMB24;
	spin_lock_init(&dcrtc->irq_lock);
	spin_lock_init(&dcrtc->irq_lock);
	dcrtc->irq_ena = CLEAN_SPU_IRQ_ISR;
	dcrtc->irq_ena = CLEAN_SPU_IRQ_ISR;
	INIT_LIST_HEAD(&dcrtc->vbl_list);
	init_waitqueue_head(&dcrtc->frame_wait);


	/* Initialize some registers which we don't otherwise set */
	/* Initialize some registers which we don't otherwise set */
	writel_relaxed(0x00000001, dcrtc->base + LCD_CFG_SCLK_DIV);
	writel_relaxed(0x00000001, dcrtc->base + LCD_CFG_SCLK_DIV);
@@ -1118,7 +1201,32 @@ int armada_drm_crtc_create(struct drm_device *drm, struct device *dev,
	priv->dcrtc[dcrtc->num] = dcrtc;
	priv->dcrtc[dcrtc->num] = dcrtc;


	dcrtc->crtc.port = port;
	dcrtc->crtc.port = port;
	drm_crtc_init(drm, &dcrtc->crtc, &armada_crtc_funcs);

	primary = kzalloc(sizeof(*primary), GFP_KERNEL);
	if (!primary)
		return -ENOMEM;

	ret = armada_drm_plane_init(primary);
	if (ret) {
		kfree(primary);
		return ret;
	}

	ret = drm_universal_plane_init(drm, &primary->base, 0,
				       &armada_primary_plane_funcs,
				       armada_primary_formats,
				       ARRAY_SIZE(armada_primary_formats),
				       DRM_PLANE_TYPE_PRIMARY);
	if (ret) {
		kfree(primary);
		return ret;
	}

	ret = drm_crtc_init_with_planes(drm, &dcrtc->crtc, &primary->base, NULL,
					&armada_crtc_funcs);
	if (ret)
		goto err_crtc_init;

	drm_crtc_helper_add(&dcrtc->crtc, &armada_crtc_helper_funcs);
	drm_crtc_helper_add(&dcrtc->crtc, &armada_crtc_helper_funcs);


	drm_object_attach_property(&dcrtc->crtc.base, priv->csc_yuv_prop,
	drm_object_attach_property(&dcrtc->crtc.base, priv->csc_yuv_prop,
@@ -1127,6 +1235,10 @@ int armada_drm_crtc_create(struct drm_device *drm, struct device *dev,
				   dcrtc->csc_rgb_mode);
				   dcrtc->csc_rgb_mode);


	return armada_overlay_plane_create(drm, 1 << dcrtc->num);
	return armada_overlay_plane_create(drm, 1 << dcrtc->num);

err_crtc_init:
	primary->base.funcs->destroy(&primary->base);
	return ret;
}
}


static int
static int
+25 −9
Original line number Original line Diff line number Diff line
@@ -31,9 +31,30 @@ struct armada_regs {
#define armada_reg_queue_end(_r, _i)		\
#define armada_reg_queue_end(_r, _i)		\
	armada_reg_queue_mod(_r, _i, 0, 0, ~0)
	armada_reg_queue_mod(_r, _i, 0, 0, ~0)


struct armada_frame_work;
struct armada_crtc;
struct armada_plane;
struct armada_variant;
struct armada_variant;


struct armada_plane_work {
	void			(*fn)(struct armada_crtc *,
				      struct armada_plane *,
				      struct armada_plane_work *);
};

struct armada_plane {
	struct drm_plane	base;
	wait_queue_head_t	frame_wait;
	struct armada_plane_work *work;
};
#define drm_to_armada_plane(p) container_of(p, struct armada_plane, base)

int armada_drm_plane_init(struct armada_plane *plane);
int armada_drm_plane_work_queue(struct armada_crtc *dcrtc,
	struct armada_plane *plane, struct armada_plane_work *work);
int armada_drm_plane_work_wait(struct armada_plane *plane, long timeout);
struct armada_plane_work *armada_drm_plane_work_cancel(
	struct armada_crtc *dcrtc, struct armada_plane *plane);

struct armada_crtc {
struct armada_crtc {
	struct drm_crtc		crtc;
	struct drm_crtc		crtc;
	const struct armada_variant *variant;
	const struct armada_variant *variant;
@@ -66,25 +87,20 @@ struct armada_crtc {
	uint32_t		dumb_ctrl;
	uint32_t		dumb_ctrl;
	uint32_t		spu_iopad_ctrl;
	uint32_t		spu_iopad_ctrl;


	wait_queue_head_t	frame_wait;
	struct armada_frame_work *frame_work;

	spinlock_t		irq_lock;
	spinlock_t		irq_lock;
	uint32_t		irq_ena;
	uint32_t		irq_ena;
	struct list_head	vbl_list;
};
};
#define drm_to_armada_crtc(c) container_of(c, struct armada_crtc, crtc)
#define drm_to_armada_crtc(c) container_of(c, struct armada_crtc, crtc)


struct device_node;
int armada_drm_crtc_create(struct drm_device *, struct device *,
	struct resource *, int, const struct armada_variant *,
	struct device_node *);
void armada_drm_crtc_gamma_set(struct drm_crtc *, u16, u16, u16, int);
void armada_drm_crtc_gamma_set(struct drm_crtc *, u16, u16, u16, int);
void armada_drm_crtc_gamma_get(struct drm_crtc *, u16 *, u16 *, u16 *, int);
void armada_drm_crtc_gamma_get(struct drm_crtc *, u16 *, u16 *, u16 *, int);
void armada_drm_crtc_disable_irq(struct armada_crtc *, u32);
void armada_drm_crtc_disable_irq(struct armada_crtc *, u32);
void armada_drm_crtc_enable_irq(struct armada_crtc *, u32);
void armada_drm_crtc_enable_irq(struct armada_crtc *, u32);
void armada_drm_crtc_update_regs(struct armada_crtc *, struct armada_regs *);
void armada_drm_crtc_update_regs(struct armada_crtc *, struct armada_regs *);


void armada_drm_crtc_plane_disable(struct armada_crtc *dcrtc,
	struct drm_plane *plane);

extern struct platform_driver armada_lcd_platform_driver;
extern struct platform_driver armada_lcd_platform_driver;


#endif
#endif
+0 −16
Original line number Original line Diff line number Diff line
@@ -37,22 +37,6 @@ static inline uint32_t armada_pitch(uint32_t width, uint32_t bpp)
	return ALIGN(pitch, 128);
	return ALIGN(pitch, 128);
}
}


struct armada_vbl_event {
	struct list_head	node;
	void			*data;
	void			(*fn)(struct armada_crtc *, void *);
};
void armada_drm_vbl_event_add(struct armada_crtc *,
	struct armada_vbl_event *);
void armada_drm_vbl_event_remove(struct armada_crtc *,
	struct armada_vbl_event *);
#define armada_drm_vbl_event_init(_e, _f, _d) do {	\
	struct armada_vbl_event *__e = _e;		\
	INIT_LIST_HEAD(&__e->node);			\
	__e->data = _d;					\
	__e->fn = _f;					\
} while (0)



struct armada_private;
struct armada_private;


Loading