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