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" 39*71f41f3eSFrançois Tigeot #include "intel_frontbuffer.h" 405c6c6f23SFrançois Tigeot #include <drm/i915_drm.h> 41e3adcf8fSFrançois Tigeot #include "i915_drv.h" 42e3adcf8fSFrançois Tigeot 432c9916cdSFrançois Tigeot static bool 442c9916cdSFrançois Tigeot format_is_yuv(uint32_t format) 452c9916cdSFrançois Tigeot { 462c9916cdSFrançois Tigeot switch (format) { 472c9916cdSFrançois Tigeot case DRM_FORMAT_YUYV: 482c9916cdSFrançois Tigeot case DRM_FORMAT_UYVY: 492c9916cdSFrançois Tigeot case DRM_FORMAT_VYUY: 502c9916cdSFrançois Tigeot case DRM_FORMAT_YVYU: 512c9916cdSFrançois Tigeot return true; 522c9916cdSFrançois Tigeot default: 532c9916cdSFrançois Tigeot return false; 542c9916cdSFrançois Tigeot } 552c9916cdSFrançois Tigeot } 562c9916cdSFrançois Tigeot 5787df8fc6SFrançois Tigeot static int usecs_to_scanlines(const struct drm_display_mode *adjusted_mode, 58352ff8bdSFrançois Tigeot int usecs) 59ba55f2f5SFrançois Tigeot { 60ba55f2f5SFrançois Tigeot /* paranoia */ 61352ff8bdSFrançois Tigeot if (!adjusted_mode->crtc_htotal) 62ba55f2f5SFrançois Tigeot return 1; 63ba55f2f5SFrançois Tigeot 64352ff8bdSFrançois Tigeot return DIV_ROUND_UP(usecs * adjusted_mode->crtc_clock, 65352ff8bdSFrançois Tigeot 1000 * adjusted_mode->crtc_htotal); 66ba55f2f5SFrançois Tigeot } 67ba55f2f5SFrançois Tigeot 682c9916cdSFrançois Tigeot /** 692c9916cdSFrançois Tigeot * intel_pipe_update_start() - start update of a set of display registers 702c9916cdSFrançois Tigeot * @crtc: the crtc of which the registers are going to be updated 712c9916cdSFrançois Tigeot * @start_vbl_count: vblank counter return pointer used for error checking 722c9916cdSFrançois Tigeot * 732c9916cdSFrançois Tigeot * Mark the start of an update to pipe registers that should be updated 742c9916cdSFrançois Tigeot * atomically regarding vblank. If the next vblank will happens within 752c9916cdSFrançois Tigeot * the next 100 us, this function waits until the vblank passes. 762c9916cdSFrançois Tigeot * 772c9916cdSFrançois Tigeot * After a successful call to this function, interrupts will be disabled 782c9916cdSFrançois Tigeot * until a subsequent call to intel_pipe_update_end(). That is done to 792c9916cdSFrançois Tigeot * avoid random delays. The value written to @start_vbl_count should be 802c9916cdSFrançois Tigeot * supplied to intel_pipe_update_end() for error checking. 812c9916cdSFrançois Tigeot */ 82352ff8bdSFrançois Tigeot void intel_pipe_update_start(struct intel_crtc *crtc) 83ba55f2f5SFrançois Tigeot { 84352ff8bdSFrançois Tigeot const struct drm_display_mode *adjusted_mode = &crtc->config->base.adjusted_mode; 85ba55f2f5SFrançois Tigeot long timeout = msecs_to_jiffies_timeout(1); 86ba55f2f5SFrançois Tigeot int scanline, min, max, vblank_start; 871b13d190SFrançois Tigeot wait_queue_head_t *wq = drm_crtc_vblank_waitqueue(&crtc->base); 88ba55f2f5SFrançois Tigeot DEFINE_WAIT(wait); 89ba55f2f5SFrançois Tigeot 90352ff8bdSFrançois Tigeot vblank_start = adjusted_mode->crtc_vblank_start; 91352ff8bdSFrançois Tigeot if (adjusted_mode->flags & DRM_MODE_FLAG_INTERLACE) 92ba55f2f5SFrançois Tigeot vblank_start = DIV_ROUND_UP(vblank_start, 2); 93ba55f2f5SFrançois Tigeot 94ba55f2f5SFrançois Tigeot /* FIXME needs to be calibrated sensibly */ 9587df8fc6SFrançois Tigeot min = vblank_start - usecs_to_scanlines(adjusted_mode, 100); 96ba55f2f5SFrançois Tigeot max = vblank_start - 1; 97ba55f2f5SFrançois Tigeot 98a05eeebfSFrançois Tigeot local_irq_disable(); 99a05eeebfSFrançois Tigeot 100ba55f2f5SFrançois Tigeot if (min <= 0 || max <= 0) 101a05eeebfSFrançois Tigeot return; 102ba55f2f5SFrançois Tigeot 103477eb7f9SFrançois Tigeot if (WARN_ON(drm_crtc_vblank_get(&crtc->base))) 104a05eeebfSFrançois Tigeot return; 105ba55f2f5SFrançois Tigeot 106352ff8bdSFrançois Tigeot crtc->debug.min_vbl = min; 107352ff8bdSFrançois Tigeot crtc->debug.max_vbl = max; 108352ff8bdSFrançois Tigeot trace_i915_pipe_update_start(crtc); 109ba55f2f5SFrançois Tigeot 110ba55f2f5SFrançois Tigeot for (;;) { 111ba55f2f5SFrançois Tigeot /* 112ba55f2f5SFrançois Tigeot * prepare_to_wait() has a memory barrier, which guarantees 113ba55f2f5SFrançois Tigeot * other CPUs can see the task state update by the time we 114ba55f2f5SFrançois Tigeot * read the scanline. 115ba55f2f5SFrançois Tigeot */ 1161b13d190SFrançois Tigeot prepare_to_wait(wq, &wait, TASK_UNINTERRUPTIBLE); 117ba55f2f5SFrançois Tigeot 118ba55f2f5SFrançois Tigeot scanline = intel_get_crtc_scanline(crtc); 119ba55f2f5SFrançois Tigeot if (scanline < min || scanline > max) 120ba55f2f5SFrançois Tigeot break; 121ba55f2f5SFrançois Tigeot 122ba55f2f5SFrançois Tigeot if (timeout <= 0) { 123ba55f2f5SFrançois Tigeot DRM_ERROR("Potential atomic update failure on pipe %c\n", 124ba55f2f5SFrançois Tigeot pipe_name(crtc->pipe)); 125ba55f2f5SFrançois Tigeot break; 126ba55f2f5SFrançois Tigeot } 127ba55f2f5SFrançois Tigeot 128ba55f2f5SFrançois Tigeot local_irq_enable(); 129ba55f2f5SFrançois Tigeot 130ba55f2f5SFrançois Tigeot timeout = schedule_timeout(timeout); 131ba55f2f5SFrançois Tigeot 132ba55f2f5SFrançois Tigeot local_irq_disable(); 133ba55f2f5SFrançois Tigeot } 134ba55f2f5SFrançois Tigeot 1351b13d190SFrançois Tigeot finish_wait(wq, &wait); 136ba55f2f5SFrançois Tigeot 137477eb7f9SFrançois Tigeot drm_crtc_vblank_put(&crtc->base); 138ba55f2f5SFrançois Tigeot 139352ff8bdSFrançois Tigeot crtc->debug.scanline_start = scanline; 140352ff8bdSFrançois Tigeot crtc->debug.start_vbl_time = ktime_get(); 1411487f786SFrançois Tigeot crtc->debug.start_vbl_count = intel_crtc_get_vblank_counter(crtc); 142ba55f2f5SFrançois Tigeot 143352ff8bdSFrançois Tigeot trace_i915_pipe_update_vblank_evaded(crtc); 144ba55f2f5SFrançois Tigeot } 145ba55f2f5SFrançois Tigeot 1462c9916cdSFrançois Tigeot /** 1472c9916cdSFrançois Tigeot * intel_pipe_update_end() - end update of a set of display registers 1482c9916cdSFrançois Tigeot * @crtc: the crtc of which the registers were updated 1492c9916cdSFrançois Tigeot * @start_vbl_count: start vblank counter (used for error checking) 1502c9916cdSFrançois Tigeot * 1512c9916cdSFrançois Tigeot * Mark the end of an update started with intel_pipe_update_start(). This 1522c9916cdSFrançois Tigeot * re-enables interrupts and verifies the update was actually completed 1532c9916cdSFrançois Tigeot * before a vblank using the value of @start_vbl_count. 1542c9916cdSFrançois Tigeot */ 1551487f786SFrançois Tigeot void intel_pipe_update_end(struct intel_crtc *crtc, struct intel_flip_work *work) 156ba55f2f5SFrançois Tigeot { 157ba55f2f5SFrançois Tigeot enum i915_pipe pipe = crtc->pipe; 158352ff8bdSFrançois Tigeot int scanline_end = intel_get_crtc_scanline(crtc); 1591487f786SFrançois Tigeot u32 end_vbl_count = intel_crtc_get_vblank_counter(crtc); 160352ff8bdSFrançois Tigeot ktime_t end_vbl_time = ktime_get(); 161ba55f2f5SFrançois Tigeot 1621487f786SFrançois Tigeot if (work) { 1631487f786SFrançois Tigeot work->flip_queued_vblank = end_vbl_count; 1641487f786SFrançois Tigeot smp_mb__before_atomic(); 1651487f786SFrançois Tigeot atomic_set(&work->pending, 1); 1661487f786SFrançois Tigeot } 1671487f786SFrançois Tigeot 168352ff8bdSFrançois Tigeot trace_i915_pipe_update_end(crtc, end_vbl_count, scanline_end); 169ba55f2f5SFrançois Tigeot 1701487f786SFrançois Tigeot /* We're still in the vblank-evade critical section, this can't race. 1711487f786SFrançois Tigeot * Would be slightly nice to just grab the vblank count and arm the 1721487f786SFrançois Tigeot * event outside of the critical section - the spinlock might spin for a 1731487f786SFrançois Tigeot * while ... */ 1741487f786SFrançois Tigeot if (crtc->base.state->event) { 1751487f786SFrançois Tigeot WARN_ON(drm_crtc_vblank_get(&crtc->base) != 0); 1761487f786SFrançois Tigeot 1771487f786SFrançois Tigeot lockmgr(&crtc->base.dev->event_lock, LK_EXCLUSIVE); 1781487f786SFrançois Tigeot drm_crtc_arm_vblank_event(&crtc->base, crtc->base.state->event); 1791487f786SFrançois Tigeot lockmgr(&crtc->base.dev->event_lock, LK_RELEASE); 1801487f786SFrançois Tigeot 1811487f786SFrançois Tigeot crtc->base.state->event = NULL; 1821487f786SFrançois Tigeot } 1831487f786SFrançois Tigeot 184ba55f2f5SFrançois Tigeot local_irq_enable(); 185ba55f2f5SFrançois Tigeot 186352ff8bdSFrançois Tigeot if (crtc->debug.start_vbl_count && 187352ff8bdSFrançois Tigeot crtc->debug.start_vbl_count != end_vbl_count) { 188352ff8bdSFranç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", 189352ff8bdSFrançois Tigeot pipe_name(pipe), crtc->debug.start_vbl_count, 190352ff8bdSFrançois Tigeot end_vbl_count, 191352ff8bdSFrançois Tigeot ktime_us_delta(end_vbl_time, crtc->debug.start_vbl_time), 192352ff8bdSFrançois Tigeot crtc->debug.min_vbl, crtc->debug.max_vbl, 193352ff8bdSFrançois Tigeot crtc->debug.scanline_start, scanline_end); 194352ff8bdSFrançois Tigeot } 195ba55f2f5SFrançois Tigeot } 196ba55f2f5SFrançois Tigeot 197e3adcf8fSFrançois Tigeot static void 198c0e85e96SFrançois Tigeot skl_update_plane(struct drm_plane *drm_plane, 199c0e85e96SFrançois Tigeot const struct intel_crtc_state *crtc_state, 200c0e85e96SFrançois Tigeot const struct intel_plane_state *plane_state) 2012c9916cdSFrançois Tigeot { 2022c9916cdSFrançois Tigeot struct drm_device *dev = drm_plane->dev; 203bf017597SFrançois Tigeot struct drm_i915_private *dev_priv = to_i915(dev); 2042c9916cdSFrançois Tigeot struct intel_plane *intel_plane = to_intel_plane(drm_plane); 205c0e85e96SFrançois Tigeot struct drm_framebuffer *fb = plane_state->base.fb; 206477eb7f9SFrançois Tigeot struct drm_i915_gem_object *obj = intel_fb_obj(fb); 2072c9916cdSFrançois Tigeot const int pipe = intel_plane->pipe; 2082c9916cdSFrançois Tigeot const int plane = intel_plane->plane + 1; 20919c468b4SFrançois Tigeot u32 plane_ctl, stride_div, stride; 210c0e85e96SFrançois Tigeot const struct drm_intel_sprite_colorkey *key = &plane_state->ckey; 211aee94f86SFrançois Tigeot u32 surf_addr; 21219c468b4SFrançois Tigeot u32 tile_height, plane_offset, plane_size; 2138621f407SFrançois Tigeot unsigned int rotation = plane_state->base.rotation; 21419c468b4SFrançois Tigeot int x_offset, y_offset; 215c0e85e96SFrançois Tigeot int crtc_x = plane_state->dst.x1; 216c0e85e96SFrançois Tigeot int crtc_y = plane_state->dst.y1; 217c0e85e96SFrançois Tigeot uint32_t crtc_w = drm_rect_width(&plane_state->dst); 218c0e85e96SFrançois Tigeot uint32_t crtc_h = drm_rect_height(&plane_state->dst); 219c0e85e96SFrançois Tigeot uint32_t x = plane_state->src.x1 >> 16; 220c0e85e96SFrançois Tigeot uint32_t y = plane_state->src.y1 >> 16; 221c0e85e96SFrançois Tigeot uint32_t src_w = drm_rect_width(&plane_state->src) >> 16; 222c0e85e96SFrançois Tigeot uint32_t src_h = drm_rect_height(&plane_state->src) >> 16; 2232c9916cdSFrançois Tigeot 224477eb7f9SFrançois Tigeot plane_ctl = PLANE_CTL_ENABLE | 225352ff8bdSFrançois Tigeot PLANE_CTL_PIPE_GAMMA_ENABLE | 226477eb7f9SFrançois Tigeot PLANE_CTL_PIPE_CSC_ENABLE; 2272c9916cdSFrançois Tigeot 22819c468b4SFrançois Tigeot plane_ctl |= skl_plane_ctl_format(fb->pixel_format); 22919c468b4SFrançois Tigeot plane_ctl |= skl_plane_ctl_tiling(fb->modifier[0]); 2302c9916cdSFrançois Tigeot 23119c468b4SFrançois Tigeot plane_ctl |= skl_plane_ctl_rotation(rotation); 2322c9916cdSFrançois Tigeot 233c0e85e96SFrançois Tigeot stride_div = intel_fb_stride_alignment(dev_priv, fb->modifier[0], 234477eb7f9SFrançois Tigeot fb->pixel_format); 235477eb7f9SFrançois Tigeot 2362c9916cdSFrançois Tigeot /* Sizes are 0 based */ 2372c9916cdSFrançois Tigeot src_w--; 2382c9916cdSFrançois Tigeot src_h--; 2392c9916cdSFrançois Tigeot crtc_w--; 2402c9916cdSFrançois Tigeot crtc_h--; 2412c9916cdSFrançois Tigeot 242477eb7f9SFrançois Tigeot if (key->flags) { 243477eb7f9SFrançois Tigeot I915_WRITE(PLANE_KEYVAL(pipe, plane), key->min_value); 244477eb7f9SFrançois Tigeot I915_WRITE(PLANE_KEYMAX(pipe, plane), key->max_value); 245477eb7f9SFrançois Tigeot I915_WRITE(PLANE_KEYMSK(pipe, plane), key->channel_mask); 246477eb7f9SFrançois Tigeot } 247477eb7f9SFrançois Tigeot 248477eb7f9SFrançois Tigeot if (key->flags & I915_SET_COLORKEY_DESTINATION) 249477eb7f9SFrançois Tigeot plane_ctl |= PLANE_CTL_KEY_ENABLE_DESTINATION; 250477eb7f9SFrançois Tigeot else if (key->flags & I915_SET_COLORKEY_SOURCE) 251477eb7f9SFrançois Tigeot plane_ctl |= PLANE_CTL_KEY_ENABLE_SOURCE; 252477eb7f9SFrançois Tigeot 253352ff8bdSFrançois Tigeot surf_addr = intel_plane_obj_offset(intel_plane, obj, 0); 254477eb7f9SFrançois Tigeot 25519c468b4SFrançois Tigeot if (intel_rotation_90_or_270(rotation)) { 256c0e85e96SFrançois Tigeot int cpp = drm_format_plane_cpp(fb->pixel_format, 0); 257c0e85e96SFrançois Tigeot 25819c468b4SFrançois Tigeot /* stride: Surface height in tiles */ 259c0e85e96SFrançois Tigeot tile_height = intel_tile_height(dev_priv, fb->modifier[0], cpp); 26019c468b4SFrançois Tigeot stride = DIV_ROUND_UP(fb->height, tile_height); 26119c468b4SFrançois Tigeot plane_size = (src_w << 16) | src_h; 26219c468b4SFrançois Tigeot x_offset = stride * tile_height - y - (src_h + 1); 26319c468b4SFrançois Tigeot y_offset = x; 26419c468b4SFrançois Tigeot } else { 26519c468b4SFrançois Tigeot stride = fb->pitches[0] / stride_div; 26619c468b4SFrançois Tigeot plane_size = (src_h << 16) | src_w; 26719c468b4SFrançois Tigeot x_offset = x; 26819c468b4SFrançois Tigeot y_offset = y; 26919c468b4SFrançois Tigeot } 27019c468b4SFrançois Tigeot plane_offset = y_offset << 16 | x_offset; 27119c468b4SFrançois Tigeot 27219c468b4SFrançois Tigeot I915_WRITE(PLANE_OFFSET(pipe, plane), plane_offset); 27319c468b4SFrançois Tigeot I915_WRITE(PLANE_STRIDE(pipe, plane), stride); 27419c468b4SFrançois Tigeot I915_WRITE(PLANE_SIZE(pipe, plane), plane_size); 27519c468b4SFrançois Tigeot 27619c468b4SFrançois Tigeot /* program plane scaler */ 277c0e85e96SFrançois Tigeot if (plane_state->scaler_id >= 0) { 278c0e85e96SFrançois Tigeot int scaler_id = plane_state->scaler_id; 2791487f786SFrançois Tigeot const struct intel_scaler *scaler; 28019c468b4SFrançois Tigeot 28119c468b4SFrançois Tigeot DRM_DEBUG_KMS("plane = %d PS_PLANE_SEL(plane) = 0x%x\n", plane, 28219c468b4SFrançois Tigeot PS_PLANE_SEL(plane)); 2831487f786SFrançois Tigeot 2841487f786SFrançois Tigeot scaler = &crtc_state->scaler_state.scalers[scaler_id]; 2851487f786SFrançois Tigeot 2861487f786SFrançois Tigeot I915_WRITE(SKL_PS_CTRL(pipe, scaler_id), 2871487f786SFrançois Tigeot PS_SCALER_EN | PS_PLANE_SEL(plane) | scaler->mode); 28819c468b4SFrançois Tigeot I915_WRITE(SKL_PS_PWR_GATE(pipe, scaler_id), 0); 28919c468b4SFrançois Tigeot I915_WRITE(SKL_PS_WIN_POS(pipe, scaler_id), (crtc_x << 16) | crtc_y); 29019c468b4SFrançois Tigeot I915_WRITE(SKL_PS_WIN_SZ(pipe, scaler_id), 29119c468b4SFrançois Tigeot ((crtc_w + 1) << 16)|(crtc_h + 1)); 29219c468b4SFrançois Tigeot 29319c468b4SFrançois Tigeot I915_WRITE(PLANE_POS(pipe, plane), 0); 29419c468b4SFrançois Tigeot } else { 2952c9916cdSFrançois Tigeot I915_WRITE(PLANE_POS(pipe, plane), (crtc_y << 16) | crtc_x); 29619c468b4SFrançois Tigeot } 29719c468b4SFrançois Tigeot 2982c9916cdSFrançois Tigeot I915_WRITE(PLANE_CTL(pipe, plane), plane_ctl); 299477eb7f9SFrançois Tigeot I915_WRITE(PLANE_SURF(pipe, plane), surf_addr); 3002c9916cdSFrançois Tigeot POSTING_READ(PLANE_SURF(pipe, plane)); 3012c9916cdSFrançois Tigeot } 3022c9916cdSFrançois Tigeot 3032c9916cdSFrançois Tigeot static void 304a05eeebfSFrançois Tigeot skl_disable_plane(struct drm_plane *dplane, struct drm_crtc *crtc) 3052c9916cdSFrançois Tigeot { 30619c468b4SFrançois Tigeot struct drm_device *dev = dplane->dev; 307bf017597SFrançois Tigeot struct drm_i915_private *dev_priv = to_i915(dev); 30819c468b4SFrançois Tigeot struct intel_plane *intel_plane = to_intel_plane(dplane); 3092c9916cdSFrançois Tigeot const int pipe = intel_plane->pipe; 3102c9916cdSFrançois Tigeot const int plane = intel_plane->plane + 1; 3112c9916cdSFrançois Tigeot 312477eb7f9SFrançois Tigeot I915_WRITE(PLANE_CTL(pipe, plane), 0); 3132c9916cdSFrançois Tigeot 314477eb7f9SFrançois Tigeot I915_WRITE(PLANE_SURF(pipe, plane), 0); 315477eb7f9SFrançois Tigeot POSTING_READ(PLANE_SURF(pipe, plane)); 3162c9916cdSFrançois Tigeot } 3172c9916cdSFrançois Tigeot 3182c9916cdSFrançois Tigeot static void 3192c9916cdSFrançois Tigeot chv_update_csc(struct intel_plane *intel_plane, uint32_t format) 3202c9916cdSFrançois Tigeot { 321bf017597SFrançois Tigeot struct drm_i915_private *dev_priv = to_i915(intel_plane->base.dev); 3222c9916cdSFrançois Tigeot int plane = intel_plane->plane; 3232c9916cdSFrançois Tigeot 3242c9916cdSFrançois Tigeot /* Seems RGB data bypasses the CSC always */ 3252c9916cdSFrançois Tigeot if (!format_is_yuv(format)) 3262c9916cdSFrançois Tigeot return; 3272c9916cdSFrançois Tigeot 3282c9916cdSFrançois Tigeot /* 3292c9916cdSFrançois Tigeot * BT.601 limited range YCbCr -> full range RGB 3302c9916cdSFrançois Tigeot * 3312c9916cdSFrançois Tigeot * |r| | 6537 4769 0| |cr | 3322c9916cdSFrançois Tigeot * |g| = |-3330 4769 -1605| x |y-64| 3332c9916cdSFrançois Tigeot * |b| | 0 4769 8263| |cb | 3342c9916cdSFrançois Tigeot * 3352c9916cdSFrançois Tigeot * Cb and Cr apparently come in as signed already, so no 3362c9916cdSFrançois Tigeot * need for any offset. For Y we need to remove the offset. 3372c9916cdSFrançois Tigeot */ 3382c9916cdSFrançois Tigeot I915_WRITE(SPCSCYGOFF(plane), SPCSC_OOFF(0) | SPCSC_IOFF(-64)); 3392c9916cdSFrançois Tigeot I915_WRITE(SPCSCCBOFF(plane), SPCSC_OOFF(0) | SPCSC_IOFF(0)); 3402c9916cdSFrançois Tigeot I915_WRITE(SPCSCCROFF(plane), SPCSC_OOFF(0) | SPCSC_IOFF(0)); 3412c9916cdSFrançois Tigeot 3422c9916cdSFrançois Tigeot I915_WRITE(SPCSCC01(plane), SPCSC_C1(4769) | SPCSC_C0(6537)); 3432c9916cdSFrançois Tigeot I915_WRITE(SPCSCC23(plane), SPCSC_C1(-3330) | SPCSC_C0(0)); 3442c9916cdSFrançois Tigeot I915_WRITE(SPCSCC45(plane), SPCSC_C1(-1605) | SPCSC_C0(4769)); 3452c9916cdSFrançois Tigeot I915_WRITE(SPCSCC67(plane), SPCSC_C1(4769) | SPCSC_C0(0)); 3462c9916cdSFrançois Tigeot I915_WRITE(SPCSCC8(plane), SPCSC_C0(8263)); 3472c9916cdSFrançois Tigeot 3482c9916cdSFrançois Tigeot I915_WRITE(SPCSCYGICLAMP(plane), SPCSC_IMAX(940) | SPCSC_IMIN(64)); 3492c9916cdSFrançois Tigeot I915_WRITE(SPCSCCBICLAMP(plane), SPCSC_IMAX(448) | SPCSC_IMIN(-448)); 3502c9916cdSFrançois Tigeot I915_WRITE(SPCSCCRICLAMP(plane), SPCSC_IMAX(448) | SPCSC_IMIN(-448)); 3512c9916cdSFrançois Tigeot 3522c9916cdSFrançois Tigeot I915_WRITE(SPCSCYGOCLAMP(plane), SPCSC_OMAX(1023) | SPCSC_OMIN(0)); 3532c9916cdSFrançois Tigeot I915_WRITE(SPCSCCBOCLAMP(plane), SPCSC_OMAX(1023) | SPCSC_OMIN(0)); 3542c9916cdSFrançois Tigeot I915_WRITE(SPCSCCROCLAMP(plane), SPCSC_OMAX(1023) | SPCSC_OMIN(0)); 3552c9916cdSFrançois Tigeot } 3562c9916cdSFrançois Tigeot 3572c9916cdSFrançois Tigeot static void 358c0e85e96SFrançois Tigeot vlv_update_plane(struct drm_plane *dplane, 359c0e85e96SFrançois Tigeot const struct intel_crtc_state *crtc_state, 360c0e85e96SFrançois Tigeot const struct intel_plane_state *plane_state) 3618e26cdf6SFrançois Tigeot { 3628e26cdf6SFrançois Tigeot struct drm_device *dev = dplane->dev; 363bf017597SFrançois Tigeot struct drm_i915_private *dev_priv = to_i915(dev); 3648e26cdf6SFrançois Tigeot struct intel_plane *intel_plane = to_intel_plane(dplane); 365c0e85e96SFrançois Tigeot struct drm_framebuffer *fb = plane_state->base.fb; 366477eb7f9SFrançois Tigeot struct drm_i915_gem_object *obj = intel_fb_obj(fb); 3678e26cdf6SFrançois Tigeot int pipe = intel_plane->pipe; 3688e26cdf6SFrançois Tigeot int plane = intel_plane->plane; 3698e26cdf6SFrançois Tigeot u32 sprctl; 370c0e85e96SFrançois Tigeot u32 sprsurf_offset, linear_offset; 3718621f407SFrançois Tigeot unsigned int rotation = dplane->state->rotation; 372c0e85e96SFrançois Tigeot int cpp = drm_format_plane_cpp(fb->pixel_format, 0); 373c0e85e96SFrançois Tigeot const struct drm_intel_sprite_colorkey *key = &plane_state->ckey; 374c0e85e96SFrançois Tigeot int crtc_x = plane_state->dst.x1; 375c0e85e96SFrançois Tigeot int crtc_y = plane_state->dst.y1; 376c0e85e96SFrançois Tigeot uint32_t crtc_w = drm_rect_width(&plane_state->dst); 377c0e85e96SFrançois Tigeot uint32_t crtc_h = drm_rect_height(&plane_state->dst); 378c0e85e96SFrançois Tigeot uint32_t x = plane_state->src.x1 >> 16; 379c0e85e96SFrançois Tigeot uint32_t y = plane_state->src.y1 >> 16; 380c0e85e96SFrançois Tigeot uint32_t src_w = drm_rect_width(&plane_state->src) >> 16; 381c0e85e96SFrançois Tigeot uint32_t src_h = drm_rect_height(&plane_state->src) >> 16; 3828e26cdf6SFrançois Tigeot 383477eb7f9SFrançois Tigeot sprctl = SP_ENABLE; 3848e26cdf6SFrançois Tigeot 3858e26cdf6SFrançois Tigeot switch (fb->pixel_format) { 3868e26cdf6SFrançois Tigeot case DRM_FORMAT_YUYV: 3878e26cdf6SFrançois Tigeot sprctl |= SP_FORMAT_YUV422 | SP_YUV_ORDER_YUYV; 3888e26cdf6SFrançois Tigeot break; 3898e26cdf6SFrançois Tigeot case DRM_FORMAT_YVYU: 3908e26cdf6SFrançois Tigeot sprctl |= SP_FORMAT_YUV422 | SP_YUV_ORDER_YVYU; 3918e26cdf6SFrançois Tigeot break; 3928e26cdf6SFrançois Tigeot case DRM_FORMAT_UYVY: 3938e26cdf6SFrançois Tigeot sprctl |= SP_FORMAT_YUV422 | SP_YUV_ORDER_UYVY; 3948e26cdf6SFrançois Tigeot break; 3958e26cdf6SFrançois Tigeot case DRM_FORMAT_VYUY: 3968e26cdf6SFrançois Tigeot sprctl |= SP_FORMAT_YUV422 | SP_YUV_ORDER_VYUY; 3978e26cdf6SFrançois Tigeot break; 3988e26cdf6SFrançois Tigeot case DRM_FORMAT_RGB565: 3998e26cdf6SFrançois Tigeot sprctl |= SP_FORMAT_BGR565; 4008e26cdf6SFrançois Tigeot break; 4018e26cdf6SFrançois Tigeot case DRM_FORMAT_XRGB8888: 4028e26cdf6SFrançois Tigeot sprctl |= SP_FORMAT_BGRX8888; 4038e26cdf6SFrançois Tigeot break; 4048e26cdf6SFrançois Tigeot case DRM_FORMAT_ARGB8888: 4058e26cdf6SFrançois Tigeot sprctl |= SP_FORMAT_BGRA8888; 4068e26cdf6SFrançois Tigeot break; 4078e26cdf6SFrançois Tigeot case DRM_FORMAT_XBGR2101010: 4088e26cdf6SFrançois Tigeot sprctl |= SP_FORMAT_RGBX1010102; 4098e26cdf6SFrançois Tigeot break; 4108e26cdf6SFrançois Tigeot case DRM_FORMAT_ABGR2101010: 4118e26cdf6SFrançois Tigeot sprctl |= SP_FORMAT_RGBA1010102; 4128e26cdf6SFrançois Tigeot break; 4138e26cdf6SFrançois Tigeot case DRM_FORMAT_XBGR8888: 4148e26cdf6SFrançois Tigeot sprctl |= SP_FORMAT_RGBX8888; 4158e26cdf6SFrançois Tigeot break; 4168e26cdf6SFrançois Tigeot case DRM_FORMAT_ABGR8888: 4178e26cdf6SFrançois Tigeot sprctl |= SP_FORMAT_RGBA8888; 4188e26cdf6SFrançois Tigeot break; 4198e26cdf6SFrançois Tigeot default: 4208e26cdf6SFrançois Tigeot /* 4218e26cdf6SFrançois Tigeot * If we get here one of the upper layers failed to filter 4228e26cdf6SFrançois Tigeot * out the unsupported plane formats 4238e26cdf6SFrançois Tigeot */ 4248e26cdf6SFrançois Tigeot BUG(); 4258e26cdf6SFrançois Tigeot break; 4268e26cdf6SFrançois Tigeot } 4278e26cdf6SFrançois Tigeot 4289edbd4a0SFrançois Tigeot /* 4299edbd4a0SFrançois Tigeot * Enable gamma to match primary/cursor plane behaviour. 4309edbd4a0SFrançois Tigeot * FIXME should be user controllable via propertiesa. 4319edbd4a0SFrançois Tigeot */ 4329edbd4a0SFrançois Tigeot sprctl |= SP_GAMMA_ENABLE; 4339edbd4a0SFrançois Tigeot 434*71f41f3eSFrançois Tigeot if (i915_gem_object_is_tiled(obj)) 4358e26cdf6SFrançois Tigeot sprctl |= SP_TILED; 4368e26cdf6SFrançois Tigeot 4378e26cdf6SFrançois Tigeot /* Sizes are 0 based */ 4388e26cdf6SFrançois Tigeot src_w--; 4398e26cdf6SFrançois Tigeot src_h--; 4408e26cdf6SFrançois Tigeot crtc_w--; 4418e26cdf6SFrançois Tigeot crtc_h--; 4428e26cdf6SFrançois Tigeot 443c0e85e96SFrançois Tigeot linear_offset = y * fb->pitches[0] + x * cpp; 4448621f407SFrançois Tigeot sprsurf_offset = intel_compute_tile_offset(&x, &y, fb, 0, 4458621f407SFrançois Tigeot fb->pitches[0], rotation); 4468e26cdf6SFrançois Tigeot linear_offset -= sprsurf_offset; 4478e26cdf6SFrançois Tigeot 44887df8fc6SFrançois Tigeot if (rotation == BIT(DRM_ROTATE_180)) { 4491b13d190SFrançois Tigeot sprctl |= SP_ROTATE_180; 4501b13d190SFrançois Tigeot 4511b13d190SFrançois Tigeot x += src_w; 4521b13d190SFrançois Tigeot y += src_h; 453c0e85e96SFrançois Tigeot linear_offset += src_h * fb->pitches[0] + src_w * cpp; 4541b13d190SFrançois Tigeot } 4551b13d190SFrançois Tigeot 456477eb7f9SFrançois Tigeot if (key->flags) { 457477eb7f9SFrançois Tigeot I915_WRITE(SPKEYMINVAL(pipe, plane), key->min_value); 458477eb7f9SFrançois Tigeot I915_WRITE(SPKEYMAXVAL(pipe, plane), key->max_value); 459477eb7f9SFrançois Tigeot I915_WRITE(SPKEYMSK(pipe, plane), key->channel_mask); 460477eb7f9SFrançois Tigeot } 461477eb7f9SFrançois Tigeot 462477eb7f9SFrançois Tigeot if (key->flags & I915_SET_COLORKEY_SOURCE) 463477eb7f9SFrançois Tigeot sprctl |= SP_SOURCE_KEY; 464477eb7f9SFrançois Tigeot 4652c9916cdSFrançois Tigeot if (IS_CHERRYVIEW(dev) && pipe == PIPE_B) 4662c9916cdSFrançois Tigeot chv_update_csc(intel_plane, fb->pixel_format); 4672c9916cdSFrançois Tigeot 468ba55f2f5SFrançois Tigeot I915_WRITE(SPSTRIDE(pipe, plane), fb->pitches[0]); 469ba55f2f5SFrançois Tigeot I915_WRITE(SPPOS(pipe, plane), (crtc_y << 16) | crtc_x); 470ba55f2f5SFrançois Tigeot 471*71f41f3eSFrançois Tigeot if (i915_gem_object_is_tiled(obj)) 4728e26cdf6SFrançois Tigeot I915_WRITE(SPTILEOFF(pipe, plane), (y << 16) | x); 4738e26cdf6SFrançois Tigeot else 4748e26cdf6SFrançois Tigeot I915_WRITE(SPLINOFF(pipe, plane), linear_offset); 4758e26cdf6SFrançois Tigeot 4762c9916cdSFrançois Tigeot I915_WRITE(SPCONSTALPHA(pipe, plane), 0); 4772c9916cdSFrançois Tigeot 4788e26cdf6SFrançois Tigeot I915_WRITE(SPSIZE(pipe, plane), (crtc_h << 16) | crtc_w); 4798e26cdf6SFrançois Tigeot I915_WRITE(SPCNTR(pipe, plane), sprctl); 4809edbd4a0SFrançois Tigeot I915_WRITE(SPSURF(pipe, plane), i915_gem_obj_ggtt_offset(obj) + 4818e26cdf6SFrançois Tigeot sprsurf_offset); 48219c468b4SFrançois Tigeot POSTING_READ(SPSURF(pipe, plane)); 4838e26cdf6SFrançois Tigeot } 4848e26cdf6SFrançois Tigeot 4858e26cdf6SFrançois Tigeot static void 486a05eeebfSFrançois Tigeot vlv_disable_plane(struct drm_plane *dplane, struct drm_crtc *crtc) 4878e26cdf6SFrançois Tigeot { 4888e26cdf6SFrançois Tigeot struct drm_device *dev = dplane->dev; 489bf017597SFrançois Tigeot struct drm_i915_private *dev_priv = to_i915(dev); 4908e26cdf6SFrançois Tigeot struct intel_plane *intel_plane = to_intel_plane(dplane); 4918e26cdf6SFrançois Tigeot int pipe = intel_plane->pipe; 4928e26cdf6SFrançois Tigeot int plane = intel_plane->plane; 493ba55f2f5SFrançois Tigeot 494477eb7f9SFrançois Tigeot I915_WRITE(SPCNTR(pipe, plane), 0); 495477eb7f9SFrançois Tigeot 4969edbd4a0SFrançois Tigeot I915_WRITE(SPSURF(pipe, plane), 0); 49719c468b4SFrançois Tigeot POSTING_READ(SPSURF(pipe, plane)); 4988e26cdf6SFrançois Tigeot } 4998e26cdf6SFrançois Tigeot 5008e26cdf6SFrançois Tigeot static void 501c0e85e96SFrançois Tigeot ivb_update_plane(struct drm_plane *plane, 502c0e85e96SFrançois Tigeot const struct intel_crtc_state *crtc_state, 503c0e85e96SFrançois Tigeot const struct intel_plane_state *plane_state) 504e3adcf8fSFrançois Tigeot { 505e3adcf8fSFrançois Tigeot struct drm_device *dev = plane->dev; 506bf017597SFrançois Tigeot struct drm_i915_private *dev_priv = to_i915(dev); 507e3adcf8fSFrançois Tigeot struct intel_plane *intel_plane = to_intel_plane(plane); 508c0e85e96SFrançois Tigeot struct drm_framebuffer *fb = plane_state->base.fb; 509477eb7f9SFrançois Tigeot struct drm_i915_gem_object *obj = intel_fb_obj(fb); 510477eb7f9SFrançois Tigeot enum i915_pipe pipe = intel_plane->pipe; 511e3adcf8fSFrançois Tigeot u32 sprctl, sprscale = 0; 512c0e85e96SFrançois Tigeot u32 sprsurf_offset, linear_offset; 5138621f407SFrançois Tigeot unsigned int rotation = plane_state->base.rotation; 514c0e85e96SFrançois Tigeot int cpp = drm_format_plane_cpp(fb->pixel_format, 0); 515c0e85e96SFrançois Tigeot const struct drm_intel_sprite_colorkey *key = &plane_state->ckey; 516c0e85e96SFrançois Tigeot int crtc_x = plane_state->dst.x1; 517c0e85e96SFrançois Tigeot int crtc_y = plane_state->dst.y1; 518c0e85e96SFrançois Tigeot uint32_t crtc_w = drm_rect_width(&plane_state->dst); 519c0e85e96SFrançois Tigeot uint32_t crtc_h = drm_rect_height(&plane_state->dst); 520c0e85e96SFrançois Tigeot uint32_t x = plane_state->src.x1 >> 16; 521c0e85e96SFrançois Tigeot uint32_t y = plane_state->src.y1 >> 16; 522c0e85e96SFrançois Tigeot uint32_t src_w = drm_rect_width(&plane_state->src) >> 16; 523c0e85e96SFrançois Tigeot uint32_t src_h = drm_rect_height(&plane_state->src) >> 16; 524e3adcf8fSFrançois Tigeot 525477eb7f9SFrançois Tigeot sprctl = SPRITE_ENABLE; 526e3adcf8fSFrançois Tigeot 527e3adcf8fSFrançois Tigeot switch (fb->pixel_format) { 528e3adcf8fSFrançois Tigeot case DRM_FORMAT_XBGR8888: 5292c84b0b6SFrançois Tigeot sprctl |= SPRITE_FORMAT_RGBX888 | SPRITE_RGB_ORDER_RGBX; 530e3adcf8fSFrançois Tigeot break; 531e3adcf8fSFrançois Tigeot case DRM_FORMAT_XRGB8888: 5322c84b0b6SFrançois Tigeot sprctl |= SPRITE_FORMAT_RGBX888; 533e3adcf8fSFrançois Tigeot break; 534e3adcf8fSFrançois Tigeot case DRM_FORMAT_YUYV: 535e3adcf8fSFrançois Tigeot sprctl |= SPRITE_FORMAT_YUV422 | SPRITE_YUV_ORDER_YUYV; 536e3adcf8fSFrançois Tigeot break; 537e3adcf8fSFrançois Tigeot case DRM_FORMAT_YVYU: 538e3adcf8fSFrançois Tigeot sprctl |= SPRITE_FORMAT_YUV422 | SPRITE_YUV_ORDER_YVYU; 539e3adcf8fSFrançois Tigeot break; 540e3adcf8fSFrançois Tigeot case DRM_FORMAT_UYVY: 541e3adcf8fSFrançois Tigeot sprctl |= SPRITE_FORMAT_YUV422 | SPRITE_YUV_ORDER_UYVY; 542e3adcf8fSFrançois Tigeot break; 543e3adcf8fSFrançois Tigeot case DRM_FORMAT_VYUY: 544e3adcf8fSFrançois Tigeot sprctl |= SPRITE_FORMAT_YUV422 | SPRITE_YUV_ORDER_VYUY; 545e3adcf8fSFrançois Tigeot break; 546e3adcf8fSFrançois Tigeot default: 5472c84b0b6SFrançois Tigeot BUG(); 548e3adcf8fSFrançois Tigeot } 549e3adcf8fSFrançois Tigeot 5509edbd4a0SFrançois Tigeot /* 5519edbd4a0SFrançois Tigeot * Enable gamma to match primary/cursor plane behaviour. 5529edbd4a0SFrançois Tigeot * FIXME should be user controllable via propertiesa. 5539edbd4a0SFrançois Tigeot */ 5549edbd4a0SFrançois Tigeot sprctl |= SPRITE_GAMMA_ENABLE; 5559edbd4a0SFrançois Tigeot 556*71f41f3eSFrançois Tigeot if (i915_gem_object_is_tiled(obj)) 557e3adcf8fSFrançois Tigeot sprctl |= SPRITE_TILED; 558e3adcf8fSFrançois Tigeot 5599edbd4a0SFrançois Tigeot if (IS_HASWELL(dev) || IS_BROADWELL(dev)) 5609edbd4a0SFrançois Tigeot sprctl &= ~SPRITE_TRICKLE_FEED_DISABLE; 5619edbd4a0SFrançois Tigeot else 562e3adcf8fSFrançois Tigeot sprctl |= SPRITE_TRICKLE_FEED_DISABLE; 5639edbd4a0SFrançois Tigeot 5649edbd4a0SFrançois Tigeot if (IS_HASWELL(dev) || IS_BROADWELL(dev)) 565a2fdbec6SFrançois Tigeot sprctl |= SPRITE_PIPE_CSC_ENABLE; 566a2fdbec6SFrançois Tigeot 567e3adcf8fSFrançois Tigeot /* Sizes are 0 based */ 568e3adcf8fSFrançois Tigeot src_w--; 569e3adcf8fSFrançois Tigeot src_h--; 570e3adcf8fSFrançois Tigeot crtc_w--; 571e3adcf8fSFrançois Tigeot crtc_h--; 572e3adcf8fSFrançois Tigeot 5739edbd4a0SFrançois Tigeot if (crtc_w != src_w || crtc_h != src_h) 574e3adcf8fSFrançois Tigeot sprscale = SPRITE_SCALE_ENABLE | (src_w << 16) | src_h; 575e3adcf8fSFrançois Tigeot 576c0e85e96SFrançois Tigeot linear_offset = y * fb->pitches[0] + x * cpp; 5778621f407SFrançois Tigeot sprsurf_offset = intel_compute_tile_offset(&x, &y, fb, 0, 5788621f407SFrançois Tigeot fb->pitches[0], rotation); 5792c84b0b6SFrançois Tigeot linear_offset -= sprsurf_offset; 5802c84b0b6SFrançois Tigeot 58187df8fc6SFrançois Tigeot if (rotation == BIT(DRM_ROTATE_180)) { 5821b13d190SFrançois Tigeot sprctl |= SPRITE_ROTATE_180; 5831b13d190SFrançois Tigeot 5841b13d190SFrançois Tigeot /* HSW and BDW does this automagically in hardware */ 5851b13d190SFrançois Tigeot if (!IS_HASWELL(dev) && !IS_BROADWELL(dev)) { 5861b13d190SFrançois Tigeot x += src_w; 5871b13d190SFrançois Tigeot y += src_h; 588c0e85e96SFrançois Tigeot linear_offset += src_h * fb->pitches[0] + src_w * cpp; 5891b13d190SFrançois Tigeot } 5901b13d190SFrançois Tigeot } 5911b13d190SFrançois Tigeot 592477eb7f9SFrançois Tigeot if (key->flags) { 593477eb7f9SFrançois Tigeot I915_WRITE(SPRKEYVAL(pipe), key->min_value); 594477eb7f9SFrançois Tigeot I915_WRITE(SPRKEYMAX(pipe), key->max_value); 595477eb7f9SFrançois Tigeot I915_WRITE(SPRKEYMSK(pipe), key->channel_mask); 596477eb7f9SFrançois Tigeot } 597477eb7f9SFrançois Tigeot 598477eb7f9SFrançois Tigeot if (key->flags & I915_SET_COLORKEY_DESTINATION) 599477eb7f9SFrançois Tigeot sprctl |= SPRITE_DEST_KEY; 600477eb7f9SFrançois Tigeot else if (key->flags & I915_SET_COLORKEY_SOURCE) 601477eb7f9SFrançois Tigeot sprctl |= SPRITE_SOURCE_KEY; 602477eb7f9SFrançois Tigeot 603ba55f2f5SFrançois Tigeot I915_WRITE(SPRSTRIDE(pipe), fb->pitches[0]); 604ba55f2f5SFrançois Tigeot I915_WRITE(SPRPOS(pipe), (crtc_y << 16) | crtc_x); 605ba55f2f5SFrançois Tigeot 6062c84b0b6SFrançois Tigeot /* HSW consolidates SPRTILEOFF and SPRLINOFF into a single SPROFFSET 6072c84b0b6SFrançois Tigeot * register */ 6089edbd4a0SFrançois Tigeot if (IS_HASWELL(dev) || IS_BROADWELL(dev)) 6092c84b0b6SFrançois Tigeot I915_WRITE(SPROFFSET(pipe), (y << 16) | x); 610*71f41f3eSFrançois Tigeot else if (i915_gem_object_is_tiled(obj)) 6112c84b0b6SFrançois Tigeot I915_WRITE(SPRTILEOFF(pipe), (y << 16) | x); 6122c84b0b6SFrançois Tigeot else 6132c84b0b6SFrançois Tigeot I915_WRITE(SPRLINOFF(pipe), linear_offset); 6142c84b0b6SFrançois Tigeot 615e3adcf8fSFrançois Tigeot I915_WRITE(SPRSIZE(pipe), (crtc_h << 16) | crtc_w); 6162c84b0b6SFrançois Tigeot if (intel_plane->can_scale) 617e3adcf8fSFrançois Tigeot I915_WRITE(SPRSCALE(pipe), sprscale); 618e3adcf8fSFrançois Tigeot I915_WRITE(SPRCTL(pipe), sprctl); 6199edbd4a0SFrançois Tigeot I915_WRITE(SPRSURF(pipe), 6209edbd4a0SFrançois Tigeot i915_gem_obj_ggtt_offset(obj) + sprsurf_offset); 62119c468b4SFrançois Tigeot POSTING_READ(SPRSURF(pipe)); 622e3adcf8fSFrançois Tigeot } 623e3adcf8fSFrançois Tigeot 624e3adcf8fSFrançois Tigeot static void 625a05eeebfSFrançois Tigeot ivb_disable_plane(struct drm_plane *plane, struct drm_crtc *crtc) 626e3adcf8fSFrançois Tigeot { 627e3adcf8fSFrançois Tigeot struct drm_device *dev = plane->dev; 628bf017597SFrançois Tigeot struct drm_i915_private *dev_priv = to_i915(dev); 629e3adcf8fSFrançois Tigeot struct intel_plane *intel_plane = to_intel_plane(plane); 630e3adcf8fSFrançois Tigeot int pipe = intel_plane->pipe; 631ba55f2f5SFrançois Tigeot 632352ff8bdSFrançois Tigeot I915_WRITE(SPRCTL(pipe), 0); 633e3adcf8fSFrançois Tigeot /* Can't leave the scaler enabled... */ 6342c84b0b6SFrançois Tigeot if (intel_plane->can_scale) 635e3adcf8fSFrançois Tigeot I915_WRITE(SPRSCALE(pipe), 0); 636ba55f2f5SFrançois Tigeot 63719c468b4SFrançois Tigeot I915_WRITE(SPRSURF(pipe), 0); 63819c468b4SFrançois Tigeot POSTING_READ(SPRSURF(pipe)); 639e3adcf8fSFrançois Tigeot } 640e3adcf8fSFrançois Tigeot 641e3adcf8fSFrançois Tigeot static void 642c0e85e96SFrançois Tigeot ilk_update_plane(struct drm_plane *plane, 643c0e85e96SFrançois Tigeot const struct intel_crtc_state *crtc_state, 644c0e85e96SFrançois Tigeot const struct intel_plane_state *plane_state) 645e3adcf8fSFrançois Tigeot { 646e3adcf8fSFrançois Tigeot struct drm_device *dev = plane->dev; 647bf017597SFrançois Tigeot struct drm_i915_private *dev_priv = to_i915(dev); 648e3adcf8fSFrançois Tigeot struct intel_plane *intel_plane = to_intel_plane(plane); 649c0e85e96SFrançois Tigeot struct drm_framebuffer *fb = plane_state->base.fb; 650477eb7f9SFrançois Tigeot struct drm_i915_gem_object *obj = intel_fb_obj(fb); 6512c84b0b6SFrançois Tigeot int pipe = intel_plane->pipe; 6522c84b0b6SFrançois Tigeot u32 dvscntr, dvsscale; 653c0e85e96SFrançois Tigeot u32 dvssurf_offset, linear_offset; 6548621f407SFrançois Tigeot unsigned int rotation = plane_state->base.rotation; 655c0e85e96SFrançois Tigeot int cpp = drm_format_plane_cpp(fb->pixel_format, 0); 656c0e85e96SFrançois Tigeot const struct drm_intel_sprite_colorkey *key = &plane_state->ckey; 657c0e85e96SFrançois Tigeot int crtc_x = plane_state->dst.x1; 658c0e85e96SFrançois Tigeot int crtc_y = plane_state->dst.y1; 659c0e85e96SFrançois Tigeot uint32_t crtc_w = drm_rect_width(&plane_state->dst); 660c0e85e96SFrançois Tigeot uint32_t crtc_h = drm_rect_height(&plane_state->dst); 661c0e85e96SFrançois Tigeot uint32_t x = plane_state->src.x1 >> 16; 662c0e85e96SFrançois Tigeot uint32_t y = plane_state->src.y1 >> 16; 663c0e85e96SFrançois Tigeot uint32_t src_w = drm_rect_width(&plane_state->src) >> 16; 664c0e85e96SFrançois Tigeot uint32_t src_h = drm_rect_height(&plane_state->src) >> 16; 665e3adcf8fSFrançois Tigeot 666477eb7f9SFrançois Tigeot dvscntr = DVS_ENABLE; 667e3adcf8fSFrançois Tigeot 668e3adcf8fSFrançois Tigeot switch (fb->pixel_format) { 669e3adcf8fSFrançois Tigeot case DRM_FORMAT_XBGR8888: 670e3adcf8fSFrançois Tigeot dvscntr |= DVS_FORMAT_RGBX888 | DVS_RGB_ORDER_XBGR; 671e3adcf8fSFrançois Tigeot break; 672e3adcf8fSFrançois Tigeot case DRM_FORMAT_XRGB8888: 673e3adcf8fSFrançois Tigeot dvscntr |= DVS_FORMAT_RGBX888; 674e3adcf8fSFrançois Tigeot break; 675e3adcf8fSFrançois Tigeot case DRM_FORMAT_YUYV: 676e3adcf8fSFrançois Tigeot dvscntr |= DVS_FORMAT_YUV422 | DVS_YUV_ORDER_YUYV; 677e3adcf8fSFrançois Tigeot break; 678e3adcf8fSFrançois Tigeot case DRM_FORMAT_YVYU: 679e3adcf8fSFrançois Tigeot dvscntr |= DVS_FORMAT_YUV422 | DVS_YUV_ORDER_YVYU; 680e3adcf8fSFrançois Tigeot break; 681e3adcf8fSFrançois Tigeot case DRM_FORMAT_UYVY: 682e3adcf8fSFrançois Tigeot dvscntr |= DVS_FORMAT_YUV422 | DVS_YUV_ORDER_UYVY; 683e3adcf8fSFrançois Tigeot break; 684e3adcf8fSFrançois Tigeot case DRM_FORMAT_VYUY: 685e3adcf8fSFrançois Tigeot dvscntr |= DVS_FORMAT_YUV422 | DVS_YUV_ORDER_VYUY; 686e3adcf8fSFrançois Tigeot break; 687e3adcf8fSFrançois Tigeot default: 6882c84b0b6SFrançois Tigeot BUG(); 689e3adcf8fSFrançois Tigeot } 690e3adcf8fSFrançois Tigeot 6919edbd4a0SFrançois Tigeot /* 6929edbd4a0SFrançois Tigeot * Enable gamma to match primary/cursor plane behaviour. 6939edbd4a0SFrançois Tigeot * FIXME should be user controllable via propertiesa. 6949edbd4a0SFrançois Tigeot */ 6959edbd4a0SFrançois Tigeot dvscntr |= DVS_GAMMA_ENABLE; 6969edbd4a0SFrançois Tigeot 697*71f41f3eSFrançois Tigeot if (i915_gem_object_is_tiled(obj)) 698e3adcf8fSFrançois Tigeot dvscntr |= DVS_TILED; 699e3adcf8fSFrançois Tigeot 7002c84b0b6SFrançois Tigeot if (IS_GEN6(dev)) 7012c84b0b6SFrançois Tigeot dvscntr |= DVS_TRICKLE_FEED_DISABLE; /* must disable */ 702e3adcf8fSFrançois Tigeot 703e3adcf8fSFrançois Tigeot /* Sizes are 0 based */ 704e3adcf8fSFrançois Tigeot src_w--; 705e3adcf8fSFrançois Tigeot src_h--; 706e3adcf8fSFrançois Tigeot crtc_w--; 707e3adcf8fSFrançois Tigeot crtc_h--; 708e3adcf8fSFrançois Tigeot 7092c84b0b6SFrançois Tigeot dvsscale = 0; 7109edbd4a0SFrançois Tigeot if (crtc_w != src_w || crtc_h != src_h) 711e3adcf8fSFrançois Tigeot dvsscale = DVS_SCALE_ENABLE | (src_w << 16) | src_h; 712e3adcf8fSFrançois Tigeot 713c0e85e96SFrançois Tigeot linear_offset = y * fb->pitches[0] + x * cpp; 7148621f407SFrançois Tigeot dvssurf_offset = intel_compute_tile_offset(&x, &y, fb, 0, 7158621f407SFrançois Tigeot fb->pitches[0], rotation); 7162c84b0b6SFrançois Tigeot linear_offset -= dvssurf_offset; 7172c84b0b6SFrançois Tigeot 71887df8fc6SFrançois Tigeot if (rotation == BIT(DRM_ROTATE_180)) { 7191b13d190SFrançois Tigeot dvscntr |= DVS_ROTATE_180; 7201b13d190SFrançois Tigeot 7211b13d190SFrançois Tigeot x += src_w; 7221b13d190SFrançois Tigeot y += src_h; 723c0e85e96SFrançois Tigeot linear_offset += src_h * fb->pitches[0] + src_w * cpp; 7241b13d190SFrançois Tigeot } 7251b13d190SFrançois Tigeot 726477eb7f9SFrançois Tigeot if (key->flags) { 727477eb7f9SFrançois Tigeot I915_WRITE(DVSKEYVAL(pipe), key->min_value); 728477eb7f9SFrançois Tigeot I915_WRITE(DVSKEYMAX(pipe), key->max_value); 729477eb7f9SFrançois Tigeot I915_WRITE(DVSKEYMSK(pipe), key->channel_mask); 730477eb7f9SFrançois Tigeot } 731477eb7f9SFrançois Tigeot 732477eb7f9SFrançois Tigeot if (key->flags & I915_SET_COLORKEY_DESTINATION) 733477eb7f9SFrançois Tigeot dvscntr |= DVS_DEST_KEY; 734477eb7f9SFrançois Tigeot else if (key->flags & I915_SET_COLORKEY_SOURCE) 735477eb7f9SFrançois Tigeot dvscntr |= DVS_SOURCE_KEY; 736477eb7f9SFrançois Tigeot 737ba55f2f5SFrançois Tigeot I915_WRITE(DVSSTRIDE(pipe), fb->pitches[0]); 738ba55f2f5SFrançois Tigeot I915_WRITE(DVSPOS(pipe), (crtc_y << 16) | crtc_x); 739ba55f2f5SFrançois Tigeot 740*71f41f3eSFrançois Tigeot if (i915_gem_object_is_tiled(obj)) 7412c84b0b6SFrançois Tigeot I915_WRITE(DVSTILEOFF(pipe), (y << 16) | x); 7422c84b0b6SFrançois Tigeot else 7432c84b0b6SFrançois Tigeot I915_WRITE(DVSLINOFF(pipe), linear_offset); 7442c84b0b6SFrançois Tigeot 745e3adcf8fSFrançois Tigeot I915_WRITE(DVSSIZE(pipe), (crtc_h << 16) | crtc_w); 746e3adcf8fSFrançois Tigeot I915_WRITE(DVSSCALE(pipe), dvsscale); 747e3adcf8fSFrançois Tigeot I915_WRITE(DVSCNTR(pipe), dvscntr); 7489edbd4a0SFrançois Tigeot I915_WRITE(DVSSURF(pipe), 7499edbd4a0SFrançois Tigeot i915_gem_obj_ggtt_offset(obj) + dvssurf_offset); 75019c468b4SFrançois Tigeot POSTING_READ(DVSSURF(pipe)); 751e3adcf8fSFrançois Tigeot } 752e3adcf8fSFrançois Tigeot 753e3adcf8fSFrançois Tigeot static void 754a05eeebfSFrançois Tigeot ilk_disable_plane(struct drm_plane *plane, struct drm_crtc *crtc) 755e3adcf8fSFrançois Tigeot { 756e3adcf8fSFrançois Tigeot struct drm_device *dev = plane->dev; 757bf017597SFrançois Tigeot struct drm_i915_private *dev_priv = to_i915(dev); 758e3adcf8fSFrançois Tigeot struct intel_plane *intel_plane = to_intel_plane(plane); 759e3adcf8fSFrançois Tigeot int pipe = intel_plane->pipe; 760ba55f2f5SFrançois Tigeot 761477eb7f9SFrançois Tigeot I915_WRITE(DVSCNTR(pipe), 0); 762e3adcf8fSFrançois Tigeot /* Disable the scaler */ 763e3adcf8fSFrançois Tigeot I915_WRITE(DVSSCALE(pipe), 0); 764477eb7f9SFrançois Tigeot 7659edbd4a0SFrançois Tigeot I915_WRITE(DVSSURF(pipe), 0); 76619c468b4SFrançois Tigeot POSTING_READ(DVSSURF(pipe)); 7679edbd4a0SFrançois Tigeot } 7689edbd4a0SFrançois Tigeot 769e3adcf8fSFrançois Tigeot static int 7702c9916cdSFrançois Tigeot intel_check_sprite_plane(struct drm_plane *plane, 771a05eeebfSFrançois Tigeot struct intel_crtc_state *crtc_state, 7722c9916cdSFrançois Tigeot struct intel_plane_state *state) 773e3adcf8fSFrançois Tigeot { 77419c468b4SFrançois Tigeot struct drm_device *dev = plane->dev; 775a05eeebfSFrançois Tigeot struct drm_crtc *crtc = state->base.crtc; 776a05eeebfSFrançois Tigeot struct intel_crtc *intel_crtc = to_intel_crtc(crtc); 777e3adcf8fSFrançois Tigeot struct intel_plane *intel_plane = to_intel_plane(plane); 7782c9916cdSFrançois Tigeot struct drm_framebuffer *fb = state->base.fb; 7799edbd4a0SFrançois Tigeot int crtc_x, crtc_y; 7809edbd4a0SFrançois Tigeot unsigned int crtc_w, crtc_h; 7819edbd4a0SFrançois Tigeot uint32_t src_x, src_y, src_w, src_h; 7822c9916cdSFrançois Tigeot struct drm_rect *src = &state->src; 7832c9916cdSFrançois Tigeot struct drm_rect *dst = &state->dst; 7842c9916cdSFrançois Tigeot const struct drm_rect *clip = &state->clip; 7852c9916cdSFrançois Tigeot int hscale, vscale; 7862c9916cdSFrançois Tigeot int max_scale, min_scale; 78719c468b4SFrançois Tigeot bool can_scale; 7882c9916cdSFrançois Tigeot 7892c9916cdSFrançois Tigeot if (!fb) { 7902c9916cdSFrançois Tigeot state->visible = false; 791a05eeebfSFrançois Tigeot return 0; 7922c9916cdSFrançois Tigeot } 793e3adcf8fSFrançois Tigeot 794e3adcf8fSFrançois Tigeot /* Don't modify another pipe's plane */ 7955d0b1887SFrançois Tigeot if (intel_plane->pipe != intel_crtc->pipe) { 7965d0b1887SFrançois Tigeot DRM_DEBUG_KMS("Wrong plane <-> crtc mapping\n"); 797e3adcf8fSFrançois Tigeot return -EINVAL; 7985d0b1887SFrançois Tigeot } 7995d0b1887SFrançois Tigeot 8005d0b1887SFrançois Tigeot /* FIXME check all gen limits */ 8015d0b1887SFrançois Tigeot if (fb->width < 3 || fb->height < 3 || fb->pitches[0] > 16384) { 8025d0b1887SFrançois Tigeot DRM_DEBUG_KMS("Unsuitable framebuffer for plane\n"); 8035d0b1887SFrançois Tigeot return -EINVAL; 8045d0b1887SFrançois Tigeot } 805e3adcf8fSFrançois Tigeot 80619c468b4SFrançois Tigeot /* setup can_scale, min_scale, max_scale */ 80719c468b4SFrançois Tigeot if (INTEL_INFO(dev)->gen >= 9) { 80819c468b4SFrançois Tigeot /* use scaler when colorkey is not required */ 809a05eeebfSFrançois Tigeot if (state->ckey.flags == I915_SET_COLORKEY_NONE) { 81019c468b4SFrançois Tigeot can_scale = 1; 81119c468b4SFrançois Tigeot min_scale = 1; 81219c468b4SFrançois Tigeot max_scale = skl_max_scale(intel_crtc, crtc_state); 81319c468b4SFrançois Tigeot } else { 81419c468b4SFrançois Tigeot can_scale = 0; 81519c468b4SFrançois Tigeot min_scale = DRM_PLANE_HELPER_NO_SCALING; 81619c468b4SFrançois Tigeot max_scale = DRM_PLANE_HELPER_NO_SCALING; 81719c468b4SFrançois Tigeot } 81819c468b4SFrançois Tigeot } else { 81919c468b4SFrançois Tigeot can_scale = intel_plane->can_scale; 82019c468b4SFrançois Tigeot max_scale = intel_plane->max_downscale << 16; 82119c468b4SFrançois Tigeot min_scale = intel_plane->can_scale ? 1 : (1 << 16); 82219c468b4SFrançois Tigeot } 82319c468b4SFrançois Tigeot 824e3adcf8fSFrançois Tigeot /* 8255d0b1887SFrançois Tigeot * FIXME the following code does a bunch of fuzzy adjustments to the 8265d0b1887SFrançois Tigeot * coordinates and sizes. We probably need some way to decide whether 8275d0b1887SFrançois Tigeot * more strict checking should be done instead. 828e3adcf8fSFrançois Tigeot */ 8292c9916cdSFrançois Tigeot drm_rect_rotate(src, fb->width << 16, fb->height << 16, 8302c9916cdSFrançois Tigeot state->base.rotation); 8311b13d190SFrançois Tigeot 8322c9916cdSFrançois Tigeot hscale = drm_rect_calc_hscale_relaxed(src, dst, min_scale, max_scale); 8335d0b1887SFrançois Tigeot BUG_ON(hscale < 0); 834e3adcf8fSFrançois Tigeot 8352c9916cdSFrançois Tigeot vscale = drm_rect_calc_vscale_relaxed(src, dst, min_scale, max_scale); 8365d0b1887SFrançois Tigeot BUG_ON(vscale < 0); 8375d0b1887SFrançois Tigeot 8382c9916cdSFrançois Tigeot state->visible = drm_rect_clip_scaled(src, dst, clip, hscale, vscale); 8395d0b1887SFrançois Tigeot 8402c9916cdSFrançois Tigeot crtc_x = dst->x1; 8412c9916cdSFrançois Tigeot crtc_y = dst->y1; 8422c9916cdSFrançois Tigeot crtc_w = drm_rect_width(dst); 8432c9916cdSFrançois Tigeot crtc_h = drm_rect_height(dst); 8445d0b1887SFrançois Tigeot 8452c9916cdSFrançois Tigeot if (state->visible) { 8465d0b1887SFrançois Tigeot /* check again in case clipping clamped the results */ 8472c9916cdSFrançois Tigeot hscale = drm_rect_calc_hscale(src, dst, min_scale, max_scale); 8485d0b1887SFrançois Tigeot if (hscale < 0) { 8495d0b1887SFrançois Tigeot DRM_DEBUG_KMS("Horizontal scaling factor out of limits\n"); 850aee94f86SFrançois Tigeot drm_rect_debug_print("src: ", src, true); 851aee94f86SFrançois Tigeot drm_rect_debug_print("dst: ", dst, false); 8525d0b1887SFrançois Tigeot 8535d0b1887SFrançois Tigeot return hscale; 8545d0b1887SFrançois Tigeot } 8555d0b1887SFrançois Tigeot 8562c9916cdSFrançois Tigeot vscale = drm_rect_calc_vscale(src, dst, min_scale, max_scale); 8575d0b1887SFrançois Tigeot if (vscale < 0) { 8585d0b1887SFrançois Tigeot DRM_DEBUG_KMS("Vertical scaling factor out of limits\n"); 859aee94f86SFrançois Tigeot drm_rect_debug_print("src: ", src, true); 860aee94f86SFrançois Tigeot drm_rect_debug_print("dst: ", dst, false); 8615d0b1887SFrançois Tigeot 8625d0b1887SFrançois Tigeot return vscale; 8635d0b1887SFrançois Tigeot } 8645d0b1887SFrançois Tigeot 8655d0b1887SFrançois Tigeot /* Make the source viewport size an exact multiple of the scaling factors. */ 8662c9916cdSFrançois Tigeot drm_rect_adjust_size(src, 8672c9916cdSFrançois Tigeot drm_rect_width(dst) * hscale - drm_rect_width(src), 8682c9916cdSFrançois Tigeot drm_rect_height(dst) * vscale - drm_rect_height(src)); 8695d0b1887SFrançois Tigeot 8702c9916cdSFrançois Tigeot drm_rect_rotate_inv(src, fb->width << 16, fb->height << 16, 8712c9916cdSFrançois Tigeot state->base.rotation); 8721b13d190SFrançois Tigeot 8735d0b1887SFrançois Tigeot /* sanity check to make sure the src viewport wasn't enlarged */ 8742c9916cdSFrançois Tigeot WARN_ON(src->x1 < (int) state->base.src_x || 8752c9916cdSFrançois Tigeot src->y1 < (int) state->base.src_y || 8762c9916cdSFrançois Tigeot src->x2 > (int) state->base.src_x + state->base.src_w || 8772c9916cdSFrançois Tigeot src->y2 > (int) state->base.src_y + state->base.src_h); 878e3adcf8fSFrançois Tigeot 879e3adcf8fSFrançois Tigeot /* 8805d0b1887SFrançois Tigeot * Hardware doesn't handle subpixel coordinates. 8815d0b1887SFrançois Tigeot * Adjust to (macro)pixel boundary, but be careful not to 8825d0b1887SFrançois Tigeot * increase the source viewport size, because that could 8835d0b1887SFrançois Tigeot * push the downscaling factor out of bounds. 8842c84b0b6SFrançois Tigeot */ 8852c9916cdSFrançois Tigeot src_x = src->x1 >> 16; 8862c9916cdSFrançois Tigeot src_w = drm_rect_width(src) >> 16; 8872c9916cdSFrançois Tigeot src_y = src->y1 >> 16; 8882c9916cdSFrançois Tigeot src_h = drm_rect_height(src) >> 16; 8895d0b1887SFrançois Tigeot 8905d0b1887SFrançois Tigeot if (format_is_yuv(fb->pixel_format)) { 8915d0b1887SFrançois Tigeot src_x &= ~1; 8925d0b1887SFrançois Tigeot src_w &= ~1; 8932c84b0b6SFrançois Tigeot 8942c84b0b6SFrançois Tigeot /* 8955d0b1887SFrançois Tigeot * Must keep src and dst the 8965d0b1887SFrançois Tigeot * same if we can't scale. 897e3adcf8fSFrançois Tigeot */ 89819c468b4SFrançois Tigeot if (!can_scale) 8995d0b1887SFrançois Tigeot crtc_w &= ~1; 9005d0b1887SFrançois Tigeot 9015d0b1887SFrançois Tigeot if (crtc_w == 0) 9022c9916cdSFrançois Tigeot state->visible = false; 9035d0b1887SFrançois Tigeot } 9045d0b1887SFrançois Tigeot } 9055d0b1887SFrançois Tigeot 9065d0b1887SFrançois Tigeot /* Check size restrictions when scaling */ 9072c9916cdSFrançois Tigeot if (state->visible && (src_w != crtc_w || src_h != crtc_h)) { 9085d0b1887SFrançois Tigeot unsigned int width_bytes; 909c0e85e96SFrançois Tigeot int cpp = drm_format_plane_cpp(fb->pixel_format, 0); 9105d0b1887SFrançois Tigeot 91119c468b4SFrançois Tigeot WARN_ON(!can_scale); 9125d0b1887SFrançois Tigeot 9135d0b1887SFrançois Tigeot /* FIXME interlacing min height is 6 */ 9145d0b1887SFrançois Tigeot 9155d0b1887SFrançois Tigeot if (crtc_w < 3 || crtc_h < 3) 9162c9916cdSFrançois Tigeot state->visible = false; 9175d0b1887SFrançois Tigeot 9185d0b1887SFrançois Tigeot if (src_w < 3 || src_h < 3) 9192c9916cdSFrançois Tigeot state->visible = false; 9205d0b1887SFrançois Tigeot 921c0e85e96SFrançois Tigeot width_bytes = ((src_x * cpp) & 63) + src_w * cpp; 9225d0b1887SFrançois Tigeot 92319c468b4SFrançois Tigeot if (INTEL_INFO(dev)->gen < 9 && (src_w > 2048 || src_h > 2048 || 92419c468b4SFrançois Tigeot width_bytes > 4096 || fb->pitches[0] > 4096)) { 9255d0b1887SFrançois Tigeot DRM_DEBUG_KMS("Source dimensions exceed hardware limits\n"); 926e3adcf8fSFrançois Tigeot return -EINVAL; 9275d0b1887SFrançois Tigeot } 9285d0b1887SFrançois Tigeot } 9295d0b1887SFrançois Tigeot 9302c9916cdSFrançois Tigeot if (state->visible) { 93119c468b4SFrançois Tigeot src->x1 = src_x << 16; 93219c468b4SFrançois Tigeot src->x2 = (src_x + src_w) << 16; 93319c468b4SFrançois Tigeot src->y1 = src_y << 16; 93419c468b4SFrançois Tigeot src->y2 = (src_y + src_h) << 16; 9352c9916cdSFrançois Tigeot } 936e3adcf8fSFrançois Tigeot 9372c9916cdSFrançois Tigeot dst->x1 = crtc_x; 9382c9916cdSFrançois Tigeot dst->x2 = crtc_x + crtc_w; 9392c9916cdSFrançois Tigeot dst->y1 = crtc_y; 9402c9916cdSFrançois Tigeot dst->y2 = crtc_y + crtc_h; 9412c9916cdSFrançois Tigeot 9422c9916cdSFrançois Tigeot return 0; 9432c9916cdSFrançois Tigeot } 9442c9916cdSFrançois Tigeot 945e3adcf8fSFrançois Tigeot int intel_sprite_set_colorkey(struct drm_device *dev, void *data, 946e3adcf8fSFrançois Tigeot struct drm_file *file_priv) 947e3adcf8fSFrançois Tigeot { 948e3adcf8fSFrançois Tigeot struct drm_intel_sprite_colorkey *set = data; 949e3adcf8fSFrançois Tigeot struct drm_plane *plane; 950a05eeebfSFrançois Tigeot struct drm_plane_state *plane_state; 951a05eeebfSFrançois Tigeot struct drm_atomic_state *state; 952a05eeebfSFrançois Tigeot struct drm_modeset_acquire_ctx ctx; 953e3adcf8fSFrançois Tigeot int ret = 0; 954e3adcf8fSFrançois Tigeot 955e3adcf8fSFrançois Tigeot /* Make sure we don't try to enable both src & dest simultaneously */ 956e3adcf8fSFrançois Tigeot if ((set->flags & (I915_SET_COLORKEY_DESTINATION | I915_SET_COLORKEY_SOURCE)) == (I915_SET_COLORKEY_DESTINATION | I915_SET_COLORKEY_SOURCE)) 957e3adcf8fSFrançois Tigeot return -EINVAL; 958e3adcf8fSFrançois Tigeot 959aee94f86SFrançois Tigeot if ((IS_VALLEYVIEW(dev) || IS_CHERRYVIEW(dev)) && 960477eb7f9SFrançois Tigeot set->flags & I915_SET_COLORKEY_DESTINATION) 961477eb7f9SFrançois Tigeot return -EINVAL; 962477eb7f9SFrançois Tigeot 96324edb884SFrançois Tigeot plane = drm_plane_find(dev, set->plane_id); 964a05eeebfSFrançois Tigeot if (!plane || plane->type != DRM_PLANE_TYPE_OVERLAY) 965a05eeebfSFrançois Tigeot return -ENOENT; 966a05eeebfSFrançois Tigeot 967a05eeebfSFrançois Tigeot drm_modeset_acquire_init(&ctx, 0); 968a05eeebfSFrançois Tigeot 969a05eeebfSFrançois Tigeot state = drm_atomic_state_alloc(plane->dev); 970a05eeebfSFrançois Tigeot if (!state) { 971a05eeebfSFrançois Tigeot ret = -ENOMEM; 972a05eeebfSFrançois Tigeot goto out; 973a05eeebfSFrançois Tigeot } 974a05eeebfSFrançois Tigeot state->acquire_ctx = &ctx; 975a05eeebfSFrançois Tigeot 976a05eeebfSFrançois Tigeot while (1) { 977a05eeebfSFrançois Tigeot plane_state = drm_atomic_get_plane_state(state, plane); 978a05eeebfSFrançois Tigeot ret = PTR_ERR_OR_ZERO(plane_state); 979a05eeebfSFrançois Tigeot if (!ret) { 980a05eeebfSFrançois Tigeot to_intel_plane_state(plane_state)->ckey = *set; 981a05eeebfSFrançois Tigeot ret = drm_atomic_commit(state); 982e3adcf8fSFrançois Tigeot } 983e3adcf8fSFrançois Tigeot 984a05eeebfSFrançois Tigeot if (ret != -EDEADLK) 985a05eeebfSFrançois Tigeot break; 98619c468b4SFrançois Tigeot 987a05eeebfSFrançois Tigeot drm_atomic_state_clear(state); 988a05eeebfSFrançois Tigeot drm_modeset_backoff(&ctx); 98919c468b4SFrançois Tigeot } 99019c468b4SFrançois Tigeot 991a05eeebfSFrançois Tigeot if (ret) 992a05eeebfSFrançois Tigeot drm_atomic_state_free(state); 993e3adcf8fSFrançois Tigeot 994a05eeebfSFrançois Tigeot out: 995a05eeebfSFrançois Tigeot drm_modeset_drop_locks(&ctx); 996a05eeebfSFrançois Tigeot drm_modeset_acquire_fini(&ctx); 997e3adcf8fSFrançois Tigeot return ret; 998e3adcf8fSFrançois Tigeot } 999e3adcf8fSFrançois Tigeot 100019c468b4SFrançois Tigeot static const uint32_t ilk_plane_formats[] = { 10012c84b0b6SFrançois Tigeot DRM_FORMAT_XRGB8888, 10022c84b0b6SFrançois Tigeot DRM_FORMAT_YUYV, 10032c84b0b6SFrançois Tigeot DRM_FORMAT_YVYU, 10042c84b0b6SFrançois Tigeot DRM_FORMAT_UYVY, 10052c84b0b6SFrançois Tigeot DRM_FORMAT_VYUY, 10062c84b0b6SFrançois Tigeot }; 10072c84b0b6SFrançois Tigeot 100819c468b4SFrançois Tigeot static const uint32_t snb_plane_formats[] = { 1009e3adcf8fSFrançois Tigeot DRM_FORMAT_XBGR8888, 1010e3adcf8fSFrançois Tigeot DRM_FORMAT_XRGB8888, 1011e3adcf8fSFrançois Tigeot DRM_FORMAT_YUYV, 1012e3adcf8fSFrançois Tigeot DRM_FORMAT_YVYU, 1013e3adcf8fSFrançois Tigeot DRM_FORMAT_UYVY, 1014e3adcf8fSFrançois Tigeot DRM_FORMAT_VYUY, 1015e3adcf8fSFrançois Tigeot }; 1016e3adcf8fSFrançois Tigeot 101719c468b4SFrançois Tigeot static const uint32_t vlv_plane_formats[] = { 10188e26cdf6SFrançois Tigeot DRM_FORMAT_RGB565, 10198e26cdf6SFrançois Tigeot DRM_FORMAT_ABGR8888, 10208e26cdf6SFrançois Tigeot DRM_FORMAT_ARGB8888, 10218e26cdf6SFrançois Tigeot DRM_FORMAT_XBGR8888, 10228e26cdf6SFrançois Tigeot DRM_FORMAT_XRGB8888, 10238e26cdf6SFrançois Tigeot DRM_FORMAT_XBGR2101010, 10248e26cdf6SFrançois Tigeot DRM_FORMAT_ABGR2101010, 10258e26cdf6SFrançois Tigeot DRM_FORMAT_YUYV, 10268e26cdf6SFrançois Tigeot DRM_FORMAT_YVYU, 10278e26cdf6SFrançois Tigeot DRM_FORMAT_UYVY, 10288e26cdf6SFrançois Tigeot DRM_FORMAT_VYUY, 10298e26cdf6SFrançois Tigeot }; 10308e26cdf6SFrançois Tigeot 10312c9916cdSFrançois Tigeot static uint32_t skl_plane_formats[] = { 10322c9916cdSFrançois Tigeot DRM_FORMAT_RGB565, 10332c9916cdSFrançois Tigeot DRM_FORMAT_ABGR8888, 10342c9916cdSFrançois Tigeot DRM_FORMAT_ARGB8888, 10352c9916cdSFrançois Tigeot DRM_FORMAT_XBGR8888, 10362c9916cdSFrançois Tigeot DRM_FORMAT_XRGB8888, 10372c9916cdSFrançois Tigeot DRM_FORMAT_YUYV, 10382c9916cdSFrançois Tigeot DRM_FORMAT_YVYU, 10392c9916cdSFrançois Tigeot DRM_FORMAT_UYVY, 10402c9916cdSFrançois Tigeot DRM_FORMAT_VYUY, 10412c9916cdSFrançois Tigeot }; 10422c9916cdSFrançois Tigeot 1043e3adcf8fSFrançois Tigeot int 10448e26cdf6SFrançois Tigeot intel_plane_init(struct drm_device *dev, enum i915_pipe pipe, int plane) 1045e3adcf8fSFrançois Tigeot { 10468621f407SFrançois Tigeot struct intel_plane *intel_plane = NULL; 10478621f407SFrançois Tigeot struct intel_plane_state *state = NULL; 1048e3adcf8fSFrançois Tigeot unsigned long possible_crtcs; 10492c84b0b6SFrançois Tigeot const uint32_t *plane_formats; 10502c84b0b6SFrançois Tigeot int num_plane_formats; 1051e3adcf8fSFrançois Tigeot int ret; 1052e3adcf8fSFrançois Tigeot 10532c84b0b6SFrançois Tigeot if (INTEL_INFO(dev)->gen < 5) 1054e3adcf8fSFrançois Tigeot return -ENODEV; 1055e3adcf8fSFrançois Tigeot 10569edbd4a0SFrançois Tigeot intel_plane = kzalloc(sizeof(*intel_plane), GFP_KERNEL); 10578621f407SFrançois Tigeot if (!intel_plane) { 10588621f407SFrançois Tigeot ret = -ENOMEM; 10598621f407SFrançois Tigeot goto fail; 10608621f407SFrançois Tigeot } 10612c84b0b6SFrançois Tigeot 10622c9916cdSFrançois Tigeot state = intel_create_plane_state(&intel_plane->base); 10632c9916cdSFrançois Tigeot if (!state) { 10648621f407SFrançois Tigeot ret = -ENOMEM; 10658621f407SFrançois Tigeot goto fail; 10662c9916cdSFrançois Tigeot } 10672c9916cdSFrançois Tigeot intel_plane->base.state = &state->base; 10682c9916cdSFrançois Tigeot 10692c84b0b6SFrançois Tigeot switch (INTEL_INFO(dev)->gen) { 10702c84b0b6SFrançois Tigeot case 5: 10712c84b0b6SFrançois Tigeot case 6: 10722c84b0b6SFrançois Tigeot intel_plane->can_scale = true; 10732c84b0b6SFrançois Tigeot intel_plane->max_downscale = 16; 10742c84b0b6SFrançois Tigeot intel_plane->update_plane = ilk_update_plane; 10752c84b0b6SFrançois Tigeot intel_plane->disable_plane = ilk_disable_plane; 1076e3adcf8fSFrançois Tigeot 1077e3adcf8fSFrançois Tigeot if (IS_GEN6(dev)) { 10782c84b0b6SFrançois Tigeot plane_formats = snb_plane_formats; 10792c84b0b6SFrançois Tigeot num_plane_formats = ARRAY_SIZE(snb_plane_formats); 10802c84b0b6SFrançois Tigeot } else { 10812c84b0b6SFrançois Tigeot plane_formats = ilk_plane_formats; 10822c84b0b6SFrançois Tigeot num_plane_formats = ARRAY_SIZE(ilk_plane_formats); 10832c84b0b6SFrançois Tigeot } 10842c84b0b6SFrançois Tigeot break; 10852c84b0b6SFrançois Tigeot 10862c84b0b6SFrançois Tigeot case 7: 10879edbd4a0SFrançois Tigeot case 8: 10885d0b1887SFrançois Tigeot if (IS_IVYBRIDGE(dev)) { 10892c84b0b6SFrançois Tigeot intel_plane->can_scale = true; 10905d0b1887SFrançois Tigeot intel_plane->max_downscale = 2; 10915d0b1887SFrançois Tigeot } else { 10925d0b1887SFrançois Tigeot intel_plane->can_scale = false; 10935d0b1887SFrançois Tigeot intel_plane->max_downscale = 1; 10945d0b1887SFrançois Tigeot } 10958e26cdf6SFrançois Tigeot 1096aee94f86SFrançois Tigeot if (IS_VALLEYVIEW(dev) || IS_CHERRYVIEW(dev)) { 10978e26cdf6SFrançois Tigeot intel_plane->update_plane = vlv_update_plane; 10988e26cdf6SFrançois Tigeot intel_plane->disable_plane = vlv_disable_plane; 10998e26cdf6SFrançois Tigeot 11008e26cdf6SFrançois Tigeot plane_formats = vlv_plane_formats; 11018e26cdf6SFrançois Tigeot num_plane_formats = ARRAY_SIZE(vlv_plane_formats); 11028e26cdf6SFrançois Tigeot } else { 1103e3adcf8fSFrançois Tigeot intel_plane->update_plane = ivb_update_plane; 1104e3adcf8fSFrançois Tigeot intel_plane->disable_plane = ivb_disable_plane; 11052c84b0b6SFrançois Tigeot 11062c84b0b6SFrançois Tigeot plane_formats = snb_plane_formats; 11072c84b0b6SFrançois Tigeot num_plane_formats = ARRAY_SIZE(snb_plane_formats); 11088e26cdf6SFrançois Tigeot } 11092c84b0b6SFrançois Tigeot break; 11102c9916cdSFrançois Tigeot case 9: 111119c468b4SFrançois Tigeot intel_plane->can_scale = true; 11122c9916cdSFrançois Tigeot intel_plane->update_plane = skl_update_plane; 11132c9916cdSFrançois Tigeot intel_plane->disable_plane = skl_disable_plane; 111419c468b4SFrançois Tigeot state->scaler_id = -1; 11152c84b0b6SFrançois Tigeot 11162c9916cdSFrançois Tigeot plane_formats = skl_plane_formats; 11172c9916cdSFrançois Tigeot num_plane_formats = ARRAY_SIZE(skl_plane_formats); 11182c9916cdSFrançois Tigeot break; 11192c84b0b6SFrançois Tigeot default: 11208621f407SFrançois Tigeot MISSING_CASE(INTEL_INFO(dev)->gen); 11218621f407SFrançois Tigeot ret = -ENODEV; 11228621f407SFrançois Tigeot goto fail; 1123e3adcf8fSFrançois Tigeot } 1124e3adcf8fSFrançois Tigeot 1125e3adcf8fSFrançois Tigeot intel_plane->pipe = pipe; 11268e26cdf6SFrançois Tigeot intel_plane->plane = plane; 1127352ff8bdSFrançois Tigeot intel_plane->frontbuffer_bit = INTEL_FRONTBUFFER_SPRITE(pipe, plane); 11282c9916cdSFrançois Tigeot intel_plane->check_plane = intel_check_sprite_plane; 11298621f407SFrançois Tigeot 1130e3adcf8fSFrançois Tigeot possible_crtcs = (1 << pipe); 11318621f407SFrançois Tigeot 11321487f786SFrançois Tigeot if (INTEL_INFO(dev)->gen >= 9) 11331b13d190SFrançois Tigeot ret = drm_universal_plane_init(dev, &intel_plane->base, possible_crtcs, 11342c84b0b6SFrançois Tigeot &intel_plane_funcs, 11352c84b0b6SFrançois Tigeot plane_formats, num_plane_formats, 11361487f786SFrançois Tigeot DRM_PLANE_TYPE_OVERLAY, 11371487f786SFrançois Tigeot "plane %d%c", plane + 2, pipe_name(pipe)); 11381487f786SFrançois Tigeot else 11391487f786SFrançois Tigeot ret = drm_universal_plane_init(dev, &intel_plane->base, possible_crtcs, 11401487f786SFrançois Tigeot &intel_plane_funcs, 11411487f786SFrançois Tigeot plane_formats, num_plane_formats, 11421487f786SFrançois Tigeot DRM_PLANE_TYPE_OVERLAY, 11431487f786SFrançois Tigeot "sprite %c", sprite_name(pipe, plane)); 11448621f407SFrançois Tigeot if (ret) 11458621f407SFrançois Tigeot goto fail; 1146e3adcf8fSFrançois Tigeot 114719c468b4SFrançois Tigeot intel_create_rotation_property(dev, intel_plane); 11482c9916cdSFrançois Tigeot 11492c9916cdSFrançois Tigeot drm_plane_helper_add(&intel_plane->base, &intel_plane_helper_funcs); 11501b13d190SFrançois Tigeot 11518621f407SFrançois Tigeot return 0; 11528621f407SFrançois Tigeot 11538621f407SFrançois Tigeot fail: 11548621f407SFrançois Tigeot kfree(state); 11558621f407SFrançois Tigeot kfree(intel_plane); 11568621f407SFrançois Tigeot 1157e3adcf8fSFrançois Tigeot return ret; 1158e3adcf8fSFrançois Tigeot } 1159