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 2361ba2527SRussell King #define DEFAULT_BRIGHTNESS 0 2461ba2527SRussell King #define DEFAULT_CONTRAST 0x4000 2561ba2527SRussell King #define DEFAULT_SATURATION 0x4000 2661ba2527SRussell King 2728a2aebeSRussell King struct armada_ovl_plane { 28561f60bcSRussell King struct armada_plane base; 2963b93c08SRussell King struct armada_plane_work works[2]; 3063b93c08SRussell King bool next_work; 313acea7b9SRussell King bool wait_vblank; 3296f60e37SRussell King }; 33561f60bcSRussell King #define drm_to_armada_ovl_plane(p) \ 34561f60bcSRussell King container_of(p, struct armada_ovl_plane, base.base) 3596f60e37SRussell King 3661ba2527SRussell King struct armada_overlay_state { 3761ba2527SRussell King struct drm_plane_state base; 38c96103b6SRussell King u32 colorkey_yr; 39c96103b6SRussell King u32 colorkey_ug; 40c96103b6SRussell King u32 colorkey_vb; 41c96103b6SRussell King u32 colorkey_mode; 42c96103b6SRussell King u32 colorkey_enable; 4361ba2527SRussell King s16 brightness; 4461ba2527SRussell King u16 contrast; 4561ba2527SRussell King u16 saturation; 4661ba2527SRussell King }; 4761ba2527SRussell King #define drm_to_overlay_state(s) \ 4861ba2527SRussell King container_of(s, struct armada_overlay_state, base) 4961ba2527SRussell King 5061ba2527SRussell King static inline u32 armada_spu_contrast(struct drm_plane_state *state) 5161ba2527SRussell King { 5261ba2527SRussell King return drm_to_overlay_state(state)->brightness << 16 | 5361ba2527SRussell King drm_to_overlay_state(state)->contrast; 5461ba2527SRussell King } 5561ba2527SRussell King 5661ba2527SRussell King static inline u32 armada_spu_saturation(struct drm_plane_state *state) 5761ba2527SRussell King { 5861ba2527SRussell King /* Docs say 15:0, but it seems to actually be 31:16 on Armada 510 */ 5961ba2527SRussell King return drm_to_overlay_state(state)->saturation << 16; 6061ba2527SRussell King } 6196f60e37SRussell King 6296f60e37SRussell King /* === Plane support === */ 634a8506d2SRussell King static void armada_ovl_plane_work(struct armada_crtc *dcrtc, 64eaab0130SRussell King struct armada_plane_work *work) 6596f60e37SRussell King { 66a3f6a18fSRussell King unsigned long flags; 6796f60e37SRussell King 68eaab0130SRussell King trace_armada_ovl_plane_work(&dcrtc->crtc, work->plane); 69c8a220c6SRussell King 70a3f6a18fSRussell King spin_lock_irqsave(&dcrtc->irq_lock, flags); 71eaa66279SRussell King armada_drm_crtc_update_regs(dcrtc, work->regs); 72a3f6a18fSRussell King spin_unlock_irqrestore(&dcrtc->irq_lock, flags); 7396f60e37SRussell King } 7496f60e37SRussell King 7547dc413bSRussell King static void armada_drm_overlay_plane_atomic_update(struct drm_plane *plane, 7647dc413bSRussell King struct drm_plane_state *old_state) 7747dc413bSRussell King { 7847dc413bSRussell King struct drm_plane_state *state = plane->state; 7947dc413bSRussell King struct armada_crtc *dcrtc; 8047dc413bSRussell King struct armada_regs *regs; 813acea7b9SRussell King unsigned int idx; 823acea7b9SRussell King u32 cfg, cfg_mask, val; 8347dc413bSRussell King 8447dc413bSRussell King DRM_DEBUG_KMS("[PLANE:%d:%s]\n", plane->base.id, plane->name); 8547dc413bSRussell King 8647dc413bSRussell King if (!state->fb || WARN_ON(!state->crtc)) 8747dc413bSRussell King return; 8847dc413bSRussell King 8947dc413bSRussell King DRM_DEBUG_KMS("[PLANE:%d:%s] is on [CRTC:%d:%s] with [FB:%d] visible %u->%u\n", 9047dc413bSRussell King plane->base.id, plane->name, 9147dc413bSRussell King state->crtc->base.id, state->crtc->name, 9247dc413bSRussell King state->fb->base.id, 9347dc413bSRussell King old_state->visible, state->visible); 9447dc413bSRussell King 9547dc413bSRussell King dcrtc = drm_to_armada_crtc(state->crtc); 9647dc413bSRussell King regs = dcrtc->regs + dcrtc->regs_idx; 9747dc413bSRussell King 983acea7b9SRussell King drm_to_armada_ovl_plane(plane)->wait_vblank = false; 993acea7b9SRussell King 1003acea7b9SRussell King idx = 0; 1013acea7b9SRussell King if (!old_state->visible && state->visible) 1023acea7b9SRussell King armada_reg_queue_mod(regs, idx, 1033acea7b9SRussell King 0, CFG_PDWN16x66 | CFG_PDWN32x66, 1043acea7b9SRussell King LCD_SPU_SRAM_PARA1); 1053acea7b9SRussell King val = armada_rect_hw_fp(&state->src); 1063acea7b9SRussell King if (armada_rect_hw_fp(&old_state->src) != val) 1073acea7b9SRussell King armada_reg_queue_set(regs, idx, val, LCD_SPU_DMA_HPXL_VLN); 1083acea7b9SRussell King val = armada_rect_yx(&state->dst); 1093acea7b9SRussell King if (armada_rect_yx(&old_state->dst) != val) 1103acea7b9SRussell King armada_reg_queue_set(regs, idx, val, LCD_SPU_DMA_OVSA_HPXL_VLN); 1113acea7b9SRussell King val = armada_rect_hw(&state->dst); 1123acea7b9SRussell King if (armada_rect_hw(&old_state->dst) != val) 1133acea7b9SRussell King armada_reg_queue_set(regs, idx, val, LCD_SPU_DZM_HPXL_VLN); 1143acea7b9SRussell King /* FIXME: overlay on an interlaced display */ 1153acea7b9SRussell King if (old_state->src.x1 != state->src.x1 || 1163acea7b9SRussell King old_state->src.y1 != state->src.y1 || 1173acea7b9SRussell King old_state->fb != state->fb) { 1183acea7b9SRussell King const struct drm_format_info *format; 1193acea7b9SRussell King u16 src_x = state->src.x1 >> 16; 1203acea7b9SRussell King u16 src_y = state->src.y1 >> 16; 1213acea7b9SRussell King u32 addrs[3]; 1223acea7b9SRussell King 1233acea7b9SRussell King armada_drm_plane_calc_addrs(addrs, state->fb, src_x, src_y); 1243acea7b9SRussell King 1253acea7b9SRussell King armada_reg_queue_set(regs, idx, addrs[0], 1263acea7b9SRussell King LCD_SPU_DMA_START_ADDR_Y0); 1273acea7b9SRussell King armada_reg_queue_set(regs, idx, addrs[1], 1283acea7b9SRussell King LCD_SPU_DMA_START_ADDR_U0); 1293acea7b9SRussell King armada_reg_queue_set(regs, idx, addrs[2], 1303acea7b9SRussell King LCD_SPU_DMA_START_ADDR_V0); 1313acea7b9SRussell King armada_reg_queue_set(regs, idx, addrs[0], 1323acea7b9SRussell King LCD_SPU_DMA_START_ADDR_Y1); 1333acea7b9SRussell King armada_reg_queue_set(regs, idx, addrs[1], 1343acea7b9SRussell King LCD_SPU_DMA_START_ADDR_U1); 1353acea7b9SRussell King armada_reg_queue_set(regs, idx, addrs[2], 1363acea7b9SRussell King LCD_SPU_DMA_START_ADDR_V1); 1373acea7b9SRussell King 1383acea7b9SRussell King val = state->fb->pitches[0] << 16 | state->fb->pitches[0]; 1393acea7b9SRussell King armada_reg_queue_set(regs, idx, val, LCD_SPU_DMA_PITCH_YC); 1403acea7b9SRussell King val = state->fb->pitches[1] << 16 | state->fb->pitches[2]; 1413acea7b9SRussell King armada_reg_queue_set(regs, idx, val, LCD_SPU_DMA_PITCH_UV); 1423acea7b9SRussell King 1433acea7b9SRussell King cfg = CFG_DMA_FMT(drm_fb_to_armada_fb(state->fb)->fmt) | 1443acea7b9SRussell King CFG_DMA_MOD(drm_fb_to_armada_fb(state->fb)->mod) | 1453acea7b9SRussell King CFG_CBSH_ENA; 1463acea7b9SRussell King if (state->visible) 1473acea7b9SRussell King cfg |= CFG_DMA_ENA; 1483acea7b9SRussell King 1493acea7b9SRussell King /* 1503acea7b9SRussell King * Shifting a YUV packed format image by one pixel causes the 1513acea7b9SRussell King * U/V planes to swap. Compensate for it by also toggling 1523acea7b9SRussell King * the UV swap. 1533acea7b9SRussell King */ 1543acea7b9SRussell King format = state->fb->format; 1553acea7b9SRussell King if (format->num_planes == 1 && src_x & (format->hsub - 1)) 1563acea7b9SRussell King cfg ^= CFG_DMA_MOD(CFG_SWAPUV); 1573acea7b9SRussell King cfg_mask = CFG_CBSH_ENA | CFG_DMAFORMAT | 1583acea7b9SRussell King CFG_DMA_MOD(CFG_SWAPRB | CFG_SWAPUV | 1593acea7b9SRussell King CFG_SWAPYU | CFG_YUV2RGB) | 1603acea7b9SRussell King CFG_DMA_FTOGGLE | CFG_DMA_TSTMODE | 1613acea7b9SRussell King CFG_DMA_ENA; 1623acea7b9SRussell King 1633acea7b9SRussell King drm_to_armada_ovl_plane(plane)->wait_vblank = true; 1643acea7b9SRussell King } else if (old_state->visible != state->visible) { 1653acea7b9SRussell King cfg = state->visible ? CFG_DMA_ENA : 0; 1663acea7b9SRussell King cfg_mask = CFG_DMA_ENA; 1673acea7b9SRussell King } else { 1683acea7b9SRussell King cfg = cfg_mask = 0; 1693acea7b9SRussell King } 1703acea7b9SRussell King if (drm_rect_width(&old_state->src) != drm_rect_width(&state->src) || 1713acea7b9SRussell King drm_rect_width(&old_state->dst) != drm_rect_width(&state->dst)) { 1723acea7b9SRussell King cfg_mask |= CFG_DMA_HSMOOTH; 1733acea7b9SRussell King if (drm_rect_width(&state->src) >> 16 != 1743acea7b9SRussell King drm_rect_width(&state->dst)) 1753acea7b9SRussell King cfg |= CFG_DMA_HSMOOTH; 1763acea7b9SRussell King } 1773acea7b9SRussell King 1783acea7b9SRussell King if (cfg_mask) 1793acea7b9SRussell King armada_reg_queue_mod(regs, idx, cfg, cfg_mask, 1803acea7b9SRussell King LCD_SPU_DMA_CTRL0); 1813acea7b9SRussell King 18261ba2527SRussell King val = armada_spu_contrast(state); 18361ba2527SRussell King if ((!old_state->visible && state->visible) || 18461ba2527SRussell King armada_spu_contrast(old_state) != val) 18561ba2527SRussell King armada_reg_queue_set(regs, idx, val, LCD_SPU_CONTRAST); 18661ba2527SRussell King val = armada_spu_saturation(state); 18761ba2527SRussell King if ((!old_state->visible && state->visible) || 18861ba2527SRussell King armada_spu_saturation(old_state) != val) 18961ba2527SRussell King armada_reg_queue_set(regs, idx, val, LCD_SPU_SATURATION); 19061ba2527SRussell King if (!old_state->visible && state->visible) 19161ba2527SRussell King armada_reg_queue_set(regs, idx, 0x00002000, LCD_SPU_CBSH_HUE); 192c96103b6SRussell King val = drm_to_overlay_state(state)->colorkey_yr; 193c96103b6SRussell King if ((!old_state->visible && state->visible) || 194c96103b6SRussell King drm_to_overlay_state(old_state)->colorkey_yr != val) 195c96103b6SRussell King armada_reg_queue_set(regs, idx, val, LCD_SPU_COLORKEY_Y); 196c96103b6SRussell King val = drm_to_overlay_state(state)->colorkey_ug; 197c96103b6SRussell King if ((!old_state->visible && state->visible) || 198c96103b6SRussell King drm_to_overlay_state(old_state)->colorkey_ug != val) 199c96103b6SRussell King armada_reg_queue_set(regs, idx, val, LCD_SPU_COLORKEY_U); 200c96103b6SRussell King val = drm_to_overlay_state(state)->colorkey_vb; 201c96103b6SRussell King if ((!old_state->visible && state->visible) || 202c96103b6SRussell King drm_to_overlay_state(old_state)->colorkey_vb != val) 203c96103b6SRussell King armada_reg_queue_set(regs, idx, val, LCD_SPU_COLORKEY_V); 204c96103b6SRussell King val = drm_to_overlay_state(state)->colorkey_mode; 205c96103b6SRussell King if ((!old_state->visible && state->visible) || 206c96103b6SRussell King drm_to_overlay_state(old_state)->colorkey_mode != val) 207c96103b6SRussell King armada_reg_queue_mod(regs, idx, val, CFG_CKMODE_MASK | 208c96103b6SRussell King CFG_ALPHAM_MASK | CFG_ALPHA_MASK, 209c96103b6SRussell King LCD_SPU_DMA_CTRL1); 210c96103b6SRussell King val = drm_to_overlay_state(state)->colorkey_enable; 211c96103b6SRussell King if (((!old_state->visible && state->visible) || 212c96103b6SRussell King drm_to_overlay_state(old_state)->colorkey_enable != val) && 213c96103b6SRussell King dcrtc->variant->has_spu_adv_reg) 214c96103b6SRussell King armada_reg_queue_mod(regs, idx, val, ADV_GRACOLORKEY | 215c96103b6SRussell King ADV_VIDCOLORKEY, LCD_SPU_ADV_REG); 21661ba2527SRussell King 2173acea7b9SRussell King dcrtc->regs_idx += idx; 21847dc413bSRussell King } 21947dc413bSRussell King 22047dc413bSRussell King static void armada_drm_overlay_plane_atomic_disable(struct drm_plane *plane, 22147dc413bSRussell King struct drm_plane_state *old_state) 22247dc413bSRussell King { 22347dc413bSRussell King struct armada_crtc *dcrtc; 22447dc413bSRussell King struct armada_regs *regs; 22547dc413bSRussell King unsigned int idx = 0; 22647dc413bSRussell King 22747dc413bSRussell King DRM_DEBUG_KMS("[PLANE:%d:%s]\n", plane->base.id, plane->name); 22847dc413bSRussell King 22947dc413bSRussell King if (!old_state->crtc) 23047dc413bSRussell King return; 23147dc413bSRussell King 23247dc413bSRussell King DRM_DEBUG_KMS("[PLANE:%d:%s] was on [CRTC:%d:%s] with [FB:%d]\n", 23347dc413bSRussell King plane->base.id, plane->name, 23447dc413bSRussell King old_state->crtc->base.id, old_state->crtc->name, 23547dc413bSRussell King old_state->fb->base.id); 23647dc413bSRussell King 23747dc413bSRussell King dcrtc = drm_to_armada_crtc(old_state->crtc); 23847dc413bSRussell King regs = dcrtc->regs + dcrtc->regs_idx; 23947dc413bSRussell King 24047dc413bSRussell King /* Disable plane and power down the YUV FIFOs */ 24147dc413bSRussell King armada_reg_queue_mod(regs, idx, 0, CFG_DMA_ENA, LCD_SPU_DMA_CTRL0); 24247dc413bSRussell King armada_reg_queue_mod(regs, idx, CFG_PDWN16x66 | CFG_PDWN32x66, 0, 24347dc413bSRussell King LCD_SPU_SRAM_PARA1); 24447dc413bSRussell King 24547dc413bSRussell King dcrtc->regs_idx += idx; 24647dc413bSRussell King 24747dc413bSRussell King if (dcrtc->plane == plane) 24847dc413bSRussell King dcrtc->plane = NULL; 24947dc413bSRussell King } 25047dc413bSRussell King 25147dc413bSRussell King static const struct drm_plane_helper_funcs armada_overlay_plane_helper_funcs = { 25247dc413bSRussell King .prepare_fb = armada_drm_plane_prepare_fb, 25347dc413bSRussell King .cleanup_fb = armada_drm_plane_cleanup_fb, 25447dc413bSRussell King .atomic_check = armada_drm_plane_atomic_check, 25547dc413bSRussell King .atomic_update = armada_drm_overlay_plane_atomic_update, 25647dc413bSRussell King .atomic_disable = armada_drm_overlay_plane_atomic_disable, 25747dc413bSRussell King }; 25847dc413bSRussell King 25947dc413bSRussell King static int armada_overlay_commit(struct drm_plane *plane, 26047dc413bSRussell King struct drm_plane_state *state) 26196f60e37SRussell King { 26228a2aebeSRussell King struct armada_ovl_plane *dplane = drm_to_armada_ovl_plane(plane); 26347dc413bSRussell King const struct drm_plane_helper_funcs *plane_funcs; 26447dc413bSRussell King struct armada_crtc *dcrtc = drm_to_armada_crtc(state->crtc); 265d924155dSRussell King struct armada_plane_work *work; 26696f60e37SRussell King int ret; 26796f60e37SRussell King 26847dc413bSRussell King plane_funcs = plane->helper_private; 26947dc413bSRussell King ret = plane_funcs->atomic_check(plane, state); 27098fb74f4SRussell King if (ret) 27147dc413bSRussell King goto put_state; 27298fb74f4SRussell King 27363b93c08SRussell King work = &dplane->works[dplane->next_work]; 27496f60e37SRussell King 27547dc413bSRussell King if (plane->state->fb != state->fb) { 27696f60e37SRussell King /* 27796f60e37SRussell King * Take a reference on the new framebuffer - we want to 27896f60e37SRussell King * hold on to it while the hardware is displaying it. 27996f60e37SRussell King */ 28047dc413bSRussell King drm_framebuffer_reference(state->fb); 28196f60e37SRussell King 28247dc413bSRussell King work->old_fb = plane->state->fb; 283b972a80fSRussell King } else { 284eaa66279SRussell King work->old_fb = NULL; 28596f60e37SRussell King } 28696f60e37SRussell King 28747dc413bSRussell King /* Point of no return */ 28847dc413bSRussell King swap(plane->state, state); 28998fb74f4SRussell King 29061ba2527SRussell King /* No CRTC, can't update */ 29161ba2527SRussell King if (!plane->state->crtc) 29261ba2527SRussell King goto put_state; 29361ba2527SRussell King 29447dc413bSRussell King dcrtc->regs_idx = 0; 29547dc413bSRussell King dcrtc->regs = work->regs; 29647dc413bSRussell King 29747dc413bSRussell King plane_funcs->atomic_update(plane, state); 29847dc413bSRussell King 29947dc413bSRussell King /* If nothing was updated, short-circuit */ 3003acea7b9SRussell King if (dcrtc->regs_idx == 0) 30147dc413bSRussell King goto put_state; 30247dc413bSRussell King 30347dc413bSRussell King armada_reg_queue_end(dcrtc->regs, dcrtc->regs_idx); 304d19f6ee5SRussell King 30507da3c78SRussell King /* Wait for pending work to complete */ 30607da3c78SRussell King if (armada_drm_plane_work_wait(&dplane->base, HZ / 25) == 0) 30707da3c78SRussell King armada_drm_plane_work_cancel(dcrtc, &dplane->base); 30807da3c78SRussell King 309d19f6ee5SRussell King /* Just updating the position/size? */ 3103acea7b9SRussell King if (!dplane->wait_vblank) { 311d19f6ee5SRussell King armada_ovl_plane_work(dcrtc, work); 31247dc413bSRussell King goto put_state; 313d19f6ee5SRussell King } 31496f60e37SRussell King 31596f60e37SRussell King dcrtc->plane = plane; 31696f60e37SRussell King 317eaab0130SRussell King /* Queue it for update on the next interrupt if we are enabled */ 318c93dfdcdSRussell King ret = armada_drm_plane_work_queue(dcrtc, work); 31947dc413bSRussell King if (ret) { 320c93dfdcdSRussell King DRM_ERROR("failed to queue plane work: %d\n", ret); 32147dc413bSRussell King ret = 0; 32247dc413bSRussell King } 32396f60e37SRussell King 32463b93c08SRussell King dplane->next_work = !dplane->next_work; 32596f60e37SRussell King 32647dc413bSRussell King put_state: 32761ba2527SRussell King plane->funcs->atomic_destroy_state(plane, state); 32847dc413bSRussell King return ret; 32947dc413bSRussell King } 33047dc413bSRussell King 33147dc413bSRussell King static int 33247dc413bSRussell King armada_ovl_plane_update(struct drm_plane *plane, struct drm_crtc *crtc, 33347dc413bSRussell King struct drm_framebuffer *fb, 33447dc413bSRussell King int crtc_x, int crtc_y, unsigned crtc_w, unsigned crtc_h, 33547dc413bSRussell King uint32_t src_x, uint32_t src_y, uint32_t src_w, uint32_t src_h, 33647dc413bSRussell King struct drm_modeset_acquire_ctx *ctx) 33747dc413bSRussell King { 33847dc413bSRussell King struct drm_plane_state *state; 33947dc413bSRussell King 34047dc413bSRussell King trace_armada_ovl_plane_update(plane, crtc, fb, 34147dc413bSRussell King crtc_x, crtc_y, crtc_w, crtc_h, 34247dc413bSRussell King src_x, src_y, src_w, src_h); 34347dc413bSRussell King 34447dc413bSRussell King /* Construct new state for the overlay plane */ 34561ba2527SRussell King state = plane->funcs->atomic_duplicate_state(plane); 34647dc413bSRussell King if (!state) 34747dc413bSRussell King return -ENOMEM; 34847dc413bSRussell King 34947dc413bSRussell King state->crtc = crtc; 35047dc413bSRussell King drm_atomic_set_fb_for_plane(state, fb); 35147dc413bSRussell King state->crtc_x = crtc_x; 35247dc413bSRussell King state->crtc_y = crtc_y; 35347dc413bSRussell King state->crtc_h = crtc_h; 35447dc413bSRussell King state->crtc_w = crtc_w; 35547dc413bSRussell King state->src_x = src_x; 35647dc413bSRussell King state->src_y = src_y; 35747dc413bSRussell King state->src_h = src_h; 35847dc413bSRussell King state->src_w = src_w; 35947dc413bSRussell King 36047dc413bSRussell King return armada_overlay_commit(plane, state); 36196f60e37SRussell King } 36296f60e37SRussell King 36328a2aebeSRussell King static void armada_ovl_plane_destroy(struct drm_plane *plane) 36496f60e37SRussell King { 36528a2aebeSRussell King struct armada_ovl_plane *dplane = drm_to_armada_ovl_plane(plane); 36641dbb2dbSRussell King 36741dbb2dbSRussell King drm_plane_cleanup(plane); 36841dbb2dbSRussell King 36941dbb2dbSRussell King kfree(dplane); 37096f60e37SRussell King } 37196f60e37SRussell King 37228a2aebeSRussell King static int armada_ovl_plane_set_property(struct drm_plane *plane, 37396f60e37SRussell King struct drm_property *property, uint64_t val) 37496f60e37SRussell King { 37561ba2527SRussell King struct drm_plane_state *state; 37661ba2527SRussell King int ret; 37761ba2527SRussell King 37861ba2527SRussell King state = plane->funcs->atomic_duplicate_state(plane); 37961ba2527SRussell King if (!state) 38061ba2527SRussell King return -ENOMEM; 38161ba2527SRussell King 382c96103b6SRussell King ret = plane->funcs->atomic_set_property(plane, state, property, val); 38361ba2527SRussell King if (ret) { 38461ba2527SRussell King plane->funcs->atomic_destroy_state(plane, state); 38561ba2527SRussell King return ret; 38661ba2527SRussell King } 38761ba2527SRussell King 38861ba2527SRussell King return armada_overlay_commit(plane, state); 38996f60e37SRussell King } 39096f60e37SRussell King 39161ba2527SRussell King static void armada_overlay_reset(struct drm_plane *plane) 39261ba2527SRussell King { 39361ba2527SRussell King struct armada_overlay_state *state; 39461ba2527SRussell King 39561ba2527SRussell King if (plane->state) 39661ba2527SRussell King __drm_atomic_helper_plane_destroy_state(plane->state); 39761ba2527SRussell King kfree(plane->state); 39861ba2527SRussell King 39961ba2527SRussell King state = kzalloc(sizeof(*state), GFP_KERNEL); 40061ba2527SRussell King if (state) { 40161ba2527SRussell King state->base.plane = plane; 40261ba2527SRussell King state->base.rotation = DRM_MODE_ROTATE_0; 403c96103b6SRussell King state->colorkey_yr = 0xfefefe00; 404c96103b6SRussell King state->colorkey_ug = 0x01010100; 405c96103b6SRussell King state->colorkey_vb = 0x01010100; 406c96103b6SRussell King state->colorkey_mode = CFG_CKMODE(CKMODE_RGB) | 407c96103b6SRussell King CFG_ALPHAM_GRA | CFG_ALPHA(0); 408c96103b6SRussell King state->colorkey_enable = ADV_GRACOLORKEY; 40961ba2527SRussell King state->brightness = DEFAULT_BRIGHTNESS; 41061ba2527SRussell King state->contrast = DEFAULT_CONTRAST; 41161ba2527SRussell King state->saturation = DEFAULT_SATURATION; 41261ba2527SRussell King } 41361ba2527SRussell King plane->state = &state->base; 41461ba2527SRussell King } 41561ba2527SRussell King 41661ba2527SRussell King struct drm_plane_state * 41761ba2527SRussell King armada_overlay_duplicate_state(struct drm_plane *plane) 41861ba2527SRussell King { 41961ba2527SRussell King struct armada_overlay_state *state; 42061ba2527SRussell King 42161ba2527SRussell King if (WARN_ON(!plane->state)) 42261ba2527SRussell King return NULL; 42361ba2527SRussell King 42461ba2527SRussell King state = kmemdup(plane->state, sizeof(*state), GFP_KERNEL); 42561ba2527SRussell King if (state) 42661ba2527SRussell King __drm_atomic_helper_plane_duplicate_state(plane, &state->base); 42761ba2527SRussell King return &state->base; 42861ba2527SRussell King } 42961ba2527SRussell King 43061ba2527SRussell King static int armada_overlay_set_property(struct drm_plane *plane, 43161ba2527SRussell King struct drm_plane_state *state, struct drm_property *property, 43261ba2527SRussell King uint64_t val) 43361ba2527SRussell King { 43461ba2527SRussell King struct armada_private *priv = plane->dev->dev_private; 43561ba2527SRussell King 436c96103b6SRussell King #define K2R(val) (((val) >> 0) & 0xff) 437c96103b6SRussell King #define K2G(val) (((val) >> 8) & 0xff) 438c96103b6SRussell King #define K2B(val) (((val) >> 16) & 0xff) 439c96103b6SRussell King if (property == priv->colorkey_prop) { 440c96103b6SRussell King #define CCC(v) ((v) << 24 | (v) << 16 | (v) << 8) 441c96103b6SRussell King drm_to_overlay_state(state)->colorkey_yr = CCC(K2R(val)); 442c96103b6SRussell King drm_to_overlay_state(state)->colorkey_ug = CCC(K2G(val)); 443c96103b6SRussell King drm_to_overlay_state(state)->colorkey_vb = CCC(K2B(val)); 444c96103b6SRussell King #undef CCC 445c96103b6SRussell King } else if (property == priv->colorkey_min_prop) { 446c96103b6SRussell King drm_to_overlay_state(state)->colorkey_yr &= ~0x00ff0000; 447c96103b6SRussell King drm_to_overlay_state(state)->colorkey_yr |= K2R(val) << 16; 448c96103b6SRussell King drm_to_overlay_state(state)->colorkey_ug &= ~0x00ff0000; 449c96103b6SRussell King drm_to_overlay_state(state)->colorkey_ug |= K2G(val) << 16; 450c96103b6SRussell King drm_to_overlay_state(state)->colorkey_vb &= ~0x00ff0000; 451c96103b6SRussell King drm_to_overlay_state(state)->colorkey_vb |= K2B(val) << 16; 452c96103b6SRussell King } else if (property == priv->colorkey_max_prop) { 453c96103b6SRussell King drm_to_overlay_state(state)->colorkey_yr &= ~0xff000000; 454c96103b6SRussell King drm_to_overlay_state(state)->colorkey_yr |= K2R(val) << 24; 455c96103b6SRussell King drm_to_overlay_state(state)->colorkey_ug &= ~0xff000000; 456c96103b6SRussell King drm_to_overlay_state(state)->colorkey_ug |= K2G(val) << 24; 457c96103b6SRussell King drm_to_overlay_state(state)->colorkey_vb &= ~0xff000000; 458c96103b6SRussell King drm_to_overlay_state(state)->colorkey_vb |= K2B(val) << 24; 459c96103b6SRussell King } else if (property == priv->colorkey_val_prop) { 460c96103b6SRussell King drm_to_overlay_state(state)->colorkey_yr &= ~0x0000ff00; 461c96103b6SRussell King drm_to_overlay_state(state)->colorkey_yr |= K2R(val) << 8; 462c96103b6SRussell King drm_to_overlay_state(state)->colorkey_ug &= ~0x0000ff00; 463c96103b6SRussell King drm_to_overlay_state(state)->colorkey_ug |= K2G(val) << 8; 464c96103b6SRussell King drm_to_overlay_state(state)->colorkey_vb &= ~0x0000ff00; 465c96103b6SRussell King drm_to_overlay_state(state)->colorkey_vb |= K2B(val) << 8; 466c96103b6SRussell King } else if (property == priv->colorkey_alpha_prop) { 467c96103b6SRussell King drm_to_overlay_state(state)->colorkey_yr &= ~0x000000ff; 468c96103b6SRussell King drm_to_overlay_state(state)->colorkey_yr |= K2R(val); 469c96103b6SRussell King drm_to_overlay_state(state)->colorkey_ug &= ~0x000000ff; 470c96103b6SRussell King drm_to_overlay_state(state)->colorkey_ug |= K2G(val); 471c96103b6SRussell King drm_to_overlay_state(state)->colorkey_vb &= ~0x000000ff; 472c96103b6SRussell King drm_to_overlay_state(state)->colorkey_vb |= K2B(val); 473c96103b6SRussell King } else if (property == priv->colorkey_mode_prop) { 474c96103b6SRussell King if (val == CKMODE_DISABLE) { 475c96103b6SRussell King drm_to_overlay_state(state)->colorkey_mode = 476c96103b6SRussell King CFG_CKMODE(CKMODE_DISABLE) | 477c96103b6SRussell King CFG_ALPHAM_CFG | CFG_ALPHA(255); 478c96103b6SRussell King drm_to_overlay_state(state)->colorkey_enable = 0; 479c96103b6SRussell King } else { 480c96103b6SRussell King drm_to_overlay_state(state)->colorkey_mode = 481c96103b6SRussell King CFG_CKMODE(val) | 482c96103b6SRussell King CFG_ALPHAM_GRA | CFG_ALPHA(0); 483c96103b6SRussell King drm_to_overlay_state(state)->colorkey_enable = 484c96103b6SRussell King ADV_GRACOLORKEY; 485c96103b6SRussell King } 486c96103b6SRussell King } else if (property == priv->brightness_prop) { 48761ba2527SRussell King drm_to_overlay_state(state)->brightness = val - 256; 48861ba2527SRussell King } else if (property == priv->contrast_prop) { 48961ba2527SRussell King drm_to_overlay_state(state)->contrast = val; 49061ba2527SRussell King } else if (property == priv->saturation_prop) { 49161ba2527SRussell King drm_to_overlay_state(state)->saturation = val; 49261ba2527SRussell King } else { 49361ba2527SRussell King return -EINVAL; 49461ba2527SRussell King } 49561ba2527SRussell King return 0; 49661ba2527SRussell King } 49761ba2527SRussell King 49861ba2527SRussell King static int armada_overlay_get_property(struct drm_plane *plane, 49961ba2527SRussell King const struct drm_plane_state *state, struct drm_property *property, 50061ba2527SRussell King uint64_t *val) 50161ba2527SRussell King { 50261ba2527SRussell King struct armada_private *priv = plane->dev->dev_private; 50361ba2527SRussell King 504c96103b6SRussell King #define C2K(c,s) (((c) >> (s)) & 0xff) 505c96103b6SRussell King #define R2BGR(r,g,b,s) (C2K(r,s) << 0 | C2K(g,s) << 8 | C2K(b,s) << 16) 506c96103b6SRussell King if (property == priv->colorkey_prop) { 507c96103b6SRussell King /* Do best-efforts here for this property */ 508c96103b6SRussell King *val = R2BGR(drm_to_overlay_state(state)->colorkey_yr, 509c96103b6SRussell King drm_to_overlay_state(state)->colorkey_ug, 510c96103b6SRussell King drm_to_overlay_state(state)->colorkey_vb, 16); 511c96103b6SRussell King /* If min != max, or min != val, error out */ 512c96103b6SRussell King if (*val != R2BGR(drm_to_overlay_state(state)->colorkey_yr, 513c96103b6SRussell King drm_to_overlay_state(state)->colorkey_ug, 514c96103b6SRussell King drm_to_overlay_state(state)->colorkey_vb, 24) || 515c96103b6SRussell King *val != R2BGR(drm_to_overlay_state(state)->colorkey_yr, 516c96103b6SRussell King drm_to_overlay_state(state)->colorkey_ug, 517c96103b6SRussell King drm_to_overlay_state(state)->colorkey_vb, 8)) 518c96103b6SRussell King return -EINVAL; 519c96103b6SRussell King } else if (property == priv->colorkey_min_prop) { 520c96103b6SRussell King *val = R2BGR(drm_to_overlay_state(state)->colorkey_yr, 521c96103b6SRussell King drm_to_overlay_state(state)->colorkey_ug, 522c96103b6SRussell King drm_to_overlay_state(state)->colorkey_vb, 16); 523c96103b6SRussell King } else if (property == priv->colorkey_max_prop) { 524c96103b6SRussell King *val = R2BGR(drm_to_overlay_state(state)->colorkey_yr, 525c96103b6SRussell King drm_to_overlay_state(state)->colorkey_ug, 526c96103b6SRussell King drm_to_overlay_state(state)->colorkey_vb, 24); 527c96103b6SRussell King } else if (property == priv->colorkey_val_prop) { 528c96103b6SRussell King *val = R2BGR(drm_to_overlay_state(state)->colorkey_yr, 529c96103b6SRussell King drm_to_overlay_state(state)->colorkey_ug, 530c96103b6SRussell King drm_to_overlay_state(state)->colorkey_vb, 8); 531c96103b6SRussell King } else if (property == priv->colorkey_alpha_prop) { 532c96103b6SRussell King *val = R2BGR(drm_to_overlay_state(state)->colorkey_yr, 533c96103b6SRussell King drm_to_overlay_state(state)->colorkey_ug, 534c96103b6SRussell King drm_to_overlay_state(state)->colorkey_vb, 0); 535c96103b6SRussell King } else if (property == priv->colorkey_mode_prop) { 536c96103b6SRussell King *val = (drm_to_overlay_state(state)->colorkey_mode & 537c96103b6SRussell King CFG_CKMODE_MASK) >> ffs(CFG_CKMODE_MASK); 538c96103b6SRussell King } else if (property == priv->brightness_prop) { 53961ba2527SRussell King *val = drm_to_overlay_state(state)->brightness + 256; 54061ba2527SRussell King } else if (property == priv->contrast_prop) { 54161ba2527SRussell King *val = drm_to_overlay_state(state)->contrast; 54261ba2527SRussell King } else if (property == priv->saturation_prop) { 54361ba2527SRussell King *val = drm_to_overlay_state(state)->saturation; 54461ba2527SRussell King } else { 54561ba2527SRussell King return -EINVAL; 54661ba2527SRussell King } 54761ba2527SRussell King return 0; 54861ba2527SRussell King } 54961ba2527SRussell King 55028a2aebeSRussell King static const struct drm_plane_funcs armada_ovl_plane_funcs = { 55128a2aebeSRussell King .update_plane = armada_ovl_plane_update, 55247dc413bSRussell King .disable_plane = drm_plane_helper_disable, 55328a2aebeSRussell King .destroy = armada_ovl_plane_destroy, 55428a2aebeSRussell King .set_property = armada_ovl_plane_set_property, 55561ba2527SRussell King .reset = armada_overlay_reset, 55661ba2527SRussell King .atomic_duplicate_state = armada_overlay_duplicate_state, 55761ba2527SRussell King .atomic_destroy_state = drm_atomic_helper_plane_destroy_state, 55861ba2527SRussell King .atomic_set_property = armada_overlay_set_property, 55961ba2527SRussell King .atomic_get_property = armada_overlay_get_property, 56096f60e37SRussell King }; 56196f60e37SRussell King 56228a2aebeSRussell King static const uint32_t armada_ovl_formats[] = { 56396f60e37SRussell King DRM_FORMAT_UYVY, 56496f60e37SRussell King DRM_FORMAT_YUYV, 56596f60e37SRussell King DRM_FORMAT_YUV420, 56696f60e37SRussell King DRM_FORMAT_YVU420, 56796f60e37SRussell King DRM_FORMAT_YUV422, 56896f60e37SRussell King DRM_FORMAT_YVU422, 56996f60e37SRussell King DRM_FORMAT_VYUY, 57096f60e37SRussell King DRM_FORMAT_YVYU, 57196f60e37SRussell King DRM_FORMAT_ARGB8888, 57296f60e37SRussell King DRM_FORMAT_ABGR8888, 57396f60e37SRussell King DRM_FORMAT_XRGB8888, 57496f60e37SRussell King DRM_FORMAT_XBGR8888, 57596f60e37SRussell King DRM_FORMAT_RGB888, 57696f60e37SRussell King DRM_FORMAT_BGR888, 57796f60e37SRussell King DRM_FORMAT_ARGB1555, 57896f60e37SRussell King DRM_FORMAT_ABGR1555, 57996f60e37SRussell King DRM_FORMAT_RGB565, 58096f60e37SRussell King DRM_FORMAT_BGR565, 58196f60e37SRussell King }; 58296f60e37SRussell King 5838a63ca58SArvind Yadav static const struct drm_prop_enum_list armada_drm_colorkey_enum_list[] = { 58496f60e37SRussell King { CKMODE_DISABLE, "disabled" }, 58596f60e37SRussell King { CKMODE_Y, "Y component" }, 58696f60e37SRussell King { CKMODE_U, "U component" }, 58796f60e37SRussell King { CKMODE_V, "V component" }, 58896f60e37SRussell King { CKMODE_RGB, "RGB" }, 58996f60e37SRussell King { CKMODE_R, "R component" }, 59096f60e37SRussell King { CKMODE_G, "G component" }, 59196f60e37SRussell King { CKMODE_B, "B component" }, 59296f60e37SRussell King }; 59396f60e37SRussell King 59496f60e37SRussell King static int armada_overlay_create_properties(struct drm_device *dev) 59596f60e37SRussell King { 59696f60e37SRussell King struct armada_private *priv = dev->dev_private; 59796f60e37SRussell King 59896f60e37SRussell King if (priv->colorkey_prop) 59996f60e37SRussell King return 0; 60096f60e37SRussell King 60196f60e37SRussell King priv->colorkey_prop = drm_property_create_range(dev, 0, 60296f60e37SRussell King "colorkey", 0, 0xffffff); 60396f60e37SRussell King priv->colorkey_min_prop = drm_property_create_range(dev, 0, 60496f60e37SRussell King "colorkey_min", 0, 0xffffff); 60596f60e37SRussell King priv->colorkey_max_prop = drm_property_create_range(dev, 0, 60696f60e37SRussell King "colorkey_max", 0, 0xffffff); 60796f60e37SRussell King priv->colorkey_val_prop = drm_property_create_range(dev, 0, 60896f60e37SRussell King "colorkey_val", 0, 0xffffff); 60996f60e37SRussell King priv->colorkey_alpha_prop = drm_property_create_range(dev, 0, 61096f60e37SRussell King "colorkey_alpha", 0, 0xffffff); 61196f60e37SRussell King priv->colorkey_mode_prop = drm_property_create_enum(dev, 0, 61296f60e37SRussell King "colorkey_mode", 61396f60e37SRussell King armada_drm_colorkey_enum_list, 61496f60e37SRussell King ARRAY_SIZE(armada_drm_colorkey_enum_list)); 61596f60e37SRussell King priv->brightness_prop = drm_property_create_range(dev, 0, 61696f60e37SRussell King "brightness", 0, 256 + 255); 61796f60e37SRussell King priv->contrast_prop = drm_property_create_range(dev, 0, 61896f60e37SRussell King "contrast", 0, 0x7fff); 61996f60e37SRussell King priv->saturation_prop = drm_property_create_range(dev, 0, 62096f60e37SRussell King "saturation", 0, 0x7fff); 62196f60e37SRussell King 62296f60e37SRussell King if (!priv->colorkey_prop) 62396f60e37SRussell King return -ENOMEM; 62496f60e37SRussell King 62596f60e37SRussell King return 0; 62696f60e37SRussell King } 62796f60e37SRussell King 62896f60e37SRussell King int armada_overlay_plane_create(struct drm_device *dev, unsigned long crtcs) 62996f60e37SRussell King { 63096f60e37SRussell King struct armada_private *priv = dev->dev_private; 63196f60e37SRussell King struct drm_mode_object *mobj; 63228a2aebeSRussell King struct armada_ovl_plane *dplane; 63396f60e37SRussell King int ret; 63496f60e37SRussell King 63596f60e37SRussell King ret = armada_overlay_create_properties(dev); 63696f60e37SRussell King if (ret) 63796f60e37SRussell King return ret; 63896f60e37SRussell King 63996f60e37SRussell King dplane = kzalloc(sizeof(*dplane), GFP_KERNEL); 64096f60e37SRussell King if (!dplane) 64196f60e37SRussell King return -ENOMEM; 64296f60e37SRussell King 6435740d27fSRussell King ret = armada_drm_plane_init(&dplane->base); 6445740d27fSRussell King if (ret) { 6455740d27fSRussell King kfree(dplane); 6465740d27fSRussell King return ret; 6475740d27fSRussell King } 6485740d27fSRussell King 64963b93c08SRussell King dplane->works[0].plane = &dplane->base.base; 65063b93c08SRussell King dplane->works[0].fn = armada_ovl_plane_work; 65163b93c08SRussell King dplane->works[1].plane = &dplane->base.base; 65263b93c08SRussell King dplane->works[1].fn = armada_ovl_plane_work; 65396f60e37SRussell King 65447dc413bSRussell King drm_plane_helper_add(&dplane->base.base, 65547dc413bSRussell King &armada_overlay_plane_helper_funcs); 65647dc413bSRussell King 657561f60bcSRussell King ret = drm_universal_plane_init(dev, &dplane->base.base, crtcs, 658d563c245SRussell King &armada_ovl_plane_funcs, 659d563c245SRussell King armada_ovl_formats, 660d563c245SRussell King ARRAY_SIZE(armada_ovl_formats), 661e6fc3b68SBen Widawsky NULL, 662b0b3b795SVille Syrjälä DRM_PLANE_TYPE_OVERLAY, NULL); 66328a2aebeSRussell King if (ret) { 66428a2aebeSRussell King kfree(dplane); 66528a2aebeSRussell King return ret; 66628a2aebeSRussell King } 66796f60e37SRussell King 668561f60bcSRussell King mobj = &dplane->base.base.base; 66996f60e37SRussell King drm_object_attach_property(mobj, priv->colorkey_prop, 67096f60e37SRussell King 0x0101fe); 67196f60e37SRussell King drm_object_attach_property(mobj, priv->colorkey_min_prop, 67296f60e37SRussell King 0x0101fe); 67396f60e37SRussell King drm_object_attach_property(mobj, priv->colorkey_max_prop, 67496f60e37SRussell King 0x0101fe); 67596f60e37SRussell King drm_object_attach_property(mobj, priv->colorkey_val_prop, 67696f60e37SRussell King 0x0101fe); 67796f60e37SRussell King drm_object_attach_property(mobj, priv->colorkey_alpha_prop, 67896f60e37SRussell King 0x000000); 67996f60e37SRussell King drm_object_attach_property(mobj, priv->colorkey_mode_prop, 68096f60e37SRussell King CKMODE_RGB); 68161ba2527SRussell King drm_object_attach_property(mobj, priv->brightness_prop, 68261ba2527SRussell King 256 + DEFAULT_BRIGHTNESS); 68396f60e37SRussell King drm_object_attach_property(mobj, priv->contrast_prop, 68461ba2527SRussell King DEFAULT_CONTRAST); 68596f60e37SRussell King drm_object_attach_property(mobj, priv->saturation_prop, 68661ba2527SRussell King DEFAULT_SATURATION); 68796f60e37SRussell King 68896f60e37SRussell King return 0; 68996f60e37SRussell King } 690