| /* |
| * Copyright © 2006-2007 Intel Corporation |
| * |
| * Permission is hereby granted, free of charge, to any person obtaining a |
| * copy of this software and associated documentation files (the "Software"), |
| * to deal in the Software without restriction, including without limitation |
| * the rights to use, copy, modify, merge, publish, distribute, sublicense, |
| * and/or sell copies of the Software, and to permit persons to whom the |
| * Software is furnished to do so, subject to the following conditions: |
| * |
| * The above copyright notice and this permission notice (including the next |
| * paragraph) shall be included in all copies or substantial portions of the |
| * Software. |
| * |
| * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
| * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
| * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
| * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
| * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING |
| * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER |
| * DEALINGS IN THE SOFTWARE. |
| * |
| * Authors: |
| * Eric Anholt <eric@anholt.net> |
| */ |
| |
| #include <linux/dmi.h> |
| #include <linux/module.h> |
| #include <linux/input.h> |
| #include <linux/i2c.h> |
| #include <linux/kernel.h> |
| #include <linux/slab.h> |
| #include <linux/vgaarb.h> |
| #include <drm/drm_edid.h> |
| #include <drm/drmP.h> |
| #include "intel_drv.h" |
| #include <drm/i915_drm.h> |
| #include "i915_drv.h" |
| #include "i915_trace.h" |
| #include <drm/drm_dp_helper.h> |
| #include <drm/drm_crtc_helper.h> |
| #include <drm/drm_plane_helper.h> |
| #include <drm/drm_rect.h> |
| #include <linux/dma_remapping.h> |
| |
| /* Primary plane formats supported by all gen */ |
| #define COMMON_PRIMARY_FORMATS \ |
| DRM_FORMAT_C8, \ |
| DRM_FORMAT_RGB565, \ |
| DRM_FORMAT_XRGB8888, \ |
| DRM_FORMAT_ARGB8888 |
| |
| /* Primary plane formats for gen <= 3 */ |
| static const uint32_t intel_primary_formats_gen2[] = { |
| COMMON_PRIMARY_FORMATS, |
| DRM_FORMAT_XRGB1555, |
| DRM_FORMAT_ARGB1555, |
| }; |
| |
| /* Primary plane formats for gen >= 4 */ |
| static const uint32_t intel_primary_formats_gen4[] = { |
| COMMON_PRIMARY_FORMATS, \ |
| DRM_FORMAT_XBGR8888, |
| DRM_FORMAT_ABGR8888, |
| DRM_FORMAT_XRGB2101010, |
| DRM_FORMAT_ARGB2101010, |
| DRM_FORMAT_XBGR2101010, |
| DRM_FORMAT_ABGR2101010, |
| }; |
| |
| /* Cursor formats */ |
| static const uint32_t intel_cursor_formats[] = { |
| DRM_FORMAT_ARGB8888, |
| }; |
| |
| static void intel_increase_pllclock(struct drm_device *dev, |
| enum pipe pipe); |
| static void intel_crtc_update_cursor(struct drm_crtc *crtc, bool on); |
| |
| static void i9xx_crtc_clock_get(struct intel_crtc *crtc, |
| struct intel_crtc_config *pipe_config); |
| static void ironlake_pch_clock_get(struct intel_crtc *crtc, |
| struct intel_crtc_config *pipe_config); |
| |
| static int intel_set_mode(struct drm_crtc *crtc, struct drm_display_mode *mode, |
| int x, int y, struct drm_framebuffer *old_fb); |
| static int intel_framebuffer_init(struct drm_device *dev, |
| struct intel_framebuffer *ifb, |
| struct drm_mode_fb_cmd2 *mode_cmd, |
| struct drm_i915_gem_object *obj); |
| static void i9xx_set_pipeconf(struct intel_crtc *intel_crtc); |
| static void intel_set_pipe_timings(struct intel_crtc *intel_crtc); |
| static void intel_cpu_transcoder_set_m_n(struct intel_crtc *crtc, |
| struct intel_link_m_n *m_n, |
| struct intel_link_m_n *m2_n2); |
| static void ironlake_set_pipeconf(struct drm_crtc *crtc); |
| static void haswell_set_pipeconf(struct drm_crtc *crtc); |
| static void intel_set_pipe_csc(struct drm_crtc *crtc); |
| static void vlv_prepare_pll(struct intel_crtc *crtc); |
| static void chv_prepare_pll(struct intel_crtc *crtc); |
| |
| static struct intel_encoder *intel_find_encoder(struct intel_connector *connector, int pipe) |
| { |
| if (!connector->mst_port) |
| return connector->encoder; |
| else |
| return &connector->mst_port->mst_encoders[pipe]->base; |
| } |
| |
| typedef struct { |
| int min, max; |
| } intel_range_t; |
| |
| typedef struct { |
| int dot_limit; |
| int p2_slow, p2_fast; |
| } intel_p2_t; |
| |
| typedef struct intel_limit intel_limit_t; |
| struct intel_limit { |
| intel_range_t dot, vco, n, m, m1, m2, p, p1; |
| intel_p2_t p2; |
| }; |
| |
| int |
| intel_pch_rawclk(struct drm_device *dev) |
| { |
| struct drm_i915_private *dev_priv = dev->dev_private; |
| |
| WARN_ON(!HAS_PCH_SPLIT(dev)); |
| |
| return I915_READ(PCH_RAWCLK_FREQ) & RAWCLK_FREQ_MASK; |
| } |
| |
| static inline u32 /* units of 100MHz */ |
| intel_fdi_link_freq(struct drm_device *dev) |
| { |
| if (IS_GEN5(dev)) { |
| struct drm_i915_private *dev_priv = dev->dev_private; |
| return (I915_READ(FDI_PLL_BIOS_0) & FDI_PLL_FB_CLOCK_MASK) + 2; |
| } else |
| return 27; |
| } |
| |
| static const intel_limit_t intel_limits_i8xx_dac = { |
| .dot = { .min = 25000, .max = 350000 }, |
| .vco = { .min = 908000, .max = 1512000 }, |
| .n = { .min = 2, .max = 16 }, |
| .m = { .min = 96, .max = 140 }, |
| .m1 = { .min = 18, .max = 26 }, |
| .m2 = { .min = 6, .max = 16 }, |
| .p = { .min = 4, .max = 128 }, |
| .p1 = { .min = 2, .max = 33 }, |
| .p2 = { .dot_limit = 165000, |
| .p2_slow = 4, .p2_fast = 2 }, |
| }; |
| |
| static const intel_limit_t intel_limits_i8xx_dvo = { |
| .dot = { .min = 25000, .max = 350000 }, |
| .vco = { .min = 908000, .max = 1512000 }, |
| .n = { .min = 2, .max = 16 }, |
| .m = { .min = 96, .max = 140 }, |
| .m1 = { .min = 18, .max = 26 }, |
| .m2 = { .min = 6, .max = 16 }, |
| .p = { .min = 4, .max = 128 }, |
| .p1 = { .min = 2, .max = 33 }, |
| .p2 = { .dot_limit = 165000, |
| .p2_slow = 4, .p2_fast = 4 }, |
| }; |
| |
| static const intel_limit_t intel_limits_i8xx_lvds = { |
| .dot = { .min = 25000, .max = 350000 }, |
| .vco = { .min = 908000, .max = 1512000 }, |
| .n = { .min = 2, .max = 16 }, |
| .m = { .min = 96, .max = 140 }, |
| .m1 = { .min = 18, .max = 26 }, |
| .m2 = { .min = 6, .max = 16 }, |
| .p = { .min = 4, .max = 128 }, |
| .p1 = { .min = 1, .max = 6 }, |
| .p2 = { .dot_limit = 165000, |
| .p2_slow = 14, .p2_fast = 7 }, |
| }; |
| |
| static const intel_limit_t intel_limits_i9xx_sdvo = { |
| .dot = { .min = 20000, .max = 400000 }, |
| .vco = { .min = 1400000, .max = 2800000 }, |
| .n = { .min = 1, .max = 6 }, |
| .m = { .min = 70, .max = 120 }, |
| .m1 = { .min = 8, .max = 18 }, |
| .m2 = { .min = 3, .max = 7 }, |
| .p = { .min = 5, .max = 80 }, |
| .p1 = { .min = 1, .max = 8 }, |
| .p2 = { .dot_limit = 200000, |
| .p2_slow = 10, .p2_fast = 5 }, |
| }; |
| |
| static const intel_limit_t intel_limits_i9xx_lvds = { |
| .dot = { .min = 20000, .max = 400000 }, |
| .vco = { .min = 1400000, .max = 2800000 }, |
| .n = { .min = 1, .max = 6 }, |
| .m = { .min = 70, .max = 120 }, |
| .m1 = { .min = 8, .max = 18 }, |
| .m2 = { .min = 3, .max = 7 }, |
| .p = { .min = 7, .max = 98 }, |
| .p1 = { .min = 1, .max = 8 }, |
| .p2 = { .dot_limit = 112000, |
| .p2_slow = 14, .p2_fast = 7 }, |
| }; |
| |
| |
| static const intel_limit_t intel_limits_g4x_sdvo = { |
| .dot = { .min = 25000, .max = 270000 }, |
| .vco = { .min = 1750000, .max = 3500000}, |
| .n = { .min = 1, .max = 4 }, |
| .m = { .min = 104, .max = 138 }, |
| .m1 = { .min = 17, .max = 23 }, |
| .m2 = { .min = 5, .max = 11 }, |
| .p = { .min = 10, .max = 30 }, |
| .p1 = { .min = 1, .max = 3}, |
| .p2 = { .dot_limit = 270000, |
| .p2_slow = 10, |
| .p2_fast = 10 |
| }, |
| }; |
| |
| static const intel_limit_t intel_limits_g4x_hdmi = { |
| .dot = { .min = 22000, .max = 400000 }, |
| .vco = { .min = 1750000, .max = 3500000}, |
| .n = { .min = 1, .max = 4 }, |
| .m = { .min = 104, .max = 138 }, |
| .m1 = { .min = 16, .max = 23 }, |
| .m2 = { .min = 5, .max = 11 }, |
| .p = { .min = 5, .max = 80 }, |
| .p1 = { .min = 1, .max = 8}, |
| .p2 = { .dot_limit = 165000, |
| .p2_slow = 10, .p2_fast = 5 }, |
| }; |
| |
| static const intel_limit_t intel_limits_g4x_single_channel_lvds = { |
| .dot = { .min = 20000, .max = 115000 }, |
| .vco = { .min = 1750000, .max = 3500000 }, |
| .n = { .min = 1, .max = 3 }, |
| .m = { .min = 104, .max = 138 }, |
| .m1 = { .min = 17, .max = 23 }, |
| .m2 = { .min = 5, .max = 11 }, |
| .p = { .min = 28, .max = 112 }, |
| .p1 = { .min = 2, .max = 8 }, |
| .p2 = { .dot_limit = 0, |
| .p2_slow = 14, .p2_fast = 14 |
| }, |
| }; |
| |
| static const intel_limit_t intel_limits_g4x_dual_channel_lvds = { |
| .dot = { .min = 80000, .max = 224000 }, |
| .vco = { .min = 1750000, .max = 3500000 }, |
| .n = { .min = 1, .max = 3 }, |
| .m = { .min = 104, .max = 138 }, |
| .m1 = { .min = 17, .max = 23 }, |
| .m2 = { .min = 5, .max = 11 }, |
| .p = { .min = 14, .max = 42 }, |
| .p1 = { .min = 2, .max = 6 }, |
| .p2 = { .dot_limit = 0, |
| .p2_slow = 7, .p2_fast = 7 |
| }, |
| }; |
| |
| static const intel_limit_t intel_limits_pineview_sdvo = { |
| .dot = { .min = 20000, .max = 400000}, |
| .vco = { .min = 1700000, .max = 3500000 }, |
| /* Pineview's Ncounter is a ring counter */ |
| .n = { .min = 3, .max = 6 }, |
| .m = { .min = 2, .max = 256 }, |
| /* Pineview only has one combined m divider, which we treat as m2. */ |
| .m1 = { .min = 0, .max = 0 }, |
| .m2 = { .min = 0, .max = 254 }, |
| .p = { .min = 5, .max = 80 }, |
| .p1 = { .min = 1, .max = 8 }, |
| .p2 = { .dot_limit = 200000, |
| .p2_slow = 10, .p2_fast = 5 }, |
| }; |
| |
| static const intel_limit_t intel_limits_pineview_lvds = { |
| .dot = { .min = 20000, .max = 400000 }, |
| .vco = { .min = 1700000, .max = 3500000 }, |
| .n = { .min = 3, .max = 6 }, |
| .m = { .min = 2, .max = 256 }, |
| .m1 = { .min = 0, .max = 0 }, |
| .m2 = { .min = 0, .max = 254 }, |
| .p = { .min = 7, .max = 112 }, |
| .p1 = { .min = 1, .max = 8 }, |
| .p2 = { .dot_limit = 112000, |
| .p2_slow = 14, .p2_fast = 14 }, |
| }; |
| |
| /* Ironlake / Sandybridge |
| * |
| * We calculate clock using (register_value + 2) for N/M1/M2, so here |
| * the range value for them is (actual_value - 2). |
| */ |
| static const intel_limit_t intel_limits_ironlake_dac = { |
| .dot = { .min = 25000, .max = 350000 }, |
| .vco = { .min = 1760000, .max = 3510000 }, |
| .n = { .min = 1, .max = 5 }, |
| .m = { .min = 79, .max = 127 }, |
| .m1 = { .min = 12, .max = 22 }, |
| .m2 = { .min = 5, .max = 9 }, |
| .p = { .min = 5, .max = 80 }, |
| .p1 = { .min = 1, .max = 8 }, |
| .p2 = { .dot_limit = 225000, |
| .p2_slow = 10, .p2_fast = 5 }, |
| }; |
| |
| static const intel_limit_t intel_limits_ironlake_single_lvds = { |
| .dot = { .min = 25000, .max = 350000 }, |
| .vco = { .min = 1760000, .max = 3510000 }, |
| .n = { .min = 1, .max = 3 }, |
| .m = { .min = 79, .max = 118 }, |
| .m1 = { .min = 12, .max = 22 }, |
| .m2 = { .min = 5, .max = 9 }, |
| .p = { .min = 28, .max = 112 }, |
| .p1 = { .min = 2, .max = 8 }, |
| .p2 = { .dot_limit = 225000, |
| .p2_slow = 14, .p2_fast = 14 }, |
| }; |
| |
| static const intel_limit_t intel_limits_ironlake_dual_lvds = { |
| .dot = { .min = 25000, .max = 350000 }, |
| .vco = { .min = 1760000, .max = 3510000 }, |
| .n = { .min = 1, .max = 3 }, |
| .m = { .min = 79, .max = 127 }, |
| .m1 = { .min = 12, .max = 22 }, |
| .m2 = { .min = 5, .max = 9 }, |
| .p = { .min = 14, .max = 56 }, |
| .p1 = { .min = 2, .max = 8 }, |
| .p2 = { .dot_limit = 225000, |
| .p2_slow = 7, .p2_fast = 7 }, |
| }; |
| |
| /* LVDS 100mhz refclk limits. */ |
| static const intel_limit_t intel_limits_ironlake_single_lvds_100m = { |
| .dot = { .min = 25000, .max = 350000 }, |
| .vco = { .min = 1760000, .max = 3510000 }, |
| .n = { .min = 1, .max = 2 }, |
| .m = { .min = 79, .max = 126 }, |
| .m1 = { .min = 12, .max = 22 }, |
| .m2 = { .min = 5, .max = 9 }, |
| .p = { .min = 28, .max = 112 }, |
| .p1 = { .min = 2, .max = 8 }, |
| .p2 = { .dot_limit = 225000, |
| .p2_slow = 14, .p2_fast = 14 }, |
| }; |
| |
| static const intel_limit_t intel_limits_ironlake_dual_lvds_100m = { |
| .dot = { .min = 25000, .max = 350000 }, |
| .vco = { .min = 1760000, .max = 3510000 }, |
| .n = { .min = 1, .max = 3 }, |
| .m = { .min = 79, .max = 126 }, |
| .m1 = { .min = 12, .max = 22 }, |
| .m2 = { .min = 5, .max = 9 }, |
| .p = { .min = 14, .max = 42 }, |
| .p1 = { .min = 2, .max = 6 }, |
| .p2 = { .dot_limit = 225000, |
| .p2_slow = 7, .p2_fast = 7 }, |
| }; |
| |
| static const intel_limit_t intel_limits_vlv = { |
| /* |
| * These are the data rate limits (measured in fast clocks) |
| * since those are the strictest limits we have. The fast |
| * clock and actual rate limits are more relaxed, so checking |
| * them would make no difference. |
| */ |
| .dot = { .min = 25000 * 5, .max = 270000 * 5 }, |
| .vco = { .min = 4000000, .max = 6000000 }, |
| .n = { .min = 1, .max = 7 }, |
| .m1 = { .min = 2, .max = 3 }, |
| .m2 = { .min = 11, .max = 156 }, |
| .p1 = { .min = 2, .max = 3 }, |
| .p2 = { .p2_slow = 2, .p2_fast = 20 }, /* slow=min, fast=max */ |
| }; |
| |
| static const intel_limit_t intel_limits_chv = { |
| /* |
| * These are the data rate limits (measured in fast clocks) |
| * since those are the strictest limits we have. The fast |
| * clock and actual rate limits are more relaxed, so checking |
| * them would make no difference. |
| */ |
| .dot = { .min = 25000 * 5, .max = 540000 * 5}, |
| .vco = { .min = 4860000, .max = 6700000 }, |
| .n = { .min = 1, .max = 1 }, |
| .m1 = { .min = 2, .max = 2 }, |
| .m2 = { .min = 24 << 22, .max = 175 << 22 }, |
| .p1 = { .min = 2, .max = 4 }, |
| .p2 = { .p2_slow = 1, .p2_fast = 14 }, |
| }; |
| |
| static void vlv_clock(int refclk, intel_clock_t *clock) |
| { |
| clock->m = clock->m1 * clock->m2; |
| clock->p = clock->p1 * clock->p2; |
| if (WARN_ON(clock->n == 0 || clock->p == 0)) |
| return; |
| clock->vco = DIV_ROUND_CLOSEST(refclk * clock->m, clock->n); |
| clock->dot = DIV_ROUND_CLOSEST(clock->vco, clock->p); |
| } |
| |
| /** |
| * Returns whether any output on the specified pipe is of the specified type |
| */ |
| static bool intel_pipe_has_type(struct drm_crtc *crtc, int type) |
| { |
| struct drm_device *dev = crtc->dev; |
| struct intel_encoder *encoder; |
| |
| for_each_encoder_on_crtc(dev, crtc, encoder) |
| if (encoder->type == type) |
| return true; |
| |
| return false; |
| } |
| |
| static const intel_limit_t *intel_ironlake_limit(struct drm_crtc *crtc, |
| int refclk) |
| { |
| struct drm_device *dev = crtc->dev; |
| const intel_limit_t *limit; |
| |
| if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)) { |
| if (intel_is_dual_link_lvds(dev)) { |
| if (refclk == 100000) |
| limit = &intel_limits_ironlake_dual_lvds_100m; |
| else |
| limit = &intel_limits_ironlake_dual_lvds; |
| } else { |
| if (refclk == 100000) |
| limit = &intel_limits_ironlake_single_lvds_100m; |
| else |
| limit = &intel_limits_ironlake_single_lvds; |
| } |
| } else |
| limit = &intel_limits_ironlake_dac; |
| |
| return limit; |
| } |
| |
| static const intel_limit_t *intel_g4x_limit(struct drm_crtc *crtc) |
| { |
| struct drm_device *dev = crtc->dev; |
| const intel_limit_t *limit; |
| |
| if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)) { |
| if (intel_is_dual_link_lvds(dev)) |
| limit = &intel_limits_g4x_dual_channel_lvds; |
| else |
| limit = &intel_limits_g4x_single_channel_lvds; |
| } else if (intel_pipe_has_type(crtc, INTEL_OUTPUT_HDMI) || |
| intel_pipe_has_type(crtc, INTEL_OUTPUT_ANALOG)) { |
| limit = &intel_limits_g4x_hdmi; |
| } else if (intel_pipe_has_type(crtc, INTEL_OUTPUT_SDVO)) { |
| limit = &intel_limits_g4x_sdvo; |
| } else /* The option is for other outputs */ |
| limit = &intel_limits_i9xx_sdvo; |
| |
| return limit; |
| } |
| |
| static const intel_limit_t *intel_limit(struct drm_crtc *crtc, int refclk) |
| { |
| struct drm_device *dev = crtc->dev; |
| const intel_limit_t *limit; |
| |
| if (HAS_PCH_SPLIT(dev)) |
| limit = intel_ironlake_limit(crtc, refclk); |
| else if (IS_G4X(dev)) { |
| limit = intel_g4x_limit(crtc); |
| } else if (IS_PINEVIEW(dev)) { |
| if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)) |
| limit = &intel_limits_pineview_lvds; |
| else |
| limit = &intel_limits_pineview_sdvo; |
| } else if (IS_CHERRYVIEW(dev)) { |
| limit = &intel_limits_chv; |
| } else if (IS_VALLEYVIEW(dev)) { |
| limit = &intel_limits_vlv; |
| } else if (!IS_GEN2(dev)) { |
| if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)) |
| limit = &intel_limits_i9xx_lvds; |
| else |
| limit = &intel_limits_i9xx_sdvo; |
| } else { |
| if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)) |
| limit = &intel_limits_i8xx_lvds; |
| else if (intel_pipe_has_type(crtc, INTEL_OUTPUT_DVO)) |
| limit = &intel_limits_i8xx_dvo; |
| else |
| limit = &intel_limits_i8xx_dac; |
| } |
| return limit; |
| } |
| |
| /* m1 is reserved as 0 in Pineview, n is a ring counter */ |
| static void pineview_clock(int refclk, intel_clock_t *clock) |
| { |
| clock->m = clock->m2 + 2; |
| clock->p = clock->p1 * clock->p2; |
| if (WARN_ON(clock->n == 0 || clock->p == 0)) |
| return; |
| clock->vco = DIV_ROUND_CLOSEST(refclk * clock->m, clock->n); |
| clock->dot = DIV_ROUND_CLOSEST(clock->vco, clock->p); |
| } |
| |
| static uint32_t i9xx_dpll_compute_m(struct dpll *dpll) |
| { |
| return 5 * (dpll->m1 + 2) + (dpll->m2 + 2); |
| } |
| |
| static void i9xx_clock(int refclk, intel_clock_t *clock) |
| { |
| clock->m = i9xx_dpll_compute_m(clock); |
| clock->p = clock->p1 * clock->p2; |
| if (WARN_ON(clock->n + 2 == 0 || clock->p == 0)) |
| return; |
| clock->vco = DIV_ROUND_CLOSEST(refclk * clock->m, clock->n + 2); |
| clock->dot = DIV_ROUND_CLOSEST(clock->vco, clock->p); |
| } |
| |
| static void chv_clock(int refclk, intel_clock_t *clock) |
| { |
| clock->m = clock->m1 * clock->m2; |
| clock->p = clock->p1 * clock->p2; |
| if (WARN_ON(clock->n == 0 || clock->p == 0)) |
| return; |
| clock->vco = DIV_ROUND_CLOSEST_ULL((uint64_t)refclk * clock->m, |
| clock->n << 22); |
| clock->dot = DIV_ROUND_CLOSEST(clock->vco, clock->p); |
| } |
| |
| #define INTELPllInvalid(s) do { /* DRM_DEBUG(s); */ return false; } while (0) |
| /** |
| * Returns whether the given set of divisors are valid for a given refclk with |
| * the given connectors. |
| */ |
| |
| static bool intel_PLL_is_valid(struct drm_device *dev, |
| const intel_limit_t *limit, |
| const intel_clock_t *clock) |
| { |
| if (clock->n < limit->n.min || limit->n.max < clock->n) |
| INTELPllInvalid("n out of range\n"); |
| if (clock->p1 < limit->p1.min || limit->p1.max < clock->p1) |
| INTELPllInvalid("p1 out of range\n"); |
| if (clock->m2 < limit->m2.min || limit->m2.max < clock->m2) |
| INTELPllInvalid("m2 out of range\n"); |
| if (clock->m1 < limit->m1.min || limit->m1.max < clock->m1) |
| INTELPllInvalid("m1 out of range\n"); |
| |
| if (!IS_PINEVIEW(dev) && !IS_VALLEYVIEW(dev)) |
| if (clock->m1 <= clock->m2) |
| INTELPllInvalid("m1 <= m2\n"); |
| |
| if (!IS_VALLEYVIEW(dev)) { |
| if (clock->p < limit->p.min || limit->p.max < clock->p) |
| INTELPllInvalid("p out of range\n"); |
| if (clock->m < limit->m.min || limit->m.max < clock->m) |
| INTELPllInvalid("m out of range\n"); |
| } |
| |
| if (clock->vco < limit->vco.min || limit->vco.max < clock->vco) |
| INTELPllInvalid("vco out of range\n"); |
| /* XXX: We may need to be checking "Dot clock" depending on the multiplier, |
| * connector, etc., rather than just a single range. |
| */ |
| if (clock->dot < limit->dot.min || limit->dot.max < clock->dot) |
| INTELPllInvalid("dot out of range\n"); |
| |
| return true; |
| } |
| |
| static bool |
| i9xx_find_best_dpll(const intel_limit_t *limit, struct drm_crtc *crtc, |
| int target, int refclk, intel_clock_t *match_clock, |
| intel_clock_t *best_clock) |
| { |
| struct drm_device *dev = crtc->dev; |
| intel_clock_t clock; |
| int err = target; |
| |
| if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)) { |
| /* |
| * For LVDS just rely on its current settings for dual-channel. |
| * We haven't figured out how to reliably set up different |
| * single/dual channel state, if we even can. |
| */ |
| if (intel_is_dual_link_lvds(dev)) |
| clock.p2 = limit->p2.p2_fast; |
| else |
| clock.p2 = limit->p2.p2_slow; |
| } else { |
| if (target < limit->p2.dot_limit) |
| clock.p2 = limit->p2.p2_slow; |
| else |
| clock.p2 = limit->p2.p2_fast; |
| } |
| |
| memset(best_clock, 0, sizeof(*best_clock)); |
| |
| for (clock.m1 = limit->m1.min; clock.m1 <= limit->m1.max; |
| clock.m1++) { |
| for (clock.m2 = limit->m2.min; |
| clock.m2 <= limit->m2.max; clock.m2++) { |
| if (clock.m2 >= clock.m1) |
| break; |
| for (clock.n = limit->n.min; |
| clock.n <= limit->n.max; clock.n++) { |
| for (clock.p1 = limit->p1.min; |
| clock.p1 <= limit->p1.max; clock.p1++) { |
| int this_err; |
| |
| i9xx_clock(refclk, &clock); |
| if (!intel_PLL_is_valid(dev, limit, |
| &clock)) |
| continue; |
| if (match_clock && |
| clock.p != match_clock->p) |
| continue; |
| |
| this_err = abs(clock.dot - target); |
| if (this_err < err) { |
| *best_clock = clock; |
| err = this_err; |
| } |
| } |
| } |
| } |
| } |
| |
| return (err != target); |
| } |
| |
| static bool |
| pnv_find_best_dpll(const intel_limit_t *limit, struct drm_crtc *crtc, |
| int target, int refclk, intel_clock_t *match_clock, |
| intel_clock_t *best_clock) |
| { |
| struct drm_device *dev = crtc->dev; |
| intel_clock_t clock; |
| int err = target; |
| |
| if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)) { |
| /* |
| * For LVDS just rely on its current settings for dual-channel. |
| * We haven't figured out how to reliably set up different |
| * single/dual channel state, if we even can. |
| */ |
| if (intel_is_dual_link_lvds(dev)) |
| clock.p2 = limit->p2.p2_fast; |
| else |
| clock.p2 = limit->p2.p2_slow; |
| } else { |
| if (target < limit->p2.dot_limit) |
| clock.p2 = limit->p2.p2_slow; |
| else |
| clock.p2 = limit->p2.p2_fast; |
| } |
| |
| memset(best_clock, 0, sizeof(*best_clock)); |
| |
| for (clock.m1 = limit->m1.min; clock.m1 <= limit->m1.max; |
| clock.m1++) { |
| for (clock.m2 = limit->m2.min; |
| clock.m2 <= limit->m2.max; clock.m2++) { |
| for (clock.n = limit->n.min; |
| clock.n <= limit->n.max; clock.n++) { |
| for (clock.p1 = limit->p1.min; |
| clock.p1 <= limit->p1.max; clock.p1++) { |
| int this_err; |
| |
| pineview_clock(refclk, &clock); |
| if (!intel_PLL_is_valid(dev, limit, |
| &clock)) |
| continue; |
| if (match_clock && |
| clock.p != match_clock->p) |
| continue; |
| |
| this_err = abs(clock.dot - target); |
| if (this_err < err) { |
| *best_clock = clock; |
| err = this_err; |
| } |
| } |
| } |
| } |
| } |
| |
| return (err != target); |
| } |
| |
| static bool |
| g4x_find_best_dpll(const intel_limit_t *limit, struct drm_crtc *crtc, |
| int target, int refclk, intel_clock_t *match_clock, |
| intel_clock_t *best_clock) |
| { |
| struct drm_device *dev = crtc->dev; |
| intel_clock_t clock; |
| int max_n; |
| bool found; |
| /* approximately equals target * 0.00585 */ |
| int err_most = (target >> 8) + (target >> 9); |
| found = false; |
| |
| if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)) { |
| if (intel_is_dual_link_lvds(dev)) |
| clock.p2 = limit->p2.p2_fast; |
| else |
| clock.p2 = limit->p2.p2_slow; |
| } else { |
| if (target < limit->p2.dot_limit) |
| clock.p2 = limit->p2.p2_slow; |
| else |
| clock.p2 = limit->p2.p2_fast; |
| } |
| |
| memset(best_clock, 0, sizeof(*best_clock)); |
| max_n = limit->n.max; |
| /* based on hardware requirement, prefer smaller n to precision */ |
| for (clock.n = limit->n.min; clock.n <= max_n; clock.n++) { |
| /* based on hardware requirement, prefere larger m1,m2 */ |
| for (clock.m1 = limit->m1.max; |
| clock.m1 >= limit->m1.min; clock.m1--) { |
| for (clock.m2 = limit->m2.max; |
| clock.m2 >= limit->m2.min; clock.m2--) { |
| for (clock.p1 = limit->p1.max; |
| clock.p1 >= limit->p1.min; clock.p1--) { |
| int this_err; |
| |
| i9xx_clock(refclk, &clock); |
| if (!intel_PLL_is_valid(dev, limit, |
| &clock)) |
| continue; |
| |
| this_err = abs(clock.dot - target); |
| if (this_err < err_most) { |
| *best_clock = clock; |
| err_most = this_err; |
| max_n = clock.n; |
| found = true; |
| } |
| } |
| } |
| } |
| } |
| return found; |
| } |
| |
| static bool |
| vlv_find_best_dpll(const intel_limit_t *limit, struct drm_crtc *crtc, |
| int target, int refclk, intel_clock_t *match_clock, |
| intel_clock_t *best_clock) |
| { |
| struct drm_device *dev = crtc->dev; |
| intel_clock_t clock; |
| unsigned int bestppm = 1000000; |
| /* min update 19.2 MHz */ |
| int max_n = min(limit->n.max, refclk / 19200); |
| bool found = false; |
| |
| target *= 5; /* fast clock */ |
| |
| memset(best_clock, 0, sizeof(*best_clock)); |
| |
| /* based on hardware requirement, prefer smaller n to precision */ |
| for (clock.n = limit->n.min; clock.n <= max_n; clock.n++) { |
| for (clock.p1 = limit->p1.max; clock.p1 >= limit->p1.min; clock.p1--) { |
| for (clock.p2 = limit->p2.p2_fast; clock.p2 >= limit->p2.p2_slow; |
| clock.p2 -= clock.p2 > 10 ? 2 : 1) { |
| clock.p = clock.p1 * clock.p2; |
| /* based on hardware requirement, prefer bigger m1,m2 values */ |
| for (clock.m1 = limit->m1.min; clock.m1 <= limit->m1.max; clock.m1++) { |
| unsigned int ppm, diff; |
| |
| clock.m2 = DIV_ROUND_CLOSEST(target * clock.p * clock.n, |
| refclk * clock.m1); |
| |
| vlv_clock(refclk, &clock); |
| |
| if (!intel_PLL_is_valid(dev, limit, |
| &clock)) |
| continue; |
| |
| diff = abs(clock.dot - target); |
| ppm = div_u64(1000000ULL * diff, target); |
| |
| if (ppm < 100 && clock.p > best_clock->p) { |
| bestppm = 0; |
| *best_clock = clock; |
| found = true; |
| } |
| |
| if (bestppm >= 10 && ppm < bestppm - 10) { |
| bestppm = ppm; |
| *best_clock = clock; |
| found = true; |
| } |
| } |
| } |
| } |
| } |
| |
| return found; |
| } |
| |
| static bool |
| chv_find_best_dpll(const intel_limit_t *limit, struct drm_crtc *crtc, |
| int target, int refclk, intel_clock_t *match_clock, |
| intel_clock_t *best_clock) |
| { |
| struct drm_device *dev = crtc->dev; |
| intel_clock_t clock; |
| uint64_t m2; |
| int found = false; |
| |
| memset(best_clock, 0, sizeof(*best_clock)); |
| |
| /* |
| * Based on hardware doc, the n always set to 1, and m1 always |
| * set to 2. If requires to support 200Mhz refclk, we need to |
| * revisit this because n may not 1 anymore. |
| */ |
| clock.n = 1, clock.m1 = 2; |
| target *= 5; /* fast clock */ |
| |
| for (clock.p1 = limit->p1.max; clock.p1 >= limit->p1.min; clock.p1--) { |
| for (clock.p2 = limit->p2.p2_fast; |
| clock.p2 >= limit->p2.p2_slow; |
| clock.p2 -= clock.p2 > 10 ? 2 : 1) { |
| |
| clock.p = clock.p1 * clock.p2; |
| |
| m2 = DIV_ROUND_CLOSEST_ULL(((uint64_t)target * clock.p * |
| clock.n) << 22, refclk * clock.m1); |
| |
| if (m2 > INT_MAX/clock.m1) |
| continue; |
| |
| clock.m2 = m2; |
| |
| chv_clock(refclk, &clock); |
| |
| if (!intel_PLL_is_valid(dev, limit, &clock)) |
| continue; |
| |
| /* based on hardware requirement, prefer bigger p |
| */ |
| if (clock.p > best_clock->p) { |
| *best_clock = clock; |
| found = true; |
| } |
| } |
| } |
| |
| return found; |
| } |
| |
| bool intel_crtc_active(struct drm_crtc *crtc) |
| { |
| struct intel_crtc *intel_crtc = to_intel_crtc(crtc); |
| |
| /* Be paranoid as we can arrive here with only partial |
| * state retrieved from the hardware during setup. |
| * |
| * We can ditch the adjusted_mode.crtc_clock check as soon |
| * as Haswell has gained clock readout/fastboot support. |
| * |
| * We can ditch the crtc->primary->fb check as soon as we can |
| * properly reconstruct framebuffers. |
| */ |
| return intel_crtc->active && crtc->primary->fb && |
| intel_crtc->config.adjusted_mode.crtc_clock; |
| } |
| |
| enum transcoder intel_pipe_to_cpu_transcoder(struct drm_i915_private *dev_priv, |
| enum pipe pipe) |
| { |
| struct drm_crtc *crtc = dev_priv->pipe_to_crtc_mapping[pipe]; |
| struct intel_crtc *intel_crtc = to_intel_crtc(crtc); |
| |
| return intel_crtc->config.cpu_transcoder; |
| } |
| |
| static void g4x_wait_for_vblank(struct drm_device *dev, int pipe) |
| { |
| struct drm_i915_private *dev_priv = dev->dev_private; |
| u32 frame, frame_reg = PIPE_FRMCOUNT_GM45(pipe); |
| |
| frame = I915_READ(frame_reg); |
| |
| if (wait_for(I915_READ_NOTRACE(frame_reg) != frame, 50)) |
| WARN(1, "vblank wait on pipe %c timed out\n", |
| pipe_name(pipe)); |
| } |
| |
| /** |
| * intel_wait_for_vblank - wait for vblank on a given pipe |
| * @dev: drm device |
| * @pipe: pipe to wait for |
| * |
| * Wait for vblank to occur on a given pipe. Needed for various bits of |
| * mode setting code. |
| */ |
| void intel_wait_for_vblank(struct drm_device *dev, int pipe) |
| { |
| struct drm_i915_private *dev_priv = dev->dev_private; |
| int pipestat_reg = PIPESTAT(pipe); |
| |
| if (IS_G4X(dev) || INTEL_INFO(dev)->gen >= 5) { |
| g4x_wait_for_vblank(dev, pipe); |
| return; |
| } |
| |
| /* Clear existing vblank status. Note this will clear any other |
| * sticky status fields as well. |
| * |
| * This races with i915_driver_irq_handler() with the result |
| * that either function could miss a vblank event. Here it is not |
| * fatal, as we will either wait upon the next vblank interrupt or |
| * timeout. Generally speaking intel_wait_for_vblank() is only |
| * called during modeset at which time the GPU should be idle and |
| * should *not* be performing page flips and thus not waiting on |
| * vblanks... |
| * Currently, the result of us stealing a vblank from the irq |
| * handler is that a single frame will be skipped during swapbuffers. |
| */ |
| I915_WRITE(pipestat_reg, |
| I915_READ(pipestat_reg) | PIPE_VBLANK_INTERRUPT_STATUS); |
| |
| /* Wait for vblank interrupt bit to set */ |
| if (wait_for(I915_READ(pipestat_reg) & |
| PIPE_VBLANK_INTERRUPT_STATUS, |
| 50)) |
| DRM_DEBUG_KMS("vblank wait on pipe %c timed out\n", |
| pipe_name(pipe)); |
| } |
| |
| static bool pipe_dsl_stopped(struct drm_device *dev, enum pipe pipe) |
| { |
| struct drm_i915_private *dev_priv = dev->dev_private; |
| u32 reg = PIPEDSL(pipe); |
| u32 line1, line2; |
| u32 line_mask; |
| |
| if (IS_GEN2(dev)) |
| line_mask = DSL_LINEMASK_GEN2; |
| else |
| line_mask = DSL_LINEMASK_GEN3; |
| |
| line1 = I915_READ(reg) & line_mask; |
| mdelay(5); |
| line2 = I915_READ(reg) & line_mask; |
| |
| return line1 == line2; |
| } |
| |
| /* |
| * intel_wait_for_pipe_off - wait for pipe to turn off |
| * @crtc: crtc whose pipe to wait for |
| * |
| * After disabling a pipe, we can't wait for vblank in the usual way, |
| * spinning on the vblank interrupt status bit, since we won't actually |
| * see an interrupt when the pipe is disabled. |
| * |
| * On Gen4 and above: |
| * wait for the pipe register state bit to turn off |
| * |
| * Otherwise: |
| * wait for the display line value to settle (it usually |
| * ends up stopping at the start of the next frame). |
| * |
| */ |
| static void intel_wait_for_pipe_off(struct intel_crtc *crtc) |
| { |
| struct drm_device *dev = crtc->base.dev; |
| struct drm_i915_private *dev_priv = dev->dev_private; |
| enum transcoder cpu_transcoder = crtc->config.cpu_transcoder; |
| enum pipe pipe = crtc->pipe; |
| |
| if (INTEL_INFO(dev)->gen >= 4) { |
| int reg = PIPECONF(cpu_transcoder); |
| |
| /* Wait for the Pipe State to go off */ |
| if (wait_for((I915_READ(reg) & I965_PIPECONF_ACTIVE) == 0, |
| 100)) |
| WARN(1, "pipe_off wait timed out\n"); |
| } else { |
| /* Wait for the display line to settle */ |
| if (wait_for(pipe_dsl_stopped(dev, pipe), 100)) |
| WARN(1, "pipe_off wait timed out\n"); |
| } |
| } |
| |
| /* |
| * ibx_digital_port_connected - is the specified port connected? |
| * @dev_priv: i915 private structure |
| * @port: the port to test |
| * |
| * Returns true if @port is connected, false otherwise. |
| */ |
| bool ibx_digital_port_connected(struct drm_i915_private *dev_priv, |
| struct intel_digital_port *port) |
| { |
| u32 bit; |
| |
| if (HAS_PCH_IBX(dev_priv->dev)) { |
| switch (port->port) { |
| case PORT_B: |
| bit = SDE_PORTB_HOTPLUG; |
| break; |
| case PORT_C: |
| bit = SDE_PORTC_HOTPLUG; |
| break; |
| case PORT_D: |
| bit = SDE_PORTD_HOTPLUG; |
| break; |
| default: |
| return true; |
| } |
| } else { |
| switch (port->port) { |
| case PORT_B: |
| bit = SDE_PORTB_HOTPLUG_CPT; |
| break; |
| case PORT_C: |
| bit = SDE_PORTC_HOTPLUG_CPT; |
| break; |
| case PORT_D: |
| bit = SDE_PORTD_HOTPLUG_CPT; |
| break; |
| default: |
| return true; |
| } |
| } |
| |
| return I915_READ(SDEISR) & bit; |
| } |
| |
| static const char *state_string(bool enabled) |
| { |
| return enabled ? "on" : "off"; |
| } |
| |
| /* Only for pre-ILK configs */ |
| void assert_pll(struct drm_i915_private *dev_priv, |
| enum pipe pipe, bool state) |
| { |
| int reg; |
| u32 val; |
| bool cur_state; |
| |
| reg = DPLL(pipe); |
| val = I915_READ(reg); |
| cur_state = !!(val & DPLL_VCO_ENABLE); |
| WARN(cur_state != state, |
| "PLL state assertion failure (expected %s, current %s)\n", |
| state_string(state), state_string(cur_state)); |
| } |
| |
| /* XXX: the dsi pll is shared between MIPI DSI ports */ |
| static void assert_dsi_pll(struct drm_i915_private *dev_priv, bool state) |
| { |
| u32 val; |
| bool cur_state; |
| |
| mutex_lock(&dev_priv->dpio_lock); |
| val = vlv_cck_read(dev_priv, CCK_REG_DSI_PLL_CONTROL); |
| mutex_unlock(&dev_priv->dpio_lock); |
| |
| cur_state = val & DSI_PLL_VCO_EN; |
| WARN(cur_state != state, |
| "DSI PLL state assertion failure (expected %s, current %s)\n", |
| state_string(state), state_string(cur_state)); |
| } |
| #define assert_dsi_pll_enabled(d) assert_dsi_pll(d, true) |
| #define assert_dsi_pll_disabled(d) assert_dsi_pll(d, false) |
| |
| struct intel_shared_dpll * |
| intel_crtc_to_shared_dpll(struct intel_crtc *crtc) |
| { |
| struct drm_i915_private *dev_priv = crtc->base.dev->dev_private; |
| |
| if (crtc->config.shared_dpll < 0) |
| return NULL; |
| |
| return &dev_priv->shared_dplls[crtc->config.shared_dpll]; |
| } |
| |
| /* For ILK+ */ |
| void assert_shared_dpll(struct drm_i915_private *dev_priv, |
| struct intel_shared_dpll *pll, |
| bool state) |
| { |
| bool cur_state; |
| struct intel_dpll_hw_state hw_state; |
| |
| if (WARN (!pll, |
| "asserting DPLL %s with no DPLL\n", state_string(state))) |
| return; |
| |
| cur_state = pll->get_hw_state(dev_priv, pll, &hw_state); |
| WARN(cur_state != state, |
| "%s assertion failure (expected %s, current %s)\n", |
| pll->name, state_string(state), state_string(cur_state)); |
| } |
| |
| static void assert_fdi_tx(struct drm_i915_private *dev_priv, |
| enum pipe pipe, bool state) |
| { |
| int reg; |
| u32 val; |
| bool cur_state; |
| enum transcoder cpu_transcoder = intel_pipe_to_cpu_transcoder(dev_priv, |
| pipe); |
| |
| if (HAS_DDI(dev_priv->dev)) { |
| /* DDI does not have a specific FDI_TX register */ |
| reg = TRANS_DDI_FUNC_CTL(cpu_transcoder); |
| val = I915_READ(reg); |
| cur_state = !!(val & TRANS_DDI_FUNC_ENABLE); |
| } else { |
| reg = FDI_TX_CTL(pipe); |
| val = I915_READ(reg); |
| cur_state = !!(val & FDI_TX_ENABLE); |
| } |
| WARN(cur_state != state, |
| "FDI TX state assertion failure (expected %s, current %s)\n", |
| state_string(state), state_string(cur_state)); |
| } |
| #define assert_fdi_tx_enabled(d, p) assert_fdi_tx(d, p, true) |
| #define assert_fdi_tx_disabled(d, p) assert_fdi_tx(d, p, false) |
| |
| static void assert_fdi_rx(struct drm_i915_private *dev_priv, |
| enum pipe pipe, bool state) |
| { |
| int reg; |
| u32 val; |
| bool cur_state; |
| |
| reg = FDI_RX_CTL(pipe); |
| val = I915_READ(reg); |
| cur_state = !!(val & FDI_RX_ENABLE); |
| WARN(cur_state != state, |
| "FDI RX state assertion failure (expected %s, current %s)\n", |
| state_string(state), state_string(cur_state)); |
| } |
| #define assert_fdi_rx_enabled(d, p) assert_fdi_rx(d, p, true) |
| #define assert_fdi_rx_disabled(d, p) assert_fdi_rx(d, p, false) |
| |
| static void assert_fdi_tx_pll_enabled(struct drm_i915_private *dev_priv, |
| enum pipe pipe) |
| { |
| int reg; |
| u32 val; |
| |
| /* ILK FDI PLL is always enabled */ |
| if (INTEL_INFO(dev_priv->dev)->gen == 5) |
| return; |
| |
| /* On Haswell, DDI ports are responsible for the FDI PLL setup */ |
| if (HAS_DDI(dev_priv->dev)) |
| return; |
| |
| reg = FDI_TX_CTL(pipe); |
| val = I915_READ(reg); |
| WARN(!(val & FDI_TX_PLL_ENABLE), "FDI TX PLL assertion failure, should be active but is disabled\n"); |
| } |
| |
| void assert_fdi_rx_pll(struct drm_i915_private *dev_priv, |
| enum pipe pipe, bool state) |
| { |
| int reg; |
| u32 val; |
| bool cur_state; |
| |
| reg = FDI_RX_CTL(pipe); |
| val = I915_READ(reg); |
| cur_state = !!(val & FDI_RX_PLL_ENABLE); |
| WARN(cur_state != state, |
| "FDI RX PLL assertion failure (expected %s, current %s)\n", |
| state_string(state), state_string(cur_state)); |
| } |
| |
| static void assert_panel_unlocked(struct drm_i915_private *dev_priv, |
| enum pipe pipe) |
| { |
| struct drm_device *dev = dev_priv->dev; |
| int pp_reg; |
| u32 val; |
| enum pipe panel_pipe = PIPE_A; |
| bool locked = true; |
| |
| if (WARN_ON(HAS_DDI(dev))) |
| return; |
| |
| if (HAS_PCH_SPLIT(dev)) { |
| u32 port_sel; |
| |
| pp_reg = PCH_PP_CONTROL; |
| port_sel = I915_READ(PCH_PP_ON_DELAYS) & PANEL_PORT_SELECT_MASK; |
| |
| if (port_sel == PANEL_PORT_SELECT_LVDS && |
| I915_READ(PCH_LVDS) & LVDS_PIPEB_SELECT) |
| panel_pipe = PIPE_B; |
| /* XXX: else fix for eDP */ |
| } else if (IS_VALLEYVIEW(dev)) { |
| /* presumably write lock depends on pipe, not port select */ |
| pp_reg = VLV_PIPE_PP_CONTROL(pipe); |
| panel_pipe = pipe; |
| } else { |
| pp_reg = PP_CONTROL; |
| if (I915_READ(LVDS) & LVDS_PIPEB_SELECT) |
| panel_pipe = PIPE_B; |
| } |
| |
| val = I915_READ(pp_reg); |
| if (!(val & PANEL_POWER_ON) || |
| ((val & PANEL_UNLOCK_MASK) == PANEL_UNLOCK_REGS)) |
| locked = false; |
| |
| WARN(panel_pipe == pipe && locked, |
| "panel assertion failure, pipe %c regs locked\n", |
| pipe_name(pipe)); |
| } |
| |
| static void assert_cursor(struct drm_i915_private *dev_priv, |
| enum pipe pipe, bool state) |
| { |
| struct drm_device *dev = dev_priv->dev; |
| bool cur_state; |
| |
| if (IS_845G(dev) || IS_I865G(dev)) |
| cur_state = I915_READ(_CURACNTR) & CURSOR_ENABLE; |
| else |
| cur_state = I915_READ(CURCNTR(pipe)) & CURSOR_MODE; |
| |
| WARN(cur_state != state, |
| "cursor on pipe %c assertion failure (expected %s, current %s)\n", |
| pipe_name(pipe), state_string(state), state_string(cur_state)); |
| } |
| #define assert_cursor_enabled(d, p) assert_cursor(d, p, true) |
| #define assert_cursor_disabled(d, p) assert_cursor(d, p, false) |
| |
| void assert_pipe(struct drm_i915_private *dev_priv, |
| enum pipe pipe, bool state) |
| { |
| int reg; |
| u32 val; |
| bool cur_state; |
| enum transcoder cpu_transcoder = intel_pipe_to_cpu_transcoder(dev_priv, |
| pipe); |
| |
| /* if we need the pipe quirk it must be always on */ |
| if ((pipe == PIPE_A && dev_priv->quirks & QUIRK_PIPEA_FORCE) || |
| (pipe == PIPE_B && dev_priv->quirks & QUIRK_PIPEB_FORCE)) |
| state = true; |
| |
| if (!intel_display_power_enabled(dev_priv, |
| POWER_DOMAIN_TRANSCODER(cpu_transcoder))) { |
| cur_state = false; |
| } else { |
| reg = PIPECONF(cpu_transcoder); |
| val = I915_READ(reg); |
| cur_state = !!(val & PIPECONF_ENABLE); |
| } |
| |
| WARN(cur_state != state, |
| "pipe %c assertion failure (expected %s, current %s)\n", |
| pipe_name(pipe), state_string(state), state_string(cur_state)); |
| } |
| |
| static void assert_plane(struct drm_i915_private *dev_priv, |
| enum plane plane, bool state) |
| { |
| int reg; |
| u32 val; |
| bool cur_state; |
| |
| reg = DSPCNTR(plane); |
| val = I915_READ(reg); |
| cur_state = !!(val & DISPLAY_PLANE_ENABLE); |
| WARN(cur_state != state, |
| "plane %c assertion failure (expected %s, current %s)\n", |
| plane_name(plane), state_string(state), state_string(cur_state)); |
| } |
| |
| #define assert_plane_enabled(d, p) assert_plane(d, p, true) |
| #define assert_plane_disabled(d, p) assert_plane(d, p, false) |
| |
| static void assert_planes_disabled(struct drm_i915_private *dev_priv, |
| enum pipe pipe) |
| { |
| struct drm_device *dev = dev_priv->dev; |
| int reg, i; |
| u32 val; |
| int cur_pipe; |
| |
| /* Primary planes are fixed to pipes on gen4+ */ |
| if (INTEL_INFO(dev)->gen >= 4) { |
| reg = DSPCNTR(pipe); |
| val = I915_READ(reg); |
| WARN(val & DISPLAY_PLANE_ENABLE, |
| "plane %c assertion failure, should be disabled but not\n", |
| plane_name(pipe)); |
| return; |
| } |
| |
| /* Need to check both planes against the pipe */ |
| for_each_pipe(dev_priv, i) { |
| reg = DSPCNTR(i); |
| val = I915_READ(reg); |
| cur_pipe = (val & DISPPLANE_SEL_PIPE_MASK) >> |
| DISPPLANE_SEL_PIPE_SHIFT; |
| WARN((val & DISPLAY_PLANE_ENABLE) && pipe == cur_pipe, |
| "plane %c assertion failure, should be off on pipe %c but is still active\n", |
| plane_name(i), pipe_name(pipe)); |
| } |
| } |
| |
| static void assert_sprites_disabled(struct drm_i915_private *dev_priv, |
| enum pipe pipe) |
| { |
| struct drm_device *dev = dev_priv->dev; |
| int reg, sprite; |
| u32 val; |
| |
| if (IS_VALLEYVIEW(dev)) { |
| for_each_sprite(pipe, sprite) { |
| reg = SPCNTR(pipe, sprite); |
| val = I915_READ(reg); |
| WARN(val & SP_ENABLE, |
| "sprite %c assertion failure, should be off on pipe %c but is still active\n", |
| sprite_name(pipe, sprite), pipe_name(pipe)); |
| } |
| } else if (INTEL_INFO(dev)->gen >= 7) { |
| reg = SPRCTL(pipe); |
| val = I915_READ(reg); |
| WARN(val & SPRITE_ENABLE, |
| "sprite %c assertion failure, should be off on pipe %c but is still active\n", |
| plane_name(pipe), pipe_name(pipe)); |
| } else if (INTEL_INFO(dev)->gen >= 5) { |
| reg = DVSCNTR(pipe); |
| val = I915_READ(reg); |
| WARN(val & DVS_ENABLE, |
| "sprite %c assertion failure, should be off on pipe %c but is still active\n", |
| plane_name(pipe), pipe_name(pipe)); |
| } |
| } |
| |
| static void assert_vblank_disabled(struct drm_crtc *crtc) |
| { |
| if (WARN_ON(drm_crtc_vblank_get(crtc) == 0)) |
| drm_crtc_vblank_put(crtc); |
| } |
| |
| static void ibx_assert_pch_refclk_enabled(struct drm_i915_private *dev_priv) |
| { |
| u32 val; |
| bool enabled; |
| |
| WARN_ON(!(HAS_PCH_IBX(dev_priv->dev) || HAS_PCH_CPT(dev_priv->dev))); |
| |
| val = I915_READ(PCH_DREF_CONTROL); |
| enabled = !!(val & (DREF_SSC_SOURCE_MASK | DREF_NONSPREAD_SOURCE_MASK | |
| DREF_SUPERSPREAD_SOURCE_MASK)); |
| WARN(!enabled, "PCH refclk assertion failure, should be active but is disabled\n"); |
| } |
| |
| static void assert_pch_transcoder_disabled(struct drm_i915_private *dev_priv, |
| enum pipe pipe) |
| { |
| int reg; |
| u32 val; |
| bool enabled; |
| |
| reg = PCH_TRANSCONF(pipe); |
| val = I915_READ(reg); |
| enabled = !!(val & TRANS_ENABLE); |
| WARN(enabled, |
| "transcoder assertion failed, should be off on pipe %c but is still active\n", |
| pipe_name(pipe)); |
| } |
| |
| static bool dp_pipe_enabled(struct drm_i915_private *dev_priv, |
| enum pipe pipe, u32 port_sel, u32 val) |
| { |
| if ((val & DP_PORT_EN) == 0) |
| return false; |
| |
| if (HAS_PCH_CPT(dev_priv->dev)) { |
| u32 trans_dp_ctl_reg = TRANS_DP_CTL(pipe); |
| u32 trans_dp_ctl = I915_READ(trans_dp_ctl_reg); |
| if ((trans_dp_ctl & TRANS_DP_PORT_SEL_MASK) != port_sel) |
| return false; |
| } else if (IS_CHERRYVIEW(dev_priv->dev)) { |
| if ((val & DP_PIPE_MASK_CHV) != DP_PIPE_SELECT_CHV(pipe)) |
| return false; |
| } else { |
| if ((val & DP_PIPE_MASK) != (pipe << 30)) |
| return false; |
| } |
| return true; |
| } |
| |
| static bool hdmi_pipe_enabled(struct drm_i915_private *dev_priv, |
| enum pipe pipe, u32 val) |
| { |
| if ((val & SDVO_ENABLE) == 0) |
| return false; |
| |
| if (HAS_PCH_CPT(dev_priv->dev)) { |
| if ((val & SDVO_PIPE_SEL_MASK_CPT) != SDVO_PIPE_SEL_CPT(pipe)) |
| return false; |
| } else if (IS_CHERRYVIEW(dev_priv->dev)) { |
| if ((val & SDVO_PIPE_SEL_MASK_CHV) != SDVO_PIPE_SEL_CHV(pipe)) |
| return false; |
| } else { |
| if ((val & SDVO_PIPE_SEL_MASK) != SDVO_PIPE_SEL(pipe)) |
| return false; |
| } |
| return true; |
| } |
| |
| static bool lvds_pipe_enabled(struct drm_i915_private *dev_priv, |
| enum pipe pipe, u32 val) |
| { |
| if ((val & LVDS_PORT_EN) == 0) |
| return false; |
| |
| if (HAS_PCH_CPT(dev_priv->dev)) { |
| if ((val & PORT_TRANS_SEL_MASK) != PORT_TRANS_SEL_CPT(pipe)) |
| return false; |
| } else { |
| if ((val & LVDS_PIPE_MASK) != LVDS_PIPE(pipe)) |
| return false; |
| } |
| return true; |
| } |
| |
| static bool adpa_pipe_enabled(struct drm_i915_private *dev_priv, |
| enum pipe pipe, u32 val) |
| { |
| if ((val & ADPA_DAC_ENABLE) == 0) |
| return false; |
| if (HAS_PCH_CPT(dev_priv->dev)) { |
| if ((val & PORT_TRANS_SEL_MASK) != PORT_TRANS_SEL_CPT(pipe)) |
| return false; |
| } else { |
| if ((val & ADPA_PIPE_SELECT_MASK) != ADPA_PIPE_SELECT(pipe)) |
| return false; |
| } |
| return true; |
| } |
| |
| static void assert_pch_dp_disabled(struct drm_i915_private *dev_priv, |
| enum pipe pipe, int reg, u32 port_sel) |
| { |
| u32 val = I915_READ(reg); |
| WARN(dp_pipe_enabled(dev_priv, pipe, port_sel, val), |
| "PCH DP (0x%08x) enabled on transcoder %c, should be disabled\n", |
| reg, pipe_name(pipe)); |
| |
| WARN(HAS_PCH_IBX(dev_priv->dev) && (val & DP_PORT_EN) == 0 |
| && (val & DP_PIPEB_SELECT), |
| "IBX PCH dp port still using transcoder B\n"); |
| } |
| |
| static void assert_pch_hdmi_disabled(struct drm_i915_private *dev_priv, |
| enum pipe pipe, int reg) |
| { |
| u32 val = I915_READ(reg); |
| WARN(hdmi_pipe_enabled(dev_priv, pipe, val), |
| "PCH HDMI (0x%08x) enabled on transcoder %c, should be disabled\n", |
| reg, pipe_name(pipe)); |
| |
| WARN(HAS_PCH_IBX(dev_priv->dev) && (val & SDVO_ENABLE) == 0 |
| && (val & SDVO_PIPE_B_SELECT), |
| "IBX PCH hdmi port still using transcoder B\n"); |
| } |
| |
| static void assert_pch_ports_disabled(struct drm_i915_private *dev_priv, |
| enum pipe pipe) |
| { |
| int reg; |
| u32 val; |
| |
| assert_pch_dp_disabled(dev_priv, pipe, PCH_DP_B, TRANS_DP_PORT_SEL_B); |
| assert_pch_dp_disabled(dev_priv, pipe, PCH_DP_C, TRANS_DP_PORT_SEL_C); |
| assert_pch_dp_disabled(dev_priv, pipe, PCH_DP_D, TRANS_DP_PORT_SEL_D); |
| |
| reg = PCH_ADPA; |
| val = I915_READ(reg); |
| WARN(adpa_pipe_enabled(dev_priv, pipe, val), |
| "PCH VGA enabled on transcoder %c, should be disabled\n", |
| pipe_name(pipe)); |
| |
| reg = PCH_LVDS; |
| val = I915_READ(reg); |
| WARN(lvds_pipe_enabled(dev_priv, pipe, val), |
| "PCH LVDS enabled on transcoder %c, should be disabled\n", |
| pipe_name(pipe)); |
| |
| assert_pch_hdmi_disabled(dev_priv, pipe, PCH_HDMIB); |
| assert_pch_hdmi_disabled(dev_priv, pipe, PCH_HDMIC); |
| assert_pch_hdmi_disabled(dev_priv, pipe, PCH_HDMID); |
| } |
| |
| static void intel_init_dpio(struct drm_device *dev) |
| { |
| struct drm_i915_private *dev_priv = dev->dev_private; |
| |
| if (!IS_VALLEYVIEW(dev)) |
| return; |
| |
| /* |
| * IOSF_PORT_DPIO is used for VLV x2 PHY (DP/HDMI B and C), |
| * CHV x1 PHY (DP/HDMI D) |
| * IOSF_PORT_DPIO_2 is used for CHV x2 PHY (DP/HDMI B and C) |
| */ |
| if (IS_CHERRYVIEW(dev)) { |
| DPIO_PHY_IOSF_PORT(DPIO_PHY0) = IOSF_PORT_DPIO_2; |
| DPIO_PHY_IOSF_PORT(DPIO_PHY1) = IOSF_PORT_DPIO; |
| } else { |
| DPIO_PHY_IOSF_PORT(DPIO_PHY0) = IOSF_PORT_DPIO; |
| } |
| } |
| |
| static void vlv_enable_pll(struct intel_crtc *crtc) |
| { |
| struct drm_device *dev = crtc->base.dev; |
| struct drm_i915_private *dev_priv = dev->dev_private; |
| int reg = DPLL(crtc->pipe); |
| u32 dpll = crtc->config.dpll_hw_state.dpll; |
| |
| assert_pipe_disabled(dev_priv, crtc->pipe); |
| |
| /* No really, not for ILK+ */ |
| BUG_ON(!IS_VALLEYVIEW(dev_priv->dev)); |
| |
| /* PLL is protected by panel, make sure we can write it */ |
| if (IS_MOBILE(dev_priv->dev)) |
| assert_panel_unlocked(dev_priv, crtc->pipe); |
| |
| I915_WRITE(reg, dpll); |
| POSTING_READ(reg); |
| udelay(150); |
| |
| if (wait_for(((I915_READ(reg) & DPLL_LOCK_VLV) == DPLL_LOCK_VLV), 1)) |
| DRM_ERROR("DPLL %d failed to lock\n", crtc->pipe); |
| |
| I915_WRITE(DPLL_MD(crtc->pipe), crtc->config.dpll_hw_state.dpll_md); |
| POSTING_READ(DPLL_MD(crtc->pipe)); |
| |
| /* We do this three times for luck */ |
| I915_WRITE(reg, dpll); |
| POSTING_READ(reg); |
| udelay(150); /* wait for warmup */ |
| I915_WRITE(reg, dpll); |
| POSTING_READ(reg); |
| udelay(150); /* wait for warmup */ |
| I915_WRITE(reg, dpll); |
| POSTING_READ(reg); |
| udelay(150); /* wait for warmup */ |
| } |
| |
| static void chv_enable_pll(struct intel_crtc *crtc) |
| { |
| struct drm_device *dev = crtc->base.dev; |
| struct drm_i915_private *dev_priv = dev->dev_private; |
| int pipe = crtc->pipe; |
| enum dpio_channel port = vlv_pipe_to_channel(pipe); |
| u32 tmp; |
| |
| assert_pipe_disabled(dev_priv, crtc->pipe); |
| |
| BUG_ON(!IS_CHERRYVIEW(dev_priv->dev)); |
| |
| mutex_lock(&dev_priv->dpio_lock); |
| |
| /* Enable back the 10bit clock to display controller */ |
| tmp = vlv_dpio_read(dev_priv, pipe, CHV_CMN_DW14(port)); |
| tmp |= DPIO_DCLKP_EN; |
| vlv_dpio_write(dev_priv, pipe, CHV_CMN_DW14(port), tmp); |
| |
| /* |
| * Need to wait > 100ns between dclkp clock enable bit and PLL enable. |
| */ |
| udelay(1); |
| |
| /* Enable PLL */ |
| I915_WRITE(DPLL(pipe), crtc->config.dpll_hw_state.dpll); |
| |
| /* Check PLL is locked */ |
| if (wait_for(((I915_READ(DPLL(pipe)) & DPLL_LOCK_VLV) == DPLL_LOCK_VLV), 1)) |
| DRM_ERROR("PLL %d failed to lock\n", pipe); |
| |
| /* not sure when this should be written */ |
| I915_WRITE(DPLL_MD(pipe), crtc->config.dpll_hw_state.dpll_md); |
| POSTING_READ(DPLL_MD(pipe)); |
| |
| mutex_unlock(&dev_priv->dpio_lock); |
| } |
| |
| static int intel_num_dvo_pipes(struct drm_device *dev) |
| { |
| struct intel_crtc *crtc; |
| int count = 0; |
| |
| for_each_intel_crtc(dev, crtc) |
| count += crtc->active && |
| intel_pipe_has_type(&crtc->base, INTEL_OUTPUT_DVO); |
| |
| return count; |
| } |
| |
| static void i9xx_enable_pll(struct intel_crtc *crtc) |
| { |
| struct drm_device *dev = crtc->base.dev; |
| struct drm_i915_private *dev_priv = dev->dev_private; |
| int reg = DPLL(crtc->pipe); |
| u32 dpll = crtc->config.dpll_hw_state.dpll; |
| |
| assert_pipe_disabled(dev_priv, crtc->pipe); |
| |
| /* No really, not for ILK+ */ |
| BUG_ON(INTEL_INFO(dev)->gen >= 5); |
| |
| /* PLL is protected by panel, make sure we can write it */ |
| if (IS_MOBILE(dev) && !IS_I830(dev)) |
| assert_panel_unlocked(dev_priv, crtc->pipe); |
| |
| /* Enable DVO 2x clock on both PLLs if necessary */ |
| if (IS_I830(dev) && intel_num_dvo_pipes(dev) > 0) { |
| /* |
| * It appears to be important that we don't enable this |
| * for the current pipe before otherwise configuring the |
| * PLL. No idea how this should be handled if multiple |
| * DVO outputs are enabled simultaneosly. |
| */ |
| dpll |= DPLL_DVO_2X_MODE; |
| I915_WRITE(DPLL(!crtc->pipe), |
| I915_READ(DPLL(!crtc->pipe)) | DPLL_DVO_2X_MODE); |
| } |
| |
| /* Wait for the clocks to stabilize. */ |
| POSTING_READ(reg); |
| udelay(150); |
| |
| if (INTEL_INFO(dev)->gen >= 4) { |
| I915_WRITE(DPLL_MD(crtc->pipe), |
| crtc->config.dpll_hw_state.dpll_md); |
| } else { |
| /* The pixel multiplier can only be updated once the |
| * DPLL is enabled and the clocks are stable. |
| * |
| * So write it again. |
| */ |
| I915_WRITE(reg, dpll); |
| } |
| |
| /* We do this three times for luck */ |
| I915_WRITE(reg, dpll); |
| POSTING_READ(reg); |
| udelay(150); /* wait for warmup */ |
| I915_WRITE(reg, dpll); |
| POSTING_READ(reg); |
| udelay(150); /* wait for warmup */ |
| I915_WRITE(reg, dpll); |
| POSTING_READ(reg); |
| udelay(150); /* wait for warmup */ |
| } |
| |
| /** |
| * i9xx_disable_pll - disable a PLL |
| * @dev_priv: i915 private structure |
| * @pipe: pipe PLL to disable |
| * |
| * Disable the PLL for @pipe, making sure the pipe is off first. |
| * |
| * Note! This is for pre-ILK only. |
| */ |
| static void i9xx_disable_pll(struct intel_crtc *crtc) |
| { |
| struct drm_device *dev = crtc->base.dev; |
| struct drm_i915_private *dev_priv = dev->dev_private; |
| enum pipe pipe = crtc->pipe; |
| |
| /* Disable DVO 2x clock on both PLLs if necessary */ |
| if (IS_I830(dev) && |
| intel_pipe_has_type(&crtc->base, INTEL_OUTPUT_DVO) && |
| intel_num_dvo_pipes(dev) == 1) { |
| I915_WRITE(DPLL(PIPE_B), |
| I915_READ(DPLL(PIPE_B)) & ~DPLL_DVO_2X_MODE); |
| I915_WRITE(DPLL(PIPE_A), |
| I915_READ(DPLL(PIPE_A)) & ~DPLL_DVO_2X_MODE); |
| } |
| |
| /* Don't disable pipe or pipe PLLs if needed */ |
| if ((pipe == PIPE_A && dev_priv->quirks & QUIRK_PIPEA_FORCE) || |
| (pipe == PIPE_B && dev_priv->quirks & QUIRK_PIPEB_FORCE)) |
| return; |
| |
| /* Make sure the pipe isn't still relying on us */ |
| assert_pipe_disabled(dev_priv, pipe); |
| |
| I915_WRITE(DPLL(pipe), 0); |
| POSTING_READ(DPLL(pipe)); |
| } |
| |
| static void vlv_disable_pll(struct drm_i915_private *dev_priv, enum pipe pipe) |
| { |
| u32 val = 0; |
| |
| /* Make sure the pipe isn't still relying on us */ |
| assert_pipe_disabled(dev_priv, pipe); |
| |
| /* |
| * Leave integrated clock source and reference clock enabled for pipe B. |
| * The latter is needed for VGA hotplug / manual detection. |
| */ |
| if (pipe == PIPE_B) |
| val = DPLL_INTEGRATED_CRI_CLK_VLV | DPLL_REFA_CLK_ENABLE_VLV; |
| I915_WRITE(DPLL(pipe), val); |
| POSTING_READ(DPLL(pipe)); |
| |
| } |
| |
| static void chv_disable_pll(struct drm_i915_private *dev_priv, enum pipe pipe) |
| { |
| enum dpio_channel port = vlv_pipe_to_channel(pipe); |
| u32 val; |
| |
| /* Make sure the pipe isn't still relying on us */ |
| assert_pipe_disabled(dev_priv, pipe); |
| |
| /* Set PLL en = 0 */ |
| val = DPLL_SSC_REF_CLOCK_CHV | DPLL_REFA_CLK_ENABLE_VLV; |
| if (pipe != PIPE_A) |
| val |= DPLL_INTEGRATED_CRI_CLK_VLV; |
| I915_WRITE(DPLL(pipe), val); |
| POSTING_READ(DPLL(pipe)); |
| |
| mutex_lock(&dev_priv->dpio_lock); |
| |
| /* Disable 10bit clock to display controller */ |
| val = vlv_dpio_read(dev_priv, pipe, CHV_CMN_DW14(port)); |
| val &= ~DPIO_DCLKP_EN; |
| vlv_dpio_write(dev_priv, pipe, CHV_CMN_DW14(port), val); |
| |
| /* disable left/right clock distribution */ |
| if (pipe != PIPE_B) { |
| val = vlv_dpio_read(dev_priv, pipe, _CHV_CMN_DW5_CH0); |
| val &= ~(CHV_BUFLEFTENA1_MASK | CHV_BUFRIGHTENA1_MASK); |
| vlv_dpio_write(dev_priv, pipe, _CHV_CMN_DW5_CH0, val); |
| } else { |
| val = vlv_dpio_read(dev_priv, pipe, _CHV_CMN_DW1_CH1); |
| val &= ~(CHV_BUFLEFTENA2_MASK | CHV_BUFRIGHTENA2_MASK); |
| vlv_dpio_write(dev_priv, pipe, _CHV_CMN_DW1_CH1, val); |
| } |
| |
| mutex_unlock(&dev_priv->dpio_lock); |
| } |
| |
| void vlv_wait_port_ready(struct drm_i915_private *dev_priv, |
| struct intel_digital_port *dport) |
| { |
| u32 port_mask; |
| int dpll_reg; |
| |
| switch (dport->port) { |
| case PORT_B: |
| port_mask = DPLL_PORTB_READY_MASK; |
| dpll_reg = DPLL(0); |
| break; |
| case PORT_C: |
| port_mask = DPLL_PORTC_READY_MASK; |
| dpll_reg = DPLL(0); |
| break; |
| case PORT_D: |
| port_mask = DPLL_PORTD_READY_MASK; |
| dpll_reg = DPIO_PHY_STATUS; |
| break; |
| default: |
| BUG(); |
| } |
| |
| if (wait_for((I915_READ(dpll_reg) & port_mask) == 0, 1000)) |
| WARN(1, "timed out waiting for port %c ready: 0x%08x\n", |
| port_name(dport->port), I915_READ(dpll_reg)); |
| } |
| |
| static void intel_prepare_shared_dpll(struct intel_crtc *crtc) |
| { |
| struct drm_device *dev = crtc->base.dev; |
| struct drm_i915_private *dev_priv = dev->dev_private; |
| struct intel_shared_dpll *pll = intel_crtc_to_shared_dpll(crtc); |
| |
| if (WARN_ON(pll == NULL)) |
| return; |
| |
| WARN_ON(!pll->refcount); |
| if (pll->active == 0) { |
| DRM_DEBUG_DRIVER("setting up %s\n", pll->name); |
| WARN_ON(pll->on); |
| assert_shared_dpll_disabled(dev_priv, pll); |
| |
| pll->mode_set(dev_priv, pll); |
| } |
| } |
| |
| /** |
| * intel_enable_shared_dpll - enable PCH PLL |
| * @dev_priv: i915 private structure |
| * @pipe: pipe PLL to enable |
| * |
| * The PCH PLL needs to be enabled before the PCH transcoder, since it |
| * drives the transcoder clock. |
| */ |
| static void intel_enable_shared_dpll(struct intel_crtc *crtc) |
| { |
| struct drm_device *dev = crtc->base.dev; |
| struct drm_i915_private *dev_priv = dev->dev_private; |
| struct intel_shared_dpll *pll = intel_crtc_to_shared_dpll(crtc); |
| |
| if (WARN_ON(pll == NULL)) |
| return; |
| |
| if (WARN_ON(pll->refcount == 0)) |
| return; |
| |
| DRM_DEBUG_KMS("enable %s (active %d, on? %d) for crtc %d\n", |
| pll->name, pll->active, pll->on, |
| crtc->base.base.id); |
| |
| if (pll->active++) { |
| WARN_ON(!pll->on); |
| assert_shared_dpll_enabled(dev_priv, pll); |
| return; |
| } |
| WARN_ON(pll->on); |
| |
| intel_display_power_get(dev_priv, POWER_DOMAIN_PLLS); |
| |
| DRM_DEBUG_KMS("enabling %s\n", pll->name); |
| pll->enable(dev_priv, pll); |
| pll->on = true; |
| } |
| |
| static void intel_disable_shared_dpll(struct intel_crtc *crtc) |
| { |
| struct drm_device *dev = crtc->base.dev; |
| struct drm_i915_private *dev_priv = dev->dev_private; |
| struct intel_shared_dpll *pll = intel_crtc_to_shared_dpll(crtc); |
| |
| /* PCH only available on ILK+ */ |
| BUG_ON(INTEL_INFO(dev)->gen < 5); |
| if (WARN_ON(pll == NULL)) |
| return; |
| |
| if (WARN_ON(pll->refcount == 0)) |
| return; |
| |
| DRM_DEBUG_KMS("disable %s (active %d, on? %d) for crtc %d\n", |
| pll->name, pll->active, pll->on, |
| crtc->base.base.id); |
| |
| if (WARN_ON(pll->active == 0)) { |
| assert_shared_dpll_disabled(dev_priv, pll); |
| return; |
| } |
| |
| assert_shared_dpll_enabled(dev_priv, pll); |
| WARN_ON(!pll->on); |
| if (--pll->active) |
| return; |
| |
| DRM_DEBUG_KMS("disabling %s\n", pll->name); |
| pll->disable(dev_priv, pll); |
| pll->on = false; |
| |
| intel_display_power_put(dev_priv, POWER_DOMAIN_PLLS); |
| } |
| |
| static void ironlake_enable_pch_transcoder(struct drm_i915_private *dev_priv, |
| enum pipe pipe) |
| { |
| struct drm_device *dev = dev_priv->dev; |
| struct drm_crtc *crtc = dev_priv->pipe_to_crtc_mapping[pipe]; |
| struct intel_crtc *intel_crtc = to_intel_crtc(crtc); |
| uint32_t reg, val, pipeconf_val; |
| |
| /* PCH only available on ILK+ */ |
| BUG_ON(!HAS_PCH_SPLIT(dev)); |
| |
| /* Make sure PCH DPLL is enabled */ |
| assert_shared_dpll_enabled(dev_priv, |
| intel_crtc_to_shared_dpll(intel_crtc)); |
| |
| /* FDI must be feeding us bits for PCH ports */ |
| assert_fdi_tx_enabled(dev_priv, pipe); |
| assert_fdi_rx_enabled(dev_priv, pipe); |
| |
| if (HAS_PCH_CPT(dev)) { |
| /* Workaround: Set the timing override bit before enabling the |
| * pch transcoder. */ |
| reg = TRANS_CHICKEN2(pipe); |
| val = I915_READ(reg); |
| val |= TRANS_CHICKEN2_TIMING_OVERRIDE; |
| I915_WRITE(reg, val); |
| } |
| |
| reg = PCH_TRANSCONF(pipe); |
| val = I915_READ(reg); |
| pipeconf_val = I915_READ(PIPECONF(pipe)); |
| |
| if (HAS_PCH_IBX(dev_priv->dev)) { |
| /* |
| * make the BPC in transcoder be consistent with |
| * that in pipeconf reg. |
| */ |
| val &= ~PIPECONF_BPC_MASK; |
| val |= pipeconf_val & PIPECONF_BPC_MASK; |
| } |
| |
| val &= ~TRANS_INTERLACE_MASK; |
| if ((pipeconf_val & PIPECONF_INTERLACE_MASK) == PIPECONF_INTERLACED_ILK) |
| if (HAS_PCH_IBX(dev_priv->dev) && |
| intel_pipe_has_type(crtc, INTEL_OUTPUT_SDVO)) |
| val |= TRANS_LEGACY_INTERLACED_ILK; |
| else |
| val |= TRANS_INTERLACED; |
| else |
| val |= TRANS_PROGRESSIVE; |
| |
| I915_WRITE(reg, val | TRANS_ENABLE); |
| if (wait_for(I915_READ(reg) & TRANS_STATE_ENABLE, 100)) |
| DRM_ERROR("failed to enable transcoder %c\n", pipe_name(pipe)); |
| } |
| |
| static void lpt_enable_pch_transcoder(struct drm_i915_private *dev_priv, |
| enum transcoder cpu_transcoder) |
| { |
| u32 val, pipeconf_val; |
| |
| /* PCH only available on ILK+ */ |
| BUG_ON(!HAS_PCH_SPLIT(dev_priv->dev)); |
| |
| /* FDI must be feeding us bits for PCH ports */ |
| assert_fdi_tx_enabled(dev_priv, (enum pipe) cpu_transcoder); |
| assert_fdi_rx_enabled(dev_priv, TRANSCODER_A); |
| |
| /* Workaround: set timing override bit. */ |
| val = I915_READ(_TRANSA_CHICKEN2); |
| val |= TRANS_CHICKEN2_TIMING_OVERRIDE; |
| I915_WRITE(_TRANSA_CHICKEN2, val); |
| |
| val = TRANS_ENABLE; |
| pipeconf_val = I915_READ(PIPECONF(cpu_transcoder)); |
| |
| if ((pipeconf_val & PIPECONF_INTERLACE_MASK_HSW) == |
| PIPECONF_INTERLACED_ILK) |
| val |= TRANS_INTERLACED; |
| else |
| val |= TRANS_PROGRESSIVE; |
| |
| I915_WRITE(LPT_TRANSCONF, val); |
| if (wait_for(I915_READ(LPT_TRANSCONF) & TRANS_STATE_ENABLE, 100)) |
| DRM_ERROR("Failed to enable PCH transcoder\n"); |
| } |
| |
| static void ironlake_disable_pch_transcoder(struct drm_i915_private *dev_priv, |
| enum pipe pipe) |
| { |
| struct drm_device *dev = dev_priv->dev; |
| uint32_t reg, val; |
| |
| /* FDI relies on the transcoder */ |
| assert_fdi_tx_disabled(dev_priv, pipe); |
| assert_fdi_rx_disabled(dev_priv, pipe); |
| |
| /* Ports must be off as well */ |
| assert_pch_ports_disabled(dev_priv, pipe); |
| |
| reg = PCH_TRANSCONF(pipe); |
| val = I915_READ(reg); |
| val &= ~TRANS_ENABLE; |
| I915_WRITE(reg, val); |
| /* wait for PCH transcoder off, transcoder state */ |
| if (wait_for((I915_READ(reg) & TRANS_STATE_ENABLE) == 0, 50)) |
| DRM_ERROR("failed to disable transcoder %c\n", pipe_name(pipe)); |
| |
| if (!HAS_PCH_IBX(dev)) { |
| /* Workaround: Clear the timing override chicken bit again. */ |
| reg = TRANS_CHICKEN2(pipe); |
| val = I915_READ(reg); |
| val &= ~TRANS_CHICKEN2_TIMING_OVERRIDE; |
| I915_WRITE(reg, val); |
| } |
| } |
| |
| static void lpt_disable_pch_transcoder(struct drm_i915_private *dev_priv) |
| { |
| u32 val; |
| |
| val = I915_READ(LPT_TRANSCONF); |
| val &= ~TRANS_ENABLE; |
| I915_WRITE(LPT_TRANSCONF, val); |
| /* wait for PCH transcoder off, transcoder state */ |
| if (wait_for((I915_READ(LPT_TRANSCONF) & TRANS_STATE_ENABLE) == 0, 50)) |
| DRM_ERROR("Failed to disable PCH transcoder\n"); |
| |
| /* Workaround: clear timing override bit. */ |
| val = I915_READ(_TRANSA_CHICKEN2); |
| val &= ~TRANS_CHICKEN2_TIMING_OVERRIDE; |
| I915_WRITE(_TRANSA_CHICKEN2, val); |
| } |
| |
| /** |
| * intel_enable_pipe - enable a pipe, asserting requirements |
| * @crtc: crtc responsible for the pipe |
| * |
| * Enable @crtc's pipe, making sure that various hardware specific requirements |
| * are met, if applicable, e.g. PLL enabled, LVDS pairs enabled, etc. |
| */ |
| static void intel_enable_pipe(struct intel_crtc *crtc) |
| { |
| struct drm_device *dev = crtc->base.dev; |
| struct drm_i915_private *dev_priv = dev->dev_private; |
| enum pipe pipe = crtc->pipe; |
| enum transcoder cpu_transcoder = intel_pipe_to_cpu_transcoder(dev_priv, |
| pipe); |
| enum pipe pch_transcoder; |
| int reg; |
| u32 val; |
| |
| assert_planes_disabled(dev_priv, pipe); |
| assert_cursor_disabled(dev_priv, pipe); |
| assert_sprites_disabled(dev_priv, pipe); |
| |
| if (HAS_PCH_LPT(dev_priv->dev)) |
| pch_transcoder = TRANSCODER_A; |
| else |
| pch_transcoder = pipe; |
| |
| /* |
| * A pipe without a PLL won't actually be able to drive bits from |
| * a plane. On ILK+ the pipe PLLs are integrated, so we don't |
| * need the check. |
| */ |
| if (!HAS_PCH_SPLIT(dev_priv->dev)) |
| if (intel_pipe_has_type(&crtc->base, INTEL_OUTPUT_DSI)) |
| assert_dsi_pll_enabled(dev_priv); |
| else |
| assert_pll_enabled(dev_priv, pipe); |
| else { |
| if (crtc->config.has_pch_encoder) { |
| /* if driving the PCH, we need FDI enabled */ |
| assert_fdi_rx_pll_enabled(dev_priv, pch_transcoder); |
| assert_fdi_tx_pll_enabled(dev_priv, |
| (enum pipe) cpu_transcoder); |
| } |
| /* FIXME: assert CPU port conditions for SNB+ */ |
| } |
| |
| reg = PIPECONF(cpu_transcoder); |
| val = I915_READ(reg); |
| if (val & PIPECONF_ENABLE) { |
| WARN_ON(!((pipe == PIPE_A && dev_priv->quirks & QUIRK_PIPEA_FORCE) || |
| (pipe == PIPE_B && dev_priv->quirks & QUIRK_PIPEB_FORCE))); |
| return; |
| } |
| |
| I915_WRITE(reg, val | PIPECONF_ENABLE); |
| POSTING_READ(reg); |
| } |
| |
| /** |
| * intel_disable_pipe - disable a pipe, asserting requirements |
| * @crtc: crtc whose pipes is to be disabled |
| * |
| * Disable the pipe of @crtc, making sure that various hardware |
| * specific requirements are met, if applicable, e.g. plane |
| * disabled, panel fitter off, etc. |
| * |
| * Will wait until the pipe has shut down before returning. |
| */ |
| static void intel_disable_pipe(struct intel_crtc *crtc) |
| { |
| struct drm_i915_private *dev_priv = crtc->base.dev->dev_private; |
| enum transcoder cpu_transcoder = crtc->config.cpu_transcoder; |
| enum pipe pipe = crtc->pipe; |
| int reg; |
| u32 val; |
| |
| /* |
| * Make sure planes won't keep trying to pump pixels to us, |
| * or we might hang the display. |
| */ |
| assert_planes_disabled(dev_priv, pipe); |
| assert_cursor_disabled(dev_priv, pipe); |
| assert_sprites_disabled(dev_priv, pipe); |
| |
| reg = PIPECONF(cpu_transcoder); |
| val = I915_READ(reg); |
| if ((val & PIPECONF_ENABLE) == 0) |
| return; |
| |
| /* |
| * Double wide has implications for planes |
| * so best keep it disabled when not needed. |
| */ |
| if (crtc->config.double_wide) |
| val &= ~PIPECONF_DOUBLE_WIDE; |
| |
| /* Don't disable pipe or pipe PLLs if needed */ |
| if (!(pipe == PIPE_A && dev_priv->quirks & QUIRK_PIPEA_FORCE) && |
| !(pipe == PIPE_B && dev_priv->quirks & QUIRK_PIPEB_FORCE)) |
| val &= ~PIPECONF_ENABLE; |
| |
| I915_WRITE(reg, val); |
| if ((val & PIPECONF_ENABLE) == 0) |
| intel_wait_for_pipe_off(crtc); |
| } |
| |
| /* |
| * Plane regs are double buffered, going from enabled->disabled needs a |
| * trigger in order to latch. The display address reg provides this. |
| */ |
| void intel_flush_primary_plane(struct drm_i915_private *dev_priv, |
| enum plane plane) |
| { |
| struct drm_device *dev = dev_priv->dev; |
| u32 reg = INTEL_INFO(dev)->gen >= 4 ? DSPSURF(plane) : DSPADDR(plane); |
| |
| I915_WRITE(reg, I915_READ(reg)); |
| POSTING_READ(reg); |
| } |
| |
| /** |
| * intel_enable_primary_hw_plane - enable the primary plane on a given pipe |
| * @plane: plane to be enabled |
| * @crtc: crtc for the plane |
| * |
| * Enable @plane on @crtc, making sure that the pipe is running first. |
| */ |
| static void intel_enable_primary_hw_plane(struct drm_plane *plane, |
| struct drm_crtc *crtc) |
| { |
| struct drm_device *dev = plane->dev; |
| struct drm_i915_private *dev_priv = dev->dev_private; |
| struct intel_crtc *intel_crtc = to_intel_crtc(crtc); |
| |
| /* If the pipe isn't enabled, we can't pump pixels and may hang */ |
| assert_pipe_enabled(dev_priv, intel_crtc->pipe); |
| |
| if (intel_crtc->primary_enabled) |
| return; |
| |
| intel_crtc->primary_enabled = true; |
| |
| dev_priv->display.update_primary_plane(crtc, plane->fb, |
| crtc->x, crtc->y); |
| |
| /* |
| * BDW signals flip done immediately if the plane |
| * is disabled, even if the plane enable is already |
| * armed to occur at the next vblank :( |
| */ |
| if (IS_BROADWELL(dev)) |
| intel_wait_for_vblank(dev, intel_crtc->pipe); |
| } |
| |
| /** |
| * intel_disable_primary_hw_plane - disable the primary hardware plane |
| * @plane: plane to be disabled |
| * @crtc: crtc for the plane |
| * |
| * Disable @plane on @crtc, making sure that the pipe is running first. |
| */ |
| static void intel_disable_primary_hw_plane(struct drm_plane *plane, |
| struct drm_crtc *crtc) |
| { |
| struct drm_device *dev = plane->dev; |
| struct drm_i915_private *dev_priv = dev->dev_private; |
| struct intel_crtc *intel_crtc = to_intel_crtc(crtc); |
| |
| assert_pipe_enabled(dev_priv, intel_crtc->pipe); |
| |
| if (!intel_crtc->primary_enabled) |
| return; |
| |
| intel_crtc->primary_enabled = false; |
| |
| dev_priv->display.update_primary_plane(crtc, plane->fb, |
| crtc->x, crtc->y); |
| } |
| |
| static bool need_vtd_wa(struct drm_device *dev) |
| { |
| #ifdef CONFIG_INTEL_IOMMU |
| if (INTEL_INFO(dev)->gen >= 6 && intel_iommu_gfx_mapped) |
| return true; |
| #endif |
| return false; |
| } |
| |
| static int intel_align_height(struct drm_device *dev, int height, bool tiled) |
| { |
| int tile_height; |
| |
| tile_height = tiled ? (IS_GEN2(dev) ? 16 : 8) : 1; |
| return ALIGN(height, tile_height); |
| } |
| |
| int |
| intel_pin_and_fence_fb_obj(struct drm_device *dev, |
| struct drm_i915_gem_object *obj, |
| struct intel_engine_cs *pipelined) |
| { |
| struct drm_i915_private *dev_priv = dev->dev_private; |
| u32 alignment; |
| int ret; |
| |
| WARN_ON(!mutex_is_locked(&dev->struct_mutex)); |
| |
| switch (obj->tiling_mode) { |
| case I915_TILING_NONE: |
| if (IS_BROADWATER(dev) || IS_CRESTLINE(dev)) |
| alignment = 128 * 1024; |
| else if (INTEL_INFO(dev)->gen >= 4) |
| alignment = 4 * 1024; |
| else |
| alignment = 64 * 1024; |
| break; |
| case I915_TILING_X: |
| /* pin() will align the object as required by fence */ |
| alignment = 0; |
| break; |
| case I915_TILING_Y: |
| WARN(1, "Y tiled bo slipped through, driver bug!\n"); |
| return -EINVAL; |
| default: |
| BUG(); |
| } |
| |
| /* Note that the w/a also requires 64 PTE of padding following the |
| * bo. We currently fill all unused PTE with the shadow page and so |
| * we should always have valid PTE following the scanout preventing |
| * the VT-d warning. |
| */ |
| if (need_vtd_wa(dev) && alignment < 256 * 1024) |
| alignment = 256 * 1024; |
| |
| /* |
| * Global gtt pte registers are special registers which actually forward |
| * writes to a chunk of system memory. Which means that there is no risk |
| * that the register values disappear as soon as we call |
| * intel_runtime_pm_put(), so it is correct to wrap only the |
| * pin/unpin/fence and not more. |
| */ |
| intel_runtime_pm_get(dev_priv); |
| |
| dev_priv->mm.interruptible = false; |
| ret = i915_gem_object_pin_to_display_plane(obj, alignment, pipelined); |
| if (ret) |
| goto err_interruptible; |
| |
| /* Install a fence for tiled scan-out. Pre-i965 always needs a |
| * fence, whereas 965+ only requires a fence if using |
| * framebuffer compression. For simplicity, we always install |
| * a fence as the cost is not that onerous. |
| */ |
| ret = i915_gem_object_get_fence(obj); |
| if (ret) |
| goto err_unpin; |
| |
| i915_gem_object_pin_fence(obj); |
| |
| dev_priv->mm.interruptible = true; |
| intel_runtime_pm_put(dev_priv); |
| return 0; |
| |
| err_unpin: |
| i915_gem_object_unpin_from_display_plane(obj); |
| err_interruptible: |
| dev_priv->mm.interruptible = true; |
| intel_runtime_pm_put(dev_priv); |
| return ret; |
| } |
| |
| void intel_unpin_fb_obj(struct drm_i915_gem_object *obj) |
| { |
| WARN_ON(!mutex_is_locked(&obj->base.dev->struct_mutex)); |
| |
| i915_gem_object_unpin_fence(obj); |
| i915_gem_object_unpin_from_display_plane(obj); |
| } |
| |
| /* Computes the linear offset to the base tile and adjusts x, y. bytes per pixel |
| * is assumed to be a power-of-two. */ |
| unsigned long intel_gen4_compute_page_offset(int *x, int *y, |
| unsigned int tiling_mode, |
| unsigned int cpp, |
| unsigned int pitch) |
| { |
| if (tiling_mode != I915_TILING_NONE) { |
| unsigned int tile_rows, tiles; |
| |
| tile_rows = *y / 8; |
| *y %= 8; |
| |
| tiles = *x / (512/cpp); |
| *x %= 512/cpp; |
| |
| return tile_rows * pitch * 8 + tiles * 4096; |
| } else { |
| unsigned int offset; |
| |
| offset = *y * pitch + *x * cpp; |
| *y = 0; |
| *x = (offset & 4095) / cpp; |
| return offset & -4096; |
| } |
| } |
| |
| int intel_format_to_fourcc(int format) |
| { |
| switch (format) { |
| case DISPPLANE_8BPP: |
| return DRM_FORMAT_C8; |
| case DISPPLANE_BGRX555: |
| return DRM_FORMAT_XRGB1555; |
| case DISPPLANE_BGRX565: |
| return DRM_FORMAT_RGB565; |
| default: |
| case DISPPLANE_BGRX888: |
| return DRM_FORMAT_XRGB8888; |
| case DISPPLANE_RGBX888: |
| return DRM_FORMAT_XBGR8888; |
| case DISPPLANE_BGRX101010: |
| return DRM_FORMAT_XRGB2101010; |
| case DISPPLANE_RGBX101010: |
| return DRM_FORMAT_XBGR2101010; |
| } |
| } |
| |
| static bool intel_alloc_plane_obj(struct intel_crtc *crtc, |
| struct intel_plane_config *plane_config) |
| { |
| struct drm_device *dev = crtc->base.dev; |
| struct drm_i915_gem_object *obj = NULL; |
| struct drm_mode_fb_cmd2 mode_cmd = { 0 }; |
| u32 base = plane_config->base; |
| |
| if (plane_config->size == 0) |
| return false; |
| |
| obj = i915_gem_object_create_stolen_for_preallocated(dev, base, base, |
| plane_config->size); |
| if (!obj) |
| return false; |
| |
| if (plane_config->tiled) { |
| obj->tiling_mode = I915_TILING_X; |
| obj->stride = crtc->base.primary->fb->pitches[0]; |
| } |
| |
| mode_cmd.pixel_format = crtc->base.primary->fb->pixel_format; |
| mode_cmd.width = crtc->base.primary->fb->width; |
| mode_cmd.height = crtc->base.primary->fb->height; |
| mode_cmd.pitches[0] = crtc->base.primary->fb->pitches[0]; |
| |
| mutex_lock(&dev->struct_mutex); |
| |
| if (intel_framebuffer_init(dev, to_intel_framebuffer(crtc->base.primary->fb), |
| &mode_cmd, obj)) { |
| DRM_DEBUG_KMS("intel fb init failed\n"); |
| goto out_unref_obj; |
| } |
| |
| obj->frontbuffer_bits = INTEL_FRONTBUFFER_PRIMARY(crtc->pipe); |
| mutex_unlock(&dev->struct_mutex); |
| |
| DRM_DEBUG_KMS("plane fb obj %p\n", obj); |
| return true; |
| |
| out_unref_obj: |
| drm_gem_object_unreference(&obj->base); |
| mutex_unlock(&dev->struct_mutex); |
| return false; |
| } |
| |
| static void intel_find_plane_obj(struct intel_crtc *intel_crtc, |
| struct intel_plane_config *plane_config) |
| { |
| struct drm_device *dev = intel_crtc->base.dev; |
| struct drm_crtc *c; |
| struct intel_crtc *i; |
| struct drm_i915_gem_object *obj; |
| |
| if (!intel_crtc->base.primary->fb) |
| return; |
| |
| if (intel_alloc_plane_obj(intel_crtc, plane_config)) |
| return; |
| |
| kfree(intel_crtc->base.primary->fb); |
| intel_crtc->base.primary->fb = NULL; |
| |
| /* |
| * Failed to alloc the obj, check to see if we should share |
| * an fb with another CRTC instead |
| */ |
| for_each_crtc(dev, c) { |
| i = to_intel_crtc(c); |
| |
| if (c == &intel_crtc->base) |
| continue; |
| |
| if (!i->active) |
| continue; |
| |
| obj = intel_fb_obj(c->primary->fb); |
| if (obj == NULL) |
| continue; |
| |
| if (i915_gem_obj_ggtt_offset(obj) == plane_config->base) { |
| drm_framebuffer_reference(c->primary->fb); |
| intel_crtc->base.primary->fb = c->primary->fb; |
| obj->frontbuffer_bits |= INTEL_FRONTBUFFER_PRIMARY(intel_crtc->pipe); |
| break; |
| } |
| } |
| } |
| |
| static void i9xx_update_primary_plane(struct drm_crtc *crtc, |
| struct drm_framebuffer *fb, |
| int x, int y) |
| { |
| struct drm_device *dev = crtc->dev; |
| struct drm_i915_private *dev_priv = dev->dev_private; |
| struct intel_crtc *intel_crtc = to_intel_crtc(crtc); |
| struct drm_i915_gem_object *obj; |
| int plane = intel_crtc->plane; |
| unsigned long linear_offset; |
| u32 dspcntr; |
| u32 reg = DSPCNTR(plane); |
| int pixel_size; |
| |
| if (!intel_crtc->primary_enabled) { |
| I915_WRITE(reg, 0); |
| if (INTEL_INFO(dev)->gen >= 4) |
| I915_WRITE(DSPSURF(plane), 0); |
| else |
| I915_WRITE(DSPADDR(plane), 0); |
| POSTING_READ(reg); |
| return; |
| } |
| |
| obj = intel_fb_obj(fb); |
| if (WARN_ON(obj == NULL)) |
| return; |
| |
| pixel_size = drm_format_plane_cpp(fb->pixel_format, 0); |
| |
| dspcntr = DISPPLANE_GAMMA_ENABLE; |
| |
| dspcntr |= DISPLAY_PLANE_ENABLE; |
| |
| if (INTEL_INFO(dev)->gen < 4) { |
| if (intel_crtc->pipe == PIPE_B) |
| dspcntr |= DISPPLANE_SEL_PIPE_B; |
| |
| /* pipesrc and dspsize control the size that is scaled from, |
| * which should always be the user's requested size. |
| */ |
| I915_WRITE(DSPSIZE(plane), |
| ((intel_crtc->config.pipe_src_h - 1) << 16) | |
| (intel_crtc->config.pipe_src_w - 1)); |
| I915_WRITE(DSPPOS(plane), 0); |
| } |
| |
| switch (fb->pixel_format) { |
| case DRM_FORMAT_C8: |
| dspcntr |= DISPPLANE_8BPP; |
| break; |
| case DRM_FORMAT_XRGB1555: |
| case DRM_FORMAT_ARGB1555: |
| dspcntr |= DISPPLANE_BGRX555; |
| break; |
| case DRM_FORMAT_RGB565: |
| dspcntr |= DISPPLANE_BGRX565; |
| break; |
| case DRM_FORMAT_XRGB8888: |
| case DRM_FORMAT_ARGB8888: |
| dspcntr |= DISPPLANE_BGRX888; |
| break; |
| case DRM_FORMAT_XBGR8888: |
| case DRM_FORMAT_ABGR8888: |
| dspcntr |= DISPPLANE_RGBX888; |
| break; |
| case DRM_FORMAT_XRGB2101010: |
| case DRM_FORMAT_ARGB2101010: |
| dspcntr |= DISPPLANE_BGRX101010; |
| break; |
| case DRM_FORMAT_XBGR2101010: |
| case DRM_FORMAT_ABGR2101010: |
| dspcntr |= DISPPLANE_RGBX101010; |
| break; |
| default: |
| BUG(); |
| } |
| |
| if (INTEL_INFO(dev)->gen >= 4 && |
| obj->tiling_mode != I915_TILING_NONE) |
| dspcntr |= DISPPLANE_TILED; |
| |
| if (IS_G4X(dev)) |
| dspcntr |= DISPPLANE_TRICKLE_FEED_DISABLE; |
| |
| linear_offset = y * fb->pitches[0] + x * pixel_size; |
| |
| if (INTEL_INFO(dev)->gen >= 4) { |
| intel_crtc->dspaddr_offset = |
| intel_gen4_compute_page_offset(&x, &y, obj->tiling_mode, |
| pixel_size, |
| fb->pitches[0]); |
| linear_offset -= intel_crtc->dspaddr_offset; |
| } else { |
| intel_crtc->dspaddr_offset = linear_offset; |
| } |
| |
| if (to_intel_plane(crtc->primary)->rotation == BIT(DRM_ROTATE_180)) { |
| dspcntr |= DISPPLANE_ROTATE_180; |
| |
| x += (intel_crtc->config.pipe_src_w - 1); |
| y += (intel_crtc->config.pipe_src_h - 1); |
| |
| /* Finding the last pixel of the last line of the display |
| data and adding to linear_offset*/ |
| linear_offset += |
| (intel_crtc->config.pipe_src_h - 1) * fb->pitches[0] + |
| (intel_crtc->config.pipe_src_w - 1) * pixel_size; |
| } |
| |
| I915_WRITE(reg, dspcntr); |
| |
| DRM_DEBUG_KMS("Writing base %08lX %08lX %d %d %d\n", |
| i915_gem_obj_ggtt_offset(obj), linear_offset, x, y, |
| fb->pitches[0]); |
| I915_WRITE(DSPSTRIDE(plane), fb->pitches[0]); |
| if (INTEL_INFO(dev)->gen >= 4) { |
| I915_WRITE(DSPSURF(plane), |
| i915_gem_obj_ggtt_offset(obj) + intel_crtc->dspaddr_offset); |
| I915_WRITE(DSPTILEOFF(plane), (y << 16) | x); |
| I915_WRITE(DSPLINOFF(plane), linear_offset); |
| } else |
| I915_WRITE(DSPADDR(plane), i915_gem_obj_ggtt_offset(obj) + linear_offset); |
| POSTING_READ(reg); |
| } |
| |
| static void ironlake_update_primary_plane(struct drm_crtc *crtc, |
| struct drm_framebuffer *fb, |
| int x, int y) |
| { |
| struct drm_device *dev = crtc->dev; |
| struct drm_i915_private *dev_priv = dev->dev_private; |
| struct intel_crtc *intel_crtc = to_intel_crtc(crtc); |
| struct drm_i915_gem_object *obj; |
| int plane = intel_crtc->plane; |
| unsigned long linear_offset; |
| u32 dspcntr; |
| u32 reg = DSPCNTR(plane); |
| int pixel_size; |
| |
| if (!intel_crtc->primary_enabled) { |
| I915_WRITE(reg, 0); |
| I915_WRITE(DSPSURF(plane), 0); |
| POSTING_READ(reg); |
| return; |
| } |
| |
| obj = intel_fb_obj(fb); |
| if (WARN_ON(obj == NULL)) |
| return; |
| |
| pixel_size = drm_format_plane_cpp(fb->pixel_format, 0); |
| |
| dspcntr = DISPPLANE_GAMMA_ENABLE; |
| |
| dspcntr |= DISPLAY_PLANE_ENABLE; |
| |
| if (IS_HASWELL(dev) || IS_BROADWELL(dev)) |
| dspcntr |= DISPPLANE_PIPE_CSC_ENABLE; |
| |
| switch (fb->pixel_format) { |
| case DRM_FORMAT_C8: |
| dspcntr |= DISPPLANE_8BPP; |
| break; |
| case DRM_FORMAT_RGB565: |
| dspcntr |= DISPPLANE_BGRX565; |
| break; |
| case DRM_FORMAT_XRGB8888: |
| case DRM_FORMAT_ARGB8888: |
| dspcntr |= DISPPLANE_BGRX888; |
| break; |
| case DRM_FORMAT_XBGR8888: |
| case DRM_FORMAT_ABGR8888: |
| dspcntr |= DISPPLANE_RGBX888; |
| break; |
| case DRM_FORMAT_XRGB2101010: |
| case DRM_FORMAT_ARGB2101010: |
| dspcntr |= DISPPLANE_BGRX101010; |
| break; |
| case DRM_FORMAT_XBGR2101010: |
| case DRM_FORMAT_ABGR2101010: |
| dspcntr |= DISPPLANE_RGBX101010; |
| break; |
| default: |
| BUG(); |
| } |
| |
| if (obj->tiling_mode != I915_TILING_NONE) |
| dspcntr |= DISPPLANE_TILED; |
| |
| if (!IS_HASWELL(dev) && !IS_BROADWELL(dev)) |
| dspcntr |= DISPPLANE_TRICKLE_FEED_DISABLE; |
| |
| linear_offset = y * fb->pitches[0] + x * pixel_size; |
| intel_crtc->dspaddr_offset = |
| intel_gen4_compute_page_offset(&x, &y, obj->tiling_mode, |
| pixel_size, |
| fb->pitches[0]); |
| linear_offset -= intel_crtc->dspaddr_offset; |
| if (to_intel_plane(crtc->primary)->rotation == BIT(DRM_ROTATE_180)) { |
| dspcntr |= DISPPLANE_ROTATE_180; |
| |
| if (!IS_HASWELL(dev) && !IS_BROADWELL(dev)) { |
| x += (intel_crtc->config.pipe_src_w - 1); |
| y += (intel_crtc->config.pipe_src_h - 1); |
| |
| /* Finding the last pixel of the last line of the display |
| data and adding to linear_offset*/ |
| linear_offset += |
| (intel_crtc->config.pipe_src_h - 1) * fb->pitches[0] + |
| (intel_crtc->config.pipe_src_w - 1) * pixel_size; |
| } |
| } |
| |
| I915_WRITE(reg, dspcntr); |
| |
| DRM_DEBUG_KMS("Writing base %08lX %08lX %d %d %d\n", |
| i915_gem_obj_ggtt_offset(obj), linear_offset, x, y, |
| fb->pitches[0]); |
| I915_WRITE(DSPSTRIDE(plane), fb->pitches[0]); |
| I915_WRITE(DSPSURF(plane), |
| i915_gem_obj_ggtt_offset(obj) + intel_crtc->dspaddr_offset); |
| if (IS_HASWELL(dev) || IS_BROADWELL(dev)) { |
| I915_WRITE(DSPOFFSET(plane), (y << 16) | x); |
| } else { |
| I915_WRITE(DSPTILEOFF(plane), (y << 16) | x); |
| I915_WRITE(DSPLINOFF(plane), linear_offset); |
| } |
| POSTING_READ(reg); |
| } |
| |
| /* Assume fb object is pinned & idle & fenced and just update base pointers */ |
| static int |
| intel_pipe_set_base_atomic(struct drm_crtc *crtc, struct drm_framebuffer *fb, |
| int x, int y, enum mode_set_atomic state) |
| { |
| struct drm_device *dev = crtc->dev; |
| struct drm_i915_private *dev_priv = dev->dev_private; |
| |
| if (dev_priv->display.disable_fbc) |
| dev_priv->display.disable_fbc(dev); |
| intel_increase_pllclock(dev, to_intel_crtc(crtc)->pipe); |
| |
| dev_priv->display.update_primary_plane(crtc, fb, x, y); |
| |
| return 0; |
| } |
| |
| void intel_display_handle_reset(struct drm_device *dev) |
| { |
| struct drm_i915_private *dev_priv = dev->dev_private; |
| struct drm_crtc *crtc; |
| |
| /* |
| * Flips in the rings have been nuked by the reset, |
| * so complete all pending flips so that user space |
| * will get its events and not get stuck. |
| * |
| * Also update the base address of all primary |
| * planes to the the last fb to make sure we're |
| * showing the correct fb after a reset. |
| * |
| * Need to make two loops over the crtcs so that we |
| * don't try to grab a crtc mutex before the |
| * pending_flip_queue really got woken up. |
| */ |
| |
| for_each_crtc(dev, crtc) { |
| struct intel_crtc *intel_crtc = to_intel_crtc(crtc); |
| enum plane plane = intel_crtc->plane; |
| |
| intel_prepare_page_flip(dev, plane); |
| intel_finish_page_flip_plane(dev, plane); |
| } |
| |
| for_each_crtc(dev, crtc) { |
| struct intel_crtc *intel_crtc = to_intel_crtc(crtc); |
| |
| drm_modeset_lock(&crtc->mutex, NULL); |
| /* |
| * FIXME: Once we have proper support for primary planes (and |
| * disabling them without disabling the entire crtc) allow again |
| * a NULL crtc->primary->fb. |
| */ |
| if (intel_crtc->active && crtc->primary->fb) |
| dev_priv->display.update_primary_plane(crtc, |
| crtc->primary->fb, |
| crtc->x, |
| crtc->y); |
| drm_modeset_unlock(&crtc->mutex); |
| } |
| } |
| |
| static int |
| intel_finish_fb(struct drm_framebuffer *old_fb) |
| { |
| struct drm_i915_gem_object *obj = intel_fb_obj(old_fb); |
| struct drm_i915_private *dev_priv = obj->base.dev->dev_private; |
| bool was_interruptible = dev_priv->mm.interruptible; |
| int ret; |
| |
| /* Big Hammer, we also need to ensure that any pending |
| * MI_WAIT_FOR_EVENT inside a user batch buffer on the |
| * current scanout is retired before unpinning the old |
| * framebuffer. |
| * |
| * This should only fail upon a hung GPU, in which case we |
| * can safely continue. |
| */ |
| dev_priv->mm.interruptible = false; |
| ret = i915_gem_object_finish_gpu(obj); |
| dev_priv->mm.interruptible = was_interruptible; |
| |
| return ret; |
| } |
| |
| static bool intel_crtc_has_pending_flip(struct drm_crtc *crtc) |
| { |
| struct drm_device *dev = crtc->dev; |
| struct drm_i915_private *dev_priv = dev->dev_private; |
| struct intel_crtc *intel_crtc = to_intel_crtc(crtc); |
| unsigned long flags; |
| bool pending; |
| |
| if (i915_reset_in_progress(&dev_priv->gpu_error) || |
| intel_crtc->reset_counter != atomic_read(&dev_priv->gpu_error.reset_counter)) |
| return false; |
| |
| spin_lock_irqsave(&dev->event_lock, flags); |
| pending = to_intel_crtc(crtc)->unpin_work != NULL; |
| spin_unlock_irqrestore(&dev->event_lock, flags); |
| |
| return pending; |
| } |
| |
| static int |
| intel_pipe_set_base(struct drm_crtc *crtc, int x, int y, |
| struct drm_framebuffer *fb) |
| { |
| struct drm_device *dev = crtc->dev; |
| struct drm_i915_private *dev_priv = dev->dev_private; |
| struct intel_crtc *intel_crtc = to_intel_crtc(crtc); |
| enum pipe pipe = intel_crtc->pipe; |
| struct drm_framebuffer *old_fb = crtc->primary->fb; |
| struct drm_i915_gem_object *obj = intel_fb_obj(fb); |
| struct drm_i915_gem_object *old_obj = intel_fb_obj(old_fb); |
| int ret; |
| |
| if (intel_crtc_has_pending_flip(crtc)) { |
| DRM_ERROR("pipe is still busy with an old pageflip\n"); |
| return -EBUSY; |
| } |
| |
| /* no fb bound */ |
| if (!fb) { |
| DRM_ERROR("No FB bound\n"); |
| return 0; |
| } |
| |
| if (intel_crtc->plane > INTEL_INFO(dev)->num_pipes) { |
| DRM_ERROR("no plane for crtc: plane %c, num_pipes %d\n", |
| plane_name(intel_crtc->plane), |
| INTEL_INFO(dev)->num_pipes); |
| return -EINVAL; |
| } |
| |
| mutex_lock(&dev->struct_mutex); |
| ret = intel_pin_and_fence_fb_obj(dev, obj, NULL); |
| if (ret == 0) |
| i915_gem_track_fb(old_obj, obj, |
| INTEL_FRONTBUFFER_PRIMARY(pipe)); |
| mutex_unlock(&dev->struct_mutex); |
| if (ret != 0) { |
| DRM_ERROR("pin & fence failed\n"); |
| return ret; |
| } |
| |
| /* |
| * Update pipe size and adjust fitter if needed: the reason for this is |
| * that in compute_mode_changes we check the native mode (not the pfit |
| * mode) to see if we can flip rather than do a full mode set. In the |
| * fastboot case, we'll flip, but if we don't update the pipesrc and |
| * pfit state, we'll end up with a big fb scanned out into the wrong |
| * sized surface. |
| * |
| * To fix this properly, we need to hoist the checks up into |
| * compute_mode_changes (or above), check the actual pfit state and |
| * whether the platform allows pfit disable with pipe active, and only |
| * then update the pipesrc and pfit state, even on the flip path. |
| */ |
| if (i915.fastboot) { |
| const struct drm_display_mode *adjusted_mode = |
| &intel_crtc->config.adjusted_mode; |
| |
| I915_WRITE(PIPESRC(intel_crtc->pipe), |
| ((adjusted_mode->crtc_hdisplay - 1) << 16) | |
| (adjusted_mode->crtc_vdisplay - 1)); |
| if (!intel_crtc->config.pch_pfit.enabled && |
| (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS) || |
| intel_pipe_has_type(crtc, INTEL_OUTPUT_EDP))) { |
| I915_WRITE(PF_CTL(intel_crtc->pipe), 0); |
| I915_WRITE(PF_WIN_POS(intel_crtc->pipe), 0); |
| I915_WRITE(PF_WIN_SZ(intel_crtc->pipe), 0); |
| } |
| intel_crtc->config.pipe_src_w = adjusted_mode->crtc_hdisplay; |
| intel_crtc->config.pipe_src_h = adjusted_mode->crtc_vdisplay; |
|