aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/i915/intel_display.c
diff options
context:
space:
mode:
authorMatt Roper <matthew.d.roper@intel.com>2014-05-29 11:06:54 -0400
committerDaniel Vetter <daniel.vetter@ffwll.ch>2014-06-11 10:57:37 -0400
commit465c120c4c252e127b57cd133c4611b075e0a237 (patch)
tree64ce35ceb987b81f22b3a36bc67b415ff6ff22f2 /drivers/gpu/drm/i915/intel_display.c
parent3b150f08e5013297729627a222e410284832effe (diff)
drm/i915: Intel-specific primary plane handling (v8)
Intel hardware allows the primary plane to be disabled independently of the CRTC. Provide custom primary plane handling to allow this. v8: - Pin/unpin properly when clipping causes the primary plane to be disabled when it has previously been enabled. - s/drm_primary_helper_check_update/drm_plane_helper_check_update/ v7: - Clip primary plane to invisible when crtc is disabled since intel_crtc->config.pipe_src_{w,h} may be garbage otherwise. - Unpin old fb before pinning new one in the "just pin and return" case that is used when the crtc is disabled. - Don't treat implicit disabling of the primary plane (caused by clipping) the same way as explicit disabling (caused by fb=0). For implicit disables, we should leave the fb set and pinned, whereas for explicit disables we need to unpin the fb before primary->fb is cleared. v6: - Pass rectangles to primary helper check function and get plane visibility back. - Wait for pending pageflips on primary plane update/disable. - Allow primary plane to be updated while the crtc is disabled (changes will take effect when the crtc is re-enabled if modeset passes -1 for the fb id). - Drop WARN() if we try to disable the primary plane when it's already been disabled. This will happen if the crtc gets disabled after the primary plane has already been disabled independently. v5: - Use new drm_primary_helper_check_update() helper function to check setplane parameter validity. - Swap primary plane's pipe for pre-gen4 FBC (caught by Ville Syrjälä) - Cleanup primary plane properly on crtc init failure v4: - Don't add a primary_plane field to intel_crtc; that was left over from a much earlier iteration of this patch series, but is no longer needed/used now that the DRM core primary plane support has been merged. v3: - Provide gen-specific primary plane format lists (suggested by Daniel Vetter). - If the primary plane is already enabled, go ahead and just call the primary plane helper to do the update (suggested by Daniel Vetter). - Don't try to disable the primary plane on destruction; the DRM layer should have already taken care of this for us. v2: - Unpin fb properly on primary plane disable - Provide an Intel-specific set of primary plane formats - Additional sanity checks on setplane (in line with the checks currently being done by the DRM core primary plane helper) Reviewed-by: Chon Ming Lee <chon.ming.lee@intel.com> Signed-off-by: Matt Roper <matthew.d.roper@intel.com> Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Diffstat (limited to 'drivers/gpu/drm/i915/intel_display.c')
-rw-r--r--drivers/gpu/drm/i915/intel_display.c232
1 files changed, 229 insertions, 3 deletions
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index d99be95276d1..e6a2a75c4f5f 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -39,10 +39,37 @@
39#include "i915_trace.h" 39#include "i915_trace.h"
40#include <drm/drm_dp_helper.h> 40#include <drm/drm_dp_helper.h>
41#include <drm/drm_crtc_helper.h> 41#include <drm/drm_crtc_helper.h>
42#include <drm/drm_plane_helper.h>
43#include <drm/drm_rect.h>
42#include <linux/dma_remapping.h> 44#include <linux/dma_remapping.h>
43 45
46/* Primary plane formats supported by all gen */
47#define COMMON_PRIMARY_FORMATS \
48 DRM_FORMAT_C8, \
49 DRM_FORMAT_RGB565, \
50 DRM_FORMAT_XRGB8888, \
51 DRM_FORMAT_ARGB8888
52
53/* Primary plane formats for gen <= 3 */
54static const uint32_t intel_primary_formats_gen2[] = {
55 COMMON_PRIMARY_FORMATS,
56 DRM_FORMAT_XRGB1555,
57 DRM_FORMAT_ARGB1555,
58};
59
60/* Primary plane formats for gen >= 4 */
61static const uint32_t intel_primary_formats_gen4[] = {
62 COMMON_PRIMARY_FORMATS, \
63 DRM_FORMAT_XBGR8888,
64 DRM_FORMAT_ABGR8888,
65 DRM_FORMAT_XRGB2101010,
66 DRM_FORMAT_ARGB2101010,
67 DRM_FORMAT_XBGR2101010,
68 DRM_FORMAT_ABGR2101010,
69};
70
44#define DIV_ROUND_CLOSEST_ULL(ll, d) \ 71#define DIV_ROUND_CLOSEST_ULL(ll, d) \
45 ({ unsigned long long _tmp = (ll)+(d)/2; do_div(_tmp, d); _tmp; }) 72({ unsigned long long _tmp = (ll)+(d)/2; do_div(_tmp, d); _tmp; })
46 73
47static void intel_increase_pllclock(struct drm_crtc *crtc); 74static void intel_increase_pllclock(struct drm_crtc *crtc);
48static void intel_crtc_update_cursor(struct drm_crtc *crtc, bool on); 75static void intel_crtc_update_cursor(struct drm_crtc *crtc, bool on);
@@ -10977,17 +11004,216 @@ static void intel_shared_dpll_init(struct drm_device *dev)
10977 BUG_ON(dev_priv->num_shared_dpll > I915_NUM_PLLS); 11004 BUG_ON(dev_priv->num_shared_dpll > I915_NUM_PLLS);
10978} 11005}
10979 11006
11007static int
11008intel_primary_plane_disable(struct drm_plane *plane)
11009{
11010 struct drm_device *dev = plane->dev;
11011 struct drm_i915_private *dev_priv = dev->dev_private;
11012 struct intel_plane *intel_plane = to_intel_plane(plane);
11013 struct intel_crtc *intel_crtc;
11014
11015 if (!plane->fb)
11016 return 0;
11017
11018 BUG_ON(!plane->crtc);
11019
11020 intel_crtc = to_intel_crtc(plane->crtc);
11021
11022 /*
11023 * Even though we checked plane->fb above, it's still possible that
11024 * the primary plane has been implicitly disabled because the crtc
11025 * coordinates given weren't visible, or because we detected
11026 * that it was 100% covered by a sprite plane. Or, the CRTC may be
11027 * off and we've set a fb, but haven't actually turned on the CRTC yet.
11028 * In either case, we need to unpin the FB and let the fb pointer get
11029 * updated, but otherwise we don't need to touch the hardware.
11030 */
11031 if (!intel_crtc->primary_enabled)
11032 goto disable_unpin;
11033
11034 intel_crtc_wait_for_pending_flips(plane->crtc);
11035 intel_disable_primary_hw_plane(dev_priv, intel_plane->plane,
11036 intel_plane->pipe);
11037
11038disable_unpin:
11039 intel_unpin_fb_obj(to_intel_framebuffer(plane->fb)->obj);
11040 plane->fb = NULL;
11041
11042 return 0;
11043}
11044
11045static int
11046intel_primary_plane_setplane(struct drm_plane *plane, struct drm_crtc *crtc,
11047 struct drm_framebuffer *fb, int crtc_x, int crtc_y,
11048 unsigned int crtc_w, unsigned int crtc_h,
11049 uint32_t src_x, uint32_t src_y,
11050 uint32_t src_w, uint32_t src_h)
11051{
11052 struct drm_device *dev = crtc->dev;
11053 struct drm_i915_private *dev_priv = dev->dev_private;
11054 struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
11055 struct intel_plane *intel_plane = to_intel_plane(plane);
11056 struct drm_rect dest = {
11057 /* integer pixels */
11058 .x1 = crtc_x,
11059 .y1 = crtc_y,
11060 .x2 = crtc_x + crtc_w,
11061 .y2 = crtc_y + crtc_h,
11062 };
11063 struct drm_rect src = {
11064 /* 16.16 fixed point */
11065 .x1 = src_x,
11066 .y1 = src_y,
11067 .x2 = src_x + src_w,
11068 .y2 = src_y + src_h,
11069 };
11070 const struct drm_rect clip = {
11071 /* integer pixels */
11072 .x2 = intel_crtc->active ? intel_crtc->config.pipe_src_w : 0,
11073 .y2 = intel_crtc->active ? intel_crtc->config.pipe_src_h : 0,
11074 };
11075 bool visible;
11076 int ret;
11077
11078 ret = drm_plane_helper_check_update(plane, crtc, fb,
11079 &src, &dest, &clip,
11080 DRM_PLANE_HELPER_NO_SCALING,
11081 DRM_PLANE_HELPER_NO_SCALING,
11082 false, true, &visible);
11083
11084 if (ret)
11085 return ret;
11086
11087 /*
11088 * If the CRTC isn't enabled, we're just pinning the framebuffer,
11089 * updating the fb pointer, and returning without touching the
11090 * hardware. This allows us to later do a drmModeSetCrtc with fb=-1 to
11091 * turn on the display with all planes setup as desired.
11092 */
11093 if (!crtc->enabled) {
11094 /*
11095 * If we already called setplane while the crtc was disabled,
11096 * we may have an fb pinned; unpin it.
11097 */
11098 if (plane->fb)
11099 intel_unpin_fb_obj(to_intel_framebuffer(plane->fb)->obj);
11100
11101 /* Pin and return without programming hardware */
11102 return intel_pin_and_fence_fb_obj(dev,
11103 to_intel_framebuffer(fb)->obj,
11104 NULL);
11105 }
11106
11107 intel_crtc_wait_for_pending_flips(crtc);
11108
11109 /*
11110 * If clipping results in a non-visible primary plane, we'll disable
11111 * the primary plane. Note that this is a bit different than what
11112 * happens if userspace explicitly disables the plane by passing fb=0
11113 * because plane->fb still gets set and pinned.
11114 */
11115 if (!visible) {
11116 /*
11117 * Try to pin the new fb first so that we can bail out if we
11118 * fail.
11119 */
11120 if (plane->fb != fb) {
11121 ret = intel_pin_and_fence_fb_obj(dev,
11122 to_intel_framebuffer(fb)->obj,
11123 NULL);
11124 if (ret)
11125 return ret;
11126 }
11127
11128 if (intel_crtc->primary_enabled)
11129 intel_disable_primary_hw_plane(dev_priv,
11130 intel_plane->plane,
11131 intel_plane->pipe);
11132
11133
11134 if (plane->fb != fb)
11135 if (plane->fb)
11136 intel_unpin_fb_obj(to_intel_framebuffer(plane->fb)->obj);
11137
11138 return 0;
11139 }
11140
11141 ret = intel_pipe_set_base(crtc, src.x1, src.y1, fb);
11142 if (ret)
11143 return ret;
11144
11145 if (!intel_crtc->primary_enabled)
11146 intel_enable_primary_hw_plane(dev_priv, intel_crtc->plane,
11147 intel_crtc->pipe);
11148
11149 return 0;
11150}
11151
11152static void intel_primary_plane_destroy(struct drm_plane *plane)
11153{
11154 struct intel_plane *intel_plane = to_intel_plane(plane);
11155 drm_plane_cleanup(plane);
11156 kfree(intel_plane);
11157}
11158
11159static const struct drm_plane_funcs intel_primary_plane_funcs = {
11160 .update_plane = intel_primary_plane_setplane,
11161 .disable_plane = intel_primary_plane_disable,
11162 .destroy = intel_primary_plane_destroy,
11163};
11164
11165static struct drm_plane *intel_primary_plane_create(struct drm_device *dev,
11166 int pipe)
11167{
11168 struct intel_plane *primary;
11169 const uint32_t *intel_primary_formats;
11170 int num_formats;
11171
11172 primary = kzalloc(sizeof(*primary), GFP_KERNEL);
11173 if (primary == NULL)
11174 return NULL;
11175
11176 primary->can_scale = false;
11177 primary->max_downscale = 1;
11178 primary->pipe = pipe;
11179 primary->plane = pipe;
11180 if (HAS_FBC(dev) && INTEL_INFO(dev)->gen < 4)
11181 primary->plane = !pipe;
11182
11183 if (INTEL_INFO(dev)->gen <= 3) {
11184 intel_primary_formats = intel_primary_formats_gen2;
11185 num_formats = ARRAY_SIZE(intel_primary_formats_gen2);
11186 } else {
11187 intel_primary_formats = intel_primary_formats_gen4;
11188 num_formats = ARRAY_SIZE(intel_primary_formats_gen4);
11189 }
11190
11191 drm_universal_plane_init(dev, &primary->base, 0,
11192 &intel_primary_plane_funcs,
11193 intel_primary_formats, num_formats,
11194 DRM_PLANE_TYPE_PRIMARY);
11195 return &primary->base;
11196}
11197
10980static void intel_crtc_init(struct drm_device *dev, int pipe) 11198static void intel_crtc_init(struct drm_device *dev, int pipe)
10981{ 11199{
10982 struct drm_i915_private *dev_priv = dev->dev_private; 11200 struct drm_i915_private *dev_priv = dev->dev_private;
10983 struct intel_crtc *intel_crtc; 11201 struct intel_crtc *intel_crtc;
10984 int i; 11202 struct drm_plane *primary;
11203 int i, ret;
10985 11204
10986 intel_crtc = kzalloc(sizeof(*intel_crtc), GFP_KERNEL); 11205 intel_crtc = kzalloc(sizeof(*intel_crtc), GFP_KERNEL);
10987 if (intel_crtc == NULL) 11206 if (intel_crtc == NULL)
10988 return; 11207 return;
10989 11208
10990 drm_crtc_init(dev, &intel_crtc->base, &intel_crtc_funcs); 11209 primary = intel_primary_plane_create(dev, pipe);
11210 ret = drm_crtc_init_with_planes(dev, &intel_crtc->base, primary,
11211 NULL, &intel_crtc_funcs);
11212 if (ret) {
11213 drm_plane_cleanup(primary);
11214 kfree(intel_crtc);
11215 return;
11216 }
10991 11217
10992 drm_mode_crtc_set_gamma_size(&intel_crtc->base, 256); 11218 drm_mode_crtc_set_gamma_size(&intel_crtc->base, 256);
10993 for (i = 0; i < 256; i++) { 11219 for (i = 0; i < 256; i++) {