From d15a13f6856210838756020a93b5b8643689cd09 Mon Sep 17 00:00:00 2001 From: "Sergey Semyonov (Serge)" Date: Wed, 24 Apr 2013 20:04:21 +0000 Subject: [PATCH] i915-v3.9-rc8 git-svn-id: svn://kolibrios.org@3480 a494cfbc-eb01-0410-851d-a64ba20cac60 --- drivers/ddk/core.S | 12 + drivers/include/ddk.h | 2 +- drivers/include/drm/drm_crtc.h | 2 +- drivers/include/linux/bug.h | 2 + drivers/include/linux/compiler-gcc.h | 3 + drivers/include/linux/compiler-gcc3.h | 8 +- drivers/include/linux/compiler-gcc4.h | 36 +- drivers/include/linux/compiler.h | 37 +- drivers/include/linux/kernel.h | 14 +- drivers/include/linux/wait.h | 16 + drivers/video/drm/drm_crtc.c | 820 ++++--- drivers/video/drm/drm_crtc_helper.c | 27 +- drivers/video/drm/drm_edid.c | 874 ++++++- drivers/video/drm/drm_fb_helper.c | 263 +- drivers/video/drm/drm_gem.c | 49 +- drivers/video/drm/drm_irq.c | 6 +- drivers/video/drm/drm_mm.c | 96 +- drivers/video/drm/drm_modes.c | 68 + drivers/video/drm/drm_pci.c | 28 +- drivers/video/drm/i915/Gtt/intel-gtt.c | 83 +- drivers/video/drm/i915/i915_dma.c | 125 +- drivers/video/drm/i915/i915_drv.c | 43 +- drivers/video/drm/i915/i915_drv.h | 482 ++-- drivers/video/drm/i915/i915_gem.c | 595 +++-- drivers/video/drm/i915/i915_gem_context.c | 36 +- drivers/video/drm/i915/i915_gem_execbuffer.c | 342 ++- drivers/video/drm/i915/i915_gem_gtt.c | 732 +++--- drivers/video/drm/i915/i915_gem_stolen.c | 309 ++- drivers/video/drm/i915/i915_gem_tiling.c | 33 +- drivers/video/drm/i915/i915_irq.c | 416 ++-- drivers/video/drm/i915/i915_reg.h | 432 ++-- drivers/video/drm/i915/intel_crt.c | 102 +- drivers/video/drm/i915/intel_ddi.c | 71 +- drivers/video/drm/i915/intel_display.c | 971 ++++---- drivers/video/drm/i915/intel_dp.c | 377 +-- drivers/video/drm/i915/intel_drv.h | 35 +- drivers/video/drm/i915/intel_dvo.c | 1 - drivers/video/drm/i915/intel_fb.c | 37 +- drivers/video/drm/i915/intel_hdmi.c | 111 +- drivers/video/drm/i915/intel_i2c.c | 112 +- drivers/video/drm/i915/intel_lvds.c | 237 +- drivers/video/drm/i915/intel_modes.c | 12 +- drivers/video/drm/i915/intel_pm.c | 98 +- drivers/video/drm/i915/intel_ringbuffer.c | 111 +- drivers/video/drm/i915/intel_ringbuffer.h | 11 +- drivers/video/drm/i915/intel_sdvo.c | 69 +- drivers/video/drm/i915/intel_sprite.c | 40 +- drivers/video/drm/i915/kms_display.c | 71 +- drivers/video/drm/i915/main.c | 21 +- .../drm/i915/render/exa_wm_mask_affine.g6b | 4 - .../drm/i915/render/exa_wm_mask_sample_a.g6b | 3 - drivers/video/drm/i915/render/exa_wm_noca.g6b | 4 - .../drm/i915/render/exa_wm_src_affine.g6b | 4 - .../drm/i915/render/exa_wm_src_projective.g6b | 12 - .../i915/render/exa_wm_src_sample_argb.g6b | 3 - .../video/drm/i915/render/exa_wm_write.g6b | 17 - drivers/video/drm/i915/sna/compiler.h | 55 - drivers/video/drm/i915/sna/gen6_render.c | 2163 ----------------- drivers/video/drm/i915/sna/gen6_render.h | 1585 ------------ drivers/video/drm/i915/sna/kgem.c | 1718 ------------- drivers/video/drm/i915/sna/kgem.h | 538 ---- drivers/video/drm/i915/sna/sna.c | 387 --- drivers/video/drm/i915/sna/sna.h | 125 - drivers/video/drm/i915/sna/sna_reg.h | 81 - drivers/video/drm/i915/sna/sna_render.h | 478 ---- drivers/video/drm/i915/sna/sna_stream.c | 108 - drivers/video/drm/i915/utils.c | 408 ++++ 67 files changed, 5880 insertions(+), 10291 deletions(-) delete mode 100644 drivers/video/drm/i915/render/exa_wm_mask_affine.g6b delete mode 100644 drivers/video/drm/i915/render/exa_wm_mask_sample_a.g6b delete mode 100644 drivers/video/drm/i915/render/exa_wm_noca.g6b delete mode 100644 drivers/video/drm/i915/render/exa_wm_src_affine.g6b delete mode 100644 drivers/video/drm/i915/render/exa_wm_src_projective.g6b delete mode 100644 drivers/video/drm/i915/render/exa_wm_src_sample_argb.g6b delete mode 100644 drivers/video/drm/i915/render/exa_wm_write.g6b delete mode 100644 drivers/video/drm/i915/sna/compiler.h delete mode 100644 drivers/video/drm/i915/sna/gen6_render.c delete mode 100644 drivers/video/drm/i915/sna/gen6_render.h delete mode 100644 drivers/video/drm/i915/sna/kgem.c delete mode 100644 drivers/video/drm/i915/sna/kgem.h delete mode 100644 drivers/video/drm/i915/sna/sna.c delete mode 100644 drivers/video/drm/i915/sna/sna.h delete mode 100644 drivers/video/drm/i915/sna/sna_reg.h delete mode 100644 drivers/video/drm/i915/sna/sna_render.h delete mode 100644 drivers/video/drm/i915/sna/sna_stream.c diff --git a/drivers/ddk/core.S b/drivers/ddk/core.S index 1b16f52d0a..dd6ac408aa 100644 --- a/drivers/ddk/core.S +++ b/drivers/ddk/core.S @@ -18,6 +18,9 @@ .global _DestroyEvent .global _DestroyObject + .global _DiskAdd + .global _DiskMediaChanged + .global _FreeKernelSpace .global _FreePage @@ -82,6 +85,9 @@ .def _DestroyEvent; .scl 2; .type 32; .endef .def _DestroyObject; .scl 2; .type 32; .endef + .def _DiskAdd; .scl 2; .type 32; .endef + .def _DiskMediaChanged; .scl 2; .type 32; .endef + .def _FreeKernelSpace; .scl 2; .type 32; .endef .def _FreePage; .scl 2; .type 32; .endef @@ -146,6 +152,9 @@ _Delay: _DestroyEvent: _DestroyObject: +_DiskAdd: +_DiskMediaChanged: + _FreeKernelSpace: _FreePage: @@ -214,6 +223,9 @@ _WaitEventTimeout: .ascii " -export:DestroyEvent" .ascii " -export:DestroyObject" + .ascii " -export:DiskAdd" # stdcall + .ascii " -export:DiskMediaChanged" # stdcall + .ascii " -export:FreeKernelSpace" # stdcall .ascii " -export:FreePage" # diff --git a/drivers/include/ddk.h b/drivers/include/ddk.h index c9d7bc3524..59733f2cd8 100644 --- a/drivers/include/ddk.h +++ b/drivers/include/ddk.h @@ -50,7 +50,7 @@ typedef struct int out_size; }ioctl_t; -typedef int (__stdcall *srv_proc_t)(ioctl_t *); +typedef int ( __stdcall *srv_proc_t)(ioctl_t *); #define ERR_OK 0 #define ERR_PARAM -1 diff --git a/drivers/include/drm/drm_crtc.h b/drivers/include/drm/drm_crtc.h index a7685682ad..29bea244a9 100644 --- a/drivers/include/drm/drm_crtc.h +++ b/drivers/include/drm/drm_crtc.h @@ -817,7 +817,7 @@ struct drm_mode_config { /* output poll support */ bool poll_enabled; bool poll_running; -// struct delayed_work output_poll_work; + struct delayed_work output_poll_work; /* pointers to standard properties */ struct list_head property_blob_list; diff --git a/drivers/include/linux/bug.h b/drivers/include/linux/bug.h index fb11319b1e..d5c3bd9d9a 100644 --- a/drivers/include/linux/bug.h +++ b/drivers/include/linux/bug.h @@ -58,6 +58,8 @@ #define BUG_ON(condition) do { if (unlikely(condition)) BUG(); } while(0) +#define BUILD_BUG_ON_NOT_POWER_OF_2(n) \ + BUILD_BUG_ON((n) == 0 || (((n) & ((n) - 1)) != 0)) #endif diff --git a/drivers/include/linux/compiler-gcc.h b/drivers/include/linux/compiler-gcc.h index 6bcdc3234a..7b8934a69a 100644 --- a/drivers/include/linux/compiler-gcc.h +++ b/drivers/include/linux/compiler-gcc.h @@ -5,6 +5,9 @@ /* * Common definitions for all gcc versions go here. */ +#define GCC_VERSION (__GNUC__ * 10000 \ + + __GNUC_MINOR__ * 100 \ + + __GNUC_PATCHLEVEL__) /* Optimization barrier */ diff --git a/drivers/include/linux/compiler-gcc3.h b/drivers/include/linux/compiler-gcc3.h index 8a2485ddb2..52b6b48237 100644 --- a/drivers/include/linux/compiler-gcc3.h +++ b/drivers/include/linux/compiler-gcc3.h @@ -2,22 +2,22 @@ #error "Please don't include directly, include instead." #endif -#if __GNUC_MINOR__ < 2 +#if GCC_VERSION < 30200 # error Sorry, your compiler is too old - please upgrade it. #endif -#if __GNUC_MINOR__ >= 3 +#if GCC_VERSION >= 30300 # define __used __attribute__((__used__)) #else # define __used __attribute__((__unused__)) #endif -#if __GNUC_MINOR__ >= 4 +#if GCC_VERSION >= 30400 #define __must_check __attribute__((warn_unused_result)) #endif #ifdef CONFIG_GCOV_KERNEL -# if __GNUC_MINOR__ < 4 +# if GCC_VERSION < 30400 # error "GCOV profiling support for gcc versions below 3.4 not included" # endif /* __GNUC_MINOR__ */ #endif /* CONFIG_GCOV_KERNEL */ diff --git a/drivers/include/linux/compiler-gcc4.h b/drivers/include/linux/compiler-gcc4.h index 2b4ebfdbfe..8dbd3953a6 100644 --- a/drivers/include/linux/compiler-gcc4.h +++ b/drivers/include/linux/compiler-gcc4.h @@ -4,7 +4,7 @@ /* GCC 4.1.[01] miscompiles __weak */ #ifdef __KERNEL__ -# if __GNUC_MINOR__ == 1 && __GNUC_PATCHLEVEL__ <= 1 +# if GCC_VERSION >= 40100 && GCC_VERSION <= 40101 # error Your version of gcc miscompiles the __weak directive # endif #endif @@ -13,7 +13,11 @@ #define __must_check __attribute__((warn_unused_result)) #define __compiler_offsetof(a,b) __builtin_offsetof(a,b) -#if __GNUC_MINOR__ >= 3 +#if GCC_VERSION >= 40100 +# define __compiletime_object_size(obj) __builtin_object_size(obj, 0) +#endif + +#if GCC_VERSION >= 40300 /* Mark functions as cold. gcc will assume any path leading to a call to them will be unlikely. This means a lot of manual unlikely()s are unnecessary now for any paths leading to the usual suspects @@ -29,9 +33,15 @@ the kernel context */ #define __cold __attribute__((__cold__)) -#define __linktime_error(message) __attribute__((__error__(message))) +#define __UNIQUE_ID(prefix) __PASTE(__PASTE(__UNIQUE_ID_, prefix), __COUNTER__) -#if __GNUC_MINOR__ >= 5 +#ifndef __CHECKER__ +# define __compiletime_warning(message) __attribute__((warning(message))) +# define __compiletime_error(message) __attribute__((error(message))) +#endif /* __CHECKER__ */ +#endif /* GCC_VERSION >= 40300 */ + +#if GCC_VERSION >= 40500 /* * Mark a position in code as unreachable. This can be used to * suppress control flow warnings after asm blocks that transfer @@ -46,30 +56,22 @@ /* Mark a function definition as prohibited from being cloned. */ #define __noclone __attribute__((__noclone__)) -#endif -#endif +#endif /* GCC_VERSION >= 40500 */ -#if __GNUC_MINOR__ >= 6 +#if GCC_VERSION >= 40600 /* * Tell the optimizer that something else uses this function or variable. */ #define __visible __attribute__((externally_visible)) #endif -#if __GNUC_MINOR__ > 0 -#define __compiletime_object_size(obj) __builtin_object_size(obj, 0) -#endif -#if __GNUC_MINOR__ >= 3 && !defined(__CHECKER__) -#define __compiletime_warning(message) __attribute__((warning(message))) -#define __compiletime_error(message) __attribute__((error(message))) -#endif #ifdef CONFIG_ARCH_USE_BUILTIN_BSWAP -#if __GNUC_MINOR__ >= 4 +#if GCC_VERSION >= 40400 #define __HAVE_BUILTIN_BSWAP32__ #define __HAVE_BUILTIN_BSWAP64__ #endif -#if __GNUC_MINOR__ >= 8 || (defined(__powerpc__) && __GNUC_MINOR__ >= 6) +#if GCC_VERSION >= 40800 || (defined(__powerpc__) && GCC_VERSION >= 40600) #define __HAVE_BUILTIN_BSWAP16__ #endif -#endif +#endif /* CONFIG_ARCH_USE_BUILTIN_BSWAP */ diff --git a/drivers/include/linux/compiler.h b/drivers/include/linux/compiler.h index e6573485d2..44c079c257 100644 --- a/drivers/include/linux/compiler.h +++ b/drivers/include/linux/compiler.h @@ -170,6 +170,11 @@ void ftrace_likely_update(struct ftrace_branch_data *f, int val, int expect); (typeof(ptr)) (__ptr + (off)); }) #endif +/* Not-quite-unique ID. */ +#ifndef __UNIQUE_ID +# define __UNIQUE_ID(prefix) __PASTE(__PASTE(__UNIQUE_ID_, prefix), __LINE__) +#endif + #endif /* __KERNEL__ */ #endif /* __ASSEMBLY__ */ @@ -302,10 +307,36 @@ void ftrace_likely_update(struct ftrace_branch_data *f, int val, int expect); #endif #ifndef __compiletime_error # define __compiletime_error(message) +# define __compiletime_error_fallback(condition) \ + do { ((void)sizeof(char[1 - 2 * condition])); } while (0) +#else +# define __compiletime_error_fallback(condition) do { } while (0) #endif -#ifndef __linktime_error -# define __linktime_error(message) -#endif + +#define __compiletime_assert(condition, msg, prefix, suffix) \ + do { \ + bool __cond = !(condition); \ + extern void prefix ## suffix(void) __compiletime_error(msg); \ + if (__cond) \ + prefix ## suffix(); \ + __compiletime_error_fallback(__cond); \ + } while (0) + +#define _compiletime_assert(condition, msg, prefix, suffix) \ + __compiletime_assert(condition, msg, prefix, suffix) + +/** + * compiletime_assert - break build and emit msg if condition is false + * @condition: a compile-time constant condition to check + * @msg: a message to emit if condition is false + * + * In tradition of POSIX assert, this macro will break the build if the + * supplied condition is *false*, emitting the supplied error message if the + * compiler has support to do so. + */ +#define compiletime_assert(condition, msg) \ + _compiletime_assert(condition, msg, __compiletime_assert_, __LINE__) + /* * Prevent the compiler from merging or refetching accesses. The compiler * is also forbidden from reordering successive instances of ACCESS_ONCE(), diff --git a/drivers/include/linux/kernel.h b/drivers/include/linux/kernel.h index 5cdd2534ba..5d07818e53 100644 --- a/drivers/include/linux/kernel.h +++ b/drivers/include/linux/kernel.h @@ -87,8 +87,14 @@ static inline char *pack_hex_byte(char *buf, u8 byte) return buf; } -extern int hex_to_bin(char ch); -extern void hex2bin(u8 *dst, const char *src, size_t count); +enum { + DUMP_PREFIX_NONE, + DUMP_PREFIX_ADDRESS, + DUMP_PREFIX_OFFSET +}; + +int hex_to_bin(char ch); +int hex2bin(u8 *dst, const char *src, size_t count); //int printk(const char *fmt, ...); @@ -335,8 +341,8 @@ static inline void writeq(__u64 val, volatile void __iomem *addr) #define dev_info(dev, format, arg...) \ printk("Info %s " format , __func__, ## arg) -#define BUILD_BUG_ON(condition) ((void)sizeof(char[1 - 2*!!(condition)])) - +//#define BUILD_BUG_ON(condition) ((void)sizeof(char[1 - 2*!!(condition)])) +#define BUILD_BUG_ON(condition) struct page { diff --git a/drivers/include/linux/wait.h b/drivers/include/linux/wait.h index c17eeb69c4..74ad8177f8 100644 --- a/drivers/include/linux/wait.h +++ b/drivers/include/linux/wait.h @@ -172,6 +172,13 @@ struct delayed_work { struct work_struct work; }; +static inline struct delayed_work *to_delayed_work(struct work_struct *work) +{ + return container_of(work, struct delayed_work, work); +} + + + struct workqueue_struct *alloc_workqueue_key(const char *fmt, unsigned int flags, int max_active); @@ -182,6 +189,13 @@ struct workqueue_struct *alloc_workqueue_key(const char *fmt, int queue_delayed_work(struct workqueue_struct *wq, struct delayed_work *dwork, unsigned long delay); +#define INIT_WORK(_work, _func) \ + do { \ + INIT_LIST_HEAD(&(_work)->entry); \ + (_work)->func = _func; \ + } while (0) + + #define INIT_DELAYED_WORK(_work, _func) \ do { \ INIT_LIST_HEAD(&(_work)->work.entry); \ @@ -207,5 +221,7 @@ int autoremove_wake_function(wait_queue_t *wait, unsigned mode, int sync, void * #define DEFINE_WAIT(name) DEFINE_WAIT_FUNC(name, autoremove_wake_function) + + #endif diff --git a/drivers/video/drm/drm_crtc.c b/drivers/video/drm/drm_crtc.c index db69b5f551..f3f801ada7 100644 --- a/drivers/video/drm/drm_crtc.c +++ b/drivers/video/drm/drm_crtc.c @@ -37,6 +37,54 @@ #include #include +/** + * drm_modeset_lock_all - take all modeset locks + * @dev: drm device + * + * This function takes all modeset locks, suitable where a more fine-grained + * scheme isn't (yet) implemented. + */ +void drm_modeset_lock_all(struct drm_device *dev) +{ + struct drm_crtc *crtc; + + mutex_lock(&dev->mode_config.mutex); + + list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) + mutex_lock_nest_lock(&crtc->mutex, &dev->mode_config.mutex); +} +EXPORT_SYMBOL(drm_modeset_lock_all); + +/** + * drm_modeset_unlock_all - drop all modeset locks + * @dev: device + */ +void drm_modeset_unlock_all(struct drm_device *dev) +{ + struct drm_crtc *crtc; + + list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) + mutex_unlock(&crtc->mutex); + + mutex_unlock(&dev->mode_config.mutex); +} +EXPORT_SYMBOL(drm_modeset_unlock_all); + +/** + * drm_warn_on_modeset_not_all_locked - check that all modeset locks are locked + * @dev: device + */ +void drm_warn_on_modeset_not_all_locked(struct drm_device *dev) +{ + struct drm_crtc *crtc; + + list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) + WARN_ON(!mutex_is_locked(&crtc->mutex)); + + WARN_ON(!mutex_is_locked(&dev->mode_config.mutex)); +} +EXPORT_SYMBOL(drm_warn_on_modeset_not_all_locked); + /* Avoid boilerplate. I'm tired of typing. */ #define DRM_ENUM_NAME_FN(fnname, list) \ char *fnname(int val) \ @@ -203,12 +251,10 @@ char *drm_get_connector_status_name(enum drm_connector_status status) } /** - * drm_mode_object_get - allocate a new identifier + * drm_mode_object_get - allocate a new modeset identifier * @dev: DRM device - * @ptr: object pointer, used to generate unique ID - * @type: object type - * - * LOCKING: + * @obj: object pointer, used to generate unique ID + * @obj_type: object type * * Create a unique identifier based on @ptr in @dev's identifier space. Used * for tracking modes, CRTCs and connectors. @@ -220,35 +266,27 @@ char *drm_get_connector_status_name(enum drm_connector_status status) static int drm_mode_object_get(struct drm_device *dev, struct drm_mode_object *obj, uint32_t obj_type) { - int new_id = 0; int ret; -again: - if (idr_pre_get(&dev->mode_config.crtc_idr, GFP_KERNEL) == 0) { - DRM_ERROR("Ran out memory getting a mode number\n"); - return -ENOMEM; - } - mutex_lock(&dev->mode_config.idr_mutex); - ret = idr_get_new_above(&dev->mode_config.crtc_idr, obj, 1, &new_id); + ret = idr_alloc(&dev->mode_config.crtc_idr, obj, 1, 0, GFP_KERNEL); + if (ret >= 0) { + /* + * Set up the object linking under the protection of the idr + * lock so that other users can't see inconsistent state. + */ + obj->id = ret; + obj->type = obj_type; + } mutex_unlock(&dev->mode_config.idr_mutex); - if (ret == -EAGAIN) - goto again; - else if (ret) - return ret; - obj->id = new_id; - obj->type = obj_type; - return 0; + return ret < 0 ? ret : 0; } /** - * drm_mode_object_put - free an identifer + * drm_mode_object_put - free a modeset identifer * @dev: DRM device - * @id: ID to free - * - * LOCKING: - * Caller must hold DRM mode_config lock. + * @object: object to free * * Free @id from @dev's unique identifier pool. */ @@ -260,11 +298,24 @@ static void drm_mode_object_put(struct drm_device *dev, mutex_unlock(&dev->mode_config.idr_mutex); } +/** + * drm_mode_object_find - look up a drm object with static lifetime + * @dev: drm device + * @id: id of the mode object + * @type: type of the mode object + * + * Note that framebuffers cannot be looked up with this functions - since those + * are reference counted, they need special treatment. + */ struct drm_mode_object *drm_mode_object_find(struct drm_device *dev, uint32_t id, uint32_t type) { struct drm_mode_object *obj = NULL; + /* Framebuffers are reference counted and need their own lookup + * function.*/ + WARN_ON(type == DRM_MODE_OBJECT_FB); + mutex_lock(&dev->mode_config.idr_mutex); obj = idr_find(&dev->mode_config.crtc_idr, id); if (!obj || (obj->type != type) || (obj->id != id)) @@ -278,13 +329,18 @@ EXPORT_SYMBOL(drm_mode_object_find); /** * drm_framebuffer_init - initialize a framebuffer * @dev: DRM device - * - * LOCKING: - * Caller must hold mode config lock. + * @fb: framebuffer to be initialized + * @funcs: ... with these functions * * Allocates an ID for the framebuffer's parent mode object, sets its mode * functions & device file and adds it to the master fd list. * + * IMPORTANT: + * This functions publishes the fb and makes it available for concurrent access + * by other users. Which means by this point the fb _must_ be fully set up - + * since all the fb attributes are invariant over its lifetime, no further + * locking but only correct reference counting is required. + * * RETURNS: * Zero on success, error code on failure. */ @@ -293,48 +349,241 @@ int drm_framebuffer_init(struct drm_device *dev, struct drm_framebuffer *fb, { int ret; - ret = drm_mode_object_get(dev, &fb->base, DRM_MODE_OBJECT_FB); - if (ret) - return ret; - + mutex_lock(&dev->mode_config.fb_lock); + kref_init(&fb->refcount); + INIT_LIST_HEAD(&fb->filp_head); fb->dev = dev; fb->funcs = funcs; + + ret = drm_mode_object_get(dev, &fb->base, DRM_MODE_OBJECT_FB); + if (ret) + goto out; + + /* Grab the idr reference. */ + drm_framebuffer_reference(fb); + dev->mode_config.num_fb++; list_add(&fb->head, &dev->mode_config.fb_list); +out: + mutex_unlock(&dev->mode_config.fb_lock); return 0; } EXPORT_SYMBOL(drm_framebuffer_init); +static void drm_framebuffer_free(struct kref *kref) +{ + struct drm_framebuffer *fb = + container_of(kref, struct drm_framebuffer, refcount); + fb->funcs->destroy(fb); +} + +static struct drm_framebuffer *__drm_framebuffer_lookup(struct drm_device *dev, + uint32_t id) +{ + struct drm_mode_object *obj = NULL; + struct drm_framebuffer *fb; + + mutex_lock(&dev->mode_config.idr_mutex); + obj = idr_find(&dev->mode_config.crtc_idr, id); + if (!obj || (obj->type != DRM_MODE_OBJECT_FB) || (obj->id != id)) + fb = NULL; + else + fb = obj_to_fb(obj); + mutex_unlock(&dev->mode_config.idr_mutex); + + return fb; +} + +/** + * drm_framebuffer_lookup - look up a drm framebuffer and grab a reference + * @dev: drm device + * @id: id of the fb object + * + * If successful, this grabs an additional reference to the framebuffer - + * callers need to make sure to eventually unreference the returned framebuffer + * again. + */ +struct drm_framebuffer *drm_framebuffer_lookup(struct drm_device *dev, + uint32_t id) +{ + struct drm_framebuffer *fb; + + mutex_lock(&dev->mode_config.fb_lock); + fb = __drm_framebuffer_lookup(dev, id); + if (fb) + kref_get(&fb->refcount); + mutex_unlock(&dev->mode_config.fb_lock); + + return fb; +} +EXPORT_SYMBOL(drm_framebuffer_lookup); + +/** + * drm_framebuffer_unreference - unref a framebuffer + * @fb: framebuffer to unref + * + * This functions decrements the fb's refcount and frees it if it drops to zero. + */ +void drm_framebuffer_unreference(struct drm_framebuffer *fb) +{ + DRM_DEBUG("FB ID: %d\n", fb->base.id); + kref_put(&fb->refcount, drm_framebuffer_free); +} +EXPORT_SYMBOL(drm_framebuffer_unreference); + +/** + * drm_framebuffer_reference - incr the fb refcnt + * @fb: framebuffer + */ +void drm_framebuffer_reference(struct drm_framebuffer *fb) +{ + DRM_DEBUG("FB ID: %d\n", fb->base.id); + kref_get(&fb->refcount); +} +EXPORT_SYMBOL(drm_framebuffer_reference); + +static void drm_framebuffer_free_bug(struct kref *kref) +{ + BUG(); +} + +static void __drm_framebuffer_unreference(struct drm_framebuffer *fb) +{ + DRM_DEBUG("FB ID: %d\n", fb->base.id); + kref_put(&fb->refcount, drm_framebuffer_free_bug); +} + +/* dev->mode_config.fb_lock must be held! */ +static void __drm_framebuffer_unregister(struct drm_device *dev, + struct drm_framebuffer *fb) +{ + mutex_lock(&dev->mode_config.idr_mutex); + idr_remove(&dev->mode_config.crtc_idr, fb->base.id); + mutex_unlock(&dev->mode_config.idr_mutex); + + fb->base.id = 0; + + __drm_framebuffer_unreference(fb); +} + +/** + * drm_framebuffer_unregister_private - unregister a private fb from the lookup idr + * @fb: fb to unregister + * + * Drivers need to call this when cleaning up driver-private framebuffers, e.g. + * those used for fbdev. Note that the caller must hold a reference of it's own, + * i.e. the object may not be destroyed through this call (since it'll lead to a + * locking inversion). + */ +void drm_framebuffer_unregister_private(struct drm_framebuffer *fb) +{ + struct drm_device *dev = fb->dev; + + mutex_lock(&dev->mode_config.fb_lock); + /* Mark fb as reaped and drop idr ref. */ + __drm_framebuffer_unregister(dev, fb); + mutex_unlock(&dev->mode_config.fb_lock); +} +EXPORT_SYMBOL(drm_framebuffer_unregister_private); + /** * drm_framebuffer_cleanup - remove a framebuffer object * @fb: framebuffer to remove * - * LOCKING: - * Caller must hold mode config lock. + * Cleanup references to a user-created framebuffer. This function is intended + * to be used from the drivers ->destroy callback. * - * Scans all the CRTCs in @dev's mode_config. If they're using @fb, removes - * it, setting it to NULL. + * Note that this function does not remove the fb from active usuage - if it is + * still used anywhere, hilarity can ensue since userspace could call getfb on + * the id and get back -EINVAL. Obviously no concern at driver unload time. + * + * Also, the framebuffer will not be removed from the lookup idr - for + * user-created framebuffers this will happen in in the rmfb ioctl. For + * driver-private objects (e.g. for fbdev) drivers need to explicitly call + * drm_framebuffer_unregister_private. */ void drm_framebuffer_cleanup(struct drm_framebuffer *fb) { struct drm_device *dev = fb->dev; - /* - * This could be moved to drm_framebuffer_remove(), but for - * debugging is nice to keep around the list of fb's that are - * no longer associated w/ a drm_file but are not unreferenced - * yet. (i915 and omapdrm have debugfs files which will show - * this.) - */ - drm_mode_object_put(dev, &fb->base); + + mutex_lock(&dev->mode_config.fb_lock); list_del(&fb->head); dev->mode_config.num_fb--; + mutex_unlock(&dev->mode_config.fb_lock); } EXPORT_SYMBOL(drm_framebuffer_cleanup); +/** + * drm_framebuffer_remove - remove and unreference a framebuffer object + * @fb: framebuffer to remove + * + * Scans all the CRTCs and planes in @dev's mode_config. If they're + * using @fb, removes it, setting it to NULL. Then drops the reference to the + * passed-in framebuffer. Might take the modeset locks. + * + * Note that this function optimizes the cleanup away if the caller holds the + * last reference to the framebuffer. It is also guaranteed to not take the + * modeset locks in this case. + */ +void drm_framebuffer_remove(struct drm_framebuffer *fb) +{ + struct drm_device *dev = fb->dev; + struct drm_crtc *crtc; + struct drm_plane *plane; + struct drm_mode_set set; + int ret; + WARN_ON(!list_empty(&fb->filp_head)); + /* + * drm ABI mandates that we remove any deleted framebuffers from active + * useage. But since most sane clients only remove framebuffers they no + * longer need, try to optimize this away. + * + * Since we're holding a reference ourselves, observing a refcount of 1 + * means that we're the last holder and can skip it. Also, the refcount + * can never increase from 1 again, so we don't need any barriers or + * locks. + * + * Note that userspace could try to race with use and instate a new + * usage _after_ we've cleared all current ones. End result will be an + * in-use fb with fb-id == 0. Userspace is allowed to shoot its own foot + * in this manner. + */ + if (atomic_read(&fb->refcount.refcount) > 1) { + drm_modeset_lock_all(dev); + /* remove from any CRTC */ + list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { + if (crtc->fb == fb) { + /* should turn off the crtc */ + memset(&set, 0, sizeof(struct drm_mode_set)); + set.crtc = crtc; + set.fb = NULL; + ret = drm_mode_set_config_internal(&set); + if (ret) + DRM_ERROR("failed to reset crtc %p when fb was deleted\n", crtc); + } + } + list_for_each_entry(plane, &dev->mode_config.plane_list, head) { + if (plane->fb == fb) { + /* should turn off the crtc */ + ret = plane->funcs->disable_plane(plane); + if (ret) + DRM_ERROR("failed to disable plane with busy fb\n"); + /* disconnect the plane from the fb and crtc: */ + __drm_framebuffer_unreference(plane->fb); + plane->fb = NULL; + plane->crtc = NULL; + } + } + drm_modeset_unlock_all(dev); + } + + drm_framebuffer_unreference(fb); +} +EXPORT_SYMBOL(drm_framebuffer_remove); /** * drm_crtc_init - Initialise a new CRTC object @@ -342,9 +591,6 @@ EXPORT_SYMBOL(drm_framebuffer_cleanup); * @crtc: CRTC object to init * @funcs: callbacks for the new CRTC * - * LOCKING: - * Takes mode_config lock. - * * Inits a new object created as base part of an driver crtc object. * * RETURNS: @@ -359,7 +605,9 @@ int drm_crtc_init(struct drm_device *dev, struct drm_crtc *crtc, crtc->funcs = funcs; crtc->invert_dimensions = false; - mutex_lock(&dev->mode_config.mutex); + drm_modeset_lock_all(dev); + mutex_init(&crtc->mutex); + mutex_lock_nest_lock(&crtc->mutex, &dev->mode_config.mutex); ret = drm_mode_object_get(dev, &crtc->base, DRM_MODE_OBJECT_CRTC); if (ret) @@ -371,7 +619,7 @@ int drm_crtc_init(struct drm_device *dev, struct drm_crtc *crtc, dev->mode_config.num_crtc++; out: - mutex_unlock(&dev->mode_config.mutex); + drm_modeset_unlock_all(dev); return ret; } @@ -381,9 +629,6 @@ EXPORT_SYMBOL(drm_crtc_init); * drm_crtc_cleanup - Cleans up the core crtc usage. * @crtc: CRTC to cleanup * - * LOCKING: - * Caller must hold mode config lock. - * * Cleanup @crtc. Removes from drm modesetting space * does NOT free object, caller does that. */ @@ -405,9 +650,6 @@ EXPORT_SYMBOL(drm_crtc_cleanup); * @connector: connector the new mode * @mode: mode data * - * LOCKING: - * Caller must hold mode config lock. - * * Add @mode to @connector's mode list for later use. */ void drm_mode_probed_add(struct drm_connector *connector, @@ -422,9 +664,6 @@ EXPORT_SYMBOL(drm_mode_probed_add); * @connector: connector list to modify * @mode: mode to remove * - * LOCKING: - * Caller must hold mode config lock. - * * Remove @mode from @connector's mode list, then free it. */ void drm_mode_remove(struct drm_connector *connector, @@ -440,10 +679,7 @@ EXPORT_SYMBOL(drm_mode_remove); * @dev: DRM device * @connector: the connector to init * @funcs: callbacks for this connector - * @name: user visible name of the connector - * - * LOCKING: - * Takes mode config lock. + * @connector_type: user visible type of the connector * * Initialises a preallocated connector. Connectors should be * subclassed as part of driver connector objects. @@ -458,7 +694,7 @@ int drm_connector_init(struct drm_device *dev, { int ret; - mutex_lock(&dev->mode_config.mutex); + drm_modeset_lock_all(dev); ret = drm_mode_object_get(dev, &connector->base, DRM_MODE_OBJECT_CONNECTOR); if (ret) @@ -488,7 +724,7 @@ int drm_connector_init(struct drm_device *dev, dev->mode_config.dpms_property, 0); out: - mutex_unlock(&dev->mode_config.mutex); + drm_modeset_unlock_all(dev); return ret; } @@ -498,9 +734,6 @@ EXPORT_SYMBOL(drm_connector_init); * drm_connector_cleanup - cleans up an initialised connector * @connector: connector to cleanup * - * LOCKING: - * Takes mode config lock. - * * Cleans up the connector but doesn't free the object. */ void drm_connector_cleanup(struct drm_connector *connector) @@ -517,11 +750,9 @@ void drm_connector_cleanup(struct drm_connector *connector) list_for_each_entry_safe(mode, t, &connector->user_modes, head) drm_mode_remove(connector, mode); - mutex_lock(&dev->mode_config.mutex); drm_mode_object_put(dev, &connector->base); list_del(&connector->head); dev->mode_config.num_connector--; - mutex_unlock(&dev->mode_config.mutex); } EXPORT_SYMBOL(drm_connector_cleanup); @@ -543,7 +774,7 @@ int drm_encoder_init(struct drm_device *dev, { int ret; - mutex_lock(&dev->mode_config.mutex); + drm_modeset_lock_all(dev); ret = drm_mode_object_get(dev, &encoder->base, DRM_MODE_OBJECT_ENCODER); if (ret) @@ -557,7 +788,7 @@ int drm_encoder_init(struct drm_device *dev, dev->mode_config.num_encoder++; out: - mutex_unlock(&dev->mode_config.mutex); + drm_modeset_unlock_all(dev); return ret; } @@ -566,11 +797,11 @@ EXPORT_SYMBOL(drm_encoder_init); void drm_encoder_cleanup(struct drm_encoder *encoder) { struct drm_device *dev = encoder->dev; - mutex_lock(&dev->mode_config.mutex); + drm_modeset_lock_all(dev); drm_mode_object_put(dev, &encoder->base); list_del(&encoder->head); dev->mode_config.num_encoder--; - mutex_unlock(&dev->mode_config.mutex); + drm_modeset_unlock_all(dev); } EXPORT_SYMBOL(drm_encoder_cleanup); @@ -582,7 +813,7 @@ int drm_plane_init(struct drm_device *dev, struct drm_plane *plane, { int ret; - mutex_lock(&dev->mode_config.mutex); + drm_modeset_lock_all(dev); ret = drm_mode_object_get(dev, &plane->base, DRM_MODE_OBJECT_PLANE); if (ret) @@ -616,7 +847,7 @@ int drm_plane_init(struct drm_device *dev, struct drm_plane *plane, } out: - mutex_unlock(&dev->mode_config.mutex); + drm_modeset_unlock_all(dev); return ret; } @@ -626,7 +857,7 @@ void drm_plane_cleanup(struct drm_plane *plane) { struct drm_device *dev = plane->dev; - mutex_lock(&dev->mode_config.mutex); + drm_modeset_lock_all(dev); kfree(plane->format_types); drm_mode_object_put(dev, &plane->base); /* if not added to a list, it must be a private plane */ @@ -634,7 +865,7 @@ void drm_plane_cleanup(struct drm_plane *plane) list_del(&plane->head); dev->mode_config.num_plane--; } - mutex_unlock(&dev->mode_config.mutex); + drm_modeset_unlock_all(dev); } EXPORT_SYMBOL(drm_plane_cleanup); @@ -642,9 +873,6 @@ EXPORT_SYMBOL(drm_plane_cleanup); * drm_mode_create - create a new display mode * @dev: DRM device * - * LOCKING: - * Caller must hold DRM mode_config lock. - * * Create a new drm_display_mode, give it an ID, and return it. * * RETURNS: @@ -672,9 +900,6 @@ EXPORT_SYMBOL(drm_mode_create); * @dev: DRM device * @mode: mode to remove * - * LOCKING: - * Caller must hold mode config lock. - * * Free @mode's unique identifier, then free it. */ void drm_mode_destroy(struct drm_device *dev, struct drm_display_mode *mode) @@ -899,16 +1124,19 @@ EXPORT_SYMBOL(drm_mode_create_dirty_info_property); * drm_mode_config_init - initialize DRM mode_configuration structure * @dev: DRM device * - * LOCKING: - * None, should happen single threaded at init time. - * * Initialize @dev's mode_config structure, used for tracking the graphics * configuration of @dev. + * + * Since this initializes the modeset locks, no locking is possible. Which is no + * problem, since this should happen single threaded at init time. It is the + * driver's problem to ensure this guarantee. + * */ void drm_mode_config_init(struct drm_device *dev) { mutex_init(&dev->mode_config.mutex); mutex_init(&dev->mode_config.idr_mutex); + mutex_init(&dev->mode_config.fb_lock); INIT_LIST_HEAD(&dev->mode_config.fb_list); INIT_LIST_HEAD(&dev->mode_config.crtc_list); INIT_LIST_HEAD(&dev->mode_config.connector_list); @@ -918,9 +1146,9 @@ void drm_mode_config_init(struct drm_device *dev) INIT_LIST_HEAD(&dev->mode_config.plane_list); idr_init(&dev->mode_config.crtc_idr); - mutex_lock(&dev->mode_config.mutex); + drm_modeset_lock_all(dev); drm_mode_create_standard_connector_properties(dev); - mutex_unlock(&dev->mode_config.mutex); + drm_modeset_unlock_all(dev); /* Just to be sure */ dev->mode_config.num_fb = 0; @@ -978,12 +1206,13 @@ EXPORT_SYMBOL(drm_mode_group_init_legacy_group); * drm_mode_config_cleanup - free up DRM mode_config info * @dev: DRM device * - * LOCKING: - * Caller must hold mode config lock. - * * Free up all the connectors and CRTCs associated with this DRM device, then * free up the framebuffers and associated buffer objects. * + * Note that since this /should/ happen single-threaded at driver/device + * teardown time, no locking is required. It's the driver's job to ensure that + * this guarantee actually holds true. + * * FIXME: cleanup any dangling user buffer objects too */ void drm_mode_config_cleanup(struct drm_device *dev) @@ -1010,6 +1239,19 @@ void drm_mode_config_cleanup(struct drm_device *dev) drm_property_destroy(dev, property); } + /* + * Single-threaded teardown context, so it's not required to grab the + * fb_lock to protect against concurrent fb_list access. Contrary, it + * would actually deadlock with the drm_framebuffer_cleanup function. + * + * Also, if there are any framebuffers left, that's a driver leak now, + * so politely WARN about this. + */ + WARN_ON(!list_empty(&dev->mode_config.fb_list)); + list_for_each_entry_safe(fb, fbt, &dev->mode_config.fb_list, head) { + drm_framebuffer_remove(fb); + } + list_for_each_entry_safe(plane, plt, &dev->mode_config.plane_list, head) { plane->funcs->destroy(plane); @@ -1019,7 +1261,6 @@ void drm_mode_config_cleanup(struct drm_device *dev) crtc->funcs->destroy(crtc); } - idr_remove_all(&dev->mode_config.crtc_idr); idr_destroy(&dev->mode_config.crtc_idr); } EXPORT_SYMBOL(drm_mode_config_cleanup); @@ -1029,9 +1270,6 @@ EXPORT_SYMBOL(drm_mode_config_cleanup); * @out: drm_mode_modeinfo struct to return to the user * @in: drm_display_mode to use * - * LOCKING: - * None. - * * Convert a drm_display_mode into a drm_mode_modeinfo structure to return to * the user. */ @@ -1068,9 +1306,6 @@ static void drm_crtc_convert_to_umode(struct drm_mode_modeinfo *out, * @out: drm_display_mode to return to the user * @in: drm_mode_modeinfo to use * - * LOCKING: - * None. - * * Convert a drm_mode_modeinfo into a drm_display_mode structure to return to * the caller. * @@ -1107,13 +1342,9 @@ static int drm_crtc_convert_umode(struct drm_display_mode *out, #if 0 /** * drm_mode_getresources - get graphics configuration - * @inode: inode from the ioctl - * @filp: file * from the ioctl - * @cmd: cmd from ioctl - * @arg: arg from ioctl - * - * LOCKING: - * Takes mode config lock. + * @dev: drm device for the ioctl + * @data: data pointer for the ioctl + * @file_priv: drm file for the ioctl call * * Construct a set of configuration description structures and return * them to the user, including CRTC, connector and framebuffer configuration. @@ -1147,8 +1378,8 @@ int drm_mode_getresources(struct drm_device *dev, void *data, if (!drm_core_check_feature(dev, DRIVER_MODESET)) return -EINVAL; - mutex_lock(&dev->mode_config.mutex); + mutex_lock(&file_priv->fbs_lock); /* * For the non-control nodes we need to limit the list of resources * by IDs in the group list for this node @@ -1156,6 +1387,23 @@ int drm_mode_getresources(struct drm_device *dev, void *data, list_for_each(lh, &file_priv->fbs) fb_count++; + /* handle this in 4 parts */ + /* FBs */ + if (card_res->count_fbs >= fb_count) { + copied = 0; + fb_id = (uint32_t __user *)(unsigned long)card_res->fb_id_ptr; + list_for_each_entry(fb, &file_priv->fbs, filp_head) { + if (put_user(fb->base.id, fb_id + copied)) { + mutex_unlock(&file_priv->fbs_lock); + return -EFAULT; + } + copied++; + } + } + card_res->count_fbs = fb_count; + mutex_unlock(&file_priv->fbs_lock); + + drm_modeset_lock_all(dev); mode_group = &file_priv->master->minor->mode_group; if (file_priv->master->minor->type == DRM_MINOR_CONTROL) { @@ -1179,21 +1427,6 @@ int drm_mode_getresources(struct drm_device *dev, void *data, card_res->max_width = dev->mode_config.max_width; card_res->min_width = dev->mode_config.min_width; - /* handle this in 4 parts */ - /* FBs */ - if (card_res->count_fbs >= fb_count) { - copied = 0; - fb_id = (uint32_t __user *)(unsigned long)card_res->fb_id_ptr; - list_for_each_entry(fb, &file_priv->fbs, filp_head) { - if (put_user(fb->base.id, fb_id + copied)) { - ret = -EFAULT; - goto out; - } - copied++; - } - } - card_res->count_fbs = fb_count; - /* CRTCs */ if (card_res->count_crtcs >= crtc_count) { copied = 0; @@ -1289,19 +1522,15 @@ int drm_mode_getresources(struct drm_device *dev, void *data, card_res->count_connectors, card_res->count_encoders); out: - mutex_unlock(&dev->mode_config.mutex); + drm_modeset_unlock_all(dev); return ret; } /** * drm_mode_getcrtc - get CRTC configuration - * @inode: inode from the ioctl - * @filp: file * from the ioctl - * @cmd: cmd from ioctl - * @arg: arg from ioctl - * - * LOCKING: - * Takes mode config lock. + * @dev: drm device for the ioctl + * @data: data pointer for the ioctl + * @file_priv: drm file for the ioctl call * * Construct a CRTC configuration structure to return to the user. * @@ -1321,7 +1550,7 @@ int drm_mode_getcrtc(struct drm_device *dev, if (!drm_core_check_feature(dev, DRIVER_MODESET)) return -EINVAL; - mutex_lock(&dev->mode_config.mutex); + drm_modeset_lock_all(dev); obj = drm_mode_object_find(dev, crtc_resp->crtc_id, DRM_MODE_OBJECT_CRTC); @@ -1349,19 +1578,15 @@ int drm_mode_getcrtc(struct drm_device *dev, } out: - mutex_unlock(&dev->mode_config.mutex); + drm_modeset_unlock_all(dev); return ret; } /** * drm_mode_getconnector - get connector configuration - * @inode: inode from the ioctl - * @filp: file * from the ioctl - * @cmd: cmd from ioctl - * @arg: arg from ioctl - * - * LOCKING: - * Takes mode config lock. + * @dev: drm device for the ioctl + * @data: data pointer for the ioctl + * @file_priv: drm file for the ioctl call * * Construct a connector configuration structure to return to the user. * @@ -1494,6 +1719,7 @@ int drm_mode_getconnector(struct drm_device *dev, void *data, out: mutex_unlock(&dev->mode_config.mutex); + return ret; } @@ -1508,7 +1734,7 @@ int drm_mode_getencoder(struct drm_device *dev, void *data, if (!drm_core_check_feature(dev, DRIVER_MODESET)) return -EINVAL; - mutex_lock(&dev->mode_config.mutex); + drm_modeset_lock_all(dev); obj = drm_mode_object_find(dev, enc_resp->encoder_id, DRM_MODE_OBJECT_ENCODER); if (!obj) { @@ -1527,7 +1753,7 @@ int drm_mode_getencoder(struct drm_device *dev, void *data, enc_resp->possible_clones = encoder->possible_clones; out: - mutex_unlock(&dev->mode_config.mutex); + drm_modeset_unlock_all(dev); return ret; } @@ -1537,9 +1763,6 @@ out: * @data: ioctl data * @file_priv: DRM file info * - * LOCKING: - * Takes mode config lock. - * * Return an plane count and set of IDs. */ int drm_mode_getplane_res(struct drm_device *dev, void *data, @@ -1554,7 +1777,7 @@ int drm_mode_getplane_res(struct drm_device *dev, void *data, if (!drm_core_check_feature(dev, DRIVER_MODESET)) return -EINVAL; - mutex_lock(&dev->mode_config.mutex); + drm_modeset_lock_all(dev); config = &dev->mode_config; /* @@ -1576,7 +1799,7 @@ int drm_mode_getplane_res(struct drm_device *dev, void *data, plane_resp->count_planes = config->num_plane; out: - mutex_unlock(&dev->mode_config.mutex); + drm_modeset_unlock_all(dev); return ret; } @@ -1586,9 +1809,6 @@ out: * @data: ioctl data * @file_priv: DRM file info * - * LOCKING: - * Takes mode config lock. - * * Return plane info, including formats supported, gamma size, any * current fb, etc. */ @@ -1604,7 +1824,7 @@ int drm_mode_getplane(struct drm_device *dev, void *data, if (!drm_core_check_feature(dev, DRIVER_MODESET)) return -EINVAL; - mutex_lock(&dev->mode_config.mutex); + drm_modeset_lock_all(dev); obj = drm_mode_object_find(dev, plane_resp->plane_id, DRM_MODE_OBJECT_PLANE); if (!obj) { @@ -1644,7 +1864,7 @@ int drm_mode_getplane(struct drm_device *dev, void *data, plane_resp->count_format_types = plane->format_count; out: - mutex_unlock(&dev->mode_config.mutex); + drm_modeset_unlock_all(dev); return ret; } @@ -1652,10 +1872,7 @@ out: * drm_mode_setplane - set up or tear down an plane * @dev: DRM device * @data: ioctl data* - * @file_prive: DRM file info - * - * LOCKING: - * Takes mode config lock. + * @file_priv: DRM file info * * Set plane info, including placement, fb, scaling, and other factors. * Or pass a NULL fb to disable. @@ -1667,7 +1884,7 @@ int drm_mode_setplane(struct drm_device *dev, void *data, struct drm_mode_object *obj; struct drm_plane *plane; struct drm_crtc *crtc; - struct drm_framebuffer *fb; + struct drm_framebuffer *fb = NULL, *old_fb = NULL; int ret = 0; unsigned int fb_width, fb_height; int i; @@ -1675,8 +1892,6 @@ int drm_mode_setplane(struct drm_device *dev, void *data, if (!drm_core_check_feature(dev, DRIVER_MODESET)) return -EINVAL; - mutex_lock(&dev->mode_config.mutex); - /* * First, find the plane, crtc, and fb objects. If not available, * we don't bother to call the driver. @@ -1686,16 +1901,18 @@ int drm_mode_setplane(struct drm_device *dev, void *data, if (!obj) { DRM_DEBUG_KMS("Unknown plane ID %d\n", plane_req->plane_id); - ret = -ENOENT; - goto out; + return -ENOENT; } plane = obj_to_plane(obj); /* No fb means shut it down */ if (!plane_req->fb_id) { + drm_modeset_lock_all(dev); + old_fb = plane->fb; plane->funcs->disable_plane(plane); plane->crtc = NULL; plane->fb = NULL; + drm_modeset_unlock_all(dev); goto out; } @@ -1709,15 +1926,13 @@ int drm_mode_setplane(struct drm_device *dev, void *data, } crtc = obj_to_crtc(obj); - obj = drm_mode_object_find(dev, plane_req->fb_id, - DRM_MODE_OBJECT_FB); - if (!obj) { + fb = drm_framebuffer_lookup(dev, plane_req->fb_id); + if (!fb) { DRM_DEBUG_KMS("Unknown framebuffer ID %d\n", plane_req->fb_id); ret = -ENOENT; goto out; } - fb = obj_to_fb(obj); /* Check whether this plane supports the fb pixel format. */ for (i = 0; i < plane->format_count; i++) @@ -1763,31 +1978,64 @@ int drm_mode_setplane(struct drm_device *dev, void *data, goto out; } + drm_modeset_lock_all(dev); ret = plane->funcs->update_plane(plane, crtc, fb, plane_req->crtc_x, plane_req->crtc_y, plane_req->crtc_w, plane_req->crtc_h, plane_req->src_x, plane_req->src_y, plane_req->src_w, plane_req->src_h); if (!ret) { + old_fb = plane->fb; plane->crtc = crtc; plane->fb = fb; + fb = NULL; } + drm_modeset_unlock_all(dev); out: - mutex_unlock(&dev->mode_config.mutex); + if (fb) + drm_framebuffer_unreference(fb); + if (old_fb) + drm_framebuffer_unreference(old_fb); return ret; } +#endif /** - * drm_mode_setcrtc - set CRTC configuration - * @inode: inode from the ioctl - * @filp: file * from the ioctl - * @cmd: cmd from ioctl - * @arg: arg from ioctl + * drm_mode_set_config_internal - helper to call ->set_config + * @set: modeset config to set * - * LOCKING: - * Takes mode config lock. + * This is a little helper to wrap internal calls to the ->set_config driver + * interface. The only thing it adds is correct refcounting dance. + */ +int drm_mode_set_config_internal(struct drm_mode_set *set) +{ + struct drm_crtc *crtc = set->crtc; + struct drm_framebuffer *fb, *old_fb; + int ret; + + old_fb = crtc->fb; + fb = set->fb; + + ret = crtc->funcs->set_config(set); + if (ret == 0) { + if (old_fb) + drm_framebuffer_unreference(old_fb); + if (fb) + drm_framebuffer_reference(fb); + } + + return ret; +} +EXPORT_SYMBOL(drm_mode_set_config_internal); + +#if 0 +/** + * drm_mode_setcrtc - set CRTC configuration + * @dev: drm device for the ioctl + * @data: data pointer for the ioctl + * @file_priv: drm file for the ioctl call * * Build a new CRTC configuration based on user request. * @@ -1818,7 +2066,7 @@ int drm_mode_setcrtc(struct drm_device *dev, void *data, if (crtc_req->x > INT_MAX || crtc_req->y > INT_MAX) return -ERANGE; - mutex_lock(&dev->mode_config.mutex); + drm_modeset_lock_all(dev); obj = drm_mode_object_find(dev, crtc_req->crtc_id, DRM_MODE_OBJECT_CRTC); if (!obj) { @@ -1840,16 +2088,16 @@ int drm_mode_setcrtc(struct drm_device *dev, void *data, goto out; } fb = crtc->fb; + /* Make refcounting symmetric with the lookup path. */ + drm_framebuffer_reference(fb); } else { - obj = drm_mode_object_find(dev, crtc_req->fb_id, - DRM_MODE_OBJECT_FB); - if (!obj) { + fb = drm_framebuffer_lookup(dev, crtc_req->fb_id); + if (!fb) { DRM_DEBUG_KMS("Unknown FB ID%d\n", crtc_req->fb_id); ret = -EINVAL; goto out; } - fb = obj_to_fb(obj); } mode = drm_mode_create(dev); @@ -1946,12 +2194,15 @@ int drm_mode_setcrtc(struct drm_device *dev, void *data, set.connectors = connector_set; set.num_connectors = crtc_req->count_connectors; set.fb = fb; - ret = crtc->funcs->set_config(&set); + ret = drm_mode_set_config_internal(&set); out: + if (fb) + drm_framebuffer_unreference(fb); + kfree(connector_set); drm_mode_destroy(dev, mode); - mutex_unlock(&dev->mode_config.mutex); + drm_modeset_unlock_all(dev); return ret; } @@ -1969,15 +2220,14 @@ int drm_mode_cursor_ioctl(struct drm_device *dev, if (!req->flags || (~DRM_MODE_CURSOR_FLAGS & req->flags)) return -EINVAL; - mutex_lock(&dev->mode_config.mutex); obj = drm_mode_object_find(dev, req->crtc_id, DRM_MODE_OBJECT_CRTC); if (!obj) { DRM_DEBUG_KMS("Unknown CRTC ID %d\n", req->crtc_id); - ret = -EINVAL; - goto out; + return -EINVAL; } crtc = obj_to_crtc(obj); + mutex_lock(&crtc->mutex); if (req->flags & DRM_MODE_CURSOR_BO) { if (!crtc->funcs->cursor_set) { ret = -ENXIO; @@ -1997,7 +2247,8 @@ int drm_mode_cursor_ioctl(struct drm_device *dev, } } out: - mutex_unlock(&dev->mode_config.mutex); + mutex_unlock(&crtc->mutex); + return ret; } #endif @@ -2008,7 +2259,7 @@ uint32_t drm_mode_legacy_fb_format(uint32_t bpp, uint32_t depth) switch (bpp) { case 8: - fmt = DRM_FORMAT_RGB332; + fmt = DRM_FORMAT_C8; break; case 16: if (depth == 15) @@ -2039,13 +2290,9 @@ EXPORT_SYMBOL(drm_mode_legacy_fb_format); #if 0 /** * drm_mode_addfb - add an FB to the graphics configuration - * @inode: inode from the ioctl - * @filp: file * from the ioctl - * @cmd: cmd from ioctl - * @arg: arg from ioctl - * - * LOCKING: - * Takes mode config lock. + * @dev: drm device for the ioctl + * @data: data pointer for the ioctl + * @file_priv: drm file for the ioctl call * * Add a new FB to the specified CRTC, given a user request. * @@ -2080,24 +2327,18 @@ int drm_mode_addfb(struct drm_device *dev, if ((config->min_height > r.height) || (r.height > config->max_height)) return -EINVAL; - mutex_lock(&dev->mode_config.mutex); - - /* TODO check buffer is sufficiently large */ - /* TODO setup destructor callback */ - fb = dev->mode_config.funcs->fb_create(dev, file_priv, &r); if (IS_ERR(fb)) { DRM_DEBUG_KMS("could not create framebuffer\n"); - ret = PTR_ERR(fb); - goto out; + return PTR_ERR(fb); } + mutex_lock(&file_priv->fbs_lock); or->fb_id = fb->base.id; list_add(&fb->filp_head, &file_priv->fbs); DRM_DEBUG_KMS("[FB:%d]\n", fb->base.id); + mutex_unlock(&file_priv->fbs_lock); -out: - mutex_unlock(&dev->mode_config.mutex); return ret; } @@ -2223,13 +2464,9 @@ static int framebuffer_check(const struct drm_mode_fb_cmd2 *r) /** * drm_mode_addfb2 - add an FB to the graphics configuration - * @inode: inode from the ioctl - * @filp: file * from the ioctl - * @cmd: cmd from ioctl - * @arg: arg from ioctl - * - * LOCKING: - * Takes mode config lock. + * @dev: drm device for the ioctl + * @data: data pointer for the ioctl + * @file_priv: drm file for the ioctl call * * Add a new FB to the specified CRTC, given a user request with format. * @@ -2269,33 +2506,27 @@ int drm_mode_addfb2(struct drm_device *dev, if (ret) return ret; - mutex_lock(&dev->mode_config.mutex); - fb = dev->mode_config.funcs->fb_create(dev, file_priv, r); if (IS_ERR(fb)) { DRM_DEBUG_KMS("could not create framebuffer\n"); - ret = PTR_ERR(fb); - goto out; + return PTR_ERR(fb); } + mutex_lock(&file_priv->fbs_lock); r->fb_id = fb->base.id; list_add(&fb->filp_head, &file_priv->fbs); DRM_DEBUG_KMS("[FB:%d]\n", fb->base.id); + mutex_unlock(&file_priv->fbs_lock); + -out: - mutex_unlock(&dev->mode_config.mutex); return ret; } /** * drm_mode_rmfb - remove an FB from the configuration - * @inode: inode from the ioctl - * @filp: file * from the ioctl - * @cmd: cmd from ioctl - * @arg: arg from ioctl - * - * LOCKING: - * Takes mode config lock. + * @dev: drm device for the ioctl + * @data: data pointer for the ioctl + * @file_priv: drm file for the ioctl call * * Remove the FB specified by the user. * @@ -2307,50 +2538,49 @@ out: int drm_mode_rmfb(struct drm_device *dev, void *data, struct drm_file *file_priv) { - struct drm_mode_object *obj; struct drm_framebuffer *fb = NULL; struct drm_framebuffer *fbl = NULL; uint32_t *id = data; - int ret = 0; int found = 0; if (!drm_core_check_feature(dev, DRIVER_MODESET)) return -EINVAL; - mutex_lock(&dev->mode_config.mutex); - obj = drm_mode_object_find(dev, *id, DRM_MODE_OBJECT_FB); - /* TODO check that we really get a framebuffer back. */ - if (!obj) { - ret = -EINVAL; - goto out; - } - fb = obj_to_fb(obj); + mutex_lock(&file_priv->fbs_lock); + mutex_lock(&dev->mode_config.fb_lock); + fb = __drm_framebuffer_lookup(dev, *id); + if (!fb) + goto fail_lookup; list_for_each_entry(fbl, &file_priv->fbs, filp_head) if (fb == fbl) found = 1; + if (!found) + goto fail_lookup; - if (!found) { - ret = -EINVAL; - goto out; - } + /* Mark fb as reaped, we still have a ref from fpriv->fbs. */ + __drm_framebuffer_unregister(dev, fb); + + list_del_init(&fb->filp_head); + mutex_unlock(&dev->mode_config.fb_lock); + mutex_unlock(&file_priv->fbs_lock); drm_framebuffer_remove(fb); -out: - mutex_unlock(&dev->mode_config.mutex); - return ret; + return 0; + +fail_lookup: + mutex_unlock(&dev->mode_config.fb_lock); + mutex_unlock(&file_priv->fbs_lock); + + return -EINVAL; } /** * drm_mode_getfb - get FB info - * @inode: inode from the ioctl - * @filp: file * from the ioctl - * @cmd: cmd from ioctl - * @arg: arg from ioctl - * - * LOCKING: - * Takes mode config lock. + * @dev: drm device for the ioctl + * @data: data pointer for the ioctl + * @file_priv: drm file for the ioctl call * * Lookup the FB given its ID and return info about it. * @@ -2363,30 +2593,28 @@ int drm_mode_getfb(struct drm_device *dev, void *data, struct drm_file *file_priv) { struct drm_mode_fb_cmd *r = data; - struct drm_mode_object *obj; struct drm_framebuffer *fb; - int ret = 0; + int ret; if (!drm_core_check_feature(dev, DRIVER_MODESET)) return -EINVAL; - mutex_lock(&dev->mode_config.mutex); - obj = drm_mode_object_find(dev, r->fb_id, DRM_MODE_OBJECT_FB); - if (!obj) { - ret = -EINVAL; - goto out; - } - fb = obj_to_fb(obj); + fb = drm_framebuffer_lookup(dev, r->fb_id); + if (!fb) + return -EINVAL; r->height = fb->height; r->width = fb->width; r->depth = fb->depth; r->bpp = fb->bits_per_pixel; r->pitch = fb->pitches[0]; - fb->funcs->create_handle(fb, file_priv, &r->handle); + if (fb->funcs->create_handle) + ret = fb->funcs->create_handle(fb, file_priv, &r->handle); + else + ret = -ENODEV; + + drm_framebuffer_unreference(fb); -out: - mutex_unlock(&dev->mode_config.mutex); return ret; } @@ -2396,7 +2624,6 @@ int drm_mode_dirtyfb_ioctl(struct drm_device *dev, struct drm_clip_rect __user *clips_ptr; struct drm_clip_rect *clips = NULL; struct drm_mode_fb_dirty_cmd *r = data; - struct drm_mode_object *obj; struct drm_framebuffer *fb; unsigned flags; int num_clips; @@ -2405,13 +2632,9 @@ int drm_mode_dirtyfb_ioctl(struct drm_device *dev, if (!drm_core_check_feature(dev, DRIVER_MODESET)) return -EINVAL; - mutex_lock(&dev->mode_config.mutex); - obj = drm_mode_object_find(dev, r->fb_id, DRM_MODE_OBJECT_FB); - if (!obj) { - ret = -EINVAL; - goto out_err1; - } - fb = obj_to_fb(obj); + fb = drm_framebuffer_lookup(dev, r->fb_id); + if (!fb) + return -EINVAL; num_clips = r->num_clips; clips_ptr = (struct drm_clip_rect __user *)(unsigned long)r->clips_ptr; @@ -2449,27 +2672,26 @@ int drm_mode_dirtyfb_ioctl(struct drm_device *dev, } if (fb->funcs->dirty) { + drm_modeset_lock_all(dev); ret = fb->funcs->dirty(fb, file_priv, flags, r->color, clips, num_clips); + drm_modeset_unlock_all(dev); } else { ret = -ENOSYS; - goto out_err2; } out_err2: kfree(clips); out_err1: - mutex_unlock(&dev->mode_config.mutex); + drm_framebuffer_unreference(fb); + return ret; } /** * drm_fb_release - remove and free the FBs on this file - * @filp: file * from the ioctl - * - * LOCKING: - * Takes mode config lock. + * @priv: drm file for the ioctl * * Destroy all the FBs associated with @filp. * @@ -2483,11 +2705,20 @@ void drm_fb_release(struct drm_file *priv) struct drm_device *dev = priv->minor->dev; struct drm_framebuffer *fb, *tfb; - mutex_lock(&dev->mode_config.mutex); + mutex_lock(&priv->fbs_lock); list_for_each_entry_safe(fb, tfb, &priv->fbs, filp_head) { + + mutex_lock(&dev->mode_config.fb_lock); + /* Mark fb as reaped, we still have a ref from fpriv->fbs. */ + __drm_framebuffer_unregister(dev, fb); + mutex_unlock(&dev->mode_config.fb_lock); + + list_del_init(&fb->filp_head); + + /* This will also drop the fpriv->fbs reference. */ drm_framebuffer_remove(fb); } - mutex_unlock(&dev->mode_config.mutex); + mutex_unlock(&priv->fbs_lock); } #endif @@ -2582,10 +2813,9 @@ EXPORT_SYMBOL(drm_mode_detachmode_crtc); /** * drm_fb_attachmode - Attach a user mode to an connector - * @inode: inode from the ioctl - * @filp: file * from the ioctl - * @cmd: cmd from ioctl - * @arg: arg from ioctl + * @dev: drm device for the ioctl + * @data: data pointer for the ioctl + * @file_priv: drm file for the ioctl call * * This attaches a user specified mode to an connector. * Called by the user via ioctl. @@ -2606,7 +2836,7 @@ int drm_mode_attachmode_ioctl(struct drm_device *dev, if (!drm_core_check_feature(dev, DRIVER_MODESET)) return -EINVAL; - mutex_lock(&dev->mode_config.mutex); + drm_modeset_lock_all(dev); obj = drm_mode_object_find(dev, mode_cmd->connector_id, DRM_MODE_OBJECT_CONNECTOR); if (!obj) { @@ -2630,17 +2860,16 @@ int drm_mode_attachmode_ioctl(struct drm_device *dev, drm_mode_attachmode(dev, connector, mode); out: - mutex_unlock(&dev->mode_config.mutex); + drm_modeset_unlock_all(dev); return ret; } /** * drm_fb_detachmode - Detach a user specified mode from an connector - * @inode: inode from the ioctl - * @filp: file * from the ioctl - * @cmd: cmd from ioctl - * @arg: arg from ioctl + * @dev: drm device for the ioctl + * @data: data pointer for the ioctl + * @file_priv: drm file for the ioctl call * * Called by the user via ioctl. * @@ -2660,7 +2889,7 @@ int drm_mode_detachmode_ioctl(struct drm_device *dev, if (!drm_core_check_feature(dev, DRIVER_MODESET)) return -EINVAL; - mutex_lock(&dev->mode_config.mutex); + drm_modeset_lock_all(dev); obj = drm_mode_object_find(dev, mode_cmd->connector_id, DRM_MODE_OBJECT_CONNECTOR); if (!obj) { @@ -2677,7 +2906,7 @@ int drm_mode_detachmode_ioctl(struct drm_device *dev, ret = drm_mode_detachmode(dev, connector, &mode); out: - mutex_unlock(&dev->mode_config.mutex); + drm_modeset_unlock_all(dev); return ret; } #endif @@ -2925,7 +3154,7 @@ int drm_mode_getproperty_ioctl(struct drm_device *dev, if (!drm_core_check_feature(dev, DRIVER_MODESET)) return -EINVAL; - mutex_lock(&dev->mode_config.mutex); + drm_modeset_lock_all(dev); obj = drm_mode_object_find(dev, out_resp->prop_id, DRM_MODE_OBJECT_PROPERTY); if (!obj) { ret = -EINVAL; @@ -3003,7 +3232,7 @@ int drm_mode_getproperty_ioctl(struct drm_device *dev, out_resp->count_enum_blobs = blob_count; } done: - mutex_unlock(&dev->mode_config.mutex); + drm_modeset_unlock_all(dev); return ret; } #endif @@ -3056,7 +3285,7 @@ int drm_mode_getblob_ioctl(struct drm_device *dev, if (!drm_core_check_feature(dev, DRIVER_MODESET)) return -EINVAL; - mutex_lock(&dev->mode_config.mutex); + drm_modeset_lock_all(dev); obj = drm_mode_object_find(dev, out_resp->blob_id, DRM_MODE_OBJECT_BLOB); if (!obj) { ret = -EINVAL; @@ -3074,7 +3303,7 @@ int drm_mode_getblob_ioctl(struct drm_device *dev, out_resp->length = blob->length; done: - mutex_unlock(&dev->mode_config.mutex); + drm_modeset_unlock_all(dev); return ret; } #endif @@ -3177,7 +3406,7 @@ int drm_mode_obj_get_properties_ioctl(struct drm_device *dev, void *data, if (!drm_core_check_feature(dev, DRIVER_MODESET)) return -EINVAL; - mutex_lock(&dev->mode_config.mutex); + drm_modeset_lock_all(dev); obj = drm_mode_object_find(dev, arg->obj_id, arg->obj_type); if (!obj) { @@ -3214,7 +3443,7 @@ int drm_mode_obj_get_properties_ioctl(struct drm_device *dev, void *data, } arg->count_props = props_count; out: - mutex_unlock(&dev->mode_config.mutex); + drm_modeset_unlock_all(dev); return ret; } @@ -3231,7 +3460,7 @@ int drm_mode_obj_set_property_ioctl(struct drm_device *dev, void *data, if (!drm_core_check_feature(dev, DRIVER_MODESET)) return -EINVAL; - mutex_lock(&dev->mode_config.mutex); + drm_modeset_lock_all(dev); arg_obj = drm_mode_object_find(dev, arg->obj_id, arg->obj_type); if (!arg_obj) @@ -3269,7 +3498,7 @@ int drm_mode_obj_set_property_ioctl(struct drm_device *dev, void *data, } out: - mutex_unlock(&dev->mode_config.mutex); + drm_modeset_unlock_all(dev); return ret; } #endif @@ -3333,7 +3562,7 @@ int drm_mode_gamma_set_ioctl(struct drm_device *dev, if (!drm_core_check_feature(dev, DRIVER_MODESET)) return -EINVAL; - mutex_lock(&dev->mode_config.mutex); + drm_modeset_lock_all(dev); obj = drm_mode_object_find(dev, crtc_lut->crtc_id, DRM_MODE_OBJECT_CRTC); if (!obj) { ret = -EINVAL; @@ -3374,7 +3603,7 @@ int drm_mode_gamma_set_ioctl(struct drm_device *dev, crtc->funcs->gamma_set(crtc, r_base, g_base, b_base, 0, crtc->gamma_size); out: - mutex_unlock(&dev->mode_config.mutex); + drm_modeset_unlock_all(dev); return ret; } @@ -3392,7 +3621,7 @@ int drm_mode_gamma_get_ioctl(struct drm_device *dev, if (!drm_core_check_feature(dev, DRIVER_MODESET)) return -EINVAL; - mutex_lock(&dev->mode_config.mutex); + drm_modeset_lock_all(dev); obj = drm_mode_object_find(dev, crtc_lut->crtc_id, DRM_MODE_OBJECT_CRTC); if (!obj) { ret = -EINVAL; @@ -3425,7 +3654,7 @@ int drm_mode_gamma_get_ioctl(struct drm_device *dev, goto out; } out: - mutex_unlock(&dev->mode_config.mutex); + drm_modeset_unlock_all(dev); return ret; } @@ -3462,6 +3691,7 @@ void drm_fb_get_bpp_depth(uint32_t format, unsigned int *depth, int *bpp) { switch (format) { + case DRM_FORMAT_C8: case DRM_FORMAT_RGB332: case DRM_FORMAT_BGR233: *depth = 8; diff --git a/drivers/video/drm/drm_crtc_helper.c b/drivers/video/drm/drm_crtc_helper.c index f32988a2bd..49295d8913 100644 --- a/drivers/video/drm/drm_crtc_helper.c +++ b/drivers/video/drm/drm_crtc_helper.c @@ -69,6 +69,7 @@ void drm_helper_move_panel_connectors_to_head(struct drm_device *dev) EXPORT_SYMBOL(drm_helper_move_panel_connectors_to_head); static bool drm_kms_helper_poll = true; +module_param_named(poll, drm_kms_helper_poll, bool, 0600); static void drm_mode_validate_flag(struct drm_connector *connector, int flags) @@ -141,6 +142,12 @@ int drm_helper_probe_single_connector_modes(struct drm_connector *connector, // dbgprintf("status %x\n", connector->status); } + /* Re-enable polling in case the global poll config changed. */ + if (drm_kms_helper_poll != dev->mode_config.poll_running) + drm_kms_helper_poll_enable(dev); + + dev->mode_config.poll_running = drm_kms_helper_poll; + if (connector->status == connector_status_disconnected) { DRM_DEBUG_KMS("[CONNECTOR:%d:%s] disconnected\n", connector->base.id, drm_get_connector_name(connector)); @@ -955,7 +962,13 @@ int drm_helper_resume_force_mode(struct drm_device *dev) } EXPORT_SYMBOL(drm_helper_resume_force_mode); -#if 0 +void drm_kms_helper_hotplug_event(struct drm_device *dev) +{ + /* send a uevent + call fbdev */ + if (dev->mode_config.funcs->output_poll_changed) + dev->mode_config.funcs->output_poll_changed(dev); +} +EXPORT_SYMBOL(drm_kms_helper_hotplug_event); #define DRM_OUTPUT_POLL_PERIOD (10*HZ) static void output_poll_execute(struct work_struct *work) @@ -1004,15 +1017,15 @@ static void output_poll_execute(struct work_struct *work) if (changed) drm_kms_helper_hotplug_event(dev); - if (repoll) - schedule_delayed_work(delayed_work, DRM_OUTPUT_POLL_PERIOD); +// if (repoll) +// schedule_delayed_work(delayed_work, DRM_OUTPUT_POLL_PERIOD); } void drm_kms_helper_poll_disable(struct drm_device *dev) { if (!dev->mode_config.poll_enabled) return; - cancel_delayed_work_sync(&dev->mode_config.output_poll_work); +// cancel_delayed_work_sync(&dev->mode_config.output_poll_work); } EXPORT_SYMBOL(drm_kms_helper_poll_disable); @@ -1030,8 +1043,8 @@ void drm_kms_helper_poll_enable(struct drm_device *dev) poll = true; } - if (poll) - schedule_delayed_work(&dev->mode_config.output_poll_work, DRM_OUTPUT_POLL_PERIOD); +// if (poll) +// schedule_delayed_work(&dev->mode_config.output_poll_work, DRM_OUTPUT_POLL_PERIOD); } EXPORT_SYMBOL(drm_kms_helper_poll_enable); @@ -1083,5 +1096,3 @@ void drm_helper_hpd_irq_event(struct drm_device *dev) drm_kms_helper_hotplug_event(dev); } EXPORT_SYMBOL(drm_helper_hpd_irq_event); - -#endif diff --git a/drivers/video/drm/drm_edid.c b/drivers/video/drm/drm_edid.c index e8bc36bfce..47bd94c323 100644 --- a/drivers/video/drm/drm_edid.c +++ b/drivers/video/drm/drm_edid.c @@ -29,11 +29,11 @@ */ #include #include +#include #include #include #include #include -#include "drm_edid_modes.h" #define version_greater(edid, maj, min) \ (((edid)->version > (maj)) || \ @@ -87,9 +87,6 @@ static struct edid_quirk { int product_id; u32 quirks; } edid_quirk_list[] = { - /* ASUS VW222S */ - { "ACI", 0x22a2, EDID_QUIRK_FORCE_REDUCED_BLANKING }, - /* Acer AL1706 */ { "ACR", 44358, EDID_QUIRK_PREFER_LARGE_60 }, /* Acer F51 */ @@ -130,6 +127,746 @@ static struct edid_quirk { { "VSC", 5020, EDID_QUIRK_FORCE_REDUCED_BLANKING }, }; +/* + * Autogenerated from the DMT spec. + * This table is copied from xfree86/modes/xf86EdidModes.c. + */ +static const struct drm_display_mode drm_dmt_modes[] = { + /* 640x350@85Hz */ + { DRM_MODE("640x350", DRM_MODE_TYPE_DRIVER, 31500, 640, 672, + 736, 832, 0, 350, 382, 385, 445, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC) }, + /* 640x400@85Hz */ + { DRM_MODE("640x400", DRM_MODE_TYPE_DRIVER, 31500, 640, 672, + 736, 832, 0, 400, 401, 404, 445, 0, + DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) }, + /* 720x400@85Hz */ + { DRM_MODE("720x400", DRM_MODE_TYPE_DRIVER, 35500, 720, 756, + 828, 936, 0, 400, 401, 404, 446, 0, + DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) }, + /* 640x480@60Hz */ + { DRM_MODE("640x480", DRM_MODE_TYPE_DRIVER, 25175, 640, 656, + 752, 800, 0, 480, 489, 492, 525, 0, + DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, + /* 640x480@72Hz */ + { DRM_MODE("640x480", DRM_MODE_TYPE_DRIVER, 31500, 640, 664, + 704, 832, 0, 480, 489, 492, 520, 0, + DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, + /* 640x480@75Hz */ + { DRM_MODE("640x480", DRM_MODE_TYPE_DRIVER, 31500, 640, 656, + 720, 840, 0, 480, 481, 484, 500, 0, + DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, + /* 640x480@85Hz */ + { DRM_MODE("640x480", DRM_MODE_TYPE_DRIVER, 36000, 640, 696, + 752, 832, 0, 480, 481, 484, 509, 0, + DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, + /* 800x600@56Hz */ + { DRM_MODE("800x600", DRM_MODE_TYPE_DRIVER, 36000, 800, 824, + 896, 1024, 0, 600, 601, 603, 625, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, + /* 800x600@60Hz */ + { DRM_MODE("800x600", DRM_MODE_TYPE_DRIVER, 40000, 800, 840, + 968, 1056, 0, 600, 601, 605, 628, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, + /* 800x600@72Hz */ + { DRM_MODE("800x600", DRM_MODE_TYPE_DRIVER, 50000, 800, 856, + 976, 1040, 0, 600, 637, 643, 666, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, + /* 800x600@75Hz */ + { DRM_MODE("800x600", DRM_MODE_TYPE_DRIVER, 49500, 800, 816, + 896, 1056, 0, 600, 601, 604, 625, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, + /* 800x600@85Hz */ + { DRM_MODE("800x600", DRM_MODE_TYPE_DRIVER, 56250, 800, 832, + 896, 1048, 0, 600, 601, 604, 631, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, + /* 800x600@120Hz RB */ + { DRM_MODE("800x600", DRM_MODE_TYPE_DRIVER, 73250, 800, 848, + 880, 960, 0, 600, 603, 607, 636, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC) }, + /* 848x480@60Hz */ + { DRM_MODE("848x480", DRM_MODE_TYPE_DRIVER, 33750, 848, 864, + 976, 1088, 0, 480, 486, 494, 517, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, + /* 1024x768@43Hz, interlace */ + { DRM_MODE("1024x768i", DRM_MODE_TYPE_DRIVER, 44900, 1024, 1032, + 1208, 1264, 0, 768, 768, 772, 817, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC | + DRM_MODE_FLAG_INTERLACE) }, + /* 1024x768@60Hz */ + { DRM_MODE("1024x768", DRM_MODE_TYPE_DRIVER, 65000, 1024, 1048, + 1184, 1344, 0, 768, 771, 777, 806, 0, + DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, + /* 1024x768@70Hz */ + { DRM_MODE("1024x768", DRM_MODE_TYPE_DRIVER, 75000, 1024, 1048, + 1184, 1328, 0, 768, 771, 777, 806, 0, + DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, + /* 1024x768@75Hz */ + { DRM_MODE("1024x768", DRM_MODE_TYPE_DRIVER, 78750, 1024, 1040, + 1136, 1312, 0, 768, 769, 772, 800, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, + /* 1024x768@85Hz */ + { DRM_MODE("1024x768", DRM_MODE_TYPE_DRIVER, 94500, 1024, 1072, + 1168, 1376, 0, 768, 769, 772, 808, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, + /* 1024x768@120Hz RB */ + { DRM_MODE("1024x768", DRM_MODE_TYPE_DRIVER, 115500, 1024, 1072, + 1104, 1184, 0, 768, 771, 775, 813, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC) }, + /* 1152x864@75Hz */ + { DRM_MODE("1152x864", DRM_MODE_TYPE_DRIVER, 108000, 1152, 1216, + 1344, 1600, 0, 864, 865, 868, 900, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, + /* 1280x768@60Hz RB */ + { DRM_MODE("1280x768", DRM_MODE_TYPE_DRIVER, 68250, 1280, 1328, + 1360, 1440, 0, 768, 771, 778, 790, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC) }, + /* 1280x768@60Hz */ + { DRM_MODE("1280x768", DRM_MODE_TYPE_DRIVER, 79500, 1280, 1344, + 1472, 1664, 0, 768, 771, 778, 798, 0, + DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) }, + /* 1280x768@75Hz */ + { DRM_MODE("1280x768", DRM_MODE_TYPE_DRIVER, 102250, 1280, 1360, + 1488, 1696, 0, 768, 771, 778, 805, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC) }, + /* 1280x768@85Hz */ + { DRM_MODE("1280x768", DRM_MODE_TYPE_DRIVER, 117500, 1280, 1360, + 1496, 1712, 0, 768, 771, 778, 809, 0, + DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) }, + /* 1280x768@120Hz RB */ + { DRM_MODE("1280x768", DRM_MODE_TYPE_DRIVER, 140250, 1280, 1328, + 1360, 1440, 0, 768, 771, 778, 813, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC) }, + /* 1280x800@60Hz RB */ + { DRM_MODE("1280x800", DRM_MODE_TYPE_DRIVER, 71000, 1280, 1328, + 1360, 1440, 0, 800, 803, 809, 823, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC) }, + /* 1280x800@60Hz */ + { DRM_MODE("1280x800", DRM_MODE_TYPE_DRIVER, 83500, 1280, 1352, + 1480, 1680, 0, 800, 803, 809, 831, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC) }, + /* 1280x800@75Hz */ + { DRM_MODE("1280x800", DRM_MODE_TYPE_DRIVER, 106500, 1280, 1360, + 1488, 1696, 0, 800, 803, 809, 838, 0, + DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) }, + /* 1280x800@85Hz */ + { DRM_MODE("1280x800", DRM_MODE_TYPE_DRIVER, 122500, 1280, 1360, + 1496, 1712, 0, 800, 803, 809, 843, 0, + DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) }, + /* 1280x800@120Hz RB */ + { DRM_MODE("1280x800", DRM_MODE_TYPE_DRIVER, 146250, 1280, 1328, + 1360, 1440, 0, 800, 803, 809, 847, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC) }, + /* 1280x960@60Hz */ + { DRM_MODE("1280x960", DRM_MODE_TYPE_DRIVER, 108000, 1280, 1376, + 1488, 1800, 0, 960, 961, 964, 1000, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, + /* 1280x960@85Hz */ + { DRM_MODE("1280x960", DRM_MODE_TYPE_DRIVER, 148500, 1280, 1344, + 1504, 1728, 0, 960, 961, 964, 1011, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, + /* 1280x960@120Hz RB */ + { DRM_MODE("1280x960", DRM_MODE_TYPE_DRIVER, 175500, 1280, 1328, + 1360, 1440, 0, 960, 963, 967, 1017, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC) }, + /* 1280x1024@60Hz */ + { DRM_MODE("1280x1024", DRM_MODE_TYPE_DRIVER, 108000, 1280, 1328, + 1440, 1688, 0, 1024, 1025, 1028, 1066, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, + /* 1280x1024@75Hz */ + { DRM_MODE("1280x1024", DRM_MODE_TYPE_DRIVER, 135000, 1280, 1296, + 1440, 1688, 0, 1024, 1025, 1028, 1066, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, + /* 1280x1024@85Hz */ + { DRM_MODE("1280x1024", DRM_MODE_TYPE_DRIVER, 157500, 1280, 1344, + 1504, 1728, 0, 1024, 1025, 1028, 1072, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, + /* 1280x1024@120Hz RB */ + { DRM_MODE("1280x1024", DRM_MODE_TYPE_DRIVER, 187250, 1280, 1328, + 1360, 1440, 0, 1024, 1027, 1034, 1084, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC) }, + /* 1360x768@60Hz */ + { DRM_MODE("1360x768", DRM_MODE_TYPE_DRIVER, 85500, 1360, 1424, + 1536, 1792, 0, 768, 771, 777, 795, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, + /* 1360x768@120Hz RB */ + { DRM_MODE("1360x768", DRM_MODE_TYPE_DRIVER, 148250, 1360, 1408, + 1440, 1520, 0, 768, 771, 776, 813, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC) }, + /* 1400x1050@60Hz RB */ + { DRM_MODE("1400x1050", DRM_MODE_TYPE_DRIVER, 101000, 1400, 1448, + 1480, 1560, 0, 1050, 1053, 1057, 1080, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC) }, + /* 1400x1050@60Hz */ + { DRM_MODE("1400x1050", DRM_MODE_TYPE_DRIVER, 121750, 1400, 1488, + 1632, 1864, 0, 1050, 1053, 1057, 1089, 0, + DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) }, + /* 1400x1050@75Hz */ + { DRM_MODE("1400x1050", DRM_MODE_TYPE_DRIVER, 156000, 1400, 1504, + 1648, 1896, 0, 1050, 1053, 1057, 1099, 0, + DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) }, + /* 1400x1050@85Hz */ + { DRM_MODE("1400x1050", DRM_MODE_TYPE_DRIVER, 179500, 1400, 1504, + 1656, 1912, 0, 1050, 1053, 1057, 1105, 0, + DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) }, + /* 1400x1050@120Hz RB */ + { DRM_MODE("1400x1050", DRM_MODE_TYPE_DRIVER, 208000, 1400, 1448, + 1480, 1560, 0, 1050, 1053, 1057, 1112, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC) }, + /* 1440x900@60Hz RB */ + { DRM_MODE("1440x900", DRM_MODE_TYPE_DRIVER, 88750, 1440, 1488, + 1520, 1600, 0, 900, 903, 909, 926, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC) }, + /* 1440x900@60Hz */ + { DRM_MODE("1440x900", DRM_MODE_TYPE_DRIVER, 106500, 1440, 1520, + 1672, 1904, 0, 900, 903, 909, 934, 0, + DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) }, + /* 1440x900@75Hz */ + { DRM_MODE("1440x900", DRM_MODE_TYPE_DRIVER, 136750, 1440, 1536, + 1688, 1936, 0, 900, 903, 909, 942, 0, + DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) }, + /* 1440x900@85Hz */ + { DRM_MODE("1440x900", DRM_MODE_TYPE_DRIVER, 157000, 1440, 1544, + 1696, 1952, 0, 900, 903, 909, 948, 0, + DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) }, + /* 1440x900@120Hz RB */ + { DRM_MODE("1440x900", DRM_MODE_TYPE_DRIVER, 182750, 1440, 1488, + 1520, 1600, 0, 900, 903, 909, 953, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC) }, + /* 1600x1200@60Hz */ + { DRM_MODE("1600x1200", DRM_MODE_TYPE_DRIVER, 162000, 1600, 1664, + 1856, 2160, 0, 1200, 1201, 1204, 1250, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, + /* 1600x1200@65Hz */ + { DRM_MODE("1600x1200", DRM_MODE_TYPE_DRIVER, 175500, 1600, 1664, + 1856, 2160, 0, 1200, 1201, 1204, 1250, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, + /* 1600x1200@70Hz */ + { DRM_MODE("1600x1200", DRM_MODE_TYPE_DRIVER, 189000, 1600, 1664, + 1856, 2160, 0, 1200, 1201, 1204, 1250, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, + /* 1600x1200@75Hz */ + { DRM_MODE("1600x1200", DRM_MODE_TYPE_DRIVER, 202500, 1600, 1664, + 1856, 2160, 0, 1200, 1201, 1204, 1250, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, + /* 1600x1200@85Hz */ + { DRM_MODE("1600x1200", DRM_MODE_TYPE_DRIVER, 229500, 1600, 1664, + 1856, 2160, 0, 1200, 1201, 1204, 1250, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, + /* 1600x1200@120Hz RB */ + { DRM_MODE("1600x1200", DRM_MODE_TYPE_DRIVER, 268250, 1600, 1648, + 1680, 1760, 0, 1200, 1203, 1207, 1271, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC) }, + /* 1680x1050@60Hz RB */ + { DRM_MODE("1680x1050", DRM_MODE_TYPE_DRIVER, 119000, 1680, 1728, + 1760, 1840, 0, 1050, 1053, 1059, 1080, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC) }, + /* 1680x1050@60Hz */ + { DRM_MODE("1680x1050", DRM_MODE_TYPE_DRIVER, 146250, 1680, 1784, + 1960, 2240, 0, 1050, 1053, 1059, 1089, 0, + DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) }, + /* 1680x1050@75Hz */ + { DRM_MODE("1680x1050", DRM_MODE_TYPE_DRIVER, 187000, 1680, 1800, + 1976, 2272, 0, 1050, 1053, 1059, 1099, 0, + DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) }, + /* 1680x1050@85Hz */ + { DRM_MODE("1680x1050", DRM_MODE_TYPE_DRIVER, 214750, 1680, 1808, + 1984, 2288, 0, 1050, 1053, 1059, 1105, 0, + DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) }, + /* 1680x1050@120Hz RB */ + { DRM_MODE("1680x1050", DRM_MODE_TYPE_DRIVER, 245500, 1680, 1728, + 1760, 1840, 0, 1050, 1053, 1059, 1112, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC) }, + /* 1792x1344@60Hz */ + { DRM_MODE("1792x1344", DRM_MODE_TYPE_DRIVER, 204750, 1792, 1920, + 2120, 2448, 0, 1344, 1345, 1348, 1394, 0, + DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) }, + /* 1792x1344@75Hz */ + { DRM_MODE("1792x1344", DRM_MODE_TYPE_DRIVER, 261000, 1792, 1888, + 2104, 2456, 0, 1344, 1345, 1348, 1417, 0, + DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) }, + /* 1792x1344@120Hz RB */ + { DRM_MODE("1792x1344", DRM_MODE_TYPE_DRIVER, 333250, 1792, 1840, + 1872, 1952, 0, 1344, 1347, 1351, 1423, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC) }, + /* 1856x1392@60Hz */ + { DRM_MODE("1856x1392", DRM_MODE_TYPE_DRIVER, 218250, 1856, 1952, + 2176, 2528, 0, 1392, 1393, 1396, 1439, 0, + DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) }, + /* 1856x1392@75Hz */ + { DRM_MODE("1856x1392", DRM_MODE_TYPE_DRIVER, 288000, 1856, 1984, + 2208, 2560, 0, 1392, 1395, 1399, 1500, 0, + DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) }, + /* 1856x1392@120Hz RB */ + { DRM_MODE("1856x1392", DRM_MODE_TYPE_DRIVER, 356500, 1856, 1904, + 1936, 2016, 0, 1392, 1395, 1399, 1474, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC) }, + /* 1920x1200@60Hz RB */ + { DRM_MODE("1920x1200", DRM_MODE_TYPE_DRIVER, 154000, 1920, 1968, + 2000, 2080, 0, 1200, 1203, 1209, 1235, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC) }, + /* 1920x1200@60Hz */ + { DRM_MODE("1920x1200", DRM_MODE_TYPE_DRIVER, 193250, 1920, 2056, + 2256, 2592, 0, 1200, 1203, 1209, 1245, 0, + DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) }, + /* 1920x1200@75Hz */ + { DRM_MODE("1920x1200", DRM_MODE_TYPE_DRIVER, 245250, 1920, 2056, + 2264, 2608, 0, 1200, 1203, 1209, 1255, 0, + DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) }, + /* 1920x1200@85Hz */ + { DRM_MODE("1920x1200", DRM_MODE_TYPE_DRIVER, 281250, 1920, 2064, + 2272, 2624, 0, 1200, 1203, 1209, 1262, 0, + DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) }, + /* 1920x1200@120Hz RB */ + { DRM_MODE("1920x1200", DRM_MODE_TYPE_DRIVER, 317000, 1920, 1968, + 2000, 2080, 0, 1200, 1203, 1209, 1271, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC) }, + /* 1920x1440@60Hz */ + { DRM_MODE("1920x1440", DRM_MODE_TYPE_DRIVER, 234000, 1920, 2048, + 2256, 2600, 0, 1440, 1441, 1444, 1500, 0, + DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) }, + /* 1920x1440@75Hz */ + { DRM_MODE("1920x1440", DRM_MODE_TYPE_DRIVER, 297000, 1920, 2064, + 2288, 2640, 0, 1440, 1441, 1444, 1500, 0, + DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) }, + /* 1920x1440@120Hz RB */ + { DRM_MODE("1920x1440", DRM_MODE_TYPE_DRIVER, 380500, 1920, 1968, + 2000, 2080, 0, 1440, 1443, 1447, 1525, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC) }, + /* 2560x1600@60Hz RB */ + { DRM_MODE("2560x1600", DRM_MODE_TYPE_DRIVER, 268500, 2560, 2608, + 2640, 2720, 0, 1600, 1603, 1609, 1646, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC) }, + /* 2560x1600@60Hz */ + { DRM_MODE("2560x1600", DRM_MODE_TYPE_DRIVER, 348500, 2560, 2752, + 3032, 3504, 0, 1600, 1603, 1609, 1658, 0, + DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) }, + /* 2560x1600@75HZ */ + { DRM_MODE("2560x1600", DRM_MODE_TYPE_DRIVER, 443250, 2560, 2768, + 3048, 3536, 0, 1600, 1603, 1609, 1672, 0, + DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) }, + /* 2560x1600@85HZ */ + { DRM_MODE("2560x1600", DRM_MODE_TYPE_DRIVER, 505250, 2560, 2768, + 3048, 3536, 0, 1600, 1603, 1609, 1682, 0, + DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) }, + /* 2560x1600@120Hz RB */ + { DRM_MODE("2560x1600", DRM_MODE_TYPE_DRIVER, 552750, 2560, 2608, + 2640, 2720, 0, 1600, 1603, 1609, 1694, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC) }, +}; + +static const struct drm_display_mode edid_est_modes[] = { + { DRM_MODE("800x600", DRM_MODE_TYPE_DRIVER, 40000, 800, 840, + 968, 1056, 0, 600, 601, 605, 628, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, /* 800x600@60Hz */ + { DRM_MODE("800x600", DRM_MODE_TYPE_DRIVER, 36000, 800, 824, + 896, 1024, 0, 600, 601, 603, 625, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, /* 800x600@56Hz */ + { DRM_MODE("640x480", DRM_MODE_TYPE_DRIVER, 31500, 640, 656, + 720, 840, 0, 480, 481, 484, 500, 0, + DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, /* 640x480@75Hz */ + { DRM_MODE("640x480", DRM_MODE_TYPE_DRIVER, 31500, 640, 664, + 704, 832, 0, 480, 489, 491, 520, 0, + DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, /* 640x480@72Hz */ + { DRM_MODE("640x480", DRM_MODE_TYPE_DRIVER, 30240, 640, 704, + 768, 864, 0, 480, 483, 486, 525, 0, + DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, /* 640x480@67Hz */ + { DRM_MODE("640x480", DRM_MODE_TYPE_DRIVER, 25200, 640, 656, + 752, 800, 0, 480, 490, 492, 525, 0, + DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, /* 640x480@60Hz */ + { DRM_MODE("720x400", DRM_MODE_TYPE_DRIVER, 35500, 720, 738, + 846, 900, 0, 400, 421, 423, 449, 0, + DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, /* 720x400@88Hz */ + { DRM_MODE("720x400", DRM_MODE_TYPE_DRIVER, 28320, 720, 738, + 846, 900, 0, 400, 412, 414, 449, 0, + DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) }, /* 720x400@70Hz */ + { DRM_MODE("1280x1024", DRM_MODE_TYPE_DRIVER, 135000, 1280, 1296, + 1440, 1688, 0, 1024, 1025, 1028, 1066, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, /* 1280x1024@75Hz */ + { DRM_MODE("1024x768", DRM_MODE_TYPE_DRIVER, 78800, 1024, 1040, + 1136, 1312, 0, 768, 769, 772, 800, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, /* 1024x768@75Hz */ + { DRM_MODE("1024x768", DRM_MODE_TYPE_DRIVER, 75000, 1024, 1048, + 1184, 1328, 0, 768, 771, 777, 806, 0, + DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, /* 1024x768@70Hz */ + { DRM_MODE("1024x768", DRM_MODE_TYPE_DRIVER, 65000, 1024, 1048, + 1184, 1344, 0, 768, 771, 777, 806, 0, + DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, /* 1024x768@60Hz */ + { DRM_MODE("1024x768i", DRM_MODE_TYPE_DRIVER,44900, 1024, 1032, + 1208, 1264, 0, 768, 768, 776, 817, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC | DRM_MODE_FLAG_INTERLACE) }, /* 1024x768@43Hz */ + { DRM_MODE("832x624", DRM_MODE_TYPE_DRIVER, 57284, 832, 864, + 928, 1152, 0, 624, 625, 628, 667, 0, + DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, /* 832x624@75Hz */ + { DRM_MODE("800x600", DRM_MODE_TYPE_DRIVER, 49500, 800, 816, + 896, 1056, 0, 600, 601, 604, 625, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, /* 800x600@75Hz */ + { DRM_MODE("800x600", DRM_MODE_TYPE_DRIVER, 50000, 800, 856, + 976, 1040, 0, 600, 637, 643, 666, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, /* 800x600@72Hz */ + { DRM_MODE("1152x864", DRM_MODE_TYPE_DRIVER, 108000, 1152, 1216, + 1344, 1600, 0, 864, 865, 868, 900, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, /* 1152x864@75Hz */ +}; + +struct minimode { + short w; + short h; + short r; + short rb; +}; + +static const struct minimode est3_modes[] = { + /* byte 6 */ + { 640, 350, 85, 0 }, + { 640, 400, 85, 0 }, + { 720, 400, 85, 0 }, + { 640, 480, 85, 0 }, + { 848, 480, 60, 0 }, + { 800, 600, 85, 0 }, + { 1024, 768, 85, 0 }, + { 1152, 864, 75, 0 }, + /* byte 7 */ + { 1280, 768, 60, 1 }, + { 1280, 768, 60, 0 }, + { 1280, 768, 75, 0 }, + { 1280, 768, 85, 0 }, + { 1280, 960, 60, 0 }, + { 1280, 960, 85, 0 }, + { 1280, 1024, 60, 0 }, + { 1280, 1024, 85, 0 }, + /* byte 8 */ + { 1360, 768, 60, 0 }, + { 1440, 900, 60, 1 }, + { 1440, 900, 60, 0 }, + { 1440, 900, 75, 0 }, + { 1440, 900, 85, 0 }, + { 1400, 1050, 60, 1 }, + { 1400, 1050, 60, 0 }, + { 1400, 1050, 75, 0 }, + /* byte 9 */ + { 1400, 1050, 85, 0 }, + { 1680, 1050, 60, 1 }, + { 1680, 1050, 60, 0 }, + { 1680, 1050, 75, 0 }, + { 1680, 1050, 85, 0 }, + { 1600, 1200, 60, 0 }, + { 1600, 1200, 65, 0 }, + { 1600, 1200, 70, 0 }, + /* byte 10 */ + { 1600, 1200, 75, 0 }, + { 1600, 1200, 85, 0 }, + { 1792, 1344, 60, 0 }, + { 1792, 1344, 85, 0 }, + { 1856, 1392, 60, 0 }, + { 1856, 1392, 75, 0 }, + { 1920, 1200, 60, 1 }, + { 1920, 1200, 60, 0 }, + /* byte 11 */ + { 1920, 1200, 75, 0 }, + { 1920, 1200, 85, 0 }, + { 1920, 1440, 60, 0 }, + { 1920, 1440, 75, 0 }, +}; + +static const struct minimode extra_modes[] = { + { 1024, 576, 60, 0 }, + { 1366, 768, 60, 0 }, + { 1600, 900, 60, 0 }, + { 1680, 945, 60, 0 }, + { 1920, 1080, 60, 0 }, + { 2048, 1152, 60, 0 }, + { 2048, 1536, 60, 0 }, +}; + +/* + * Probably taken from CEA-861 spec. + * This table is converted from xorg's hw/xfree86/modes/xf86EdidModes.c. + */ +static const struct drm_display_mode edid_cea_modes[] = { + /* 1 - 640x480@60Hz */ + { DRM_MODE("640x480", DRM_MODE_TYPE_DRIVER, 25175, 640, 656, + 752, 800, 0, 480, 490, 492, 525, 0, + DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, + /* 2 - 720x480@60Hz */ + { DRM_MODE("720x480", DRM_MODE_TYPE_DRIVER, 27000, 720, 736, + 798, 858, 0, 480, 489, 495, 525, 0, + DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, + /* 3 - 720x480@60Hz */ + { DRM_MODE("720x480", DRM_MODE_TYPE_DRIVER, 27000, 720, 736, + 798, 858, 0, 480, 489, 495, 525, 0, + DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, + /* 4 - 1280x720@60Hz */ + { DRM_MODE("1280x720", DRM_MODE_TYPE_DRIVER, 74250, 1280, 1390, + 1430, 1650, 0, 720, 725, 730, 750, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, + /* 5 - 1920x1080i@60Hz */ + { DRM_MODE("1920x1080i", DRM_MODE_TYPE_DRIVER, 74250, 1920, 2008, + 2052, 2200, 0, 1080, 1084, 1094, 1125, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC | + DRM_MODE_FLAG_INTERLACE) }, + /* 6 - 1440x480i@60Hz */ + { DRM_MODE("1440x480i", DRM_MODE_TYPE_DRIVER, 27000, 1440, 1478, + 1602, 1716, 0, 480, 488, 494, 525, 0, + DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC | + DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK) }, + /* 7 - 1440x480i@60Hz */ + { DRM_MODE("1440x480i", DRM_MODE_TYPE_DRIVER, 27000, 1440, 1478, + 1602, 1716, 0, 480, 488, 494, 525, 0, + DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC | + DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK) }, + /* 8 - 1440x240@60Hz */ + { DRM_MODE("1440x240", DRM_MODE_TYPE_DRIVER, 27000, 1440, 1478, + 1602, 1716, 0, 240, 244, 247, 262, 0, + DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC | + DRM_MODE_FLAG_DBLCLK) }, + /* 9 - 1440x240@60Hz */ + { DRM_MODE("1440x240", DRM_MODE_TYPE_DRIVER, 27000, 1440, 1478, + 1602, 1716, 0, 240, 244, 247, 262, 0, + DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC | + DRM_MODE_FLAG_DBLCLK) }, + /* 10 - 2880x480i@60Hz */ + { DRM_MODE("2880x480i", DRM_MODE_TYPE_DRIVER, 54000, 2880, 2956, + 3204, 3432, 0, 480, 488, 494, 525, 0, + DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC | + DRM_MODE_FLAG_INTERLACE) }, + /* 11 - 2880x480i@60Hz */ + { DRM_MODE("2880x480i", DRM_MODE_TYPE_DRIVER, 54000, 2880, 2956, + 3204, 3432, 0, 480, 488, 494, 525, 0, + DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC | + DRM_MODE_FLAG_INTERLACE) }, + /* 12 - 2880x240@60Hz */ + { DRM_MODE("2880x240", DRM_MODE_TYPE_DRIVER, 54000, 2880, 2956, + 3204, 3432, 0, 240, 244, 247, 262, 0, + DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, + /* 13 - 2880x240@60Hz */ + { DRM_MODE("2880x240", DRM_MODE_TYPE_DRIVER, 54000, 2880, 2956, + 3204, 3432, 0, 240, 244, 247, 262, 0, + DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, + /* 14 - 1440x480@60Hz */ + { DRM_MODE("1440x480", DRM_MODE_TYPE_DRIVER, 54000, 1440, 1472, + 1596, 1716, 0, 480, 489, 495, 525, 0, + DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, + /* 15 - 1440x480@60Hz */ + { DRM_MODE("1440x480", DRM_MODE_TYPE_DRIVER, 54000, 1440, 1472, + 1596, 1716, 0, 480, 489, 495, 525, 0, + DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, + /* 16 - 1920x1080@60Hz */ + { DRM_MODE("1920x1080", DRM_MODE_TYPE_DRIVER, 148500, 1920, 2008, + 2052, 2200, 0, 1080, 1084, 1089, 1125, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, + /* 17 - 720x576@50Hz */ + { DRM_MODE("720x576", DRM_MODE_TYPE_DRIVER, 27000, 720, 732, + 796, 864, 0, 576, 581, 586, 625, 0, + DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, + /* 18 - 720x576@50Hz */ + { DRM_MODE("720x576", DRM_MODE_TYPE_DRIVER, 27000, 720, 732, + 796, 864, 0, 576, 581, 586, 625, 0, + DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, + /* 19 - 1280x720@50Hz */ + { DRM_MODE("1280x720", DRM_MODE_TYPE_DRIVER, 74250, 1280, 1720, + 1760, 1980, 0, 720, 725, 730, 750, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, + /* 20 - 1920x1080i@50Hz */ + { DRM_MODE("1920x1080i", DRM_MODE_TYPE_DRIVER, 74250, 1920, 2448, + 2492, 2640, 0, 1080, 1084, 1094, 1125, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC | + DRM_MODE_FLAG_INTERLACE) }, + /* 21 - 1440x576i@50Hz */ + { DRM_MODE("1440x576i", DRM_MODE_TYPE_DRIVER, 27000, 1440, 1464, + 1590, 1728, 0, 576, 580, 586, 625, 0, + DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC | + DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK) }, + /* 22 - 1440x576i@50Hz */ + { DRM_MODE("1440x576i", DRM_MODE_TYPE_DRIVER, 27000, 1440, 1464, + 1590, 1728, 0, 576, 580, 586, 625, 0, + DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC | + DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK) }, + /* 23 - 1440x288@50Hz */ + { DRM_MODE("1440x288", DRM_MODE_TYPE_DRIVER, 27000, 1440, 1464, + 1590, 1728, 0, 288, 290, 293, 312, 0, + DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC | + DRM_MODE_FLAG_DBLCLK) }, + /* 24 - 1440x288@50Hz */ + { DRM_MODE("1440x288", DRM_MODE_TYPE_DRIVER, 27000, 1440, 1464, + 1590, 1728, 0, 288, 290, 293, 312, 0, + DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC | + DRM_MODE_FLAG_DBLCLK) }, + /* 25 - 2880x576i@50Hz */ + { DRM_MODE("2880x576i", DRM_MODE_TYPE_DRIVER, 54000, 2880, 2928, + 3180, 3456, 0, 576, 580, 586, 625, 0, + DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC | + DRM_MODE_FLAG_INTERLACE) }, + /* 26 - 2880x576i@50Hz */ + { DRM_MODE("2880x576i", DRM_MODE_TYPE_DRIVER, 54000, 2880, 2928, + 3180, 3456, 0, 576, 580, 586, 625, 0, + DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC | + DRM_MODE_FLAG_INTERLACE) }, + /* 27 - 2880x288@50Hz */ + { DRM_MODE("2880x288", DRM_MODE_TYPE_DRIVER, 54000, 2880, 2928, + 3180, 3456, 0, 288, 290, 293, 312, 0, + DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, + /* 28 - 2880x288@50Hz */ + { DRM_MODE("2880x288", DRM_MODE_TYPE_DRIVER, 54000, 2880, 2928, + 3180, 3456, 0, 288, 290, 293, 312, 0, + DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, + /* 29 - 1440x576@50Hz */ + { DRM_MODE("1440x576", DRM_MODE_TYPE_DRIVER, 54000, 1440, 1464, + 1592, 1728, 0, 576, 581, 586, 625, 0, + DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, + /* 30 - 1440x576@50Hz */ + { DRM_MODE("1440x576", DRM_MODE_TYPE_DRIVER, 54000, 1440, 1464, + 1592, 1728, 0, 576, 581, 586, 625, 0, + DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, + /* 31 - 1920x1080@50Hz */ + { DRM_MODE("1920x1080", DRM_MODE_TYPE_DRIVER, 148500, 1920, 2448, + 2492, 2640, 0, 1080, 1084, 1089, 1125, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, + /* 32 - 1920x1080@24Hz */ + { DRM_MODE("1920x1080", DRM_MODE_TYPE_DRIVER, 74250, 1920, 2558, + 2602, 2750, 0, 1080, 1084, 1089, 1125, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, + /* 33 - 1920x1080@25Hz */ + { DRM_MODE("1920x1080", DRM_MODE_TYPE_DRIVER, 74250, 1920, 2448, + 2492, 2640, 0, 1080, 1084, 1089, 1125, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, + /* 34 - 1920x1080@30Hz */ + { DRM_MODE("1920x1080", DRM_MODE_TYPE_DRIVER, 74250, 1920, 2008, + 2052, 2200, 0, 1080, 1084, 1089, 1125, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, + /* 35 - 2880x480@60Hz */ + { DRM_MODE("2880x480", DRM_MODE_TYPE_DRIVER, 108000, 2880, 2944, + 3192, 3432, 0, 480, 489, 495, 525, 0, + DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, + /* 36 - 2880x480@60Hz */ + { DRM_MODE("2880x480", DRM_MODE_TYPE_DRIVER, 108000, 2880, 2944, + 3192, 3432, 0, 480, 489, 495, 525, 0, + DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, + /* 37 - 2880x576@50Hz */ + { DRM_MODE("2880x576", DRM_MODE_TYPE_DRIVER, 108000, 2880, 2928, + 3184, 3456, 0, 576, 581, 586, 625, 0, + DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, + /* 38 - 2880x576@50Hz */ + { DRM_MODE("2880x576", DRM_MODE_TYPE_DRIVER, 108000, 2880, 2928, + 3184, 3456, 0, 576, 581, 586, 625, 0, + DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, + /* 39 - 1920x1080i@50Hz */ + { DRM_MODE("1920x1080i", DRM_MODE_TYPE_DRIVER, 72000, 1920, 1952, + 2120, 2304, 0, 1080, 1126, 1136, 1250, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC | + DRM_MODE_FLAG_INTERLACE) }, + /* 40 - 1920x1080i@100Hz */ + { DRM_MODE("1920x1080i", DRM_MODE_TYPE_DRIVER, 148500, 1920, 2448, + 2492, 2640, 0, 1080, 1084, 1094, 1125, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC | + DRM_MODE_FLAG_INTERLACE) }, + /* 41 - 1280x720@100Hz */ + { DRM_MODE("1280x720", DRM_MODE_TYPE_DRIVER, 148500, 1280, 1720, + 1760, 1980, 0, 720, 725, 730, 750, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, + /* 42 - 720x576@100Hz */ + { DRM_MODE("720x576", DRM_MODE_TYPE_DRIVER, 54000, 720, 732, + 796, 864, 0, 576, 581, 586, 625, 0, + DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, + /* 43 - 720x576@100Hz */ + { DRM_MODE("720x576", DRM_MODE_TYPE_DRIVER, 54000, 720, 732, + 796, 864, 0, 576, 581, 586, 625, 0, + DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, + /* 44 - 1440x576i@100Hz */ + { DRM_MODE("1440x576", DRM_MODE_TYPE_DRIVER, 54000, 1440, 1464, + 1590, 1728, 0, 576, 580, 586, 625, 0, + DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC | + DRM_MODE_FLAG_DBLCLK) }, + /* 45 - 1440x576i@100Hz */ + { DRM_MODE("1440x576", DRM_MODE_TYPE_DRIVER, 54000, 1440, 1464, + 1590, 1728, 0, 576, 580, 586, 625, 0, + DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC | + DRM_MODE_FLAG_DBLCLK) }, + /* 46 - 1920x1080i@120Hz */ + { DRM_MODE("1920x1080i", DRM_MODE_TYPE_DRIVER, 148500, 1920, 2008, + 2052, 2200, 0, 1080, 1084, 1094, 1125, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC | + DRM_MODE_FLAG_INTERLACE) }, + /* 47 - 1280x720@120Hz */ + { DRM_MODE("1280x720", DRM_MODE_TYPE_DRIVER, 148500, 1280, 1390, + 1430, 1650, 0, 720, 725, 730, 750, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, + /* 48 - 720x480@120Hz */ + { DRM_MODE("720x480", DRM_MODE_TYPE_DRIVER, 54000, 720, 736, + 798, 858, 0, 480, 489, 495, 525, 0, + DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, + /* 49 - 720x480@120Hz */ + { DRM_MODE("720x480", DRM_MODE_TYPE_DRIVER, 54000, 720, 736, + 798, 858, 0, 480, 489, 495, 525, 0, + DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, + /* 50 - 1440x480i@120Hz */ + { DRM_MODE("1440x480i", DRM_MODE_TYPE_DRIVER, 54000, 1440, 1478, + 1602, 1716, 0, 480, 488, 494, 525, 0, + DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC | + DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK) }, + /* 51 - 1440x480i@120Hz */ + { DRM_MODE("1440x480i", DRM_MODE_TYPE_DRIVER, 54000, 1440, 1478, + 1602, 1716, 0, 480, 488, 494, 525, 0, + DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC | + DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK) }, + /* 52 - 720x576@200Hz */ + { DRM_MODE("720x576", DRM_MODE_TYPE_DRIVER, 108000, 720, 732, + 796, 864, 0, 576, 581, 586, 625, 0, + DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, + /* 53 - 720x576@200Hz */ + { DRM_MODE("720x576", DRM_MODE_TYPE_DRIVER, 108000, 720, 732, + 796, 864, 0, 576, 581, 586, 625, 0, + DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, + /* 54 - 1440x576i@200Hz */ + { DRM_MODE("1440x576i", DRM_MODE_TYPE_DRIVER, 108000, 1440, 1464, + 1590, 1728, 0, 576, 580, 586, 625, 0, + DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC | + DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK) }, + /* 55 - 1440x576i@200Hz */ + { DRM_MODE("1440x576i", DRM_MODE_TYPE_DRIVER, 108000, 1440, 1464, + 1590, 1728, 0, 576, 580, 586, 625, 0, + DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC | + DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK) }, + /* 56 - 720x480@240Hz */ + { DRM_MODE("720x480", DRM_MODE_TYPE_DRIVER, 108000, 720, 736, + 798, 858, 0, 480, 489, 495, 525, 0, + DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, + /* 57 - 720x480@240Hz */ + { DRM_MODE("720x480", DRM_MODE_TYPE_DRIVER, 108000, 720, 736, + 798, 858, 0, 480, 489, 495, 525, 0, + DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, + /* 58 - 1440x480i@240 */ + { DRM_MODE("1440x480i", DRM_MODE_TYPE_DRIVER, 108000, 1440, 1478, + 1602, 1716, 0, 480, 488, 494, 525, 0, + DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC | + DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK) }, + /* 59 - 1440x480i@240 */ + { DRM_MODE("1440x480i", DRM_MODE_TYPE_DRIVER, 108000, 1440, 1478, + 1602, 1716, 0, 480, 488, 494, 525, 0, + DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC | + DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK) }, + /* 60 - 1280x720@24Hz */ + { DRM_MODE("1280x720", DRM_MODE_TYPE_DRIVER, 59400, 1280, 3040, + 3080, 3300, 0, 720, 725, 730, 750, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, + /* 61 - 1280x720@25Hz */ + { DRM_MODE("1280x720", DRM_MODE_TYPE_DRIVER, 74250, 1280, 3700, + 3740, 3960, 0, 720, 725, 730, 750, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, + /* 62 - 1280x720@30Hz */ + { DRM_MODE("1280x720", DRM_MODE_TYPE_DRIVER, 74250, 1280, 3040, + 3080, 3300, 0, 720, 725, 730, 750, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, + /* 63 - 1920x1080@120Hz */ + { DRM_MODE("1920x1080", DRM_MODE_TYPE_DRIVER, 297000, 1920, 2008, + 2052, 2200, 0, 1080, 1084, 1089, 1125, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, + /* 64 - 1920x1080@100Hz */ + { DRM_MODE("1920x1080", DRM_MODE_TYPE_DRIVER, 297000, 1920, 2448, + 2492, 2640, 0, 1080, 1084, 1094, 1125, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, +}; + /*** DDC fetch and block validation ***/ static const u8 edid_header[] = { @@ -153,9 +890,9 @@ int drm_edid_header_is_valid(const u8 *raw_edid) EXPORT_SYMBOL(drm_edid_header_is_valid); static int edid_fixup __read_mostly = 6; -//module_param_named(edid_fixup, edid_fixup, int, 0400); -//MODULE_PARM_DESC(edid_fixup, -// "Minimum number of valid EDID header bytes (0-8, default 6)"); +module_param_named(edid_fixup, edid_fixup, int, 0400); +MODULE_PARM_DESC(edid_fixup, + "Minimum number of valid EDID header bytes (0-8, default 6)"); /* * Sanity check the EDID block (base or extension). Return 0 if the block @@ -214,7 +951,8 @@ bool drm_edid_block_valid(u8 *raw_edid, int block, bool print_bad_edid) bad: if (raw_edid && print_bad_edid) { printk(KERN_ERR "Raw EDID:\n"); -// print_hex_dump_bytes(KERN_ERR, DUMP_PREFIX_NONE, raw_edid, EDID_LENGTH); + print_hex_dump(KERN_ERR, " \t", DUMP_PREFIX_NONE, 16, 1, + raw_edid, EDID_LENGTH, false); } return 0; } @@ -306,19 +1044,15 @@ drm_do_probe_ddc_edid(struct i2c_adapter *adapter, unsigned char *buf, static bool drm_edid_is_zero(u8 *in_edid, int length) { - int i; - u32 *raw_edid = (u32 *)in_edid; + if (memchr_inv(in_edid, 0, length)) + return false; - for (i = 0; i < length / 4; i++) - if (*(raw_edid + i) != 0) - return false; return true; } static u8 * drm_do_get_edid(struct drm_connector *connector, struct i2c_adapter *adapter) { - size_t alloc_size; int i, j = 0, valid_extensions = 0; u8 *block, *new; bool print_bad_edid = !connector->bad_edid_counter || (drm_debug & DRM_UT_KMS); @@ -344,16 +1078,9 @@ drm_do_get_edid(struct drm_connector *connector, struct i2c_adapter *adapter) if (block[0x7e] == 0) return block; - alloc_size = (block[0x7e] + 1) * EDID_LENGTH ; - - new = kmalloc(alloc_size, GFP_KERNEL); - + new = krealloc(block, (block[0x7e] + 1) * EDID_LENGTH, GFP_KERNEL); if (!new) goto out; - - memcpy(new, block, EDID_LENGTH); - kfree(block); - block = new; for (j = 1; j <= block[0x7e]; j++) { @@ -367,20 +1094,22 @@ drm_do_get_edid(struct drm_connector *connector, struct i2c_adapter *adapter) break; } } - if (i == 4) + + if (i == 4 && print_bad_edid) { dev_warn(connector->dev->dev, "%s: Ignoring invalid EDID block %d.\n", drm_get_connector_name(connector), j); + + connector->bad_edid_counter++; + } } if (valid_extensions != block[0x7e]) { block[EDID_LENGTH-1] += block[0x7e] - valid_extensions; block[0x7e] = valid_extensions; - new = kmalloc((valid_extensions + 1) * EDID_LENGTH, GFP_KERNEL); + new = krealloc(block, (valid_extensions + 1) * EDID_LENGTH, GFP_KERNEL); if (!new) goto out; - memcpy(new, block, alloc_size); - kfree(block); block = new; } @@ -553,7 +1282,7 @@ struct drm_display_mode *drm_mode_find_dmt(struct drm_device *dev, { int i; - for (i = 0; i < drm_num_dmt_modes; i++) { + for (i = 0; i < ARRAY_SIZE(drm_dmt_modes); i++) { const struct drm_display_mode *ptr = &drm_dmt_modes[i]; if (hsize != ptr->hdisplay) continue; @@ -905,7 +1634,7 @@ static struct drm_display_mode *drm_mode_detailed(struct drm_device *dev, unsigned vblank = (pt->vactive_vblank_hi & 0xf) << 8 | pt->vblank_lo; unsigned hsync_offset = (pt->hsync_vsync_offset_pulse_width_hi & 0xc0) << 2 | pt->hsync_offset_lo; unsigned hsync_pulse_width = (pt->hsync_vsync_offset_pulse_width_hi & 0x30) << 4 | pt->hsync_pulse_width_lo; - unsigned vsync_offset = (pt->hsync_vsync_offset_pulse_width_hi & 0xc) >> 2 | pt->vsync_offset_pulse_width_lo >> 4; + unsigned vsync_offset = (pt->hsync_vsync_offset_pulse_width_hi & 0xc) << 2 | pt->vsync_offset_pulse_width_lo >> 4; unsigned vsync_pulse_width = (pt->hsync_vsync_offset_pulse_width_hi & 0x3) << 4 | (pt->vsync_offset_pulse_width_lo & 0xf); /* ignore tiny modes */ @@ -986,6 +1715,7 @@ set_size: } mode->type = DRM_MODE_TYPE_DRIVER; + mode->vrefresh = drm_mode_vrefresh(mode); drm_mode_set_name(mode); return mode; @@ -1094,7 +1824,7 @@ drm_dmt_modes_for_range(struct drm_connector *connector, struct edid *edid, struct drm_display_mode *newmode; struct drm_device *dev = connector->dev; - for (i = 0; i < drm_num_dmt_modes; i++) { + for (i = 0; i < ARRAY_SIZE(drm_dmt_modes); i++) { if (mode_in_range(drm_dmt_modes + i, edid, timing) && valid_inferred_mode(connector, drm_dmt_modes + i)) { newmode = drm_mode_duplicate(dev, &drm_dmt_modes[i]); @@ -1129,7 +1859,7 @@ drm_gtf_modes_for_range(struct drm_connector *connector, struct edid *edid, struct drm_display_mode *newmode; struct drm_device *dev = connector->dev; - for (i = 0; i < num_extra_modes; i++) { + for (i = 0; i < ARRAY_SIZE(extra_modes); i++) { const struct minimode *m = &extra_modes[i]; newmode = drm_gtf_mode(dev, m->w, m->h, m->r, 0, 0); if (!newmode) @@ -1158,7 +1888,7 @@ drm_cvt_modes_for_range(struct drm_connector *connector, struct edid *edid, struct drm_device *dev = connector->dev; bool rb = drm_monitor_supports_rb(edid); - for (i = 0; i < num_extra_modes; i++) { + for (i = 0; i < ARRAY_SIZE(extra_modes); i++) { const struct minimode *m = &extra_modes[i]; newmode = drm_cvt_mode(dev, m->w, m->h, m->r, rb, 0, 0); if (!newmode) @@ -1495,9 +2225,11 @@ add_detailed_modes(struct drm_connector *connector, struct edid *edid, #define VIDEO_BLOCK 0x02 #define VENDOR_BLOCK 0x03 #define SPEAKER_BLOCK 0x04 +#define VIDEO_CAPABILITY_BLOCK 0x07 #define EDID_BASIC_AUDIO (1 << 6) #define EDID_CEA_YCRCB444 (1 << 5) #define EDID_CEA_YCRCB422 (1 << 4) +#define EDID_CEA_VCDB_QS (1 << 6) /** * Search EDID for CEA extension block. @@ -1525,16 +2257,19 @@ u8 *drm_find_cea_extension(struct edid *edid) } EXPORT_SYMBOL(drm_find_cea_extension); -/* - * Looks for a CEA mode matching given drm_display_mode. - * Returns its CEA Video ID code, or 0 if not found. +/** + * drm_match_cea_mode - look for a CEA mode matching given mode + * @to_match: display mode + * + * Returns the CEA Video ID (VIC) of the mode or 0 if it isn't a CEA-861 + * mode. */ -u8 drm_match_cea_mode(struct drm_display_mode *to_match) +u8 drm_match_cea_mode(const struct drm_display_mode *to_match) { struct drm_display_mode *cea_mode; u8 mode; - for (mode = 0; mode < drm_num_cea_modes; mode++) { + for (mode = 0; mode < ARRAY_SIZE(edid_cea_modes); mode++) { cea_mode = (struct drm_display_mode *)&edid_cea_modes[mode]; if (drm_mode_equal(to_match, cea_mode)) @@ -1554,7 +2289,7 @@ do_cea_modes (struct drm_connector *connector, u8 *db, u8 len) for (mode = db; mode < db + len; mode++) { cea_mode = (*mode & 127) - 1; /* CEA modes are numbered 1..127 */ - if (cea_mode < drm_num_cea_modes) { + if (cea_mode < ARRAY_SIZE(edid_cea_modes)) { struct drm_display_mode *newmode; newmode = drm_mode_duplicate(dev, &edid_cea_modes[cea_mode]); @@ -1913,6 +2648,37 @@ end: } EXPORT_SYMBOL(drm_detect_monitor_audio); +/** + * drm_rgb_quant_range_selectable - is RGB quantization range selectable? + * + * Check whether the monitor reports the RGB quantization range selection + * as supported. The AVI infoframe can then be used to inform the monitor + * which quantization range (full or limited) is used. + */ +bool drm_rgb_quant_range_selectable(struct edid *edid) +{ + u8 *edid_ext; + int i, start, end; + + edid_ext = drm_find_cea_extension(edid); + if (!edid_ext) + return false; + + if (cea_db_offsets(edid_ext, &start, &end)) + return false; + + for_each_cea_db(edid_ext, i, start, end) { + if (cea_db_tag(&edid_ext[i]) == VIDEO_CAPABILITY_BLOCK && + cea_db_payload_len(&edid_ext[i]) == 2) { + DRM_DEBUG_KMS("CEA VCDB 0x%02x\n", edid_ext[i + 2]); + return edid_ext[i + 2] & EDID_CEA_VCDB_QS; + } + } + + return false; +} +EXPORT_SYMBOL(drm_rgb_quant_range_selectable); + /** * drm_add_display_info - pull display info out if present * @edid: EDID data @@ -2032,6 +2798,7 @@ int drm_add_edid_modes(struct drm_connector *connector, struct edid *edid) num_modes += add_cvt_modes(connector, edid); num_modes += add_standard_modes(connector, edid); num_modes += add_established_modes(connector, edid); + if (edid->features & DRM_EDID_FEATURE_DEFAULT_GTF) num_modes += add_inferred_modes(connector, edid); num_modes += add_cea_modes(connector, edid); @@ -2093,20 +2860,33 @@ int drm_add_modes_noedid(struct drm_connector *connector, EXPORT_SYMBOL(drm_add_modes_noedid); /** - * drm_mode_cea_vic - return the CEA-861 VIC of a given mode - * @mode: mode + * drm_hdmi_avi_infoframe_from_display_mode() - fill an HDMI AVI infoframe with + * data from a DRM display mode + * @frame: HDMI AVI infoframe + * @mode: DRM display mode * - * RETURNS: - * The VIC number, 0 in case it's not a CEA-861 mode. + * Returns 0 on success or a negative error code on failure. */ -uint8_t drm_mode_cea_vic(const struct drm_display_mode *mode) +int +drm_hdmi_avi_infoframe_from_display_mode(struct hdmi_avi_infoframe *frame, + const struct drm_display_mode *mode) { - uint8_t i; + int err; - for (i = 0; i < drm_num_cea_modes; i++) - if (drm_mode_equal(mode, &edid_cea_modes[i])) - return i + 1; + if (!frame || !mode) + return -EINVAL; + + err = hdmi_avi_infoframe_init(frame); + if (err < 0) + return err; + + frame->video_code = drm_match_cea_mode(mode); + if (!frame->video_code) + return 0; + + frame->picture_aspect = HDMI_PICTURE_ASPECT_NONE; + frame->active_aspect = HDMI_ACTIVE_ASPECT_PICTURE; return 0; } -EXPORT_SYMBOL(drm_mode_cea_vic); +EXPORT_SYMBOL(drm_hdmi_avi_infoframe_from_display_mode); diff --git a/drivers/video/drm/drm_fb_helper.c b/drivers/video/drm/drm_fb_helper.c index ac51174fdd..e769d3746b 100644 --- a/drivers/video/drm/drm_fb_helper.c +++ b/drivers/video/drm/drm_fb_helper.c @@ -52,9 +52,36 @@ static LIST_HEAD(kernel_fb_helper_list); * mode setting driver. They can be used mostly independantely from the crtc * helper functions used by many drivers to implement the kernel mode setting * interfaces. + * + * Initialization is done as a three-step process with drm_fb_helper_init(), + * drm_fb_helper_single_add_all_connectors() and drm_fb_helper_initial_config(). + * Drivers with fancier requirements than the default beheviour can override the + * second step with their own code. Teardown is done with drm_fb_helper_fini(). + * + * At runtime drivers should restore the fbdev console by calling + * drm_fb_helper_restore_fbdev_mode() from their ->lastclose callback. They + * should also notify the fb helper code from updates to the output + * configuration by calling drm_fb_helper_hotplug_event(). For easier + * integration with the output polling code in drm_crtc_helper.c the modeset + * code proves a ->output_poll_changed callback. + * + * All other functions exported by the fb helper library can be used to + * implement the fbdev driver interface by the driver. */ -/* simple single crtc case helper function */ +/** + * drm_fb_helper_single_add_all_connectors() - add all connectors to fbdev + * emulation helper + * @fb_helper: fbdev initialized with drm_fb_helper_init + * + * This functions adds all the available connectors for use with the given + * fb_helper. This is a separate step to allow drivers to freely assign + * connectors to the fbdev, e.g. if some are reserved for special purposes or + * not adequate to be used for the fbcon. + * + * Since this is part of the initial setup before the fbdev is published, no + * locking is required. + */ int drm_fb_helper_single_add_all_connectors(struct drm_fb_helper *fb_helper) { struct drm_device *dev = fb_helper->dev; @@ -110,6 +137,23 @@ static void drm_fb_helper_restore_lut_atomic(struct drm_crtc *crtc) } +static bool drm_fb_helper_is_bound(struct drm_fb_helper *fb_helper) +{ + struct drm_device *dev = fb_helper->dev; + struct drm_crtc *crtc; + int bound = 0, crtcs_bound = 0; + + list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { + if (crtc->fb) + crtcs_bound++; + if (crtc->fb == fb_helper->fb) + bound++; + } + + if (bound < crtcs_bound) + return false; + return true; +} static void drm_fb_helper_dpms(struct fb_info *info, int dpms_mode) { @@ -119,10 +163,21 @@ static void drm_fb_helper_dpms(struct fb_info *info, int dpms_mode) struct drm_connector *connector; int i, j; + /* + * fbdev->blank can be called from irq context in case of a panic. + * Since we already have our own special panic handler which will + * restore the fbdev console mode completely, just bail out early. + */ + /* * For each CRTC in this fb, turn the connectors on/off. */ - mutex_lock(&dev->mode_config.mutex); + drm_modeset_lock_all(dev); + if (!drm_fb_helper_is_bound(fb_helper)) { + drm_modeset_unlock_all(dev); + return; + } + for (i = 0; i < fb_helper->crtc_count; i++) { crtc = fb_helper->crtc_info[i].mode_set.crtc; @@ -137,9 +192,14 @@ static void drm_fb_helper_dpms(struct fb_info *info, int dpms_mode) dev->mode_config.dpms_property, dpms_mode); } } - mutex_unlock(&dev->mode_config.mutex); + drm_modeset_unlock_all(dev); } +/** + * drm_fb_helper_blank - implementation for ->fb_blank + * @blank: desired blanking state + * @info: fbdev registered by the helper + */ int drm_fb_helper_blank(int blank, struct fb_info *info) { switch (blank) { @@ -183,6 +243,24 @@ static void drm_fb_helper_crtc_free(struct drm_fb_helper *helper) kfree(helper->crtc_info); } +/** + * drm_fb_helper_init - initialize a drm_fb_helper structure + * @dev: drm device + * @fb_helper: driver-allocated fbdev helper structure to initialize + * @crtc_count: maximum number of crtcs to support in this fbdev emulation + * @max_conn_count: max connector count + * + * This allocates the structures for the fbdev helper with the given limits. + * Note that this won't yet touch the hardware (through the driver interfaces) + * nor register the fbdev. This is only done in drm_fb_helper_initial_config() + * to allow driver writes more control over the exact init sequence. + * + * Drivers must set fb_helper->funcs before calling + * drm_fb_helper_initial_config(). + * + * RETURNS: + * Zero if everything went ok, nonzero otherwise. + */ int drm_fb_helper_init(struct drm_device *dev, struct drm_fb_helper *fb_helper, int crtc_count, int max_conn_count) @@ -294,6 +372,11 @@ static int setcolreg(struct drm_crtc *crtc, u16 red, u16 green, return 0; } +/** + * drm_fb_helper_setcmap - implementation for ->fb_setcmap + * @cmap: cmap to set + * @info: fbdev registered by the helper + */ int drm_fb_helper_setcmap(struct fb_cmap *cmap, struct fb_info *info) { struct drm_fb_helper *fb_helper = info->par; @@ -333,6 +416,11 @@ int drm_fb_helper_setcmap(struct fb_cmap *cmap, struct fb_info *info) } EXPORT_SYMBOL(drm_fb_helper_setcmap); +/** + * drm_fb_helper_check_var - implementation for ->fb_check_var + * @var: screeninfo to check + * @info: fbdev registered by the helper + */ int drm_fb_helper_check_var(struct fb_var_screeninfo *var, struct fb_info *info) { @@ -425,13 +513,19 @@ int drm_fb_helper_check_var(struct fb_var_screeninfo *var, } EXPORT_SYMBOL(drm_fb_helper_check_var); -/* this will let fbcon do the mode init */ +/** + * drm_fb_helper_set_par - implementation for ->fb_set_par + * @info: fbdev registered by the helper + * + * This will let fbcon do the mode init and is called at initialization time by + * the fbdev core when registering the driver, and later on through the hotplug + * callback. + */ int drm_fb_helper_set_par(struct fb_info *info) { struct drm_fb_helper *fb_helper = info->par; struct drm_device *dev = fb_helper->dev; struct fb_var_screeninfo *var = &info->var; - struct drm_crtc *crtc; int ret; int i; @@ -440,25 +534,29 @@ int drm_fb_helper_set_par(struct fb_info *info) return -EINVAL; } - mutex_lock(&dev->mode_config.mutex); + drm_modeset_lock_all(dev); for (i = 0; i < fb_helper->crtc_count; i++) { - crtc = fb_helper->crtc_info[i].mode_set.crtc; - ret = crtc->funcs->set_config(&fb_helper->crtc_info[i].mode_set); + ret = drm_mode_set_config_internal(&fb_helper->crtc_info[i].mode_set); if (ret) { - mutex_unlock(&dev->mode_config.mutex); + drm_modeset_unlock_all(dev); return ret; } } - mutex_unlock(&dev->mode_config.mutex); + drm_modeset_unlock_all(dev); if (fb_helper->delayed_hotplug) { fb_helper->delayed_hotplug = false; -// drm_fb_helper_hotplug_event(fb_helper); + drm_fb_helper_hotplug_event(fb_helper); } return 0; } EXPORT_SYMBOL(drm_fb_helper_set_par); +/** + * drm_fb_helper_pan_display - implementation for ->fb_pan_display + * @var: updated screen information + * @info: fbdev registered by the helper + */ int drm_fb_helper_pan_display(struct fb_var_screeninfo *var, struct fb_info *info) { @@ -469,7 +567,12 @@ int drm_fb_helper_pan_display(struct fb_var_screeninfo *var, int ret = 0; int i; - mutex_lock(&dev->mode_config.mutex); + drm_modeset_lock_all(dev); + if (!drm_fb_helper_is_bound(fb_helper)) { + drm_modeset_unlock_all(dev); + return -EBUSY; + } + for (i = 0; i < fb_helper->crtc_count; i++) { crtc = fb_helper->crtc_info[i].mode_set.crtc; @@ -479,22 +582,27 @@ int drm_fb_helper_pan_display(struct fb_var_screeninfo *var, modeset->y = var->yoffset; if (modeset->num_connectors) { - ret = crtc->funcs->set_config(modeset); + ret = drm_mode_set_config_internal(modeset); if (!ret) { info->var.xoffset = var->xoffset; info->var.yoffset = var->yoffset; } } } - mutex_unlock(&dev->mode_config.mutex); + drm_modeset_unlock_all(dev); return ret; } EXPORT_SYMBOL(drm_fb_helper_pan_display); -int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper, +/* + * Allocates the backing storage and sets up the fbdev info structure through + * the ->fb_probe callback and then registers the fbdev and sets up the panic + * notifier. + */ +static int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper, int preferred_bpp) { - int new_fb = 0; + int ret = 0; int crtc_count = 0; int i; struct fb_info *info; @@ -572,34 +680,44 @@ int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper, } /* push down into drivers */ - new_fb = (*fb_helper->funcs->fb_probe)(fb_helper, &sizes); - if (new_fb < 0) - return new_fb; + ret = (*fb_helper->funcs->fb_probe)(fb_helper, &sizes); + if (ret < 0) + return ret; info = fb_helper->fbdev; - /* set the fb pointer */ + /* + * Set the fb pointer - usually drm_setup_crtcs does this for hotplug + * events, but at init time drm_setup_crtcs needs to be called before + * the fb is allocated (since we need to figure out the desired size of + * the fb before we can allocate it ...). Hence we need to fix things up + * here again. + */ for (i = 0; i < fb_helper->crtc_count; i++) + if (fb_helper->crtc_info[i].mode_set.num_connectors) fb_helper->crtc_info[i].mode_set.fb = fb_helper->fb; - if (new_fb) { + info->var.pixclock = 0; -// dev_info(fb_helper->dev->dev, "fb%d: %s frame buffer device\n", -// info->node, info->fix.id); - - } else { - drm_fb_helper_set_par(info); - } - - - if (new_fb) list_add(&fb_helper->kernel_fb_list, &kernel_fb_helper_list); return 0; } -EXPORT_SYMBOL(drm_fb_helper_single_fb_probe); +/** + * drm_fb_helper_fill_fix - initializes fixed fbdev information + * @info: fbdev registered by the helper + * @pitch: desired pitch + * @depth: desired depth + * + * Helper to fill in the fixed fbdev information useful for a non-accelerated + * fbdev emulations. Drivers which support acceleration methods which impose + * additional constraints need to set up their own limits. + * + * Drivers should call this (or their equivalent setup code) from their + * ->fb_probe callback. + */ void drm_fb_helper_fill_fix(struct fb_info *info, uint32_t pitch, uint32_t depth) { @@ -620,6 +738,20 @@ void drm_fb_helper_fill_fix(struct fb_info *info, uint32_t pitch, } EXPORT_SYMBOL(drm_fb_helper_fill_fix); +/** + * drm_fb_helper_fill_var - initalizes variable fbdev information + * @info: fbdev instance to set up + * @fb_helper: fb helper instance to use as template + * @fb_width: desired fb width + * @fb_height: desired fb height + * + * Sets up the variable fbdev metainformation from the given fb helper instance + * and the drm framebuffer allocated in fb_helper->fb. + * + * Drivers should call this (or their equivalent setup code) from their + * ->fb_probe callback after having allocated the fbdev backing + * storage framebuffer. + */ void drm_fb_helper_fill_var(struct fb_info *info, struct drm_fb_helper *fb_helper, uint32_t fb_width, uint32_t fb_height) { @@ -937,6 +1069,7 @@ static void drm_setup_crtcs(struct drm_fb_helper *fb_helper) for (i = 0; i < fb_helper->crtc_count; i++) { modeset = &fb_helper->crtc_info[i].mode_set; modeset->num_connectors = 0; + modeset->fb = NULL; } for (i = 0; i < fb_helper->connector_count; i++) { @@ -953,9 +1086,21 @@ static void drm_setup_crtcs(struct drm_fb_helper *fb_helper) modeset->mode = drm_mode_duplicate(dev, fb_crtc->desired_mode); modeset->connectors[modeset->num_connectors++] = fb_helper->connector_info[i]->connector; + modeset->fb = fb_helper->fb; } } + /* Clear out any old modes if there are no more connected outputs. */ + for (i = 0; i < fb_helper->crtc_count; i++) { + modeset = &fb_helper->crtc_info[i].mode_set; + if (modeset->num_connectors == 0) { + BUG_ON(modeset->fb); + BUG_ON(modeset->num_connectors); + if (modeset->mode) + drm_mode_destroy(dev, modeset->mode); + modeset->mode = NULL; + } + } out: kfree(crtcs); kfree(modes); @@ -963,18 +1108,23 @@ out: } /** - * drm_helper_initial_config - setup a sane initial connector configuration + * drm_fb_helper_initial_config - setup a sane initial connector configuration * @fb_helper: fb_helper device struct * @bpp_sel: bpp value to use for the framebuffer configuration * - * LOCKING: - * Called at init time by the driver to set up the @fb_helper initial - * configuration, must take the mode config lock. - * * Scans the CRTCs and connectors and tries to put together an initial setup. * At the moment, this is a cloned configuration across all heads with * a new framebuffer object as the backing store. * + * Note that this also registers the fbdev and so allows userspace to call into + * the driver through the fbdev interfaces. + * + * This function will call down into the ->fb_probe callback to let + * the driver allocate and initialize the fbdev info structure and the drm + * framebuffer used to back the fbdev. drm_fb_helper_fill_var() and + * drm_fb_helper_fill_fix() are provided as helpers to setup simple default + * values for the fbdev info structure. + * * RETURNS: * Zero if everything went ok, nonzero otherwise. */ @@ -983,9 +1133,6 @@ bool drm_fb_helper_initial_config(struct drm_fb_helper *fb_helper, int bpp_sel) struct drm_device *dev = fb_helper->dev; int count = 0; - /* disable all the possible outputs/crtcs before entering KMS mode */ - drm_helper_disable_unused_functions(fb_helper->dev); - // drm_fb_helper_parse_command_line(fb_helper); count = drm_fb_helper_probe_connector_modes(fb_helper, @@ -1003,18 +1150,22 @@ bool drm_fb_helper_initial_config(struct drm_fb_helper *fb_helper, int bpp_sel) } EXPORT_SYMBOL(drm_fb_helper_initial_config); -#if 0 /** * drm_fb_helper_hotplug_event - respond to a hotplug notification by * probing all the outputs attached to the fb * @fb_helper: the drm_fb_helper * - * LOCKING: - * Called at runtime, must take mode config lock. - * * Scan the connectors attached to the fb_helper and try to put together a * setup after *notification of a change in output configuration. * + * Called at runtime, takes the mode config locks to be able to check/change the + * modeset configuration. Must be run from process context (which usually means + * either the output polling work or a work item launched from the driver's + * hotplug interrupt). + * + * Note that the driver must ensure that this is only called _after_ the fb has + * been fully set up, i.e. after the call to drm_fb_helper_initial_config. + * * RETURNS: * 0 on success and a non-zero error code otherwise. */ @@ -1023,23 +1174,14 @@ int drm_fb_helper_hotplug_event(struct drm_fb_helper *fb_helper) struct drm_device *dev = fb_helper->dev; int count = 0; u32 max_width, max_height, bpp_sel; - int bound = 0, crtcs_bound = 0; - struct drm_crtc *crtc; if (!fb_helper->fb) return 0; - mutex_lock(&dev->mode_config.mutex); - list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { - if (crtc->fb) - crtcs_bound++; - if (crtc->fb == fb_helper->fb) - bound++; - } - - if (bound < crtcs_bound) { + mutex_lock(&fb_helper->dev->mode_config.mutex); + if (!drm_fb_helper_is_bound(fb_helper)) { fb_helper->delayed_hotplug = true; - mutex_unlock(&dev->mode_config.mutex); + mutex_unlock(&fb_helper->dev->mode_config.mutex); return 0; } DRM_DEBUG_KMS("\n"); @@ -1050,13 +1192,16 @@ int drm_fb_helper_hotplug_event(struct drm_fb_helper *fb_helper) count = drm_fb_helper_probe_connector_modes(fb_helper, max_width, max_height); - drm_setup_crtcs(fb_helper); - mutex_unlock(&dev->mode_config.mutex); + mutex_unlock(&fb_helper->dev->mode_config.mutex); - return drm_fb_helper_single_fb_probe(fb_helper, bpp_sel); + drm_modeset_lock_all(dev); + drm_setup_crtcs(fb_helper); + drm_modeset_unlock_all(dev); + drm_fb_helper_set_par(fb_helper->fbdev); + + return 0; } EXPORT_SYMBOL(drm_fb_helper_hotplug_event); -#endif diff --git a/drivers/video/drm/drm_gem.c b/drivers/video/drm/drm_gem.c index 3a2ff7d3f2..66cef1b3d2 100644 --- a/drivers/video/drm/drm_gem.c +++ b/drivers/video/drm/drm_gem.c @@ -217,6 +217,9 @@ drm_gem_handle_delete(struct drm_file *filp, u32 handle) * we may want to use ida for number allocation and a hash table * for the pointers, anyway. */ + if(handle == -2) + printf("%s handle %d\n", __FUNCTION__, handle); + spin_lock(&filp->table_lock); /* Check if we currently have a reference on the object */ @@ -257,21 +260,19 @@ drm_gem_handle_create(struct drm_file *file_priv, int ret; /* - * Get the user-visible handle using idr. + * Get the user-visible handle using idr. Preload and perform + * allocation under our spinlock. */ -again: - /* ensure there is space available to allocate a handle */ - if (idr_pre_get(&file_priv->object_idr, GFP_KERNEL) == 0) - return -ENOMEM; - - /* do the allocation under our spinlock */ + idr_preload(GFP_KERNEL); spin_lock(&file_priv->table_lock); - ret = idr_get_new_above(&file_priv->object_idr, obj, 1, (int *)handlep); + + ret = idr_alloc(&file_priv->object_idr, obj, 1, 0, GFP_NOWAIT); + spin_unlock(&file_priv->table_lock); - if (ret == -EAGAIN) - goto again; - else if (ret) + idr_preload_end(); + if (ret < 0) return ret; + *handlep = ret; drm_gem_object_handle_reference(obj); @@ -384,6 +385,9 @@ drm_gem_object_lookup(struct drm_device *dev, struct drm_file *filp, { struct drm_gem_object *obj; + if(handle == -2) + printf("%s handle %d\n", __FUNCTION__, handle); + spin_lock(&filp->table_lock); /* Check if we currently have a reference on the object */ @@ -439,29 +443,25 @@ drm_gem_flink_ioctl(struct drm_device *dev, void *data, if (obj == NULL) return -ENOENT; -again: - if (idr_pre_get(&dev->object_name_idr, GFP_KERNEL) == 0) { - ret = -ENOMEM; - goto err; - } - + idr_preload(GFP_KERNEL); spin_lock(&dev->object_name_lock); if (!obj->name) { - ret = idr_get_new_above(&dev->object_name_idr, obj, 1, - &obj->name); + ret = idr_alloc(&dev->object_name_idr, obj, 1, 0, GFP_NOWAIT); + obj->name = ret; args->name = (uint64_t) obj->name; spin_unlock(&dev->object_name_lock); + idr_preload_end(); - if (ret == -EAGAIN) - goto again; - else if (ret) + if (ret < 0) goto err; + ret = 0; /* Allocate a reference for the name table. */ drm_gem_object_reference(obj); } else { args->name = (uint64_t) obj->name; spin_unlock(&dev->object_name_lock); + idr_preload_end(); ret = 0; } @@ -488,6 +488,9 @@ drm_gem_open_ioctl(struct drm_device *dev, void *data, if (!(dev->driver->driver_features & DRIVER_GEM)) return -ENODEV; + if(handle == -2) + printf("%s handle %d\n", __FUNCTION__, handle); + spin_lock(&dev->object_name_lock); obj = idr_find(&dev->object_name_idr, (int) args->name); if (obj) @@ -549,8 +552,6 @@ drm_gem_release(struct drm_device *dev, struct drm_file *file_private) { idr_for_each(&file_private->object_idr, &drm_gem_object_release_handle, file_private); - - idr_remove_all(&file_private->object_idr); idr_destroy(&file_private->object_idr); } #endif diff --git a/drivers/video/drm/drm_irq.c b/drivers/video/drm/drm_irq.c index 74631bfe68..0480ada472 100644 --- a/drivers/video/drm/drm_irq.c +++ b/drivers/video/drm/drm_irq.c @@ -111,6 +111,7 @@ void drm_calc_timestamping_constants(struct drm_crtc *crtc) /* Valid dotclock? */ if (dotclock > 0) { + int frame_size; /* Convert scanline length in pixels and video dot clock to * line duration, frame duration and pixel duration in * nanoseconds: @@ -118,7 +119,10 @@ void drm_calc_timestamping_constants(struct drm_crtc *crtc) pixeldur_ns = (s64) div64_u64(1000000000, dotclock); linedur_ns = (s64) div64_u64(((u64) crtc->hwmode.crtc_htotal * 1000000000), dotclock); - framedur_ns = (s64) crtc->hwmode.crtc_vtotal * linedur_ns; + frame_size = crtc->hwmode.crtc_htotal * + crtc->hwmode.crtc_vtotal; + framedur_ns = (s64) div64_u64((u64) frame_size * 1000000000, + dotclock); } else DRM_ERROR("crtc %d: Can't calculate constants, dotclock = 0!\n", crtc->base.id); diff --git a/drivers/video/drm/drm_mm.c b/drivers/video/drm/drm_mm.c index a43c624dad..71c4b39f56 100644 --- a/drivers/video/drm/drm_mm.c +++ b/drivers/video/drm/drm_mm.c @@ -102,20 +102,6 @@ int drm_mm_pre_get(struct drm_mm *mm) } EXPORT_SYMBOL(drm_mm_pre_get); -static inline unsigned long drm_mm_hole_node_start(struct drm_mm_node *hole_node) -{ - return hole_node->start + hole_node->size; -} - -static inline unsigned long drm_mm_hole_node_end(struct drm_mm_node *hole_node) -{ - struct drm_mm_node *next_node = - list_entry(hole_node->node_list.next, struct drm_mm_node, - node_list); - - return next_node->start; -} - static void drm_mm_insert_helper(struct drm_mm_node *hole_node, struct drm_mm_node *node, unsigned long size, unsigned alignment, @@ -127,7 +113,7 @@ static void drm_mm_insert_helper(struct drm_mm_node *hole_node, unsigned long adj_start = hole_start; unsigned long adj_end = hole_end; - BUG_ON(!hole_node->hole_follows || node->allocated); + BUG_ON(node->allocated); if (mm->color_adjust) mm->color_adjust(hole_node, color, &adj_start, &adj_end); @@ -155,12 +141,57 @@ static void drm_mm_insert_helper(struct drm_mm_node *hole_node, BUG_ON(node->start + node->size > adj_end); node->hole_follows = 0; - if (node->start + node->size < hole_end) { + if (__drm_mm_hole_node_start(node) < hole_end) { list_add(&node->hole_stack, &mm->hole_stack); node->hole_follows = 1; } } +struct drm_mm_node *drm_mm_create_block(struct drm_mm *mm, + unsigned long start, + unsigned long size, + bool atomic) +{ + struct drm_mm_node *hole, *node; + unsigned long end = start + size; + unsigned long hole_start; + unsigned long hole_end; + + drm_mm_for_each_hole(hole, mm, hole_start, hole_end) { + if (hole_start > start || hole_end < end) + continue; + + node = drm_mm_kmalloc(mm, atomic); + if (unlikely(node == NULL)) + return NULL; + + node->start = start; + node->size = size; + node->mm = mm; + node->allocated = 1; + + INIT_LIST_HEAD(&node->hole_stack); + list_add(&node->node_list, &hole->node_list); + + if (start == hole_start) { + hole->hole_follows = 0; + list_del_init(&hole->hole_stack); + } + + node->hole_follows = 0; + if (end != hole_end) { + list_add(&node->hole_stack, &mm->hole_stack); + node->hole_follows = 1; + } + + return node; + } + + WARN(1, "no hole found for block 0x%lx + 0x%lx\n", start, size); + return NULL; +} +EXPORT_SYMBOL(drm_mm_create_block); + struct drm_mm_node *drm_mm_get_block_generic(struct drm_mm_node *hole_node, unsigned long size, unsigned alignment, @@ -253,7 +284,7 @@ static void drm_mm_insert_helper_range(struct drm_mm_node *hole_node, BUG_ON(node->start + node->size > end); node->hole_follows = 0; - if (node->start + node->size < hole_end) { + if (__drm_mm_hole_node_start(node) < hole_end) { list_add(&node->hole_stack, &mm->hole_stack); node->hole_follows = 1; } @@ -327,12 +358,13 @@ void drm_mm_remove_node(struct drm_mm_node *node) list_entry(node->node_list.prev, struct drm_mm_node, node_list); if (node->hole_follows) { - BUG_ON(drm_mm_hole_node_start(node) - == drm_mm_hole_node_end(node)); + BUG_ON(__drm_mm_hole_node_start(node) == + __drm_mm_hole_node_end(node)); list_del(&node->hole_stack); } else - BUG_ON(drm_mm_hole_node_start(node) - != drm_mm_hole_node_end(node)); + BUG_ON(__drm_mm_hole_node_start(node) != + __drm_mm_hole_node_end(node)); + if (!prev_node->hole_follows) { prev_node->hole_follows = 1; @@ -390,6 +422,8 @@ struct drm_mm_node *drm_mm_search_free_generic(const struct drm_mm *mm, { struct drm_mm_node *entry; struct drm_mm_node *best; + unsigned long adj_start; + unsigned long adj_end; unsigned long best_size; BUG_ON(mm->scanned_blocks); @@ -397,17 +431,13 @@ struct drm_mm_node *drm_mm_search_free_generic(const struct drm_mm *mm, best = NULL; best_size = ~0UL; - list_for_each_entry(entry, &mm->hole_stack, hole_stack) { - unsigned long adj_start = drm_mm_hole_node_start(entry); - unsigned long adj_end = drm_mm_hole_node_end(entry); - + drm_mm_for_each_hole(entry, mm, adj_start, adj_end) { if (mm->color_adjust) { mm->color_adjust(entry, color, &adj_start, &adj_end); if (adj_end <= adj_start) continue; } - BUG_ON(!entry->hole_follows); if (!check_free_hole(adj_start, adj_end, size, alignment)) continue; @@ -434,6 +464,8 @@ struct drm_mm_node *drm_mm_search_free_in_range_generic(const struct drm_mm *mm, { struct drm_mm_node *entry; struct drm_mm_node *best; + unsigned long adj_start; + unsigned long adj_end; unsigned long best_size; BUG_ON(mm->scanned_blocks); @@ -441,13 +473,11 @@ struct drm_mm_node *drm_mm_search_free_in_range_generic(const struct drm_mm *mm, best = NULL; best_size = ~0UL; - list_for_each_entry(entry, &mm->hole_stack, hole_stack) { - unsigned long adj_start = drm_mm_hole_node_start(entry) < start ? - start : drm_mm_hole_node_start(entry); - unsigned long adj_end = drm_mm_hole_node_end(entry) > end ? - end : drm_mm_hole_node_end(entry); - - BUG_ON(!entry->hole_follows); + drm_mm_for_each_hole(entry, mm, adj_start, adj_end) { + if (adj_start < start) + adj_start = start; + if (adj_end > end) + adj_end = end; if (mm->color_adjust) { mm->color_adjust(entry, color, &adj_start, &adj_end); diff --git a/drivers/video/drm/drm_modes.c b/drivers/video/drm/drm_modes.c index d349704136..1ad5557782 100644 --- a/drivers/video/drm/drm_modes.c +++ b/drivers/video/drm/drm_modes.c @@ -504,6 +504,74 @@ drm_gtf_mode(struct drm_device *dev, int hdisplay, int vdisplay, int vrefresh, } EXPORT_SYMBOL(drm_gtf_mode); +#if IS_ENABLED(CONFIG_VIDEOMODE) +int drm_display_mode_from_videomode(const struct videomode *vm, + struct drm_display_mode *dmode) +{ + dmode->hdisplay = vm->hactive; + dmode->hsync_start = dmode->hdisplay + vm->hfront_porch; + dmode->hsync_end = dmode->hsync_start + vm->hsync_len; + dmode->htotal = dmode->hsync_end + vm->hback_porch; + + dmode->vdisplay = vm->vactive; + dmode->vsync_start = dmode->vdisplay + vm->vfront_porch; + dmode->vsync_end = dmode->vsync_start + vm->vsync_len; + dmode->vtotal = dmode->vsync_end + vm->vback_porch; + + dmode->clock = vm->pixelclock / 1000; + + dmode->flags = 0; + if (vm->dmt_flags & VESA_DMT_HSYNC_HIGH) + dmode->flags |= DRM_MODE_FLAG_PHSYNC; + else if (vm->dmt_flags & VESA_DMT_HSYNC_LOW) + dmode->flags |= DRM_MODE_FLAG_NHSYNC; + if (vm->dmt_flags & VESA_DMT_VSYNC_HIGH) + dmode->flags |= DRM_MODE_FLAG_PVSYNC; + else if (vm->dmt_flags & VESA_DMT_VSYNC_LOW) + dmode->flags |= DRM_MODE_FLAG_NVSYNC; + if (vm->data_flags & DISPLAY_FLAGS_INTERLACED) + dmode->flags |= DRM_MODE_FLAG_INTERLACE; + if (vm->data_flags & DISPLAY_FLAGS_DOUBLESCAN) + dmode->flags |= DRM_MODE_FLAG_DBLSCAN; + drm_mode_set_name(dmode); + + return 0; +} +EXPORT_SYMBOL_GPL(drm_display_mode_from_videomode); +#endif + +#if IS_ENABLED(CONFIG_OF_VIDEOMODE) +/** + * of_get_drm_display_mode - get a drm_display_mode from devicetree + * @np: device_node with the timing specification + * @dmode: will be set to the return value + * @index: index into the list of display timings in devicetree + * + * This function is expensive and should only be used, if only one mode is to be + * read from DT. To get multiple modes start with of_get_display_timings and + * work with that instead. + */ +int of_get_drm_display_mode(struct device_node *np, + struct drm_display_mode *dmode, int index) +{ + struct videomode vm; + int ret; + + ret = of_get_videomode(np, &vm, index); + if (ret) + return ret; + + drm_display_mode_from_videomode(&vm, dmode); + + pr_debug("%s: got %dx%d display mode from %s\n", + of_node_full_name(np), vm.hactive, vm.vactive, np->name); + drm_mode_debug_printmodeline(dmode); + + return 0; +} +EXPORT_SYMBOL_GPL(of_get_drm_display_mode); +#endif + /** * drm_mode_set_name - set the name on a mode * @mode: name will be set in this mode diff --git a/drivers/video/drm/drm_pci.c b/drivers/video/drm/drm_pci.c index cbff6be193..09b00832c2 100644 --- a/drivers/video/drm/drm_pci.c +++ b/drivers/video/drm/drm_pci.c @@ -88,7 +88,6 @@ drm_dma_handle_t *drm_pci_alloc(struct drm_device * dev, size_t size, size_t ali int drm_pcie_get_speed_cap_mask(struct drm_device *dev, u32 *mask) { struct pci_dev *root; - int pos; u32 lnkcap, lnkcap2; *mask = 0; @@ -103,33 +102,26 @@ int drm_pcie_get_speed_cap_mask(struct drm_device *dev, u32 *mask) #if 0 root = dev->pdev->bus->self; - pos = pci_pcie_cap(root); - if (!pos) + /* we've been informed via and serverworks don't make the cut */ + if (root->vendor == PCI_VENDOR_ID_VIA || + root->vendor == PCI_VENDOR_ID_SERVERWORKS) return -EINVAL; - /* we've been informed via and serverworks don't make the cut */ -// if (root->vendor == PCI_VENDOR_ID_VIA || -// root->vendor == PCI_VENDOR_ID_SERVERWORKS) -// return -EINVAL; + pcie_capability_read_dword(root, PCI_EXP_LNKCAP, &lnkcap); + pcie_capability_read_dword(root, PCI_EXP_LNKCAP2, &lnkcap2); - pci_read_config_dword(root, pos + PCI_EXP_LNKCAP, &lnkcap); - pci_read_config_dword(root, pos + PCI_EXP_LNKCAP2, &lnkcap2); - - lnkcap &= PCI_EXP_LNKCAP_SLS; - lnkcap2 &= 0xfe; - - if (lnkcap2) { /* PCIE GEN 3.0 */ + if (lnkcap2) { /* PCIe r3.0-compliant */ if (lnkcap2 & PCI_EXP_LNKCAP2_SLS_2_5GB) *mask |= DRM_PCIE_SPEED_25; if (lnkcap2 & PCI_EXP_LNKCAP2_SLS_5_0GB) *mask |= DRM_PCIE_SPEED_50; if (lnkcap2 & PCI_EXP_LNKCAP2_SLS_8_0GB) *mask |= DRM_PCIE_SPEED_80; - } else { - if (lnkcap & 1) + } else { /* pre-r3.0 */ + if (lnkcap & PCI_EXP_LNKCAP_SLS_2_5GB) *mask |= DRM_PCIE_SPEED_25; - if (lnkcap & 2) - *mask |= DRM_PCIE_SPEED_50; + if (lnkcap & PCI_EXP_LNKCAP_SLS_5_0GB) + *mask |= (DRM_PCIE_SPEED_25 | DRM_PCIE_SPEED_50); } DRM_INFO("probing gen 2 caps for device %x:%x = %x/%x\n", root->vendor, root->device, lnkcap, lnkcap2); diff --git a/drivers/video/drm/i915/Gtt/intel-gtt.c b/drivers/video/drm/i915/Gtt/intel-gtt.c index 5aba0f0729..23c5575728 100644 --- a/drivers/video/drm/i915/Gtt/intel-gtt.c +++ b/drivers/video/drm/i915/Gtt/intel-gtt.c @@ -15,6 +15,8 @@ * /fairy-tale-mode off */ +#include + #include #include #include @@ -30,7 +32,6 @@ #include "intel-agp.h" #include -#include struct pci_dev * pci_get_device(unsigned int vendor, unsigned int device, struct pci_dev *from); @@ -86,7 +87,6 @@ struct intel_gtt_driver { }; static struct _intel_private { - struct intel_gtt base; const struct intel_gtt_driver *driver; struct pci_dev *pcidev; /* device one */ struct pci_dev *bridge_dev; @@ -101,7 +101,18 @@ static struct _intel_private { struct resource ifp_resource; int resource_valid; struct page *scratch_page; + phys_addr_t scratch_page_dma; int refcount; + /* Whether i915 needs to use the dmar apis or not. */ + unsigned int needs_dmar : 1; + phys_addr_t gma_bus_addr; + /* Size of memory reserved for graphics by the BIOS */ + unsigned int stolen_size; + /* Total number of gtt entries. */ + unsigned int gtt_total_entries; + /* Part of the gtt that is mappable by the cpu, for those chips where + * this is not the full gtt. */ + unsigned int gtt_mappable_entries; } intel_private; #define INTEL_GTT_GEN intel_private.driver->gen @@ -118,7 +129,7 @@ static int intel_gtt_setup_scratch_page(void) page = alloc_page(GFP_KERNEL | GFP_DMA32 | __GFP_ZERO); if (page == NULL) return -ENOMEM; - intel_private.base.scratch_page_dma = page_to_phys(page); + intel_private.scratch_page_dma = page_to_phys(page); intel_private.scratch_page = page; @@ -300,7 +311,7 @@ static unsigned int intel_gtt_total_entries(void) /* On previous hardware, the GTT size was just what was * required to map the aperture. */ - return intel_private.base.gtt_mappable_entries; + return intel_private.gtt_mappable_entries; } } @@ -362,8 +373,8 @@ static int intel_gtt_init(void) if (ret != 0) return ret; - intel_private.base.gtt_mappable_entries = intel_gtt_mappable_entries(); - intel_private.base.gtt_total_entries = intel_gtt_total_entries(); + intel_private.gtt_mappable_entries = intel_gtt_mappable_entries(); + intel_private.gtt_total_entries = intel_gtt_total_entries(); /* save the PGETBL reg for resume */ intel_private.PGETBL_save = @@ -375,10 +386,10 @@ static int intel_gtt_init(void) dev_info(&intel_private.bridge_dev->dev, "detected gtt size: %dK total, %dK mappable\n", - intel_private.base.gtt_total_entries * 4, - intel_private.base.gtt_mappable_entries * 4); + intel_private.gtt_total_entries * 4, + intel_private.gtt_mappable_entries * 4); - gtt_map_size = intel_private.base.gtt_total_entries * 4; + gtt_map_size = intel_private.gtt_total_entries * 4; intel_private.gtt = NULL; if (intel_private.gtt == NULL) @@ -389,13 +400,12 @@ static int intel_gtt_init(void) iounmap(intel_private.registers); return -ENOMEM; } - intel_private.base.gtt = intel_private.gtt; asm volatile("wbinvd"); - intel_private.base.stolen_size = intel_gtt_stolen_size(); + intel_private.stolen_size = intel_gtt_stolen_size(); - intel_private.base.needs_dmar = USE_PCI_DMA_API && INTEL_GTT_GEN > 2; + intel_private.needs_dmar = USE_PCI_DMA_API && INTEL_GTT_GEN > 2; ret = intel_gtt_setup_scratch_page(); if (ret != 0) { @@ -410,7 +420,8 @@ static int intel_gtt_init(void) pci_read_config_dword(intel_private.pcidev, I915_GMADDR, &gma_addr); - intel_private.base.gma_bus_addr = (gma_addr & PCI_BASE_ADDRESS_MEM_MASK); + intel_private.gma_bus_addr = (gma_addr & PCI_BASE_ADDRESS_MEM_MASK); + return 0; } @@ -528,7 +539,7 @@ void intel_gtt_clear_range(unsigned int first_entry, unsigned int num_entries) unsigned int i; for (i = first_entry; i < (first_entry + num_entries); i++) { - intel_private.driver->write_entry(intel_private.base.scratch_page_dma, + intel_private.driver->write_entry(intel_private.scratch_page_dma, i, 0); } readl(intel_private.gtt+i-1); @@ -594,25 +605,6 @@ static void i965_write_entry(dma_addr_t addr, writel(addr | pte_flags, intel_private.gtt + entry); } -/* Certain Gen5 chipsets require require idling the GPU before - * unmapping anything from the GTT when VT-d is enabled. - */ -static inline int needs_idle_maps(void) -{ -#ifdef CONFIG_INTEL_IOMMU - const unsigned short gpu_devid = intel_private.pcidev->device; - - /* Query intel_iommu to see if we need the workaround. Presumably that - * was loaded first. - */ - if ((gpu_devid == PCI_DEVICE_ID_INTEL_IRONLAKE_M_HB || - gpu_devid == PCI_DEVICE_ID_INTEL_IRONLAKE_M_IG) && - intel_iommu_gfx_mapped) - return 1; -#endif - return 0; -} - static int i9xx_setup(void) { u32 reg_addr, gtt_addr; @@ -640,9 +632,6 @@ static int i9xx_setup(void) break; } - if (needs_idle_maps()) - intel_private.base.do_idle_maps = 1; - intel_i9xx_setup_flush(); return 0; @@ -794,7 +783,17 @@ int intel_gmch_probe(struct pci_dev *bridge_pdev, struct pci_dev *gpu_pdev, struct agp_bridge_data *bridge) { int i, mask; - intel_private.driver = NULL; + + /* + * Can be called from the fake agp driver but also directly from + * drm/i915.ko. Hence we need to check whether everything is set up + * already. + */ + if (intel_private.driver) { + intel_private.refcount++; + return 1; + } + for (i = 0; intel_gtt_chipsets[i].name != NULL; i++) { if (find_gmch(intel_gtt_chipsets[i].gmch_chip_id)) { @@ -807,6 +806,8 @@ int intel_gmch_probe(struct pci_dev *bridge_pdev, struct pci_dev *gpu_pdev, if (!intel_private.driver) return 0; + intel_private.refcount++; + if (bridge) { bridge->dev_private_data = &intel_private; bridge->dev = bridge_pdev; @@ -834,9 +835,13 @@ int intel_gmch_probe(struct pci_dev *bridge_pdev, struct pci_dev *gpu_pdev, } EXPORT_SYMBOL(intel_gmch_probe); -struct intel_gtt *intel_gtt_get(void) +void intel_gtt_get(size_t *gtt_total, size_t *stolen_size, + phys_addr_t *mappable_base, unsigned long *mappable_end) { - return &intel_private.base; + *gtt_total = intel_private.gtt_total_entries << PAGE_SHIFT; + *stolen_size = intel_private.stolen_size; + *mappable_base = intel_private.gma_bus_addr; + *mappable_end = intel_private.gtt_mappable_entries << PAGE_SHIFT; } EXPORT_SYMBOL(intel_gtt_get); diff --git a/drivers/video/drm/i915/i915_dma.c b/drivers/video/drm/i915/i915_dma.c index 5eb00ed655..a170a0eafd 100644 --- a/drivers/video/drm/i915/i915_dma.c +++ b/drivers/video/drm/i915/i915_dma.c @@ -997,6 +997,12 @@ static int i915_getparam(struct drm_device *dev, void *data, case I915_PARAM_HAS_PINNED_BATCHES: value = 1; break; + case I915_PARAM_HAS_EXEC_NO_RELOC: + value = 1; + break; + case I915_PARAM_HAS_EXEC_HANDLE_LUT: + value = 1; + break; default: DRM_DEBUG_DRIVER("Unknown parameter %d\n", param->param); @@ -1051,53 +1057,6 @@ static int i915_setparam(struct drm_device *dev, void *data, #endif -static int i915_set_status_page(struct drm_device *dev, void *data, - struct drm_file *file_priv) -{ - drm_i915_private_t *dev_priv = dev->dev_private; - drm_i915_hws_addr_t *hws = data; - struct intel_ring_buffer *ring; - - if (drm_core_check_feature(dev, DRIVER_MODESET)) - return -ENODEV; - - if (!I915_NEED_GFX_HWS(dev)) - return -EINVAL; - - if (!dev_priv) { - DRM_ERROR("called with no initialization\n"); - return -EINVAL; - } - - if (drm_core_check_feature(dev, DRIVER_MODESET)) { - WARN(1, "tried to set status page when mode setting active\n"); - return 0; - } - - DRM_DEBUG_DRIVER("set status page addr 0x%08x\n", (u32)hws->addr); - - ring = LP_RING(dev_priv); - ring->status_page.gfx_addr = hws->addr & (0x1ffff<<12); - - dev_priv->dri1.gfx_hws_cpu_addr = - ioremap(dev_priv->mm.gtt_base_addr + hws->addr, 4096); - if (dev_priv->dri1.gfx_hws_cpu_addr == NULL) { - i915_dma_cleanup(dev); - ring->status_page.gfx_addr = 0; - DRM_ERROR("can not ioremap virtual address for" - " G33 hw status page\n"); - return -ENOMEM; - } - - memset(dev_priv->dri1.gfx_hws_cpu_addr, 0, PAGE_SIZE); - I915_WRITE(HWS_PGA, ring->status_page.gfx_addr); - - DRM_DEBUG_DRIVER("load hws HWS_PGA with gfx mem 0x%x\n", - ring->status_page.gfx_addr); - DRM_DEBUG_DRIVER("load hws at %p\n", - ring->status_page.page_addr); - return 0; -} static int i915_get_bridge_dev(struct drm_device *dev) { @@ -1200,40 +1159,61 @@ static int i915_load_modeset_init(struct drm_device *dev) if (ret) goto cleanup_vga_switcheroo; + ret = drm_irq_install(dev); + if (ret) + goto cleanup_gem_stolen; + + /* Important: The output setup functions called by modeset_init need + * working irqs for e.g. gmbus and dp aux transfers. */ intel_modeset_init(dev); ret = i915_gem_init(dev); if (ret) - goto cleanup_gem_stolen; + goto cleanup_irq; + intel_modeset_gem_init(dev); - ret = drm_irq_install(dev); - if (ret) - goto cleanup_gem; - /* Always safe in the mode setting case. */ /* FIXME: do pre/post-mode set stuff in core KMS code */ dev->vblank_disable_allowed = 1; ret = intel_fbdev_init(dev); if (ret) - goto cleanup_irq; + goto cleanup_gem; -// drm_kms_helper_poll_init(dev); + /* Only enable hotplug handling once the fbdev is fully set up. */ + intel_hpd_init(dev); + + /* + * Some ports require correctly set-up hpd registers for detection to + * work properly (leading to ghost connected connector status), e.g. VGA + * on gm45. Hence we can only set up the initial fbdev config after hpd + * irqs are fully enabled. Now we should scan for the initial config + * only once hotplug handling is enabled, but due to screwed-up locking + * around kms/fbdev init we can't protect the fdbev initial config + * scanning against hotplug events. Hence do this first and ignore the + * tiny window where we will loose hotplug notifactions. + */ + intel_fbdev_initial_config(dev); + + /* Only enable hotplug handling once the fbdev is fully set up. */ + dev_priv->enable_hotplug_processing = true; + + drm_kms_helper_poll_init(dev); /* We're off and running w/KMS */ dev_priv->mm.suspended = 0; return 0; +cleanup_gem: + mutex_lock(&dev->struct_mutex); + i915_gem_cleanup_ringbuffer(dev); + mutex_unlock(&dev->struct_mutex); + i915_gem_cleanup_aliasing_ppgtt(dev); cleanup_irq: // drm_irq_uninstall(dev); -cleanup_gem: -// mutex_lock(&dev->struct_mutex); -// i915_gem_cleanup_ringbuffer(dev); -// mutex_unlock(&dev->struct_mutex); -// i915_gem_cleanup_aliasing_ppgtt(dev); cleanup_gem_stolen: // i915_gem_cleanup_stolen(dev); cleanup_vga_switcheroo: @@ -1336,8 +1316,7 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) goto put_gmch; } - aperture_size = dev_priv->mm.gtt->gtt_mappable_entries << PAGE_SHIFT; - dev_priv->mm.gtt_base_addr = dev_priv->mm.gtt->gma_bus_addr; + aperture_size = dev_priv->gtt.mappable_end; @@ -1389,11 +1368,12 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) */ spin_lock_init(&dev_priv->irq_lock); - spin_lock_init(&dev_priv->error_lock); + spin_lock_init(&dev_priv->gpu_error.lock); spin_lock_init(&dev_priv->rps.lock); - spin_lock_init(&dev_priv->dpio_lock); + mutex_init(&dev_priv->dpio_lock); mutex_init(&dev_priv->rps.hw_lock); + mutex_init(&dev_priv->modeset_restore_lock); if (IS_IVYBRIDGE(dev) || IS_HASWELL(dev)) dev_priv->num_pipe = 3; @@ -1444,7 +1424,7 @@ out_mtrrfree: out_rmmap: pci_iounmap(dev->pdev, dev_priv->regs); put_gmch: -// intel_gmch_remove(); +// dev_priv->gtt.gtt_remove(dev); put_bridge: // pci_dev_put(dev_priv->bridge_dev); free_priv: @@ -1476,11 +1456,11 @@ int i915_driver_unload(struct drm_device *dev) /* Cancel the retire work handler, which should be idle now. */ cancel_delayed_work_sync(&dev_priv->mm.retire_work); - io_mapping_free(dev_priv->mm.gtt_mapping); + io_mapping_free(dev_priv->gtt.mappable); if (dev_priv->mm.gtt_mtrr >= 0) { mtrr_del(dev_priv->mm.gtt_mtrr, - dev_priv->mm.gtt_base_addr, - dev_priv->mm.gtt->gtt_mappable_entries * PAGE_SIZE); + dev_priv->gtt.mappable_base, + dev_priv->gtt.mappable_end); dev_priv->mm.gtt_mtrr = -1; } @@ -1506,8 +1486,8 @@ int i915_driver_unload(struct drm_device *dev) } /* Free error state after interrupts are fully disabled. */ - del_timer_sync(&dev_priv->hangcheck_timer); - cancel_work_sync(&dev_priv->error_work); + del_timer_sync(&dev_priv->gpu_error.hangcheck_timer); + cancel_work_sync(&dev_priv->gpu_error.work); i915_destroy_error_state(dev); if (dev->pdev->msi_enabled) @@ -1526,9 +1506,6 @@ int i915_driver_unload(struct drm_device *dev) mutex_unlock(&dev->struct_mutex); i915_gem_cleanup_aliasing_ppgtt(dev); i915_gem_cleanup_stolen(dev); - drm_mm_takedown(&dev_priv->mm.stolen); - - intel_cleanup_overlay(dev); if (!I915_NEED_GFX_HWS(dev)) i915_free_hws(dev); @@ -1541,6 +1518,10 @@ int i915_driver_unload(struct drm_device *dev) intel_teardown_mchbar(dev); destroy_workqueue(dev_priv->wq); + pm_qos_remove_request(&dev_priv->pm_qos); + + if (dev_priv->slab) + kmem_cache_destroy(dev_priv->slab); pci_dev_put(dev_priv->bridge_dev); kfree(dev->dev_private); diff --git a/drivers/video/drm/i915/i915_drv.c b/drivers/video/drm/i915/i915_drv.c index 969172a7ae..fb25577e91 100644 --- a/drivers/video/drm/i915/i915_drv.c +++ b/drivers/video/drm/i915/i915_drv.c @@ -52,26 +52,30 @@ struct drm_device *main_device; struct drm_file *drm_file_handlers[256]; static int i915_modeset __read_mostly = 1; +module_param_named(modeset, i915_modeset, int, 0400); MODULE_PARM_DESC(modeset, "Use kernel modesetting [KMS] (0=DRM_I915_KMS from .config, " "1=on, -1=force vga console preference [default])"); -int i915_panel_ignore_lid __read_mostly = 0; +int i915_panel_ignore_lid __read_mostly = 1; +module_param_named(panel_ignore_lid, i915_panel_ignore_lid, int, 0600); MODULE_PARM_DESC(panel_ignore_lid, - "Override lid status (0=autodetect [default], 1=lid open, " - "-1=lid closed)"); + "Override lid status (0=autodetect, 1=autodetect disabled [default], " + "-1=force lid closed, -2=force lid open)"); unsigned int i915_powersave __read_mostly = 0; +module_param_named(powersave, i915_powersave, int, 0600); MODULE_PARM_DESC(powersave, "Enable powersavings, fbc, downclocking, etc. (default: true)"); int i915_semaphores __read_mostly = -1; - +module_param_named(semaphores, i915_semaphores, int, 0600); MODULE_PARM_DESC(semaphores, "Use semaphores for inter-ring sync (default: -1 (use per-chip defaults))"); int i915_enable_rc6 __read_mostly = 0; +module_param_named(i915_enable_rc6, i915_enable_rc6, int, 0400); MODULE_PARM_DESC(i915_enable_rc6, "Enable power-saving render C-state 6. " "Different stages can be selected via bitmask values " @@ -80,44 +84,53 @@ MODULE_PARM_DESC(i915_enable_rc6, "default: -1 (use per-chip default)"); int i915_enable_fbc __read_mostly = 0; +module_param_named(i915_enable_fbc, i915_enable_fbc, int, 0600); MODULE_PARM_DESC(i915_enable_fbc, "Enable frame buffer compression for power savings " "(default: -1 (use per-chip default))"); unsigned int i915_lvds_downclock __read_mostly = 0; +module_param_named(lvds_downclock, i915_lvds_downclock, int, 0400); MODULE_PARM_DESC(lvds_downclock, "Use panel (LVDS/eDP) downclocking for power savings " "(default: false)"); int i915_lvds_channel_mode __read_mostly; +module_param_named(lvds_channel_mode, i915_lvds_channel_mode, int, 0600); MODULE_PARM_DESC(lvds_channel_mode, "Specify LVDS channel mode " "(0=probe BIOS [default], 1=single-channel, 2=dual-channel)"); int i915_panel_use_ssc __read_mostly = -1; +module_param_named(lvds_use_ssc, i915_panel_use_ssc, int, 0600); MODULE_PARM_DESC(lvds_use_ssc, "Use Spread Spectrum Clock with panels [LVDS/eDP] " "(default: auto from VBT)"); int i915_vbt_sdvo_panel_type __read_mostly = -1; +module_param_named(vbt_sdvo_panel_type, i915_vbt_sdvo_panel_type, int, 0600); MODULE_PARM_DESC(vbt_sdvo_panel_type, "Override/Ignore selection of SDVO panel mode in the VBT " "(-2=ignore, -1=auto [default], index in VBT BIOS table)"); static bool i915_try_reset __read_mostly = true; +module_param_named(reset, i915_try_reset, bool, 0600); MODULE_PARM_DESC(reset, "Attempt GPU resets (default: true)"); bool i915_enable_hangcheck __read_mostly = false; +module_param_named(enable_hangcheck, i915_enable_hangcheck, bool, 0644); MODULE_PARM_DESC(enable_hangcheck, "Periodically check GPU activity for detecting hangs. " "WARNING: Disabling this can cause system wide hangs. " "(default: true)"); int i915_enable_ppgtt __read_mostly = false; +module_param_named(i915_enable_ppgtt, i915_enable_ppgtt, int, 0600); MODULE_PARM_DESC(i915_enable_ppgtt, "Enable PPGTT (default: true)"); unsigned int i915_preliminary_hw_support __read_mostly = true; +module_param_named(preliminary_hw_support, i915_preliminary_hw_support, int, 0600); MODULE_PARM_DESC(preliminary_hw_support, "Enable preliminary hardware support. " "Enable Haswell and ValleyView Support. " @@ -254,6 +267,7 @@ static const struct intel_device_info intel_valleyview_m_info = { .has_bsd_ring = 1, .has_blt_ring = 1, .is_valleyview = 1, + .display_mmio_offset = VLV_DISPLAY_BASE, }; static const struct intel_device_info intel_valleyview_d_info = { @@ -263,6 +277,7 @@ static const struct intel_device_info intel_valleyview_d_info = { .has_bsd_ring = 1, .has_blt_ring = 1, .is_valleyview = 1, + .display_mmio_offset = VLV_DISPLAY_BASE, }; static const struct intel_device_info intel_haswell_d_info = { @@ -350,15 +365,15 @@ static const struct pci_device_id pciidlist[] = { /* aka */ INTEL_VGA_DEVICE(0x0A06, &intel_haswell_m_info), /* ULT GT1 mobile */ INTEL_VGA_DEVICE(0x0A16, &intel_haswell_m_info), /* ULT GT2 mobile */ INTEL_VGA_DEVICE(0x0A26, &intel_haswell_m_info), /* ULT GT2 mobile */ - INTEL_VGA_DEVICE(0x0D12, &intel_haswell_d_info), /* CRW GT1 desktop */ + INTEL_VGA_DEVICE(0x0D02, &intel_haswell_d_info), /* CRW GT1 desktop */ + INTEL_VGA_DEVICE(0x0D12, &intel_haswell_d_info), /* CRW GT2 desktop */ INTEL_VGA_DEVICE(0x0D22, &intel_haswell_d_info), /* CRW GT2 desktop */ - INTEL_VGA_DEVICE(0x0D32, &intel_haswell_d_info), /* CRW GT2 desktop */ - INTEL_VGA_DEVICE(0x0D1A, &intel_haswell_d_info), /* CRW GT1 server */ + INTEL_VGA_DEVICE(0x0D0A, &intel_haswell_d_info), /* CRW GT1 server */ + INTEL_VGA_DEVICE(0x0D1A, &intel_haswell_d_info), /* CRW GT2 server */ INTEL_VGA_DEVICE(0x0D2A, &intel_haswell_d_info), /* CRW GT2 server */ - INTEL_VGA_DEVICE(0x0D3A, &intel_haswell_d_info), /* CRW GT2 server */ - INTEL_VGA_DEVICE(0x0D16, &intel_haswell_m_info), /* CRW GT1 mobile */ + INTEL_VGA_DEVICE(0x0D06, &intel_haswell_m_info), /* CRW GT1 mobile */ + INTEL_VGA_DEVICE(0x0D16, &intel_haswell_m_info), /* CRW GT2 mobile */ INTEL_VGA_DEVICE(0x0D26, &intel_haswell_m_info), /* CRW GT2 mobile */ - INTEL_VGA_DEVICE(0x0D36, &intel_haswell_m_info), /* CRW GT2 mobile */ INTEL_VGA_DEVICE(0x0f30, &intel_valleyview_m_info), INTEL_VGA_DEVICE(0x0157, &intel_valleyview_m_info), INTEL_VGA_DEVICE(0x0155, &intel_valleyview_d_info), @@ -454,7 +469,7 @@ int i915_init(void) if( unlikely(ent == NULL) ) { dbgprintf("device not found\n"); - return 0; + return -ENODEV; }; struct intel_device_info *intel_info = @@ -730,8 +745,6 @@ u##x i915_read##x(struct drm_i915_private *dev_priv, u32 reg) { \ if (dev_priv->forcewake_count == 0) \ dev_priv->gt.force_wake_put(dev_priv); \ spin_unlock_irqrestore(&dev_priv->gt_lock, irqflags); \ - } else if (IS_VALLEYVIEW(dev_priv->dev) && IS_DISPLAYREG(reg)) { \ - val = read##y(dev_priv->regs + reg + 0x180000); \ } else { \ val = read##y(dev_priv->regs + reg); \ } \ @@ -757,11 +770,7 @@ void i915_write##x(struct drm_i915_private *dev_priv, u32 reg, u##x val) { \ DRM_ERROR("Unknown unclaimed register before writing to %x\n", reg); \ I915_WRITE_NOTRACE(GEN7_ERR_INT, ERR_INT_MMIO_UNCLAIMED); \ } \ - if (IS_VALLEYVIEW(dev_priv->dev) && IS_DISPLAYREG(reg)) { \ - write##y(val, dev_priv->regs + reg + 0x180000); \ - } else { \ write##y(val, dev_priv->regs + reg); \ - } \ if (unlikely(__fifo_ret)) { \ gen6_gt_check_fifodbg(dev_priv); \ } \ diff --git a/drivers/video/drm/i915/i915_drv.h b/drivers/video/drm/i915/i915_drv.h index f1a7c026c5..8df933a007 100644 --- a/drivers/video/drm/i915/i915_drv.h +++ b/drivers/video/drm/i915/i915_drv.h @@ -30,6 +30,8 @@ #ifndef _I915_DRV_H_ #define _I915_DRV_H_ +#include + #include "i915_reg.h" #include "intel_bios.h" #include "intel_ringbuffer.h" @@ -96,7 +98,12 @@ enum port { }; #define port_name(p) ((p) + 'A') -#define I915_GEM_GPU_DOMAINS (~(I915_GEM_DOMAIN_CPU | I915_GEM_DOMAIN_GTT)) +#define I915_GEM_GPU_DOMAINS \ + (I915_GEM_DOMAIN_RENDER | \ + I915_GEM_DOMAIN_SAMPLER | \ + I915_GEM_DOMAIN_COMMAND | \ + I915_GEM_DOMAIN_INSTRUCTION | \ + I915_GEM_DOMAIN_VERTEX) #define for_each_pipe(p) for ((p) = 0; (p) < dev_priv->num_pipe; (p)++) @@ -114,6 +121,19 @@ struct intel_pch_pll { }; #define I915_NUM_PLLS 2 +/* Used by dp and fdi links */ +struct intel_link_m_n { + uint32_t tu; + uint32_t gmch_m; + uint32_t gmch_n; + uint32_t link_m; + uint32_t link_n; +}; + +void intel_link_compute_m_n(int bpp, int nlanes, + int pixel_clock, int link_clock, + struct intel_link_m_n *m_n); + struct intel_ddi_plls { int spll_refcount; int wrpll1_refcount; @@ -143,7 +163,12 @@ struct intel_ddi_plls { #define I915_GEM_PHYS_OVERLAY_REGS 3 #define I915_MAX_PHYS_OBJECT (I915_GEM_PHYS_OVERLAY_REGS) - +struct drm_i915_gem_phys_object { + int id; + struct page **page_list; + drm_dma_handle_t *handle; + struct drm_i915_gem_object *cur_obj; +}; struct opregion_header; struct opregion_acpi; @@ -287,6 +312,7 @@ struct drm_i915_display_funcs { struct drm_i915_gem_object *obj); int (*update_plane)(struct drm_crtc *crtc, struct drm_framebuffer *fb, int x, int y); + void (*hpd_irq_setup)(struct drm_device *dev); /* clock updates for mode set */ /* cursor updates */ /* render clock increase/decrease */ @@ -326,6 +352,7 @@ struct drm_i915_gt_funcs { DEV_INFO_FLAG(has_llc) struct intel_device_info { + u32 display_mmio_offset; u8 gen; u8 is_mobile:1; u8 is_i85x:1; @@ -353,6 +380,50 @@ struct intel_device_info { u8 has_llc:1; }; +enum i915_cache_level { + I915_CACHE_NONE = 0, + I915_CACHE_LLC, + I915_CACHE_LLC_MLC, /* gen6+, in docs at least! */ +}; + +/* The Graphics Translation Table is the way in which GEN hardware translates a + * Graphics Virtual Address into a Physical Address. In addition to the normal + * collateral associated with any va->pa translations GEN hardware also has a + * portion of the GTT which can be mapped by the CPU and remain both coherent + * and correct (in cases like swizzling). That region is referred to as GMADR in + * the spec. + */ +struct i915_gtt { + unsigned long start; /* Start offset of used GTT */ + size_t total; /* Total size GTT can map */ + size_t stolen_size; /* Total size of stolen memory */ + + unsigned long mappable_end; /* End offset that we can CPU map */ + struct io_mapping *mappable; /* Mapping to our CPU mappable region */ + phys_addr_t mappable_base; /* PA of our GMADR */ + + /** "Graphics Stolen Memory" holds the global PTEs */ + void __iomem *gsm; + + bool do_idle_maps; + dma_addr_t scratch_page_dma; + struct page *scratch_page; + + /* global gtt ops */ + int (*gtt_probe)(struct drm_device *dev, size_t *gtt_total, + size_t *stolen, phys_addr_t *mappable_base, + unsigned long *mappable_end); + void (*gtt_remove)(struct drm_device *dev); + void (*gtt_clear_range)(struct drm_device *dev, + unsigned int first_entry, + unsigned int num_entries); + void (*gtt_insert_entries)(struct drm_device *dev, + struct sg_table *st, + unsigned int pg_start, + enum i915_cache_level cache_level); +}; +#define gtt_total_entries(gtt) ((gtt).total >> PAGE_SHIFT) + #define I915_PPGTT_PD_ENTRIES 512 #define I915_PPGTT_PT_ENTRIES 1024 struct i915_hw_ppgtt { @@ -362,6 +433,16 @@ struct i915_hw_ppgtt { uint32_t pd_offset; dma_addr_t *pt_dma_addr; dma_addr_t scratch_page_dma_addr; + + /* pte functions, mirroring the interface of the global gtt. */ + void (*clear_range)(struct i915_hw_ppgtt *ppgtt, + unsigned int first_entry, + unsigned int num_entries); + void (*insert_entries)(struct i915_hw_ppgtt *ppgtt, + struct sg_table *st, + unsigned int pg_start, + enum i915_cache_level cache_level); + void (*cleanup)(struct i915_hw_ppgtt *ppgtt); }; @@ -588,6 +669,9 @@ struct intel_gen6_power_mgmt { struct mutex hw_lock; }; +/* defined intel_pm.c */ +extern spinlock_t mchdev_lock; + struct intel_ilk_power_mgmt { u8 cur_delay; u8 min_delay; @@ -628,6 +712,158 @@ struct intel_l3_parity { struct work_struct error_work; }; +struct i915_gem_mm { + /** Memory allocator for GTT stolen memory */ + struct drm_mm stolen; + /** Memory allocator for GTT */ + struct drm_mm gtt_space; + /** List of all objects in gtt_space. Used to restore gtt + * mappings on resume */ + struct list_head bound_list; + /** + * List of objects which are not bound to the GTT (thus + * are idle and not used by the GPU) but still have + * (presumably uncached) pages still attached. + */ + struct list_head unbound_list; + + /** Usable portion of the GTT for GEM */ + unsigned long stolen_base; /* limited to low memory (32-bit) */ + + int gtt_mtrr; + + /** PPGTT used for aliasing the PPGTT with the GTT */ + struct i915_hw_ppgtt *aliasing_ppgtt; + + bool shrinker_no_lock_stealing; + + /** + * List of objects currently involved in rendering. + * + * Includes buffers having the contents of their GPU caches + * flushed, not necessarily primitives. last_rendering_seqno + * represents when the rendering involved will be completed. + * + * A reference is held on the buffer while on this list. + */ + struct list_head active_list; + + /** + * LRU list of objects which are not in the ringbuffer and + * are ready to unbind, but are still in the GTT. + * + * last_rendering_seqno is 0 while an object is in this list. + * + * A reference is not held on the buffer while on this list, + * as merely being GTT-bound shouldn't prevent its being + * freed, and we'll pull it off the list in the free path. + */ + struct list_head inactive_list; + + /** LRU list of objects with fence regs on them. */ + struct list_head fence_list; + + /** + * We leave the user IRQ off as much as possible, + * but this means that requests will finish and never + * be retired once the system goes idle. Set a timer to + * fire periodically while the ring is running. When it + * fires, go retire requests. + */ + struct delayed_work retire_work; + + /** + * Are we in a non-interruptible section of code like + * modesetting? + */ + bool interruptible; + + /** + * Flag if the X Server, and thus DRM, is not currently in + * control of the device. + * + * This is set between LeaveVT and EnterVT. It needs to be + * replaced with a semaphore. It also needs to be + * transitioned away from for kernel modesetting. + */ + int suspended; + + /** Bit 6 swizzling required for X tiling */ + uint32_t bit_6_swizzle_x; + /** Bit 6 swizzling required for Y tiling */ + uint32_t bit_6_swizzle_y; + + /* storage for physical objects */ + struct drm_i915_gem_phys_object *phys_objs[I915_MAX_PHYS_OBJECT]; + + /* accounting, useful for userland debugging */ + size_t object_memory; + u32 object_count; +}; + +struct i915_gpu_error { + /* For hangcheck timer */ +#define DRM_I915_HANGCHECK_PERIOD 1500 /* in ms */ +#define DRM_I915_HANGCHECK_JIFFIES msecs_to_jiffies(DRM_I915_HANGCHECK_PERIOD) + struct timer_list hangcheck_timer; + int hangcheck_count; + uint32_t last_acthd[I915_NUM_RINGS]; + uint32_t prev_instdone[I915_NUM_INSTDONE_REG]; + + /* For reset and error_state handling. */ + spinlock_t lock; + /* Protected by the above dev->gpu_error.lock. */ + struct drm_i915_error_state *first_error; + struct work_struct work; + + unsigned long last_reset; + + /** + * State variable and reset counter controlling the reset flow + * + * Upper bits are for the reset counter. This counter is used by the + * wait_seqno code to race-free noticed that a reset event happened and + * that it needs to restart the entire ioctl (since most likely the + * seqno it waited for won't ever signal anytime soon). + * + * This is important for lock-free wait paths, where no contended lock + * naturally enforces the correct ordering between the bail-out of the + * waiter and the gpu reset work code. + * + * Lowest bit controls the reset state machine: Set means a reset is in + * progress. This state will (presuming we don't have any bugs) decay + * into either unset (successful reset) or the special WEDGED value (hw + * terminally sour). All waiters on the reset_queue will be woken when + * that happens. + */ + atomic_t reset_counter; + + /** + * Special values/flags for reset_counter + * + * Note that the code relies on + * I915_WEDGED & I915_RESET_IN_PROGRESS_FLAG + * being true. + */ +#define I915_RESET_IN_PROGRESS_FLAG 1 +#define I915_WEDGED 0xffffffff + + /** + * Waitqueue to signal when the reset has completed. Used by clients + * that wait for dev_priv->mm.wedged to settle. + */ + wait_queue_head_t reset_queue; + + /* For gpu hang simulation. */ + unsigned int stop_rings; +}; + +enum modeset_restore { + MODESET_ON_LID_OPEN, + MODESET_DONE, + MODESET_SUSPENDED, +}; + typedef struct drm_i915_private { struct drm_device *dev; @@ -644,10 +880,11 @@ typedef struct drm_i915_private { /** forcewake_count is protected by gt_lock */ unsigned forcewake_count; /** gt_lock is also taken in irq contexts. */ - struct spinlock gt_lock; + spinlock_t gt_lock; struct intel_gmbus gmbus[GMBUS_NUM_PORTS]; + /** gmbus_mutex protects against concurrent usage of the single hw gmbus * controller on different i2c buses. */ struct mutex gmbus_mutex; @@ -657,9 +894,11 @@ typedef struct drm_i915_private { */ uint32_t gpio_mmio_base; + wait_queue_head_t gmbus_wait_queue; + struct pci_dev *bridge_dev; struct intel_ring_buffer ring[I915_NUM_RINGS]; - uint32_t next_seqno; + uint32_t last_seqno, next_seqno; drm_dma_handle_t *status_page_dmah; struct resource mch_res; @@ -669,31 +908,24 @@ typedef struct drm_i915_private { /* protects the irq masks */ spinlock_t irq_lock; + /* To control wakeup latency, e.g. for irq-driven dp aux transfers. */ +// struct pm_qos_request pm_qos; + /* DPIO indirect register protection */ - spinlock_t dpio_lock; + struct mutex dpio_lock; /** Cached value of IMR to avoid reads in updating the bitfield */ u32 pipestat[2]; u32 irq_mask; u32 gt_irq_mask; - u32 pch_irq_mask; u32 hotplug_supported_mask; struct work_struct hotplug_work; + bool enable_hotplug_processing; int num_pipe; int num_pch_pll; - /* For hangcheck timer */ -#define DRM_I915_HANGCHECK_PERIOD 1500 /* in ms */ -#define DRM_I915_HANGCHECK_JIFFIES msecs_to_jiffies(DRM_I915_HANGCHECK_PERIOD) - struct timer_list hangcheck_timer; - int hangcheck_count; - uint32_t last_acthd[I915_NUM_RINGS]; - uint32_t prev_instdone[I915_NUM_INSTDONE_REG]; - - unsigned int stop_rings; - unsigned long cfb_size; unsigned int cfb_fb; enum plane cfb_plane; @@ -704,7 +936,7 @@ typedef struct drm_i915_private { /* overlay */ struct intel_overlay *overlay; - bool sprite_scaling_enabled; + unsigned int sprite_scaling_enabled; /* LVDS info */ int backlight_level; /* restore backlight to this value */ @@ -721,7 +953,6 @@ typedef struct drm_i915_private { unsigned int display_clock_mode:1; int lvds_ssc_freq; unsigned int bios_lvds_val; /* initial [PCH_]LVDS reg val in VBIOS */ - unsigned int lvds_val; /* used for checking LVDS channel mode */ struct { int rate; int lanes; @@ -742,11 +973,6 @@ typedef struct drm_i915_private { unsigned int fsb_freq, mem_freq, is_ddr3; - spinlock_t error_lock; - /* Protected by dev->error_lock. */ - struct drm_i915_error_state *first_error; - struct work_struct error_work; - struct completion error_completion; struct workqueue_struct *wq; /* Display functions */ @@ -758,115 +984,12 @@ typedef struct drm_i915_private { unsigned long quirks; - /* Register state */ - bool modeset_on_lid; + enum modeset_restore modeset_restore; + struct mutex modeset_restore_lock; - struct { - /** Bridge to intel-gtt-ko */ - struct intel_gtt *gtt; - /** Memory allocator for GTT stolen memory */ - struct drm_mm stolen; - /** Memory allocator for GTT */ - struct drm_mm gtt_space; - /** List of all objects in gtt_space. Used to restore gtt - * mappings on resume */ - struct list_head bound_list; - /** - * List of objects which are not bound to the GTT (thus - * are idle and not used by the GPU) but still have - * (presumably uncached) pages still attached. - */ - struct list_head unbound_list; + struct i915_gtt gtt; - /** Usable portion of the GTT for GEM */ - unsigned long gtt_start; - unsigned long gtt_mappable_end; - unsigned long gtt_end; - -// struct io_mapping *gtt_mapping; - phys_addr_t gtt_base_addr; - int gtt_mtrr; - - /** PPGTT used for aliasing the PPGTT with the GTT */ - struct i915_hw_ppgtt *aliasing_ppgtt; - -// struct shrinker inactive_shrinker; - bool shrinker_no_lock_stealing; - - /** - * List of objects currently involved in rendering. - * - * Includes buffers having the contents of their GPU caches - * flushed, not necessarily primitives. last_rendering_seqno - * represents when the rendering involved will be completed. - * - * A reference is held on the buffer while on this list. - */ - struct list_head active_list; - - /** - * LRU list of objects which are not in the ringbuffer and - * are ready to unbind, but are still in the GTT. - * - * last_rendering_seqno is 0 while an object is in this list. - * - * A reference is not held on the buffer while on this list, - * as merely being GTT-bound shouldn't prevent its being - * freed, and we'll pull it off the list in the free path. - */ - struct list_head inactive_list; - - /** LRU list of objects with fence regs on them. */ - struct list_head fence_list; - - /** - * We leave the user IRQ off as much as possible, - * but this means that requests will finish and never - * be retired once the system goes idle. Set a timer to - * fire periodically while the ring is running. When it - * fires, go retire requests. - */ - struct delayed_work retire_work; - - /** - * Are we in a non-interruptible section of code like - * modesetting? - */ - bool interruptible; - - /** - * Flag if the X Server, and thus DRM, is not currently in - * control of the device. - * - * This is set between LeaveVT and EnterVT. It needs to be - * replaced with a semaphore. It also needs to be - * transitioned away from for kernel modesetting. - */ - int suspended; - - /** - * Flag if the hardware appears to be wedged. - * - * This is set when attempts to idle the device timeout. - * It prevents command submission from occurring and makes - * every pending request fail - */ - atomic_t wedged; - - /** Bit 6 swizzling required for X tiling */ - uint32_t bit_6_swizzle_x; - /** Bit 6 swizzling required for Y tiling */ - uint32_t bit_6_swizzle_y; - - /* storage for physical objects */ -// struct drm_i915_gem_phys_object *phys_objs[I915_MAX_PHYS_OBJECT]; - - /* accounting, useful for userland debugging */ - size_t gtt_total; - size_t mappable_gtt_total; - size_t object_memory; - u32 object_count; - } mm; + struct i915_gem_mm mm; /* Kernel Modesetting */ @@ -908,7 +1031,7 @@ typedef struct drm_i915_private { struct drm_mm_node *compressed_fb; struct drm_mm_node *compressed_llb; - unsigned long last_gpu_reset; + struct i915_gpu_error gpu_error; /* list of fbdev register on this device */ struct intel_fbdev *fbdev; @@ -927,7 +1050,7 @@ typedef struct drm_i915_private { bool hw_contexts_disabled; uint32_t hw_context_size; - bool fdi_rx_polarity_reversed; + u32 fdi_rx_config; struct i915_suspend_saved_registers regfile; @@ -948,11 +1071,7 @@ enum hdmi_force_audio { HDMI_AUDIO_ON, /* force turn on HDMI audio */ }; -enum i915_cache_level { - I915_CACHE_NONE = 0, - I915_CACHE_LLC, - I915_CACHE_LLC_MLC, /* gen6+, in docs at least! */ -}; +#define I915_GTT_RESERVED ((struct drm_mm_node *)0x1) struct drm_i915_gem_object_ops { /* Interface between the GEM object and its backing storage. @@ -977,10 +1096,10 @@ struct drm_i915_gem_object { const struct drm_i915_gem_object_ops *ops; -// void *mapped; - /** Current space allocated to this object in the GTT, if any. */ struct drm_mm_node *gtt_space; + /** Stolen memory for this object, instead of being backed by shmem. */ + struct drm_mm_node *stolen; struct list_head gtt_list; /** This object's place on the active/inactive lists */ @@ -1065,7 +1184,6 @@ struct drm_i915_gem_object { unsigned int has_global_gtt_mapping:1; unsigned int has_dma_mapping:1; -// dma_addr_t *allocated_pages; struct sg_table *pages; int pages_pin_count; @@ -1107,13 +1225,6 @@ struct drm_i915_gem_object { /** for phy allocated objects */ struct drm_i915_gem_phys_object *phys_obj; - - /** - * Number of crtcs where this object is currently the fb, but - * will be page flipped away on the next vblank. When it - * reaches 0, dev_priv->pending_flip_queue will be woken up. - */ - atomic_t pending_flip; }; #define to_gem_object(obj) (&((struct drm_i915_gem_object *)(obj))->base) @@ -1152,7 +1263,7 @@ struct drm_i915_gem_request { struct drm_i915_file_private { struct { - struct spinlock lock; + spinlock_t lock; struct list_head request_list; } mm; struct idr context_idr; @@ -1238,6 +1349,8 @@ struct drm_i915_file_private { #define HAS_PIPE_CONTROL(dev) (INTEL_INFO(dev)->gen >= 5) +#define HAS_DDI(dev) (IS_HASWELL(dev)) + #define INTEL_PCH_DEVICE_ID_MASK 0xff00 #define INTEL_PCH_IBX_DEVICE_ID_TYPE 0x3b00 #define INTEL_PCH_CPT_DEVICE_ID_TYPE 0x1c00 @@ -1293,6 +1406,7 @@ extern int i915_enable_fbc __read_mostly; extern bool i915_enable_hangcheck __read_mostly; extern int i915_enable_ppgtt __read_mostly; extern unsigned int i915_preliminary_hw_support __read_mostly; +extern int i915_disable_power_well __read_mostly; extern int i915_master_create(struct drm_device *dev, struct drm_master *master); extern void i915_master_destroy(struct drm_device *dev, struct drm_master *master); @@ -1329,6 +1443,7 @@ void i915_hangcheck_elapsed(unsigned long data); void i915_handle_error(struct drm_device *dev, bool wedged); extern void intel_irq_init(struct drm_device *dev); +extern void intel_hpd_init(struct drm_device *dev); extern void intel_gt_init(struct drm_device *dev); extern void intel_gt_reset(struct drm_device *dev); @@ -1397,18 +1512,22 @@ int i915_gem_get_aperture_ioctl(struct drm_device *dev, void *data, int i915_gem_wait_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); void i915_gem_load(struct drm_device *dev); +void *i915_gem_object_alloc(struct drm_device *dev); +void i915_gem_object_free(struct drm_i915_gem_object *obj); int i915_gem_init_object(struct drm_gem_object *obj); void i915_gem_object_init(struct drm_i915_gem_object *obj, const struct drm_i915_gem_object_ops *ops); struct drm_i915_gem_object *i915_gem_alloc_object(struct drm_device *dev, size_t size); void i915_gem_free_object(struct drm_gem_object *obj); + int __must_check i915_gem_object_pin(struct drm_i915_gem_object *obj, uint32_t alignment, bool map_and_fenceable, bool nonblocking); void i915_gem_object_unpin(struct drm_i915_gem_object *obj); int __must_check i915_gem_object_unbind(struct drm_i915_gem_object *obj); +int i915_gem_object_put_pages(struct drm_i915_gem_object *obj); void i915_gem_release_mmap(struct drm_i915_gem_object *obj); void i915_gem_lastclose(struct drm_device *dev); @@ -1460,8 +1579,8 @@ i915_seqno_passed(uint32_t seq1, uint32_t seq2) return (int32_t)(seq1 - seq2) >= 0; } -extern int i915_gem_get_seqno(struct drm_device *dev, u32 *seqno); - +int __must_check i915_gem_get_seqno(struct drm_device *dev, u32 *seqno); +int __must_check i915_gem_set_seqno(struct drm_device *dev, u32 seqno); int __must_check i915_gem_object_get_fence(struct drm_i915_gem_object *obj); int __must_check i915_gem_object_put_fence(struct drm_i915_gem_object *obj); @@ -1487,8 +1606,18 @@ i915_gem_object_unpin_fence(struct drm_i915_gem_object *obj) void i915_gem_retire_requests(struct drm_device *dev); void i915_gem_retire_requests_ring(struct intel_ring_buffer *ring); -int __must_check i915_gem_check_wedge(struct drm_i915_private *dev_priv, +int __must_check i915_gem_check_wedge(struct i915_gpu_error *error, bool interruptible); +static inline bool i915_reset_in_progress(struct i915_gpu_error *error) +{ + return unlikely(atomic_read(&error->reset_counter) + & I915_RESET_IN_PROGRESS_FLAG); +} + +static inline bool i915_terminally_wedged(struct i915_gpu_error *error) +{ + return atomic_read(&error->reset_counter) == I915_WEDGED; +} void i915_gem_reset(struct drm_device *dev); void i915_gem_clflush_object(struct drm_i915_gem_object *obj); @@ -1529,9 +1658,10 @@ void i915_gem_free_all_phys_object(struct drm_device *dev); void i915_gem_release(struct drm_device *dev, struct drm_file *file); uint32_t -i915_gem_get_unfenced_gtt_alignment(struct drm_device *dev, - uint32_t size, - int tiling_mode); +i915_gem_get_gtt_size(struct drm_device *dev, uint32_t size, int tiling_mode); +uint32_t +i915_gem_get_gtt_alignment(struct drm_device *dev, uint32_t size, + int tiling_mode, bool fenced); int i915_gem_object_set_cache_level(struct drm_i915_gem_object *obj, enum i915_cache_level cache_level); @@ -1552,7 +1682,6 @@ int i915_gem_context_destroy_ioctl(struct drm_device *dev, void *data, struct drm_file *file); /* i915_gem_gtt.c */ -int __must_check i915_gem_init_aliasing_ppgtt(struct drm_device *dev); void i915_gem_cleanup_aliasing_ppgtt(struct drm_device *dev); void i915_ppgtt_bind_object(struct i915_hw_ppgtt *ppgtt, struct drm_i915_gem_object *obj, @@ -1566,12 +1695,10 @@ void i915_gem_gtt_bind_object(struct drm_i915_gem_object *obj, enum i915_cache_level cache_level); void i915_gem_gtt_unbind_object(struct drm_i915_gem_object *obj); void i915_gem_gtt_finish_object(struct drm_i915_gem_object *obj); -void i915_gem_init_global_gtt(struct drm_device *dev, - unsigned long start, - unsigned long mappable_end, - unsigned long end); +void i915_gem_init_global_gtt(struct drm_device *dev); +void i915_gem_setup_global_gtt(struct drm_device *dev, unsigned long start, + unsigned long mappable_end, unsigned long end); int i915_gem_gtt_init(struct drm_device *dev); -void i915_gem_gtt_fini(struct drm_device *dev); static inline void i915_gem_chipset_flush(struct drm_device *dev) { if (INTEL_INFO(dev)->gen < 6) @@ -1589,9 +1716,22 @@ int i915_gem_evict_everything(struct drm_device *dev); /* i915_gem_stolen.c */ int i915_gem_init_stolen(struct drm_device *dev); +int i915_gem_stolen_setup_compression(struct drm_device *dev, int size); +void i915_gem_stolen_cleanup_compression(struct drm_device *dev); void i915_gem_cleanup_stolen(struct drm_device *dev); +struct drm_i915_gem_object * +i915_gem_object_create_stolen(struct drm_device *dev, u32 size); +void i915_gem_object_release_stolen(struct drm_i915_gem_object *obj); /* i915_gem_tiling.c */ +inline static bool i915_gem_object_needs_bit17_swizzle(struct drm_i915_gem_object *obj) +{ + drm_i915_private_t *dev_priv = obj->base.dev->dev_private; + + return dev_priv->mm.bit_6_swizzle_x == I915_BIT_6_SWIZZLE_9_10_17 && + obj->tiling_mode != I915_TILING_NONE; +} + void i915_gem_detect_bit_6_swizzle(struct drm_device *dev); void i915_gem_object_do_bit_17_swizzle(struct drm_i915_gem_object *obj); void i915_gem_object_save_bit_17_swizzle(struct drm_i915_gem_object *obj); @@ -1617,9 +1757,9 @@ void i915_debugfs_cleanup(struct drm_minor *minor); extern int i915_save_state(struct drm_device *dev); extern int i915_restore_state(struct drm_device *dev); -/* i915_suspend.c */ -extern int i915_save_state(struct drm_device *dev); -extern int i915_restore_state(struct drm_device *dev); +/* i915_ums.c */ +void i915_save_display_reg(struct drm_device *dev); +void i915_restore_display_reg(struct drm_device *dev); /* i915_sysfs.c */ void i915_setup_sysfs(struct drm_device *dev_priv); @@ -1676,6 +1816,7 @@ extern void intel_modeset_cleanup(struct drm_device *dev); extern int intel_modeset_vga_set_state(struct drm_device *dev, bool state); extern void intel_modeset_setup_hw_state(struct drm_device *dev, bool force_restore); +extern void i915_redisable_vga(struct drm_device *dev); extern bool intel_fbc_enabled(struct drm_device *dev); extern void intel_disable_fbc(struct drm_device *dev); extern bool ironlake_set_drps(struct drm_device *dev, u8 val); @@ -1748,6 +1889,21 @@ __i915_write(64, q) #define POSTING_READ(reg) (void)I915_READ_NOTRACE(reg) #define POSTING_READ16(reg) (void)I915_READ16_NOTRACE(reg) +/* "Broadcast RGB" property */ +#define INTEL_BROADCAST_RGB_AUTO 0 +#define INTEL_BROADCAST_RGB_FULL 1 +#define INTEL_BROADCAST_RGB_LIMITED 2 + +static inline uint32_t i915_vgacntrl_reg(struct drm_device *dev) +{ + if (HAS_PCH_SPLIT(dev)) + return CPU_VGACNTRL; + else if (IS_VALLEYVIEW(dev)) + return VLV_VGACNTRL; + else + return VGACNTRL; +} + typedef struct { int width; diff --git a/drivers/video/drm/i915/i915_gem.c b/drivers/video/drm/i915/i915_gem.c index 76ae5d4bad..87620fef0b 100644 --- a/drivers/video/drm/i915/i915_gem.c +++ b/drivers/video/drm/i915/i915_gem.c @@ -118,14 +118,12 @@ static void i915_gem_info_remove_obj(struct drm_i915_private *dev_priv, } static int -i915_gem_wait_for_error(struct drm_device *dev) +i915_gem_wait_for_error(struct i915_gpu_error *error) { - struct drm_i915_private *dev_priv = dev->dev_private; - struct completion *x = &dev_priv->error_completion; - unsigned long flags; int ret; - if (!atomic_read(&dev_priv->mm.wedged)) +#define EXIT_COND (!i915_reset_in_progress(error)) + if (EXIT_COND) return 0; #if 0 /* @@ -133,7 +131,9 @@ i915_gem_wait_for_error(struct drm_device *dev) * userspace. If it takes that long something really bad is going on and * we should simply try to bail out and fail as gracefully as possible. */ - ret = wait_for_completion_interruptible_timeout(x, 10*HZ); + ret = wait_event_interruptible_timeout(error->reset_queue, + EXIT_COND, + 10*HZ); if (ret == 0) { DRM_ERROR("Timed out waiting for the gpu reset to complete\n"); return -EIO; @@ -141,30 +141,24 @@ i915_gem_wait_for_error(struct drm_device *dev) return ret; } - if (atomic_read(&dev_priv->mm.wedged)) { - /* GPU is hung, bump the completion count to account for - * the token we just consumed so that we never hit zero and - * end up waiting upon a subsequent completion event that - * will never happen. - */ - spin_lock_irqsave(&x->wait.lock, flags); - x->done++; - spin_unlock_irqrestore(&x->wait.lock, flags); - } #endif +#undef EXIT_COND return 0; } int i915_mutex_lock_interruptible(struct drm_device *dev) { + struct drm_i915_private *dev_priv = dev->dev_private; int ret; - ret = i915_gem_wait_for_error(dev); + ret = i915_gem_wait_for_error(&dev_priv->gpu_error); if (ret) return ret; - mutex_lock(&dev->struct_mutex); + ret = mutex_lock_interruptible(&dev->struct_mutex); + if (ret) + return ret; WARN_ON(i915_verify_lists(dev)); return 0; @@ -183,6 +177,7 @@ int i915_gem_init_ioctl(struct drm_device *dev, void *data, struct drm_file *file) { + struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_gem_init *args = data; if (drm_core_check_feature(dev, DRIVER_MODESET)) @@ -197,8 +192,9 @@ i915_gem_init_ioctl(struct drm_device *dev, void *data, return -ENODEV; mutex_lock(&dev->struct_mutex); - i915_gem_init_global_gtt(dev, args->gtt_start, - args->gtt_end, args->gtt_end); + i915_gem_setup_global_gtt(dev, args->gtt_start, args->gtt_end, + args->gtt_end); + dev_priv->gtt.mappable_end = args->gtt_end; mutex_unlock(&dev->struct_mutex); return 0; @@ -221,12 +217,24 @@ i915_gem_get_aperture_ioctl(struct drm_device *dev, void *data, pinned += obj->gtt_space->size; mutex_unlock(&dev->struct_mutex); - args->aper_size = dev_priv->mm.gtt_total; + args->aper_size = dev_priv->gtt.total; args->aper_available_size = args->aper_size - pinned; return 0; } +void *i915_gem_object_alloc(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + return kmalloc(sizeof(struct drm_i915_gem_object), 0); +} + +void i915_gem_object_free(struct drm_i915_gem_object *obj) +{ + struct drm_i915_private *dev_priv = obj->base.dev->dev_private; + kfree(obj); +} + static int i915_gem_create(struct drm_file *file, struct drm_device *dev, @@ -297,13 +305,7 @@ i915_gem_create_ioctl(struct drm_device *dev, void *data, args->size, &args->handle); } -static int i915_gem_object_needs_bit17_swizzle(struct drm_i915_gem_object *obj) -{ - drm_i915_private_t *dev_priv = obj->base.dev->dev_private; - return dev_priv->mm.bit_6_swizzle_x == I915_BIT_6_SWIZZLE_9_10_17 && - obj->tiling_mode != I915_TILING_NONE; -} #if 0 static inline int @@ -446,7 +448,6 @@ i915_gem_shmem_pread(struct drm_device *dev, loff_t offset; int shmem_page_offset, page_length, ret = 0; int obj_do_bit17_swizzling, page_do_bit17_swizzling; - int hit_slowpath = 0; int prefaulted = 0; int needs_clflush = 0; struct scatterlist *sg; @@ -508,7 +509,6 @@ i915_gem_shmem_pread(struct drm_device *dev, if (ret == 0) goto next_page; - hit_slowpath = 1; mutex_unlock(&dev->struct_mutex); if (!prefaulted) { @@ -541,12 +541,6 @@ next_page: out: i915_gem_object_unpin_pages(obj); - if (hit_slowpath) { - /* Fixup: Kill any reinstated backing storage pages */ - if (obj->madv == __I915_MADV_PURGED) - i915_gem_object_truncate(obj); - } - return ret; } @@ -888,12 +882,13 @@ out: i915_gem_object_unpin_pages(obj); if (hit_slowpath) { - /* Fixup: Kill any reinstated backing storage pages */ - if (obj->madv == __I915_MADV_PURGED) - i915_gem_object_truncate(obj); - /* and flush dirty cachelines in case the object isn't in the cpu write - * domain anymore. */ - if (obj->base.write_domain != I915_GEM_DOMAIN_CPU) { + /* + * Fixup: Flush cpu caches in case we didn't flush the dirty + * cachelines in-line while writing and the object moved + * out of the cpu write domain while we've dropped the lock. + */ + if (!needs_clflush_after && + obj->base.write_domain != I915_GEM_DOMAIN_CPU) { i915_gem_clflush_object(obj); i915_gem_chipset_flush(dev); } @@ -918,6 +913,12 @@ i915_gem_pwrite_ioctl(struct drm_device *dev, void *data, struct drm_i915_gem_object *obj; int ret; + if(args->handle == -2) + { + printf("%s handle %d\n", __FUNCTION__, args->handle); + return 0; + } + if (args->size == 0) return 0; @@ -980,26 +981,17 @@ unlock: } int -i915_gem_check_wedge(struct drm_i915_private *dev_priv, +i915_gem_check_wedge(struct i915_gpu_error *error, bool interruptible) { - if (atomic_read(&dev_priv->mm.wedged)) { - struct completion *x = &dev_priv->error_completion; - bool recovery_complete; - unsigned long flags; - - /* Give the error handler a chance to run. */ - spin_lock_irqsave(&x->wait.lock, flags); - recovery_complete = x->done > 0; - spin_unlock_irqrestore(&x->wait.lock, flags); - + if (i915_reset_in_progress(error)) { /* Non-interruptible callers can't handle -EAGAIN, hence return * -EIO unconditionally for these. */ if (!interruptible) return -EIO; - /* Recovery complete, but still wedged means reset failure. */ - if (recovery_complete) + /* Recovery complete, but the reset failed ... */ + if (i915_terminally_wedged(error)) return -EIO; return -EAGAIN; @@ -1030,13 +1022,22 @@ i915_gem_check_olr(struct intel_ring_buffer *ring, u32 seqno) * __wait_seqno - wait until execution of seqno has finished * @ring: the ring expected to report seqno * @seqno: duh! + * @reset_counter: reset sequence associated with the given seqno * @interruptible: do an interruptible wait (normally yes) * @timeout: in - how long to wait (NULL forever); out - how much time remaining * + * Note: It is of utmost importance that the passed in seqno and reset_counter + * values have been read by the caller in an smp safe manner. Where read-side + * locks are involved, it is sufficient to read the reset_counter before + * unlocking the lock that protects the seqno. For lockless tricks, the + * reset_counter _must_ be read before, and an appropriate smp_rmb must be + * inserted. + * * Returns 0 if the seqno was found within the alloted time. Else returns the * errno with remaining time filled in timeout argument. */ static int __wait_seqno(struct intel_ring_buffer *ring, u32 seqno, + unsigned reset_counter, bool interruptible, struct timespec *timeout) { drm_i915_private_t *dev_priv = ring->dev->dev_private; @@ -1066,7 +1067,8 @@ static int __wait_seqno(struct intel_ring_buffer *ring, u32 seqno, #define EXIT_COND \ (i915_seqno_passed(ring->get_seqno(ring, false), seqno) || \ - atomic_read(&dev_priv->mm.wedged)) + i915_reset_in_progress(&dev_priv->gpu_error) || \ + reset_counter != atomic_read(&dev_priv->gpu_error.reset_counter)) do { if (interruptible) end = wait_event_interruptible_timeout(ring->irq_queue, @@ -1076,7 +1078,14 @@ static int __wait_seqno(struct intel_ring_buffer *ring, u32 seqno, end = wait_event_timeout(ring->irq_queue, EXIT_COND, timeout_jiffies); - ret = i915_gem_check_wedge(dev_priv, interruptible); + /* We need to check whether any gpu reset happened in between + * the caller grabbing the seqno and now ... */ + if (reset_counter != atomic_read(&dev_priv->gpu_error.reset_counter)) + end = -EAGAIN; + + /* ... but upgrade the -EGAIN to an -EIO if the gpu is truely + * gone. */ + ret = i915_gem_check_wedge(&dev_priv->gpu_error, interruptible); if (ret) end = ret; } while (end == 0 && wait_forever); @@ -1122,7 +1131,7 @@ i915_wait_seqno(struct intel_ring_buffer *ring, uint32_t seqno) BUG_ON(!mutex_is_locked(&dev->struct_mutex)); BUG_ON(seqno == 0); - ret = i915_gem_check_wedge(dev_priv, interruptible); + ret = i915_gem_check_wedge(&dev_priv->gpu_error, interruptible); if (ret) return ret; @@ -1130,7 +1139,9 @@ i915_wait_seqno(struct intel_ring_buffer *ring, uint32_t seqno) if (ret) return ret; - return __wait_seqno(ring, seqno, interruptible, NULL); + return __wait_seqno(ring, seqno, + atomic_read(&dev_priv->gpu_error.reset_counter), + interruptible, NULL); } /** @@ -1177,6 +1188,7 @@ i915_gem_object_wait_rendering__nonblocking(struct drm_i915_gem_object *obj, struct drm_device *dev = obj->base.dev; struct drm_i915_private *dev_priv = dev->dev_private; struct intel_ring_buffer *ring = obj->ring; + unsigned reset_counter; u32 seqno; int ret; @@ -1187,7 +1199,7 @@ i915_gem_object_wait_rendering__nonblocking(struct drm_i915_gem_object *obj, if (seqno == 0) return 0; - ret = i915_gem_check_wedge(dev_priv, true); + ret = i915_gem_check_wedge(&dev_priv->gpu_error, true); if (ret) return ret; @@ -1195,8 +1207,9 @@ i915_gem_object_wait_rendering__nonblocking(struct drm_i915_gem_object *obj, if (ret) return ret; + reset_counter = atomic_read(&dev_priv->gpu_error.reset_counter); mutex_unlock(&dev->struct_mutex); - ret = __wait_seqno(ring, seqno, true, NULL); + ret = __wait_seqno(ring, seqno, reset_counter, true, NULL); mutex_lock(&dev->struct_mutex); i915_gem_retire_requests_ring(ring); @@ -1227,6 +1240,13 @@ i915_gem_set_domain_ioctl(struct drm_device *dev, void *data, uint32_t write_domain = args->write_domain; int ret; + + if(args->handle == -2) + { + printf("%s handle %d\n", __FUNCTION__, args->handle); + return 0; + } + /* Only handle setting domains to types used by the CPU. */ if (write_domain & I915_GEM_GPU_DOMAINS) return -EINVAL; @@ -1298,6 +1318,12 @@ i915_gem_mmap_ioctl(struct drm_device *dev, void *data, struct drm_gem_object *obj; unsigned long addr = 0; + if(args->handle == -2) + { + printf("%s handle %d\n", __FUNCTION__, args->handle); + return 0; + } + obj = drm_gem_object_lookup(dev, file, args->handle); if (obj == NULL) return -ENOENT; @@ -1364,7 +1390,7 @@ i915_gem_release_mmap(struct drm_i915_gem_object *obj) obj->fault_mappable = false; } -static uint32_t +uint32_t i915_gem_get_gtt_size(struct drm_device *dev, uint32_t size, int tiling_mode) { uint32_t gtt_size; @@ -1392,16 +1418,15 @@ i915_gem_get_gtt_size(struct drm_device *dev, uint32_t size, int tiling_mode) * Return the required GTT alignment for an object, taking into account * potential fence register mapping. */ -static uint32_t -i915_gem_get_gtt_alignment(struct drm_device *dev, - uint32_t size, - int tiling_mode) +uint32_t +i915_gem_get_gtt_alignment(struct drm_device *dev, uint32_t size, + int tiling_mode, bool fenced) { /* * Minimum alignment is 4k (GTT page size), but might be greater * if a fence register is needed for the object. */ - if (INTEL_INFO(dev)->gen >= 4 || + if (INTEL_INFO(dev)->gen >= 4 || (!fenced && IS_G33(dev)) || tiling_mode == I915_TILING_NONE) return 4096; @@ -1441,6 +1466,104 @@ i915_gem_get_unfenced_gtt_alignment(struct drm_device *dev, return i915_gem_get_gtt_size(dev, size, tiling_mode); } +int +i915_gem_mmap_gtt(struct drm_file *file, + struct drm_device *dev, + uint32_t handle, + uint64_t *offset) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + struct drm_i915_gem_object *obj; + unsigned long pfn; + char *mem, *ptr; + int ret; + + ret = i915_mutex_lock_interruptible(dev); + if (ret) + return ret; + + obj = to_intel_bo(drm_gem_object_lookup(dev, file, handle)); + if (&obj->base == NULL) { + ret = -ENOENT; + goto unlock; + } + + if (obj->base.size > dev_priv->gtt.mappable_end) { + ret = -E2BIG; + goto out; + } + + if (obj->madv != I915_MADV_WILLNEED) { + DRM_ERROR("Attempting to mmap a purgeable buffer\n"); + ret = -EINVAL; + goto out; + } + /* Now bind it into the GTT if needed */ + ret = i915_gem_object_pin(obj, 0, true, false); + if (ret) + goto out; + + ret = i915_gem_object_set_to_gtt_domain(obj, 1); + if (ret) + goto unpin; + + ret = i915_gem_object_get_fence(obj); + if (ret) + goto unpin; + + obj->fault_mappable = true; + + pfn = dev_priv->gtt.mappable_base + obj->gtt_offset; + + /* Finally, remap it using the new GTT offset */ + + mem = UserAlloc(obj->base.size); + if(unlikely(mem == NULL)) + { + ret = -ENOMEM; + goto unpin; + } + + for(ptr = mem; ptr < mem + obj->base.size; ptr+= 4096, pfn+= 4096) + MapPage(ptr, pfn, PG_SHARED|PG_UW); + +unpin: + i915_gem_object_unpin(obj); + + + *offset = (u64)mem; + +out: + drm_gem_object_unreference(&obj->base); +unlock: + mutex_unlock(&dev->struct_mutex); + return ret; +} + +/** + * i915_gem_mmap_gtt_ioctl - prepare an object for GTT mmap'ing + * @dev: DRM device + * @data: GTT mapping ioctl data + * @file: GEM object info + * + * Simply returns the fake offset to userspace so it can mmap it. + * The mmap call will end up in drm_gem_mmap(), which will set things + * up so we can get faults in the handler above. + * + * The fault handler will take care of binding the object into the GTT + * (since it may have been evicted to make room for something), allocating + * a fence register, and mapping the appropriate aperture address into + * userspace. + */ +int +i915_gem_mmap_gtt_ioctl(struct drm_device *dev, void *data, + struct drm_file *file) +{ + struct drm_i915_gem_mmap_gtt *args = data; + + return i915_gem_mmap_gtt(file, dev, args->handle, &args->offset); +} + /* Immediately discard the backing storage */ static void i915_gem_object_truncate(struct drm_i915_gem_object *obj) @@ -1504,7 +1627,7 @@ i915_gem_object_put_pages_gtt(struct drm_i915_gem_object *obj) kfree(obj->pages); } -static int +int i915_gem_object_put_pages(struct drm_i915_gem_object *obj) { const struct drm_i915_gem_object_ops *ops = obj->ops; @@ -1669,9 +1792,6 @@ i915_gem_object_move_to_inactive(struct drm_i915_gem_object *obj) BUG_ON(obj->base.write_domain & ~I915_GEM_GPU_DOMAINS); BUG_ON(!obj->active); - if (obj->pin_count) /* are we a framebuffer? */ - intel_mark_fb_idle(obj); - list_move_tail(&obj->mm_list, &dev_priv->mm.inactive_list); list_del_init(&obj->ring_list); @@ -1691,30 +1811,24 @@ i915_gem_object_move_to_inactive(struct drm_i915_gem_object *obj) } static int -i915_gem_handle_seqno_wrap(struct drm_device *dev) +i915_gem_init_seqno(struct drm_device *dev, u32 seqno) { struct drm_i915_private *dev_priv = dev->dev_private; struct intel_ring_buffer *ring; int ret, i, j; - /* The hardware uses various monotonic 32-bit counters, if we - * detect that they will wraparound we need to idle the GPU - * and reset those counters. - */ - ret = 0; + /* Carefully retire all requests without writing to the rings */ for_each_ring(ring, dev_priv, i) { - for (j = 0; j < ARRAY_SIZE(ring->sync_seqno); j++) - ret |= ring->sync_seqno[j] != 0; - } - if (ret == 0) - return ret; - - ret = i915_gpu_idle(dev); + ret = intel_ring_idle(ring); if (ret) return ret; - + } i915_gem_retire_requests(dev); + + /* Finally reset hw state */ for_each_ring(ring, dev_priv, i) { + intel_ring_init_seqno(ring, seqno); + for (j = 0; j < ARRAY_SIZE(ring->sync_seqno); j++) ring->sync_seqno[j] = 0; } @@ -1722,6 +1836,32 @@ i915_gem_handle_seqno_wrap(struct drm_device *dev) return 0; } +int i915_gem_set_seqno(struct drm_device *dev, u32 seqno) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + int ret; + + if (seqno == 0) + return -EINVAL; + + /* HWS page needs to be set less than what we + * will inject to ring + */ + ret = i915_gem_init_seqno(dev, seqno - 1); + if (ret) + return ret; + + /* Carefully set the last_seqno value so that wrap + * detection still works + */ + dev_priv->next_seqno = seqno; + dev_priv->last_seqno = seqno - 1; + if (dev_priv->last_seqno == 0) + dev_priv->last_seqno--; + + return 0; +} + int i915_gem_get_seqno(struct drm_device *dev, u32 *seqno) { @@ -1729,14 +1869,14 @@ i915_gem_get_seqno(struct drm_device *dev, u32 *seqno) /* reserve 0 for non-seqno */ if (dev_priv->next_seqno == 0) { - int ret = i915_gem_handle_seqno_wrap(dev); + int ret = i915_gem_init_seqno(dev, 0); if (ret) return ret; dev_priv->next_seqno = 1; } - *seqno = dev_priv->next_seqno++; + *seqno = dev_priv->last_seqno = dev_priv->next_seqno++; return 0; } @@ -2126,15 +2266,15 @@ static void i915_gem_object_finish_gtt(struct drm_i915_gem_object *obj) { u32 old_write_domain, old_read_domains; - /* Act a barrier for all accesses through the GTT */ - mb(); - /* Force a pagefault for domain tracking on next user access */ // i915_gem_release_mmap(obj); if ((obj->base.read_domains & I915_GEM_DOMAIN_GTT) == 0) return; + /* Wait for any direct GTT access to complete */ + mb(); + old_read_domains = obj->base.read_domains; old_write_domain = obj->base.write_domain; @@ -2153,7 +2293,7 @@ int i915_gem_object_unbind(struct drm_i915_gem_object *obj) { drm_i915_private_t *dev_priv = obj->base.dev->dev_private; - int ret = 0; + int ret; if(obj == get_fb_obj()) return 0; @@ -2223,52 +2363,38 @@ int i915_gpu_idle(struct drm_device *dev) return 0; } -static void sandybridge_write_fence_reg(struct drm_device *dev, int reg, +static void i965_write_fence_reg(struct drm_device *dev, int reg, struct drm_i915_gem_object *obj) { drm_i915_private_t *dev_priv = dev->dev_private; + int fence_reg; + int fence_pitch_shift; uint64_t val; + if (INTEL_INFO(dev)->gen >= 6) { + fence_reg = FENCE_REG_SANDYBRIDGE_0; + fence_pitch_shift = SANDYBRIDGE_FENCE_PITCH_SHIFT; + } else { + fence_reg = FENCE_REG_965_0; + fence_pitch_shift = I965_FENCE_PITCH_SHIFT; + } + if (obj) { u32 size = obj->gtt_space->size; val = (uint64_t)((obj->gtt_offset + size - 4096) & 0xfffff000) << 32; val |= obj->gtt_offset & 0xfffff000; - val |= (uint64_t)((obj->stride / 128) - 1) << - SANDYBRIDGE_FENCE_PITCH_SHIFT; - + val |= (uint64_t)((obj->stride / 128) - 1) << fence_pitch_shift; if (obj->tiling_mode == I915_TILING_Y) val |= 1 << I965_FENCE_TILING_Y_SHIFT; val |= I965_FENCE_REG_VALID; } else val = 0; - I915_WRITE64(FENCE_REG_SANDYBRIDGE_0 + reg * 8, val); - POSTING_READ(FENCE_REG_SANDYBRIDGE_0 + reg * 8); -} - -static void i965_write_fence_reg(struct drm_device *dev, int reg, - struct drm_i915_gem_object *obj) -{ - drm_i915_private_t *dev_priv = dev->dev_private; - uint64_t val; - - if (obj) { - u32 size = obj->gtt_space->size; - - val = (uint64_t)((obj->gtt_offset + size - 4096) & - 0xfffff000) << 32; - val |= obj->gtt_offset & 0xfffff000; - val |= ((obj->stride / 128) - 1) << I965_FENCE_PITCH_SHIFT; - if (obj->tiling_mode == I915_TILING_Y) - val |= 1 << I965_FENCE_TILING_Y_SHIFT; - val |= I965_FENCE_REG_VALID; - } else - val = 0; - - I915_WRITE64(FENCE_REG_965_0 + reg * 8, val); - POSTING_READ(FENCE_REG_965_0 + reg * 8); + fence_reg += reg * 8; + I915_WRITE64(fence_reg, val); + POSTING_READ(fence_reg); } static void i915_write_fence_reg(struct drm_device *dev, int reg, @@ -2347,18 +2473,37 @@ static void i830_write_fence_reg(struct drm_device *dev, int reg, POSTING_READ(FENCE_REG_830_0 + reg * 4); } +inline static bool i915_gem_object_needs_mb(struct drm_i915_gem_object *obj) +{ + return obj && obj->base.read_domains & I915_GEM_DOMAIN_GTT; +} + static void i915_gem_write_fence(struct drm_device *dev, int reg, struct drm_i915_gem_object *obj) { + struct drm_i915_private *dev_priv = dev->dev_private; + + /* Ensure that all CPU reads are completed before installing a fence + * and all writes before removing the fence. + */ + if (i915_gem_object_needs_mb(dev_priv->fence_regs[reg].obj)) + mb(); + switch (INTEL_INFO(dev)->gen) { case 7: - case 6: sandybridge_write_fence_reg(dev, reg, obj); break; + case 6: case 5: case 4: i965_write_fence_reg(dev, reg, obj); break; case 3: i915_write_fence_reg(dev, reg, obj); break; case 2: i830_write_fence_reg(dev, reg, obj); break; - default: break; + default: BUG(); } + + /* And similarly be paranoid that no direct access to this region + * is reordered to before the fence is installed. + */ + if (i915_gem_object_needs_mb(obj)) + mb(); } static inline int fence_number(struct drm_i915_private *dev_priv, @@ -2388,7 +2533,7 @@ static void i915_gem_object_update_fence(struct drm_i915_gem_object *obj, } static int -i915_gem_object_flush_fence(struct drm_i915_gem_object *obj) +i915_gem_object_wait_fence(struct drm_i915_gem_object *obj) { if (obj->last_fenced_seqno) { int ret = i915_wait_seqno(obj->ring, obj->last_fenced_seqno); @@ -2398,12 +2543,6 @@ i915_gem_object_flush_fence(struct drm_i915_gem_object *obj) obj->last_fenced_seqno = 0; } - /* Ensure that all CPU reads are completed before installing a fence - * and all writes before removing the fence. - */ - if (obj->base.read_domains & I915_GEM_DOMAIN_GTT) - mb(); - obj->fenced_gpu_access = false; return 0; } @@ -2414,7 +2553,7 @@ i915_gem_object_put_fence(struct drm_i915_gem_object *obj) struct drm_i915_private *dev_priv = obj->base.dev->dev_private; int ret; - ret = i915_gem_object_flush_fence(obj); + ret = i915_gem_object_wait_fence(obj); if (ret) return ret; @@ -2488,7 +2627,7 @@ i915_gem_object_get_fence(struct drm_i915_gem_object *obj) * will need to serialise the write to the associated fence register? */ if (obj->fence_dirty) { - ret = i915_gem_object_flush_fence(obj); + ret = i915_gem_object_wait_fence(obj); if (ret) return ret; } @@ -2509,7 +2648,7 @@ i915_gem_object_get_fence(struct drm_i915_gem_object *obj) if (reg->obj) { struct drm_i915_gem_object *old = reg->obj; - ret = i915_gem_object_flush_fence(old); + ret = i915_gem_object_wait_fence(old); if (ret) return ret; @@ -2532,7 +2671,7 @@ static bool i915_gem_valid_gtt_space(struct drm_device *dev, /* On non-LLC machines we have to be careful when putting differing * types of snoopable memory together to avoid the prefetcher - * crossing memory domains and dieing. + * crossing memory domains and dying. */ if (HAS_LLC(dev)) return true; @@ -2610,21 +2749,16 @@ i915_gem_object_bind_to_gtt(struct drm_i915_gem_object *obj, bool mappable, fenceable; int ret; - if (obj->madv != I915_MADV_WILLNEED) { - DRM_ERROR("Attempting to bind a purgeable object\n"); - return -EINVAL; - } - fence_size = i915_gem_get_gtt_size(dev, obj->base.size, obj->tiling_mode); fence_alignment = i915_gem_get_gtt_alignment(dev, obj->base.size, - obj->tiling_mode); + obj->tiling_mode, true); unfenced_alignment = - i915_gem_get_unfenced_gtt_alignment(dev, + i915_gem_get_gtt_alignment(dev, obj->base.size, - obj->tiling_mode); + obj->tiling_mode, false); if (alignment == 0) alignment = map_and_fenceable ? fence_alignment : @@ -2640,7 +2774,7 @@ i915_gem_object_bind_to_gtt(struct drm_i915_gem_object *obj, * before evicting everything in a vain attempt to find space. */ if (obj->base.size > - (map_and_fenceable ? dev_priv->mm.gtt_mappable_end : dev_priv->mm.gtt_total)) { + (map_and_fenceable ? dev_priv->gtt.mappable_end : dev_priv->gtt.total)) { DRM_ERROR("Attempting to bind an object larger than the aperture\n"); return -E2BIG; } @@ -2661,7 +2795,7 @@ i915_gem_object_bind_to_gtt(struct drm_i915_gem_object *obj, if (map_and_fenceable) ret = drm_mm_insert_node_in_range_generic(&dev_priv->mm.gtt_space, node, size, alignment, obj->cache_level, - 0, dev_priv->mm.gtt_mappable_end); + 0, dev_priv->gtt.mappable_end); else ret = drm_mm_insert_node_generic(&dev_priv->mm.gtt_space, node, size, alignment, obj->cache_level); @@ -2695,7 +2829,7 @@ i915_gem_object_bind_to_gtt(struct drm_i915_gem_object *obj, (node->start & (fence_alignment - 1)) == 0; mappable = - obj->gtt_offset + obj->base.size <= dev_priv->mm.gtt_mappable_end; + obj->gtt_offset + obj->base.size <= dev_priv->gtt.mappable_end; obj->map_and_fenceable = mappable && fenceable; @@ -2715,6 +2849,13 @@ i915_gem_clflush_object(struct drm_i915_gem_object *obj) if (obj->pages == NULL) return; + /* + * Stolen memory is always coherent with the GPU as it is explicitly + * marked as wc by the system, or the system is cache-coherent. + */ + if (obj->stolen) + return; + /* If the GPU is snooping the contents of the CPU cache, * we do not need to manually clear the CPU cache lines. However, * the caches are only snooped when the render cache is @@ -2848,6 +2989,13 @@ i915_gem_object_set_to_gtt_domain(struct drm_i915_gem_object *obj, bool write) i915_gem_object_flush_cpu_write_domain(obj); + /* Serialise direct access to this object with the barriers for + * coherent writes from the GPU, by effectively invalidating the + * GTT domain upon first access. + */ + if ((obj->base.read_domains & I915_GEM_DOMAIN_GTT) == 0) + mb(); + old_write_domain = obj->base.write_domain; old_read_domains = obj->base.read_domains; @@ -2955,6 +3103,12 @@ int i915_gem_get_caching_ioctl(struct drm_device *dev, void *data, struct drm_i915_gem_object *obj; int ret; + if(args->handle == -2) + { + printf("%s handle %d\n", __FUNCTION__, args->handle); + return 0; + } + ret = i915_mutex_lock_interruptible(dev); if (ret) return ret; @@ -2981,6 +3135,12 @@ int i915_gem_set_caching_ioctl(struct drm_device *dev, void *data, enum i915_cache_level level; int ret; + if(args->handle == -2) + { + printf("%s handle %d\n", __FUNCTION__, args->handle); + return 0; + } + switch (args->caching) { case I915_CACHING_NONE: level = I915_CACHE_NONE; @@ -3154,11 +3314,17 @@ i915_gem_ring_throttle(struct drm_device *dev, struct drm_file *file) unsigned long recent_enough = GetTimerTicks() - msecs_to_jiffies(20); struct drm_i915_gem_request *request; struct intel_ring_buffer *ring = NULL; + unsigned reset_counter; u32 seqno = 0; int ret; - if (atomic_read(&dev_priv->mm.wedged)) - return -EIO; + ret = i915_gem_wait_for_error(&dev_priv->gpu_error); + if (ret) + return ret; + + ret = i915_gem_check_wedge(&dev_priv->gpu_error, false); + if (ret) + return ret; spin_lock(&file_priv->mm.lock); list_for_each_entry(request, &file_priv->mm.request_list, client_list) { @@ -3168,12 +3334,13 @@ i915_gem_ring_throttle(struct drm_device *dev, struct drm_file *file) ring = request->ring; seqno = request->seqno; } + reset_counter = atomic_read(&dev_priv->gpu_error.reset_counter); spin_unlock(&file_priv->mm.lock); if (seqno == 0) return 0; - ret = __wait_seqno(ring, seqno, true, NULL); + ret = __wait_seqno(ring, seqno, reset_counter, true, NULL); if (ret == 0) queue_delayed_work(dev_priv->wq, &dev_priv->mm.retire_work, 0); @@ -3247,6 +3414,12 @@ i915_gem_pin_ioctl(struct drm_device *dev, void *data, struct drm_i915_gem_object *obj; int ret; + if(args->handle == -2) + { + printf("%s handle %d\n", __FUNCTION__, args->handle); + return 0; + } + ret = i915_mutex_lock_interruptible(dev); if (ret) return ret; @@ -3344,6 +3517,12 @@ i915_gem_busy_ioctl(struct drm_device *dev, void *data, if (ret) return ret; + if(args->handle == -2) + { + obj = get_fb_obj(); + drm_gem_object_reference(&obj->base); + } + else obj = to_intel_bo(drm_gem_object_lookup(dev, file, args->handle)); if (&obj->base == NULL) { ret = -ENOENT; @@ -3454,7 +3633,7 @@ struct drm_i915_gem_object *i915_gem_alloc_object(struct drm_device *dev, { struct drm_i915_gem_object *obj; struct address_space *mapping; - u32 mask; + gfp_t mask; obj = kzalloc(sizeof(*obj), GFP_KERNEL); if (obj == NULL) @@ -3565,6 +3744,10 @@ i915_gem_idle(struct drm_device *dev) } i915_gem_retire_requests(dev); + /* Under UMS, be paranoid and evict. */ + if (!drm_core_check_feature(dev, DRIVER_MODESET)) + i915_gem_evict_everything(dev); + i915_gem_reset_fences(dev); /* Hack! Don't let anybody do execbuf while we don't control the chip. @@ -3572,7 +3755,7 @@ i915_gem_idle(struct drm_device *dev) * And not confound mm.suspended! */ dev_priv->mm.suspended = 1; - del_timer_sync(&dev_priv->hangcheck_timer); + del_timer_sync(&dev_priv->gpu_error.hangcheck_timer); i915_kernel_lost_context(dev); i915_gem_cleanup_ringbuffer(dev); @@ -3592,7 +3775,7 @@ void i915_gem_l3_remap(struct drm_device *dev) u32 misccpctl; int i; - if (!IS_IVYBRIDGE(dev)) + if (!HAS_L3_GPU_CACHE(dev)) return; if (!dev_priv->l3_parity.remap_info) @@ -3635,8 +3818,10 @@ void i915_gem_init_swizzling(struct drm_device *dev) I915_WRITE(TILECTL, I915_READ(TILECTL) | TILECTL_SWZCTL); if (IS_GEN6(dev)) I915_WRITE(ARB_MODE, _MASKED_BIT_ENABLE(ARB_MODE_SWIZZLE_SNB)); - else + else if (IS_GEN7(dev)) I915_WRITE(ARB_MODE, _MASKED_BIT_ENABLE(ARB_MODE_SWIZZLE_IVB)); + else + BUG(); } static bool @@ -3655,22 +3840,11 @@ intel_enable_blt(struct drm_device *dev) return true; } -int -i915_gem_init_hw(struct drm_device *dev) +static int i915_gem_init_rings(struct drm_device *dev) { - drm_i915_private_t *dev_priv = dev->dev_private; + struct drm_i915_private *dev_priv = dev->dev_private; int ret; - if (INTEL_INFO(dev)->gen < 6 && !intel_enable_gtt()) - return -EIO; - - if (IS_HASWELL(dev) && (I915_READ(0x120010) == 1)) - I915_WRITE(0x9008, I915_READ(0x9008) | 0xf0000); - - i915_gem_l3_remap(dev); - - i915_gem_init_swizzling(dev); - ret = intel_init_render_ring_buffer(dev); if (ret) return ret; @@ -3687,7 +3861,41 @@ i915_gem_init_hw(struct drm_device *dev) goto cleanup_bsd_ring; } - dev_priv->next_seqno = 1; + ret = i915_gem_set_seqno(dev, ((u32)~0 - 0x1000)); + if (ret) + goto cleanup_blt_ring; + + return 0; + +cleanup_blt_ring: + intel_cleanup_ring_buffer(&dev_priv->ring[BCS]); +cleanup_bsd_ring: + intel_cleanup_ring_buffer(&dev_priv->ring[VCS]); +cleanup_render_ring: + intel_cleanup_ring_buffer(&dev_priv->ring[RCS]); + + return ret; +} + +int +i915_gem_init_hw(struct drm_device *dev) +{ + drm_i915_private_t *dev_priv = dev->dev_private; + int ret; + + if (INTEL_INFO(dev)->gen < 6 && !intel_enable_gtt()) + return -EIO; + + if (IS_HASWELL(dev) && (I915_READ(0x120010) == 1)) + I915_WRITE(0x9008, I915_READ(0x9008) | 0xf0000); + + i915_gem_l3_remap(dev); + + i915_gem_init_swizzling(dev); + + ret = i915_gem_init_rings(dev); + if (ret) + return ret; /* * XXX: There was some w/a described somewhere suggesting loading @@ -3697,27 +3905,6 @@ i915_gem_init_hw(struct drm_device *dev) i915_gem_init_ppgtt(dev); return 0; - -cleanup_bsd_ring: - intel_cleanup_ring_buffer(&dev_priv->ring[VCS]); -cleanup_render_ring: - intel_cleanup_ring_buffer(&dev_priv->ring[RCS]); - return ret; -} - -static bool -intel_enable_ppgtt(struct drm_device *dev) -{ - if (i915_enable_ppgtt >= 0) - return i915_enable_ppgtt; - -#ifdef CONFIG_INTEL_IOMMU - /* Disable ppgtt on SNB if VT-d is on. */ - if (INTEL_INFO(dev)->gen == 6 && intel_iommu_gfx_mapped) - return false; -#endif - - return true; } #define LFB_SIZE 0xC00000 @@ -3725,39 +3912,10 @@ intel_enable_ppgtt(struct drm_device *dev) int i915_gem_init(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; - unsigned long gtt_size, mappable_size; int ret; - gtt_size = dev_priv->mm.gtt->gtt_total_entries << PAGE_SHIFT; - mappable_size = dev_priv->mm.gtt->gtt_mappable_entries << PAGE_SHIFT; - mutex_lock(&dev->struct_mutex); - if (intel_enable_ppgtt(dev) && HAS_ALIASING_PPGTT(dev)) { - /* PPGTT pdes are stolen from global gtt ptes, so shrink the - * aperture accordingly when using aliasing ppgtt. */ - gtt_size -= I915_PPGTT_PD_ENTRIES*PAGE_SIZE; - - i915_gem_init_global_gtt(dev, LFB_SIZE, mappable_size, gtt_size - LFB_SIZE); - - ret = i915_gem_init_aliasing_ppgtt(dev); - if (ret) { - mutex_unlock(&dev->struct_mutex); - return ret; - } - } else { - /* Let GEM Manage all of the aperture. - * - * However, leave one page at the end still bound to the scratch - * page. There are a number of places where the hardware - * apparently prefetches past the end of the object, and we've - * seen multiple hangs with the GPU head pointer stuck in a - * batchbuffer bound at the last page of the aperture. One page - * should be enough to keep any prefetching inside of the - * aperture. - */ - i915_gem_init_global_gtt(dev, LFB_SIZE, mappable_size, gtt_size - LFB_SIZE); - } - + i915_gem_init_global_gtt(dev); ret = i915_gem_init_hw(dev); mutex_unlock(&dev->struct_mutex); if (ret) { @@ -3791,9 +3949,9 @@ i915_gem_entervt_ioctl(struct drm_device *dev, void *data, if (drm_core_check_feature(dev, DRIVER_MODESET)) return 0; - if (atomic_read(&dev_priv->mm.wedged)) { + if (i915_reset_in_progress(&dev_priv->gpu_error)) { DRM_ERROR("Reenabling wedged hardware, good luck\n"); - atomic_set(&dev_priv->mm.wedged, 0); + atomic_set(&dev_priv->gpu_error.reset_counter, 0); } mutex_lock(&dev->struct_mutex); @@ -3858,8 +4016,8 @@ init_ring_lists(struct intel_ring_buffer *ring) void i915_gem_load(struct drm_device *dev) { + drm_i915_private_t *dev_priv = dev->dev_private; int i; - drm_i915_private_t *dev_priv = dev->dev_private; INIT_LIST_HEAD(&dev_priv->mm.active_list); INIT_LIST_HEAD(&dev_priv->mm.inactive_list); @@ -3872,6 +4030,7 @@ i915_gem_load(struct drm_device *dev) INIT_LIST_HEAD(&dev_priv->fence_regs[i].lru_list); INIT_DELAYED_WORK(&dev_priv->mm.retire_work, i915_gem_retire_work_handler); + init_waitqueue_head(&dev_priv->gpu_error.reset_queue); /* On GEN3 we really need to make sure the ARB C3 LP bit is set */ if (IS_GEN3(dev)) { diff --git a/drivers/video/drm/i915/i915_gem_context.c b/drivers/video/drm/i915/i915_gem_context.c index ac79e4f59f..df117b3790 100644 --- a/drivers/video/drm/i915/i915_gem_context.c +++ b/drivers/video/drm/i915/i915_gem_context.c @@ -128,13 +128,8 @@ static int get_context_size(struct drm_device *dev) static void do_destroy(struct i915_hw_context *ctx) { - struct drm_device *dev = ctx->obj->base.dev; - struct drm_i915_private *dev_priv = dev->dev_private; - if (ctx->file_priv) idr_remove(&ctx->file_priv->context_idr, ctx->id); - else - BUG_ON(ctx != dev_priv->ring[RCS].default_context); drm_gem_object_unreference(&ctx->obj->base); kfree(ctx); @@ -146,7 +141,7 @@ create_hw_context(struct drm_device *dev, { struct drm_i915_private *dev_priv = dev->dev_private; struct i915_hw_context *ctx; - int ret, id; + int ret; ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); if (ctx == NULL) @@ -171,22 +166,11 @@ create_hw_context(struct drm_device *dev, ctx->file_priv = file_priv; -again: - if (idr_pre_get(&file_priv->context_idr, GFP_KERNEL) == 0) { - ret = -ENOMEM; - DRM_DEBUG_DRIVER("idr allocation failed\n"); - goto err_out; - } - - ret = idr_get_new_above(&file_priv->context_idr, ctx, - DEFAULT_CONTEXT_ID + 1, &id); - if (ret == 0) - ctx->id = id; - - if (ret == -EAGAIN) - goto again; - else if (ret) + ret = idr_alloc(&file_priv->context_idr, ctx, DEFAULT_CONTEXT_ID + 1, 0, + GFP_KERNEL); + if (ret < 0) goto err_out; + ctx->id = ret; return ctx; @@ -245,10 +229,6 @@ err_destroy: void i915_gem_context_init(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; - uint32_t ctx_size; - - dev_priv->hw_contexts_disabled = true; - return; #if 0 if (!HAS_HW_CONTEXTS(dev)) { @@ -261,11 +241,9 @@ void i915_gem_context_init(struct drm_device *dev) dev_priv->ring[RCS].default_context) return; - ctx_size = get_context_size(dev); - dev_priv->hw_context_size = get_context_size(dev); - dev_priv->hw_context_size = round_up(dev_priv->hw_context_size, 4096); + dev_priv->hw_context_size = round_up(get_context_size(dev), 4096); - if (ctx_size <= 0 || ctx_size > (1<<20)) { + if (dev_priv->hw_context_size > (1<<20)) { dev_priv->hw_contexts_disabled = true; return; } diff --git a/drivers/video/drm/i915/i915_gem_execbuffer.c b/drivers/video/drm/i915/i915_gem_execbuffer.c index fa5198d7e0..2a84f1c844 100644 --- a/drivers/video/drm/i915/i915_gem_execbuffer.c +++ b/drivers/video/drm/i915/i915_gem_execbuffer.c @@ -63,61 +63,136 @@ copy_from_user(void *to, const void __user *from, unsigned long n) } struct eb_objects { + struct list_head objects; int and; + union { + struct drm_i915_gem_object *lut[0]; struct hlist_head buckets[0]; + }; }; static struct eb_objects * -eb_create(int size) +eb_create(struct drm_i915_gem_execbuffer2 *args) { - struct eb_objects *eb; + struct eb_objects *eb = NULL; + + if (args->flags & I915_EXEC_HANDLE_LUT) { + int size = args->buffer_count; + size *= sizeof(struct drm_i915_gem_object *); + size += sizeof(struct eb_objects); + eb = kmalloc(size, GFP_TEMPORARY | __GFP_NOWARN | __GFP_NORETRY); + } + + if (eb == NULL) { + int size = args->buffer_count; int count = PAGE_SIZE / sizeof(struct hlist_head) / 2; - BUILD_BUG_ON(!is_power_of_2(PAGE_SIZE / sizeof(struct hlist_head))); - while (count > size) + BUILD_BUG_ON_NOT_POWER_OF_2(PAGE_SIZE / sizeof(struct hlist_head)); + while (count > 2*size) count >>= 1; eb = kzalloc(count*sizeof(struct hlist_head) + sizeof(struct eb_objects), - GFP_KERNEL); + GFP_TEMPORARY); if (eb == NULL) return eb; eb->and = count - 1; + } else + eb->and = -args->buffer_count; + + INIT_LIST_HEAD(&eb->objects); return eb; } static void eb_reset(struct eb_objects *eb) { + if (eb->and >= 0) memset(eb->buckets, 0, (eb->and+1)*sizeof(struct hlist_head)); } -static void -eb_add_object(struct eb_objects *eb, struct drm_i915_gem_object *obj) +static int +eb_lookup_objects(struct eb_objects *eb, + struct drm_i915_gem_exec_object2 *exec, + const struct drm_i915_gem_execbuffer2 *args, + struct drm_file *file) { + int i; + + spin_lock(&file->table_lock); + for (i = 0; i < args->buffer_count; i++) { + struct drm_i915_gem_object *obj; + + if(exec[i].handle == -2) + obj = get_fb_obj(); + else + obj = to_intel_bo(idr_find(&file->object_idr, exec[i].handle)); + if (obj == NULL) { + spin_unlock(&file->table_lock); + DRM_DEBUG("Invalid object handle %d at index %d\n", + exec[i].handle, i); + return -ENOENT; + } + + if (!list_empty(&obj->exec_list)) { + spin_unlock(&file->table_lock); + DRM_DEBUG("Object %p [handle %d, index %d] appears more than once in object list\n", + obj, exec[i].handle, i); + return -EINVAL; + } + + drm_gem_object_reference(&obj->base); + list_add_tail(&obj->exec_list, &eb->objects); + + obj->exec_entry = &exec[i]; + if (eb->and < 0) { + eb->lut[i] = obj; + } else { + uint32_t handle = args->flags & I915_EXEC_HANDLE_LUT ? i : exec[i].handle; + obj->exec_handle = handle; hlist_add_head(&obj->exec_node, - &eb->buckets[obj->exec_handle & eb->and]); + &eb->buckets[handle & eb->and]); + } + } + spin_unlock(&file->table_lock); + + return 0; } static struct drm_i915_gem_object * eb_get_object(struct eb_objects *eb, unsigned long handle) { + if (eb->and < 0) { + if (handle >= -eb->and) + return NULL; + return eb->lut[handle]; + } else { struct hlist_head *head; struct hlist_node *node; - struct drm_i915_gem_object *obj; head = &eb->buckets[handle & eb->and]; hlist_for_each(node, head) { + struct drm_i915_gem_object *obj; + obj = hlist_entry(node, struct drm_i915_gem_object, exec_node); if (obj->exec_handle == handle) return obj; } - return NULL; + } } static void eb_destroy(struct eb_objects *eb) { + while (!list_empty(&eb->objects)) { + struct drm_i915_gem_object *obj; + + obj = list_first_entry(&eb->objects, + struct drm_i915_gem_object, + exec_list); + list_del_init(&obj->exec_list); + drm_gem_object_unreference(&obj->base); + } kfree(eb); } @@ -179,17 +254,6 @@ i915_gem_execbuffer_relocate_entry(struct drm_i915_gem_object *obj, reloc->write_domain); return ret; } - if (unlikely(reloc->write_domain && target_obj->pending_write_domain && - reloc->write_domain != target_obj->pending_write_domain)) { - DRM_DEBUG("Write domain conflict: " - "obj %p target %d offset %d " - "new %08x old %08x\n", - obj, reloc->target_handle, - (int) reloc->offset, - reloc->write_domain, - target_obj->pending_write_domain); - return ret; - } target_obj->pending_read_domains |= reloc->read_domains; target_obj->pending_write_domain |= reloc->write_domain; @@ -218,9 +282,6 @@ i915_gem_execbuffer_relocate_entry(struct drm_i915_gem_object *obj, } /* We can't wait for rendering with pagefaults disabled */ -// if (obj->active && in_atomic()) -// return -EFAULT; - reloc->delta += target_offset; if (use_cpu_reloc(obj)) { @@ -324,8 +385,7 @@ i915_gem_execbuffer_relocate_object_slow(struct drm_i915_gem_object *obj, static int i915_gem_execbuffer_relocate(struct drm_device *dev, - struct eb_objects *eb, - struct list_head *objects) + struct eb_objects *eb) { struct drm_i915_gem_object *obj; int ret = 0; @@ -338,7 +398,7 @@ i915_gem_execbuffer_relocate(struct drm_device *dev, * lockdep complains vehemently. */ // pagefault_disable(); - list_for_each_entry(obj, objects, exec_list) { + list_for_each_entry(obj, &eb->objects, exec_list) { ret = i915_gem_execbuffer_relocate_object(obj, eb); if (ret) break; @@ -360,7 +420,8 @@ need_reloc_mappable(struct drm_i915_gem_object *obj) static int i915_gem_execbuffer_reserve_object(struct drm_i915_gem_object *obj, - struct intel_ring_buffer *ring) + struct intel_ring_buffer *ring, + bool *need_reloc) { struct drm_i915_private *dev_priv = obj->base.dev->dev_private; struct drm_i915_gem_exec_object2 *entry = obj->exec_entry; @@ -409,8 +470,19 @@ i915_gem_execbuffer_reserve_object(struct drm_i915_gem_object *obj, obj->has_aliasing_ppgtt_mapping = 1; } + if (entry->offset != obj->gtt_offset) { entry->offset = obj->gtt_offset; -// LEAVE(); + *need_reloc = true; + } + + if (entry->flags & EXEC_OBJECT_WRITE) { + obj->base.pending_read_domains = I915_GEM_DOMAIN_RENDER; + obj->base.pending_write_domain = I915_GEM_DOMAIN_RENDER; + } + + if (entry->flags & EXEC_OBJECT_NEEDS_GTT && + !obj->has_global_gtt_mapping) + i915_gem_gtt_bind_object(obj, obj->cache_level); return 0; } @@ -437,7 +509,8 @@ i915_gem_execbuffer_unreserve_object(struct drm_i915_gem_object *obj) static int i915_gem_execbuffer_reserve(struct intel_ring_buffer *ring, struct drm_file *file, - struct list_head *objects) + struct list_head *objects, + bool *need_relocs) { struct drm_i915_gem_object *obj; struct list_head ordered_objects; @@ -467,7 +540,7 @@ i915_gem_execbuffer_reserve(struct intel_ring_buffer *ring, else list_move_tail(&obj->exec_list, &ordered_objects); - obj->base.pending_read_domains = 0; + obj->base.pending_read_domains = I915_GEM_GPU_DOMAINS & ~I915_GEM_DOMAIN_COMMAND; obj->base.pending_write_domain = 0; obj->pending_fenced_gpu_access = false; } @@ -507,7 +580,7 @@ i915_gem_execbuffer_reserve(struct intel_ring_buffer *ring, (need_mappable && !obj->map_and_fenceable)) ret = i915_gem_object_unbind(obj); else - ret = i915_gem_execbuffer_reserve_object(obj, ring); + ret = i915_gem_execbuffer_reserve_object(obj, ring, need_relocs); if (ret) goto err; } @@ -517,7 +590,7 @@ i915_gem_execbuffer_reserve(struct intel_ring_buffer *ring, if (obj->gtt_space) continue; - ret = i915_gem_execbuffer_reserve_object(obj, ring); + ret = i915_gem_execbuffer_reserve_object(obj, ring, need_relocs); if (ret) goto err; } @@ -540,21 +613,22 @@ err: /* Decrement pin count for bound objects */ static int i915_gem_execbuffer_relocate_slow(struct drm_device *dev, + struct drm_i915_gem_execbuffer2 *args, struct drm_file *file, struct intel_ring_buffer *ring, - struct list_head *objects, struct eb_objects *eb, - struct drm_i915_gem_exec_object2 *exec, - int count) + struct drm_i915_gem_exec_object2 *exec) { struct drm_i915_gem_relocation_entry *reloc; struct drm_i915_gem_object *obj; + bool need_relocs; int *reloc_offset; int i, total, ret; + int count = args->buffer_count; /* We may process another execbuffer during the unlock... */ - while (!list_empty(objects)) { - obj = list_first_entry(objects, + while (!list_empty(&eb->objects)) { + obj = list_first_entry(&eb->objects, struct drm_i915_gem_object, exec_list); list_del_init(&obj->exec_list); @@ -622,34 +696,16 @@ i915_gem_execbuffer_relocate_slow(struct drm_device *dev, /* reacquire the objects */ eb_reset(eb); - for (i = 0; i < count; i++) { - - if(exec[i].handle == -2) - { - obj = get_fb_obj(); - drm_gem_object_reference(&obj->base); - } - else - obj = to_intel_bo(drm_gem_object_lookup(dev, file, - exec[i].handle)); - if (&obj->base == NULL) { - DRM_DEBUG("Invalid object handle %d at index %d\n", - exec[i].handle, i); - ret = -ENOENT; + ret = eb_lookup_objects(eb, exec, args, file); + if (ret) goto err; - } - list_add_tail(&obj->exec_list, objects); - obj->exec_handle = exec[i].handle; - obj->exec_entry = &exec[i]; - eb_add_object(eb, obj); - } - - ret = i915_gem_execbuffer_reserve(ring, file, objects); + need_relocs = (args->flags & I915_EXEC_NO_RELOC) == 0; + ret = i915_gem_execbuffer_reserve(ring, file, &eb->objects, &need_relocs); if (ret) goto err; - list_for_each_entry(obj, objects, exec_list) { + list_for_each_entry(obj, &eb->objects, exec_list) { int offset = obj->exec_entry - exec; ret = i915_gem_execbuffer_relocate_object_slow(obj, eb, reloc + reloc_offset[offset]); @@ -669,45 +725,12 @@ err: return ret; } -static int -i915_gem_execbuffer_wait_for_flips(struct intel_ring_buffer *ring, u32 flips) -{ - u32 plane, flip_mask; - int ret; - - /* Check for any pending flips. As we only maintain a flip queue depth - * of 1, we can simply insert a WAIT for the next display flip prior - * to executing the batch and avoid stalling the CPU. - */ - - for (plane = 0; flips >> plane; plane++) { - if (((flips >> plane) & 1) == 0) - continue; - - if (plane) - flip_mask = MI_WAIT_FOR_PLANE_B_FLIP; - else - flip_mask = MI_WAIT_FOR_PLANE_A_FLIP; - - ret = intel_ring_begin(ring, 2); - if (ret) - return ret; - - intel_ring_emit(ring, MI_WAIT_FOR_EVENT | flip_mask); - intel_ring_emit(ring, MI_NOOP); - intel_ring_advance(ring); - } - - return 0; -} - static int i915_gem_execbuffer_move_to_gpu(struct intel_ring_buffer *ring, struct list_head *objects) { struct drm_i915_gem_object *obj; uint32_t flush_domains = 0; - uint32_t flips = 0; int ret; list_for_each_entry(obj, objects, exec_list) { @@ -718,18 +741,9 @@ i915_gem_execbuffer_move_to_gpu(struct intel_ring_buffer *ring, if (obj->base.write_domain & I915_GEM_DOMAIN_CPU) i915_gem_clflush_object(obj); - if (obj->base.pending_write_domain) - flips |= atomic_read(&obj->pending_flip); - flush_domains |= obj->base.write_domain; } - if (flips) { - ret = i915_gem_execbuffer_wait_for_flips(ring, flips); - if (ret) - return ret; - } - if (flush_domains & I915_GEM_DOMAIN_CPU) i915_gem_chipset_flush(ring->dev); @@ -745,6 +759,9 @@ i915_gem_execbuffer_move_to_gpu(struct intel_ring_buffer *ring, static bool i915_gem_check_execbuffer(struct drm_i915_gem_execbuffer2 *exec) { + if (exec->flags & __I915_EXEC_UNKNOWN_FLAGS) + return false; + return ((exec->batch_start_offset | exec->batch_len) & 0x7) == 0; } @@ -753,21 +770,26 @@ validate_exec_list(struct drm_i915_gem_exec_object2 *exec, int count) { int i; + int relocs_total = 0; + int relocs_max = INT_MAX / sizeof(struct drm_i915_gem_relocation_entry); for (i = 0; i < count; i++) { char __user *ptr = (char __user *)(uintptr_t)exec[i].relocs_ptr; int length; /* limited by fault_in_pages_readable() */ - /* First check for malicious input causing overflow */ - if (exec[i].relocation_count > - INT_MAX / sizeof(struct drm_i915_gem_relocation_entry)) + if (exec[i].flags & __EXEC_OBJECT_UNKNOWN_FLAGS) return -EINVAL; + /* First check for malicious input causing overflow in + * the worst case where we need to allocate the entire + * relocation tree as a single array. + */ + if (exec[i].relocation_count > relocs_max - relocs_total) + return -EINVAL; + relocs_total += exec[i].relocation_count; + length = exec[i].relocation_count * sizeof(struct drm_i915_gem_relocation_entry); -// if (!access_ok(VERIFY_READ, ptr, length)) -// return -EFAULT; - /* we may also need to update the presumed offsets */ // if (!access_ok(VERIFY_WRITE, ptr, length)) // return -EFAULT; @@ -789,8 +811,10 @@ i915_gem_execbuffer_move_to_active(struct list_head *objects, u32 old_read = obj->base.read_domains; u32 old_write = obj->base.write_domain; - obj->base.read_domains = obj->base.pending_read_domains; obj->base.write_domain = obj->base.pending_write_domain; + if (obj->base.write_domain == 0) + obj->base.pending_read_domains |= obj->base.read_domains; + obj->base.read_domains = obj->base.pending_read_domains; obj->fenced_gpu_access = obj->pending_fenced_gpu_access; i915_gem_object_move_to_active(obj, ring); @@ -849,19 +873,18 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, struct drm_i915_gem_exec_object2 *exec) { drm_i915_private_t *dev_priv = dev->dev_private; - struct list_head objects; struct eb_objects *eb; struct drm_i915_gem_object *batch_obj; struct drm_clip_rect *cliprects = NULL; struct intel_ring_buffer *ring; u32 ctx_id = i915_execbuffer2_get_context_id(*args); u32 exec_start, exec_len; - u32 mask; - u32 flags; + u32 mask, flags; int ret, mode, i; + bool need_relocs; - if (!i915_gem_check_execbuffer(args)) { - DRM_DEBUG("execbuf with invalid offset/length\n"); + if (!i915_gem_check_execbuffer(args)) + { FAIL(); return -EINVAL; } @@ -875,8 +898,6 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, flags = 0; if (args->flags & I915_EXEC_SECURE) { -// if (!file->is_master || !capable(CAP_SYS_ADMIN)) -// return -EPERM; flags |= I915_DISPATCH_SECURE; } @@ -989,7 +1010,7 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, goto pre_mutex_err; } - eb = eb_create(args->buffer_count); + eb = eb_create(args); if (eb == NULL) { mutex_unlock(&dev->struct_mutex); ret = -ENOMEM; @@ -997,60 +1018,28 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, } /* Look up object handles */ - INIT_LIST_HEAD(&objects); - for (i = 0; i < args->buffer_count; i++) { - struct drm_i915_gem_object *obj; - - if(exec[i].handle == -2) - { - obj = get_fb_obj(); - drm_gem_object_reference(&obj->base); - } - else - obj = to_intel_bo(drm_gem_object_lookup(dev, file, - exec[i].handle)); - -// printf("%s object %p handle %d\n", __FUNCTION__, obj, exec[i].handle); - - if (&obj->base == NULL) { - DRM_DEBUG("Invalid object handle %d at index %d\n", - exec[i].handle, i); - /* prevent error path from reading uninitialized data */ - ret = -ENOENT; + ret = eb_lookup_objects(eb, exec, args, file); + if (ret) goto err; - } - - if (!list_empty(&obj->exec_list)) { - DRM_DEBUG("Object %p [handle %d, index %d] appears more than once in object list\n", - obj, exec[i].handle, i); - ret = -EINVAL; - goto err; - } - - list_add_tail(&obj->exec_list, &objects); - obj->exec_handle = exec[i].handle; - obj->exec_entry = &exec[i]; - eb_add_object(eb, obj); - } /* take note of the batch buffer before we might reorder the lists */ - batch_obj = list_entry(objects.prev, + batch_obj = list_entry(eb->objects.prev, struct drm_i915_gem_object, exec_list); /* Move the objects en-masse into the GTT, evicting if necessary. */ - ret = i915_gem_execbuffer_reserve(ring, file, &objects); + need_relocs = (args->flags & I915_EXEC_NO_RELOC) == 0; + ret = i915_gem_execbuffer_reserve(ring, file, &eb->objects, &need_relocs); if (ret) goto err; /* The objects are in their final locations, apply the relocations. */ - ret = i915_gem_execbuffer_relocate(dev, eb, &objects); + if (need_relocs) + ret = i915_gem_execbuffer_relocate(dev, eb); if (ret) { if (ret == -EFAULT) { - ret = i915_gem_execbuffer_relocate_slow(dev, file, ring, - &objects, eb, - exec, - args->buffer_count); + ret = i915_gem_execbuffer_relocate_slow(dev, args, file, ring, + eb, exec); BUG_ON(!mutex_is_locked(&dev->struct_mutex)); } if (ret) @@ -1072,7 +1061,7 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, if (flags & I915_DISPATCH_SECURE && !batch_obj->has_global_gtt_mapping) i915_gem_gtt_bind_object(batch_obj, batch_obj->cache_level); - ret = i915_gem_execbuffer_move_to_gpu(ring, &objects); + ret = i915_gem_execbuffer_move_to_gpu(ring, &eb->objects); if (ret) goto err; @@ -1104,18 +1093,7 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, exec_start = batch_obj->gtt_offset + args->batch_start_offset; exec_len = args->batch_len; if (cliprects) { -// for (i = 0; i < args->num_cliprects; i++) { -// ret = i915_emit_box(dev, &cliprects[i], -// args->DR1, args->DR4); -// if (ret) -// goto err; -// ret = ring->dispatch_execbuffer(ring, -// exec_start, exec_len, -// flags); -// if (ret) -// goto err; -// } } else { ret = ring->dispatch_execbuffer(ring, exec_start, exec_len, @@ -1126,30 +1104,21 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, trace_i915_gem_ring_dispatch(ring, intel_ring_get_seqno(ring), flags); - i915_gem_execbuffer_move_to_active(&objects, ring); + i915_gem_execbuffer_move_to_active(&eb->objects, ring); i915_gem_execbuffer_retire_commands(dev, file, ring); err: eb_destroy(eb); - while (!list_empty(&objects)) { - struct drm_i915_gem_object *obj; - - obj = list_first_entry(&objects, - struct drm_i915_gem_object, - exec_list); - list_del_init(&obj->exec_list); - drm_gem_object_unreference(&obj->base); - } mutex_unlock(&dev->struct_mutex); pre_mutex_err: kfree(cliprects); - - return ret; } + + int i915_gem_execbuffer2(struct drm_device *dev, void *data, struct drm_file *file) @@ -1167,11 +1136,8 @@ i915_gem_execbuffer2(struct drm_device *dev, void *data, return -EINVAL; } - exec2_list = malloc(sizeof(*exec2_list)*args->buffer_count); - -// if (exec2_list == NULL) -// exec2_list = drm_malloc_ab(sizeof(*exec2_list), -// args->buffer_count); + exec2_list = kmalloc(sizeof(*exec2_list)*args->buffer_count, + GFP_TEMPORARY | __GFP_NOWARN | __GFP_NORETRY); if (exec2_list == NULL) { DRM_DEBUG("Failed to allocate exec list for %d buffers\n", args->buffer_count); diff --git a/drivers/video/drm/i915/i915_gem_gtt.c b/drivers/video/drm/i915/i915_gem_gtt.c index 1d874ba78e..39cd8557f0 100644 --- a/drivers/video/drm/i915/i915_gem_gtt.c +++ b/drivers/video/drm/i915/i915_gem_gtt.c @@ -24,16 +24,18 @@ #define iowrite32(v, addr) writel((v), (addr)) +#define AGP_NORMAL_MEMORY 0 + +#define AGP_USER_TYPES (1 << 16) +#define AGP_USER_MEMORY (AGP_USER_TYPES) +#define AGP_USER_CACHED_MEMORY (AGP_USER_TYPES + 1) + #include #include #include "i915_drv.h" #include "i915_trace.h" #include "intel_drv.h" -#define AGP_USER_TYPES (1 << 16) -#define AGP_USER_MEMORY (AGP_USER_TYPES) -#define AGP_USER_CACHED_MEMORY (AGP_USER_TYPES + 1) - typedef uint32_t gtt_pte_t; /* PPGTT stuff */ @@ -50,7 +52,7 @@ typedef uint32_t gtt_pte_t; #define GEN6_PTE_CACHE_LLC_MLC (3 << 1) #define GEN6_PTE_ADDR_ENCODE(addr) GEN6_GTT_ADDR_ENCODE(addr) -static inline gtt_pte_t pte_encode(struct drm_device *dev, +static inline gtt_pte_t gen6_pte_encode(struct drm_device *dev, dma_addr_t addr, enum i915_cache_level level) { @@ -83,7 +85,7 @@ static inline gtt_pte_t pte_encode(struct drm_device *dev, } /* PPGTT support for Sandybdrige/Gen6 and later */ -static void i915_ppgtt_clear_range(struct i915_hw_ppgtt *ppgtt, +static void gen6_ppgtt_clear_range(struct i915_hw_ppgtt *ppgtt, unsigned first_entry, unsigned num_entries) { @@ -93,15 +95,16 @@ static void i915_ppgtt_clear_range(struct i915_hw_ppgtt *ppgtt, unsigned first_pte = first_entry % I915_PPGTT_PT_ENTRIES; unsigned last_pte, i; - scratch_pte = pte_encode(ppgtt->dev, ppgtt->scratch_page_dma_addr, + scratch_pte = gen6_pte_encode(ppgtt->dev, + ppgtt->scratch_page_dma_addr, I915_CACHE_LLC); pt_vaddr = AllocKernelSpace(4096); - if(pt_vaddr != NULL) - { - while (num_entries) - { + if(pt_vaddr == NULL) + return; + + while (num_entries) { last_pte = first_pte + num_entries; if (last_pte > I915_PPGTT_PT_ENTRIES) last_pte = I915_PPGTT_PT_ENTRIES; @@ -114,121 +117,15 @@ static void i915_ppgtt_clear_range(struct i915_hw_ppgtt *ppgtt, num_entries -= last_pte - first_pte; first_pte = 0; act_pd++; - } - FreeKernelSpace(pt_vaddr); }; + + FreeKernelSpace(pt_vaddr); } -int i915_gem_init_aliasing_ppgtt(struct drm_device *dev) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - struct i915_hw_ppgtt *ppgtt; - unsigned first_pd_entry_in_global_pt; - int i; - int ret = -ENOMEM; - - /* ppgtt PDEs reside in the global gtt pagetable, which has 512*1024 - * entries. For aliasing ppgtt support we just steal them at the end for - * now. */ - first_pd_entry_in_global_pt = dev_priv->mm.gtt->gtt_total_entries - I915_PPGTT_PD_ENTRIES; - - ppgtt = kzalloc(sizeof(*ppgtt), GFP_KERNEL); - if (!ppgtt) - return ret; - - ppgtt->num_pd_entries = I915_PPGTT_PD_ENTRIES; - ppgtt->pt_pages = kzalloc(sizeof(struct page *)*ppgtt->num_pd_entries, - GFP_KERNEL); - if (!ppgtt->pt_pages) - goto err_ppgtt; - - for (i = 0; i < ppgtt->num_pd_entries; i++) { - ppgtt->pt_pages[i] = alloc_page(GFP_KERNEL); - if (!ppgtt->pt_pages[i]) - goto err_pt_alloc; - } - -/* - if (dev_priv->mm.gtt->needs_dmar) { - ppgtt->pt_dma_addr = kzalloc(sizeof(dma_addr_t) - *ppgtt->num_pd_entries, - GFP_KERNEL); - if (!ppgtt->pt_dma_addr) - goto err_pt_alloc; - - for (i = 0; i < ppgtt->num_pd_entries; i++) { - dma_addr_t pt_addr; - - pt_addr = pci_map_page(dev->pdev, ppgtt->pt_pages[i], - 0, 4096, - PCI_DMA_BIDIRECTIONAL); - - if (pci_dma_mapping_error(dev->pdev, - pt_addr)) { - ret = -EIO; - goto err_pd_pin; - - } - ppgtt->pt_dma_addr[i] = pt_addr; - } - } -*/ - ppgtt->scratch_page_dma_addr = dev_priv->mm.gtt->scratch_page_dma; - - i915_ppgtt_clear_range(ppgtt, 0, - ppgtt->num_pd_entries*I915_PPGTT_PT_ENTRIES); - - ppgtt->pd_offset = (first_pd_entry_in_global_pt)*sizeof(gtt_pte_t); - - dev_priv->mm.aliasing_ppgtt = ppgtt; - - return 0; - -err_pd_pin: -// if (ppgtt->pt_dma_addr) { -// for (i--; i >= 0; i--) -// pci_unmap_page(dev->pdev, ppgtt->pt_dma_addr[i], -// 4096, PCI_DMA_BIDIRECTIONAL); -// } -err_pt_alloc: -// kfree(ppgtt->pt_dma_addr); - for (i = 0; i < ppgtt->num_pd_entries; i++) { - if (ppgtt->pt_pages[i]) - FreePage((addr_t)(ppgtt->pt_pages[i])); - } - kfree(ppgtt->pt_pages); -err_ppgtt: - kfree(ppgtt); - - return ret; -} - -void i915_gem_cleanup_aliasing_ppgtt(struct drm_device *dev) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - struct i915_hw_ppgtt *ppgtt = dev_priv->mm.aliasing_ppgtt; - int i; - - if (!ppgtt) - return; - -// if (ppgtt->pt_dma_addr) { -// for (i = 0; i < ppgtt->num_pd_entries; i++) -// pci_unmap_page(dev->pdev, ppgtt->pt_dma_addr[i], -// 4096, PCI_DMA_BIDIRECTIONAL); -// } - -// kfree(ppgtt->pt_dma_addr); - for (i = 0; i < ppgtt->num_pd_entries; i++) - FreePage((addr_t)(ppgtt->pt_pages[i])); - kfree(ppgtt->pt_pages); - kfree(ppgtt); -} - -static void i915_ppgtt_insert_sg_entries(struct i915_hw_ppgtt *ppgtt, - const struct sg_table *pages, - unsigned first_entry, - enum i915_cache_level cache_level) +static void gen6_ppgtt_insert_entries(struct i915_hw_ppgtt *ppgtt, + struct sg_table *pages, + unsigned first_entry, + enum i915_cache_level cache_level) { gtt_pte_t *pt_vaddr; unsigned act_pd = first_entry / I915_PPGTT_PT_ENTRIES; @@ -244,16 +141,17 @@ static void i915_ppgtt_insert_sg_entries(struct i915_hw_ppgtt *ppgtt, m = 0; pt_vaddr = AllocKernelSpace(4096); - if( pt_vaddr == NULL) - return; + + if(pt_vaddr == NULL) + return; while (i < pages->nents) { - MapPage(pt_vaddr,(addr_t)ppgtt->pt_pages[act_pd], 3); + MapPage(pt_vaddr,(addr_t)(ppgtt->pt_pages[act_pd]), 3); - for (j = first_pte; j < I915_PPGTT_PT_ENTRIES; j++) { + for (j = first_pte; j < I915_PPGTT_PT_ENTRIES; j++) { page_addr = sg_dma_address(sg) + (m << PAGE_SHIFT); - pt_vaddr[j] = pte_encode(ppgtt->dev, page_addr, - cache_level); + pt_vaddr[j] = gen6_pte_encode(ppgtt->dev, page_addr, + cache_level); /* grab the next page */ if (++m == segment_len) { @@ -266,19 +164,136 @@ static void i915_ppgtt_insert_sg_entries(struct i915_hw_ppgtt *ppgtt, } } - - first_pte = 0; - act_pd++; + first_pte = 0; + act_pd++; } FreeKernelSpace(pt_vaddr); } +static void gen6_ppgtt_cleanup(struct i915_hw_ppgtt *ppgtt) +{ + int i; + + if (ppgtt->pt_dma_addr) { + for (i = 0; i < ppgtt->num_pd_entries; i++) + pci_unmap_page(ppgtt->dev->pdev, + ppgtt->pt_dma_addr[i], + 4096, PCI_DMA_BIDIRECTIONAL); + } + + kfree(ppgtt->pt_dma_addr); + for (i = 0; i < ppgtt->num_pd_entries; i++) + __free_page(ppgtt->pt_pages[i]); + kfree(ppgtt->pt_pages); + kfree(ppgtt); +} + +static int gen6_ppgtt_init(struct i915_hw_ppgtt *ppgtt) +{ + struct drm_device *dev = ppgtt->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + unsigned first_pd_entry_in_global_pt; + int i; + int ret = -ENOMEM; + + /* ppgtt PDEs reside in the global gtt pagetable, which has 512*1024 + * entries. For aliasing ppgtt support we just steal them at the end for + * now. */ + first_pd_entry_in_global_pt = + gtt_total_entries(dev_priv->gtt) - I915_PPGTT_PD_ENTRIES; + + ppgtt->num_pd_entries = I915_PPGTT_PD_ENTRIES; + ppgtt->clear_range = gen6_ppgtt_clear_range; + ppgtt->insert_entries = gen6_ppgtt_insert_entries; + ppgtt->cleanup = gen6_ppgtt_cleanup; + ppgtt->pt_pages = kzalloc(sizeof(struct page *)*ppgtt->num_pd_entries, + GFP_KERNEL); + if (!ppgtt->pt_pages) + return -ENOMEM; + + for (i = 0; i < ppgtt->num_pd_entries; i++) { + ppgtt->pt_pages[i] = alloc_page(GFP_KERNEL); + if (!ppgtt->pt_pages[i]) + goto err_pt_alloc; + } + + ppgtt->pt_dma_addr = kzalloc(sizeof(dma_addr_t) *ppgtt->num_pd_entries, + GFP_KERNEL); + if (!ppgtt->pt_dma_addr) + goto err_pt_alloc; + + for (i = 0; i < ppgtt->num_pd_entries; i++) { + dma_addr_t pt_addr; + + pt_addr = pci_map_page(dev->pdev, ppgtt->pt_pages[i], 0, 4096, + PCI_DMA_BIDIRECTIONAL); + + ppgtt->pt_dma_addr[i] = pt_addr; + } + + ppgtt->scratch_page_dma_addr = dev_priv->gtt.scratch_page_dma; + + ppgtt->clear_range(ppgtt, 0, + ppgtt->num_pd_entries*I915_PPGTT_PT_ENTRIES); + + ppgtt->pd_offset = (first_pd_entry_in_global_pt)*sizeof(gtt_pte_t); + + return 0; + +err_pd_pin: + if (ppgtt->pt_dma_addr) { + for (i--; i >= 0; i--) + pci_unmap_page(dev->pdev, ppgtt->pt_dma_addr[i], + 4096, PCI_DMA_BIDIRECTIONAL); + } +err_pt_alloc: + kfree(ppgtt->pt_dma_addr); + for (i = 0; i < ppgtt->num_pd_entries; i++) { + if (ppgtt->pt_pages[i]) + __free_page(ppgtt->pt_pages[i]); + } + kfree(ppgtt->pt_pages); + + return ret; +} + +static int i915_gem_init_aliasing_ppgtt(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + struct i915_hw_ppgtt *ppgtt; + int ret; + + ppgtt = kzalloc(sizeof(*ppgtt), GFP_KERNEL); + if (!ppgtt) + return -ENOMEM; + + ppgtt->dev = dev; + + ret = gen6_ppgtt_init(ppgtt); + if (ret) + kfree(ppgtt); + else + dev_priv->mm.aliasing_ppgtt = ppgtt; + + return ret; +} + +void i915_gem_cleanup_aliasing_ppgtt(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + struct i915_hw_ppgtt *ppgtt = dev_priv->mm.aliasing_ppgtt; + + if (!ppgtt) + return; + + ppgtt->cleanup(ppgtt); +} + void i915_ppgtt_bind_object(struct i915_hw_ppgtt *ppgtt, struct drm_i915_gem_object *obj, enum i915_cache_level cache_level) { - i915_ppgtt_insert_sg_entries(ppgtt, - obj->pages, + ppgtt->insert_entries(ppgtt, obj->pages, obj->gtt_space->start >> PAGE_SHIFT, cache_level); } @@ -286,7 +301,7 @@ void i915_ppgtt_bind_object(struct i915_hw_ppgtt *ppgtt, void i915_ppgtt_unbind_object(struct i915_hw_ppgtt *ppgtt, struct drm_i915_gem_object *obj) { - i915_ppgtt_clear_range(ppgtt, + ppgtt->clear_range(ppgtt, obj->gtt_space->start >> PAGE_SHIFT, obj->base.size >> PAGE_SHIFT); } @@ -297,7 +312,7 @@ void i915_gem_init_ppgtt(struct drm_device *dev) uint32_t pd_offset; struct intel_ring_buffer *ring; struct i915_hw_ppgtt *ppgtt = dev_priv->mm.aliasing_ppgtt; - uint32_t __iomem *pd_addr; + gtt_pte_t __iomem *pd_addr; uint32_t pd_entry; int i; @@ -305,15 +320,11 @@ void i915_gem_init_ppgtt(struct drm_device *dev) return; - pd_addr = dev_priv->mm.gtt->gtt + ppgtt->pd_offset/sizeof(uint32_t); + pd_addr = (gtt_pte_t __iomem*)dev_priv->gtt.gsm + ppgtt->pd_offset/sizeof(gtt_pte_t); for (i = 0; i < ppgtt->num_pd_entries; i++) { dma_addr_t pt_addr; - if (dev_priv->mm.gtt->needs_dmar) pt_addr = ppgtt->pt_dma_addr[i]; - else - pt_addr = page_to_phys(ppgtt->pt_pages[i]); - pd_entry = GEN6_PDE_ADDR_ENCODE(pt_addr); pd_entry |= GEN6_PDE_VALID; @@ -353,11 +364,27 @@ void i915_gem_init_ppgtt(struct drm_device *dev) } } +extern int intel_iommu_gfx_mapped; +/* Certain Gen5 chipsets require require idling the GPU before + * unmapping anything from the GTT when VT-d is enabled. + */ +static inline bool needs_idle_maps(struct drm_device *dev) +{ +#ifdef CONFIG_INTEL_IOMMU + /* Query intel_iommu to see if we need the workaround. Presumably that + * was loaded first. + */ + if (IS_GEN5(dev) && IS_MOBILE(dev) && intel_iommu_gfx_mapped) + return true; +#endif + return false; +} + static bool do_idling(struct drm_i915_private *dev_priv) { bool ret = dev_priv->mm.interruptible; - if (unlikely(dev_priv->mm.gtt->do_idle_maps)) { + if (unlikely(dev_priv->gtt.do_idle_maps)) { dev_priv->mm.interruptible = false; if (i915_gpu_idle(dev_priv->dev)) { DRM_ERROR("Couldn't idle GPU\n"); @@ -371,47 +398,18 @@ static bool do_idling(struct drm_i915_private *dev_priv) static void undo_idling(struct drm_i915_private *dev_priv, bool interruptible) { - if (unlikely(dev_priv->mm.gtt->do_idle_maps)) + if (unlikely(dev_priv->gtt.do_idle_maps)) dev_priv->mm.interruptible = interruptible; } - -static void i915_ggtt_clear_range(struct drm_device *dev, - unsigned first_entry, - unsigned num_entries) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - gtt_pte_t scratch_pte; - gtt_pte_t __iomem *gtt_base = dev_priv->mm.gtt->gtt + first_entry; - const int max_entries = dev_priv->mm.gtt->gtt_total_entries - first_entry; - int i; - - if (INTEL_INFO(dev)->gen < 6) { - intel_gtt_clear_range(first_entry, num_entries); - return; - } - - if (WARN(num_entries > max_entries, - "First entry = %d; Num entries = %d (max=%d)\n", - first_entry, num_entries, max_entries)) - num_entries = max_entries; - - scratch_pte = pte_encode(dev, dev_priv->mm.gtt->scratch_page_dma, I915_CACHE_LLC); - for (i = 0; i < num_entries; i++) - iowrite32(scratch_pte, >t_base[i]); - readl(gtt_base); -} - - -#if 0 void i915_gem_restore_gtt_mappings(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_gem_object *obj; /* First fill our portion of the GTT with scratch pages */ - i915_ggtt_clear_range(dev, dev_priv->mm.gtt_start / PAGE_SIZE, - (dev_priv->mm.gtt_end - dev_priv->mm.gtt_start) / PAGE_SIZE); + dev_priv->gtt.gtt_clear_range(dev, dev_priv->gtt.start / PAGE_SIZE, + dev_priv->gtt.total / PAGE_SIZE); list_for_each_entry(obj, &dev_priv->mm.bound_list, gtt_list) { i915_gem_clflush_object(obj); @@ -420,29 +418,16 @@ void i915_gem_restore_gtt_mappings(struct drm_device *dev) i915_gem_chipset_flush(dev); } -#endif int i915_gem_gtt_prepare_object(struct drm_i915_gem_object *obj) { - struct scatterlist *sg, *s; - unsigned int nents ; - int i; - if (obj->has_dma_mapping) return 0; - sg = obj->pages->sgl; - nents = obj->pages->nents; - - - WARN_ON(nents == 0 || sg[0].length == 0); - - for_each_sg(sg, s, nents, i) { - BUG_ON(!sg_page(s)); - s->dma_address = sg_phys(s); - } - - asm volatile("lock; addl $0,0(%%esp)": : :"memory"); + if (!dma_map_sg(&obj->base.dev->pdev->dev, + obj->pages->sgl, obj->pages->nents, + PCI_DMA_BIDIRECTIONAL)) + return -ENOSPC; return 0; } @@ -453,16 +438,15 @@ int i915_gem_gtt_prepare_object(struct drm_i915_gem_object *obj) * within the global GTT as well as accessible by the GPU through the GMADR * mapped BAR (dev_priv->mm.gtt->gtt). */ -static void gen6_ggtt_bind_object(struct drm_i915_gem_object *obj, +static void gen6_ggtt_insert_entries(struct drm_device *dev, + struct sg_table *st, + unsigned int first_entry, enum i915_cache_level level) { - struct drm_device *dev = obj->base.dev; struct drm_i915_private *dev_priv = dev->dev_private; - struct sg_table *st = obj->pages; struct scatterlist *sg = st->sgl; - const int first_entry = obj->gtt_space->start >> PAGE_SHIFT; - const int max_entries = dev_priv->mm.gtt->gtt_total_entries - first_entry; - gtt_pte_t __iomem *gtt_entries = dev_priv->mm.gtt->gtt + first_entry; + gtt_pte_t __iomem *gtt_entries = + (gtt_pte_t __iomem *)dev_priv->gtt.gsm + first_entry; int unused, i = 0; unsigned int len, m = 0; dma_addr_t addr; @@ -471,14 +455,12 @@ static void gen6_ggtt_bind_object(struct drm_i915_gem_object *obj, len = sg_dma_len(sg) >> PAGE_SHIFT; for (m = 0; m < len; m++) { addr = sg_dma_address(sg) + (m << PAGE_SHIFT); - iowrite32(pte_encode(dev, addr, level), >t_entries[i]); + iowrite32(gen6_pte_encode(dev, addr, level), + >t_entries[i]); i++; } } - BUG_ON(i > max_entries); - BUG_ON(i != obj->base.size / PAGE_SIZE); - /* XXX: This serves as a posting read to make sure that the PTE has * actually been updated. There is some concern that even though * registers and PTEs are within the same BAR that they are potentially @@ -486,7 +468,8 @@ static void gen6_ggtt_bind_object(struct drm_i915_gem_object *obj, * hardware should work, we must keep this posting read for paranoia. */ if (i != 0) - WARN_ON(readl(>t_entries[i-1]) != pte_encode(dev, addr, level)); + WARN_ON(readl(>t_entries[i-1]) + != gen6_pte_encode(dev, addr, level)); /* This next bit makes the above posting read even more important. We * want to flush the TLBs only after we're certain all the PTE updates @@ -496,26 +479,68 @@ static void gen6_ggtt_bind_object(struct drm_i915_gem_object *obj, POSTING_READ(GFX_FLSH_CNTL_GEN6); } +static void gen6_ggtt_clear_range(struct drm_device *dev, + unsigned int first_entry, + unsigned int num_entries) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + gtt_pte_t scratch_pte; + gtt_pte_t __iomem *gtt_base = (gtt_pte_t __iomem *) dev_priv->gtt.gsm + first_entry; + const int max_entries = gtt_total_entries(dev_priv->gtt) - first_entry; + int i; + + if (WARN(num_entries > max_entries, + "First entry = %d; Num entries = %d (max=%d)\n", + first_entry, num_entries, max_entries)) + num_entries = max_entries; + + scratch_pte = gen6_pte_encode(dev, dev_priv->gtt.scratch_page_dma, + I915_CACHE_LLC); + for (i = 0; i < num_entries; i++) + iowrite32(scratch_pte, >t_base[i]); + readl(gtt_base); +} + + +static void i915_ggtt_insert_entries(struct drm_device *dev, + struct sg_table *st, + unsigned int pg_start, + enum i915_cache_level cache_level) +{ + unsigned int flags = (cache_level == I915_CACHE_NONE) ? + AGP_USER_MEMORY : AGP_USER_CACHED_MEMORY; + + intel_gtt_insert_sg_entries(st, pg_start, flags); + +} + +static void i915_ggtt_clear_range(struct drm_device *dev, + unsigned int first_entry, + unsigned int num_entries) +{ + intel_gtt_clear_range(first_entry, num_entries); +} + + void i915_gem_gtt_bind_object(struct drm_i915_gem_object *obj, enum i915_cache_level cache_level) { struct drm_device *dev = obj->base.dev; - if (INTEL_INFO(dev)->gen < 6) { - unsigned int flags = (cache_level == I915_CACHE_NONE) ? - AGP_USER_MEMORY : AGP_USER_CACHED_MEMORY; - intel_gtt_insert_sg_entries(obj->pages, + struct drm_i915_private *dev_priv = dev->dev_private; + + dev_priv->gtt.gtt_insert_entries(dev, obj->pages, obj->gtt_space->start >> PAGE_SHIFT, - flags); - } else { - gen6_ggtt_bind_object(obj, cache_level); - } + cache_level); obj->has_global_gtt_mapping = 1; } void i915_gem_gtt_unbind_object(struct drm_i915_gem_object *obj) { - i915_ggtt_clear_range(obj->base.dev, + struct drm_device *dev = obj->base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; + + dev_priv->gtt.gtt_clear_range(obj->base.dev, obj->gtt_space->start >> PAGE_SHIFT, obj->base.size >> PAGE_SHIFT); @@ -530,10 +555,10 @@ void i915_gem_gtt_finish_object(struct drm_i915_gem_object *obj) interruptible = do_idling(dev_priv); -// if (!obj->has_dma_mapping) -// dma_unmap_sg(&dev->pdev->dev, -// obj->pages->sgl, obj->pages->nents, -// PCI_DMA_BIDIRECTIONAL); + if (!obj->has_dma_mapping) + dma_unmap_sg(&dev->pdev->dev, + obj->pages->sgl, obj->pages->nents, + PCI_DMA_BIDIRECTIONAL); undo_idling(dev_priv, interruptible); } @@ -554,27 +579,102 @@ static void i915_gtt_color_adjust(struct drm_mm_node *node, *end -= 4096; } } - -void i915_gem_init_global_gtt(struct drm_device *dev, +void i915_gem_setup_global_gtt(struct drm_device *dev, unsigned long start, unsigned long mappable_end, unsigned long end) { + /* Let GEM Manage all of the aperture. + * + * However, leave one page at the end still bound to the scratch page. + * There are a number of places where the hardware apparently prefetches + * past the end of the object, and we've seen multiple hangs with the + * GPU head pointer stuck in a batchbuffer bound at the last page of the + * aperture. One page should be enough to keep any prefetching inside + * of the aperture. + */ drm_i915_private_t *dev_priv = dev->dev_private; + struct drm_mm_node *entry; + struct drm_i915_gem_object *obj; + unsigned long hole_start, hole_end; - /* Substract the guard page ... */ + BUG_ON(mappable_end > end); + + /* Subtract the guard page ... */ drm_mm_init(&dev_priv->mm.gtt_space, start, end - start - PAGE_SIZE); if (!HAS_LLC(dev)) dev_priv->mm.gtt_space.color_adjust = i915_gtt_color_adjust; - dev_priv->mm.gtt_start = start; - dev_priv->mm.gtt_mappable_end = mappable_end; - dev_priv->mm.gtt_end = end; - dev_priv->mm.gtt_total = end - start; - dev_priv->mm.mappable_gtt_total = min(end, mappable_end) - start; + /* Mark any preallocated objects as occupied */ + list_for_each_entry(obj, &dev_priv->mm.bound_list, gtt_list) { + DRM_DEBUG_KMS("reserving preallocated space: %x + %zx\n", + obj->gtt_offset, obj->base.size); - /* ... but ensure that we clear the entire range. */ - i915_ggtt_clear_range(dev, start / PAGE_SIZE, (end-start) / PAGE_SIZE); + BUG_ON(obj->gtt_space != I915_GTT_RESERVED); + obj->gtt_space = drm_mm_create_block(&dev_priv->mm.gtt_space, + obj->gtt_offset, + obj->base.size, + false); + obj->has_global_gtt_mapping = 1; + } + + dev_priv->gtt.start = start; + dev_priv->gtt.total = end - start; + + /* Clear any non-preallocated blocks */ + drm_mm_for_each_hole(entry, &dev_priv->mm.gtt_space, + hole_start, hole_end) { + DRM_DEBUG_KMS("clearing unused GTT space: [%lx, %lx]\n", + hole_start, hole_end); + dev_priv->gtt.gtt_clear_range(dev, hole_start / PAGE_SIZE, + (hole_end-hole_start) / PAGE_SIZE); + } + + /* And finally clear the reserved guard page */ + dev_priv->gtt.gtt_clear_range(dev, end / PAGE_SIZE - 1, 1); +} + +static bool +intel_enable_ppgtt(struct drm_device *dev) +{ + if (i915_enable_ppgtt >= 0) + return i915_enable_ppgtt; + +#ifdef CONFIG_INTEL_IOMMU + /* Disable ppgtt on SNB if VT-d is on. */ + if (INTEL_INFO(dev)->gen == 6 && intel_iommu_gfx_mapped) + return false; +#endif + + return true; +} + +void i915_gem_init_global_gtt(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + unsigned long gtt_size, mappable_size; + + gtt_size = dev_priv->gtt.total; + mappable_size = dev_priv->gtt.mappable_end; + + if (intel_enable_ppgtt(dev) && HAS_ALIASING_PPGTT(dev)) { + int ret; + /* PPGTT pdes are stolen from global gtt ptes, so shrink the + * aperture accordingly when using aliasing ppgtt. */ + gtt_size -= I915_PPGTT_PD_ENTRIES*PAGE_SIZE; + gtt_size -= LFB_SIZE; + + i915_gem_setup_global_gtt(dev, LFB_SIZE, mappable_size, gtt_size); + + ret = i915_gem_init_aliasing_ppgtt(dev); + if (!ret) + return; + + DRM_ERROR("Aliased PPGTT setup failed %d\n", ret); + drm_mm_takedown(&dev_priv->mm.gtt_space); + gtt_size += I915_PPGTT_PD_ENTRIES*PAGE_SIZE; + } + i915_gem_setup_global_gtt(dev, LFB_SIZE, mappable_size, gtt_size); } static int setup_scratch_page(struct drm_device *dev) @@ -586,6 +686,8 @@ static int setup_scratch_page(struct drm_device *dev) page = alloc_page(GFP_KERNEL | GFP_DMA32 | __GFP_ZERO); if (page == NULL) return -ENOMEM; + get_page(page); + set_pages_uc(page, 1); #ifdef CONFIG_INTEL_IOMMU dma_addr = pci_map_page(dev->pdev, page, 0, PAGE_SIZE, @@ -595,12 +697,21 @@ static int setup_scratch_page(struct drm_device *dev) #else dma_addr = page_to_phys(page); #endif - dev_priv->mm.gtt->scratch_page = page; - dev_priv->mm.gtt->scratch_page_dma = dma_addr; + dev_priv->gtt.scratch_page = page; + dev_priv->gtt.scratch_page_dma = dma_addr; return 0; } +static void teardown_scratch_page(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + set_pages_wb(dev_priv->gtt.scratch_page, 1); + pci_unmap_page(dev->pdev, dev_priv->gtt.scratch_page_dma, + PAGE_SIZE, PCI_DMA_BIDIRECTIONAL); + put_page(dev_priv->gtt.scratch_page); + __free_page(dev_priv->gtt.scratch_page); +} static inline unsigned int gen6_get_total_gtt_size(u16 snb_gmch_ctl) { @@ -609,14 +720,14 @@ static inline unsigned int gen6_get_total_gtt_size(u16 snb_gmch_ctl) return snb_gmch_ctl << 20; } -static inline unsigned int gen6_get_stolen_size(u16 snb_gmch_ctl) +static inline size_t gen6_get_stolen_size(u16 snb_gmch_ctl) { snb_gmch_ctl >>= SNB_GMCH_GMS_SHIFT; snb_gmch_ctl &= SNB_GMCH_GMS_MASK; return snb_gmch_ctl << 25; /* 32 MB units */ } -static inline unsigned int gen7_get_stolen_size(u16 snb_gmch_ctl) +static inline size_t gen7_get_stolen_size(u16 snb_gmch_ctl) { static const int stolen_decoder[] = { 0, 0, 0, 0, 0, 32, 48, 64, 128, 256, 96, 160, 224, 352}; @@ -625,91 +736,130 @@ static inline unsigned int gen7_get_stolen_size(u16 snb_gmch_ctl) return stolen_decoder[snb_gmch_ctl] << 20; } -int i915_gem_gtt_init(struct drm_device *dev) +static int gen6_gmch_probe(struct drm_device *dev, + size_t *gtt_total, + size_t *stolen, + phys_addr_t *mappable_base, + unsigned long *mappable_end) { struct drm_i915_private *dev_priv = dev->dev_private; phys_addr_t gtt_bus_addr; + unsigned int gtt_size; u16 snb_gmch_ctl; int ret; - /* On modern platforms we need not worry ourself with the legacy - * hostbridge query stuff. Skip it entirely + *mappable_base = pci_resource_start(dev->pdev, 2); + *mappable_end = pci_resource_len(dev->pdev, 2); + + /* 64/512MB is the current min/max we actually know of, but this is just + * a coarse sanity check. */ - if (INTEL_INFO(dev)->gen < 6) { - ret = intel_gmch_probe(dev_priv->bridge_dev, dev->pdev, NULL); - if (!ret) { - DRM_ERROR("failed to set up gmch\n"); - return -EIO; + if ((*mappable_end < (64<<20) || (*mappable_end > (512<<20)))) { + DRM_ERROR("Unknown GMADR size (%lx)\n", + dev_priv->gtt.mappable_end); + return -ENXIO; } - dev_priv->mm.gtt = intel_gtt_get(); - if (!dev_priv->mm.gtt) { - DRM_ERROR("Failed to initialize GTT\n"); - return -ENODEV; - } - return 0; - } + if (!pci_set_dma_mask(dev->pdev, DMA_BIT_MASK(40))) + pci_set_consistent_dma_mask(dev->pdev, DMA_BIT_MASK(40)); + pci_read_config_word(dev->pdev, SNB_GMCH_CTRL, &snb_gmch_ctl); + gtt_size = gen6_get_total_gtt_size(snb_gmch_ctl); - dev_priv->mm.gtt = kzalloc(sizeof(*dev_priv->mm.gtt), GFP_KERNEL); - if (!dev_priv->mm.gtt) - return -ENOMEM; + if (IS_GEN7(dev)) + *stolen = gen7_get_stolen_size(snb_gmch_ctl); + else + *stolen = gen6_get_stolen_size(snb_gmch_ctl); - -#ifdef CONFIG_INTEL_IOMMU - dev_priv->mm.gtt->needs_dmar = 1; -#endif + *gtt_total = (gtt_size / sizeof(gtt_pte_t)) << PAGE_SHIFT; /* For GEN6+ the PTEs for the ggtt live at 2MB + BAR0 */ gtt_bus_addr = pci_resource_start(dev->pdev, 0) + (2<<20); - dev_priv->mm.gtt->gma_bus_addr = pci_resource_start(dev->pdev, 2); - - /* i9xx_setup */ - pci_read_config_word(dev->pdev, SNB_GMCH_CTRL, &snb_gmch_ctl); - dev_priv->mm.gtt->gtt_total_entries = - gen6_get_total_gtt_size(snb_gmch_ctl) / sizeof(gtt_pte_t); - if (INTEL_INFO(dev)->gen < 7) - dev_priv->mm.gtt->stolen_size = gen6_get_stolen_size(snb_gmch_ctl); - else - dev_priv->mm.gtt->stolen_size = gen7_get_stolen_size(snb_gmch_ctl); - - dev_priv->mm.gtt->gtt_mappable_entries = pci_resource_len(dev->pdev, 2) >> PAGE_SHIFT; - /* 64/512MB is the current min/max we actually know of, but this is just a - * coarse sanity check. - */ - if ((dev_priv->mm.gtt->gtt_mappable_entries >> 8) < 64 || - dev_priv->mm.gtt->gtt_mappable_entries > dev_priv->mm.gtt->gtt_total_entries) { - DRM_ERROR("Unknown GMADR entries (%d)\n", - dev_priv->mm.gtt->gtt_mappable_entries); - ret = -ENXIO; - goto err_out; + dev_priv->gtt.gsm = ioremap_wc(gtt_bus_addr, gtt_size); + if (!dev_priv->gtt.gsm) { + DRM_ERROR("Failed to map the gtt page table\n"); + return -ENOMEM; } ret = setup_scratch_page(dev); - if (ret) { + if (ret) DRM_ERROR("Scratch setup failed\n"); - goto err_out; - } - dev_priv->mm.gtt->gtt = ioremap(gtt_bus_addr, - dev_priv->mm.gtt->gtt_total_entries * sizeof(gtt_pte_t)); - if (!dev_priv->mm.gtt->gtt) { - DRM_ERROR("Failed to map the gtt page table\n"); - ret = -ENOMEM; - goto err_out; - } + dev_priv->gtt.gtt_clear_range = gen6_ggtt_clear_range; + dev_priv->gtt.gtt_insert_entries = gen6_ggtt_insert_entries; - /* GMADR is the PCI aperture used by SW to access tiled GFX surfaces in a linear fashion. */ - DRM_INFO("Memory usable by graphics device = %dM\n", dev_priv->mm.gtt->gtt_total_entries >> 8); - DRM_DEBUG_DRIVER("GMADR size = %dM\n", dev_priv->mm.gtt->gtt_mappable_entries >> 8); - DRM_DEBUG_DRIVER("GTT stolen size = %dM\n", dev_priv->mm.gtt->stolen_size >> 20); - - return 0; - -err_out: - kfree(dev_priv->mm.gtt); return ret; } +static void gen6_gmch_remove(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + iounmap(dev_priv->gtt.gsm); + teardown_scratch_page(dev_priv->dev); +} + +static int i915_gmch_probe(struct drm_device *dev, + size_t *gtt_total, + size_t *stolen, + phys_addr_t *mappable_base, + unsigned long *mappable_end) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + int ret; + + ret = intel_gmch_probe(dev_priv->bridge_dev, dev_priv->dev->pdev, NULL); + if (!ret) { + DRM_ERROR("failed to set up gmch\n"); + return -EIO; + } + + intel_gtt_get(gtt_total, stolen, mappable_base, mappable_end); + + dev_priv->gtt.do_idle_maps = needs_idle_maps(dev_priv->dev); + dev_priv->gtt.gtt_clear_range = i915_ggtt_clear_range; + dev_priv->gtt.gtt_insert_entries = i915_ggtt_insert_entries; + + return 0; +} + +static void i915_gmch_remove(struct drm_device *dev) +{ +// intel_gmch_remove(); +} + +int i915_gem_gtt_init(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + struct i915_gtt *gtt = &dev_priv->gtt; + unsigned long gtt_size; + int ret; + + if (INTEL_INFO(dev)->gen <= 5) { + dev_priv->gtt.gtt_probe = i915_gmch_probe; + dev_priv->gtt.gtt_remove = i915_gmch_remove; + } else { + dev_priv->gtt.gtt_probe = gen6_gmch_probe; + dev_priv->gtt.gtt_remove = gen6_gmch_remove; + } + + ret = dev_priv->gtt.gtt_probe(dev, &dev_priv->gtt.total, + &dev_priv->gtt.stolen_size, + >t->mappable_base, + >t->mappable_end); + if (ret) + return ret; + + gtt_size = (dev_priv->gtt.total >> PAGE_SHIFT) * sizeof(gtt_pte_t); + + /* GMADR is the PCI mmio aperture into the global GTT. */ + DRM_INFO("Memory usable by graphics device = %zdM\n", + dev_priv->gtt.total >> 20); + DRM_DEBUG_DRIVER("GMADR size = %ldM\n", + dev_priv->gtt.mappable_end >> 20); + DRM_DEBUG_DRIVER("GTT stolen size = %zdM\n", + dev_priv->gtt.stolen_size >> 20); + + return 0; +} struct scatterlist *sg_next(struct scatterlist *sg) { diff --git a/drivers/video/drm/i915/i915_gem_stolen.c b/drivers/video/drm/i915/i915_gem_stolen.c index 8e91083b12..4239285da6 100644 --- a/drivers/video/drm/i915/i915_gem_stolen.c +++ b/drivers/video/drm/i915/i915_gem_stolen.c @@ -42,85 +42,73 @@ * for is a boon. */ -#define PTE_ADDRESS_MASK 0xfffff000 -#define PTE_ADDRESS_MASK_HIGH 0x000000f0 /* i915+ */ -#define PTE_MAPPING_TYPE_UNCACHED (0 << 1) -#define PTE_MAPPING_TYPE_DCACHE (1 << 1) /* i830 only */ -#define PTE_MAPPING_TYPE_CACHED (3 << 1) -#define PTE_MAPPING_TYPE_MASK (3 << 1) -#define PTE_VALID (1 << 0) - -/** - * i915_stolen_to_phys - take an offset into stolen memory and turn it into - * a physical one - * @dev: drm device - * @offset: address to translate - * - * Some chip functions require allocations from stolen space and need the - * physical address of the memory in question. - */ -static unsigned long i915_stolen_to_phys(struct drm_device *dev, u32 offset) +static unsigned long i915_stolen_to_physical(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; struct pci_dev *pdev = dev_priv->bridge_dev; u32 base; -#if 0 /* On the machines I have tested the Graphics Base of Stolen Memory - * is unreliable, so compute the base by subtracting the stolen memory - * from the Top of Low Usable DRAM which is where the BIOS places - * the graphics stolen memory. + * is unreliable, so on those compute the base by subtracting the + * stolen memory from the Top of Low Usable DRAM which is where the + * BIOS places the graphics stolen memory. + * + * On gen2, the layout is slightly different with the Graphics Segment + * immediately following Top of Memory (or Top of Usable DRAM). Note + * it appears that TOUD is only reported by 865g, so we just use the + * top of memory as determined by the e820 probe. + * + * XXX gen2 requires an unavailable symbol and 945gm fails with + * its value of TOLUD. */ - if (INTEL_INFO(dev)->gen > 3 || IS_G33(dev)) { - /* top 32bits are reserved = 0 */ + base = 0; + if (INTEL_INFO(dev)->gen >= 6) { + /* Read Base Data of Stolen Memory Register (BDSM) directly. + * Note that there is also a MCHBAR miror at 0x1080c0 or + * we could use device 2:0x5c instead. + */ + pci_read_config_dword(pdev, 0xB0, &base); + base &= ~4095; /* lower bits used for locking register */ + } else if (INTEL_INFO(dev)->gen > 3 || IS_G33(dev)) { + /* Read Graphics Base of Stolen Memory directly */ pci_read_config_dword(pdev, 0xA4, &base); - } else { - /* XXX presume 8xx is the same as i915 */ - pci_bus_read_config_dword(pdev->bus, 2, 0x5C, &base); - } -#else - if (INTEL_INFO(dev)->gen > 3 || IS_G33(dev)) { - u16 val; - pci_read_config_word(pdev, 0xb0, &val); - base = val >> 4 << 20; - } else { +#if 0 + } else if (IS_GEN3(dev)) { u8 val; + /* Stolen is immediately below Top of Low Usable DRAM */ pci_read_config_byte(pdev, 0x9c, &val); base = val >> 3 << 27; - } base -= dev_priv->mm.gtt->stolen_size; + } else { + /* Stolen is immediately above Top of Memory */ + base = max_low_pfn_mapped << PAGE_SHIFT; #endif + } - return base + offset; + return base; } -static void i915_warn_stolen(struct drm_device *dev) -{ - DRM_INFO("not enough stolen space for compressed buffer, disabling\n"); - DRM_INFO("hint: you may be able to increase stolen memory size in the BIOS to avoid this\n"); -} - -static void i915_setup_compression(struct drm_device *dev, int size) +static int i915_setup_compression(struct drm_device *dev, int size) { struct drm_i915_private *dev_priv = dev->dev_private; struct drm_mm_node *compressed_fb, *uninitialized_var(compressed_llb); - unsigned long cfb_base; - unsigned long ll_base = 0; - /* Just in case the BIOS is doing something questionable. */ - intel_disable_fbc(dev); - - compressed_fb = drm_mm_search_free(&dev_priv->mm.stolen, size, 4096, 0); + /* Try to over-allocate to reduce reallocations and fragmentation */ + compressed_fb = drm_mm_search_free(&dev_priv->mm.stolen, + size <<= 1, 4096, 0); + if (!compressed_fb) + compressed_fb = drm_mm_search_free(&dev_priv->mm.stolen, + size >>= 1, 4096, 0); if (compressed_fb) compressed_fb = drm_mm_get_block(compressed_fb, size, 4096); if (!compressed_fb) goto err; - cfb_base = i915_stolen_to_phys(dev, compressed_fb->start); - if (!cfb_base) - goto err_fb; - - if (!(IS_GM45(dev) || HAS_PCH_SPLIT(dev))) { + if (HAS_PCH_SPLIT(dev)) + I915_WRITE(ILK_DPFC_CB_BASE, compressed_fb->start); + else if (IS_GM45(dev)) { + I915_WRITE(DPFC_CB_BASE, compressed_fb->start); + } else { compressed_llb = drm_mm_search_free(&dev_priv->mm.stolen, 4096, 4096, 0); if (compressed_llb) @@ -129,73 +117,206 @@ static void i915_setup_compression(struct drm_device *dev, int size) if (!compressed_llb) goto err_fb; - ll_base = i915_stolen_to_phys(dev, compressed_llb->start); - if (!ll_base) - goto err_llb; - } + dev_priv->compressed_llb = compressed_llb; - dev_priv->cfb_size = size; + I915_WRITE(FBC_CFB_BASE, + dev_priv->mm.stolen_base + compressed_fb->start); + I915_WRITE(FBC_LL_BASE, + dev_priv->mm.stolen_base + compressed_llb->start); + } dev_priv->compressed_fb = compressed_fb; - if (HAS_PCH_SPLIT(dev)) - I915_WRITE(ILK_DPFC_CB_BASE, compressed_fb->start); - else if (IS_GM45(dev)) { - I915_WRITE(DPFC_CB_BASE, compressed_fb->start); - } else { - I915_WRITE(FBC_CFB_BASE, cfb_base); - I915_WRITE(FBC_LL_BASE, ll_base); - dev_priv->compressed_llb = compressed_llb; - } + dev_priv->cfb_size = size; - DRM_DEBUG_KMS("FBC base 0x%08lx, ll base 0x%08lx, size %dM\n", - cfb_base, ll_base, size >> 20); - return; + DRM_DEBUG_KMS("reserved %d bytes of contiguous stolen space for FBC\n", + size); + + return 0; -err_llb: - drm_mm_put_block(compressed_llb); err_fb: drm_mm_put_block(compressed_fb); err: - dev_priv->no_fbc_reason = FBC_STOLEN_TOO_SMALL; - i915_warn_stolen(dev); + return -ENOSPC; } -static void i915_cleanup_compression(struct drm_device *dev) +int i915_gem_stolen_setup_compression(struct drm_device *dev, int size) { struct drm_i915_private *dev_priv = dev->dev_private; + if (dev_priv->mm.stolen_base == 0) + return -ENODEV; + + if (size < dev_priv->cfb_size) + return 0; + + /* Release any current block */ + i915_gem_stolen_cleanup_compression(dev); + + return i915_setup_compression(dev, size); +} + +void i915_gem_stolen_cleanup_compression(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + + if (dev_priv->cfb_size == 0) + return; + + if (dev_priv->compressed_fb) drm_mm_put_block(dev_priv->compressed_fb); + if (dev_priv->compressed_llb) drm_mm_put_block(dev_priv->compressed_llb); + + dev_priv->cfb_size = 0; } void i915_gem_cleanup_stolen(struct drm_device *dev) { - if (I915_HAS_FBC(dev) && i915_powersave) - i915_cleanup_compression(dev); + struct drm_i915_private *dev_priv = dev->dev_private; + + i915_gem_stolen_cleanup_compression(dev); + drm_mm_takedown(&dev_priv->mm.stolen); } int i915_gem_init_stolen(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; - unsigned long prealloc_size = dev_priv->mm.gtt->stolen_size; + + dev_priv->mm.stolen_base = i915_stolen_to_physical(dev); + if (dev_priv->mm.stolen_base == 0) + return 0; + + DRM_DEBUG_KMS("found %zd bytes of stolen memory at %08lx\n", + dev_priv->gtt.stolen_size, dev_priv->mm.stolen_base); /* Basic memrange allocator for stolen space */ - drm_mm_init(&dev_priv->mm.stolen, 0, prealloc_size); - - /* Try to set up FBC with a reasonable compressed buffer size */ - if (I915_HAS_FBC(dev) && i915_powersave) { - int cfb_size; - - /* Leave 1M for line length buffer & misc. */ - - /* Try to get a 32M buffer... */ - if (prealloc_size > (36*1024*1024)) - cfb_size = 32*1024*1024; - else /* fall back to 7/8 of the stolen space */ - cfb_size = prealloc_size * 7 / 8; - i915_setup_compression(dev, cfb_size); - } + drm_mm_init(&dev_priv->mm.stolen, 0, dev_priv->gtt.stolen_size); return 0; } + +static struct sg_table * +i915_pages_create_for_stolen(struct drm_device *dev, + u32 offset, u32 size) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + struct sg_table *st; + struct scatterlist *sg; + + DRM_DEBUG_DRIVER("offset=0x%x, size=%d\n", offset, size); + BUG_ON(offset > dev_priv->gtt.stolen_size - size); + + /* We hide that we have no struct page backing our stolen object + * by wrapping the contiguous physical allocation with a fake + * dma mapping in a single scatterlist. + */ + + st = kmalloc(sizeof(*st), GFP_KERNEL); + if (st == NULL) + return NULL; + + if (sg_alloc_table(st, 1, GFP_KERNEL)) { + kfree(st); + return NULL; + } + + sg = st->sgl; + sg->offset = offset; + sg->length = size; + + sg_dma_address(sg) = (dma_addr_t)dev_priv->mm.stolen_base + offset; + sg_dma_len(sg) = size; + + return st; +} + +static int i915_gem_object_get_pages_stolen(struct drm_i915_gem_object *obj) +{ + BUG(); + return -EINVAL; +} + +static void i915_gem_object_put_pages_stolen(struct drm_i915_gem_object *obj) +{ + /* Should only be called during free */ + sg_free_table(obj->pages); + kfree(obj->pages); +} + +static const struct drm_i915_gem_object_ops i915_gem_object_stolen_ops = { + .get_pages = i915_gem_object_get_pages_stolen, + .put_pages = i915_gem_object_put_pages_stolen, +}; + +static struct drm_i915_gem_object * +_i915_gem_object_create_stolen(struct drm_device *dev, + struct drm_mm_node *stolen) +{ + struct drm_i915_gem_object *obj; + + obj = i915_gem_object_alloc(dev); + if (obj == NULL) + return NULL; + + if (drm_gem_private_object_init(dev, &obj->base, stolen->size)) + goto cleanup; + + i915_gem_object_init(obj, &i915_gem_object_stolen_ops); + + obj->pages = i915_pages_create_for_stolen(dev, + stolen->start, stolen->size); + if (obj->pages == NULL) + goto cleanup; + + obj->has_dma_mapping = true; + obj->pages_pin_count = 1; + obj->stolen = stolen; + + obj->base.write_domain = I915_GEM_DOMAIN_GTT; + obj->base.read_domains = I915_GEM_DOMAIN_GTT; + obj->cache_level = I915_CACHE_NONE; + + return obj; + +cleanup: + i915_gem_object_free(obj); + return NULL; +} + +struct drm_i915_gem_object * +i915_gem_object_create_stolen(struct drm_device *dev, u32 size) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + struct drm_i915_gem_object *obj; + struct drm_mm_node *stolen; + + if (dev_priv->mm.stolen_base == 0) + return NULL; + + DRM_DEBUG_KMS("creating stolen object: size=%x\n", size); + if (size == 0) + return NULL; + + stolen = drm_mm_search_free(&dev_priv->mm.stolen, size, 4096, 0); + if (stolen) + stolen = drm_mm_get_block(stolen, size, 4096); + if (stolen == NULL) + return NULL; + + obj = _i915_gem_object_create_stolen(dev, stolen); + if (obj) + return obj; + + drm_mm_put_block(stolen); + return NULL; +} + +void +i915_gem_object_release_stolen(struct drm_i915_gem_object *obj) +{ + if (obj->stolen) { + drm_mm_put_block(obj->stolen); + obj->stolen = NULL; + } +} diff --git a/drivers/video/drm/i915/i915_gem_tiling.c b/drivers/video/drm/i915/i915_gem_tiling.c index 96b6a3387c..e5cd8491d8 100644 --- a/drivers/video/drm/i915/i915_gem_tiling.c +++ b/drivers/video/drm/i915/i915_gem_tiling.c @@ -291,18 +291,7 @@ i915_gem_object_fence_ok(struct drm_i915_gem_object *obj, int tiling_mode) return false; } - /* - * Previous chips need to be aligned to the size of the smallest - * fence register that can contain the object. - */ - if (INTEL_INFO(obj->base.dev)->gen == 3) - size = 1024*1024; - else - size = 512*1024; - - while (size < obj->base.size) - size <<= 1; - + size = i915_gem_get_gtt_size(obj->base.dev, obj->base.size, tiling_mode); if (obj->gtt_space->size != size) return false; @@ -387,15 +376,15 @@ i915_gem_set_tiling(struct drm_device *dev, void *data, obj->map_and_fenceable = obj->gtt_space == NULL || - (obj->gtt_offset + obj->base.size <= dev_priv->mm.gtt_mappable_end && + (obj->gtt_offset + obj->base.size <= dev_priv->gtt.mappable_end && i915_gem_object_fence_ok(obj, args->tiling_mode)); /* Rebind if we need a change of alignment */ if (!obj->map_and_fenceable) { u32 unfenced_alignment = - i915_gem_get_unfenced_gtt_alignment(dev, - obj->base.size, - args->tiling_mode); + i915_gem_get_gtt_alignment(dev, obj->base.size, + args->tiling_mode, + false); if (obj->gtt_offset & (unfenced_alignment - 1)) ret = i915_gem_object_unbind(obj); } @@ -415,6 +404,18 @@ i915_gem_set_tiling(struct drm_device *dev, void *data, /* we have to maintain this existing ABI... */ args->stride = obj->stride; args->tiling_mode = obj->tiling_mode; + + /* Try to preallocate memory required to save swizzling on put-pages */ + if (i915_gem_object_needs_bit17_swizzle(obj)) { + if (obj->bit_17 == NULL) { + obj->bit_17 = kmalloc(BITS_TO_LONGS(obj->base.size >> PAGE_SHIFT) * + sizeof(long), GFP_KERNEL); + } + } else { + kfree(obj->bit_17); + obj->bit_17 = NULL; + } + drm_gem_object_unreference(&obj->base); mutex_unlock(&dev->struct_mutex); diff --git a/drivers/video/drm/i915/i915_irq.c b/drivers/video/drm/i915/i915_irq.c index 64c8759220..be069e6fe8 100644 --- a/drivers/video/drm/i915/i915_irq.c +++ b/drivers/video/drm/i915/i915_irq.c @@ -45,32 +45,7 @@ #define MAX_NOPID ((u32)~0) -/** - * Interrupts that are always left unmasked. - * - * Since pipe events are edge-triggered from the PIPESTAT register to IIR, - * we leave them always unmasked in IMR and then control enabling them through - * PIPESTAT alone. - */ -#define I915_INTERRUPT_ENABLE_FIX \ - (I915_ASLE_INTERRUPT | \ - I915_DISPLAY_PIPE_A_EVENT_INTERRUPT | \ - I915_DISPLAY_PIPE_B_EVENT_INTERRUPT | \ - I915_DISPLAY_PLANE_A_FLIP_PENDING_INTERRUPT | \ - I915_DISPLAY_PLANE_B_FLIP_PENDING_INTERRUPT | \ - I915_RENDER_COMMAND_PARSER_ERROR_INTERRUPT) -/** Interrupts that we mask and unmask at runtime. */ -#define I915_INTERRUPT_ENABLE_VAR (I915_USER_INTERRUPT | I915_BSD_USER_INTERRUPT) - -#define I915_PIPE_VBLANK_STATUS (PIPE_START_VBLANK_INTERRUPT_STATUS |\ - PIPE_VBLANK_INTERRUPT_STATUS) - -#define I915_PIPE_VBLANK_ENABLE (PIPE_START_VBLANK_INTERRUPT_ENABLE |\ - PIPE_VBLANK_INTERRUPT_ENABLE) - -#define DRM_I915_VBLANK_PIPE_ALL (DRM_I915_VBLANK_PIPE_A | \ - DRM_I915_VBLANK_PIPE_B) /* For display hotplug interrupt */ static void @@ -215,6 +190,33 @@ static u32 gm45_get_vblank_counter(struct drm_device *dev, int pipe) return I915_READ(reg); } +/* + * Handle hotplug events outside the interrupt handler proper. + */ +static void i915_hotplug_work_func(struct work_struct *work) +{ + drm_i915_private_t *dev_priv = container_of(work, drm_i915_private_t, + hotplug_work); + struct drm_device *dev = dev_priv->dev; + struct drm_mode_config *mode_config = &dev->mode_config; + struct intel_encoder *encoder; + + /* HPD irq before everything is fully set up. */ + if (!dev_priv->enable_hotplug_processing) + return; + + mutex_lock(&mode_config->mutex); + DRM_DEBUG_KMS("running encoder hotplug functions\n"); + + list_for_each_entry(encoder, &mode_config->encoder_list, base.head) + if (encoder->hot_plug) + encoder->hot_plug(encoder); + + mutex_unlock(&mode_config->mutex); + + /* Just fire off a uevent and let userspace tell us what to do */ + drm_helper_hpd_irq_event(dev); +} static void notify_ring(struct drm_device *dev, struct intel_ring_buffer *ring) @@ -402,6 +404,20 @@ static void gen6_queue_rps_work(struct drm_i915_private *dev_priv, // queue_work(dev_priv->wq, &dev_priv->rps.work); } +static void gmbus_irq_handler(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = (drm_i915_private_t *) dev->dev_private; + + wake_up_all(&dev_priv->gmbus_wait_queue); +} + +static void dp_aux_irq_handler(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = (drm_i915_private_t *) dev->dev_private; + + wake_up_all(&dev_priv->gmbus_wait_queue); +} + static irqreturn_t valleyview_irq_handler(int irq, void *arg) { struct drm_device *dev = (struct drm_device *) arg; @@ -411,7 +427,6 @@ static irqreturn_t valleyview_irq_handler(int irq, void *arg) unsigned long irqflags; int pipe; u32 pipe_stats[I915_MAX_PIPES]; - bool blc_event; atomic_inc(&dev_priv->irq_received); @@ -462,19 +477,19 @@ static irqreturn_t valleyview_irq_handler(int irq, void *arg) DRM_DEBUG_DRIVER("hotplug event received, stat 0x%08x\n", hotplug_status); -// if (hotplug_status & dev_priv->hotplug_supported_mask) -// queue_work(dev_priv->wq, -// &dev_priv->hotplug_work); + if (hotplug_status & dev_priv->hotplug_supported_mask) + queue_work(dev_priv->wq, + &dev_priv->hotplug_work); I915_WRITE(PORT_HOTPLUG_STAT, hotplug_status); I915_READ(PORT_HOTPLUG_STAT); } - if (pipe_stats[pipe] & PIPE_LEGACY_BLC_EVENT_STATUS) - blc_event = true; + if (pipe_stats[0] & PIPE_GMBUS_INTERRUPT_STATUS) + gmbus_irq_handler(dev); - if (pm_iir & GEN6_PM_DEFERRED_EVENTS) - gen6_queue_rps_work(dev_priv, pm_iir); +// if (pm_iir & GEN6_PM_DEFERRED_EVENTS) +// gen6_queue_rps_work(dev_priv, pm_iir); I915_WRITE(GTIIR, gt_iir); I915_WRITE(GEN6_PMIIR, pm_iir); @@ -490,15 +505,19 @@ static void ibx_irq_handler(struct drm_device *dev, u32 pch_iir) drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; int pipe; - printf("%s\n", __FUNCTION__); + if (pch_iir & SDE_HOTPLUG_MASK) + queue_work(dev_priv->wq, &dev_priv->hotplug_work); if (pch_iir & SDE_AUDIO_POWER_MASK) DRM_DEBUG_DRIVER("PCH audio power change on port %d\n", (pch_iir & SDE_AUDIO_POWER_MASK) >> SDE_AUDIO_POWER_SHIFT); + if (pch_iir & SDE_AUX_MASK) + dp_aux_irq_handler(dev); + if (pch_iir & SDE_GMBUS) - DRM_DEBUG_DRIVER("PCH GMBUS interrupt\n"); + gmbus_irq_handler(dev); if (pch_iir & SDE_AUDIO_HDCP_MASK) DRM_DEBUG_DRIVER("PCH HDCP audio interrupt\n"); @@ -532,16 +551,19 @@ static void cpt_irq_handler(struct drm_device *dev, u32 pch_iir) drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; int pipe; + if (pch_iir & SDE_HOTPLUG_MASK_CPT) + queue_work(dev_priv->wq, &dev_priv->hotplug_work); + if (pch_iir & SDE_AUDIO_POWER_MASK_CPT) DRM_DEBUG_DRIVER("PCH audio power change on port %d\n", (pch_iir & SDE_AUDIO_POWER_MASK_CPT) >> SDE_AUDIO_POWER_SHIFT_CPT); if (pch_iir & SDE_AUX_MASK_CPT) - DRM_DEBUG_DRIVER("AUX channel interrupt\n"); + dp_aux_irq_handler(dev); if (pch_iir & SDE_GMBUS_CPT) - DRM_DEBUG_DRIVER("PCH GMBUS interrupt\n"); + gmbus_irq_handler(dev); if (pch_iir & SDE_AUDIO_CP_REQ_CPT) DRM_DEBUG_DRIVER("Audio CP request interrupt\n"); @@ -560,7 +582,7 @@ static irqreturn_t ivybridge_irq_handler(int irq, void *arg) { struct drm_device *dev = (struct drm_device *) arg; drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; - u32 de_iir, gt_iir, de_ier, pm_iir; + u32 de_iir, gt_iir, de_ier, pm_iir, sde_ier; irqreturn_t ret = IRQ_NONE; int i; @@ -570,6 +592,15 @@ static irqreturn_t ivybridge_irq_handler(int irq, void *arg) de_ier = I915_READ(DEIER); I915_WRITE(DEIER, de_ier & ~DE_MASTER_IRQ_CONTROL); + /* Disable south interrupts. We'll only write to SDEIIR once, so further + * interrupts will will be stored on its back queue, and then we'll be + * able to process them after we restore SDEIER (as soon as we restore + * it, we'll get an interrupt if SDEIIR still has something to process + * due to its back queue). */ + sde_ier = I915_READ(SDEIER); + I915_WRITE(SDEIER, 0); + POSTING_READ(SDEIER); + gt_iir = I915_READ(GTIIR); if (gt_iir) { snb_gt_irq_handler(dev, dev_priv, gt_iir); @@ -579,6 +610,8 @@ static irqreturn_t ivybridge_irq_handler(int irq, void *arg) de_iir = I915_READ(DEIIR); if (de_iir) { + if (de_iir & DE_AUX_CHANNEL_A_IVB) + dp_aux_irq_handler(dev); #if 0 if (de_iir & DE_GSE_IVB) intel_opregion_gse_intr(dev); @@ -596,8 +629,6 @@ static irqreturn_t ivybridge_irq_handler(int irq, void *arg) if (de_iir & DE_PCH_EVENT_IVB) { u32 pch_iir = I915_READ(SDEIIR); -// if (pch_iir & SDE_HOTPLUG_MASK_CPT) -// queue_work(dev_priv->wq, &dev_priv->hotplug_work); cpt_irq_handler(dev, pch_iir); /* clear PCH hotplug event before clear CPU irq */ @@ -618,6 +649,8 @@ static irqreturn_t ivybridge_irq_handler(int irq, void *arg) I915_WRITE(DEIER, de_ier); POSTING_READ(DEIER); + I915_WRITE(SDEIER, sde_ier); + POSTING_READ(SDEIER); return ret; } @@ -637,7 +670,7 @@ static irqreturn_t ironlake_irq_handler(int irq, void *arg) struct drm_device *dev = (struct drm_device *) arg; drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; int ret = IRQ_NONE; - u32 de_iir, gt_iir, de_ier, pch_iir, pm_iir; + u32 de_iir, gt_iir, de_ier, pm_iir, sde_ier; atomic_inc(&dev_priv->irq_received); @@ -646,13 +679,20 @@ static irqreturn_t ironlake_irq_handler(int irq, void *arg) I915_WRITE(DEIER, de_ier & ~DE_MASTER_IRQ_CONTROL); POSTING_READ(DEIER); + /* Disable south interrupts. We'll only write to SDEIIR once, so further + * interrupts will will be stored on its back queue, and then we'll be + * able to process them after we restore SDEIER (as soon as we restore + * it, we'll get an interrupt if SDEIIR still has something to process + * due to its back queue). */ + sde_ier = I915_READ(SDEIER); + I915_WRITE(SDEIER, 0); + POSTING_READ(SDEIER); + de_iir = I915_READ(DEIIR); gt_iir = I915_READ(GTIIR); - pch_iir = I915_READ(SDEIIR); pm_iir = I915_READ(GEN6_PMIIR); - if (de_iir == 0 && gt_iir == 0 && pch_iir == 0 && - (!IS_GEN6(dev) || pm_iir == 0)) + if (de_iir == 0 && gt_iir == 0 && (!IS_GEN6(dev) || pm_iir == 0)) goto done; ret = IRQ_HANDLED; @@ -661,6 +701,10 @@ static irqreturn_t ironlake_irq_handler(int irq, void *arg) ilk_gt_irq_handler(dev, dev_priv, gt_iir); else snb_gt_irq_handler(dev, dev_priv, gt_iir); + + if (de_iir & DE_AUX_CHANNEL_A) + dp_aux_irq_handler(dev); + #if 0 if (de_iir & DE_GSE) intel_opregion_gse_intr(dev); @@ -684,12 +728,15 @@ static irqreturn_t ironlake_irq_handler(int irq, void *arg) /* check event from PCH */ if (de_iir & DE_PCH_EVENT) { -// if (pch_iir & hotplug_mask) -// queue_work(dev_priv->wq, &dev_priv->hotplug_work); + u32 pch_iir = I915_READ(SDEIIR); + if (HAS_PCH_CPT(dev)) cpt_irq_handler(dev, pch_iir); else ibx_irq_handler(dev, pch_iir); + + /* should clear PCH hotplug event before clear CPU irq */ + I915_WRITE(SDEIIR, pch_iir); } #if 0 if (IS_GEN5(dev) && de_iir & DE_PCU_EVENT) @@ -698,8 +745,6 @@ static irqreturn_t ironlake_irq_handler(int irq, void *arg) if (IS_GEN6(dev) && pm_iir & GEN6_PM_DEFERRED_EVENTS) gen6_queue_rps_work(dev_priv, pm_iir); #endif - /* should clear PCH hotplug event before clear CPU irq */ - I915_WRITE(SDEIIR, pch_iir); I915_WRITE(GTIIR, gt_iir); I915_WRITE(DEIIR, de_iir); I915_WRITE(GEN6_PMIIR, pm_iir); @@ -707,6 +752,8 @@ static irqreturn_t ironlake_irq_handler(int irq, void *arg) done: I915_WRITE(DEIER, de_ier); POSTING_READ(DEIER); + I915_WRITE(SDEIER, sde_ier); + POSTING_READ(SDEIER); return ret; } @@ -733,7 +780,7 @@ static void i915_get_extra_instdone(struct drm_device *dev, instdone[1] = I915_READ(INSTDONE1); break; default: - WARN(1, "Unsupported platform\n"); + WARN_ONCE(1, "Unsupported platform\n"); case 7: instdone[0] = I915_READ(GEN7_INSTDONE_1); instdone[1] = I915_READ(GEN7_SC_INSTDONE); @@ -771,7 +818,7 @@ i915_error_object_create(struct drm_i915_private *dev_priv, goto unwind; local_irq_save(flags); - if (reloc_offset < dev_priv->mm.gtt_mappable_end && + if (reloc_offset < dev_priv->gtt.mappable_end && src->has_global_gtt_mapping) { void __iomem *s; @@ -780,10 +827,18 @@ i915_error_object_create(struct drm_i915_private *dev_priv, * captures what the GPU read. */ - s = io_mapping_map_atomic_wc(dev_priv->mm.gtt_mapping, + s = io_mapping_map_atomic_wc(dev_priv->gtt.mappable, reloc_offset); memcpy_fromio(d, s, PAGE_SIZE); io_mapping_unmap_atomic(s); + } else if (src->stolen) { + unsigned long offset; + + offset = dev_priv->mm.stolen_base; + offset += src->stolen->start; + offset += i << PAGE_SHIFT; + + memcpy_fromio(d, (void __iomem *) offset, PAGE_SIZE); } else { struct page *page; void *s; @@ -930,6 +985,8 @@ static void i915_gem_record_fences(struct drm_device *dev, error->fence[i] = I915_READ(FENCE_REG_830_0 + (i * 4)); break; + default: + BUG(); } } @@ -943,6 +1000,18 @@ i915_error_first_batchbuffer(struct drm_i915_private *dev_priv, if (!ring->get_seqno) return NULL; + if (HAS_BROKEN_CS_TLB(dev_priv->dev)) { + u32 acthd = I915_READ(ACTHD); + + if (WARN_ON(ring->id != RCS)) + return NULL; + + obj = ring->private; + if (acthd >= obj->gtt_offset && + acthd < obj->gtt_offset + obj->base.size) + return i915_error_object_create(dev_priv, obj); + } + seqno = ring->get_seqno(ring, false); list_for_each_entry(obj, &dev_priv->mm.active_list, mm_list) { if (obj->ring != ring) @@ -1066,9 +1135,9 @@ static void i915_capture_error_state(struct drm_device *dev) unsigned long flags; int i, pipe; - spin_lock_irqsave(&dev_priv->error_lock, flags); - error = dev_priv->first_error; - spin_unlock_irqrestore(&dev_priv->error_lock, flags); + spin_lock_irqsave(&dev_priv->gpu_error.lock, flags); + error = dev_priv->gpu_error.first_error; + spin_unlock_irqrestore(&dev_priv->gpu_error.lock, flags); if (error) return; @@ -1079,7 +1148,8 @@ static void i915_capture_error_state(struct drm_device *dev) return; } - DRM_INFO("capturing error event; look for more information in /debug/dri/%d/i915_error_state\n", + DRM_INFO("capturing error event; look for more information in" + "/sys/kernel/debug/dri/%d/i915_error_state\n", dev->primary->index); kref_init(&error->ref); @@ -1162,12 +1232,12 @@ static void i915_capture_error_state(struct drm_device *dev) error->overlay = intel_overlay_capture_error_state(dev); error->display = intel_display_capture_error_state(dev); - spin_lock_irqsave(&dev_priv->error_lock, flags); - if (dev_priv->first_error == NULL) { - dev_priv->first_error = error; + spin_lock_irqsave(&dev_priv->gpu_error.lock, flags); + if (dev_priv->gpu_error.first_error == NULL) { + dev_priv->gpu_error.first_error = error; error = NULL; } - spin_unlock_irqrestore(&dev_priv->error_lock, flags); + spin_unlock_irqrestore(&dev_priv->gpu_error.lock, flags); if (error) i915_error_state_free(&error->ref); @@ -1179,10 +1249,10 @@ void i915_destroy_error_state(struct drm_device *dev) struct drm_i915_error_state *error; unsigned long flags; - spin_lock_irqsave(&dev_priv->error_lock, flags); - error = dev_priv->first_error; - dev_priv->first_error = NULL; - spin_unlock_irqrestore(&dev_priv->error_lock, flags); + spin_lock_irqsave(&dev_priv->gpu_error.lock, flags); + error = dev_priv->gpu_error.first_error; + dev_priv->gpu_error.first_error = NULL; + spin_unlock_irqrestore(&dev_priv->gpu_error.lock, flags); if (error) kref_put(&error->ref, i915_error_state_free); @@ -1303,11 +1373,12 @@ void i915_handle_error(struct drm_device *dev, bool wedged) i915_report_and_clear_eir(dev); if (wedged) { -// INIT_COMPLETION(dev_priv->error_completion); - atomic_set(&dev_priv->mm.wedged, 1); + atomic_set_mask(I915_RESET_IN_PROGRESS_FLAG, + &dev_priv->gpu_error.reset_counter); /* - * Wakeup waiting processes so they don't hang + * Wakeup waiting processes so that the reset work item + * doesn't deadlock trying to grab various locks. */ for_each_ring(ring, dev_priv, i) wake_up_all(&ring->irq_queue); @@ -1579,7 +1650,7 @@ static void valleyview_irq_preinstall(struct drm_device *dev) * This register is the same on all known PCH chips. */ -static void ironlake_enable_pch_hotplug(struct drm_device *dev) +static void ibx_enable_hotplug(struct drm_device *dev) { drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; u32 hotplug; @@ -1592,14 +1663,36 @@ static void ironlake_enable_pch_hotplug(struct drm_device *dev) I915_WRITE(PCH_PORT_HOTPLUG, hotplug); } +static void ibx_irq_postinstall(struct drm_device *dev) +{ + drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; + u32 mask; + + if (HAS_PCH_IBX(dev)) + mask = SDE_HOTPLUG_MASK | + SDE_GMBUS | + SDE_AUX_MASK; + else + mask = SDE_HOTPLUG_MASK_CPT | + SDE_GMBUS_CPT | + SDE_AUX_MASK_CPT; + + I915_WRITE(SDEIIR, I915_READ(SDEIIR)); + I915_WRITE(SDEIMR, ~mask); + I915_WRITE(SDEIER, mask); + POSTING_READ(SDEIER); + + ibx_enable_hotplug(dev); +} + static int ironlake_irq_postinstall(struct drm_device *dev) { drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; /* enable kind of interrupts always enabled */ u32 display_mask = DE_MASTER_IRQ_CONTROL | DE_GSE | DE_PCH_EVENT | - DE_PLANEA_FLIP_DONE | DE_PLANEB_FLIP_DONE; + DE_PLANEA_FLIP_DONE | DE_PLANEB_FLIP_DONE | + DE_AUX_CHANNEL_A; u32 render_irqs; - u32 hotplug_mask; dev_priv->irq_mask = ~display_mask; @@ -1627,33 +1720,13 @@ static int ironlake_irq_postinstall(struct drm_device *dev) I915_WRITE(GTIER, render_irqs); POSTING_READ(GTIER); - if (HAS_PCH_CPT(dev)) { - hotplug_mask = (SDE_CRT_HOTPLUG_CPT | - SDE_PORTB_HOTPLUG_CPT | - SDE_PORTC_HOTPLUG_CPT | - SDE_PORTD_HOTPLUG_CPT); - } else { - hotplug_mask = (SDE_CRT_HOTPLUG | - SDE_PORTB_HOTPLUG | - SDE_PORTC_HOTPLUG | - SDE_PORTD_HOTPLUG | - SDE_AUX_MASK); - } - - dev_priv->pch_irq_mask = ~hotplug_mask; - - I915_WRITE(SDEIIR, I915_READ(SDEIIR)); - I915_WRITE(SDEIMR, dev_priv->pch_irq_mask); - I915_WRITE(SDEIER, hotplug_mask); - POSTING_READ(SDEIER); - -// ironlake_enable_pch_hotplug(dev); + ibx_irq_postinstall(dev); if (IS_IRONLAKE_M(dev)) { /* Clear & enable PCU event interrupts */ I915_WRITE(DEIIR, DE_PCU_EVENT); I915_WRITE(DEIER, I915_READ(DEIER) | DE_PCU_EVENT); -// ironlake_enable_display_irq(dev_priv, DE_PCU_EVENT); + ironlake_enable_display_irq(dev_priv, DE_PCU_EVENT); } return 0; @@ -1667,9 +1740,9 @@ static int ivybridge_irq_postinstall(struct drm_device *dev) DE_MASTER_IRQ_CONTROL | DE_GSE_IVB | DE_PCH_EVENT_IVB | DE_PLANEC_FLIP_DONE_IVB | DE_PLANEB_FLIP_DONE_IVB | - DE_PLANEA_FLIP_DONE_IVB; + DE_PLANEA_FLIP_DONE_IVB | + DE_AUX_CHANNEL_A_IVB; u32 render_irqs; - u32 hotplug_mask; dev_priv->irq_mask = ~display_mask; @@ -1693,18 +1766,7 @@ static int ivybridge_irq_postinstall(struct drm_device *dev) I915_WRITE(GTIER, render_irqs); POSTING_READ(GTIER); - hotplug_mask = (SDE_CRT_HOTPLUG_CPT | - SDE_PORTB_HOTPLUG_CPT | - SDE_PORTC_HOTPLUG_CPT | - SDE_PORTD_HOTPLUG_CPT); - dev_priv->pch_irq_mask = ~hotplug_mask; - - I915_WRITE(SDEIIR, I915_READ(SDEIIR)); - I915_WRITE(SDEIMR, dev_priv->pch_irq_mask); - I915_WRITE(SDEIER, hotplug_mask); - POSTING_READ(SDEIER); - -// ironlake_enable_pch_hotplug(dev); + ibx_irq_postinstall(dev); return 0; } @@ -1713,7 +1775,6 @@ static int valleyview_irq_postinstall(struct drm_device *dev) { drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; u32 enable_mask; - u32 hotplug_en = I915_READ(PORT_HOTPLUG_EN); u32 pipestat_enable = PLANE_FLIP_DONE_INT_EN_VLV; u32 render_irqs; u16 msid; @@ -1742,6 +1803,9 @@ static int valleyview_irq_postinstall(struct drm_device *dev) // msid |= (1<<14); // pci_write_config_word(dev_priv->dev->pdev, 0x98, msid); + I915_WRITE(PORT_HOTPLUG_EN, 0); + POSTING_READ(PORT_HOTPLUG_EN); + I915_WRITE(VLV_IMR, dev_priv->irq_mask); I915_WRITE(VLV_IER, enable_mask); I915_WRITE(VLV_IIR, 0xffffffff); @@ -1750,6 +1814,7 @@ static int valleyview_irq_postinstall(struct drm_device *dev) POSTING_READ(VLV_IER); i915_enable_pipestat(dev_priv, 0, pipestat_enable); + i915_enable_pipestat(dev_priv, 0, PIPE_GMBUS_EVENT_ENABLE); i915_enable_pipestat(dev_priv, 1, pipestat_enable); I915_WRITE(VLV_IIR, 0xffffffff); @@ -1770,14 +1835,22 @@ static int valleyview_irq_postinstall(struct drm_device *dev) #endif I915_WRITE(VLV_MASTER_IER, MASTER_INTERRUPT_ENABLE); -#if 0 /* FIXME: check register definitions; some have moved */ + + return 0; +} + +static void valleyview_hpd_irq_setup(struct drm_device *dev) +{ + drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; + u32 hotplug_en = I915_READ(PORT_HOTPLUG_EN); + /* Note HDMI and DP share bits */ - if (dev_priv->hotplug_supported_mask & HDMIB_HOTPLUG_INT_STATUS) - hotplug_en |= HDMIB_HOTPLUG_INT_EN; - if (dev_priv->hotplug_supported_mask & HDMIC_HOTPLUG_INT_STATUS) - hotplug_en |= HDMIC_HOTPLUG_INT_EN; - if (dev_priv->hotplug_supported_mask & HDMID_HOTPLUG_INT_STATUS) - hotplug_en |= HDMID_HOTPLUG_INT_EN; + if (dev_priv->hotplug_supported_mask & PORTB_HOTPLUG_INT_STATUS) + hotplug_en |= PORTB_HOTPLUG_INT_EN; + if (dev_priv->hotplug_supported_mask & PORTC_HOTPLUG_INT_STATUS) + hotplug_en |= PORTC_HOTPLUG_INT_EN; + if (dev_priv->hotplug_supported_mask & PORTD_HOTPLUG_INT_STATUS) + hotplug_en |= PORTD_HOTPLUG_INT_EN; if (dev_priv->hotplug_supported_mask & SDVOC_HOTPLUG_INT_STATUS_I915) hotplug_en |= SDVOC_HOTPLUG_INT_EN; if (dev_priv->hotplug_supported_mask & SDVOB_HOTPLUG_INT_STATUS_I915) @@ -1786,11 +1859,8 @@ static int valleyview_irq_postinstall(struct drm_device *dev) hotplug_en |= CRT_HOTPLUG_INT_EN; hotplug_en |= CRT_HOTPLUG_VOLTAGE_COMPARE_50; } -#endif I915_WRITE(PORT_HOTPLUG_EN, hotplug_en); - - return 0; } static void valleyview_irq_uninstall(struct drm_device *dev) @@ -2022,28 +2092,40 @@ static int i915_irq_postinstall(struct drm_device *dev) I915_DISPLAY_PIPE_B_EVENT_INTERRUPT | I915_RENDER_COMMAND_PARSER_ERROR_INTERRUPT | I915_USER_INTERRUPT; -#if 0 + if (I915_HAS_HOTPLUG(dev)) { + I915_WRITE(PORT_HOTPLUG_EN, 0); + POSTING_READ(PORT_HOTPLUG_EN); + /* Enable in IER... */ enable_mask |= I915_DISPLAY_PORT_INTERRUPT; /* and unmask in IMR */ dev_priv->irq_mask &= ~I915_DISPLAY_PORT_INTERRUPT; } -#endif I915_WRITE(IMR, dev_priv->irq_mask); I915_WRITE(IER, enable_mask); POSTING_READ(IER); +// intel_opregion_enable_asle(dev); + + return 0; +} + +static void i915_hpd_irq_setup(struct drm_device *dev) +{ + drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; + u32 hotplug_en; + if (I915_HAS_HOTPLUG(dev)) { - u32 hotplug_en = I915_READ(PORT_HOTPLUG_EN); -#if 0 - if (dev_priv->hotplug_supported_mask & HDMIB_HOTPLUG_INT_STATUS) - hotplug_en |= HDMIB_HOTPLUG_INT_EN; - if (dev_priv->hotplug_supported_mask & HDMIC_HOTPLUG_INT_STATUS) - hotplug_en |= HDMIC_HOTPLUG_INT_EN; - if (dev_priv->hotplug_supported_mask & HDMID_HOTPLUG_INT_STATUS) - hotplug_en |= HDMID_HOTPLUG_INT_EN; + hotplug_en = I915_READ(PORT_HOTPLUG_EN); + + if (dev_priv->hotplug_supported_mask & PORTB_HOTPLUG_INT_STATUS) + hotplug_en |= PORTB_HOTPLUG_INT_EN; + if (dev_priv->hotplug_supported_mask & PORTC_HOTPLUG_INT_STATUS) + hotplug_en |= PORTC_HOTPLUG_INT_EN; + if (dev_priv->hotplug_supported_mask & PORTD_HOTPLUG_INT_STATUS) + hotplug_en |= PORTD_HOTPLUG_INT_EN; if (dev_priv->hotplug_supported_mask & SDVOC_HOTPLUG_INT_STATUS_I915) hotplug_en |= SDVOC_HOTPLUG_INT_EN; if (dev_priv->hotplug_supported_mask & SDVOB_HOTPLUG_INT_STATUS_I915) @@ -2052,15 +2134,11 @@ static int i915_irq_postinstall(struct drm_device *dev) hotplug_en |= CRT_HOTPLUG_INT_EN; hotplug_en |= CRT_HOTPLUG_VOLTAGE_COMPARE_50; } -#endif + /* Ignore TV since it's buggy */ I915_WRITE(PORT_HOTPLUG_EN, hotplug_en); } - -// intel_opregion_enable_asle(dev); - - return 0; } static irqreturn_t i915_irq_handler(int irq, void *arg) @@ -2119,9 +2197,9 @@ static irqreturn_t i915_irq_handler(int irq, void *arg) DRM_DEBUG_DRIVER("hotplug event received, stat 0x%08x\n", hotplug_status); -// if (hotplug_status & dev_priv->hotplug_supported_mask) -// queue_work(dev_priv->wq, -// &dev_priv->hotplug_work); + if (hotplug_status & dev_priv->hotplug_supported_mask) + queue_work(dev_priv->wq, + &dev_priv->hotplug_work); I915_WRITE(PORT_HOTPLUG_STAT, hotplug_status); POSTING_READ(PORT_HOTPLUG_STAT); @@ -2220,7 +2298,6 @@ static void i965_irq_preinstall(struct drm_device * dev) static int i965_irq_postinstall(struct drm_device *dev) { drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; - u32 hotplug_en; u32 enable_mask; u32 error_mask; @@ -2241,6 +2318,7 @@ static int i965_irq_postinstall(struct drm_device *dev) dev_priv->pipestat[0] = 0; dev_priv->pipestat[1] = 0; + i915_enable_pipestat(dev_priv, 0, PIPE_GMBUS_EVENT_ENABLE); /* * Enable some error detection, note the instruction error mask @@ -2261,15 +2339,27 @@ static int i965_irq_postinstall(struct drm_device *dev) I915_WRITE(IER, enable_mask); POSTING_READ(IER); + I915_WRITE(PORT_HOTPLUG_EN, 0); + POSTING_READ(PORT_HOTPLUG_EN); + +// intel_opregion_enable_asle(dev); + + return 0; +} + +static void i965_hpd_irq_setup(struct drm_device *dev) +{ + drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; + u32 hotplug_en; + /* Note HDMI and DP share hotplug bits */ hotplug_en = 0; -#if 0 - if (dev_priv->hotplug_supported_mask & HDMIB_HOTPLUG_INT_STATUS) - hotplug_en |= HDMIB_HOTPLUG_INT_EN; - if (dev_priv->hotplug_supported_mask & HDMIC_HOTPLUG_INT_STATUS) - hotplug_en |= HDMIC_HOTPLUG_INT_EN; - if (dev_priv->hotplug_supported_mask & HDMID_HOTPLUG_INT_STATUS) - hotplug_en |= HDMID_HOTPLUG_INT_EN; + if (dev_priv->hotplug_supported_mask & PORTB_HOTPLUG_INT_STATUS) + hotplug_en |= PORTB_HOTPLUG_INT_EN; + if (dev_priv->hotplug_supported_mask & PORTC_HOTPLUG_INT_STATUS) + hotplug_en |= PORTC_HOTPLUG_INT_EN; + if (dev_priv->hotplug_supported_mask & PORTD_HOTPLUG_INT_STATUS) + hotplug_en |= PORTD_HOTPLUG_INT_EN; if (IS_G4X(dev)) { if (dev_priv->hotplug_supported_mask & SDVOC_HOTPLUG_INT_STATUS_G4X) hotplug_en |= SDVOC_HOTPLUG_INT_EN; @@ -2292,14 +2382,10 @@ static int i965_irq_postinstall(struct drm_device *dev) hotplug_en |= CRT_HOTPLUG_ACTIVATION_PERIOD_64; hotplug_en |= CRT_HOTPLUG_VOLTAGE_COMPARE_50; } -#endif + /* Ignore TV since it's buggy */ I915_WRITE(PORT_HOTPLUG_EN, hotplug_en); - -// intel_opregion_enable_asle(dev); - - return 0; } static irqreturn_t i965_irq_handler(int irq, void *arg) @@ -2358,9 +2444,9 @@ static irqreturn_t i965_irq_handler(int irq, void *arg) DRM_DEBUG_DRIVER("hotplug event received, stat 0x%08x\n", hotplug_status); -// if (hotplug_status & dev_priv->hotplug_supported_mask) -// queue_work(dev_priv->wq, -// &dev_priv->hotplug_work); + if (hotplug_status & dev_priv->hotplug_supported_mask) + queue_work(dev_priv->wq, + &dev_priv->hotplug_work); I915_WRITE(PORT_HOTPLUG_STAT, hotplug_status); I915_READ(PORT_HOTPLUG_STAT); @@ -2395,6 +2481,9 @@ static irqreturn_t i965_irq_handler(int irq, void *arg) // if (blc_event || (iir & I915_ASLE_INTERRUPT)) // intel_opregion_asle_intr(dev); + if (pipe_stats[0] & PIPE_GMBUS_INTERRUPT_STATUS) + gmbus_irq_handler(dev); + /* With MSI, interrupts are only generated when iir * transitions from zero to nonzero. If another bit got * set while we were handling the existing iir bits, then @@ -2445,20 +2534,22 @@ void intel_irq_init(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; + INIT_WORK(&dev_priv->hotplug_work, i915_hotplug_work_func); + +// pm_qos_add_request(&dev_priv->pm_qos, PM_QOS_CPU_DMA_LATENCY, PM_QOS_DEFAULT_VALUE); + + + if (IS_VALLEYVIEW(dev)) { dev->driver->irq_handler = valleyview_irq_handler; dev->driver->irq_preinstall = valleyview_irq_preinstall; dev->driver->irq_postinstall = valleyview_irq_postinstall; - } else if (IS_IVYBRIDGE(dev)) { + dev_priv->display.hpd_irq_setup = valleyview_hpd_irq_setup; + } else if (IS_IVYBRIDGE(dev) || IS_HASWELL(dev)) { /* Share pre & uninstall handlers with ILK/SNB */ dev->driver->irq_handler = ivybridge_irq_handler; dev->driver->irq_preinstall = ironlake_irq_preinstall; dev->driver->irq_postinstall = ivybridge_irq_postinstall; - } else if (IS_HASWELL(dev)) { - /* Share interrupts handling with IVB */ - dev->driver->irq_handler = ivybridge_irq_handler; - dev->driver->irq_preinstall = ironlake_irq_preinstall; - dev->driver->irq_postinstall = ivybridge_irq_postinstall; } else if (HAS_PCH_SPLIT(dev)) { dev->driver->irq_handler = ironlake_irq_handler; dev->driver->irq_preinstall = ironlake_irq_preinstall; @@ -2469,16 +2560,25 @@ void intel_irq_init(struct drm_device *dev) dev->driver->irq_preinstall = i915_irq_preinstall; dev->driver->irq_postinstall = i915_irq_postinstall; dev->driver->irq_handler = i915_irq_handler; + dev_priv->display.hpd_irq_setup = i915_hpd_irq_setup; } else { dev->driver->irq_preinstall = i965_irq_preinstall; dev->driver->irq_postinstall = i965_irq_postinstall; dev->driver->irq_handler = i965_irq_handler; + dev_priv->display.hpd_irq_setup = i965_hpd_irq_setup; } } - -// printf("device %p driver %p handler %p\n", dev, dev->driver, dev->driver->irq_handler) ; } +void intel_hpd_init(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + + if (dev_priv->display.hpd_irq_setup) + dev_priv->display.hpd_irq_setup(dev); +} + + irqreturn_t intel_irq_handler(struct drm_device *dev) { diff --git a/drivers/video/drm/i915/i915_reg.h b/drivers/video/drm/i915/i915_reg.h index eb487a9ea5..cdecae3595 100644 --- a/drivers/video/drm/i915/i915_reg.h +++ b/drivers/video/drm/i915/i915_reg.h @@ -141,8 +141,15 @@ #define VGA_MSR_MEM_EN (1<<1) #define VGA_MSR_CGA_MODE (1<<0) -#define VGA_SR_INDEX 0x3c4 -#define VGA_SR_DATA 0x3c5 +/* + * SR01 is the only VGA register touched on non-UMS setups. + * VLV doesn't do UMS, so the sequencer index/data registers + * are the only VGA registers which need to include + * display_mmio_offset. + */ +#define VGA_SR_INDEX (dev_priv->info->display_mmio_offset + 0x3c4) +#define SR01 1 +#define VGA_SR_DATA (dev_priv->info->display_mmio_offset + 0x3c5) #define VGA_AR_INDEX 0x3c0 #define VGA_AR_VID_EN (1<<5) @@ -301,6 +308,7 @@ #define DISPLAY_PLANE_A (0<<20) #define DISPLAY_PLANE_B (1<<20) #define GFX_OP_PIPE_CONTROL(len) ((0x3<<29)|(0x3<<27)|(0x2<<24)|(len-2)) +#define PIPE_CONTROL_GLOBAL_GTT_IVB (1<<24) /* gen7+ */ #define PIPE_CONTROL_CS_STALL (1<<20) #define PIPE_CONTROL_TLB_INVALIDATE (1<<18) #define PIPE_CONTROL_QW_WRITE (1<<14) @@ -335,17 +343,19 @@ * 0x801c/3c: core clock bits * 0x8048/68: low pass filter coefficients * 0x8100: fast clock controls + * + * DPIO is VLV only. */ -#define DPIO_PKT 0x2100 +#define DPIO_PKT (VLV_DISPLAY_BASE + 0x2100) #define DPIO_RID (0<<24) #define DPIO_OP_WRITE (1<<16) #define DPIO_OP_READ (0<<16) #define DPIO_PORTID (0x12<<8) #define DPIO_BYTE (0xf<<4) #define DPIO_BUSY (1<<0) /* status only */ -#define DPIO_DATA 0x2104 -#define DPIO_REG 0x2108 -#define DPIO_CTL 0x2110 +#define DPIO_DATA (VLV_DISPLAY_BASE + 0x2104) +#define DPIO_REG (VLV_DISPLAY_BASE + 0x2108) +#define DPIO_CTL (VLV_DISPLAY_BASE + 0x2110) #define DPIO_MODSEL1 (1<<3) /* if ref clk b == 27 */ #define DPIO_MODSEL0 (1<<2) /* if ref clk a == 27 */ #define DPIO_SFR_BYPASS (1<<1) @@ -556,13 +566,13 @@ #define IIR 0x020a4 #define IMR 0x020a8 #define ISR 0x020ac -#define VLV_GUNIT_CLOCK_GATE 0x182060 +#define VLV_GUNIT_CLOCK_GATE (VLV_DISPLAY_BASE + 0x2060) #define GCFG_DIS (1<<8) -#define VLV_IIR_RW 0x182084 -#define VLV_IER 0x1820a0 -#define VLV_IIR 0x1820a4 -#define VLV_IMR 0x1820a8 -#define VLV_ISR 0x1820ac +#define VLV_IIR_RW (VLV_DISPLAY_BASE + 0x2084) +#define VLV_IER (VLV_DISPLAY_BASE + 0x20a0) +#define VLV_IIR (VLV_DISPLAY_BASE + 0x20a4) +#define VLV_IMR (VLV_DISPLAY_BASE + 0x20a8) +#define VLV_ISR (VLV_DISPLAY_BASE + 0x20ac) #define I915_PIPE_CONTROL_NOTIFY_INTERRUPT (1<<18) #define I915_DISPLAY_PORT_INTERRUPT (1<<17) #define I915_RENDER_COMMAND_PARSER_ERROR_INTERRUPT (1<<15) @@ -735,6 +745,7 @@ #define GEN7_FF_TS_SCHED_HS0 (0x3<<16) #define GEN7_FF_TS_SCHED_LOAD_BALANCE (0x1<<16) #define GEN7_FF_TS_SCHED_HW (0x0<<16) /* Default */ +#define GEN7_FF_VS_REF_CNT_FFME (1 << 15) #define GEN7_FF_VS_SCHED_HS1 (0x5<<12) #define GEN7_FF_VS_SCHED_HS0 (0x3<<12) #define GEN7_FF_VS_SCHED_LOAD_BALANCE (0x1<<12) /* Default */ @@ -921,8 +932,8 @@ #define VGA1_PD_P1_DIV_2 (1 << 13) #define VGA1_PD_P1_SHIFT 8 #define VGA1_PD_P1_MASK (0x1f << 8) -#define _DPLL_A 0x06014 -#define _DPLL_B 0x06018 +#define _DPLL_A (dev_priv->info->display_mmio_offset + 0x6014) +#define _DPLL_B (dev_priv->info->display_mmio_offset + 0x6018) #define DPLL(pipe) _PIPE(pipe, _DPLL_A, _DPLL_B) #define DPLL_VCO_ENABLE (1 << 31) #define DPLL_DVO_HIGH_SPEED (1 << 30) @@ -943,23 +954,6 @@ #define DPLL_LOCK_VLV (1<<15) #define DPLL_INTEGRATED_CLOCK_VLV (1<<13) -#define SRX_INDEX 0x3c4 -#define SRX_DATA 0x3c5 -#define SR01 1 -#define SR01_SCREEN_OFF (1<<5) - -#define PPCR 0x61204 -#define PPCR_ON (1<<0) - -#define DVOB 0x61140 -#define DVOB_ON (1<<31) -#define DVOC 0x61160 -#define DVOC_ON (1<<31) -#define LVDS 0x61180 -#define LVDS_ON (1<<31) - -/* Scratch pad debug 0 reg: - */ #define DPLL_FPA01_P1_POST_DIV_MASK_I830 0x001f0000 /* * The i830 generation, in LVDS mode, defines P1 as the bit number set within @@ -998,7 +992,7 @@ #define SDVO_MULTIPLIER_MASK 0x000000ff #define SDVO_MULTIPLIER_SHIFT_HIRES 4 #define SDVO_MULTIPLIER_SHIFT_VGA 0 -#define _DPLL_A_MD 0x0601c /* 965+ only */ +#define _DPLL_A_MD (dev_priv->info->display_mmio_offset + 0x601c) /* 965+ only */ /* * UDI pixel divider, controlling how many pixels are stuffed into a packet. * @@ -1035,7 +1029,7 @@ */ #define DPLL_MD_VGA_UDI_MULTIPLIER_MASK 0x0000003f #define DPLL_MD_VGA_UDI_MULTIPLIER_SHIFT 0 -#define _DPLL_B_MD 0x06020 /* 965+ only */ +#define _DPLL_B_MD (dev_priv->info->display_mmio_offset + 0x6020) /* 965+ only */ #define DPLL_MD(pipe) _PIPE(pipe, _DPLL_A_MD, _DPLL_B_MD) #define _FPA0 0x06040 @@ -1178,15 +1172,15 @@ #define RAMCLK_GATE_D 0x6210 /* CRL only */ #define DEUC 0x6214 /* CRL only */ -#define FW_BLC_SELF_VLV 0x6500 +#define FW_BLC_SELF_VLV (VLV_DISPLAY_BASE + 0x6500) #define FW_CSPWRDWNEN (1<<15) /* * Palette regs */ -#define _PALETTE_A 0x0a000 -#define _PALETTE_B 0x0a800 +#define _PALETTE_A (dev_priv->info->display_mmio_offset + 0xa000) +#define _PALETTE_B (dev_priv->info->display_mmio_offset + 0xa800) #define PALETTE(pipe) _PIPE(pipe, _PALETTE_A, _PALETTE_B) /* MCH MMIO space */ @@ -1242,6 +1236,10 @@ #define MAD_DIMM_A_SIZE_SHIFT 0 #define MAD_DIMM_A_SIZE_MASK (0xff << MAD_DIMM_A_SIZE_SHIFT) +/** snb MCH registers for priority tuning */ +#define MCH_SSKPD (MCHBAR_MIRROR_BASE_SNB + 0x5d10) +#define MCH_SSKPD_WM0_MASK 0x3f +#define MCH_SSKPD_WM0_VAL 0xc /* Clocking configuration register */ #define CLKCFG 0x10c00 @@ -1551,26 +1549,26 @@ */ /* Pipe A timing regs */ -#define _HTOTAL_A 0x60000 -#define _HBLANK_A 0x60004 -#define _HSYNC_A 0x60008 -#define _VTOTAL_A 0x6000c -#define _VBLANK_A 0x60010 -#define _VSYNC_A 0x60014 -#define _PIPEASRC 0x6001c -#define _BCLRPAT_A 0x60020 -#define _VSYNCSHIFT_A 0x60028 +#define _HTOTAL_A (dev_priv->info->display_mmio_offset + 0x60000) +#define _HBLANK_A (dev_priv->info->display_mmio_offset + 0x60004) +#define _HSYNC_A (dev_priv->info->display_mmio_offset + 0x60008) +#define _VTOTAL_A (dev_priv->info->display_mmio_offset + 0x6000c) +#define _VBLANK_A (dev_priv->info->display_mmio_offset + 0x60010) +#define _VSYNC_A (dev_priv->info->display_mmio_offset + 0x60014) +#define _PIPEASRC (dev_priv->info->display_mmio_offset + 0x6001c) +#define _BCLRPAT_A (dev_priv->info->display_mmio_offset + 0x60020) +#define _VSYNCSHIFT_A (dev_priv->info->display_mmio_offset + 0x60028) /* Pipe B timing regs */ -#define _HTOTAL_B 0x61000 -#define _HBLANK_B 0x61004 -#define _HSYNC_B 0x61008 -#define _VTOTAL_B 0x6100c -#define _VBLANK_B 0x61010 -#define _VSYNC_B 0x61014 -#define _PIPEBSRC 0x6101c -#define _BCLRPAT_B 0x61020 -#define _VSYNCSHIFT_B 0x61028 +#define _HTOTAL_B (dev_priv->info->display_mmio_offset + 0x61000) +#define _HBLANK_B (dev_priv->info->display_mmio_offset + 0x61004) +#define _HSYNC_B (dev_priv->info->display_mmio_offset + 0x61008) +#define _VTOTAL_B (dev_priv->info->display_mmio_offset + 0x6100c) +#define _VBLANK_B (dev_priv->info->display_mmio_offset + 0x61010) +#define _VSYNC_B (dev_priv->info->display_mmio_offset + 0x61014) +#define _PIPEBSRC (dev_priv->info->display_mmio_offset + 0x6101c) +#define _BCLRPAT_B (dev_priv->info->display_mmio_offset + 0x61020) +#define _VSYNCSHIFT_B (dev_priv->info->display_mmio_offset + 0x61028) #define HTOTAL(trans) _TRANSCODER(trans, _HTOTAL_A, _HTOTAL_B) @@ -1615,9 +1613,9 @@ #define ADPA_CRT_HOTPLUG_FORCE_TRIGGER (1<<16) #define ADPA_USE_VGA_HVPOLARITY (1<<15) #define ADPA_SETS_HVPOLARITY 0 -#define ADPA_VSYNC_CNTL_DISABLE (1<<11) +#define ADPA_VSYNC_CNTL_DISABLE (1<<10) #define ADPA_VSYNC_CNTL_ENABLE 0 -#define ADPA_HSYNC_CNTL_DISABLE (1<<10) +#define ADPA_HSYNC_CNTL_DISABLE (1<<11) #define ADPA_HSYNC_CNTL_ENABLE 0 #define ADPA_VSYNC_ACTIVE_HIGH (1<<4) #define ADPA_VSYNC_ACTIVE_LOW 0 @@ -1631,13 +1629,10 @@ /* Hotplug control (945+ only) */ -#define PORT_HOTPLUG_EN 0x61110 -#define HDMIB_HOTPLUG_INT_EN (1 << 29) -#define DPB_HOTPLUG_INT_EN (1 << 29) -#define HDMIC_HOTPLUG_INT_EN (1 << 28) -#define DPC_HOTPLUG_INT_EN (1 << 28) -#define HDMID_HOTPLUG_INT_EN (1 << 27) -#define DPD_HOTPLUG_INT_EN (1 << 27) +#define PORT_HOTPLUG_EN (dev_priv->info->display_mmio_offset + 0x61110) +#define PORTB_HOTPLUG_INT_EN (1 << 29) +#define PORTC_HOTPLUG_INT_EN (1 << 28) +#define PORTD_HOTPLUG_INT_EN (1 << 27) #define SDVOB_HOTPLUG_INT_EN (1 << 26) #define SDVOC_HOTPLUG_INT_EN (1 << 25) #define TV_HOTPLUG_INT_EN (1 << 18) @@ -1658,21 +1653,14 @@ #define CRT_HOTPLUG_DETECT_VOLTAGE_325MV (0 << 2) #define CRT_HOTPLUG_DETECT_VOLTAGE_475MV (1 << 2) -#define PORT_HOTPLUG_STAT 0x61114 +#define PORT_HOTPLUG_STAT (dev_priv->info->display_mmio_offset + 0x61114) /* HDMI/DP bits are gen4+ */ -#define DPB_HOTPLUG_LIVE_STATUS (1 << 29) -#define DPC_HOTPLUG_LIVE_STATUS (1 << 28) -#define DPD_HOTPLUG_LIVE_STATUS (1 << 27) -#define DPD_HOTPLUG_INT_STATUS (3 << 21) -#define DPC_HOTPLUG_INT_STATUS (3 << 19) -#define DPB_HOTPLUG_INT_STATUS (3 << 17) -/* HDMI bits are shared with the DP bits */ -#define HDMIB_HOTPLUG_LIVE_STATUS (1 << 29) -#define HDMIC_HOTPLUG_LIVE_STATUS (1 << 28) -#define HDMID_HOTPLUG_LIVE_STATUS (1 << 27) -#define HDMID_HOTPLUG_INT_STATUS (3 << 21) -#define HDMIC_HOTPLUG_INT_STATUS (3 << 19) -#define HDMIB_HOTPLUG_INT_STATUS (3 << 17) +#define PORTB_HOTPLUG_LIVE_STATUS (1 << 29) +#define PORTC_HOTPLUG_LIVE_STATUS (1 << 28) +#define PORTD_HOTPLUG_LIVE_STATUS (1 << 27) +#define PORTD_HOTPLUG_INT_STATUS (3 << 21) +#define PORTC_HOTPLUG_INT_STATUS (3 << 19) +#define PORTB_HOTPLUG_INT_STATUS (3 << 17) /* CRT/TV common between gen3+ */ #define CRT_HOTPLUG_INT_STATUS (1 << 11) #define TV_HOTPLUG_INT_STATUS (1 << 10) @@ -1877,7 +1865,7 @@ #define PP_DIVISOR 0x61210 /* Panel fitting */ -#define PFIT_CONTROL 0x61230 +#define PFIT_CONTROL (dev_priv->info->display_mmio_offset + 0x61230) #define PFIT_ENABLE (1 << 31) #define PFIT_PIPE_MASK (3 << 29) #define PFIT_PIPE_SHIFT 29 @@ -1895,9 +1883,7 @@ #define PFIT_SCALING_PROGRAMMED (1 << 26) #define PFIT_SCALING_PILLAR (2 << 26) #define PFIT_SCALING_LETTER (3 << 26) -#define PFIT_PGM_RATIOS 0x61234 -#define PFIT_VERT_SCALE_MASK 0xfff00000 -#define PFIT_HORIZ_SCALE_MASK 0x0000fff0 +#define PFIT_PGM_RATIOS (dev_priv->info->display_mmio_offset + 0x61234) /* Pre-965 */ #define PFIT_VERT_SCALE_SHIFT 20 #define PFIT_VERT_SCALE_MASK 0xfff00000 @@ -1909,7 +1895,7 @@ #define PFIT_HORIZ_SCALE_SHIFT_965 0 #define PFIT_HORIZ_SCALE_MASK_965 0x00001fff -#define PFIT_AUTO_RATIOS 0x61238 +#define PFIT_AUTO_RATIOS (dev_priv->info->display_mmio_offset + 0x61238) /* Backlight control */ #define BLC_PWM_CTL2 0x61250 /* 965+ only */ @@ -2639,10 +2625,10 @@ /* Display & cursor control */ /* Pipe A */ -#define _PIPEADSL 0x70000 +#define _PIPEADSL (dev_priv->info->display_mmio_offset + 0x70000) #define DSL_LINEMASK_GEN2 0x00000fff #define DSL_LINEMASK_GEN3 0x00001fff -#define _PIPEACONF 0x70008 +#define _PIPEACONF (dev_priv->info->display_mmio_offset + 0x70008) #define PIPECONF_ENABLE (1<<31) #define PIPECONF_DISABLE 0 #define PIPECONF_DOUBLE_WIDE (1<<30) @@ -2671,18 +2657,19 @@ #define PIPECONF_INTERLACED_DBL_ILK (4 << 21) /* ilk/snb only */ #define PIPECONF_PFIT_PF_INTERLACED_DBL_ILK (5 << 21) /* ilk/snb only */ #define PIPECONF_CXSR_DOWNCLOCK (1<<16) -#define PIPECONF_BPP_MASK (0x000000e0) -#define PIPECONF_BPP_8 (0<<5) -#define PIPECONF_BPP_10 (1<<5) -#define PIPECONF_BPP_6 (2<<5) -#define PIPECONF_BPP_12 (3<<5) +#define PIPECONF_COLOR_RANGE_SELECT (1 << 13) +#define PIPECONF_BPC_MASK (0x7 << 5) +#define PIPECONF_8BPC (0<<5) +#define PIPECONF_10BPC (1<<5) +#define PIPECONF_6BPC (2<<5) +#define PIPECONF_12BPC (3<<5) #define PIPECONF_DITHER_EN (1<<4) #define PIPECONF_DITHER_TYPE_MASK (0x0000000c) #define PIPECONF_DITHER_TYPE_SP (0<<2) #define PIPECONF_DITHER_TYPE_ST1 (1<<2) #define PIPECONF_DITHER_TYPE_ST2 (2<<2) #define PIPECONF_DITHER_TYPE_TEMP (3<<2) -#define _PIPEASTAT 0x70024 +#define _PIPEASTAT (dev_priv->info->display_mmio_offset + 0x70024) #define PIPE_FIFO_UNDERRUN_STATUS (1UL<<31) #define SPRITE1_FLIPDONE_INT_EN_VLV (1UL<<30) #define PIPE_CRC_ERROR_ENABLE (1UL<<29) @@ -2693,7 +2680,7 @@ #define PIPE_VSYNC_INTERRUPT_ENABLE (1UL<<25) #define PIPE_DISPLAY_LINE_COMPARE_ENABLE (1UL<<24) #define PIPE_DPST_EVENT_ENABLE (1UL<<23) -#define SPRITE0_FLIP_DONE_INT_EN_VLV (1UL<<26) +#define SPRITE0_FLIP_DONE_INT_EN_VLV (1UL<<22) #define PIPE_LEGACY_BLC_EVENT_ENABLE (1UL<<22) #define PIPE_ODD_FIELD_INTERRUPT_ENABLE (1UL<<21) #define PIPE_EVEN_FIELD_INTERRUPT_ENABLE (1UL<<20) @@ -2703,7 +2690,7 @@ #define PIPEA_HBLANK_INT_EN_VLV (1UL<<16) #define PIPE_OVERLAY_UPDATED_ENABLE (1UL<<16) #define SPRITE1_FLIPDONE_INT_STATUS_VLV (1UL<<15) -#define SPRITE0_FLIPDONE_INT_STATUS_VLV (1UL<<15) +#define SPRITE0_FLIPDONE_INT_STATUS_VLV (1UL<<14) #define PIPE_CRC_ERROR_INTERRUPT_STATUS (1UL<<13) #define PIPE_CRC_DONE_INTERRUPT_STATUS (1UL<<12) #define PIPE_GMBUS_INTERRUPT_STATUS (1UL<<11) @@ -2719,11 +2706,6 @@ #define PIPE_START_VBLANK_INTERRUPT_STATUS (1UL<<2) /* 965 or later */ #define PIPE_VBLANK_INTERRUPT_STATUS (1UL<<1) #define PIPE_OVERLAY_UPDATED_STATUS (1UL<<0) -#define PIPE_BPC_MASK (7 << 5) /* Ironlake */ -#define PIPE_8BPC (0 << 5) -#define PIPE_10BPC (1 << 5) -#define PIPE_6BPC (2 << 5) -#define PIPE_12BPC (3 << 5) #define PIPESRC(pipe) _PIPE(pipe, _PIPEASRC, _PIPEBSRC) #define PIPECONF(tran) _TRANSCODER(tran, _PIPEACONF, _PIPEBCONF) @@ -2732,7 +2714,7 @@ #define PIPEFRAMEPIXEL(pipe) _PIPE(pipe, _PIPEAFRAMEPIXEL, _PIPEBFRAMEPIXEL) #define PIPESTAT(pipe) _PIPE(pipe, _PIPEASTAT, _PIPEBSTAT) -#define VLV_DPFLIPSTAT 0x70028 +#define VLV_DPFLIPSTAT (VLV_DISPLAY_BASE + 0x70028) #define PIPEB_LINE_COMPARE_INT_EN (1<<29) #define PIPEB_HLINE_INT_EN (1<<28) #define PIPEB_VBLANK_INT_EN (1<<27) @@ -2746,7 +2728,7 @@ #define SPRITEA_FLIPDONE_INT_EN (1<<17) #define PLANEA_FLIPDONE_INT_EN (1<<16) -#define DPINVGTT 0x7002c /* VLV only */ +#define DPINVGTT (VLV_DISPLAY_BASE + 0x7002c) /* VLV only */ #define CURSORB_INVALID_GTT_INT_EN (1<<23) #define CURSORA_INVALID_GTT_INT_EN (1<<22) #define SPRITED_INVALID_GTT_INT_EN (1<<21) @@ -2774,7 +2756,7 @@ #define DSPARB_BEND_SHIFT 9 /* on 855 */ #define DSPARB_AEND_SHIFT 0 -#define DSPFW1 0x70034 +#define DSPFW1 (dev_priv->info->display_mmio_offset + 0x70034) #define DSPFW_SR_SHIFT 23 #define DSPFW_SR_MASK (0x1ff<<23) #define DSPFW_CURSORB_SHIFT 16 @@ -2782,11 +2764,11 @@ #define DSPFW_PLANEB_SHIFT 8 #define DSPFW_PLANEB_MASK (0x7f<<8) #define DSPFW_PLANEA_MASK (0x7f) -#define DSPFW2 0x70038 +#define DSPFW2 (dev_priv->info->display_mmio_offset + 0x70038) #define DSPFW_CURSORA_MASK 0x00003f00 #define DSPFW_CURSORA_SHIFT 8 #define DSPFW_PLANEC_MASK (0x7f) -#define DSPFW3 0x7003c +#define DSPFW3 (dev_priv->info->display_mmio_offset + 0x7003c) #define DSPFW_HPLL_SR_EN (1<<31) #define DSPFW_CURSOR_SR_SHIFT 24 #define PINEVIEW_SELF_REFRESH_EN (1<<30) @@ -2798,13 +2780,13 @@ /* drain latency register values*/ #define DRAIN_LATENCY_PRECISION_32 32 #define DRAIN_LATENCY_PRECISION_16 16 -#define VLV_DDL1 0x70050 +#define VLV_DDL1 (VLV_DISPLAY_BASE + 0x70050) #define DDL_CURSORA_PRECISION_32 (1<<31) #define DDL_CURSORA_PRECISION_16 (0<<31) #define DDL_CURSORA_SHIFT 24 #define DDL_PLANEA_PRECISION_32 (1<<7) #define DDL_PLANEA_PRECISION_16 (0<<7) -#define VLV_DDL2 0x70054 +#define VLV_DDL2 (VLV_DISPLAY_BASE + 0x70054) #define DDL_CURSORB_PRECISION_32 (1<<31) #define DDL_CURSORB_PRECISION_16 (0<<31) #define DDL_CURSORB_SHIFT 24 @@ -2948,10 +2930,10 @@ * } while (high1 != high2); * frame = (high1 << 8) | low1; */ -#define _PIPEAFRAMEHIGH 0x70040 +#define _PIPEAFRAMEHIGH (dev_priv->info->display_mmio_offset + 0x70040) #define PIPE_FRAME_HIGH_MASK 0x0000ffff #define PIPE_FRAME_HIGH_SHIFT 0 -#define _PIPEAFRAMEPIXEL 0x70044 +#define _PIPEAFRAMEPIXEL (dev_priv->info->display_mmio_offset + 0x70044) #define PIPE_FRAME_LOW_MASK 0xff000000 #define PIPE_FRAME_LOW_SHIFT 24 #define PIPE_PIXEL_MASK 0x00ffffff @@ -2962,11 +2944,12 @@ #define PIPE_FRMCOUNT_GM45(pipe) _PIPE(pipe, _PIPEA_FRMCOUNT_GM45, _PIPEB_FRMCOUNT_GM45) /* Cursor A & B regs */ -#define _CURACNTR 0x70080 +#define _CURACNTR (dev_priv->info->display_mmio_offset + 0x70080) /* Old style CUR*CNTR flags (desktop 8xx) */ #define CURSOR_ENABLE 0x80000000 #define CURSOR_GAMMA_ENABLE 0x40000000 #define CURSOR_STRIDE_MASK 0x30000000 +#define CURSOR_PIPE_CSC_ENABLE (1<<24) #define CURSOR_FORMAT_SHIFT 24 #define CURSOR_FORMAT_MASK (0x07 << CURSOR_FORMAT_SHIFT) #define CURSOR_FORMAT_2C (0x00 << CURSOR_FORMAT_SHIFT) @@ -2983,16 +2966,16 @@ #define MCURSOR_PIPE_A 0x00 #define MCURSOR_PIPE_B (1 << 28) #define MCURSOR_GAMMA_ENABLE (1 << 26) -#define _CURABASE 0x70084 -#define _CURAPOS 0x70088 +#define _CURABASE (dev_priv->info->display_mmio_offset + 0x70084) +#define _CURAPOS (dev_priv->info->display_mmio_offset + 0x70088) #define CURSOR_POS_MASK 0x007FF #define CURSOR_POS_SIGN 0x8000 #define CURSOR_X_SHIFT 0 #define CURSOR_Y_SHIFT 16 #define CURSIZE 0x700a0 -#define _CURBCNTR 0x700c0 -#define _CURBBASE 0x700c4 -#define _CURBPOS 0x700c8 +#define _CURBCNTR (dev_priv->info->display_mmio_offset + 0x700c0) +#define _CURBBASE (dev_priv->info->display_mmio_offset + 0x700c4) +#define _CURBPOS (dev_priv->info->display_mmio_offset + 0x700c8) #define _CURBCNTR_IVB 0x71080 #define _CURBBASE_IVB 0x71084 @@ -3007,7 +2990,7 @@ #define CURPOS_IVB(pipe) _PIPE(pipe, _CURAPOS, _CURBPOS_IVB) /* Display A control */ -#define _DSPACNTR 0x70180 +#define _DSPACNTR (dev_priv->info->display_mmio_offset + 0x70180) #define DISPLAY_PLANE_ENABLE (1<<31) #define DISPLAY_PLANE_DISABLE 0 #define DISPPLANE_GAMMA_ENABLE (1<<30) @@ -3028,6 +3011,7 @@ #define DISPPLANE_RGBA888 (0xf<<26) #define DISPPLANE_STEREO_ENABLE (1<<25) #define DISPPLANE_STEREO_DISABLE 0 +#define DISPPLANE_PIPE_CSC_ENABLE (1<<24) #define DISPPLANE_SEL_PIPE_SHIFT 24 #define DISPPLANE_SEL_PIPE_MASK (3<info->display_mmio_offset + 0x70184) +#define _DSPASTRIDE (dev_priv->info->display_mmio_offset + 0x70188) +#define _DSPAPOS (dev_priv->info->display_mmio_offset + 0x7018C) /* reserved */ +#define _DSPASIZE (dev_priv->info->display_mmio_offset + 0x70190) +#define _DSPASURF (dev_priv->info->display_mmio_offset + 0x7019C) /* 965+ only */ +#define _DSPATILEOFF (dev_priv->info->display_mmio_offset + 0x701A4) /* 965+ only */ +#define _DSPAOFFSET (dev_priv->info->display_mmio_offset + 0x701A4) /* HSW */ +#define _DSPASURFLIVE (dev_priv->info->display_mmio_offset + 0x701AC) #define DSPCNTR(plane) _PIPE(plane, _DSPACNTR, _DSPBCNTR) #define DSPADDR(plane) _PIPE(plane, _DSPAADDR, _DSPBADDR) @@ -3068,44 +3052,44 @@ (I915_WRITE((reg), (gfx_addr) | I915_LO_DISPBASE(I915_READ(reg)))) /* VBIOS flags */ -#define SWF00 0x71410 -#define SWF01 0x71414 -#define SWF02 0x71418 -#define SWF03 0x7141c -#define SWF04 0x71420 -#define SWF05 0x71424 -#define SWF06 0x71428 -#define SWF10 0x70410 -#define SWF11 0x70414 -#define SWF14 0x71420 -#define SWF30 0x72414 -#define SWF31 0x72418 -#define SWF32 0x7241c +#define SWF00 (dev_priv->info->display_mmio_offset + 0x71410) +#define SWF01 (dev_priv->info->display_mmio_offset + 0x71414) +#define SWF02 (dev_priv->info->display_mmio_offset + 0x71418) +#define SWF03 (dev_priv->info->display_mmio_offset + 0x7141c) +#define SWF04 (dev_priv->info->display_mmio_offset + 0x71420) +#define SWF05 (dev_priv->info->display_mmio_offset + 0x71424) +#define SWF06 (dev_priv->info->display_mmio_offset + 0x71428) +#define SWF10 (dev_priv->info->display_mmio_offset + 0x70410) +#define SWF11 (dev_priv->info->display_mmio_offset + 0x70414) +#define SWF14 (dev_priv->info->display_mmio_offset + 0x71420) +#define SWF30 (dev_priv->info->display_mmio_offset + 0x72414) +#define SWF31 (dev_priv->info->display_mmio_offset + 0x72418) +#define SWF32 (dev_priv->info->display_mmio_offset + 0x7241c) /* Pipe B */ -#define _PIPEBDSL 0x71000 -#define _PIPEBCONF 0x71008 -#define _PIPEBSTAT 0x71024 -#define _PIPEBFRAMEHIGH 0x71040 -#define _PIPEBFRAMEPIXEL 0x71044 +#define _PIPEBDSL (dev_priv->info->display_mmio_offset + 0x71000) +#define _PIPEBCONF (dev_priv->info->display_mmio_offset + 0x71008) +#define _PIPEBSTAT (dev_priv->info->display_mmio_offset + 0x71024) +#define _PIPEBFRAMEHIGH (dev_priv->info->display_mmio_offset + 0x71040) +#define _PIPEBFRAMEPIXEL (dev_priv->info->display_mmio_offset + 0x71044) #define _PIPEB_FRMCOUNT_GM45 0x71040 #define _PIPEB_FLIPCOUNT_GM45 0x71044 /* Display B control */ -#define _DSPBCNTR 0x71180 +#define _DSPBCNTR (dev_priv->info->display_mmio_offset + 0x71180) #define DISPPLANE_ALPHA_TRANS_ENABLE (1<<15) #define DISPPLANE_ALPHA_TRANS_DISABLE 0 #define DISPPLANE_SPRITE_ABOVE_DISPLAY 0 #define DISPPLANE_SPRITE_ABOVE_OVERLAY (1) -#define _DSPBADDR 0x71184 -#define _DSPBSTRIDE 0x71188 -#define _DSPBPOS 0x7118C -#define _DSPBSIZE 0x71190 -#define _DSPBSURF 0x7119C -#define _DSPBTILEOFF 0x711A4 -#define _DSPBOFFSET 0x711A4 -#define _DSPBSURFLIVE 0x711AC +#define _DSPBADDR (dev_priv->info->display_mmio_offset + 0x71184) +#define _DSPBSTRIDE (dev_priv->info->display_mmio_offset + 0x71188) +#define _DSPBPOS (dev_priv->info->display_mmio_offset + 0x7118C) +#define _DSPBSIZE (dev_priv->info->display_mmio_offset + 0x71190) +#define _DSPBSURF (dev_priv->info->display_mmio_offset + 0x7119C) +#define _DSPBTILEOFF (dev_priv->info->display_mmio_offset + 0x711A4) +#define _DSPBOFFSET (dev_priv->info->display_mmio_offset + 0x711A4) +#define _DSPBSURFLIVE (dev_priv->info->display_mmio_offset + 0x711AC) /* Sprite A control */ #define _DVSACNTR 0x72180 @@ -3116,6 +3100,7 @@ #define DVS_FORMAT_RGBX101010 (1<<25) #define DVS_FORMAT_RGBX888 (2<<25) #define DVS_FORMAT_RGBX161616 (3<<25) +#define DVS_PIPE_CSC_ENABLE (1<<24) #define DVS_SOURCE_KEY (1<<22) #define DVS_RGB_ORDER_XBGR (1<<20) #define DVS_YUV_BYTE_ORDER_MASK (3<<16) @@ -3183,7 +3168,7 @@ #define SPRITE_FORMAT_RGBX161616 (3<<25) #define SPRITE_FORMAT_YUV444 (4<<25) #define SPRITE_FORMAT_XR_BGR101010 (5<<25) /* Extended range */ -#define SPRITE_CSC_ENABLE (1<<24) +#define SPRITE_PIPE_CSC_ENABLE (1<<24) #define SPRITE_SOURCE_KEY (1<<22) #define SPRITE_RGB_ORDER_RGBX (1<<20) /* only for 888 and 161616 */ #define SPRITE_YUV_TO_RGB_CSC_DISABLE (1<<19) @@ -3254,6 +3239,8 @@ # define VGA_2X_MODE (1 << 30) # define VGA_PIPE_B_SELECT (1 << 29) +#define VLV_VGACNTRL (VLV_DISPLAY_BASE + 0x71400) + /* Ironlake */ #define CPU_VGACNTRL 0x41000 @@ -3294,41 +3281,41 @@ #define FDI_PLL_FREQ_DISABLE_COUNT_LIMIT_MASK 0xff -#define _PIPEA_DATA_M1 0x60030 +#define _PIPEA_DATA_M1 (dev_priv->info->display_mmio_offset + 0x60030) #define TU_SIZE(x) (((x)-1) << 25) /* default size 64 */ #define TU_SIZE_MASK 0x7e000000 #define PIPE_DATA_M1_OFFSET 0 -#define _PIPEA_DATA_N1 0x60034 +#define _PIPEA_DATA_N1 (dev_priv->info->display_mmio_offset + 0x60034) #define PIPE_DATA_N1_OFFSET 0 -#define _PIPEA_DATA_M2 0x60038 +#define _PIPEA_DATA_M2 (dev_priv->info->display_mmio_offset + 0x60038) #define PIPE_DATA_M2_OFFSET 0 -#define _PIPEA_DATA_N2 0x6003c +#define _PIPEA_DATA_N2 (dev_priv->info->display_mmio_offset + 0x6003c) #define PIPE_DATA_N2_OFFSET 0 -#define _PIPEA_LINK_M1 0x60040 +#define _PIPEA_LINK_M1 (dev_priv->info->display_mmio_offset + 0x60040) #define PIPE_LINK_M1_OFFSET 0 -#define _PIPEA_LINK_N1 0x60044 +#define _PIPEA_LINK_N1 (dev_priv->info->display_mmio_offset + 0x60044) #define PIPE_LINK_N1_OFFSET 0 -#define _PIPEA_LINK_M2 0x60048 +#define _PIPEA_LINK_M2 (dev_priv->info->display_mmio_offset + 0x60048) #define PIPE_LINK_M2_OFFSET 0 -#define _PIPEA_LINK_N2 0x6004c +#define _PIPEA_LINK_N2 (dev_priv->info->display_mmio_offset + 0x6004c) #define PIPE_LINK_N2_OFFSET 0 /* PIPEB timing regs are same start from 0x61000 */ -#define _PIPEB_DATA_M1 0x61030 -#define _PIPEB_DATA_N1 0x61034 +#define _PIPEB_DATA_M1 (dev_priv->info->display_mmio_offset + 0x61030) +#define _PIPEB_DATA_N1 (dev_priv->info->display_mmio_offset + 0x61034) -#define _PIPEB_DATA_M2 0x61038 -#define _PIPEB_DATA_N2 0x6103c +#define _PIPEB_DATA_M2 (dev_priv->info->display_mmio_offset + 0x61038) +#define _PIPEB_DATA_N2 (dev_priv->info->display_mmio_offset + 0x6103c) -#define _PIPEB_LINK_M1 0x61040 -#define _PIPEB_LINK_N1 0x61044 +#define _PIPEB_LINK_M1 (dev_priv->info->display_mmio_offset + 0x61040) +#define _PIPEB_LINK_N1 (dev_priv->info->display_mmio_offset + 0x61044) -#define _PIPEB_LINK_M2 0x61048 -#define _PIPEB_LINK_N2 0x6104c +#define _PIPEB_LINK_M2 (dev_priv->info->display_mmio_offset + 0x61048) +#define _PIPEB_LINK_N2 (dev_priv->info->display_mmio_offset + 0x6104c) #define PIPE_DATA_M1(tran) _TRANSCODER(tran, _PIPEA_DATA_M1, _PIPEB_DATA_M1) #define PIPE_DATA_N1(tran) _TRANSCODER(tran, _PIPEA_DATA_N1, _PIPEB_DATA_N1) @@ -3581,27 +3568,30 @@ #define PORTD_PULSE_DURATION_6ms (2 << 18) #define PORTD_PULSE_DURATION_100ms (3 << 18) #define PORTD_PULSE_DURATION_MASK (3 << 18) -#define PORTD_HOTPLUG_NO_DETECT (0) +#define PORTD_HOTPLUG_STATUS_MASK (0x3 << 16) +#define PORTD_HOTPLUG_NO_DETECT (0 << 16) #define PORTD_HOTPLUG_SHORT_DETECT (1 << 16) -#define PORTD_HOTPLUG_LONG_DETECT (1 << 17) +#define PORTD_HOTPLUG_LONG_DETECT (2 << 16) #define PORTC_HOTPLUG_ENABLE (1 << 12) #define PORTC_PULSE_DURATION_2ms (0) #define PORTC_PULSE_DURATION_4_5ms (1 << 10) #define PORTC_PULSE_DURATION_6ms (2 << 10) #define PORTC_PULSE_DURATION_100ms (3 << 10) #define PORTC_PULSE_DURATION_MASK (3 << 10) -#define PORTC_HOTPLUG_NO_DETECT (0) +#define PORTC_HOTPLUG_STATUS_MASK (0x3 << 8) +#define PORTC_HOTPLUG_NO_DETECT (0 << 8) #define PORTC_HOTPLUG_SHORT_DETECT (1 << 8) -#define PORTC_HOTPLUG_LONG_DETECT (1 << 9) +#define PORTC_HOTPLUG_LONG_DETECT (2 << 8) #define PORTB_HOTPLUG_ENABLE (1 << 4) #define PORTB_PULSE_DURATION_2ms (0) #define PORTB_PULSE_DURATION_4_5ms (1 << 2) #define PORTB_PULSE_DURATION_6ms (2 << 2) #define PORTB_PULSE_DURATION_100ms (3 << 2) #define PORTB_PULSE_DURATION_MASK (3 << 2) -#define PORTB_HOTPLUG_NO_DETECT (0) +#define PORTB_HOTPLUG_STATUS_MASK (0x3 << 0) +#define PORTB_HOTPLUG_NO_DETECT (0 << 0) #define PORTB_HOTPLUG_SHORT_DETECT (1 << 0) -#define PORTB_HOTPLUG_LONG_DETECT (1 << 1) +#define PORTB_HOTPLUG_LONG_DETECT (2 << 0) #define PCH_GPIOA 0xc5010 #define PCH_GPIOB 0xc5014 @@ -3722,13 +3712,13 @@ #define TVIDEO_DIP_DATA(pipe) _PIPE(pipe, _VIDEO_DIP_DATA_A, _VIDEO_DIP_DATA_B) #define TVIDEO_DIP_GCP(pipe) _PIPE(pipe, _VIDEO_DIP_GCP_A, _VIDEO_DIP_GCP_B) -#define VLV_VIDEO_DIP_CTL_A 0x60200 -#define VLV_VIDEO_DIP_DATA_A 0x60208 -#define VLV_VIDEO_DIP_GDCP_PAYLOAD_A 0x60210 +#define VLV_VIDEO_DIP_CTL_A (VLV_DISPLAY_BASE + 0x60200) +#define VLV_VIDEO_DIP_DATA_A (VLV_DISPLAY_BASE + 0x60208) +#define VLV_VIDEO_DIP_GDCP_PAYLOAD_A (VLV_DISPLAY_BASE + 0x60210) -#define VLV_VIDEO_DIP_CTL_B 0x61170 -#define VLV_VIDEO_DIP_DATA_B 0x61174 -#define VLV_VIDEO_DIP_GDCP_PAYLOAD_B 0x61178 +#define VLV_VIDEO_DIP_CTL_B (VLV_DISPLAY_BASE + 0x61170) +#define VLV_VIDEO_DIP_DATA_B (VLV_DISPLAY_BASE + 0x61174) +#define VLV_VIDEO_DIP_GDCP_PAYLOAD_B (VLV_DISPLAY_BASE + 0x61178) #define VLV_TVIDEO_DIP_CTL(pipe) \ _PIPE(pipe, VLV_VIDEO_DIP_CTL_A, VLV_VIDEO_DIP_CTL_B) @@ -3820,8 +3810,6 @@ #define TRANS_FSYNC_DELAY_HB2 (1<<27) #define TRANS_FSYNC_DELAY_HB3 (2<<27) #define TRANS_FSYNC_DELAY_HB4 (3<<27) -#define TRANS_DP_AUDIO_ONLY (1<<26) -#define TRANS_DP_VIDEO_AUDIO (0<<26) #define TRANS_INTERLACE_MASK (7<<21) #define TRANS_PROGRESSIVE (0<<21) #define TRANS_INTERLACED (3<<21) @@ -3927,7 +3915,7 @@ #define FDI_10BPC (1<<16) #define FDI_6BPC (2<<16) #define FDI_12BPC (3<<16) -#define FDI_LINK_REVERSE_OVERWRITE (1<<15) +#define FDI_RX_LINK_REVERSAL_OVERRIDE (1<<15) #define FDI_DMI_LINK_REVERSE_MASK (1<<14) #define FDI_RX_PLL_ENABLE (1<<13) #define FDI_FS_ERR_CORRECT_ENABLE (1<<11) @@ -4020,17 +4008,17 @@ #define LVDS_DETECTED (1 << 1) /* vlv has 2 sets of panel control regs. */ -#define PIPEA_PP_STATUS 0x61200 -#define PIPEA_PP_CONTROL 0x61204 -#define PIPEA_PP_ON_DELAYS 0x61208 -#define PIPEA_PP_OFF_DELAYS 0x6120c -#define PIPEA_PP_DIVISOR 0x61210 +#define PIPEA_PP_STATUS (VLV_DISPLAY_BASE + 0x61200) +#define PIPEA_PP_CONTROL (VLV_DISPLAY_BASE + 0x61204) +#define PIPEA_PP_ON_DELAYS (VLV_DISPLAY_BASE + 0x61208) +#define PIPEA_PP_OFF_DELAYS (VLV_DISPLAY_BASE + 0x6120c) +#define PIPEA_PP_DIVISOR (VLV_DISPLAY_BASE + 0x61210) -#define PIPEB_PP_STATUS 0x61300 -#define PIPEB_PP_CONTROL 0x61304 -#define PIPEB_PP_ON_DELAYS 0x61308 -#define PIPEB_PP_OFF_DELAYS 0x6130c -#define PIPEB_PP_DIVISOR 0x61310 +#define PIPEB_PP_STATUS (VLV_DISPLAY_BASE + 0x61300) +#define PIPEB_PP_CONTROL (VLV_DISPLAY_BASE + 0x61304) +#define PIPEB_PP_ON_DELAYS (VLV_DISPLAY_BASE + 0x61308) +#define PIPEB_PP_OFF_DELAYS (VLV_DISPLAY_BASE + 0x6130c) +#define PIPEB_PP_DIVISOR (VLV_DISPLAY_BASE + 0x61310) #define PCH_PP_STATUS 0xc7200 #define PCH_PP_CONTROL 0xc7204 @@ -4211,7 +4199,9 @@ #define GEN6_RP_INTERRUPT_LIMITS 0xA014 #define GEN6_RPSTAT1 0xA01C #define GEN6_CAGF_SHIFT 8 +#define HSW_CAGF_SHIFT 7 #define GEN6_CAGF_MASK (0x7f << GEN6_CAGF_SHIFT) +#define HSW_CAGF_MASK (0x7f << HSW_CAGF_SHIFT) #define GEN6_RP_CONTROL 0xA024 #define GEN6_RP_MEDIA_TURBO (1<<11) #define GEN6_RP_MEDIA_MODE_MASK (3<<9) @@ -4280,8 +4270,8 @@ #define GEN6_PCODE_READ_MIN_FREQ_TABLE 0x9 #define GEN6_PCODE_WRITE_RC6VIDS 0x4 #define GEN6_PCODE_READ_RC6VIDS 0x5 -#define GEN6_ENCODE_RC6_VID(mv) (((mv) / 5) - 245) < 0 ?: 0 -#define GEN6_DECODE_RC6_VID(vids) (((vids) * 5) > 0 ? ((vids) * 5) + 245 : 0) +#define GEN6_ENCODE_RC6_VID(mv) (((mv) - 245) / 5) +#define GEN6_DECODE_RC6_VID(vids) (((vids) * 5) + 245) #define GEN6_PCODE_DATA 0x138128 #define GEN6_PCODE_FREQ_IA_RATIO_SHIFT 8 @@ -4322,7 +4312,7 @@ #define GEN7_ROW_CHICKEN2_GT2 0xf4f4 #define DOP_CLOCK_GATING_DISABLE (1<<0) -#define G4X_AUD_VID_DID 0x62020 +#define G4X_AUD_VID_DID (dev_priv->info->display_mmio_offset + 0x62020) #define INTEL_AUDIO_DEVCL 0x808629FB #define INTEL_AUDIO_DEVBLC 0x80862801 #define INTEL_AUDIO_DEVCTG 0x80862802 @@ -4438,10 +4428,10 @@ #define AUDIO_CP_READY_C (1<<9) /* HSW Power Wells */ -#define HSW_PWR_WELL_CTL1 0x45400 /* BIOS */ -#define HSW_PWR_WELL_CTL2 0x45404 /* Driver */ -#define HSW_PWR_WELL_CTL3 0x45408 /* KVMR */ -#define HSW_PWR_WELL_CTL4 0x4540C /* Debug */ +#define HSW_PWR_WELL_BIOS 0x45400 /* CTL1 */ +#define HSW_PWR_WELL_DRIVER 0x45404 /* CTL2 */ +#define HSW_PWR_WELL_KVMR 0x45408 /* CTL3 */ +#define HSW_PWR_WELL_DEBUG 0x4540C /* CTL4 */ #define HSW_PWR_WELL_ENABLE (1<<31) #define HSW_PWR_WELL_STATE (1<<30) #define HSW_PWR_WELL_CTL5 0x45410 @@ -4524,6 +4514,7 @@ #define DDI_BUF_EMP_800MV_0DB_HSW (7<<24) /* Sel7 */ #define DDI_BUF_EMP_800MV_3_5DB_HSW (8<<24) /* Sel8 */ #define DDI_BUF_EMP_MASK (0xf<<24) +#define DDI_BUF_PORT_REVERSAL (1<<16) #define DDI_BUF_IS_IDLE (1<<7) #define DDI_A_4_LANES (1<<4) #define DDI_PORT_WIDTH_X1 (0<<1) @@ -4657,4 +4648,51 @@ #define WM_DBG_DISALLOW_MAXFIFO (1<<1) #define WM_DBG_DISALLOW_SPRITE (1<<2) +/* pipe CSC */ +#define _PIPE_A_CSC_COEFF_RY_GY 0x49010 +#define _PIPE_A_CSC_COEFF_BY 0x49014 +#define _PIPE_A_CSC_COEFF_RU_GU 0x49018 +#define _PIPE_A_CSC_COEFF_BU 0x4901c +#define _PIPE_A_CSC_COEFF_RV_GV 0x49020 +#define _PIPE_A_CSC_COEFF_BV 0x49024 +#define _PIPE_A_CSC_MODE 0x49028 +#define _PIPE_A_CSC_PREOFF_HI 0x49030 +#define _PIPE_A_CSC_PREOFF_ME 0x49034 +#define _PIPE_A_CSC_PREOFF_LO 0x49038 +#define _PIPE_A_CSC_POSTOFF_HI 0x49040 +#define _PIPE_A_CSC_POSTOFF_ME 0x49044 +#define _PIPE_A_CSC_POSTOFF_LO 0x49048 + +#define _PIPE_B_CSC_COEFF_RY_GY 0x49110 +#define _PIPE_B_CSC_COEFF_BY 0x49114 +#define _PIPE_B_CSC_COEFF_RU_GU 0x49118 +#define _PIPE_B_CSC_COEFF_BU 0x4911c +#define _PIPE_B_CSC_COEFF_RV_GV 0x49120 +#define _PIPE_B_CSC_COEFF_BV 0x49124 +#define _PIPE_B_CSC_MODE 0x49128 +#define _PIPE_B_CSC_PREOFF_HI 0x49130 +#define _PIPE_B_CSC_PREOFF_ME 0x49134 +#define _PIPE_B_CSC_PREOFF_LO 0x49138 +#define _PIPE_B_CSC_POSTOFF_HI 0x49140 +#define _PIPE_B_CSC_POSTOFF_ME 0x49144 +#define _PIPE_B_CSC_POSTOFF_LO 0x49148 + +#define CSC_BLACK_SCREEN_OFFSET (1 << 2) +#define CSC_POSITION_BEFORE_GAMMA (1 << 1) +#define CSC_MODE_YUV_TO_RGB (1 << 0) + +#define PIPE_CSC_COEFF_RY_GY(pipe) _PIPE(pipe, _PIPE_A_CSC_COEFF_RY_GY, _PIPE_B_CSC_COEFF_RY_GY) +#define PIPE_CSC_COEFF_BY(pipe) _PIPE(pipe, _PIPE_A_CSC_COEFF_BY, _PIPE_B_CSC_COEFF_BY) +#define PIPE_CSC_COEFF_RU_GU(pipe) _PIPE(pipe, _PIPE_A_CSC_COEFF_RU_GU, _PIPE_B_CSC_COEFF_RU_GU) +#define PIPE_CSC_COEFF_BU(pipe) _PIPE(pipe, _PIPE_A_CSC_COEFF_BU, _PIPE_B_CSC_COEFF_BU) +#define PIPE_CSC_COEFF_RV_GV(pipe) _PIPE(pipe, _PIPE_A_CSC_COEFF_RV_GV, _PIPE_B_CSC_COEFF_RV_GV) +#define PIPE_CSC_COEFF_BV(pipe) _PIPE(pipe, _PIPE_A_CSC_COEFF_BV, _PIPE_B_CSC_COEFF_BV) +#define PIPE_CSC_MODE(pipe) _PIPE(pipe, _PIPE_A_CSC_MODE, _PIPE_B_CSC_MODE) +#define PIPE_CSC_PREOFF_HI(pipe) _PIPE(pipe, _PIPE_A_CSC_PREOFF_HI, _PIPE_B_CSC_PREOFF_HI) +#define PIPE_CSC_PREOFF_ME(pipe) _PIPE(pipe, _PIPE_A_CSC_PREOFF_ME, _PIPE_B_CSC_PREOFF_ME) +#define PIPE_CSC_PREOFF_LO(pipe) _PIPE(pipe, _PIPE_A_CSC_PREOFF_LO, _PIPE_B_CSC_PREOFF_LO) +#define PIPE_CSC_POSTOFF_HI(pipe) _PIPE(pipe, _PIPE_A_CSC_POSTOFF_HI, _PIPE_B_CSC_POSTOFF_HI) +#define PIPE_CSC_POSTOFF_ME(pipe) _PIPE(pipe, _PIPE_A_CSC_POSTOFF_ME, _PIPE_B_CSC_POSTOFF_ME) +#define PIPE_CSC_POSTOFF_LO(pipe) _PIPE(pipe, _PIPE_A_CSC_POSTOFF_LO, _PIPE_B_CSC_POSTOFF_LO) + #endif /* _I915_REG_H_ */ diff --git a/drivers/video/drm/i915/intel_crt.c b/drivers/video/drm/i915/intel_crt.c index 47cb4f7765..66c8a2962d 100644 --- a/drivers/video/drm/i915/intel_crt.c +++ b/drivers/video/drm/i915/intel_crt.c @@ -44,6 +44,9 @@ struct intel_crt { struct intel_encoder base; + /* DPMS state is stored in the connector, which we need in the + * encoder's enable/disable callbacks */ + struct intel_connector *connector; bool force_hotplug_required; u32 adpa_reg; }; @@ -80,29 +83,6 @@ static bool intel_crt_get_hw_state(struct intel_encoder *encoder, return true; } -static void intel_disable_crt(struct intel_encoder *encoder) -{ - struct drm_i915_private *dev_priv = encoder->base.dev->dev_private; - struct intel_crt *crt = intel_encoder_to_crt(encoder); - u32 temp; - - temp = I915_READ(crt->adpa_reg); - temp &= ~(ADPA_HSYNC_CNTL_DISABLE | ADPA_VSYNC_CNTL_DISABLE); - temp &= ~ADPA_DAC_ENABLE; - I915_WRITE(crt->adpa_reg, temp); -} - -static void intel_enable_crt(struct intel_encoder *encoder) -{ - struct drm_i915_private *dev_priv = encoder->base.dev->dev_private; - struct intel_crt *crt = intel_encoder_to_crt(encoder); - u32 temp; - - temp = I915_READ(crt->adpa_reg); - temp |= ADPA_DAC_ENABLE; - I915_WRITE(crt->adpa_reg, temp); -} - /* Note: The caller is required to filter out dpms modes not supported by the * platform. */ static void intel_crt_set_dpms(struct intel_encoder *encoder, int mode) @@ -134,6 +114,19 @@ static void intel_crt_set_dpms(struct intel_encoder *encoder, int mode) I915_WRITE(crt->adpa_reg, temp); } +static void intel_disable_crt(struct intel_encoder *encoder) +{ + intel_crt_set_dpms(encoder, DRM_MODE_DPMS_OFF); +} + +static void intel_enable_crt(struct intel_encoder *encoder) +{ + struct intel_crt *crt = intel_encoder_to_crt(encoder); + + intel_crt_set_dpms(encoder, crt->connector->base.dpms); +} + + static void intel_crt_dpms(struct drm_connector *connector, int mode) { struct drm_device *dev = connector->dev; @@ -259,6 +252,8 @@ static bool intel_ironlake_crt_detect_hotplug(struct drm_connector *connector) u32 adpa; bool ret; + ENTER(); + /* The first time through, trigger an explicit detection cycle */ if (crt->force_hotplug_required) { bool turn_off_dac = HAS_PCH_SPLIT(dev); @@ -266,59 +261,64 @@ static bool intel_ironlake_crt_detect_hotplug(struct drm_connector *connector) crt->force_hotplug_required = 0; - save_adpa = adpa = I915_READ(PCH_ADPA); + save_adpa = adpa = I915_READ(crt->adpa_reg); DRM_DEBUG_KMS("trigger hotplug detect cycle: adpa=0x%x\n", adpa); adpa |= ADPA_CRT_HOTPLUG_FORCE_TRIGGER; if (turn_off_dac) adpa &= ~ADPA_DAC_ENABLE; - I915_WRITE(PCH_ADPA, adpa); + I915_WRITE(crt->adpa_reg, adpa); - if (wait_for((I915_READ(PCH_ADPA) & ADPA_CRT_HOTPLUG_FORCE_TRIGGER) == 0, + if (wait_for((I915_READ(crt->adpa_reg) & ADPA_CRT_HOTPLUG_FORCE_TRIGGER) == 0, 1000)) DRM_DEBUG_KMS("timed out waiting for FORCE_TRIGGER"); if (turn_off_dac) { - I915_WRITE(PCH_ADPA, save_adpa); - POSTING_READ(PCH_ADPA); + I915_WRITE(crt->adpa_reg, save_adpa); + POSTING_READ(crt->adpa_reg); } } /* Check the status to see if both blue and green are on now */ - adpa = I915_READ(PCH_ADPA); + adpa = I915_READ(crt->adpa_reg); if ((adpa & ADPA_CRT_HOTPLUG_MONITOR_MASK) != 0) ret = true; else ret = false; DRM_DEBUG_KMS("ironlake hotplug adpa=0x%x, result %d\n", adpa, ret); + LEAVE(); + return ret; } static bool valleyview_crt_detect_hotplug(struct drm_connector *connector) { struct drm_device *dev = connector->dev; + struct intel_crt *crt = intel_attached_crt(connector); struct drm_i915_private *dev_priv = dev->dev_private; u32 adpa; bool ret; u32 save_adpa; - save_adpa = adpa = I915_READ(ADPA); + ENTER(); + + save_adpa = adpa = I915_READ(crt->adpa_reg); DRM_DEBUG_KMS("trigger hotplug detect cycle: adpa=0x%x\n", adpa); adpa |= ADPA_CRT_HOTPLUG_FORCE_TRIGGER; - I915_WRITE(ADPA, adpa); + I915_WRITE(crt->adpa_reg, adpa); - if (wait_for((I915_READ(ADPA) & ADPA_CRT_HOTPLUG_FORCE_TRIGGER) == 0, + if (wait_for((I915_READ(crt->adpa_reg) & ADPA_CRT_HOTPLUG_FORCE_TRIGGER) == 0, 1000)) { DRM_DEBUG_KMS("timed out waiting for FORCE_TRIGGER"); - I915_WRITE(ADPA, save_adpa); + I915_WRITE(crt->adpa_reg, save_adpa); } /* Check the status to see if both blue and green are on now */ - adpa = I915_READ(ADPA); + adpa = I915_READ(crt->adpa_reg); if ((adpa & ADPA_CRT_HOTPLUG_MONITOR_MASK) != 0) ret = true; else @@ -329,6 +329,8 @@ static bool valleyview_crt_detect_hotplug(struct drm_connector *connector) /* FIXME: debug force function and remove */ ret = true; + LEAVE(); + return ret; } @@ -348,6 +350,8 @@ static bool intel_crt_detect_hotplug(struct drm_connector *connector) bool ret = false; int i, tries = 0; + ENTER(); + if (HAS_PCH_SPLIT(dev)) return intel_ironlake_crt_detect_hotplug(connector); @@ -386,6 +390,8 @@ static bool intel_crt_detect_hotplug(struct drm_connector *connector) /* and put the bits back */ I915_WRITE(PORT_HOTPLUG_EN, orig); + LEAVE(); + return ret; } @@ -394,6 +400,8 @@ static struct edid *intel_crt_get_edid(struct drm_connector *connector, { struct edid *edid; + ENTER(); + edid = drm_get_edid(connector, i2c); if (!edid && !intel_gmbus_is_forced_bit(i2c)) { @@ -403,6 +411,8 @@ static struct edid *intel_crt_get_edid(struct drm_connector *connector, intel_gmbus_force_bit(i2c, false); } + LEAVE(); + return edid; } @@ -664,11 +674,11 @@ static void intel_crt_reset(struct drm_connector *connector) if (HAS_PCH_SPLIT(dev)) { u32 adpa; - adpa = I915_READ(PCH_ADPA); + adpa = I915_READ(crt->adpa_reg); adpa &= ~ADPA_CRT_HOTPLUG_MASK; adpa |= ADPA_HOTPLUG_BITS; - I915_WRITE(PCH_ADPA, adpa); - POSTING_READ(PCH_ADPA); + I915_WRITE(crt->adpa_reg, adpa); + POSTING_READ(crt->adpa_reg); DRM_DEBUG_KMS("pch crt adpa set to 0x%x\n", adpa); crt->force_hotplug_required = 1; @@ -683,7 +693,6 @@ static void intel_crt_reset(struct drm_connector *connector) static const struct drm_encoder_helper_funcs crt_encoder_funcs = { .mode_fixup = intel_crt_mode_fixup, .mode_set = intel_crt_mode_set, - .disable = intel_encoder_noop, }; static const struct drm_connector_funcs intel_crt_connector_funcs = { @@ -723,6 +732,7 @@ void intel_crt_init(struct drm_device *dev) } connector = &intel_connector->base; + crt->connector = intel_connector; drm_connector_init(dev, &intel_connector->base, &intel_crt_connector_funcs, DRM_MODE_CONNECTOR_VGA); @@ -753,7 +763,7 @@ void intel_crt_init(struct drm_device *dev) crt->base.disable = intel_disable_crt; crt->base.enable = intel_enable_crt; - if (IS_HASWELL(dev)) + if (HAS_DDI(dev)) crt->base.get_hw_state = intel_ddi_get_hw_state; else crt->base.get_hw_state = intel_crt_get_hw_state; @@ -777,10 +787,14 @@ void intel_crt_init(struct drm_device *dev) dev_priv->hotplug_supported_mask |= CRT_HOTPLUG_INT_STATUS; /* - * TODO: find a proper way to discover whether we need to set the - * polarity reversal bit or not, instead of relying on the BIOS. + * TODO: find a proper way to discover whether we need to set the the + * polarity and link reversal bits or not, instead of relying on the + * BIOS. */ - if (HAS_PCH_LPT(dev)) - dev_priv->fdi_rx_polarity_reversed = - !!(I915_READ(_FDI_RXA_CTL) & FDI_RX_POLARITY_REVERSED_LPT); + if (HAS_PCH_LPT(dev)) { + u32 fdi_config = FDI_RX_POLARITY_REVERSED_LPT | + FDI_RX_LINK_REVERSAL_OVERRIDE; + + dev_priv->fdi_rx_config = I915_READ(_FDI_RXA_CTL) & fdi_config; + } } diff --git a/drivers/video/drm/i915/intel_ddi.c b/drivers/video/drm/i915/intel_ddi.c index b893a423e1..6802865c0a 100644 --- a/drivers/video/drm/i915/intel_ddi.c +++ b/drivers/video/drm/i915/intel_ddi.c @@ -84,7 +84,8 @@ static enum port intel_ddi_get_encoder_port(struct intel_encoder *intel_encoder) * in either FDI or DP modes only, as HDMI connections will work with both * of those */ -void intel_prepare_ddi_buffers(struct drm_device *dev, enum port port, bool use_fdi_mode) +static void intel_prepare_ddi_buffers(struct drm_device *dev, enum port port, + bool use_fdi_mode) { struct drm_i915_private *dev_priv = dev->dev_private; u32 reg; @@ -114,16 +115,17 @@ void intel_prepare_ddi(struct drm_device *dev) { int port; - if (IS_HASWELL(dev)) { + if (!HAS_DDI(dev)) + return; + for (port = PORT_A; port < PORT_E; port++) intel_prepare_ddi_buffers(dev, port, false); - /* DDI E is the suggested one to work in FDI mode, so program is as such by - * default. It will have to be re-programmed in case a digital DP output - * will be detected on it + /* DDI E is the suggested one to work in FDI mode, so program is as such + * by default. It will have to be re-programmed in case a digital DP + * output will be detected on it */ intel_prepare_ddi_buffers(dev, PORT_E, true); - } } static const long hsw_ddi_buf_ctl_values[] = { @@ -178,10 +180,8 @@ void hsw_fdi_link_train(struct drm_crtc *crtc) FDI_RX_TP1_TO_TP2_48 | FDI_RX_FDI_DELAY_90); /* Enable the PCH Receiver FDI PLL */ - rx_ctl_val = FDI_RX_PLL_ENABLE | FDI_RX_ENHANCE_FRAME_ENABLE | - ((intel_crtc->fdi_lanes - 1) << 19); - if (dev_priv->fdi_rx_polarity_reversed) - rx_ctl_val |= FDI_RX_POLARITY_REVERSED_LPT; + rx_ctl_val = dev_priv->fdi_rx_config | FDI_RX_ENHANCE_FRAME_ENABLE | + FDI_RX_PLL_ENABLE | ((intel_crtc->fdi_lanes - 1) << 19); I915_WRITE(_FDI_RXA_CTL, rx_ctl_val); POSTING_READ(_FDI_RXA_CTL); udelay(220); @@ -203,7 +203,10 @@ void hsw_fdi_link_train(struct drm_crtc *crtc) DP_TP_CTL_LINK_TRAIN_PAT1 | DP_TP_CTL_ENABLE); - /* Configure and enable DDI_BUF_CTL for DDI E with next voltage */ + /* Configure and enable DDI_BUF_CTL for DDI E with next voltage. + * DDI E does not support port reversal, the functionality is + * achieved on the PCH side in FDI_RX_CTL, so no need to set the + * port reversal bit */ I915_WRITE(DDI_BUF_CTL(PORT_E), DDI_BUF_CTL_ENABLE | ((intel_crtc->fdi_lanes - 1) << 1) | @@ -675,10 +678,14 @@ static void intel_ddi_mode_set(struct drm_encoder *encoder, DRM_DEBUG_KMS("Preparing DDI mode for Haswell on port %c, pipe %c\n", port_name(port), pipe_name(pipe)); + intel_crtc->eld_vld = false; if (type == INTEL_OUTPUT_DISPLAYPORT || type == INTEL_OUTPUT_EDP) { struct intel_dp *intel_dp = enc_to_intel_dp(encoder); + struct intel_digital_port *intel_dig_port = + enc_to_dig_port(encoder); - intel_dp->DP = DDI_BUF_CTL_ENABLE | DDI_BUF_EMP_400MV_0DB_HSW; + intel_dp->DP = intel_dig_port->port_reversal | + DDI_BUF_CTL_ENABLE | DDI_BUF_EMP_400MV_0DB_HSW; switch (intel_dp->lane_count) { case 1: intel_dp->DP |= DDI_PORT_WIDTH_X1; @@ -985,7 +992,13 @@ void intel_ddi_enable_pipe_func(struct drm_crtc *crtc) if (cpu_transcoder == TRANSCODER_EDP) { switch (pipe) { case PIPE_A: + /* Can only use the always-on power well for eDP when + * not using the panel fitter, and when not using motion + * blur mitigation (which we don't support). */ + if (dev_priv->pch_pf_size) temp |= TRANS_DDI_EDP_INPUT_A_ONOFF; + else + temp |= TRANS_DDI_EDP_INPUT_A_ON; break; case PIPE_B: temp |= TRANS_DDI_EDP_INPUT_B_ONOFF; @@ -1069,7 +1082,7 @@ bool intel_ddi_connector_get_hw_state(struct intel_connector *intel_connector) if (port == PORT_A) cpu_transcoder = TRANSCODER_EDP; else - cpu_transcoder = pipe; + cpu_transcoder = (enum transcoder) pipe; tmp = I915_READ(TRANS_DDI_FUNC_CTL(cpu_transcoder)); @@ -1285,34 +1298,58 @@ static void intel_ddi_post_disable(struct intel_encoder *intel_encoder) static void intel_enable_ddi(struct intel_encoder *intel_encoder) { struct drm_encoder *encoder = &intel_encoder->base; + struct drm_crtc *crtc = encoder->crtc; + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + int pipe = intel_crtc->pipe; struct drm_device *dev = encoder->dev; struct drm_i915_private *dev_priv = dev->dev_private; enum port port = intel_ddi_get_encoder_port(intel_encoder); int type = intel_encoder->type; + uint32_t tmp; if (type == INTEL_OUTPUT_HDMI) { + struct intel_digital_port *intel_dig_port = + enc_to_dig_port(encoder); + /* In HDMI/DVI mode, the port width, and swing/emphasis values * are ignored so nothing special needs to be done besides * enabling the port. */ - I915_WRITE(DDI_BUF_CTL(port), DDI_BUF_CTL_ENABLE); + I915_WRITE(DDI_BUF_CTL(port), + intel_dig_port->port_reversal | DDI_BUF_CTL_ENABLE); } else if (type == INTEL_OUTPUT_EDP) { struct intel_dp *intel_dp = enc_to_intel_dp(encoder); ironlake_edp_backlight_on(intel_dp); } + + if (intel_crtc->eld_vld) { + tmp = I915_READ(HSW_AUD_PIN_ELD_CP_VLD); + tmp |= ((AUDIO_OUTPUT_ENABLE_A | AUDIO_ELD_VALID_A) << (pipe * 4)); + I915_WRITE(HSW_AUD_PIN_ELD_CP_VLD, tmp); + } } static void intel_disable_ddi(struct intel_encoder *intel_encoder) { struct drm_encoder *encoder = &intel_encoder->base; + struct drm_crtc *crtc = encoder->crtc; + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + int pipe = intel_crtc->pipe; int type = intel_encoder->type; + struct drm_device *dev = encoder->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + uint32_t tmp; if (type == INTEL_OUTPUT_EDP) { struct intel_dp *intel_dp = enc_to_intel_dp(encoder); ironlake_edp_backlight_off(intel_dp); } + + tmp = I915_READ(HSW_AUD_PIN_ELD_CP_VLD); + tmp &= ~((AUDIO_OUTPUT_ENABLE_A | AUDIO_ELD_VALID_A) << (pipe * 4)); + I915_WRITE(HSW_AUD_PIN_ELD_CP_VLD, tmp); } int intel_ddi_get_cdclk_freq(struct drm_i915_private *dev_priv) @@ -1354,8 +1391,8 @@ void intel_ddi_prepare_link_retrain(struct drm_encoder *encoder) struct intel_dp *intel_dp = &intel_dig_port->dp; struct drm_i915_private *dev_priv = encoder->dev->dev_private; enum port port = intel_dig_port->port; - bool wait; uint32_t val; + bool wait = false; if (I915_READ(DP_TP_CTL(port)) & DP_TP_CTL_ENABLE) { val = I915_READ(DDI_BUF_CTL(port)); @@ -1452,11 +1489,11 @@ static const struct drm_encoder_funcs intel_ddi_funcs = { static const struct drm_encoder_helper_funcs intel_ddi_helper_funcs = { .mode_fixup = intel_ddi_mode_fixup, .mode_set = intel_ddi_mode_set, - .disable = intel_encoder_noop, }; void intel_ddi_init(struct drm_device *dev, enum port port) { + struct drm_i915_private *dev_priv = dev->dev_private; struct intel_digital_port *intel_dig_port; struct intel_encoder *intel_encoder; struct drm_encoder *encoder; @@ -1497,6 +1534,8 @@ void intel_ddi_init(struct drm_device *dev, enum port port) intel_encoder->get_hw_state = intel_ddi_get_hw_state; intel_dig_port->port = port; + intel_dig_port->port_reversal = I915_READ(DDI_BUF_CTL(port)) & + DDI_BUF_PORT_REVERSAL; if (hdmi_connector) intel_dig_port->hdmi.sdvox_reg = DDI_BUF_CTL(port); else diff --git a/drivers/video/drm/i915/intel_display.c b/drivers/video/drm/i915/intel_display.c index daa3a399c4..171421dbb3 100644 --- a/drivers/video/drm/i915/intel_display.c +++ b/drivers/video/drm/i915/intel_display.c @@ -166,8 +166,8 @@ static const intel_limit_t intel_limits_i9xx_sdvo = { .vco = { .min = 1400000, .max = 2800000 }, .n = { .min = 1, .max = 6 }, .m = { .min = 70, .max = 120 }, - .m1 = { .min = 10, .max = 22 }, - .m2 = { .min = 5, .max = 9 }, + .m1 = { .min = 8, .max = 18 }, + .m2 = { .min = 3, .max = 7 }, .p = { .min = 5, .max = 80 }, .p1 = { .min = 1, .max = 8 }, .p2 = { .dot_limit = 200000, @@ -180,8 +180,8 @@ static const intel_limit_t intel_limits_i9xx_lvds = { .vco = { .min = 1400000, .max = 2800000 }, .n = { .min = 1, .max = 6 }, .m = { .min = 70, .max = 120 }, - .m1 = { .min = 10, .max = 22 }, - .m2 = { .min = 5, .max = 9 }, + .m1 = { .min = 8, .max = 18 }, + .m2 = { .min = 3, .max = 7 }, .p = { .min = 7, .max = 98 }, .p1 = { .min = 1, .max = 8 }, .p2 = { .dot_limit = 112000, @@ -428,13 +428,11 @@ static const intel_limit_t intel_limits_vlv_dp = { u32 intel_dpio_read(struct drm_i915_private *dev_priv, int reg) { - unsigned long flags; - u32 val = 0; + WARN_ON(!mutex_is_locked(&dev_priv->dpio_lock)); - spin_lock_irqsave(&dev_priv->dpio_lock, flags); if (wait_for_atomic_us((I915_READ(DPIO_PKT) & DPIO_BUSY) == 0, 100)) { DRM_ERROR("DPIO idle wait timed out\n"); - goto out_unlock; + return 0; } I915_WRITE(DPIO_REG, reg); @@ -442,24 +440,20 @@ u32 intel_dpio_read(struct drm_i915_private *dev_priv, int reg) DPIO_BYTE); if (wait_for_atomic_us((I915_READ(DPIO_PKT) & DPIO_BUSY) == 0, 100)) { DRM_ERROR("DPIO read wait timed out\n"); - goto out_unlock; + return 0; } - val = I915_READ(DPIO_DATA); -out_unlock: - spin_unlock_irqrestore(&dev_priv->dpio_lock, flags); - return val; + return I915_READ(DPIO_DATA); } static void intel_dpio_write(struct drm_i915_private *dev_priv, int reg, u32 val) { - unsigned long flags; + WARN_ON(!mutex_is_locked(&dev_priv->dpio_lock)); - spin_lock_irqsave(&dev_priv->dpio_lock, flags); if (wait_for_atomic_us((I915_READ(DPIO_PKT) & DPIO_BUSY) == 0, 100)) { DRM_ERROR("DPIO idle wait timed out\n"); - goto out_unlock; + return; } I915_WRITE(DPIO_DATA, val); @@ -468,9 +462,6 @@ static void intel_dpio_write(struct drm_i915_private *dev_priv, int reg, DPIO_BYTE); if (wait_for_atomic_us((I915_READ(DPIO_PKT) & DPIO_BUSY) == 0, 100)) DRM_ERROR("DPIO write wait timed out\n"); - -out_unlock: - spin_unlock_irqrestore(&dev_priv->dpio_lock, flags); } static void vlv_init_dpio(struct drm_device *dev) @@ -484,61 +475,14 @@ static void vlv_init_dpio(struct drm_device *dev) POSTING_READ(DPIO_CTL); } -static int intel_dual_link_lvds_callback(const struct dmi_system_id *id) -{ - DRM_INFO("Forcing lvds to dual link mode on %s\n", id->ident); - return 1; -} - -static const struct dmi_system_id intel_dual_link_lvds[] = { - { - .callback = intel_dual_link_lvds_callback, - .ident = "Apple MacBook Pro (Core i5/i7 Series)", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."), - DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro8,2"), - }, - }, - { } /* terminating entry */ -}; - -static bool is_dual_link_lvds(struct drm_i915_private *dev_priv, - unsigned int reg) -{ - unsigned int val; - - /* use the module option value if specified */ - if (i915_lvds_channel_mode > 0) - return i915_lvds_channel_mode == 2; - -// if (dmi_check_system(intel_dual_link_lvds)) -// return true; - - if (dev_priv->lvds_val) - val = dev_priv->lvds_val; - else { - /* BIOS should set the proper LVDS register value at boot, but - * in reality, it doesn't set the value when the lid is closed; - * we need to check "the value to be set" in VBT when LVDS - * register is uninitialized. - */ - val = I915_READ(reg); - if (!(val & ~(LVDS_PIPE_MASK | LVDS_DETECTED))) - val = dev_priv->bios_lvds_val; - dev_priv->lvds_val = val; - } - return (val & LVDS_CLKB_POWER_MASK) == LVDS_CLKB_POWER_UP; -} - static const intel_limit_t *intel_ironlake_limit(struct drm_crtc *crtc, int refclk) { struct drm_device *dev = crtc->dev; - struct drm_i915_private *dev_priv = dev->dev_private; const intel_limit_t *limit; if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)) { - if (is_dual_link_lvds(dev_priv, PCH_LVDS)) { + if (intel_is_dual_link_lvds(dev)) { /* LVDS dual channel */ if (refclk == 100000) limit = &intel_limits_ironlake_dual_lvds_100m; @@ -562,11 +506,10 @@ static const intel_limit_t *intel_ironlake_limit(struct drm_crtc *crtc, static const intel_limit_t *intel_g4x_limit(struct drm_crtc *crtc) { struct drm_device *dev = crtc->dev; - struct drm_i915_private *dev_priv = dev->dev_private; const intel_limit_t *limit; if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)) { - if (is_dual_link_lvds(dev_priv, LVDS)) + if (intel_is_dual_link_lvds(dev)) /* LVDS with dual channel */ limit = &intel_limits_g4x_dual_channel_lvds; else @@ -698,19 +641,16 @@ intel_find_best_PLL(const intel_limit_t *limit, struct drm_crtc *crtc, { struct drm_device *dev = crtc->dev; - struct drm_i915_private *dev_priv = dev->dev_private; intel_clock_t clock; int err = target; - if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS) && - (I915_READ(LVDS)) != 0) { + if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)) { /* - * For LVDS, if the panel is on, 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. + * 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 (is_dual_link_lvds(dev_priv, LVDS)) + if (intel_is_dual_link_lvds(dev)) clock.p2 = limit->p2.p2_fast; else clock.p2 = limit->p2.p2_slow; @@ -763,7 +703,6 @@ intel_g4x_find_best_PLL(const intel_limit_t *limit, struct drm_crtc *crtc, intel_clock_t *best_clock) { struct drm_device *dev = crtc->dev; - struct drm_i915_private *dev_priv = dev->dev_private; intel_clock_t clock; int max_n; bool found; @@ -778,8 +717,7 @@ intel_g4x_find_best_PLL(const intel_limit_t *limit, struct drm_crtc *crtc, lvds_reg = PCH_LVDS; else lvds_reg = LVDS; - if ((I915_READ(lvds_reg) & LVDS_CLKB_POWER_MASK) == - LVDS_CLKB_POWER_UP) + if (intel_is_dual_link_lvds(dev)) clock.p2 = limit->p2.p2_fast; else clock.p2 = limit->p2.p2_slow; @@ -1059,6 +997,51 @@ void intel_wait_for_pipe_off(struct drm_device *dev, int pipe) } } +/* + * 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"; @@ -1137,8 +1120,8 @@ static void assert_fdi_tx(struct drm_i915_private *dev_priv, enum transcoder cpu_transcoder = intel_pipe_to_cpu_transcoder(dev_priv, pipe); - if (IS_HASWELL(dev_priv->dev)) { - /* On Haswell, DDI is used instead of FDI_TX_CTL */ + 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); @@ -1182,7 +1165,7 @@ static void assert_fdi_tx_pll_enabled(struct drm_i915_private *dev_priv, return; /* On Haswell, DDI ports are responsible for the FDI PLL setup */ - if (IS_HASWELL(dev_priv->dev)) + if (HAS_DDI(dev_priv->dev)) return; reg = FDI_TX_CTL(pipe); @@ -1243,9 +1226,15 @@ void assert_pipe(struct drm_i915_private *dev_priv, if (pipe == PIPE_A && dev_priv->quirks & QUIRK_PIPEA_FORCE) state = true; + if (IS_HASWELL(dev_priv->dev) && cpu_transcoder != TRANSCODER_EDP && + !(I915_READ(HSW_PWR_WELL_DRIVER) & HSW_PWR_WELL_ENABLE)) { + 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)); @@ -1521,13 +1510,14 @@ static void intel_sbi_write(struct drm_i915_private *dev_priv, u16 reg, u32 value, enum intel_sbi_destination destination) { - unsigned long flags; u32 tmp; - spin_lock_irqsave(&dev_priv->dpio_lock, flags); - if (wait_for((I915_READ(SBI_CTL_STAT) & SBI_BUSY) == 0, 100)) { + WARN_ON(!mutex_is_locked(&dev_priv->dpio_lock)); + + if (wait_for((I915_READ(SBI_CTL_STAT) & SBI_BUSY) == 0, + 100)) { DRM_ERROR("timeout waiting for SBI to become ready\n"); - goto out_unlock; + return; } I915_WRITE(SBI_ADDR, (reg << 16)); @@ -1542,24 +1532,21 @@ intel_sbi_write(struct drm_i915_private *dev_priv, u16 reg, u32 value, if (wait_for((I915_READ(SBI_CTL_STAT) & (SBI_BUSY | SBI_RESPONSE_FAIL)) == 0, 100)) { DRM_ERROR("timeout waiting for SBI to complete write transaction\n"); - goto out_unlock; + return; } - -out_unlock: - spin_unlock_irqrestore(&dev_priv->dpio_lock, flags); } static u32 intel_sbi_read(struct drm_i915_private *dev_priv, u16 reg, enum intel_sbi_destination destination) { - unsigned long flags; u32 value = 0; + WARN_ON(!mutex_is_locked(&dev_priv->dpio_lock)); - spin_lock_irqsave(&dev_priv->dpio_lock, flags); - if (wait_for((I915_READ(SBI_CTL_STAT) & SBI_BUSY) == 0, 100)) { + if (wait_for((I915_READ(SBI_CTL_STAT) & SBI_BUSY) == 0, + 100)) { DRM_ERROR("timeout waiting for SBI to become ready\n"); - goto out_unlock; + return 0; } I915_WRITE(SBI_ADDR, (reg << 16)); @@ -1573,14 +1560,10 @@ intel_sbi_read(struct drm_i915_private *dev_priv, u16 reg, if (wait_for((I915_READ(SBI_CTL_STAT) & (SBI_BUSY | SBI_RESPONSE_FAIL)) == 0, 100)) { DRM_ERROR("timeout waiting for SBI to complete read transaction\n"); - goto out_unlock; + return 0; } - value = I915_READ(SBI_DATA); - -out_unlock: - spin_unlock_irqrestore(&dev_priv->dpio_lock, flags); - return value; + return I915_READ(SBI_DATA); } /** @@ -1712,8 +1695,8 @@ static void ironlake_enable_pch_transcoder(struct drm_i915_private *dev_priv, * make the BPC in transcoder be consistent with * that in pipeconf reg. */ - val &= ~PIPE_BPC_MASK; - val |= pipeconf_val & PIPE_BPC_MASK; + val &= ~PIPECONF_BPC_MASK; + val |= pipeconf_val & PIPECONF_BPC_MASK; } val &= ~TRANS_INTERLACE_MASK; @@ -1740,7 +1723,7 @@ static void lpt_enable_pch_transcoder(struct drm_i915_private *dev_priv, BUG_ON(dev_priv->info->gen < 5); /* FDI must be feeding us bits for PCH ports */ - assert_fdi_tx_enabled(dev_priv, cpu_transcoder); + assert_fdi_tx_enabled(dev_priv, (enum pipe) cpu_transcoder); assert_fdi_rx_enabled(dev_priv, TRANSCODER_A); /* Workaround: set timing override bit. */ @@ -1828,11 +1811,11 @@ static void intel_enable_pipe(struct drm_i915_private *dev_priv, enum pipe pipe, { enum transcoder cpu_transcoder = intel_pipe_to_cpu_transcoder(dev_priv, pipe); - enum transcoder pch_transcoder; + enum pipe pch_transcoder; int reg; u32 val; - if (IS_HASWELL(dev_priv->dev)) + if (HAS_PCH_LPT(dev_priv->dev)) pch_transcoder = TRANSCODER_A; else pch_transcoder = pipe; @@ -1848,7 +1831,8 @@ static void intel_enable_pipe(struct drm_i915_private *dev_priv, enum pipe pipe, if (pch_port) { /* if driving the PCH, we need FDI enabled */ assert_fdi_rx_pll_enabled(dev_priv, pch_transcoder); - assert_fdi_tx_pll_enabled(dev_priv, cpu_transcoder); + assert_fdi_tx_pll_enabled(dev_priv, + (enum pipe) cpu_transcoder); } /* FIXME: assert CPU port conditions for SNB+ */ } @@ -2005,6 +1989,11 @@ intel_pin_and_fence_fb_obj(struct drm_device *dev, * 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; return 0; @@ -2024,18 +2013,29 @@ void intel_unpin_fb_obj(struct drm_i915_gem_object *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_offset_xtiled(int *x, int *y, - unsigned int bpp, +unsigned long intel_gen4_compute_page_offset(int *x, int *y, + unsigned int tiling_mode, + unsigned int cpp, unsigned int pitch) { - int tile_rows, tiles; + if (tiling_mode != I915_TILING_NONE) { + unsigned int tile_rows, tiles; tile_rows = *y / 8; *y %= 8; - tiles = *x / (512/bpp); - *x %= 512/bpp; + + 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; + } } static int i9xx_update_plane(struct drm_crtc *crtc, struct drm_framebuffer *fb, @@ -2112,7 +2112,7 @@ static int i9xx_update_plane(struct drm_crtc *crtc, struct drm_framebuffer *fb, if (INTEL_INFO(dev)->gen >= 4) { intel_crtc->dspaddr_offset = - intel_gen4_compute_offset_xtiled(&x, &y, + intel_gen4_compute_page_offset(&x, &y, obj->tiling_mode, fb->bits_per_pixel / 8, fb->pitches[0]); linear_offset -= intel_crtc->dspaddr_offset; @@ -2193,9 +2193,9 @@ static int ironlake_update_plane(struct drm_crtc *crtc, return -EINVAL; } -// if (obj->tiling_mode != I915_TILING_NONE) -// dspcntr |= DISPPLANE_TILED; -// else + if (obj->tiling_mode != I915_TILING_NONE) + dspcntr |= DISPPLANE_TILED; + else dspcntr &= ~DISPPLANE_TILED; /* must disable */ @@ -2205,7 +2205,7 @@ static int ironlake_update_plane(struct drm_crtc *crtc, linear_offset = y * fb->pitches[0] + x * (fb->bits_per_pixel / 8); intel_crtc->dspaddr_offset = - intel_gen4_compute_offset_xtiled(&x, &y, + intel_gen4_compute_page_offset(&x, &y, obj->tiling_mode, fb->bits_per_pixel / 8, fb->pitches[0]); linear_offset -= intel_crtc->dspaddr_offset; @@ -2250,10 +2250,6 @@ intel_finish_fb(struct drm_framebuffer *old_fb) bool was_interruptible = dev_priv->mm.interruptible; int ret; - wait_event(dev_priv->pending_flip_queue, - atomic_read(&dev_priv->mm.wedged) || - atomic_read(&obj->pending_flip) == 0); - /* 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 @@ -2330,43 +2326,6 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y, return 0; } -static void ironlake_set_pll_edp(struct drm_crtc *crtc, int clock) -{ - struct drm_device *dev = crtc->dev; - struct drm_i915_private *dev_priv = dev->dev_private; - u32 dpa_ctl; - - DRM_DEBUG_KMS("eDP PLL enable for clock %d\n", clock); - dpa_ctl = I915_READ(DP_A); - dpa_ctl &= ~DP_PLL_FREQ_MASK; - - if (clock < 200000) { - u32 temp; - dpa_ctl |= DP_PLL_FREQ_160MHZ; - /* workaround for 160Mhz: - 1) program 0x4600c bits 15:0 = 0x8124 - 2) program 0x46010 bit 0 = 1 - 3) program 0x46034 bit 24 = 1 - 4) program 0x64000 bit 14 = 1 - */ - temp = I915_READ(0x4600c); - temp &= 0xffff0000; - I915_WRITE(0x4600c, temp | 0x8124); - - temp = I915_READ(0x46010); - I915_WRITE(0x46010, temp | 1); - - temp = I915_READ(0x46034); - I915_WRITE(0x46034, temp | (1 << 24)); - } else { - dpa_ctl |= DP_PLL_FREQ_270MHZ; - } - I915_WRITE(DP_A, dpa_ctl); - - POSTING_READ(DP_A); - udelay(500); -} - static void intel_fdi_normal_train(struct drm_crtc *crtc) { struct drm_device *dev = crtc->dev; @@ -2795,7 +2754,7 @@ static void ironlake_fdi_pll_enable(struct intel_crtc *intel_crtc) temp = I915_READ(reg); temp &= ~((0x7 << 19) | (0x7 << 16)); temp |= (intel_crtc->fdi_lanes - 1) << 19; - temp |= (I915_READ(PIPECONF(pipe)) & PIPE_BPC_MASK) << 11; + temp |= (I915_READ(PIPECONF(pipe)) & PIPECONF_BPC_MASK) << 11; I915_WRITE(reg, temp | FDI_RX_PLL_ENABLE); POSTING_READ(reg); @@ -2808,9 +2767,6 @@ static void ironlake_fdi_pll_enable(struct intel_crtc *intel_crtc) POSTING_READ(reg); udelay(200); - /* On Haswell, the PLL configuration for ports and pipes is handled - * separately, as part of DDI setup */ - if (!IS_HASWELL(dev)) { /* Enable CPU FDI TX PLL, always on for Ironlake */ reg = FDI_TX_CTL(pipe); temp = I915_READ(reg); @@ -2820,7 +2776,6 @@ static void ironlake_fdi_pll_enable(struct intel_crtc *intel_crtc) POSTING_READ(reg); udelay(100); } - } } static void ironlake_fdi_pll_disable(struct intel_crtc *intel_crtc) @@ -2869,7 +2824,7 @@ static void ironlake_fdi_disable(struct drm_crtc *crtc) reg = FDI_RX_CTL(pipe); temp = I915_READ(reg); temp &= ~(0x7 << 16); - temp |= (I915_READ(PIPECONF(pipe)) & PIPE_BPC_MASK) << 11; + temp |= (I915_READ(PIPECONF(pipe)) & PIPECONF_BPC_MASK) << 11; I915_WRITE(reg, temp & ~FDI_RX_ENABLE); POSTING_READ(reg); @@ -2898,7 +2853,7 @@ static void ironlake_fdi_disable(struct drm_crtc *crtc) } /* BPC in FDI rx is consistent with that in PIPECONF */ temp &= ~(0x07 << 16); - temp |= (I915_READ(PIPECONF(pipe)) & PIPE_BPC_MASK) << 11; + temp |= (I915_READ(PIPECONF(pipe)) & PIPECONF_BPC_MASK) << 11; I915_WRITE(reg, temp); POSTING_READ(reg); @@ -2909,10 +2864,12 @@ 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 (atomic_read(&dev_priv->mm.wedged)) + 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); @@ -2931,6 +2888,8 @@ static void intel_crtc_wait_for_pending_flips(struct drm_crtc *crtc) if (crtc->fb == NULL) return; + WARN_ON(waitqueue_active(&dev_priv->pending_flip_queue)); + wait_event(dev_priv->pending_flip_queue, !intel_crtc_has_pending_flip(crtc)); @@ -2974,6 +2933,8 @@ static void lpt_program_iclkip(struct drm_crtc *crtc) u32 divsel, phaseinc, auxdiv, phasedir = 0; u32 temp; + mutex_lock(&dev_priv->dpio_lock); + /* It is necessary to ungate the pixclk gate prior to programming * the divisors, and gate it back when it is done. */ @@ -3048,6 +3009,8 @@ static void lpt_program_iclkip(struct drm_crtc *crtc) udelay(24); I915_WRITE(PIXCLK_GATE, PIXCLK_GATE_UNGATE); + + mutex_unlock(&dev_priv->dpio_lock); } /* @@ -3128,7 +3091,7 @@ static void ironlake_pch_enable(struct drm_crtc *crtc) if (HAS_PCH_CPT(dev) && (intel_pipe_has_type(crtc, INTEL_OUTPUT_DISPLAYPORT) || intel_pipe_has_type(crtc, INTEL_OUTPUT_EDP))) { - u32 bpc = (I915_READ(PIPECONF(pipe)) & PIPE_BPC_MASK) >> 5; + u32 bpc = (I915_READ(PIPECONF(pipe)) & PIPECONF_BPC_MASK) >> 5; reg = TRANS_DP_CTL(pipe); temp = I915_READ(reg); temp &= ~(TRANS_DP_PORT_SEL_MASK | @@ -3602,7 +3565,7 @@ static void haswell_crtc_off(struct drm_crtc *crtc) /* Stop saying we're using TRANSCODER_EDP because some other CRTC might * start using it. */ - intel_crtc->cpu_transcoder = intel_crtc->pipe; + intel_crtc->cpu_transcoder = (enum transcoder) intel_crtc->pipe; intel_ddi_put_crtc_pll(crtc); } @@ -3625,6 +3588,30 @@ static void intel_crtc_dpms_overlay(struct intel_crtc *intel_crtc, bool enable) */ } +/** + * i9xx_fixup_plane - ugly workaround for G45 to fire up the hardware + * cursor plane briefly if not already running after enabling the display + * plane. + * This workaround avoids occasional blank screens when self refresh is + * enabled. + */ +static void +g4x_fixup_plane(struct drm_i915_private *dev_priv, enum pipe pipe) +{ + u32 cntl = I915_READ(CURCNTR(pipe)); + + if ((cntl & CURSOR_MODE) == 0) { + u32 fw_bcl_self = I915_READ(FW_BLC_SELF); + + I915_WRITE(FW_BLC_SELF, fw_bcl_self & ~FW_BLC_SELF_EN); + I915_WRITE(CURCNTR(pipe), CURSOR_MODE_64_ARGB_AX); + intel_wait_for_vblank(dev_priv->dev, pipe); + I915_WRITE(CURCNTR(pipe), cntl); + I915_WRITE(CURBASE(pipe), I915_READ(CURBASE(pipe))); + I915_WRITE(FW_BLC_SELF, fw_bcl_self); + } +} + static void i9xx_crtc_enable(struct drm_crtc *crtc) { struct drm_device *dev = crtc->dev; @@ -3643,8 +3630,15 @@ static void i9xx_crtc_enable(struct drm_crtc *crtc) intel_update_watermarks(dev); intel_enable_pll(dev_priv, pipe); + + for_each_encoder_on_crtc(dev, crtc, encoder) + if (encoder->pre_enable) + encoder->pre_enable(encoder); + intel_enable_pipe(dev_priv, pipe, false); intel_enable_plane(dev_priv, plane, pipe); + if (IS_G4X(dev)) + g4x_fixup_plane(dev_priv, pipe); intel_crtc_load_lut(crtc); intel_update_fbc(dev); @@ -3665,6 +3659,7 @@ static void i9xx_crtc_disable(struct drm_crtc *crtc) struct intel_encoder *encoder; int pipe = intel_crtc->pipe; int plane = intel_crtc->plane; + u32 pctl; if (!intel_crtc->active) @@ -3684,6 +3679,13 @@ static void i9xx_crtc_disable(struct drm_crtc *crtc) intel_disable_plane(dev_priv, plane, pipe); intel_disable_pipe(dev_priv, pipe); + + /* Disable pannel fitter if it is on this pipe. */ + pctl = I915_READ(PFIT_CONTROL); + if ((pctl & PFIT_ENABLE) && + ((pctl & PFIT_PIPE_MASK) >> PFIT_PIPE_SHIFT) == pipe) + I915_WRITE(PFIT_CONTROL, 0); + intel_disable_pll(dev_priv, pipe); intel_crtc->active = false; @@ -3750,19 +3752,17 @@ void intel_crtc_update_dpms(struct drm_crtc *crtc) intel_crtc_update_sarea(crtc, enable); } -static void intel_crtc_noop(struct drm_crtc *crtc) -{ -} - static void intel_crtc_disable(struct drm_crtc *crtc) { struct drm_device *dev = crtc->dev; struct drm_connector *connector; struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); /* crtc should still be enabled when we disable it. */ WARN_ON(!crtc->enabled); + intel_crtc->eld_vld = false; dev_priv->display.crtc_disable(crtc); intel_crtc_update_sarea(crtc, false); dev_priv->display.off(crtc); @@ -3800,10 +3800,6 @@ void intel_modeset_disable(struct drm_device *dev) } } -void intel_encoder_noop(struct drm_encoder *encoder) -{ -} - void intel_encoder_destroy(struct drm_encoder *encoder) { struct intel_encoder *intel_encoder = to_intel_encoder(encoder); @@ -3995,16 +3991,8 @@ static int i830_get_display_clock_speed(struct drm_device *dev) return 133000; } -struct fdi_m_n { - u32 tu; - u32 gmch_m; - u32 gmch_n; - u32 link_m; - u32 link_n; -}; - static void -fdi_reduce_ratio(u32 *num, u32 *den) +intel_reduce_ratio(uint32_t *num, uint32_t *den) { while (*num > 0xffffff || *den > 0xffffff) { *num >>= 1; @@ -4012,20 +4000,18 @@ fdi_reduce_ratio(u32 *num, u32 *den) } } -static void -ironlake_compute_m_n(int bits_per_pixel, int nlanes, int pixel_clock, - int link_clock, struct fdi_m_n *m_n) +void +intel_link_compute_m_n(int bits_per_pixel, int nlanes, + int pixel_clock, int link_clock, + struct intel_link_m_n *m_n) { - m_n->tu = 64; /* default size */ - - /* BUG_ON(pixel_clock > INT_MAX / 36); */ + m_n->tu = 64; m_n->gmch_m = bits_per_pixel * pixel_clock; m_n->gmch_n = link_clock * nlanes * 8; - fdi_reduce_ratio(&m_n->gmch_m, &m_n->gmch_n); - + intel_reduce_ratio(&m_n->gmch_m, &m_n->gmch_n); m_n->link_m = pixel_clock; m_n->link_n = link_clock; - fdi_reduce_ratio(&m_n->link_m, &m_n->link_n); + intel_reduce_ratio(&m_n->link_m, &m_n->link_n); } static inline bool intel_panel_use_ssc(struct drm_i915_private *dev_priv) @@ -4272,51 +4258,6 @@ static void i9xx_update_pll_dividers(struct drm_crtc *crtc, } } -static void intel_update_lvds(struct drm_crtc *crtc, intel_clock_t *clock, - struct drm_display_mode *adjusted_mode) -{ - struct drm_device *dev = crtc->dev; - struct drm_i915_private *dev_priv = dev->dev_private; - struct intel_crtc *intel_crtc = to_intel_crtc(crtc); - int pipe = intel_crtc->pipe; - u32 temp; - - temp = I915_READ(LVDS); - temp |= LVDS_PORT_EN | LVDS_A0A2_CLKA_POWER_UP; - if (pipe == 1) { - temp |= LVDS_PIPEB_SELECT; - } else { - temp &= ~LVDS_PIPEB_SELECT; - } - /* set the corresponsding LVDS_BORDER bit */ - temp |= dev_priv->lvds_border_bits; - /* Set the B0-B3 data pairs corresponding to whether we're going to - * set the DPLLs for dual-channel mode or not. - */ - if (clock->p2 == 7) - temp |= LVDS_B0B3_POWER_UP | LVDS_CLKB_POWER_UP; - else - temp &= ~(LVDS_B0B3_POWER_UP | LVDS_CLKB_POWER_UP); - - /* It would be nice to set 24 vs 18-bit mode (LVDS_A3_POWER_UP) - * appropriately here, but we need to look more thoroughly into how - * panels behave in the two modes. - */ - /* set the dithering flag on LVDS as needed */ - if (INTEL_INFO(dev)->gen >= 4) { - if (dev_priv->lvds_dither) - temp |= LVDS_ENABLE_DITHER; - else - temp &= ~LVDS_ENABLE_DITHER; - } - temp &= ~(LVDS_HSYNC_POLARITY | LVDS_VSYNC_POLARITY); - if (adjusted_mode->flags & DRM_MODE_FLAG_NHSYNC) - temp |= LVDS_HSYNC_POLARITY; - if (adjusted_mode->flags & DRM_MODE_FLAG_NVSYNC) - temp |= LVDS_VSYNC_POLARITY; - I915_WRITE(LVDS, temp); -} - static void vlv_update_pll(struct drm_crtc *crtc, struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode, @@ -4332,6 +4273,8 @@ static void vlv_update_pll(struct drm_crtc *crtc, bool is_sdvo; u32 temp; + mutex_lock(&dev_priv->dpio_lock); + is_sdvo = intel_pipe_has_type(crtc, INTEL_OUTPUT_SDVO) || intel_pipe_has_type(crtc, INTEL_OUTPUT_HDMI); @@ -4415,6 +4358,8 @@ static void vlv_update_pll(struct drm_crtc *crtc, temp |= (1 << 21); intel_dpio_write(dev_priv, DPIO_DATA_CHANNEL2, temp); } + + mutex_unlock(&dev_priv->dpio_lock); } static void i9xx_update_pll(struct drm_crtc *crtc, @@ -4426,6 +4371,7 @@ static void i9xx_update_pll(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); + struct intel_encoder *encoder; int pipe = intel_crtc->pipe; u32 dpll; bool is_sdvo; @@ -4494,12 +4440,9 @@ static void i9xx_update_pll(struct drm_crtc *crtc, POSTING_READ(DPLL(pipe)); udelay(150); - /* The LVDS pin pair needs to be on before the DPLLs are enabled. - * This is an exception to the general rule that mode_set doesn't turn - * things on. - */ - if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)) - intel_update_lvds(crtc, clock, adjusted_mode); + for_each_encoder_on_crtc(dev, crtc, encoder) + if (encoder->pre_pll_enable) + encoder->pre_pll_enable(encoder); if (intel_pipe_has_type(crtc, INTEL_OUTPUT_DISPLAYPORT)) intel_dp_set_m_n(crtc, mode, adjusted_mode); @@ -4538,6 +4481,7 @@ static void i8xx_update_pll(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); + struct intel_encoder *encoder; int pipe = intel_crtc->pipe; u32 dpll; @@ -4571,12 +4515,9 @@ static void i8xx_update_pll(struct drm_crtc *crtc, POSTING_READ(DPLL(pipe)); udelay(150); - /* The LVDS pin pair needs to be on before the DPLLs are enabled. - * This is an exception to the general rule that mode_set doesn't turn - * things on. - */ - if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)) - intel_update_lvds(crtc, clock, adjusted_mode); + for_each_encoder_on_crtc(dev, crtc, encoder) + if (encoder->pre_pll_enable) + encoder->pre_pll_enable(encoder); I915_WRITE(DPLL(pipe), dpll); @@ -4766,10 +4707,10 @@ static int i9xx_crtc_mode_set(struct drm_crtc *crtc, } /* default to 8bpc */ - pipeconf &= ~(PIPECONF_BPP_MASK | PIPECONF_DITHER_EN); + pipeconf &= ~(PIPECONF_BPC_MASK | PIPECONF_DITHER_EN); if (is_dp) { if (adjusted_mode->private_flags & INTEL_MODE_DP_FORCE_6BPC) { - pipeconf |= PIPECONF_BPP_6 | + pipeconf |= PIPECONF_6BPC | PIPECONF_DITHER_EN | PIPECONF_DITHER_TYPE_SP; } @@ -4777,7 +4718,7 @@ static int i9xx_crtc_mode_set(struct drm_crtc *crtc, if (IS_VALLEYVIEW(dev) && intel_pipe_has_type(crtc, INTEL_OUTPUT_EDP)) { if (adjusted_mode->private_flags & INTEL_MODE_DP_FORCE_6BPC) { - pipeconf |= PIPECONF_BPP_6 | + pipeconf |= PIPECONF_6BPC | PIPECONF_ENABLE | I965_PIPECONF_ACTIVE; } @@ -4964,6 +4905,8 @@ static void lpt_init_pch_refclk(struct drm_device *dev) if (!has_vga) return; + mutex_lock(&dev_priv->dpio_lock); + /* XXX: Rip out SDV support once Haswell ships for real. */ if (IS_HASWELL(dev) && (dev->pci_device & 0xFF00) == 0x0C00) is_sdv = true; @@ -5106,6 +5049,8 @@ static void lpt_init_pch_refclk(struct drm_device *dev) tmp = intel_sbi_read(dev_priv, SBI_DBUFF0, SBI_ICLK); tmp |= SBI_DBUFF0_ENABLE; intel_sbi_write(dev_priv, SBI_DBUFF0, tmp, SBI_ICLK); + + mutex_unlock(&dev_priv->dpio_lock); } /* @@ -5160,19 +5105,19 @@ static void ironlake_set_pipeconf(struct drm_crtc *crtc, val = I915_READ(PIPECONF(pipe)); - val &= ~PIPE_BPC_MASK; + val &= ~PIPECONF_BPC_MASK; switch (intel_crtc->bpp) { case 18: - val |= PIPE_6BPC; + val |= PIPECONF_6BPC; break; case 24: - val |= PIPE_8BPC; + val |= PIPECONF_8BPC; break; case 30: - val |= PIPE_10BPC; + val |= PIPECONF_10BPC; break; case 36: - val |= PIPE_12BPC; + val |= PIPECONF_12BPC; break; default: /* Case prevented by intel_choose_pipe_bpp_dither. */ @@ -5189,10 +5134,80 @@ static void ironlake_set_pipeconf(struct drm_crtc *crtc, else val |= PIPECONF_PROGRESSIVE; + if (adjusted_mode->private_flags & INTEL_MODE_LIMITED_COLOR_RANGE) + val |= PIPECONF_COLOR_RANGE_SELECT; + else + val &= ~PIPECONF_COLOR_RANGE_SELECT; + I915_WRITE(PIPECONF(pipe), val); POSTING_READ(PIPECONF(pipe)); } +/* + * Set up the pipe CSC unit. + * + * Currently only full range RGB to limited range RGB conversion + * is supported, but eventually this should handle various + * RGB<->YCbCr scenarios as well. + */ +static void intel_set_pipe_csc(struct drm_crtc *crtc, + const struct drm_display_mode *adjusted_mode) +{ + struct drm_device *dev = crtc->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + int pipe = intel_crtc->pipe; + uint16_t coeff = 0x7800; /* 1.0 */ + + /* + * TODO: Check what kind of values actually come out of the pipe + * with these coeff/postoff values and adjust to get the best + * accuracy. Perhaps we even need to take the bpc value into + * consideration. + */ + + if (adjusted_mode->private_flags & INTEL_MODE_LIMITED_COLOR_RANGE) + coeff = ((235 - 16) * (1 << 12) / 255) & 0xff8; /* 0.xxx... */ + + /* + * GY/GU and RY/RU should be the other way around according + * to BSpec, but reality doesn't agree. Just set them up in + * a way that results in the correct picture. + */ + I915_WRITE(PIPE_CSC_COEFF_RY_GY(pipe), coeff << 16); + I915_WRITE(PIPE_CSC_COEFF_BY(pipe), 0); + + I915_WRITE(PIPE_CSC_COEFF_RU_GU(pipe), coeff); + I915_WRITE(PIPE_CSC_COEFF_BU(pipe), 0); + + I915_WRITE(PIPE_CSC_COEFF_RV_GV(pipe), 0); + I915_WRITE(PIPE_CSC_COEFF_BV(pipe), coeff << 16); + + I915_WRITE(PIPE_CSC_PREOFF_HI(pipe), 0); + I915_WRITE(PIPE_CSC_PREOFF_ME(pipe), 0); + I915_WRITE(PIPE_CSC_PREOFF_LO(pipe), 0); + + if (INTEL_INFO(dev)->gen > 6) { + uint16_t postoff = 0; + + if (adjusted_mode->private_flags & INTEL_MODE_LIMITED_COLOR_RANGE) + postoff = (16 * (1 << 13) / 255) & 0x1fff; + + I915_WRITE(PIPE_CSC_POSTOFF_HI(pipe), postoff); + I915_WRITE(PIPE_CSC_POSTOFF_ME(pipe), postoff); + I915_WRITE(PIPE_CSC_POSTOFF_LO(pipe), postoff); + + I915_WRITE(PIPE_CSC_MODE(pipe), 0); + } else { + uint32_t mode = CSC_MODE_YUV_TO_RGB; + + if (adjusted_mode->private_flags & INTEL_MODE_LIMITED_COLOR_RANGE) + mode |= CSC_BLACK_SCREEN_OFFSET; + + I915_WRITE(PIPE_CSC_MODE(pipe), mode); + } +} + static void haswell_set_pipeconf(struct drm_crtc *crtc, struct drm_display_mode *adjusted_mode, bool dither) @@ -5383,7 +5398,7 @@ static void ironlake_set_m_n(struct drm_crtc *crtc, struct intel_crtc *intel_crtc = to_intel_crtc(crtc); enum transcoder cpu_transcoder = intel_crtc->cpu_transcoder; struct intel_encoder *intel_encoder, *edp_encoder = NULL; - struct fdi_m_n m_n = {0}; + struct intel_link_m_n m_n = {0}; int target_clock, pixel_multiplier, lane, link_bw; bool is_dp = false, is_cpu_edp = false; @@ -5435,8 +5450,7 @@ static void ironlake_set_m_n(struct drm_crtc *crtc, if (pixel_multiplier > 1) link_bw *= pixel_multiplier; - ironlake_compute_m_n(intel_crtc->bpp, lane, target_clock, link_bw, - &m_n); + intel_link_compute_m_n(intel_crtc->bpp, lane, target_clock, link_bw, &m_n); I915_WRITE(PIPE_DATA_M1(cpu_transcoder), TU_SIZE(m_n.tu) | m_n.gmch_m); I915_WRITE(PIPE_DATA_N1(cpu_transcoder), m_n.gmch_n); @@ -5489,7 +5503,7 @@ static uint32_t ironlake_compute_dpll(struct intel_crtc *intel_crtc, if (is_lvds) { if ((intel_panel_use_ssc(dev_priv) && dev_priv->lvds_ssc_freq == 100) || - (I915_READ(PCH_LVDS) & LVDS_CLKB_POWER_MASK) == LVDS_CLKB_POWER_UP) + intel_is_dual_link_lvds(dev)) factor = 25; } else if (is_sdvo && is_tv) factor = 20; @@ -5564,7 +5578,6 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc, bool ok, has_reduced_clock = false; bool is_lvds = false, is_dp = false, is_cpu_edp = false; struct intel_encoder *encoder; - u32 temp; int ret; bool dither, fdi_config_ok; @@ -5628,54 +5641,12 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc, } else intel_put_pch_pll(intel_crtc); - /* The LVDS pin pair needs to be on before the DPLLs are enabled. - * This is an exception to the general rule that mode_set doesn't turn - * things on. - */ - if (is_lvds) { - temp = I915_READ(PCH_LVDS); - temp |= LVDS_PORT_EN | LVDS_A0A2_CLKA_POWER_UP; - if (HAS_PCH_CPT(dev)) { - temp &= ~PORT_TRANS_SEL_MASK; - temp |= PORT_TRANS_SEL_CPT(pipe); - } else { - if (pipe == 1) - temp |= LVDS_PIPEB_SELECT; - else - temp &= ~LVDS_PIPEB_SELECT; - } + if (is_dp && !is_cpu_edp) + intel_dp_set_m_n(crtc, mode, adjusted_mode); - /* set the corresponsding LVDS_BORDER bit */ - temp |= dev_priv->lvds_border_bits; - /* Set the B0-B3 data pairs corresponding to whether we're going to - * set the DPLLs for dual-channel mode or not. - */ - if (clock.p2 == 7) - temp |= LVDS_B0B3_POWER_UP | LVDS_CLKB_POWER_UP; - else - temp &= ~(LVDS_B0B3_POWER_UP | LVDS_CLKB_POWER_UP); - - /* It would be nice to set 24 vs 18-bit mode (LVDS_A3_POWER_UP) - * appropriately here, but we need to look more thoroughly into how - * panels behave in the two modes. - */ - temp &= ~(LVDS_HSYNC_POLARITY | LVDS_VSYNC_POLARITY); - if (adjusted_mode->flags & DRM_MODE_FLAG_NHSYNC) - temp |= LVDS_HSYNC_POLARITY; - if (adjusted_mode->flags & DRM_MODE_FLAG_NVSYNC) - temp |= LVDS_VSYNC_POLARITY; - I915_WRITE(PCH_LVDS, temp); - } - - if (is_dp && !is_cpu_edp) { - intel_dp_set_m_n(crtc, mode, adjusted_mode); - } else { - /* For non-DP output, clear any trans DP clock recovery setting.*/ - I915_WRITE(TRANSDATA_M1(pipe), 0); - I915_WRITE(TRANSDATA_N1(pipe), 0); - I915_WRITE(TRANSDPLINK_M1(pipe), 0); - I915_WRITE(TRANSDPLINK_N1(pipe), 0); - } + for_each_encoder_on_crtc(dev, crtc, encoder) + if (encoder->pre_pll_enable) + encoder->pre_pll_enable(encoder); if (intel_crtc->pch_pll) { I915_WRITE(intel_crtc->pch_pll->pll_reg, dpll); @@ -5710,9 +5681,6 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc, fdi_config_ok = ironlake_check_fdi_lanes(intel_crtc); - if (is_cpu_edp) - ironlake_set_pll_edp(crtc, adjusted_mode->clock); - ironlake_set_pipeconf(crtc, adjusted_mode, dither); intel_wait_for_vblank(dev, pipe); @@ -5730,6 +5698,35 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc, return fdi_config_ok ? ret : -EINVAL; } +static void haswell_modeset_global_resources(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + bool enable = false; + struct intel_crtc *crtc; + struct intel_encoder *encoder; + + list_for_each_entry(crtc, &dev->mode_config.crtc_list, base.head) { + if (crtc->pipe != PIPE_A && crtc->base.enabled) + enable = true; + /* XXX: Should check for edp transcoder here, but thanks to init + * sequence that's not yet available. Just in case desktop eDP + * on PORT D is possible on haswell, too. */ + } + + list_for_each_entry(encoder, &dev->mode_config.encoder_list, + base.head) { + if (encoder->type != INTEL_OUTPUT_EDP && + encoder->connectors_active) + enable = true; + } + + /* Even the eDP panel fitter is outside the always-on well. */ + if (dev_priv->pch_pf_size) + enable = true; + + intel_set_power_well(dev, enable); +} + static int haswell_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode, @@ -5742,20 +5739,13 @@ static int haswell_crtc_mode_set(struct drm_crtc *crtc, int pipe = intel_crtc->pipe; int plane = intel_crtc->plane; int num_connectors = 0; - intel_clock_t clock, reduced_clock; - u32 dpll = 0, fp = 0, fp2 = 0; - bool ok, has_reduced_clock = false; - bool is_lvds = false, is_dp = false, is_cpu_edp = false; + bool is_dp = false, is_cpu_edp = false; struct intel_encoder *encoder; - u32 temp; int ret; bool dither; for_each_encoder_on_crtc(dev, crtc, encoder) { switch (encoder->type) { - case INTEL_OUTPUT_LVDS: - is_lvds = true; - break; case INTEL_OUTPUT_DISPLAYPORT: is_dp = true; break; @@ -5789,147 +5779,32 @@ static int haswell_crtc_mode_set(struct drm_crtc *crtc, if (!intel_ddi_pll_mode_set(crtc, adjusted_mode->clock)) return -EINVAL; - if (HAS_PCH_IBX(dev) || HAS_PCH_CPT(dev)) { - ok = ironlake_compute_clocks(crtc, adjusted_mode, &clock, - &has_reduced_clock, - &reduced_clock); - if (!ok) { - DRM_ERROR("Couldn't find PLL settings for mode!\n"); - return -EINVAL; - } - } - /* Ensure that the cursor is valid for the new mode before changing... */ // intel_crtc_update_cursor(crtc, true); /* determine panel color depth */ dither = intel_choose_pipe_bpp_dither(crtc, fb, &intel_crtc->bpp, adjusted_mode); - if (is_lvds && dev_priv->lvds_dither) - dither = true; DRM_DEBUG_KMS("Mode for pipe %d:\n", pipe); drm_mode_debug_printmodeline(mode); - if (HAS_PCH_IBX(dev) || HAS_PCH_CPT(dev)) { - fp = clock.n << 16 | clock.m1 << 8 | clock.m2; - if (has_reduced_clock) - fp2 = reduced_clock.n << 16 | reduced_clock.m1 << 8 | - reduced_clock.m2; - - dpll = ironlake_compute_dpll(intel_crtc, adjusted_mode, &clock, - fp); - - /* CPU eDP is the only output that doesn't need a PCH PLL of its - * own on pre-Haswell/LPT generation */ - if (!is_cpu_edp) { - struct intel_pch_pll *pll; - - pll = intel_get_pch_pll(intel_crtc, dpll, fp); - if (pll == NULL) { - DRM_DEBUG_DRIVER("failed to find PLL for pipe %d\n", - pipe); - return -EINVAL; - } - } else - intel_put_pch_pll(intel_crtc); - - /* The LVDS pin pair needs to be on before the DPLLs are - * enabled. This is an exception to the general rule that - * mode_set doesn't turn things on. - */ - if (is_lvds) { - temp = I915_READ(PCH_LVDS); - temp |= LVDS_PORT_EN | LVDS_A0A2_CLKA_POWER_UP; - if (HAS_PCH_CPT(dev)) { - temp &= ~PORT_TRANS_SEL_MASK; - temp |= PORT_TRANS_SEL_CPT(pipe); - } else { - if (pipe == 1) - temp |= LVDS_PIPEB_SELECT; - else - temp &= ~LVDS_PIPEB_SELECT; - } - - /* set the corresponsding LVDS_BORDER bit */ - temp |= dev_priv->lvds_border_bits; - /* Set the B0-B3 data pairs corresponding to whether - * we're going to set the DPLLs for dual-channel mode or - * not. - */ - if (clock.p2 == 7) - temp |= LVDS_B0B3_POWER_UP | LVDS_CLKB_POWER_UP; - else - temp &= ~(LVDS_B0B3_POWER_UP | - LVDS_CLKB_POWER_UP); - - /* It would be nice to set 24 vs 18-bit mode - * (LVDS_A3_POWER_UP) appropriately here, but we need to - * look more thoroughly into how panels behave in the - * two modes. - */ - temp &= ~(LVDS_HSYNC_POLARITY | LVDS_VSYNC_POLARITY); - if (adjusted_mode->flags & DRM_MODE_FLAG_NHSYNC) - temp |= LVDS_HSYNC_POLARITY; - if (adjusted_mode->flags & DRM_MODE_FLAG_NVSYNC) - temp |= LVDS_VSYNC_POLARITY; - I915_WRITE(PCH_LVDS, temp); - } - } - - if (is_dp && !is_cpu_edp) { + if (is_dp && !is_cpu_edp) intel_dp_set_m_n(crtc, mode, adjusted_mode); - } else { - if (HAS_PCH_IBX(dev) || HAS_PCH_CPT(dev)) { - /* For non-DP output, clear any trans DP clock recovery - * setting.*/ - I915_WRITE(TRANSDATA_M1(pipe), 0); - I915_WRITE(TRANSDATA_N1(pipe), 0); - I915_WRITE(TRANSDPLINK_M1(pipe), 0); - I915_WRITE(TRANSDPLINK_N1(pipe), 0); - } - } intel_crtc->lowfreq_avail = false; - if (HAS_PCH_IBX(dev) || HAS_PCH_CPT(dev)) { - if (intel_crtc->pch_pll) { - I915_WRITE(intel_crtc->pch_pll->pll_reg, dpll); - - /* Wait for the clocks to stabilize. */ - POSTING_READ(intel_crtc->pch_pll->pll_reg); - udelay(150); - - /* The pixel multiplier can only be updated once the - * DPLL is enabled and the clocks are stable. - * - * So write it again. - */ - I915_WRITE(intel_crtc->pch_pll->pll_reg, dpll); - } - - if (intel_crtc->pch_pll) { - if (is_lvds && has_reduced_clock && i915_powersave) { - I915_WRITE(intel_crtc->pch_pll->fp1_reg, fp2); - intel_crtc->lowfreq_avail = true; - } else { - I915_WRITE(intel_crtc->pch_pll->fp1_reg, fp); - } - } - } intel_set_pipe_timings(intel_crtc, mode, adjusted_mode); if (!is_dp || is_cpu_edp) ironlake_set_m_n(crtc, mode, adjusted_mode); - if (HAS_PCH_IBX(dev) || HAS_PCH_CPT(dev)) - if (is_cpu_edp) - ironlake_set_pll_edp(crtc, adjusted_mode->clock); - haswell_set_pipeconf(crtc, adjusted_mode, dither); + intel_set_pipe_csc(crtc, adjusted_mode); + /* Set up the display plane register */ - I915_WRITE(DSPCNTR(plane), DISPPLANE_GAMMA_ENABLE); + I915_WRITE(DSPCNTR(plane), DISPPLANE_GAMMA_ENABLE | DISPPLANE_PIPE_CSC_ENABLE); POSTING_READ(DSPCNTR(plane)); ret = intel_pipe_set_base(crtc, x, y, fb); @@ -6051,6 +5926,7 @@ static void haswell_write_eld(struct drm_connector *connector, struct drm_i915_private *dev_priv = connector->dev->dev_private; uint8_t *eld = connector->eld; struct drm_device *dev = crtc->dev; + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); uint32_t eldv; uint32_t i; int len; @@ -6092,6 +5968,7 @@ static void haswell_write_eld(struct drm_connector *connector, DRM_DEBUG_DRIVER("ELD on pipe %c\n", pipe_name(pipe)); eldv = AUDIO_ELD_VALID_A << (pipe * 4); + intel_crtc->eld_vld = true; if (intel_pipe_has_type(crtc, INTEL_OUTPUT_DISPLAYPORT)) { DRM_DEBUG_DRIVER("ELD: DisplayPort detected\n"); @@ -6328,6 +6205,8 @@ static void ivb_update_cursor(struct drm_crtc *crtc, u32 base) cntl &= ~(CURSOR_MODE | MCURSOR_GAMMA_ENABLE); cntl |= CURSOR_MODE_DISABLE; } + if (IS_HASWELL(dev)) + cntl |= CURSOR_PIPE_CSC_ENABLE; I915_WRITE(CURCNTR_IVB(pipe), cntl); intel_crtc->cursor_visible = visible; @@ -6685,6 +6564,8 @@ bool intel_get_load_detect_pipe(struct drm_connector *connector, if (encoder->crtc) { crtc = encoder->crtc; + mutex_lock(&crtc->mutex); + old->dpms_mode = connector->dpms; old->load_detect_temp = false; @@ -6714,6 +6595,7 @@ bool intel_get_load_detect_pipe(struct drm_connector *connector, return false; } + mutex_lock(&crtc->mutex); intel_encoder->new_crtc = to_intel_crtc(crtc); to_intel_connector(connector)->new_encoder = intel_encoder; @@ -6741,13 +6623,15 @@ bool intel_get_load_detect_pipe(struct drm_connector *connector, DRM_DEBUG_KMS("reusing fbdev for load-detection framebuffer\n"); if (IS_ERR(fb)) { DRM_DEBUG_KMS("failed to allocate framebuffer for load-detection\n"); + mutex_unlock(&crtc->mutex); return false; } - if (!intel_set_mode(crtc, mode, 0, 0, fb)) { + if (intel_set_mode(crtc, mode, 0, 0, fb)) { DRM_DEBUG_KMS("failed to set mode on load-detect pipe\n"); if (old->release_fb) old->release_fb->funcs->destroy(old->release_fb); + mutex_unlock(&crtc->mutex); return false; } @@ -6762,27 +6646,31 @@ void intel_release_load_detect_pipe(struct drm_connector *connector, struct intel_encoder *intel_encoder = intel_attached_encoder(connector); struct drm_encoder *encoder = &intel_encoder->base; + struct drm_crtc *crtc = encoder->crtc; DRM_DEBUG_KMS("[CONNECTOR:%d:%s], [ENCODER:%d:%s]\n", connector->base.id, drm_get_connector_name(connector), encoder->base.id, drm_get_encoder_name(encoder)); if (old->load_detect_temp) { - struct drm_crtc *crtc = encoder->crtc; - to_intel_connector(connector)->new_encoder = NULL; intel_encoder->new_crtc = NULL; intel_set_mode(crtc, NULL, 0, 0, NULL); - if (old->release_fb) - old->release_fb->funcs->destroy(old->release_fb); + if (old->release_fb) { + drm_framebuffer_unregister_private(old->release_fb); + drm_framebuffer_unreference(old->release_fb); + } + mutex_unlock(&crtc->mutex); return; } /* Switch crtc and encoder back off if necessary */ if (old->dpms_mode != DRM_MODE_DPMS_ON) connector->funcs->dpms(connector, old->dpms_mode); + + mutex_unlock(&crtc->mutex); } /* Returns the clock of the currently programmed mode of the given pipe. */ @@ -6978,6 +6866,17 @@ void intel_mark_busy(struct drm_device *dev) void intel_mark_idle(struct drm_device *dev) { + struct drm_crtc *crtc; + + if (!i915_powersave) + return; + + list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { + if (!crtc->fb) + continue; + + intel_decrease_pllclock(crtc); + } } void intel_mark_fb_busy(struct drm_i915_gem_object *obj) @@ -6985,8 +6884,6 @@ void intel_mark_fb_busy(struct drm_i915_gem_object *obj) struct drm_device *dev = obj->base.dev; struct drm_crtc *crtc; - ENTER(); - if (!i915_powersave) return; @@ -6999,23 +6896,6 @@ void intel_mark_fb_busy(struct drm_i915_gem_object *obj) } } -void intel_mark_fb_idle(struct drm_i915_gem_object *obj) -{ - struct drm_device *dev = obj->base.dev; - struct drm_crtc *crtc; - - if (!i915_powersave) - return; - - list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { - if (!crtc->fb) - continue; - - if (to_intel_framebuffer(crtc->fb)->obj == obj) - intel_decrease_pllclock(crtc); - } -} - static void intel_crtc_destroy(struct drm_crtc *crtc) { struct intel_crtc *intel_crtc = to_intel_crtc(crtc); @@ -7097,9 +6977,7 @@ static void do_intel_finish_page_flip(struct drm_device *dev, obj = work->old_fb_obj; - atomic_clear_mask(1 << intel_crtc->plane, - &obj->pending_flip.counter); - wake_up(&dev_priv->pending_flip_queue); + wake_up_all(&dev_priv->pending_flip_queue); queue_work(dev_priv->wq, &work->work); @@ -7395,8 +7273,8 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc, { struct drm_device *dev = crtc->dev; struct drm_i915_private *dev_priv = dev->dev_private; - struct intel_framebuffer *intel_fb; - struct drm_i915_gem_object *obj; + struct drm_framebuffer *old_fb = crtc->fb; + struct drm_i915_gem_object *obj = to_intel_framebuffer(fb)->obj; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); struct intel_unpin_work *work; unsigned long flags; @@ -7421,8 +7299,7 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc, work->event = event; work->crtc = crtc; - intel_fb = to_intel_framebuffer(crtc->fb); - work->old_fb_obj = intel_fb->obj; + work->old_fb_obj = to_intel_framebuffer(old_fb)->obj; INIT_WORK(&work->work, intel_unpin_work_fn); ret = drm_vblank_get(dev, intel_crtc->pipe); @@ -7442,9 +7319,6 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc, intel_crtc->unpin_work = work; spin_unlock_irqrestore(&dev->event_lock, flags); - intel_fb = to_intel_framebuffer(fb); - obj = intel_fb->obj; - if (atomic_read(&intel_crtc->unpin_work_count) >= 2) flush_workqueue(dev_priv->wq); @@ -7462,11 +7336,8 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc, work->enable_stall_check = true; - /* Block clients from rendering to the new back buffer until - * the flip occurs and the object is no longer visible. - */ - atomic_add(1 << intel_crtc->plane, &work->old_fb_obj->pending_flip); atomic_inc(&intel_crtc->unpin_work_count); + intel_crtc->reset_counter = atomic_read(&dev_priv->gpu_error.reset_counter); ret = dev_priv->display.queue_flip(dev, crtc, fb, obj); if (ret) @@ -7482,7 +7353,7 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc, cleanup_pending: atomic_dec(&intel_crtc->unpin_work_count); - atomic_sub(1 << intel_crtc->plane, &work->old_fb_obj->pending_flip); + crtc->fb = old_fb; drm_gem_object_unreference(&work->old_fb_obj->base); drm_gem_object_unreference(&obj->base); mutex_unlock(&dev->struct_mutex); @@ -7504,7 +7375,6 @@ free_work: static struct drm_crtc_helper_funcs intel_helper_funcs = { .mode_set_base_atomic = intel_pipe_set_base_atomic, .load_lut = intel_crtc_load_lut, - .disable = intel_crtc_noop, }; bool intel_encoder_check_is_cloned(struct intel_encoder *encoder) @@ -7894,16 +7764,21 @@ intel_modeset_check_state(struct drm_device *dev) } } -bool intel_set_mode(struct drm_crtc *crtc, +int intel_set_mode(struct drm_crtc *crtc, struct drm_display_mode *mode, int x, int y, struct drm_framebuffer *fb) { struct drm_device *dev = crtc->dev; drm_i915_private_t *dev_priv = dev->dev_private; - struct drm_display_mode *adjusted_mode, saved_mode, saved_hwmode; + struct drm_display_mode *adjusted_mode, *saved_mode, *saved_hwmode; struct intel_crtc *intel_crtc; unsigned disable_pipes, prepare_pipes, modeset_pipes; - bool ret = true; + int ret = 0; + + saved_mode = kmalloc(2 * sizeof(*saved_mode), GFP_KERNEL); + if (!saved_mode) + return -ENOMEM; + saved_hwmode = saved_mode + 1; intel_modeset_affected_pipes(crtc, &modeset_pipes, &prepare_pipes, &disable_pipes); @@ -7914,8 +7789,8 @@ bool intel_set_mode(struct drm_crtc *crtc, for_each_intel_crtc_masked(dev, disable_pipes, intel_crtc) intel_crtc_disable(&intel_crtc->base); - saved_hwmode = crtc->hwmode; - saved_mode = crtc->mode; + *saved_hwmode = crtc->hwmode; + *saved_mode = crtc->mode; /* Hack: Because we don't (yet) support global modeset on multiple * crtcs, we don't keep track of the new mode for more than one crtc. @@ -7926,7 +7801,8 @@ bool intel_set_mode(struct drm_crtc *crtc, if (modeset_pipes) { adjusted_mode = intel_modeset_adjusted_mode(crtc, mode); if (IS_ERR(adjusted_mode)) { - return false; + ret = PTR_ERR(adjusted_mode); + goto out; } } @@ -7952,10 +7828,10 @@ bool intel_set_mode(struct drm_crtc *crtc, * on the DPLL. */ for_each_intel_crtc_masked(dev, modeset_pipes, intel_crtc) { - ret = !intel_crtc_mode_set(&intel_crtc->base, + ret = intel_crtc_mode_set(&intel_crtc->base, mode, adjusted_mode, x, y, fb); - if (!ret) + if (ret) goto done; } @@ -7977,16 +7853,23 @@ bool intel_set_mode(struct drm_crtc *crtc, /* FIXME: add subpixel order */ done: drm_mode_destroy(dev, adjusted_mode); - if (!ret && crtc->enabled) { - crtc->hwmode = saved_hwmode; - crtc->mode = saved_mode; + if (ret && crtc->enabled) { + crtc->hwmode = *saved_hwmode; + crtc->mode = *saved_mode; } else { intel_modeset_check_state(dev); } +out: + kfree(saved_mode); return ret; } +void intel_crtc_restore_mode(struct drm_crtc *crtc) +{ + intel_set_mode(crtc, &crtc->mode, crtc->x, crtc->y, crtc->fb); +} + #undef for_each_intel_crtc_masked static void intel_set_config_free(struct intel_set_config *config) @@ -8099,7 +7982,7 @@ intel_modeset_stage_output_state(struct drm_device *dev, struct intel_encoder *encoder; int count, ro; - /* The upper layers ensure that we either disabl a crtc or have a list + /* The upper layers ensure that we either disable a crtc or have a list * of connectors. For paranoia, double-check this. */ WARN_ON(!set->fb && (set->num_connectors != 0)); WARN_ON(set->fb && (set->num_connectors == 0)); @@ -8201,14 +8084,9 @@ static int intel_crtc_set_config(struct drm_mode_set *set) BUG_ON(!set->crtc); BUG_ON(!set->crtc->helper_private); - if (!set->mode) - set->fb = NULL; - - /* The fb helper likes to play gross jokes with ->mode_set_config. - * Unfortunately the crtc helper doesn't do much at all for this case, - * so we have to cope with this madness until the fb helper is fixed up. */ - if (set->fb && set->num_connectors == 0) - return 0; + /* Enforce sane interface api - has been abused by the fb helper. */ + BUG_ON(!set->mode && set->fb); + BUG_ON(set->fb && set->num_connectors == 0); if (set->fb) { DRM_DEBUG_KMS("[CRTC:%d] [FB:%d] #connectors=%d (x y) (%i %i)\n", @@ -8252,11 +8130,11 @@ static int intel_crtc_set_config(struct drm_mode_set *set) drm_mode_debug_printmodeline(set->mode); } - if (!intel_set_mode(set->crtc, set->mode, - set->x, set->y, set->fb)) { - DRM_ERROR("failed to set mode on [CRTC:%d]\n", - set->crtc->base.id); - ret = -EINVAL; + ret = intel_set_mode(set->crtc, set->mode, + set->x, set->y, set->fb); + if (ret) { + DRM_ERROR("failed to set mode on [CRTC:%d], err = %d\n", + set->crtc->base.id, ret); goto fail; } } else if (config->fb_changed) { @@ -8273,7 +8151,7 @@ fail: /* Try to restore the config */ if (config->mode_changed && - !intel_set_mode(save_set.crtc, save_set.mode, + intel_set_mode(save_set.crtc, save_set.mode, save_set.x, save_set.y, save_set.fb)) DRM_ERROR("failed to restore config after modeset failure\n"); @@ -8293,7 +8171,7 @@ static const struct drm_crtc_funcs intel_crtc_funcs = { static void intel_cpu_pll_init(struct drm_device *dev) { - if (IS_HASWELL(dev)) + if (HAS_DDI(dev)) intel_ddi_pll_init(dev); } @@ -8426,11 +8304,10 @@ static void intel_setup_outputs(struct drm_device *dev) I915_WRITE(PFIT_CONTROL, 0); } - if (!(IS_HASWELL(dev) && - (I915_READ(DDI_BUF_CTL(PORT_A)) & DDI_A_4_LANES))) + if (!(HAS_DDI(dev) && (I915_READ(DDI_BUF_CTL(PORT_A)) & DDI_A_4_LANES))) intel_crt_init(dev); - if (IS_HASWELL(dev)) { + if (HAS_DDI(dev)) { int found; /* Haswell uses DDI functions to detect digital outputs */ @@ -8477,23 +8354,18 @@ static void intel_setup_outputs(struct drm_device *dev) if (I915_READ(PCH_DP_D) & DP_DETECTED) intel_dp_init(dev, PCH_DP_D, PORT_D); } else if (IS_VALLEYVIEW(dev)) { - int found; - /* Check for built-in panel first. Shares lanes with HDMI on SDVOC */ - if (I915_READ(DP_C) & DP_DETECTED) - intel_dp_init(dev, DP_C, PORT_C); + if (I915_READ(VLV_DISPLAY_BASE + DP_C) & DP_DETECTED) + intel_dp_init(dev, VLV_DISPLAY_BASE + DP_C, PORT_C); - if (I915_READ(SDVOB) & PORT_DETECTED) { - /* SDVOB multiplex with HDMIB */ - found = intel_sdvo_init(dev, SDVOB, true); - if (!found) - intel_hdmi_init(dev, SDVOB, PORT_B); - if (!found && (I915_READ(DP_B) & DP_DETECTED)) - intel_dp_init(dev, DP_B, PORT_B); + if (I915_READ(VLV_DISPLAY_BASE + SDVOB) & PORT_DETECTED) { + intel_hdmi_init(dev, VLV_DISPLAY_BASE + SDVOB, PORT_B); + if (I915_READ(VLV_DISPLAY_BASE + DP_B) & DP_DETECTED) + intel_dp_init(dev, VLV_DISPLAY_BASE + DP_B, PORT_B); } - if (I915_READ(SDVOC) & PORT_DETECTED) - intel_hdmi_init(dev, SDVOC, PORT_C); + if (I915_READ(VLV_DISPLAY_BASE + SDVOC) & PORT_DETECTED) + intel_hdmi_init(dev, VLV_DISPLAY_BASE + SDVOC, PORT_C); } else if (SUPPORTS_DIGITAL_OUTPUTS(dev)) { bool found = false; @@ -8635,21 +8507,22 @@ int intel_framebuffer_init(struct drm_device *dev, if (mode_cmd->offsets[0] != 0) return -EINVAL; + drm_helper_mode_fill_fb_struct(&intel_fb->base, mode_cmd); + intel_fb->obj = obj; + ret = drm_framebuffer_init(dev, &intel_fb->base, &intel_fb_funcs); if (ret) { DRM_ERROR("framebuffer init failed %d\n", ret); return ret; } - drm_helper_mode_fill_fb_struct(&intel_fb->base, mode_cmd); - intel_fb->obj = obj; return 0; } static const struct drm_mode_config_funcs intel_mode_funcs = { .fb_create = NULL /*intel_user_framebuffer_create*/, - .output_poll_changed = NULL /*intel_fb_output_poll_changed*/, + .output_poll_changed = intel_fb_output_poll_changed, }; /* Set up chip specific display functions */ @@ -8658,7 +8531,7 @@ static void intel_init_display(struct drm_device *dev) struct drm_i915_private *dev_priv = dev->dev_private; /* We always want a DPMS function */ - if (IS_HASWELL(dev)) { + if (HAS_DDI(dev)) { dev_priv->display.crtc_mode_set = haswell_crtc_mode_set; dev_priv->display.crtc_enable = haswell_crtc_enable; dev_priv->display.crtc_disable = haswell_crtc_disable; @@ -8720,8 +8593,9 @@ static void intel_init_display(struct drm_device *dev) } else if (IS_HASWELL(dev)) { dev_priv->display.fdi_link_train = hsw_fdi_link_train; dev_priv->display.write_eld = haswell_write_eld; - } else - dev_priv->display.update_wm = NULL; + dev_priv->display.modeset_global_resources = + haswell_modeset_global_resources; + } } else if (IS_G4X(dev)) { dev_priv->display.write_eld = g4x_write_eld; } @@ -8825,6 +8699,18 @@ static struct intel_quirk intel_quirks[] = { /* Acer Aspire 5734Z must invert backlight brightness */ { 0x2a42, 0x1025, 0x0459, quirk_invert_brightness }, + + /* Acer/eMachines G725 */ + { 0x2a42, 0x1025, 0x0210, quirk_invert_brightness }, + + /* Acer/eMachines e725 */ + { 0x2a42, 0x1025, 0x0212, quirk_invert_brightness }, + + /* Acer/Packard Bell NCL20 */ + { 0x2a42, 0x1025, 0x034b, quirk_invert_brightness }, + + /* Acer Aspire 4736Z */ + { 0x2a42, 0x1025, 0x0260, quirk_invert_brightness }, }; static void intel_init_quirks(struct drm_device *dev) @@ -8853,12 +8739,7 @@ static void i915_disable_vga(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; u8 sr1; - u32 vga_reg; - - if (HAS_PCH_SPLIT(dev)) - vga_reg = CPU_VGACNTRL; - else - vga_reg = VGACNTRL; + u32 vga_reg = i915_vgacntrl_reg(dev); // vga_get_uninterruptible(dev->pdev, VGA_RSRC_LEGACY_IO); out8(SR01, VGA_SR_INDEX); @@ -8873,10 +8754,7 @@ static void i915_disable_vga(struct drm_device *dev) void intel_modeset_init_hw(struct drm_device *dev) { - /* We attempt to init the necessary power wells early in the initialization - * time, so the subsystems that expect power to be enabled can work. - */ - intel_init_power_wells(dev); + intel_init_power_well(dev); intel_prepare_ddi(dev); @@ -8918,7 +8796,7 @@ void intel_modeset_init(struct drm_device *dev) dev->mode_config.max_width = 8192; dev->mode_config.max_height = 8192; } - dev->mode_config.fb_base = dev_priv->mm.gtt_base_addr; + dev->mode_config.fb_base = dev_priv->gtt.mappable_base; DRM_DEBUG_KMS("%d display pipe%s available.\n", dev_priv->num_pipe, dev_priv->num_pipe > 1 ? "s" : ""); @@ -8936,6 +8814,9 @@ void intel_modeset_init(struct drm_device *dev) /* Just disable it once at startup */ i915_disable_vga(dev); intel_setup_outputs(dev); + + /* Just in case the BIOS is doing something questionable. */ + intel_disable_fbc(dev); } static void @@ -9129,7 +9010,7 @@ void intel_modeset_setup_hw_state(struct drm_device *dev, struct intel_encoder *encoder; struct intel_connector *connector; - if (IS_HASWELL(dev)) { + if (HAS_DDI(dev)) { tmp = I915_READ(TRANS_DDI_FUNC_CTL(TRANSCODER_EDP)); if (tmp & TRANS_DDI_FUNC_ENABLE) { @@ -9170,7 +9051,7 @@ void intel_modeset_setup_hw_state(struct drm_device *dev, crtc->active ? "enabled" : "disabled"); } - if (IS_HASWELL(dev)) + if (HAS_DDI(dev)) intel_ddi_setup_hw_pll_state(dev); list_for_each_entry(encoder, &dev->mode_config.encoder_list, @@ -9221,9 +9102,7 @@ void intel_modeset_setup_hw_state(struct drm_device *dev, if (force_restore) { for_each_pipe(pipe) { - crtc = to_intel_crtc(dev_priv->pipe_to_crtc_mapping[pipe]); - intel_set_mode(&crtc->base, &crtc->base.mode, - crtc->base.x, crtc->base.y, crtc->base.fb); + intel_crtc_restore_mode(dev_priv->pipe_to_crtc_mapping[pipe]); } // i915_redisable_vga(dev); diff --git a/drivers/video/drm/i915/intel_dp.c b/drivers/video/drm/i915/intel_dp.c index c2d08b1231..5dcf45a065 100644 --- a/drivers/video/drm/i915/intel_dp.c +++ b/drivers/video/drm/i915/intel_dp.c @@ -148,15 +148,6 @@ intel_dp_max_link_bw(struct intel_dp *intel_dp) return max_link_bw; } -static int -intel_dp_link_clock(uint8_t link_bw) -{ - if (link_bw == DP_LINK_BW_2_7) - return 270000; - else - return 162000; -} - /* * The units on the numbers in the next two are... bizarre. Examples will * make it clearer; this one parallels an example in the eDP spec. @@ -191,7 +182,8 @@ intel_dp_adjust_dithering(struct intel_dp *intel_dp, struct drm_display_mode *mode, bool adjust_mode) { - int max_link_clock = intel_dp_link_clock(intel_dp_max_link_bw(intel_dp)); + int max_link_clock = + drm_dp_bw_code_to_link_rate(intel_dp_max_link_bw(intel_dp)); int max_lanes = drm_dp_max_lane_count(intel_dp->dpcd); int max_rate, mode_rate; @@ -330,6 +322,49 @@ intel_dp_check_edp(struct intel_dp *intel_dp) } } +static uint32_t +intel_dp_aux_wait_done(struct intel_dp *intel_dp, bool has_aux_irq) +{ + struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp); + struct drm_device *dev = intel_dig_port->base.base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; + uint32_t ch_ctl = intel_dp->output_reg + 0x10; + uint32_t status; + bool done; + + if (IS_HASWELL(dev)) { + switch (intel_dig_port->port) { + case PORT_A: + ch_ctl = DPA_AUX_CH_CTL; + break; + case PORT_B: + ch_ctl = PCH_DPB_AUX_CH_CTL; + break; + case PORT_C: + ch_ctl = PCH_DPC_AUX_CH_CTL; + break; + case PORT_D: + ch_ctl = PCH_DPD_AUX_CH_CTL; + break; + default: + BUG(); + } + } + +#define C (((status = I915_READ_NOTRACE(ch_ctl)) & DP_AUX_CH_CTL_SEND_BUSY) == 0) + if (has_aux_irq) + done = wait_event_timeout(dev_priv->gmbus_wait_queue, C, + msecs_to_jiffies(10)); + else + done = wait_for_atomic(C, 10) == 0; + if (!done) + DRM_ERROR("dp aux hw did not signal timeout (has irq: %i)!\n", + has_aux_irq); +#undef C + + return status; +} + static int intel_dp_aux_ch(struct intel_dp *intel_dp, uint8_t *send, int send_bytes, @@ -341,11 +376,17 @@ intel_dp_aux_ch(struct intel_dp *intel_dp, struct drm_i915_private *dev_priv = dev->dev_private; uint32_t ch_ctl = output_reg + 0x10; uint32_t ch_data = ch_ctl + 4; - int i; - int recv_bytes; + int i, ret, recv_bytes; uint32_t status; uint32_t aux_clock_divider; int try, precharge; + bool has_aux_irq = INTEL_INFO(dev)->gen >= 5 && !IS_VALLEYVIEW(dev); + + /* dp aux is extremely sensitive to irq latency, hence request the + * lowest possible wakeup latency and so prevent the cpu from going into + * deep sleep states. + */ +// pm_qos_update_request(&dev_priv->pm_qos, 0); if (IS_HASWELL(dev)) { switch (intel_dig_port->port) { @@ -379,7 +420,7 @@ intel_dp_aux_ch(struct intel_dp *intel_dp, * clock divider. */ if (is_cpu_edp(intel_dp)) { - if (IS_HASWELL(dev)) + if (HAS_DDI(dev)) aux_clock_divider = intel_ddi_get_cdclk_freq(dev_priv) >> 1; else if (IS_VALLEYVIEW(dev)) aux_clock_divider = 100; @@ -399,7 +440,7 @@ intel_dp_aux_ch(struct intel_dp *intel_dp, /* Try to wait for any previous AUX channel activity */ for (try = 0; try < 3; try++) { - status = I915_READ(ch_ctl); + status = I915_READ_NOTRACE(ch_ctl); if ((status & DP_AUX_CH_CTL_SEND_BUSY) == 0) break; msleep(1); @@ -408,7 +449,8 @@ intel_dp_aux_ch(struct intel_dp *intel_dp, if (try == 3) { WARN(1, "dp_aux_ch not started status 0x%08x\n", I915_READ(ch_ctl)); - return -EBUSY; + ret = -EBUSY; + goto out; } /* Must try at least 3 times according to DP spec */ @@ -421,6 +463,7 @@ intel_dp_aux_ch(struct intel_dp *intel_dp, /* Send the command and wait for it to complete */ I915_WRITE(ch_ctl, DP_AUX_CH_CTL_SEND_BUSY | + (has_aux_irq ? DP_AUX_CH_CTL_INTERRUPT : 0) | DP_AUX_CH_CTL_TIME_OUT_400us | (send_bytes << DP_AUX_CH_CTL_MESSAGE_SIZE_SHIFT) | (precharge << DP_AUX_CH_CTL_PRECHARGE_2US_SHIFT) | @@ -428,12 +471,8 @@ intel_dp_aux_ch(struct intel_dp *intel_dp, DP_AUX_CH_CTL_DONE | DP_AUX_CH_CTL_TIME_OUT_ERROR | DP_AUX_CH_CTL_RECEIVE_ERROR); - for (;;) { - status = I915_READ(ch_ctl); - if ((status & DP_AUX_CH_CTL_SEND_BUSY) == 0) - break; - udelay(100); - } + + status = intel_dp_aux_wait_done(intel_dp, has_aux_irq); /* Clear done status and any errors */ I915_WRITE(ch_ctl, @@ -451,7 +490,8 @@ intel_dp_aux_ch(struct intel_dp *intel_dp, if ((status & DP_AUX_CH_CTL_DONE) == 0) { DRM_ERROR("dp_aux_ch not done status 0x%08x\n", status); - return -EBUSY; + ret = -EBUSY; + goto out; } /* Check for timeout or receive error. @@ -459,14 +499,16 @@ intel_dp_aux_ch(struct intel_dp *intel_dp, */ if (status & DP_AUX_CH_CTL_RECEIVE_ERROR) { DRM_ERROR("dp_aux_ch receive error status 0x%08x\n", status); - return -EIO; + ret = -EIO; + goto out; } /* Timeouts occur when the device isn't connected, so they're * "normal" -- don't fill the kernel log with these */ if (status & DP_AUX_CH_CTL_TIME_OUT_ERROR) { DRM_DEBUG_KMS("dp_aux_ch timeout status 0x%08x\n", status); - return -ETIMEDOUT; + ret = -ETIMEDOUT; + goto out; } /* Unload any bytes sent back from the other side */ @@ -479,7 +521,11 @@ intel_dp_aux_ch(struct intel_dp *intel_dp, unpack_aux(I915_READ(ch_data + i), recv + i, recv_bytes - i); - return recv_bytes; + ret = recv_bytes; +out: +// pm_qos_update_request(&dev_priv->pm_qos, PM_QOS_DEFAULT_VALUE); + + return ret; } /* Write data to the aux channel in native mode */ @@ -718,16 +764,35 @@ intel_dp_mode_fixup(struct drm_encoder *encoder, return false; bpp = adjusted_mode->private_flags & INTEL_MODE_DP_FORCE_6BPC ? 18 : 24; + + if (intel_dp->color_range_auto) { + /* + * See: + * CEA-861-E - 5.1 Default Encoding Parameters + * VESA DisplayPort Ver.1.2a - 5.1.1.1 Video Colorimetry + */ + if (bpp != 18 && drm_match_cea_mode(adjusted_mode) > 1) + intel_dp->color_range = DP_COLOR_RANGE_16_235; + else + intel_dp->color_range = 0; + } + + if (intel_dp->color_range) + adjusted_mode->private_flags |= INTEL_MODE_LIMITED_COLOR_RANGE; + mode_rate = intel_dp_link_required(adjusted_mode->clock, bpp); for (clock = 0; clock <= max_clock; clock++) { for (lane_count = 1; lane_count <= max_lane_count; lane_count <<= 1) { - int link_avail = intel_dp_max_data_rate(intel_dp_link_clock(bws[clock]), lane_count); + int link_bw_clock = + drm_dp_bw_code_to_link_rate(bws[clock]); + int link_avail = intel_dp_max_data_rate(link_bw_clock, + lane_count); if (mode_rate <= link_avail) { intel_dp->link_bw = bws[clock]; intel_dp->lane_count = lane_count; - adjusted_mode->clock = intel_dp_link_clock(intel_dp->link_bw); + adjusted_mode->clock = link_bw_clock; DRM_DEBUG_KMS("DP link bw %02x lane " "count %d clock %d bpp %d\n", intel_dp->link_bw, intel_dp->lane_count, @@ -742,39 +807,6 @@ intel_dp_mode_fixup(struct drm_encoder *encoder, return false; } -struct intel_dp_m_n { - uint32_t tu; - uint32_t gmch_m; - uint32_t gmch_n; - uint32_t link_m; - uint32_t link_n; -}; - -static void -intel_reduce_ratio(uint32_t *num, uint32_t *den) -{ - while (*num > 0xffffff || *den > 0xffffff) { - *num >>= 1; - *den >>= 1; - } -} - -static void -intel_dp_compute_m_n(int bpp, - int nlanes, - int pixel_clock, - int link_clock, - struct intel_dp_m_n *m_n) -{ - m_n->tu = 64; - m_n->gmch_m = (pixel_clock * bpp) >> 3; - m_n->gmch_n = link_clock * nlanes; - intel_reduce_ratio(&m_n->gmch_m, &m_n->gmch_n); - m_n->link_m = pixel_clock; - m_n->link_n = link_clock; - intel_reduce_ratio(&m_n->link_m, &m_n->link_n); -} - void intel_dp_set_m_n(struct drm_crtc *crtc, struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode) @@ -785,9 +817,10 @@ intel_dp_set_m_n(struct drm_crtc *crtc, struct drm_display_mode *mode, struct drm_i915_private *dev_priv = dev->dev_private; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); int lane_count = 4; - struct intel_dp_m_n m_n; + struct intel_link_m_n m_n; int pipe = intel_crtc->pipe; enum transcoder cpu_transcoder = intel_crtc->cpu_transcoder; + int target_clock; /* * Find the lane count in the intel_encoder private @@ -803,13 +836,22 @@ intel_dp_set_m_n(struct drm_crtc *crtc, struct drm_display_mode *mode, } } + target_clock = mode->clock; + for_each_encoder_on_crtc(dev, crtc, intel_encoder) { + if (intel_encoder->type == INTEL_OUTPUT_EDP) { + target_clock = intel_edp_target_clock(intel_encoder, + mode); + break; + } + } + /* * Compute the GMCH and Link ratios. The '3' here is * the number of bytes_per_pixel post-LUT, which we always * set up for 8-bits of R/G/B, or 3 bytes total. */ - intel_dp_compute_m_n(intel_crtc->bpp, lane_count, - mode->clock, adjusted_mode->clock, &m_n); + intel_link_compute_m_n(intel_crtc->bpp, lane_count, + target_clock, adjusted_mode->clock, &m_n); if (IS_HASWELL(dev)) { I915_WRITE(PIPE_DATA_M1(cpu_transcoder), @@ -851,6 +893,32 @@ void intel_dp_init_link_config(struct intel_dp *intel_dp) } } +static void ironlake_set_pll_edp(struct drm_crtc *crtc, int clock) +{ + struct drm_device *dev = crtc->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + u32 dpa_ctl; + + DRM_DEBUG_KMS("eDP PLL enable for clock %d\n", clock); + dpa_ctl = I915_READ(DP_A); + dpa_ctl &= ~DP_PLL_FREQ_MASK; + + if (clock < 200000) { + /* For a long time we've carried around a ILK-DevA w/a for the + * 160MHz clock. If we're really unlucky, it's still required. + */ + DRM_DEBUG_KMS("160MHz cpu eDP clock, might need ilk devA w/a\n"); + dpa_ctl |= DP_PLL_FREQ_160MHZ; + } else { + dpa_ctl |= DP_PLL_FREQ_270MHZ; + } + + I915_WRITE(DP_A, dpa_ctl); + + POSTING_READ(DP_A); + udelay(500); +} + static void intel_dp_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode) @@ -926,6 +994,7 @@ intel_dp_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode, else intel_dp->DP |= DP_PLL_FREQ_270MHZ; } else if (!HAS_PCH_CPT(dev) || is_cpu_edp(intel_dp)) { + if (!HAS_PCH_SPLIT(dev)) intel_dp->DP |= intel_dp->color_range; if (adjusted_mode->flags & DRM_MODE_FLAG_PHSYNC) @@ -950,6 +1019,9 @@ intel_dp_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode, } else { intel_dp->DP |= DP_LINK_TRAIN_OFF_CPT; } + + if (is_cpu_edp(intel_dp)) + ironlake_set_pll_edp(crtc, adjusted_mode->clock); } #define IDLE_ON_MASK (PP_ON | 0 | PP_SEQUENCE_MASK | 0 | PP_SEQUENCE_STATE_MASK) @@ -1057,6 +1129,8 @@ static void ironlake_panel_vdd_off_sync(struct intel_dp *intel_dp) struct drm_i915_private *dev_priv = dev->dev_private; u32 pp; + WARN_ON(!mutex_is_locked(&dev->mode_config.mutex)); + if (!intel_dp->want_panel_vdd && ironlake_edp_have_panel_vdd(intel_dp)) { pp = ironlake_get_pp_control(dev_priv); pp &= ~EDP_FORCE_VDD; @@ -1543,7 +1617,7 @@ intel_get_adjust_train(struct intel_dp *intel_dp, uint8_t link_status[DP_LINK_ST } static uint32_t -intel_dp_signal_levels(uint8_t train_set) +intel_gen4_signal_levels(uint8_t train_set) { uint32_t signal_levels = 0; @@ -1641,7 +1715,7 @@ intel_gen7_edp_signal_levels(uint8_t train_set) /* Gen7.5's (HSW) DP voltage swing and pre-emphasis control */ static uint32_t -intel_dp_signal_levels_hsw(uint8_t train_set) +intel_hsw_signal_levels(uint8_t train_set) { int signal_levels = train_set & (DP_TRAIN_VOLTAGE_SWING_MASK | DP_TRAIN_PRE_EMPHASIS_MASK); @@ -1673,6 +1747,34 @@ intel_dp_signal_levels_hsw(uint8_t train_set) } } +/* Properly updates "DP" with the correct signal levels. */ +static void +intel_dp_set_signal_levels(struct intel_dp *intel_dp, uint32_t *DP) +{ + struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp); + struct drm_device *dev = intel_dig_port->base.base.dev; + uint32_t signal_levels, mask; + uint8_t train_set = intel_dp->train_set[0]; + + if (IS_HASWELL(dev)) { + signal_levels = intel_hsw_signal_levels(train_set); + mask = DDI_BUF_EMP_MASK; + } else if (IS_GEN7(dev) && is_cpu_edp(intel_dp) && !IS_VALLEYVIEW(dev)) { + signal_levels = intel_gen7_edp_signal_levels(train_set); + mask = EDP_LINK_TRAIN_VOL_EMP_MASK_IVB; + } else if (IS_GEN6(dev) && is_cpu_edp(intel_dp)) { + signal_levels = intel_gen6_edp_signal_levels(train_set); + mask = EDP_LINK_TRAIN_VOL_EMP_MASK_SNB; + } else { + signal_levels = intel_gen4_signal_levels(train_set); + mask = DP_VOLTAGE_MASK | DP_PRE_EMPHASIS_MASK; + } + + DRM_DEBUG_KMS("Using signal levels %08x\n", signal_levels); + + *DP = (*DP & ~mask) | signal_levels; +} + static bool intel_dp_set_link_train(struct intel_dp *intel_dp, uint32_t dp_reg_value, @@ -1696,6 +1798,8 @@ intel_dp_set_link_train(struct intel_dp *intel_dp, temp &= ~DP_TP_CTL_LINK_TRAIN_MASK; switch (dp_train_pat & DP_TRAINING_PATTERN_MASK) { case DP_TRAINING_PATTERN_DISABLE: + + if (port != PORT_A) { temp |= DP_TP_CTL_LINK_TRAIN_IDLE; I915_WRITE(DP_TP_CTL(port), temp); @@ -1704,6 +1808,8 @@ intel_dp_set_link_train(struct intel_dp *intel_dp, DRM_ERROR("Timed out waiting for DP idle patterns\n"); temp &= ~DP_TP_CTL_LINK_TRAIN_MASK; + } + temp |= DP_TP_CTL_LINK_TRAIN_NORMAL; break; @@ -1791,7 +1897,7 @@ intel_dp_start_link_train(struct intel_dp *intel_dp) int voltage_tries, loop_tries; uint32_t DP = intel_dp->DP; - if (IS_HASWELL(dev)) + if (HAS_DDI(dev)) intel_ddi_prepare_link_retrain(encoder); /* Write the link configuration data */ @@ -1809,24 +1915,8 @@ intel_dp_start_link_train(struct intel_dp *intel_dp) for (;;) { /* Use intel_dp->train_set[0] to set the voltage and pre emphasis values */ uint8_t link_status[DP_LINK_STATUS_SIZE]; - uint32_t signal_levels; - if (IS_HASWELL(dev)) { - signal_levels = intel_dp_signal_levels_hsw( - intel_dp->train_set[0]); - DP = (DP & ~DDI_BUF_EMP_MASK) | signal_levels; - } else if (IS_GEN7(dev) && is_cpu_edp(intel_dp) && !IS_VALLEYVIEW(dev)) { - signal_levels = intel_gen7_edp_signal_levels(intel_dp->train_set[0]); - DP = (DP & ~EDP_LINK_TRAIN_VOL_EMP_MASK_IVB) | signal_levels; - } else if (IS_GEN6(dev) && is_cpu_edp(intel_dp)) { - signal_levels = intel_gen6_edp_signal_levels(intel_dp->train_set[0]); - DP = (DP & ~EDP_LINK_TRAIN_VOL_EMP_MASK_SNB) | signal_levels; - } else { - signal_levels = intel_dp_signal_levels(intel_dp->train_set[0]); - DP = (DP & ~(DP_VOLTAGE_MASK|DP_PRE_EMPHASIS_MASK)) | signal_levels; - } - DRM_DEBUG_KMS("training pattern 1 signal levels %08x\n", - signal_levels); + intel_dp_set_signal_levels(intel_dp, &DP); /* Set training pattern 1 */ if (!intel_dp_set_link_train(intel_dp, DP, @@ -1850,7 +1940,7 @@ intel_dp_start_link_train(struct intel_dp *intel_dp) for (i = 0; i < intel_dp->lane_count; i++) if ((intel_dp->train_set[i] & DP_TRAIN_MAX_SWING_REACHED) == 0) break; - if (i == intel_dp->lane_count && voltage_tries == 5) { + if (i == intel_dp->lane_count) { ++loop_tries; if (loop_tries == 5) { DRM_DEBUG_KMS("too many full retries, give up\n"); @@ -1882,7 +1972,6 @@ intel_dp_start_link_train(struct intel_dp *intel_dp) void intel_dp_complete_link_train(struct intel_dp *intel_dp) { - struct drm_device *dev = intel_dp_to_dev(intel_dp); bool channel_eq = false; int tries, cr_tries; uint32_t DP = intel_dp->DP; @@ -1892,8 +1981,6 @@ intel_dp_complete_link_train(struct intel_dp *intel_dp) cr_tries = 0; channel_eq = false; for (;;) { - /* Use intel_dp->train_set[0] to set the voltage and pre emphasis values */ - uint32_t signal_levels; uint8_t link_status[DP_LINK_STATUS_SIZE]; if (cr_tries > 5) { @@ -1902,19 +1989,7 @@ intel_dp_complete_link_train(struct intel_dp *intel_dp) break; } - if (IS_HASWELL(dev)) { - signal_levels = intel_dp_signal_levels_hsw(intel_dp->train_set[0]); - DP = (DP & ~DDI_BUF_EMP_MASK) | signal_levels; - } else if (IS_GEN7(dev) && is_cpu_edp(intel_dp) && !IS_VALLEYVIEW(dev)) { - signal_levels = intel_gen7_edp_signal_levels(intel_dp->train_set[0]); - DP = (DP & ~EDP_LINK_TRAIN_VOL_EMP_MASK_IVB) | signal_levels; - } else if (IS_GEN6(dev) && is_cpu_edp(intel_dp)) { - signal_levels = intel_gen6_edp_signal_levels(intel_dp->train_set[0]); - DP = (DP & ~EDP_LINK_TRAIN_VOL_EMP_MASK_SNB) | signal_levels; - } else { - signal_levels = intel_dp_signal_levels(intel_dp->train_set[0]); - DP = (DP & ~(DP_VOLTAGE_MASK|DP_PRE_EMPHASIS_MASK)) | signal_levels; - } + intel_dp_set_signal_levels(intel_dp, &DP); /* channel eq pattern */ if (!intel_dp_set_link_train(intel_dp, DP, @@ -1964,6 +2039,8 @@ intel_dp_link_down(struct intel_dp *intel_dp) struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp); struct drm_device *dev = intel_dig_port->base.base.dev; struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_crtc *intel_crtc = + to_intel_crtc(intel_dig_port->base.base.crtc); uint32_t DP = intel_dp->DP; /* @@ -1981,7 +2058,7 @@ intel_dp_link_down(struct intel_dp *intel_dp) * intel_ddi_prepare_link_retrain will take care of redoing the link * train. */ - if (IS_HASWELL(dev)) + if (HAS_DDI(dev)) return; if (WARN_ON((I915_READ(intel_dp->output_reg) & DP_PORT_EN) == 0)) @@ -1998,7 +2075,8 @@ intel_dp_link_down(struct intel_dp *intel_dp) } POSTING_READ(intel_dp->output_reg); - msleep(17); + /* We don't really know why we're doing this */ + intel_wait_for_vblank(dev, intel_crtc->pipe); if (HAS_PCH_IBX(dev) && I915_READ(intel_dp->output_reg) & DP_PIPEB_SELECT) { @@ -2018,19 +2096,14 @@ intel_dp_link_down(struct intel_dp *intel_dp) /* Changes to enable or select take place the vblank * after being written. */ - if (crtc == NULL) { - /* We can arrive here never having been attached - * to a CRTC, for instance, due to inheriting - * random state from the BIOS. - * - * If the pipe is not running, play safe and - * wait for the clocks to stabilise before - * continuing. - */ + if (WARN_ON(crtc == NULL)) { + /* We should never try to disable a port without a crtc + * attached. For paranoia keep the code around for a + * bit. */ POSTING_READ(intel_dp->output_reg); msleep(50); } else - intel_wait_for_vblank(dev, to_intel_crtc(crtc)->pipe); + intel_wait_for_vblank(dev, intel_crtc->pipe); } DP &= ~DP_AUDIO_OUTPUT_ENABLE; @@ -2042,10 +2115,16 @@ intel_dp_link_down(struct intel_dp *intel_dp) static bool intel_dp_get_dpcd(struct intel_dp *intel_dp) { + char dpcd_hex_dump[sizeof(intel_dp->dpcd) * 3]; + if (intel_dp_aux_native_read_retry(intel_dp, 0x000, intel_dp->dpcd, sizeof(intel_dp->dpcd)) == 0) return false; /* aux transfer failed */ + hex_dump_to_buffer(intel_dp->dpcd, sizeof(intel_dp->dpcd), + 32, 1, dpcd_hex_dump, sizeof(dpcd_hex_dump), false); + DRM_DEBUG_KMS("DPCD: %s\n", dpcd_hex_dump); + if (intel_dp->dpcd[DP_DPCD_REV] == 0) return false; /* DPCD not present */ @@ -2206,6 +2285,8 @@ static enum drm_connector_status ironlake_dp_detect(struct intel_dp *intel_dp) { struct drm_device *dev = intel_dp_to_dev(intel_dp); + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp); enum drm_connector_status status; /* Can't disconnect eDP, but you can close the lid... */ @@ -2216,6 +2297,9 @@ ironlake_dp_detect(struct intel_dp *intel_dp) return status; } + if (!ibx_digital_port_connected(dev_priv, intel_dig_port)) + return connector_status_disconnected; + return intel_dp_detect_dpcd(intel_dp); } @@ -2224,17 +2308,18 @@ g4x_dp_detect(struct intel_dp *intel_dp) { struct drm_device *dev = intel_dp_to_dev(intel_dp); struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp); uint32_t bit; - switch (intel_dp->output_reg) { - case DP_B: - bit = DPB_HOTPLUG_LIVE_STATUS; + switch (intel_dig_port->port) { + case PORT_B: + bit = PORTB_HOTPLUG_LIVE_STATUS; break; - case DP_C: - bit = DPC_HOTPLUG_LIVE_STATUS; + case PORT_C: + bit = PORTC_HOTPLUG_LIVE_STATUS; break; - case DP_D: - bit = DPD_HOTPLUG_LIVE_STATUS; + case PORT_D: + bit = PORTD_HOTPLUG_LIVE_STATUS; break; default: return connector_status_unknown; @@ -2290,13 +2375,6 @@ intel_dp_get_edid_modes(struct drm_connector *connector, struct i2c_adapter *ada return intel_ddc_get_modes(connector, adapter); } - -/** - * Uses CRT_HOTPLUG_EN and CRT_HOTPLUG_STAT to detect DP connection. - * - * \return true if DP port is connected. - * \return false if DP port is disconnected. - */ static enum drm_connector_status intel_dp_detect(struct drm_connector *connector, bool force) { @@ -2306,7 +2384,6 @@ intel_dp_detect(struct drm_connector *connector, bool force) struct drm_device *dev = connector->dev; enum drm_connector_status status; struct edid *edid = NULL; - char dpcd_hex_dump[sizeof(intel_dp->dpcd) * 3]; intel_dp->has_audio = false; @@ -2315,10 +2392,6 @@ intel_dp_detect(struct drm_connector *connector, bool force) else status = g4x_dp_detect(intel_dp); -// hex_dump_to_buffer(intel_dp->dpcd, sizeof(intel_dp->dpcd), -// 32, 1, dpcd_hex_dump, sizeof(dpcd_hex_dump), false); -// DRM_DEBUG_KMS("DPCD: %s\n", dpcd_hex_dump); - if (status != connector_status_connected) return status; @@ -2396,7 +2469,7 @@ intel_dp_set_property(struct drm_connector *connector, ret = drm_object_property_set_value(&connector->base, property, val); if (ret) return ret; -#if 0 + if (property == dev_priv->force_audio_property) { int i = val; bool has_audio; @@ -2419,13 +2492,23 @@ intel_dp_set_property(struct drm_connector *connector, } if (property == dev_priv->broadcast_rgb_property) { - if (val == !!intel_dp->color_range) - return 0; - - intel_dp->color_range = val ? DP_COLOR_RANGE_16_235 : 0; + switch (val) { + case INTEL_BROADCAST_RGB_AUTO: + intel_dp->color_range_auto = true; + break; + case INTEL_BROADCAST_RGB_FULL: + intel_dp->color_range_auto = false; + intel_dp->color_range = 0; + break; + case INTEL_BROADCAST_RGB_LIMITED: + intel_dp->color_range_auto = false; + intel_dp->color_range = DP_COLOR_RANGE_16_235; + break; + default: + return -EINVAL; + } goto done; } -#endif if (is_edp(intel_dp) && property == connector->dev->mode_config.scaling_mode_property) { @@ -2446,11 +2529,8 @@ intel_dp_set_property(struct drm_connector *connector, return -EINVAL; done: - if (intel_encoder->base.crtc) { - struct drm_crtc *crtc = intel_encoder->base.crtc; - intel_set_mode(crtc, &crtc->mode, - crtc->x, crtc->y, crtc->fb); - } + if (intel_encoder->base.crtc) + intel_crtc_restore_mode(intel_encoder->base.crtc); return 0; } @@ -2479,12 +2559,15 @@ void intel_dp_encoder_destroy(struct drm_encoder *encoder) { struct intel_digital_port *intel_dig_port = enc_to_dig_port(encoder); struct intel_dp *intel_dp = &intel_dig_port->dp; + struct drm_device *dev = intel_dp_to_dev(intel_dp); i2c_del_adapter(&intel_dp->adapter); drm_encoder_cleanup(encoder); if (is_edp(intel_dp)) { // cancel_delayed_work_sync(&intel_dp->panel_vdd_work); + mutex_lock(&dev->mode_config.mutex); ironlake_panel_vdd_off_sync(intel_dp); + mutex_unlock(&dev->mode_config.mutex); } kfree(intel_dig_port); } @@ -2492,7 +2575,6 @@ void intel_dp_encoder_destroy(struct drm_encoder *encoder) static const struct drm_encoder_helper_funcs intel_dp_helper_funcs = { .mode_fixup = intel_dp_mode_fixup, .mode_set = intel_dp_mode_set, - .disable = intel_encoder_noop, }; static const struct drm_connector_funcs intel_dp_connector_funcs = { @@ -2567,6 +2649,7 @@ intel_dp_add_properties(struct intel_dp *intel_dp, struct drm_connector *connect intel_attach_force_audio_property(connector); intel_attach_broadcast_rgb_property(connector); + intel_dp->color_range_auto = true; if (is_edp(intel_dp)) { drm_mode_create_scaling_mode_property(connector->dev); @@ -2756,7 +2839,7 @@ intel_dp_init_connector(struct intel_digital_port *intel_dig_port, intel_connector_attach_encoder(intel_connector, intel_encoder); drm_sysfs_connector_add(connector); - if (IS_HASWELL(dev)) + if (HAS_DDI(dev)) intel_connector->get_hw_state = intel_ddi_connector_get_hw_state; else intel_connector->get_hw_state = intel_connector_get_hw_state; @@ -2768,15 +2851,15 @@ intel_dp_init_connector(struct intel_digital_port *intel_dig_port, name = "DPDDC-A"; break; case PORT_B: - dev_priv->hotplug_supported_mask |= DPB_HOTPLUG_INT_STATUS; + dev_priv->hotplug_supported_mask |= PORTB_HOTPLUG_INT_STATUS; name = "DPDDC-B"; break; case PORT_C: - dev_priv->hotplug_supported_mask |= DPC_HOTPLUG_INT_STATUS; + dev_priv->hotplug_supported_mask |= PORTC_HOTPLUG_INT_STATUS; name = "DPDDC-C"; break; case PORT_D: - dev_priv->hotplug_supported_mask |= DPD_HOTPLUG_INT_STATUS; + dev_priv->hotplug_supported_mask |= PORTD_HOTPLUG_INT_STATUS; name = "DPDDC-D"; break; default: diff --git a/drivers/video/drm/i915/intel_drv.h b/drivers/video/drm/i915/intel_drv.h index 2a42ba71ee..91951005e8 100644 --- a/drivers/video/drm/i915/intel_drv.h +++ b/drivers/video/drm/i915/intel_drv.h @@ -118,6 +118,11 @@ * timings in the mode to prevent the crtc fixup from overwriting them. * Currently only lvds needs that. */ #define INTEL_MODE_CRTC_TIMINGS_SET (0x20) +/* + * Set when limited 16-235 (as opposed to full 0-255) RGB color range is + * to be used. + */ +#define INTEL_MODE_LIMITED_COLOR_RANGE (0x40) static inline void intel_mode_set_pixel_multiplier(struct drm_display_mode *mode, @@ -162,6 +167,7 @@ struct intel_encoder { bool cloneable; bool connectors_active; void (*hot_plug)(struct intel_encoder *); + void (*pre_pll_enable)(struct intel_encoder *); void (*pre_enable)(struct intel_encoder *); void (*enable)(struct intel_encoder *); void (*disable)(struct intel_encoder *); @@ -214,6 +220,7 @@ struct intel_crtc { * some outputs connected to this crtc. */ bool active; + bool eld_vld; bool primary_disabled; /* is the crtc obscured by a plane? */ bool lowfreq_avail; struct intel_overlay *overlay; @@ -237,6 +244,9 @@ struct intel_crtc { /* We can share PLLs across outputs if the timings match */ struct intel_pch_pll *pch_pll; uint32_t ddi_pll_sel; + + /* reset counter value when the last flip was submitted */ + unsigned int reset_counter; }; struct intel_plane { @@ -292,6 +302,9 @@ struct cxsr_latency { #define DIP_LEN_AVI 13 #define DIP_AVI_PR_1 0 #define DIP_AVI_PR_2 1 +#define DIP_AVI_RGB_QUANT_RANGE_DEFAULT (0 << 2) +#define DIP_AVI_RGB_QUANT_RANGE_LIMITED (1 << 2) +#define DIP_AVI_RGB_QUANT_RANGE_FULL (2 << 2) #define DIP_TYPE_SPD 0x83 #define DIP_VERSION_SPD 0x1 @@ -346,9 +359,11 @@ struct intel_hdmi { u32 sdvox_reg; int ddc_bus; uint32_t color_range; + bool color_range_auto; bool has_hdmi_sink; bool has_audio; enum hdmi_force_audio force_audio; + bool rgb_quant_range_selectable; void (*write_infoframe)(struct drm_encoder *encoder, struct dip_infoframe *frame); void (*set_infoframes)(struct drm_encoder *encoder, @@ -365,6 +380,7 @@ struct intel_dp { bool has_audio; enum hdmi_force_audio force_audio; uint32_t color_range; + bool color_range_auto; uint8_t link_bw; uint8_t lane_count; uint8_t dpcd[DP_RECEIVER_CAP_SIZE]; @@ -386,6 +402,7 @@ struct intel_dp { struct intel_digital_port { struct intel_encoder base; enum port port; + u32 port_reversal; struct intel_dp dp; struct intel_hdmi hdmi; }; @@ -448,10 +465,10 @@ extern bool intel_sdvo_init(struct drm_device *dev, uint32_t sdvo_reg, extern void intel_dvo_init(struct drm_device *dev); extern void intel_tv_init(struct drm_device *dev); extern void intel_mark_busy(struct drm_device *dev); -extern void intel_mark_idle(struct drm_device *dev); extern void intel_mark_fb_busy(struct drm_i915_gem_object *obj); -extern void intel_mark_fb_idle(struct drm_i915_gem_object *obj); +extern void intel_mark_idle(struct drm_device *dev); extern bool intel_lvds_init(struct drm_device *dev); +extern bool intel_is_dual_link_lvds(struct drm_device *dev); extern void intel_dp_init(struct drm_device *dev, int output_reg, enum port port); extern void intel_dp_init_connector(struct intel_digital_port *intel_dig_port, @@ -511,12 +528,12 @@ struct intel_set_config { bool mode_changed; }; -extern bool intel_set_mode(struct drm_crtc *crtc, struct drm_display_mode *mode, +extern int intel_set_mode(struct drm_crtc *crtc, struct drm_display_mode *mode, int x, int y, struct drm_framebuffer *old_fb); extern void intel_modeset_disable(struct drm_device *dev); +extern void intel_crtc_restore_mode(struct drm_crtc *crtc); extern void intel_crtc_load_lut(struct drm_crtc *crtc); extern void intel_crtc_update_dpms(struct drm_crtc *crtc); -extern void intel_encoder_noop(struct drm_encoder *encoder); extern void intel_encoder_destroy(struct drm_encoder *encoder); extern void intel_encoder_dpms(struct intel_encoder *encoder, int mode); extern bool intel_encoder_check_is_cloned(struct intel_encoder *encoder); @@ -555,6 +572,9 @@ hdmi_to_dig_port(struct intel_hdmi *intel_hdmi) return container_of(intel_hdmi, struct intel_digital_port, hdmi); } +bool ibx_digital_port_connected(struct drm_i915_private *dev_priv, + struct intel_digital_port *port); + extern void intel_connector_attach_encoder(struct intel_connector *connector, struct intel_encoder *encoder); extern struct drm_encoder *intel_best_encoder(struct drm_connector *connector); @@ -598,6 +618,7 @@ extern int intel_framebuffer_init(struct drm_device *dev, struct drm_mode_fb_cmd2 *mode_cmd, struct drm_i915_gem_object *obj); extern int intel_fbdev_init(struct drm_device *dev); +extern void intel_fbdev_initial_config(struct drm_device *dev); extern void intel_fbdev_fini(struct drm_device *dev); extern void intel_fbdev_set_suspend(struct drm_device *dev, int state); extern void intel_prepare_page_flip(struct drm_device *dev, int plane); @@ -636,7 +657,8 @@ extern void intel_update_sprite_watermarks(struct drm_device *dev, int pipe, extern void intel_update_linetime_watermarks(struct drm_device *dev, int pipe, struct drm_display_mode *mode); -extern unsigned long intel_gen4_compute_offset_xtiled(int *x, int *y, +extern unsigned long intel_gen4_compute_page_offset(int *x, int *y, + unsigned int tiling_mode, unsigned int bpp, unsigned int pitch); @@ -657,7 +679,8 @@ extern void intel_update_fbc(struct drm_device *dev); extern void intel_gpu_ips_init(struct drm_i915_private *dev_priv); extern void intel_gpu_ips_teardown(void); -extern void intel_init_power_wells(struct drm_device *dev); +extern void intel_init_power_well(struct drm_device *dev); +extern void intel_set_power_well(struct drm_device *dev, bool enable); extern void intel_enable_gt_powersave(struct drm_device *dev); extern void intel_disable_gt_powersave(struct drm_device *dev); extern void gen6_gt_check_fifodbg(struct drm_i915_private *dev_priv); diff --git a/drivers/video/drm/i915/intel_dvo.c b/drivers/video/drm/i915/intel_dvo.c index 3198ca436a..7ef63b294e 100644 --- a/drivers/video/drm/i915/intel_dvo.c +++ b/drivers/video/drm/i915/intel_dvo.c @@ -345,7 +345,6 @@ static void intel_dvo_destroy(struct drm_connector *connector) static const struct drm_encoder_helper_funcs intel_dvo_helper_funcs = { .mode_fixup = intel_dvo_mode_fixup, .mode_set = intel_dvo_mode_set, - .disable = intel_encoder_noop, }; static const struct drm_connector_funcs intel_dvo_connector_funcs = { diff --git a/drivers/video/drm/i915/intel_fb.c b/drivers/video/drm/i915/intel_fb.c index 09f9c49804..0b123be7bc 100644 --- a/drivers/video/drm/i915/intel_fb.c +++ b/drivers/video/drm/i915/intel_fb.c @@ -91,9 +91,10 @@ static struct fb_ops intelfb_ops = { // .fb_debug_leave = drm_fb_helper_debug_leave, }; -static int intelfb_create(struct intel_fbdev *ifbdev, +static int intelfb_create(struct drm_fb_helper *helper, struct drm_fb_helper_surface_size *sizes) { + struct intel_fbdev *ifbdev = (struct intel_fbdev *)helper; struct drm_device *dev = ifbdev->helper.dev; struct drm_i915_private *dev_priv = dev->dev_private; struct fb_info *info; @@ -186,8 +187,7 @@ static int intelfb_create(struct intel_fbdev *ifbdev, goto out_unpin; } info->apertures->ranges[0].base = dev->mode_config.fb_base; - info->apertures->ranges[0].size = - dev_priv->mm.gtt->gtt_mappable_entries << PAGE_SHIFT; + info->apertures->ranges[0].size = dev_priv->gtt.mappable_end; info->fix.smem_start = dev->mode_config.fb_base + obj->gtt_offset; info->fix.smem_len = size; @@ -223,26 +223,10 @@ out: return ret; } -static int intel_fb_find_or_create_single(struct drm_fb_helper *helper, - struct drm_fb_helper_surface_size *sizes) -{ - struct intel_fbdev *ifbdev = (struct intel_fbdev *)helper; - int new_fb = 0; - int ret; - - if (!helper->fb) { - ret = intelfb_create(ifbdev, sizes); - if (ret) - return ret; - new_fb = 1; - } - return new_fb; -} - static struct drm_fb_helper_funcs intel_fb_helper_funcs = { .gamma_set = intel_crtc_fb_gamma_set, .gamma_get = intel_crtc_fb_gamma_get, - .fb_probe = intel_fb_find_or_create_single, + .fb_probe = intelfb_create, }; @@ -268,9 +252,20 @@ int intel_fbdev_init(struct drm_device *dev) } drm_fb_helper_single_add_all_connectors(&ifbdev->helper); - drm_fb_helper_initial_config(&ifbdev->helper, 32); return 0; } +void intel_fbdev_initial_config(struct drm_device *dev) +{ + drm_i915_private_t *dev_priv = dev->dev_private; + /* Due to peculiar init order wrt to hpd handling this is separate. */ + drm_fb_helper_initial_config(&dev_priv->fbdev->helper, 32); +} + +void intel_fb_output_poll_changed(struct drm_device *dev) +{ + drm_i915_private_t *dev_priv = dev->dev_private; + drm_fb_helper_hotplug_event(&dev_priv->fbdev->helper); +} diff --git a/drivers/video/drm/i915/intel_hdmi.c b/drivers/video/drm/i915/intel_hdmi.c index a4bd2bae32..7ef238d2f0 100644 --- a/drivers/video/drm/i915/intel_hdmi.c +++ b/drivers/video/drm/i915/intel_hdmi.c @@ -48,7 +48,7 @@ assert_hdmi_port_disabled(struct intel_hdmi *intel_hdmi) struct drm_i915_private *dev_priv = dev->dev_private; uint32_t enabled_bits; - enabled_bits = IS_HASWELL(dev) ? DDI_BUF_CTL_ENABLE : SDVO_ENABLE; + enabled_bits = HAS_DDI(dev) ? DDI_BUF_CTL_ENABLE : SDVO_ENABLE; WARN(I915_READ(intel_hdmi->sdvox_reg) & enabled_bits, "HDMI port enabled, expecting disabled\n"); @@ -331,6 +331,7 @@ static void intel_set_infoframe(struct drm_encoder *encoder, static void intel_hdmi_set_avi_infoframe(struct drm_encoder *encoder, struct drm_display_mode *adjusted_mode) { + struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder); struct dip_infoframe avi_if = { .type = DIP_TYPE_AVI, .ver = DIP_VERSION_AVI, @@ -340,7 +341,14 @@ static void intel_hdmi_set_avi_infoframe(struct drm_encoder *encoder, if (adjusted_mode->flags & DRM_MODE_FLAG_DBLCLK) avi_if.body.avi.YQ_CN_PR |= DIP_AVI_PR_2; - avi_if.body.avi.VIC = drm_mode_cea_vic(adjusted_mode); + if (intel_hdmi->rgb_quant_range_selectable) { + if (adjusted_mode->private_flags & INTEL_MODE_LIMITED_COLOR_RANGE) + avi_if.body.avi.ITC_EC_Q_SC |= DIP_AVI_RGB_QUANT_RANGE_LIMITED; + else + avi_if.body.avi.ITC_EC_Q_SC |= DIP_AVI_RGB_QUANT_RANGE_FULL; + } + + avi_if.body.avi.VIC = drm_match_cea_mode(adjusted_mode); intel_set_infoframe(encoder, &avi_if); } @@ -364,7 +372,8 @@ static void g4x_set_infoframes(struct drm_encoder *encoder, struct drm_display_mode *adjusted_mode) { struct drm_i915_private *dev_priv = encoder->dev->dev_private; - struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder); + struct intel_digital_port *intel_dig_port = enc_to_dig_port(encoder); + struct intel_hdmi *intel_hdmi = &intel_dig_port->hdmi; u32 reg = VIDEO_DIP_CTL; u32 val = I915_READ(reg); u32 port; @@ -391,11 +400,11 @@ static void g4x_set_infoframes(struct drm_encoder *encoder, return; } - switch (intel_hdmi->sdvox_reg) { - case SDVOB: + switch (intel_dig_port->port) { + case PORT_B: port = VIDEO_DIP_PORT_B; break; - case SDVOC: + case PORT_C: port = VIDEO_DIP_PORT_C; break; default: @@ -428,7 +437,8 @@ static void ibx_set_infoframes(struct drm_encoder *encoder, { struct drm_i915_private *dev_priv = encoder->dev->dev_private; struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc); - struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder); + struct intel_digital_port *intel_dig_port = enc_to_dig_port(encoder); + struct intel_hdmi *intel_hdmi = &intel_dig_port->hdmi; u32 reg = TVIDEO_DIP_CTL(intel_crtc->pipe); u32 val = I915_READ(reg); u32 port; @@ -447,14 +457,14 @@ static void ibx_set_infoframes(struct drm_encoder *encoder, return; } - switch (intel_hdmi->sdvox_reg) { - case HDMIB: + switch (intel_dig_port->port) { + case PORT_B: port = VIDEO_DIP_PORT_B; break; - case HDMIC: + case PORT_C: port = VIDEO_DIP_PORT_C; break; - case HDMID: + case PORT_D: port = VIDEO_DIP_PORT_D; break; default: @@ -766,46 +776,38 @@ bool intel_hdmi_mode_fixup(struct drm_encoder *encoder, const struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode) { - return true; -} + struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder); -static bool g4x_hdmi_connected(struct intel_hdmi *intel_hdmi) -{ - struct drm_device *dev = intel_hdmi_to_dev(intel_hdmi); - struct drm_i915_private *dev_priv = dev->dev_private; - uint32_t bit; - - switch (intel_hdmi->sdvox_reg) { - case SDVOB: - bit = HDMIB_HOTPLUG_LIVE_STATUS; - break; - case SDVOC: - bit = HDMIC_HOTPLUG_LIVE_STATUS; - break; - default: - bit = 0; - break; + if (intel_hdmi->color_range_auto) { + /* See CEA-861-E - 5.1 Default Encoding Parameters */ + if (intel_hdmi->has_hdmi_sink && + drm_match_cea_mode(adjusted_mode) > 1) + intel_hdmi->color_range = SDVO_COLOR_RANGE_16_235; + else + intel_hdmi->color_range = 0; } - return I915_READ(PORT_HOTPLUG_STAT) & bit; + if (intel_hdmi->color_range) + adjusted_mode->private_flags |= INTEL_MODE_LIMITED_COLOR_RANGE; + + return true; } static enum drm_connector_status intel_hdmi_detect(struct drm_connector *connector, bool force) { + struct drm_device *dev = connector->dev; struct intel_hdmi *intel_hdmi = intel_attached_hdmi(connector); struct intel_digital_port *intel_dig_port = hdmi_to_dig_port(intel_hdmi); struct intel_encoder *intel_encoder = &intel_dig_port->base; - struct drm_i915_private *dev_priv = connector->dev->dev_private; + struct drm_i915_private *dev_priv = dev->dev_private; struct edid *edid; enum drm_connector_status status = connector_status_disconnected; - if (IS_G4X(connector->dev) && !g4x_hdmi_connected(intel_hdmi)) - return status; - intel_hdmi->has_hdmi_sink = false; intel_hdmi->has_audio = false; + intel_hdmi->rgb_quant_range_selectable = false; edid = drm_get_edid(connector, intel_gmbus_get_adapter(dev_priv, intel_hdmi->ddc_bus)); @@ -817,6 +819,8 @@ intel_hdmi_detect(struct drm_connector *connector, bool force) intel_hdmi->has_hdmi_sink = drm_detect_hdmi_monitor(edid); intel_hdmi->has_audio = drm_detect_monitor_audio(edid); + intel_hdmi->rgb_quant_range_selectable = + drm_rgb_quant_range_selectable(edid); } kfree(edid); } @@ -879,7 +883,7 @@ intel_hdmi_set_property(struct drm_connector *connector, ret = drm_object_property_set_value(&connector->base, property, val); if (ret) return ret; -#if 0 + if (property == dev_priv->force_audio_property) { enum hdmi_force_audio i = val; bool has_audio; @@ -900,24 +904,31 @@ intel_hdmi_set_property(struct drm_connector *connector, intel_hdmi->has_audio = has_audio; goto done; } -#endif if (property == dev_priv->broadcast_rgb_property) { - if (val == !!intel_hdmi->color_range) - return 0; - - intel_hdmi->color_range = val ? SDVO_COLOR_RANGE_16_235 : 0; + switch (val) { + case INTEL_BROADCAST_RGB_AUTO: + intel_hdmi->color_range_auto = true; + break; + case INTEL_BROADCAST_RGB_FULL: + intel_hdmi->color_range_auto = false; + intel_hdmi->color_range = 0; + break; + case INTEL_BROADCAST_RGB_LIMITED: + intel_hdmi->color_range_auto = false; + intel_hdmi->color_range = SDVO_COLOR_RANGE_16_235; + break; + default: + return -EINVAL; + } goto done; } return -EINVAL; done: - if (intel_dig_port->base.base.crtc) { - struct drm_crtc *crtc = intel_dig_port->base.base.crtc; - intel_set_mode(crtc, &crtc->mode, - crtc->x, crtc->y, crtc->fb); - } + if (intel_dig_port->base.base.crtc) + intel_crtc_restore_mode(intel_dig_port->base.base.crtc); return 0; } @@ -932,7 +943,6 @@ static void intel_hdmi_destroy(struct drm_connector *connector) static const struct drm_encoder_helper_funcs intel_hdmi_helper_funcs = { .mode_fixup = intel_hdmi_mode_fixup, .mode_set = intel_hdmi_mode_set, - .disable = intel_encoder_noop, }; static const struct drm_connector_funcs intel_hdmi_connector_funcs = { @@ -958,6 +968,7 @@ intel_hdmi_add_properties(struct intel_hdmi *intel_hdmi, struct drm_connector *c { intel_attach_force_audio_property(connector); intel_attach_broadcast_rgb_property(connector); + intel_hdmi->color_range_auto = true; } void intel_hdmi_init_connector(struct intel_digital_port *intel_dig_port, @@ -981,15 +992,15 @@ void intel_hdmi_init_connector(struct intel_digital_port *intel_dig_port, switch (port) { case PORT_B: intel_hdmi->ddc_bus = GMBUS_PORT_DPB; - dev_priv->hotplug_supported_mask |= HDMIB_HOTPLUG_INT_STATUS; + dev_priv->hotplug_supported_mask |= PORTB_HOTPLUG_INT_STATUS; break; case PORT_C: intel_hdmi->ddc_bus = GMBUS_PORT_DPC; - dev_priv->hotplug_supported_mask |= HDMIC_HOTPLUG_INT_STATUS; + dev_priv->hotplug_supported_mask |= PORTC_HOTPLUG_INT_STATUS; break; case PORT_D: intel_hdmi->ddc_bus = GMBUS_PORT_DPD; - dev_priv->hotplug_supported_mask |= HDMID_HOTPLUG_INT_STATUS; + dev_priv->hotplug_supported_mask |= PORTD_HOTPLUG_INT_STATUS; break; case PORT_A: /* Internal port only for eDP. */ @@ -1014,7 +1025,7 @@ void intel_hdmi_init_connector(struct intel_digital_port *intel_dig_port, intel_hdmi->set_infoframes = cpt_set_infoframes; } - if (IS_HASWELL(dev)) + if (HAS_DDI(dev)) intel_connector->get_hw_state = intel_ddi_connector_get_hw_state; else intel_connector->get_hw_state = intel_connector_get_hw_state; diff --git a/drivers/video/drm/i915/intel_i2c.c b/drivers/video/drm/i915/intel_i2c.c index 3ef5af15b8..ef4744e1bf 100644 --- a/drivers/video/drm/i915/intel_i2c.c +++ b/drivers/video/drm/i915/intel_i2c.c @@ -63,6 +63,7 @@ intel_i2c_reset(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; I915_WRITE(dev_priv->gpio_mmio_base + GMBUS0, 0); + I915_WRITE(dev_priv->gpio_mmio_base + GMBUS4, 0); } static void intel_i2c_quirk_set(struct drm_i915_private *dev_priv, bool enable) @@ -202,6 +203,77 @@ intel_gpio_setup(struct intel_gmbus *bus, u32 pin) algo->data = bus; } +/* + * gmbus on gen4 seems to be able to generate legacy interrupts even when in MSI + * mode. This results in spurious interrupt warnings if the legacy irq no. is + * shared with another device. The kernel then disables that interrupt source + * and so prevents the other device from working properly. + */ +#define HAS_GMBUS_IRQ(dev) (INTEL_INFO(dev)->gen >= 5) +static int +gmbus_wait_hw_status(struct drm_i915_private *dev_priv, + u32 gmbus2_status, + u32 gmbus4_irq_en) +{ + int i; + int reg_offset = dev_priv->gpio_mmio_base; + u32 gmbus2 = 0; + DEFINE_WAIT(wait); + + if (!HAS_GMBUS_IRQ(dev_priv->dev)) + gmbus4_irq_en = 0; + + /* Important: The hw handles only the first bit, so set only one! Since + * we also need to check for NAKs besides the hw ready/idle signal, we + * need to wake up periodically and check that ourselves. */ + I915_WRITE(GMBUS4 + reg_offset, gmbus4_irq_en); + + for (i = 0; i < msecs_to_jiffies(50) + 1; i++) { + prepare_to_wait(&dev_priv->gmbus_wait_queue, &wait, + TASK_UNINTERRUPTIBLE); + + gmbus2 = I915_READ_NOTRACE(GMBUS2 + reg_offset); + if (gmbus2 & (GMBUS_SATOER | gmbus2_status)) + break; + + schedule_timeout(1); + } + finish_wait(&dev_priv->gmbus_wait_queue, &wait); + + I915_WRITE(GMBUS4 + reg_offset, 0); + + if (gmbus2 & GMBUS_SATOER) + return -ENXIO; + if (gmbus2 & gmbus2_status) + return 0; + return -ETIMEDOUT; +} + +static int +gmbus_wait_idle(struct drm_i915_private *dev_priv) +{ + int ret; + int reg_offset = dev_priv->gpio_mmio_base; + +#define C ((I915_READ_NOTRACE(GMBUS2 + reg_offset) & GMBUS_ACTIVE) == 0) + + if (!HAS_GMBUS_IRQ(dev_priv->dev)) + return wait_for(C, 10); + + /* Important: The hw handles only the first bit, so set only one! */ + I915_WRITE(GMBUS4 + reg_offset, GMBUS_IDLE_EN); + + ret = wait_event_timeout(dev_priv->gmbus_wait_queue, C, 10); + + I915_WRITE(GMBUS4 + reg_offset, 0); + + if (ret) + return 0; + else + return -ETIMEDOUT; +#undef C +} + static int gmbus_xfer_read(struct drm_i915_private *dev_priv, struct i2c_msg *msg, u32 gmbus1_index) @@ -219,15 +291,11 @@ gmbus_xfer_read(struct drm_i915_private *dev_priv, struct i2c_msg *msg, while (len) { int ret; u32 val, loop = 0; - u32 gmbus2; - ret = wait_for((gmbus2 = I915_READ(GMBUS2 + reg_offset)) & - (GMBUS_SATOER | GMBUS_HW_RDY), - 50); + ret = gmbus_wait_hw_status(dev_priv, GMBUS_HW_RDY, + GMBUS_HW_RDY_EN); if (ret) - return -ETIMEDOUT; - if (gmbus2 & GMBUS_SATOER) - return -ENXIO; + return ret; val = I915_READ(GMBUS3 + reg_offset); do { @@ -261,7 +329,6 @@ gmbus_xfer_write(struct drm_i915_private *dev_priv, struct i2c_msg *msg) GMBUS_SLAVE_WRITE | GMBUS_SW_RDY); while (len) { int ret; - u32 gmbus2; val = loop = 0; do { @@ -270,13 +337,10 @@ gmbus_xfer_write(struct drm_i915_private *dev_priv, struct i2c_msg *msg) I915_WRITE(GMBUS3 + reg_offset, val); - ret = wait_for((gmbus2 = I915_READ(GMBUS2 + reg_offset)) & - (GMBUS_SATOER | GMBUS_HW_RDY), - 50); + ret = gmbus_wait_hw_status(dev_priv, GMBUS_HW_RDY, + GMBUS_HW_RDY_EN); if (ret) - return -ETIMEDOUT; - if (gmbus2 & GMBUS_SATOER) - return -ENXIO; + return ret; } return 0; } @@ -345,8 +409,6 @@ gmbus_xfer(struct i2c_adapter *adapter, I915_WRITE(GMBUS0 + reg_offset, bus->reg0); for (i = 0; i < num; i++) { - u32 gmbus2; - if (gmbus_is_index_read(msgs, i, num)) { ret = gmbus_xfer_index_read(dev_priv, &msgs[i]); i += 1; /* set i to the index of the read xfer */ @@ -361,13 +423,12 @@ gmbus_xfer(struct i2c_adapter *adapter, if (ret == -ENXIO) goto clear_err; - ret = wait_for((gmbus2 = I915_READ(GMBUS2 + reg_offset)) & - (GMBUS_SATOER | GMBUS_HW_WAIT_PHASE), - 50); + ret = gmbus_wait_hw_status(dev_priv, GMBUS_HW_WAIT_PHASE, + GMBUS_HW_WAIT_EN); + if (ret == -ENXIO) + goto clear_err; if (ret) goto timeout; - if (gmbus2 & GMBUS_SATOER) - goto clear_err; } /* Generate a STOP condition on the bus. Note that gmbus can't generata @@ -380,8 +441,7 @@ gmbus_xfer(struct i2c_adapter *adapter, * We will re-enable it at the start of the next xfer, * till then let it sleep. */ - if (wait_for((I915_READ(GMBUS2 + reg_offset) & GMBUS_ACTIVE) == 0, - 10)) { + if (gmbus_wait_idle(dev_priv)) { DRM_DEBUG_KMS("GMBUS [%s] timed out waiting for idle\n", adapter->name); ret = -ETIMEDOUT; @@ -405,8 +465,7 @@ clear_err: * it's slow responding and only answers on the 2nd retry. */ ret = -ENXIO; - if (wait_for((I915_READ(GMBUS2 + reg_offset) & GMBUS_ACTIVE) == 0, - 10)) { + if (gmbus_wait_idle(dev_priv)) { DRM_DEBUG_KMS("GMBUS [%s] timed out after NAK\n", adapter->name); ret = -ETIMEDOUT; @@ -465,10 +524,13 @@ int intel_setup_gmbus(struct drm_device *dev) if (HAS_PCH_SPLIT(dev)) dev_priv->gpio_mmio_base = PCH_GPIOA - GPIOA; + else if (IS_VALLEYVIEW(dev)) + dev_priv->gpio_mmio_base = VLV_DISPLAY_BASE; else dev_priv->gpio_mmio_base = 0; mutex_init(&dev_priv->gmbus_mutex); + init_waitqueue_head(&dev_priv->gmbus_wait_queue); for (i = 0; i < GMBUS_NUM_PORTS; i++) { struct intel_gmbus *bus = &dev_priv->gmbus[i]; diff --git a/drivers/video/drm/i915/intel_lvds.c b/drivers/video/drm/i915/intel_lvds.c index 0b7156b218..1158bbaa1f 100644 --- a/drivers/video/drm/i915/intel_lvds.c +++ b/drivers/video/drm/i915/intel_lvds.c @@ -51,7 +51,8 @@ struct intel_lvds_encoder { u32 pfit_control; u32 pfit_pgm_ratios; - bool pfit_dirty; + bool is_dual_link; + u32 reg; struct intel_lvds_connector *attached_connector; }; @@ -71,15 +72,10 @@ static bool intel_lvds_get_hw_state(struct intel_encoder *encoder, { struct drm_device *dev = encoder->base.dev; struct drm_i915_private *dev_priv = dev->dev_private; - u32 lvds_reg, tmp; + struct intel_lvds_encoder *lvds_encoder = to_lvds_encoder(&encoder->base); + u32 tmp; - if (HAS_PCH_SPLIT(dev)) { - lvds_reg = PCH_LVDS; - } else { - lvds_reg = LVDS; - } - - tmp = I915_READ(lvds_reg); + tmp = I915_READ(lvds_encoder->reg); if (!(tmp & LVDS_PORT_EN)) return false; @@ -92,6 +88,91 @@ static bool intel_lvds_get_hw_state(struct intel_encoder *encoder, return true; } +/* The LVDS pin pair needs to be on before the DPLLs are enabled. + * This is an exception to the general rule that mode_set doesn't turn + * things on. + */ +static void intel_pre_pll_enable_lvds(struct intel_encoder *encoder) +{ + struct intel_lvds_encoder *lvds_encoder = to_lvds_encoder(&encoder->base); + struct drm_device *dev = encoder->base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_crtc *intel_crtc = to_intel_crtc(encoder->base.crtc); + struct drm_display_mode *fixed_mode = + lvds_encoder->attached_connector->base.panel.fixed_mode; + int pipe = intel_crtc->pipe; + u32 temp; + + temp = I915_READ(lvds_encoder->reg); + temp |= LVDS_PORT_EN | LVDS_A0A2_CLKA_POWER_UP; + + if (HAS_PCH_CPT(dev)) { + temp &= ~PORT_TRANS_SEL_MASK; + temp |= PORT_TRANS_SEL_CPT(pipe); + } else { + if (pipe == 1) { + temp |= LVDS_PIPEB_SELECT; + } else { + temp &= ~LVDS_PIPEB_SELECT; + } + } + + /* set the corresponsding LVDS_BORDER bit */ + temp |= dev_priv->lvds_border_bits; + /* Set the B0-B3 data pairs corresponding to whether we're going to + * set the DPLLs for dual-channel mode or not. + */ + if (lvds_encoder->is_dual_link) + temp |= LVDS_B0B3_POWER_UP | LVDS_CLKB_POWER_UP; + else + temp &= ~(LVDS_B0B3_POWER_UP | LVDS_CLKB_POWER_UP); + + /* It would be nice to set 24 vs 18-bit mode (LVDS_A3_POWER_UP) + * appropriately here, but we need to look more thoroughly into how + * panels behave in the two modes. + */ + + /* Set the dithering flag on LVDS as needed, note that there is no + * special lvds dither control bit on pch-split platforms, dithering is + * only controlled through the PIPECONF reg. */ + if (INTEL_INFO(dev)->gen == 4) { + if (dev_priv->lvds_dither) + temp |= LVDS_ENABLE_DITHER; + else + temp &= ~LVDS_ENABLE_DITHER; + } + temp &= ~(LVDS_HSYNC_POLARITY | LVDS_VSYNC_POLARITY); + if (fixed_mode->flags & DRM_MODE_FLAG_NHSYNC) + temp |= LVDS_HSYNC_POLARITY; + if (fixed_mode->flags & DRM_MODE_FLAG_NVSYNC) + temp |= LVDS_VSYNC_POLARITY; + + I915_WRITE(lvds_encoder->reg, temp); +} + +static void intel_pre_enable_lvds(struct intel_encoder *encoder) +{ + struct drm_device *dev = encoder->base.dev; + struct intel_lvds_encoder *enc = to_lvds_encoder(&encoder->base); + struct drm_i915_private *dev_priv = dev->dev_private; + + if (HAS_PCH_SPLIT(dev) || !enc->pfit_control) + return; + + /* + * Enable automatic panel scaling so that non-native modes + * fill the screen. The panel fitter should only be + * adjusted whilst the pipe is disabled, according to + * register description and PRM. + */ + DRM_DEBUG_KMS("applying panel-fitter: %x, %x\n", + enc->pfit_control, + enc->pfit_pgm_ratios); + + I915_WRITE(PFIT_PGM_RATIOS, enc->pfit_pgm_ratios); + I915_WRITE(PFIT_CONTROL, enc->pfit_control); +} + /** * Sets the power state for the panel. */ @@ -101,38 +182,20 @@ static void intel_enable_lvds(struct intel_encoder *encoder) struct intel_lvds_encoder *lvds_encoder = to_lvds_encoder(&encoder->base); struct intel_crtc *intel_crtc = to_intel_crtc(encoder->base.crtc); struct drm_i915_private *dev_priv = dev->dev_private; - u32 ctl_reg, lvds_reg, stat_reg; + u32 ctl_reg, stat_reg; if (HAS_PCH_SPLIT(dev)) { ctl_reg = PCH_PP_CONTROL; - lvds_reg = PCH_LVDS; stat_reg = PCH_PP_STATUS; } else { ctl_reg = PP_CONTROL; - lvds_reg = LVDS; stat_reg = PP_STATUS; } - I915_WRITE(lvds_reg, I915_READ(lvds_reg) | LVDS_PORT_EN); - - if (lvds_encoder->pfit_dirty) { - /* - * Enable automatic panel scaling so that non-native modes - * fill the screen. The panel fitter should only be - * adjusted whilst the pipe is disabled, according to - * register description and PRM. - */ - DRM_DEBUG_KMS("applying panel-fitter: %x, %x\n", - lvds_encoder->pfit_control, - lvds_encoder->pfit_pgm_ratios); - - I915_WRITE(PFIT_PGM_RATIOS, lvds_encoder->pfit_pgm_ratios); - I915_WRITE(PFIT_CONTROL, lvds_encoder->pfit_control); - lvds_encoder->pfit_dirty = false; - } + I915_WRITE(lvds_encoder->reg, I915_READ(lvds_encoder->reg) | LVDS_PORT_EN); I915_WRITE(ctl_reg, I915_READ(ctl_reg) | POWER_TARGET_ON); - POSTING_READ(lvds_reg); + POSTING_READ(lvds_encoder->reg); if (wait_for((I915_READ(stat_reg) & PP_ON) != 0, 1000)) DRM_ERROR("timed out waiting for panel to power on\n"); @@ -144,15 +207,13 @@ static void intel_disable_lvds(struct intel_encoder *encoder) struct drm_device *dev = encoder->base.dev; struct intel_lvds_encoder *lvds_encoder = to_lvds_encoder(&encoder->base); struct drm_i915_private *dev_priv = dev->dev_private; - u32 ctl_reg, lvds_reg, stat_reg; + u32 ctl_reg, stat_reg; if (HAS_PCH_SPLIT(dev)) { ctl_reg = PCH_PP_CONTROL; - lvds_reg = PCH_LVDS; stat_reg = PCH_PP_STATUS; } else { ctl_reg = PP_CONTROL; - lvds_reg = LVDS; stat_reg = PP_STATUS; } @@ -162,13 +223,8 @@ static void intel_disable_lvds(struct intel_encoder *encoder) if (wait_for((I915_READ(stat_reg) & PP_ON) == 0, 1000)) DRM_ERROR("timed out waiting for panel to power off\n"); - if (lvds_encoder->pfit_control) { - I915_WRITE(PFIT_CONTROL, 0); - lvds_encoder->pfit_dirty = true; - } - - I915_WRITE(lvds_reg, I915_READ(lvds_reg) & ~LVDS_PORT_EN); - POSTING_READ(lvds_reg); + I915_WRITE(lvds_encoder->reg, I915_READ(lvds_encoder->reg) & ~LVDS_PORT_EN); + POSTING_READ(lvds_encoder->reg); } static int intel_lvds_mode_valid(struct drm_connector *connector, @@ -406,7 +462,6 @@ out: pfit_pgm_ratios != lvds_encoder->pfit_pgm_ratios) { lvds_encoder->pfit_control = pfit_control; lvds_encoder->pfit_pgm_ratios = pfit_pgm_ratios; - lvds_encoder->pfit_dirty = true; } dev_priv->lvds_border_bits = border; @@ -493,13 +548,14 @@ static const struct dmi_system_id intel_no_modeset_on_lid[] = { #if 0 /* - * Lid events. Note the use of 'modeset_on_lid': - * - we set it on lid close, and reset it on open + * Lid events. Note the use of 'modeset': + * - we set it to MODESET_ON_LID_OPEN on lid close, + * and set it to MODESET_DONE on open * - we use it as a "only once" bit (ie we ignore - * duplicate events where it was already properly - * set/reset) - * - the suspend/resume paths will also set it to - * zero, since they restore the mode ("lid open"). + * duplicate events where it was already properly set) + * - the suspend/resume paths will set it to + * MODESET_SUSPENDED and ignore the lid open event, + * because they restore the mode ("lid open"). */ static int intel_lid_notify(struct notifier_block *nb, unsigned long val, void *unused) @@ -513,6 +569,9 @@ static int intel_lid_notify(struct notifier_block *nb, unsigned long val, if (dev->switch_power_state != DRM_SWITCH_POWER_ON) return NOTIFY_OK; + mutex_lock(&dev_priv->modeset_restore_lock); + if (dev_priv->modeset_restore == MODESET_SUSPENDED) + goto exit; /* * check and update the status of LVDS connector after receiving * the LID nofication event. @@ -521,21 +580,24 @@ static int intel_lid_notify(struct notifier_block *nb, unsigned long val, /* Don't force modeset on machines where it causes a GPU lockup */ if (dmi_check_system(intel_no_modeset_on_lid)) - return NOTIFY_OK; + goto exit; if (!acpi_lid_open()) { - dev_priv->modeset_on_lid = 1; - return NOTIFY_OK; + /* do modeset on next lid open event */ + dev_priv->modeset_restore = MODESET_ON_LID_OPEN; + goto exit; } - if (!dev_priv->modeset_on_lid) - return NOTIFY_OK; + if (dev_priv->modeset_restore == MODESET_DONE) + goto exit; - dev_priv->modeset_on_lid = 0; - - mutex_lock(&dev->mode_config.mutex); + drm_modeset_lock_all(dev); intel_modeset_setup_hw_state(dev, true); - mutex_unlock(&dev->mode_config.mutex); + drm_modeset_unlock_all(dev); + dev_priv->modeset_restore = MODESET_DONE; + +exit: + mutex_unlock(&dev_priv->modeset_restore_lock); return NOTIFY_OK; } #endif @@ -591,8 +653,7 @@ static int intel_lvds_set_property(struct drm_connector *connector, * If the CRTC is enabled, the display will be changed * according to the new panel fitting mode. */ - intel_set_mode(crtc, &crtc->mode, - crtc->x, crtc->y, crtc->fb); + intel_crtc_restore_mode(crtc); } } @@ -602,7 +663,6 @@ static int intel_lvds_set_property(struct drm_connector *connector, static const struct drm_encoder_helper_funcs intel_lvds_helper_funcs = { .mode_fixup = intel_lvds_mode_fixup, .mode_set = intel_lvds_mode_set, - .disable = intel_encoder_noop, }; static const struct drm_connector_helper_funcs intel_lvds_connector_helper_funcs = { @@ -895,6 +955,53 @@ static bool lvds_is_present_in_vbt(struct drm_device *dev, return false; } +static int intel_dual_link_lvds_callback(const struct dmi_system_id *id) +{ + DRM_INFO("Forcing lvds to dual link mode on %s\n", id->ident); + return 1; +} +bool intel_is_dual_link_lvds(struct drm_device *dev) +{ + struct intel_encoder *encoder; + struct intel_lvds_encoder *lvds_encoder; + + list_for_each_entry(encoder, &dev->mode_config.encoder_list, + base.head) { + if (encoder->type == INTEL_OUTPUT_LVDS) { + lvds_encoder = to_lvds_encoder(&encoder->base); + + return lvds_encoder->is_dual_link; + } + } + + return false; +} + +static bool compute_is_dual_link_lvds(struct intel_lvds_encoder *lvds_encoder) +{ + struct drm_device *dev = lvds_encoder->base.base.dev; + unsigned int val; + struct drm_i915_private *dev_priv = dev->dev_private; + + /* use the module option value if specified */ + if (i915_lvds_channel_mode > 0) + return i915_lvds_channel_mode == 2; + +// if (dmi_check_system(intel_dual_link_lvds)) +// return true; + + /* BIOS should set the proper LVDS register value at boot, but + * in reality, it doesn't set the value when the lid is closed; + * we need to check "the value to be set" in VBT when LVDS + * register is uninitialized. + */ + val = I915_READ(lvds_encoder->reg); + if (!(val & ~(LVDS_PIPE_MASK | LVDS_DETECTED))) + val = dev_priv->bios_lvds_val; + + return (val & LVDS_CLKB_POWER_MASK) == LVDS_CLKB_POWER_UP; +} + static bool intel_lvds_supported(struct drm_device *dev) { /* With the introduction of the PCH we gained a dedicated @@ -980,6 +1087,8 @@ bool intel_lvds_init(struct drm_device *dev) DRM_MODE_ENCODER_LVDS); intel_encoder->enable = intel_enable_lvds; + intel_encoder->pre_enable = intel_pre_enable_lvds; + intel_encoder->pre_pll_enable = intel_pre_pll_enable_lvds; intel_encoder->disable = intel_disable_lvds; intel_encoder->get_hw_state = intel_lvds_get_hw_state; intel_connector->get_hw_state = intel_connector_get_hw_state; @@ -1001,6 +1110,12 @@ bool intel_lvds_init(struct drm_device *dev) connector->interlace_allowed = false; connector->doublescan_allowed = false; + if (HAS_PCH_SPLIT(dev)) { + lvds_encoder->reg = PCH_LVDS; + } else { + lvds_encoder->reg = LVDS; + } + /* create the scaling mode property */ drm_mode_create_scaling_mode_property(dev); drm_object_attach_property(&connector->base, @@ -1101,6 +1216,10 @@ bool intel_lvds_init(struct drm_device *dev) goto failed; out: + lvds_encoder->is_dual_link = compute_is_dual_link_lvds(lvds_encoder); + DRM_DEBUG_KMS("detected %s-link lvds configuration\n", + lvds_encoder->is_dual_link ? "dual" : "single"); + /* * Unlock registers and just * leave them unlocked diff --git a/drivers/video/drm/i915/intel_modes.c b/drivers/video/drm/i915/intel_modes.c index 6c3f00291a..fd117ed2f5 100644 --- a/drivers/video/drm/i915/intel_modes.c +++ b/drivers/video/drm/i915/intel_modes.c @@ -28,7 +28,6 @@ #include #include #include -#include #include "intel_drv.h" #include "i915_drv.h" @@ -85,7 +84,7 @@ intel_attach_force_audio_property(struct drm_connector *connector) struct drm_device *dev = connector->dev; struct drm_i915_private *dev_priv = dev->dev_private; struct drm_property *prop; -#if 0 + prop = dev_priv->force_audio_property; if (prop == NULL) { prop = drm_property_create_enum(dev, 0, @@ -98,12 +97,12 @@ intel_attach_force_audio_property(struct drm_connector *connector) dev_priv->force_audio_property = prop; } drm_object_attach_property(&connector->base, prop, 0); -#endif } static const struct drm_prop_enum_list broadcast_rgb_names[] = { - { 0, "Full" }, - { 1, "Limited 16:235" }, + { INTEL_BROADCAST_RGB_AUTO, "Automatic" }, + { INTEL_BROADCAST_RGB_FULL, "Full" }, + { INTEL_BROADCAST_RGB_LIMITED, "Limited 16:235" }, }; void @@ -112,7 +111,7 @@ intel_attach_broadcast_rgb_property(struct drm_connector *connector) struct drm_device *dev = connector->dev; struct drm_i915_private *dev_priv = dev->dev_private; struct drm_property *prop; -#if 0 + prop = dev_priv->broadcast_rgb_property; if (prop == NULL) { prop = drm_property_create_enum(dev, DRM_MODE_PROP_ENUM, @@ -126,5 +125,4 @@ intel_attach_broadcast_rgb_property(struct drm_connector *connector) } drm_object_attach_property(&connector->base, prop, 0); -#endif } diff --git a/drivers/video/drm/i915/intel_pm.c b/drivers/video/drm/i915/intel_pm.c index 0ef698d61c..750dea02d7 100644 --- a/drivers/video/drm/i915/intel_pm.c +++ b/drivers/video/drm/i915/intel_pm.c @@ -470,12 +470,6 @@ void intel_update_fbc(struct drm_device *dev) dev_priv->no_fbc_reason = FBC_MODULE_PARAM; goto out_disable; } - if (intel_fb->obj->base.size > dev_priv->cfb_size) { - DRM_DEBUG_KMS("framebuffer too large, disabling " - "compression\n"); - dev_priv->no_fbc_reason = FBC_STOLEN_TOO_SMALL; - goto out_disable; - } if ((crtc->mode.flags & DRM_MODE_FLAG_INTERLACE) || (crtc->mode.flags & DRM_MODE_FLAG_DBLSCAN)) { DRM_DEBUG_KMS("mode incompatible with compression, " @@ -509,6 +503,14 @@ void intel_update_fbc(struct drm_device *dev) if (in_dbg_master()) goto out_disable; + if (i915_gem_stolen_setup_compression(dev, intel_fb->obj->base.size)) { + DRM_INFO("not enough stolen space for compressed buffer (need %zd bytes), disabling\n", intel_fb->obj->base.size); + DRM_INFO("hint: you may be able to increase stolen memory size in the BIOS to avoid this\n"); + DRM_DEBUG_KMS("framebuffer too large, disabling compression\n"); + dev_priv->no_fbc_reason = FBC_STOLEN_TOO_SMALL; + goto out_disable; + } + /* If the scanout has not changed, don't modify the FBC settings. * Note that we make the fundamental assumption that the fb->obj * cannot be unpinned (and have its GTT offset and fence revoked) @@ -556,6 +558,7 @@ out_disable: DRM_DEBUG_KMS("unsupported config, disabling FBC\n"); intel_disable_fbc(dev); } + i915_gem_stolen_cleanup_compression(dev); } static void i915_pineview_get_mem_freq(struct drm_device *dev) @@ -2309,7 +2312,6 @@ err_unpin: i915_gem_object_unpin(ctx); err_unref: drm_gem_object_unreference(&ctx->base); - mutex_unlock(&dev->struct_mutex); return NULL; } @@ -2595,7 +2597,7 @@ static void gen6_enable_rps(struct drm_device *dev) I915_WRITE(GEN6_RC_SLEEP, 0); I915_WRITE(GEN6_RC1e_THRESHOLD, 1000); I915_WRITE(GEN6_RC6_THRESHOLD, 50000); - I915_WRITE(GEN6_RC6p_THRESHOLD, 100000); + I915_WRITE(GEN6_RC6p_THRESHOLD, 150000); I915_WRITE(GEN6_RC6pp_THRESHOLD, 64000); /* unused */ /* Check if we are enabling RC6 */ @@ -3465,6 +3467,7 @@ void intel_disable_gt_powersave(struct drm_device *dev) ironlake_disable_rc6(dev); } else if (INTEL_INFO(dev)->gen >= 6 && !IS_VALLEYVIEW(dev)) { gen6_disable_rps(dev); + mutex_unlock(&dev_priv->rps.hw_lock); } } @@ -3590,6 +3593,19 @@ static void cpt_init_clock_gating(struct drm_device *dev) } } +static void gen6_check_mch_setup(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + uint32_t tmp; + + tmp = I915_READ(MCH_SSKPD); + if ((tmp & MCH_SSKPD_WM0_MASK) != MCH_SSKPD_WM0_VAL) { + DRM_INFO("Wrong MCH_SSKPD value: 0x%08x\n", tmp); + DRM_INFO("This can cause pipe underruns and display issues.\n"); + DRM_INFO("Please upgrade your BIOS to fix this.\n"); + } +} + static void gen6_init_clock_gating(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; @@ -3682,6 +3698,8 @@ static void gen6_init_clock_gating(struct drm_device *dev) I915_WRITE(GEN6_GT_MODE, _MASKED_BIT_ENABLE(GEN6_GT_MODE_HI)); cpt_init_clock_gating(dev); + + gen6_check_mch_setup(dev); } static void gen7_setup_fixed_func_scheduler(struct drm_i915_private *dev_priv) @@ -3693,6 +3711,10 @@ static void gen7_setup_fixed_func_scheduler(struct drm_i915_private *dev_priv) reg |= GEN7_FF_VS_SCHED_HW; reg |= GEN7_FF_DS_SCHED_HW; + /* WaVSRefCountFullforceMissDisable */ + if (IS_HASWELL(dev_priv->dev)) + reg &= ~GEN7_FF_VS_REF_CNT_FFME; + I915_WRITE(GEN7_FF_THREAD_MODE, reg); } @@ -3863,6 +3885,8 @@ static void ivybridge_init_clock_gating(struct drm_device *dev) I915_WRITE(GEN6_MBCUNIT_SNPCR, snpcr); cpt_init_clock_gating(dev); + + gen6_check_mch_setup(dev); } static void valleyview_init_clock_gating(struct drm_device *dev) @@ -4056,35 +4080,57 @@ void intel_init_clock_gating(struct drm_device *dev) dev_priv->display.init_clock_gating(dev); } -/* Starting with Haswell, we have different power wells for - * different parts of the GPU. This attempts to enable them all. - */ -void intel_init_power_wells(struct drm_device *dev) +void intel_set_power_well(struct drm_device *dev, bool enable) { struct drm_i915_private *dev_priv = dev->dev_private; - unsigned long power_wells[] = { - HSW_PWR_WELL_CTL1, - HSW_PWR_WELL_CTL2, - HSW_PWR_WELL_CTL4 - }; - int i; + bool is_enabled, enable_requested; + uint32_t tmp; if (!IS_HASWELL(dev)) return; - mutex_lock(&dev->struct_mutex); + tmp = I915_READ(HSW_PWR_WELL_DRIVER); + is_enabled = tmp & HSW_PWR_WELL_STATE; + enable_requested = tmp & HSW_PWR_WELL_ENABLE; - for (i = 0; i < ARRAY_SIZE(power_wells); i++) { - int well = I915_READ(power_wells[i]); + if (enable) { + if (!enable_requested) + I915_WRITE(HSW_PWR_WELL_DRIVER, HSW_PWR_WELL_ENABLE); - if ((well & HSW_PWR_WELL_STATE) == 0) { - I915_WRITE(power_wells[i], well & HSW_PWR_WELL_ENABLE); - if (wait_for((I915_READ(power_wells[i]) & HSW_PWR_WELL_STATE), 20)) - DRM_ERROR("Error enabling power well %lx\n", power_wells[i]); + if (!is_enabled) { + DRM_DEBUG_KMS("Enabling power well\n"); + if (wait_for((I915_READ(HSW_PWR_WELL_DRIVER) & + HSW_PWR_WELL_STATE), 20)) + DRM_ERROR("Timeout enabling power well\n"); } + } else { + if (enable_requested) { + I915_WRITE(HSW_PWR_WELL_DRIVER, 0); + DRM_DEBUG_KMS("Requesting to disable the power well\n"); } + } +} - mutex_unlock(&dev->struct_mutex); +/* + * Starting with Haswell, we have a "Power Down Well" that can be turned off + * when not needed anymore. We have 4 registers that can request the power well + * to be enabled, and it will only be disabled if none of the registers is + * requesting it to be enabled. + */ +void intel_init_power_well(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + + if (!IS_HASWELL(dev)) + return; + + /* For now, we need the power well to be always enabled. */ + intel_set_power_well(dev, true); + + /* We're taking over the BIOS, so clear any requests made by it since + * the driver is in charge now. */ + if (I915_READ(HSW_PWR_WELL_BIOS) & HSW_PWR_WELL_ENABLE) + I915_WRITE(HSW_PWR_WELL_BIOS, 0); } /* Set up chip specific power management-related functions */ diff --git a/drivers/video/drm/i915/intel_ringbuffer.c b/drivers/video/drm/i915/intel_ringbuffer.c index cb1fa7dc7b..b4bb7e73b6 100644 --- a/drivers/video/drm/i915/intel_ringbuffer.c +++ b/drivers/video/drm/i915/intel_ringbuffer.c @@ -320,6 +320,7 @@ gen7_render_ring_flush(struct intel_ring_buffer *ring, * TLB invalidate requires a post-sync write. */ flags |= PIPE_CONTROL_QW_WRITE; + flags |= PIPE_CONTROL_GLOBAL_GTT_IVB; /* Workaround: we must issue a pipe_control with CS-stall bit * set before a pipe_control command that has the state cache @@ -333,7 +334,7 @@ gen7_render_ring_flush(struct intel_ring_buffer *ring, intel_ring_emit(ring, GFX_OP_PIPE_CONTROL(4)); intel_ring_emit(ring, flags); - intel_ring_emit(ring, scratch_addr | PIPE_CONTROL_GLOBAL_GTT); + intel_ring_emit(ring, scratch_addr); intel_ring_emit(ring, 0); intel_ring_advance(ring); @@ -465,6 +466,9 @@ init_pipe_control(struct intel_ring_buffer *ring) if (pc->cpu_page == NULL) goto err_unpin; + DRM_DEBUG_DRIVER("%s pipe control offset: 0x%08x\n", + ring->name, pc->gtt_offset); + pc->obj = obj; ring->private = pc; return 0; @@ -556,6 +560,8 @@ static int init_render_ring(struct intel_ring_buffer *ring) static void render_ring_cleanup(struct intel_ring_buffer *ring) { + struct drm_device *dev = ring->dev; + if (!ring->private) return; @@ -605,6 +611,13 @@ gen6_add_request(struct intel_ring_buffer *ring) return 0; } +static inline bool i915_gem_has_seqno_wrapped(struct drm_device *dev, + u32 seqno) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + return dev_priv->last_seqno < seqno; +} + /** * intel_ring_sync - sync the waiter to the signaller on seqno * @@ -635,11 +648,20 @@ gen6_ring_sync(struct intel_ring_buffer *waiter, if (ret) return ret; + /* If seqno wrap happened, omit the wait with no-ops */ + if (likely(!i915_gem_has_seqno_wrapped(waiter->dev, seqno))) { intel_ring_emit(waiter, - dw1 | signaller->semaphore_register[waiter->id]); + dw1 | + signaller->semaphore_register[waiter->id]); intel_ring_emit(waiter, seqno); intel_ring_emit(waiter, 0); intel_ring_emit(waiter, MI_NOOP); + } else { + intel_ring_emit(waiter, MI_NOOP); + intel_ring_emit(waiter, MI_NOOP); + intel_ring_emit(waiter, MI_NOOP); + intel_ring_emit(waiter, MI_NOOP); + } intel_ring_advance(waiter); return 0; @@ -720,6 +742,12 @@ ring_get_seqno(struct intel_ring_buffer *ring, bool lazy_coherency) return intel_read_status_page(ring, I915_GEM_HWS_INDEX); } +static void +ring_set_seqno(struct intel_ring_buffer *ring, u32 seqno) +{ + intel_write_status_page(ring, I915_GEM_HWS_INDEX, seqno); +} + static u32 pc_render_get_seqno(struct intel_ring_buffer *ring, bool lazy_coherency) { @@ -727,6 +755,13 @@ pc_render_get_seqno(struct intel_ring_buffer *ring, bool lazy_coherency) return pc->cpu_page[0]; } +static void +pc_render_set_seqno(struct intel_ring_buffer *ring, u32 seqno) +{ + struct pipe_control *pc = ring->private; + pc->cpu_page[0] = seqno; +} + static bool gen5_ring_get_irq(struct intel_ring_buffer *ring) { @@ -1156,6 +1191,10 @@ static int intel_init_ring_buffer(struct drm_device *dev, return ret; } + obj = NULL; + if (!HAS_LLC(dev)) + obj = i915_gem_object_create_stolen(dev, ring->size); + if (obj == NULL) obj = i915_gem_alloc_object(dev, ring->size); if (obj == NULL) { DRM_ERROR("Failed to allocate ringbuffer\n"); @@ -1174,7 +1213,7 @@ static int intel_init_ring_buffer(struct drm_device *dev, goto err_unpin; ring->virtual_start = - ioremap(dev_priv->mm.gtt->gma_bus_addr + obj->gtt_offset, + ioremap_wc(dev_priv->gtt.mappable_base + obj->gtt_offset, ring->size); if (ring->virtual_start == NULL) { DRM_ERROR("Failed to map ringbuffer.\n"); @@ -1197,7 +1236,7 @@ static int intel_init_ring_buffer(struct drm_device *dev, return 0; err_unmap: - FreeKernelSpace(ring->virtual_start); + iounmap(ring->virtual_start); err_unpin: i915_gem_object_unpin(obj); err_unref: @@ -1225,7 +1264,7 @@ void intel_cleanup_ring_buffer(struct intel_ring_buffer *ring) I915_WRITE_CTL(ring, 0); -// drm_core_ioremapfree(&ring->map, ring->dev); + iounmap(ring->virtual_start); i915_gem_object_unpin(ring->obj); drm_gem_object_unreference(&ring->obj->base); @@ -1334,7 +1373,8 @@ static int ring_wait_for_space(struct intel_ring_buffer *ring, int n) msleep(1); - ret = i915_gem_check_wedge(dev_priv, dev_priv->mm.interruptible); + ret = i915_gem_check_wedge(&dev_priv->gpu_error, + dev_priv->mm.interruptible); if (ret) return ret; } while (!time_after(GetTimerTicks(), end)); @@ -1396,14 +1436,35 @@ intel_ring_alloc_seqno(struct intel_ring_buffer *ring) return i915_gem_get_seqno(ring->dev, &ring->outstanding_lazy_request); } +static int __intel_ring_begin(struct intel_ring_buffer *ring, + int bytes) +{ + int ret; + + if (unlikely(ring->tail + bytes > ring->effective_size)) { + ret = intel_wrap_ring_buffer(ring); + if (unlikely(ret)) + return ret; + } + + if (unlikely(ring->space < bytes)) { + ret = ring_wait_for_space(ring, bytes); + if (unlikely(ret)) + return ret; + } + + ring->space -= bytes; + return 0; +} + int intel_ring_begin(struct intel_ring_buffer *ring, int num_dwords) { drm_i915_private_t *dev_priv = ring->dev->dev_private; - int n = 4*num_dwords; int ret; - ret = i915_gem_check_wedge(dev_priv, dev_priv->mm.interruptible); + ret = i915_gem_check_wedge(&dev_priv->gpu_error, + dev_priv->mm.interruptible); if (ret) return ret; @@ -1412,20 +1473,21 @@ int intel_ring_begin(struct intel_ring_buffer *ring, if (ret) return ret; - if (unlikely(ring->tail + n > ring->effective_size)) { - ret = intel_wrap_ring_buffer(ring); - if (unlikely(ret)) - return ret; + return __intel_ring_begin(ring, num_dwords * sizeof(uint32_t)); +} + +void intel_ring_init_seqno(struct intel_ring_buffer *ring, u32 seqno) +{ + struct drm_i915_private *dev_priv = ring->dev->dev_private; + + BUG_ON(ring->outstanding_lazy_request); + + if (INTEL_INFO(ring->dev)->gen >= 6) { + I915_WRITE(RING_SYNC_0(ring->mmio_base), 0); + I915_WRITE(RING_SYNC_1(ring->mmio_base), 0); } - if (unlikely(ring->space < n)) { - ret = ring_wait_for_space(ring, n); - if (unlikely(ret)) - return ret; - } - - ring->space -= n; - return 0; + ring->set_seqno(ring, seqno); } void intel_ring_advance(struct intel_ring_buffer *ring) @@ -1433,7 +1495,7 @@ void intel_ring_advance(struct intel_ring_buffer *ring) struct drm_i915_private *dev_priv = ring->dev->dev_private; ring->tail &= ring->size - 1; - if (dev_priv->stop_rings & intel_ring_flag(ring)) + if (dev_priv->gpu_error.stop_rings & intel_ring_flag(ring)) return; ring->write_tail(ring, ring->tail); } @@ -1590,6 +1652,7 @@ int intel_init_render_ring_buffer(struct drm_device *dev) ring->irq_put = gen6_ring_put_irq; ring->irq_enable_mask = GT_USER_INTERRUPT; ring->get_seqno = gen6_ring_get_seqno; + ring->set_seqno = ring_set_seqno; ring->sync_to = gen6_ring_sync; ring->semaphore_register[0] = MI_SEMAPHORE_SYNC_INVALID; ring->semaphore_register[1] = MI_SEMAPHORE_SYNC_RV; @@ -1600,6 +1663,7 @@ int intel_init_render_ring_buffer(struct drm_device *dev) ring->add_request = pc_render_add_request; ring->flush = gen4_render_ring_flush; ring->get_seqno = pc_render_get_seqno; + ring->set_seqno = pc_render_set_seqno; ring->irq_get = gen5_ring_get_irq; ring->irq_put = gen5_ring_put_irq; ring->irq_enable_mask = GT_USER_INTERRUPT | GT_PIPE_NOTIFY; @@ -1610,6 +1674,7 @@ int intel_init_render_ring_buffer(struct drm_device *dev) else ring->flush = gen4_render_ring_flush; ring->get_seqno = ring_get_seqno; + ring->set_seqno = ring_set_seqno; if (IS_GEN2(dev)) { ring->irq_get = i8xx_ring_get_irq; ring->irq_put = i8xx_ring_put_irq; @@ -1682,6 +1747,7 @@ int intel_render_ring_init_dri(struct drm_device *dev, u64 start, u32 size) else ring->flush = gen4_render_ring_flush; ring->get_seqno = ring_get_seqno; + ring->set_seqno = ring_set_seqno; if (IS_GEN2(dev)) { ring->irq_get = i8xx_ring_get_irq; ring->irq_put = i8xx_ring_put_irq; @@ -1743,6 +1809,7 @@ int intel_init_bsd_ring_buffer(struct drm_device *dev) ring->flush = gen6_ring_flush; ring->add_request = gen6_add_request; ring->get_seqno = gen6_ring_get_seqno; + ring->set_seqno = ring_set_seqno; ring->irq_enable_mask = GEN6_BSD_USER_INTERRUPT; ring->irq_get = gen6_ring_get_irq; ring->irq_put = gen6_ring_put_irq; @@ -1758,6 +1825,7 @@ int intel_init_bsd_ring_buffer(struct drm_device *dev) ring->flush = bsd_ring_flush; ring->add_request = i9xx_add_request; ring->get_seqno = ring_get_seqno; + ring->set_seqno = ring_set_seqno; if (IS_GEN5(dev)) { ring->irq_enable_mask = GT_BSD_USER_INTERRUPT; ring->irq_get = gen5_ring_get_irq; @@ -1787,6 +1855,7 @@ int intel_init_blt_ring_buffer(struct drm_device *dev) ring->flush = blt_ring_flush; ring->add_request = gen6_add_request; ring->get_seqno = gen6_ring_get_seqno; + ring->set_seqno = ring_set_seqno; ring->irq_enable_mask = GEN6_BLITTER_USER_INTERRUPT; ring->irq_get = gen6_ring_get_irq; ring->irq_put = gen6_ring_put_irq; diff --git a/drivers/video/drm/i915/intel_ringbuffer.h b/drivers/video/drm/i915/intel_ringbuffer.h index 9baa7c17ad..d75cf1b5d2 100644 --- a/drivers/video/drm/i915/intel_ringbuffer.h +++ b/drivers/video/drm/i915/intel_ringbuffer.h @@ -90,6 +90,8 @@ struct intel_ring_buffer { */ u32 (*get_seqno)(struct intel_ring_buffer *ring, bool lazy_coherency); + void (*set_seqno)(struct intel_ring_buffer *ring, + u32 seqno); int (*dispatch_execbuffer)(struct intel_ring_buffer *ring, u32 offset, u32 length, unsigned flags); @@ -178,6 +180,13 @@ intel_read_status_page(struct intel_ring_buffer *ring, return ring->status_page.page_addr[reg]; } +static inline void +intel_write_status_page(struct intel_ring_buffer *ring, + int reg, u32 value) +{ + ring->status_page.page_addr[reg] = value; +} + /** * Reads a dword out of the status page, which is written to from the command * queue by automatic updates, MI_REPORT_HEAD, MI_STORE_DATA_INDEX, or @@ -208,7 +217,7 @@ static inline void intel_ring_emit(struct intel_ring_buffer *ring, } void intel_ring_advance(struct intel_ring_buffer *ring); int __must_check intel_ring_idle(struct intel_ring_buffer *ring); - +void intel_ring_init_seqno(struct intel_ring_buffer *ring, u32 seqno); int intel_ring_flush_all_caches(struct intel_ring_buffer *ring); int intel_ring_invalidate_all_caches(struct intel_ring_buffer *ring); diff --git a/drivers/video/drm/i915/intel_sdvo.c b/drivers/video/drm/i915/intel_sdvo.c index d0f657d6ca..606fd7f8d1 100644 --- a/drivers/video/drm/i915/intel_sdvo.c +++ b/drivers/video/drm/i915/intel_sdvo.c @@ -112,6 +112,7 @@ struct intel_sdvo { * It is only valid when using TMDS encoding and 8 bit per color mode. */ uint32_t color_range; + bool color_range_auto; /** * This is set if we're going to treat the device as TV-out. @@ -134,6 +135,7 @@ struct intel_sdvo { bool is_hdmi; bool has_hdmi_monitor; bool has_hdmi_audio; + bool rgb_quant_range_selectable; /** * This is set if we detect output of sdvo device as LVDS and @@ -955,7 +957,8 @@ static bool intel_sdvo_write_infoframe(struct intel_sdvo *intel_sdvo, &tx_rate, 1); } -static bool intel_sdvo_set_avi_infoframe(struct intel_sdvo *intel_sdvo) +static bool intel_sdvo_set_avi_infoframe(struct intel_sdvo *intel_sdvo, + const struct drm_display_mode *adjusted_mode) { struct dip_infoframe avi_if = { .type = DIP_TYPE_AVI, @@ -964,6 +967,13 @@ static bool intel_sdvo_set_avi_infoframe(struct intel_sdvo *intel_sdvo) }; uint8_t sdvo_data[4 + sizeof(avi_if.body.avi)]; + if (intel_sdvo->rgb_quant_range_selectable) { + if (adjusted_mode->private_flags & INTEL_MODE_LIMITED_COLOR_RANGE) + avi_if.body.avi.ITC_EC_Q_SC |= DIP_AVI_RGB_QUANT_RANGE_LIMITED; + else + avi_if.body.avi.ITC_EC_Q_SC |= DIP_AVI_RGB_QUANT_RANGE_FULL; + } + intel_dip_infoframe_csum(&avi_if); /* sdvo spec says that the ecc is handled by the hw, and it looks like @@ -1073,6 +1083,18 @@ static bool intel_sdvo_mode_fixup(struct drm_encoder *encoder, multiplier = intel_sdvo_get_pixel_multiplier(adjusted_mode); intel_mode_set_pixel_multiplier(adjusted_mode, multiplier); + if (intel_sdvo->color_range_auto) { + /* See CEA-861-E - 5.1 Default Encoding Parameters */ + if (intel_sdvo->has_hdmi_monitor && + drm_match_cea_mode(adjusted_mode) > 1) + intel_sdvo->color_range = SDVO_COLOR_RANGE_16_235; + else + intel_sdvo->color_range = 0; + } + + if (intel_sdvo->color_range) + adjusted_mode->private_flags |= INTEL_MODE_LIMITED_COLOR_RANGE; + return true; } @@ -1130,7 +1152,7 @@ static void intel_sdvo_mode_set(struct drm_encoder *encoder, intel_sdvo_set_encode(intel_sdvo, SDVO_ENCODE_HDMI); intel_sdvo_set_colorimetry(intel_sdvo, SDVO_COLORIMETRY_RGB256); - intel_sdvo_set_avi_infoframe(intel_sdvo); + intel_sdvo_set_avi_infoframe(intel_sdvo, adjusted_mode); } else intel_sdvo_set_encode(intel_sdvo, SDVO_ENCODE_DVI); @@ -1162,7 +1184,7 @@ static void intel_sdvo_mode_set(struct drm_encoder *encoder, /* The real mode polarity is set by the SDVO commands, using * struct intel_sdvo_dtd. */ sdvox = SDVO_VSYNC_ACTIVE_HIGH | SDVO_HSYNC_ACTIVE_HIGH; - if (intel_sdvo->is_hdmi) + if (!HAS_PCH_SPLIT(dev) && intel_sdvo->is_hdmi) sdvox |= intel_sdvo->color_range; if (INTEL_INFO(dev)->gen < 5) sdvox |= SDVO_BORDER_ENABLE; @@ -1522,6 +1544,8 @@ intel_sdvo_tmds_sink_detect(struct drm_connector *connector) if (intel_sdvo->is_hdmi) { intel_sdvo->has_hdmi_monitor = drm_detect_hdmi_monitor(edid); intel_sdvo->has_hdmi_audio = drm_detect_monitor_audio(edid); + intel_sdvo->rgb_quant_range_selectable = + drm_rgb_quant_range_selectable(edid); } } else status = connector_status_disconnected; @@ -1573,6 +1597,7 @@ intel_sdvo_detect(struct drm_connector *connector, bool force) intel_sdvo->has_hdmi_monitor = false; intel_sdvo->has_hdmi_audio = false; + intel_sdvo->rgb_quant_range_selectable = false; if ((intel_sdvo_connector->output_flag & response) == 0) ret = connector_status_disconnected; @@ -1884,7 +1909,6 @@ intel_sdvo_set_property(struct drm_connector *connector, if (ret) return ret; -#if 0 if (property == dev_priv->force_audio_property) { int i = val; bool has_audio; @@ -1907,13 +1931,23 @@ intel_sdvo_set_property(struct drm_connector *connector, } if (property == dev_priv->broadcast_rgb_property) { - if (val == !!intel_sdvo->color_range) - return 0; - - intel_sdvo->color_range = val ? SDVO_COLOR_RANGE_16_235 : 0; + switch (val) { + case INTEL_BROADCAST_RGB_AUTO: + intel_sdvo->color_range_auto = true; + break; + case INTEL_BROADCAST_RGB_FULL: + intel_sdvo->color_range_auto = false; + intel_sdvo->color_range = 0; + break; + case INTEL_BROADCAST_RGB_LIMITED: + intel_sdvo->color_range_auto = false; + intel_sdvo->color_range = SDVO_COLOR_RANGE_16_235; + break; + default: + return -EINVAL; + } goto done; } -#endif #define CHECK_PROPERTY(name, NAME) \ if (intel_sdvo_connector->name == property) { \ @@ -2008,11 +2042,8 @@ set_value: done: - if (intel_sdvo->base.base.crtc) { - struct drm_crtc *crtc = intel_sdvo->base.base.crtc; - intel_set_mode(crtc, &crtc->mode, - crtc->x, crtc->y, crtc->fb); - } + if (intel_sdvo->base.base.crtc) + intel_crtc_restore_mode(intel_sdvo->base.base.crtc); return 0; #undef CHECK_PROPERTY @@ -2021,7 +2052,6 @@ done: static const struct drm_encoder_helper_funcs intel_sdvo_helper_funcs = { .mode_fixup = intel_sdvo_mode_fixup, .mode_set = intel_sdvo_mode_set, - .disable = intel_encoder_noop, }; static const struct drm_connector_funcs intel_sdvo_connector_funcs = { @@ -2211,13 +2241,16 @@ intel_sdvo_connector_init(struct intel_sdvo_connector *connector, } static void -intel_sdvo_add_hdmi_properties(struct intel_sdvo_connector *connector) +intel_sdvo_add_hdmi_properties(struct intel_sdvo *intel_sdvo, + struct intel_sdvo_connector *connector) { struct drm_device *dev = connector->base.base.dev; intel_attach_force_audio_property(&connector->base.base); - if (INTEL_INFO(dev)->gen >= 4 && IS_MOBILE(dev)) + if (INTEL_INFO(dev)->gen >= 4 && IS_MOBILE(dev)) { intel_attach_broadcast_rgb_property(&connector->base.base); + intel_sdvo->color_range_auto = true; + } } static bool @@ -2265,7 +2298,7 @@ intel_sdvo_dvi_init(struct intel_sdvo *intel_sdvo, int device) intel_sdvo_connector_init(intel_sdvo_connector, intel_sdvo); if (intel_sdvo->is_hdmi) - intel_sdvo_add_hdmi_properties(intel_sdvo_connector); + intel_sdvo_add_hdmi_properties(intel_sdvo, intel_sdvo_connector); return true; } diff --git a/drivers/video/drm/i915/intel_sprite.c b/drivers/video/drm/i915/intel_sprite.c index ff1e6c001a..bc5d0cd051 100644 --- a/drivers/video/drm/i915/intel_sprite.c +++ b/drivers/video/drm/i915/intel_sprite.c @@ -50,6 +50,7 @@ ivb_update_plane(struct drm_plane *plane, struct drm_framebuffer *fb, u32 sprctl, sprscale = 0; unsigned long sprsurf_offset, linear_offset; int pixel_size = drm_format_plane_cpp(fb->pixel_format, 0); + bool scaling_was_enabled = dev_priv->sprite_scaling_enabled; sprctl = I915_READ(SPRCTL(pipe)); @@ -89,6 +90,9 @@ ivb_update_plane(struct drm_plane *plane, struct drm_framebuffer *fb, sprctl |= SPRITE_TRICKLE_FEED_DISABLE; sprctl |= SPRITE_ENABLE; + if (IS_HASWELL(dev)) + sprctl |= SPRITE_PIPE_CSC_ENABLE; + /* Sizes are 0 based */ src_w--; src_h--; @@ -103,26 +107,22 @@ ivb_update_plane(struct drm_plane *plane, struct drm_framebuffer *fb, * when scaling is disabled. */ if (crtc_w != src_w || crtc_h != src_h) { - if (!dev_priv->sprite_scaling_enabled) { - dev_priv->sprite_scaling_enabled = true; + dev_priv->sprite_scaling_enabled |= 1 << pipe; + + if (!scaling_was_enabled) { intel_update_watermarks(dev); intel_wait_for_vblank(dev, pipe); } sprscale = SPRITE_SCALE_ENABLE | (src_w << 16) | src_h; - } else { - if (dev_priv->sprite_scaling_enabled) { - dev_priv->sprite_scaling_enabled = false; - /* potentially re-enable LP watermarks */ - intel_update_watermarks(dev); - } - } + } else + dev_priv->sprite_scaling_enabled &= ~(1 << pipe); I915_WRITE(SPRSTRIDE(pipe), fb->pitches[0]); I915_WRITE(SPRPOS(pipe), (crtc_y << 16) | crtc_x); linear_offset = y * fb->pitches[0] + x * pixel_size; sprsurf_offset = - intel_gen4_compute_offset_xtiled(&x, &y, + intel_gen4_compute_page_offset(&x, &y, obj->tiling_mode, pixel_size, fb->pitches[0]); linear_offset -= sprsurf_offset; @@ -141,6 +141,10 @@ ivb_update_plane(struct drm_plane *plane, struct drm_framebuffer *fb, I915_WRITE(SPRCTL(pipe), sprctl); I915_MODIFY_DISPBASE(SPRSURF(pipe), obj->gtt_offset + sprsurf_offset); POSTING_READ(SPRSURF(pipe)); + + /* potentially re-enable LP watermarks */ + if (scaling_was_enabled && !dev_priv->sprite_scaling_enabled) + intel_update_watermarks(dev); } static void @@ -150,6 +154,7 @@ ivb_disable_plane(struct drm_plane *plane) struct drm_i915_private *dev_priv = dev->dev_private; struct intel_plane *intel_plane = to_intel_plane(plane); int pipe = intel_plane->pipe; + bool scaling_was_enabled = dev_priv->sprite_scaling_enabled; I915_WRITE(SPRCTL(pipe), I915_READ(SPRCTL(pipe)) & ~SPRITE_ENABLE); /* Can't leave the scaler enabled... */ @@ -159,7 +164,10 @@ ivb_disable_plane(struct drm_plane *plane) I915_MODIFY_DISPBASE(SPRSURF(pipe), 0); POSTING_READ(SPRSURF(pipe)); - dev_priv->sprite_scaling_enabled = false; + dev_priv->sprite_scaling_enabled &= ~(1 << pipe); + + /* potentially re-enable LP watermarks */ + if (scaling_was_enabled && !dev_priv->sprite_scaling_enabled) intel_update_watermarks(dev); } @@ -287,7 +295,7 @@ ilk_update_plane(struct drm_plane *plane, struct drm_framebuffer *fb, linear_offset = y * fb->pitches[0] + x * pixel_size; dvssurf_offset = - intel_gen4_compute_offset_xtiled(&x, &y, + intel_gen4_compute_page_offset(&x, &y, obj->tiling_mode, pixel_size, fb->pitches[0]); linear_offset -= dvssurf_offset; @@ -591,7 +599,7 @@ int intel_sprite_set_colorkey(struct drm_device *dev, void *data, if ((set->flags & (I915_SET_COLORKEY_DESTINATION | I915_SET_COLORKEY_SOURCE)) == (I915_SET_COLORKEY_DESTINATION | I915_SET_COLORKEY_SOURCE)) return -EINVAL; - mutex_lock(&dev->mode_config.mutex); + drm_modeset_lock_all(dev); obj = drm_mode_object_find(dev, set->plane_id, DRM_MODE_OBJECT_PLANE); if (!obj) { @@ -604,7 +612,7 @@ int intel_sprite_set_colorkey(struct drm_device *dev, void *data, ret = intel_plane->update_colorkey(plane, set); out_unlock: - mutex_unlock(&dev->mode_config.mutex); + drm_modeset_unlock_all(dev); return ret; } @@ -618,7 +626,7 @@ int intel_sprite_get_colorkey(struct drm_device *dev, void *data, int ret = 0; - mutex_lock(&dev->mode_config.mutex); + drm_modeset_lock_all(dev); obj = drm_mode_object_find(dev, get->plane_id, DRM_MODE_OBJECT_PLANE); if (!obj) { @@ -631,7 +639,7 @@ int intel_sprite_get_colorkey(struct drm_device *dev, void *data, intel_plane->get_colorkey(plane, get); out_unlock: - mutex_unlock(&dev->mode_config.mutex); + drm_modeset_unlock_all(dev); return ret; } diff --git a/drivers/video/drm/i915/kms_display.c b/drivers/video/drm/i915/kms_display.c index 43e5f5c5e4..c2c0be5f94 100644 --- a/drivers/video/drm/i915/kms_display.c +++ b/drivers/video/drm/i915/kms_display.c @@ -480,7 +480,7 @@ int init_cursor(cursor_t *cursor) /* You don't need to worry about fragmentation issues. * GTT space is continuous. I guarantee it. */ - mapped = bits = (u32*)MapIoMem(dev_priv->mm.gtt->gma_bus_addr + obj->gtt_offset, + mapped = bits = (u32*)MapIoMem(dev_priv->gtt.mappable_base + obj->gtt_offset, CURSOR_WIDTH*CURSOR_HEIGHT*4, PG_SW); if (unlikely(bits == NULL)) @@ -681,6 +681,12 @@ int i915_mask_update(struct drm_device *dev, void *data, u32 slot; int ret; + if(mask->handle == -2) + { + printf("%s handle %d\n", __FUNCTION__, mask->handle); + return 0; + } + obj = drm_gem_object_lookup(dev, file, mask->handle); if (obj == NULL) return -ENOENT; @@ -883,6 +889,12 @@ int __queue_work(struct workqueue_struct *wq, return 1; }; +bool queue_work(struct workqueue_struct *wq, struct work_struct *work) +{ + return __queue_work(wq, work); +} + + void __stdcall delayed_work_timer_fn(unsigned long __data) { struct delayed_work *dwork = (struct delayed_work *)__data; @@ -962,4 +974,61 @@ void set_normalized_timespec(struct timespec *ts, time_t sec, long nsec) } +void +prepare_to_wait(wait_queue_head_t *q, wait_queue_t *wait, int state) +{ + unsigned long flags; + +// wait->flags &= ~WQ_FLAG_EXCLUSIVE; + spin_lock_irqsave(&q->lock, flags); + if (list_empty(&wait->task_list)) + __add_wait_queue(q, wait); + spin_unlock_irqrestore(&q->lock, flags); +} + +/** + * finish_wait - clean up after waiting in a queue + * @q: waitqueue waited on + * @wait: wait descriptor + * + * Sets current thread back to running state and removes + * the wait descriptor from the given waitqueue if still + * queued. + */ +void finish_wait(wait_queue_head_t *q, wait_queue_t *wait) +{ + unsigned long flags; + +// __set_current_state(TASK_RUNNING); + /* + * We can check for list emptiness outside the lock + * IFF: + * - we use the "careful" check that verifies both + * the next and prev pointers, so that there cannot + * be any half-pending updates in progress on other + * CPU's that we haven't seen yet (and that might + * still change the stack area. + * and + * - all other users take the lock (ie we can only + * have _one_ other CPU that looks at or modifies + * the list). + */ + if (!list_empty_careful(&wait->task_list)) { + spin_lock_irqsave(&q->lock, flags); + list_del_init(&wait->task_list); + spin_unlock_irqrestore(&q->lock, flags); + } + + DestroyEvent(wait->evnt); +} + +int autoremove_wake_function(wait_queue_t *wait, unsigned mode, int sync, void *key) +{ + list_del_init(&wait->task_list); + return 1; +} + + + + diff --git a/drivers/video/drm/i915/main.c b/drivers/video/drm/i915/main.c index 2a4f1bb68d..324dcd774f 100644 --- a/drivers/video/drm/i915/main.c +++ b/drivers/video/drm/i915/main.c @@ -57,7 +57,7 @@ int x86_clflush_size; int i915_modeset = 1; -u32_t drvEntry(int action, char *cmdline) +u32_t __attribute__((externally_visible)) drvEntry(int action, char *cmdline) { int err = 0; @@ -82,10 +82,10 @@ u32_t drvEntry(int action, char *cmdline) return 0; }; } - dbgprintf("i915 RC 10.5\n cmdline: %s\n", cmdline); + dbgprintf(" i915 v3.9-rc8\n cmdline: %s\n", cmdline); cpu_detect(); - dbgprintf("\ncache line size %d\n", x86_clflush_size); +// dbgprintf("\ncache line size %d\n", x86_clflush_size); enum_pci_devices(); @@ -105,6 +105,14 @@ u32_t drvEntry(int action, char *cmdline) return err; }; +//int __declspec(dllexport) DllMain(int, char*) __attribute__ ((weak, alias ("drvEntry"))); + +//int __declspec(dllexport) DllMain( int hinstDLL, int fdwReason, void *lpReserved ) +//{ +// +// return 1; +//} + #define CURRENT_API 0x0200 /* 2.00 */ #define COMPATIBLE_API 0x0100 /* 1.00 */ @@ -138,7 +146,7 @@ u32_t drvEntry(int action, char *cmdline) #define SRV_I915_GEM_BUSY 28 #define SRV_I915_GEM_SET_DOMAIN 29 #define SRV_I915_GEM_MMAP 30 - +#define SRV_I915_GEM_MMAP_GTT 31 #define SRV_I915_GEM_THROTTLE 32 #define SRV_FBINFO 33 #define SRV_I915_GEM_EXECBUFFER2 34 @@ -267,6 +275,11 @@ int _stdcall display_handler(ioctl_t *io) retval = i915_gem_mmap_ioctl(main_device, inp, file); break; + case SRV_I915_GEM_MMAP_GTT: + retval = i915_gem_mmap_gtt_ioctl(main_device, inp, file); + break; + + case SRV_FBINFO: retval = i915_fbinfo(inp); break; diff --git a/drivers/video/drm/i915/render/exa_wm_mask_affine.g6b b/drivers/video/drm/i915/render/exa_wm_mask_affine.g6b deleted file mode 100644 index e4bef29e96..0000000000 --- a/drivers/video/drm/i915/render/exa_wm_mask_affine.g6b +++ /dev/null @@ -1,4 +0,0 @@ - { 0x0060005a, 0x210077be, 0x00000100, 0x008d0040 }, - { 0x0060005a, 0x212077be, 0x00000100, 0x008d0080 }, - { 0x0060005a, 0x214077be, 0x00000110, 0x008d0040 }, - { 0x0060005a, 0x216077be, 0x00000110, 0x008d0080 }, diff --git a/drivers/video/drm/i915/render/exa_wm_mask_sample_a.g6b b/drivers/video/drm/i915/render/exa_wm_mask_sample_a.g6b deleted file mode 100644 index 6d1eae9379..0000000000 --- a/drivers/video/drm/i915/render/exa_wm_mask_sample_a.g6b +++ /dev/null @@ -1,3 +0,0 @@ - { 0x00000201, 0x20080061, 0x00000000, 0x00007000 }, - { 0x00600001, 0x20e00022, 0x008d0000, 0x00000000 }, - { 0x02800031, 0x23801cc9, 0x000000e0, 0x0a2a0102 }, diff --git a/drivers/video/drm/i915/render/exa_wm_noca.g6b b/drivers/video/drm/i915/render/exa_wm_noca.g6b deleted file mode 100644 index e77ea2dd2d..0000000000 --- a/drivers/video/drm/i915/render/exa_wm_noca.g6b +++ /dev/null @@ -1,4 +0,0 @@ - { 0x00800041, 0x21c077bd, 0x008d01c0, 0x008d0380 }, - { 0x00800041, 0x220077bd, 0x008d0200, 0x008d0380 }, - { 0x00800041, 0x224077bd, 0x008d0240, 0x008d0380 }, - { 0x00800041, 0x228077bd, 0x008d0280, 0x008d0380 }, diff --git a/drivers/video/drm/i915/render/exa_wm_src_affine.g6b b/drivers/video/drm/i915/render/exa_wm_src_affine.g6b deleted file mode 100644 index 7035e6a5ce..0000000000 --- a/drivers/video/drm/i915/render/exa_wm_src_affine.g6b +++ /dev/null @@ -1,4 +0,0 @@ - { 0x0060005a, 0x204077be, 0x000000c0, 0x008d0040 }, - { 0x0060005a, 0x206077be, 0x000000c0, 0x008d0080 }, - { 0x0060005a, 0x208077be, 0x000000d0, 0x008d0040 }, - { 0x0060005a, 0x20a077be, 0x000000d0, 0x008d0080 }, diff --git a/drivers/video/drm/i915/render/exa_wm_src_projective.g6b b/drivers/video/drm/i915/render/exa_wm_src_projective.g6b deleted file mode 100644 index 8e39bffa8a..0000000000 --- a/drivers/video/drm/i915/render/exa_wm_src_projective.g6b +++ /dev/null @@ -1,12 +0,0 @@ - { 0x0060005a, 0x23c077bd, 0x000000e0, 0x008d0040 }, - { 0x0060005a, 0x23e077bd, 0x000000e0, 0x008d0080 }, - { 0x01600038, 0x218003bd, 0x008d03c0, 0x00000000 }, - { 0x01600038, 0x21a003bd, 0x008d03e0, 0x00000000 }, - { 0x0060005a, 0x23c077bd, 0x000000c0, 0x008d0040 }, - { 0x0060005a, 0x23e077bd, 0x000000c0, 0x008d0080 }, - { 0x00600041, 0x204077be, 0x008d03c0, 0x008d0180 }, - { 0x00600041, 0x206077be, 0x008d03e0, 0x008d01a0 }, - { 0x0060005a, 0x23c077bd, 0x000000d0, 0x008d0040 }, - { 0x0060005a, 0x23e077bd, 0x000000d0, 0x008d0080 }, - { 0x00600041, 0x208077be, 0x008d03c0, 0x008d0180 }, - { 0x00600041, 0x20a077be, 0x008d03e0, 0x008d01a0 }, diff --git a/drivers/video/drm/i915/render/exa_wm_src_sample_argb.g6b b/drivers/video/drm/i915/render/exa_wm_src_sample_argb.g6b deleted file mode 100644 index 8bfe849864..0000000000 --- a/drivers/video/drm/i915/render/exa_wm_src_sample_argb.g6b +++ /dev/null @@ -1,3 +0,0 @@ - { 0x00000201, 0x20080061, 0x00000000, 0x00000000 }, - { 0x00600001, 0x20200022, 0x008d0000, 0x00000000 }, - { 0x02800031, 0x21c01cc9, 0x00000020, 0x0a8a0001 }, diff --git a/drivers/video/drm/i915/render/exa_wm_write.g6b b/drivers/video/drm/i915/render/exa_wm_write.g6b deleted file mode 100644 index 3cb6bff383..0000000000 --- a/drivers/video/drm/i915/render/exa_wm_write.g6b +++ /dev/null @@ -1,17 +0,0 @@ - { 0x00600001, 0x204003be, 0x008d01c0, 0x00000000 }, - { 0x00600001, 0x206003be, 0x008d01e0, 0x00000000 }, - { 0x00600001, 0x208003be, 0x008d0200, 0x00000000 }, - { 0x00600001, 0x20a003be, 0x008d0220, 0x00000000 }, - { 0x00600001, 0x20c003be, 0x008d0240, 0x00000000 }, - { 0x00600001, 0x20e003be, 0x008d0260, 0x00000000 }, - { 0x00600001, 0x210003be, 0x008d0280, 0x00000000 }, - { 0x00600001, 0x212003be, 0x008d02a0, 0x00000000 }, - { 0x05800031, 0x24001cc8, 0x00000040, 0x90019000 }, - { 0x0000007e, 0x00000000, 0x00000000, 0x00000000 }, - { 0x0000007e, 0x00000000, 0x00000000, 0x00000000 }, - { 0x0000007e, 0x00000000, 0x00000000, 0x00000000 }, - { 0x0000007e, 0x00000000, 0x00000000, 0x00000000 }, - { 0x0000007e, 0x00000000, 0x00000000, 0x00000000 }, - { 0x0000007e, 0x00000000, 0x00000000, 0x00000000 }, - { 0x0000007e, 0x00000000, 0x00000000, 0x00000000 }, - { 0x0000007e, 0x00000000, 0x00000000, 0x00000000 }, diff --git a/drivers/video/drm/i915/sna/compiler.h b/drivers/video/drm/i915/sna/compiler.h deleted file mode 100644 index 91579f329a..0000000000 --- a/drivers/video/drm/i915/sna/compiler.h +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright (c) 2011 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: - * Chris Wilson - * - */ - -#ifndef _SNA_COMPILER_H_ -#define _SNA_COMPILER_H_ - -#if defined(__GNUC__) && (__GNUC__ > 2) && defined(__OPTIMIZE__) -#define noinline __attribute__((noinline)) -#define fastcall __attribute__((regparm(3))) -#define must_check __attribute__((warn_unused_result)) -#define constant __attribute__((const)) -#else -#define likely(expr) (expr) -#define unlikely(expr) (expr) -#define noinline -#define fastcall -#define must_check -#define constant -#endif - -#ifdef HAVE_VALGRIND -#define VG(x) x -#else -#define VG(x) -#endif - -#define VG_CLEAR(s) VG(memset(&s, 0, sizeof(s))) - -#define COMPILE_TIME_ASSERT(E) ((void)sizeof(char[1 - 2*!(E)])) - -#endif /* _SNA_COMPILER_H_ */ diff --git a/drivers/video/drm/i915/sna/gen6_render.c b/drivers/video/drm/i915/sna/gen6_render.c deleted file mode 100644 index ff82586577..0000000000 --- a/drivers/video/drm/i915/sna/gen6_render.c +++ /dev/null @@ -1,2163 +0,0 @@ -/* - * Copyright © 2006,2008,2011 Intel Corporation - * Copyright © 2007 Red Hat, Inc. - * - * 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: - * Wang Zhenyu - * Eric Anholt - * Carl Worth - * Keith Packard - * Chris Wilson - * - */ - -#include -#include -#include "i915_drm.h" -#include "i915_drv.h" -#include "intel_drv.h" - -#include -#include -#include -#include - -#include - -#include "../bitmap.h" - -#include "sna.h" -//#include "sna_reg.h" -#include "sna_render.h" -//#include "sna_render_inline.h" -//#include "sna_video.h" - -#include "gen6_render.h" - - -#define NO_COMPOSITE 0 -#define NO_COMPOSITE_SPANS 0 -#define NO_COPY 0 -#define NO_COPY_BOXES 0 -#define NO_FILL 0 -#define NO_FILL_BOXES 0 -#define NO_CLEAR 0 - -#define NO_RING_SWITCH 1 - -#define GEN6_MAX_SIZE 8192 - -static const uint32_t ps_kernel_nomask_affine[][4] = { -#include "exa_wm_src_affine.g6b" -#include "exa_wm_src_sample_argb.g6b" -#include "exa_wm_write.g6b" -}; - -static const uint32_t ps_kernel_masknoca_affine[][4] = { -#include "exa_wm_src_affine.g6b" -#include "exa_wm_src_sample_argb.g6b" -#include "exa_wm_mask_affine.g6b" -#include "exa_wm_mask_sample_a.g6b" -#include "exa_wm_noca.g6b" -#include "exa_wm_write.g6b" -}; - - -#define KERNEL(kernel_enum, kernel, masked) \ - [GEN6_WM_KERNEL_##kernel_enum] = {#kernel_enum, kernel, sizeof(kernel), masked} -static const struct wm_kernel_info { - const char *name; - const void *data; - unsigned int size; - Bool has_mask; -} wm_kernels[] = { -// KERNEL(NOMASK, ps_kernel_nomask_affine, FALSE), -// KERNEL(MASK, ps_kernel_masknoca_affine, TRUE), - KERNEL(NOMASK, ps_kernel_masknoca_affine, TRUE), - KERNEL(MASK, ps_kernel_masknoca_affine, TRUE), -}; -#undef KERNEL - -static const struct blendinfo { - Bool src_alpha; - uint32_t src_blend; - uint32_t dst_blend; -} gen6_blend_op[] = { - /* Clear */ {0, GEN6_BLENDFACTOR_ZERO, GEN6_BLENDFACTOR_ZERO}, - /* Src */ {0, GEN6_BLENDFACTOR_ONE, GEN6_BLENDFACTOR_ZERO}, - /* Dst */ {0, GEN6_BLENDFACTOR_ZERO, GEN6_BLENDFACTOR_ONE}, - /* Over */ {1, GEN6_BLENDFACTOR_ONE, GEN6_BLENDFACTOR_INV_SRC_ALPHA}, - /* OverReverse */ {0, GEN6_BLENDFACTOR_INV_DST_ALPHA, GEN6_BLENDFACTOR_ONE}, - /* In */ {0, GEN6_BLENDFACTOR_DST_ALPHA, GEN6_BLENDFACTOR_ZERO}, - /* InReverse */ {1, GEN6_BLENDFACTOR_ZERO, GEN6_BLENDFACTOR_SRC_ALPHA}, - /* Out */ {0, GEN6_BLENDFACTOR_INV_DST_ALPHA, GEN6_BLENDFACTOR_ZERO}, - /* OutReverse */ {1, GEN6_BLENDFACTOR_ZERO, GEN6_BLENDFACTOR_INV_SRC_ALPHA}, - /* Atop */ {1, GEN6_BLENDFACTOR_DST_ALPHA, GEN6_BLENDFACTOR_INV_SRC_ALPHA}, - /* AtopReverse */ {1, GEN6_BLENDFACTOR_INV_DST_ALPHA, GEN6_BLENDFACTOR_SRC_ALPHA}, - /* Xor */ {1, GEN6_BLENDFACTOR_INV_DST_ALPHA, GEN6_BLENDFACTOR_INV_SRC_ALPHA}, - /* Add */ {0, GEN6_BLENDFACTOR_ONE, GEN6_BLENDFACTOR_ONE}, -}; - - -/** - * Highest-valued BLENDFACTOR used in gen6_blend_op. - * - * This leaves out GEN6_BLENDFACTOR_INV_DST_COLOR, - * GEN6_BLENDFACTOR_INV_CONST_{COLOR,ALPHA}, - * GEN6_BLENDFACTOR_INV_SRC1_{COLOR,ALPHA} - */ -#define GEN6_BLENDFACTOR_COUNT (GEN6_BLENDFACTOR_INV_DST_ALPHA + 1) - -/* FIXME: surface format defined in gen6_defines.h, shared Sampling engine - * 1.7.2 - -static const struct formatinfo { - CARD32 pict_fmt; - uint32_t card_fmt; -} gen6_tex_formats[] = { - {PICT_a8, GEN6_SURFACEFORMAT_A8_UNORM}, - {PICT_a8r8g8b8, GEN6_SURFACEFORMAT_B8G8R8A8_UNORM}, - {PICT_x8r8g8b8, GEN6_SURFACEFORMAT_B8G8R8X8_UNORM}, - {PICT_a8b8g8r8, GEN6_SURFACEFORMAT_R8G8B8A8_UNORM}, - {PICT_x8b8g8r8, GEN6_SURFACEFORMAT_R8G8B8X8_UNORM}, - {PICT_r8g8b8, GEN6_SURFACEFORMAT_R8G8B8_UNORM}, - {PICT_r5g6b5, GEN6_SURFACEFORMAT_B5G6R5_UNORM}, - {PICT_a1r5g5b5, GEN6_SURFACEFORMAT_B5G5R5A1_UNORM}, - {PICT_a2r10g10b10, GEN6_SURFACEFORMAT_B10G10R10A2_UNORM}, - {PICT_x2r10g10b10, GEN6_SURFACEFORMAT_B10G10R10X2_UNORM}, - {PICT_a2b10g10r10, GEN6_SURFACEFORMAT_R10G10B10A2_UNORM}, - {PICT_x2r10g10b10, GEN6_SURFACEFORMAT_B10G10R10X2_UNORM}, - {PICT_a4r4g4b4, GEN6_SURFACEFORMAT_B4G4R4A4_UNORM}, -}; - */ - -#define GEN6_BLEND_STATE_PADDED_SIZE ALIGN(sizeof(struct gen6_blend_state), 64) - -#define BLEND_OFFSET(s, d) \ - (((s) * GEN6_BLENDFACTOR_COUNT + (d)) * GEN6_BLEND_STATE_PADDED_SIZE) - -#define SAMPLER_OFFSET(sf, se, mf, me) \ - (((((sf) * EXTEND_COUNT + (se)) * FILTER_COUNT + (mf)) * EXTEND_COUNT + (me)) * 2 * sizeof(struct gen6_sampler_state)) - -#define OUT_BATCH(v) batch_emit(sna, v) -#define OUT_VERTEX(x,y) vertex_emit_2s(sna, x,y) -#define OUT_VERTEX_F(v) vertex_emit(sna, v) - -static inline bool too_large(int width, int height) -{ - return width > GEN6_MAX_SIZE || height > GEN6_MAX_SIZE; -} - -static uint32_t gen6_get_blend(int op, - bool has_component_alpha, - uint32_t dst_format) -{ - uint32_t src, dst; - -// src = GEN6_BLENDFACTOR_ONE; //gen6_blend_op[op].src_blend; -// dst = GEN6_BLENDFACTOR_ZERO; //gen6_blend_op[op].dst_blend; - - src = GEN6_BLENDFACTOR_ONE; //gen6_blend_op[op].src_blend; - dst = GEN6_BLENDFACTOR_INV_SRC_ALPHA; //gen6_blend_op[op].dst_blend; - -#if 0 - /* If there's no dst alpha channel, adjust the blend op so that - * we'll treat it always as 1. - */ - if (PICT_FORMAT_A(dst_format) == 0) { - if (src == GEN6_BLENDFACTOR_DST_ALPHA) - src = GEN6_BLENDFACTOR_ONE; - else if (src == GEN6_BLENDFACTOR_INV_DST_ALPHA) - src = GEN6_BLENDFACTOR_ZERO; - } - - /* If the source alpha is being used, then we should only be in a - * case where the source blend factor is 0, and the source blend - * value is the mask channels multiplied by the source picture's alpha. - */ - if (has_component_alpha && gen6_blend_op[op].src_alpha) { - if (dst == GEN6_BLENDFACTOR_SRC_ALPHA) - dst = GEN6_BLENDFACTOR_SRC_COLOR; - else if (dst == GEN6_BLENDFACTOR_INV_SRC_ALPHA) - dst = GEN6_BLENDFACTOR_INV_SRC_COLOR; - } - - DBG(("blend op=%d, dst=%x [A=%d] => src=%d, dst=%d => offset=%x\n", - op, dst_format, PICT_FORMAT_A(dst_format), - src, dst, (int)BLEND_OFFSET(src, dst))); -#endif - - return BLEND_OFFSET(src, dst); -} - -static uint32_t gen6_get_dest_format(CARD32 format) -{ - return GEN6_SURFACEFORMAT_B8G8R8A8_UNORM; - -/* - switch (format) { - default: - assert(0); - case PICT_a8r8g8b8: - case PICT_x8r8g8b8: - return GEN6_SURFACEFORMAT_B8G8R8A8_UNORM; - case PICT_a8b8g8r8: - case PICT_x8b8g8r8: - return GEN6_SURFACEFORMAT_R8G8B8A8_UNORM; - case PICT_a2r10g10b10: - case PICT_x2r10g10b10: - return GEN6_SURFACEFORMAT_B10G10R10A2_UNORM; - case PICT_r5g6b5: - return GEN6_SURFACEFORMAT_B5G6R5_UNORM; - case PICT_x1r5g5b5: - case PICT_a1r5g5b5: - return GEN6_SURFACEFORMAT_B5G5R5A1_UNORM; - case PICT_a8: - return GEN6_SURFACEFORMAT_A8_UNORM; - case PICT_a4r4g4b4: - case PICT_x4r4g4b4: - return GEN6_SURFACEFORMAT_B4G4R4A4_UNORM; - } - */ -} - -#if 0 -static Bool gen6_check_dst_format(PictFormat format) -{ - switch (format) { - case PICT_a8r8g8b8: - case PICT_x8r8g8b8: - case PICT_a8b8g8r8: - case PICT_x8b8g8r8: - case PICT_a2r10g10b10: - case PICT_x2r10g10b10: - case PICT_r5g6b5: - case PICT_x1r5g5b5: - case PICT_a1r5g5b5: - case PICT_a8: - case PICT_a4r4g4b4: - case PICT_x4r4g4b4: - return TRUE; - } - return FALSE; -} - -static bool gen6_check_format(uint32_t format) -{ - switch (format) { - case PICT_a8r8g8b8: - case PICT_x8r8g8b8: - case PICT_a8b8g8r8: - case PICT_x8b8g8r8: - case PICT_a2r10g10b10: - case PICT_x2r10g10b10: - case PICT_r8g8b8: - case PICT_r5g6b5: - case PICT_a1r5g5b5: - case PICT_a8: - case PICT_a4r4g4b4: - case PICT_x4r4g4b4: - return true; - default: - DBG(("%s: unhandled format: %x\n", __FUNCTION__, format)); - return false; - } -} - -static uint32_t gen6_filter(uint32_t filter) -{ - switch (filter) { - default: - assert(0); - case PictFilterNearest: - return SAMPLER_FILTER_NEAREST; - case PictFilterBilinear: - return SAMPLER_FILTER_BILINEAR; - } -} - -static uint32_t gen6_check_filter(PicturePtr picture) -{ - switch (picture->filter) { - case PictFilterNearest: - case PictFilterBilinear: - return TRUE; - default: - return FALSE; - } -} - -static uint32_t gen6_repeat(uint32_t repeat) -{ - switch (repeat) { - default: - assert(0); - case RepeatNone: - return SAMPLER_EXTEND_NONE; - case RepeatNormal: - return SAMPLER_EXTEND_REPEAT; - case RepeatPad: - return SAMPLER_EXTEND_PAD; - case RepeatReflect: - return SAMPLER_EXTEND_REFLECT; - } -} - -static bool gen6_check_repeat(PicturePtr picture) -{ - if (!picture->repeat) - return TRUE; - - switch (picture->repeatType) { - case RepeatNone: - case RepeatNormal: - case RepeatPad: - case RepeatReflect: - return TRUE; - default: - return FALSE; - } -} -#endif - -static int -gen6_choose_composite_kernel(int op, Bool has_mask, Bool is_ca, Bool is_affine) -{ - int base; - - if (has_mask) { -/* - if (is_ca) { - if (gen6_blend_op[op].src_alpha) - base = GEN6_WM_KERNEL_MASKCA_SRCALPHA; - else - base = GEN6_WM_KERNEL_MASKCA; - } else - base = GEN6_WM_KERNEL_MASK; -*/ - } else - base = GEN6_WM_KERNEL_NOMASK; - - return base + !is_affine; -} - -static void -gen6_emit_urb(struct sna *sna) -{ - OUT_BATCH(GEN6_3DSTATE_URB | (3 - 2)); - OUT_BATCH(((1 - 1) << GEN6_3DSTATE_URB_VS_SIZE_SHIFT) | - (24 << GEN6_3DSTATE_URB_VS_ENTRIES_SHIFT)); /* at least 24 on GEN6 */ - OUT_BATCH((0 << GEN6_3DSTATE_URB_GS_SIZE_SHIFT) | - (0 << GEN6_3DSTATE_URB_GS_ENTRIES_SHIFT)); /* no GS thread */ -} - -static void -gen6_emit_state_base_address(struct sna *sna) -{ - OUT_BATCH(GEN6_STATE_BASE_ADDRESS | (10 - 2)); - OUT_BATCH(0); /* general */ - - OUT_BATCH((sna->kgem.batch_obj->gtt_offset+ - sna->kgem.batch_idx*4096)|BASE_ADDRESS_MODIFY); - - OUT_BATCH(sna->render_state.gen6.general_bo->gaddr|BASE_ADDRESS_MODIFY); - - OUT_BATCH(0); /* indirect */ - - OUT_BATCH(sna->render_state.gen6.general_bo->gaddr|BASE_ADDRESS_MODIFY); - - /* upper bounds, disable */ - OUT_BATCH(0); - OUT_BATCH(BASE_ADDRESS_MODIFY); - OUT_BATCH(0); - OUT_BATCH(BASE_ADDRESS_MODIFY); -} - -static void -gen6_emit_viewports(struct sna *sna) -{ - OUT_BATCH(GEN6_3DSTATE_VIEWPORT_STATE_POINTERS | - GEN6_3DSTATE_VIEWPORT_STATE_MODIFY_CC | - (4 - 2)); - OUT_BATCH(0); - OUT_BATCH(0); - OUT_BATCH(sna->render_state.gen6.cc_vp); -} - -static void -gen6_emit_vs(struct sna *sna) -{ - /* disable VS constant buffer */ - OUT_BATCH(GEN6_3DSTATE_CONSTANT_VS | (5 - 2)); - OUT_BATCH(0); - OUT_BATCH(0); - OUT_BATCH(0); - OUT_BATCH(0); - - OUT_BATCH(GEN6_3DSTATE_VS | (6 - 2)); - OUT_BATCH(0); /* no VS kernel */ - OUT_BATCH(0); - OUT_BATCH(0); - OUT_BATCH(0); - OUT_BATCH(0); /* pass-through */ -} - -static void -gen6_emit_gs(struct sna *sna) -{ - /* disable GS constant buffer */ - OUT_BATCH(GEN6_3DSTATE_CONSTANT_GS | (5 - 2)); - OUT_BATCH(0); - OUT_BATCH(0); - OUT_BATCH(0); - OUT_BATCH(0); - - OUT_BATCH(GEN6_3DSTATE_GS | (7 - 2)); - OUT_BATCH(0); /* no GS kernel */ - OUT_BATCH(0); - OUT_BATCH(0); - OUT_BATCH(0); - OUT_BATCH(0); - OUT_BATCH(0); /* pass-through */ -} - -static void -gen6_emit_clip(struct sna *sna) -{ - OUT_BATCH(GEN6_3DSTATE_CLIP | (4 - 2)); - OUT_BATCH(0); - OUT_BATCH(0); /* pass-through */ - OUT_BATCH(0); -} - -static void -gen6_emit_wm_constants(struct sna *sna) -{ - /* disable WM constant buffer */ - OUT_BATCH(GEN6_3DSTATE_CONSTANT_PS | (5 - 2)); - OUT_BATCH(0); - OUT_BATCH(0); - OUT_BATCH(0); - OUT_BATCH(0); -} - -static void -gen6_emit_null_depth_buffer(struct sna *sna) -{ - OUT_BATCH(GEN6_3DSTATE_DEPTH_BUFFER | (7 - 2)); - OUT_BATCH(GEN6_SURFACE_NULL << GEN6_3DSTATE_DEPTH_BUFFER_TYPE_SHIFT | - GEN6_DEPTHFORMAT_D32_FLOAT << GEN6_3DSTATE_DEPTH_BUFFER_FORMAT_SHIFT); - OUT_BATCH(0); - OUT_BATCH(0); - OUT_BATCH(0); - OUT_BATCH(0); - OUT_BATCH(0); - - OUT_BATCH(GEN6_3DSTATE_CLEAR_PARAMS | (2 - 2)); - OUT_BATCH(0); -} - -static void -gen6_emit_invariant(struct sna *sna) -{ - OUT_BATCH(GEN6_PIPELINE_SELECT | PIPELINE_SELECT_3D); - - OUT_BATCH(GEN6_3DSTATE_MULTISAMPLE | (3 - 2)); - OUT_BATCH(GEN6_3DSTATE_MULTISAMPLE_PIXEL_LOCATION_CENTER | - GEN6_3DSTATE_MULTISAMPLE_NUMSAMPLES_1); /* 1 sample/pixel */ - OUT_BATCH(0); - - OUT_BATCH(GEN6_3DSTATE_SAMPLE_MASK | (2 - 2)); - OUT_BATCH(1); - - gen6_emit_urb(sna); - - gen6_emit_state_base_address(sna); - - gen6_emit_viewports(sna); - gen6_emit_vs(sna); - gen6_emit_gs(sna); - gen6_emit_clip(sna); - gen6_emit_wm_constants(sna); - gen6_emit_null_depth_buffer(sna); - - sna->render_state.gen6.needs_invariant = FALSE; -} - -static bool -gen6_emit_cc(struct sna *sna, - int op, bool has_component_alpha, uint32_t dst_format) -{ - struct gen6_render_state *render = &sna->render_state.gen6; - uint32_t blend; - - blend = gen6_get_blend(op, has_component_alpha, dst_format); - - DBG(("%s(op=%d, ca=%d, format=%x): new=%x, current=%x\n", - __FUNCTION__, - op, has_component_alpha, dst_format, - blend, render->blend)); - if (render->blend == blend) - return op <= PictOpSrc; - - OUT_BATCH(GEN6_3DSTATE_CC_STATE_POINTERS | (4 - 2)); - OUT_BATCH((render->cc_blend + blend) | 1); - if (render->blend == (unsigned)-1) { - OUT_BATCH(1); - OUT_BATCH(1); - } else { - OUT_BATCH(0); - OUT_BATCH(0); - } - - render->blend = blend; - return op <= PictOpSrc; -} - -static void -gen6_emit_sampler(struct sna *sna, uint32_t state) -{ - assert(state < - 2 * sizeof(struct gen6_sampler_state) * - FILTER_COUNT * EXTEND_COUNT * - FILTER_COUNT * EXTEND_COUNT); - - if (sna->render_state.gen6.samplers == state) - return; - - sna->render_state.gen6.samplers = state; - - OUT_BATCH(GEN6_3DSTATE_SAMPLER_STATE_POINTERS | - GEN6_3DSTATE_SAMPLER_STATE_MODIFY_PS | - (4 - 2)); - OUT_BATCH(0); /* VS */ - OUT_BATCH(0); /* GS */ - OUT_BATCH(sna->render_state.gen6.wm_state + state); -} - -static void -gen6_emit_sf(struct sna *sna, Bool has_mask) -{ - int num_sf_outputs = has_mask ? 2 : 1; - - if (sna->render_state.gen6.num_sf_outputs == num_sf_outputs) - return; - - DBG(("%s: num_sf_outputs=%d, read_length=%d, read_offset=%d\n", - __FUNCTION__, num_sf_outputs, 1, 0)); - - sna->render_state.gen6.num_sf_outputs = num_sf_outputs; - - OUT_BATCH(GEN6_3DSTATE_SF | (20 - 2)); - OUT_BATCH(num_sf_outputs << GEN6_3DSTATE_SF_NUM_OUTPUTS_SHIFT | - 1 << GEN6_3DSTATE_SF_URB_ENTRY_READ_LENGTH_SHIFT | - 1 << GEN6_3DSTATE_SF_URB_ENTRY_READ_OFFSET_SHIFT); - OUT_BATCH(0); - OUT_BATCH(GEN6_3DSTATE_SF_CULL_NONE); - OUT_BATCH(2 << GEN6_3DSTATE_SF_TRIFAN_PROVOKE_SHIFT); /* DW4 */ - OUT_BATCH(0); - OUT_BATCH(0); - OUT_BATCH(0); - OUT_BATCH(0); - OUT_BATCH(0); /* DW9 */ - OUT_BATCH(0); - OUT_BATCH(0); - OUT_BATCH(0); - OUT_BATCH(0); - OUT_BATCH(0); /* DW14 */ - OUT_BATCH(0); - OUT_BATCH(0); - OUT_BATCH(0); - OUT_BATCH(0); - OUT_BATCH(0); /* DW19 */ -} - -static void -gen6_emit_wm(struct sna *sna, unsigned int kernel, int nr_surfaces, int nr_inputs) -{ - if (sna->render_state.gen6.kernel == kernel) - return; - - sna->render_state.gen6.kernel = kernel; - - DBG(("%s: switching to %s\n", __FUNCTION__, wm_kernels[kernel].name)); - - OUT_BATCH(GEN6_3DSTATE_WM | (9 - 2)); - OUT_BATCH(sna->render_state.gen6.wm_kernel[kernel]); - OUT_BATCH(1 << GEN6_3DSTATE_WM_SAMPLER_COUNT_SHIFT | - nr_surfaces << GEN6_3DSTATE_WM_BINDING_TABLE_ENTRY_COUNT_SHIFT); - OUT_BATCH(0); - OUT_BATCH(6 << GEN6_3DSTATE_WM_DISPATCH_START_GRF_0_SHIFT); /* DW4 */ - OUT_BATCH((40 - 1) << GEN6_3DSTATE_WM_MAX_THREADS_SHIFT | - GEN6_3DSTATE_WM_DISPATCH_ENABLE | - GEN6_3DSTATE_WM_16_DISPATCH_ENABLE); - OUT_BATCH(nr_inputs << GEN6_3DSTATE_WM_NUM_SF_OUTPUTS_SHIFT | - GEN6_3DSTATE_WM_PERSPECTIVE_PIXEL_BARYCENTRIC); - OUT_BATCH(0); - OUT_BATCH(0); -} - -static bool -gen6_emit_binding_table(struct sna *sna, uint16_t offset) -{ - if (sna->render_state.gen6.surface_table == offset) - return false; - - /* Binding table pointers */ - OUT_BATCH(GEN6_3DSTATE_BINDING_TABLE_POINTERS | - GEN6_3DSTATE_BINDING_TABLE_MODIFY_PS | - (4 - 2)); - OUT_BATCH(0); /* vs */ - OUT_BATCH(0); /* gs */ - /* Only the PS uses the binding table */ - OUT_BATCH(offset*4); - - sna->render_state.gen6.surface_table = offset; - return true; -} - -static bool -gen6_emit_drawing_rectangle(struct sna *sna, - const struct sna_composite_op *op) -{ - uint32_t limit = (op->dst.height - 1) << 16 | (op->dst.width - 1); - uint32_t offset = (uint16_t)op->dst.y << 16 | (uint16_t)op->dst.x; - - assert(!too_large(op->dst.x, op->dst.y)); - assert(!too_large(op->dst.width, op->dst.height)); - - if (sna->render_state.gen6.drawrect_limit == limit && - sna->render_state.gen6.drawrect_offset == offset) - return false; - - /* [DevSNB-C+{W/A}] Before any depth stall flush (including those - * produced by non-pipelined state commands), software needs to first - * send a PIPE_CONTROL with no bits set except Post-Sync Operation != - * 0. - * - * [Dev-SNB{W/A}]: Pipe-control with CS-stall bit set must be sent - * BEFORE the pipe-control with a post-sync op and no write-cache - * flushes. - */ - OUT_BATCH(GEN6_PIPE_CONTROL | (4 - 2)); - OUT_BATCH(GEN6_PIPE_CONTROL_CS_STALL | - GEN6_PIPE_CONTROL_STALL_AT_SCOREBOARD); - OUT_BATCH(0); - OUT_BATCH(0); - - OUT_BATCH(GEN6_PIPE_CONTROL | (4 - 2)); - OUT_BATCH(GEN6_PIPE_CONTROL_WRITE_TIME); - - OUT_BATCH(sna->render_state.gen6.general_bo->gaddr+64); - - OUT_BATCH(0); - - OUT_BATCH(GEN6_3DSTATE_DRAWING_RECTANGLE | (4 - 2)); - OUT_BATCH(0); - OUT_BATCH(limit); - OUT_BATCH(offset); - - sna->render_state.gen6.drawrect_offset = offset; - sna->render_state.gen6.drawrect_limit = limit; - return true; -} - -static void -gen6_emit_vertex_elements(struct sna *sna, - const struct sna_composite_op *op) -{ - /* - * vertex data in vertex buffer - * position: (x, y) - * texture coordinate 0: (u0, v0) if (is_affine is TRUE) else (u0, v0, w0) - * texture coordinate 1 if (has_mask is TRUE): same as above - */ - struct gen6_render_state *render = &sna->render_state.gen6; - int nelem = op->mask.bo ? 2 : 1; - int selem = op->is_affine ? 2 : 3; - uint32_t w_component; - uint32_t src_format; - int id = op->u.gen6.ve_id; - - if (render->ve_id == id) - return; - render->ve_id = id; - - if (op->is_affine) { - src_format = GEN6_SURFACEFORMAT_R32G32_FLOAT; - w_component = GEN6_VFCOMPONENT_STORE_1_FLT; - } else { - src_format = GEN6_SURFACEFORMAT_R32G32B32_FLOAT; - w_component = GEN6_VFCOMPONENT_STORE_SRC; - } - - /* The VUE layout - * dword 0-3: pad (0.0, 0.0, 0.0. 0.0) - * dword 4-7: position (x, y, 1.0, 1.0), - * dword 8-11: texture coordinate 0 (u0, v0, w0, 1.0) - * dword 12-15: texture coordinate 1 (u1, v1, w1, 1.0) - * - * dword 4-15 are fetched from vertex buffer - */ - OUT_BATCH(GEN6_3DSTATE_VERTEX_ELEMENTS | - ((2 * (2 + nelem)) + 1 - 2)); - - OUT_BATCH(id << VE0_VERTEX_BUFFER_INDEX_SHIFT | VE0_VALID | - GEN6_SURFACEFORMAT_R32G32B32A32_FLOAT << VE0_FORMAT_SHIFT | - 0 << VE0_OFFSET_SHIFT); - OUT_BATCH(GEN6_VFCOMPONENT_STORE_0 << VE1_VFCOMPONENT_0_SHIFT | - GEN6_VFCOMPONENT_STORE_0 << VE1_VFCOMPONENT_1_SHIFT | - GEN6_VFCOMPONENT_STORE_0 << VE1_VFCOMPONENT_2_SHIFT | - GEN6_VFCOMPONENT_STORE_0 << VE1_VFCOMPONENT_3_SHIFT); - - /* x,y */ - OUT_BATCH(id << VE0_VERTEX_BUFFER_INDEX_SHIFT | VE0_VALID | - GEN6_SURFACEFORMAT_R16G16_SSCALED << VE0_FORMAT_SHIFT | - 0 << VE0_OFFSET_SHIFT); /* offsets vb in bytes */ - OUT_BATCH(GEN6_VFCOMPONENT_STORE_SRC << VE1_VFCOMPONENT_0_SHIFT | - GEN6_VFCOMPONENT_STORE_SRC << VE1_VFCOMPONENT_1_SHIFT | - GEN6_VFCOMPONENT_STORE_1_FLT << VE1_VFCOMPONENT_2_SHIFT | - GEN6_VFCOMPONENT_STORE_1_FLT << VE1_VFCOMPONENT_3_SHIFT); - - /* u0, v0, w0 */ - OUT_BATCH(id << VE0_VERTEX_BUFFER_INDEX_SHIFT | VE0_VALID | - src_format << VE0_FORMAT_SHIFT | - 4 << VE0_OFFSET_SHIFT); /* offset vb in bytes */ - OUT_BATCH(GEN6_VFCOMPONENT_STORE_SRC << VE1_VFCOMPONENT_0_SHIFT | - GEN6_VFCOMPONENT_STORE_SRC << VE1_VFCOMPONENT_1_SHIFT | - w_component << VE1_VFCOMPONENT_2_SHIFT | - GEN6_VFCOMPONENT_STORE_1_FLT << VE1_VFCOMPONENT_3_SHIFT); - - /* u1, v1, w1 */ - if (op->mask.bo) { - OUT_BATCH(id << VE0_VERTEX_BUFFER_INDEX_SHIFT | VE0_VALID | - src_format << VE0_FORMAT_SHIFT | - ((1 + selem) * 4) << VE0_OFFSET_SHIFT); /* vb offset in bytes */ - OUT_BATCH(GEN6_VFCOMPONENT_STORE_SRC << VE1_VFCOMPONENT_0_SHIFT | - GEN6_VFCOMPONENT_STORE_SRC << VE1_VFCOMPONENT_1_SHIFT | - w_component << VE1_VFCOMPONENT_2_SHIFT | - GEN6_VFCOMPONENT_STORE_1_FLT << VE1_VFCOMPONENT_3_SHIFT); - } -} - -static void -gen6_emit_flush(struct sna *sna) -{ - OUT_BATCH(GEN6_PIPE_CONTROL | (4 - 2)); - OUT_BATCH(GEN6_PIPE_CONTROL_WC_FLUSH | - GEN6_PIPE_CONTROL_TC_FLUSH | - GEN6_PIPE_CONTROL_CS_STALL); - OUT_BATCH(0); - OUT_BATCH(0); -} - -static void -gen6_emit_state(struct sna *sna, - const struct sna_composite_op *op, - uint16_t wm_binding_table) -{ - bool need_stall = wm_binding_table & 1; - - if (gen6_emit_cc(sna, op->op, op->has_component_alpha, op->dst.format)) - need_stall = false; - gen6_emit_sampler(sna, - SAMPLER_OFFSET(op->src.filter, - op->src.repeat, - op->mask.filter, - op->mask.repeat)); - gen6_emit_sf(sna, op->mask.bo != NULL); - gen6_emit_wm(sna, - op->u.gen6.wm_kernel, - op->u.gen6.nr_surfaces, - op->u.gen6.nr_inputs); - gen6_emit_vertex_elements(sna, op); - need_stall |= gen6_emit_binding_table(sna, wm_binding_table & ~1); - if (gen6_emit_drawing_rectangle(sna, op)) - need_stall = false; -// if (kgem_bo_is_dirty(op->src.bo) || kgem_bo_is_dirty(op->mask.bo)) { - gen6_emit_flush(sna); - kgem_clear_dirty(&sna->kgem); - kgem_bo_mark_dirty(op->dst.bo); - need_stall = false; -// } - if (need_stall) { - OUT_BATCH(GEN6_PIPE_CONTROL | (4 - 2)); - OUT_BATCH(GEN6_PIPE_CONTROL_CS_STALL | - GEN6_PIPE_CONTROL_STALL_AT_SCOREBOARD); - OUT_BATCH(0); - OUT_BATCH(0); - } -} - -static void gen6_magic_ca_pass(struct sna *sna, - const struct sna_composite_op *op) -{ - struct gen6_render_state *state = &sna->render_state.gen6; - - if (!op->need_magic_ca_pass) - return; - - DBG(("%s: CA fixup (%d -> %d)\n", __FUNCTION__, - sna->render.vertex_start, sna->render.vertex_index)); - - gen6_emit_flush(sna); - - gen6_emit_cc(sna, PictOpAdd, TRUE, op->dst.format); - gen6_emit_wm(sna, - gen6_choose_composite_kernel(PictOpAdd, - TRUE, TRUE, - op->is_affine), - 3, 2); - - OUT_BATCH(GEN6_3DPRIMITIVE | - GEN6_3DPRIMITIVE_VERTEX_SEQUENTIAL | - _3DPRIM_RECTLIST << GEN6_3DPRIMITIVE_TOPOLOGY_SHIFT | - 0 << 9 | - 4); - OUT_BATCH(sna->render.vertex_index - sna->render.vertex_start); - OUT_BATCH(sna->render.vertex_start); - OUT_BATCH(1); /* single instance */ - OUT_BATCH(0); /* start instance location */ - OUT_BATCH(0); /* index buffer offset, ignored */ - - state->last_primitive = sna->kgem.nbatch; -} - -static void gen6_vertex_flush(struct sna *sna) -{ - assert(sna->render_state.gen6.vertex_offset); - - DBG(("%s[%x] = %d\n", __FUNCTION__, - 4*sna->render_state.gen6.vertex_offset, - sna->render.vertex_index - sna->render.vertex_start)); - sna->kgem.batch[sna->render_state.gen6.vertex_offset] = - sna->render.vertex_index - sna->render.vertex_start; - sna->render_state.gen6.vertex_offset = 0; -} - -static int gen6_vertex_finish(struct sna *sna) -{ - struct kgem_bo *bo; - unsigned int i; - - DBG(("%s: used=%d / %d\n", __FUNCTION__, - sna->render.vertex_used, sna->render.vertex_size)); - assert(sna->render.vertex_used); - - /* Note: we only need dword alignment (currently) */ -/* - bo = sna->render.vbo; - if (bo) { - for (i = 0; i < ARRAY_SIZE(sna->render.vertex_reloc); i++) { - if (sna->render.vertex_reloc[i]) { - DBG(("%s: reloc[%d] = %d\n", __FUNCTION__, - i, sna->render.vertex_reloc[i])); - - sna->kgem.batch[sna->render.vertex_reloc[i]] = - kgem_add_reloc(&sna->kgem, - sna->render.vertex_reloc[i], - bo, - I915_GEM_DOMAIN_VERTEX << 16, - 0); - sna->kgem.batch[sna->render.vertex_reloc[i]+1] = - kgem_add_reloc(&sna->kgem, - sna->render.vertex_reloc[i]+1, - bo, - I915_GEM_DOMAIN_VERTEX << 16, - 0 + sna->render.vertex_used * 4 - 1); - sna->render.vertex_reloc[i] = 0; - } - } - - sna->render.vertex_used = 0; - sna->render.vertex_index = 0; - sna->render_state.gen6.vb_id = 0; - - kgem_bo_destroy(&sna->kgem, bo); - } -*/ - sna->render.vertices = NULL; - sna->render.vbo = kgem_create_linear(&sna->kgem, 256*1024); - if (sna->render.vbo) - sna->render.vertices = kgem_bo_map__cpu(&sna->kgem, sna->render.vbo); - if (sna->render.vertices == NULL) { - kgem_bo_destroy(&sna->kgem, sna->render.vbo); - sna->render.vbo = NULL; - return 0; - } - -// kgem_bo_sync__cpu(&sna->kgem, sna->render.vbo); - if (sna->render.vertex_used) { - DBG(("%s: copying initial buffer x %d to handle=%d\n", - __FUNCTION__, - sna->render.vertex_used, - sna->render.vbo->handle)); - memcpy(sna->render.vertices, - sna->render.vertex_data, - sizeof(float)*sna->render.vertex_used); - } - sna->render.vertex_size = 64 * 1024 - 1; - return sna->render.vertex_size - sna->render.vertex_used; -} - -static void gen6_vertex_close(struct sna *sna) -{ - struct kgem_bo *bo; - unsigned int i, delta = 0; - - if (!sna->render.vertex_used) { - assert(sna->render.vbo == NULL); - assert(sna->render.vertices == sna->render.vertex_data); - assert(sna->render.vertex_size == ARRAY_SIZE(sna->render.vertex_data)); - return; - } - - DBG(("%s: used=%d / %d\n", __FUNCTION__, - sna->render.vertex_used, sna->render.vertex_size)); - - bo = sna->render.vbo; - if (bo == NULL) { - assert(sna->render.vertices == sna->render.vertex_data); - assert(sna->render.vertex_used < ARRAY_SIZE(sna->render.vertex_data)); - if (sna->kgem.nbatch + sna->render.vertex_used <= sna->kgem.surface) { - DBG(("%s: copy to batch: %d @ %d\n", __FUNCTION__, - sna->render.vertex_used, sna->kgem.nbatch)); - memcpy(sna->kgem.batch + sna->kgem.nbatch, - sna->render.vertex_data, - sna->render.vertex_used * 4); - delta = sna->kgem.nbatch * 4; - bo = NULL; - sna->kgem.nbatch += sna->render.vertex_used; - } else { - bo = kgem_create_linear(&sna->kgem, 4*sna->render.vertex_used); - if (bo && !kgem_bo_write(&sna->kgem, bo, - sna->render.vertex_data, - 4*sna->render.vertex_used)) { - kgem_bo_destroy(&sna->kgem, bo); - goto reset; - } - DBG(("%s: new vbo: %d\n", __FUNCTION__, - sna->render.vertex_used)); - } - } - - for (i = 0; i < ARRAY_SIZE(sna->render.vertex_reloc); i++) { - if (sna->render.vertex_reloc[i]) { - DBG(("%s: reloc[%d] = %d\n", __FUNCTION__, - i, sna->render.vertex_reloc[i])); - - sna->kgem.batch[sna->render.vertex_reloc[i]] = - sna->kgem.batch_obj->gtt_offset+delta+ - sna->kgem.batch_idx*4096; - - sna->kgem.batch[sna->render.vertex_reloc[i]+1] = - sna->kgem.batch_obj->gtt_offset+delta+ - sna->kgem.batch_idx*4096+ - sna->render.vertex_used * 4 - 1; - - sna->render.vertex_reloc[i] = 0; - } - } - -// if (bo) -// kgem_bo_destroy(&sna->kgem, bo); - -reset: - sna->render.vertex_used = 0; - sna->render.vertex_index = 0; - sna->render_state.gen6.vb_id = 0; - - sna->render.vbo = NULL; - sna->render.vertices = sna->render.vertex_data; - sna->render.vertex_size = ARRAY_SIZE(sna->render.vertex_data); -} - -typedef struct gen6_surface_state_padded { - struct gen6_surface_state state; - char pad[32 - sizeof(struct gen6_surface_state)]; -} gen6_surface_state_padded; - -static void null_create(struct sna_static_stream *stream) -{ - /* A bunch of zeros useful for legacy border color and depth-stencil */ - sna_static_stream_map(stream, 64, 64); -} - -static void scratch_create(struct sna_static_stream *stream) -{ - /* 64 bytes of scratch space for random writes, such as - * the pipe-control w/a. - */ - sna_static_stream_map(stream, 64, 64); -} - -static void -sampler_state_init(struct gen6_sampler_state *sampler_state, - sampler_filter_t filter, - sampler_extend_t extend) -{ - sampler_state->ss0.lod_preclamp = 1; /* GL mode */ - - /* We use the legacy mode to get the semantics specified by - * the Render extension. */ - sampler_state->ss0.border_color_mode = GEN6_BORDER_COLOR_MODE_LEGACY; - - switch (filter) { - default: - case SAMPLER_FILTER_NEAREST: - sampler_state->ss0.min_filter = GEN6_MAPFILTER_NEAREST; - sampler_state->ss0.mag_filter = GEN6_MAPFILTER_NEAREST; - break; - case SAMPLER_FILTER_BILINEAR: - sampler_state->ss0.min_filter = GEN6_MAPFILTER_LINEAR; - sampler_state->ss0.mag_filter = GEN6_MAPFILTER_LINEAR; - break; - } - - switch (extend) { - default: - case SAMPLER_EXTEND_NONE: - sampler_state->ss1.r_wrap_mode = GEN6_TEXCOORDMODE_CLAMP_BORDER; - sampler_state->ss1.s_wrap_mode = GEN6_TEXCOORDMODE_CLAMP_BORDER; - sampler_state->ss1.t_wrap_mode = GEN6_TEXCOORDMODE_CLAMP_BORDER; - break; - case SAMPLER_EXTEND_REPEAT: - sampler_state->ss1.r_wrap_mode = GEN6_TEXCOORDMODE_WRAP; - sampler_state->ss1.s_wrap_mode = GEN6_TEXCOORDMODE_WRAP; - sampler_state->ss1.t_wrap_mode = GEN6_TEXCOORDMODE_WRAP; - break; - case SAMPLER_EXTEND_PAD: - sampler_state->ss1.r_wrap_mode = GEN6_TEXCOORDMODE_CLAMP; - sampler_state->ss1.s_wrap_mode = GEN6_TEXCOORDMODE_CLAMP; - sampler_state->ss1.t_wrap_mode = GEN6_TEXCOORDMODE_CLAMP; - break; - case SAMPLER_EXTEND_REFLECT: - sampler_state->ss1.r_wrap_mode = GEN6_TEXCOORDMODE_MIRROR; - sampler_state->ss1.s_wrap_mode = GEN6_TEXCOORDMODE_MIRROR; - sampler_state->ss1.t_wrap_mode = GEN6_TEXCOORDMODE_MIRROR; - break; - } -} - -static uint32_t gen6_create_cc_viewport(struct sna_static_stream *stream) -{ - struct gen6_cc_viewport vp; - - vp.min_depth = -1.e35; - vp.max_depth = 1.e35; - - return sna_static_stream_add(stream, &vp, sizeof(vp), 32); -} - -#if 0 - -static uint32_t gen6_get_card_format(PictFormat format) -{ - unsigned int i; - - for (i = 0; i < ARRAY_SIZE(gen6_tex_formats); i++) { - if (gen6_tex_formats[i].pict_fmt == format) - return gen6_tex_formats[i].card_fmt; - } - return -1; -} -#endif - -static uint32_t -gen6_tiling_bits(uint32_t tiling) -{ - return 0; -/* - switch (tiling) { - default: assert(0); - case I915_TILING_NONE: return 0; - case I915_TILING_X: return GEN6_SURFACE_TILED; - case I915_TILING_Y: return GEN6_SURFACE_TILED | GEN6_SURFACE_TILED_Y; - } -*/ -} - -/** - * Sets up the common fields for a surface state buffer for the given - * picture in the given surface state buffer. - */ -static int -gen6_bind_bo(struct sna *sna, - struct kgem_bo *bo, - uint32_t width, - uint32_t height, - uint32_t format, - Bool is_dst) -{ - uint32_t *ss; - uint32_t domains; - uint16_t offset; - - /* After the first bind, we manage the cache domains within the batch */ - if (is_dst) { - domains = I915_GEM_DOMAIN_RENDER << 16 |I915_GEM_DOMAIN_RENDER; -// kgem_bo_mark_dirty(bo); - } else - domains = I915_GEM_DOMAIN_SAMPLER << 16; - -// offset = kgem_bo_get_binding(bo, format); -// if (offset) { -// DBG(("[%x] bo(handle=%x), format=%d, reuse %s binding\n", -// offset, bo->handle, format, -// domains & 0xffff ? "render" : "sampler")); -// return offset; -// } - - offset = sna->kgem.surface - sizeof(struct gen6_surface_state_padded) / sizeof(uint32_t); - offset *= sizeof(uint32_t); - - sna->kgem.surface -= - sizeof(struct gen6_surface_state_padded) / sizeof(uint32_t); - ss = sna->kgem.batch + sna->kgem.surface; - ss[0] = (GEN6_SURFACE_2D << GEN6_SURFACE_TYPE_SHIFT | - GEN6_SURFACE_BLEND_ENABLED | - format << GEN6_SURFACE_FORMAT_SHIFT); - ss[1] = bo->gaddr; - ss[2] = ((width - 1) << GEN6_SURFACE_WIDTH_SHIFT | - (height - 1) << GEN6_SURFACE_HEIGHT_SHIFT); - assert(bo->pitch <= (1 << 18)); - ss[3] = (gen6_tiling_bits(0) | - (bo->pitch - 1) << GEN6_SURFACE_PITCH_SHIFT); - ss[4] = 0; - ss[5] = 0; - -// kgem_bo_set_binding(bo, format, offset); - - DBG(("[%x] bind bo(handle=%d, addr=%d), format=%d, width=%d, height=%d, pitch=%d, tiling=%d -> %s\n", - offset, bo->handle, ss[1], - format, width, height, bo->pitch, bo->tiling, - domains & 0xffff ? "render" : "sampler")); - - return offset; -} - - -static void gen6_emit_vertex_buffer(struct sna *sna, - const struct sna_composite_op *op) -{ - int id = op->u.gen6.ve_id; - - OUT_BATCH(GEN6_3DSTATE_VERTEX_BUFFERS | 3); - OUT_BATCH(id << VB0_BUFFER_INDEX_SHIFT | VB0_VERTEXDATA | - 4*op->floats_per_vertex << VB0_BUFFER_PITCH_SHIFT); - sna->render.vertex_reloc[id] = sna->kgem.nbatch; - OUT_BATCH(0); - OUT_BATCH(0); - OUT_BATCH(0); - - sna->render_state.gen6.vb_id |= 1 << id; -} - -static void gen6_emit_primitive(struct sna *sna) -{ - if (sna->kgem.nbatch == sna->render_state.gen6.last_primitive) { - DBG(("%s: continuing previous primitive, start=%d, index=%d\n", - __FUNCTION__, - sna->render.vertex_start, - sna->render.vertex_index)); - sna->render_state.gen6.vertex_offset = sna->kgem.nbatch - 5; - return; - } - - OUT_BATCH(GEN6_3DPRIMITIVE | - GEN6_3DPRIMITIVE_VERTEX_SEQUENTIAL | - _3DPRIM_RECTLIST << GEN6_3DPRIMITIVE_TOPOLOGY_SHIFT | - 0 << 9 | - 4); - sna->render_state.gen6.vertex_offset = sna->kgem.nbatch; - OUT_BATCH(0); /* vertex count, to be filled in later */ - OUT_BATCH(sna->render.vertex_index); - OUT_BATCH(1); /* single instance */ - OUT_BATCH(0); /* start instance location */ - OUT_BATCH(0); /* index buffer offset, ignored */ - sna->render.vertex_start = sna->render.vertex_index; - DBG(("%s: started new primitive: index=%d\n", - __FUNCTION__, sna->render.vertex_start)); - - sna->render_state.gen6.last_primitive = sna->kgem.nbatch; -} - -static bool gen6_rectangle_begin(struct sna *sna, - const struct sna_composite_op *op) -{ - int id = 1 << op->u.gen6.ve_id; - int ndwords; - - ndwords = op->need_magic_ca_pass ? 60 : 6; - if ((sna->render_state.gen6.vb_id & id) == 0) - ndwords += 5; - if (!kgem_check_batch(&sna->kgem, ndwords)) - return false; - - if ((sna->render_state.gen6.vb_id & id) == 0) - gen6_emit_vertex_buffer(sna, op); - - gen6_emit_primitive(sna); - return true; -} - -static int gen6_get_rectangles__flush(struct sna *sna, - const struct sna_composite_op *op) -{ - if (sna->render_state.gen6.vertex_offset) { - gen6_vertex_flush(sna); - gen6_magic_ca_pass(sna, op); - } - - if (!kgem_check_batch(&sna->kgem, op->need_magic_ca_pass ? 65 : 5)) - return 0; - if (sna->kgem.nexec > KGEM_EXEC_SIZE(&sna->kgem) - 1) - return 0; - if (sna->kgem.nreloc > KGEM_RELOC_SIZE(&sna->kgem) - 2) - return 0; - - return gen6_vertex_finish(sna); -} - -inline static int gen6_get_rectangles(struct sna *sna, - const struct sna_composite_op *op, - int want) -{ - int rem = vertex_space(sna); - - if (rem < op->floats_per_rect) { - DBG(("flushing vbo for %s: %d < %d\n", - __FUNCTION__, rem, op->floats_per_rect)); - rem = gen6_get_rectangles__flush(sna, op); - if (rem == 0) - return 0; - } - - if (sna->render_state.gen6.vertex_offset == 0 && - !gen6_rectangle_begin(sna, op)) - return 0; - - if (want > 1 && want * op->floats_per_rect > rem) - want = rem / op->floats_per_rect; - - assert(want > 0); - sna->render.vertex_index += 3*want; - return want; -} - -inline static uint32_t *gen6_composite_get_binding_table(struct sna *sna, - uint16_t *offset) -{ - uint32_t *table; - - sna->kgem.surface -= - sizeof(struct gen6_surface_state_padded) / sizeof(uint32_t); - /* Clear all surplus entries to zero in case of prefetch */ - table = memset(sna->kgem.batch + sna->kgem.surface, - 0, sizeof(struct gen6_surface_state_padded)); - - DBG(("%s(%x)\n", __FUNCTION__, 4*sna->kgem.surface)); - - *offset = sna->kgem.surface; - return table; -} - -static uint32_t -gen6_choose_composite_vertex_buffer(const struct sna_composite_op *op) -{ - int has_mask = op->mask.bo != NULL; - int is_affine = op->is_affine; - return has_mask << 1 | is_affine; -} - -static void -gen6_get_batch(struct sna *sna) -{ - kgem_set_mode(&sna->kgem, KGEM_RENDER); -/* - if (!kgem_check_batch_with_surfaces(&sna->kgem, 150, 4)) { - DBG(("%s: flushing batch: %d < %d+%d\n", - __FUNCTION__, sna->kgem.surface - sna->kgem.nbatch, - 150, 4*8)); - kgem_submit(&sna->kgem); - _kgem_set_mode(&sna->kgem, KGEM_RENDER); - } -*/ - - if (sna->render_state.gen6.needs_invariant) - gen6_emit_invariant(sna); -} - -static void gen6_emit_composite_state(struct sna *sna, - const struct sna_composite_op *op) -{ - uint32_t *binding_table; - uint16_t offset; - bool dirty; - - gen6_get_batch(sna); - dirty = FALSE; - - binding_table = gen6_composite_get_binding_table(sna, &offset); - - binding_table[0] = - gen6_bind_bo(sna, - op->dst.bo, op->dst.width, op->dst.height, - op->dst.format, - TRUE); - binding_table[1] = - gen6_bind_bo(sna, - op->src.bo, op->src.width, op->src.height, - op->src.card_format, - FALSE); - if (op->mask.bo) { - binding_table[2] = - gen6_bind_bo(sna, - op->mask.bo, - op->mask.width, - op->mask.height, - op->mask.card_format, - FALSE); - } - - if (sna->kgem.surface == offset && - *(uint64_t *)(sna->kgem.batch + sna->render_state.gen6.surface_table) == *(uint64_t*)binding_table && - (op->mask.bo == NULL || - sna->kgem.batch[sna->render_state.gen6.surface_table+2] == binding_table[2])) { - sna->kgem.surface += sizeof(struct gen6_surface_state_padded) / sizeof(uint32_t); - offset = sna->render_state.gen6.surface_table; - } - - gen6_emit_state(sna, op, offset | dirty); -} - - - -static void -gen6_align_vertex(struct sna *sna, const struct sna_composite_op *op) -{ - assert (sna->render_state.gen6.vertex_offset == 0); - if (op->floats_per_vertex != sna->render_state.gen6.floats_per_vertex) { - if (sna->render.vertex_size - sna->render.vertex_used < 2*op->floats_per_rect) - /* XXX propagate failure */ - gen6_vertex_finish(sna); - - DBG(("aligning vertex: was %d, now %d floats per vertex, %d->%d\n", - sna->render_state.gen6.floats_per_vertex, - op->floats_per_vertex, - sna->render.vertex_index, - (sna->render.vertex_used + op->floats_per_vertex - 1) / op->floats_per_vertex)); - sna->render.vertex_index = (sna->render.vertex_used + op->floats_per_vertex - 1) / op->floats_per_vertex; - sna->render.vertex_used = sna->render.vertex_index * op->floats_per_vertex; - sna->render_state.gen6.floats_per_vertex = op->floats_per_vertex; - } -} - - -#ifndef MAX -#define MAX(a,b) ((a) > (b) ? (a) : (b)) -#endif - -static uint32_t -gen6_composite_create_blend_state(struct sna_static_stream *stream) -{ - char *base, *ptr; - int src, dst; - - base = sna_static_stream_map(stream, - GEN6_BLENDFACTOR_COUNT * GEN6_BLENDFACTOR_COUNT * GEN6_BLEND_STATE_PADDED_SIZE, - 64); - - ptr = base; - for (src = 0; src < GEN6_BLENDFACTOR_COUNT; src++) { - for (dst= 0; dst < GEN6_BLENDFACTOR_COUNT; dst++) { - struct gen6_blend_state *blend = - (struct gen6_blend_state *)ptr; - - blend->blend0.dest_blend_factor = dst; - blend->blend0.source_blend_factor = src; - blend->blend0.blend_func = GEN6_BLENDFUNCTION_ADD; - blend->blend0.blend_enable = - !(dst == GEN6_BLENDFACTOR_ZERO && src == GEN6_BLENDFACTOR_ONE); - - blend->blend1.post_blend_clamp_enable = 1; - blend->blend1.pre_blend_clamp_enable = 1; - - ptr += GEN6_BLEND_STATE_PADDED_SIZE; - } - } - - return sna_static_stream_offsetof(stream, base); -} - -#if 0 -static uint32_t gen6_bind_video_source(struct sna *sna, - struct kgem_bo *src_bo, - uint32_t src_offset, - int src_width, - int src_height, - int src_pitch, - uint32_t src_surf_format) -{ - struct gen6_surface_state *ss; - - sna->kgem.surface -= sizeof(struct gen6_surface_state_padded) / sizeof(uint32_t); - - ss = memset(sna->kgem.batch + sna->kgem.surface, 0, sizeof(*ss)); - ss->ss0.surface_type = GEN6_SURFACE_2D; - ss->ss0.surface_format = src_surf_format; - - ss->ss1.base_addr = - kgem_add_reloc(&sna->kgem, - sna->kgem.surface + 1, - src_bo, - I915_GEM_DOMAIN_SAMPLER << 16, - src_offset); - - ss->ss2.width = src_width - 1; - ss->ss2.height = src_height - 1; - ss->ss3.pitch = src_pitch - 1; - - return sna->kgem.surface * sizeof(uint32_t); -} - -static void gen6_emit_video_state(struct sna *sna, - struct sna_composite_op *op, - struct sna_video_frame *frame) -{ - uint32_t src_surf_format; - uint32_t src_surf_base[6]; - int src_width[6]; - int src_height[6]; - int src_pitch[6]; - uint32_t *binding_table; - uint16_t offset; - bool dirty; - int n_src, n; - - gen6_get_batch(sna); - dirty = kgem_bo_is_dirty(op->dst.bo); - - src_surf_base[0] = 0; - src_surf_base[1] = 0; - src_surf_base[2] = frame->VBufOffset; - src_surf_base[3] = frame->VBufOffset; - src_surf_base[4] = frame->UBufOffset; - src_surf_base[5] = frame->UBufOffset; - - if (is_planar_fourcc(frame->id)) { - src_surf_format = GEN6_SURFACEFORMAT_R8_UNORM; - src_width[1] = src_width[0] = frame->width; - src_height[1] = src_height[0] = frame->height; - src_pitch[1] = src_pitch[0] = frame->pitch[1]; - src_width[4] = src_width[5] = src_width[2] = src_width[3] = - frame->width / 2; - src_height[4] = src_height[5] = src_height[2] = src_height[3] = - frame->height / 2; - src_pitch[4] = src_pitch[5] = src_pitch[2] = src_pitch[3] = - frame->pitch[0]; - n_src = 6; - } else { - if (frame->id == FOURCC_UYVY) - src_surf_format = GEN6_SURFACEFORMAT_YCRCB_SWAPY; - else - src_surf_format = GEN6_SURFACEFORMAT_YCRCB_NORMAL; - - src_width[0] = frame->width; - src_height[0] = frame->height; - src_pitch[0] = frame->pitch[0]; - n_src = 1; - } - - binding_table = gen6_composite_get_binding_table(sna, &offset); - - binding_table[0] = - gen6_bind_bo(sna, - op->dst.bo, op->dst.width, op->dst.height, - gen6_get_dest_format(op->dst.format), - TRUE); - for (n = 0; n < n_src; n++) { - binding_table[1+n] = - gen6_bind_video_source(sna, - frame->bo, - src_surf_base[n], - src_width[n], - src_height[n], - src_pitch[n], - src_surf_format); - } - - gen6_emit_state(sna, op, offset | dirty); -} - -static Bool -gen6_render_video(struct sna *sna, - struct sna_video *video, - struct sna_video_frame *frame, - RegionPtr dstRegion, - short src_w, short src_h, - short drw_w, short drw_h, - PixmapPtr pixmap) -{ - struct sna_composite_op tmp; - int nbox, dxo, dyo, pix_xoff, pix_yoff; - float src_scale_x, src_scale_y; - struct sna_pixmap *priv; - BoxPtr box; - - DBG(("%s: src=(%d, %d), dst=(%d, %d), %dx[(%d, %d), (%d, %d)...]\n", - __FUNCTION__, src_w, src_h, drw_w, drw_h, - REGION_NUM_RECTS(dstRegion), - REGION_EXTENTS(NULL, dstRegion)->x1, - REGION_EXTENTS(NULL, dstRegion)->y1, - REGION_EXTENTS(NULL, dstRegion)->x2, - REGION_EXTENTS(NULL, dstRegion)->y2)); - - priv = sna_pixmap_force_to_gpu(pixmap, MOVE_READ | MOVE_WRITE); - if (priv == NULL) - return FALSE; - - memset(&tmp, 0, sizeof(tmp)); - - tmp.op = PictOpSrc; - tmp.dst.pixmap = pixmap; - tmp.dst.width = pixmap->drawable.width; - tmp.dst.height = pixmap->drawable.height; - tmp.dst.format = sna_render_format_for_depth(pixmap->drawable.depth); - tmp.dst.bo = priv->gpu_bo; - - tmp.src.bo = frame->bo; - tmp.src.filter = SAMPLER_FILTER_BILINEAR; - tmp.src.repeat = SAMPLER_EXTEND_PAD; - - tmp.mask.bo = NULL; - - tmp.is_affine = TRUE; - tmp.floats_per_vertex = 3; - tmp.floats_per_rect = 9; - - if (is_planar_fourcc(frame->id)) { - tmp.u.gen6.wm_kernel = GEN6_WM_KERNEL_VIDEO_PLANAR; - tmp.u.gen6.nr_surfaces = 7; - } else { - tmp.u.gen6.wm_kernel = GEN6_WM_KERNEL_VIDEO_PACKED; - tmp.u.gen6.nr_surfaces = 2; - } - tmp.u.gen6.nr_inputs = 1; - tmp.u.gen6.ve_id = 1; - - kgem_set_mode(&sna->kgem, KGEM_RENDER); - if (!kgem_check_bo(&sna->kgem, tmp.dst.bo, frame->bo, NULL)) { - kgem_submit(&sna->kgem); - assert(kgem_check_bo(&sna->kgem, tmp.dst.bo, frame->bo, NULL)); - _kgem_set_mode(&sna->kgem, KGEM_RENDER); - } - - gen6_emit_video_state(sna, &tmp, frame); - gen6_align_vertex(sna, &tmp); - - /* Set up the offset for translating from the given region (in screen - * coordinates) to the backing pixmap. - */ -#ifdef COMPOSITE - pix_xoff = -pixmap->screen_x + pixmap->drawable.x; - pix_yoff = -pixmap->screen_y + pixmap->drawable.y; -#else - pix_xoff = 0; - pix_yoff = 0; -#endif - - dxo = dstRegion->extents.x1; - dyo = dstRegion->extents.y1; - - /* Use normalized texture coordinates */ - src_scale_x = ((float)src_w / frame->width) / (float)drw_w; - src_scale_y = ((float)src_h / frame->height) / (float)drw_h; - - box = REGION_RECTS(dstRegion); - nbox = REGION_NUM_RECTS(dstRegion); - while (nbox--) { - BoxRec r; - - r.x1 = box->x1 + pix_xoff; - r.x2 = box->x2 + pix_xoff; - r.y1 = box->y1 + pix_yoff; - r.y2 = box->y2 + pix_yoff; - - if (unlikely(!gen6_get_rectangles(sna, &tmp, 1))) { - _kgem_submit(&sna->kgem); - gen6_emit_video_state(sna, &tmp, frame); - gen6_get_rectangles(sna, &tmp, 1); - } - - OUT_VERTEX(r.x2, r.y2); - OUT_VERTEX_F((box->x2 - dxo) * src_scale_x); - OUT_VERTEX_F((box->y2 - dyo) * src_scale_y); - - OUT_VERTEX(r.x1, r.y2); - OUT_VERTEX_F((box->x1 - dxo) * src_scale_x); - OUT_VERTEX_F((box->y2 - dyo) * src_scale_y); - - OUT_VERTEX(r.x1, r.y1); - OUT_VERTEX_F((box->x1 - dxo) * src_scale_x); - OUT_VERTEX_F((box->y1 - dyo) * src_scale_y); - - if (!DAMAGE_IS_ALL(priv->gpu_damage)) { - sna_damage_add_box(&priv->gpu_damage, &r); - sna_damage_subtract_box(&priv->cpu_damage, &r); - } - box++; - } - priv->clear = false; - - gen6_vertex_flush(sna); - return TRUE; -} - -#endif - - -fastcall static void -gen6_emit_composite_primitive_identity_source_mask(struct sna *sna, - const struct sna_composite_op *op, - const struct sna_composite_rectangles *r) -{ - union { - struct sna_coordinate p; - float f; - } dst; - float src_x, src_y; - float msk_x, msk_y; - float w, h; - float *v; - - src_x = r->src.x + op->src.offset[0]; - src_y = r->src.y + op->src.offset[1]; - msk_x = r->mask.x + op->mask.offset[0]; - msk_y = r->mask.y + op->mask.offset[1]; - w = r->width; - h = r->height; - - v = sna->render.vertices + sna->render.vertex_used; - sna->render.vertex_used += 15; - - dst.p.x = r->dst.x + r->width; - dst.p.y = r->dst.y + r->height; - v[0] = dst.f; - v[1] = (src_x + w) * op->src.scale[0]; - v[2] = (src_y + h) * op->src.scale[1]; - v[3] = (msk_x + w) * op->mask.scale[0]; - v[4] = (msk_y + h) * op->mask.scale[1]; - - dst.p.x = r->dst.x; - v[5] = dst.f; - v[6] = src_x * op->src.scale[0]; - v[7] = v[2]; - v[8] = msk_x * op->mask.scale[0]; - v[9] = v[4]; - - dst.p.y = r->dst.y; - v[10] = dst.f; - v[11] = v[6]; - v[12] = src_y * op->src.scale[1]; - v[13] = v[8]; - v[14] = msk_y * op->mask.scale[1]; -} - -fastcall static void -gen6_render_composite_box(struct sna *sna, - const struct sna_composite_op *op, - const BoxRec *box) -{ - struct sna_composite_rectangles r; - - if (unlikely(!gen6_get_rectangles(sna, op, 1))) { -// _kgem_submit(&sna->kgem); -// gen6_emit_composite_state(sna, op); -// gen6_get_rectangles(sna, op, 1); - } - - DBG((" %s: (%d, %d), (%d, %d)\n", - __FUNCTION__, - box->x1, box->y1, box->x2, box->y2)); - - r.dst.x = box->x1; - r.dst.y = box->y1; - r.width = box->x2 - box->x1; - r.height = box->y2 - box->y1; - r.src = r.mask = r.dst; - - op->prim_emit(sna, op, &r); -} - - -static void gen6_render_composite_done(struct sna *sna, - const struct sna_composite_op *op) -{ - DBG(("%s\n", __FUNCTION__)); - - if (sna->render_state.gen6.vertex_offset) { - gen6_vertex_flush(sna); - gen6_magic_ca_pass(sna, op); - } - -// if (op->mask.bo) -// kgem_bo_destroy(&sna->kgem, op->mask.bo); -// if (op->src.bo) -// kgem_bo_destroy(&sna->kgem, op->src.bo); - -// sna_render_composite_redirect_done(sna, op); -} - - -static Bool -gen6_render_composite(struct sna *sna, - uint8_t op, - bitmap_t *src, - struct kgem_bo *src_bo, - bitmap_t *mask, - struct kgem_bo *mask_bo, - bitmap_t *dst, - struct kgem_bo *dst_bo, - int16_t src_x, int16_t src_y, - int16_t msk_x, int16_t msk_y, - int16_t dst_x, int16_t dst_y, - int16_t width, int16_t height, - struct sna_composite_op *tmp) -{ -// if (op >= ARRAY_SIZE(gen6_blend_op)) -// return FALSE; - -// ENTER(); - - DBG(("%s: %dx%d, current mode=%d\n", __FUNCTION__, - width, height, sna->kgem.ring)); - - tmp->op = PictOpSrc; - - tmp->dst.bo = dst_bo; - tmp->dst.width = dst->width; - tmp->dst.height = dst->height; - tmp->dst.format = GEN6_SURFACEFORMAT_B8G8R8A8_UNORM; - - - tmp->src.bo = src_bo; - tmp->src.card_format = GEN6_SURFACEFORMAT_B8G8R8A8_UNORM; - tmp->src.width = src->width; - tmp->src.height = src->height; - - tmp->src.scale[0] = 1.f/width; //src->width; - tmp->src.scale[1] = 1.f/height; //src->height; - tmp->src.filter = SAMPLER_FILTER_BILINEAR; - tmp->src.repeat = SAMPLER_EXTEND_NONE; - tmp->src.offset[0] = -dst_x; - tmp->src.offset[1] = -dst_y; - tmp->src.is_affine = TRUE; - - - tmp->mask.bo = mask_bo; - tmp->mask.card_format = GEN6_SURFACEFORMAT_A8_UNORM; - tmp->mask.width = mask->width; - tmp->mask.height = mask->height; - - tmp->mask.scale[0] = 1.f/mask->width; - tmp->mask.scale[1] = 1.f/mask->height; - tmp->mask.filter = SAMPLER_FILTER_NEAREST; - tmp->mask.repeat = SAMPLER_EXTEND_NONE; - tmp->mask.offset[0] = -dst_x; - tmp->mask.offset[1] = -dst_y; - tmp->mask.is_affine = TRUE; - - tmp->is_affine = TRUE; - tmp->has_component_alpha = FALSE; - tmp->need_magic_ca_pass = FALSE; - - tmp->prim_emit = gen6_emit_composite_primitive_identity_source_mask; - - tmp->floats_per_vertex = 5 + 2 * !tmp->is_affine; - - tmp->floats_per_rect = 3 * tmp->floats_per_vertex; - - tmp->u.gen6.wm_kernel = GEN6_WM_KERNEL_MASK; - tmp->u.gen6.nr_surfaces = 2 + 1; - tmp->u.gen6.nr_inputs = 1 + 1; - tmp->u.gen6.ve_id = gen6_choose_composite_vertex_buffer(tmp); - - tmp->need_magic_ca_pass = TRUE; - -// tmp->blt = gen6_render_composite_blt; - tmp->box = gen6_render_composite_box; -// tmp->boxes = gen6_render_composite_boxes; - tmp->done = gen6_render_composite_done; - - gen6_emit_composite_state(sna, tmp); - gen6_align_vertex(sna, tmp); - -// LEAVE(); - - return TRUE; -} - - -static void -gen6_emit_copy_state(struct sna *sna, - const struct sna_composite_op *op) -{ - uint32_t *binding_table; - uint16_t offset; - bool dirty; - - gen6_get_batch(sna); - - binding_table = gen6_composite_get_binding_table(sna, &offset); - - binding_table[0] = - gen6_bind_bo(sna, - op->dst.bo, op->dst.width, op->dst.height, - GEN6_SURFACEFORMAT_B8G8R8A8_UNORM, - TRUE); - binding_table[1] = - gen6_bind_bo(sna, - op->src.bo, op->src.width, op->src.height, - GEN6_SURFACEFORMAT_B8G8R8A8_UNORM, - FALSE); - - if (sna->kgem.surface == offset && - *(uint64_t *)(sna->kgem.batch + sna->render_state.gen6.surface_table) == *(uint64_t*)binding_table) { - sna->kgem.surface += sizeof(struct gen6_surface_state_padded) / sizeof(uint32_t); - offset = sna->render_state.gen6.surface_table; - } - - gen6_emit_state(sna, op, offset | dirty); -} - - -static void -gen6_render_copy_blt(struct sna *sna, - const struct sna_composite_op *op, - int16_t sx, int16_t sy, - int16_t w, int16_t h, - int16_t dx, int16_t dy) -{ - if (unlikely(!gen6_get_rectangles(sna, op, 1))) { -// _kgem_submit(&sna->kgem); - gen6_emit_copy_state(sna, op); - gen6_get_rectangles(sna, op, 1); - } - - OUT_VERTEX(dx+w, dy+h); - OUT_VERTEX_F((sx+w)*op->src.scale[0]); - OUT_VERTEX_F((sy+h)*op->src.scale[1]); - - OUT_VERTEX(dx, dy+h); - OUT_VERTEX_F(sx*op->src.scale[0]); - OUT_VERTEX_F((sy+h)*op->src.scale[1]); - - OUT_VERTEX(dx, dy); - OUT_VERTEX_F(sx*op->src.scale[0]); - OUT_VERTEX_F(sy*op->src.scale[1]); -} - -static void -gen6_render_copy_done(struct sna *sna) -{ - DBG(("%s()\n", __FUNCTION__)); - - if (sna->render_state.gen6.vertex_offset) - gen6_vertex_flush(sna); -} - -static Bool -gen6_render_copy(struct sna *sna, uint8_t alu, - bitmap_t *src, struct kgem_bo *src_bo, - bitmap_t *dst, struct kgem_bo *dst_bo, - int dst_x, int dst_y, int src_x, int src_y, int w, int h) -{ - struct sna_composite_op op; - - memset(&op, 0, sizeof(op)); - - DBG(("%s (alu=%d, src=(%dx%d), dst=(%dx%d))\n", - __FUNCTION__, alu, - src->width, src->height, - dst->width, dst->height)); - -// printf("%s %dx%d src=(%dx%d), dst=(%dx%d)\n", -// __FUNCTION__,dst_x, dst_y, -// src->width, src->height, -// dst->width, dst->height); - - op.dst.format = 0; - op.src.pict_format = 0; - - op.op = PictOpSrc; - - op.dst.pixmap = dst; - op.dst.width = dst->width; - op.dst.height = dst->height; - op.dst.bo = dst_bo; - - op.src.bo = src_bo; - op.src.card_format = GEN6_SURFACEFORMAT_B8G8R8X8_UNORM; - op.src.width = src->width; - op.src.height = src->height; - - op.src.scale[0] = 1.f/w; //src->width; - op.src.scale[1] = 1.f/h; //src->height; - op.src.filter = SAMPLER_FILTER_BILINEAR; - op.src.repeat = SAMPLER_EXTEND_NONE; - - op.mask.bo = NULL; - - op.is_affine = true; - op.floats_per_vertex = 3; - op.floats_per_rect = 9; - - op.u.gen6.wm_kernel = GEN6_WM_KERNEL_NOMASK; - op.u.gen6.nr_surfaces = 2; - op.u.gen6.nr_inputs = 1; - op.u.gen6.ve_id = 1; - - gen6_emit_copy_state(sna, &op); - gen6_align_vertex(sna, &op); - - gen6_render_copy_blt(sna, &op, src_x, src_y, w, h, dst_x, dst_y); - gen6_render_copy_done(sna); - - return TRUE; -} - -static void -gen6_emit_fill_state(struct sna *sna, const struct sna_composite_op *op) -{ - uint32_t *binding_table; - uint16_t offset; - bool dirty; - - gen6_get_batch(sna); -// dirty = kgem_bo_is_dirty(op->dst.bo); - - binding_table = gen6_composite_get_binding_table(sna, &offset); - - binding_table[0] = - gen6_bind_bo(sna, - op->dst.bo, 1024, 768, - GEN6_SURFACEFORMAT_B8G8R8A8_UNORM, - TRUE); - binding_table[1] = - gen6_bind_bo(sna, - op->src.bo, 1, 1, - GEN6_SURFACEFORMAT_B8G8R8A8_UNORM, - FALSE); - - if (sna->kgem.surface == offset && - *(uint64_t *)(sna->kgem.batch + sna->render_state.gen6.surface_table) == *(uint64_t*)binding_table) { - sna->kgem.surface += - sizeof(struct gen6_surface_state_padded)/sizeof(uint32_t); - offset = sna->render_state.gen6.surface_table; - } - - gen6_emit_state(sna, op, offset | dirty); -} - - -static Bool -gen6_render_clear(struct sna *sna, bitmap_t *dst, struct kgem_bo *bo) -{ - struct sna_composite_op tmp; - - - DBG(("%s: %dx%d\n", - __FUNCTION__, - dst->width, - dst->height)); - - tmp.op = PictOpSrc; - - tmp.dst.pixmap = dst; - tmp.dst.width = dst->width; - tmp.dst.height = dst->height; - tmp.dst.format = 0; //PICT_a8r8g8b8; - tmp.dst.bo = bo; - tmp.dst.x = tmp.dst.y = 0; - -// tmp.src.bo = sna_render_get_solid(sna, 0); - tmp.src.bo = bo; - tmp.src.filter = SAMPLER_FILTER_NEAREST; - tmp.src.repeat = SAMPLER_EXTEND_REPEAT; - - tmp.mask.bo = NULL; - tmp.mask.filter = SAMPLER_FILTER_NEAREST; - tmp.mask.repeat = SAMPLER_EXTEND_NONE; - - tmp.is_affine = TRUE; - tmp.floats_per_vertex = 3; - tmp.floats_per_rect = 9; - tmp.has_component_alpha = 0; - tmp.need_magic_ca_pass = FALSE; - - tmp.u.gen6.wm_kernel = GEN6_WM_KERNEL_NOMASK; - tmp.u.gen6.nr_surfaces = 2; - tmp.u.gen6.nr_inputs = 1; - tmp.u.gen6.ve_id = 1; - -// if (!kgem_check_bo(&sna->kgem, bo, NULL)) { -// _kgem_submit(&sna->kgem); -// assert(kgem_check_bo(&sna->kgem, bo, NULL)); -// } - - gen6_emit_fill_state(sna, &tmp); - gen6_align_vertex(sna, &tmp); - - if (unlikely(!gen6_get_rectangles(sna, &tmp, 1))) { -// _kgem_submit(&sna->kgem); - gen6_emit_fill_state(sna, &tmp); - gen6_get_rectangles(sna, &tmp, 1); - } - - OUT_VERTEX(dst->width, dst->height); - OUT_VERTEX_F(1); - OUT_VERTEX_F(1); - - OUT_VERTEX(0, dst->height); - OUT_VERTEX_F(0); - OUT_VERTEX_F(1); - - OUT_VERTEX(0, 0); - OUT_VERTEX_F(0); - OUT_VERTEX_F(0); - - gen6_vertex_flush(sna); -// kgem_bo_destroy(&sna->kgem, tmp.src.bo); -// gen6_render_composite_done(sna, &tmp); -// _kgem_submit(&sna->kgem); - - return TRUE; -} - -static void gen6_render_flush(struct sna *sna) -{ - gen6_vertex_close(sna); -} - - -static void -gen6_render_retire(struct kgem *kgem) -{ - if (kgem->ring && (kgem->has_semaphores || !kgem->need_retire)) - kgem->ring = kgem->mode; -} - -static void gen6_render_reset(struct sna *sna) -{ - sna->render_state.gen6.needs_invariant = TRUE; - sna->render_state.gen6.vb_id = 0; - sna->render_state.gen6.ve_id = -1; - sna->render_state.gen6.last_primitive = -1; - - sna->render_state.gen6.num_sf_outputs = 0; - sna->render_state.gen6.samplers = -1; - sna->render_state.gen6.blend = -1; - sna->render_state.gen6.kernel = -1; - sna->render_state.gen6.drawrect_offset = -1; - sna->render_state.gen6.drawrect_limit = -1; - sna->render_state.gen6.surface_table = -1; -} - -static void gen6_render_fini(struct sna *sna) -{ -// kgem_bo_destroy(&sna->kgem, sna->render_state.gen6.general_bo); -} - -static Bool gen6_render_setup(struct sna *sna) -{ - struct gen6_render_state *state = &sna->render_state.gen6; - struct sna_static_stream general; - struct gen6_sampler_state *ss; - int i, j, k, l, m; - - sna_static_stream_init(&general); - - /* Zero pad the start. If you see an offset of 0x0 in the batchbuffer - * dumps, you know it points to zero. - */ - null_create(&general); - scratch_create(&general); - - for (m = 0; m < GEN6_KERNEL_COUNT; m++) - state->wm_kernel[m] = - sna_static_stream_add(&general, - wm_kernels[m].data, - wm_kernels[m].size, - 64); - - ss = sna_static_stream_map(&general, - 2 * sizeof(*ss) * - FILTER_COUNT * EXTEND_COUNT * - FILTER_COUNT * EXTEND_COUNT, - 32); - state->wm_state = sna_static_stream_offsetof(&general, ss); - for (i = 0; i < FILTER_COUNT; i++) { - for (j = 0; j < EXTEND_COUNT; j++) { - for (k = 0; k < FILTER_COUNT; k++) { - for (l = 0; l < EXTEND_COUNT; l++) { - sampler_state_init(ss++, i, j); - sampler_state_init(ss++, k, l); - } - } - } - } - - state->cc_vp = gen6_create_cc_viewport(&general); - state->cc_blend = gen6_composite_create_blend_state(&general); - - state->general_bo = sna_static_stream_fini(sna, &general); - return state->general_bo != NULL; -} - -Bool gen6_render_init(struct sna *sna) -{ - if (!gen6_render_setup(sna)) - return FALSE; - -// sna->kgem.context_switch = gen6_render_context_switch; - sna->kgem.retire = gen6_render_retire; - - sna->render.composite = gen6_render_composite; -// sna->render.video = gen6_render_video; - -// sna->render.copy_boxes = gen6_render_copy_boxes; - sna->render.copy = gen6_render_copy; - -// sna->render.fill_boxes = gen6_render_fill_boxes; -// sna->render.fill = gen6_render_fill; -// sna->render.fill_one = gen6_render_fill_one; - sna->render.clear = gen6_render_clear; - - sna->render.flush = gen6_render_flush; - sna->render.reset = gen6_render_reset; -// sna->render.fini = gen6_render_fini; - - sna->render.max_3d_size = GEN6_MAX_SIZE; - sna->render.max_3d_pitch = 1 << 18; - return TRUE; -} diff --git a/drivers/video/drm/i915/sna/gen6_render.h b/drivers/video/drm/i915/sna/gen6_render.h deleted file mode 100644 index eded2b7cb8..0000000000 --- a/drivers/video/drm/i915/sna/gen6_render.h +++ /dev/null @@ -1,1585 +0,0 @@ -#ifndef GEN6_RENDER_H -#define GEN6_RENDER_H - -#define GEN6_MASK(high, low) (((1 << ((high) - (low) + 1)) - 1) << (low)) - -#define GEN6_3D(Pipeline,Opcode,Subopcode) ((3 << 29) | \ - ((Pipeline) << 27) | \ - ((Opcode) << 24) | \ - ((Subopcode) << 16)) - -#define GEN6_STATE_BASE_ADDRESS GEN6_3D(0, 1, 1) -#define GEN6_STATE_SIP GEN6_3D(0, 1, 2) - -#define GEN6_PIPELINE_SELECT GEN6_3D(1, 1, 4) - -#define GEN6_MEDIA_STATE_POINTERS GEN6_3D(2, 0, 0) -#define GEN6_MEDIA_OBJECT GEN6_3D(2, 1, 0) - -#define GEN6_3DSTATE_BINDING_TABLE_POINTERS GEN6_3D(3, 0, 1) -# define GEN6_3DSTATE_BINDING_TABLE_MODIFY_PS (1 << 12)/* for GEN6 */ -# define GEN6_3DSTATE_BINDING_TABLE_MODIFY_GS (1 << 9) /* for GEN6 */ -# define GEN6_3DSTATE_BINDING_TABLE_MODIFY_VS (1 << 8) /* for GEN6 */ - -#define GEN6_3DSTATE_VERTEX_BUFFERS GEN6_3D(3, 0, 8) -#define GEN6_3DSTATE_VERTEX_ELEMENTS GEN6_3D(3, 0, 9) -#define GEN6_3DSTATE_INDEX_BUFFER GEN6_3D(3, 0, 0xa) -#define GEN6_3DSTATE_VF_STATISTICS GEN6_3D(3, 0, 0xb) - -#define GEN6_3DSTATE_DRAWING_RECTANGLE GEN6_3D(3, 1, 0) -#define GEN6_3DSTATE_CONSTANT_COLOR GEN6_3D(3, 1, 1) -#define GEN6_3DSTATE_SAMPLER_PALETTE_LOAD GEN6_3D(3, 1, 2) -#define GEN6_3DSTATE_CHROMA_KEY GEN6_3D(3, 1, 4) -#define GEN6_3DSTATE_DEPTH_BUFFER GEN6_3D(3, 1, 5) -# define GEN6_3DSTATE_DEPTH_BUFFER_TYPE_SHIFT 29 -# define GEN6_3DSTATE_DEPTH_BUFFER_FORMAT_SHIFT 18 - -#define GEN6_3DSTATE_POLY_STIPPLE_OFFSET GEN6_3D(3, 1, 6) -#define GEN6_3DSTATE_POLY_STIPPLE_PATTERN GEN6_3D(3, 1, 7) -#define GEN6_3DSTATE_LINE_STIPPLE GEN6_3D(3, 1, 8) -#define GEN6_3DSTATE_GLOBAL_DEPTH_OFFSET_CLAMP GEN6_3D(3, 1, 9) -/* These two are BLC and CTG only, not BW or CL */ -#define GEN6_3DSTATE_AA_LINE_PARAMS GEN6_3D(3, 1, 0xa) -#define GEN6_3DSTATE_GS_SVB_INDEX GEN6_3D(3, 1, 0xb) - -#define GEN6_3DPRIMITIVE GEN6_3D(3, 3, 0) - -#define GEN6_3DSTATE_CLEAR_PARAMS GEN6_3D(3, 1, 0x10) -/* DW1 */ -# define GEN6_3DSTATE_DEPTH_CLEAR_VALID (1 << 15) - -#define GEN6_3DSTATE_SAMPLER_STATE_POINTERS GEN6_3D(3, 0, 0x02) -# define GEN6_3DSTATE_SAMPLER_STATE_MODIFY_PS (1 << 12) -# define GEN6_3DSTATE_SAMPLER_STATE_MODIFY_GS (1 << 9) -# define GEN6_3DSTATE_SAMPLER_STATE_MODIFY_VS (1 << 8) - -#define GEN6_3DSTATE_URB GEN6_3D(3, 0, 0x05) -/* DW1 */ -# define GEN6_3DSTATE_URB_VS_SIZE_SHIFT 16 -# define GEN6_3DSTATE_URB_VS_ENTRIES_SHIFT 0 -/* DW2 */ -# define GEN6_3DSTATE_URB_GS_ENTRIES_SHIFT 8 -# define GEN6_3DSTATE_URB_GS_SIZE_SHIFT 0 - -#define GEN6_3DSTATE_VIEWPORT_STATE_POINTERS GEN6_3D(3, 0, 0x0d) -# define GEN6_3DSTATE_VIEWPORT_STATE_MODIFY_CC (1 << 12) -# define GEN6_3DSTATE_VIEWPORT_STATE_MODIFY_SF (1 << 11) -# define GEN6_3DSTATE_VIEWPORT_STATE_MODIFY_CLIP (1 << 10) - -#define GEN6_3DSTATE_CC_STATE_POINTERS GEN6_3D(3, 0, 0x0e) - -#define GEN6_3DSTATE_VS GEN6_3D(3, 0, 0x10) - -#define GEN6_3DSTATE_GS GEN6_3D(3, 0, 0x11) -/* DW4 */ -# define GEN6_3DSTATE_GS_DISPATCH_START_GRF_SHIFT 0 - -#define GEN6_3DSTATE_CLIP GEN6_3D(3, 0, 0x12) - -#define GEN6_3DSTATE_SF GEN6_3D(3, 0, 0x13) -/* DW1 */ -# define GEN6_3DSTATE_SF_NUM_OUTPUTS_SHIFT 22 -# define GEN6_3DSTATE_SF_URB_ENTRY_READ_LENGTH_SHIFT 11 -# define GEN6_3DSTATE_SF_URB_ENTRY_READ_OFFSET_SHIFT 4 -/* DW2 */ -/* DW3 */ -# define GEN6_3DSTATE_SF_CULL_BOTH (0 << 29) -# define GEN6_3DSTATE_SF_CULL_NONE (1 << 29) -# define GEN6_3DSTATE_SF_CULL_FRONT (2 << 29) -# define GEN6_3DSTATE_SF_CULL_BACK (3 << 29) -/* DW4 */ -# define GEN6_3DSTATE_SF_TRI_PROVOKE_SHIFT 29 -# define GEN6_3DSTATE_SF_LINE_PROVOKE_SHIFT 27 -# define GEN6_3DSTATE_SF_TRIFAN_PROVOKE_SHIFT 25 - -#define GEN6_3DSTATE_WM GEN6_3D(3, 0, 0x14) -/* DW2 */ -# define GEN6_3DSTATE_WM_SAMPLER_COUNT_SHIFT 27 -# define GEN6_3DSTATE_WM_BINDING_TABLE_ENTRY_COUNT_SHIFT 18 -/* DW4 */ -# define GEN6_3DSTATE_WM_DISPATCH_START_GRF_0_SHIFT 16 -/* DW5 */ -# define GEN6_3DSTATE_WM_MAX_THREADS_SHIFT 25 -# define GEN6_3DSTATE_WM_DISPATCH_ENABLE (1 << 19) -# define GEN6_3DSTATE_WM_16_DISPATCH_ENABLE (1 << 1) -# define GEN6_3DSTATE_WM_8_DISPATCH_ENABLE (1 << 0) -/* DW6 */ -# define GEN6_3DSTATE_WM_NUM_SF_OUTPUTS_SHIFT 20 -# define GEN6_3DSTATE_WM_NONPERSPECTIVE_SAMPLE_BARYCENTRIC (1 << 15) -# define GEN6_3DSTATE_WM_NONPERSPECTIVE_CENTROID_BARYCENTRIC (1 << 14) -# define GEN6_3DSTATE_WM_NONPERSPECTIVE_PIXEL_BARYCENTRIC (1 << 13) -# define GEN6_3DSTATE_WM_PERSPECTIVE_SAMPLE_BARYCENTRIC (1 << 12) -# define GEN6_3DSTATE_WM_PERSPECTIVE_CENTROID_BARYCENTRIC (1 << 11) -# define GEN6_3DSTATE_WM_PERSPECTIVE_PIXEL_BARYCENTRIC (1 << 10) - - -#define GEN6_3DSTATE_CONSTANT_VS GEN6_3D(3, 0, 0x15) -#define GEN6_3DSTATE_CONSTANT_GS GEN6_3D(3, 0, 0x16) -#define GEN6_3DSTATE_CONSTANT_PS GEN6_3D(3, 0, 0x17) - -#define GEN6_3DSTATE_SAMPLE_MASK GEN6_3D(3, 0, 0x18) - -#define GEN6_3DSTATE_MULTISAMPLE GEN6_3D(3, 1, 0x0d) -/* DW1 */ -# define GEN6_3DSTATE_MULTISAMPLE_PIXEL_LOCATION_CENTER (0 << 4) -# define GEN6_3DSTATE_MULTISAMPLE_PIXEL_LOCATION_UPPER_LEFT (1 << 4) -# define GEN6_3DSTATE_MULTISAMPLE_NUMSAMPLES_1 (0 << 1) -# define GEN6_3DSTATE_MULTISAMPLE_NUMSAMPLES_4 (2 << 1) -# define GEN6_3DSTATE_MULTISAMPLE_NUMSAMPLES_8 (3 << 1) - -#define PIPELINE_SELECT_3D 0 -#define PIPELINE_SELECT_MEDIA 1 - -/* for GEN6_STATE_BASE_ADDRESS */ -#define BASE_ADDRESS_MODIFY (1 << 0) - -/* VERTEX_BUFFER_STATE Structure */ -#define VB0_BUFFER_INDEX_SHIFT 26 -#define VB0_VERTEXDATA (0 << 20) -#define VB0_INSTANCEDATA (1 << 20) -#define VB0_BUFFER_PITCH_SHIFT 0 - -/* VERTEX_ELEMENT_STATE Structure */ -#define VE0_VERTEX_BUFFER_INDEX_SHIFT 26 /* for GEN6 */ -#define VE0_VALID (1 << 25) /* for GEN6 */ -#define VE0_FORMAT_SHIFT 16 -#define VE0_OFFSET_SHIFT 0 -#define VE1_VFCOMPONENT_0_SHIFT 28 -#define VE1_VFCOMPONENT_1_SHIFT 24 -#define VE1_VFCOMPONENT_2_SHIFT 20 -#define VE1_VFCOMPONENT_3_SHIFT 16 -#define VE1_DESTINATION_ELEMENT_OFFSET_SHIFT 0 - -/* 3DPRIMITIVE bits */ -#define GEN6_3DPRIMITIVE_VERTEX_SEQUENTIAL (0 << 15) -#define GEN6_3DPRIMITIVE_VERTEX_RANDOM (1 << 15) -/* Primitive types are in gen6_defines.h */ -#define GEN6_3DPRIMITIVE_TOPOLOGY_SHIFT 10 - -#define GEN6_SVG_CTL 0x7400 - -#define GEN6_SVG_CTL_GS_BA (0 << 8) -#define GEN6_SVG_CTL_SS_BA (1 << 8) -#define GEN6_SVG_CTL_IO_BA (2 << 8) -#define GEN6_SVG_CTL_GS_AUB (3 << 8) -#define GEN6_SVG_CTL_IO_AUB (4 << 8) -#define GEN6_SVG_CTL_SIP (5 << 8) - -#define GEN6_SVG_RDATA 0x7404 -#define GEN6_SVG_WORK_CTL 0x7408 - -#define GEN6_VF_CTL 0x7500 - -#define GEN6_VF_CTL_SNAPSHOT_COMPLETE (1 << 31) -#define GEN6_VF_CTL_SNAPSHOT_MUX_SELECT_THREADID (0 << 8) -#define GEN6_VF_CTL_SNAPSHOT_MUX_SELECT_VF_DEBUG (1 << 8) -#define GEN6_VF_CTL_SNAPSHOT_TYPE_VERTEX_SEQUENCE (0 << 4) -#define GEN6_VF_CTL_SNAPSHOT_TYPE_VERTEX_INDEX (1 << 4) -#define GEN6_VF_CTL_SKIP_INITIAL_PRIMITIVES (1 << 3) -#define GEN6_VF_CTL_MAX_PRIMITIVES_LIMIT_ENABLE (1 << 2) -#define GEN6_VF_CTL_VERTEX_RANGE_LIMIT_ENABLE (1 << 1) -#define GEN6_VF_CTL_SNAPSHOT_ENABLE (1 << 0) - -#define GEN6_VF_STRG_VAL 0x7504 -#define GEN6_VF_STR_VL_OVR 0x7508 -#define GEN6_VF_VC_OVR 0x750c -#define GEN6_VF_STR_PSKIP 0x7510 -#define GEN6_VF_MAX_PRIM 0x7514 -#define GEN6_VF_RDATA 0x7518 - -#define GEN6_VS_CTL 0x7600 -#define GEN6_VS_CTL_SNAPSHOT_COMPLETE (1 << 31) -#define GEN6_VS_CTL_SNAPSHOT_MUX_VERTEX_0 (0 << 8) -#define GEN6_VS_CTL_SNAPSHOT_MUX_VERTEX_1 (1 << 8) -#define GEN6_VS_CTL_SNAPSHOT_MUX_VALID_COUNT (2 << 8) -#define GEN6_VS_CTL_SNAPSHOT_MUX_VS_KERNEL_POINTER (3 << 8) -#define GEN6_VS_CTL_SNAPSHOT_ALL_THREADS (1 << 2) -#define GEN6_VS_CTL_THREAD_SNAPSHOT_ENABLE (1 << 1) -#define GEN6_VS_CTL_SNAPSHOT_ENABLE (1 << 0) - -#define GEN6_VS_STRG_VAL 0x7604 -#define GEN6_VS_RDATA 0x7608 - -#define GEN6_SF_CTL 0x7b00 -#define GEN6_SF_CTL_SNAPSHOT_COMPLETE (1 << 31) -#define GEN6_SF_CTL_SNAPSHOT_MUX_VERTEX_0_FF_ID (0 << 8) -#define GEN6_SF_CTL_SNAPSHOT_MUX_VERTEX_0_REL_COUNT (1 << 8) -#define GEN6_SF_CTL_SNAPSHOT_MUX_VERTEX_1_FF_ID (2 << 8) -#define GEN6_SF_CTL_SNAPSHOT_MUX_VERTEX_1_REL_COUNT (3 << 8) -#define GEN6_SF_CTL_SNAPSHOT_MUX_VERTEX_2_FF_ID (4 << 8) -#define GEN6_SF_CTL_SNAPSHOT_MUX_VERTEX_2_REL_COUNT (5 << 8) -#define GEN6_SF_CTL_SNAPSHOT_MUX_VERTEX_COUNT (6 << 8) -#define GEN6_SF_CTL_SNAPSHOT_MUX_SF_KERNEL_POINTER (7 << 8) -#define GEN6_SF_CTL_MIN_MAX_PRIMITIVE_RANGE_ENABLE (1 << 4) -#define GEN6_SF_CTL_DEBUG_CLIP_RECTANGLE_ENABLE (1 << 3) -#define GEN6_SF_CTL_SNAPSHOT_ALL_THREADS (1 << 2) -#define GEN6_SF_CTL_THREAD_SNAPSHOT_ENABLE (1 << 1) -#define GEN6_SF_CTL_SNAPSHOT_ENABLE (1 << 0) - -#define GEN6_SF_STRG_VAL 0x7b04 -#define GEN6_SF_RDATA 0x7b18 - -#define GEN6_WIZ_CTL 0x7c00 -#define GEN6_WIZ_CTL_SNAPSHOT_COMPLETE (1 << 31) -#define GEN6_WIZ_CTL_SUBSPAN_INSTANCE_SHIFT 16 -#define GEN6_WIZ_CTL_SNAPSHOT_MUX_WIZ_KERNEL_POINTER (0 << 8) -#define GEN6_WIZ_CTL_SNAPSHOT_MUX_SUBSPAN_INSTANCE (1 << 8) -#define GEN6_WIZ_CTL_SNAPSHOT_MUX_PRIMITIVE_SEQUENCE (2 << 8) -#define GEN6_WIZ_CTL_SINGLE_SUBSPAN_DISPATCH (1 << 6) -#define GEN6_WIZ_CTL_IGNORE_COLOR_SCOREBOARD_STALLS (1 << 5) -#define GEN6_WIZ_CTL_ENABLE_SUBSPAN_INSTANCE_COMPARE (1 << 4) -#define GEN6_WIZ_CTL_USE_UPSTREAM_SNAPSHOT_FLAG (1 << 3) -#define GEN6_WIZ_CTL_SNAPSHOT_ALL_THREADS (1 << 2) -#define GEN6_WIZ_CTL_THREAD_SNAPSHOT_ENABLE (1 << 1) -#define GEN6_WIZ_CTL_SNAPSHOT_ENABLE (1 << 0) - -#define GEN6_WIZ_STRG_VAL 0x7c04 -#define GEN6_WIZ_RDATA 0x7c18 - -#define GEN6_TS_CTL 0x7e00 -#define GEN6_TS_CTL_SNAPSHOT_COMPLETE (1 << 31) -#define GEN6_TS_CTL_SNAPSHOT_MESSAGE_ERROR (0 << 8) -#define GEN6_TS_CTL_SNAPSHOT_INTERFACE_DESCRIPTOR (3 << 8) -#define GEN6_TS_CTL_SNAPSHOT_ALL_CHILD_THREADS (1 << 2) -#define GEN6_TS_CTL_SNAPSHOT_ALL_ROOT_THREADS (1 << 1) -#define GEN6_TS_CTL_SNAPSHOT_ENABLE (1 << 0) - -#define GEN6_TS_STRG_VAL 0x7e04 -#define GEN6_TS_RDATA 0x7e08 - -#define GEN6_TD_CTL 0x8000 -#define GEN6_TD_CTL_MUX_SHIFT 8 -#define GEN6_TD_CTL_EXTERNAL_HALT_R0_DEBUG_MATCH (1 << 7) -#define GEN6_TD_CTL_FORCE_EXTERNAL_HALT (1 << 6) -#define GEN6_TD_CTL_EXCEPTION_MASK_OVERRIDE (1 << 5) -#define GEN6_TD_CTL_FORCE_THREAD_BREAKPOINT_ENABLE (1 << 4) -#define GEN6_TD_CTL_BREAKPOINT_ENABLE (1 << 2) -#define GEN6_TD_CTL2 0x8004 -#define GEN6_TD_CTL2_ILLEGAL_OPCODE_EXCEPTION_OVERRIDE (1 << 28) -#define GEN6_TD_CTL2_MASKSTACK_EXCEPTION_OVERRIDE (1 << 26) -#define GEN6_TD_CTL2_SOFTWARE_EXCEPTION_OVERRIDE (1 << 25) -#define GEN6_TD_CTL2_ACTIVE_THREAD_LIMIT_SHIFT 16 -#define GEN6_TD_CTL2_ACTIVE_THREAD_LIMIT_ENABLE (1 << 8) -#define GEN6_TD_CTL2_THREAD_SPAWNER_EXECUTION_MASK_ENABLE (1 << 7) -#define GEN6_TD_CTL2_WIZ_EXECUTION_MASK_ENABLE (1 << 6) -#define GEN6_TD_CTL2_SF_EXECUTION_MASK_ENABLE (1 << 5) -#define GEN6_TD_CTL2_CLIPPER_EXECUTION_MASK_ENABLE (1 << 4) -#define GEN6_TD_CTL2_GS_EXECUTION_MASK_ENABLE (1 << 3) -#define GEN6_TD_CTL2_VS_EXECUTION_MASK_ENABLE (1 << 0) -#define GEN6_TD_VF_VS_EMSK 0x8008 -#define GEN6_TD_GS_EMSK 0x800c -#define GEN6_TD_CLIP_EMSK 0x8010 -#define GEN6_TD_SF_EMSK 0x8014 -#define GEN6_TD_WIZ_EMSK 0x8018 -#define GEN6_TD_0_6_EHTRG_VAL 0x801c -#define GEN6_TD_0_7_EHTRG_VAL 0x8020 -#define GEN6_TD_0_6_EHTRG_MSK 0x8024 -#define GEN6_TD_0_7_EHTRG_MSK 0x8028 -#define GEN6_TD_RDATA 0x802c -#define GEN6_TD_TS_EMSK 0x8030 - -#define GEN6_EU_CTL 0x8800 -#define GEN6_EU_CTL_SELECT_SHIFT 16 -#define GEN6_EU_CTL_DATA_MUX_SHIFT 8 -#define GEN6_EU_ATT_0 0x8810 -#define GEN6_EU_ATT_1 0x8814 -#define GEN6_EU_ATT_DATA_0 0x8820 -#define GEN6_EU_ATT_DATA_1 0x8824 -#define GEN6_EU_ATT_CLR_0 0x8830 -#define GEN6_EU_ATT_CLR_1 0x8834 -#define GEN6_EU_RDATA 0x8840 - -#define GEN6_3D(Pipeline,Opcode,Subopcode) ((3 << 29) | \ - ((Pipeline) << 27) | \ - ((Opcode) << 24) | \ - ((Subopcode) << 16)) - -#define GEN6_STATE_BASE_ADDRESS GEN6_3D(0, 1, 1) -#define GEN6_STATE_SIP GEN6_3D(0, 1, 2) - -#define GEN6_PIPELINE_SELECT GEN6_3D(1, 1, 4) - -#define GEN6_MEDIA_STATE_POINTERS GEN6_3D(2, 0, 0) -#define GEN6_MEDIA_OBJECT GEN6_3D(2, 1, 0) - -#define GEN6_3DSTATE_BINDING_TABLE_POINTERS GEN6_3D(3, 0, 1) -# define GEN6_3DSTATE_BINDING_TABLE_MODIFY_PS (1 << 12)/* for GEN6 */ -# define GEN6_3DSTATE_BINDING_TABLE_MODIFY_GS (1 << 9) /* for GEN6 */ -# define GEN6_3DSTATE_BINDING_TABLE_MODIFY_VS (1 << 8) /* for GEN6 */ - -#define GEN6_3DSTATE_VERTEX_BUFFERS GEN6_3D(3, 0, 8) -#define GEN6_3DSTATE_VERTEX_ELEMENTS GEN6_3D(3, 0, 9) -#define GEN6_3DSTATE_INDEX_BUFFER GEN6_3D(3, 0, 0xa) -#define GEN6_3DSTATE_VF_STATISTICS GEN6_3D(3, 0, 0xb) - -#define GEN6_3DSTATE_DRAWING_RECTANGLE GEN6_3D(3, 1, 0) -#define GEN6_3DSTATE_CONSTANT_COLOR GEN6_3D(3, 1, 1) -#define GEN6_3DSTATE_SAMPLER_PALETTE_LOAD GEN6_3D(3, 1, 2) -#define GEN6_3DSTATE_CHROMA_KEY GEN6_3D(3, 1, 4) -#define GEN6_3DSTATE_DEPTH_BUFFER GEN6_3D(3, 1, 5) -# define GEN6_3DSTATE_DEPTH_BUFFER_TYPE_SHIFT 29 -# define GEN6_3DSTATE_DEPTH_BUFFER_FORMAT_SHIFT 18 - -#define GEN6_3DSTATE_POLY_STIPPLE_OFFSET GEN6_3D(3, 1, 6) -#define GEN6_3DSTATE_POLY_STIPPLE_PATTERN GEN6_3D(3, 1, 7) -#define GEN6_3DSTATE_LINE_STIPPLE GEN6_3D(3, 1, 8) -#define GEN6_3DSTATE_GLOBAL_DEPTH_OFFSET_CLAMP GEN6_3D(3, 1, 9) -/* These two are BLC and CTG only, not BW or CL */ -#define GEN6_3DSTATE_AA_LINE_PARAMS GEN6_3D(3, 1, 0xa) -#define GEN6_3DSTATE_GS_SVB_INDEX GEN6_3D(3, 1, 0xb) - -#define GEN6_3DPRIMITIVE GEN6_3D(3, 3, 0) - -#define GEN6_3DSTATE_CLEAR_PARAMS GEN6_3D(3, 1, 0x10) -/* DW1 */ -# define GEN6_3DSTATE_DEPTH_CLEAR_VALID (1 << 15) - -/* for GEN6+ */ -#define GEN6_3DSTATE_SAMPLER_STATE_POINTERS GEN6_3D(3, 0, 0x02) -# define GEN6_3DSTATE_SAMPLER_STATE_MODIFY_PS (1 << 12) -# define GEN6_3DSTATE_SAMPLER_STATE_MODIFY_GS (1 << 9) -# define GEN6_3DSTATE_SAMPLER_STATE_MODIFY_VS (1 << 8) - -#define GEN6_3DSTATE_URB GEN6_3D(3, 0, 0x05) -/* DW1 */ -# define GEN6_3DSTATE_URB_VS_SIZE_SHIFT 16 -# define GEN6_3DSTATE_URB_VS_ENTRIES_SHIFT 0 -/* DW2 */ -# define GEN6_3DSTATE_URB_GS_ENTRIES_SHIFT 8 -# define GEN6_3DSTATE_URB_GS_SIZE_SHIFT 0 - -#define GEN6_3DSTATE_VIEWPORT_STATE_POINTERS GEN6_3D(3, 0, 0x0d) -# define GEN6_3DSTATE_VIEWPORT_STATE_MODIFY_CC (1 << 12) -# define GEN6_3DSTATE_VIEWPORT_STATE_MODIFY_SF (1 << 11) -# define GEN6_3DSTATE_VIEWPORT_STATE_MODIFY_CLIP (1 << 10) - -#define GEN6_3DSTATE_CC_STATE_POINTERS GEN6_3D(3, 0, 0x0e) - -#define GEN6_3DSTATE_VS GEN6_3D(3, 0, 0x10) - -#define GEN6_3DSTATE_GS GEN6_3D(3, 0, 0x11) -/* DW4 */ -# define GEN6_3DSTATE_GS_DISPATCH_START_GRF_SHIFT 0 - -#define GEN6_3DSTATE_CLIP GEN6_3D(3, 0, 0x12) - -#define GEN6_3DSTATE_SF GEN6_3D(3, 0, 0x13) -/* DW1 */ -# define GEN6_3DSTATE_SF_NUM_OUTPUTS_SHIFT 22 -# define GEN6_3DSTATE_SF_URB_ENTRY_READ_LENGTH_SHIFT 11 -# define GEN6_3DSTATE_SF_URB_ENTRY_READ_OFFSET_SHIFT 4 -/* DW2 */ -/* DW3 */ -# define GEN6_3DSTATE_SF_CULL_BOTH (0 << 29) -# define GEN6_3DSTATE_SF_CULL_NONE (1 << 29) -# define GEN6_3DSTATE_SF_CULL_FRONT (2 << 29) -# define GEN6_3DSTATE_SF_CULL_BACK (3 << 29) -/* DW4 */ -# define GEN6_3DSTATE_SF_TRI_PROVOKE_SHIFT 29 -# define GEN6_3DSTATE_SF_LINE_PROVOKE_SHIFT 27 -# define GEN6_3DSTATE_SF_TRIFAN_PROVOKE_SHIFT 25 - - -#define GEN6_3DSTATE_WM GEN6_3D(3, 0, 0x14) -/* DW2 */ -# define GEN6_3DSTATE_WM_SAMPLER_COUNT_SHITF 27 -# define GEN6_3DSTATE_WM_BINDING_TABLE_ENTRY_COUNT_SHIFT 18 -/* DW4 */ -# define GEN6_3DSTATE_WM_DISPATCH_START_GRF_0_SHIFT 16 -/* DW5 */ -# define GEN6_3DSTATE_WM_MAX_THREADS_SHIFT 25 -# define GEN6_3DSTATE_WM_DISPATCH_ENABLE (1 << 19) -# define GEN6_3DSTATE_WM_16_DISPATCH_ENABLE (1 << 1) -# define GEN6_3DSTATE_WM_8_DISPATCH_ENABLE (1 << 0) -/* DW6 */ -# define GEN6_3DSTATE_WM_NUM_SF_OUTPUTS_SHIFT 20 -# define GEN6_3DSTATE_WM_NONPERSPECTIVE_SAMPLE_BARYCENTRIC (1 << 15) -# define GEN6_3DSTATE_WM_NONPERSPECTIVE_CENTROID_BARYCENTRIC (1 << 14) -# define GEN6_3DSTATE_WM_NONPERSPECTIVE_PIXEL_BARYCENTRIC (1 << 13) -# define GEN6_3DSTATE_WM_PERSPECTIVE_SAMPLE_BARYCENTRIC (1 << 12) -# define GEN6_3DSTATE_WM_PERSPECTIVE_CENTROID_BARYCENTRIC (1 << 11) -# define GEN6_3DSTATE_WM_PERSPECTIVE_PIXEL_BARYCENTRIC (1 << 10) - - -#define GEN6_3DSTATE_CONSTANT_VS GEN6_3D(3, 0, 0x15) -#define GEN6_3DSTATE_CONSTANT_GS GEN6_3D(3, 0, 0x16) -#define GEN6_3DSTATE_CONSTANT_PS GEN6_3D(3, 0, 0x17) - -#define GEN6_3DSTATE_SAMPLE_MASK GEN6_3D(3, 0, 0x18) - -#define GEN6_3DSTATE_MULTISAMPLE GEN6_3D(3, 1, 0x0d) -/* DW1 */ -# define GEN6_3DSTATE_MULTISAMPLE_PIXEL_LOCATION_CENTER (0 << 4) -# define GEN6_3DSTATE_MULTISAMPLE_PIXEL_LOCATION_UPPER_LEFT (1 << 4) -# define GEN6_3DSTATE_MULTISAMPLE_NUMSAMPLES_1 (0 << 1) -# define GEN6_3DSTATE_MULTISAMPLE_NUMSAMPLES_4 (2 << 1) -# define GEN6_3DSTATE_MULTISAMPLE_NUMSAMPLES_8 (3 << 1) - -#define PIPELINE_SELECT_3D 0 -#define PIPELINE_SELECT_MEDIA 1 - -#define UF0_CS_REALLOC (1 << 13) -#define UF0_VFE_REALLOC (1 << 12) -#define UF0_SF_REALLOC (1 << 11) -#define UF0_CLIP_REALLOC (1 << 10) -#define UF0_GS_REALLOC (1 << 9) -#define UF0_VS_REALLOC (1 << 8) -#define UF1_CLIP_FENCE_SHIFT 20 -#define UF1_GS_FENCE_SHIFT 10 -#define UF1_VS_FENCE_SHIFT 0 -#define UF2_CS_FENCE_SHIFT 20 -#define UF2_VFE_FENCE_SHIFT 10 -#define UF2_SF_FENCE_SHIFT 0 - -/* for GEN6_STATE_BASE_ADDRESS */ -#define BASE_ADDRESS_MODIFY (1 << 0) - -/* for GEN6_3DSTATE_PIPELINED_POINTERS */ -#define GEN6_GS_DISABLE 0 -#define GEN6_GS_ENABLE 1 -#define GEN6_CLIP_DISABLE 0 -#define GEN6_CLIP_ENABLE 1 - -/* for GEN6_PIPE_CONTROL */ -#define GEN6_PIPE_CONTROL GEN6_3D(3, 2, 0) -#define GEN6_PIPE_CONTROL_CS_STALL (1 << 20) -#define GEN6_PIPE_CONTROL_NOWRITE (0 << 14) -#define GEN6_PIPE_CONTROL_WRITE_QWORD (1 << 14) -#define GEN6_PIPE_CONTROL_WRITE_DEPTH (2 << 14) -#define GEN6_PIPE_CONTROL_WRITE_TIME (3 << 14) -#define GEN6_PIPE_CONTROL_DEPTH_STALL (1 << 13) -#define GEN6_PIPE_CONTROL_WC_FLUSH (1 << 12) -#define GEN6_PIPE_CONTROL_IS_FLUSH (1 << 11) -#define GEN6_PIPE_CONTROL_TC_FLUSH (1 << 10) -#define GEN6_PIPE_CONTROL_NOTIFY_ENABLE (1 << 8) -#define GEN6_PIPE_CONTROL_GLOBAL_GTT (1 << 2) -#define GEN6_PIPE_CONTROL_LOCAL_PGTT (0 << 2) -#define GEN6_PIPE_CONTROL_STALL_AT_SCOREBOARD (1 << 1) -#define GEN6_PIPE_CONTROL_DEPTH_CACHE_FLUSH (1 << 0) - -/* 3DPRIMITIVE bits */ -#define GEN6_3DPRIMITIVE_VERTEX_SEQUENTIAL (0 << 15) -#define GEN6_3DPRIMITIVE_VERTEX_RANDOM (1 << 15) -/* Primitive types are in gen6_defines.h */ -#define GEN6_3DPRIMITIVE_TOPOLOGY_SHIFT 10 - -#define GEN6_SVG_CTL 0x7400 - -#define GEN6_SVG_CTL_GS_BA (0 << 8) -#define GEN6_SVG_CTL_SS_BA (1 << 8) -#define GEN6_SVG_CTL_IO_BA (2 << 8) -#define GEN6_SVG_CTL_GS_AUB (3 << 8) -#define GEN6_SVG_CTL_IO_AUB (4 << 8) -#define GEN6_SVG_CTL_SIP (5 << 8) - -#define GEN6_SVG_RDATA 0x7404 -#define GEN6_SVG_WORK_CTL 0x7408 - -#define GEN6_VF_CTL 0x7500 - -#define GEN6_VF_CTL_SNAPSHOT_COMPLETE (1 << 31) -#define GEN6_VF_CTL_SNAPSHOT_MUX_SELECT_THREADID (0 << 8) -#define GEN6_VF_CTL_SNAPSHOT_MUX_SELECT_VF_DEBUG (1 << 8) -#define GEN6_VF_CTL_SNAPSHOT_TYPE_VERTEX_SEQUENCE (0 << 4) -#define GEN6_VF_CTL_SNAPSHOT_TYPE_VERTEX_INDEX (1 << 4) -#define GEN6_VF_CTL_SKIP_INITIAL_PRIMITIVES (1 << 3) -#define GEN6_VF_CTL_MAX_PRIMITIVES_LIMIT_ENABLE (1 << 2) -#define GEN6_VF_CTL_VERTEX_RANGE_LIMIT_ENABLE (1 << 1) -#define GEN6_VF_CTL_SNAPSHOT_ENABLE (1 << 0) - -#define GEN6_VF_STRG_VAL 0x7504 -#define GEN6_VF_STR_VL_OVR 0x7508 -#define GEN6_VF_VC_OVR 0x750c -#define GEN6_VF_STR_PSKIP 0x7510 -#define GEN6_VF_MAX_PRIM 0x7514 -#define GEN6_VF_RDATA 0x7518 - -#define GEN6_VS_CTL 0x7600 -#define GEN6_VS_CTL_SNAPSHOT_COMPLETE (1 << 31) -#define GEN6_VS_CTL_SNAPSHOT_MUX_VERTEX_0 (0 << 8) -#define GEN6_VS_CTL_SNAPSHOT_MUX_VERTEX_1 (1 << 8) -#define GEN6_VS_CTL_SNAPSHOT_MUX_VALID_COUNT (2 << 8) -#define GEN6_VS_CTL_SNAPSHOT_MUX_VS_KERNEL_POINTER (3 << 8) -#define GEN6_VS_CTL_SNAPSHOT_ALL_THREADS (1 << 2) -#define GEN6_VS_CTL_THREAD_SNAPSHOT_ENABLE (1 << 1) -#define GEN6_VS_CTL_SNAPSHOT_ENABLE (1 << 0) - -#define GEN6_VS_STRG_VAL 0x7604 -#define GEN6_VS_RDATA 0x7608 - -#define GEN6_SF_CTL 0x7b00 -#define GEN6_SF_CTL_SNAPSHOT_COMPLETE (1 << 31) -#define GEN6_SF_CTL_SNAPSHOT_MUX_VERTEX_0_FF_ID (0 << 8) -#define GEN6_SF_CTL_SNAPSHOT_MUX_VERTEX_0_REL_COUNT (1 << 8) -#define GEN6_SF_CTL_SNAPSHOT_MUX_VERTEX_1_FF_ID (2 << 8) -#define GEN6_SF_CTL_SNAPSHOT_MUX_VERTEX_1_REL_COUNT (3 << 8) -#define GEN6_SF_CTL_SNAPSHOT_MUX_VERTEX_2_FF_ID (4 << 8) -#define GEN6_SF_CTL_SNAPSHOT_MUX_VERTEX_2_REL_COUNT (5 << 8) -#define GEN6_SF_CTL_SNAPSHOT_MUX_VERTEX_COUNT (6 << 8) -#define GEN6_SF_CTL_SNAPSHOT_MUX_SF_KERNEL_POINTER (7 << 8) -#define GEN6_SF_CTL_MIN_MAX_PRIMITIVE_RANGE_ENABLE (1 << 4) -#define GEN6_SF_CTL_DEBUG_CLIP_RECTANGLE_ENABLE (1 << 3) -#define GEN6_SF_CTL_SNAPSHOT_ALL_THREADS (1 << 2) -#define GEN6_SF_CTL_THREAD_SNAPSHOT_ENABLE (1 << 1) -#define GEN6_SF_CTL_SNAPSHOT_ENABLE (1 << 0) - -#define GEN6_SF_STRG_VAL 0x7b04 -#define GEN6_SF_RDATA 0x7b18 - -#define GEN6_WIZ_CTL 0x7c00 -#define GEN6_WIZ_CTL_SNAPSHOT_COMPLETE (1 << 31) -#define GEN6_WIZ_CTL_SUBSPAN_INSTANCE_SHIFT 16 -#define GEN6_WIZ_CTL_SNAPSHOT_MUX_WIZ_KERNEL_POINTER (0 << 8) -#define GEN6_WIZ_CTL_SNAPSHOT_MUX_SUBSPAN_INSTANCE (1 << 8) -#define GEN6_WIZ_CTL_SNAPSHOT_MUX_PRIMITIVE_SEQUENCE (2 << 8) -#define GEN6_WIZ_CTL_SINGLE_SUBSPAN_DISPATCH (1 << 6) -#define GEN6_WIZ_CTL_IGNORE_COLOR_SCOREBOARD_STALLS (1 << 5) -#define GEN6_WIZ_CTL_ENABLE_SUBSPAN_INSTANCE_COMPARE (1 << 4) -#define GEN6_WIZ_CTL_USE_UPSTREAM_SNAPSHOT_FLAG (1 << 3) -#define GEN6_WIZ_CTL_SNAPSHOT_ALL_THREADS (1 << 2) -#define GEN6_WIZ_CTL_THREAD_SNAPSHOT_ENABLE (1 << 1) -#define GEN6_WIZ_CTL_SNAPSHOT_ENABLE (1 << 0) - -#define GEN6_WIZ_STRG_VAL 0x7c04 -#define GEN6_WIZ_RDATA 0x7c18 - -#define GEN6_TS_CTL 0x7e00 -#define GEN6_TS_CTL_SNAPSHOT_COMPLETE (1 << 31) -#define GEN6_TS_CTL_SNAPSHOT_MESSAGE_ERROR (0 << 8) -#define GEN6_TS_CTL_SNAPSHOT_INTERFACE_DESCRIPTOR (3 << 8) -#define GEN6_TS_CTL_SNAPSHOT_ALL_CHILD_THREADS (1 << 2) -#define GEN6_TS_CTL_SNAPSHOT_ALL_ROOT_THREADS (1 << 1) -#define GEN6_TS_CTL_SNAPSHOT_ENABLE (1 << 0) - -#define GEN6_TS_STRG_VAL 0x7e04 -#define GEN6_TS_RDATA 0x7e08 - -#define GEN6_TD_CTL 0x8000 -#define GEN6_TD_CTL_MUX_SHIFT 8 -#define GEN6_TD_CTL_EXTERNAL_HALT_R0_DEBUG_MATCH (1 << 7) -#define GEN6_TD_CTL_FORCE_EXTERNAL_HALT (1 << 6) -#define GEN6_TD_CTL_EXCEPTION_MASK_OVERRIDE (1 << 5) -#define GEN6_TD_CTL_FORCE_THREAD_BREAKPOINT_ENABLE (1 << 4) -#define GEN6_TD_CTL_BREAKPOINT_ENABLE (1 << 2) -#define GEN6_TD_CTL2 0x8004 -#define GEN6_TD_CTL2_ILLEGAL_OPCODE_EXCEPTION_OVERRIDE (1 << 28) -#define GEN6_TD_CTL2_MASKSTACK_EXCEPTION_OVERRIDE (1 << 26) -#define GEN6_TD_CTL2_SOFTWARE_EXCEPTION_OVERRIDE (1 << 25) -#define GEN6_TD_CTL2_ACTIVE_THREAD_LIMIT_SHIFT 16 -#define GEN6_TD_CTL2_ACTIVE_THREAD_LIMIT_ENABLE (1 << 8) -#define GEN6_TD_CTL2_THREAD_SPAWNER_EXECUTION_MASK_ENABLE (1 << 7) -#define GEN6_TD_CTL2_WIZ_EXECUTION_MASK_ENABLE (1 << 6) -#define GEN6_TD_CTL2_SF_EXECUTION_MASK_ENABLE (1 << 5) -#define GEN6_TD_CTL2_CLIPPER_EXECUTION_MASK_ENABLE (1 << 4) -#define GEN6_TD_CTL2_GS_EXECUTION_MASK_ENABLE (1 << 3) -#define GEN6_TD_CTL2_VS_EXECUTION_MASK_ENABLE (1 << 0) -#define GEN6_TD_VF_VS_EMSK 0x8008 -#define GEN6_TD_GS_EMSK 0x800c -#define GEN6_TD_CLIP_EMSK 0x8010 -#define GEN6_TD_SF_EMSK 0x8014 -#define GEN6_TD_WIZ_EMSK 0x8018 -#define GEN6_TD_0_6_EHTRG_VAL 0x801c -#define GEN6_TD_0_7_EHTRG_VAL 0x8020 -#define GEN6_TD_0_6_EHTRG_MSK 0x8024 -#define GEN6_TD_0_7_EHTRG_MSK 0x8028 -#define GEN6_TD_RDATA 0x802c -#define GEN6_TD_TS_EMSK 0x8030 - -#define GEN6_EU_CTL 0x8800 -#define GEN6_EU_CTL_SELECT_SHIFT 16 -#define GEN6_EU_CTL_DATA_MUX_SHIFT 8 -#define GEN6_EU_ATT_0 0x8810 -#define GEN6_EU_ATT_1 0x8814 -#define GEN6_EU_ATT_DATA_0 0x8820 -#define GEN6_EU_ATT_DATA_1 0x8824 -#define GEN6_EU_ATT_CLR_0 0x8830 -#define GEN6_EU_ATT_CLR_1 0x8834 -#define GEN6_EU_RDATA 0x8840 - -/* 3D state: - */ -#define _3DOP_3DSTATE_PIPELINED 0x0 -#define _3DOP_3DSTATE_NONPIPELINED 0x1 -#define _3DOP_3DCONTROL 0x2 -#define _3DOP_3DPRIMITIVE 0x3 - -#define _3DSTATE_PIPELINED_POINTERS 0x00 -#define _3DSTATE_BINDING_TABLE_POINTERS 0x01 -#define _3DSTATE_VERTEX_BUFFERS 0x08 -#define _3DSTATE_VERTEX_ELEMENTS 0x09 -#define _3DSTATE_INDEX_BUFFER 0x0A -#define _3DSTATE_VF_STATISTICS 0x0B -#define _3DSTATE_DRAWING_RECTANGLE 0x00 -#define _3DSTATE_CONSTANT_COLOR 0x01 -#define _3DSTATE_SAMPLER_PALETTE_LOAD 0x02 -#define _3DSTATE_CHROMA_KEY 0x04 -#define _3DSTATE_DEPTH_BUFFER 0x05 -#define _3DSTATE_POLY_STIPPLE_OFFSET 0x06 -#define _3DSTATE_POLY_STIPPLE_PATTERN 0x07 -#define _3DSTATE_LINE_STIPPLE 0x08 -#define _3DSTATE_GLOBAL_DEPTH_OFFSET_CLAMP 0x09 -#define _3DCONTROL 0x00 -#define _3DPRIMITIVE 0x00 - -#define _3DPRIM_POINTLIST 0x01 -#define _3DPRIM_LINELIST 0x02 -#define _3DPRIM_LINESTRIP 0x03 -#define _3DPRIM_TRILIST 0x04 -#define _3DPRIM_TRISTRIP 0x05 -#define _3DPRIM_TRIFAN 0x06 -#define _3DPRIM_QUADLIST 0x07 -#define _3DPRIM_QUADSTRIP 0x08 -#define _3DPRIM_LINELIST_ADJ 0x09 -#define _3DPRIM_LINESTRIP_ADJ 0x0A -#define _3DPRIM_TRILIST_ADJ 0x0B -#define _3DPRIM_TRISTRIP_ADJ 0x0C -#define _3DPRIM_TRISTRIP_REVERSE 0x0D -#define _3DPRIM_POLYGON 0x0E -#define _3DPRIM_RECTLIST 0x0F -#define _3DPRIM_LINELOOP 0x10 -#define _3DPRIM_POINTLIST_BF 0x11 -#define _3DPRIM_LINESTRIP_CONT 0x12 -#define _3DPRIM_LINESTRIP_BF 0x13 -#define _3DPRIM_LINESTRIP_CONT_BF 0x14 -#define _3DPRIM_TRIFAN_NOSTIPPLE 0x15 - -#define _3DPRIM_VERTEXBUFFER_ACCESS_SEQUENTIAL 0 -#define _3DPRIM_VERTEXBUFFER_ACCESS_RANDOM 1 - -#define GEN6_ANISORATIO_2 0 -#define GEN6_ANISORATIO_4 1 -#define GEN6_ANISORATIO_6 2 -#define GEN6_ANISORATIO_8 3 -#define GEN6_ANISORATIO_10 4 -#define GEN6_ANISORATIO_12 5 -#define GEN6_ANISORATIO_14 6 -#define GEN6_ANISORATIO_16 7 - -#define GEN6_BLENDFACTOR_ONE 0x1 -#define GEN6_BLENDFACTOR_SRC_COLOR 0x2 -#define GEN6_BLENDFACTOR_SRC_ALPHA 0x3 -#define GEN6_BLENDFACTOR_DST_ALPHA 0x4 -#define GEN6_BLENDFACTOR_DST_COLOR 0x5 -#define GEN6_BLENDFACTOR_SRC_ALPHA_SATURATE 0x6 -#define GEN6_BLENDFACTOR_CONST_COLOR 0x7 -#define GEN6_BLENDFACTOR_CONST_ALPHA 0x8 -#define GEN6_BLENDFACTOR_SRC1_COLOR 0x9 -#define GEN6_BLENDFACTOR_SRC1_ALPHA 0x0A -#define GEN6_BLENDFACTOR_ZERO 0x11 -#define GEN6_BLENDFACTOR_INV_SRC_COLOR 0x12 -#define GEN6_BLENDFACTOR_INV_SRC_ALPHA 0x13 -#define GEN6_BLENDFACTOR_INV_DST_ALPHA 0x14 -#define GEN6_BLENDFACTOR_INV_DST_COLOR 0x15 -#define GEN6_BLENDFACTOR_INV_CONST_COLOR 0x17 -#define GEN6_BLENDFACTOR_INV_CONST_ALPHA 0x18 -#define GEN6_BLENDFACTOR_INV_SRC1_COLOR 0x19 -#define GEN6_BLENDFACTOR_INV_SRC1_ALPHA 0x1A - -#define GEN6_BLENDFUNCTION_ADD 0 -#define GEN6_BLENDFUNCTION_SUBTRACT 1 -#define GEN6_BLENDFUNCTION_REVERSE_SUBTRACT 2 -#define GEN6_BLENDFUNCTION_MIN 3 -#define GEN6_BLENDFUNCTION_MAX 4 - -#define GEN6_ALPHATEST_FORMAT_UNORM8 0 -#define GEN6_ALPHATEST_FORMAT_FLOAT32 1 - -#define GEN6_CHROMAKEY_KILL_ON_ANY_MATCH 0 -#define GEN6_CHROMAKEY_REPLACE_BLACK 1 - -#define GEN6_CLIP_API_OGL 0 -#define GEN6_CLIP_API_DX 1 - -#define GEN6_CLIPMODE_NORMAL 0 -#define GEN6_CLIPMODE_CLIP_ALL 1 -#define GEN6_CLIPMODE_CLIP_NON_REJECTED 2 -#define GEN6_CLIPMODE_REJECT_ALL 3 -#define GEN6_CLIPMODE_ACCEPT_ALL 4 - -#define GEN6_CLIP_NDCSPACE 0 -#define GEN6_CLIP_SCREENSPACE 1 - -#define GEN6_COMPAREFUNCTION_ALWAYS 0 -#define GEN6_COMPAREFUNCTION_NEVER 1 -#define GEN6_COMPAREFUNCTION_LESS 2 -#define GEN6_COMPAREFUNCTION_EQUAL 3 -#define GEN6_COMPAREFUNCTION_LEQUAL 4 -#define GEN6_COMPAREFUNCTION_GREATER 5 -#define GEN6_COMPAREFUNCTION_NOTEQUAL 6 -#define GEN6_COMPAREFUNCTION_GEQUAL 7 - -#define GEN6_COVERAGE_PIXELS_HALF 0 -#define GEN6_COVERAGE_PIXELS_1 1 -#define GEN6_COVERAGE_PIXELS_2 2 -#define GEN6_COVERAGE_PIXELS_4 3 - -#define GEN6_CULLMODE_BOTH 0 -#define GEN6_CULLMODE_NONE 1 -#define GEN6_CULLMODE_FRONT 2 -#define GEN6_CULLMODE_BACK 3 - -#define GEN6_DEFAULTCOLOR_R8G8B8A8_UNORM 0 -#define GEN6_DEFAULTCOLOR_R32G32B32A32_FLOAT 1 - -#define GEN6_DEPTHFORMAT_D32_FLOAT_S8X24_UINT 0 -#define GEN6_DEPTHFORMAT_D32_FLOAT 1 -#define GEN6_DEPTHFORMAT_D24_UNORM_S8_UINT 2 -#define GEN6_DEPTHFORMAT_D16_UNORM 5 - -#define GEN6_FLOATING_POINT_IEEE_754 0 -#define GEN6_FLOATING_POINT_NON_IEEE_754 1 - -#define GEN6_FRONTWINDING_CW 0 -#define GEN6_FRONTWINDING_CCW 1 - -#define GEN6_INDEX_BYTE 0 -#define GEN6_INDEX_WORD 1 -#define GEN6_INDEX_DWORD 2 - -#define GEN6_LOGICOPFUNCTION_CLEAR 0 -#define GEN6_LOGICOPFUNCTION_NOR 1 -#define GEN6_LOGICOPFUNCTION_AND_INVERTED 2 -#define GEN6_LOGICOPFUNCTION_COPY_INVERTED 3 -#define GEN6_LOGICOPFUNCTION_AND_REVERSE 4 -#define GEN6_LOGICOPFUNCTION_INVERT 5 -#define GEN6_LOGICOPFUNCTION_XOR 6 -#define GEN6_LOGICOPFUNCTION_NAND 7 -#define GEN6_LOGICOPFUNCTION_AND 8 -#define GEN6_LOGICOPFUNCTION_EQUIV 9 -#define GEN6_LOGICOPFUNCTION_NOOP 10 -#define GEN6_LOGICOPFUNCTION_OR_INVERTED 11 -#define GEN6_LOGICOPFUNCTION_COPY 12 -#define GEN6_LOGICOPFUNCTION_OR_REVERSE 13 -#define GEN6_LOGICOPFUNCTION_OR 14 -#define GEN6_LOGICOPFUNCTION_SET 15 - -#define GEN6_MAPFILTER_NEAREST 0x0 -#define GEN6_MAPFILTER_LINEAR 0x1 -#define GEN6_MAPFILTER_ANISOTROPIC 0x2 - -#define GEN6_MIPFILTER_NONE 0 -#define GEN6_MIPFILTER_NEAREST 1 -#define GEN6_MIPFILTER_LINEAR 3 - -#define GEN6_POLYGON_FRONT_FACING 0 -#define GEN6_POLYGON_BACK_FACING 1 - -#define GEN6_PREFILTER_ALWAYS 0x0 -#define GEN6_PREFILTER_NEVER 0x1 -#define GEN6_PREFILTER_LESS 0x2 -#define GEN6_PREFILTER_EQUAL 0x3 -#define GEN6_PREFILTER_LEQUAL 0x4 -#define GEN6_PREFILTER_GREATER 0x5 -#define GEN6_PREFILTER_NOTEQUAL 0x6 -#define GEN6_PREFILTER_GEQUAL 0x7 - -#define GEN6_PROVOKING_VERTEX_0 0 -#define GEN6_PROVOKING_VERTEX_1 1 -#define GEN6_PROVOKING_VERTEX_2 2 - -#define GEN6_RASTRULE_UPPER_LEFT 0 -#define GEN6_RASTRULE_UPPER_RIGHT 1 - -#define GEN6_RENDERTARGET_CLAMPRANGE_UNORM 0 -#define GEN6_RENDERTARGET_CLAMPRANGE_SNORM 1 -#define GEN6_RENDERTARGET_CLAMPRANGE_FORMAT 2 - -#define GEN6_STENCILOP_KEEP 0 -#define GEN6_STENCILOP_ZERO 1 -#define GEN6_STENCILOP_REPLACE 2 -#define GEN6_STENCILOP_INCRSAT 3 -#define GEN6_STENCILOP_DECRSAT 4 -#define GEN6_STENCILOP_INCR 5 -#define GEN6_STENCILOP_DECR 6 -#define GEN6_STENCILOP_INVERT 7 - -#define GEN6_SURFACE_MIPMAPLAYOUT_BELOW 0 -#define GEN6_SURFACE_MIPMAPLAYOUT_RIGHT 1 - -#define GEN6_SURFACEFORMAT_R32G32B32A32_FLOAT 0x000 -#define GEN6_SURFACEFORMAT_R32G32B32A32_SINT 0x001 -#define GEN6_SURFACEFORMAT_R32G32B32A32_UINT 0x002 -#define GEN6_SURFACEFORMAT_R32G32B32A32_UNORM 0x003 -#define GEN6_SURFACEFORMAT_R32G32B32A32_SNORM 0x004 -#define GEN6_SURFACEFORMAT_R64G64_FLOAT 0x005 -#define GEN6_SURFACEFORMAT_R32G32B32X32_FLOAT 0x006 -#define GEN6_SURFACEFORMAT_R32G32B32A32_SSCALED 0x007 -#define GEN6_SURFACEFORMAT_R32G32B32A32_USCALED 0x008 -#define GEN6_SURFACEFORMAT_R32G32B32_FLOAT 0x040 -#define GEN6_SURFACEFORMAT_R32G32B32_SINT 0x041 -#define GEN6_SURFACEFORMAT_R32G32B32_UINT 0x042 -#define GEN6_SURFACEFORMAT_R32G32B32_UNORM 0x043 -#define GEN6_SURFACEFORMAT_R32G32B32_SNORM 0x044 -#define GEN6_SURFACEFORMAT_R32G32B32_SSCALED 0x045 -#define GEN6_SURFACEFORMAT_R32G32B32_USCALED 0x046 -#define GEN6_SURFACEFORMAT_R16G16B16A16_UNORM 0x080 -#define GEN6_SURFACEFORMAT_R16G16B16A16_SNORM 0x081 -#define GEN6_SURFACEFORMAT_R16G16B16A16_SINT 0x082 -#define GEN6_SURFACEFORMAT_R16G16B16A16_UINT 0x083 -#define GEN6_SURFACEFORMAT_R16G16B16A16_FLOAT 0x084 -#define GEN6_SURFACEFORMAT_R32G32_FLOAT 0x085 -#define GEN6_SURFACEFORMAT_R32G32_SINT 0x086 -#define GEN6_SURFACEFORMAT_R32G32_UINT 0x087 -#define GEN6_SURFACEFORMAT_R32_FLOAT_X8X24_TYPELESS 0x088 -#define GEN6_SURFACEFORMAT_X32_TYPELESS_G8X24_UINT 0x089 -#define GEN6_SURFACEFORMAT_L32A32_FLOAT 0x08A -#define GEN6_SURFACEFORMAT_R32G32_UNORM 0x08B -#define GEN6_SURFACEFORMAT_R32G32_SNORM 0x08C -#define GEN6_SURFACEFORMAT_R64_FLOAT 0x08D -#define GEN6_SURFACEFORMAT_R16G16B16X16_UNORM 0x08E -#define GEN6_SURFACEFORMAT_R16G16B16X16_FLOAT 0x08F -#define GEN6_SURFACEFORMAT_A32X32_FLOAT 0x090 -#define GEN6_SURFACEFORMAT_L32X32_FLOAT 0x091 -#define GEN6_SURFACEFORMAT_I32X32_FLOAT 0x092 -#define GEN6_SURFACEFORMAT_R16G16B16A16_SSCALED 0x093 -#define GEN6_SURFACEFORMAT_R16G16B16A16_USCALED 0x094 -#define GEN6_SURFACEFORMAT_R32G32_SSCALED 0x095 -#define GEN6_SURFACEFORMAT_R32G32_USCALED 0x096 -#define GEN6_SURFACEFORMAT_B8G8R8A8_UNORM 0x0C0 -#define GEN6_SURFACEFORMAT_B8G8R8A8_UNORM_SRGB 0x0C1 -#define GEN6_SURFACEFORMAT_R10G10B10A2_UNORM 0x0C2 -#define GEN6_SURFACEFORMAT_R10G10B10A2_UNORM_SRGB 0x0C3 -#define GEN6_SURFACEFORMAT_R10G10B10A2_UINT 0x0C4 -#define GEN6_SURFACEFORMAT_R10G10B10_SNORM_A2_UNORM 0x0C5 -#define GEN6_SURFACEFORMAT_R8G8B8A8_UNORM 0x0C7 -#define GEN6_SURFACEFORMAT_R8G8B8A8_UNORM_SRGB 0x0C8 -#define GEN6_SURFACEFORMAT_R8G8B8A8_SNORM 0x0C9 -#define GEN6_SURFACEFORMAT_R8G8B8A8_SINT 0x0CA -#define GEN6_SURFACEFORMAT_R8G8B8A8_UINT 0x0CB -#define GEN6_SURFACEFORMAT_R16G16_UNORM 0x0CC -#define GEN6_SURFACEFORMAT_R16G16_SNORM 0x0CD -#define GEN6_SURFACEFORMAT_R16G16_SINT 0x0CE -#define GEN6_SURFACEFORMAT_R16G16_UINT 0x0CF -#define GEN6_SURFACEFORMAT_R16G16_FLOAT 0x0D0 -#define GEN6_SURFACEFORMAT_B10G10R10A2_UNORM 0x0D1 -#define GEN6_SURFACEFORMAT_B10G10R10A2_UNORM_SRGB 0x0D2 -#define GEN6_SURFACEFORMAT_R11G11B10_FLOAT 0x0D3 -#define GEN6_SURFACEFORMAT_R32_SINT 0x0D6 -#define GEN6_SURFACEFORMAT_R32_UINT 0x0D7 -#define GEN6_SURFACEFORMAT_R32_FLOAT 0x0D8 -#define GEN6_SURFACEFORMAT_R24_UNORM_X8_TYPELESS 0x0D9 -#define GEN6_SURFACEFORMAT_X24_TYPELESS_G8_UINT 0x0DA -#define GEN6_SURFACEFORMAT_L16A16_UNORM 0x0DF -#define GEN6_SURFACEFORMAT_I24X8_UNORM 0x0E0 -#define GEN6_SURFACEFORMAT_L24X8_UNORM 0x0E1 -#define GEN6_SURFACEFORMAT_A24X8_UNORM 0x0E2 -#define GEN6_SURFACEFORMAT_I32_FLOAT 0x0E3 -#define GEN6_SURFACEFORMAT_L32_FLOAT 0x0E4 -#define GEN6_SURFACEFORMAT_A32_FLOAT 0x0E5 -#define GEN6_SURFACEFORMAT_B8G8R8X8_UNORM 0x0E9 -#define GEN6_SURFACEFORMAT_B8G8R8X8_UNORM_SRGB 0x0EA -#define GEN6_SURFACEFORMAT_R8G8B8X8_UNORM 0x0EB -#define GEN6_SURFACEFORMAT_R8G8B8X8_UNORM_SRGB 0x0EC -#define GEN6_SURFACEFORMAT_R9G9B9E5_SHAREDEXP 0x0ED -#define GEN6_SURFACEFORMAT_B10G10R10X2_UNORM 0x0EE -#define GEN6_SURFACEFORMAT_L16A16_FLOAT 0x0F0 -#define GEN6_SURFACEFORMAT_R32_UNORM 0x0F1 -#define GEN6_SURFACEFORMAT_R32_SNORM 0x0F2 -#define GEN6_SURFACEFORMAT_R10G10B10X2_USCALED 0x0F3 -#define GEN6_SURFACEFORMAT_R8G8B8A8_SSCALED 0x0F4 -#define GEN6_SURFACEFORMAT_R8G8B8A8_USCALED 0x0F5 -#define GEN6_SURFACEFORMAT_R16G16_SSCALED 0x0F6 -#define GEN6_SURFACEFORMAT_R16G16_USCALED 0x0F7 -#define GEN6_SURFACEFORMAT_R32_SSCALED 0x0F8 -#define GEN6_SURFACEFORMAT_R32_USCALED 0x0F9 -#define GEN6_SURFACEFORMAT_B5G6R5_UNORM 0x100 -#define GEN6_SURFACEFORMAT_B5G6R5_UNORM_SRGB 0x101 -#define GEN6_SURFACEFORMAT_B5G5R5A1_UNORM 0x102 -#define GEN6_SURFACEFORMAT_B5G5R5A1_UNORM_SRGB 0x103 -#define GEN6_SURFACEFORMAT_B4G4R4A4_UNORM 0x104 -#define GEN6_SURFACEFORMAT_B4G4R4A4_UNORM_SRGB 0x105 -#define GEN6_SURFACEFORMAT_R8G8_UNORM 0x106 -#define GEN6_SURFACEFORMAT_R8G8_SNORM 0x107 -#define GEN6_SURFACEFORMAT_R8G8_SINT 0x108 -#define GEN6_SURFACEFORMAT_R8G8_UINT 0x109 -#define GEN6_SURFACEFORMAT_R16_UNORM 0x10A -#define GEN6_SURFACEFORMAT_R16_SNORM 0x10B -#define GEN6_SURFACEFORMAT_R16_SINT 0x10C -#define GEN6_SURFACEFORMAT_R16_UINT 0x10D -#define GEN6_SURFACEFORMAT_R16_FLOAT 0x10E -#define GEN6_SURFACEFORMAT_I16_UNORM 0x111 -#define GEN6_SURFACEFORMAT_L16_UNORM 0x112 -#define GEN6_SURFACEFORMAT_A16_UNORM 0x113 -#define GEN6_SURFACEFORMAT_L8A8_UNORM 0x114 -#define GEN6_SURFACEFORMAT_I16_FLOAT 0x115 -#define GEN6_SURFACEFORMAT_L16_FLOAT 0x116 -#define GEN6_SURFACEFORMAT_A16_FLOAT 0x117 -#define GEN6_SURFACEFORMAT_R5G5_SNORM_B6_UNORM 0x119 -#define GEN6_SURFACEFORMAT_B5G5R5X1_UNORM 0x11A -#define GEN6_SURFACEFORMAT_B5G5R5X1_UNORM_SRGB 0x11B -#define GEN6_SURFACEFORMAT_R8G8_SSCALED 0x11C -#define GEN6_SURFACEFORMAT_R8G8_USCALED 0x11D -#define GEN6_SURFACEFORMAT_R16_SSCALED 0x11E -#define GEN6_SURFACEFORMAT_R16_USCALED 0x11F -#define GEN6_SURFACEFORMAT_R8_UNORM 0x140 -#define GEN6_SURFACEFORMAT_R8_SNORM 0x141 -#define GEN6_SURFACEFORMAT_R8_SINT 0x142 -#define GEN6_SURFACEFORMAT_R8_UINT 0x143 -#define GEN6_SURFACEFORMAT_A8_UNORM 0x144 -#define GEN6_SURFACEFORMAT_I8_UNORM 0x145 -#define GEN6_SURFACEFORMAT_L8_UNORM 0x146 -#define GEN6_SURFACEFORMAT_P4A4_UNORM 0x147 -#define GEN6_SURFACEFORMAT_A4P4_UNORM 0x148 -#define GEN6_SURFACEFORMAT_R8_SSCALED 0x149 -#define GEN6_SURFACEFORMAT_R8_USCALED 0x14A -#define GEN6_SURFACEFORMAT_R1_UINT 0x181 -#define GEN6_SURFACEFORMAT_YCRCB_NORMAL 0x182 -#define GEN6_SURFACEFORMAT_YCRCB_SWAPUVY 0x183 -#define GEN6_SURFACEFORMAT_BC1_UNORM 0x186 -#define GEN6_SURFACEFORMAT_BC2_UNORM 0x187 -#define GEN6_SURFACEFORMAT_BC3_UNORM 0x188 -#define GEN6_SURFACEFORMAT_BC4_UNORM 0x189 -#define GEN6_SURFACEFORMAT_BC5_UNORM 0x18A -#define GEN6_SURFACEFORMAT_BC1_UNORM_SRGB 0x18B -#define GEN6_SURFACEFORMAT_BC2_UNORM_SRGB 0x18C -#define GEN6_SURFACEFORMAT_BC3_UNORM_SRGB 0x18D -#define GEN6_SURFACEFORMAT_MONO8 0x18E -#define GEN6_SURFACEFORMAT_YCRCB_SWAPUV 0x18F -#define GEN6_SURFACEFORMAT_YCRCB_SWAPY 0x190 -#define GEN6_SURFACEFORMAT_DXT1_RGB 0x191 -#define GEN6_SURFACEFORMAT_FXT1 0x192 -#define GEN6_SURFACEFORMAT_R8G8B8_UNORM 0x193 -#define GEN6_SURFACEFORMAT_R8G8B8_SNORM 0x194 -#define GEN6_SURFACEFORMAT_R8G8B8_SSCALED 0x195 -#define GEN6_SURFACEFORMAT_R8G8B8_USCALED 0x196 -#define GEN6_SURFACEFORMAT_R64G64B64A64_FLOAT 0x197 -#define GEN6_SURFACEFORMAT_R64G64B64_FLOAT 0x198 -#define GEN6_SURFACEFORMAT_BC4_SNORM 0x199 -#define GEN6_SURFACEFORMAT_BC5_SNORM 0x19A -#define GEN6_SURFACEFORMAT_R16G16B16_UNORM 0x19C -#define GEN6_SURFACEFORMAT_R16G16B16_SNORM 0x19D -#define GEN6_SURFACEFORMAT_R16G16B16_SSCALED 0x19E -#define GEN6_SURFACEFORMAT_R16G16B16_USCALED 0x19F - -#define GEN6_SURFACERETURNFORMAT_FLOAT32 0 -#define GEN6_SURFACERETURNFORMAT_S1 1 - -#define GEN6_SURFACE_1D 0 -#define GEN6_SURFACE_2D 1 -#define GEN6_SURFACE_3D 2 -#define GEN6_SURFACE_CUBE 3 -#define GEN6_SURFACE_BUFFER 4 -#define GEN6_SURFACE_NULL 7 - -#define GEN6_BORDER_COLOR_MODE_DEFAULT 0 -#define GEN6_BORDER_COLOR_MODE_LEGACY 1 - -#define GEN6_TEXCOORDMODE_WRAP 0 -#define GEN6_TEXCOORDMODE_MIRROR 1 -#define GEN6_TEXCOORDMODE_CLAMP 2 -#define GEN6_TEXCOORDMODE_CUBE 3 -#define GEN6_TEXCOORDMODE_CLAMP_BORDER 4 -#define GEN6_TEXCOORDMODE_MIRROR_ONCE 5 - -#define GEN6_THREAD_PRIORITY_NORMAL 0 -#define GEN6_THREAD_PRIORITY_HIGH 1 - -#define GEN6_TILEWALK_XMAJOR 0 -#define GEN6_TILEWALK_YMAJOR 1 - -#define GEN6_VERTEX_SUBPIXEL_PRECISION_8BITS 0 -#define GEN6_VERTEX_SUBPIXEL_PRECISION_4BITS 1 - -#define GEN6_VERTEXBUFFER_ACCESS_VERTEXDATA 0 -#define GEN6_VERTEXBUFFER_ACCESS_INSTANCEDATA 1 - -#define GEN6_VFCOMPONENT_NOSTORE 0 -#define GEN6_VFCOMPONENT_STORE_SRC 1 -#define GEN6_VFCOMPONENT_STORE_0 2 -#define GEN6_VFCOMPONENT_STORE_1_FLT 3 -#define GEN6_VFCOMPONENT_STORE_1_INT 4 -#define GEN6_VFCOMPONENT_STORE_VID 5 -#define GEN6_VFCOMPONENT_STORE_IID 6 -#define GEN6_VFCOMPONENT_STORE_PID 7 - - - -/* Execution Unit (EU) defines - */ - -#define GEN6_ALIGN_1 0 -#define GEN6_ALIGN_16 1 - -#define GEN6_ADDRESS_DIRECT 0 -#define GEN6_ADDRESS_REGISTER_INDIRECT_REGISTER 1 - -#define GEN6_CHANNEL_X 0 -#define GEN6_CHANNEL_Y 1 -#define GEN6_CHANNEL_Z 2 -#define GEN6_CHANNEL_W 3 - -#define GEN6_COMPRESSION_NONE 0 -#define GEN6_COMPRESSION_2NDHALF 1 -#define GEN6_COMPRESSION_COMPRESSED 2 - -#define GEN6_CONDITIONAL_NONE 0 -#define GEN6_CONDITIONAL_Z 1 -#define GEN6_CONDITIONAL_NZ 2 -#define GEN6_CONDITIONAL_EQ 1 /* Z */ -#define GEN6_CONDITIONAL_NEQ 2 /* NZ */ -#define GEN6_CONDITIONAL_G 3 -#define GEN6_CONDITIONAL_GE 4 -#define GEN6_CONDITIONAL_L 5 -#define GEN6_CONDITIONAL_LE 6 -#define GEN6_CONDITIONAL_C 7 -#define GEN6_CONDITIONAL_O 8 - -#define GEN6_DEBUG_NONE 0 -#define GEN6_DEBUG_BREAKPOINT 1 - -#define GEN6_DEPENDENCY_NORMAL 0 -#define GEN6_DEPENDENCY_NOTCLEARED 1 -#define GEN6_DEPENDENCY_NOTCHECKED 2 -#define GEN6_DEPENDENCY_DISABLE 3 - -#define GEN6_EXECUTE_1 0 -#define GEN6_EXECUTE_2 1 -#define GEN6_EXECUTE_4 2 -#define GEN6_EXECUTE_8 3 -#define GEN6_EXECUTE_16 4 -#define GEN6_EXECUTE_32 5 - -#define GEN6_HORIZONTAL_STRIDE_0 0 -#define GEN6_HORIZONTAL_STRIDE_1 1 -#define GEN6_HORIZONTAL_STRIDE_2 2 -#define GEN6_HORIZONTAL_STRIDE_4 3 - -#define GEN6_INSTRUCTION_NORMAL 0 -#define GEN6_INSTRUCTION_SATURATE 1 - -#define GEN6_MASK_ENABLE 0 -#define GEN6_MASK_DISABLE 1 - -#define GEN6_OPCODE_MOV 1 -#define GEN6_OPCODE_SEL 2 -#define GEN6_OPCODE_NOT 4 -#define GEN6_OPCODE_AND 5 -#define GEN6_OPCODE_OR 6 -#define GEN6_OPCODE_XOR 7 -#define GEN6_OPCODE_SHR 8 -#define GEN6_OPCODE_SHL 9 -#define GEN6_OPCODE_RSR 10 -#define GEN6_OPCODE_RSL 11 -#define GEN6_OPCODE_ASR 12 -#define GEN6_OPCODE_CMP 16 -#define GEN6_OPCODE_JMPI 32 -#define GEN6_OPCODE_IF 34 -#define GEN6_OPCODE_IFF 35 -#define GEN6_OPCODE_ELSE 36 -#define GEN6_OPCODE_ENDIF 37 -#define GEN6_OPCODE_DO 38 -#define GEN6_OPCODE_WHILE 39 -#define GEN6_OPCODE_BREAK 40 -#define GEN6_OPCODE_CONTINUE 41 -#define GEN6_OPCODE_HALT 42 -#define GEN6_OPCODE_MSAVE 44 -#define GEN6_OPCODE_MRESTORE 45 -#define GEN6_OPCODE_PUSH 46 -#define GEN6_OPCODE_POP 47 -#define GEN6_OPCODE_WAIT 48 -#define GEN6_OPCODE_SEND 49 -#define GEN6_OPCODE_ADD 64 -#define GEN6_OPCODE_MUL 65 -#define GEN6_OPCODE_AVG 66 -#define GEN6_OPCODE_FRC 67 -#define GEN6_OPCODE_RNDU 68 -#define GEN6_OPCODE_RNDD 69 -#define GEN6_OPCODE_RNDE 70 -#define GEN6_OPCODE_RNDZ 71 -#define GEN6_OPCODE_MAC 72 -#define GEN6_OPCODE_MACH 73 -#define GEN6_OPCODE_LZD 74 -#define GEN6_OPCODE_SAD2 80 -#define GEN6_OPCODE_SADA2 81 -#define GEN6_OPCODE_DP4 84 -#define GEN6_OPCODE_DPH 85 -#define GEN6_OPCODE_DP3 86 -#define GEN6_OPCODE_DP2 87 -#define GEN6_OPCODE_DPA2 88 -#define GEN6_OPCODE_LINE 89 -#define GEN6_OPCODE_NOP 126 - -#define GEN6_PREDICATE_NONE 0 -#define GEN6_PREDICATE_NORMAL 1 -#define GEN6_PREDICATE_ALIGN1_ANYV 2 -#define GEN6_PREDICATE_ALIGN1_ALLV 3 -#define GEN6_PREDICATE_ALIGN1_ANY2H 4 -#define GEN6_PREDICATE_ALIGN1_ALL2H 5 -#define GEN6_PREDICATE_ALIGN1_ANY4H 6 -#define GEN6_PREDICATE_ALIGN1_ALL4H 7 -#define GEN6_PREDICATE_ALIGN1_ANY8H 8 -#define GEN6_PREDICATE_ALIGN1_ALL8H 9 -#define GEN6_PREDICATE_ALIGN1_ANY16H 10 -#define GEN6_PREDICATE_ALIGN1_ALL16H 11 -#define GEN6_PREDICATE_ALIGN16_REPLICATE_X 2 -#define GEN6_PREDICATE_ALIGN16_REPLICATE_Y 3 -#define GEN6_PREDICATE_ALIGN16_REPLICATE_Z 4 -#define GEN6_PREDICATE_ALIGN16_REPLICATE_W 5 -#define GEN6_PREDICATE_ALIGN16_ANY4H 6 -#define GEN6_PREDICATE_ALIGN16_ALL4H 7 - -#define GEN6_ARCHITECTURE_REGISTER_FILE 0 -#define GEN6_GENERAL_REGISTER_FILE 1 -#define GEN6_MESSAGE_REGISTER_FILE 2 -#define GEN6_IMMEDIATE_VALUE 3 - -#define GEN6_REGISTER_TYPE_UD 0 -#define GEN6_REGISTER_TYPE_D 1 -#define GEN6_REGISTER_TYPE_UW 2 -#define GEN6_REGISTER_TYPE_W 3 -#define GEN6_REGISTER_TYPE_UB 4 -#define GEN6_REGISTER_TYPE_B 5 -#define GEN6_REGISTER_TYPE_VF 5 /* packed float vector, immediates only? */ -#define GEN6_REGISTER_TYPE_HF 6 -#define GEN6_REGISTER_TYPE_V 6 /* packed int vector, immediates only, uword dest only */ -#define GEN6_REGISTER_TYPE_F 7 - -#define GEN6_ARF_NULL 0x00 -#define GEN6_ARF_ADDRESS 0x10 -#define GEN6_ARF_ACCUMULATOR 0x20 -#define GEN6_ARF_FLAG 0x30 -#define GEN6_ARF_MASK 0x40 -#define GEN6_ARF_MASK_STACK 0x50 -#define GEN6_ARF_MASK_STACK_DEPTH 0x60 -#define GEN6_ARF_STATE 0x70 -#define GEN6_ARF_CONTROL 0x80 -#define GEN6_ARF_NOTIFICATION_COUNT 0x90 -#define GEN6_ARF_IP 0xA0 - -#define GEN6_AMASK 0 -#define GEN6_IMASK 1 -#define GEN6_LMASK 2 -#define GEN6_CMASK 3 - - - -#define GEN6_THREAD_NORMAL 0 -#define GEN6_THREAD_ATOMIC 1 -#define GEN6_THREAD_SWITCH 2 - -#define GEN6_VERTICAL_STRIDE_0 0 -#define GEN6_VERTICAL_STRIDE_1 1 -#define GEN6_VERTICAL_STRIDE_2 2 -#define GEN6_VERTICAL_STRIDE_4 3 -#define GEN6_VERTICAL_STRIDE_8 4 -#define GEN6_VERTICAL_STRIDE_16 5 -#define GEN6_VERTICAL_STRIDE_32 6 -#define GEN6_VERTICAL_STRIDE_64 7 -#define GEN6_VERTICAL_STRIDE_128 8 -#define GEN6_VERTICAL_STRIDE_256 9 -#define GEN6_VERTICAL_STRIDE_ONE_DIMENSIONAL 0xF - -#define GEN6_WIDTH_1 0 -#define GEN6_WIDTH_2 1 -#define GEN6_WIDTH_4 2 -#define GEN6_WIDTH_8 3 -#define GEN6_WIDTH_16 4 - -#define GEN6_STATELESS_BUFFER_BOUNDARY_1K 0 -#define GEN6_STATELESS_BUFFER_BOUNDARY_2K 1 -#define GEN6_STATELESS_BUFFER_BOUNDARY_4K 2 -#define GEN6_STATELESS_BUFFER_BOUNDARY_8K 3 -#define GEN6_STATELESS_BUFFER_BOUNDARY_16K 4 -#define GEN6_STATELESS_BUFFER_BOUNDARY_32K 5 -#define GEN6_STATELESS_BUFFER_BOUNDARY_64K 6 -#define GEN6_STATELESS_BUFFER_BOUNDARY_128K 7 -#define GEN6_STATELESS_BUFFER_BOUNDARY_256K 8 -#define GEN6_STATELESS_BUFFER_BOUNDARY_512K 9 -#define GEN6_STATELESS_BUFFER_BOUNDARY_1M 10 -#define GEN6_STATELESS_BUFFER_BOUNDARY_2M 11 - -#define GEN6_POLYGON_FACING_FRONT 0 -#define GEN6_POLYGON_FACING_BACK 1 - -#define GEN6_MESSAGE_TARGET_NULL 0 -#define GEN6_MESSAGE_TARGET_MATH 1 -#define GEN6_MESSAGE_TARGET_SAMPLER 2 -#define GEN6_MESSAGE_TARGET_GATEWAY 3 -#define GEN6_MESSAGE_TARGET_DATAPORT_READ 4 -#define GEN6_MESSAGE_TARGET_DATAPORT_WRITE 5 -#define GEN6_MESSAGE_TARGET_URB 6 -#define GEN6_MESSAGE_TARGET_THREAD_SPAWNER 7 - -#define GEN6_SAMPLER_RETURN_FORMAT_FLOAT32 0 -#define GEN6_SAMPLER_RETURN_FORMAT_UINT32 2 -#define GEN6_SAMPLER_RETURN_FORMAT_SINT32 3 - -#define GEN6_SAMPLER_MESSAGE_SIMD8_SAMPLE 0 -#define GEN6_SAMPLER_MESSAGE_SIMD16_SAMPLE 0 -#define GEN6_SAMPLER_MESSAGE_SIMD16_SAMPLE_BIAS 0 -#define GEN6_SAMPLER_MESSAGE_SIMD8_KILLPIX 1 -#define GEN6_SAMPLER_MESSAGE_SIMD4X2_SAMPLE_LOD 1 -#define GEN6_SAMPLER_MESSAGE_SIMD16_SAMPLE_LOD 1 -#define GEN6_SAMPLER_MESSAGE_SIMD4X2_SAMPLE_GRADIENTS 2 -#define GEN6_SAMPLER_MESSAGE_SIMD8_SAMPLE_GRADIENTS 2 -#define GEN6_SAMPLER_MESSAGE_SIMD4X2_SAMPLE_COMPARE 0 -#define GEN6_SAMPLER_MESSAGE_SIMD16_SAMPLE_COMPARE 2 -#define GEN6_SAMPLER_MESSAGE_SIMD4X2_RESINFO 2 -#define GEN6_SAMPLER_MESSAGE_SIMD8_RESINFO 2 -#define GEN6_SAMPLER_MESSAGE_SIMD16_RESINFO 2 -#define GEN6_SAMPLER_MESSAGE_SIMD4X2_LD 3 -#define GEN6_SAMPLER_MESSAGE_SIMD8_LD 3 -#define GEN6_SAMPLER_MESSAGE_SIMD16_LD 3 - -#define GEN6_DATAPORT_OWORD_BLOCK_1_OWORDLOW 0 -#define GEN6_DATAPORT_OWORD_BLOCK_1_OWORDHIGH 1 -#define GEN6_DATAPORT_OWORD_BLOCK_2_OWORDS 2 -#define GEN6_DATAPORT_OWORD_BLOCK_4_OWORDS 3 -#define GEN6_DATAPORT_OWORD_BLOCK_8_OWORDS 4 - -#define GEN6_DATAPORT_OWORD_DUAL_BLOCK_1OWORD 0 -#define GEN6_DATAPORT_OWORD_DUAL_BLOCK_4OWORDS 2 - -#define GEN6_DATAPORT_DWORD_SCATTERED_BLOCK_8DWORDS 2 -#define GEN6_DATAPORT_DWORD_SCATTERED_BLOCK_16DWORDS 3 - -#define GEN6_DATAPORT_READ_MESSAGE_OWORD_BLOCK_READ 0 -#define GEN6_DATAPORT_READ_MESSAGE_OWORD_DUAL_BLOCK_READ 1 -#define GEN6_DATAPORT_READ_MESSAGE_DWORD_BLOCK_READ 2 -#define GEN6_DATAPORT_READ_MESSAGE_DWORD_SCATTERED_READ 3 - -#define GEN6_DATAPORT_READ_TARGET_DATA_CACHE 0 -#define GEN6_DATAPORT_READ_TARGET_RENDER_CACHE 1 -#define GEN6_DATAPORT_READ_TARGET_SAMPLER_CACHE 2 - -#define GEN6_DATAPORT_RENDER_TARGET_WRITE_SIMD16_SINGLE_SOURCE 0 -#define GEN6_DATAPORT_RENDER_TARGET_WRITE_SIMD16_SINGLE_SOURCE_REPLICATED 1 -#define GEN6_DATAPORT_RENDER_TARGET_WRITE_SIMD8_DUAL_SOURCE_SUBSPAN01 2 -#define GEN6_DATAPORT_RENDER_TARGET_WRITE_SIMD8_DUAL_SOURCE_SUBSPAN23 3 -#define GEN6_DATAPORT_RENDER_TARGET_WRITE_SIMD8_SINGLE_SOURCE_SUBSPAN01 4 - -#define GEN6_DATAPORT_WRITE_MESSAGE_OWORD_BLOCK_WRITE 0 -#define GEN6_DATAPORT_WRITE_MESSAGE_OWORD_DUAL_BLOCK_WRITE 1 -#define GEN6_DATAPORT_WRITE_MESSAGE_DWORD_BLOCK_WRITE 2 -#define GEN6_DATAPORT_WRITE_MESSAGE_DWORD_SCATTERED_WRITE 3 -#define GEN6_DATAPORT_WRITE_MESSAGE_RENDER_TARGET_WRITE 4 -#define GEN6_DATAPORT_WRITE_MESSAGE_STREAMED_VERTEX_BUFFER_WRITE 5 -#define GEN6_DATAPORT_WRITE_MESSAGE_FLUSH_RENDER_CACHE 7 - -#define GEN6_MATH_FUNCTION_INV 1 -#define GEN6_MATH_FUNCTION_LOG 2 -#define GEN6_MATH_FUNCTION_EXP 3 -#define GEN6_MATH_FUNCTION_SQRT 4 -#define GEN6_MATH_FUNCTION_RSQ 5 -#define GEN6_MATH_FUNCTION_SIN 6 /* was 7 */ -#define GEN6_MATH_FUNCTION_COS 7 /* was 8 */ -#define GEN6_MATH_FUNCTION_SINCOS 8 /* was 6 */ -#define GEN6_MATH_FUNCTION_TAN 9 -#define GEN6_MATH_FUNCTION_POW 10 -#define GEN6_MATH_FUNCTION_INT_DIV_QUOTIENT_AND_REMAINDER 11 -#define GEN6_MATH_FUNCTION_INT_DIV_QUOTIENT 12 -#define GEN6_MATH_FUNCTION_INT_DIV_REMAINDER 13 - -#define GEN6_MATH_INTEGER_UNSIGNED 0 -#define GEN6_MATH_INTEGER_SIGNED 1 - -#define GEN6_MATH_PRECISION_FULL 0 -#define GEN6_MATH_PRECISION_PARTIAL 1 - -#define GEN6_MATH_SATURATE_NONE 0 -#define GEN6_MATH_SATURATE_SATURATE 1 - -#define GEN6_MATH_DATA_VECTOR 0 -#define GEN6_MATH_DATA_SCALAR 1 - -#define GEN6_URB_OPCODE_WRITE 0 - -#define GEN6_URB_SWIZZLE_NONE 0 -#define GEN6_URB_SWIZZLE_INTERLEAVE 1 -#define GEN6_URB_SWIZZLE_TRANSPOSE 2 - -#define GEN6_SCRATCH_SPACE_SIZE_1K 0 -#define GEN6_SCRATCH_SPACE_SIZE_2K 1 -#define GEN6_SCRATCH_SPACE_SIZE_4K 2 -#define GEN6_SCRATCH_SPACE_SIZE_8K 3 -#define GEN6_SCRATCH_SPACE_SIZE_16K 4 -#define GEN6_SCRATCH_SPACE_SIZE_32K 5 -#define GEN6_SCRATCH_SPACE_SIZE_64K 6 -#define GEN6_SCRATCH_SPACE_SIZE_128K 7 -#define GEN6_SCRATCH_SPACE_SIZE_256K 8 -#define GEN6_SCRATCH_SPACE_SIZE_512K 9 -#define GEN6_SCRATCH_SPACE_SIZE_1M 10 -#define GEN6_SCRATCH_SPACE_SIZE_2M 11 - -/* The hardware supports two different modes for border color. The - * default (OpenGL) mode uses floating-point color channels, while the - * legacy mode uses 4 bytes. - * - * More significantly, the legacy mode respects the components of the - * border color for channels not present in the source, (whereas the - * default mode will ignore the border color's alpha channel and use - * alpha==1 for an RGB source, for example). - * - * The legacy mode matches the semantics specified by the Render - * extension. - */ -struct gen6_sampler_default_border_color { - float color[4]; -}; - -struct gen6_sampler_legacy_border_color { - uint8_t color[4]; -}; - -struct gen6_sampler_state { - struct { - uint32_t shadow_function:3; - uint32_t lod_bias:11; - uint32_t min_filter:3; - uint32_t mag_filter:3; - uint32_t mip_filter:2; - uint32_t base_level:5; - uint32_t pad:1; - uint32_t lod_preclamp:1; - uint32_t border_color_mode:1; - uint32_t pad0:1; - uint32_t disable:1; - } ss0; - - struct { - uint32_t r_wrap_mode:3; - uint32_t t_wrap_mode:3; - uint32_t s_wrap_mode:3; - uint32_t pad:3; - uint32_t max_lod:10; - uint32_t min_lod:10; - } ss1; - - struct { - uint32_t border_color; - } ss2; - - struct { - uint32_t pad:19; - uint32_t max_aniso:3; - uint32_t chroma_key_mode:1; - uint32_t chroma_key_index:2; - uint32_t chroma_key_enable:1; - uint32_t monochrome_filter_width:3; - uint32_t monochrome_filter_height:3; - } ss3; -}; - -struct gen6_blend_state { - struct { - uint32_t dest_blend_factor:5; - uint32_t source_blend_factor:5; - uint32_t pad3:1; - uint32_t blend_func:3; - uint32_t pad2:1; - uint32_t ia_dest_blend_factor:5; - uint32_t ia_source_blend_factor:5; - uint32_t pad1:1; - uint32_t ia_blend_func:3; - uint32_t pad0:1; - uint32_t ia_blend_enable:1; - uint32_t blend_enable:1; - } blend0; - - struct { - uint32_t post_blend_clamp_enable:1; - uint32_t pre_blend_clamp_enable:1; - uint32_t clamp_range:2; - uint32_t pad0:4; - uint32_t x_dither_offset:2; - uint32_t y_dither_offset:2; - uint32_t dither_enable:1; - uint32_t alpha_test_func:3; - uint32_t alpha_test_enable:1; - uint32_t pad1:1; - uint32_t logic_op_func:4; - uint32_t logic_op_enable:1; - uint32_t pad2:1; - uint32_t write_disable_b:1; - uint32_t write_disable_g:1; - uint32_t write_disable_r:1; - uint32_t write_disable_a:1; - uint32_t pad3:1; - uint32_t alpha_to_coverage_dither:1; - uint32_t alpha_to_one:1; - uint32_t alpha_to_coverage:1; - } blend1; -}; - -struct gen6_color_calc_state { - struct { - uint32_t alpha_test_format:1; - uint32_t pad0:14; - uint32_t round_disable:1; - uint32_t bf_stencil_ref:8; - uint32_t stencil_ref:8; - } cc0; - - union { - float alpha_ref_f; - struct { - uint32_t ui:8; - uint32_t pad0:24; - } alpha_ref_fi; - } cc1; - - float constant_r; - float constant_g; - float constant_b; - float constant_a; -}; - -struct gen6_depth_stencil_state { - struct { - uint32_t pad0:3; - uint32_t bf_stencil_pass_depth_pass_op:3; - uint32_t bf_stencil_pass_depth_fail_op:3; - uint32_t bf_stencil_fail_op:3; - uint32_t bf_stencil_func:3; - uint32_t bf_stencil_enable:1; - uint32_t pad1:2; - uint32_t stencil_write_enable:1; - uint32_t stencil_pass_depth_pass_op:3; - uint32_t stencil_pass_depth_fail_op:3; - uint32_t stencil_fail_op:3; - uint32_t stencil_func:3; - uint32_t stencil_enable:1; - } ds0; - - struct { - uint32_t bf_stencil_write_mask:8; - uint32_t bf_stencil_test_mask:8; - uint32_t stencil_write_mask:8; - uint32_t stencil_test_mask:8; - } ds1; - - struct { - uint32_t pad0:26; - uint32_t depth_write_enable:1; - uint32_t depth_test_func:3; - uint32_t pad1:1; - uint32_t depth_test_enable:1; - } ds2; -}; - -struct gen6_surface_state { - struct { - uint32_t cube_pos_z:1; - uint32_t cube_neg_z:1; - uint32_t cube_pos_y:1; - uint32_t cube_neg_y:1; - uint32_t cube_pos_x:1; - uint32_t cube_neg_x:1; - uint32_t pad:3; - uint32_t render_cache_read_mode:1; - uint32_t mipmap_layout_mode:1; - uint32_t vert_line_stride_ofs:1; - uint32_t vert_line_stride:1; - uint32_t color_blend:1; - uint32_t writedisable_blue:1; - uint32_t writedisable_green:1; - uint32_t writedisable_red:1; - uint32_t writedisable_alpha:1; - uint32_t surface_format:9; - uint32_t data_return_format:1; - uint32_t pad0:1; - uint32_t surface_type:3; - } ss0; - - struct { - uint32_t base_addr; - } ss1; - - struct { - uint32_t render_target_rotation:2; - uint32_t mip_count:4; - uint32_t width:13; - uint32_t height:13; - } ss2; - - struct { - uint32_t tile_walk:1; - uint32_t tiled_surface:1; - uint32_t pad:1; - uint32_t pitch:18; - uint32_t depth:11; - } ss3; - - struct { - uint32_t pad:19; - uint32_t min_array_elt:9; - uint32_t min_lod:4; - } ss4; - - struct { - uint32_t pad:20; - uint32_t y_offset:4; - uint32_t pad2:1; - uint32_t x_offset:7; - } ss5; -}; - -/* Surface state DW0 */ -#define GEN6_SURFACE_RC_READ_WRITE (1 << 8) -#define GEN6_SURFACE_MIPLAYOUT_SHIFT 10 -#define GEN6_SURFACE_MIPMAPLAYOUT_BELOW 0 -#define GEN6_SURFACE_MIPMAPLAYOUT_RIGHT 1 -#define GEN6_SURFACE_CUBEFACE_ENABLES 0x3f -#define GEN6_SURFACE_BLEND_ENABLED (1 << 13) -#define GEN6_SURFACE_WRITEDISABLE_B_SHIFT 14 -#define GEN6_SURFACE_WRITEDISABLE_G_SHIFT 15 -#define GEN6_SURFACE_WRITEDISABLE_R_SHIFT 16 -#define GEN6_SURFACE_WRITEDISABLE_A_SHIFT 17 -#define GEN6_SURFACE_FORMAT_SHIFT 18 -#define GEN6_SURFACE_FORMAT_MASK INTEL_MASK(26, 18) - -#define GEN6_SURFACE_TYPE_SHIFT 29 -#define GEN6_SURFACE_TYPE_MASK GEN6_MASK(31, 29) -#define GEN6_SURFACE_1D 0 -#define GEN6_SURFACE_2D 1 -#define GEN6_SURFACE_3D 2 -#define GEN6_SURFACE_CUBE 3 -#define GEN6_SURFACE_BUFFER 4 -#define GEN6_SURFACE_NULL 7 - -/* Surface state DW2 */ -#define GEN6_SURFACE_HEIGHT_SHIFT 19 -#define GEN6_SURFACE_HEIGHT_MASK GEN6_MASK(31, 19) -#define GEN6_SURFACE_WIDTH_SHIFT 6 -#define GEN6_SURFACE_WIDTH_MASK GEN6_MASK(18, 6) -#define GEN6_SURFACE_LOD_SHIFT 2 -#define GEN6_SURFACE_LOD_MASK GEN6_MASK(5, 2) - -/* Surface state DW3 */ -#define GEN6_SURFACE_DEPTH_SHIFT 21 -#define GEN6_SURFACE_DEPTH_MASK GEN6_MASK(31, 21) -#define GEN6_SURFACE_PITCH_SHIFT 3 -#define GEN6_SURFACE_PITCH_MASK GEN6_MASK(19, 3) -#define GEN6_SURFACE_TILED (1 << 1) -#define GEN6_SURFACE_TILED_Y (1 << 0) - -/* Surface state DW4 */ -#define GEN6_SURFACE_MIN_LOD_SHIFT 28 -#define GEN6_SURFACE_MIN_LOD_MASK GEN6_MASK(31, 28) - -/* Surface state DW5 */ -#define GEN6_SURFACE_X_OFFSET_SHIFT 25 -#define GEN6_SURFACE_X_OFFSET_MASK GEN6_MASK(31, 25) -#define GEN6_SURFACE_Y_OFFSET_SHIFT 20 -#define GEN6_SURFACE_Y_OFFSET_MASK GEN6_MASK(23, 20) - -struct gen6_cc_viewport { - float min_depth; - float max_depth; -}; - -typedef enum { - SAMPLER_FILTER_NEAREST = 0, - SAMPLER_FILTER_BILINEAR, - FILTER_COUNT -} sampler_filter_t; - -typedef enum { - SAMPLER_EXTEND_NONE = 0, - SAMPLER_EXTEND_REPEAT, - SAMPLER_EXTEND_PAD, - SAMPLER_EXTEND_REFLECT, - EXTEND_COUNT -} sampler_extend_t; - -#endif diff --git a/drivers/video/drm/i915/sna/kgem.c b/drivers/video/drm/i915/sna/kgem.c deleted file mode 100644 index 60ecf8b304..0000000000 --- a/drivers/video/drm/i915/sna/kgem.c +++ /dev/null @@ -1,1718 +0,0 @@ -/* - * Copyright (c) 2011 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: - * Chris Wilson - * - */ - - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include -#include -#include "i915_drm.h" -#include "i915_drv.h" -#include "intel_drv.h" - -#include -#include "../bitmap.h" -#include "sna.h" -//#include "sna_reg.h" -//#include -//#include - -#define NO_CACHE 1 - -#define list_is_empty list_empty -#define list_init INIT_LIST_HEAD - -extern struct drm_device *main_device; - -static struct kgem_bo * -search_linear_cache(struct kgem *kgem, unsigned int num_pages, - unsigned flags); - -#define INT16_MAX (32767) - -#define PAGE_ALIGN(x) ALIGN(x, PAGE_SIZE) -#define NUM_PAGES(x) (((x) + PAGE_SIZE-1) / PAGE_SIZE) - -#define MAX_GTT_VMA_CACHE 512 -#define MAX_CPU_VMA_CACHE INT16_MAX -#define MAP_PRESERVE_TIME 10 - -#define CPU_MAP(ptr) ((void*)((uintptr_t)(ptr) & ~1)) -#define MAKE_CPU_MAP(ptr) ((void*)((uintptr_t)(ptr) | 1)) - -struct kgem_partial_bo { - struct kgem_bo base; - void *mem; - uint32_t used; - uint32_t need_io : 1; - uint32_t write : 2; - uint32_t mmapped : 1; -}; - -static struct kgem_bo *__kgem_freed_bo; -static struct drm_i915_gem_exec_object2 _kgem_dummy_exec; - -static inline int bytes(struct kgem_bo *bo) -{ - return kgem_bo_size(bo); -} - -#define bucket(B) (B)->size.pages.bucket -#define num_pages(B) (B)->size.pages.count - -static void kgem_sna_reset(struct kgem *kgem) -{ - struct sna *sna = container_of(kgem, struct sna, kgem); - - sna->render.reset(sna); - sna->blt_state.fill_bo = 0; -} - -static void kgem_sna_flush(struct kgem *kgem) -{ - struct sna *sna = container_of(kgem, struct sna, kgem); - - sna->render.flush(sna); - - if (sna->render.solid_cache.dirty) - sna_render_flush_solid(sna); -} - -static int __gem_write(int fd, uint32_t handle, - int offset, int length, - const void *src) -{ - DBG(("%s(handle=%x, offset=%d, len=%d)\n", __FUNCTION__, - handle, offset, length)); - - write_gem_object(handle, offset, length, src); - return 0; -} - - -static int gem_write(int fd, uint32_t handle, - int offset, int length, - const void *src) -{ - u32 _offset; - u32 _size; - u8 *data_ptr; - - DBG(("%s(handle=%x, offset=%d, len=%d)\n", __FUNCTION__, - handle, offset, length)); - - /* align the transfer to cachelines; fortuitously this is safe! */ - if ((offset | length) & 63) { - _offset = offset & ~63; - _size = ALIGN(offset+length, 64) - _offset; - data_ptr = (u8*)src + _offset - offset; - } else { - _offset = offset; - _size = length; - data_ptr = (u8*)src; - } - - write_gem_object(handle, _offset, _size, data_ptr); - return 0; -} - -static void kgem_bo_retire(struct kgem *kgem, struct kgem_bo *bo) -{ - DBG(("%s: handle=%x, domain=%d\n", - __FUNCTION__, bo->handle, bo->domain)); - assert(!kgem_busy(kgem, bo->handle)); - - if (bo->domain == DOMAIN_GPU) - kgem_retire(kgem); - - if (bo->exec == NULL) { - DBG(("%s: retiring bo handle=%x (needed flush? %d), rq? %d\n", - __FUNCTION__, bo->handle, bo->needs_flush, bo->rq != NULL)); - bo->rq = NULL; - list_del(&bo->request); - bo->needs_flush = bo->flush; - } -} - -Bool kgem_bo_write(struct kgem *kgem, struct kgem_bo *bo, - const void *data, int length) -{ - assert(bo->refcnt); - assert(!bo->purged); - assert(!kgem_busy(kgem, bo->handle)); - - assert(length <= bytes(bo)); - if (gem_write(kgem->fd, bo->handle, 0, length, data)) - return FALSE; - - DBG(("%s: flush=%d, domain=%d\n", __FUNCTION__, bo->flush, bo->domain)); - kgem_bo_retire(kgem, bo); - bo->domain = DOMAIN_NONE; - return TRUE; -} - -static uint32_t gem_create(int fd, int num_pages) -{ - struct drm_i915_gem_object *obj; - int ret; - - /* Allocate the new object */ - obj = i915_gem_alloc_object(main_device, - PAGE_SIZE * num_pages); - if (obj == NULL) - goto err1; - - ret = i915_gem_object_pin(obj, 4096, true); - if (ret) - goto err2; - - return (uint32_t)obj; - -err2: - drm_gem_object_unreference(&obj->base); -err1: - return 0; -} - -static bool -kgem_bo_set_purgeable(struct kgem *kgem, struct kgem_bo *bo) -{ - return true; -} - - -static bool -kgem_bo_clear_purgeable(struct kgem *kgem, struct kgem_bo *bo) -{ - return true; -} - -static void gem_close(int fd, uint32_t handle) -{ - destroy_gem_object(handle); -} - - -/* -constant inline static unsigned long __fls(unsigned long word) -{ - asm("bsr %1,%0" - : "=r" (word) - : "rm" (word)); - return word; -} -*/ - -constant inline static int cache_bucket(int num_pages) -{ - return __fls(num_pages); -} - -static struct kgem_bo *__kgem_bo_init(struct kgem_bo *bo, - int handle, int num_pages) -{ - assert(num_pages); - memset(bo, 0, sizeof(*bo)); - - bo->refcnt = 1; - bo->handle = handle; - num_pages(bo) = num_pages; - bucket(bo) = cache_bucket(num_pages); - bo->reusable = true; - bo->domain = DOMAIN_CPU; - list_init(&bo->request); - list_init(&bo->list); - list_init(&bo->vma); - - return bo; -} - -static struct kgem_bo *__kgem_bo_alloc(int handle, int num_pages) -{ - struct kgem_bo *bo; - - if (__kgem_freed_bo) { - bo = __kgem_freed_bo; - __kgem_freed_bo = *(struct kgem_bo **)bo; - } else { - bo = malloc(sizeof(*bo)); - if (bo == NULL) - return NULL; - } - - return __kgem_bo_init(bo, handle, num_pages); -} - -static struct kgem_request _kgem_static_request; - -static struct kgem_request *__kgem_request_alloc(void) -{ - struct kgem_request *rq; - - rq = malloc(sizeof(*rq)); - if (rq == NULL) - rq = &_kgem_static_request; - - list_init(&rq->buffers); - - return rq; -} - -static struct list_head *inactive(struct kgem *kgem, int num_pages) -{ - return &kgem->inactive[cache_bucket(num_pages)]; -} - -static struct list_head *active(struct kgem *kgem, int num_pages, int tiling) -{ - return &kgem->active[cache_bucket(num_pages)][tiling]; -} - - - -void kgem_init(struct kgem *kgem, int gen) -{ - struct drm_i915_gem_get_aperture aperture; - struct drm_i915_gem_object *obj; - - size_t totalram; - unsigned int i, j; - int ret; - - memset(kgem, 0, sizeof(*kgem)); - - kgem->gen = gen; - kgem->wedged = 0; -// kgem->wedged |= DBG_NO_HW; - - obj = i915_gem_alloc_object(main_device, 4096*4); - if (obj == NULL) - goto err2; - - ret = i915_gem_object_pin(obj, 4096, true); - if (ret) - goto err3; - - kgem->batch_ptr = drm_intel_bo_map(obj, true); - kgem->batch = kgem->batch_ptr; - kgem->batch_idx = 0; - kgem->batch_obj = obj; - - kgem->max_batch_size = 1024; //ARRAY_SIZE(kgem->batch); - - kgem->half_cpu_cache_pages = (2048*1024) >> 13; - - list_init(&kgem->partial); - list_init(&kgem->requests); - list_init(&kgem->flushing); - list_init(&kgem->large); - for (i = 0; i < ARRAY_SIZE(kgem->inactive); i++) - list_init(&kgem->inactive[i]); - for (i = 0; i < ARRAY_SIZE(kgem->active); i++) { - for (j = 0; j < ARRAY_SIZE(kgem->active[i]); j++) - list_init(&kgem->active[i][j]); - } - for (i = 0; i < ARRAY_SIZE(kgem->vma); i++) { - for (j = 0; j < ARRAY_SIZE(kgem->vma[i].inactive); j++) - list_init(&kgem->vma[i].inactive[j]); - } - kgem->vma[MAP_GTT].count = -MAX_GTT_VMA_CACHE; - kgem->vma[MAP_CPU].count = -MAX_CPU_VMA_CACHE; - - kgem->next_request = __kgem_request_alloc(); - -//#if defined(USE_VMAP) && defined(I915_PARAM_HAS_VMAP) -// if (!DBG_NO_VMAP) -// kgem->has_vmap = gem_param(kgem, I915_PARAM_HAS_VMAP) > 0; -//#endif -// DBG(("%s: using vmap=%d\n", __FUNCTION__, kgem->has_vmap)); - - if (gen < 40) { -// if (!DBG_NO_RELAXED_FENCING) { -// kgem->has_relaxed_fencing = -// gem_param(kgem, I915_PARAM_HAS_RELAXED_FENCING) > 0; -// } - } else - kgem->has_relaxed_fencing = 1; - DBG(("%s: has relaxed fencing? %d\n", __FUNCTION__, - kgem->has_relaxed_fencing)); - - kgem->has_llc = (gen >= 60)?true:false; - kgem->has_cpu_bo = kgem->has_llc; - DBG(("%s: cpu bo enabled %d: llc? %d\n", __FUNCTION__, - kgem->has_cpu_bo, kgem->has_llc)); - - kgem->has_semaphores = false; -// if (gen >= 60 && semaphores_enabled()) -// kgem->has_semaphores = true; -// DBG(("%s: semaphores enabled? %d\n", __FUNCTION__, -// kgem->has_semaphores)); - - VG_CLEAR(aperture); - aperture.aper_size = 64*1024*1024; - i915_gem_get_aperture_ioctl(main_device, &aperture, NULL); - kgem->aperture_total = aperture.aper_size; - kgem->aperture_high = aperture.aper_size * 3/4; - kgem->aperture_low = aperture.aper_size * 1/3; - DBG(("%s: aperture low=%d [%d], high=%d [%d]\n", __FUNCTION__, - kgem->aperture_low, kgem->aperture_low / (1024*1024), - kgem->aperture_high, kgem->aperture_high / (1024*1024))); - - kgem->aperture_mappable = aperture.aper_size; - DBG(("%s: aperture mappable=%d [%d MiB]\n", __FUNCTION__, - kgem->aperture_mappable, kgem->aperture_mappable / (1024*1024))); - - kgem->partial_buffer_size = 64 * 1024; - while (kgem->partial_buffer_size < kgem->aperture_mappable >> 10) - kgem->partial_buffer_size *= 2; - DBG(("%s: partial buffer size=%d [%d KiB]\n", __FUNCTION__, - kgem->partial_buffer_size, kgem->partial_buffer_size / 1024)); - - kgem->min_alignment = 4; - if (gen < 60) - /* XXX workaround an issue where we appear to fail to - * disable dual-stream mode */ - kgem->min_alignment = 64; - - kgem->max_object_size = 2 * kgem->aperture_total / 3; - kgem->max_cpu_size = kgem->max_object_size; - kgem->max_gpu_size = kgem->max_object_size; - if (!kgem->has_llc) - kgem->max_gpu_size = MAX_CACHE_SIZE; - if (gen < 40) { - /* If we have to use fences for blitting, we have to make - * sure we can fit them into the aperture. - */ - kgem->max_gpu_size = kgem->aperture_mappable / 2; - if (kgem->max_gpu_size > kgem->aperture_low) - kgem->max_gpu_size = kgem->aperture_low; - } - if (kgem->max_gpu_size > kgem->max_cpu_size) - kgem->max_gpu_size = kgem->max_cpu_size; - - kgem->max_upload_tile_size = kgem->aperture_mappable / 2; - if (kgem->max_upload_tile_size > kgem->max_gpu_size / 2) - kgem->max_upload_tile_size = kgem->max_gpu_size / 2; - - kgem->max_copy_tile_size = (MAX_CACHE_SIZE + 1)/2; - if (kgem->max_copy_tile_size > kgem->max_gpu_size / 2) - kgem->max_copy_tile_size = kgem->max_gpu_size / 2; - - totalram = 1024*1024; //total_ram_size(); - if (totalram == 0) { - DBG(("%s: total ram size unknown, assuming maximum of total aperture\n", - __FUNCTION__)); - totalram = kgem->aperture_total; - } - if (kgem->max_object_size > totalram / 2) - kgem->max_object_size = totalram / 2; - if (kgem->max_cpu_size > totalram / 2) - kgem->max_cpu_size = totalram / 2; - if (kgem->max_gpu_size > totalram / 4) - kgem->max_gpu_size = totalram / 4; - - kgem->large_object_size = MAX_CACHE_SIZE; - if (kgem->large_object_size > kgem->max_gpu_size) - kgem->large_object_size = kgem->max_gpu_size; - - DBG(("%s: large object thresold=%d\n", - __FUNCTION__, kgem->large_object_size)); - DBG(("%s: max object size (gpu=%d, cpu=%d, tile upload=%d, copy=%d)\n", - __FUNCTION__, - kgem->max_gpu_size, kgem->max_cpu_size, - kgem->max_upload_tile_size, kgem->max_copy_tile_size)); - - /* Convert the aperture thresholds to pages */ - kgem->aperture_low /= PAGE_SIZE; - kgem->aperture_high /= PAGE_SIZE; - -// kgem->fence_max = gem_param(kgem, I915_PARAM_NUM_FENCES_AVAIL) - 2; -// if ((int)kgem->fence_max < 0) - kgem->fence_max = 5; /* minimum safe value for all hw */ - DBG(("%s: max fences=%d\n", __FUNCTION__, kgem->fence_max)); -err3: -err2: - return; -} - -static struct drm_i915_gem_exec_object2 * -kgem_add_handle(struct kgem *kgem, struct kgem_bo *bo) -{ - struct drm_i915_gem_exec_object2 *exec; - - DBG(("%s: handle=%d, index=%d\n", - __FUNCTION__, bo->handle, kgem->nexec)); - - assert(kgem->nexec < ARRAY_SIZE(kgem->exec)); - exec = memset(&kgem->exec[kgem->nexec++], 0, sizeof(*exec)); - exec->handle = bo->handle; - exec->offset = bo->presumed_offset; - - kgem->aperture += num_pages(bo); - - return exec; -} - -void _kgem_add_bo(struct kgem *kgem, struct kgem_bo *bo) -{ - bo->exec = kgem_add_handle(kgem, bo); - bo->rq = kgem->next_request; - - list_move(&bo->request, &kgem->next_request->buffers); - - /* XXX is it worth working around gcc here? */ - kgem->flush |= bo->flush; - kgem->sync |= bo->sync; - kgem->scanout |= bo->scanout; -} - -static uint32_t kgem_end_batch(struct kgem *kgem) -{ -// kgem->context_switch(kgem, KGEM_NONE); - - kgem->batch[kgem->nbatch++] = MI_BATCH_BUFFER_END; - if (kgem->nbatch & 1) - kgem->batch[kgem->nbatch++] = MI_NOOP; - - return kgem->nbatch; -} - -static void kgem_fixup_self_relocs(struct kgem *kgem, struct kgem_bo *bo) -{ - int n; - - for (n = 0; n < kgem->nreloc; n++) - { - if (kgem->reloc[n].target_handle == 0) - { - kgem->reloc[n].target_handle = bo->handle; - kgem->reloc[n].presumed_offset = bo->presumed_offset; - kgem->batch[kgem->reloc[n].offset/sizeof(kgem->batch[0])] = - kgem->reloc[n].delta + bo->presumed_offset; - - dbgprintf("fixup reloc %d pos %d handle %d delta %x \n", - n, kgem->reloc[n].offset/sizeof(kgem->batch[0]), - bo->handle, kgem->reloc[n].delta); - } - } -} - -static void kgem_bo_binding_free(struct kgem *kgem, struct kgem_bo *bo) -{ - struct kgem_bo_binding *b; - - b = bo->binding.next; - while (b) { - struct kgem_bo_binding *next = b->next; - free (b); - b = next; - } -} - -static void kgem_bo_release_map(struct kgem *kgem, struct kgem_bo *bo) -{ - int type = IS_CPU_MAP(bo->map); - - DBG(("%s: releasing %s vma for handle=%d, count=%d\n", - __FUNCTION__, type ? "CPU" : "GTT", - bo->handle, kgem->vma[type].count)); - - VG(if (type) VALGRIND_FREELIKE_BLOCK(CPU_MAP(bo->map), 0)); -// munmap(CPU_MAP(bo->map), bytes(bo)); - bo->map = NULL; - - if (!list_is_empty(&bo->vma)) { - list_del(&bo->vma); - kgem->vma[type].count--; - } -} - -static void kgem_bo_free(struct kgem *kgem, struct kgem_bo *bo) -{ - DBG(("%s: handle=%d\n", __FUNCTION__, bo->handle)); - assert(bo->refcnt == 0); - assert(bo->exec == NULL); - - kgem_bo_binding_free(kgem, bo); - - if (bo->map) - kgem_bo_release_map(kgem, bo); - assert(list_is_empty(&bo->vma)); - - list_del(&bo->list); - list_del(&bo->request); - gem_close(kgem->fd, bo->handle); - - if (!bo->io) { - *(struct kgem_bo **)bo = __kgem_freed_bo; - __kgem_freed_bo = bo; - } else - free(bo); -} - -inline static void kgem_bo_move_to_inactive(struct kgem *kgem, - struct kgem_bo *bo) -{ - assert(!kgem_busy(kgem, bo->handle)); - assert(!bo->proxy); - assert(!bo->io); - assert(!bo->needs_flush); - assert(bo->rq == NULL); - assert(bo->domain != DOMAIN_GPU); - - if (bucket(bo) >= NUM_CACHE_BUCKETS) { - kgem_bo_free(kgem, bo); - return; - } - - list_move(&bo->list, &kgem->inactive[bucket(bo)]); - if (bo->map) { - int type = IS_CPU_MAP(bo->map); - if (bucket(bo) >= NUM_CACHE_BUCKETS || - (!type && !kgem_bo_is_mappable(kgem, bo))) { - list_del(&bo->vma); -// munmap(CPU_MAP(bo->map), bytes(bo)); - bo->map = NULL; - } - if (bo->map) { - list_move(&bo->vma, &kgem->vma[type].inactive[bucket(bo)]); - kgem->vma[type].count++; - } - } - - kgem->need_expire = true; -} - -inline static void kgem_bo_remove_from_inactive(struct kgem *kgem, - struct kgem_bo *bo) -{ - list_del(&bo->list); - assert(bo->rq == NULL); - if (bo->map) { - assert(!list_is_empty(&bo->vma)); - list_del(&bo->vma); - kgem->vma[IS_CPU_MAP(bo->map)].count--; - } -} - -inline static void kgem_bo_remove_from_active(struct kgem *kgem, - struct kgem_bo *bo) -{ - list_del(&bo->list); - if (bo->rq == &_kgem_static_request) - list_del(&bo->request); - assert(list_is_empty(&bo->vma)); -} - -static void __kgem_bo_destroy(struct kgem *kgem, struct kgem_bo *bo) -{ - DBG(("%s: handle=%d\n", __FUNCTION__, bo->handle)); - - assert(list_is_empty(&bo->list)); - assert(bo->refcnt == 0); - - bo->binding.offset = 0; - - if (NO_CACHE) - goto destroy; - - if (bo->io) { - struct kgem_bo *base; - - base = malloc(sizeof(*base)); - if (base) { - DBG(("%s: transferring io handle=%d to bo\n", - __FUNCTION__, bo->handle)); - /* transfer the handle to a minimum bo */ - memcpy(base, bo, sizeof (*base)); - base->reusable = true; - base->io = false; - list_init(&base->list); - list_replace(&bo->request, &base->request); - list_replace(&bo->vma, &base->vma); - free(bo); - bo = base; - } - } - - if (!bo->reusable) { - DBG(("%s: handle=%d, not reusable\n", - __FUNCTION__, bo->handle)); - goto destroy; - } - - if (!kgem->has_llc && IS_CPU_MAP(bo->map) && bo->domain != DOMAIN_CPU) - kgem_bo_release_map(kgem, bo); - - assert(list_is_empty(&bo->vma)); - assert(list_is_empty(&bo->list)); - assert(bo->vmap == false && bo->sync == false); - assert(bo->io == false); - - bo->scanout = bo->flush = false; - if (bo->rq) { - struct list *cache; - - DBG(("%s: handle=%d -> active\n", __FUNCTION__, bo->handle)); - if (bucket(bo) < NUM_CACHE_BUCKETS) - cache = &kgem->active[bucket(bo)][bo->tiling]; - else - cache = &kgem->large; - list_add(&bo->list, cache); - return; - } - - assert(bo->exec == NULL); - assert(list_is_empty(&bo->request)); -/* - if (bo->needs_flush) { - if ((bo->needs_flush = kgem_busy(kgem, bo->handle))) { - struct list *cache; - - DBG(("%s: handle=%d -> flushing\n", - __FUNCTION__, bo->handle)); - - list_add(&bo->request, &kgem->flushing); - if (bucket(bo) < NUM_CACHE_BUCKETS) - cache = &kgem->active[bucket(bo)][bo->tiling]; - else - cache = &kgem->large; - list_add(&bo->list, cache); - bo->rq = &_kgem_static_request; - return; - } - - bo->domain = DOMAIN_NONE; - } -*/ - if (!IS_CPU_MAP(bo->map)) { - if (!kgem_bo_set_purgeable(kgem, bo)) - goto destroy; - - if (!kgem->has_llc && bo->domain == DOMAIN_CPU) - goto destroy; - - DBG(("%s: handle=%d, purged\n", - __FUNCTION__, bo->handle)); - } - - DBG(("%s: handle=%d -> inactive\n", __FUNCTION__, bo->handle)); - kgem_bo_move_to_inactive(kgem, bo); - return; - -destroy: - if (!bo->exec) - kgem_bo_free(kgem, bo); -} - - - - - -bool kgem_retire(struct kgem *kgem) -{ - struct kgem_bo *bo, *next; - bool retired = false; - - DBG(("%s\n", __FUNCTION__)); - - list_for_each_entry_safe(bo, next, &kgem->flushing, request) { - assert(bo->refcnt == 0); - assert(bo->rq == &_kgem_static_request); - assert(bo->exec == NULL); - -// if (kgem_busy(kgem, bo->handle)) -// break; - - DBG(("%s: moving %d from flush to inactive\n", - __FUNCTION__, bo->handle)); - if (kgem_bo_set_purgeable(kgem, bo)) { - bo->needs_flush = false; - bo->domain = DOMAIN_NONE; - bo->rq = NULL; - list_del(&bo->request); - kgem_bo_move_to_inactive(kgem, bo); - } else - kgem_bo_free(kgem, bo); - - retired = true; - } - - while (!list_is_empty(&kgem->requests)) { - struct kgem_request *rq; - - rq = list_first_entry(&kgem->requests, - struct kgem_request, - list); -// if (kgem_busy(kgem, rq->bo->handle)) -// break; - - DBG(("%s: request %d complete\n", - __FUNCTION__, rq->bo->handle)); - - while (!list_is_empty(&rq->buffers)) { - bo = list_first_entry(&rq->buffers, - struct kgem_bo, - request); - - assert(bo->rq == rq); - assert(bo->exec == NULL); - assert(bo->domain == DOMAIN_GPU); - - list_del(&bo->request); - bo->rq = NULL; - -// if (bo->needs_flush) -// bo->needs_flush = kgem_busy(kgem, bo->handle); - if (!bo->needs_flush) - bo->domain = DOMAIN_NONE; - - if (bo->refcnt) - continue; - - if (!bo->reusable) { - DBG(("%s: closing %d\n", - __FUNCTION__, bo->handle)); - kgem_bo_free(kgem, bo); - continue; - } - - if (bo->needs_flush) { - DBG(("%s: moving %d to flushing\n", - __FUNCTION__, bo->handle)); - list_add(&bo->request, &kgem->flushing); - bo->rq = &_kgem_static_request; - } else if (kgem_bo_set_purgeable(kgem, bo)) { - DBG(("%s: moving %d to inactive\n", - __FUNCTION__, bo->handle)); - kgem_bo_move_to_inactive(kgem, bo); - retired = true; - } else { - DBG(("%s: closing %d\n", - __FUNCTION__, bo->handle)); - kgem_bo_free(kgem, bo); - } - } - - rq->bo->refcnt--; - assert(rq->bo->refcnt == 0); - assert(rq->bo->rq == NULL); - assert(list_is_empty(&rq->bo->request)); - if (kgem_bo_set_purgeable(kgem, rq->bo)) { - kgem_bo_move_to_inactive(kgem, rq->bo); - retired = true; - } else { - DBG(("%s: closing %d\n", - __FUNCTION__, rq->bo->handle)); - kgem_bo_free(kgem, rq->bo); - } - - list_del(&rq->list); - free(rq); - } - - kgem->need_retire = !list_is_empty(&kgem->requests); - DBG(("%s -- need_retire=%d\n", __FUNCTION__, kgem->need_retire)); - - kgem->retire(kgem); - - return retired; -} - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -static int kgem_batch_write(struct kgem *kgem, uint32_t handle, uint32_t size) -{ - int ret; - - assert(!kgem_busy(kgem, handle)); - - /* If there is no surface data, just upload the batch */ - if (kgem->surface == kgem->max_batch_size) - return gem_write(kgem->fd, handle, - 0, sizeof(uint32_t)*kgem->nbatch, - kgem->batch); - - /* Are the batch pages conjoint with the surface pages? */ - if (kgem->surface < kgem->nbatch + PAGE_SIZE/4) { - assert(size == sizeof(kgem->batch)); - return gem_write(kgem->fd, handle, - 0, sizeof(kgem->batch), - kgem->batch); - } - - /* Disjoint surface/batch, upload separately */ - ret = gem_write(kgem->fd, handle, - 0, sizeof(uint32_t)*kgem->nbatch, - kgem->batch); - if (ret) - return ret; - - assert(kgem->nbatch*sizeof(uint32_t) <= - sizeof(uint32_t)*kgem->surface - (sizeof(kgem->batch)-size)); - return __gem_write(kgem->fd, handle, - sizeof(uint32_t)*kgem->surface - (sizeof(kgem->batch)-size), - sizeof(kgem->batch) - sizeof(uint32_t)*kgem->surface, - kgem->batch + kgem->surface); -} - -void kgem_reset(struct kgem *kgem) -{ -// ENTER(); - - kgem->nfence = 0; - kgem->nexec = 0; - kgem->nreloc = 0; - kgem->aperture = 0; - kgem->aperture_fenced = 0; - kgem->nbatch = 0; - kgem->surface = kgem->max_batch_size; - kgem->mode = KGEM_NONE; - kgem->flush = 0; - kgem->scanout = 0; - - kgem->batch = kgem->batch_ptr+1024*kgem->batch_idx; - - kgem->next_request = __kgem_request_alloc(); - - kgem_sna_reset(kgem); -// dbgprintf("surface %x\n", kgem->surface); -// LEAVE(); -} - -static int compact_batch_surface(struct kgem *kgem) -{ - int size, shrink, n; - - /* See if we can pack the contents into one or two pages */ - size = kgem->max_batch_size - kgem->surface + kgem->nbatch; - if (size > 2048) - return sizeof(kgem->batch); - else if (size > 1024) - size = 8192, shrink = 2*4096; - else - size = 4096, shrink = 3*4096; - - - for (n = 0; n < kgem->nreloc; n++) { - if (kgem->reloc[n].read_domains == I915_GEM_DOMAIN_INSTRUCTION && - kgem->reloc[n].target_handle == 0) - kgem->reloc[n].delta -= shrink; - - if (kgem->reloc[n].offset >= size) - kgem->reloc[n].offset -= shrink; - } - - return size; -} - -int exec_batch(struct drm_device *dev, struct intel_ring_buffer *ring, - batchbuffer_t *exec); - -void _kgem_submit(struct kgem *kgem, batchbuffer_t *exb) -{ - struct kgem_request *rq; - uint32_t batch_end; - int size; - - assert(!DBG_NO_HW); - - assert(kgem->nbatch); - assert(kgem->nbatch <= KGEM_BATCH_SIZE(kgem)); - assert(kgem->nbatch <= kgem->surface); - - batch_end = kgem_end_batch(kgem); - kgem_sna_flush(kgem); - - DBG(("batch[%d/%d]: %d %d %d, nreloc=%d, nexec=%d, nfence=%d, aperture=%d\n", - kgem->mode, kgem->ring, batch_end, kgem->nbatch, kgem->surface, - kgem->nreloc, kgem->nexec, kgem->nfence, kgem->aperture)); - - assert(kgem->nbatch <= kgem->max_batch_size); - assert(kgem->nbatch <= kgem->surface); - assert(kgem->nreloc <= ARRAY_SIZE(kgem->reloc)); - assert(kgem->nexec < ARRAY_SIZE(kgem->exec)); - assert(kgem->nfence <= kgem->fence_max); - -// kgem_finish_partials(kgem); - - rq = kgem->next_request; -// if (kgem->surface != kgem->max_batch_size) -// size = compact_batch_surface(kgem); -// else - size = kgem->nbatch * sizeof(kgem->batch[0]); -#if 0 - { - int i; - - dbgprintf("\nDump batch\n\n"); - - for(i=0; i < kgem->nbatch; i++) - { - dbgprintf("\t0x%08x,\t/* %d */\n", - kgem->batch[i], i); - } - dbgprintf("\ndone\n"); - }; -#endif - - exb->batch = kgem->batch_obj; - exb->exec_start = kgem->batch_obj->gtt_offset+kgem->batch_idx*4096; - exb->exec_len = sizeof(uint32_t)*kgem->nbatch; - - exec_batch(main_device, NULL, exb); - -// if (kgem->wedged) -// kgem_cleanup(kgem); - - kgem->batch_idx++; - kgem->batch_idx&= 3; - - kgem->flush_now = kgem->scanout; - kgem_reset(kgem); - - assert(kgem->next_request != NULL); -} - -static struct kgem_bo * -search_linear_cache(struct kgem *kgem, unsigned int num_pages, unsigned flags) -{ - struct kgem_bo *bo, *first = NULL; - bool use_active = (flags & CREATE_INACTIVE) == 0; - struct list_head *cache; - - if (num_pages >= MAX_CACHE_SIZE / PAGE_SIZE) - return NULL; - - if (!use_active && - list_is_empty(inactive(kgem, num_pages)) && - !list_is_empty(active(kgem, num_pages, I915_TILING_NONE)) && - !kgem_retire(kgem)) - return NULL; - - if (!use_active && flags & (CREATE_CPU_MAP | CREATE_GTT_MAP)) { - int for_cpu = !!(flags & CREATE_CPU_MAP); - cache = &kgem->vma[for_cpu].inactive[cache_bucket(num_pages)]; - list_for_each_entry(bo, cache, vma) { - assert(IS_CPU_MAP(bo->map) == for_cpu); - assert(bucket(bo) == cache_bucket(num_pages)); - - if (num_pages > num_pages(bo)) { - DBG(("inactive too small: %d < %d\n", - num_pages(bo), num_pages)); - continue; - } - - if (bo->purged && !kgem_bo_clear_purgeable(kgem, bo)) { - kgem_bo_free(kgem, bo); - break; - } - -// if (I915_TILING_NONE != bo->tiling && -// gem_set_tiling(kgem->fd, bo->handle, -// I915_TILING_NONE, 0) != I915_TILING_NONE) -// continue; - - kgem_bo_remove_from_inactive(kgem, bo); - - bo->tiling = I915_TILING_NONE; - bo->pitch = 0; - bo->delta = 0; - DBG((" %s: found handle=%d (num_pages=%d) in linear vma cache\n", - __FUNCTION__, bo->handle, num_pages(bo))); - assert(use_active || bo->domain != DOMAIN_GPU); - assert(!bo->needs_flush); - //assert(!kgem_busy(kgem, bo->handle)); - return bo; - } - } - - cache = use_active ? active(kgem, num_pages, I915_TILING_NONE) : inactive(kgem, num_pages); - list_for_each_entry(bo, cache, list) { - assert(bo->refcnt == 0); - assert(bo->reusable); - assert(!!bo->rq == !!use_active); - - if (num_pages > num_pages(bo)) - continue; - - if (use_active && bo->tiling != I915_TILING_NONE) - continue; - - if (bo->purged && !kgem_bo_clear_purgeable(kgem, bo)) { - kgem_bo_free(kgem, bo); - break; - } -/* - if (I915_TILING_NONE != bo->tiling) { - if (use_active) - continue; - - if (gem_set_tiling(kgem->fd, bo->handle, - I915_TILING_NONE, 0) != I915_TILING_NONE) - continue; - - bo->tiling = I915_TILING_NONE; - } -*/ - if (bo->map) { - if (flags & (CREATE_CPU_MAP | CREATE_GTT_MAP)) { - int for_cpu = !!(flags & CREATE_CPU_MAP); - if (IS_CPU_MAP(bo->map) != for_cpu) { - if (first != NULL) - break; - - first = bo; - continue; - } - } else { - if (first != NULL) - break; - - first = bo; - continue; - } - } else { - if (flags & (CREATE_CPU_MAP | CREATE_GTT_MAP)) { - if (first != NULL) - break; - - first = bo; - continue; - } - } - - if (use_active) - kgem_bo_remove_from_active(kgem, bo); - else - kgem_bo_remove_from_inactive(kgem, bo); - - assert(bo->tiling == I915_TILING_NONE); - bo->pitch = 0; - bo->delta = 0; - DBG((" %s: found handle=%d (num_pages=%d) in linear %s cache\n", - __FUNCTION__, bo->handle, num_pages(bo), - use_active ? "active" : "inactive")); - assert(use_active || bo->domain != DOMAIN_GPU); - assert(!bo->needs_flush || use_active); - //assert(use_active || !kgem_busy(kgem, bo->handle)); - return bo; - } - - if (first) { - assert(first->tiling == I915_TILING_NONE); - - if (use_active) - kgem_bo_remove_from_active(kgem, first); - else - kgem_bo_remove_from_inactive(kgem, first); - - first->pitch = 0; - first->delta = 0; - DBG((" %s: found handle=%d (num_pages=%d) in linear %s cache\n", - __FUNCTION__, first->handle, num_pages(first), - use_active ? "active" : "inactive")); - assert(use_active || first->domain != DOMAIN_GPU); - assert(!first->needs_flush || use_active); - //assert(use_active || !kgem_busy(kgem, first->handle)); - return first; - } - - return NULL; -} - - - - - - -struct kgem_bo *kgem_create_linear(struct kgem *kgem, int size) -{ - struct kgem_bo *bo; - uint32_t handle; - - DBG(("%s(%d)\n", __FUNCTION__, size)); - - size = (size + PAGE_SIZE - 1) / PAGE_SIZE; - bo = search_linear_cache(kgem, size, CREATE_INACTIVE); - if (bo) - return kgem_bo_reference(bo); - - handle = gem_create(kgem->fd, size); - if (handle == 0) - return NULL; - - DBG(("%s: new handle=%x\n", __FUNCTION__, handle)); - bo = __kgem_bo_alloc(handle, size); - if (bo == NULL) { - gem_close(kgem->fd, handle); - return NULL; - } - struct drm_i915_gem_object *obj; - obj = (void*)handle; - - bo->gaddr = obj->gtt_offset; - return bo; -} - - - - - - -inline int kgem_bo_fenced_size(struct kgem *kgem, struct kgem_bo *bo) -{ - unsigned int size; - - assert(bo->tiling); - assert(kgem->gen < 40); - - if (kgem->gen < 30) - size = 512 * 1024; - else - size = 1024 * 1024; - while (size < bytes(bo)) - size *= 2; - - return size; -} - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void _kgem_bo_destroy(struct kgem *kgem, struct kgem_bo *bo) -{ -// if (bo->proxy) { -// assert(bo->map == NULL); -// if (bo->io && bo->exec == NULL) -// _kgem_bo_delete_partial(kgem, bo); -// kgem_bo_unref(kgem, bo->proxy); -// kgem_bo_binding_free(kgem, bo); -// _list_del(&bo->request); -// free(bo); -// return; -// } - -// if (bo->vmap) -// kgem_bo_sync__cpu(kgem, bo); - - __kgem_bo_destroy(kgem, bo); -} - -void __kgem_flush(struct kgem *kgem, struct kgem_bo *bo) -{ - /* The kernel will emit a flush *and* update its own flushing lists. */ -// kgem_busy(kgem, bo->handle); -} - -bool kgem_check_bo(struct kgem *kgem, ...) -{ - va_list ap; - struct kgem_bo *bo; - int num_exec = 0; - int num_pages = 0; - - va_start(ap, kgem); - while ((bo = va_arg(ap, struct kgem_bo *))) { - if (bo->exec) - continue; - - if (bo->proxy) { - bo = bo->proxy; - if (bo->exec) - continue; - } - num_pages += num_pages(bo); - num_exec++; - } - va_end(ap); - - if (!num_pages) - return true; - - if (kgem->aperture > kgem->aperture_low) - return false; - - if (num_pages + kgem->aperture > kgem->aperture_high) - return false; - - if (kgem->nexec + num_exec >= KGEM_EXEC_SIZE(kgem)) - return false; - - return true; -} - -/* -bool kgem_check_bo_fenced(struct kgem *kgem, ...) -{ - va_list ap; - struct kgem_bo *bo; - int num_fence = 0; - int num_exec = 0; - int num_pages = 0; - int fenced_size = 0; - - va_start(ap, kgem); - while ((bo = va_arg(ap, struct kgem_bo *))) { - if (bo->proxy) - bo = bo->proxy; - if (bo->exec) { - if (kgem->gen >= 40 || bo->tiling == I915_TILING_NONE) - continue; - - if ((bo->exec->flags & EXEC_OBJECT_NEEDS_FENCE) == 0) { - fenced_size += kgem_bo_fenced_size(kgem, bo); - num_fence++; - } - - continue; - } - - num_pages += num_pages(bo); - num_exec++; - if (kgem->gen < 40 && bo->tiling) { - fenced_size += kgem_bo_fenced_size(kgem, bo); - num_fence++; - } - } - va_end(ap); - - if (fenced_size + kgem->aperture_fenced > kgem->aperture_mappable) - return false; - - if (kgem->nfence + num_fence > kgem->fence_max) - return false; - - if (!num_pages) - return true; - - if (kgem->aperture > kgem->aperture_low) - return false; - - if (num_pages + kgem->aperture > kgem->aperture_high) - return false; - - if (kgem->nexec + num_exec >= KGEM_EXEC_SIZE(kgem)) - return false; - - return true; -} -*/ -#if 0 -uint32_t kgem_add_reloc(struct kgem *kgem, - uint32_t pos, - struct kgem_bo *bo, - uint32_t read_write_domain, - uint32_t delta) -{ - int index; - - DBG(("%s: handle=%d, pos=%d, delta=%d, domains=%08x\n", - __FUNCTION__, bo ? bo->handle : 0, pos, delta, read_write_domain)); - - assert((read_write_domain & 0x7fff) == 0 || bo != NULL); - - index = kgem->nreloc++; - assert(index < ARRAY_SIZE(kgem->reloc)); - kgem->reloc[index].offset = pos * sizeof(kgem->batch[0]); - if (bo) { - assert(bo->refcnt); - assert(!bo->purged); - - delta += bo->delta; - if (bo->proxy) { - DBG(("%s: adding proxy for handle=%d\n", - __FUNCTION__, bo->handle)); - assert(bo->handle == bo->proxy->handle); - /* need to release the cache upon batch submit */ - list_move(&bo->request, &kgem->next_request->buffers); - bo->exec = &_kgem_dummy_exec; - bo = bo->proxy; - } - - assert(!bo->purged); - -// if (bo->exec == NULL) -// _kgem_add_bo(kgem, bo); - -// if (kgem->gen < 40 && read_write_domain & KGEM_RELOC_FENCED) { -// if (bo->tiling && -// (bo->exec->flags & EXEC_OBJECT_NEEDS_FENCE) == 0) { -// assert(kgem->nfence < kgem->fence_max); -// kgem->aperture_fenced += -// kgem_bo_fenced_size(kgem, bo); -// kgem->nfence++; -// } -// bo->exec->flags |= EXEC_OBJECT_NEEDS_FENCE; -// } - - kgem->reloc[index].delta = delta; - kgem->reloc[index].target_handle = bo->handle; - kgem->reloc[index].presumed_offset = bo->presumed_offset; - - if (read_write_domain & 0x7fff) { - DBG(("%s: marking handle=%d dirty\n", - __FUNCTION__, bo->handle)); - bo->needs_flush = bo->dirty = true; - } - - delta += bo->presumed_offset; - } else { - kgem->reloc[index].delta = delta; - kgem->reloc[index].target_handle = 0; - kgem->reloc[index].presumed_offset = 0; - } - kgem->reloc[index].read_domains = read_write_domain >> 16; - kgem->reloc[index].write_domain = read_write_domain & 0x7fff; - - return delta; -} -#endif - - - - - - - - - -void *kgem_bo_map(struct kgem *kgem, struct kgem_bo *bo) -{ - void *ptr; - - DBG(("%s: handle=%d, offset=%d, tiling=%d, map=%p, domain=%d\n", __FUNCTION__, - bo->handle, bo->presumed_offset, bo->tiling, bo->map, bo->domain)); - - assert(!bo->purged); - assert(bo->exec == NULL); - assert(list_is_empty(&bo->list)); - -// if (bo->tiling == I915_TILING_NONE && -// (kgem->has_llc || bo->domain == bo->presumed_offset)) { - DBG(("%s: converting request for GTT map into CPU map\n", - __FUNCTION__)); - ptr = kgem_bo_map__cpu(kgem, bo); -// kgem_bo_sync__cpu(kgem, bo); - return ptr; -// } - -#if 0 - - if (IS_CPU_MAP(bo->map)) - kgem_bo_release_map(kgem, bo); - - ptr = bo->map; - if (ptr == NULL) { - assert(bytes(bo) <= kgem->aperture_mappable / 4); - - kgem_trim_vma_cache(kgem, MAP_GTT, bucket(bo)); - - ptr = gem_mmap(kgem->fd, bo->handle, bytes(bo), - PROT_READ | PROT_WRITE); - if (ptr == NULL) - return NULL; - - /* Cache this mapping to avoid the overhead of an - * excruciatingly slow GTT pagefault. This is more an - * issue with compositing managers which need to frequently - * flush CPU damage to their GPU bo. - */ - bo->map = ptr; - DBG(("%s: caching GTT vma for %d\n", __FUNCTION__, bo->handle)); - } - - if (bo->domain != DOMAIN_GTT) { - struct drm_i915_gem_set_domain set_domain; - - DBG(("%s: sync: needs_flush? %d, domain? %d\n", __FUNCTION__, - bo->needs_flush, bo->domain)); - - /* XXX use PROT_READ to avoid the write flush? */ - - VG_CLEAR(set_domain); - set_domain.handle = bo->handle; - set_domain.read_domains = I915_GEM_DOMAIN_GTT; - set_domain.write_domain = I915_GEM_DOMAIN_GTT; - drmIoctl(kgem->fd, DRM_IOCTL_I915_GEM_SET_DOMAIN, &set_domain); - - kgem_bo_retire(kgem, bo); - bo->domain = DOMAIN_GTT; - } -#endif - - return ptr; -} - -void *kgem_bo_map__cpu(struct kgem *kgem, struct kgem_bo *bo) -{ -// struct drm_i915_gem_mmap mmap_arg; - - DBG(("%s(handle=%d, size=%d)\n", __FUNCTION__, bo->handle, bytes(bo))); - assert(!bo->purged); - assert(list_is_empty(&bo->list)); - - if (IS_CPU_MAP(bo->map)) - return CPU_MAP(bo->map); - - struct drm_i915_gem_object *obj = (void*)bo->handle; - u8 *dst; - int ret; - - if(obj->pin_count == 0) - { - ret = i915_gem_object_pin(obj, 4096, true); - if (ret) - return NULL; - }; - - dst = drm_intel_bo_map(obj, true); - DBG(("%s: caching CPU vma for %d\n", __FUNCTION__, bo->handle)); - bo->map = MAKE_CPU_MAP(dst); - return (void *)dst; - - -#if 0 - if (bo->map) - kgem_bo_release_map(kgem, bo); - - kgem_trim_vma_cache(kgem, MAP_CPU, bucket(bo)); - - VG_CLEAR(mmap_arg); - mmap_arg.handle = bo->handle; - mmap_arg.offset = 0; - mmap_arg.size = bytes(bo); - if (drmIoctl(kgem->fd, DRM_IOCTL_I915_GEM_MMAP, &mmap_arg)) { - ErrorF("%s: failed to mmap %d, %d bytes, into CPU domain\n", - __FUNCTION__, bo->handle, bytes(bo)); - return NULL; - } - - VG(VALGRIND_MALLOCLIKE_BLOCK(mmap_arg.addr_ptr, bytes(bo), 0, 1)); -#endif - -} - - - - - - - - - - - - - - - - - - - -void kgem_clear_dirty(struct kgem *kgem) -{ - struct kgem_request *rq = kgem->next_request; - struct kgem_bo *bo; - - list_for_each_entry(bo, &rq->buffers, request) - bo->dirty = false; -} - -struct kgem_bo *kgem_create_proxy(struct kgem_bo *target, - int offset, int length) -{ - struct kgem_bo *bo; - - DBG(("%s: target handle=%d, offset=%d, length=%d, io=%d\n", - __FUNCTION__, target->handle, offset, length, target->io)); - - bo = __kgem_bo_alloc(target->handle, length); - if (bo == NULL) - return NULL; - - bo->reusable = false; - bo->size.bytes = length; - - bo->io = target->io; - bo->dirty = target->dirty; - bo->tiling = target->tiling; - bo->pitch = target->pitch; - - if (target->proxy) { - offset += target->delta; - target = target->proxy; - } - bo->proxy = kgem_bo_reference(target); - bo->delta = offset; - bo->gaddr = offset + target->gaddr; - return bo; -} - - - - - - - - - - -uint32_t kgem_bo_get_binding(struct kgem_bo *bo, uint32_t format) -{ - struct kgem_bo_binding *b; - - for (b = &bo->binding; b && b->offset; b = b->next) - if (format == b->format) - return b->offset; - - return 0; -} - -void kgem_bo_set_binding(struct kgem_bo *bo, uint32_t format, uint16_t offset) -{ - struct kgem_bo_binding *b; - - for (b = &bo->binding; b; b = b->next) { - if (b->offset) - continue; - - b->offset = offset; - b->format = format; - - if (b->next) - b->next->offset = 0; - - return; - } - - b = malloc(sizeof(*b)); - if (b) { - b->next = bo->binding.next; - b->format = format; - b->offset = offset; - bo->binding.next = b; - } -} - - -struct kgem_bo *create_bo(bitmap_t *bitmap) -{ - struct kgem_bo *bo; - - bo = __kgem_bo_alloc(bitmap->obj, 1024*768*4/4096); - bo->gaddr = bitmap->gaddr; - bo->pitch = bitmap->pitch; - bo->tiling = 0; - return bo; - -}; diff --git a/drivers/video/drm/i915/sna/kgem.h b/drivers/video/drm/i915/sna/kgem.h deleted file mode 100644 index 1751048d41..0000000000 --- a/drivers/video/drm/i915/sna/kgem.h +++ /dev/null @@ -1,538 +0,0 @@ -/* - * Copyright (c) 2011 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: - * Chris Wilson - * - */ - -#ifndef KGEM_H -#define KGEM_H - -#include "compiler.h" -#include -//#include - -#include - - -#if DEBUG_KGEM -#define DBG_HDR(x) ErrorF x -#else -#define DBG_HDR(x) -#endif - -struct kgem_bo { - struct kgem_bo *proxy; - - struct list_head list; - struct list_head request; - struct list_head vma; - - void *map; - uint32_t gaddr; - -#define IS_CPU_MAP(ptr) ((uintptr_t)(ptr) & 1) -#define IS_GTT_MAP(ptr) (ptr && ((uintptr_t)(ptr) & 1) == 0) - struct kgem_request *rq; - struct drm_i915_gem_exec_object2 *exec; - - struct kgem_bo_binding { - struct kgem_bo_binding *next; - uint32_t format; - uint16_t offset; - } binding; - - uint32_t unique_id; - uint32_t refcnt; - uint32_t handle; - uint32_t presumed_offset; - uint32_t delta; - union { - struct { - uint32_t count:27; - uint32_t bucket:5; -#define NUM_CACHE_BUCKETS 16 -#define MAX_CACHE_SIZE (1 << (NUM_CACHE_BUCKETS+12)) - } pages; - uint32_t bytes; - } size; - uint32_t pitch : 18; /* max 128k */ - uint32_t tiling : 2; - uint32_t reusable : 1; - uint32_t dirty : 1; - uint32_t domain : 2; - uint32_t needs_flush : 1; - uint32_t vmap : 1; - uint32_t io : 1; - uint32_t flush : 1; - uint32_t scanout : 1; - uint32_t sync : 1; - uint32_t purged : 1; -}; -#define DOMAIN_NONE 0 -#define DOMAIN_CPU 1 -#define DOMAIN_GTT 2 -#define DOMAIN_GPU 3 - -struct kgem_request { - struct list_head list; - struct kgem_bo *bo; - struct list_head buffers; -}; - -enum { - MAP_GTT = 0, - MAP_CPU, - NUM_MAP_TYPES, -}; - -struct kgem { - int fd; - int wedged; - int gen; - - uint32_t unique_id; - - enum kgem_mode { - /* order matches I915_EXEC_RING ordering */ - KGEM_NONE = 0, - KGEM_RENDER, - KGEM_BSD, - KGEM_BLT, - } mode, ring; - - struct list_head flushing; - struct list_head large; - struct list_head active[NUM_CACHE_BUCKETS][3]; - struct list_head inactive[NUM_CACHE_BUCKETS]; - struct list_head partial; - struct list_head requests; - struct kgem_request *next_request; - - struct { - struct list_head inactive[NUM_CACHE_BUCKETS]; - int16_t count; - } vma[NUM_MAP_TYPES]; - - uint16_t nbatch; - uint16_t surface; - uint16_t nexec; - uint16_t nreloc; - uint16_t nfence; - uint16_t max_batch_size; - - uint32_t flush:1; - uint32_t sync:1; - uint32_t need_expire:1; - uint32_t need_purge:1; - uint32_t need_retire:1; - uint32_t scanout:1; - uint32_t flush_now:1; - uint32_t busy:1; - - uint32_t has_vmap :1; - uint32_t has_relaxed_fencing :1; - uint32_t has_semaphores :1; - uint32_t has_llc :1; - uint32_t has_cpu_bo :1; - - uint16_t fence_max; - uint16_t half_cpu_cache_pages; - uint32_t aperture_total, aperture_high, aperture_low, aperture_mappable; - uint32_t aperture, aperture_fenced; - uint32_t min_alignment; - uint32_t max_upload_tile_size, max_copy_tile_size; - uint32_t max_gpu_size, max_cpu_size; - uint32_t large_object_size, max_object_size; - uint32_t partial_buffer_size; - -// void (*context_switch)(struct kgem *kgem, int new_mode); - void (*retire)(struct kgem *kgem); - - uint32_t *batch; - uint32_t *batch_ptr; - int batch_idx; - struct drm_i915_gem_object *batch_obj; - - struct drm_i915_gem_exec_object2 exec[256]; - struct drm_i915_gem_relocation_entry reloc[384]; -}; - -typedef struct -{ - struct drm_i915_gem_object *batch; - struct list_head objects; - u32 exec_start; - u32 exec_len; - -}batchbuffer_t; - -#define KGEM_BATCH_RESERVED 1 -#define KGEM_RELOC_RESERVED 4 -#define KGEM_EXEC_RESERVED 1 - -#define KGEM_BATCH_SIZE(K) ((K)->max_batch_size-KGEM_BATCH_RESERVED) -#define KGEM_EXEC_SIZE(K) (int)(ARRAY_SIZE((K)->exec)-KGEM_EXEC_RESERVED) -#define KGEM_RELOC_SIZE(K) (int)(ARRAY_SIZE((K)->reloc)-KGEM_RELOC_RESERVED) - -void kgem_init(struct kgem *kgem, int gen); -void kgem_reset(struct kgem *kgem); - -struct kgem_bo *kgem_create_map(struct kgem *kgem, - void *ptr, uint32_t size, - bool read_only); - -struct kgem_bo *kgem_create_for_name(struct kgem *kgem, uint32_t name); - -struct kgem_bo *kgem_create_linear(struct kgem *kgem, int size); -struct kgem_bo *kgem_create_proxy(struct kgem_bo *target, - int offset, int length); - -//struct kgem_bo *kgem_upload_source_image(struct kgem *kgem, -// const void *data, -// BoxPtr box, -// int stride, int bpp); - -int kgem_choose_tiling(struct kgem *kgem, - int tiling, int width, int height, int bpp); -unsigned kgem_can_create_2d(struct kgem *kgem, int width, int height, int depth); -#define KGEM_CAN_CREATE_GPU 0x1 -#define KGEM_CAN_CREATE_CPU 0x2 -#define KGEM_CAN_CREATE_LARGE 0x4 - -struct kgem_bo * -kgem_replace_bo(struct kgem *kgem, - struct kgem_bo *src, - uint32_t width, - uint32_t height, - uint32_t pitch, - uint32_t bpp); -enum { - CREATE_EXACT = 0x1, - CREATE_INACTIVE = 0x2, - CREATE_CPU_MAP = 0x4, - CREATE_GTT_MAP = 0x8, - CREATE_SCANOUT = 0x10, -}; -struct kgem_bo *kgem_create_2d(struct kgem *kgem, - int width, - int height, - int bpp, - int tiling, - uint32_t flags); - -uint32_t kgem_bo_get_binding(struct kgem_bo *bo, uint32_t format); -void kgem_bo_set_binding(struct kgem_bo *bo, uint32_t format, uint16_t offset); - -bool kgem_retire(struct kgem *kgem); - -void _kgem_submit(struct kgem *kgem, batchbuffer_t *exb); -//static inline void kgem_submit(struct kgem *kgem) -//{ -// if (kgem->nbatch) -// _kgem_submit(kgem); -//} - -/* -static inline void kgem_bo_submit(struct kgem *kgem, struct kgem_bo *bo) -{ - if (bo->exec) - _kgem_submit(kgem); -} - -void __kgem_flush(struct kgem *kgem, struct kgem_bo *bo); -static inline void kgem_bo_flush(struct kgem *kgem, struct kgem_bo *bo) -{ - kgem_bo_submit(kgem, bo); - - if (!bo->needs_flush) - return; - - __kgem_flush(kgem, bo); - - bo->needs_flush = false; -} -*/ -static inline struct kgem_bo *kgem_bo_reference(struct kgem_bo *bo) -{ - bo->refcnt++; - return bo; -} - -void _kgem_bo_destroy(struct kgem *kgem, struct kgem_bo *bo); -static inline void kgem_bo_destroy(struct kgem *kgem, struct kgem_bo *bo) -{ - assert(bo->refcnt); - if (--bo->refcnt == 0) - _kgem_bo_destroy(kgem, bo); -} - -void kgem_clear_dirty(struct kgem *kgem); - -static inline void kgem_set_mode(struct kgem *kgem, enum kgem_mode mode) -{ - assert(!kgem->wedged); - -#if DEBUG_FLUSH_BATCH - kgem_submit(kgem); -#endif - - if (kgem->mode == mode) - return; - -// kgem->context_switch(kgem, mode); - kgem->mode = mode; -} - - -static inline void _kgem_set_mode(struct kgem *kgem, enum kgem_mode mode) -{ - assert(kgem->mode == KGEM_NONE); -// kgem->context_switch(kgem, mode); - kgem->mode = mode; -} - -static inline bool kgem_check_batch(struct kgem *kgem, int num_dwords) -{ - return likely(kgem->nbatch + num_dwords + KGEM_BATCH_RESERVED <= kgem->surface); -} - -static inline bool kgem_check_reloc(struct kgem *kgem, int n) -{ - return likely(kgem->nreloc + n <= KGEM_RELOC_SIZE(kgem)); -} - -static inline bool kgem_check_exec(struct kgem *kgem, int n) -{ - return likely(kgem->nexec + n <= KGEM_EXEC_SIZE(kgem)); -} - -static inline bool kgem_check_batch_with_surfaces(struct kgem *kgem, - int num_dwords, - int num_surfaces) -{ - return (int)(kgem->nbatch + num_dwords + KGEM_BATCH_RESERVED) <= (int)(kgem->surface - num_surfaces*8) && - kgem_check_reloc(kgem, num_surfaces); -} - -static inline uint32_t *kgem_get_batch(struct kgem *kgem, int num_dwords) -{ -// if (!kgem_check_batch(kgem, num_dwords)) -// _kgem_submit(kgem); - - return kgem->batch + kgem->nbatch; -} - -static inline void kgem_advance_batch(struct kgem *kgem, int num_dwords) -{ - kgem->nbatch += num_dwords; -} - -bool kgem_check_bo(struct kgem *kgem, ...) __attribute__((sentinel(0))); -bool kgem_check_bo_fenced(struct kgem *kgem, ...) __attribute__((sentinel(0))); - -void _kgem_add_bo(struct kgem *kgem, struct kgem_bo *bo); -static inline void kgem_add_bo(struct kgem *kgem, struct kgem_bo *bo) -{ - if (bo->proxy) - bo = bo->proxy; - - if (bo->exec == NULL) - _kgem_add_bo(kgem, bo); -} - -#define KGEM_RELOC_FENCED 0x8000 -uint32_t kgem_add_reloc(struct kgem *kgem, - uint32_t pos, - struct kgem_bo *bo, - uint32_t read_write_domains, - uint32_t delta); - -void *kgem_bo_map(struct kgem *kgem, struct kgem_bo *bo); -void *kgem_bo_map__debug(struct kgem *kgem, struct kgem_bo *bo); -void *kgem_bo_map__cpu(struct kgem *kgem, struct kgem_bo *bo); -void kgem_bo_sync__cpu(struct kgem *kgem, struct kgem_bo *bo); -uint32_t kgem_bo_flink(struct kgem *kgem, struct kgem_bo *bo); - -Bool kgem_bo_write(struct kgem *kgem, struct kgem_bo *bo, - const void *data, int length); - -int kgem_bo_fenced_size(struct kgem *kgem, struct kgem_bo *bo); -void kgem_get_tile_size(struct kgem *kgem, int tiling, - int *tile_width, int *tile_height, int *tile_size); - -static inline int kgem_bo_size(struct kgem_bo *bo) -{ - assert(!(bo->proxy && bo->io)); - return PAGE_SIZE * bo->size.pages.count; -} - -static inline int kgem_buffer_size(struct kgem_bo *bo) -{ - assert(bo->proxy && bo->io); - return bo->size.bytes; -} - -/* -static inline bool kgem_bo_blt_pitch_is_ok(struct kgem *kgem, - struct kgem_bo *bo) -{ - int pitch = bo->pitch; - if (kgem->gen >= 40 && bo->tiling) - pitch /= 4; - if (pitch > MAXSHORT) { - DBG(("%s: can not blt to handle=%d, adjusted pitch=%d\n", - __FUNCTION__, pitch)); - return false; - } - - return true; -} - -static inline bool kgem_bo_can_blt(struct kgem *kgem, - struct kgem_bo *bo) -{ - if (bo->tiling == I915_TILING_Y) { - DBG(("%s: can not blt to handle=%d, tiling=Y\n", - __FUNCTION__, bo->handle)); - return false; - } - - return kgem_bo_blt_pitch_is_ok(kgem, bo); -} -*/ -static inline bool kgem_bo_is_mappable(struct kgem *kgem, - struct kgem_bo *bo) -{ - DBG_HDR(("%s: domain=%d, offset: %d size: %d\n", - __FUNCTION__, bo->domain, bo->presumed_offset, kgem_bo_size(bo))); - - if (bo->domain == DOMAIN_GTT) - return true; - - if (IS_GTT_MAP(bo->map)) - return true; - - if (kgem->gen < 40 && bo->tiling && - bo->presumed_offset & (kgem_bo_fenced_size(kgem, bo) - 1)) - return false; - - if (!bo->presumed_offset) - return kgem_bo_size(bo) <= kgem->aperture_mappable / 4; - - return bo->presumed_offset + kgem_bo_size(bo) <= kgem->aperture_mappable; -} - -static inline bool kgem_bo_mapped(struct kgem_bo *bo) -{ - DBG_HDR(("%s: map=%p, tiling=%d\n", __FUNCTION__, bo->map, bo->tiling)); - - if (bo->map == NULL) - return false; - - return IS_CPU_MAP(bo->map) == !bo->tiling; -} - -static inline bool kgem_bo_is_busy(struct kgem_bo *bo) -{ - DBG_HDR(("%s: domain: %d exec? %d, rq? %d\n", - __FUNCTION__, bo->domain, bo->exec != NULL, bo->rq != NULL)); - assert(bo->proxy == NULL); - return bo->rq; -} -/* -static inline bool kgem_bo_map_will_stall(struct kgem *kgem, struct kgem_bo *bo) -{ - DBG(("%s? handle=%d, domain=%d, offset=%x, size=%x\n", - __FUNCTION__, bo->handle, - bo->domain, bo->presumed_offset, bo->size)); - - if (!kgem_bo_is_mappable(kgem, bo)) - return true; - - if (kgem->wedged) - return false; - - if (kgem_bo_is_busy(bo)) - return true; - - if (bo->presumed_offset == 0) - return !list_is_empty(&kgem->requests); - - return false; -} -*/ - -static inline bool kgem_bo_is_dirty(struct kgem_bo *bo) -{ - if (bo == NULL) - return FALSE; - - return bo->dirty; -} - -static inline void kgem_bo_mark_dirty(struct kgem_bo *bo) -{ - DBG_HDR(("%s: handle=%d\n", __FUNCTION__, bo->handle)); - bo->dirty = true; -} - -void kgem_sync(struct kgem *kgem); - -#define KGEM_BUFFER_WRITE 0x1 -#define KGEM_BUFFER_INPLACE 0x2 -#define KGEM_BUFFER_LAST 0x4 - -#define KGEM_BUFFER_WRITE_INPLACE (KGEM_BUFFER_WRITE | KGEM_BUFFER_INPLACE) - -struct kgem_bo *kgem_create_buffer(struct kgem *kgem, - uint32_t size, uint32_t flags, - void **ret); -struct kgem_bo *kgem_create_buffer_2d(struct kgem *kgem, - int width, int height, int bpp, - uint32_t flags, - void **ret); -void kgem_buffer_read_sync(struct kgem *kgem, struct kgem_bo *bo); - -void kgem_throttle(struct kgem *kgem); -#define MAX_INACTIVE_TIME 10 -bool kgem_expire_cache(struct kgem *kgem); -void kgem_purge_cache(struct kgem *kgem); -void kgem_cleanup_cache(struct kgem *kgem); - -#if HAS_EXTRA_DEBUG -void __kgem_batch_debug(struct kgem *kgem, uint32_t nbatch); -#else -static inline void __kgem_batch_debug(struct kgem *kgem, uint32_t nbatch) -{ - (void)kgem; - (void)nbatch; -} -#endif - -#undef DBG_HDR - -u32 get_buffer_offset(uint32_t handle); - - -#endif /* KGEM_H */ diff --git a/drivers/video/drm/i915/sna/sna.c b/drivers/video/drm/i915/sna/sna.c deleted file mode 100644 index 3ab1708da6..0000000000 --- a/drivers/video/drm/i915/sna/sna.c +++ /dev/null @@ -1,387 +0,0 @@ -#include -#include -#include "i915_drm.h" -#include "i915_drv.h" -#include "intel_drv.h" - -#include -#include -#include -#include - -#include - -#include "../bitmap.h" - -#include "sna.h" - -struct kgem_bo *create_bo(bitmap_t *bitmap); - -static Bool sna_solid_cache_init(struct sna *sna); - -struct sna *sna_device; - -void no_render_init(struct sna *sna) -{ - struct sna_render *render = &sna->render; - - memset (render,0, sizeof (*render)); - - render->vertices = render->vertex_data; - render->vertex_size = ARRAY_SIZE(render->vertex_data); - -// render->composite = no_render_composite; - -// render->copy_boxes = no_render_copy_boxes; -// render->copy = no_render_copy; - -// render->fill_boxes = no_render_fill_boxes; -// render->fill = no_render_fill; -// render->fill_one = no_render_fill_one; -// render->clear = no_render_clear; - -// render->reset = no_render_reset; -// render->flush = no_render_flush; -// render->fini = no_render_fini; - -// sna->kgem.context_switch = no_render_context_switch; -// sna->kgem.retire = no_render_retire; - -// if (sna->kgem.gen >= 60) - sna->kgem.ring = KGEM_RENDER; -} - - -Bool sna_accel_init(struct sna *sna) -{ - const char *backend; - -// list_init(&sna->deferred_free); -// list_init(&sna->dirty_pixmaps); -// list_init(&sna->active_pixmaps); -// list_init(&sna->inactive_clock[0]); -// list_init(&sna->inactive_clock[1]); - -// sna_accel_install_timers(sna); - - - backend = "no"; - sna->have_render = false; - sna->default_tiling = 0; //I915_TILING_X; - no_render_init(sna); - - if ((sna->have_render = gen6_render_init(sna))) - backend = "SandyBridge"; - -/* - if (sna->chipset.info->gen >= 80) { - } else if (sna->chipset.info->gen >= 70) { - if ((sna->have_render = gen7_render_init(sna))) - backend = "IvyBridge"; - } else if (sna->chipset.info->gen >= 60) { - if ((sna->have_render = gen6_render_init(sna))) - backend = "SandyBridge"; - } else if (sna->chipset.info->gen >= 50) { - if ((sna->have_render = gen5_render_init(sna))) - backend = "Ironlake"; - } else if (sna->chipset.info->gen >= 40) { - if ((sna->have_render = gen4_render_init(sna))) - backend = "Broadwater"; - } else if (sna->chipset.info->gen >= 30) { - if ((sna->have_render = gen3_render_init(sna))) - backend = "gen3"; - } else if (sna->chipset.info->gen >= 20) { - if ((sna->have_render = gen2_render_init(sna))) - backend = "gen2"; - } -*/ - DBG(("%s(backend=%s, have_render=%d)\n", - __FUNCTION__, backend, sna->have_render)); - - kgem_reset(&sna->kgem); - - if (!sna_solid_cache_init(sna)) - return FALSE; - - sna_device = sna; -#if 0 - { - struct kgem_bo *screen_bo; - bitmap_t screen; - - screen.pitch = 1024*4; - screen.gaddr = 0; - screen.width = 1024; - screen.height = 768; - screen.obj = (void*)-1; - - screen_bo = create_bo(&screen); - - sna->render.clear(sna, &screen, screen_bo); - } -#endif - - return TRUE; -} - -int sna_init() -{ - struct sna *sna; - - DBG(("%s\n", __FUNCTION__)); - - sna = kzalloc(sizeof(struct sna), 0); - if (sna == NULL) - return FALSE; - -// sna->mode.cpp = 4; - - kgem_init(&sna->kgem, 60); -/* - if (!xf86ReturnOptValBool(sna->Options, - OPTION_RELAXED_FENCING, - sna->kgem.has_relaxed_fencing)) { - xf86DrvMsg(scrn->scrnIndex, - sna->kgem.has_relaxed_fencing ? X_CONFIG : X_PROBED, - "Disabling use of relaxed fencing\n"); - sna->kgem.has_relaxed_fencing = 0; - } - if (!xf86ReturnOptValBool(sna->Options, - OPTION_VMAP, - sna->kgem.has_vmap)) { - xf86DrvMsg(scrn->scrnIndex, - sna->kgem.has_vmap ? X_CONFIG : X_PROBED, - "Disabling use of vmap\n"); - sna->kgem.has_vmap = 0; - } -*/ - - /* Disable tiling by default */ - sna->tiling = SNA_TILING_DISABLE; - - /* Default fail-safe value of 75 Hz */ -// sna->vblank_interval = 1000 * 1000 * 1000 / 75; - - sna->flags = 0; - sna->flags |= SNA_NO_THROTTLE; - sna->flags |= SNA_NO_DELAYED_FLUSH; - - return sna_accel_init(sna); -} - - -static Bool sna_solid_cache_init(struct sna *sna) -{ - struct sna_solid_cache *cache = &sna->render.solid_cache; - - DBG(("%s\n", __FUNCTION__)); - - cache->cache_bo = - kgem_create_linear(&sna->kgem, sizeof(cache->color)); - if (!cache->cache_bo) - return FALSE; - - /* - * Initialise [0] with white since it is very common and filling the - * zeroth slot simplifies some of the checks. - */ - cache->color[0] = 0xffffffff; - cache->bo[0] = kgem_create_proxy(cache->cache_bo, 0, sizeof(uint32_t)); - cache->bo[0]->pitch = 4; - cache->dirty = 1; - cache->size = 1; - cache->last = 0; - - return TRUE; -} - -void -sna_render_flush_solid(struct sna *sna) -{ - struct sna_solid_cache *cache = &sna->render.solid_cache; - - DBG(("sna_render_flush_solid(size=%d)\n", cache->size)); - assert(cache->dirty); - assert(cache->size); - - kgem_bo_write(&sna->kgem, cache->cache_bo, - cache->color, cache->size*sizeof(uint32_t)); - cache->dirty = 0; - cache->last = 0; -} - -static void -sna_render_finish_solid(struct sna *sna, bool force) -{ - struct sna_solid_cache *cache = &sna->render.solid_cache; - int i; - - DBG(("sna_render_finish_solid(force=%d, domain=%d, busy=%d, dirty=%d)\n", - force, cache->cache_bo->domain, cache->cache_bo->rq != NULL, cache->dirty)); - - if (!force && cache->cache_bo->domain != DOMAIN_GPU) - return; - - if (cache->dirty) - sna_render_flush_solid(sna); - - for (i = 0; i < cache->size; i++) { - if (cache->bo[i] == NULL) - continue; - - kgem_bo_destroy(&sna->kgem, cache->bo[i]); - cache->bo[i] = NULL; - } - kgem_bo_destroy(&sna->kgem, cache->cache_bo); - - DBG(("sna_render_finish_solid reset\n")); - - cache->cache_bo = kgem_create_linear(&sna->kgem, sizeof(cache->color)); - cache->bo[0] = kgem_create_proxy(cache->cache_bo, 0, sizeof(uint32_t)); - cache->bo[0]->pitch = 4; - if (force) - cache->size = 1; -} - - -struct kgem_bo * -sna_render_get_solid(struct sna *sna, uint32_t color) -{ - struct sna_solid_cache *cache = &sna->render.solid_cache; - int i; - - DBG(("%s: %08x\n", __FUNCTION__, color)); - -// if ((color & 0xffffff) == 0) /* alpha only */ -// return kgem_bo_reference(sna->render.alpha_cache.bo[color>>24]); - - if (color == 0xffffffff) { - DBG(("%s(white)\n", __FUNCTION__)); - return kgem_bo_reference(cache->bo[0]); - } - - if (cache->color[cache->last] == color) { - DBG(("sna_render_get_solid(%d) = %x (last)\n", - cache->last, color)); - return kgem_bo_reference(cache->bo[cache->last]); - } - - for (i = 1; i < cache->size; i++) { - if (cache->color[i] == color) { - if (cache->bo[i] == NULL) { - DBG(("sna_render_get_solid(%d) = %x (recreate)\n", - i, color)); - goto create; - } else { - DBG(("sna_render_get_solid(%d) = %x (old)\n", - i, color)); - goto done; - } - } - } - - sna_render_finish_solid(sna, i == ARRAY_SIZE(cache->color)); - - i = cache->size++; - cache->color[i] = color; - cache->dirty = 1; - DBG(("sna_render_get_solid(%d) = %x (new)\n", i, color)); - -create: - cache->bo[i] = kgem_create_proxy(cache->cache_bo, - i*sizeof(uint32_t), sizeof(uint32_t)); - cache->bo[i]->pitch = 4; - -done: - cache->last = i; - return kgem_bo_reference(cache->bo[i]); -} - -int sna_blit_copy(bitmap_t *dst_bitmap, int dst_x, int dst_y, - int w, int h, bitmap_t *src_bitmap, int src_x, int src_y) - -{ - batchbuffer_t execbuffer; - - struct kgem_bo src_bo, dst_bo; - - memset(&execbuffer, 0, sizeof(execbuffer)); - memset(&src_bo, 0, sizeof(src_bo)); - memset(&dst_bo, 0, sizeof(dst_bo)); - - INIT_LIST_HEAD(&execbuffer.objects); - - src_bo.gaddr = src_bitmap->gaddr; - src_bo.pitch = src_bitmap->pitch; - src_bo.tiling = 0; - - dst_bo.gaddr = dst_bitmap->gaddr; - dst_bo.pitch = dst_bitmap->pitch; - dst_bo.tiling = 0; - - sna_device->render.copy(sna_device, 0, src_bitmap, &src_bo, - dst_bitmap, &dst_bo, dst_x, dst_y, - src_x, src_y, w, h); - - INIT_LIST_HEAD(&execbuffer.objects); - list_add_tail(&src_bitmap->obj->exec_list, &execbuffer.objects); - - _kgem_submit(&sna_device->kgem, &execbuffer); - -}; - - -int sna_blit_tex(bitmap_t *dst_bitmap, int dst_x, int dst_y, - int w, int h, bitmap_t *src_bitmap, int src_x, int src_y, - bitmap_t *mask_bitmap) - -{ - struct sna_composite_op cop; - batchbuffer_t execbuffer; - BoxRec box; - - struct kgem_bo src_bo, mask_bo, dst_bo; - - memset(&cop, 0, sizeof(cop)); - memset(&execbuffer, 0, sizeof(execbuffer)); - memset(&src_bo, 0, sizeof(src_bo)); - memset(&dst_bo, 0, sizeof(dst_bo)); - memset(&mask_bo, 0, sizeof(mask_bo)); - - src_bo.gaddr = src_bitmap->gaddr; - src_bo.pitch = src_bitmap->pitch; - src_bo.tiling = 0; - - dst_bo.gaddr = dst_bitmap->gaddr; - dst_bo.pitch = dst_bitmap->pitch; - dst_bo.tiling = 0; - - mask_bo.gaddr = mask_bitmap->gaddr; - mask_bo.pitch = mask_bitmap->pitch; - mask_bo.tiling = 0; - - box.x1 = dst_x; - box.y1 = dst_y; - box.x2 = dst_x+w; - box.y2 = dst_y+h; - - sna_device->render.composite(sna_device, 0, - src_bitmap, &src_bo, - mask_bitmap, &mask_bo, - dst_bitmap, &dst_bo, - src_x, src_y, - src_x, src_y, - dst_x, dst_y, - w, h, &cop); - - cop.box(sna_device, &cop, &box); - cop.done(sna_device, &cop); - - INIT_LIST_HEAD(&execbuffer.objects); - list_add_tail(&src_bitmap->obj->exec_list, &execbuffer.objects); - list_add_tail(&mask_bitmap->obj->exec_list, &execbuffer.objects); - - _kgem_submit(&sna_device->kgem, &execbuffer); - -}; - diff --git a/drivers/video/drm/i915/sna/sna.h b/drivers/video/drm/i915/sna/sna.h deleted file mode 100644 index 7a8676a60f..0000000000 --- a/drivers/video/drm/i915/sna/sna.h +++ /dev/null @@ -1,125 +0,0 @@ - -#define FALSE 0 -#define TRUE 1 - -#define DBG(x) -//#define DBG(x) dbgprintf x - -#define assert(x) - - -#include "compiler.h" -#include - -struct pixman_box16 -{ - int16_t x1, y1, x2, y2; -}; - -typedef struct pixman_box16 BoxRec; -typedef unsigned int CARD32; - -#include "sna_render.h" -#include "kgem.h" - -#define PictOpClear 0 -#define PictOpSrc 1 -#define PictOpDst 2 -#define PictOpOver 3 -#define PictOpOverReverse 4 -#define PictOpIn 5 -#define PictOpInReverse 6 -#define PictOpOut 7 -#define PictOpOutReverse 8 -#define PictOpAtop 9 -#define PictOpAtopReverse 10 -#define PictOpXor 11 -#define PictOpAdd 12 -#define PictOpSaturate 13 -#define PictOpMaximum 13 - -struct sna { - unsigned flags; -#define SNA_NO_THROTTLE 0x1 -#define SNA_NO_DELAYED_FLUSH 0x2 - -// int timer[NUM_TIMERS]; - -// uint16_t timer_active; -// uint16_t timer_ready; - -// int vblank_interval; - -// struct list deferred_free; -// struct list dirty_pixmaps; -// struct list active_pixmaps; -// struct list inactive_clock[2]; - - unsigned int tiling; -#define SNA_TILING_DISABLE 0x0 -#define SNA_TILING_FB 0x1 -#define SNA_TILING_2D 0x2 -#define SNA_TILING_3D 0x4 -#define SNA_TILING_ALL (~0) - - int Chipset; -// EntityInfoPtr pEnt; -// struct pci_device *PciInfo; -// struct intel_chipset chipset; - -// PicturePtr clear; - struct { - uint32_t fill_bo; - uint32_t fill_pixel; - uint32_t fill_alu; - } blt_state; - union { -// struct gen2_render_state gen2; -// struct gen3_render_state gen3; -// struct gen4_render_state gen4; -// struct gen5_render_state gen5; - struct gen6_render_state gen6; -// struct gen7_render_state gen7; - } render_state; - uint32_t have_render; - uint32_t default_tiling; - -// Bool directRenderingOpen; -// char *deviceName; - - /* Broken-out options. */ -// OptionInfoPtr Options; - - /* Driver phase/state information */ -// Bool suspended; - - struct kgem kgem; - struct sna_render render; -}; - -static inline int vertex_space(struct sna *sna) -{ - return sna->render.vertex_size - sna->render.vertex_used; -} - -static inline void vertex_emit(struct sna *sna, float v) -{ - assert(sna->render.vertex_used < sna->render.vertex_size); - sna->render.vertices[sna->render.vertex_used++] = v; -} - -static inline void vertex_emit_2s(struct sna *sna, int16_t x, int16_t y) -{ - int16_t *v = (int16_t *)&sna->render.vertices[sna->render.vertex_used++]; - assert(sna->render.vertex_used <= sna->render.vertex_size); - v[0] = x; - v[1] = y; -} - -static inline void batch_emit(struct sna *sna, uint32_t dword) -{ - assert(sna->kgem.mode != KGEM_NONE); - assert(sna->kgem.nbatch + KGEM_BATCH_RESERVED < sna->kgem.surface); - sna->kgem.batch[sna->kgem.nbatch++] = dword; -} - diff --git a/drivers/video/drm/i915/sna/sna_reg.h b/drivers/video/drm/i915/sna/sna_reg.h deleted file mode 100644 index 551d64b0ef..0000000000 --- a/drivers/video/drm/i915/sna/sna_reg.h +++ /dev/null @@ -1,81 +0,0 @@ -#ifndef SNA_REG_H -#define SNA_REG_H - -/* Flush */ -#define MI_FLUSH (0x04<<23) -#define MI_FLUSH_DW (0x26<<23) - -#define MI_WRITE_DIRTY_STATE (1<<4) -#define MI_END_SCENE (1<<3) -#define MI_GLOBAL_SNAPSHOT_COUNT_RESET (1<<3) -#define MI_INHIBIT_RENDER_CACHE_FLUSH (1<<2) -#define MI_STATE_INSTRUCTION_CACHE_FLUSH (1<<1) -#define MI_INVALIDATE_MAP_CACHE (1<<0) -/* broadwater flush bits */ -#define BRW_MI_GLOBAL_SNAPSHOT_RESET (1 << 3) - -#define MI_BATCH_BUFFER_END (0xA << 23) - -/* Noop */ -#define MI_NOOP 0x00 -#define MI_NOOP_WRITE_ID (1<<22) -#define MI_NOOP_ID_MASK (1<<22 - 1) - -/* Wait for Events */ -#define MI_WAIT_FOR_EVENT (0x03<<23) -#define MI_WAIT_FOR_PIPEB_SVBLANK (1<<18) -#define MI_WAIT_FOR_PIPEA_SVBLANK (1<<17) -#define MI_WAIT_FOR_OVERLAY_FLIP (1<<16) -#define MI_WAIT_FOR_PIPEB_VBLANK (1<<7) -#define MI_WAIT_FOR_PIPEB_SCAN_LINE_WINDOW (1<<5) -#define MI_WAIT_FOR_PIPEA_VBLANK (1<<3) -#define MI_WAIT_FOR_PIPEA_SCAN_LINE_WINDOW (1<<1) - -/* Set the scan line for MI_WAIT_FOR_PIPE?_SCAN_LINE_WINDOW */ -#define MI_LOAD_SCAN_LINES_INCL (0x12<<23) -#define MI_LOAD_SCAN_LINES_DISPLAY_PIPEA (0) -#define MI_LOAD_SCAN_LINES_DISPLAY_PIPEB (0x1<<20) - -/* BLT commands */ -#define BLT_WRITE_ALPHA (1<<21) -#define BLT_WRITE_RGB (1<<20) -#define BLT_SRC_TILED (1<<15) -#define BLT_DST_TILED (1<<11) - -#define COLOR_BLT_CMD ((2<<29)|(0x40<<22)|(0x3)) -#define XY_COLOR_BLT ((2<<29)|(0x50<<22)|(0x4)) -#define XY_SETUP_BLT ((2<<29)|(1<<22)|6) -#define XY_SETUP_MONO_PATTERN_SL_BLT ((2<<29)|(0x11<<22)|7) -#define XY_SETUP_CLIP ((2<<29)|(3<<22)|1) -#define XY_SCANLINE_BLT ((2<<29)|(0x25<<22)|1) -#define XY_TEXT_IMMEDIATE_BLT ((2<<29)|(0x31<<22)|(1<<16)) -#define XY_SRC_COPY_BLT_CMD ((2<<29)|(0x53<<22)|6) -#define SRC_COPY_BLT_CMD ((2<<29)|(0x43<<22)|0x4) -#define XY_PAT_BLT_IMMEDIATE ((2<<29)|(0x72<<22)) -#define XY_MONO_PAT ((0x2<<29)|(0x52<<22)|0x7) -#define XY_MONO_SRC_COPY ((0x2<<29)|(0x54<<22)|(0x6)) -#define XY_MONO_SRC_COPY_IMM ((0x2<<29)|(0x71<<22)) -#define XY_FULL_MONO_PATTERN_BLT ((0x2<<29)|(0x57<<22)|0xa) -#define XY_FULL_MONO_PATTERN_MONO_SRC_BLT ((0x2<<29)|(0x58<<22)|0xa) - -/* FLUSH commands */ -#define BRW_3D(Pipeline,Opcode,Subopcode) \ - ((3 << 29) | \ - ((Pipeline) << 27) | \ - ((Opcode) << 24) | \ - ((Subopcode) << 16)) -#define PIPE_CONTROL BRW_3D(3, 2, 0) -#define PIPE_CONTROL_NOWRITE (0 << 14) -#define PIPE_CONTROL_WRITE_QWORD (1 << 14) -#define PIPE_CONTROL_WRITE_DEPTH (2 << 14) -#define PIPE_CONTROL_WRITE_TIME (3 << 14) -#define PIPE_CONTROL_DEPTH_STALL (1 << 13) -#define PIPE_CONTROL_WC_FLUSH (1 << 12) -#define PIPE_CONTROL_IS_FLUSH (1 << 11) -#define PIPE_CONTROL_TC_FLUSH (1 << 10) -#define PIPE_CONTROL_NOTIFY_ENABLE (1 << 8) -#define PIPE_CONTROL_GLOBAL_GTT (1 << 2) -#define PIPE_CONTROL_LOCAL_PGTT (0 << 2) -#define PIPE_CONTROL_DEPTH_CACHE_FLUSH (1 << 0) - -#endif diff --git a/drivers/video/drm/i915/sna/sna_render.h b/drivers/video/drm/i915/sna/sna_render.h deleted file mode 100644 index e3dd0b7aa4..0000000000 --- a/drivers/video/drm/i915/sna/sna_render.h +++ /dev/null @@ -1,478 +0,0 @@ -#ifndef SNA_RENDER_H -#define SNA_RENDER_H - -typedef int Bool; - -#define GRADIENT_CACHE_SIZE 16 - -struct sna; - -struct sna_composite_rectangles { - struct sna_coordinate { - int16_t x, y; - } src, mask, dst; - int16_t width, height; -}; - -struct sna_composite_op { - fastcall void (*blt)(struct sna *sna, const struct sna_composite_op *op, - const struct sna_composite_rectangles *r); - fastcall void (*box)(struct sna *sna, - const struct sna_composite_op *op, - const BoxRec *box); - void (*boxes)(struct sna *sna, const struct sna_composite_op *op, - const BoxRec *box, int nbox); - void (*done)(struct sna *sna, const struct sna_composite_op *op); - - struct sna_damage **damage; - - uint32_t op; - - struct { - bitmap_t *pixmap; - CARD32 format; - struct kgem_bo *bo; - int16_t x, y; - uint16_t width, height; - } dst; - - struct sna_composite_channel { - struct kgem_bo *bo; -// PictTransform *transform; - uint16_t width; - uint16_t height; - uint32_t pict_format; - uint32_t card_format; - uint32_t filter; - uint32_t repeat; - uint32_t is_affine : 1; - uint32_t is_solid : 1; - uint32_t is_linear : 1; - uint32_t is_opaque : 1; - uint32_t alpha_fixup : 1; - uint32_t rb_reversed : 1; - int16_t offset[2]; - float scale[2]; - -// pixman_transform_t embedded_transform; - - union { - struct { - uint32_t pixel; - float linear_dx; - float linear_dy; - float linear_offset; - } gen2; - struct gen3_shader_channel { - int type; - uint32_t mode; - uint32_t constants; - } gen3; - } u; - } src, mask; - uint32_t is_affine : 1; - uint32_t has_component_alpha : 1; - uint32_t need_magic_ca_pass : 1; - uint32_t rb_reversed : 1; - - int16_t floats_per_vertex; - int16_t floats_per_rect; - fastcall void (*prim_emit)(struct sna *sna, - const struct sna_composite_op *op, - const struct sna_composite_rectangles *r); - - struct sna_composite_redirect { - struct kgem_bo *real_bo; - struct sna_damage **real_damage, *damage; - BoxRec box; - } redirect; - - union { - struct sna_blt_state { - bitmap_t *src_pixmap; - int16_t sx, sy; - - uint32_t inplace :1; - uint32_t overwrites:1; - uint32_t bpp : 6; - - uint32_t cmd; - uint32_t br13; - uint32_t pitch[2]; - uint32_t pixel; - struct kgem_bo *bo[2]; - } blt; - - struct { - float constants[8]; - uint32_t num_constants; - } gen3; - - struct { - int wm_kernel; - int ve_id; - } gen4; - - struct { - int wm_kernel; - int ve_id; - } gen5; - - struct { - int wm_kernel; - int nr_surfaces; - int nr_inputs; - int ve_id; - } gen6; - - struct { - int wm_kernel; - int nr_surfaces; - int nr_inputs; - int ve_id; - } gen7; - - void *priv; - } u; -}; - - -struct sna_render { - int max_3d_size; - int max_3d_pitch; - - Bool (*composite)(struct sna *sna, uint8_t op, - bitmap_t *src, struct kgem_bo *src_bo, - bitmap_t *mask, struct kgem_bo *mask_bo, - bitmap_t *dst, struct kgem_bo *dst_bo, - int16_t src_x, int16_t src_y, - int16_t msk_x, int16_t msk_y, - int16_t dst_x, int16_t dst_y, - int16_t w, int16_t h, - struct sna_composite_op *tmp); -/* - Bool (*composite_spans)(struct sna *sna, uint8_t op, - PicturePtr dst, PicturePtr src, - int16_t src_x, int16_t src_y, - int16_t dst_x, int16_t dst_y, - int16_t w, int16_t h, - unsigned flags, - struct sna_composite_spans_op *tmp); -#define COMPOSITE_SPANS_RECTILINEAR 0x1 - - Bool (*video)(struct sna *sna, - struct sna_video *video, - struct sna_video_frame *frame, - RegionPtr dstRegion, - short src_w, short src_h, - short drw_w, short drw_h, - PixmapPtr pixmap); - - Bool (*fill_boxes)(struct sna *sna, - CARD8 op, - PictFormat format, - const xRenderColor *color, - PixmapPtr dst, struct kgem_bo *dst_bo, - const BoxRec *box, int n); - Bool (*fill)(struct sna *sna, uint8_t alu, - PixmapPtr dst, struct kgem_bo *dst_bo, - uint32_t color, - struct sna_fill_op *tmp); - Bool (*fill_one)(struct sna *sna, PixmapPtr dst, struct kgem_bo *dst_bo, - uint32_t color, - int16_t x1, int16_t y1, int16_t x2, int16_t y2, - uint8_t alu); -*/ - Bool (*clear)(struct sna *sna, bitmap_t *dst, struct kgem_bo *dst_bo); -/* - Bool (*copy_boxes)(struct sna *sna, uint8_t alu, - PixmapPtr src, struct kgem_bo *src_bo, int16_t src_dx, int16_t src_dy, - PixmapPtr dst, struct kgem_bo *dst_bo, int16_t dst_dx, int16_t dst_dy, - const BoxRec *box, int n); -*/ - Bool (*copy)(struct sna *sna, uint8_t alu, - bitmap_t *src, struct kgem_bo *src_bo, - bitmap_t *dst, struct kgem_bo *dst_bo, - int dst_x, int dst_y, int src_x, int src_y, - int w, int h); - - void (*flush)(struct sna *sna); - void (*reset)(struct sna *sna); - void (*fini)(struct sna *sna); - -// struct sna_alpha_cache { -// struct kgem_bo *cache_bo; -// struct kgem_bo *bo[256]; -// } alpha_cache; - - struct sna_solid_cache { - struct kgem_bo *cache_bo; - uint32_t color[1024]; - struct kgem_bo *bo[1024]; - int last; - int size; - int dirty; - } solid_cache; - -// struct { -// struct sna_gradient_cache { -// struct kgem_bo *bo; -// int nstops; -// PictGradientStop *stops; -// } cache[GRADIENT_CACHE_SIZE]; -// int size; -// } gradient_cache; - -// struct sna_glyph_cache{ -// PicturePtr picture; -// struct sna_glyph **glyphs; -// uint16_t count; -// uint16_t evict; -// } glyph[2]; - - uint16_t vertex_start; - uint16_t vertex_index; - uint16_t vertex_used; - uint16_t vertex_size; - uint16_t vertex_reloc[8]; - - struct kgem_bo *vbo; - float *vertices; - - float vertex_data[1024]; -}; - -enum { - GEN6_WM_KERNEL_NOMASK = 0, - GEN6_WM_KERNEL_MASK, - - GEN6_KERNEL_COUNT -}; - -struct gen6_render_state { - struct kgem_bo *general_bo; - - uint32_t vs_state; - uint32_t sf_state; - uint32_t sf_mask_state; - uint32_t wm_state; - uint32_t wm_kernel[GEN6_KERNEL_COUNT]; - - uint32_t cc_vp; - uint32_t cc_blend; - - uint32_t drawrect_offset; - uint32_t drawrect_limit; - uint32_t blend; - uint32_t samplers; - uint32_t kernel; - - uint16_t num_sf_outputs; - uint16_t vb_id; - uint16_t ve_id; - uint16_t vertex_offset; - uint16_t last_primitive; - int16_t floats_per_vertex; - uint16_t surface_table; - - Bool needs_invariant; -}; - - - -struct sna_static_stream { - uint32_t size, used; - uint8_t *data; -}; - -int sna_static_stream_init(struct sna_static_stream *stream); -uint32_t sna_static_stream_add(struct sna_static_stream *stream, - const void *data, uint32_t len, uint32_t align); -void *sna_static_stream_map(struct sna_static_stream *stream, - uint32_t len, uint32_t align); -uint32_t sna_static_stream_offsetof(struct sna_static_stream *stream, - void *ptr); -struct kgem_bo *sna_static_stream_fini(struct sna *sna, - struct sna_static_stream *stream); - -/* -struct kgem_bo * -sna_render_get_solid(struct sna *sna, - uint32_t color); - -void -sna_render_flush_solid(struct sna *sna); - -struct kgem_bo * -sna_render_get_gradient(struct sna *sna, - PictGradient *pattern); - -uint32_t sna_rgba_for_color(uint32_t color, int depth); -Bool sna_picture_is_solid(PicturePtr picture, uint32_t *color); -*/ -void no_render_init(struct sna *sna); - -Bool gen2_render_init(struct sna *sna); -Bool gen3_render_init(struct sna *sna); -Bool gen4_render_init(struct sna *sna); -Bool gen5_render_init(struct sna *sna); -Bool gen6_render_init(struct sna *sna); -Bool gen7_render_init(struct sna *sna); -/* -Bool sna_tiling_composite(uint32_t op, - PicturePtr src, - PicturePtr mask, - PicturePtr dst, - int16_t src_x, int16_t src_y, - int16_t mask_x, int16_t mask_y, - int16_t dst_x, int16_t dst_y, - int16_t width, int16_t height, - struct sna_composite_op *tmp); -Bool sna_tiling_fill_boxes(struct sna *sna, - CARD8 op, - PictFormat format, - const xRenderColor *color, - PixmapPtr dst, struct kgem_bo *dst_bo, - const BoxRec *box, int n); - -Bool sna_tiling_copy_boxes(struct sna *sna, uint8_t alu, - PixmapPtr src, struct kgem_bo *src_bo, int16_t src_dx, int16_t src_dy, - PixmapPtr dst, struct kgem_bo *dst_bo, int16_t dst_dx, int16_t dst_dy, - const BoxRec *box, int n); - -Bool sna_tiling_blt_copy_boxes(struct sna *sna, uint8_t alu, - struct kgem_bo *src_bo, int16_t src_dx, int16_t src_dy, - struct kgem_bo *dst_bo, int16_t dst_dx, int16_t dst_dy, - int bpp, const BoxRec *box, int nbox); - -Bool sna_blt_composite(struct sna *sna, - uint32_t op, - PicturePtr src, - PicturePtr dst, - int16_t src_x, int16_t src_y, - int16_t dst_x, int16_t dst_y, - int16_t width, int16_t height, - struct sna_composite_op *tmp); - -bool sna_blt_fill(struct sna *sna, uint8_t alu, - struct kgem_bo *bo, - int bpp, - uint32_t pixel, - struct sna_fill_op *fill); - -bool sna_blt_copy(struct sna *sna, uint8_t alu, - struct kgem_bo *src, - struct kgem_bo *dst, - int bpp, - struct sna_copy_op *copy); - -Bool sna_blt_fill_boxes(struct sna *sna, uint8_t alu, - struct kgem_bo *bo, - int bpp, - uint32_t pixel, - const BoxRec *box, int n); - -Bool sna_blt_copy_boxes(struct sna *sna, uint8_t alu, - struct kgem_bo *src_bo, int16_t src_dx, int16_t src_dy, - struct kgem_bo *dst_bo, int16_t dst_dx, int16_t dst_dy, - int bpp, - const BoxRec *box, int n); -Bool sna_blt_copy_boxes_fallback(struct sna *sna, uint8_t alu, - PixmapPtr src, struct kgem_bo *src_bo, int16_t src_dx, int16_t src_dy, - PixmapPtr dst, struct kgem_bo *dst_bo, int16_t dst_dx, int16_t dst_dy, - const BoxRec *box, int nbox); - -Bool _sna_get_pixel_from_rgba(uint32_t *pixel, - uint16_t red, - uint16_t green, - uint16_t blue, - uint16_t alpha, - uint32_t format); - -static inline Bool -sna_get_pixel_from_rgba(uint32_t * pixel, - uint16_t red, - uint16_t green, - uint16_t blue, - uint16_t alpha, - uint32_t format) -{ - switch (format) { - case PICT_x8r8g8b8: - alpha = 0xffff; - case PICT_a8r8g8b8: - *pixel = ((alpha >> 8 << 24) | - (red >> 8 << 16) | - (green & 0xff00) | - (blue >> 8)); - return TRUE; - case PICT_a8: - *pixel = alpha >> 8; - return TRUE; - } - - return _sna_get_pixel_from_rgba(pixel, red, green, blue, alpha, format); -} - -int -sna_render_pixmap_bo(struct sna *sna, - struct sna_composite_channel *channel, - PixmapPtr pixmap, - int16_t x, int16_t y, - int16_t w, int16_t h, - int16_t dst_x, int16_t dst_y); - -bool -sna_render_pixmap_partial(struct sna *sna, - PixmapPtr pixmap, - struct kgem_bo *bo, - struct sna_composite_channel *channel, - int16_t x, int16_t y, - int16_t w, int16_t h); - -int -sna_render_picture_extract(struct sna *sna, - PicturePtr picture, - struct sna_composite_channel *channel, - int16_t x, int16_t y, - int16_t w, int16_t h, - int16_t dst_x, int16_t dst_y); - -int -sna_render_picture_fixup(struct sna *sna, - PicturePtr picture, - struct sna_composite_channel *channel, - int16_t x, int16_t y, - int16_t w, int16_t h, - int16_t dst_x, int16_t dst_y); - -int -sna_render_picture_convert(struct sna *sna, - PicturePtr picture, - struct sna_composite_channel *channel, - PixmapPtr pixmap, - int16_t x, int16_t y, - int16_t w, int16_t h, - int16_t dst_x, int16_t dst_y); - -inline static void sna_render_composite_redirect_init(struct sna_composite_op *op) -{ - struct sna_composite_redirect *t = &op->redirect; - t->real_bo = NULL; - t->damage = NULL; -} - -Bool -sna_render_composite_redirect(struct sna *sna, - struct sna_composite_op *op, - int x, int y, int width, int height); - -void -sna_render_composite_redirect_done(struct sna *sna, - const struct sna_composite_op *op); - -bool -sna_composite_mask_is_opaque(PicturePtr mask); -*/ - -#endif /* SNA_RENDER_H */ diff --git a/drivers/video/drm/i915/sna/sna_stream.c b/drivers/video/drm/i915/sna/sna_stream.c deleted file mode 100644 index be83a11e44..0000000000 --- a/drivers/video/drm/i915/sna/sna_stream.c +++ /dev/null @@ -1,108 +0,0 @@ -/* - * Copyright © 2011 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: - * Chris Wilson - * - */ - -#include -#include "../bitmap.h" - -#include "sna.h" -#include "sna_render.h" -#include - -#if DEBUG_STREAM -#undef DBG -#define DBG(x) ErrorF x -#endif - -int sna_static_stream_init(struct sna_static_stream *stream) -{ - stream->used = 0; - stream->size = 64*1024; - - stream->data = malloc(stream->size); - return stream->data != NULL; -} - -static uint32_t sna_static_stream_alloc(struct sna_static_stream *stream, - uint32_t len, uint32_t align) -{ - uint32_t offset = ALIGN(stream->used, align); - uint32_t size = offset + len; - - if (size > stream->size) { -/* - do - stream->size *= 2; - while (stream->size < size); - - stream->data = realloc(stream->data, stream->size); -*/ - dbgprintf("%s: EPIC FAIL\n", __FUNCTION__); - return 0; - } - - stream->used = size; - return offset; -} - -uint32_t sna_static_stream_add(struct sna_static_stream *stream, - const void *data, uint32_t len, uint32_t align) -{ - uint32_t offset = sna_static_stream_alloc(stream, len, align); - memcpy(stream->data + offset, data, len); - return offset; -} - -void *sna_static_stream_map(struct sna_static_stream *stream, - uint32_t len, uint32_t align) -{ - uint32_t offset = sna_static_stream_alloc(stream, len, align); - return memset(stream->data + offset, 0, len); -} - -uint32_t sna_static_stream_offsetof(struct sna_static_stream *stream, void *ptr) -{ - return (uint8_t *)ptr - stream->data; -} - - -struct kgem_bo *sna_static_stream_fini(struct sna *sna, - struct sna_static_stream *stream) -{ - struct kgem_bo *bo; - - DBG(("uploaded %d bytes of static state\n", stream->used)); - - bo = kgem_create_linear(&sna->kgem, stream->used); - if (bo && !kgem_bo_write(&sna->kgem, bo, stream->data, stream->used)) { -// kgem_bo_destroy(&sna->kgem, bo); - return NULL; - } - - free(stream->data); - LEAVE(); - return bo; -} diff --git a/drivers/video/drm/i915/utils.c b/drivers/video/drm/i915/utils.c index d4ad3b4156..75a23fbc7a 100644 --- a/drivers/video/drm/i915/utils.c +++ b/drivers/video/drm/i915/utils.c @@ -4,6 +4,7 @@ #include #include "i915_drv.h" #include "intel_drv.h" +#include struct file *shmem_file_setup(const char *name, loff_t size, unsigned long flags) @@ -102,3 +103,410 @@ void shmem_file_delete(struct file *filep) if(filep->pages) kfree(filep->pages); } + +/** + * hdmi_avi_infoframe_init() - initialize an HDMI AVI infoframe + * @frame: HDMI AVI infoframe + * + * Returns 0 on success or a negative error code on failure. + */ +int hdmi_avi_infoframe_init(struct hdmi_avi_infoframe *frame) +{ + memset(frame, 0, sizeof(*frame)); + + frame->type = HDMI_INFOFRAME_TYPE_AVI; + frame->version = 2; + frame->length = 13; + + return 0; +} + + +static void *check_bytes8(const u8 *start, u8 value, unsigned int bytes) +{ + while (bytes) { + if (*start != value) + return (void *)start; + start++; + bytes--; + } + return NULL; +} + +/** + * memchr_inv - Find an unmatching character in an area of memory. + * @start: The memory area + * @c: Find a character other than c + * @bytes: The size of the area. + * + * returns the address of the first character other than @c, or %NULL + * if the whole buffer contains just @c. + */ +void *memchr_inv(const void *start, int c, size_t bytes) +{ + u8 value = c; + u64 value64; + unsigned int words, prefix; + + if (bytes <= 16) + return check_bytes8(start, value, bytes); + + value64 = value; +#if defined(ARCH_HAS_FAST_MULTIPLIER) && BITS_PER_LONG == 64 + value64 *= 0x0101010101010101; +#elif defined(ARCH_HAS_FAST_MULTIPLIER) + value64 *= 0x01010101; + value64 |= value64 << 32; +#else + value64 |= value64 << 8; + value64 |= value64 << 16; + value64 |= value64 << 32; +#endif + + prefix = (unsigned long)start % 8; + if (prefix) { + u8 *r; + + prefix = 8 - prefix; + r = check_bytes8(start, value, prefix); + if (r) + return r; + start += prefix; + bytes -= prefix; + } + + words = bytes / 8; + + while (words) { + if (*(u64 *)start != value64) + return check_bytes8(start, value, 8); + start += 8; + words--; + } + + return check_bytes8(start, value, bytes % 8); +} + + + +int dma_map_sg(struct device *dev, struct scatterlist *sglist, + int nelems, int dir) +{ + struct scatterlist *s; + int i; + + for_each_sg(sglist, s, nelems, i) { + s->dma_address = (dma_addr_t)sg_phys(s); +#ifdef CONFIG_NEED_SG_DMA_LENGTH + s->dma_length = s->length; +#endif + } + + return nelems; +} + + +int vscnprintf(char *buf, size_t size, const char *fmt, va_list args) +{ + int i; + + i = vsnprintf(buf, size, fmt, args); + + if (likely(i < size)) + return i; + if (size != 0) + return size - 1; + return 0; +} + + +int scnprintf(char *buf, size_t size, const char *fmt, ...) +{ + va_list args; + int i; + + va_start(args, fmt); + i = vscnprintf(buf, size, fmt, args); + va_end(args); + + return i; +} + + + +#define _U 0x01 /* upper */ +#define _L 0x02 /* lower */ +#define _D 0x04 /* digit */ +#define _C 0x08 /* cntrl */ +#define _P 0x10 /* punct */ +#define _S 0x20 /* white space (space/lf/tab) */ +#define _X 0x40 /* hex digit */ +#define _SP 0x80 /* hard space (0x20) */ + +extern const unsigned char _ctype[]; + +#define __ismask(x) (_ctype[(int)(unsigned char)(x)]) + +#define isalnum(c) ((__ismask(c)&(_U|_L|_D)) != 0) +#define isalpha(c) ((__ismask(c)&(_U|_L)) != 0) +#define iscntrl(c) ((__ismask(c)&(_C)) != 0) +#define isdigit(c) ((__ismask(c)&(_D)) != 0) +#define isgraph(c) ((__ismask(c)&(_P|_U|_L|_D)) != 0) +#define islower(c) ((__ismask(c)&(_L)) != 0) +#define isprint(c) ((__ismask(c)&(_P|_U|_L|_D|_SP)) != 0) +#define ispunct(c) ((__ismask(c)&(_P)) != 0) +/* Note: isspace() must return false for %NUL-terminator */ +#define isspace(c) ((__ismask(c)&(_S)) != 0) +#define isupper(c) ((__ismask(c)&(_U)) != 0) +#define isxdigit(c) ((__ismask(c)&(_D|_X)) != 0) + +#define isascii(c) (((unsigned char)(c))<=0x7f) +#define toascii(c) (((unsigned char)(c))&0x7f) + +static inline unsigned char __tolower(unsigned char c) +{ + if (isupper(c)) + c -= 'A'-'a'; + return c; +} + +static inline unsigned char __toupper(unsigned char c) +{ + if (islower(c)) + c -= 'a'-'A'; + return c; +} + +#define tolower(c) __tolower(c) +#define toupper(c) __toupper(c) + +/* + * Fast implementation of tolower() for internal usage. Do not use in your + * code. + */ +static inline char _tolower(const char c) +{ + return c | 0x20; +} + + + +//const char hex_asc[] = "0123456789abcdef"; + +/** + * hex_to_bin - convert a hex digit to its real value + * @ch: ascii character represents hex digit + * + * hex_to_bin() converts one hex digit to its actual value or -1 in case of bad + * input. + */ +int hex_to_bin(char ch) +{ + if ((ch >= '0') && (ch <= '9')) + return ch - '0'; + ch = tolower(ch); + if ((ch >= 'a') && (ch <= 'f')) + return ch - 'a' + 10; + return -1; +} +EXPORT_SYMBOL(hex_to_bin); + +/** + * hex2bin - convert an ascii hexadecimal string to its binary representation + * @dst: binary result + * @src: ascii hexadecimal string + * @count: result length + * + * Return 0 on success, -1 in case of bad input. + */ +int hex2bin(u8 *dst, const char *src, size_t count) +{ + while (count--) { + int hi = hex_to_bin(*src++); + int lo = hex_to_bin(*src++); + + if ((hi < 0) || (lo < 0)) + return -1; + + *dst++ = (hi << 4) | lo; + } + return 0; +} +EXPORT_SYMBOL(hex2bin); + +/** + * hex_dump_to_buffer - convert a blob of data to "hex ASCII" in memory + * @buf: data blob to dump + * @len: number of bytes in the @buf + * @rowsize: number of bytes to print per line; must be 16 or 32 + * @groupsize: number of bytes to print at a time (1, 2, 4, 8; default = 1) + * @linebuf: where to put the converted data + * @linebuflen: total size of @linebuf, including space for terminating NUL + * @ascii: include ASCII after the hex output + * + * hex_dump_to_buffer() works on one "line" of output at a time, i.e., + * 16 or 32 bytes of input data converted to hex + ASCII output. + * + * Given a buffer of u8 data, hex_dump_to_buffer() converts the input data + * to a hex + ASCII dump at the supplied memory location. + * The converted output is always NUL-terminated. + * + * E.g.: + * hex_dump_to_buffer(frame->data, frame->len, 16, 1, + * linebuf, sizeof(linebuf), true); + * + * example output buffer: + * 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f @ABCDEFGHIJKLMNO + */ +void hex_dump_to_buffer(const void *buf, size_t len, int rowsize, + int groupsize, char *linebuf, size_t linebuflen, + bool ascii) +{ + const u8 *ptr = buf; + u8 ch; + int j, lx = 0; + int ascii_column; + + if (rowsize != 16 && rowsize != 32) + rowsize = 16; + + if (!len) + goto nil; + if (len > rowsize) /* limit to one line at a time */ + len = rowsize; + if ((len % groupsize) != 0) /* no mixed size output */ + groupsize = 1; + + switch (groupsize) { + case 8: { + const u64 *ptr8 = buf; + int ngroups = len / groupsize; + + for (j = 0; j < ngroups; j++) + lx += scnprintf(linebuf + lx, linebuflen - lx, + "%s%16.16llx", j ? " " : "", + (unsigned long long)*(ptr8 + j)); + ascii_column = 17 * ngroups + 2; + break; + } + + case 4: { + const u32 *ptr4 = buf; + int ngroups = len / groupsize; + + for (j = 0; j < ngroups; j++) + lx += scnprintf(linebuf + lx, linebuflen - lx, + "%s%8.8x", j ? " " : "", *(ptr4 + j)); + ascii_column = 9 * ngroups + 2; + break; + } + + case 2: { + const u16 *ptr2 = buf; + int ngroups = len / groupsize; + + for (j = 0; j < ngroups; j++) + lx += scnprintf(linebuf + lx, linebuflen - lx, + "%s%4.4x", j ? " " : "", *(ptr2 + j)); + ascii_column = 5 * ngroups + 2; + break; + } + + default: + for (j = 0; (j < len) && (lx + 3) <= linebuflen; j++) { + ch = ptr[j]; + linebuf[lx++] = hex_asc_hi(ch); + linebuf[lx++] = hex_asc_lo(ch); + linebuf[lx++] = ' '; + } + if (j) + lx--; + + ascii_column = 3 * rowsize + 2; + break; + } + if (!ascii) + goto nil; + + while (lx < (linebuflen - 1) && lx < (ascii_column - 1)) + linebuf[lx++] = ' '; + for (j = 0; (j < len) && (lx + 2) < linebuflen; j++) { + ch = ptr[j]; + linebuf[lx++] = (isascii(ch) && isprint(ch)) ? ch : '.'; + } +nil: + linebuf[lx++] = '\0'; +} + +/** + * print_hex_dump - print a text hex dump to syslog for a binary blob of data + * @level: kernel log level (e.g. KERN_DEBUG) + * @prefix_str: string to prefix each line with; + * caller supplies trailing spaces for alignment if desired + * @prefix_type: controls whether prefix of an offset, address, or none + * is printed (%DUMP_PREFIX_OFFSET, %DUMP_PREFIX_ADDRESS, %DUMP_PREFIX_NONE) + * @rowsize: number of bytes to print per line; must be 16 or 32 + * @groupsize: number of bytes to print at a time (1, 2, 4, 8; default = 1) + * @buf: data blob to dump + * @len: number of bytes in the @buf + * @ascii: include ASCII after the hex output + * + * Given a buffer of u8 data, print_hex_dump() prints a hex + ASCII dump + * to the kernel log at the specified kernel log level, with an optional + * leading prefix. + * + * print_hex_dump() works on one "line" of output at a time, i.e., + * 16 or 32 bytes of input data converted to hex + ASCII output. + * print_hex_dump() iterates over the entire input @buf, breaking it into + * "line size" chunks to format and print. + * + * E.g.: + * print_hex_dump(KERN_DEBUG, "raw data: ", DUMP_PREFIX_ADDRESS, + * 16, 1, frame->data, frame->len, true); + * + * Example output using %DUMP_PREFIX_OFFSET and 1-byte mode: + * 0009ab42: 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f @ABCDEFGHIJKLMNO + * Example output using %DUMP_PREFIX_ADDRESS and 4-byte mode: + * ffffffff88089af0: 73727170 77767574 7b7a7978 7f7e7d7c pqrstuvwxyz{|}~. + */ +void print_hex_dump(const char *level, const char *prefix_str, int prefix_type, + int rowsize, int groupsize, + const void *buf, size_t len, bool ascii) +{ + const u8 *ptr = buf; + int i, linelen, remaining = len; + unsigned char linebuf[32 * 3 + 2 + 32 + 1]; + + if (rowsize != 16 && rowsize != 32) + rowsize = 16; + + for (i = 0; i < len; i += rowsize) { + linelen = min(remaining, rowsize); + remaining -= rowsize; + + hex_dump_to_buffer(ptr + i, linelen, rowsize, groupsize, + linebuf, sizeof(linebuf), ascii); + + switch (prefix_type) { + case DUMP_PREFIX_ADDRESS: + printk("%s%s%p: %s\n", + level, prefix_str, ptr + i, linebuf); + break; + case DUMP_PREFIX_OFFSET: + printk("%s%s%.8x: %s\n", level, prefix_str, i, linebuf); + break; + default: + printk("%s%s%s\n", level, prefix_str, linebuf); + break; + } + } +} + +void print_hex_dump_bytes(const char *prefix_str, int prefix_type, + const void *buf, size_t len) +{ + print_hex_dump(KERN_DEBUG, prefix_str, prefix_type, 16, 1, + buf, len, true); +} + +