196f60e37SRussell King /*
296f60e37SRussell King  * Copyright (C) 2012 Russell King
396f60e37SRussell King  *  Rewritten from the dovefb driver, and Armada510 manuals.
496f60e37SRussell King  *
596f60e37SRussell King  * This program is free software; you can redistribute it and/or modify
696f60e37SRussell King  * it under the terms of the GNU General Public License version 2 as
796f60e37SRussell King  * published by the Free Software Foundation.
896f60e37SRussell King  */
996f60e37SRussell King #include <drm/drmP.h>
1047dc413bSRussell King #include <drm/drm_atomic.h>
11bcd21a47SDave Airlie #include <drm/drm_atomic_helper.h>
1247dc413bSRussell King #include <drm/drm_plane_helper.h>
13d40af7b1SRussell King #include <drm/armada_drm.h>
1496f60e37SRussell King #include "armada_crtc.h"
1596f60e37SRussell King #include "armada_drm.h"
1696f60e37SRussell King #include "armada_fb.h"
1796f60e37SRussell King #include "armada_gem.h"
1896f60e37SRussell King #include "armada_hw.h"
1996f60e37SRussell King #include "armada_ioctlP.h"
20d40af7b1SRussell King #include "armada_plane.h"
21c8a220c6SRussell King #include "armada_trace.h"
2296f60e37SRussell King 
2328a2aebeSRussell King struct armada_ovl_plane_properties {
2496f60e37SRussell King 	uint32_t colorkey_yr;
2596f60e37SRussell King 	uint32_t colorkey_ug;
2696f60e37SRussell King 	uint32_t colorkey_vb;
2796f60e37SRussell King #define K2R(val) (((val) >> 0) & 0xff)
2896f60e37SRussell King #define K2G(val) (((val) >> 8) & 0xff)
2996f60e37SRussell King #define K2B(val) (((val) >> 16) & 0xff)
3096f60e37SRussell King 	int16_t  brightness;
3196f60e37SRussell King 	uint16_t contrast;
3296f60e37SRussell King 	uint16_t saturation;
3396f60e37SRussell King 	uint32_t colorkey_mode;
34d378859aSRussell King 	uint32_t colorkey_enable;
3596f60e37SRussell King };
3696f60e37SRussell King 
3728a2aebeSRussell King struct armada_ovl_plane {
38561f60bcSRussell King 	struct armada_plane base;
393acea7b9SRussell King 	bool wait_vblank;
4028a2aebeSRussell King 	struct armada_ovl_plane_properties prop;
4196f60e37SRussell King };
42561f60bcSRussell King #define drm_to_armada_ovl_plane(p) \
43561f60bcSRussell King 	container_of(p, struct armada_ovl_plane, base.base)
4496f60e37SRussell King 
4596f60e37SRussell King 
4696f60e37SRussell King static void
4728a2aebeSRussell King armada_ovl_update_attr(struct armada_ovl_plane_properties *prop,
4896f60e37SRussell King 	struct armada_crtc *dcrtc)
4996f60e37SRussell King {
5096f60e37SRussell King 	writel_relaxed(prop->colorkey_yr, dcrtc->base + LCD_SPU_COLORKEY_Y);
5196f60e37SRussell King 	writel_relaxed(prop->colorkey_ug, dcrtc->base + LCD_SPU_COLORKEY_U);
5296f60e37SRussell King 	writel_relaxed(prop->colorkey_vb, dcrtc->base + LCD_SPU_COLORKEY_V);
5396f60e37SRussell King 
5496f60e37SRussell King 	writel_relaxed(prop->brightness << 16 | prop->contrast,
5596f60e37SRussell King 		       dcrtc->base + LCD_SPU_CONTRAST);
5696f60e37SRussell King 	/* Docs say 15:0, but it seems to actually be 31:16 on Armada 510 */
5796f60e37SRussell King 	writel_relaxed(prop->saturation << 16,
5896f60e37SRussell King 		       dcrtc->base + LCD_SPU_SATURATION);
5996f60e37SRussell King 	writel_relaxed(0x00002000, dcrtc->base + LCD_SPU_CBSH_HUE);
6096f60e37SRussell King 
6196f60e37SRussell King 	spin_lock_irq(&dcrtc->irq_lock);
62d378859aSRussell King 	armada_updatel(prop->colorkey_mode,
6396f60e37SRussell King 		       CFG_CKMODE_MASK | CFG_ALPHAM_MASK | CFG_ALPHA_MASK,
6496f60e37SRussell King 		       dcrtc->base + LCD_SPU_DMA_CTRL1);
65d378859aSRussell King 	if (dcrtc->variant->has_spu_adv_reg)
66d378859aSRussell King 		armada_updatel(prop->colorkey_enable,
67d378859aSRussell King 			       ADV_GRACOLORKEY | ADV_VIDCOLORKEY,
68d378859aSRussell King 			       dcrtc->base + LCD_SPU_ADV_REG);
6996f60e37SRussell King 	spin_unlock_irq(&dcrtc->irq_lock);
7096f60e37SRussell King }
7196f60e37SRussell King 
7296f60e37SRussell King /* === Plane support === */
734a8506d2SRussell King static void armada_ovl_plane_work(struct armada_crtc *dcrtc,
74eaab0130SRussell King 	struct armada_plane_work *work)
7596f60e37SRussell King {
76a3f6a18fSRussell King 	unsigned long flags;
7796f60e37SRussell King 
78eaab0130SRussell King 	trace_armada_ovl_plane_work(&dcrtc->crtc, work->plane);
79c8a220c6SRussell King 
80a3f6a18fSRussell King 	spin_lock_irqsave(&dcrtc->irq_lock, flags);
81eaa66279SRussell King 	armada_drm_crtc_update_regs(dcrtc, work->regs);
82a3f6a18fSRussell King 	spin_unlock_irqrestore(&dcrtc->irq_lock, flags);
8396f60e37SRussell King }
8496f60e37SRussell King 
8547dc413bSRussell King static void armada_drm_overlay_plane_atomic_update(struct drm_plane *plane,
8647dc413bSRussell King 	struct drm_plane_state *old_state)
8747dc413bSRussell King {
8847dc413bSRussell King 	struct drm_plane_state *state = plane->state;
8947dc413bSRussell King 	struct armada_crtc *dcrtc;
9047dc413bSRussell King 	struct armada_regs *regs;
913acea7b9SRussell King 	unsigned int idx;
923acea7b9SRussell King 	u32 cfg, cfg_mask, val;
9347dc413bSRussell King 
9447dc413bSRussell King 	DRM_DEBUG_KMS("[PLANE:%d:%s]\n", plane->base.id, plane->name);
9547dc413bSRussell King 
9647dc413bSRussell King 	if (!state->fb || WARN_ON(!state->crtc))
9747dc413bSRussell King 		return;
9847dc413bSRussell King 
9947dc413bSRussell King 	DRM_DEBUG_KMS("[PLANE:%d:%s] is on [CRTC:%d:%s] with [FB:%d] visible %u->%u\n",
10047dc413bSRussell King 		plane->base.id, plane->name,
10147dc413bSRussell King 		state->crtc->base.id, state->crtc->name,
10247dc413bSRussell King 		state->fb->base.id,
10347dc413bSRussell King 		old_state->visible, state->visible);
10447dc413bSRussell King 
10547dc413bSRussell King 	dcrtc = drm_to_armada_crtc(state->crtc);
10647dc413bSRussell King 	regs = dcrtc->regs + dcrtc->regs_idx;
10747dc413bSRussell King 
1083acea7b9SRussell King 	drm_to_armada_ovl_plane(plane)->wait_vblank = false;
1093acea7b9SRussell King 
1103acea7b9SRussell King 	idx = 0;
1113acea7b9SRussell King 	if (!old_state->visible && state->visible)
1123acea7b9SRussell King 		armada_reg_queue_mod(regs, idx,
1133acea7b9SRussell King 				     0, CFG_PDWN16x66 | CFG_PDWN32x66,
1143acea7b9SRussell King 				     LCD_SPU_SRAM_PARA1);
1153acea7b9SRussell King 	val = armada_rect_hw_fp(&state->src);
1163acea7b9SRussell King 	if (armada_rect_hw_fp(&old_state->src) != val)
1173acea7b9SRussell King 		armada_reg_queue_set(regs, idx, val, LCD_SPU_DMA_HPXL_VLN);
1183acea7b9SRussell King 	val = armada_rect_yx(&state->dst);
1193acea7b9SRussell King 	if (armada_rect_yx(&old_state->dst) != val)
1203acea7b9SRussell King 		armada_reg_queue_set(regs, idx, val, LCD_SPU_DMA_OVSA_HPXL_VLN);
1213acea7b9SRussell King 	val = armada_rect_hw(&state->dst);
1223acea7b9SRussell King 	if (armada_rect_hw(&old_state->dst) != val)
1233acea7b9SRussell King 		armada_reg_queue_set(regs, idx, val, LCD_SPU_DZM_HPXL_VLN);
1243acea7b9SRussell King 	/* FIXME: overlay on an interlaced display */
1253acea7b9SRussell King 	if (old_state->src.x1 != state->src.x1 ||
1263acea7b9SRussell King 	    old_state->src.y1 != state->src.y1 ||
1273acea7b9SRussell King 	    old_state->fb != state->fb) {
1283acea7b9SRussell King 		const struct drm_format_info *format;
1293acea7b9SRussell King 		u16 src_x = state->src.x1 >> 16;
1303acea7b9SRussell King 		u16 src_y = state->src.y1 >> 16;
1313acea7b9SRussell King 		u32 addrs[3];
1323acea7b9SRussell King 
1333acea7b9SRussell King 		armada_drm_plane_calc_addrs(addrs, state->fb, src_x, src_y);
1343acea7b9SRussell King 
1353acea7b9SRussell King 		armada_reg_queue_set(regs, idx, addrs[0],
1363acea7b9SRussell King 				     LCD_SPU_DMA_START_ADDR_Y0);
1373acea7b9SRussell King 		armada_reg_queue_set(regs, idx, addrs[1],
1383acea7b9SRussell King 				     LCD_SPU_DMA_START_ADDR_U0);
1393acea7b9SRussell King 		armada_reg_queue_set(regs, idx, addrs[2],
1403acea7b9SRussell King 				     LCD_SPU_DMA_START_ADDR_V0);
1413acea7b9SRussell King 		armada_reg_queue_set(regs, idx, addrs[0],
1423acea7b9SRussell King 				     LCD_SPU_DMA_START_ADDR_Y1);
1433acea7b9SRussell King 		armada_reg_queue_set(regs, idx, addrs[1],
1443acea7b9SRussell King 				     LCD_SPU_DMA_START_ADDR_U1);
1453acea7b9SRussell King 		armada_reg_queue_set(regs, idx, addrs[2],
1463acea7b9SRussell King 				     LCD_SPU_DMA_START_ADDR_V1);
1473acea7b9SRussell King 
1483acea7b9SRussell King 		val = state->fb->pitches[0] << 16 | state->fb->pitches[0];
1493acea7b9SRussell King 		armada_reg_queue_set(regs, idx, val, LCD_SPU_DMA_PITCH_YC);
1503acea7b9SRussell King 		val = state->fb->pitches[1] << 16 | state->fb->pitches[2];
1513acea7b9SRussell King 		armada_reg_queue_set(regs, idx, val, LCD_SPU_DMA_PITCH_UV);
1523acea7b9SRussell King 
1533acea7b9SRussell King 		cfg = CFG_DMA_FMT(drm_fb_to_armada_fb(state->fb)->fmt) |
1543acea7b9SRussell King 		      CFG_DMA_MOD(drm_fb_to_armada_fb(state->fb)->mod) |
1553acea7b9SRussell King 		      CFG_CBSH_ENA;
1563acea7b9SRussell King 		if (state->visible)
1573acea7b9SRussell King 			cfg |= CFG_DMA_ENA;
1583acea7b9SRussell King 
1593acea7b9SRussell King 		/*
1603acea7b9SRussell King 		 * Shifting a YUV packed format image by one pixel causes the
1613acea7b9SRussell King 		 * U/V planes to swap.  Compensate for it by also toggling
1623acea7b9SRussell King 		 * the UV swap.
1633acea7b9SRussell King 		 */
1643acea7b9SRussell King 		format = state->fb->format;
1653acea7b9SRussell King 		if (format->num_planes == 1 && src_x & (format->hsub - 1))
1663acea7b9SRussell King 			cfg ^= CFG_DMA_MOD(CFG_SWAPUV);
1673acea7b9SRussell King 		cfg_mask = CFG_CBSH_ENA | CFG_DMAFORMAT |
1683acea7b9SRussell King 			   CFG_DMA_MOD(CFG_SWAPRB | CFG_SWAPUV |
1693acea7b9SRussell King 				       CFG_SWAPYU | CFG_YUV2RGB) |
1703acea7b9SRussell King 			   CFG_DMA_FTOGGLE | CFG_DMA_TSTMODE |
1713acea7b9SRussell King 			   CFG_DMA_ENA;
1723acea7b9SRussell King 
1733acea7b9SRussell King 		drm_to_armada_ovl_plane(plane)->wait_vblank = true;
1743acea7b9SRussell King 	} else if (old_state->visible != state->visible) {
1753acea7b9SRussell King 		cfg = state->visible ? CFG_DMA_ENA : 0;
1763acea7b9SRussell King 		cfg_mask = CFG_DMA_ENA;
1773acea7b9SRussell King 	} else {
1783acea7b9SRussell King 		cfg = cfg_mask = 0;
1793acea7b9SRussell King 	}
1803acea7b9SRussell King 	if (drm_rect_width(&old_state->src) != drm_rect_width(&state->src) ||
1813acea7b9SRussell King 	    drm_rect_width(&old_state->dst) != drm_rect_width(&state->dst)) {
1823acea7b9SRussell King 		cfg_mask |= CFG_DMA_HSMOOTH;
1833acea7b9SRussell King 		if (drm_rect_width(&state->src) >> 16 !=
1843acea7b9SRussell King 		    drm_rect_width(&state->dst))
1853acea7b9SRussell King 			cfg |= CFG_DMA_HSMOOTH;
1863acea7b9SRussell King 	}
1873acea7b9SRussell King 
1883acea7b9SRussell King 	if (cfg_mask)
1893acea7b9SRussell King 		armada_reg_queue_mod(regs, idx, cfg, cfg_mask,
1903acea7b9SRussell King 				     LCD_SPU_DMA_CTRL0);
1913acea7b9SRussell King 
1923acea7b9SRussell King 	dcrtc->regs_idx += idx;
19347dc413bSRussell King }
19447dc413bSRussell King 
19547dc413bSRussell King static void armada_drm_overlay_plane_atomic_disable(struct drm_plane *plane,
19647dc413bSRussell King 	struct drm_plane_state *old_state)
19747dc413bSRussell King {
19847dc413bSRussell King 	struct armada_crtc *dcrtc;
19947dc413bSRussell King 	struct armada_regs *regs;
20047dc413bSRussell King 	unsigned int idx = 0;
20147dc413bSRussell King 
20247dc413bSRussell King 	DRM_DEBUG_KMS("[PLANE:%d:%s]\n", plane->base.id, plane->name);
20347dc413bSRussell King 
20447dc413bSRussell King 	if (!old_state->crtc)
20547dc413bSRussell King 		return;
20647dc413bSRussell King 
20747dc413bSRussell King 	DRM_DEBUG_KMS("[PLANE:%d:%s] was on [CRTC:%d:%s] with [FB:%d]\n",
20847dc413bSRussell King 		plane->base.id, plane->name,
20947dc413bSRussell King 		old_state->crtc->base.id, old_state->crtc->name,
21047dc413bSRussell King 		old_state->fb->base.id);
21147dc413bSRussell King 
21247dc413bSRussell King 	dcrtc = drm_to_armada_crtc(old_state->crtc);
21347dc413bSRussell King 	regs = dcrtc->regs + dcrtc->regs_idx;
21447dc413bSRussell King 
21547dc413bSRussell King 	/* Disable plane and power down the YUV FIFOs */
21647dc413bSRussell King 	armada_reg_queue_mod(regs, idx, 0, CFG_DMA_ENA, LCD_SPU_DMA_CTRL0);
21747dc413bSRussell King 	armada_reg_queue_mod(regs, idx, CFG_PDWN16x66 | CFG_PDWN32x66, 0,
21847dc413bSRussell King 			     LCD_SPU_SRAM_PARA1);
21947dc413bSRussell King 
22047dc413bSRussell King 	dcrtc->regs_idx += idx;
22147dc413bSRussell King 
22247dc413bSRussell King 	if (dcrtc->plane == plane)
22347dc413bSRussell King 		dcrtc->plane = NULL;
22447dc413bSRussell King }
22547dc413bSRussell King 
22647dc413bSRussell King static const struct drm_plane_helper_funcs armada_overlay_plane_helper_funcs = {
22747dc413bSRussell King 	.prepare_fb	= armada_drm_plane_prepare_fb,
22847dc413bSRussell King 	.cleanup_fb	= armada_drm_plane_cleanup_fb,
22947dc413bSRussell King 	.atomic_check	= armada_drm_plane_atomic_check,
23047dc413bSRussell King 	.atomic_update	= armada_drm_overlay_plane_atomic_update,
23147dc413bSRussell King 	.atomic_disable	= armada_drm_overlay_plane_atomic_disable,
23247dc413bSRussell King };
23347dc413bSRussell King 
23447dc413bSRussell King static int armada_overlay_commit(struct drm_plane *plane,
23547dc413bSRussell King 	struct drm_plane_state *state)
23696f60e37SRussell King {
23728a2aebeSRussell King 	struct armada_ovl_plane *dplane = drm_to_armada_ovl_plane(plane);
23847dc413bSRussell King 	const struct drm_plane_helper_funcs *plane_funcs;
23947dc413bSRussell King 	struct armada_crtc *dcrtc = drm_to_armada_crtc(state->crtc);
240d924155dSRussell King 	struct armada_plane_work *work;
24196f60e37SRussell King 	int ret;
24296f60e37SRussell King 
24347dc413bSRussell King 	plane_funcs = plane->helper_private;
24447dc413bSRussell King 	ret = plane_funcs->atomic_check(plane, state);
24598fb74f4SRussell King 	if (ret)
24647dc413bSRussell King 		goto put_state;
24798fb74f4SRussell King 
248d924155dSRussell King 	work = &dplane->base.works[dplane->base.next_work];
24996f60e37SRussell King 
25047dc413bSRussell King 	if (plane->state->fb != state->fb) {
25196f60e37SRussell King 		/*
25296f60e37SRussell King 		 * Take a reference on the new framebuffer - we want to
25396f60e37SRussell King 		 * hold on to it while the hardware is displaying it.
25496f60e37SRussell King 		 */
25547dc413bSRussell King 		drm_framebuffer_reference(state->fb);
25696f60e37SRussell King 
25747dc413bSRussell King 		work->old_fb = plane->state->fb;
258b972a80fSRussell King 	} else {
259eaa66279SRussell King 		work->old_fb = NULL;
26096f60e37SRussell King 	}
26196f60e37SRussell King 
26247dc413bSRussell King 	/* Point of no return */
26347dc413bSRussell King 	swap(plane->state, state);
26498fb74f4SRussell King 
26547dc413bSRussell King 	dcrtc->regs_idx = 0;
26647dc413bSRussell King 	dcrtc->regs = work->regs;
26747dc413bSRussell King 
26847dc413bSRussell King 	plane_funcs->atomic_update(plane, state);
26947dc413bSRussell King 
27047dc413bSRussell King 	/* If nothing was updated, short-circuit */
2713acea7b9SRussell King 	if (dcrtc->regs_idx == 0)
27247dc413bSRussell King 		goto put_state;
27347dc413bSRussell King 
27447dc413bSRussell King 	armada_reg_queue_end(dcrtc->regs, dcrtc->regs_idx);
275d19f6ee5SRussell King 
27607da3c78SRussell King 	/* Wait for pending work to complete */
27707da3c78SRussell King 	if (armada_drm_plane_work_wait(&dplane->base, HZ / 25) == 0)
27807da3c78SRussell King 		armada_drm_plane_work_cancel(dcrtc, &dplane->base);
27907da3c78SRussell King 
280d19f6ee5SRussell King 	/* Just updating the position/size? */
2813acea7b9SRussell King 	if (!dplane->wait_vblank) {
282d19f6ee5SRussell King 		armada_ovl_plane_work(dcrtc, work);
28347dc413bSRussell King 		goto put_state;
284d19f6ee5SRussell King 	}
28596f60e37SRussell King 
28696f60e37SRussell King 	if (!dcrtc->plane) {
28796f60e37SRussell King 		dcrtc->plane = plane;
28896f60e37SRussell King 		armada_ovl_update_attr(&dplane->prop, dcrtc);
28996f60e37SRussell King 	}
29096f60e37SRussell King 
291eaab0130SRussell King 	/* Queue it for update on the next interrupt if we are enabled */
292c93dfdcdSRussell King 	ret = armada_drm_plane_work_queue(dcrtc, work);
29347dc413bSRussell King 	if (ret) {
294c93dfdcdSRussell King 		DRM_ERROR("failed to queue plane work: %d\n", ret);
29547dc413bSRussell King 		ret = 0;
29647dc413bSRussell King 	}
29796f60e37SRussell King 
298d924155dSRussell King 	dplane->base.next_work = !dplane->base.next_work;
29996f60e37SRussell King 
30047dc413bSRussell King put_state:
30147dc413bSRussell King 	drm_atomic_helper_plane_destroy_state(plane, state);
30247dc413bSRussell King 	return ret;
30347dc413bSRussell King }
30447dc413bSRussell King 
30547dc413bSRussell King static int
30647dc413bSRussell King armada_ovl_plane_update(struct drm_plane *plane, struct drm_crtc *crtc,
30747dc413bSRussell King 	struct drm_framebuffer *fb,
30847dc413bSRussell King 	int crtc_x, int crtc_y, unsigned crtc_w, unsigned crtc_h,
30947dc413bSRussell King 	uint32_t src_x, uint32_t src_y, uint32_t src_w, uint32_t src_h,
31047dc413bSRussell King 	struct drm_modeset_acquire_ctx *ctx)
31147dc413bSRussell King {
31247dc413bSRussell King 	struct drm_plane_state *state;
31347dc413bSRussell King 
31447dc413bSRussell King 	trace_armada_ovl_plane_update(plane, crtc, fb,
31547dc413bSRussell King 				 crtc_x, crtc_y, crtc_w, crtc_h,
31647dc413bSRussell King 				 src_x, src_y, src_w, src_h);
31747dc413bSRussell King 
31847dc413bSRussell King 	/* Construct new state for the overlay plane */
31947dc413bSRussell King 	state = drm_atomic_helper_plane_duplicate_state(plane);
32047dc413bSRussell King 	if (!state)
32147dc413bSRussell King 		return -ENOMEM;
32247dc413bSRussell King 
32347dc413bSRussell King 	state->crtc = crtc;
32447dc413bSRussell King 	drm_atomic_set_fb_for_plane(state, fb);
32547dc413bSRussell King 	state->crtc_x = crtc_x;
32647dc413bSRussell King 	state->crtc_y = crtc_y;
32747dc413bSRussell King 	state->crtc_h = crtc_h;
32847dc413bSRussell King 	state->crtc_w = crtc_w;
32947dc413bSRussell King 	state->src_x = src_x;
33047dc413bSRussell King 	state->src_y = src_y;
33147dc413bSRussell King 	state->src_h = src_h;
33247dc413bSRussell King 	state->src_w = src_w;
33347dc413bSRussell King 
33447dc413bSRussell King 	return armada_overlay_commit(plane, state);
33596f60e37SRussell King }
33696f60e37SRussell King 
33728a2aebeSRussell King static void armada_ovl_plane_destroy(struct drm_plane *plane)
33896f60e37SRussell King {
33928a2aebeSRussell King 	struct armada_ovl_plane *dplane = drm_to_armada_ovl_plane(plane);
34041dbb2dbSRussell King 
34141dbb2dbSRussell King 	drm_plane_cleanup(plane);
34241dbb2dbSRussell King 
34341dbb2dbSRussell King 	kfree(dplane);
34496f60e37SRussell King }
34596f60e37SRussell King 
34628a2aebeSRussell King static int armada_ovl_plane_set_property(struct drm_plane *plane,
34796f60e37SRussell King 	struct drm_property *property, uint64_t val)
34896f60e37SRussell King {
34996f60e37SRussell King 	struct armada_private *priv = plane->dev->dev_private;
35028a2aebeSRussell King 	struct armada_ovl_plane *dplane = drm_to_armada_ovl_plane(plane);
35196f60e37SRussell King 	bool update_attr = false;
35296f60e37SRussell King 
35396f60e37SRussell King 	if (property == priv->colorkey_prop) {
35496f60e37SRussell King #define CCC(v) ((v) << 24 | (v) << 16 | (v) << 8)
35596f60e37SRussell King 		dplane->prop.colorkey_yr = CCC(K2R(val));
35696f60e37SRussell King 		dplane->prop.colorkey_ug = CCC(K2G(val));
35796f60e37SRussell King 		dplane->prop.colorkey_vb = CCC(K2B(val));
35896f60e37SRussell King #undef CCC
35996f60e37SRussell King 		update_attr = true;
36096f60e37SRussell King 	} else if (property == priv->colorkey_min_prop) {
36196f60e37SRussell King 		dplane->prop.colorkey_yr &= ~0x00ff0000;
36296f60e37SRussell King 		dplane->prop.colorkey_yr |= K2R(val) << 16;
36396f60e37SRussell King 		dplane->prop.colorkey_ug &= ~0x00ff0000;
36496f60e37SRussell King 		dplane->prop.colorkey_ug |= K2G(val) << 16;
36596f60e37SRussell King 		dplane->prop.colorkey_vb &= ~0x00ff0000;
36696f60e37SRussell King 		dplane->prop.colorkey_vb |= K2B(val) << 16;
36796f60e37SRussell King 		update_attr = true;
36896f60e37SRussell King 	} else if (property == priv->colorkey_max_prop) {
36996f60e37SRussell King 		dplane->prop.colorkey_yr &= ~0xff000000;
37096f60e37SRussell King 		dplane->prop.colorkey_yr |= K2R(val) << 24;
37196f60e37SRussell King 		dplane->prop.colorkey_ug &= ~0xff000000;
37296f60e37SRussell King 		dplane->prop.colorkey_ug |= K2G(val) << 24;
37396f60e37SRussell King 		dplane->prop.colorkey_vb &= ~0xff000000;
37496f60e37SRussell King 		dplane->prop.colorkey_vb |= K2B(val) << 24;
37596f60e37SRussell King 		update_attr = true;
37696f60e37SRussell King 	} else if (property == priv->colorkey_val_prop) {
37796f60e37SRussell King 		dplane->prop.colorkey_yr &= ~0x0000ff00;
37896f60e37SRussell King 		dplane->prop.colorkey_yr |= K2R(val) << 8;
37996f60e37SRussell King 		dplane->prop.colorkey_ug &= ~0x0000ff00;
38096f60e37SRussell King 		dplane->prop.colorkey_ug |= K2G(val) << 8;
38196f60e37SRussell King 		dplane->prop.colorkey_vb &= ~0x0000ff00;
38296f60e37SRussell King 		dplane->prop.colorkey_vb |= K2B(val) << 8;
38396f60e37SRussell King 		update_attr = true;
38496f60e37SRussell King 	} else if (property == priv->colorkey_alpha_prop) {
38596f60e37SRussell King 		dplane->prop.colorkey_yr &= ~0x000000ff;
38696f60e37SRussell King 		dplane->prop.colorkey_yr |= K2R(val);
38796f60e37SRussell King 		dplane->prop.colorkey_ug &= ~0x000000ff;
38896f60e37SRussell King 		dplane->prop.colorkey_ug |= K2G(val);
38996f60e37SRussell King 		dplane->prop.colorkey_vb &= ~0x000000ff;
39096f60e37SRussell King 		dplane->prop.colorkey_vb |= K2B(val);
39196f60e37SRussell King 		update_attr = true;
39296f60e37SRussell King 	} else if (property == priv->colorkey_mode_prop) {
393d378859aSRussell King 		if (val == CKMODE_DISABLE) {
394d378859aSRussell King 			dplane->prop.colorkey_mode =
395d378859aSRussell King 				CFG_CKMODE(CKMODE_DISABLE) |
396d378859aSRussell King 				CFG_ALPHAM_CFG | CFG_ALPHA(255);
397d378859aSRussell King 			dplane->prop.colorkey_enable = 0;
398d378859aSRussell King 		} else {
399d378859aSRussell King 			dplane->prop.colorkey_mode =
400d378859aSRussell King 				CFG_CKMODE(val) |
401d378859aSRussell King 				CFG_ALPHAM_GRA | CFG_ALPHA(0);
402d378859aSRussell King 			dplane->prop.colorkey_enable = ADV_GRACOLORKEY;
403d378859aSRussell King 		}
40496f60e37SRussell King 		update_attr = true;
40596f60e37SRussell King 	} else if (property == priv->brightness_prop) {
40696f60e37SRussell King 		dplane->prop.brightness = val - 256;
40796f60e37SRussell King 		update_attr = true;
40896f60e37SRussell King 	} else if (property == priv->contrast_prop) {
40996f60e37SRussell King 		dplane->prop.contrast = val;
41096f60e37SRussell King 		update_attr = true;
41196f60e37SRussell King 	} else if (property == priv->saturation_prop) {
41296f60e37SRussell King 		dplane->prop.saturation = val;
41396f60e37SRussell King 		update_attr = true;
41496f60e37SRussell King 	}
41596f60e37SRussell King 
416561f60bcSRussell King 	if (update_attr && dplane->base.base.crtc)
41796f60e37SRussell King 		armada_ovl_update_attr(&dplane->prop,
418561f60bcSRussell King 				       drm_to_armada_crtc(dplane->base.base.crtc));
41996f60e37SRussell King 
42096f60e37SRussell King 	return 0;
42196f60e37SRussell King }
42296f60e37SRussell King 
42328a2aebeSRussell King static const struct drm_plane_funcs armada_ovl_plane_funcs = {
42428a2aebeSRussell King 	.update_plane	= armada_ovl_plane_update,
42547dc413bSRussell King 	.disable_plane	= drm_plane_helper_disable,
42628a2aebeSRussell King 	.destroy	= armada_ovl_plane_destroy,
42728a2aebeSRussell King 	.set_property	= armada_ovl_plane_set_property,
42847dc413bSRussell King 	.reset		= drm_atomic_helper_plane_reset,
42996f60e37SRussell King };
43096f60e37SRussell King 
43128a2aebeSRussell King static const uint32_t armada_ovl_formats[] = {
43296f60e37SRussell King 	DRM_FORMAT_UYVY,
43396f60e37SRussell King 	DRM_FORMAT_YUYV,
43496f60e37SRussell King 	DRM_FORMAT_YUV420,
43596f60e37SRussell King 	DRM_FORMAT_YVU420,
43696f60e37SRussell King 	DRM_FORMAT_YUV422,
43796f60e37SRussell King 	DRM_FORMAT_YVU422,
43896f60e37SRussell King 	DRM_FORMAT_VYUY,
43996f60e37SRussell King 	DRM_FORMAT_YVYU,
44096f60e37SRussell King 	DRM_FORMAT_ARGB8888,
44196f60e37SRussell King 	DRM_FORMAT_ABGR8888,
44296f60e37SRussell King 	DRM_FORMAT_XRGB8888,
44396f60e37SRussell King 	DRM_FORMAT_XBGR8888,
44496f60e37SRussell King 	DRM_FORMAT_RGB888,
44596f60e37SRussell King 	DRM_FORMAT_BGR888,
44696f60e37SRussell King 	DRM_FORMAT_ARGB1555,
44796f60e37SRussell King 	DRM_FORMAT_ABGR1555,
44896f60e37SRussell King 	DRM_FORMAT_RGB565,
44996f60e37SRussell King 	DRM_FORMAT_BGR565,
45096f60e37SRussell King };
45196f60e37SRussell King 
4528a63ca58SArvind Yadav static const struct drm_prop_enum_list armada_drm_colorkey_enum_list[] = {
45396f60e37SRussell King 	{ CKMODE_DISABLE, "disabled" },
45496f60e37SRussell King 	{ CKMODE_Y,       "Y component" },
45596f60e37SRussell King 	{ CKMODE_U,       "U component" },
45696f60e37SRussell King 	{ CKMODE_V,       "V component" },
45796f60e37SRussell King 	{ CKMODE_RGB,     "RGB" },
45896f60e37SRussell King 	{ CKMODE_R,       "R component" },
45996f60e37SRussell King 	{ CKMODE_G,       "G component" },
46096f60e37SRussell King 	{ CKMODE_B,       "B component" },
46196f60e37SRussell King };
46296f60e37SRussell King 
46396f60e37SRussell King static int armada_overlay_create_properties(struct drm_device *dev)
46496f60e37SRussell King {
46596f60e37SRussell King 	struct armada_private *priv = dev->dev_private;
46696f60e37SRussell King 
46796f60e37SRussell King 	if (priv->colorkey_prop)
46896f60e37SRussell King 		return 0;
46996f60e37SRussell King 
47096f60e37SRussell King 	priv->colorkey_prop = drm_property_create_range(dev, 0,
47196f60e37SRussell King 				"colorkey", 0, 0xffffff);
47296f60e37SRussell King 	priv->colorkey_min_prop = drm_property_create_range(dev, 0,
47396f60e37SRussell King 				"colorkey_min", 0, 0xffffff);
47496f60e37SRussell King 	priv->colorkey_max_prop = drm_property_create_range(dev, 0,
47596f60e37SRussell King 				"colorkey_max", 0, 0xffffff);
47696f60e37SRussell King 	priv->colorkey_val_prop = drm_property_create_range(dev, 0,
47796f60e37SRussell King 				"colorkey_val", 0, 0xffffff);
47896f60e37SRussell King 	priv->colorkey_alpha_prop = drm_property_create_range(dev, 0,
47996f60e37SRussell King 				"colorkey_alpha", 0, 0xffffff);
48096f60e37SRussell King 	priv->colorkey_mode_prop = drm_property_create_enum(dev, 0,
48196f60e37SRussell King 				"colorkey_mode",
48296f60e37SRussell King 				armada_drm_colorkey_enum_list,
48396f60e37SRussell King 				ARRAY_SIZE(armada_drm_colorkey_enum_list));
48496f60e37SRussell King 	priv->brightness_prop = drm_property_create_range(dev, 0,
48596f60e37SRussell King 				"brightness", 0, 256 + 255);
48696f60e37SRussell King 	priv->contrast_prop = drm_property_create_range(dev, 0,
48796f60e37SRussell King 				"contrast", 0, 0x7fff);
48896f60e37SRussell King 	priv->saturation_prop = drm_property_create_range(dev, 0,
48996f60e37SRussell King 				"saturation", 0, 0x7fff);
49096f60e37SRussell King 
49196f60e37SRussell King 	if (!priv->colorkey_prop)
49296f60e37SRussell King 		return -ENOMEM;
49396f60e37SRussell King 
49496f60e37SRussell King 	return 0;
49596f60e37SRussell King }
49696f60e37SRussell King 
49796f60e37SRussell King int armada_overlay_plane_create(struct drm_device *dev, unsigned long crtcs)
49896f60e37SRussell King {
49996f60e37SRussell King 	struct armada_private *priv = dev->dev_private;
50096f60e37SRussell King 	struct drm_mode_object *mobj;
50128a2aebeSRussell King 	struct armada_ovl_plane *dplane;
50296f60e37SRussell King 	int ret;
50396f60e37SRussell King 
50496f60e37SRussell King 	ret = armada_overlay_create_properties(dev);
50596f60e37SRussell King 	if (ret)
50696f60e37SRussell King 		return ret;
50796f60e37SRussell King 
50896f60e37SRussell King 	dplane = kzalloc(sizeof(*dplane), GFP_KERNEL);
50996f60e37SRussell King 	if (!dplane)
51096f60e37SRussell King 		return -ENOMEM;
51196f60e37SRussell King 
5125740d27fSRussell King 	ret = armada_drm_plane_init(&dplane->base);
5135740d27fSRussell King 	if (ret) {
5145740d27fSRussell King 		kfree(dplane);
5155740d27fSRussell King 		return ret;
5165740d27fSRussell King 	}
5175740d27fSRussell King 
518d924155dSRussell King 	dplane->base.works[0].fn = armada_ovl_plane_work;
519d924155dSRussell King 	dplane->base.works[1].fn = armada_ovl_plane_work;
52096f60e37SRussell King 
52147dc413bSRussell King 	drm_plane_helper_add(&dplane->base.base,
52247dc413bSRussell King 			     &armada_overlay_plane_helper_funcs);
52347dc413bSRussell King 
524561f60bcSRussell King 	ret = drm_universal_plane_init(dev, &dplane->base.base, crtcs,
525d563c245SRussell King 				       &armada_ovl_plane_funcs,
526d563c245SRussell King 				       armada_ovl_formats,
527d563c245SRussell King 				       ARRAY_SIZE(armada_ovl_formats),
528e6fc3b68SBen Widawsky 				       NULL,
529b0b3b795SVille Syrjälä 				       DRM_PLANE_TYPE_OVERLAY, NULL);
53028a2aebeSRussell King 	if (ret) {
53128a2aebeSRussell King 		kfree(dplane);
53228a2aebeSRussell King 		return ret;
53328a2aebeSRussell King 	}
53496f60e37SRussell King 
53596f60e37SRussell King 	dplane->prop.colorkey_yr = 0xfefefe00;
53696f60e37SRussell King 	dplane->prop.colorkey_ug = 0x01010100;
53796f60e37SRussell King 	dplane->prop.colorkey_vb = 0x01010100;
538d378859aSRussell King 	dplane->prop.colorkey_mode = CFG_CKMODE(CKMODE_RGB) |
539d378859aSRussell King 				     CFG_ALPHAM_GRA | CFG_ALPHA(0);
540d378859aSRussell King 	dplane->prop.colorkey_enable = ADV_GRACOLORKEY;
54196f60e37SRussell King 	dplane->prop.brightness = 0;
54296f60e37SRussell King 	dplane->prop.contrast = 0x4000;
54396f60e37SRussell King 	dplane->prop.saturation = 0x4000;
54496f60e37SRussell King 
545561f60bcSRussell King 	mobj = &dplane->base.base.base;
54696f60e37SRussell King 	drm_object_attach_property(mobj, priv->colorkey_prop,
54796f60e37SRussell King 				   0x0101fe);
54896f60e37SRussell King 	drm_object_attach_property(mobj, priv->colorkey_min_prop,
54996f60e37SRussell King 				   0x0101fe);
55096f60e37SRussell King 	drm_object_attach_property(mobj, priv->colorkey_max_prop,
55196f60e37SRussell King 				   0x0101fe);
55296f60e37SRussell King 	drm_object_attach_property(mobj, priv->colorkey_val_prop,
55396f60e37SRussell King 				   0x0101fe);
55496f60e37SRussell King 	drm_object_attach_property(mobj, priv->colorkey_alpha_prop,
55596f60e37SRussell King 				   0x000000);
55696f60e37SRussell King 	drm_object_attach_property(mobj, priv->colorkey_mode_prop,
55796f60e37SRussell King 				   CKMODE_RGB);
55896f60e37SRussell King 	drm_object_attach_property(mobj, priv->brightness_prop, 256);
55996f60e37SRussell King 	drm_object_attach_property(mobj, priv->contrast_prop,
56096f60e37SRussell King 				   dplane->prop.contrast);
56196f60e37SRussell King 	drm_object_attach_property(mobj, priv->saturation_prop,
56296f60e37SRussell King 				   dplane->prop.saturation);
56396f60e37SRussell King 
56496f60e37SRussell King 	return 0;
56596f60e37SRussell King }
566