1e3adcf8fSFrançois Tigeot /* 2e3adcf8fSFrançois Tigeot * Copyright © 2011 Intel Corporation 3e3adcf8fSFrançois Tigeot * 4e3adcf8fSFrançois Tigeot * Permission is hereby granted, free of charge, to any person obtaining a 5e3adcf8fSFrançois Tigeot * copy of this software and associated documentation files (the "Software"), 6e3adcf8fSFrançois Tigeot * to deal in the Software without restriction, including without limitation 7e3adcf8fSFrançois Tigeot * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8e3adcf8fSFrançois Tigeot * and/or sell copies of the Software, and to permit persons to whom the 9e3adcf8fSFrançois Tigeot * Software is furnished to do so, subject to the following conditions: 10e3adcf8fSFrançois Tigeot * 11e3adcf8fSFrançois Tigeot * The above copyright notice and this permission notice (including the next 12e3adcf8fSFrançois Tigeot * paragraph) shall be included in all copies or substantial portions of the 13e3adcf8fSFrançois Tigeot * Software. 14e3adcf8fSFrançois Tigeot * 15e3adcf8fSFrançois Tigeot * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16e3adcf8fSFrançois Tigeot * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17e3adcf8fSFrançois Tigeot * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18e3adcf8fSFrançois Tigeot * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19e3adcf8fSFrançois Tigeot * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20e3adcf8fSFrançois Tigeot * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21e3adcf8fSFrançois Tigeot * SOFTWARE. 22e3adcf8fSFrançois Tigeot * 23e3adcf8fSFrançois Tigeot * Authors: 24e3adcf8fSFrançois Tigeot * Jesse Barnes <jbarnes@virtuousgeek.org> 25e3adcf8fSFrançois Tigeot * 26e3adcf8fSFrançois Tigeot * New plane/sprite handling. 27e3adcf8fSFrançois Tigeot * 28e3adcf8fSFrançois Tigeot * The older chips had a separate interface for programming plane related 29e3adcf8fSFrançois Tigeot * registers; newer ones are much simpler and we can use the new DRM plane 30e3adcf8fSFrançois Tigeot * support. 31e3adcf8fSFrançois Tigeot */ 3218e26a6dSFrançois Tigeot #include <drm/drmP.h> 3318e26a6dSFrançois Tigeot #include <drm/drm_crtc.h> 3483b4b9b9SFrançois Tigeot #include <drm/drm_fourcc.h> 355d0b1887SFrançois Tigeot #include <drm/drm_rect.h> 3619c468b4SFrançois Tigeot #include <drm/drm_atomic.h> 372c9916cdSFrançois Tigeot #include <drm/drm_plane_helper.h> 3818e26a6dSFrançois Tigeot #include "intel_drv.h" 395c6c6f23SFrançois Tigeot #include <drm/i915_drm.h> 40e3adcf8fSFrançois Tigeot #include "i915_drv.h" 41e3adcf8fSFrançois Tigeot 422c9916cdSFrançois Tigeot static bool 432c9916cdSFrançois Tigeot format_is_yuv(uint32_t format) 442c9916cdSFrançois Tigeot { 452c9916cdSFrançois Tigeot switch (format) { 462c9916cdSFrançois Tigeot case DRM_FORMAT_YUYV: 472c9916cdSFrançois Tigeot case DRM_FORMAT_UYVY: 482c9916cdSFrançois Tigeot case DRM_FORMAT_VYUY: 492c9916cdSFrançois Tigeot case DRM_FORMAT_YVYU: 502c9916cdSFrançois Tigeot return true; 512c9916cdSFrançois Tigeot default: 522c9916cdSFrançois Tigeot return false; 532c9916cdSFrançois Tigeot } 542c9916cdSFrançois Tigeot } 552c9916cdSFrançois Tigeot 56*87df8fc6SFrançois Tigeot static int usecs_to_scanlines(const struct drm_display_mode *adjusted_mode, 57352ff8bdSFrançois Tigeot int usecs) 58ba55f2f5SFrançois Tigeot { 59ba55f2f5SFrançois Tigeot /* paranoia */ 60352ff8bdSFrançois Tigeot if (!adjusted_mode->crtc_htotal) 61ba55f2f5SFrançois Tigeot return 1; 62ba55f2f5SFrançois Tigeot 63352ff8bdSFrançois Tigeot return DIV_ROUND_UP(usecs * adjusted_mode->crtc_clock, 64352ff8bdSFrançois Tigeot 1000 * adjusted_mode->crtc_htotal); 65ba55f2f5SFrançois Tigeot } 66ba55f2f5SFrançois Tigeot 672c9916cdSFrançois Tigeot /** 682c9916cdSFrançois Tigeot * intel_pipe_update_start() - start update of a set of display registers 692c9916cdSFrançois Tigeot * @crtc: the crtc of which the registers are going to be updated 702c9916cdSFrançois Tigeot * @start_vbl_count: vblank counter return pointer used for error checking 712c9916cdSFrançois Tigeot * 722c9916cdSFrançois Tigeot * Mark the start of an update to pipe registers that should be updated 732c9916cdSFrançois Tigeot * atomically regarding vblank. If the next vblank will happens within 742c9916cdSFrançois Tigeot * the next 100 us, this function waits until the vblank passes. 752c9916cdSFrançois Tigeot * 762c9916cdSFrançois Tigeot * After a successful call to this function, interrupts will be disabled 772c9916cdSFrançois Tigeot * until a subsequent call to intel_pipe_update_end(). That is done to 782c9916cdSFrançois Tigeot * avoid random delays. The value written to @start_vbl_count should be 792c9916cdSFrançois Tigeot * supplied to intel_pipe_update_end() for error checking. 802c9916cdSFrançois Tigeot */ 81352ff8bdSFrançois Tigeot void intel_pipe_update_start(struct intel_crtc *crtc) 82ba55f2f5SFrançois Tigeot { 83352ff8bdSFrançois Tigeot const struct drm_display_mode *adjusted_mode = &crtc->config->base.adjusted_mode; 84ba55f2f5SFrançois Tigeot long timeout = msecs_to_jiffies_timeout(1); 85ba55f2f5SFrançois Tigeot int scanline, min, max, vblank_start; 861b13d190SFrançois Tigeot wait_queue_head_t *wq = drm_crtc_vblank_waitqueue(&crtc->base); 87ba55f2f5SFrançois Tigeot DEFINE_WAIT(wait); 88ba55f2f5SFrançois Tigeot 89352ff8bdSFrançois Tigeot vblank_start = adjusted_mode->crtc_vblank_start; 90352ff8bdSFrançois Tigeot if (adjusted_mode->flags & DRM_MODE_FLAG_INTERLACE) 91ba55f2f5SFrançois Tigeot vblank_start = DIV_ROUND_UP(vblank_start, 2); 92ba55f2f5SFrançois Tigeot 93ba55f2f5SFrançois Tigeot /* FIXME needs to be calibrated sensibly */ 94*87df8fc6SFrançois Tigeot min = vblank_start - usecs_to_scanlines(adjusted_mode, 100); 95ba55f2f5SFrançois Tigeot max = vblank_start - 1; 96ba55f2f5SFrançois Tigeot 97a05eeebfSFrançois Tigeot local_irq_disable(); 98a05eeebfSFrançois Tigeot 99ba55f2f5SFrançois Tigeot if (min <= 0 || max <= 0) 100a05eeebfSFrançois Tigeot return; 101ba55f2f5SFrançois Tigeot 102477eb7f9SFrançois Tigeot if (WARN_ON(drm_crtc_vblank_get(&crtc->base))) 103a05eeebfSFrançois Tigeot return; 104ba55f2f5SFrançois Tigeot 105352ff8bdSFrançois Tigeot crtc->debug.min_vbl = min; 106352ff8bdSFrançois Tigeot crtc->debug.max_vbl = max; 107352ff8bdSFrançois Tigeot trace_i915_pipe_update_start(crtc); 108ba55f2f5SFrançois Tigeot 109ba55f2f5SFrançois Tigeot for (;;) { 110ba55f2f5SFrançois Tigeot /* 111ba55f2f5SFrançois Tigeot * prepare_to_wait() has a memory barrier, which guarantees 112ba55f2f5SFrançois Tigeot * other CPUs can see the task state update by the time we 113ba55f2f5SFrançois Tigeot * read the scanline. 114ba55f2f5SFrançois Tigeot */ 1151b13d190SFrançois Tigeot prepare_to_wait(wq, &wait, TASK_UNINTERRUPTIBLE); 116ba55f2f5SFrançois Tigeot 117ba55f2f5SFrançois Tigeot scanline = intel_get_crtc_scanline(crtc); 118ba55f2f5SFrançois Tigeot if (scanline < min || scanline > max) 119ba55f2f5SFrançois Tigeot break; 120ba55f2f5SFrançois Tigeot 121ba55f2f5SFrançois Tigeot if (timeout <= 0) { 122ba55f2f5SFrançois Tigeot DRM_ERROR("Potential atomic update failure on pipe %c\n", 123ba55f2f5SFrançois Tigeot pipe_name(crtc->pipe)); 124ba55f2f5SFrançois Tigeot break; 125ba55f2f5SFrançois Tigeot } 126ba55f2f5SFrançois Tigeot 127ba55f2f5SFrançois Tigeot local_irq_enable(); 128ba55f2f5SFrançois Tigeot 129ba55f2f5SFrançois Tigeot timeout = schedule_timeout(timeout); 130ba55f2f5SFrançois Tigeot 131ba55f2f5SFrançois Tigeot local_irq_disable(); 132ba55f2f5SFrançois Tigeot } 133ba55f2f5SFrançois Tigeot 1341b13d190SFrançois Tigeot finish_wait(wq, &wait); 135ba55f2f5SFrançois Tigeot 136477eb7f9SFrançois Tigeot drm_crtc_vblank_put(&crtc->base); 137ba55f2f5SFrançois Tigeot 138352ff8bdSFrançois Tigeot crtc->debug.scanline_start = scanline; 139352ff8bdSFrançois Tigeot crtc->debug.start_vbl_time = ktime_get(); 1401487f786SFrançois Tigeot crtc->debug.start_vbl_count = intel_crtc_get_vblank_counter(crtc); 141ba55f2f5SFrançois Tigeot 142352ff8bdSFrançois Tigeot trace_i915_pipe_update_vblank_evaded(crtc); 143ba55f2f5SFrançois Tigeot } 144ba55f2f5SFrançois Tigeot 1452c9916cdSFrançois Tigeot /** 1462c9916cdSFrançois Tigeot * intel_pipe_update_end() - end update of a set of display registers 1472c9916cdSFrançois Tigeot * @crtc: the crtc of which the registers were updated 1482c9916cdSFrançois Tigeot * @start_vbl_count: start vblank counter (used for error checking) 1492c9916cdSFrançois Tigeot * 1502c9916cdSFrançois Tigeot * Mark the end of an update started with intel_pipe_update_start(). This 1512c9916cdSFrançois Tigeot * re-enables interrupts and verifies the update was actually completed 1522c9916cdSFrançois Tigeot * before a vblank using the value of @start_vbl_count. 1532c9916cdSFrançois Tigeot */ 1541487f786SFrançois Tigeot void intel_pipe_update_end(struct intel_crtc *crtc, struct intel_flip_work *work) 155ba55f2f5SFrançois Tigeot { 156ba55f2f5SFrançois Tigeot enum i915_pipe pipe = crtc->pipe; 157352ff8bdSFrançois Tigeot int scanline_end = intel_get_crtc_scanline(crtc); 1581487f786SFrançois Tigeot u32 end_vbl_count = intel_crtc_get_vblank_counter(crtc); 159352ff8bdSFrançois Tigeot ktime_t end_vbl_time = ktime_get(); 160ba55f2f5SFrançois Tigeot 1611487f786SFrançois Tigeot if (work) { 1621487f786SFrançois Tigeot work->flip_queued_vblank = end_vbl_count; 1631487f786SFrançois Tigeot smp_mb__before_atomic(); 1641487f786SFrançois Tigeot atomic_set(&work->pending, 1); 1651487f786SFrançois Tigeot } 1661487f786SFrançois Tigeot 167352ff8bdSFrançois Tigeot trace_i915_pipe_update_end(crtc, end_vbl_count, scanline_end); 168ba55f2f5SFrançois Tigeot 1691487f786SFrançois Tigeot /* We're still in the vblank-evade critical section, this can't race. 1701487f786SFrançois Tigeot * Would be slightly nice to just grab the vblank count and arm the 1711487f786SFrançois Tigeot * event outside of the critical section - the spinlock might spin for a 1721487f786SFrançois Tigeot * while ... */ 1731487f786SFrançois Tigeot if (crtc->base.state->event) { 1741487f786SFrançois Tigeot WARN_ON(drm_crtc_vblank_get(&crtc->base) != 0); 1751487f786SFrançois Tigeot 1761487f786SFrançois Tigeot lockmgr(&crtc->base.dev->event_lock, LK_EXCLUSIVE); 1771487f786SFrançois Tigeot drm_crtc_arm_vblank_event(&crtc->base, crtc->base.state->event); 1781487f786SFrançois Tigeot lockmgr(&crtc->base.dev->event_lock, LK_RELEASE); 1791487f786SFrançois Tigeot 1801487f786SFrançois Tigeot crtc->base.state->event = NULL; 1811487f786SFrançois Tigeot } 1821487f786SFrançois Tigeot 183ba55f2f5SFrançois Tigeot local_irq_enable(); 184ba55f2f5SFrançois Tigeot 185352ff8bdSFrançois Tigeot if (crtc->debug.start_vbl_count && 186352ff8bdSFrançois Tigeot crtc->debug.start_vbl_count != end_vbl_count) { 187352ff8bdSFrançois Tigeot DRM_ERROR("Atomic update failure on pipe %c (start=%u end=%u) time %lld us, min %d, max %d, scanline start %d, end %d\n", 188352ff8bdSFrançois Tigeot pipe_name(pipe), crtc->debug.start_vbl_count, 189352ff8bdSFrançois Tigeot end_vbl_count, 190352ff8bdSFrançois Tigeot ktime_us_delta(end_vbl_time, crtc->debug.start_vbl_time), 191352ff8bdSFrançois Tigeot crtc->debug.min_vbl, crtc->debug.max_vbl, 192352ff8bdSFrançois Tigeot crtc->debug.scanline_start, scanline_end); 193352ff8bdSFrançois Tigeot } 194ba55f2f5SFrançois Tigeot } 195ba55f2f5SFrançois Tigeot 196e3adcf8fSFrançois Tigeot static void 197c0e85e96SFrançois Tigeot skl_update_plane(struct drm_plane *drm_plane, 198c0e85e96SFrançois Tigeot const struct intel_crtc_state *crtc_state, 199c0e85e96SFrançois Tigeot const struct intel_plane_state *plane_state) 2002c9916cdSFrançois Tigeot { 2012c9916cdSFrançois Tigeot struct drm_device *dev = drm_plane->dev; 202bf017597SFrançois Tigeot struct drm_i915_private *dev_priv = to_i915(dev); 2032c9916cdSFrançois Tigeot struct intel_plane *intel_plane = to_intel_plane(drm_plane); 204c0e85e96SFrançois Tigeot struct drm_framebuffer *fb = plane_state->base.fb; 205477eb7f9SFrançois Tigeot struct drm_i915_gem_object *obj = intel_fb_obj(fb); 2062c9916cdSFrançois Tigeot const int pipe = intel_plane->pipe; 2072c9916cdSFrançois Tigeot const int plane = intel_plane->plane + 1; 20819c468b4SFrançois Tigeot u32 plane_ctl, stride_div, stride; 209c0e85e96SFrançois Tigeot const struct drm_intel_sprite_colorkey *key = &plane_state->ckey; 210aee94f86SFrançois Tigeot u32 surf_addr; 21119c468b4SFrançois Tigeot u32 tile_height, plane_offset, plane_size; 2128621f407SFrançois Tigeot unsigned int rotation = plane_state->base.rotation; 21319c468b4SFrançois Tigeot int x_offset, y_offset; 214c0e85e96SFrançois Tigeot int crtc_x = plane_state->dst.x1; 215c0e85e96SFrançois Tigeot int crtc_y = plane_state->dst.y1; 216c0e85e96SFrançois Tigeot uint32_t crtc_w = drm_rect_width(&plane_state->dst); 217c0e85e96SFrançois Tigeot uint32_t crtc_h = drm_rect_height(&plane_state->dst); 218c0e85e96SFrançois Tigeot uint32_t x = plane_state->src.x1 >> 16; 219c0e85e96SFrançois Tigeot uint32_t y = plane_state->src.y1 >> 16; 220c0e85e96SFrançois Tigeot uint32_t src_w = drm_rect_width(&plane_state->src) >> 16; 221c0e85e96SFrançois Tigeot uint32_t src_h = drm_rect_height(&plane_state->src) >> 16; 2222c9916cdSFrançois Tigeot 223477eb7f9SFrançois Tigeot plane_ctl = PLANE_CTL_ENABLE | 224352ff8bdSFrançois Tigeot PLANE_CTL_PIPE_GAMMA_ENABLE | 225477eb7f9SFrançois Tigeot PLANE_CTL_PIPE_CSC_ENABLE; 2262c9916cdSFrançois Tigeot 22719c468b4SFrançois Tigeot plane_ctl |= skl_plane_ctl_format(fb->pixel_format); 22819c468b4SFrançois Tigeot plane_ctl |= skl_plane_ctl_tiling(fb->modifier[0]); 2292c9916cdSFrançois Tigeot 23019c468b4SFrançois Tigeot plane_ctl |= skl_plane_ctl_rotation(rotation); 2312c9916cdSFrançois Tigeot 232c0e85e96SFrançois Tigeot stride_div = intel_fb_stride_alignment(dev_priv, fb->modifier[0], 233477eb7f9SFrançois Tigeot fb->pixel_format); 234477eb7f9SFrançois Tigeot 2352c9916cdSFrançois Tigeot /* Sizes are 0 based */ 2362c9916cdSFrançois Tigeot src_w--; 2372c9916cdSFrançois Tigeot src_h--; 2382c9916cdSFrançois Tigeot crtc_w--; 2392c9916cdSFrançois Tigeot crtc_h--; 2402c9916cdSFrançois Tigeot 241477eb7f9SFrançois Tigeot if (key->flags) { 242477eb7f9SFrançois Tigeot I915_WRITE(PLANE_KEYVAL(pipe, plane), key->min_value); 243477eb7f9SFrançois Tigeot I915_WRITE(PLANE_KEYMAX(pipe, plane), key->max_value); 244477eb7f9SFrançois Tigeot I915_WRITE(PLANE_KEYMSK(pipe, plane), key->channel_mask); 245477eb7f9SFrançois Tigeot } 246477eb7f9SFrançois Tigeot 247477eb7f9SFrançois Tigeot if (key->flags & I915_SET_COLORKEY_DESTINATION) 248477eb7f9SFrançois Tigeot plane_ctl |= PLANE_CTL_KEY_ENABLE_DESTINATION; 249477eb7f9SFrançois Tigeot else if (key->flags & I915_SET_COLORKEY_SOURCE) 250477eb7f9SFrançois Tigeot plane_ctl |= PLANE_CTL_KEY_ENABLE_SOURCE; 251477eb7f9SFrançois Tigeot 252352ff8bdSFrançois Tigeot surf_addr = intel_plane_obj_offset(intel_plane, obj, 0); 253477eb7f9SFrançois Tigeot 25419c468b4SFrançois Tigeot if (intel_rotation_90_or_270(rotation)) { 255c0e85e96SFrançois Tigeot int cpp = drm_format_plane_cpp(fb->pixel_format, 0); 256c0e85e96SFrançois Tigeot 25719c468b4SFrançois Tigeot /* stride: Surface height in tiles */ 258c0e85e96SFrançois Tigeot tile_height = intel_tile_height(dev_priv, fb->modifier[0], cpp); 25919c468b4SFrançois Tigeot stride = DIV_ROUND_UP(fb->height, tile_height); 26019c468b4SFrançois Tigeot plane_size = (src_w << 16) | src_h; 26119c468b4SFrançois Tigeot x_offset = stride * tile_height - y - (src_h + 1); 26219c468b4SFrançois Tigeot y_offset = x; 26319c468b4SFrançois Tigeot } else { 26419c468b4SFrançois Tigeot stride = fb->pitches[0] / stride_div; 26519c468b4SFrançois Tigeot plane_size = (src_h << 16) | src_w; 26619c468b4SFrançois Tigeot x_offset = x; 26719c468b4SFrançois Tigeot y_offset = y; 26819c468b4SFrançois Tigeot } 26919c468b4SFrançois Tigeot plane_offset = y_offset << 16 | x_offset; 27019c468b4SFrançois Tigeot 27119c468b4SFrançois Tigeot I915_WRITE(PLANE_OFFSET(pipe, plane), plane_offset); 27219c468b4SFrançois Tigeot I915_WRITE(PLANE_STRIDE(pipe, plane), stride); 27319c468b4SFrançois Tigeot I915_WRITE(PLANE_SIZE(pipe, plane), plane_size); 27419c468b4SFrançois Tigeot 27519c468b4SFrançois Tigeot /* program plane scaler */ 276c0e85e96SFrançois Tigeot if (plane_state->scaler_id >= 0) { 277c0e85e96SFrançois Tigeot int scaler_id = plane_state->scaler_id; 2781487f786SFrançois Tigeot const struct intel_scaler *scaler; 27919c468b4SFrançois Tigeot 28019c468b4SFrançois Tigeot DRM_DEBUG_KMS("plane = %d PS_PLANE_SEL(plane) = 0x%x\n", plane, 28119c468b4SFrançois Tigeot PS_PLANE_SEL(plane)); 2821487f786SFrançois Tigeot 2831487f786SFrançois Tigeot scaler = &crtc_state->scaler_state.scalers[scaler_id]; 2841487f786SFrançois Tigeot 2851487f786SFrançois Tigeot I915_WRITE(SKL_PS_CTRL(pipe, scaler_id), 2861487f786SFrançois Tigeot PS_SCALER_EN | PS_PLANE_SEL(plane) | scaler->mode); 28719c468b4SFrançois Tigeot I915_WRITE(SKL_PS_PWR_GATE(pipe, scaler_id), 0); 28819c468b4SFrançois Tigeot I915_WRITE(SKL_PS_WIN_POS(pipe, scaler_id), (crtc_x << 16) | crtc_y); 28919c468b4SFrançois Tigeot I915_WRITE(SKL_PS_WIN_SZ(pipe, scaler_id), 29019c468b4SFrançois Tigeot ((crtc_w + 1) << 16)|(crtc_h + 1)); 29119c468b4SFrançois Tigeot 29219c468b4SFrançois Tigeot I915_WRITE(PLANE_POS(pipe, plane), 0); 29319c468b4SFrançois Tigeot } else { 2942c9916cdSFrançois Tigeot I915_WRITE(PLANE_POS(pipe, plane), (crtc_y << 16) | crtc_x); 29519c468b4SFrançois Tigeot } 29619c468b4SFrançois Tigeot 2972c9916cdSFrançois Tigeot I915_WRITE(PLANE_CTL(pipe, plane), plane_ctl); 298477eb7f9SFrançois Tigeot I915_WRITE(PLANE_SURF(pipe, plane), surf_addr); 2992c9916cdSFrançois Tigeot POSTING_READ(PLANE_SURF(pipe, plane)); 3002c9916cdSFrançois Tigeot } 3012c9916cdSFrançois Tigeot 3022c9916cdSFrançois Tigeot static void 303a05eeebfSFrançois Tigeot skl_disable_plane(struct drm_plane *dplane, struct drm_crtc *crtc) 3042c9916cdSFrançois Tigeot { 30519c468b4SFrançois Tigeot struct drm_device *dev = dplane->dev; 306bf017597SFrançois Tigeot struct drm_i915_private *dev_priv = to_i915(dev); 30719c468b4SFrançois Tigeot struct intel_plane *intel_plane = to_intel_plane(dplane); 3082c9916cdSFrançois Tigeot const int pipe = intel_plane->pipe; 3092c9916cdSFrançois Tigeot const int plane = intel_plane->plane + 1; 3102c9916cdSFrançois Tigeot 311477eb7f9SFrançois Tigeot I915_WRITE(PLANE_CTL(pipe, plane), 0); 3122c9916cdSFrançois Tigeot 313477eb7f9SFrançois Tigeot I915_WRITE(PLANE_SURF(pipe, plane), 0); 314477eb7f9SFrançois Tigeot POSTING_READ(PLANE_SURF(pipe, plane)); 3152c9916cdSFrançois Tigeot } 3162c9916cdSFrançois Tigeot 3172c9916cdSFrançois Tigeot static void 3182c9916cdSFrançois Tigeot chv_update_csc(struct intel_plane *intel_plane, uint32_t format) 3192c9916cdSFrançois Tigeot { 320bf017597SFrançois Tigeot struct drm_i915_private *dev_priv = to_i915(intel_plane->base.dev); 3212c9916cdSFrançois Tigeot int plane = intel_plane->plane; 3222c9916cdSFrançois Tigeot 3232c9916cdSFrançois Tigeot /* Seems RGB data bypasses the CSC always */ 3242c9916cdSFrançois Tigeot if (!format_is_yuv(format)) 3252c9916cdSFrançois Tigeot return; 3262c9916cdSFrançois Tigeot 3272c9916cdSFrançois Tigeot /* 3282c9916cdSFrançois Tigeot * BT.601 limited range YCbCr -> full range RGB 3292c9916cdSFrançois Tigeot * 3302c9916cdSFrançois Tigeot * |r| | 6537 4769 0| |cr | 3312c9916cdSFrançois Tigeot * |g| = |-3330 4769 -1605| x |y-64| 3322c9916cdSFrançois Tigeot * |b| | 0 4769 8263| |cb | 3332c9916cdSFrançois Tigeot * 3342c9916cdSFrançois Tigeot * Cb and Cr apparently come in as signed already, so no 3352c9916cdSFrançois Tigeot * need for any offset. For Y we need to remove the offset. 3362c9916cdSFrançois Tigeot */ 3372c9916cdSFrançois Tigeot I915_WRITE(SPCSCYGOFF(plane), SPCSC_OOFF(0) | SPCSC_IOFF(-64)); 3382c9916cdSFrançois Tigeot I915_WRITE(SPCSCCBOFF(plane), SPCSC_OOFF(0) | SPCSC_IOFF(0)); 3392c9916cdSFrançois Tigeot I915_WRITE(SPCSCCROFF(plane), SPCSC_OOFF(0) | SPCSC_IOFF(0)); 3402c9916cdSFrançois Tigeot 3412c9916cdSFrançois Tigeot I915_WRITE(SPCSCC01(plane), SPCSC_C1(4769) | SPCSC_C0(6537)); 3422c9916cdSFrançois Tigeot I915_WRITE(SPCSCC23(plane), SPCSC_C1(-3330) | SPCSC_C0(0)); 3432c9916cdSFrançois Tigeot I915_WRITE(SPCSCC45(plane), SPCSC_C1(-1605) | SPCSC_C0(4769)); 3442c9916cdSFrançois Tigeot I915_WRITE(SPCSCC67(plane), SPCSC_C1(4769) | SPCSC_C0(0)); 3452c9916cdSFrançois Tigeot I915_WRITE(SPCSCC8(plane), SPCSC_C0(8263)); 3462c9916cdSFrançois Tigeot 3472c9916cdSFrançois Tigeot I915_WRITE(SPCSCYGICLAMP(plane), SPCSC_IMAX(940) | SPCSC_IMIN(64)); 3482c9916cdSFrançois Tigeot I915_WRITE(SPCSCCBICLAMP(plane), SPCSC_IMAX(448) | SPCSC_IMIN(-448)); 3492c9916cdSFrançois Tigeot I915_WRITE(SPCSCCRICLAMP(plane), SPCSC_IMAX(448) | SPCSC_IMIN(-448)); 3502c9916cdSFrançois Tigeot 3512c9916cdSFrançois Tigeot I915_WRITE(SPCSCYGOCLAMP(plane), SPCSC_OMAX(1023) | SPCSC_OMIN(0)); 3522c9916cdSFrançois Tigeot I915_WRITE(SPCSCCBOCLAMP(plane), SPCSC_OMAX(1023) | SPCSC_OMIN(0)); 3532c9916cdSFrançois Tigeot I915_WRITE(SPCSCCROCLAMP(plane), SPCSC_OMAX(1023) | SPCSC_OMIN(0)); 3542c9916cdSFrançois Tigeot } 3552c9916cdSFrançois Tigeot 3562c9916cdSFrançois Tigeot static void 357c0e85e96SFrançois Tigeot vlv_update_plane(struct drm_plane *dplane, 358c0e85e96SFrançois Tigeot const struct intel_crtc_state *crtc_state, 359c0e85e96SFrançois Tigeot const struct intel_plane_state *plane_state) 3608e26cdf6SFrançois Tigeot { 3618e26cdf6SFrançois Tigeot struct drm_device *dev = dplane->dev; 362bf017597SFrançois Tigeot struct drm_i915_private *dev_priv = to_i915(dev); 3638e26cdf6SFrançois Tigeot struct intel_plane *intel_plane = to_intel_plane(dplane); 364c0e85e96SFrançois Tigeot struct drm_framebuffer *fb = plane_state->base.fb; 365477eb7f9SFrançois Tigeot struct drm_i915_gem_object *obj = intel_fb_obj(fb); 3668e26cdf6SFrançois Tigeot int pipe = intel_plane->pipe; 3678e26cdf6SFrançois Tigeot int plane = intel_plane->plane; 3688e26cdf6SFrançois Tigeot u32 sprctl; 369c0e85e96SFrançois Tigeot u32 sprsurf_offset, linear_offset; 3708621f407SFrançois Tigeot unsigned int rotation = dplane->state->rotation; 371c0e85e96SFrançois Tigeot int cpp = drm_format_plane_cpp(fb->pixel_format, 0); 372c0e85e96SFrançois Tigeot const struct drm_intel_sprite_colorkey *key = &plane_state->ckey; 373c0e85e96SFrançois Tigeot int crtc_x = plane_state->dst.x1; 374c0e85e96SFrançois Tigeot int crtc_y = plane_state->dst.y1; 375c0e85e96SFrançois Tigeot uint32_t crtc_w = drm_rect_width(&plane_state->dst); 376c0e85e96SFrançois Tigeot uint32_t crtc_h = drm_rect_height(&plane_state->dst); 377c0e85e96SFrançois Tigeot uint32_t x = plane_state->src.x1 >> 16; 378c0e85e96SFrançois Tigeot uint32_t y = plane_state->src.y1 >> 16; 379c0e85e96SFrançois Tigeot uint32_t src_w = drm_rect_width(&plane_state->src) >> 16; 380c0e85e96SFrançois Tigeot uint32_t src_h = drm_rect_height(&plane_state->src) >> 16; 3818e26cdf6SFrançois Tigeot 382477eb7f9SFrançois Tigeot sprctl = SP_ENABLE; 3838e26cdf6SFrançois Tigeot 3848e26cdf6SFrançois Tigeot switch (fb->pixel_format) { 3858e26cdf6SFrançois Tigeot case DRM_FORMAT_YUYV: 3868e26cdf6SFrançois Tigeot sprctl |= SP_FORMAT_YUV422 | SP_YUV_ORDER_YUYV; 3878e26cdf6SFrançois Tigeot break; 3888e26cdf6SFrançois Tigeot case DRM_FORMAT_YVYU: 3898e26cdf6SFrançois Tigeot sprctl |= SP_FORMAT_YUV422 | SP_YUV_ORDER_YVYU; 3908e26cdf6SFrançois Tigeot break; 3918e26cdf6SFrançois Tigeot case DRM_FORMAT_UYVY: 3928e26cdf6SFrançois Tigeot sprctl |= SP_FORMAT_YUV422 | SP_YUV_ORDER_UYVY; 3938e26cdf6SFrançois Tigeot break; 3948e26cdf6SFrançois Tigeot case DRM_FORMAT_VYUY: 3958e26cdf6SFrançois Tigeot sprctl |= SP_FORMAT_YUV422 | SP_YUV_ORDER_VYUY; 3968e26cdf6SFrançois Tigeot break; 3978e26cdf6SFrançois Tigeot case DRM_FORMAT_RGB565: 3988e26cdf6SFrançois Tigeot sprctl |= SP_FORMAT_BGR565; 3998e26cdf6SFrançois Tigeot break; 4008e26cdf6SFrançois Tigeot case DRM_FORMAT_XRGB8888: 4018e26cdf6SFrançois Tigeot sprctl |= SP_FORMAT_BGRX8888; 4028e26cdf6SFrançois Tigeot break; 4038e26cdf6SFrançois Tigeot case DRM_FORMAT_ARGB8888: 4048e26cdf6SFrançois Tigeot sprctl |= SP_FORMAT_BGRA8888; 4058e26cdf6SFrançois Tigeot break; 4068e26cdf6SFrançois Tigeot case DRM_FORMAT_XBGR2101010: 4078e26cdf6SFrançois Tigeot sprctl |= SP_FORMAT_RGBX1010102; 4088e26cdf6SFrançois Tigeot break; 4098e26cdf6SFrançois Tigeot case DRM_FORMAT_ABGR2101010: 4108e26cdf6SFrançois Tigeot sprctl |= SP_FORMAT_RGBA1010102; 4118e26cdf6SFrançois Tigeot break; 4128e26cdf6SFrançois Tigeot case DRM_FORMAT_XBGR8888: 4138e26cdf6SFrançois Tigeot sprctl |= SP_FORMAT_RGBX8888; 4148e26cdf6SFrançois Tigeot break; 4158e26cdf6SFrançois Tigeot case DRM_FORMAT_ABGR8888: 4168e26cdf6SFrançois Tigeot sprctl |= SP_FORMAT_RGBA8888; 4178e26cdf6SFrançois Tigeot break; 4188e26cdf6SFrançois Tigeot default: 4198e26cdf6SFrançois Tigeot /* 4208e26cdf6SFrançois Tigeot * If we get here one of the upper layers failed to filter 4218e26cdf6SFrançois Tigeot * out the unsupported plane formats 4228e26cdf6SFrançois Tigeot */ 4238e26cdf6SFrançois Tigeot BUG(); 4248e26cdf6SFrançois Tigeot break; 4258e26cdf6SFrançois Tigeot } 4268e26cdf6SFrançois Tigeot 4279edbd4a0SFrançois Tigeot /* 4289edbd4a0SFrançois Tigeot * Enable gamma to match primary/cursor plane behaviour. 4299edbd4a0SFrançois Tigeot * FIXME should be user controllable via propertiesa. 4309edbd4a0SFrançois Tigeot */ 4319edbd4a0SFrançois Tigeot sprctl |= SP_GAMMA_ENABLE; 4329edbd4a0SFrançois Tigeot 4338e26cdf6SFrançois Tigeot if (obj->tiling_mode != I915_TILING_NONE) 4348e26cdf6SFrançois Tigeot sprctl |= SP_TILED; 4358e26cdf6SFrançois Tigeot 4368e26cdf6SFrançois Tigeot /* Sizes are 0 based */ 4378e26cdf6SFrançois Tigeot src_w--; 4388e26cdf6SFrançois Tigeot src_h--; 4398e26cdf6SFrançois Tigeot crtc_w--; 4408e26cdf6SFrançois Tigeot crtc_h--; 4418e26cdf6SFrançois Tigeot 442c0e85e96SFrançois Tigeot linear_offset = y * fb->pitches[0] + x * cpp; 4438621f407SFrançois Tigeot sprsurf_offset = intel_compute_tile_offset(&x, &y, fb, 0, 4448621f407SFrançois Tigeot fb->pitches[0], rotation); 4458e26cdf6SFrançois Tigeot linear_offset -= sprsurf_offset; 4468e26cdf6SFrançois Tigeot 447*87df8fc6SFrançois Tigeot if (rotation == BIT(DRM_ROTATE_180)) { 4481b13d190SFrançois Tigeot sprctl |= SP_ROTATE_180; 4491b13d190SFrançois Tigeot 4501b13d190SFrançois Tigeot x += src_w; 4511b13d190SFrançois Tigeot y += src_h; 452c0e85e96SFrançois Tigeot linear_offset += src_h * fb->pitches[0] + src_w * cpp; 4531b13d190SFrançois Tigeot } 4541b13d190SFrançois Tigeot 455477eb7f9SFrançois Tigeot if (key->flags) { 456477eb7f9SFrançois Tigeot I915_WRITE(SPKEYMINVAL(pipe, plane), key->min_value); 457477eb7f9SFrançois Tigeot I915_WRITE(SPKEYMAXVAL(pipe, plane), key->max_value); 458477eb7f9SFrançois Tigeot I915_WRITE(SPKEYMSK(pipe, plane), key->channel_mask); 459477eb7f9SFrançois Tigeot } 460477eb7f9SFrançois Tigeot 461477eb7f9SFrançois Tigeot if (key->flags & I915_SET_COLORKEY_SOURCE) 462477eb7f9SFrançois Tigeot sprctl |= SP_SOURCE_KEY; 463477eb7f9SFrançois Tigeot 4642c9916cdSFrançois Tigeot if (IS_CHERRYVIEW(dev) && pipe == PIPE_B) 4652c9916cdSFrançois Tigeot chv_update_csc(intel_plane, fb->pixel_format); 4662c9916cdSFrançois Tigeot 467ba55f2f5SFrançois Tigeot I915_WRITE(SPSTRIDE(pipe, plane), fb->pitches[0]); 468ba55f2f5SFrançois Tigeot I915_WRITE(SPPOS(pipe, plane), (crtc_y << 16) | crtc_x); 469ba55f2f5SFrançois Tigeot 4708e26cdf6SFrançois Tigeot if (obj->tiling_mode != I915_TILING_NONE) 4718e26cdf6SFrançois Tigeot I915_WRITE(SPTILEOFF(pipe, plane), (y << 16) | x); 4728e26cdf6SFrançois Tigeot else 4738e26cdf6SFrançois Tigeot I915_WRITE(SPLINOFF(pipe, plane), linear_offset); 4748e26cdf6SFrançois Tigeot 4752c9916cdSFrançois Tigeot I915_WRITE(SPCONSTALPHA(pipe, plane), 0); 4762c9916cdSFrançois Tigeot 4778e26cdf6SFrançois Tigeot I915_WRITE(SPSIZE(pipe, plane), (crtc_h << 16) | crtc_w); 4788e26cdf6SFrançois Tigeot I915_WRITE(SPCNTR(pipe, plane), sprctl); 4799edbd4a0SFrançois Tigeot I915_WRITE(SPSURF(pipe, plane), i915_gem_obj_ggtt_offset(obj) + 4808e26cdf6SFrançois Tigeot sprsurf_offset); 48119c468b4SFrançois Tigeot POSTING_READ(SPSURF(pipe, plane)); 4828e26cdf6SFrançois Tigeot } 4838e26cdf6SFrançois Tigeot 4848e26cdf6SFrançois Tigeot static void 485a05eeebfSFrançois Tigeot vlv_disable_plane(struct drm_plane *dplane, struct drm_crtc *crtc) 4868e26cdf6SFrançois Tigeot { 4878e26cdf6SFrançois Tigeot struct drm_device *dev = dplane->dev; 488bf017597SFrançois Tigeot struct drm_i915_private *dev_priv = to_i915(dev); 4898e26cdf6SFrançois Tigeot struct intel_plane *intel_plane = to_intel_plane(dplane); 4908e26cdf6SFrançois Tigeot int pipe = intel_plane->pipe; 4918e26cdf6SFrançois Tigeot int plane = intel_plane->plane; 492ba55f2f5SFrançois Tigeot 493477eb7f9SFrançois Tigeot I915_WRITE(SPCNTR(pipe, plane), 0); 494477eb7f9SFrançois Tigeot 4959edbd4a0SFrançois Tigeot I915_WRITE(SPSURF(pipe, plane), 0); 49619c468b4SFrançois Tigeot POSTING_READ(SPSURF(pipe, plane)); 4978e26cdf6SFrançois Tigeot } 4988e26cdf6SFrançois Tigeot 4998e26cdf6SFrançois Tigeot static void 500c0e85e96SFrançois Tigeot ivb_update_plane(struct drm_plane *plane, 501c0e85e96SFrançois Tigeot const struct intel_crtc_state *crtc_state, 502c0e85e96SFrançois Tigeot const struct intel_plane_state *plane_state) 503e3adcf8fSFrançois Tigeot { 504e3adcf8fSFrançois Tigeot struct drm_device *dev = plane->dev; 505bf017597SFrançois Tigeot struct drm_i915_private *dev_priv = to_i915(dev); 506e3adcf8fSFrançois Tigeot struct intel_plane *intel_plane = to_intel_plane(plane); 507c0e85e96SFrançois Tigeot struct drm_framebuffer *fb = plane_state->base.fb; 508477eb7f9SFrançois Tigeot struct drm_i915_gem_object *obj = intel_fb_obj(fb); 509477eb7f9SFrançois Tigeot enum i915_pipe pipe = intel_plane->pipe; 510e3adcf8fSFrançois Tigeot u32 sprctl, sprscale = 0; 511c0e85e96SFrançois Tigeot u32 sprsurf_offset, linear_offset; 5128621f407SFrançois Tigeot unsigned int rotation = plane_state->base.rotation; 513c0e85e96SFrançois Tigeot int cpp = drm_format_plane_cpp(fb->pixel_format, 0); 514c0e85e96SFrançois Tigeot const struct drm_intel_sprite_colorkey *key = &plane_state->ckey; 515c0e85e96SFrançois Tigeot int crtc_x = plane_state->dst.x1; 516c0e85e96SFrançois Tigeot int crtc_y = plane_state->dst.y1; 517c0e85e96SFrançois Tigeot uint32_t crtc_w = drm_rect_width(&plane_state->dst); 518c0e85e96SFrançois Tigeot uint32_t crtc_h = drm_rect_height(&plane_state->dst); 519c0e85e96SFrançois Tigeot uint32_t x = plane_state->src.x1 >> 16; 520c0e85e96SFrançois Tigeot uint32_t y = plane_state->src.y1 >> 16; 521c0e85e96SFrançois Tigeot uint32_t src_w = drm_rect_width(&plane_state->src) >> 16; 522c0e85e96SFrançois Tigeot uint32_t src_h = drm_rect_height(&plane_state->src) >> 16; 523e3adcf8fSFrançois Tigeot 524477eb7f9SFrançois Tigeot sprctl = SPRITE_ENABLE; 525e3adcf8fSFrançois Tigeot 526e3adcf8fSFrançois Tigeot switch (fb->pixel_format) { 527e3adcf8fSFrançois Tigeot case DRM_FORMAT_XBGR8888: 5282c84b0b6SFrançois Tigeot sprctl |= SPRITE_FORMAT_RGBX888 | SPRITE_RGB_ORDER_RGBX; 529e3adcf8fSFrançois Tigeot break; 530e3adcf8fSFrançois Tigeot case DRM_FORMAT_XRGB8888: 5312c84b0b6SFrançois Tigeot sprctl |= SPRITE_FORMAT_RGBX888; 532e3adcf8fSFrançois Tigeot break; 533e3adcf8fSFrançois Tigeot case DRM_FORMAT_YUYV: 534e3adcf8fSFrançois Tigeot sprctl |= SPRITE_FORMAT_YUV422 | SPRITE_YUV_ORDER_YUYV; 535e3adcf8fSFrançois Tigeot break; 536e3adcf8fSFrançois Tigeot case DRM_FORMAT_YVYU: 537e3adcf8fSFrançois Tigeot sprctl |= SPRITE_FORMAT_YUV422 | SPRITE_YUV_ORDER_YVYU; 538e3adcf8fSFrançois Tigeot break; 539e3adcf8fSFrançois Tigeot case DRM_FORMAT_UYVY: 540e3adcf8fSFrançois Tigeot sprctl |= SPRITE_FORMAT_YUV422 | SPRITE_YUV_ORDER_UYVY; 541e3adcf8fSFrançois Tigeot break; 542e3adcf8fSFrançois Tigeot case DRM_FORMAT_VYUY: 543e3adcf8fSFrançois Tigeot sprctl |= SPRITE_FORMAT_YUV422 | SPRITE_YUV_ORDER_VYUY; 544e3adcf8fSFrançois Tigeot break; 545e3adcf8fSFrançois Tigeot default: 5462c84b0b6SFrançois Tigeot BUG(); 547e3adcf8fSFrançois Tigeot } 548e3adcf8fSFrançois Tigeot 5499edbd4a0SFrançois Tigeot /* 5509edbd4a0SFrançois Tigeot * Enable gamma to match primary/cursor plane behaviour. 5519edbd4a0SFrançois Tigeot * FIXME should be user controllable via propertiesa. 5529edbd4a0SFrançois Tigeot */ 5539edbd4a0SFrançois Tigeot sprctl |= SPRITE_GAMMA_ENABLE; 5549edbd4a0SFrançois Tigeot 555e3adcf8fSFrançois Tigeot if (obj->tiling_mode != I915_TILING_NONE) 556e3adcf8fSFrançois Tigeot sprctl |= SPRITE_TILED; 557e3adcf8fSFrançois Tigeot 5589edbd4a0SFrançois Tigeot if (IS_HASWELL(dev) || IS_BROADWELL(dev)) 5599edbd4a0SFrançois Tigeot sprctl &= ~SPRITE_TRICKLE_FEED_DISABLE; 5609edbd4a0SFrançois Tigeot else 561e3adcf8fSFrançois Tigeot sprctl |= SPRITE_TRICKLE_FEED_DISABLE; 5629edbd4a0SFrançois Tigeot 5639edbd4a0SFrançois Tigeot if (IS_HASWELL(dev) || IS_BROADWELL(dev)) 564a2fdbec6SFrançois Tigeot sprctl |= SPRITE_PIPE_CSC_ENABLE; 565a2fdbec6SFrançois Tigeot 566e3adcf8fSFrançois Tigeot /* Sizes are 0 based */ 567e3adcf8fSFrançois Tigeot src_w--; 568e3adcf8fSFrançois Tigeot src_h--; 569e3adcf8fSFrançois Tigeot crtc_w--; 570e3adcf8fSFrançois Tigeot crtc_h--; 571e3adcf8fSFrançois Tigeot 5729edbd4a0SFrançois Tigeot if (crtc_w != src_w || crtc_h != src_h) 573e3adcf8fSFrançois Tigeot sprscale = SPRITE_SCALE_ENABLE | (src_w << 16) | src_h; 574e3adcf8fSFrançois Tigeot 575c0e85e96SFrançois Tigeot linear_offset = y * fb->pitches[0] + x * cpp; 5768621f407SFrançois Tigeot sprsurf_offset = intel_compute_tile_offset(&x, &y, fb, 0, 5778621f407SFrançois Tigeot fb->pitches[0], rotation); 5782c84b0b6SFrançois Tigeot linear_offset -= sprsurf_offset; 5792c84b0b6SFrançois Tigeot 580*87df8fc6SFrançois Tigeot if (rotation == BIT(DRM_ROTATE_180)) { 5811b13d190SFrançois Tigeot sprctl |= SPRITE_ROTATE_180; 5821b13d190SFrançois Tigeot 5831b13d190SFrançois Tigeot /* HSW and BDW does this automagically in hardware */ 5841b13d190SFrançois Tigeot if (!IS_HASWELL(dev) && !IS_BROADWELL(dev)) { 5851b13d190SFrançois Tigeot x += src_w; 5861b13d190SFrançois Tigeot y += src_h; 587c0e85e96SFrançois Tigeot linear_offset += src_h * fb->pitches[0] + src_w * cpp; 5881b13d190SFrançois Tigeot } 5891b13d190SFrançois Tigeot } 5901b13d190SFrançois Tigeot 591477eb7f9SFrançois Tigeot if (key->flags) { 592477eb7f9SFrançois Tigeot I915_WRITE(SPRKEYVAL(pipe), key->min_value); 593477eb7f9SFrançois Tigeot I915_WRITE(SPRKEYMAX(pipe), key->max_value); 594477eb7f9SFrançois Tigeot I915_WRITE(SPRKEYMSK(pipe), key->channel_mask); 595477eb7f9SFrançois Tigeot } 596477eb7f9SFrançois Tigeot 597477eb7f9SFrançois Tigeot if (key->flags & I915_SET_COLORKEY_DESTINATION) 598477eb7f9SFrançois Tigeot sprctl |= SPRITE_DEST_KEY; 599477eb7f9SFrançois Tigeot else if (key->flags & I915_SET_COLORKEY_SOURCE) 600477eb7f9SFrançois Tigeot sprctl |= SPRITE_SOURCE_KEY; 601477eb7f9SFrançois Tigeot 602ba55f2f5SFrançois Tigeot I915_WRITE(SPRSTRIDE(pipe), fb->pitches[0]); 603ba55f2f5SFrançois Tigeot I915_WRITE(SPRPOS(pipe), (crtc_y << 16) | crtc_x); 604ba55f2f5SFrançois Tigeot 6052c84b0b6SFrançois Tigeot /* HSW consolidates SPRTILEOFF and SPRLINOFF into a single SPROFFSET 6062c84b0b6SFrançois Tigeot * register */ 6079edbd4a0SFrançois Tigeot if (IS_HASWELL(dev) || IS_BROADWELL(dev)) 6082c84b0b6SFrançois Tigeot I915_WRITE(SPROFFSET(pipe), (y << 16) | x); 6092c84b0b6SFrançois Tigeot else if (obj->tiling_mode != I915_TILING_NONE) 6102c84b0b6SFrançois Tigeot I915_WRITE(SPRTILEOFF(pipe), (y << 16) | x); 6112c84b0b6SFrançois Tigeot else 6122c84b0b6SFrançois Tigeot I915_WRITE(SPRLINOFF(pipe), linear_offset); 6132c84b0b6SFrançois Tigeot 614e3adcf8fSFrançois Tigeot I915_WRITE(SPRSIZE(pipe), (crtc_h << 16) | crtc_w); 6152c84b0b6SFrançois Tigeot if (intel_plane->can_scale) 616e3adcf8fSFrançois Tigeot I915_WRITE(SPRSCALE(pipe), sprscale); 617e3adcf8fSFrançois Tigeot I915_WRITE(SPRCTL(pipe), sprctl); 6189edbd4a0SFrançois Tigeot I915_WRITE(SPRSURF(pipe), 6199edbd4a0SFrançois Tigeot i915_gem_obj_ggtt_offset(obj) + sprsurf_offset); 62019c468b4SFrançois Tigeot POSTING_READ(SPRSURF(pipe)); 621e3adcf8fSFrançois Tigeot } 622e3adcf8fSFrançois Tigeot 623e3adcf8fSFrançois Tigeot static void 624a05eeebfSFrançois Tigeot ivb_disable_plane(struct drm_plane *plane, struct drm_crtc *crtc) 625e3adcf8fSFrançois Tigeot { 626e3adcf8fSFrançois Tigeot struct drm_device *dev = plane->dev; 627bf017597SFrançois Tigeot struct drm_i915_private *dev_priv = to_i915(dev); 628e3adcf8fSFrançois Tigeot struct intel_plane *intel_plane = to_intel_plane(plane); 629e3adcf8fSFrançois Tigeot int pipe = intel_plane->pipe; 630ba55f2f5SFrançois Tigeot 631352ff8bdSFrançois Tigeot I915_WRITE(SPRCTL(pipe), 0); 632e3adcf8fSFrançois Tigeot /* Can't leave the scaler enabled... */ 6332c84b0b6SFrançois Tigeot if (intel_plane->can_scale) 634e3adcf8fSFrançois Tigeot I915_WRITE(SPRSCALE(pipe), 0); 635ba55f2f5SFrançois Tigeot 63619c468b4SFrançois Tigeot I915_WRITE(SPRSURF(pipe), 0); 63719c468b4SFrançois Tigeot POSTING_READ(SPRSURF(pipe)); 638e3adcf8fSFrançois Tigeot } 639e3adcf8fSFrançois Tigeot 640e3adcf8fSFrançois Tigeot static void 641c0e85e96SFrançois Tigeot ilk_update_plane(struct drm_plane *plane, 642c0e85e96SFrançois Tigeot const struct intel_crtc_state *crtc_state, 643c0e85e96SFrançois Tigeot const struct intel_plane_state *plane_state) 644e3adcf8fSFrançois Tigeot { 645e3adcf8fSFrançois Tigeot struct drm_device *dev = plane->dev; 646bf017597SFrançois Tigeot struct drm_i915_private *dev_priv = to_i915(dev); 647e3adcf8fSFrançois Tigeot struct intel_plane *intel_plane = to_intel_plane(plane); 648c0e85e96SFrançois Tigeot struct drm_framebuffer *fb = plane_state->base.fb; 649477eb7f9SFrançois Tigeot struct drm_i915_gem_object *obj = intel_fb_obj(fb); 6502c84b0b6SFrançois Tigeot int pipe = intel_plane->pipe; 6512c84b0b6SFrançois Tigeot u32 dvscntr, dvsscale; 652c0e85e96SFrançois Tigeot u32 dvssurf_offset, linear_offset; 6538621f407SFrançois Tigeot unsigned int rotation = plane_state->base.rotation; 654c0e85e96SFrançois Tigeot int cpp = drm_format_plane_cpp(fb->pixel_format, 0); 655c0e85e96SFrançois Tigeot const struct drm_intel_sprite_colorkey *key = &plane_state->ckey; 656c0e85e96SFrançois Tigeot int crtc_x = plane_state->dst.x1; 657c0e85e96SFrançois Tigeot int crtc_y = plane_state->dst.y1; 658c0e85e96SFrançois Tigeot uint32_t crtc_w = drm_rect_width(&plane_state->dst); 659c0e85e96SFrançois Tigeot uint32_t crtc_h = drm_rect_height(&plane_state->dst); 660c0e85e96SFrançois Tigeot uint32_t x = plane_state->src.x1 >> 16; 661c0e85e96SFrançois Tigeot uint32_t y = plane_state->src.y1 >> 16; 662c0e85e96SFrançois Tigeot uint32_t src_w = drm_rect_width(&plane_state->src) >> 16; 663c0e85e96SFrançois Tigeot uint32_t src_h = drm_rect_height(&plane_state->src) >> 16; 664e3adcf8fSFrançois Tigeot 665477eb7f9SFrançois Tigeot dvscntr = DVS_ENABLE; 666e3adcf8fSFrançois Tigeot 667e3adcf8fSFrançois Tigeot switch (fb->pixel_format) { 668e3adcf8fSFrançois Tigeot case DRM_FORMAT_XBGR8888: 669e3adcf8fSFrançois Tigeot dvscntr |= DVS_FORMAT_RGBX888 | DVS_RGB_ORDER_XBGR; 670e3adcf8fSFrançois Tigeot break; 671e3adcf8fSFrançois Tigeot case DRM_FORMAT_XRGB8888: 672e3adcf8fSFrançois Tigeot dvscntr |= DVS_FORMAT_RGBX888; 673e3adcf8fSFrançois Tigeot break; 674e3adcf8fSFrançois Tigeot case DRM_FORMAT_YUYV: 675e3adcf8fSFrançois Tigeot dvscntr |= DVS_FORMAT_YUV422 | DVS_YUV_ORDER_YUYV; 676e3adcf8fSFrançois Tigeot break; 677e3adcf8fSFrançois Tigeot case DRM_FORMAT_YVYU: 678e3adcf8fSFrançois Tigeot dvscntr |= DVS_FORMAT_YUV422 | DVS_YUV_ORDER_YVYU; 679e3adcf8fSFrançois Tigeot break; 680e3adcf8fSFrançois Tigeot case DRM_FORMAT_UYVY: 681e3adcf8fSFrançois Tigeot dvscntr |= DVS_FORMAT_YUV422 | DVS_YUV_ORDER_UYVY; 682e3adcf8fSFrançois Tigeot break; 683e3adcf8fSFrançois Tigeot case DRM_FORMAT_VYUY: 684e3adcf8fSFrançois Tigeot dvscntr |= DVS_FORMAT_YUV422 | DVS_YUV_ORDER_VYUY; 685e3adcf8fSFrançois Tigeot break; 686e3adcf8fSFrançois Tigeot default: 6872c84b0b6SFrançois Tigeot BUG(); 688e3adcf8fSFrançois Tigeot } 689e3adcf8fSFrançois Tigeot 6909edbd4a0SFrançois Tigeot /* 6919edbd4a0SFrançois Tigeot * Enable gamma to match primary/cursor plane behaviour. 6929edbd4a0SFrançois Tigeot * FIXME should be user controllable via propertiesa. 6939edbd4a0SFrançois Tigeot */ 6949edbd4a0SFrançois Tigeot dvscntr |= DVS_GAMMA_ENABLE; 6959edbd4a0SFrançois Tigeot 696e3adcf8fSFrançois Tigeot if (obj->tiling_mode != I915_TILING_NONE) 697e3adcf8fSFrançois Tigeot dvscntr |= DVS_TILED; 698e3adcf8fSFrançois Tigeot 6992c84b0b6SFrançois Tigeot if (IS_GEN6(dev)) 7002c84b0b6SFrançois Tigeot dvscntr |= DVS_TRICKLE_FEED_DISABLE; /* must disable */ 701e3adcf8fSFrançois Tigeot 702e3adcf8fSFrançois Tigeot /* Sizes are 0 based */ 703e3adcf8fSFrançois Tigeot src_w--; 704e3adcf8fSFrançois Tigeot src_h--; 705e3adcf8fSFrançois Tigeot crtc_w--; 706e3adcf8fSFrançois Tigeot crtc_h--; 707e3adcf8fSFrançois Tigeot 7082c84b0b6SFrançois Tigeot dvsscale = 0; 7099edbd4a0SFrançois Tigeot if (crtc_w != src_w || crtc_h != src_h) 710e3adcf8fSFrançois Tigeot dvsscale = DVS_SCALE_ENABLE | (src_w << 16) | src_h; 711e3adcf8fSFrançois Tigeot 712c0e85e96SFrançois Tigeot linear_offset = y * fb->pitches[0] + x * cpp; 7138621f407SFrançois Tigeot dvssurf_offset = intel_compute_tile_offset(&x, &y, fb, 0, 7148621f407SFrançois Tigeot fb->pitches[0], rotation); 7152c84b0b6SFrançois Tigeot linear_offset -= dvssurf_offset; 7162c84b0b6SFrançois Tigeot 717*87df8fc6SFrançois Tigeot if (rotation == BIT(DRM_ROTATE_180)) { 7181b13d190SFrançois Tigeot dvscntr |= DVS_ROTATE_180; 7191b13d190SFrançois Tigeot 7201b13d190SFrançois Tigeot x += src_w; 7211b13d190SFrançois Tigeot y += src_h; 722c0e85e96SFrançois Tigeot linear_offset += src_h * fb->pitches[0] + src_w * cpp; 7231b13d190SFrançois Tigeot } 7241b13d190SFrançois Tigeot 725477eb7f9SFrançois Tigeot if (key->flags) { 726477eb7f9SFrançois Tigeot I915_WRITE(DVSKEYVAL(pipe), key->min_value); 727477eb7f9SFrançois Tigeot I915_WRITE(DVSKEYMAX(pipe), key->max_value); 728477eb7f9SFrançois Tigeot I915_WRITE(DVSKEYMSK(pipe), key->channel_mask); 729477eb7f9SFrançois Tigeot } 730477eb7f9SFrançois Tigeot 731477eb7f9SFrançois Tigeot if (key->flags & I915_SET_COLORKEY_DESTINATION) 732477eb7f9SFrançois Tigeot dvscntr |= DVS_DEST_KEY; 733477eb7f9SFrançois Tigeot else if (key->flags & I915_SET_COLORKEY_SOURCE) 734477eb7f9SFrançois Tigeot dvscntr |= DVS_SOURCE_KEY; 735477eb7f9SFrançois Tigeot 736ba55f2f5SFrançois Tigeot I915_WRITE(DVSSTRIDE(pipe), fb->pitches[0]); 737ba55f2f5SFrançois Tigeot I915_WRITE(DVSPOS(pipe), (crtc_y << 16) | crtc_x); 738ba55f2f5SFrançois Tigeot 7392c84b0b6SFrançois Tigeot if (obj->tiling_mode != I915_TILING_NONE) 7402c84b0b6SFrançois Tigeot I915_WRITE(DVSTILEOFF(pipe), (y << 16) | x); 7412c84b0b6SFrançois Tigeot else 7422c84b0b6SFrançois Tigeot I915_WRITE(DVSLINOFF(pipe), linear_offset); 7432c84b0b6SFrançois Tigeot 744e3adcf8fSFrançois Tigeot I915_WRITE(DVSSIZE(pipe), (crtc_h << 16) | crtc_w); 745e3adcf8fSFrançois Tigeot I915_WRITE(DVSSCALE(pipe), dvsscale); 746e3adcf8fSFrançois Tigeot I915_WRITE(DVSCNTR(pipe), dvscntr); 7479edbd4a0SFrançois Tigeot I915_WRITE(DVSSURF(pipe), 7489edbd4a0SFrançois Tigeot i915_gem_obj_ggtt_offset(obj) + dvssurf_offset); 74919c468b4SFrançois Tigeot POSTING_READ(DVSSURF(pipe)); 750e3adcf8fSFrançois Tigeot } 751e3adcf8fSFrançois Tigeot 752e3adcf8fSFrançois Tigeot static void 753a05eeebfSFrançois Tigeot ilk_disable_plane(struct drm_plane *plane, struct drm_crtc *crtc) 754e3adcf8fSFrançois Tigeot { 755e3adcf8fSFrançois Tigeot struct drm_device *dev = plane->dev; 756bf017597SFrançois Tigeot struct drm_i915_private *dev_priv = to_i915(dev); 757e3adcf8fSFrançois Tigeot struct intel_plane *intel_plane = to_intel_plane(plane); 758e3adcf8fSFrançois Tigeot int pipe = intel_plane->pipe; 759ba55f2f5SFrançois Tigeot 760477eb7f9SFrançois Tigeot I915_WRITE(DVSCNTR(pipe), 0); 761e3adcf8fSFrançois Tigeot /* Disable the scaler */ 762e3adcf8fSFrançois Tigeot I915_WRITE(DVSSCALE(pipe), 0); 763477eb7f9SFrançois Tigeot 7649edbd4a0SFrançois Tigeot I915_WRITE(DVSSURF(pipe), 0); 76519c468b4SFrançois Tigeot POSTING_READ(DVSSURF(pipe)); 7669edbd4a0SFrançois Tigeot } 7679edbd4a0SFrançois Tigeot 768e3adcf8fSFrançois Tigeot static int 7692c9916cdSFrançois Tigeot intel_check_sprite_plane(struct drm_plane *plane, 770a05eeebfSFrançois Tigeot struct intel_crtc_state *crtc_state, 7712c9916cdSFrançois Tigeot struct intel_plane_state *state) 772e3adcf8fSFrançois Tigeot { 77319c468b4SFrançois Tigeot struct drm_device *dev = plane->dev; 774a05eeebfSFrançois Tigeot struct drm_crtc *crtc = state->base.crtc; 775a05eeebfSFrançois Tigeot struct intel_crtc *intel_crtc = to_intel_crtc(crtc); 776e3adcf8fSFrançois Tigeot struct intel_plane *intel_plane = to_intel_plane(plane); 7772c9916cdSFrançois Tigeot struct drm_framebuffer *fb = state->base.fb; 7789edbd4a0SFrançois Tigeot int crtc_x, crtc_y; 7799edbd4a0SFrançois Tigeot unsigned int crtc_w, crtc_h; 7809edbd4a0SFrançois Tigeot uint32_t src_x, src_y, src_w, src_h; 7812c9916cdSFrançois Tigeot struct drm_rect *src = &state->src; 7822c9916cdSFrançois Tigeot struct drm_rect *dst = &state->dst; 7832c9916cdSFrançois Tigeot const struct drm_rect *clip = &state->clip; 7842c9916cdSFrançois Tigeot int hscale, vscale; 7852c9916cdSFrançois Tigeot int max_scale, min_scale; 78619c468b4SFrançois Tigeot bool can_scale; 7872c9916cdSFrançois Tigeot 7882c9916cdSFrançois Tigeot if (!fb) { 7892c9916cdSFrançois Tigeot state->visible = false; 790a05eeebfSFrançois Tigeot return 0; 7912c9916cdSFrançois Tigeot } 792e3adcf8fSFrançois Tigeot 793e3adcf8fSFrançois Tigeot /* Don't modify another pipe's plane */ 7945d0b1887SFrançois Tigeot if (intel_plane->pipe != intel_crtc->pipe) { 7955d0b1887SFrançois Tigeot DRM_DEBUG_KMS("Wrong plane <-> crtc mapping\n"); 796e3adcf8fSFrançois Tigeot return -EINVAL; 7975d0b1887SFrançois Tigeot } 7985d0b1887SFrançois Tigeot 7995d0b1887SFrançois Tigeot /* FIXME check all gen limits */ 8005d0b1887SFrançois Tigeot if (fb->width < 3 || fb->height < 3 || fb->pitches[0] > 16384) { 8015d0b1887SFrançois Tigeot DRM_DEBUG_KMS("Unsuitable framebuffer for plane\n"); 8025d0b1887SFrançois Tigeot return -EINVAL; 8035d0b1887SFrançois Tigeot } 804e3adcf8fSFrançois Tigeot 80519c468b4SFrançois Tigeot /* setup can_scale, min_scale, max_scale */ 80619c468b4SFrançois Tigeot if (INTEL_INFO(dev)->gen >= 9) { 80719c468b4SFrançois Tigeot /* use scaler when colorkey is not required */ 808a05eeebfSFrançois Tigeot if (state->ckey.flags == I915_SET_COLORKEY_NONE) { 80919c468b4SFrançois Tigeot can_scale = 1; 81019c468b4SFrançois Tigeot min_scale = 1; 81119c468b4SFrançois Tigeot max_scale = skl_max_scale(intel_crtc, crtc_state); 81219c468b4SFrançois Tigeot } else { 81319c468b4SFrançois Tigeot can_scale = 0; 81419c468b4SFrançois Tigeot min_scale = DRM_PLANE_HELPER_NO_SCALING; 81519c468b4SFrançois Tigeot max_scale = DRM_PLANE_HELPER_NO_SCALING; 81619c468b4SFrançois Tigeot } 81719c468b4SFrançois Tigeot } else { 81819c468b4SFrançois Tigeot can_scale = intel_plane->can_scale; 81919c468b4SFrançois Tigeot max_scale = intel_plane->max_downscale << 16; 82019c468b4SFrançois Tigeot min_scale = intel_plane->can_scale ? 1 : (1 << 16); 82119c468b4SFrançois Tigeot } 82219c468b4SFrançois Tigeot 823e3adcf8fSFrançois Tigeot /* 8245d0b1887SFrançois Tigeot * FIXME the following code does a bunch of fuzzy adjustments to the 8255d0b1887SFrançois Tigeot * coordinates and sizes. We probably need some way to decide whether 8265d0b1887SFrançois Tigeot * more strict checking should be done instead. 827e3adcf8fSFrançois Tigeot */ 8282c9916cdSFrançois Tigeot drm_rect_rotate(src, fb->width << 16, fb->height << 16, 8292c9916cdSFrançois Tigeot state->base.rotation); 8301b13d190SFrançois Tigeot 8312c9916cdSFrançois Tigeot hscale = drm_rect_calc_hscale_relaxed(src, dst, min_scale, max_scale); 8325d0b1887SFrançois Tigeot BUG_ON(hscale < 0); 833e3adcf8fSFrançois Tigeot 8342c9916cdSFrançois Tigeot vscale = drm_rect_calc_vscale_relaxed(src, dst, min_scale, max_scale); 8355d0b1887SFrançois Tigeot BUG_ON(vscale < 0); 8365d0b1887SFrançois Tigeot 8372c9916cdSFrançois Tigeot state->visible = drm_rect_clip_scaled(src, dst, clip, hscale, vscale); 8385d0b1887SFrançois Tigeot 8392c9916cdSFrançois Tigeot crtc_x = dst->x1; 8402c9916cdSFrançois Tigeot crtc_y = dst->y1; 8412c9916cdSFrançois Tigeot crtc_w = drm_rect_width(dst); 8422c9916cdSFrançois Tigeot crtc_h = drm_rect_height(dst); 8435d0b1887SFrançois Tigeot 8442c9916cdSFrançois Tigeot if (state->visible) { 8455d0b1887SFrançois Tigeot /* check again in case clipping clamped the results */ 8462c9916cdSFrançois Tigeot hscale = drm_rect_calc_hscale(src, dst, min_scale, max_scale); 8475d0b1887SFrançois Tigeot if (hscale < 0) { 8485d0b1887SFrançois Tigeot DRM_DEBUG_KMS("Horizontal scaling factor out of limits\n"); 849aee94f86SFrançois Tigeot drm_rect_debug_print("src: ", src, true); 850aee94f86SFrançois Tigeot drm_rect_debug_print("dst: ", dst, false); 8515d0b1887SFrançois Tigeot 8525d0b1887SFrançois Tigeot return hscale; 8535d0b1887SFrançois Tigeot } 8545d0b1887SFrançois Tigeot 8552c9916cdSFrançois Tigeot vscale = drm_rect_calc_vscale(src, dst, min_scale, max_scale); 8565d0b1887SFrançois Tigeot if (vscale < 0) { 8575d0b1887SFrançois Tigeot DRM_DEBUG_KMS("Vertical scaling factor out of limits\n"); 858aee94f86SFrançois Tigeot drm_rect_debug_print("src: ", src, true); 859aee94f86SFrançois Tigeot drm_rect_debug_print("dst: ", dst, false); 8605d0b1887SFrançois Tigeot 8615d0b1887SFrançois Tigeot return vscale; 8625d0b1887SFrançois Tigeot } 8635d0b1887SFrançois Tigeot 8645d0b1887SFrançois Tigeot /* Make the source viewport size an exact multiple of the scaling factors. */ 8652c9916cdSFrançois Tigeot drm_rect_adjust_size(src, 8662c9916cdSFrançois Tigeot drm_rect_width(dst) * hscale - drm_rect_width(src), 8672c9916cdSFrançois Tigeot drm_rect_height(dst) * vscale - drm_rect_height(src)); 8685d0b1887SFrançois Tigeot 8692c9916cdSFrançois Tigeot drm_rect_rotate_inv(src, fb->width << 16, fb->height << 16, 8702c9916cdSFrançois Tigeot state->base.rotation); 8711b13d190SFrançois Tigeot 8725d0b1887SFrançois Tigeot /* sanity check to make sure the src viewport wasn't enlarged */ 8732c9916cdSFrançois Tigeot WARN_ON(src->x1 < (int) state->base.src_x || 8742c9916cdSFrançois Tigeot src->y1 < (int) state->base.src_y || 8752c9916cdSFrançois Tigeot src->x2 > (int) state->base.src_x + state->base.src_w || 8762c9916cdSFrançois Tigeot src->y2 > (int) state->base.src_y + state->base.src_h); 877e3adcf8fSFrançois Tigeot 878e3adcf8fSFrançois Tigeot /* 8795d0b1887SFrançois Tigeot * Hardware doesn't handle subpixel coordinates. 8805d0b1887SFrançois Tigeot * Adjust to (macro)pixel boundary, but be careful not to 8815d0b1887SFrançois Tigeot * increase the source viewport size, because that could 8825d0b1887SFrançois Tigeot * push the downscaling factor out of bounds. 8832c84b0b6SFrançois Tigeot */ 8842c9916cdSFrançois Tigeot src_x = src->x1 >> 16; 8852c9916cdSFrançois Tigeot src_w = drm_rect_width(src) >> 16; 8862c9916cdSFrançois Tigeot src_y = src->y1 >> 16; 8872c9916cdSFrançois Tigeot src_h = drm_rect_height(src) >> 16; 8885d0b1887SFrançois Tigeot 8895d0b1887SFrançois Tigeot if (format_is_yuv(fb->pixel_format)) { 8905d0b1887SFrançois Tigeot src_x &= ~1; 8915d0b1887SFrançois Tigeot src_w &= ~1; 8922c84b0b6SFrançois Tigeot 8932c84b0b6SFrançois Tigeot /* 8945d0b1887SFrançois Tigeot * Must keep src and dst the 8955d0b1887SFrançois Tigeot * same if we can't scale. 896e3adcf8fSFrançois Tigeot */ 89719c468b4SFrançois Tigeot if (!can_scale) 8985d0b1887SFrançois Tigeot crtc_w &= ~1; 8995d0b1887SFrançois Tigeot 9005d0b1887SFrançois Tigeot if (crtc_w == 0) 9012c9916cdSFrançois Tigeot state->visible = false; 9025d0b1887SFrançois Tigeot } 9035d0b1887SFrançois Tigeot } 9045d0b1887SFrançois Tigeot 9055d0b1887SFrançois Tigeot /* Check size restrictions when scaling */ 9062c9916cdSFrançois Tigeot if (state->visible && (src_w != crtc_w || src_h != crtc_h)) { 9075d0b1887SFrançois Tigeot unsigned int width_bytes; 908c0e85e96SFrançois Tigeot int cpp = drm_format_plane_cpp(fb->pixel_format, 0); 9095d0b1887SFrançois Tigeot 91019c468b4SFrançois Tigeot WARN_ON(!can_scale); 9115d0b1887SFrançois Tigeot 9125d0b1887SFrançois Tigeot /* FIXME interlacing min height is 6 */ 9135d0b1887SFrançois Tigeot 9145d0b1887SFrançois Tigeot if (crtc_w < 3 || crtc_h < 3) 9152c9916cdSFrançois Tigeot state->visible = false; 9165d0b1887SFrançois Tigeot 9175d0b1887SFrançois Tigeot if (src_w < 3 || src_h < 3) 9182c9916cdSFrançois Tigeot state->visible = false; 9195d0b1887SFrançois Tigeot 920c0e85e96SFrançois Tigeot width_bytes = ((src_x * cpp) & 63) + src_w * cpp; 9215d0b1887SFrançois Tigeot 92219c468b4SFrançois Tigeot if (INTEL_INFO(dev)->gen < 9 && (src_w > 2048 || src_h > 2048 || 92319c468b4SFrançois Tigeot width_bytes > 4096 || fb->pitches[0] > 4096)) { 9245d0b1887SFrançois Tigeot DRM_DEBUG_KMS("Source dimensions exceed hardware limits\n"); 925e3adcf8fSFrançois Tigeot return -EINVAL; 9265d0b1887SFrançois Tigeot } 9275d0b1887SFrançois Tigeot } 9285d0b1887SFrançois Tigeot 9292c9916cdSFrançois Tigeot if (state->visible) { 93019c468b4SFrançois Tigeot src->x1 = src_x << 16; 93119c468b4SFrançois Tigeot src->x2 = (src_x + src_w) << 16; 93219c468b4SFrançois Tigeot src->y1 = src_y << 16; 93319c468b4SFrançois Tigeot src->y2 = (src_y + src_h) << 16; 9342c9916cdSFrançois Tigeot } 935e3adcf8fSFrançois Tigeot 9362c9916cdSFrançois Tigeot dst->x1 = crtc_x; 9372c9916cdSFrançois Tigeot dst->x2 = crtc_x + crtc_w; 9382c9916cdSFrançois Tigeot dst->y1 = crtc_y; 9392c9916cdSFrançois Tigeot dst->y2 = crtc_y + crtc_h; 9402c9916cdSFrançois Tigeot 9412c9916cdSFrançois Tigeot return 0; 9422c9916cdSFrançois Tigeot } 9432c9916cdSFrançois Tigeot 944e3adcf8fSFrançois Tigeot int intel_sprite_set_colorkey(struct drm_device *dev, void *data, 945e3adcf8fSFrançois Tigeot struct drm_file *file_priv) 946e3adcf8fSFrançois Tigeot { 947e3adcf8fSFrançois Tigeot struct drm_intel_sprite_colorkey *set = data; 948e3adcf8fSFrançois Tigeot struct drm_plane *plane; 949a05eeebfSFrançois Tigeot struct drm_plane_state *plane_state; 950a05eeebfSFrançois Tigeot struct drm_atomic_state *state; 951a05eeebfSFrançois Tigeot struct drm_modeset_acquire_ctx ctx; 952e3adcf8fSFrançois Tigeot int ret = 0; 953e3adcf8fSFrançois Tigeot 954e3adcf8fSFrançois Tigeot /* Make sure we don't try to enable both src & dest simultaneously */ 955e3adcf8fSFrançois Tigeot if ((set->flags & (I915_SET_COLORKEY_DESTINATION | I915_SET_COLORKEY_SOURCE)) == (I915_SET_COLORKEY_DESTINATION | I915_SET_COLORKEY_SOURCE)) 956e3adcf8fSFrançois Tigeot return -EINVAL; 957e3adcf8fSFrançois Tigeot 958aee94f86SFrançois Tigeot if ((IS_VALLEYVIEW(dev) || IS_CHERRYVIEW(dev)) && 959477eb7f9SFrançois Tigeot set->flags & I915_SET_COLORKEY_DESTINATION) 960477eb7f9SFrançois Tigeot return -EINVAL; 961477eb7f9SFrançois Tigeot 96224edb884SFrançois Tigeot plane = drm_plane_find(dev, set->plane_id); 963a05eeebfSFrançois Tigeot if (!plane || plane->type != DRM_PLANE_TYPE_OVERLAY) 964a05eeebfSFrançois Tigeot return -ENOENT; 965a05eeebfSFrançois Tigeot 966a05eeebfSFrançois Tigeot drm_modeset_acquire_init(&ctx, 0); 967a05eeebfSFrançois Tigeot 968a05eeebfSFrançois Tigeot state = drm_atomic_state_alloc(plane->dev); 969a05eeebfSFrançois Tigeot if (!state) { 970a05eeebfSFrançois Tigeot ret = -ENOMEM; 971a05eeebfSFrançois Tigeot goto out; 972a05eeebfSFrançois Tigeot } 973a05eeebfSFrançois Tigeot state->acquire_ctx = &ctx; 974a05eeebfSFrançois Tigeot 975a05eeebfSFrançois Tigeot while (1) { 976a05eeebfSFrançois Tigeot plane_state = drm_atomic_get_plane_state(state, plane); 977a05eeebfSFrançois Tigeot ret = PTR_ERR_OR_ZERO(plane_state); 978a05eeebfSFrançois Tigeot if (!ret) { 979a05eeebfSFrançois Tigeot to_intel_plane_state(plane_state)->ckey = *set; 980a05eeebfSFrançois Tigeot ret = drm_atomic_commit(state); 981e3adcf8fSFrançois Tigeot } 982e3adcf8fSFrançois Tigeot 983a05eeebfSFrançois Tigeot if (ret != -EDEADLK) 984a05eeebfSFrançois Tigeot break; 98519c468b4SFrançois Tigeot 986a05eeebfSFrançois Tigeot drm_atomic_state_clear(state); 987a05eeebfSFrançois Tigeot drm_modeset_backoff(&ctx); 98819c468b4SFrançois Tigeot } 98919c468b4SFrançois Tigeot 990a05eeebfSFrançois Tigeot if (ret) 991a05eeebfSFrançois Tigeot drm_atomic_state_free(state); 992e3adcf8fSFrançois Tigeot 993a05eeebfSFrançois Tigeot out: 994a05eeebfSFrançois Tigeot drm_modeset_drop_locks(&ctx); 995a05eeebfSFrançois Tigeot drm_modeset_acquire_fini(&ctx); 996e3adcf8fSFrançois Tigeot return ret; 997e3adcf8fSFrançois Tigeot } 998e3adcf8fSFrançois Tigeot 99919c468b4SFrançois Tigeot static const uint32_t ilk_plane_formats[] = { 10002c84b0b6SFrançois Tigeot DRM_FORMAT_XRGB8888, 10012c84b0b6SFrançois Tigeot DRM_FORMAT_YUYV, 10022c84b0b6SFrançois Tigeot DRM_FORMAT_YVYU, 10032c84b0b6SFrançois Tigeot DRM_FORMAT_UYVY, 10042c84b0b6SFrançois Tigeot DRM_FORMAT_VYUY, 10052c84b0b6SFrançois Tigeot }; 10062c84b0b6SFrançois Tigeot 100719c468b4SFrançois Tigeot static const uint32_t snb_plane_formats[] = { 1008e3adcf8fSFrançois Tigeot DRM_FORMAT_XBGR8888, 1009e3adcf8fSFrançois Tigeot DRM_FORMAT_XRGB8888, 1010e3adcf8fSFrançois Tigeot DRM_FORMAT_YUYV, 1011e3adcf8fSFrançois Tigeot DRM_FORMAT_YVYU, 1012e3adcf8fSFrançois Tigeot DRM_FORMAT_UYVY, 1013e3adcf8fSFrançois Tigeot DRM_FORMAT_VYUY, 1014e3adcf8fSFrançois Tigeot }; 1015e3adcf8fSFrançois Tigeot 101619c468b4SFrançois Tigeot static const uint32_t vlv_plane_formats[] = { 10178e26cdf6SFrançois Tigeot DRM_FORMAT_RGB565, 10188e26cdf6SFrançois Tigeot DRM_FORMAT_ABGR8888, 10198e26cdf6SFrançois Tigeot DRM_FORMAT_ARGB8888, 10208e26cdf6SFrançois Tigeot DRM_FORMAT_XBGR8888, 10218e26cdf6SFrançois Tigeot DRM_FORMAT_XRGB8888, 10228e26cdf6SFrançois Tigeot DRM_FORMAT_XBGR2101010, 10238e26cdf6SFrançois Tigeot DRM_FORMAT_ABGR2101010, 10248e26cdf6SFrançois Tigeot DRM_FORMAT_YUYV, 10258e26cdf6SFrançois Tigeot DRM_FORMAT_YVYU, 10268e26cdf6SFrançois Tigeot DRM_FORMAT_UYVY, 10278e26cdf6SFrançois Tigeot DRM_FORMAT_VYUY, 10288e26cdf6SFrançois Tigeot }; 10298e26cdf6SFrançois Tigeot 10302c9916cdSFrançois Tigeot static uint32_t skl_plane_formats[] = { 10312c9916cdSFrançois Tigeot DRM_FORMAT_RGB565, 10322c9916cdSFrançois Tigeot DRM_FORMAT_ABGR8888, 10332c9916cdSFrançois Tigeot DRM_FORMAT_ARGB8888, 10342c9916cdSFrançois Tigeot DRM_FORMAT_XBGR8888, 10352c9916cdSFrançois Tigeot DRM_FORMAT_XRGB8888, 10362c9916cdSFrançois Tigeot DRM_FORMAT_YUYV, 10372c9916cdSFrançois Tigeot DRM_FORMAT_YVYU, 10382c9916cdSFrançois Tigeot DRM_FORMAT_UYVY, 10392c9916cdSFrançois Tigeot DRM_FORMAT_VYUY, 10402c9916cdSFrançois Tigeot }; 10412c9916cdSFrançois Tigeot 1042e3adcf8fSFrançois Tigeot int 10438e26cdf6SFrançois Tigeot intel_plane_init(struct drm_device *dev, enum i915_pipe pipe, int plane) 1044e3adcf8fSFrançois Tigeot { 10458621f407SFrançois Tigeot struct intel_plane *intel_plane = NULL; 10468621f407SFrançois Tigeot struct intel_plane_state *state = NULL; 1047e3adcf8fSFrançois Tigeot unsigned long possible_crtcs; 10482c84b0b6SFrançois Tigeot const uint32_t *plane_formats; 10492c84b0b6SFrançois Tigeot int num_plane_formats; 1050e3adcf8fSFrançois Tigeot int ret; 1051e3adcf8fSFrançois Tigeot 10522c84b0b6SFrançois Tigeot if (INTEL_INFO(dev)->gen < 5) 1053e3adcf8fSFrançois Tigeot return -ENODEV; 1054e3adcf8fSFrançois Tigeot 10559edbd4a0SFrançois Tigeot intel_plane = kzalloc(sizeof(*intel_plane), GFP_KERNEL); 10568621f407SFrançois Tigeot if (!intel_plane) { 10578621f407SFrançois Tigeot ret = -ENOMEM; 10588621f407SFrançois Tigeot goto fail; 10598621f407SFrançois Tigeot } 10602c84b0b6SFrançois Tigeot 10612c9916cdSFrançois Tigeot state = intel_create_plane_state(&intel_plane->base); 10622c9916cdSFrançois Tigeot if (!state) { 10638621f407SFrançois Tigeot ret = -ENOMEM; 10648621f407SFrançois Tigeot goto fail; 10652c9916cdSFrançois Tigeot } 10662c9916cdSFrançois Tigeot intel_plane->base.state = &state->base; 10672c9916cdSFrançois Tigeot 10682c84b0b6SFrançois Tigeot switch (INTEL_INFO(dev)->gen) { 10692c84b0b6SFrançois Tigeot case 5: 10702c84b0b6SFrançois Tigeot case 6: 10712c84b0b6SFrançois Tigeot intel_plane->can_scale = true; 10722c84b0b6SFrançois Tigeot intel_plane->max_downscale = 16; 10732c84b0b6SFrançois Tigeot intel_plane->update_plane = ilk_update_plane; 10742c84b0b6SFrançois Tigeot intel_plane->disable_plane = ilk_disable_plane; 1075e3adcf8fSFrançois Tigeot 1076e3adcf8fSFrançois Tigeot if (IS_GEN6(dev)) { 10772c84b0b6SFrançois Tigeot plane_formats = snb_plane_formats; 10782c84b0b6SFrançois Tigeot num_plane_formats = ARRAY_SIZE(snb_plane_formats); 10792c84b0b6SFrançois Tigeot } else { 10802c84b0b6SFrançois Tigeot plane_formats = ilk_plane_formats; 10812c84b0b6SFrançois Tigeot num_plane_formats = ARRAY_SIZE(ilk_plane_formats); 10822c84b0b6SFrançois Tigeot } 10832c84b0b6SFrançois Tigeot break; 10842c84b0b6SFrançois Tigeot 10852c84b0b6SFrançois Tigeot case 7: 10869edbd4a0SFrançois Tigeot case 8: 10875d0b1887SFrançois Tigeot if (IS_IVYBRIDGE(dev)) { 10882c84b0b6SFrançois Tigeot intel_plane->can_scale = true; 10895d0b1887SFrançois Tigeot intel_plane->max_downscale = 2; 10905d0b1887SFrançois Tigeot } else { 10915d0b1887SFrançois Tigeot intel_plane->can_scale = false; 10925d0b1887SFrançois Tigeot intel_plane->max_downscale = 1; 10935d0b1887SFrançois Tigeot } 10948e26cdf6SFrançois Tigeot 1095aee94f86SFrançois Tigeot if (IS_VALLEYVIEW(dev) || IS_CHERRYVIEW(dev)) { 10968e26cdf6SFrançois Tigeot intel_plane->update_plane = vlv_update_plane; 10978e26cdf6SFrançois Tigeot intel_plane->disable_plane = vlv_disable_plane; 10988e26cdf6SFrançois Tigeot 10998e26cdf6SFrançois Tigeot plane_formats = vlv_plane_formats; 11008e26cdf6SFrançois Tigeot num_plane_formats = ARRAY_SIZE(vlv_plane_formats); 11018e26cdf6SFrançois Tigeot } else { 1102e3adcf8fSFrançois Tigeot intel_plane->update_plane = ivb_update_plane; 1103e3adcf8fSFrançois Tigeot intel_plane->disable_plane = ivb_disable_plane; 11042c84b0b6SFrançois Tigeot 11052c84b0b6SFrançois Tigeot plane_formats = snb_plane_formats; 11062c84b0b6SFrançois Tigeot num_plane_formats = ARRAY_SIZE(snb_plane_formats); 11078e26cdf6SFrançois Tigeot } 11082c84b0b6SFrançois Tigeot break; 11092c9916cdSFrançois Tigeot case 9: 111019c468b4SFrançois Tigeot intel_plane->can_scale = true; 11112c9916cdSFrançois Tigeot intel_plane->update_plane = skl_update_plane; 11122c9916cdSFrançois Tigeot intel_plane->disable_plane = skl_disable_plane; 111319c468b4SFrançois Tigeot state->scaler_id = -1; 11142c84b0b6SFrançois Tigeot 11152c9916cdSFrançois Tigeot plane_formats = skl_plane_formats; 11162c9916cdSFrançois Tigeot num_plane_formats = ARRAY_SIZE(skl_plane_formats); 11172c9916cdSFrançois Tigeot break; 11182c84b0b6SFrançois Tigeot default: 11198621f407SFrançois Tigeot MISSING_CASE(INTEL_INFO(dev)->gen); 11208621f407SFrançois Tigeot ret = -ENODEV; 11218621f407SFrançois Tigeot goto fail; 1122e3adcf8fSFrançois Tigeot } 1123e3adcf8fSFrançois Tigeot 1124e3adcf8fSFrançois Tigeot intel_plane->pipe = pipe; 11258e26cdf6SFrançois Tigeot intel_plane->plane = plane; 1126352ff8bdSFrançois Tigeot intel_plane->frontbuffer_bit = INTEL_FRONTBUFFER_SPRITE(pipe, plane); 11272c9916cdSFrançois Tigeot intel_plane->check_plane = intel_check_sprite_plane; 11288621f407SFrançois Tigeot 1129e3adcf8fSFrançois Tigeot possible_crtcs = (1 << pipe); 11308621f407SFrançois Tigeot 11311487f786SFrançois Tigeot if (INTEL_INFO(dev)->gen >= 9) 11321b13d190SFrançois Tigeot ret = drm_universal_plane_init(dev, &intel_plane->base, possible_crtcs, 11332c84b0b6SFrançois Tigeot &intel_plane_funcs, 11342c84b0b6SFrançois Tigeot plane_formats, num_plane_formats, 11351487f786SFrançois Tigeot DRM_PLANE_TYPE_OVERLAY, 11361487f786SFrançois Tigeot "plane %d%c", plane + 2, pipe_name(pipe)); 11371487f786SFrançois Tigeot else 11381487f786SFrançois Tigeot ret = drm_universal_plane_init(dev, &intel_plane->base, possible_crtcs, 11391487f786SFrançois Tigeot &intel_plane_funcs, 11401487f786SFrançois Tigeot plane_formats, num_plane_formats, 11411487f786SFrançois Tigeot DRM_PLANE_TYPE_OVERLAY, 11421487f786SFrançois Tigeot "sprite %c", sprite_name(pipe, plane)); 11438621f407SFrançois Tigeot if (ret) 11448621f407SFrançois Tigeot goto fail; 1145e3adcf8fSFrançois Tigeot 114619c468b4SFrançois Tigeot intel_create_rotation_property(dev, intel_plane); 11472c9916cdSFrançois Tigeot 11482c9916cdSFrançois Tigeot drm_plane_helper_add(&intel_plane->base, &intel_plane_helper_funcs); 11491b13d190SFrançois Tigeot 11508621f407SFrançois Tigeot return 0; 11518621f407SFrançois Tigeot 11528621f407SFrançois Tigeot fail: 11538621f407SFrançois Tigeot kfree(state); 11548621f407SFrançois Tigeot kfree(intel_plane); 11558621f407SFrançois Tigeot 1156e3adcf8fSFrançois Tigeot return ret; 1157e3adcf8fSFrançois Tigeot } 1158