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" 3971f41f3eSFranç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 571e12ee3bSFrançois Tigeot int intel_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 68*a85cb24fSFrançois Tigeot #define VBLANK_EVASION_TIME_US 100 69*a85cb24fSFrançois Tigeot 702c9916cdSFrançois Tigeot /** 712c9916cdSFrançois Tigeot * intel_pipe_update_start() - start update of a set of display registers 722c9916cdSFrançois Tigeot * @crtc: the crtc of which the registers are going to be updated 732c9916cdSFrançois Tigeot * @start_vbl_count: vblank counter return pointer used for error checking 742c9916cdSFrançois Tigeot * 752c9916cdSFrançois Tigeot * Mark the start of an update to pipe registers that should be updated 762c9916cdSFrançois Tigeot * atomically regarding vblank. If the next vblank will happens within 772c9916cdSFrançois Tigeot * the next 100 us, this function waits until the vblank passes. 782c9916cdSFrançois Tigeot * 792c9916cdSFrançois Tigeot * After a successful call to this function, interrupts will be disabled 802c9916cdSFrançois Tigeot * until a subsequent call to intel_pipe_update_end(). That is done to 812c9916cdSFrançois Tigeot * avoid random delays. The value written to @start_vbl_count should be 822c9916cdSFrançois Tigeot * supplied to intel_pipe_update_end() for error checking. 832c9916cdSFrançois Tigeot */ 84352ff8bdSFrançois Tigeot void intel_pipe_update_start(struct intel_crtc *crtc) 85ba55f2f5SFrançois Tigeot { 86*a85cb24fSFrançois Tigeot struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); 87352ff8bdSFrançois Tigeot const struct drm_display_mode *adjusted_mode = &crtc->config->base.adjusted_mode; 88ba55f2f5SFrançois Tigeot long timeout = msecs_to_jiffies_timeout(1); 89ba55f2f5SFrançois Tigeot int scanline, min, max, vblank_start; 901b13d190SFrançois Tigeot wait_queue_head_t *wq = drm_crtc_vblank_waitqueue(&crtc->base); 91*a85cb24fSFrançois Tigeot bool need_vlv_dsi_wa = (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) && 92*a85cb24fSFrançois Tigeot intel_crtc_has_type(crtc->config, INTEL_OUTPUT_DSI); 93ba55f2f5SFrançois Tigeot DEFINE_WAIT(wait); 94ba55f2f5SFrançois Tigeot 95352ff8bdSFrançois Tigeot vblank_start = adjusted_mode->crtc_vblank_start; 96352ff8bdSFrançois Tigeot if (adjusted_mode->flags & DRM_MODE_FLAG_INTERLACE) 97ba55f2f5SFrançois Tigeot vblank_start = DIV_ROUND_UP(vblank_start, 2); 98ba55f2f5SFrançois Tigeot 99ba55f2f5SFrançois Tigeot /* FIXME needs to be calibrated sensibly */ 100*a85cb24fSFrançois Tigeot min = vblank_start - intel_usecs_to_scanlines(adjusted_mode, 101*a85cb24fSFrançois Tigeot VBLANK_EVASION_TIME_US); 102ba55f2f5SFrançois Tigeot max = vblank_start - 1; 103ba55f2f5SFrançois Tigeot 104a05eeebfSFrançois Tigeot local_irq_disable(); 105a05eeebfSFrançois Tigeot 106ba55f2f5SFrançois Tigeot if (min <= 0 || max <= 0) 107a05eeebfSFrançois Tigeot return; 108ba55f2f5SFrançois Tigeot 109477eb7f9SFrançois Tigeot if (WARN_ON(drm_crtc_vblank_get(&crtc->base))) 110a05eeebfSFrançois Tigeot return; 111ba55f2f5SFrançois Tigeot 112352ff8bdSFrançois Tigeot crtc->debug.min_vbl = min; 113352ff8bdSFrançois Tigeot crtc->debug.max_vbl = max; 114352ff8bdSFrançois Tigeot trace_i915_pipe_update_start(crtc); 115ba55f2f5SFrançois Tigeot 116ba55f2f5SFrançois Tigeot for (;;) { 117ba55f2f5SFrançois Tigeot /* 118ba55f2f5SFrançois Tigeot * prepare_to_wait() has a memory barrier, which guarantees 119ba55f2f5SFrançois Tigeot * other CPUs can see the task state update by the time we 120ba55f2f5SFrançois Tigeot * read the scanline. 121ba55f2f5SFrançois Tigeot */ 1221b13d190SFrançois Tigeot prepare_to_wait(wq, &wait, TASK_UNINTERRUPTIBLE); 123ba55f2f5SFrançois Tigeot 124ba55f2f5SFrançois Tigeot scanline = intel_get_crtc_scanline(crtc); 125ba55f2f5SFrançois Tigeot if (scanline < min || scanline > max) 126ba55f2f5SFrançois Tigeot break; 127ba55f2f5SFrançois Tigeot 128ba55f2f5SFrançois Tigeot if (timeout <= 0) { 129ba55f2f5SFrançois Tigeot DRM_ERROR("Potential atomic update failure on pipe %c\n", 130ba55f2f5SFrançois Tigeot pipe_name(crtc->pipe)); 131ba55f2f5SFrançois Tigeot break; 132ba55f2f5SFrançois Tigeot } 133ba55f2f5SFrançois Tigeot 134ba55f2f5SFrançois Tigeot local_irq_enable(); 135ba55f2f5SFrançois Tigeot 136ba55f2f5SFrançois Tigeot timeout = schedule_timeout(timeout); 137ba55f2f5SFrançois Tigeot 138ba55f2f5SFrançois Tigeot local_irq_disable(); 139ba55f2f5SFrançois Tigeot } 140ba55f2f5SFrançois Tigeot 1411b13d190SFrançois Tigeot finish_wait(wq, &wait); 142ba55f2f5SFrançois Tigeot 143477eb7f9SFrançois Tigeot drm_crtc_vblank_put(&crtc->base); 144ba55f2f5SFrançois Tigeot 145*a85cb24fSFrançois Tigeot /* 146*a85cb24fSFrançois Tigeot * On VLV/CHV DSI the scanline counter would appear to 147*a85cb24fSFrançois Tigeot * increment approx. 1/3 of a scanline before start of vblank. 148*a85cb24fSFrançois Tigeot * The registers still get latched at start of vblank however. 149*a85cb24fSFrançois Tigeot * This means we must not write any registers on the first 150*a85cb24fSFrançois Tigeot * line of vblank (since not the whole line is actually in 151*a85cb24fSFrançois Tigeot * vblank). And unfortunately we can't use the interrupt to 152*a85cb24fSFrançois Tigeot * wait here since it will fire too soon. We could use the 153*a85cb24fSFrançois Tigeot * frame start interrupt instead since it will fire after the 154*a85cb24fSFrançois Tigeot * critical scanline, but that would require more changes 155*a85cb24fSFrançois Tigeot * in the interrupt code. So for now we'll just do the nasty 156*a85cb24fSFrançois Tigeot * thing and poll for the bad scanline to pass us by. 157*a85cb24fSFrançois Tigeot * 158*a85cb24fSFrançois Tigeot * FIXME figure out if BXT+ DSI suffers from this as well 159*a85cb24fSFrançois Tigeot */ 160*a85cb24fSFrançois Tigeot while (need_vlv_dsi_wa && scanline == vblank_start) 161*a85cb24fSFrançois Tigeot scanline = intel_get_crtc_scanline(crtc); 162*a85cb24fSFrançois Tigeot 163352ff8bdSFrançois Tigeot crtc->debug.scanline_start = scanline; 164352ff8bdSFrançois Tigeot crtc->debug.start_vbl_time = ktime_get(); 1651487f786SFrançois Tigeot crtc->debug.start_vbl_count = intel_crtc_get_vblank_counter(crtc); 166ba55f2f5SFrançois Tigeot 167352ff8bdSFrançois Tigeot trace_i915_pipe_update_vblank_evaded(crtc); 168ba55f2f5SFrançois Tigeot } 169ba55f2f5SFrançois Tigeot 1702c9916cdSFrançois Tigeot /** 1712c9916cdSFrançois Tigeot * intel_pipe_update_end() - end update of a set of display registers 1722c9916cdSFrançois Tigeot * @crtc: the crtc of which the registers were updated 1732c9916cdSFrançois Tigeot * @start_vbl_count: start vblank counter (used for error checking) 1742c9916cdSFrançois Tigeot * 1752c9916cdSFrançois Tigeot * Mark the end of an update started with intel_pipe_update_start(). This 1762c9916cdSFrançois Tigeot * re-enables interrupts and verifies the update was actually completed 1772c9916cdSFrançois Tigeot * before a vblank using the value of @start_vbl_count. 1782c9916cdSFrançois Tigeot */ 1791487f786SFrançois Tigeot void intel_pipe_update_end(struct intel_crtc *crtc, struct intel_flip_work *work) 180ba55f2f5SFrançois Tigeot { 181ba55f2f5SFrançois Tigeot enum i915_pipe pipe = crtc->pipe; 182352ff8bdSFrançois Tigeot int scanline_end = intel_get_crtc_scanline(crtc); 1831487f786SFrançois Tigeot u32 end_vbl_count = intel_crtc_get_vblank_counter(crtc); 184352ff8bdSFrançois Tigeot ktime_t end_vbl_time = ktime_get(); 185*a85cb24fSFrançois Tigeot struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); 186ba55f2f5SFrançois Tigeot 1871487f786SFrançois Tigeot if (work) { 1881487f786SFrançois Tigeot work->flip_queued_vblank = end_vbl_count; 1891487f786SFrançois Tigeot smp_mb__before_atomic(); 1901487f786SFrançois Tigeot atomic_set(&work->pending, 1); 1911487f786SFrançois Tigeot } 1921487f786SFrançois Tigeot 193352ff8bdSFrançois Tigeot trace_i915_pipe_update_end(crtc, end_vbl_count, scanline_end); 194ba55f2f5SFrançois Tigeot 1951487f786SFrançois Tigeot /* We're still in the vblank-evade critical section, this can't race. 1961487f786SFrançois Tigeot * Would be slightly nice to just grab the vblank count and arm the 1971487f786SFrançois Tigeot * event outside of the critical section - the spinlock might spin for a 1981487f786SFrançois Tigeot * while ... */ 1991487f786SFrançois Tigeot if (crtc->base.state->event) { 2001487f786SFrançois Tigeot WARN_ON(drm_crtc_vblank_get(&crtc->base) != 0); 2011487f786SFrançois Tigeot 2021487f786SFrançois Tigeot lockmgr(&crtc->base.dev->event_lock, LK_EXCLUSIVE); 2031487f786SFrançois Tigeot drm_crtc_arm_vblank_event(&crtc->base, crtc->base.state->event); 2041487f786SFrançois Tigeot lockmgr(&crtc->base.dev->event_lock, LK_RELEASE); 2051487f786SFrançois Tigeot 2061487f786SFrançois Tigeot crtc->base.state->event = NULL; 2071487f786SFrançois Tigeot } 2081487f786SFrançois Tigeot 209ba55f2f5SFrançois Tigeot local_irq_enable(); 210ba55f2f5SFrançois Tigeot 211*a85cb24fSFrançois Tigeot if (intel_vgpu_active(dev_priv)) 212*a85cb24fSFrançois Tigeot return; 213*a85cb24fSFrançois Tigeot 214352ff8bdSFrançois Tigeot if (crtc->debug.start_vbl_count && 215352ff8bdSFrançois Tigeot crtc->debug.start_vbl_count != end_vbl_count) { 216352ff8bdSFranç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", 217352ff8bdSFrançois Tigeot pipe_name(pipe), crtc->debug.start_vbl_count, 218352ff8bdSFrançois Tigeot end_vbl_count, 219352ff8bdSFrançois Tigeot ktime_us_delta(end_vbl_time, crtc->debug.start_vbl_time), 220352ff8bdSFrançois Tigeot crtc->debug.min_vbl, crtc->debug.max_vbl, 221352ff8bdSFrançois Tigeot crtc->debug.scanline_start, scanline_end); 222352ff8bdSFrançois Tigeot } 223*a85cb24fSFrançois Tigeot #ifdef CONFIG_DRM_I915_DEBUG_VBLANK_EVADE 224*a85cb24fSFrançois Tigeot else if (ktime_us_delta(end_vbl_time, crtc->debug.start_vbl_time) > 225*a85cb24fSFrançois Tigeot VBLANK_EVASION_TIME_US) 226*a85cb24fSFrançois Tigeot DRM_WARN("Atomic update on pipe (%c) took %lld us, max time under evasion is %u us\n", 227*a85cb24fSFrançois Tigeot pipe_name(pipe), 228*a85cb24fSFrançois Tigeot ktime_us_delta(end_vbl_time, crtc->debug.start_vbl_time), 229*a85cb24fSFrançois Tigeot VBLANK_EVASION_TIME_US); 230*a85cb24fSFrançois Tigeot #endif 231ba55f2f5SFrançois Tigeot } 232ba55f2f5SFrançois Tigeot 233e3adcf8fSFrançois Tigeot static void 234c0e85e96SFrançois Tigeot skl_update_plane(struct drm_plane *drm_plane, 235c0e85e96SFrançois Tigeot const struct intel_crtc_state *crtc_state, 236c0e85e96SFrançois Tigeot const struct intel_plane_state *plane_state) 2372c9916cdSFrançois Tigeot { 2382c9916cdSFrançois Tigeot struct drm_device *dev = drm_plane->dev; 239bf017597SFrançois Tigeot struct drm_i915_private *dev_priv = to_i915(dev); 2402c9916cdSFrançois Tigeot struct intel_plane *intel_plane = to_intel_plane(drm_plane); 241c0e85e96SFrançois Tigeot struct drm_framebuffer *fb = plane_state->base.fb; 242*a85cb24fSFrançois Tigeot enum plane_id plane_id = intel_plane->id; 243*a85cb24fSFrançois Tigeot enum i915_pipe pipe = intel_plane->pipe; 244*a85cb24fSFrançois Tigeot u32 plane_ctl = plane_state->ctl; 245c0e85e96SFrançois Tigeot const struct drm_intel_sprite_colorkey *key = &plane_state->ckey; 2461e12ee3bSFrançois Tigeot u32 surf_addr = plane_state->main.offset; 2478621f407SFrançois Tigeot unsigned int rotation = plane_state->base.rotation; 2481e12ee3bSFrançois Tigeot u32 stride = skl_plane_stride(fb, 0, rotation); 2491e12ee3bSFrançois Tigeot int crtc_x = plane_state->base.dst.x1; 2501e12ee3bSFrançois Tigeot int crtc_y = plane_state->base.dst.y1; 2511e12ee3bSFrançois Tigeot uint32_t crtc_w = drm_rect_width(&plane_state->base.dst); 2521e12ee3bSFrançois Tigeot uint32_t crtc_h = drm_rect_height(&plane_state->base.dst); 2531e12ee3bSFrançois Tigeot uint32_t x = plane_state->main.x; 2541e12ee3bSFrançois Tigeot uint32_t y = plane_state->main.y; 2551e12ee3bSFrançois Tigeot uint32_t src_w = drm_rect_width(&plane_state->base.src) >> 16; 2561e12ee3bSFrançois Tigeot uint32_t src_h = drm_rect_height(&plane_state->base.src) >> 16; 257*a85cb24fSFrançois Tigeot unsigned long irqflags; 258477eb7f9SFrançois Tigeot 2591e12ee3bSFrançois Tigeot /* Sizes are 0 based */ 2601e12ee3bSFrançois Tigeot src_w--; 2611e12ee3bSFrançois Tigeot src_h--; 2621e12ee3bSFrançois Tigeot crtc_w--; 2631e12ee3bSFrançois Tigeot crtc_h--; 264477eb7f9SFrançois Tigeot 265*a85cb24fSFrançois Tigeot spin_lock_irqsave(&dev_priv->uncore.lock, irqflags); 266*a85cb24fSFrançois Tigeot 267*a85cb24fSFrançois Tigeot if (IS_GEMINILAKE(dev_priv)) { 268*a85cb24fSFrançois Tigeot I915_WRITE_FW(PLANE_COLOR_CTL(pipe, plane_id), 269*a85cb24fSFrançois Tigeot PLANE_COLOR_PIPE_GAMMA_ENABLE | 270*a85cb24fSFrançois Tigeot PLANE_COLOR_PIPE_CSC_ENABLE | 271*a85cb24fSFrançois Tigeot PLANE_COLOR_PLANE_GAMMA_DISABLE); 272*a85cb24fSFrançois Tigeot } 273*a85cb24fSFrançois Tigeot 274*a85cb24fSFrançois Tigeot if (key->flags) { 275*a85cb24fSFrançois Tigeot I915_WRITE_FW(PLANE_KEYVAL(pipe, plane_id), key->min_value); 276*a85cb24fSFrançois Tigeot I915_WRITE_FW(PLANE_KEYMAX(pipe, plane_id), key->max_value); 277*a85cb24fSFrançois Tigeot I915_WRITE_FW(PLANE_KEYMSK(pipe, plane_id), key->channel_mask); 278*a85cb24fSFrançois Tigeot } 279*a85cb24fSFrançois Tigeot 280*a85cb24fSFrançois Tigeot I915_WRITE_FW(PLANE_OFFSET(pipe, plane_id), (y << 16) | x); 281*a85cb24fSFrançois Tigeot I915_WRITE_FW(PLANE_STRIDE(pipe, plane_id), stride); 282*a85cb24fSFrançois Tigeot I915_WRITE_FW(PLANE_SIZE(pipe, plane_id), (src_h << 16) | src_w); 28319c468b4SFrançois Tigeot 28419c468b4SFrançois Tigeot /* program plane scaler */ 285c0e85e96SFrançois Tigeot if (plane_state->scaler_id >= 0) { 286c0e85e96SFrançois Tigeot int scaler_id = plane_state->scaler_id; 2871487f786SFrançois Tigeot const struct intel_scaler *scaler; 28819c468b4SFrançois Tigeot 2891487f786SFrançois Tigeot scaler = &crtc_state->scaler_state.scalers[scaler_id]; 2901487f786SFrançois Tigeot 291*a85cb24fSFrançois Tigeot I915_WRITE_FW(SKL_PS_CTRL(pipe, scaler_id), 292*a85cb24fSFrançois Tigeot PS_SCALER_EN | PS_PLANE_SEL(plane_id) | scaler->mode); 293*a85cb24fSFrançois Tigeot I915_WRITE_FW(SKL_PS_PWR_GATE(pipe, scaler_id), 0); 294*a85cb24fSFrançois Tigeot I915_WRITE_FW(SKL_PS_WIN_POS(pipe, scaler_id), (crtc_x << 16) | crtc_y); 295*a85cb24fSFrançois Tigeot I915_WRITE_FW(SKL_PS_WIN_SZ(pipe, scaler_id), 29619c468b4SFrançois Tigeot ((crtc_w + 1) << 16)|(crtc_h + 1)); 29719c468b4SFrançois Tigeot 298*a85cb24fSFrançois Tigeot I915_WRITE_FW(PLANE_POS(pipe, plane_id), 0); 29919c468b4SFrançois Tigeot } else { 300*a85cb24fSFrançois Tigeot I915_WRITE_FW(PLANE_POS(pipe, plane_id), (crtc_y << 16) | crtc_x); 30119c468b4SFrançois Tigeot } 30219c468b4SFrançois Tigeot 303*a85cb24fSFrançois Tigeot I915_WRITE_FW(PLANE_CTL(pipe, plane_id), plane_ctl); 304*a85cb24fSFrançois Tigeot I915_WRITE_FW(PLANE_SURF(pipe, plane_id), 3054be47400SFrançois Tigeot intel_plane_ggtt_offset(plane_state) + surf_addr); 306*a85cb24fSFrançois Tigeot POSTING_READ_FW(PLANE_SURF(pipe, plane_id)); 307*a85cb24fSFrançois Tigeot 308*a85cb24fSFrançois Tigeot spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags); 3092c9916cdSFrançois Tigeot } 3102c9916cdSFrançois Tigeot 3112c9916cdSFrançois Tigeot static void 312a05eeebfSFrançois Tigeot skl_disable_plane(struct drm_plane *dplane, struct drm_crtc *crtc) 3132c9916cdSFrançois Tigeot { 31419c468b4SFrançois Tigeot struct drm_device *dev = dplane->dev; 315bf017597SFrançois Tigeot struct drm_i915_private *dev_priv = to_i915(dev); 31619c468b4SFrançois Tigeot struct intel_plane *intel_plane = to_intel_plane(dplane); 317*a85cb24fSFrançois Tigeot enum plane_id plane_id = intel_plane->id; 318*a85cb24fSFrançois Tigeot enum i915_pipe pipe = intel_plane->pipe; 319*a85cb24fSFrançois Tigeot unsigned long irqflags; 3202c9916cdSFrançois Tigeot 321*a85cb24fSFrançois Tigeot spin_lock_irqsave(&dev_priv->uncore.lock, irqflags); 3222c9916cdSFrançois Tigeot 323*a85cb24fSFrançois Tigeot I915_WRITE_FW(PLANE_CTL(pipe, plane_id), 0); 324*a85cb24fSFrançois Tigeot 325*a85cb24fSFrançois Tigeot I915_WRITE_FW(PLANE_SURF(pipe, plane_id), 0); 326*a85cb24fSFrançois Tigeot POSTING_READ_FW(PLANE_SURF(pipe, plane_id)); 327*a85cb24fSFrançois Tigeot 328*a85cb24fSFrançois Tigeot spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags); 3292c9916cdSFrançois Tigeot } 3302c9916cdSFrançois Tigeot 3312c9916cdSFrançois Tigeot static void 3322c9916cdSFrançois Tigeot chv_update_csc(struct intel_plane *intel_plane, uint32_t format) 3332c9916cdSFrançois Tigeot { 334bf017597SFrançois Tigeot struct drm_i915_private *dev_priv = to_i915(intel_plane->base.dev); 335*a85cb24fSFrançois Tigeot enum plane_id plane_id = intel_plane->id; 3362c9916cdSFrançois Tigeot 3372c9916cdSFrançois Tigeot /* Seems RGB data bypasses the CSC always */ 3382c9916cdSFrançois Tigeot if (!format_is_yuv(format)) 3392c9916cdSFrançois Tigeot return; 3402c9916cdSFrançois Tigeot 3412c9916cdSFrançois Tigeot /* 3422c9916cdSFrançois Tigeot * BT.601 limited range YCbCr -> full range RGB 3432c9916cdSFrançois Tigeot * 3442c9916cdSFrançois Tigeot * |r| | 6537 4769 0| |cr | 3452c9916cdSFrançois Tigeot * |g| = |-3330 4769 -1605| x |y-64| 3462c9916cdSFrançois Tigeot * |b| | 0 4769 8263| |cb | 3472c9916cdSFrançois Tigeot * 3482c9916cdSFrançois Tigeot * Cb and Cr apparently come in as signed already, so no 3492c9916cdSFrançois Tigeot * need for any offset. For Y we need to remove the offset. 3502c9916cdSFrançois Tigeot */ 351*a85cb24fSFrançois Tigeot I915_WRITE_FW(SPCSCYGOFF(plane_id), SPCSC_OOFF(0) | SPCSC_IOFF(-64)); 352*a85cb24fSFrançois Tigeot I915_WRITE_FW(SPCSCCBOFF(plane_id), SPCSC_OOFF(0) | SPCSC_IOFF(0)); 353*a85cb24fSFrançois Tigeot I915_WRITE_FW(SPCSCCROFF(plane_id), SPCSC_OOFF(0) | SPCSC_IOFF(0)); 3542c9916cdSFrançois Tigeot 355*a85cb24fSFrançois Tigeot I915_WRITE_FW(SPCSCC01(plane_id), SPCSC_C1(4769) | SPCSC_C0(6537)); 356*a85cb24fSFrançois Tigeot I915_WRITE_FW(SPCSCC23(plane_id), SPCSC_C1(-3330) | SPCSC_C0(0)); 357*a85cb24fSFrançois Tigeot I915_WRITE_FW(SPCSCC45(plane_id), SPCSC_C1(-1605) | SPCSC_C0(4769)); 358*a85cb24fSFrançois Tigeot I915_WRITE_FW(SPCSCC67(plane_id), SPCSC_C1(4769) | SPCSC_C0(0)); 359*a85cb24fSFrançois Tigeot I915_WRITE_FW(SPCSCC8(plane_id), SPCSC_C0(8263)); 3602c9916cdSFrançois Tigeot 361*a85cb24fSFrançois Tigeot I915_WRITE_FW(SPCSCYGICLAMP(plane_id), SPCSC_IMAX(940) | SPCSC_IMIN(64)); 362*a85cb24fSFrançois Tigeot I915_WRITE_FW(SPCSCCBICLAMP(plane_id), SPCSC_IMAX(448) | SPCSC_IMIN(-448)); 363*a85cb24fSFrançois Tigeot I915_WRITE_FW(SPCSCCRICLAMP(plane_id), SPCSC_IMAX(448) | SPCSC_IMIN(-448)); 3642c9916cdSFrançois Tigeot 365*a85cb24fSFrançois Tigeot I915_WRITE_FW(SPCSCYGOCLAMP(plane_id), SPCSC_OMAX(1023) | SPCSC_OMIN(0)); 366*a85cb24fSFrançois Tigeot I915_WRITE_FW(SPCSCCBOCLAMP(plane_id), SPCSC_OMAX(1023) | SPCSC_OMIN(0)); 367*a85cb24fSFrançois Tigeot I915_WRITE_FW(SPCSCCROCLAMP(plane_id), SPCSC_OMAX(1023) | SPCSC_OMIN(0)); 3682c9916cdSFrançois Tigeot } 3692c9916cdSFrançois Tigeot 370*a85cb24fSFrançois Tigeot static u32 vlv_sprite_ctl(const struct intel_crtc_state *crtc_state, 371c0e85e96SFrançois Tigeot const struct intel_plane_state *plane_state) 3728e26cdf6SFrançois Tigeot { 373*a85cb24fSFrançois Tigeot const struct drm_framebuffer *fb = plane_state->base.fb; 374*a85cb24fSFrançois Tigeot unsigned int rotation = plane_state->base.rotation; 375c0e85e96SFrançois Tigeot const struct drm_intel_sprite_colorkey *key = &plane_state->ckey; 376*a85cb24fSFrançois Tigeot u32 sprctl; 3778e26cdf6SFrançois Tigeot 378*a85cb24fSFrançois Tigeot sprctl = SP_ENABLE | SP_GAMMA_ENABLE; 3798e26cdf6SFrançois Tigeot 380*a85cb24fSFrançois Tigeot switch (fb->format->format) { 3818e26cdf6SFrançois Tigeot case DRM_FORMAT_YUYV: 3828e26cdf6SFrançois Tigeot sprctl |= SP_FORMAT_YUV422 | SP_YUV_ORDER_YUYV; 3838e26cdf6SFrançois Tigeot break; 3848e26cdf6SFrançois Tigeot case DRM_FORMAT_YVYU: 3858e26cdf6SFrançois Tigeot sprctl |= SP_FORMAT_YUV422 | SP_YUV_ORDER_YVYU; 3868e26cdf6SFrançois Tigeot break; 3878e26cdf6SFrançois Tigeot case DRM_FORMAT_UYVY: 3888e26cdf6SFrançois Tigeot sprctl |= SP_FORMAT_YUV422 | SP_YUV_ORDER_UYVY; 3898e26cdf6SFrançois Tigeot break; 3908e26cdf6SFrançois Tigeot case DRM_FORMAT_VYUY: 3918e26cdf6SFrançois Tigeot sprctl |= SP_FORMAT_YUV422 | SP_YUV_ORDER_VYUY; 3928e26cdf6SFrançois Tigeot break; 3938e26cdf6SFrançois Tigeot case DRM_FORMAT_RGB565: 3948e26cdf6SFrançois Tigeot sprctl |= SP_FORMAT_BGR565; 3958e26cdf6SFrançois Tigeot break; 3968e26cdf6SFrançois Tigeot case DRM_FORMAT_XRGB8888: 3978e26cdf6SFrançois Tigeot sprctl |= SP_FORMAT_BGRX8888; 3988e26cdf6SFrançois Tigeot break; 3998e26cdf6SFrançois Tigeot case DRM_FORMAT_ARGB8888: 4008e26cdf6SFrançois Tigeot sprctl |= SP_FORMAT_BGRA8888; 4018e26cdf6SFrançois Tigeot break; 4028e26cdf6SFrançois Tigeot case DRM_FORMAT_XBGR2101010: 4038e26cdf6SFrançois Tigeot sprctl |= SP_FORMAT_RGBX1010102; 4048e26cdf6SFrançois Tigeot break; 4058e26cdf6SFrançois Tigeot case DRM_FORMAT_ABGR2101010: 4068e26cdf6SFrançois Tigeot sprctl |= SP_FORMAT_RGBA1010102; 4078e26cdf6SFrançois Tigeot break; 4088e26cdf6SFrançois Tigeot case DRM_FORMAT_XBGR8888: 4098e26cdf6SFrançois Tigeot sprctl |= SP_FORMAT_RGBX8888; 4108e26cdf6SFrançois Tigeot break; 4118e26cdf6SFrançois Tigeot case DRM_FORMAT_ABGR8888: 4128e26cdf6SFrançois Tigeot sprctl |= SP_FORMAT_RGBA8888; 4138e26cdf6SFrançois Tigeot break; 4148e26cdf6SFrançois Tigeot default: 415*a85cb24fSFrançois Tigeot MISSING_CASE(fb->format->format); 416*a85cb24fSFrançois Tigeot return 0; 4178e26cdf6SFrançois Tigeot } 4188e26cdf6SFrançois Tigeot 4194be47400SFrançois Tigeot if (fb->modifier == I915_FORMAT_MOD_X_TILED) 4208e26cdf6SFrançois Tigeot sprctl |= SP_TILED; 4218e26cdf6SFrançois Tigeot 4224be47400SFrançois Tigeot if (rotation & DRM_ROTATE_180) 4234be47400SFrançois Tigeot sprctl |= SP_ROTATE_180; 4244be47400SFrançois Tigeot 4254be47400SFrançois Tigeot if (rotation & DRM_REFLECT_X) 4264be47400SFrançois Tigeot sprctl |= SP_MIRROR; 4274be47400SFrançois Tigeot 428477eb7f9SFrançois Tigeot if (key->flags & I915_SET_COLORKEY_SOURCE) 429477eb7f9SFrançois Tigeot sprctl |= SP_SOURCE_KEY; 430477eb7f9SFrançois Tigeot 431*a85cb24fSFrançois Tigeot return sprctl; 432*a85cb24fSFrançois Tigeot } 4332c9916cdSFrançois Tigeot 434*a85cb24fSFrançois Tigeot static void 435*a85cb24fSFrançois Tigeot vlv_update_plane(struct drm_plane *dplane, 436*a85cb24fSFrançois Tigeot const struct intel_crtc_state *crtc_state, 437*a85cb24fSFrançois Tigeot const struct intel_plane_state *plane_state) 438*a85cb24fSFrançois Tigeot { 439*a85cb24fSFrançois Tigeot struct drm_device *dev = dplane->dev; 440*a85cb24fSFrançois Tigeot struct drm_i915_private *dev_priv = to_i915(dev); 441*a85cb24fSFrançois Tigeot struct intel_plane *intel_plane = to_intel_plane(dplane); 442*a85cb24fSFrançois Tigeot struct drm_framebuffer *fb = plane_state->base.fb; 443*a85cb24fSFrançois Tigeot enum i915_pipe pipe = intel_plane->pipe; 444*a85cb24fSFrançois Tigeot enum plane_id plane_id = intel_plane->id; 445*a85cb24fSFrançois Tigeot u32 sprctl = plane_state->ctl; 446*a85cb24fSFrançois Tigeot u32 sprsurf_offset = plane_state->main.offset; 447*a85cb24fSFrançois Tigeot u32 linear_offset; 448*a85cb24fSFrançois Tigeot const struct drm_intel_sprite_colorkey *key = &plane_state->ckey; 449*a85cb24fSFrançois Tigeot int crtc_x = plane_state->base.dst.x1; 450*a85cb24fSFrançois Tigeot int crtc_y = plane_state->base.dst.y1; 451*a85cb24fSFrançois Tigeot uint32_t crtc_w = drm_rect_width(&plane_state->base.dst); 452*a85cb24fSFrançois Tigeot uint32_t crtc_h = drm_rect_height(&plane_state->base.dst); 453*a85cb24fSFrançois Tigeot uint32_t x = plane_state->main.x; 454*a85cb24fSFrançois Tigeot uint32_t y = plane_state->main.y; 455*a85cb24fSFrançois Tigeot unsigned long irqflags; 456*a85cb24fSFrançois Tigeot 457*a85cb24fSFrançois Tigeot /* Sizes are 0 based */ 458*a85cb24fSFrançois Tigeot crtc_w--; 459*a85cb24fSFrançois Tigeot crtc_h--; 460*a85cb24fSFrançois Tigeot 461*a85cb24fSFrançois Tigeot linear_offset = intel_fb_xy_to_linear(x, y, plane_state, 0); 462*a85cb24fSFrançois Tigeot 463*a85cb24fSFrançois Tigeot spin_lock_irqsave(&dev_priv->uncore.lock, irqflags); 464*a85cb24fSFrançois Tigeot 465*a85cb24fSFrançois Tigeot if (IS_CHERRYVIEW(dev_priv) && pipe == PIPE_B) 466*a85cb24fSFrançois Tigeot chv_update_csc(intel_plane, fb->format->format); 467*a85cb24fSFrançois Tigeot 468*a85cb24fSFrançois Tigeot if (key->flags) { 469*a85cb24fSFrançois Tigeot I915_WRITE_FW(SPKEYMINVAL(pipe, plane_id), key->min_value); 470*a85cb24fSFrançois Tigeot I915_WRITE_FW(SPKEYMAXVAL(pipe, plane_id), key->max_value); 471*a85cb24fSFrançois Tigeot I915_WRITE_FW(SPKEYMSK(pipe, plane_id), key->channel_mask); 472*a85cb24fSFrançois Tigeot } 473*a85cb24fSFrançois Tigeot I915_WRITE_FW(SPSTRIDE(pipe, plane_id), fb->pitches[0]); 474*a85cb24fSFrançois Tigeot I915_WRITE_FW(SPPOS(pipe, plane_id), (crtc_y << 16) | crtc_x); 475ba55f2f5SFrançois Tigeot 4764be47400SFrançois Tigeot if (fb->modifier == I915_FORMAT_MOD_X_TILED) 477*a85cb24fSFrançois Tigeot I915_WRITE_FW(SPTILEOFF(pipe, plane_id), (y << 16) | x); 4788e26cdf6SFrançois Tigeot else 479*a85cb24fSFrançois Tigeot I915_WRITE_FW(SPLINOFF(pipe, plane_id), linear_offset); 4808e26cdf6SFrançois Tigeot 481*a85cb24fSFrançois Tigeot I915_WRITE_FW(SPCONSTALPHA(pipe, plane_id), 0); 4822c9916cdSFrançois Tigeot 483*a85cb24fSFrançois Tigeot I915_WRITE_FW(SPSIZE(pipe, plane_id), (crtc_h << 16) | crtc_w); 484*a85cb24fSFrançois Tigeot I915_WRITE_FW(SPCNTR(pipe, plane_id), sprctl); 485*a85cb24fSFrançois Tigeot I915_WRITE_FW(SPSURF(pipe, plane_id), 4864be47400SFrançois Tigeot intel_plane_ggtt_offset(plane_state) + sprsurf_offset); 487*a85cb24fSFrançois Tigeot POSTING_READ_FW(SPSURF(pipe, plane_id)); 488*a85cb24fSFrançois Tigeot 489*a85cb24fSFrançois Tigeot spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags); 4908e26cdf6SFrançois Tigeot } 4918e26cdf6SFrançois Tigeot 4928e26cdf6SFrançois Tigeot static void 493a05eeebfSFrançois Tigeot vlv_disable_plane(struct drm_plane *dplane, struct drm_crtc *crtc) 4948e26cdf6SFrançois Tigeot { 4958e26cdf6SFrançois Tigeot struct drm_device *dev = dplane->dev; 496bf017597SFrançois Tigeot struct drm_i915_private *dev_priv = to_i915(dev); 4978e26cdf6SFrançois Tigeot struct intel_plane *intel_plane = to_intel_plane(dplane); 498*a85cb24fSFrançois Tigeot enum i915_pipe pipe = intel_plane->pipe; 499*a85cb24fSFrançois Tigeot enum plane_id plane_id = intel_plane->id; 500*a85cb24fSFrançois Tigeot unsigned long irqflags; 501ba55f2f5SFrançois Tigeot 502*a85cb24fSFrançois Tigeot spin_lock_irqsave(&dev_priv->uncore.lock, irqflags); 503477eb7f9SFrançois Tigeot 504*a85cb24fSFrançois Tigeot I915_WRITE_FW(SPCNTR(pipe, plane_id), 0); 505*a85cb24fSFrançois Tigeot 506*a85cb24fSFrançois Tigeot I915_WRITE_FW(SPSURF(pipe, plane_id), 0); 507*a85cb24fSFrançois Tigeot POSTING_READ_FW(SPSURF(pipe, plane_id)); 508*a85cb24fSFrançois Tigeot 509*a85cb24fSFrançois Tigeot spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags); 5108e26cdf6SFrançois Tigeot } 5118e26cdf6SFrançois Tigeot 512*a85cb24fSFrançois Tigeot static u32 ivb_sprite_ctl(const struct intel_crtc_state *crtc_state, 513c0e85e96SFrançois Tigeot const struct intel_plane_state *plane_state) 514e3adcf8fSFrançois Tigeot { 515*a85cb24fSFrançois Tigeot struct drm_i915_private *dev_priv = 516*a85cb24fSFrançois Tigeot to_i915(plane_state->base.plane->dev); 517*a85cb24fSFrançois Tigeot const struct drm_framebuffer *fb = plane_state->base.fb; 5188621f407SFrançois Tigeot unsigned int rotation = plane_state->base.rotation; 519c0e85e96SFrançois Tigeot const struct drm_intel_sprite_colorkey *key = &plane_state->ckey; 520*a85cb24fSFrançois Tigeot u32 sprctl; 521e3adcf8fSFrançois Tigeot 522*a85cb24fSFrançois Tigeot sprctl = SPRITE_ENABLE | SPRITE_GAMMA_ENABLE; 523e3adcf8fSFrançois Tigeot 524*a85cb24fSFrançois Tigeot if (IS_IVYBRIDGE(dev_priv)) 525*a85cb24fSFrançois Tigeot sprctl |= SPRITE_TRICKLE_FEED_DISABLE; 526*a85cb24fSFrançois Tigeot 527*a85cb24fSFrançois Tigeot if (IS_HASWELL(dev_priv) || IS_BROADWELL(dev_priv)) 528*a85cb24fSFrançois Tigeot sprctl |= SPRITE_PIPE_CSC_ENABLE; 529*a85cb24fSFrançois Tigeot 530*a85cb24fSFrançois Tigeot switch (fb->format->format) { 531e3adcf8fSFrançois Tigeot case DRM_FORMAT_XBGR8888: 5322c84b0b6SFrançois Tigeot sprctl |= SPRITE_FORMAT_RGBX888 | SPRITE_RGB_ORDER_RGBX; 533e3adcf8fSFrançois Tigeot break; 534e3adcf8fSFrançois Tigeot case DRM_FORMAT_XRGB8888: 5352c84b0b6SFrançois Tigeot sprctl |= SPRITE_FORMAT_RGBX888; 536e3adcf8fSFrançois Tigeot break; 537e3adcf8fSFrançois Tigeot case DRM_FORMAT_YUYV: 538e3adcf8fSFrançois Tigeot sprctl |= SPRITE_FORMAT_YUV422 | SPRITE_YUV_ORDER_YUYV; 539e3adcf8fSFrançois Tigeot break; 540e3adcf8fSFrançois Tigeot case DRM_FORMAT_YVYU: 541e3adcf8fSFrançois Tigeot sprctl |= SPRITE_FORMAT_YUV422 | SPRITE_YUV_ORDER_YVYU; 542e3adcf8fSFrançois Tigeot break; 543e3adcf8fSFrançois Tigeot case DRM_FORMAT_UYVY: 544e3adcf8fSFrançois Tigeot sprctl |= SPRITE_FORMAT_YUV422 | SPRITE_YUV_ORDER_UYVY; 545e3adcf8fSFrançois Tigeot break; 546e3adcf8fSFrançois Tigeot case DRM_FORMAT_VYUY: 547e3adcf8fSFrançois Tigeot sprctl |= SPRITE_FORMAT_YUV422 | SPRITE_YUV_ORDER_VYUY; 548e3adcf8fSFrançois Tigeot break; 549e3adcf8fSFrançois Tigeot default: 550*a85cb24fSFrançois Tigeot MISSING_CASE(fb->format->format); 551*a85cb24fSFrançois Tigeot return 0; 552e3adcf8fSFrançois Tigeot } 553e3adcf8fSFrançois Tigeot 5544be47400SFrançois Tigeot if (fb->modifier == I915_FORMAT_MOD_X_TILED) 555e3adcf8fSFrançois Tigeot sprctl |= SPRITE_TILED; 556e3adcf8fSFrançois Tigeot 5574be47400SFrançois Tigeot if (rotation & DRM_ROTATE_180) 5584be47400SFrançois Tigeot sprctl |= SPRITE_ROTATE_180; 5594be47400SFrançois Tigeot 560*a85cb24fSFrançois Tigeot if (key->flags & I915_SET_COLORKEY_DESTINATION) 561*a85cb24fSFrançois Tigeot sprctl |= SPRITE_DEST_KEY; 562*a85cb24fSFrançois Tigeot else if (key->flags & I915_SET_COLORKEY_SOURCE) 563*a85cb24fSFrançois Tigeot sprctl |= SPRITE_SOURCE_KEY; 5649edbd4a0SFrançois Tigeot 565*a85cb24fSFrançois Tigeot return sprctl; 566*a85cb24fSFrançois Tigeot } 567*a85cb24fSFrançois Tigeot 568*a85cb24fSFrançois Tigeot static void 569*a85cb24fSFrançois Tigeot ivb_update_plane(struct drm_plane *plane, 570*a85cb24fSFrançois Tigeot const struct intel_crtc_state *crtc_state, 571*a85cb24fSFrançois Tigeot const struct intel_plane_state *plane_state) 572*a85cb24fSFrançois Tigeot { 573*a85cb24fSFrançois Tigeot struct drm_device *dev = plane->dev; 574*a85cb24fSFrançois Tigeot struct drm_i915_private *dev_priv = to_i915(dev); 575*a85cb24fSFrançois Tigeot struct intel_plane *intel_plane = to_intel_plane(plane); 576*a85cb24fSFrançois Tigeot struct drm_framebuffer *fb = plane_state->base.fb; 577*a85cb24fSFrançois Tigeot enum i915_pipe pipe = intel_plane->pipe; 578*a85cb24fSFrançois Tigeot u32 sprctl = plane_state->ctl, sprscale = 0; 579*a85cb24fSFrançois Tigeot u32 sprsurf_offset = plane_state->main.offset; 580*a85cb24fSFrançois Tigeot u32 linear_offset; 581*a85cb24fSFrançois Tigeot const struct drm_intel_sprite_colorkey *key = &plane_state->ckey; 582*a85cb24fSFrançois Tigeot int crtc_x = plane_state->base.dst.x1; 583*a85cb24fSFrançois Tigeot int crtc_y = plane_state->base.dst.y1; 584*a85cb24fSFrançois Tigeot uint32_t crtc_w = drm_rect_width(&plane_state->base.dst); 585*a85cb24fSFrançois Tigeot uint32_t crtc_h = drm_rect_height(&plane_state->base.dst); 586*a85cb24fSFrançois Tigeot uint32_t x = plane_state->main.x; 587*a85cb24fSFrançois Tigeot uint32_t y = plane_state->main.y; 588*a85cb24fSFrançois Tigeot uint32_t src_w = drm_rect_width(&plane_state->base.src) >> 16; 589*a85cb24fSFrançois Tigeot uint32_t src_h = drm_rect_height(&plane_state->base.src) >> 16; 590*a85cb24fSFrançois Tigeot unsigned long irqflags; 591a2fdbec6SFrançois Tigeot 592e3adcf8fSFrançois Tigeot /* Sizes are 0 based */ 593e3adcf8fSFrançois Tigeot src_w--; 594e3adcf8fSFrançois Tigeot src_h--; 595e3adcf8fSFrançois Tigeot crtc_w--; 596e3adcf8fSFrançois Tigeot crtc_h--; 597e3adcf8fSFrançois Tigeot 5989edbd4a0SFrançois Tigeot if (crtc_w != src_w || crtc_h != src_h) 599e3adcf8fSFrançois Tigeot sprscale = SPRITE_SCALE_ENABLE | (src_w << 16) | src_h; 600e3adcf8fSFrançois Tigeot 6011e12ee3bSFrançois Tigeot linear_offset = intel_fb_xy_to_linear(x, y, plane_state, 0); 6021e12ee3bSFrançois Tigeot 603*a85cb24fSFrançois Tigeot spin_lock_irqsave(&dev_priv->uncore.lock, irqflags); 604*a85cb24fSFrançois Tigeot 605477eb7f9SFrançois Tigeot if (key->flags) { 606*a85cb24fSFrançois Tigeot I915_WRITE_FW(SPRKEYVAL(pipe), key->min_value); 607*a85cb24fSFrançois Tigeot I915_WRITE_FW(SPRKEYMAX(pipe), key->max_value); 608*a85cb24fSFrançois Tigeot I915_WRITE_FW(SPRKEYMSK(pipe), key->channel_mask); 609477eb7f9SFrançois Tigeot } 610477eb7f9SFrançois Tigeot 611*a85cb24fSFrançois Tigeot I915_WRITE_FW(SPRSTRIDE(pipe), fb->pitches[0]); 612*a85cb24fSFrançois Tigeot I915_WRITE_FW(SPRPOS(pipe), (crtc_y << 16) | crtc_x); 613ba55f2f5SFrançois Tigeot 6142c84b0b6SFrançois Tigeot /* HSW consolidates SPRTILEOFF and SPRLINOFF into a single SPROFFSET 6152c84b0b6SFrançois Tigeot * register */ 6161e12ee3bSFrançois Tigeot if (IS_HASWELL(dev_priv) || IS_BROADWELL(dev_priv)) 617*a85cb24fSFrançois Tigeot I915_WRITE_FW(SPROFFSET(pipe), (y << 16) | x); 6184be47400SFrançois Tigeot else if (fb->modifier == I915_FORMAT_MOD_X_TILED) 619*a85cb24fSFrançois Tigeot I915_WRITE_FW(SPRTILEOFF(pipe), (y << 16) | x); 6202c84b0b6SFrançois Tigeot else 621*a85cb24fSFrançois Tigeot I915_WRITE_FW(SPRLINOFF(pipe), linear_offset); 6222c84b0b6SFrançois Tigeot 623*a85cb24fSFrançois Tigeot I915_WRITE_FW(SPRSIZE(pipe), (crtc_h << 16) | crtc_w); 6242c84b0b6SFrançois Tigeot if (intel_plane->can_scale) 625*a85cb24fSFrançois Tigeot I915_WRITE_FW(SPRSCALE(pipe), sprscale); 626*a85cb24fSFrançois Tigeot I915_WRITE_FW(SPRCTL(pipe), sprctl); 627*a85cb24fSFrançois Tigeot I915_WRITE_FW(SPRSURF(pipe), 6284be47400SFrançois Tigeot intel_plane_ggtt_offset(plane_state) + sprsurf_offset); 629*a85cb24fSFrançois Tigeot POSTING_READ_FW(SPRSURF(pipe)); 630*a85cb24fSFrançois Tigeot 631*a85cb24fSFrançois Tigeot spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags); 632e3adcf8fSFrançois Tigeot } 633e3adcf8fSFrançois Tigeot 634e3adcf8fSFrançois Tigeot static void 635a05eeebfSFrançois Tigeot ivb_disable_plane(struct drm_plane *plane, struct drm_crtc *crtc) 636e3adcf8fSFrançois Tigeot { 637e3adcf8fSFrançois Tigeot struct drm_device *dev = plane->dev; 638bf017597SFrançois Tigeot struct drm_i915_private *dev_priv = to_i915(dev); 639e3adcf8fSFrançois Tigeot struct intel_plane *intel_plane = to_intel_plane(plane); 640e3adcf8fSFrançois Tigeot int pipe = intel_plane->pipe; 641*a85cb24fSFrançois Tigeot unsigned long irqflags; 642ba55f2f5SFrançois Tigeot 643*a85cb24fSFrançois Tigeot spin_lock_irqsave(&dev_priv->uncore.lock, irqflags); 644*a85cb24fSFrançois Tigeot 645*a85cb24fSFrançois Tigeot I915_WRITE_FW(SPRCTL(pipe), 0); 646e3adcf8fSFrançois Tigeot /* Can't leave the scaler enabled... */ 6472c84b0b6SFrançois Tigeot if (intel_plane->can_scale) 648*a85cb24fSFrançois Tigeot I915_WRITE_FW(SPRSCALE(pipe), 0); 649ba55f2f5SFrançois Tigeot 650*a85cb24fSFrançois Tigeot I915_WRITE_FW(SPRSURF(pipe), 0); 651*a85cb24fSFrançois Tigeot POSTING_READ_FW(SPRSURF(pipe)); 652*a85cb24fSFrançois Tigeot 653*a85cb24fSFrançois Tigeot spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags); 654e3adcf8fSFrançois Tigeot } 655e3adcf8fSFrançois Tigeot 656*a85cb24fSFrançois Tigeot static u32 ilk_sprite_ctl(const struct intel_crtc_state *crtc_state, 657c0e85e96SFrançois Tigeot const struct intel_plane_state *plane_state) 658e3adcf8fSFrançois Tigeot { 659*a85cb24fSFrançois Tigeot struct drm_i915_private *dev_priv = 660*a85cb24fSFrançois Tigeot to_i915(plane_state->base.plane->dev); 661*a85cb24fSFrançois Tigeot const struct drm_framebuffer *fb = plane_state->base.fb; 6628621f407SFrançois Tigeot unsigned int rotation = plane_state->base.rotation; 663c0e85e96SFrançois Tigeot const struct drm_intel_sprite_colorkey *key = &plane_state->ckey; 664*a85cb24fSFrançois Tigeot u32 dvscntr; 665e3adcf8fSFrançois Tigeot 666*a85cb24fSFrançois Tigeot dvscntr = DVS_ENABLE | DVS_GAMMA_ENABLE; 667e3adcf8fSFrançois Tigeot 668*a85cb24fSFrançois Tigeot if (IS_GEN6(dev_priv)) 669*a85cb24fSFrançois Tigeot dvscntr |= DVS_TRICKLE_FEED_DISABLE; 670*a85cb24fSFrançois Tigeot 671*a85cb24fSFrançois Tigeot switch (fb->format->format) { 672e3adcf8fSFrançois Tigeot case DRM_FORMAT_XBGR8888: 673e3adcf8fSFrançois Tigeot dvscntr |= DVS_FORMAT_RGBX888 | DVS_RGB_ORDER_XBGR; 674e3adcf8fSFrançois Tigeot break; 675e3adcf8fSFrançois Tigeot case DRM_FORMAT_XRGB8888: 676e3adcf8fSFrançois Tigeot dvscntr |= DVS_FORMAT_RGBX888; 677e3adcf8fSFrançois Tigeot break; 678e3adcf8fSFrançois Tigeot case DRM_FORMAT_YUYV: 679e3adcf8fSFrançois Tigeot dvscntr |= DVS_FORMAT_YUV422 | DVS_YUV_ORDER_YUYV; 680e3adcf8fSFrançois Tigeot break; 681e3adcf8fSFrançois Tigeot case DRM_FORMAT_YVYU: 682e3adcf8fSFrançois Tigeot dvscntr |= DVS_FORMAT_YUV422 | DVS_YUV_ORDER_YVYU; 683e3adcf8fSFrançois Tigeot break; 684e3adcf8fSFrançois Tigeot case DRM_FORMAT_UYVY: 685e3adcf8fSFrançois Tigeot dvscntr |= DVS_FORMAT_YUV422 | DVS_YUV_ORDER_UYVY; 686e3adcf8fSFrançois Tigeot break; 687e3adcf8fSFrançois Tigeot case DRM_FORMAT_VYUY: 688e3adcf8fSFrançois Tigeot dvscntr |= DVS_FORMAT_YUV422 | DVS_YUV_ORDER_VYUY; 689e3adcf8fSFrançois Tigeot break; 690e3adcf8fSFrançois Tigeot default: 691*a85cb24fSFrançois Tigeot MISSING_CASE(fb->format->format); 692*a85cb24fSFrançois Tigeot return 0; 693e3adcf8fSFrançois Tigeot } 694e3adcf8fSFrançois Tigeot 6954be47400SFrançois Tigeot if (fb->modifier == I915_FORMAT_MOD_X_TILED) 696e3adcf8fSFrançois Tigeot dvscntr |= DVS_TILED; 697e3adcf8fSFrançois Tigeot 6984be47400SFrançois Tigeot if (rotation & DRM_ROTATE_180) 6994be47400SFrançois Tigeot dvscntr |= DVS_ROTATE_180; 7004be47400SFrançois Tigeot 701*a85cb24fSFrançois Tigeot if (key->flags & I915_SET_COLORKEY_DESTINATION) 702*a85cb24fSFrançois Tigeot dvscntr |= DVS_DEST_KEY; 703*a85cb24fSFrançois Tigeot else if (key->flags & I915_SET_COLORKEY_SOURCE) 704*a85cb24fSFrançois Tigeot dvscntr |= DVS_SOURCE_KEY; 705*a85cb24fSFrançois Tigeot 706*a85cb24fSFrançois Tigeot return dvscntr; 707*a85cb24fSFrançois Tigeot } 708*a85cb24fSFrançois Tigeot 709*a85cb24fSFrançois Tigeot static void 710*a85cb24fSFrançois Tigeot ilk_update_plane(struct drm_plane *plane, 711*a85cb24fSFrançois Tigeot const struct intel_crtc_state *crtc_state, 712*a85cb24fSFrançois Tigeot const struct intel_plane_state *plane_state) 713*a85cb24fSFrançois Tigeot { 714*a85cb24fSFrançois Tigeot struct drm_device *dev = plane->dev; 715*a85cb24fSFrançois Tigeot struct drm_i915_private *dev_priv = to_i915(dev); 716*a85cb24fSFrançois Tigeot struct intel_plane *intel_plane = to_intel_plane(plane); 717*a85cb24fSFrançois Tigeot struct drm_framebuffer *fb = plane_state->base.fb; 718*a85cb24fSFrançois Tigeot int pipe = intel_plane->pipe; 719*a85cb24fSFrançois Tigeot u32 dvscntr = plane_state->ctl, dvsscale = 0; 720*a85cb24fSFrançois Tigeot u32 dvssurf_offset = plane_state->main.offset; 721*a85cb24fSFrançois Tigeot u32 linear_offset; 722*a85cb24fSFrançois Tigeot const struct drm_intel_sprite_colorkey *key = &plane_state->ckey; 723*a85cb24fSFrançois Tigeot int crtc_x = plane_state->base.dst.x1; 724*a85cb24fSFrançois Tigeot int crtc_y = plane_state->base.dst.y1; 725*a85cb24fSFrançois Tigeot uint32_t crtc_w = drm_rect_width(&plane_state->base.dst); 726*a85cb24fSFrançois Tigeot uint32_t crtc_h = drm_rect_height(&plane_state->base.dst); 727*a85cb24fSFrançois Tigeot uint32_t x = plane_state->main.x; 728*a85cb24fSFrançois Tigeot uint32_t y = plane_state->main.y; 729*a85cb24fSFrançois Tigeot uint32_t src_w = drm_rect_width(&plane_state->base.src) >> 16; 730*a85cb24fSFrançois Tigeot uint32_t src_h = drm_rect_height(&plane_state->base.src) >> 16; 731*a85cb24fSFrançois Tigeot unsigned long irqflags; 732e3adcf8fSFrançois Tigeot 733e3adcf8fSFrançois Tigeot /* Sizes are 0 based */ 734e3adcf8fSFrançois Tigeot src_w--; 735e3adcf8fSFrançois Tigeot src_h--; 736e3adcf8fSFrançois Tigeot crtc_w--; 737e3adcf8fSFrançois Tigeot crtc_h--; 738e3adcf8fSFrançois Tigeot 7399edbd4a0SFrançois Tigeot if (crtc_w != src_w || crtc_h != src_h) 740e3adcf8fSFrançois Tigeot dvsscale = DVS_SCALE_ENABLE | (src_w << 16) | src_h; 741e3adcf8fSFrançois Tigeot 7421e12ee3bSFrançois Tigeot linear_offset = intel_fb_xy_to_linear(x, y, plane_state, 0); 7431e12ee3bSFrançois Tigeot 744*a85cb24fSFrançois Tigeot spin_lock_irqsave(&dev_priv->uncore.lock, irqflags); 745*a85cb24fSFrançois Tigeot 746477eb7f9SFrançois Tigeot if (key->flags) { 747*a85cb24fSFrançois Tigeot I915_WRITE_FW(DVSKEYVAL(pipe), key->min_value); 748*a85cb24fSFrançois Tigeot I915_WRITE_FW(DVSKEYMAX(pipe), key->max_value); 749*a85cb24fSFrançois Tigeot I915_WRITE_FW(DVSKEYMSK(pipe), key->channel_mask); 750477eb7f9SFrançois Tigeot } 751477eb7f9SFrançois Tigeot 752*a85cb24fSFrançois Tigeot I915_WRITE_FW(DVSSTRIDE(pipe), fb->pitches[0]); 753*a85cb24fSFrançois Tigeot I915_WRITE_FW(DVSPOS(pipe), (crtc_y << 16) | crtc_x); 754ba55f2f5SFrançois Tigeot 7554be47400SFrançois Tigeot if (fb->modifier == I915_FORMAT_MOD_X_TILED) 756*a85cb24fSFrançois Tigeot I915_WRITE_FW(DVSTILEOFF(pipe), (y << 16) | x); 7572c84b0b6SFrançois Tigeot else 758*a85cb24fSFrançois Tigeot I915_WRITE_FW(DVSLINOFF(pipe), linear_offset); 7592c84b0b6SFrançois Tigeot 760*a85cb24fSFrançois Tigeot I915_WRITE_FW(DVSSIZE(pipe), (crtc_h << 16) | crtc_w); 761*a85cb24fSFrançois Tigeot I915_WRITE_FW(DVSSCALE(pipe), dvsscale); 762*a85cb24fSFrançois Tigeot I915_WRITE_FW(DVSCNTR(pipe), dvscntr); 763*a85cb24fSFrançois Tigeot I915_WRITE_FW(DVSSURF(pipe), 7644be47400SFrançois Tigeot intel_plane_ggtt_offset(plane_state) + dvssurf_offset); 765*a85cb24fSFrançois Tigeot POSTING_READ_FW(DVSSURF(pipe)); 766*a85cb24fSFrançois Tigeot 767*a85cb24fSFrançois Tigeot spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags); 768e3adcf8fSFrançois Tigeot } 769e3adcf8fSFrançois Tigeot 770e3adcf8fSFrançois Tigeot static void 771a05eeebfSFrançois Tigeot ilk_disable_plane(struct drm_plane *plane, struct drm_crtc *crtc) 772e3adcf8fSFrançois Tigeot { 773e3adcf8fSFrançois Tigeot struct drm_device *dev = plane->dev; 774bf017597SFrançois Tigeot struct drm_i915_private *dev_priv = to_i915(dev); 775e3adcf8fSFrançois Tigeot struct intel_plane *intel_plane = to_intel_plane(plane); 776e3adcf8fSFrançois Tigeot int pipe = intel_plane->pipe; 777*a85cb24fSFrançois Tigeot unsigned long irqflags; 778ba55f2f5SFrançois Tigeot 779*a85cb24fSFrançois Tigeot spin_lock_irqsave(&dev_priv->uncore.lock, irqflags); 780*a85cb24fSFrançois Tigeot 781*a85cb24fSFrançois Tigeot I915_WRITE_FW(DVSCNTR(pipe), 0); 782e3adcf8fSFrançois Tigeot /* Disable the scaler */ 783*a85cb24fSFrançois Tigeot I915_WRITE_FW(DVSSCALE(pipe), 0); 784477eb7f9SFrançois Tigeot 785*a85cb24fSFrançois Tigeot I915_WRITE_FW(DVSSURF(pipe), 0); 786*a85cb24fSFrançois Tigeot POSTING_READ_FW(DVSSURF(pipe)); 787*a85cb24fSFrançois Tigeot 788*a85cb24fSFrançois Tigeot spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags); 7899edbd4a0SFrançois Tigeot } 7909edbd4a0SFrançois Tigeot 791e3adcf8fSFrançois Tigeot static int 7922c9916cdSFrançois Tigeot intel_check_sprite_plane(struct drm_plane *plane, 793a05eeebfSFrançois Tigeot struct intel_crtc_state *crtc_state, 7942c9916cdSFrançois Tigeot struct intel_plane_state *state) 795e3adcf8fSFrançois Tigeot { 7961e12ee3bSFrançois Tigeot struct drm_i915_private *dev_priv = to_i915(plane->dev); 797a05eeebfSFrançois Tigeot struct drm_crtc *crtc = state->base.crtc; 798a05eeebfSFrançois Tigeot struct intel_crtc *intel_crtc = to_intel_crtc(crtc); 799e3adcf8fSFrançois Tigeot struct intel_plane *intel_plane = to_intel_plane(plane); 8002c9916cdSFrançois Tigeot struct drm_framebuffer *fb = state->base.fb; 8019edbd4a0SFrançois Tigeot int crtc_x, crtc_y; 8029edbd4a0SFrançois Tigeot unsigned int crtc_w, crtc_h; 8039edbd4a0SFrançois Tigeot uint32_t src_x, src_y, src_w, src_h; 8041e12ee3bSFrançois Tigeot struct drm_rect *src = &state->base.src; 8051e12ee3bSFrançois Tigeot struct drm_rect *dst = &state->base.dst; 8062c9916cdSFrançois Tigeot const struct drm_rect *clip = &state->clip; 8072c9916cdSFrançois Tigeot int hscale, vscale; 8082c9916cdSFrançois Tigeot int max_scale, min_scale; 80919c468b4SFrançois Tigeot bool can_scale; 8101e12ee3bSFrançois Tigeot int ret; 8111e12ee3bSFrançois Tigeot 8124be47400SFrançois Tigeot *src = drm_plane_state_src(&state->base); 8134be47400SFrançois Tigeot *dst = drm_plane_state_dest(&state->base); 8142c9916cdSFrançois Tigeot 8152c9916cdSFrançois Tigeot if (!fb) { 8161e12ee3bSFrançois Tigeot state->base.visible = false; 817a05eeebfSFrançois Tigeot return 0; 8182c9916cdSFrançois Tigeot } 819e3adcf8fSFrançois Tigeot 820e3adcf8fSFrançois Tigeot /* Don't modify another pipe's plane */ 8215d0b1887SFrançois Tigeot if (intel_plane->pipe != intel_crtc->pipe) { 8225d0b1887SFrançois Tigeot DRM_DEBUG_KMS("Wrong plane <-> crtc mapping\n"); 823e3adcf8fSFrançois Tigeot return -EINVAL; 8245d0b1887SFrançois Tigeot } 8255d0b1887SFrançois Tigeot 8265d0b1887SFrançois Tigeot /* FIXME check all gen limits */ 8275d0b1887SFrançois Tigeot if (fb->width < 3 || fb->height < 3 || fb->pitches[0] > 16384) { 8285d0b1887SFrançois Tigeot DRM_DEBUG_KMS("Unsuitable framebuffer for plane\n"); 8295d0b1887SFrançois Tigeot return -EINVAL; 8305d0b1887SFrançois Tigeot } 831e3adcf8fSFrançois Tigeot 83219c468b4SFrançois Tigeot /* setup can_scale, min_scale, max_scale */ 8331e12ee3bSFrançois Tigeot if (INTEL_GEN(dev_priv) >= 9) { 83419c468b4SFrançois Tigeot /* use scaler when colorkey is not required */ 835a05eeebfSFrançois Tigeot if (state->ckey.flags == I915_SET_COLORKEY_NONE) { 83619c468b4SFrançois Tigeot can_scale = 1; 83719c468b4SFrançois Tigeot min_scale = 1; 83819c468b4SFrançois Tigeot max_scale = skl_max_scale(intel_crtc, crtc_state); 83919c468b4SFrançois Tigeot } else { 84019c468b4SFrançois Tigeot can_scale = 0; 84119c468b4SFrançois Tigeot min_scale = DRM_PLANE_HELPER_NO_SCALING; 84219c468b4SFrançois Tigeot max_scale = DRM_PLANE_HELPER_NO_SCALING; 84319c468b4SFrançois Tigeot } 84419c468b4SFrançois Tigeot } else { 84519c468b4SFrançois Tigeot can_scale = intel_plane->can_scale; 84619c468b4SFrançois Tigeot max_scale = intel_plane->max_downscale << 16; 84719c468b4SFrançois Tigeot min_scale = intel_plane->can_scale ? 1 : (1 << 16); 84819c468b4SFrançois Tigeot } 84919c468b4SFrançois Tigeot 850e3adcf8fSFrançois Tigeot /* 8515d0b1887SFrançois Tigeot * FIXME the following code does a bunch of fuzzy adjustments to the 8525d0b1887SFrançois Tigeot * coordinates and sizes. We probably need some way to decide whether 8535d0b1887SFrançois Tigeot * more strict checking should be done instead. 854e3adcf8fSFrançois Tigeot */ 8552c9916cdSFrançois Tigeot drm_rect_rotate(src, fb->width << 16, fb->height << 16, 8562c9916cdSFrançois Tigeot state->base.rotation); 8571b13d190SFrançois Tigeot 8582c9916cdSFrançois Tigeot hscale = drm_rect_calc_hscale_relaxed(src, dst, min_scale, max_scale); 8595d0b1887SFrançois Tigeot BUG_ON(hscale < 0); 860e3adcf8fSFrançois Tigeot 8612c9916cdSFrançois Tigeot vscale = drm_rect_calc_vscale_relaxed(src, dst, min_scale, max_scale); 8625d0b1887SFrançois Tigeot BUG_ON(vscale < 0); 8635d0b1887SFrançois Tigeot 8641e12ee3bSFrançois Tigeot state->base.visible = drm_rect_clip_scaled(src, dst, clip, hscale, vscale); 8655d0b1887SFrançois Tigeot 8662c9916cdSFrançois Tigeot crtc_x = dst->x1; 8672c9916cdSFrançois Tigeot crtc_y = dst->y1; 8682c9916cdSFrançois Tigeot crtc_w = drm_rect_width(dst); 8692c9916cdSFrançois Tigeot crtc_h = drm_rect_height(dst); 8705d0b1887SFrançois Tigeot 8711e12ee3bSFrançois Tigeot if (state->base.visible) { 8725d0b1887SFrançois Tigeot /* check again in case clipping clamped the results */ 8732c9916cdSFrançois Tigeot hscale = drm_rect_calc_hscale(src, dst, min_scale, max_scale); 8745d0b1887SFrançois Tigeot if (hscale < 0) { 8755d0b1887SFrançois Tigeot DRM_DEBUG_KMS("Horizontal scaling factor out of limits\n"); 876aee94f86SFrançois Tigeot drm_rect_debug_print("src: ", src, true); 877aee94f86SFrançois Tigeot drm_rect_debug_print("dst: ", dst, false); 8785d0b1887SFrançois Tigeot 8795d0b1887SFrançois Tigeot return hscale; 8805d0b1887SFrançois Tigeot } 8815d0b1887SFrançois Tigeot 8822c9916cdSFrançois Tigeot vscale = drm_rect_calc_vscale(src, dst, min_scale, max_scale); 8835d0b1887SFrançois Tigeot if (vscale < 0) { 8845d0b1887SFrançois Tigeot DRM_DEBUG_KMS("Vertical scaling factor out of limits\n"); 885aee94f86SFrançois Tigeot drm_rect_debug_print("src: ", src, true); 886aee94f86SFrançois Tigeot drm_rect_debug_print("dst: ", dst, false); 8875d0b1887SFrançois Tigeot 8885d0b1887SFrançois Tigeot return vscale; 8895d0b1887SFrançois Tigeot } 8905d0b1887SFrançois Tigeot 8915d0b1887SFrançois Tigeot /* Make the source viewport size an exact multiple of the scaling factors. */ 8922c9916cdSFrançois Tigeot drm_rect_adjust_size(src, 8932c9916cdSFrançois Tigeot drm_rect_width(dst) * hscale - drm_rect_width(src), 8942c9916cdSFrançois Tigeot drm_rect_height(dst) * vscale - drm_rect_height(src)); 8955d0b1887SFrançois Tigeot 8962c9916cdSFrançois Tigeot drm_rect_rotate_inv(src, fb->width << 16, fb->height << 16, 8972c9916cdSFrançois Tigeot state->base.rotation); 8981b13d190SFrançois Tigeot 8995d0b1887SFrançois Tigeot /* sanity check to make sure the src viewport wasn't enlarged */ 9002c9916cdSFrançois Tigeot WARN_ON(src->x1 < (int) state->base.src_x || 9012c9916cdSFrançois Tigeot src->y1 < (int) state->base.src_y || 9022c9916cdSFrançois Tigeot src->x2 > (int) state->base.src_x + state->base.src_w || 9032c9916cdSFrançois Tigeot src->y2 > (int) state->base.src_y + state->base.src_h); 904e3adcf8fSFrançois Tigeot 905e3adcf8fSFrançois Tigeot /* 9065d0b1887SFrançois Tigeot * Hardware doesn't handle subpixel coordinates. 9075d0b1887SFrançois Tigeot * Adjust to (macro)pixel boundary, but be careful not to 9085d0b1887SFrançois Tigeot * increase the source viewport size, because that could 9095d0b1887SFrançois Tigeot * push the downscaling factor out of bounds. 9102c84b0b6SFrançois Tigeot */ 9112c9916cdSFrançois Tigeot src_x = src->x1 >> 16; 9122c9916cdSFrançois Tigeot src_w = drm_rect_width(src) >> 16; 9132c9916cdSFrançois Tigeot src_y = src->y1 >> 16; 9142c9916cdSFrançois Tigeot src_h = drm_rect_height(src) >> 16; 9155d0b1887SFrançois Tigeot 916*a85cb24fSFrançois Tigeot if (format_is_yuv(fb->format->format)) { 9175d0b1887SFrançois Tigeot src_x &= ~1; 9185d0b1887SFrançois Tigeot src_w &= ~1; 9192c84b0b6SFrançois Tigeot 9202c84b0b6SFrançois Tigeot /* 9215d0b1887SFrançois Tigeot * Must keep src and dst the 9225d0b1887SFrançois Tigeot * same if we can't scale. 923e3adcf8fSFrançois Tigeot */ 92419c468b4SFrançois Tigeot if (!can_scale) 9255d0b1887SFrançois Tigeot crtc_w &= ~1; 9265d0b1887SFrançois Tigeot 9275d0b1887SFrançois Tigeot if (crtc_w == 0) 9281e12ee3bSFrançois Tigeot state->base.visible = false; 9295d0b1887SFrançois Tigeot } 9305d0b1887SFrançois Tigeot } 9315d0b1887SFrançois Tigeot 9325d0b1887SFrançois Tigeot /* Check size restrictions when scaling */ 9331e12ee3bSFrançois Tigeot if (state->base.visible && (src_w != crtc_w || src_h != crtc_h)) { 9345d0b1887SFrançois Tigeot unsigned int width_bytes; 935*a85cb24fSFrançois Tigeot int cpp = fb->format->cpp[0]; 9365d0b1887SFrançois Tigeot 93719c468b4SFrançois Tigeot WARN_ON(!can_scale); 9385d0b1887SFrançois Tigeot 9395d0b1887SFrançois Tigeot /* FIXME interlacing min height is 6 */ 9405d0b1887SFrançois Tigeot 9415d0b1887SFrançois Tigeot if (crtc_w < 3 || crtc_h < 3) 9421e12ee3bSFrançois Tigeot state->base.visible = false; 9435d0b1887SFrançois Tigeot 9445d0b1887SFrançois Tigeot if (src_w < 3 || src_h < 3) 9451e12ee3bSFrançois Tigeot state->base.visible = false; 9465d0b1887SFrançois Tigeot 947c0e85e96SFrançois Tigeot width_bytes = ((src_x * cpp) & 63) + src_w * cpp; 9485d0b1887SFrançois Tigeot 9491e12ee3bSFrançois Tigeot if (INTEL_GEN(dev_priv) < 9 && (src_w > 2048 || src_h > 2048 || 95019c468b4SFrançois Tigeot width_bytes > 4096 || fb->pitches[0] > 4096)) { 9515d0b1887SFrançois Tigeot DRM_DEBUG_KMS("Source dimensions exceed hardware limits\n"); 952e3adcf8fSFrançois Tigeot return -EINVAL; 9535d0b1887SFrançois Tigeot } 9545d0b1887SFrançois Tigeot } 9555d0b1887SFrançois Tigeot 9561e12ee3bSFrançois Tigeot if (state->base.visible) { 95719c468b4SFrançois Tigeot src->x1 = src_x << 16; 95819c468b4SFrançois Tigeot src->x2 = (src_x + src_w) << 16; 95919c468b4SFrançois Tigeot src->y1 = src_y << 16; 96019c468b4SFrançois Tigeot src->y2 = (src_y + src_h) << 16; 9612c9916cdSFrançois Tigeot } 962e3adcf8fSFrançois Tigeot 9632c9916cdSFrançois Tigeot dst->x1 = crtc_x; 9642c9916cdSFrançois Tigeot dst->x2 = crtc_x + crtc_w; 9652c9916cdSFrançois Tigeot dst->y1 = crtc_y; 9662c9916cdSFrançois Tigeot dst->y2 = crtc_y + crtc_h; 9672c9916cdSFrançois Tigeot 9681e12ee3bSFrançois Tigeot if (INTEL_GEN(dev_priv) >= 9) { 9691e12ee3bSFrançois Tigeot ret = skl_check_plane_surface(state); 9701e12ee3bSFrançois Tigeot if (ret) 9711e12ee3bSFrançois Tigeot return ret; 972*a85cb24fSFrançois Tigeot 973*a85cb24fSFrançois Tigeot state->ctl = skl_plane_ctl(crtc_state, state); 974*a85cb24fSFrançois Tigeot } else if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) { 975*a85cb24fSFrançois Tigeot ret = i9xx_check_plane_surface(state); 976*a85cb24fSFrançois Tigeot if (ret) 977*a85cb24fSFrançois Tigeot return ret; 978*a85cb24fSFrançois Tigeot 979*a85cb24fSFrançois Tigeot state->ctl = vlv_sprite_ctl(crtc_state, state); 980*a85cb24fSFrançois Tigeot } else if (INTEL_GEN(dev_priv) >= 7) { 981*a85cb24fSFrançois Tigeot ret = i9xx_check_plane_surface(state); 982*a85cb24fSFrançois Tigeot if (ret) 983*a85cb24fSFrançois Tigeot return ret; 984*a85cb24fSFrançois Tigeot 985*a85cb24fSFrançois Tigeot state->ctl = ivb_sprite_ctl(crtc_state, state); 986*a85cb24fSFrançois Tigeot } else { 987*a85cb24fSFrançois Tigeot ret = i9xx_check_plane_surface(state); 988*a85cb24fSFrançois Tigeot if (ret) 989*a85cb24fSFrançois Tigeot return ret; 990*a85cb24fSFrançois Tigeot 991*a85cb24fSFrançois Tigeot state->ctl = ilk_sprite_ctl(crtc_state, state); 9921e12ee3bSFrançois Tigeot } 9931e12ee3bSFrançois Tigeot 9942c9916cdSFrançois Tigeot return 0; 9952c9916cdSFrançois Tigeot } 9962c9916cdSFrançois Tigeot 997e3adcf8fSFrançois Tigeot int intel_sprite_set_colorkey(struct drm_device *dev, void *data, 998e3adcf8fSFrançois Tigeot struct drm_file *file_priv) 999e3adcf8fSFrançois Tigeot { 10001e12ee3bSFrançois Tigeot struct drm_i915_private *dev_priv = to_i915(dev); 1001e3adcf8fSFrançois Tigeot struct drm_intel_sprite_colorkey *set = data; 1002e3adcf8fSFrançois Tigeot struct drm_plane *plane; 1003a05eeebfSFrançois Tigeot struct drm_plane_state *plane_state; 1004a05eeebfSFrançois Tigeot struct drm_atomic_state *state; 1005a05eeebfSFrançois Tigeot struct drm_modeset_acquire_ctx ctx; 1006e3adcf8fSFrançois Tigeot int ret = 0; 1007e3adcf8fSFrançois Tigeot 1008e3adcf8fSFrançois Tigeot /* Make sure we don't try to enable both src & dest simultaneously */ 1009e3adcf8fSFrançois Tigeot if ((set->flags & (I915_SET_COLORKEY_DESTINATION | I915_SET_COLORKEY_SOURCE)) == (I915_SET_COLORKEY_DESTINATION | I915_SET_COLORKEY_SOURCE)) 1010e3adcf8fSFrançois Tigeot return -EINVAL; 1011e3adcf8fSFrançois Tigeot 10121e12ee3bSFrançois Tigeot if ((IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) && 1013477eb7f9SFrançois Tigeot set->flags & I915_SET_COLORKEY_DESTINATION) 1014477eb7f9SFrançois Tigeot return -EINVAL; 1015477eb7f9SFrançois Tigeot 101624edb884SFrançois Tigeot plane = drm_plane_find(dev, set->plane_id); 1017a05eeebfSFrançois Tigeot if (!plane || plane->type != DRM_PLANE_TYPE_OVERLAY) 1018a05eeebfSFrançois Tigeot return -ENOENT; 1019a05eeebfSFrançois Tigeot 1020a05eeebfSFrançois Tigeot drm_modeset_acquire_init(&ctx, 0); 1021a05eeebfSFrançois Tigeot 1022a05eeebfSFrançois Tigeot state = drm_atomic_state_alloc(plane->dev); 1023a05eeebfSFrançois Tigeot if (!state) { 1024a05eeebfSFrançois Tigeot ret = -ENOMEM; 1025a05eeebfSFrançois Tigeot goto out; 1026a05eeebfSFrançois Tigeot } 1027a05eeebfSFrançois Tigeot state->acquire_ctx = &ctx; 1028a05eeebfSFrançois Tigeot 1029a05eeebfSFrançois Tigeot while (1) { 1030a05eeebfSFrançois Tigeot plane_state = drm_atomic_get_plane_state(state, plane); 1031a05eeebfSFrançois Tigeot ret = PTR_ERR_OR_ZERO(plane_state); 1032a05eeebfSFrançois Tigeot if (!ret) { 1033a05eeebfSFrançois Tigeot to_intel_plane_state(plane_state)->ckey = *set; 1034a05eeebfSFrançois Tigeot ret = drm_atomic_commit(state); 1035e3adcf8fSFrançois Tigeot } 1036e3adcf8fSFrançois Tigeot 1037a05eeebfSFrançois Tigeot if (ret != -EDEADLK) 1038a05eeebfSFrançois Tigeot break; 103919c468b4SFrançois Tigeot 1040a05eeebfSFrançois Tigeot drm_atomic_state_clear(state); 1041a05eeebfSFrançois Tigeot drm_modeset_backoff(&ctx); 104219c468b4SFrançois Tigeot } 104319c468b4SFrançois Tigeot 10444be47400SFrançois Tigeot drm_atomic_state_put(state); 1045a05eeebfSFrançois Tigeot out: 1046a05eeebfSFrançois Tigeot drm_modeset_drop_locks(&ctx); 1047a05eeebfSFrançois Tigeot drm_modeset_acquire_fini(&ctx); 1048e3adcf8fSFrançois Tigeot return ret; 1049e3adcf8fSFrançois Tigeot } 1050e3adcf8fSFrançois Tigeot 105119c468b4SFrançois Tigeot static const uint32_t ilk_plane_formats[] = { 10522c84b0b6SFrançois Tigeot DRM_FORMAT_XRGB8888, 10532c84b0b6SFrançois Tigeot DRM_FORMAT_YUYV, 10542c84b0b6SFrançois Tigeot DRM_FORMAT_YVYU, 10552c84b0b6SFrançois Tigeot DRM_FORMAT_UYVY, 10562c84b0b6SFrançois Tigeot DRM_FORMAT_VYUY, 10572c84b0b6SFrançois Tigeot }; 10582c84b0b6SFrançois Tigeot 105919c468b4SFrançois Tigeot static const uint32_t snb_plane_formats[] = { 1060e3adcf8fSFrançois Tigeot DRM_FORMAT_XBGR8888, 1061e3adcf8fSFrançois Tigeot DRM_FORMAT_XRGB8888, 1062e3adcf8fSFrançois Tigeot DRM_FORMAT_YUYV, 1063e3adcf8fSFrançois Tigeot DRM_FORMAT_YVYU, 1064e3adcf8fSFrançois Tigeot DRM_FORMAT_UYVY, 1065e3adcf8fSFrançois Tigeot DRM_FORMAT_VYUY, 1066e3adcf8fSFrançois Tigeot }; 1067e3adcf8fSFrançois Tigeot 106819c468b4SFrançois Tigeot static const uint32_t vlv_plane_formats[] = { 10698e26cdf6SFrançois Tigeot DRM_FORMAT_RGB565, 10708e26cdf6SFrançois Tigeot DRM_FORMAT_ABGR8888, 10718e26cdf6SFrançois Tigeot DRM_FORMAT_ARGB8888, 10728e26cdf6SFrançois Tigeot DRM_FORMAT_XBGR8888, 10738e26cdf6SFrançois Tigeot DRM_FORMAT_XRGB8888, 10748e26cdf6SFrançois Tigeot DRM_FORMAT_XBGR2101010, 10758e26cdf6SFrançois Tigeot DRM_FORMAT_ABGR2101010, 10768e26cdf6SFrançois Tigeot DRM_FORMAT_YUYV, 10778e26cdf6SFrançois Tigeot DRM_FORMAT_YVYU, 10788e26cdf6SFrançois Tigeot DRM_FORMAT_UYVY, 10798e26cdf6SFrançois Tigeot DRM_FORMAT_VYUY, 10808e26cdf6SFrançois Tigeot }; 10818e26cdf6SFrançois Tigeot 10822c9916cdSFrançois Tigeot static uint32_t skl_plane_formats[] = { 10832c9916cdSFrançois Tigeot DRM_FORMAT_RGB565, 10842c9916cdSFrançois Tigeot DRM_FORMAT_ABGR8888, 10852c9916cdSFrançois Tigeot DRM_FORMAT_ARGB8888, 10862c9916cdSFrançois Tigeot DRM_FORMAT_XBGR8888, 10872c9916cdSFrançois Tigeot DRM_FORMAT_XRGB8888, 10882c9916cdSFrançois Tigeot DRM_FORMAT_YUYV, 10892c9916cdSFrançois Tigeot DRM_FORMAT_YVYU, 10902c9916cdSFrançois Tigeot DRM_FORMAT_UYVY, 10912c9916cdSFrançois Tigeot DRM_FORMAT_VYUY, 10922c9916cdSFrançois Tigeot }; 10932c9916cdSFrançois Tigeot 10944be47400SFrançois Tigeot struct intel_plane * 10954be47400SFrançois Tigeot intel_sprite_plane_create(struct drm_i915_private *dev_priv, 10964be47400SFrançois Tigeot enum i915_pipe pipe, int plane) 1097e3adcf8fSFrançois Tigeot { 10988621f407SFrançois Tigeot struct intel_plane *intel_plane = NULL; 10998621f407SFrançois Tigeot struct intel_plane_state *state = NULL; 1100e3adcf8fSFrançois Tigeot unsigned long possible_crtcs; 11012c84b0b6SFrançois Tigeot const uint32_t *plane_formats; 11024be47400SFrançois Tigeot unsigned int supported_rotations; 11032c84b0b6SFrançois Tigeot int num_plane_formats; 1104e3adcf8fSFrançois Tigeot int ret; 1105e3adcf8fSFrançois Tigeot 11069edbd4a0SFrançois Tigeot intel_plane = kzalloc(sizeof(*intel_plane), GFP_KERNEL); 11078621f407SFrançois Tigeot if (!intel_plane) { 11088621f407SFrançois Tigeot ret = -ENOMEM; 11098621f407SFrançois Tigeot goto fail; 11108621f407SFrançois Tigeot } 11112c84b0b6SFrançois Tigeot 11122c9916cdSFrançois Tigeot state = intel_create_plane_state(&intel_plane->base); 11132c9916cdSFrançois Tigeot if (!state) { 11148621f407SFrançois Tigeot ret = -ENOMEM; 11158621f407SFrançois Tigeot goto fail; 11162c9916cdSFrançois Tigeot } 11172c9916cdSFrançois Tigeot intel_plane->base.state = &state->base; 11182c9916cdSFrançois Tigeot 11194be47400SFrançois Tigeot if (INTEL_GEN(dev_priv) >= 9) { 11204be47400SFrançois Tigeot intel_plane->can_scale = true; 11214be47400SFrançois Tigeot state->scaler_id = -1; 11224be47400SFrançois Tigeot 11234be47400SFrançois Tigeot intel_plane->update_plane = skl_update_plane; 11244be47400SFrançois Tigeot intel_plane->disable_plane = skl_disable_plane; 11254be47400SFrançois Tigeot 11264be47400SFrançois Tigeot plane_formats = skl_plane_formats; 11274be47400SFrançois Tigeot num_plane_formats = ARRAY_SIZE(skl_plane_formats); 11284be47400SFrançois Tigeot } else if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) { 11294be47400SFrançois Tigeot intel_plane->can_scale = false; 11304be47400SFrançois Tigeot intel_plane->max_downscale = 1; 11314be47400SFrançois Tigeot 11324be47400SFrançois Tigeot intel_plane->update_plane = vlv_update_plane; 11334be47400SFrançois Tigeot intel_plane->disable_plane = vlv_disable_plane; 11344be47400SFrançois Tigeot 11354be47400SFrançois Tigeot plane_formats = vlv_plane_formats; 11364be47400SFrançois Tigeot num_plane_formats = ARRAY_SIZE(vlv_plane_formats); 11374be47400SFrançois Tigeot } else if (INTEL_GEN(dev_priv) >= 7) { 11384be47400SFrançois Tigeot if (IS_IVYBRIDGE(dev_priv)) { 11394be47400SFrançois Tigeot intel_plane->can_scale = true; 11404be47400SFrançois Tigeot intel_plane->max_downscale = 2; 11414be47400SFrançois Tigeot } else { 11424be47400SFrançois Tigeot intel_plane->can_scale = false; 11434be47400SFrançois Tigeot intel_plane->max_downscale = 1; 11444be47400SFrançois Tigeot } 11454be47400SFrançois Tigeot 11464be47400SFrançois Tigeot intel_plane->update_plane = ivb_update_plane; 11474be47400SFrançois Tigeot intel_plane->disable_plane = ivb_disable_plane; 11484be47400SFrançois Tigeot 11494be47400SFrançois Tigeot plane_formats = snb_plane_formats; 11504be47400SFrançois Tigeot num_plane_formats = ARRAY_SIZE(snb_plane_formats); 11514be47400SFrançois Tigeot } else { 11522c84b0b6SFrançois Tigeot intel_plane->can_scale = true; 11532c84b0b6SFrançois Tigeot intel_plane->max_downscale = 16; 11544be47400SFrançois Tigeot 11552c84b0b6SFrançois Tigeot intel_plane->update_plane = ilk_update_plane; 11562c84b0b6SFrançois Tigeot intel_plane->disable_plane = ilk_disable_plane; 1157e3adcf8fSFrançois Tigeot 11581e12ee3bSFrançois Tigeot if (IS_GEN6(dev_priv)) { 11592c84b0b6SFrançois Tigeot plane_formats = snb_plane_formats; 11602c84b0b6SFrançois Tigeot num_plane_formats = ARRAY_SIZE(snb_plane_formats); 11612c84b0b6SFrançois Tigeot } else { 11622c84b0b6SFrançois Tigeot plane_formats = ilk_plane_formats; 11632c84b0b6SFrançois Tigeot num_plane_formats = ARRAY_SIZE(ilk_plane_formats); 11642c84b0b6SFrançois Tigeot } 11655d0b1887SFrançois Tigeot } 11668e26cdf6SFrançois Tigeot 11674be47400SFrançois Tigeot if (INTEL_GEN(dev_priv) >= 9) { 11684be47400SFrançois Tigeot supported_rotations = 11694be47400SFrançois Tigeot DRM_ROTATE_0 | DRM_ROTATE_90 | 11704be47400SFrançois Tigeot DRM_ROTATE_180 | DRM_ROTATE_270; 11714be47400SFrançois Tigeot } else if (IS_CHERRYVIEW(dev_priv) && pipe == PIPE_B) { 11724be47400SFrançois Tigeot supported_rotations = 11734be47400SFrançois Tigeot DRM_ROTATE_0 | DRM_ROTATE_180 | 11744be47400SFrançois Tigeot DRM_REFLECT_X; 11758e26cdf6SFrançois Tigeot } else { 11764be47400SFrançois Tigeot supported_rotations = 11774be47400SFrançois Tigeot DRM_ROTATE_0 | DRM_ROTATE_180; 1178e3adcf8fSFrançois Tigeot } 1179e3adcf8fSFrançois Tigeot 1180e3adcf8fSFrançois Tigeot intel_plane->pipe = pipe; 11818e26cdf6SFrançois Tigeot intel_plane->plane = plane; 1182*a85cb24fSFrançois Tigeot intel_plane->id = PLANE_SPRITE0 + plane; 1183352ff8bdSFrançois Tigeot intel_plane->frontbuffer_bit = INTEL_FRONTBUFFER_SPRITE(pipe, plane); 11842c9916cdSFrançois Tigeot intel_plane->check_plane = intel_check_sprite_plane; 11858621f407SFrançois Tigeot 1186e3adcf8fSFrançois Tigeot possible_crtcs = (1 << pipe); 11878621f407SFrançois Tigeot 11884be47400SFrançois Tigeot if (INTEL_GEN(dev_priv) >= 9) 11894be47400SFrançois Tigeot ret = drm_universal_plane_init(&dev_priv->drm, &intel_plane->base, 11904be47400SFrançois Tigeot possible_crtcs, &intel_plane_funcs, 11912c84b0b6SFrançois Tigeot plane_formats, num_plane_formats, 11921487f786SFrançois Tigeot DRM_PLANE_TYPE_OVERLAY, 11931487f786SFrançois Tigeot "plane %d%c", plane + 2, pipe_name(pipe)); 11941487f786SFrançois Tigeot else 11954be47400SFrançois Tigeot ret = drm_universal_plane_init(&dev_priv->drm, &intel_plane->base, 11964be47400SFrançois Tigeot possible_crtcs, &intel_plane_funcs, 11971487f786SFrançois Tigeot plane_formats, num_plane_formats, 11981487f786SFrançois Tigeot DRM_PLANE_TYPE_OVERLAY, 11991487f786SFrançois Tigeot "sprite %c", sprite_name(pipe, plane)); 12008621f407SFrançois Tigeot if (ret) 12018621f407SFrançois Tigeot goto fail; 1202e3adcf8fSFrançois Tigeot 12034be47400SFrançois Tigeot drm_plane_create_rotation_property(&intel_plane->base, 12044be47400SFrançois Tigeot DRM_ROTATE_0, 12054be47400SFrançois Tigeot supported_rotations); 12062c9916cdSFrançois Tigeot 12072c9916cdSFrançois Tigeot drm_plane_helper_add(&intel_plane->base, &intel_plane_helper_funcs); 12081b13d190SFrançois Tigeot 12094be47400SFrançois Tigeot return intel_plane; 12108621f407SFrançois Tigeot 12118621f407SFrançois Tigeot fail: 12128621f407SFrançois Tigeot kfree(state); 12138621f407SFrançois Tigeot kfree(intel_plane); 12148621f407SFrançois Tigeot 12154be47400SFrançois Tigeot return ERR_PTR(ret); 1216e3adcf8fSFrançois Tigeot } 1217