diff --git a/[refs] b/[refs]
index 321a080af47e..33ab1726f5dd 100644
--- a/[refs]
+++ b/[refs]
@@ -1,2 +1,2 @@
---
-refs/heads/master: 2216c9e74fb3baac3cb73952158dbe38b703997e
+refs/heads/master: 4a15903db02026728d0cf2755c6fabae16b8db6a
diff --git a/trunk/Documentation/DocBook/drm.tmpl b/trunk/Documentation/DocBook/drm.tmpl
index b0300529ab13..196b8b9dba11 100644
--- a/trunk/Documentation/DocBook/drm.tmpl
+++ b/trunk/Documentation/DocBook/drm.tmpl
@@ -6,36 +6,11 @@
Linux DRM Developer's Guide
-
-
- Jesse
- Barnes
- Initial version
-
- Intel Corporation
-
- jesse.barnes@intel.com
-
-
-
-
- Laurent
- Pinchart
- Driver internals
-
- Ideas on board SPRL
-
- laurent.pinchart@ideasonboard.com
-
-
-
-
-
2008-2009
- 2012
- Intel Corporation
- Laurent Pinchart
+
+ Intel Corporation (Jesse Barnes <jesse.barnes@intel.com>)
+
@@ -45,17 +20,6 @@
the kernel source COPYING file.
-
-
-
-
- 1.0
- 2012-07-13
- LP
- Added extensive documentation about driver internals.
-
-
-
@@ -108,361 +72,342 @@
submission & fencing, suspend/resume support, and DMA
services.
+
+ The core of every DRM driver is struct drm_driver. Drivers
+ typically statically initialize a drm_driver structure,
+ then pass it to drm_init() at load time.
+
- Driver Initialization
-
- At the core of every DRM driver is a drm_driver
- structure. Drivers typically statically initialize a drm_driver structure,
- and then pass it to one of the drm_*_init() functions
- to register it with the DRM subsystem.
+ Driver initialization
+
+ Before calling the DRM initialization routines, the driver must
+ first create and fill out a struct drm_driver structure.
+
+
+ static struct drm_driver driver = {
+ /* Don't use MTRRs here; the Xserver or userspace app should
+ * deal with them for Intel hardware.
+ */
+ .driver_features =
+ DRIVER_USE_AGP | DRIVER_REQUIRE_AGP |
+ DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED | DRIVER_MODESET,
+ .load = i915_driver_load,
+ .unload = i915_driver_unload,
+ .firstopen = i915_driver_firstopen,
+ .lastclose = i915_driver_lastclose,
+ .preclose = i915_driver_preclose,
+ .save = i915_save,
+ .restore = i915_restore,
+ .device_is_agp = i915_driver_device_is_agp,
+ .get_vblank_counter = i915_get_vblank_counter,
+ .enable_vblank = i915_enable_vblank,
+ .disable_vblank = i915_disable_vblank,
+ .irq_preinstall = i915_driver_irq_preinstall,
+ .irq_postinstall = i915_driver_irq_postinstall,
+ .irq_uninstall = i915_driver_irq_uninstall,
+ .irq_handler = i915_driver_irq_handler,
+ .reclaim_buffers = drm_core_reclaim_buffers,
+ .get_map_ofs = drm_core_get_map_ofs,
+ .get_reg_ofs = drm_core_get_reg_ofs,
+ .fb_probe = intelfb_probe,
+ .fb_remove = intelfb_remove,
+ .fb_resize = intelfb_resize,
+ .master_create = i915_master_create,
+ .master_destroy = i915_master_destroy,
+#if defined(CONFIG_DEBUG_FS)
+ .debugfs_init = i915_debugfs_init,
+ .debugfs_cleanup = i915_debugfs_cleanup,
+#endif
+ .gem_init_object = i915_gem_init_object,
+ .gem_free_object = i915_gem_free_object,
+ .gem_vm_ops = &i915_gem_vm_ops,
+ .ioctls = i915_ioctls,
+ .fops = {
+ .owner = THIS_MODULE,
+ .open = drm_open,
+ .release = drm_release,
+ .ioctl = drm_ioctl,
+ .mmap = drm_mmap,
+ .poll = drm_poll,
+ .fasync = drm_fasync,
+#ifdef CONFIG_COMPAT
+ .compat_ioctl = i915_compat_ioctl,
+#endif
+ .llseek = noop_llseek,
+ },
+ .pci_driver = {
+ .name = DRIVER_NAME,
+ .id_table = pciidlist,
+ .probe = probe,
+ .remove = __devexit_p(drm_cleanup_pci),
+ },
+ .name = DRIVER_NAME,
+ .desc = DRIVER_DESC,
+ .date = DRIVER_DATE,
+ .major = DRIVER_MAJOR,
+ .minor = DRIVER_MINOR,
+ .patchlevel = DRIVER_PATCHLEVEL,
+ };
+
+
+ In the example above, taken from the i915 DRM driver, the driver
+ sets several flags indicating what core features it supports;
+ we go over the individual callbacks in later sections. Since
+ flags indicate which features your driver supports to the DRM
+ core, you need to set most of them prior to calling drm_init(). Some,
+ like DRIVER_MODESET can be set later based on user supplied parameters,
+ but that's the exception rather than the rule.
+
+
+ Driver flags
+
+ DRIVER_USE_AGP
+
+ Driver uses AGP interface
+
+
+
+ DRIVER_REQUIRE_AGP
+
+ Driver needs AGP interface to function.
+
+
+
+ DRIVER_USE_MTRR
+
+
+ Driver uses MTRR interface for mapping memory. Deprecated.
+
+
+
+
+ DRIVER_PCI_DMA
+
+ Driver is capable of PCI DMA. Deprecated.
+
+
+
+ DRIVER_SG
+
+ Driver can perform scatter/gather DMA. Deprecated.
+
+
+
+ DRIVER_HAVE_DMA
+ Driver supports DMA. Deprecated.
+
+
+ DRIVER_HAVE_IRQDRIVER_IRQ_SHARED
+
+
+ DRIVER_HAVE_IRQ indicates whether the driver has an IRQ
+ handler. DRIVER_IRQ_SHARED indicates whether the device &
+ handler support shared IRQs (note that this is required of
+ PCI drivers).
+
+
+
+
+ DRIVER_DMA_QUEUE
+
+
+ Should be set if the driver queues DMA requests and completes them
+ asynchronously. Deprecated.
+
+
+
+
+ DRIVER_FB_DMA
+
+
+ Driver supports DMA to/from the framebuffer. Deprecated.
+
+
+
+
+ DRIVER_MODESET
+
+
+ Driver supports mode setting interfaces.
+
+
+
+
+
+ In this specific case, the driver requires AGP and supports
+ IRQs. DMA, as discussed later, is handled by device-specific ioctls
+ in this case. It also supports the kernel mode setting APIs, though
+ unlike in the actual i915 driver source, this example unconditionally
+ exports KMS capability.
-
- The drm_driver structure contains static
- information that describes the driver and features it supports, and
- pointers to methods that the DRM core will call to implement the DRM API.
- We will first go through the drm_driver static
- information fields, and will then describe individual operations in
- details as they get used in later sections.
+
+
+
+
+
+ Driver load
+
+ In the previous section, we saw what a typical drm_driver
+ structure might look like. One of the more important fields in
+ the structure is the hook for the load function.
+
+
+ static struct drm_driver driver = {
+ ...
+ .load = i915_driver_load,
+ ...
+ };
+
+
+ The load function has many responsibilities: allocating a driver
+ private structure, specifying supported performance counters,
+ configuring the device (e.g. mapping registers & command
+ buffers), initializing the memory manager, and setting up the
+ initial output configuration.
+
+
+ If compatibility is a concern (e.g. with drivers converted over
+ to the new interfaces from the old ones), care must be taken to
+ prevent device initialization and control that is incompatible with
+ currently active userspace drivers. For instance, if user
+ level mode setting drivers are in use, it would be problematic
+ to perform output discovery & configuration at load time.
+ Likewise, if user-level drivers unaware of memory management are
+ in use, memory management and command buffer setup may need to
+ be omitted. These requirements are driver-specific, and care
+ needs to be taken to keep both old and new applications and
+ libraries working. The i915 driver supports the "modeset"
+ module parameter to control whether advanced features are
+ enabled at load time or in legacy fashion.
+
- Driver Information
-
- Driver Features
-
- Drivers inform the DRM core about their requirements and supported
- features by setting appropriate flags in the
- driver_features field. Since those flags
- influence the DRM core behaviour since registration time, most of them
- must be set to registering the drm_driver
- instance.
-
- u32 driver_features;
-
- Driver Feature Flags
-
- DRIVER_USE_AGP
-
- Driver uses AGP interface, the DRM core will manage AGP resources.
-
-
-
- DRIVER_REQUIRE_AGP
-
- Driver needs AGP interface to function. AGP initialization failure
- will become a fatal error.
-
-
-
- DRIVER_USE_MTRR
-
- Driver uses MTRR interface for mapping memory, the DRM core will
- manage MTRR resources. Deprecated.
-
-
-
- DRIVER_PCI_DMA
-
- Driver is capable of PCI DMA, mapping of PCI DMA buffers to
- userspace will be enabled. Deprecated.
-
-
-
- DRIVER_SG
-
- Driver can perform scatter/gather DMA, allocation and mapping of
- scatter/gather buffers will be enabled. Deprecated.
-
-
-
- DRIVER_HAVE_DMA
-
- Driver supports DMA, the userspace DMA API will be supported.
- Deprecated.
-
-
-
- DRIVER_HAVE_IRQDRIVER_IRQ_SHARED
-
- DRIVER_HAVE_IRQ indicates whether the driver has an IRQ handler. The
- DRM core will automatically register an interrupt handler when the
- flag is set. DRIVER_IRQ_SHARED indicates whether the device &
- handler support shared IRQs (note that this is required of PCI
- drivers).
-
-
-
- DRIVER_IRQ_VBL
- Unused. Deprecated.
-
-
- DRIVER_DMA_QUEUE
-
- Should be set if the driver queues DMA requests and completes them
- asynchronously. Deprecated.
-
-
-
- DRIVER_FB_DMA
-
- Driver supports DMA to/from the framebuffer, mapping of frambuffer
- DMA buffers to userspace will be supported. Deprecated.
-
-
-
- DRIVER_IRQ_VBL2
- Unused. Deprecated.
-
-
- DRIVER_GEM
-
- Driver use the GEM memory manager.
-
-
-
- DRIVER_MODESET
-
- Driver supports mode setting interfaces (KMS).
-
-
-
- DRIVER_PRIME
-
- Driver implements DRM PRIME buffer sharing.
-
-
-
-
-
- Major, Minor and Patchlevel
- int major;
-int minor;
-int patchlevel;
-
- The DRM core identifies driver versions by a major, minor and patch
- level triplet. The information is printed to the kernel log at
- initialization time and passed to userspace through the
- DRM_IOCTL_VERSION ioctl.
-
-
- The major and minor numbers are also used to verify the requested driver
- API version passed to DRM_IOCTL_SET_VERSION. When the driver API changes
- between minor versions, applications can call DRM_IOCTL_SET_VERSION to
- select a specific version of the API. If the requested major isn't equal
- to the driver major, or the requested minor is larger than the driver
- minor, the DRM_IOCTL_SET_VERSION call will return an error. Otherwise
- the driver's set_version() method will be called with the requested
- version.
-
-
-
- Name, Description and Date
- char *name;
-char *desc;
-char *date;
-
- The driver name is printed to the kernel log at initialization time,
- used for IRQ registration and passed to userspace through
- DRM_IOCTL_VERSION.
-
-
- The driver description is a purely informative string passed to
- userspace through the DRM_IOCTL_VERSION ioctl and otherwise unused by
- the kernel.
-
-
- The driver date, formatted as YYYYMMDD, is meant to identify the date of
- the latest modification to the driver. However, as most drivers fail to
- update it, its value is mostly useless. The DRM core prints it to the
- kernel log at initialization time and passes it to userspace through the
- DRM_IOCTL_VERSION ioctl.
-
-
-
-
- Driver Load
+ Driver private & performance counters
- The load method is the driver and device
- initialization entry point. The method is responsible for allocating and
- initializing driver private data, specifying supported performance
- counters, performing resource allocation and mapping (e.g. acquiring
- clocks, mapping registers or allocating command buffers), initializing
- the memory manager (), installing
- the IRQ handler (), setting up
- vertical blanking handling (), mode
- setting () and initial output
- configuration ().
+ The driver private hangs off the main drm_device structure and
+ can be used for tracking various device-specific bits of
+ information, like register offsets, command buffer status,
+ register state for suspend/resume, etc. At load time, a
+ driver may simply allocate one and set drm_device.dev_priv
+ appropriately; it should be freed and drm_device.dev_priv set
+ to NULL when the driver is unloaded.
-
- If compatibility is a concern (e.g. with drivers converted over from
- User Mode Setting to Kernel Mode Setting), care must be taken to prevent
- device initialization and control that is incompatible with currently
- active userspace drivers. For instance, if user level mode setting
- drivers are in use, it would be problematic to perform output discovery
- & configuration at load time. Likewise, if user-level drivers
- unaware of memory management are in use, memory management and command
- buffer setup may need to be omitted. These requirements are
- driver-specific, and care needs to be taken to keep both old and new
- applications and libraries working.
-
- int (*load) (struct drm_device *, unsigned long flags);
- The method takes two arguments, a pointer to the newly created
- drm_device and flags. The flags are used to
- pass the driver_data field of the device id
- corresponding to the device passed to drm_*_init().
- Only PCI devices currently use this, USB and platform DRM drivers have
- their load method called with flags to 0.
+ The DRM supports several counters which may be used for rough
+ performance characterization. Note that the DRM stat counter
+ system is not often used by applications, and supporting
+ additional counters is completely optional.
+
+
+ These interfaces are deprecated and should not be used. If performance
+ monitoring is desired, the developer should investigate and
+ potentially enhance the kernel perf and tracing infrastructure to export
+ GPU related performance information for consumption by performance
+ monitoring tools and applications.
-
- Driver Private & Performance Counters
-
- The driver private hangs off the main
- drm_device structure and can be used for
- tracking various device-specific bits of information, like register
- offsets, command buffer status, register state for suspend/resume, etc.
- At load time, a driver may simply allocate one and set
- drm_device.dev_priv
- appropriately; it should be freed and
- drm_device.dev_priv
- set to NULL when the driver is unloaded.
-
-
- DRM supports several counters which were used for rough performance
- characterization. This stat counter system is deprecated and should not
- be used. If performance monitoring is desired, the developer should
- investigate and potentially enhance the kernel perf and tracing
- infrastructure to export GPU related performance information for
- consumption by performance monitoring tools and applications.
-
-
-
- IRQ Registration
-
- The DRM core tries to facilitate IRQ handler registration and
- unregistration by providing drm_irq_install and
- drm_irq_uninstall functions. Those functions only
- support a single interrupt per device.
-
-
-
- Both functions get the device IRQ by calling
- drm_dev_to_irq. This inline function will call a
- bus-specific operation to retrieve the IRQ number. For platform devices,
- platform_get_irq(..., 0) is used to retrieve the
- IRQ number.
-
-
- drm_irq_install starts by calling the
- irq_preinstall driver operation. The operation
- is optional and must make sure that the interrupt will not get fired by
- clearing all pending interrupt flags or disabling the interrupt.
-
-
- The IRQ will then be requested by a call to
- request_irq. If the DRIVER_IRQ_SHARED driver
- feature flag is set, a shared (IRQF_SHARED) IRQ handler will be
- requested.
-
-
- The IRQ handler function must be provided as the mandatory irq_handler
- driver operation. It will get passed directly to
- request_irq and thus has the same prototype as all
- IRQ handlers. It will get called with a pointer to the DRM device as the
- second argument.
-
-
- Finally the function calls the optional
- irq_postinstall driver operation. The operation
- usually enables interrupts (excluding the vblank interrupt, which is
- enabled separately), but drivers may choose to enable/disable interrupts
- at a different time.
-
-
- drm_irq_uninstall is similarly used to uninstall an
- IRQ handler. It starts by waking up all processes waiting on a vblank
- interrupt to make sure they don't hang, and then calls the optional
- irq_uninstall driver operation. The operation
- must disable all hardware interrupts. Finally the function frees the IRQ
- by calling free_irq.
-
-
-
- Memory Manager Initialization
-
- Every DRM driver requires a memory manager which must be initialized at
- load time. DRM currently contains two memory managers, the Translation
- Table Manager (TTM) and the Graphics Execution Manager (GEM).
- This document describes the use of the GEM memory manager only. See
- for details.
-
-
-
- Miscellaneous Device Configuration
-
- Another task that may be necessary for PCI devices during configuration
- is mapping the video BIOS. On many devices, the VBIOS describes device
- configuration, LCD panel timings (if any), and contains flags indicating
- device state. Mapping the BIOS can be done using the pci_map_rom() call,
- a convenience function that takes care of mapping the actual ROM,
- whether it has been shadowed into memory (typically at address 0xc0000)
- or exists on the PCI device in the ROM BAR. Note that after the ROM has
- been mapped and any necessary information has been extracted, it should
- be unmapped; on many devices, the ROM address decoder is shared with
- other BARs, so leaving it mapped could cause undesired behaviour like
- hangs or memory corruption.
-
-
-
-
-
+
+ Configuring the device
+
+ Obviously, device configuration is device-specific.
+ However, there are several common operations: finding a
+ device's PCI resources, mapping them, and potentially setting
+ up an IRQ handler.
+
+
+ Finding & mapping resources is fairly straightforward. The
+ DRM wrapper functions, drm_get_resource_start() and
+ drm_get_resource_len(), may be used to find BARs on the given
+ drm_device struct. Once those values have been retrieved, the
+ driver load function can call drm_addmap() to create a new
+ mapping for the BAR in question. Note that you probably want a
+ drm_local_map_t in your driver private structure to track any
+ mappings you create.
+
+
+
+
+ if compatibility with other operating systems isn't a concern
+ (DRM drivers can run under various BSD variants and OpenSolaris),
+ native Linux calls may be used for the above, e.g. pci_resource_*
+ and iomap*/iounmap. See the Linux device driver book for more
+ info.
+
+
+ Once you have a register map, you may use the DRM_READn() and
+ DRM_WRITEn() macros to access the registers on your device, or
+ use driver-specific versions to offset into your MMIO space
+ relative to a driver-specific base pointer (see I915_READ for
+ an example).
+
+
+ If your device supports interrupt generation, you may want to
+ set up an interrupt handler when the driver is loaded. This
+ is done using the drm_irq_install() function. If your device
+ supports vertical blank interrupts, it should call
+ drm_vblank_init() to initialize the core vblank handling code before
+ enabling interrupts on your device. This ensures the vblank related
+ structures are allocated and allows the core to handle vblank events.
+
+
+
+ Once your interrupt handler is registered (it uses your
+ drm_driver.irq_handler as the actual interrupt handling
+ function), you can safely enable interrupts on your device,
+ assuming any other state your interrupt handler uses is also
+ initialized.
+
+
+ Another task that may be necessary during configuration is
+ mapping the video BIOS. On many devices, the VBIOS describes
+ device configuration, LCD panel timings (if any), and contains
+ flags indicating device state. Mapping the BIOS can be done
+ using the pci_map_rom() call, a convenience function that
+ takes care of mapping the actual ROM, whether it has been
+ shadowed into memory (typically at address 0xc0000) or exists
+ on the PCI device in the ROM BAR. Note that after the ROM
+ has been mapped and any necessary information has been extracted,
+ it should be unmapped; on many devices, the ROM address decoder is
+ shared with other BARs, so leaving it mapped could cause
+ undesired behavior like hangs or memory corruption.
+
+
+
-
- Memory management
-
- Modern Linux systems require large amount of graphics memory to store
- frame buffers, textures, vertices and other graphics-related data. Given
- the very dynamic nature of many of that data, managing graphics memory
- efficiently is thus crucial for the graphics stack and plays a central
- role in the DRM infrastructure.
-
-
- The DRM core includes two memory managers, namely Translation Table Maps
- (TTM) and Graphics Execution Manager (GEM). TTM was the first DRM memory
- manager to be developed and tried to be a one-size-fits-them all
- solution. It provides a single userspace API to accomodate the need of
- all hardware, supporting both Unified Memory Architecture (UMA) devices
- and devices with dedicated video RAM (i.e. most discrete video cards).
- This resulted in a large, complex piece of code that turned out to be
- hard to use for driver development.
-
-
- GEM started as an Intel-sponsored project in reaction to TTM's
- complexity. Its design philosophy is completely different: instead of
- providing a solution to every graphics memory-related problems, GEM
- identified common code between drivers and created a support library to
- share it. GEM has simpler initialization and execution requirements than
- TTM, but has no video RAM management capabitilies and is thus limited to
- UMA devices.
-
- The Translation Table Manager (TTM)
+ Memory manager initialization
- TTM design background and information belongs here.
+ In order to allocate command buffers, cursor memory, scanout
+ buffers, etc., as well as support the latest features provided
+ by packages like Mesa and the X.Org X server, your driver
+ should support a memory manager.
+
+
+ If your driver supports memory management (it should!), you
+ need to set that up at load time as well. How you initialize
+ it depends on which memory manager you're using: TTM or GEM.
TTM initialization
- This section is outdated.
-
- Drivers wishing to support TTM must fill out a drm_bo_driver
- structure. The structure contains several fields with function
- pointers for initializing the TTM, allocating and freeing memory,
- waiting for command completion and fence synchronization, and memory
- migration. See the radeon_ttm.c file for an example of usage.
+
+ TTM (for Translation Table Manager) manages video memory and
+ aperture space for graphics devices. TTM supports both UMA devices
+ and devices with dedicated video RAM (VRAM), i.e. most discrete
+ graphics devices. If your device has dedicated RAM, supporting
+ TTM is desirable. TTM also integrates tightly with your
+ driver-specific buffer execution function. See the radeon
+ driver for examples.
+
+
+ The core TTM structure is the ttm_bo_driver struct. It contains
+ several fields with function pointers for initializing the TTM,
+ allocating and freeing memory, waiting for command completion
+ and fence synchronization, and memory migration. See the
+ radeon_ttm.c file for an example of usage.
The ttm_global_reference structure is made up of several fields:
@@ -500,1081 +445,82 @@ char *date;
count for the TTM, which will call your initialization function.
-
-
- The Graphics Execution Manager (GEM)
-
- The GEM design approach has resulted in a memory manager that doesn't
- provide full coverage of all (or even all common) use cases in its
- userspace or kernel API. GEM exposes a set of standard memory-related
- operations to userspace and a set of helper functions to drivers, and let
- drivers implement hardware-specific operations with their own private API.
-
-
- The GEM userspace API is described in the
- GEM - the Graphics
- Execution Manager article on LWN. While slightly
- outdated, the document provides a good overview of the GEM API principles.
- Buffer allocation and read and write operations, described as part of the
- common GEM API, are currently implemented using driver-specific ioctls.
-
-
- GEM is data-agnostic. It manages abstract buffer objects without knowing
- what individual buffers contain. APIs that require knowledge of buffer
- contents or purpose, such as buffer allocation or synchronization
- primitives, are thus outside of the scope of GEM and must be implemented
- using driver-specific ioctls.
-
-
- On a fundamental level, GEM involves several operations:
-
- Memory allocation and freeing
- Command execution
- Aperture management at command execution time
-
- Buffer object allocation is relatively straightforward and largely
- provided by Linux's shmem layer, which provides memory to back each
- object.
-
-
- Device-specific operations, such as command execution, pinning, buffer
- read & write, mapping, and domain ownership transfers are left to
- driver-specific ioctls.
-
-
- GEM Initialization
-
- Drivers that use GEM must set the DRIVER_GEM bit in the struct
- drm_driver
- driver_features field. The DRM core will
- then automatically initialize the GEM core before calling the
- load operation. Behind the scene, this will
- create a DRM Memory Manager object which provides an address space
- pool for object allocation.
-
-
- In a KMS configuration, drivers need to allocate and initialize a
- command ring buffer following core GEM initialization if required by
- the hardware. UMA devices usually have what is called a "stolen"
- memory region, which provides space for the initial framebuffer and
- large, contiguous memory regions required by the device. This space is
- typically not managed by GEM, and must be initialized separately into
- its own DRM MM object.
-
-
-
- GEM Objects Creation
-
- GEM splits creation of GEM objects and allocation of the memory that
- backs them in two distinct operations.
-
-
- GEM objects are represented by an instance of struct
- drm_gem_object. Drivers usually need to extend
- GEM objects with private information and thus create a driver-specific
- GEM object structure type that embeds an instance of struct
- drm_gem_object.
-
-
- To create a GEM object, a driver allocates memory for an instance of its
- specific GEM object type and initializes the embedded struct
- drm_gem_object with a call to
- drm_gem_object_init. The function takes a pointer to
- the DRM device, a pointer to the GEM object and the buffer object size
- in bytes.
-
-
- GEM uses shmem to allocate anonymous pageable memory.
- drm_gem_object_init will create an shmfs file of
- the requested size and store it into the struct
- drm_gem_object filp
- field. The memory is used as either main storage for the object when the
- graphics hardware uses system memory directly or as a backing store
- otherwise.
-
-
- Drivers are responsible for the actual physical pages allocation by
- calling shmem_read_mapping_page_gfp for each page.
- Note that they can decide to allocate pages when initializing the GEM
- object, or to delay allocation until the memory is needed (for instance
- when a page fault occurs as a result of a userspace memory access or
- when the driver needs to start a DMA transfer involving the memory).
-
-
- Anonymous pageable memory allocation is not always desired, for instance
- when the hardware requires physically contiguous system memory as is
- often the case in embedded devices. Drivers can create GEM objects with
- no shmfs backing (called private GEM objects) by initializing them with
- a call to drm_gem_private_object_init instead of
- drm_gem_object_init. Storage for private GEM
- objects must be managed by drivers.
-
-
- Drivers that do not need to extend GEM objects with private information
- can call the drm_gem_object_alloc function to
- allocate and initialize a struct drm_gem_object
- instance. The GEM core will call the optional driver
- gem_init_object operation after initializing
- the GEM object with drm_gem_object_init.
- int (*gem_init_object) (struct drm_gem_object *obj);
-
-
- No alloc-and-init function exists for private GEM objects.
-
-
-
- GEM Objects Lifetime
-
- All GEM objects are reference-counted by the GEM core. References can be
- acquired and release by calling drm_gem_object_reference
- and drm_gem_object_unreference respectively. The
- caller must hold the drm_device
- struct_mutex lock. As a convenience, GEM
- provides the drm_gem_object_reference_unlocked and
- drm_gem_object_unreference_unlocked functions that
- can be called without holding the lock.
-
-
- When the last reference to a GEM object is released the GEM core calls
- the drm_driver
- gem_free_object operation. That operation is
- mandatory for GEM-enabled drivers and must free the GEM object and all
- associated resources.
-
-
- void (*gem_free_object) (struct drm_gem_object *obj);
- Drivers are responsible for freeing all GEM object resources, including
- the resources created by the GEM core. If an mmap offset has been
- created for the object (in which case
- drm_gem_object::map_list::map
- is not NULL) it must be freed by a call to
- drm_gem_free_mmap_offset. The shmfs backing store
- must be released by calling drm_gem_object_release
- (that function can safely be called if no shmfs backing store has been
- created).
-
-
-
- GEM Objects Naming
-
- Communication between userspace and the kernel refers to GEM objects
- using local handles, global names or, more recently, file descriptors.
- All of those are 32-bit integer values; the usual Linux kernel limits
- apply to the file descriptors.
-
-
- GEM handles are local to a DRM file. Applications get a handle to a GEM
- object through a driver-specific ioctl, and can use that handle to refer
- to the GEM object in other standard or driver-specific ioctls. Closing a
- DRM file handle frees all its GEM handles and dereferences the
- associated GEM objects.
-
-
- To create a handle for a GEM object drivers call
- drm_gem_handle_create. The function takes a pointer
- to the DRM file and the GEM object and returns a locally unique handle.
- When the handle is no longer needed drivers delete it with a call to
- drm_gem_handle_delete. Finally the GEM object
- associated with a handle can be retrieved by a call to
- drm_gem_object_lookup.
-
-
- Handles don't take ownership of GEM objects, they only take a reference
- to the object that will be dropped when the handle is destroyed. To
- avoid leaking GEM objects, drivers must make sure they drop the
- reference(s) they own (such as the initial reference taken at object
- creation time) as appropriate, without any special consideration for the
- handle. For example, in the particular case of combined GEM object and
- handle creation in the implementation of the
- dumb_create operation, drivers must drop the
- initial reference to the GEM object before returning the handle.
-
-
- GEM names are similar in purpose to handles but are not local to DRM
- files. They can be passed between processes to reference a GEM object
- globally. Names can't be used directly to refer to objects in the DRM
- API, applications must convert handles to names and names to handles
- using the DRM_IOCTL_GEM_FLINK and DRM_IOCTL_GEM_OPEN ioctls
- respectively. The conversion is handled by the DRM core without any
- driver-specific support.
-
-
- Similar to global names, GEM file descriptors are also used to share GEM
- objects across processes. They offer additional security: as file
- descriptors must be explictly sent over UNIX domain sockets to be shared
- between applications, they can't be guessed like the globally unique GEM
- names.
-
-
- Drivers that support GEM file descriptors, also known as the DRM PRIME
- API, must set the DRIVER_PRIME bit in the struct
- drm_driver
- driver_features field, and implement the
- prime_handle_to_fd and
- prime_fd_to_handle operations.
-
-
- int (*prime_handle_to_fd)(struct drm_device *dev,
- struct drm_file *file_priv, uint32_t handle,
- uint32_t flags, int *prime_fd);
- int (*prime_fd_to_handle)(struct drm_device *dev,
- struct drm_file *file_priv, int prime_fd,
- uint32_t *handle);
- Those two operations convert a handle to a PRIME file descriptor and
- vice versa. Drivers must use the kernel dma-buf buffer sharing framework
- to manage the PRIME file descriptors.
-
-
- While non-GEM drivers must implement the operations themselves, GEM
- drivers must use the drm_gem_prime_handle_to_fd
- and drm_gem_prime_fd_to_handle helper functions.
- Those helpers rely on the driver
- gem_prime_export and
- gem_prime_import operations to create a dma-buf
- instance from a GEM object (dma-buf exporter role) and to create a GEM
- object from a dma-buf instance (dma-buf importer role).
-
-
- struct dma_buf * (*gem_prime_export)(struct drm_device *dev,
- struct drm_gem_object *obj,
- int flags);
- struct drm_gem_object * (*gem_prime_import)(struct drm_device *dev,
- struct dma_buf *dma_buf);
- These two operations are mandatory for GEM drivers that support DRM
- PRIME.
-
-
-
- GEM Objects Mapping
-
- Because mapping operations are fairly heavyweight GEM favours
- read/write-like access to buffers, implemented through driver-specific
- ioctls, over mapping buffers to userspace. However, when random access
- to the buffer is needed (to perform software rendering for instance),
- direct access to the object can be more efficient.
-
-
- The mmap system call can't be used directly to map GEM objects, as they
- don't have their own file handle. Two alternative methods currently
- co-exist to map GEM objects to userspace. The first method uses a
- driver-specific ioctl to perform the mapping operation, calling
- do_mmap under the hood. This is often considered
- dubious, seems to be discouraged for new GEM-enabled drivers, and will
- thus not be described here.
-
-
- The second method uses the mmap system call on the DRM file handle.
- void *mmap(void *addr, size_t length, int prot, int flags, int fd,
- off_t offset);
- DRM identifies the GEM object to be mapped by a fake offset passed
- through the mmap offset argument. Prior to being mapped, a GEM object
- must thus be associated with a fake offset. To do so, drivers must call
- drm_gem_create_mmap_offset on the object. The
- function allocates a fake offset range from a pool and stores the
- offset divided by PAGE_SIZE in
- obj->map_list.hash.key. Care must be taken not to
- call drm_gem_create_mmap_offset if a fake offset
- has already been allocated for the object. This can be tested by
- obj->map_list.map being non-NULL.
-
-
- Once allocated, the fake offset value
- (obj->map_list.hash.key << PAGE_SHIFT)
- must be passed to the application in a driver-specific way and can then
- be used as the mmap offset argument.
-
-
- The GEM core provides a helper method drm_gem_mmap
- to handle object mapping. The method can be set directly as the mmap
- file operation handler. It will look up the GEM object based on the
- offset value and set the VMA operations to the
- drm_driver gem_vm_ops
- field. Note that drm_gem_mmap doesn't map memory to
- userspace, but relies on the driver-provided fault handler to map pages
- individually.
-
-
- To use drm_gem_mmap, drivers must fill the struct
- drm_driver gem_vm_ops
- field with a pointer to VM operations.
-
-
- struct vm_operations_struct *gem_vm_ops
-
- struct vm_operations_struct {
- void (*open)(struct vm_area_struct * area);
- void (*close)(struct vm_area_struct * area);
- int (*fault)(struct vm_area_struct *vma, struct vm_fault *vmf);
- };
-
-
- The open and close
- operations must update the GEM object reference count. Drivers can use
- the drm_gem_vm_open and
- drm_gem_vm_close helper functions directly as open
- and close handlers.
-
-
- The fault operation handler is responsible for mapping individual pages
- to userspace when a page fault occurs. Depending on the memory
- allocation scheme, drivers can allocate pages at fault time, or can
- decide to allocate memory for the GEM object at the time the object is
- created.
-
-
- Drivers that want to map the GEM object upfront instead of handling page
- faults can implement their own mmap file operation handler.
-
-
-
- Dumb GEM Objects
-
- The GEM API doesn't standardize GEM objects creation and leaves it to
- driver-specific ioctls. While not an issue for full-fledged graphics
- stacks that include device-specific userspace components (in libdrm for
- instance), this limit makes DRM-based early boot graphics unnecessarily
- complex.
-
-
- Dumb GEM objects partly alleviate the problem by providing a standard
- API to create dumb buffers suitable for scanout, which can then be used
- to create KMS frame buffers.
-
-
- To support dumb GEM objects drivers must implement the
- dumb_create,
- dumb_destroy and
- dumb_map_offset operations.
-
-
-
- int (*dumb_create)(struct drm_file *file_priv, struct drm_device *dev,
- struct drm_mode_create_dumb *args);
-
- The dumb_create operation creates a GEM
- object suitable for scanout based on the width, height and depth
- from the struct drm_mode_create_dumb
- argument. It fills the argument's handle,
- pitch and size
- fields with a handle for the newly created GEM object and its line
- pitch and size in bytes.
-
-
-
- int (*dumb_destroy)(struct drm_file *file_priv, struct drm_device *dev,
- uint32_t handle);
-
- The dumb_destroy operation destroys a dumb
- GEM object created by dumb_create.
-
-
-
- int (*dumb_map_offset)(struct drm_file *file_priv, struct drm_device *dev,
- uint32_t handle, uint64_t *offset);
-
- The dumb_map_offset operation associates an
- mmap fake offset with the GEM object given by the handle and returns
- it. Drivers must use the
- drm_gem_create_mmap_offset function to
- associate the fake offset as described in
- .
-
-
-
-
-
- Memory Coherency
-
- When mapped to the device or used in a command buffer, backing pages
- for an object are flushed to memory and marked write combined so as to
- be coherent with the GPU. Likewise, if the CPU accesses an object
- after the GPU has finished rendering to the object, then the object
- must be made coherent with the CPU's view of memory, usually involving
- GPU cache flushing of various kinds. This core CPU<->GPU
- coherency management is provided by a device-specific ioctl, which
- evaluates an object's current domain and performs any necessary
- flushing or synchronization to put the object into the desired
- coherency domain (note that the object may be busy, i.e. an active
- render target; in that case, setting the domain blocks the client and
- waits for rendering to complete before performing any necessary
- flushing operations).
-
-
- Command Execution
-
- Perhaps the most important GEM function for GPU devices is providing a
- command execution interface to clients. Client programs construct
- command buffers containing references to previously allocated memory
- objects, and then submit them to GEM. At that point, GEM takes care to
- bind all the objects into the GTT, execute the buffer, and provide
- necessary synchronization between clients accessing the same buffers.
- This often involves evicting some objects from the GTT and re-binding
- others (a fairly expensive operation), and providing relocation
- support which hides fixed GTT offsets from clients. Clients must take
- care not to submit command buffers that reference more objects than
- can fit in the GTT; otherwise, GEM will reject them and no rendering
- will occur. Similarly, if several objects in the buffer require fence
- registers to be allocated for correct rendering (e.g. 2D blits on
- pre-965 chips), care must be taken not to require more fence registers
- than are available to the client. Such resource management should be
- abstracted from the client in libdrm.
-
-
-
-
-
-
-
-
- Mode Setting
-
- Drivers must initialize the mode setting core by calling
- drm_mode_config_init on the DRM device. The function
- initializes the drm_device
- mode_config field and never fails. Once done,
- mode configuration must be setup by initializing the following fields.
-
-
-
- int min_width, min_height;
-int max_width, max_height;
-
- Minimum and maximum width and height of the frame buffers in pixel
- units.
+ GEM initialization
+
+ GEM is an alternative to TTM, designed specifically for UMA
+ devices. It has simpler initialization and execution requirements
+ than TTM, but has no VRAM management capability. Core GEM
+ is initialized by calling drm_mm_init() to create
+ a GTT DRM MM object, which provides an address space pool for
+ object allocation. In a KMS configuration, the driver
+ needs to allocate and initialize a command ring buffer following
+ core GEM initialization. A UMA device usually has what is called a
+ "stolen" memory region, which provides space for the initial
+ framebuffer and large, contiguous memory regions required by the
+ device. This space is not typically managed by GEM, and it must
+ be initialized separately into its own DRM MM object.
+
+
+ Initialization is driver-specific. In the case of Intel
+ integrated graphics chips like 965GM, GEM initialization can
+ be done by calling the internal GEM init function,
+ i915_gem_do_init(). Since the 965GM is a UMA device
+ (i.e. it doesn't have dedicated VRAM), GEM manages
+ making regular RAM available for GPU operations. Memory set
+ aside by the BIOS (called "stolen" memory by the i915
+ driver) is managed by the DRM memrange allocator; the
+ rest of the aperture is managed by GEM.
+
+ /* Basic memrange allocator for stolen space (aka vram) */
+ drm_memrange_init(&dev_priv->vram, 0, prealloc_size);
+ /* Let GEM Manage from end of prealloc space to end of aperture */
+ i915_gem_do_init(dev, prealloc_size, agp_size);
+
+
+
+
+ Once the memory manager has been set up, we may allocate the
+ command buffer. In the i915 case, this is also done with a
+ GEM function, i915_gem_init_ringbuffer().
-
-
- struct drm_mode_config_funcs *funcs;
- Mode setting functions.
-
-
-
- Frame Buffer Creation
- struct drm_framebuffer *(*fb_create)(struct drm_device *dev,
- struct drm_file *file_priv,
- struct drm_mode_fb_cmd2 *mode_cmd);
-
- Frame buffers are abstract memory objects that provide a source of
- pixels to scanout to a CRTC. Applications explicitly request the
- creation of frame buffers through the DRM_IOCTL_MODE_ADDFB(2) ioctls and
- receive an opaque handle that can be passed to the KMS CRTC control,
- plane configuration and page flip functions.
-
-
- Frame buffers rely on the underneath memory manager for low-level memory
- operations. When creating a frame buffer applications pass a memory
- handle (or a list of memory handles for multi-planar formats) through
- the drm_mode_fb_cmd2 argument. This document
- assumes that the driver uses GEM, those handles thus reference GEM
- objects.
-
-
- Drivers must first validate the requested frame buffer parameters passed
- through the mode_cmd argument. In particular this is where invalid
- sizes, pixel formats or pitches can be caught.
-
-
- If the parameters are deemed valid, drivers then create, initialize and
- return an instance of struct drm_framebuffer.
- If desired the instance can be embedded in a larger driver-specific
- structure. The new instance is initialized with a call to
- drm_framebuffer_init which takes a pointer to DRM
- frame buffer operations (struct
- drm_framebuffer_funcs). Frame buffer operations are
-
-
- int (*create_handle)(struct drm_framebuffer *fb,
- struct drm_file *file_priv, unsigned int *handle);
-
- Create a handle to the frame buffer underlying memory object. If
- the frame buffer uses a multi-plane format, the handle will
- reference the memory object associated with the first plane.
-
-
- Drivers call drm_gem_handle_create to create
- the handle.
-
-
-
- void (*destroy)(struct drm_framebuffer *framebuffer);
-
- Destroy the frame buffer object and frees all associated
- resources. Drivers must call
- drm_framebuffer_cleanup to free resources
- allocated by the DRM core for the frame buffer object, and must
- make sure to unreference all memory objects associated with the
- frame buffer. Handles created by the
- create_handle operation are released by
- the DRM core.
-
-
-
- int (*dirty)(struct drm_framebuffer *framebuffer,
- struct drm_file *file_priv, unsigned flags, unsigned color,
- struct drm_clip_rect *clips, unsigned num_clips);
-
- This optional operation notifies the driver that a region of the
- frame buffer has changed in response to a DRM_IOCTL_MODE_DIRTYFB
- ioctl call.
-
-
-
-
-
- After initializing the drm_framebuffer
- instance drivers must fill its width,
- height, pitches,
- offsets, depth,
- bits_per_pixel and
- pixel_format fields from the values passed
- through the drm_mode_fb_cmd2 argument. They
- should call the drm_helper_mode_fill_fb_struct
- helper function to do so.
-
-
-
- Output Polling
- void (*output_poll_changed)(struct drm_device *dev);
-
- This operation notifies the driver that the status of one or more
- connectors has changed. Drivers that use the fb helper can just call the
- drm_fb_helper_hotplug_event function to handle this
- operation.
-
-
-
-
-
-
-
- KMS Initialization and Cleanup
-
- A KMS device is abstracted and exposed as a set of planes, CRTCs, encoders
- and connectors. KMS drivers must thus create and initialize all those
- objects at load time after initializing mode setting.
-
-
- CRTCs (struct drm_crtc)
-
- A CRTC is an abstraction representing a part of the chip that contains a
- pointer to a scanout buffer. Therefore, the number of CRTCs available
- determines how many independent scanout buffers can be active at any
- given time. The CRTC structure contains several fields to support this:
- a pointer to some video memory (abstracted as a frame buffer object), a
- display mode, and an (x, y) offset into the video memory to support
- panning or configurations where one piece of video memory spans multiple
- CRTCs.
-
-
- CRTC Initialization
-
- A KMS device must create and register at least one struct
- drm_crtc instance. The instance is allocated
- and zeroed by the driver, possibly as part of a larger structure, and
- registered with a call to drm_crtc_init with a
- pointer to CRTC functions.
-
-
-
- CRTC Operations
-
- Set Configuration
- int (*set_config)(struct drm_mode_set *set);
-
- Apply a new CRTC configuration to the device. The configuration
- specifies a CRTC, a frame buffer to scan out from, a (x,y) position in
- the frame buffer, a display mode and an array of connectors to drive
- with the CRTC if possible.
-
-
- If the frame buffer specified in the configuration is NULL, the driver
- must detach all encoders connected to the CRTC and all connectors
- attached to those encoders and disable them.
-
-
- This operation is called with the mode config lock held.
-
-
- FIXME: How should set_config interact with DPMS? If the CRTC is
- suspended, should it be resumed?
-
-
-
- Page Flipping
- int (*page_flip)(struct drm_crtc *crtc, struct drm_framebuffer *fb,
- struct drm_pending_vblank_event *event);
-
- Schedule a page flip to the given frame buffer for the CRTC. This
- operation is called with the mode config mutex held.
-
-
- Page flipping is a synchronization mechanism that replaces the frame
- buffer being scanned out by the CRTC with a new frame buffer during
- vertical blanking, avoiding tearing. When an application requests a page
- flip the DRM core verifies that the new frame buffer is large enough to
- be scanned out by the CRTC in the currently configured mode and then
- calls the CRTC page_flip operation with a
- pointer to the new frame buffer.
-
-
- The page_flip operation schedules a page flip.
- Once any pending rendering targetting the new frame buffer has
- completed, the CRTC will be reprogrammed to display that frame buffer
- after the next vertical refresh. The operation must return immediately
- without waiting for rendering or page flip to complete and must block
- any new rendering to the frame buffer until the page flip completes.
-
-
- If a page flip is already pending, the
- page_flip operation must return
- -EBUSY.
-
-
- To synchronize page flip to vertical blanking the driver will likely
- need to enable vertical blanking interrupts. It should call
- drm_vblank_get for that purpose, and call
- drm_vblank_put after the page flip completes.
-
-
- If the application has requested to be notified when page flip completes
- the page_flip operation will be called with a
- non-NULL event argument pointing to a
- drm_pending_vblank_event instance. Upon page
- flip completion the driver must fill the
- event::event
- sequence, tv_sec
- and tv_usec fields with the associated
- vertical blanking count and timestamp, add the event to the
- drm_file list of events to be signaled, and wake
- up any waiting process. This can be performed with
- event.sequence = drm_vblank_count_and_time(..., &now);
- event->event.tv_sec = now.tv_sec;
- event->event.tv_usec = now.tv_usec;
-
- spin_lock_irqsave(&dev->event_lock, flags);
- list_add_tail(&event->base.link, &event->base.file_priv->event_list);
- wake_up_interruptible(&event->base.file_priv->event_wait);
- spin_unlock_irqrestore(&dev->event_lock, flags);
- ]]>
-
-
- FIXME: Could drivers that don't need to wait for rendering to complete
- just add the event to dev->vblank_event_list and
- let the DRM core handle everything, as for "normal" vertical blanking
- events?
-
-
- While waiting for the page flip to complete, the
- event->base.link list head can be used freely by
- the driver to store the pending event in a driver-specific list.
-
-
- If the file handle is closed before the event is signaled, drivers must
- take care to destroy the event in their
- preclose operation (and, if needed, call
- drm_vblank_put).
-
-
-
- Miscellaneous
-
-
- void (*gamma_set)(struct drm_crtc *crtc, u16 *r, u16 *g, u16 *b,
- uint32_t start, uint32_t size);
-
- Apply a gamma table to the device. The operation is optional.
-
-
-
- void (*destroy)(struct drm_crtc *crtc);
-
- Destroy the CRTC when not needed anymore. See
- .
-
-
-
-
-
-
-
- Planes (struct drm_plane)
-
- A plane represents an image source that can be blended with or overlayed
- on top of a CRTC during the scanout process. Planes are associated with
- a frame buffer to crop a portion of the image memory (source) and
- optionally scale it to a destination size. The result is then blended
- with or overlayed on top of a CRTC.
-
-
- Plane Initialization
-
- Planes are optional. To create a plane, a KMS drivers allocates and
- zeroes an instances of struct drm_plane
- (possibly as part of a larger structure) and registers it with a call
- to drm_plane_init. The function takes a bitmask
- of the CRTCs that can be associated with the plane, a pointer to the
- plane functions and a list of format supported formats.
-
-
-
- Plane Operations
-
-
- int (*update_plane)(struct drm_plane *plane, struct drm_crtc *crtc,
- struct drm_framebuffer *fb, int crtc_x, int crtc_y,
- unsigned int crtc_w, unsigned int crtc_h,
- uint32_t src_x, uint32_t src_y,
- uint32_t src_w, uint32_t src_h);
-
- Enable and configure the plane to use the given CRTC and frame buffer.
-
-
- The source rectangle in frame buffer memory coordinates is given by
- the src_x, src_y,
- src_w and src_h
- parameters (as 16.16 fixed point values). Devices that don't support
- subpixel plane coordinates can ignore the fractional part.
-
-
- The destination rectangle in CRTC coordinates is given by the
- crtc_x, crtc_y,
- crtc_w and crtc_h
- parameters (as integer values). Devices scale the source rectangle to
- the destination rectangle. If scaling is not supported, and the source
- rectangle size doesn't match the destination rectangle size, the
- driver must return a -EINVAL error.
-
-
-
- int (*disable_plane)(struct drm_plane *plane);
-
- Disable the plane. The DRM core calls this method in response to a
- DRM_IOCTL_MODE_SETPLANE ioctl call with the frame buffer ID set to 0.
- Disabled planes must not be processed by the CRTC.
-
-
-
- void (*destroy)(struct drm_plane *plane);
-
- Destroy the plane when not needed anymore. See
- .
-
-
-
-
-
-
- Encoders (struct drm_encoder)
-
- An encoder takes pixel data from a CRTC and converts it to a format
- suitable for any attached connectors. On some devices, it may be
- possible to have a CRTC send data to more than one encoder. In that
- case, both encoders would receive data from the same scanout buffer,
- resulting in a "cloned" display configuration across the connectors
- attached to each encoder.
-
-
- Encoder Initialization
-
- As for CRTCs, a KMS driver must create, initialize and register at
- least one struct drm_encoder instance. The
- instance is allocated and zeroed by the driver, possibly as part of a
- larger structure.
-
-
- Drivers must initialize the struct drm_encoder
- possible_crtcs and
- possible_clones fields before registering the
- encoder. Both fields are bitmasks of respectively the CRTCs that the
- encoder can be connected to, and sibling encoders candidate for cloning.
-
-
- After being initialized, the encoder must be registered with a call to
- drm_encoder_init. The function takes a pointer to
- the encoder functions and an encoder type. Supported types are
-
-
- DRM_MODE_ENCODER_DAC for VGA and analog on DVI-I/DVI-A
-
-
- DRM_MODE_ENCODER_TMDS for DVI, HDMI and (embedded) DisplayPort
-
-
- DRM_MODE_ENCODER_LVDS for display panels
-
-
- DRM_MODE_ENCODER_TVDAC for TV output (Composite, S-Video, Component,
- SCART)
-
-
- DRM_MODE_ENCODER_VIRTUAL for virtual machine displays
-
-
-
-
- Encoders must be attached to a CRTC to be used. DRM drivers leave
- encoders unattached at initialization time. Applications (or the fbdev
- compatibility layer when implemented) are responsible for attaching the
- encoders they want to use to a CRTC.
-
-
-
- Encoder Operations
-
-
- void (*destroy)(struct drm_encoder *encoder);
-
- Called to destroy the encoder when not needed anymore. See
- .
-
-
-
+
- Connectors (struct drm_connector)
+ Output configuration
- A connector is the final destination for pixel data on a device, and
- usually connects directly to an external display device like a monitor
- or laptop panel. A connector can only be attached to one encoder at a
- time. The connector is also the structure where information about the
- attached display is kept, so it contains fields for display data, EDID
- data, DPMS & connection status, and information about modes
- supported on the attached displays.
+ The final initialization task is output configuration. This involves:
+
+
+ Finding and initializing the CRTCs, encoders, and connectors
+ for the device.
+
+
+ Creating an initial configuration.
+
+
+ Registering a framebuffer console driver.
+
+
- Connector Initialization
-
- Finally a KMS driver must create, initialize, register and attach at
- least one struct drm_connector instance. The
- instance is created as other KMS objects and initialized by setting the
- following fields.
-
-
-
- interlace_allowed
-
- Whether the connector can handle interlaced modes.
-
-
-
- doublescan_allowed
-
- Whether the connector can handle doublescan.
-
-
-
- display_info
-
-
- Display information is filled from EDID information when a display
- is detected. For non hot-pluggable displays such as flat panels in
- embedded systems, the driver should initialize the
- display_info.width_mm
- and
- display_info.height_mm
- fields with the physical size of the display.
-
-
-
- polled
-
- Connector polling mode, a combination of
-
-
- DRM_CONNECTOR_POLL_HPD
-
- The connector generates hotplug events and doesn't need to be
- periodically polled. The CONNECT and DISCONNECT flags must not
- be set together with the HPD flag.
-
-
-
- DRM_CONNECTOR_POLL_CONNECT
-
- Periodically poll the connector for connection.
-
-
-
- DRM_CONNECTOR_POLL_DISCONNECT
-
- Periodically poll the connector for disconnection.
-
-
-
- Set to 0 for connectors that don't support connection status
- discovery.
-
-
-
-
- The connector is then registered with a call to
- drm_connector_init with a pointer to the connector
- functions and a connector type, and exposed through sysfs with a call to
- drm_sysfs_connector_add.
-
-
- Supported connector types are
-
- DRM_MODE_CONNECTOR_VGA
- DRM_MODE_CONNECTOR_DVII
- DRM_MODE_CONNECTOR_DVID
- DRM_MODE_CONNECTOR_DVIA
- DRM_MODE_CONNECTOR_Composite
- DRM_MODE_CONNECTOR_SVIDEO
- DRM_MODE_CONNECTOR_LVDS
- DRM_MODE_CONNECTOR_Component
- DRM_MODE_CONNECTOR_9PinDIN
- DRM_MODE_CONNECTOR_DisplayPort
- DRM_MODE_CONNECTOR_HDMIA
- DRM_MODE_CONNECTOR_HDMIB
- DRM_MODE_CONNECTOR_TV
- DRM_MODE_CONNECTOR_eDP
- DRM_MODE_CONNECTOR_VIRTUAL
-
-
-
- Connectors must be attached to an encoder to be used. For devices that
- map connectors to encoders 1:1, the connector should be attached at
- initialization time with a call to
- drm_mode_connector_attach_encoder. The driver must
- also set the drm_connector
- encoder field to point to the attached
- encoder.
-
-
- Finally, drivers must initialize the connectors state change detection
- with a call to drm_kms_helper_poll_init. If at
- least one connector is pollable but can't generate hotplug interrupts
- (indicated by the DRM_CONNECTOR_POLL_CONNECT and
- DRM_CONNECTOR_POLL_DISCONNECT connector flags), a delayed work will
- automatically be queued to periodically poll for changes. Connectors
- that can generate hotplug interrupts must be marked with the
- DRM_CONNECTOR_POLL_HPD flag instead, and their interrupt handler must
- call drm_helper_hpd_irq_event. The function will
- queue a delayed work to check the state of all connectors, but no
- periodic polling will be done.
-
-
-
- Connector Operations
-
- Unless otherwise state, all operations are mandatory.
-
-
- DPMS
- void (*dpms)(struct drm_connector *connector, int mode);
-
- The DPMS operation sets the power state of a connector. The mode
- argument is one of
-
- DRM_MODE_DPMS_ON
- DRM_MODE_DPMS_STANDBY
- DRM_MODE_DPMS_SUSPEND
- DRM_MODE_DPMS_OFF
-
-
-
- In all but DPMS_ON mode the encoder to which the connector is attached
- should put the display in low-power mode by driving its signals
- appropriately. If more than one connector is attached to the encoder
- care should be taken not to change the power state of other displays as
- a side effect. Low-power mode should be propagated to the encoders and
- CRTCs when all related connectors are put in low-power mode.
-
-
-
- Modes
- int (*fill_modes)(struct drm_connector *connector, uint32_t max_width,
- uint32_t max_height);
-
- Fill the mode list with all supported modes for the connector. If the
- max_width and max_height
- arguments are non-zero, the implementation must ignore all modes wider
- than max_width or higher than
- max_height.
-
-
- The connector must also fill in this operation its
- display_info
- width_mm and
- height_mm fields with the connected display
- physical size in millimeters. The fields should be set to 0 if the value
- isn't known or is not applicable (for instance for projector devices).
-
-
-
- Connection Status
-
- The connection status is updated through polling or hotplug events when
- supported (see ). The status
- value is reported to userspace through ioctls and must not be used
- inside the driver, as it only gets initialized by a call to
- drm_mode_getconnector from userspace.
-
- enum drm_connector_status (*detect)(struct drm_connector *connector,
- bool force);
-
- Check to see if anything is attached to the connector. The
- force parameter is set to false whilst polling or
- to true when checking the connector due to user request.
- force can be used by the driver to avoid
- expensive, destructive operations during automated probing.
-
-
- Return connector_status_connected if something is connected to the
- connector, connector_status_disconnected if nothing is connected and
- connector_status_unknown if the connection state isn't known.
-
-
- Drivers should only return connector_status_connected if the connection
- status has really been probed as connected. Connectors that can't detect
- the connection status, or failed connection status probes, should return
- connector_status_unknown.
-
-
-
- Miscellaneous
-
-
- void (*destroy)(struct drm_connector *connector);
-
- Destroy the connector when not needed anymore. See
- .
-
-
-
-
-
-
-
- Cleanup
-
- The DRM core manages its objects' lifetime. When an object is not needed
- anymore the core calls its destroy function, which must clean up and
- free every resource allocated for the object. Every
- drm_*_init call must be matched with a
- corresponding drm_*_cleanup call to cleanup CRTCs
- (drm_crtc_cleanup), planes
- (drm_plane_cleanup), encoders
- (drm_encoder_cleanup) and connectors
- (drm_connector_cleanup). Furthermore, connectors
- that have been added to sysfs must be removed by a call to
- drm_sysfs_connector_remove before calling
- drm_connector_cleanup.
-
-
- Connectors state change detection must be cleanup up with a call to
- drm_kms_helper_poll_fini.
-
-
-
- Output discovery and initialization example
- Output discovery and initialization
+
+ Several core functions exist to create CRTCs, encoders, and
+ connectors, namely: drm_crtc_init(), drm_connector_init(), and
+ drm_encoder_init(), along with several "helper" functions to
+ perform common tasks.
+
+
+ Connectors should be registered with sysfs once they've been
+ detected and initialized, using the
+ drm_sysfs_connector_add() function. Likewise, when they're
+ removed from the system, they should be destroyed with
+ drm_sysfs_connector_remove().
+
+
+
-
- In the example above (taken from the i915 driver), a CRTC, connector and
- encoder combination is created. A device-specific i2c bus is also
- created for fetching EDID data and performing monitor detection. Once
- the process is complete, the new connector is registered with sysfs to
- make its properties available to applications.
-
+}
+]]>
+
+
+ In the example above (again, taken from the i915 driver), a
+ CRT connector and encoder combination is created. A device-specific
+ i2c bus is also created for fetching EDID data and
+ performing monitor detection. Once the process is complete,
+ the new connector is registered with sysfs to make its
+ properties available to applications.
+
+
+ Helper functions and core functions
+
+ Since many PC-class graphics devices have similar display output
+ designs, the DRM provides a set of helper functions to make
+ output management easier. The core helper routines handle
+ encoder re-routing and the disabling of unused functions following
+ mode setting. Using the helpers is optional, but recommended for
+ devices with PC-style architectures (i.e. a set of display planes
+ for feeding pixels to encoders which are in turn routed to
+ connectors). Devices with more complex requirements needing
+ finer grained management may opt to use the core callbacks
+ directly.
+
+
+ [Insert typical diagram here.] [Insert OMAP style config here.]
+
+
+
+ Each encoder object needs to provide:
+
+
+ A DPMS (basically on/off) function.
+
+
+ A mode-fixup function (for converting requested modes into
+ native hardware timings).
+
+
+ Functions (prepare, set, and commit) for use by the core DRM
+ helper functions.
+
+
+ Connector helpers need to provide functions (mode-fetch, validity,
+ and encoder-matching) for returning an ideal encoder for a given
+ connector. The core connector functions include a DPMS callback,
+ save/restore routines (deprecated), detection, mode probing,
+ property handling, and cleanup functions.
+
+
+
+
+
-
+
- Mid-layer Helper Functions
+ VBlank event handling
- The CRTC, encoder and connector functions provided by the drivers
- implement the DRM API. They're called by the DRM core and ioctl handlers
- to handle device state changes and configuration request. As implementing
- those functions often requires logic not specific to drivers, mid-layer
- helper functions are available to avoid duplicating boilerplate code.
-
-
- The DRM core contains one mid-layer implementation. The mid-layer provides
- implementations of several CRTC, encoder and connector functions (called
- from the top of the mid-layer) that pre-process requests and call
- lower-level functions provided by the driver (at the bottom of the
- mid-layer). For instance, the
- drm_crtc_helper_set_config function can be used to
- fill the struct drm_crtc_funcs
- set_config field. When called, it will split
- the set_config operation in smaller, simpler
- operations and call the driver to handle them.
+ The DRM core exposes two vertical blank related ioctls:
+
+
+ DRM_IOCTL_WAIT_VBLANK
+
+
+ This takes a struct drm_wait_vblank structure as its argument,
+ and it is used to block or request a signal when a specified
+ vblank event occurs.
+
+
+
+
+ DRM_IOCTL_MODESET_CTL
+
+
+ This should be called by application level drivers before and
+ after mode setting, since on many devices the vertical blank
+ counter is reset at that time. Internally, the DRM snapshots
+ the last vblank count when the ioctl is called with the
+ _DRM_PRE_MODESET command, so that the counter won't go backwards
+ (which is dealt with when _DRM_POST_MODESET is used).
+
+
+
+
+
- To use the mid-layer, drivers call drm_crtc_helper_add,
- drm_encoder_helper_add and
- drm_connector_helper_add functions to install their
- mid-layer bottom operations handlers, and fill the
- drm_crtc_funcs,
- drm_encoder_funcs and
- drm_connector_funcs structures with pointers to
- the mid-layer top API functions. Installing the mid-layer bottom operation
- handlers is best done right after registering the corresponding KMS object.
+ To support the functions above, the DRM core provides several
+ helper functions for tracking vertical blank counters, and
+ requires drivers to provide several callbacks:
+ get_vblank_counter(), enable_vblank() and disable_vblank(). The
+ core uses get_vblank_counter() to keep the counter accurate
+ across interrupt disable periods. It should return the current
+ vertical blank event count, which is often tracked in a device
+ register. The enable and disable vblank callbacks should enable
+ and disable vertical blank interrupts, respectively. In the
+ absence of DRM clients waiting on vblank events, the core DRM
+ code uses the disable_vblank() function to disable
+ interrupts, which saves power. They are re-enabled again when
+ a client calls the vblank wait ioctl above.
- The mid-layer is not split between CRTC, encoder and connector operations.
- To use it, a driver must provide bottom functions for all of the three KMS
- entities.
+ A device that doesn't provide a count register may simply use an
+ internal atomic counter incremented on every vertical blank
+ interrupt (and then treat the enable_vblank() and disable_vblank()
+ callbacks as no-ops).
-
- Helper Functions
-
-
- int drm_crtc_helper_set_config(struct drm_mode_set *set);
-
- The drm_crtc_helper_set_config helper function
- is a CRTC set_config implementation. It
- first tries to locate the best encoder for each connector by calling
- the connector best_encoder helper
- operation.
-
-
- After locating the appropriate encoders, the helper function will
- call the mode_fixup encoder and CRTC helper
- operations to adjust the requested mode, or reject it completely in
- which case an error will be returned to the application. If the new
- configuration after mode adjustment is identical to the current
- configuration the helper function will return without performing any
- other operation.
-
-
- If the adjusted mode is identical to the current mode but changes to
- the frame buffer need to be applied, the
- drm_crtc_helper_set_config function will call
- the CRTC mode_set_base helper operation. If
- the adjusted mode differs from the current mode, or if the
- mode_set_base helper operation is not
- provided, the helper function performs a full mode set sequence by
- calling the prepare,
- mode_set and
- commit CRTC and encoder helper operations,
- in that order.
-
-
-
- void drm_helper_connector_dpms(struct drm_connector *connector, int mode);
-
- The drm_helper_connector_dpms helper function
- is a connector dpms implementation that
- tracks power state of connectors. To use the function, drivers must
- provide dpms helper operations for CRTCs
- and encoders to apply the DPMS state to the device.
-
-
- The mid-layer doesn't track the power state of CRTCs and encoders.
- The dpms helper operations can thus be
- called with a mode identical to the currently active mode.
-
-
-
- int drm_helper_probe_single_connector_modes(struct drm_connector *connector,
- uint32_t maxX, uint32_t maxY);
-
- The drm_helper_probe_single_connector_modes helper
- function is a connector fill_modes
- implementation that updates the connection status for the connector
- and then retrieves a list of modes by calling the connector
- get_modes helper operation.
-
-
- The function filters out modes larger than
- max_width and max_height
- if specified. It then calls the connector
- mode_valid helper operation for each mode in
- the probed list to check whether the mode is valid for the connector.
-
-
-
-
-
- CRTC Helper Operations
-
-
- bool (*mode_fixup)(struct drm_crtc *crtc,
- const struct drm_display_mode *mode,
- struct drm_display_mode *adjusted_mode);
-
- Let CRTCs adjust the requested mode or reject it completely. This
- operation returns true if the mode is accepted (possibly after being
- adjusted) or false if it is rejected.
-
-
- The mode_fixup operation should reject the
- mode if it can't reasonably use it. The definition of "reasonable"
- is currently fuzzy in this context. One possible behaviour would be
- to set the adjusted mode to the panel timings when a fixed-mode
- panel is used with hardware capable of scaling. Another behaviour
- would be to accept any input mode and adjust it to the closest mode
- supported by the hardware (FIXME: This needs to be clarified).
-
-
-
- int (*mode_set_base)(struct drm_crtc *crtc, int x, int y,
- struct drm_framebuffer *old_fb)
-
- Move the CRTC on the current frame buffer (stored in
- crtc->fb) to position (x,y). Any of the frame
- buffer, x position or y position may have been modified.
-
-
- This helper operation is optional. If not provided, the
- drm_crtc_helper_set_config function will fall
- back to the mode_set helper operation.
-
-
- FIXME: Why are x and y passed as arguments, as they can be accessed
- through crtc->x and
- crtc->y?
-
-
-
- void (*prepare)(struct drm_crtc *crtc);
-
- Prepare the CRTC for mode setting. This operation is called after
- validating the requested mode. Drivers use it to perform
- device-specific operations required before setting the new mode.
-
-
-
- int (*mode_set)(struct drm_crtc *crtc, struct drm_display_mode *mode,
- struct drm_display_mode *adjusted_mode, int x, int y,
- struct drm_framebuffer *old_fb);
-
- Set a new mode, position and frame buffer. Depending on the device
- requirements, the mode can be stored internally by the driver and
- applied in the commit operation, or
- programmed to the hardware immediately.
-
-
- The mode_set operation returns 0 on success
- or a negative error code if an error occurs.
-
-
-
- void (*commit)(struct drm_crtc *crtc);
-
- Commit a mode. This operation is called after setting the new mode.
- Upon return the device must use the new mode and be fully
- operational.
-
-
-
-
-
- Encoder Helper Operations
-
-
- bool (*mode_fixup)(struct drm_encoder *encoder,
- const struct drm_display_mode *mode,
- struct drm_display_mode *adjusted_mode);
-
- FIXME: The mode argument be const, but the i915 driver modifies
- mode->clock in intel_dp_mode_fixup.
-
-
- Let encoders adjust the requested mode or reject it completely. This
- operation returns true if the mode is accepted (possibly after being
- adjusted) or false if it is rejected. See the
- mode_fixup CRTC helper
- operation for an explanation of the allowed adjustments.
-
-
-
- void (*prepare)(struct drm_encoder *encoder);
-
- Prepare the encoder for mode setting. This operation is called after
- validating the requested mode. Drivers use it to perform
- device-specific operations required before setting the new mode.
-
-
-
- void (*mode_set)(struct drm_encoder *encoder,
- struct drm_display_mode *mode,
- struct drm_display_mode *adjusted_mode);
-
- Set a new mode. Depending on the device requirements, the mode can
- be stored internally by the driver and applied in the
- commit operation, or programmed to the
- hardware immediately.
-
-
-
- void (*commit)(struct drm_encoder *encoder);
-
- Commit a mode. This operation is called after setting the new mode.
- Upon return the device must use the new mode and be fully
- operational.
-
-
-
-
-
- Connector Helper Operations
-
-
- struct drm_encoder *(*best_encoder)(struct drm_connector *connector);
-
- Return a pointer to the best encoder for the connecter. Device that
- map connectors to encoders 1:1 simply return the pointer to the
- associated encoder. This operation is mandatory.
-
-
-
- int (*get_modes)(struct drm_connector *connector);
-
- Fill the connector's probed_modes list
- by parsing EDID data with drm_add_edid_modes or
- calling drm_mode_probed_add directly for every
- supported mode and return the number of modes it has detected. This
- operation is mandatory.
-
-
- When adding modes manually the driver creates each mode with a call to
- drm_mode_create and must fill the following fields.
-
-
- __u32 type;
-
- Mode type bitmask, a combination of
-
-
- DRM_MODE_TYPE_BUILTIN
- not used?
-
-
- DRM_MODE_TYPE_CLOCK_C
- not used?
-
-
- DRM_MODE_TYPE_CRTC_C
- not used?
-
-
-
- DRM_MODE_TYPE_PREFERRED - The preferred mode for the connector
-
-
- not used?
-
-
-
- DRM_MODE_TYPE_DEFAULT
- not used?
-
-
- DRM_MODE_TYPE_USERDEF
- not used?
-
-
- DRM_MODE_TYPE_DRIVER
-
-
- The mode has been created by the driver (as opposed to
- to user-created modes).
-
-
-
-
- Drivers must set the DRM_MODE_TYPE_DRIVER bit for all modes they
- create, and set the DRM_MODE_TYPE_PREFERRED bit for the preferred
- mode.
-
-
-
- __u32 clock;
- Pixel clock frequency in kHz unit
-
-
- __u16 hdisplay, hsync_start, hsync_end, htotal;
- __u16 vdisplay, vsync_start, vsync_end, vtotal;
- Horizontal and vertical timing information
- <----------------><-------------><-------------->
-
- //////////////////////|
- ////////////////////// |
- ////////////////////// |.................. ................
- _______________
-
- <----- [hv]display ----->
- <------------- [hv]sync_start ------------>
- <--------------------- [hv]sync_end --------------------->
- <-------------------------------- [hv]total ----------------------------->
-]]>
-
-
- __u16 hskew;
- __u16 vscan;
- Unknown
-
-
- __u32 flags;
-
- Mode flags, a combination of
-
-
- DRM_MODE_FLAG_PHSYNC
-
- Horizontal sync is active high
-
-
-
- DRM_MODE_FLAG_NHSYNC
-
- Horizontal sync is active low
-
-
-
- DRM_MODE_FLAG_PVSYNC
-
- Vertical sync is active high
-
-
-
- DRM_MODE_FLAG_NVSYNC
-
- Vertical sync is active low
-
-
-
- DRM_MODE_FLAG_INTERLACE
-
- Mode is interlaced
-
-
-
- DRM_MODE_FLAG_DBLSCAN
-
- Mode uses doublescan
-
-
-
- DRM_MODE_FLAG_CSYNC
-
- Mode uses composite sync
-
-
-
- DRM_MODE_FLAG_PCSYNC
-
- Composite sync is active high
-
-
-
- DRM_MODE_FLAG_NCSYNC
-
- Composite sync is active low
-
-
-
- DRM_MODE_FLAG_HSKEW
-
- hskew provided (not used?)
-
-
-
- DRM_MODE_FLAG_BCAST
-
- not used?
-
-
-
- DRM_MODE_FLAG_PIXMUX
-
- not used?
-
-
-
- DRM_MODE_FLAG_DBLCLK
-
- not used?
-
-
-
- DRM_MODE_FLAG_CLKDIV2
-
- ?
-
-
-
-
-
- Note that modes marked with the INTERLACE or DBLSCAN flags will be
- filtered out by
- drm_helper_probe_single_connector_modes if
- the connector's interlace_allowed or
- doublescan_allowed field is set to 0.
-
-
-
- char name[DRM_DISPLAY_MODE_LEN];
-
- Mode name. The driver must call
- drm_mode_set_name to fill the mode name from
- hdisplay,
- vdisplay and interlace flag after
- filling the corresponding fields.
-
-
-
-
-
- The vrefresh value is computed by
- drm_helper_probe_single_connector_modes.
-
-
- When parsing EDID data, drm_add_edid_modes fill the
- connector display_info
- width_mm and
- height_mm fields. When creating modes
- manually the get_modes helper operation must
- set the display_info
- width_mm and
- height_mm fields if they haven't been set
- already (for instance at initilization time when a fixed-size panel is
- attached to the connector). The mode width_mm
- and height_mm fields are only used internally
- during EDID parsing and should not be set when creating modes manually.
-
-
-
- int (*mode_valid)(struct drm_connector *connector,
- struct drm_display_mode *mode);
-
- Verify whether a mode is valid for the connector. Return MODE_OK for
- supported modes and one of the enum drm_mode_status values (MODE_*)
- for unsupported modes. This operation is mandatory.
-
-
- As the mode rejection reason is currently not used beside for
- immediately removing the unsupported mode, an implementation can
- return MODE_BAD regardless of the exact reason why the mode is not
- valid.
-
-
- Note that the mode_valid helper operation is
- only called for modes detected by the device, and
- not for modes set by the user through the CRTC
- set_config operation.
-
-
-
-
-
-
-
- Vertical Blanking
-
- Vertical blanking plays a major role in graphics rendering. To achieve
- tear-free display, users must synchronize page flips and/or rendering to
- vertical blanking. The DRM API offers ioctls to perform page flips
- synchronized to vertical blanking and wait for vertical blanking.
-
-
- The DRM core handles most of the vertical blanking management logic, which
- involves filtering out spurious interrupts, keeping race-free blanking
- counters, coping with counter wrap-around and resets and keeping use
- counts. It relies on the driver to generate vertical blanking interrupts
- and optionally provide a hardware vertical blanking counter. Drivers must
- implement the following operations.
-
-
-
- int (*enable_vblank) (struct drm_device *dev, int crtc);
-void (*disable_vblank) (struct drm_device *dev, int crtc);
-
- Enable or disable vertical blanking interrupts for the given CRTC.
-
-
-
- u32 (*get_vblank_counter) (struct drm_device *dev, int crtc);
-
- Retrieve the value of the vertical blanking counter for the given
- CRTC. If the hardware maintains a vertical blanking counter its value
- should be returned. Otherwise drivers can use the
- drm_vblank_count helper function to handle this
- operation.
-
-
-
-
- Drivers must initialize the vertical blanking handling core with a call to
- drm_vblank_init in their
- load operation. The function will set the struct
- drm_device
- vblank_disable_allowed field to 0. This will
- keep vertical blanking interrupts enabled permanently until the first mode
- set operation, where vblank_disable_allowed is
- set to 1. The reason behind this is not clear. Drivers can set the field
- to 1 after calling drm_vblank_init to make vertical
- blanking interrupts dynamically managed from the beginning.
-
-
- Vertical blanking interrupts can be enabled by the DRM core or by drivers
- themselves (for instance to handle page flipping operations). The DRM core
- maintains a vertical blanking use count to ensure that the interrupts are
- not disabled while a user still needs them. To increment the use count,
- drivers call drm_vblank_get. Upon return vertical
- blanking interrupts are guaranteed to be enabled.
-
-
- To decrement the use count drivers call
- drm_vblank_put. Only when the use count drops to zero
- will the DRM core disable the vertical blanking interrupts after a delay
- by scheduling a timer. The delay is accessible through the vblankoffdelay
- module parameter or the drm_vblank_offdelay global
- variable and expressed in milliseconds. Its default value is 5000 ms.
-
-
- When a vertical blanking interrupt occurs drivers only need to call the
- drm_handle_vblank function to account for the
- interrupt.
-
+
+ Memory management
- Resources allocated by drm_vblank_init must be freed
- with a call to drm_vblank_cleanup in the driver
- unload operation handler.
+ The memory manager lies at the heart of many DRM operations; it
+ is required to support advanced client features like OpenGL
+ pbuffers. The DRM currently contains two memory managers: TTM
+ and GEM.
-
-
-
-
- Open/Close, File Operations and IOCTLs
- Open and Close
- int (*firstopen) (struct drm_device *);
-void (*lastclose) (struct drm_device *);
-int (*open) (struct drm_device *, struct drm_file *);
-void (*preclose) (struct drm_device *, struct drm_file *);
-void (*postclose) (struct drm_device *, struct drm_file *);
- Open and close handlers. None of those methods are mandatory.
-
-
- The firstopen method is called by the DRM core
- when an application opens a device that has no other opened file handle.
- Similarly the lastclose method is called when
- the last application holding a file handle opened on the device closes
- it. Both methods are mostly used for UMS (User Mode Setting) drivers to
- acquire and release device resources which should be done in the
- load and unload
- methods for KMS drivers.
-
-
- Note that the lastclose method is also called
- at module unload time or, for hot-pluggable devices, when the device is
- unplugged. The firstopen and
- lastclose calls can thus be unbalanced.
-
-
- The open method is called every time the device
- is opened by an application. Drivers can allocate per-file private data
- in this method and store them in the struct
- drm_file driver_priv
- field. Note that the open method is called
- before firstopen.
-
+ The Translation Table Manager (TTM)
- The close operation is split into preclose and
- postclose methods. Drivers must stop and
- cleanup all per-file operations in the preclose
- method. For instance pending vertical blanking and page flip events must
- be cancelled. No per-file operation is allowed on the file handle after
- returning from the preclose method.
+ TTM was developed by Tungsten Graphics, primarily by Thomas
+ Hellström, and is intended to be a flexible, high performance
+ graphics memory manager.
- Finally the postclose method is called as the
- last step of the close operation, right before calling the
- lastclose method if no other open file handle
- exists for the device. Drivers that have allocated per-file private data
- in the open method should free it here.
+ Drivers wishing to support TTM must fill out a drm_bo_driver
+ structure.
- The lastclose method should restore CRTC and
- plane properties to default value, so that a subsequent open of the
- device will not inherit state from the previous user.
+ TTM design background and information belongs here.
+
- File Operations
- const struct file_operations *fops
- File operations for the DRM device node.
-
- Drivers must define the file operations structure that forms the DRM
- userspace API entry point, even though most of those operations are
- implemented in the DRM core. The open,
- release and ioctl
- operations are handled by
-
- .owner = THIS_MODULE,
- .open = drm_open,
- .release = drm_release,
- .unlocked_ioctl = drm_ioctl,
- #ifdef CONFIG_COMPAT
- .compat_ioctl = drm_compat_ioctl,
- #endif
-
-
-
- Drivers that implement private ioctls that requires 32/64bit
- compatibility support must provide their own
- compat_ioctl handler that processes private
- ioctls and calls drm_compat_ioctl for core ioctls.
-
-
- The read and poll
- operations provide support for reading DRM events and polling them. They
- are implemented by
-
- .poll = drm_poll,
- .read = drm_read,
- .fasync = drm_fasync,
- .llseek = no_llseek,
-
-
-
- The memory mapping implementation varies depending on how the driver
- manages memory. Pre-GEM drivers will use drm_mmap,
- while GEM-aware drivers will use drm_gem_mmap. See
- .
-
- .mmap = drm_gem_mmap,
-
-
+ The Graphics Execution Manager (GEM)
- No other file operation is supported by the DRM API.
+ GEM is an Intel project, authored by Eric Anholt and Keith
+ Packard. It provides simpler interfaces than TTM, and is well
+ suited for UMA devices.
-
-
- IOCTLs
- struct drm_ioctl_desc *ioctls;
-int num_ioctls;
- Driver-specific ioctls descriptors table.
- Driver-specific ioctls numbers start at DRM_COMMAND_BASE. The ioctls
- descriptors table is indexed by the ioctl number offset from the base
- value. Drivers can use the DRM_IOCTL_DEF_DRV() macro to initialize the
- table entries.
+ GEM-enabled drivers must provide gem_init_object() and
+ gem_free_object() callbacks to support the core memory
+ allocation routines. They should also provide several driver-specific
+ ioctls to support command execution, pinning, buffer
+ read & write, mapping, and domain ownership transfers.
- DRM_IOCTL_DEF_DRV(ioctl, func, flags)
-
- ioctl is the ioctl name. Drivers must define
- the DRM_##ioctl and DRM_IOCTL_##ioctl macros to the ioctl number
- offset from DRM_COMMAND_BASE and the ioctl number respectively. The
- first macro is private to the device while the second must be exposed
- to userspace in a public header.
-
-
- func is a pointer to the ioctl handler function
- compatible with the drm_ioctl_t type.
- typedef int drm_ioctl_t(struct drm_device *dev, void *data,
- struct drm_file *file_priv);
-
-
- flags is a bitmask combination of the following
- values. It restricts how the ioctl is allowed to be called.
-
-
- DRM_AUTH - Only authenticated callers allowed
-
-
- DRM_MASTER - The ioctl can only be called on the master file
- handle
-
-
- DRM_ROOT_ONLY - Only callers with the SYSADMIN capability allowed
-
-
- DRM_CONTROL_ALLOW - The ioctl can only be called on a control
- device
-
-
- DRM_UNLOCKED - The ioctl handler will be called without locking
- the DRM global mutex
-
-
-
+ On a fundamental level, GEM involves several operations:
+
+ Memory allocation and freeing
+ Command execution
+ Aperture management at command execution time
+
+ Buffer object allocation is relatively
+ straightforward and largely provided by Linux's shmem layer, which
+ provides memory to back each object. When mapped into the GTT
+ or used in a command buffer, the backing pages for an object are
+ flushed to memory and marked write combined so as to be coherent
+ with the GPU. Likewise, if the CPU accesses an object after the GPU
+ has finished rendering to the object, then the object must be made
+ coherent with the CPU's view
+ of memory, usually involving GPU cache flushing of various kinds.
+ This core CPU<->GPU coherency management is provided by a
+ device-specific ioctl, which evaluates an object's current domain and
+ performs any necessary flushing or synchronization to put the object
+ into the desired coherency domain (note that the object may be busy,
+ i.e. an active render target; in that case, setting the domain
+ blocks the client and waits for rendering to complete before
+ performing any necessary flushing operations).
+
+
+ Perhaps the most important GEM function is providing a command
+ execution interface to clients. Client programs construct command
+ buffers containing references to previously allocated memory objects,
+ and then submit them to GEM. At that point, GEM takes care to bind
+ all the objects into the GTT, execute the buffer, and provide
+ necessary synchronization between clients accessing the same buffers.
+ This often involves evicting some objects from the GTT and re-binding
+ others (a fairly expensive operation), and providing relocation
+ support which hides fixed GTT offsets from clients. Clients must
+ take care not to submit command buffers that reference more objects
+ than can fit in the GTT; otherwise, GEM will reject them and no rendering
+ will occur. Similarly, if several objects in the buffer require
+ fence registers to be allocated for correct rendering (e.g. 2D blits
+ on pre-965 chips), care must be taken not to require more fence
+ registers than are available to the client. Such resource management
+ should be abstracted from the client in libdrm.
+
+
- Command submission & fencing
+ Output management
- This should cover a few device-specific command submission
- implementations.
+ At the core of the DRM output management code is a set of
+ structures representing CRTCs, encoders, and connectors.
+
+
+ A CRTC is an abstraction representing a part of the chip that
+ contains a pointer to a scanout buffer. Therefore, the number
+ of CRTCs available determines how many independent scanout
+ buffers can be active at any given time. The CRTC structure
+ contains several fields to support this: a pointer to some video
+ memory, a display mode, and an (x, y) offset into the video
+ memory to support panning or configurations where one piece of
+ video memory spans multiple CRTCs.
+
+
+ An encoder takes pixel data from a CRTC and converts it to a
+ format suitable for any attached connectors. On some devices,
+ it may be possible to have a CRTC send data to more than one
+ encoder. In that case, both encoders would receive data from
+ the same scanout buffer, resulting in a "cloned" display
+ configuration across the connectors attached to each encoder.
+
+
+ A connector is the final destination for pixel data on a device,
+ and usually connects directly to an external display device like
+ a monitor or laptop panel. A connector can only be attached to
+ one encoder at a time. The connector is also the structure
+ where information about the attached display is kept, so it
+ contains fields for display data, EDID data, DPMS &
+ connection status, and information about modes supported on the
+ attached displays.
+
-
+
+ Framebuffer management
+
+ Clients need to provide a framebuffer object which provides a source
+ of pixels for a CRTC to deliver to the encoder(s) and ultimately the
+ connector(s). A framebuffer is fundamentally a driver-specific memory
+ object, made into an opaque handle by the DRM's addfb() function.
+ Once a framebuffer has been created this way, it may be passed to the
+ KMS mode setting routines for use in a completed configuration.
+
+
- Suspend/Resume
+ Command submission & fencing
- The DRM core provides some suspend/resume code, but drivers wanting full
- suspend/resume support should provide save() and restore() functions.
- These are called at suspend, hibernate, or resume time, and should perform
- any state save or restore required by your device across suspend or
- hibernate states.
+ This should cover a few device-specific command submission
+ implementations.
- int (*suspend) (struct drm_device *, pm_message_t state);
-int (*resume) (struct drm_device *);
+
+
+
+ Suspend/resume
- Those are legacy suspend and resume methods. New driver should use the
- power management interface provided by their bus type (usually through
- the struct device_driver dev_pm_ops) and set
- these methods to NULL.
+ The DRM core provides some suspend/resume code, but drivers
+ wanting full suspend/resume support should provide save() and
+ restore() functions. These are called at suspend,
+ hibernate, or resume time, and should perform any state save or
+ restore required by your device across suspend or hibernate
+ states.
@@ -2385,35 +833,6 @@ int (*resume) (struct drm_device *);
-
-
@@ -2434,42 +853,6 @@ int (*resume) (struct drm_device *);
Cover generic ioctls and sysfs layout here. We only need high-level
info, since man pages should cover the rest.
-
-
-
-
- VBlank event handling
-
- The DRM core exposes two vertical blank related ioctls:
-
-
- DRM_IOCTL_WAIT_VBLANK
-
-
- This takes a struct drm_wait_vblank structure as its argument,
- and it is used to block or request a signal when a specified
- vblank event occurs.
-
-
-
-
- DRM_IOCTL_MODESET_CTL
-
-
- This should be called by application level drivers before and
- after mode setting, since on many devices the vertical blank
- counter is reset at that time. Internally, the DRM snapshots
- the last vblank count when the ioctl is called with the
- _DRM_PRE_MODESET command, so that the counter won't go backwards
- (which is dealt with when _DRM_POST_MODESET is used).
-
-
-
-
-
-
-
-
diff --git a/trunk/MAINTAINERS b/trunk/MAINTAINERS
index b17587d9412f..fdc0119963e7 100644
--- a/trunk/MAINTAINERS
+++ b/trunk/MAINTAINERS
@@ -3388,7 +3388,7 @@ M: "Wolfram Sang (embedded platforms)"
L: linux-i2c@vger.kernel.org
W: http://i2c.wiki.kernel.org/
T: quilt kernel.org/pub/linux/kernel/people/jdelvare/linux-2.6/jdelvare-i2c/
-T: git git://git.pengutronix.de/git/wsa/linux.git
+T: git git://git.fluff.org/bjdooks/linux.git
S: Maintained
F: Documentation/i2c/
F: drivers/i2c/
@@ -3666,12 +3666,11 @@ F: Documentation/networking/README.ipw2200
F: drivers/net/wireless/ipw2x00/
INTEL(R) TRUSTED EXECUTION TECHNOLOGY (TXT)
-M: Richard L Maliszewski
-M: Gang Wei
+M: Joseph Cihula
M: Shane Wang
L: tboot-devel@lists.sourceforge.net
W: http://tboot.sourceforge.net
-T: hg http://tboot.hg.sourceforge.net:8000/hgroot/tboot/tboot
+T: Mercurial http://www.bughost.org/repos.hg/tboot.hg
S: Supported
F: Documentation/intel_txt.txt
F: include/linux/tboot.h
diff --git a/trunk/Makefile b/trunk/Makefile
index a3c11d589681..0f66f146d57e 100644
--- a/trunk/Makefile
+++ b/trunk/Makefile
@@ -1,8 +1,8 @@
VERSION = 3
PATCHLEVEL = 6
SUBLEVEL = 0
-EXTRAVERSION = -rc7
-NAME = Terrified Chipmunk
+EXTRAVERSION = -rc5
+NAME = Saber-toothed Squirrel
# *DOCUMENTATION*
# To see a list of typical targets execute "make help"
diff --git a/trunk/arch/arm/Kconfig.debug b/trunk/arch/arm/Kconfig.debug
index e968a52e4881..f15f82bf3a50 100644
--- a/trunk/arch/arm/Kconfig.debug
+++ b/trunk/arch/arm/Kconfig.debug
@@ -356,15 +356,15 @@ choice
is nothing connected to read from the DCC.
config DEBUG_SEMIHOSTING
- bool "Kernel low-level debug output via semihosting I/O"
+ bool "Kernel low-level debug output via semihosting I"
help
Semihosting enables code running on an ARM target to use
the I/O facilities on a host debugger/emulator through a
- simple SVC call. The host debugger or emulator must have
+ simple SVC calls. The host debugger or emulator must have
semihosting enabled for the special svc call to be trapped
otherwise the kernel will crash.
- This is known to work with OpenOCD, as well as
+ This is known to work with OpenOCD, as wellas
ARM's Fast Models, or any other controlling environment
that implements semihosting.
diff --git a/trunk/arch/arm/Makefile b/trunk/arch/arm/Makefile
index a051dfbdd7db..30eae87ead6d 100644
--- a/trunk/arch/arm/Makefile
+++ b/trunk/arch/arm/Makefile
@@ -284,10 +284,10 @@ zImage Image xipImage bootpImage uImage: vmlinux
zinstall uinstall install: vmlinux
$(Q)$(MAKE) $(build)=$(boot) MACHINE=$(MACHINE) $@
-%.dtb: scripts
+%.dtb:
$(Q)$(MAKE) $(build)=$(boot) MACHINE=$(MACHINE) $(boot)/$@
-dtbs: scripts
+dtbs:
$(Q)$(MAKE) $(build)=$(boot) MACHINE=$(MACHINE) $(boot)/$@
# We use MRPROPER_FILES and CLEAN_FILES now
diff --git a/trunk/arch/arm/boot/compressed/head.S b/trunk/arch/arm/boot/compressed/head.S
index bc67cbff3944..b8c64b80bafc 100644
--- a/trunk/arch/arm/boot/compressed/head.S
+++ b/trunk/arch/arm/boot/compressed/head.S
@@ -653,21 +653,16 @@ __armv7_mmu_cache_on:
mcrne p15, 0, r0, c8, c7, 0 @ flush I,D TLBs
#endif
mrc p15, 0, r0, c1, c0, 0 @ read control reg
- bic r0, r0, #1 << 28 @ clear SCTLR.TRE
orr r0, r0, #0x5000 @ I-cache enable, RR cache replacement
orr r0, r0, #0x003c @ write buffer
#ifdef CONFIG_MMU
#ifdef CONFIG_CPU_ENDIAN_BE8
orr r0, r0, #1 << 25 @ big-endian page tables
#endif
- mrcne p15, 0, r6, c2, c0, 2 @ read ttb control reg
orrne r0, r0, #1 @ MMU enabled
movne r1, #0xfffffffd @ domain 0 = client
- bic r6, r6, #1 << 31 @ 32-bit translation system
- bic r6, r6, #3 << 0 @ use only ttbr0
mcrne p15, 0, r3, c2, c0, 0 @ load page table pointer
mcrne p15, 0, r1, c3, c0, 0 @ load domain access control
- mcrne p15, 0, r6, c2, c0, 2 @ load ttb control
#endif
mcr p15, 0, r0, c7, c5, 4 @ ISB
mcr p15, 0, r0, c1, c0, 0 @ load control register
diff --git a/trunk/arch/arm/boot/dts/at91sam9260.dtsi b/trunk/arch/arm/boot/dts/at91sam9260.dtsi
index 7c95f76398de..66389c1c6f62 100644
--- a/trunk/arch/arm/boot/dts/at91sam9260.dtsi
+++ b/trunk/arch/arm/boot/dts/at91sam9260.dtsi
@@ -104,7 +104,6 @@
#gpio-cells = <2>;
gpio-controller;
interrupt-controller;
- #interrupt-cells = <2>;
};
pioB: gpio@fffff600 {
@@ -114,7 +113,6 @@
#gpio-cells = <2>;
gpio-controller;
interrupt-controller;
- #interrupt-cells = <2>;
};
pioC: gpio@fffff800 {
@@ -124,7 +122,6 @@
#gpio-cells = <2>;
gpio-controller;
interrupt-controller;
- #interrupt-cells = <2>;
};
dbgu: serial@fffff200 {
diff --git a/trunk/arch/arm/boot/dts/at91sam9263.dtsi b/trunk/arch/arm/boot/dts/at91sam9263.dtsi
index 195019b7ca0e..b460d6ce9eb5 100644
--- a/trunk/arch/arm/boot/dts/at91sam9263.dtsi
+++ b/trunk/arch/arm/boot/dts/at91sam9263.dtsi
@@ -95,7 +95,6 @@
#gpio-cells = <2>;
gpio-controller;
interrupt-controller;
- #interrupt-cells = <2>;
};
pioB: gpio@fffff400 {
@@ -105,7 +104,6 @@
#gpio-cells = <2>;
gpio-controller;
interrupt-controller;
- #interrupt-cells = <2>;
};
pioC: gpio@fffff600 {
@@ -115,7 +113,6 @@
#gpio-cells = <2>;
gpio-controller;
interrupt-controller;
- #interrupt-cells = <2>;
};
pioD: gpio@fffff800 {
@@ -125,7 +122,6 @@
#gpio-cells = <2>;
gpio-controller;
interrupt-controller;
- #interrupt-cells = <2>;
};
pioE: gpio@fffffa00 {
@@ -135,7 +131,6 @@
#gpio-cells = <2>;
gpio-controller;
interrupt-controller;
- #interrupt-cells = <2>;
};
dbgu: serial@ffffee00 {
diff --git a/trunk/arch/arm/boot/dts/at91sam9g45.dtsi b/trunk/arch/arm/boot/dts/at91sam9g45.dtsi
index 63751b1e744b..bafa8806fc17 100644
--- a/trunk/arch/arm/boot/dts/at91sam9g45.dtsi
+++ b/trunk/arch/arm/boot/dts/at91sam9g45.dtsi
@@ -113,7 +113,6 @@
#gpio-cells = <2>;
gpio-controller;
interrupt-controller;
- #interrupt-cells = <2>;
};
pioB: gpio@fffff400 {
@@ -123,7 +122,6 @@
#gpio-cells = <2>;
gpio-controller;
interrupt-controller;
- #interrupt-cells = <2>;
};
pioC: gpio@fffff600 {
@@ -133,7 +131,6 @@
#gpio-cells = <2>;
gpio-controller;
interrupt-controller;
- #interrupt-cells = <2>;
};
pioD: gpio@fffff800 {
@@ -143,7 +140,6 @@
#gpio-cells = <2>;
gpio-controller;
interrupt-controller;
- #interrupt-cells = <2>;
};
pioE: gpio@fffffa00 {
@@ -153,7 +149,6 @@
#gpio-cells = <2>;
gpio-controller;
interrupt-controller;
- #interrupt-cells = <2>;
};
dbgu: serial@ffffee00 {
diff --git a/trunk/arch/arm/boot/dts/at91sam9n12.dtsi b/trunk/arch/arm/boot/dts/at91sam9n12.dtsi
index ef9336ae9614..bfac0dfc332c 100644
--- a/trunk/arch/arm/boot/dts/at91sam9n12.dtsi
+++ b/trunk/arch/arm/boot/dts/at91sam9n12.dtsi
@@ -107,7 +107,6 @@
#gpio-cells = <2>;
gpio-controller;
interrupt-controller;
- #interrupt-cells = <2>;
};
pioB: gpio@fffff600 {
@@ -117,7 +116,6 @@
#gpio-cells = <2>;
gpio-controller;
interrupt-controller;
- #interrupt-cells = <2>;
};
pioC: gpio@fffff800 {
@@ -127,7 +125,6 @@
#gpio-cells = <2>;
gpio-controller;
interrupt-controller;
- #interrupt-cells = <2>;
};
pioD: gpio@fffffa00 {
@@ -137,7 +134,6 @@
#gpio-cells = <2>;
gpio-controller;
interrupt-controller;
- #interrupt-cells = <2>;
};
dbgu: serial@fffff200 {
diff --git a/trunk/arch/arm/boot/dts/at91sam9x5.dtsi b/trunk/arch/arm/boot/dts/at91sam9x5.dtsi
index 8a387a8d61b7..4a18c393b136 100644
--- a/trunk/arch/arm/boot/dts/at91sam9x5.dtsi
+++ b/trunk/arch/arm/boot/dts/at91sam9x5.dtsi
@@ -115,7 +115,6 @@
#gpio-cells = <2>;
gpio-controller;
interrupt-controller;
- #interrupt-cells = <2>;
};
pioB: gpio@fffff600 {
@@ -125,7 +124,6 @@
#gpio-cells = <2>;
gpio-controller;
interrupt-controller;
- #interrupt-cells = <2>;
};
pioC: gpio@fffff800 {
@@ -135,7 +133,6 @@
#gpio-cells = <2>;
gpio-controller;
interrupt-controller;
- #interrupt-cells = <2>;
};
pioD: gpio@fffffa00 {
@@ -145,7 +142,6 @@
#gpio-cells = <2>;
gpio-controller;
interrupt-controller;
- #interrupt-cells = <2>;
};
dbgu: serial@fffff200 {
diff --git a/trunk/arch/arm/include/asm/assembler.h b/trunk/arch/arm/include/asm/assembler.h
index 5c8b3bf4d825..03fb93621d0d 100644
--- a/trunk/arch/arm/include/asm/assembler.h
+++ b/trunk/arch/arm/include/asm/assembler.h
@@ -320,12 +320,4 @@
.size \name , . - \name
.endm
- .macro check_uaccess, addr:req, size:req, limit:req, tmp:req, bad:req
-#ifndef CONFIG_CPU_USE_DOMAINS
- adds \tmp, \addr, #\size - 1
- sbcccs \tmp, \tmp, \limit
- bcs \bad
-#endif
- .endm
-
#endif /* __ASM_ASSEMBLER_H__ */
diff --git a/trunk/arch/arm/include/asm/memory.h b/trunk/arch/arm/include/asm/memory.h
index 5f6ddcc56452..e965f1b560f1 100644
--- a/trunk/arch/arm/include/asm/memory.h
+++ b/trunk/arch/arm/include/asm/memory.h
@@ -187,7 +187,6 @@ static inline unsigned long __phys_to_virt(unsigned long x)
#define __phys_to_virt(x) ((x) - PHYS_OFFSET + PAGE_OFFSET)
#endif
#endif
-#endif /* __ASSEMBLY__ */
#ifndef PHYS_OFFSET
#ifdef PLAT_PHYS_OFFSET
@@ -197,8 +196,6 @@ static inline unsigned long __phys_to_virt(unsigned long x)
#endif
#endif
-#ifndef __ASSEMBLY__
-
/*
* PFNs are used to describe any physical page; this means
* PFN 0 == physical address 0.
diff --git a/trunk/arch/arm/include/asm/tlb.h b/trunk/arch/arm/include/asm/tlb.h
index 99a19512ee26..314d4664eae7 100644
--- a/trunk/arch/arm/include/asm/tlb.h
+++ b/trunk/arch/arm/include/asm/tlb.h
@@ -199,9 +199,6 @@ static inline void __pte_free_tlb(struct mmu_gather *tlb, pgtable_t pte,
{
pgtable_page_dtor(pte);
-#ifdef CONFIG_ARM_LPAE
- tlb_add_flush(tlb, addr);
-#else
/*
* With the classic ARM MMU, a pte page has two corresponding pmd
* entries, each covering 1MB.
@@ -209,7 +206,6 @@ static inline void __pte_free_tlb(struct mmu_gather *tlb, pgtable_t pte,
addr &= PMD_MASK;
tlb_add_flush(tlb, addr + SZ_1M - PAGE_SIZE);
tlb_add_flush(tlb, addr + SZ_1M);
-#endif
tlb_remove_page(tlb, pte);
}
diff --git a/trunk/arch/arm/include/asm/uaccess.h b/trunk/arch/arm/include/asm/uaccess.h
index 77bd79f2ffdb..479a6352e0b5 100644
--- a/trunk/arch/arm/include/asm/uaccess.h
+++ b/trunk/arch/arm/include/asm/uaccess.h
@@ -101,39 +101,28 @@ extern int __get_user_1(void *);
extern int __get_user_2(void *);
extern int __get_user_4(void *);
-#define __GUP_CLOBBER_1 "lr", "cc"
-#ifdef CONFIG_CPU_USE_DOMAINS
-#define __GUP_CLOBBER_2 "ip", "lr", "cc"
-#else
-#define __GUP_CLOBBER_2 "lr", "cc"
-#endif
-#define __GUP_CLOBBER_4 "lr", "cc"
-
-#define __get_user_x(__r2,__p,__e,__l,__s) \
+#define __get_user_x(__r2,__p,__e,__s,__i...) \
__asm__ __volatile__ ( \
__asmeq("%0", "r0") __asmeq("%1", "r2") \
- __asmeq("%3", "r1") \
"bl __get_user_" #__s \
: "=&r" (__e), "=r" (__r2) \
- : "0" (__p), "r" (__l) \
- : __GUP_CLOBBER_##__s)
+ : "0" (__p) \
+ : __i, "cc")
-#define __get_user_check(x,p) \
+#define get_user(x,p) \
({ \
- unsigned long __limit = current_thread_info()->addr_limit - 1; \
register const typeof(*(p)) __user *__p asm("r0") = (p);\
register unsigned long __r2 asm("r2"); \
- register unsigned long __l asm("r1") = __limit; \
register int __e asm("r0"); \
switch (sizeof(*(__p))) { \
case 1: \
- __get_user_x(__r2, __p, __e, __l, 1); \
- break; \
+ __get_user_x(__r2, __p, __e, 1, "lr"); \
+ break; \
case 2: \
- __get_user_x(__r2, __p, __e, __l, 2); \
+ __get_user_x(__r2, __p, __e, 2, "r3", "lr"); \
break; \
case 4: \
- __get_user_x(__r2, __p, __e, __l, 4); \
+ __get_user_x(__r2, __p, __e, 4, "lr"); \
break; \
default: __e = __get_user_bad(); break; \
} \
@@ -141,57 +130,42 @@ extern int __get_user_4(void *);
__e; \
})
-#define get_user(x,p) \
- ({ \
- might_fault(); \
- __get_user_check(x,p); \
- })
-
extern int __put_user_1(void *, unsigned int);
extern int __put_user_2(void *, unsigned int);
extern int __put_user_4(void *, unsigned int);
extern int __put_user_8(void *, unsigned long long);
-#define __put_user_x(__r2,__p,__e,__l,__s) \
+#define __put_user_x(__r2,__p,__e,__s) \
__asm__ __volatile__ ( \
__asmeq("%0", "r0") __asmeq("%2", "r2") \
- __asmeq("%3", "r1") \
"bl __put_user_" #__s \
: "=&r" (__e) \
- : "0" (__p), "r" (__r2), "r" (__l) \
+ : "0" (__p), "r" (__r2) \
: "ip", "lr", "cc")
-#define __put_user_check(x,p) \
+#define put_user(x,p) \
({ \
- unsigned long __limit = current_thread_info()->addr_limit - 1; \
register const typeof(*(p)) __r2 asm("r2") = (x); \
register const typeof(*(p)) __user *__p asm("r0") = (p);\
- register unsigned long __l asm("r1") = __limit; \
register int __e asm("r0"); \
switch (sizeof(*(__p))) { \
case 1: \
- __put_user_x(__r2, __p, __e, __l, 1); \
+ __put_user_x(__r2, __p, __e, 1); \
break; \
case 2: \
- __put_user_x(__r2, __p, __e, __l, 2); \
+ __put_user_x(__r2, __p, __e, 2); \
break; \
case 4: \
- __put_user_x(__r2, __p, __e, __l, 4); \
+ __put_user_x(__r2, __p, __e, 4); \
break; \
case 8: \
- __put_user_x(__r2, __p, __e, __l, 8); \
+ __put_user_x(__r2, __p, __e, 8); \
break; \
default: __e = __put_user_bad(); break; \
} \
__e; \
})
-#define put_user(x,p) \
- ({ \
- might_fault(); \
- __put_user_check(x,p); \
- })
-
#else /* CONFIG_MMU */
/*
@@ -245,7 +219,6 @@ do { \
unsigned long __gu_addr = (unsigned long)(ptr); \
unsigned long __gu_val; \
__chk_user_ptr(ptr); \
- might_fault(); \
switch (sizeof(*(ptr))) { \
case 1: __get_user_asm_byte(__gu_val,__gu_addr,err); break; \
case 2: __get_user_asm_half(__gu_val,__gu_addr,err); break; \
@@ -327,7 +300,6 @@ do { \
unsigned long __pu_addr = (unsigned long)(ptr); \
__typeof__(*(ptr)) __pu_val = (x); \
__chk_user_ptr(ptr); \
- might_fault(); \
switch (sizeof(*(ptr))) { \
case 1: __put_user_asm_byte(__pu_val,__pu_addr,err); break; \
case 2: __put_user_asm_half(__pu_val,__pu_addr,err); break; \
diff --git a/trunk/arch/arm/include/asm/unistd.h b/trunk/arch/arm/include/asm/unistd.h
index 2fde5fd1acce..0cab47d4a83f 100644
--- a/trunk/arch/arm/include/asm/unistd.h
+++ b/trunk/arch/arm/include/asm/unistd.h
@@ -404,7 +404,6 @@
#define __NR_setns (__NR_SYSCALL_BASE+375)
#define __NR_process_vm_readv (__NR_SYSCALL_BASE+376)
#define __NR_process_vm_writev (__NR_SYSCALL_BASE+377)
- /* 378 for kcmp */
/*
* The following SWIs are ARM private.
@@ -484,7 +483,6 @@
*/
#define __IGNORE_fadvise64_64
#define __IGNORE_migrate_pages
-#define __IGNORE_kcmp
#endif /* __KERNEL__ */
#endif /* __ASM_ARM_UNISTD_H */
diff --git a/trunk/arch/arm/kernel/calls.S b/trunk/arch/arm/kernel/calls.S
index e337879595e5..463ff4a0ec8a 100644
--- a/trunk/arch/arm/kernel/calls.S
+++ b/trunk/arch/arm/kernel/calls.S
@@ -387,7 +387,6 @@
/* 375 */ CALL(sys_setns)
CALL(sys_process_vm_readv)
CALL(sys_process_vm_writev)
- CALL(sys_ni_syscall) /* reserved for sys_kcmp */
#ifndef syscalls_counted
.equ syscalls_padding, ((NR_syscalls + 3) & ~3) - NR_syscalls
#define syscalls_counted
diff --git a/trunk/arch/arm/kernel/hw_breakpoint.c b/trunk/arch/arm/kernel/hw_breakpoint.c
index 281bf3301241..ba386bd94107 100644
--- a/trunk/arch/arm/kernel/hw_breakpoint.c
+++ b/trunk/arch/arm/kernel/hw_breakpoint.c
@@ -159,12 +159,6 @@ static int debug_arch_supported(void)
arch >= ARM_DEBUG_ARCH_V7_1;
}
-/* Can we determine the watchpoint access type from the fsr? */
-static int debug_exception_updates_fsr(void)
-{
- return 0;
-}
-
/* Determine number of WRP registers available. */
static int get_num_wrp_resources(void)
{
@@ -610,14 +604,13 @@ int arch_validate_hwbkpt_settings(struct perf_event *bp)
/* Aligned */
break;
case 1:
+ /* Allow single byte watchpoint. */
+ if (info->ctrl.len == ARM_BREAKPOINT_LEN_1)
+ break;
case 2:
/* Allow halfword watchpoints and breakpoints. */
if (info->ctrl.len == ARM_BREAKPOINT_LEN_2)
break;
- case 3:
- /* Allow single byte watchpoint. */
- if (info->ctrl.len == ARM_BREAKPOINT_LEN_1)
- break;
default:
ret = -EINVAL;
goto out;
@@ -626,35 +619,18 @@ int arch_validate_hwbkpt_settings(struct perf_event *bp)
info->address &= ~alignment_mask;
info->ctrl.len <<= offset;
- if (!bp->overflow_handler) {
- /*
- * Mismatch breakpoints are required for single-stepping
- * breakpoints.
- */
- if (!core_has_mismatch_brps())
- return -EINVAL;
-
- /* We don't allow mismatch breakpoints in kernel space. */
- if (arch_check_bp_in_kernelspace(bp))
- return -EPERM;
-
- /*
- * Per-cpu breakpoints are not supported by our stepping
- * mechanism.
- */
- if (!bp->hw.bp_target)
- return -EINVAL;
-
- /*
- * We only support specific access types if the fsr
- * reports them.
- */
- if (!debug_exception_updates_fsr() &&
- (info->ctrl.type == ARM_BREAKPOINT_LOAD ||
- info->ctrl.type == ARM_BREAKPOINT_STORE))
- return -EINVAL;
+ /*
+ * Currently we rely on an overflow handler to take
+ * care of single-stepping the breakpoint when it fires.
+ * In the case of userspace breakpoints on a core with V7 debug,
+ * we can use the mismatch feature as a poor-man's hardware
+ * single-step, but this only works for per-task breakpoints.
+ */
+ if (!bp->overflow_handler && (arch_check_bp_in_kernelspace(bp) ||
+ !core_has_mismatch_brps() || !bp->hw.bp_target)) {
+ pr_warning("overflow handler required but none found\n");
+ ret = -EINVAL;
}
-
out:
return ret;
}
@@ -730,12 +706,10 @@ static void watchpoint_handler(unsigned long addr, unsigned int fsr,
goto unlock;
/* Check that the access type matches. */
- if (debug_exception_updates_fsr()) {
- access = (fsr & ARM_FSR_ACCESS_MASK) ?
- HW_BREAKPOINT_W : HW_BREAKPOINT_R;
- if (!(access & hw_breakpoint_type(wp)))
- goto unlock;
- }
+ access = (fsr & ARM_FSR_ACCESS_MASK) ? HW_BREAKPOINT_W :
+ HW_BREAKPOINT_R;
+ if (!(access & hw_breakpoint_type(wp)))
+ goto unlock;
/* We have a winner. */
info->trigger = addr;
diff --git a/trunk/arch/arm/kernel/smp_twd.c b/trunk/arch/arm/kernel/smp_twd.c
index e1f906989bb8..fef42b21cecb 100644
--- a/trunk/arch/arm/kernel/smp_twd.c
+++ b/trunk/arch/arm/kernel/smp_twd.c
@@ -11,6 +11,7 @@
#include
#include
#include
+#include
#include
#include
#include
@@ -95,52 +96,7 @@ static void twd_timer_stop(struct clock_event_device *clk)
disable_percpu_irq(clk->irq);
}
-#ifdef CONFIG_COMMON_CLK
-
-/*
- * Updates clockevent frequency when the cpu frequency changes.
- * Called on the cpu that is changing frequency with interrupts disabled.
- */
-static void twd_update_frequency(void *new_rate)
-{
- twd_timer_rate = *((unsigned long *) new_rate);
-
- clockevents_update_freq(*__this_cpu_ptr(twd_evt), twd_timer_rate);
-}
-
-static int twd_rate_change(struct notifier_block *nb,
- unsigned long flags, void *data)
-{
- struct clk_notifier_data *cnd = data;
-
- /*
- * The twd clock events must be reprogrammed to account for the new
- * frequency. The timer is local to a cpu, so cross-call to the
- * changing cpu.
- */
- if (flags == POST_RATE_CHANGE)
- smp_call_function(twd_update_frequency,
- (void *)&cnd->new_rate, 1);
-
- return NOTIFY_OK;
-}
-
-static struct notifier_block twd_clk_nb = {
- .notifier_call = twd_rate_change,
-};
-
-static int twd_clk_init(void)
-{
- if (twd_evt && *__this_cpu_ptr(twd_evt) && !IS_ERR(twd_clk))
- return clk_notifier_register(twd_clk, &twd_clk_nb);
-
- return 0;
-}
-core_initcall(twd_clk_init);
-
-#elif defined (CONFIG_CPU_FREQ)
-
-#include
+#ifdef CONFIG_CPU_FREQ
/*
* Updates clockevent frequency when the cpu frequency changes.
diff --git a/trunk/arch/arm/kernel/traps.c b/trunk/arch/arm/kernel/traps.c
index b0179b89a04c..f7945218b8c6 100644
--- a/trunk/arch/arm/kernel/traps.c
+++ b/trunk/arch/arm/kernel/traps.c
@@ -420,23 +420,20 @@ asmlinkage void __exception do_undefinstr(struct pt_regs *regs)
#endif
instr = *(u32 *) pc;
} else if (thumb_mode(regs)) {
- if (get_user(instr, (u16 __user *)pc))
- goto die_sig;
+ get_user(instr, (u16 __user *)pc);
if (is_wide_instruction(instr)) {
unsigned int instr2;
- if (get_user(instr2, (u16 __user *)pc+1))
- goto die_sig;
+ get_user(instr2, (u16 __user *)pc+1);
instr <<= 16;
instr |= instr2;
}
- } else if (get_user(instr, (u32 __user *)pc)) {
- goto die_sig;
+ } else {
+ get_user(instr, (u32 __user *)pc);
}
if (call_undef_hook(regs, instr) == 0)
return;
-die_sig:
#ifdef CONFIG_DEBUG_USER
if (user_debug & UDBG_UNDEFINED) {
printk(KERN_INFO "%s (%d): undefined instruction: pc=%p\n",
diff --git a/trunk/arch/arm/lib/delay.c b/trunk/arch/arm/lib/delay.c
index 395d5fbb8fa2..d6dacc69254e 100644
--- a/trunk/arch/arm/lib/delay.c
+++ b/trunk/arch/arm/lib/delay.c
@@ -59,7 +59,6 @@ void __init init_current_timer_delay(unsigned long freq)
{
pr_info("Switching to timer-based delay loop\n");
lpj_fine = freq / HZ;
- loops_per_jiffy = lpj_fine;
arm_delay_ops.delay = __timer_delay;
arm_delay_ops.const_udelay = __timer_const_udelay;
arm_delay_ops.udelay = __timer_udelay;
diff --git a/trunk/arch/arm/lib/getuser.S b/trunk/arch/arm/lib/getuser.S
index 9b06bb41fca6..11093a7c3e32 100644
--- a/trunk/arch/arm/lib/getuser.S
+++ b/trunk/arch/arm/lib/getuser.S
@@ -16,9 +16,8 @@
* __get_user_X
*
* Inputs: r0 contains the address
- * r1 contains the address limit, which must be preserved
* Outputs: r0 is the error code
- * r2 contains the zero-extended value
+ * r2, r3 contains the zero-extended value
* lr corrupted
*
* No other registers must be altered. (see
@@ -28,39 +27,33 @@
* Note also that it is intended that __get_user_bad is not global.
*/
#include
-#include
#include
#include
ENTRY(__get_user_1)
- check_uaccess r0, 1, r1, r2, __get_user_bad
1: TUSER(ldrb) r2, [r0]
mov r0, #0
mov pc, lr
ENDPROC(__get_user_1)
ENTRY(__get_user_2)
- check_uaccess r0, 2, r1, r2, __get_user_bad
-#ifdef CONFIG_CPU_USE_DOMAINS
-rb .req ip
-2: ldrbt r2, [r0], #1
-3: ldrbt rb, [r0], #0
+#ifdef CONFIG_THUMB2_KERNEL
+2: TUSER(ldrb) r2, [r0]
+3: TUSER(ldrb) r3, [r0, #1]
#else
-rb .req r0
-2: ldrb r2, [r0]
-3: ldrb rb, [r0, #1]
+2: TUSER(ldrb) r2, [r0], #1
+3: TUSER(ldrb) r3, [r0]
#endif
#ifndef __ARMEB__
- orr r2, r2, rb, lsl #8
+ orr r2, r2, r3, lsl #8
#else
- orr r2, rb, r2, lsl #8
+ orr r2, r3, r2, lsl #8
#endif
mov r0, #0
mov pc, lr
ENDPROC(__get_user_2)
ENTRY(__get_user_4)
- check_uaccess r0, 4, r1, r2, __get_user_bad
4: TUSER(ldr) r2, [r0]
mov r0, #0
mov pc, lr
diff --git a/trunk/arch/arm/lib/putuser.S b/trunk/arch/arm/lib/putuser.S
index 3d73dcb959b0..7db25990c589 100644
--- a/trunk/arch/arm/lib/putuser.S
+++ b/trunk/arch/arm/lib/putuser.S
@@ -16,7 +16,6 @@
* __put_user_X
*
* Inputs: r0 contains the address
- * r1 contains the address limit, which must be preserved
* r2, r3 contains the value
* Outputs: r0 is the error code
* lr corrupted
@@ -28,19 +27,16 @@
* Note also that it is intended that __put_user_bad is not global.
*/
#include
-#include
#include
#include
ENTRY(__put_user_1)
- check_uaccess r0, 1, r1, ip, __put_user_bad
1: TUSER(strb) r2, [r0]
mov r0, #0
mov pc, lr
ENDPROC(__put_user_1)
ENTRY(__put_user_2)
- check_uaccess r0, 2, r1, ip, __put_user_bad
mov ip, r2, lsr #8
#ifdef CONFIG_THUMB2_KERNEL
#ifndef __ARMEB__
@@ -64,14 +60,12 @@ ENTRY(__put_user_2)
ENDPROC(__put_user_2)
ENTRY(__put_user_4)
- check_uaccess r0, 4, r1, ip, __put_user_bad
4: TUSER(str) r2, [r0]
mov r0, #0
mov pc, lr
ENDPROC(__put_user_4)
ENTRY(__put_user_8)
- check_uaccess r0, 8, r1, ip, __put_user_bad
#ifdef CONFIG_THUMB2_KERNEL
5: TUSER(str) r2, [r0]
6: TUSER(str) r3, [r0, #4]
diff --git a/trunk/arch/arm/mach-imx/clk-imx25.c b/trunk/arch/arm/mach-imx/clk-imx25.c
index d20d4795f4ea..fdd8cc87c9fe 100644
--- a/trunk/arch/arm/mach-imx/clk-imx25.c
+++ b/trunk/arch/arm/mach-imx/clk-imx25.c
@@ -222,8 +222,10 @@ int __init mx25_clocks_init(void)
clk_register_clkdev(clk[lcdc_ipg], "ipg", "imx-fb.0");
clk_register_clkdev(clk[lcdc_ahb], "ahb", "imx-fb.0");
clk_register_clkdev(clk[wdt_ipg], NULL, "imx2-wdt.0");
- clk_register_clkdev(clk[ssi1_ipg], NULL, "imx-ssi.0");
- clk_register_clkdev(clk[ssi2_ipg], NULL, "imx-ssi.1");
+ clk_register_clkdev(clk[ssi1_ipg_per], "per", "imx-ssi.0");
+ clk_register_clkdev(clk[ssi1_ipg], "ipg", "imx-ssi.0");
+ clk_register_clkdev(clk[ssi2_ipg_per], "per", "imx-ssi.1");
+ clk_register_clkdev(clk[ssi2_ipg], "ipg", "imx-ssi.1");
clk_register_clkdev(clk[esdhc1_ipg_per], "per", "sdhci-esdhc-imx25.0");
clk_register_clkdev(clk[esdhc1_ipg], "ipg", "sdhci-esdhc-imx25.0");
clk_register_clkdev(clk[esdhc1_ahb], "ahb", "sdhci-esdhc-imx25.0");
@@ -241,6 +243,6 @@ int __init mx25_clocks_init(void)
clk_register_clkdev(clk[sdma_ahb], "ahb", "imx35-sdma");
clk_register_clkdev(clk[iim_ipg], "iim", NULL);
- mxc_timer_init(MX25_IO_ADDRESS(MX25_GPT1_BASE_ADDR), MX25_INT_GPT1);
+ mxc_timer_init(MX25_IO_ADDRESS(MX25_GPT1_BASE_ADDR), 54);
return 0;
}
diff --git a/trunk/arch/arm/mach-imx/clk-imx35.c b/trunk/arch/arm/mach-imx/clk-imx35.c
index 65fb8bcd86cb..c6422fb10bae 100644
--- a/trunk/arch/arm/mach-imx/clk-imx35.c
+++ b/trunk/arch/arm/mach-imx/clk-imx35.c
@@ -230,8 +230,10 @@ int __init mx35_clocks_init()
clk_register_clkdev(clk[ipu_gate], NULL, "mx3_sdc_fb");
clk_register_clkdev(clk[owire_gate], NULL, "mxc_w1");
clk_register_clkdev(clk[sdma_gate], NULL, "imx35-sdma");
- clk_register_clkdev(clk[ssi1_gate], NULL, "imx-ssi.0");
- clk_register_clkdev(clk[ssi2_gate], NULL, "imx-ssi.1");
+ clk_register_clkdev(clk[ipg], "ipg", "imx-ssi.0");
+ clk_register_clkdev(clk[ssi1_div_post], "per", "imx-ssi.0");
+ clk_register_clkdev(clk[ipg], "ipg", "imx-ssi.1");
+ clk_register_clkdev(clk[ssi2_div_post], "per", "imx-ssi.1");
/* i.mx35 has the i.mx21 type uart */
clk_register_clkdev(clk[uart1_gate], "per", "imx21-uart.0");
clk_register_clkdev(clk[ipg], "ipg", "imx21-uart.0");
diff --git a/trunk/arch/arm/mach-imx/mach-armadillo5x0.c b/trunk/arch/arm/mach-imx/mach-armadillo5x0.c
index 5985ed1b8c98..2c6ab3273f9e 100644
--- a/trunk/arch/arm/mach-imx/mach-armadillo5x0.c
+++ b/trunk/arch/arm/mach-imx/mach-armadillo5x0.c
@@ -526,8 +526,7 @@ static void __init armadillo5x0_init(void)
imx31_add_mxc_nand(&armadillo5x0_nand_board_info);
/* set NAND page size to 2k if not configured via boot mode pins */
- __raw_writel(__raw_readl(mx3_ccm_base + MXC_CCM_RCSR) |
- (1 << 30), mx3_ccm_base + MXC_CCM_RCSR);
+ __raw_writel(__raw_readl(MXC_CCM_RCSR) | (1 << 30), MXC_CCM_RCSR);
/* RTC */
/* Get RTC IRQ and register the chip */
diff --git a/trunk/arch/arm/mach-omap2/Kconfig b/trunk/arch/arm/mach-omap2/Kconfig
index 346fd26f3aa6..fcd4e85c4ddc 100644
--- a/trunk/arch/arm/mach-omap2/Kconfig
+++ b/trunk/arch/arm/mach-omap2/Kconfig
@@ -232,11 +232,10 @@ config MACH_OMAP3_PANDORA
select OMAP_PACKAGE_CBB
select REGULATOR_FIXED_VOLTAGE if REGULATOR
-config MACH_TOUCHBOOK
+config MACH_OMAP3_TOUCHBOOK
bool "OMAP3 Touch Book"
depends on ARCH_OMAP3
default y
- select OMAP_PACKAGE_CBB
config MACH_OMAP_3430SDP
bool "OMAP 3430 SDP board"
diff --git a/trunk/arch/arm/mach-omap2/Makefile b/trunk/arch/arm/mach-omap2/Makefile
index 34c2c7f59f0a..f6a24b3f9c4f 100644
--- a/trunk/arch/arm/mach-omap2/Makefile
+++ b/trunk/arch/arm/mach-omap2/Makefile
@@ -255,7 +255,7 @@ obj-$(CONFIG_MACH_OMAP_3630SDP) += board-zoom-display.o
obj-$(CONFIG_MACH_CM_T35) += board-cm-t35.o
obj-$(CONFIG_MACH_CM_T3517) += board-cm-t3517.o
obj-$(CONFIG_MACH_IGEP0020) += board-igep0020.o
-obj-$(CONFIG_MACH_TOUCHBOOK) += board-omap3touchbook.o
+obj-$(CONFIG_MACH_OMAP3_TOUCHBOOK) += board-omap3touchbook.o
obj-$(CONFIG_MACH_OMAP_4430SDP) += board-4430sdp.o
obj-$(CONFIG_MACH_OMAP4_PANDA) += board-omap4panda.o
diff --git a/trunk/arch/arm/mach-omap2/clock33xx_data.c b/trunk/arch/arm/mach-omap2/clock33xx_data.c
index ae27de8899a6..25bbcc7ca4dc 100644
--- a/trunk/arch/arm/mach-omap2/clock33xx_data.c
+++ b/trunk/arch/arm/mach-omap2/clock33xx_data.c
@@ -1036,13 +1036,13 @@ static struct omap_clk am33xx_clks[] = {
CLK(NULL, "mmu_fck", &mmu_fck, CK_AM33XX),
CLK(NULL, "smartreflex0_fck", &smartreflex0_fck, CK_AM33XX),
CLK(NULL, "smartreflex1_fck", &smartreflex1_fck, CK_AM33XX),
- CLK(NULL, "timer1_fck", &timer1_fck, CK_AM33XX),
- CLK(NULL, "timer2_fck", &timer2_fck, CK_AM33XX),
- CLK(NULL, "timer3_fck", &timer3_fck, CK_AM33XX),
- CLK(NULL, "timer4_fck", &timer4_fck, CK_AM33XX),
- CLK(NULL, "timer5_fck", &timer5_fck, CK_AM33XX),
- CLK(NULL, "timer6_fck", &timer6_fck, CK_AM33XX),
- CLK(NULL, "timer7_fck", &timer7_fck, CK_AM33XX),
+ CLK(NULL, "gpt1_fck", &timer1_fck, CK_AM33XX),
+ CLK(NULL, "gpt2_fck", &timer2_fck, CK_AM33XX),
+ CLK(NULL, "gpt3_fck", &timer3_fck, CK_AM33XX),
+ CLK(NULL, "gpt4_fck", &timer4_fck, CK_AM33XX),
+ CLK(NULL, "gpt5_fck", &timer5_fck, CK_AM33XX),
+ CLK(NULL, "gpt6_fck", &timer6_fck, CK_AM33XX),
+ CLK(NULL, "gpt7_fck", &timer7_fck, CK_AM33XX),
CLK(NULL, "usbotg_fck", &usbotg_fck, CK_AM33XX),
CLK(NULL, "ieee5000_fck", &ieee5000_fck, CK_AM33XX),
CLK(NULL, "wdt1_fck", &wdt1_fck, CK_AM33XX),
diff --git a/trunk/arch/arm/mach-omap2/clockdomain2xxx_3xxx.c b/trunk/arch/arm/mach-omap2/clockdomain2xxx_3xxx.c
index f99e65cfb862..a0d68dbecfa3 100644
--- a/trunk/arch/arm/mach-omap2/clockdomain2xxx_3xxx.c
+++ b/trunk/arch/arm/mach-omap2/clockdomain2xxx_3xxx.c
@@ -241,52 +241,6 @@ static void omap3_clkdm_deny_idle(struct clockdomain *clkdm)
_clkdm_del_autodeps(clkdm);
}
-static int omap3xxx_clkdm_clk_enable(struct clockdomain *clkdm)
-{
- bool hwsup = false;
-
- if (!clkdm->clktrctrl_mask)
- return 0;
-
- hwsup = omap2_cm_is_clkdm_in_hwsup(clkdm->pwrdm.ptr->prcm_offs,
- clkdm->clktrctrl_mask);
-
- if (hwsup) {
- /* Disable HW transitions when we are changing deps */
- _disable_hwsup(clkdm);
- _clkdm_add_autodeps(clkdm);
- _enable_hwsup(clkdm);
- } else {
- if (clkdm->flags & CLKDM_CAN_FORCE_WAKEUP)
- omap3_clkdm_wakeup(clkdm);
- }
-
- return 0;
-}
-
-static int omap3xxx_clkdm_clk_disable(struct clockdomain *clkdm)
-{
- bool hwsup = false;
-
- if (!clkdm->clktrctrl_mask)
- return 0;
-
- hwsup = omap2_cm_is_clkdm_in_hwsup(clkdm->pwrdm.ptr->prcm_offs,
- clkdm->clktrctrl_mask);
-
- if (hwsup) {
- /* Disable HW transitions when we are changing deps */
- _disable_hwsup(clkdm);
- _clkdm_del_autodeps(clkdm);
- _enable_hwsup(clkdm);
- } else {
- if (clkdm->flags & CLKDM_CAN_FORCE_SLEEP)
- omap3_clkdm_sleep(clkdm);
- }
-
- return 0;
-}
-
struct clkdm_ops omap2_clkdm_operations = {
.clkdm_add_wkdep = omap2_clkdm_add_wkdep,
.clkdm_del_wkdep = omap2_clkdm_del_wkdep,
@@ -313,6 +267,6 @@ struct clkdm_ops omap3_clkdm_operations = {
.clkdm_wakeup = omap3_clkdm_wakeup,
.clkdm_allow_idle = omap3_clkdm_allow_idle,
.clkdm_deny_idle = omap3_clkdm_deny_idle,
- .clkdm_clk_enable = omap3xxx_clkdm_clk_enable,
- .clkdm_clk_disable = omap3xxx_clkdm_clk_disable,
+ .clkdm_clk_enable = omap2_clkdm_clk_enable,
+ .clkdm_clk_disable = omap2_clkdm_clk_disable,
};
diff --git a/trunk/arch/arm/mach-omap2/cm-regbits-34xx.h b/trunk/arch/arm/mach-omap2/cm-regbits-34xx.h
index 975f6bda0e0b..766338fe4d34 100644
--- a/trunk/arch/arm/mach-omap2/cm-regbits-34xx.h
+++ b/trunk/arch/arm/mach-omap2/cm-regbits-34xx.h
@@ -67,7 +67,6 @@
#define OMAP3430_EN_IVA2_DPLL_MASK (0x7 << 0)
/* CM_IDLEST_IVA2 */
-#define OMAP3430_ST_IVA2_SHIFT 0
#define OMAP3430_ST_IVA2_MASK (1 << 0)
/* CM_IDLEST_PLL_IVA2 */
diff --git a/trunk/arch/arm/mach-omap2/omap-wakeupgen.c b/trunk/arch/arm/mach-omap2/omap-wakeupgen.c
index 330d4c6e746b..05fdebfaa195 100644
--- a/trunk/arch/arm/mach-omap2/omap-wakeupgen.c
+++ b/trunk/arch/arm/mach-omap2/omap-wakeupgen.c
@@ -46,7 +46,7 @@
static void __iomem *wakeupgen_base;
static void __iomem *sar_base;
static DEFINE_SPINLOCK(wakeupgen_lock);
-static unsigned int irq_target_cpu[MAX_IRQS];
+static unsigned int irq_target_cpu[NR_IRQS];
static unsigned int irq_banks = MAX_NR_REG_BANKS;
static unsigned int max_irqs = MAX_IRQS;
static unsigned int omap_secure_apis;
diff --git a/trunk/arch/arm/mach-omap2/omap_hwmod.c b/trunk/arch/arm/mach-omap2/omap_hwmod.c
index 37afbd173c2c..6ca8e519968d 100644
--- a/trunk/arch/arm/mach-omap2/omap_hwmod.c
+++ b/trunk/arch/arm/mach-omap2/omap_hwmod.c
@@ -1889,7 +1889,6 @@ static int _enable(struct omap_hwmod *oh)
_enable_sysc(oh);
}
} else {
- _omap4_disable_module(oh);
_disable_clocks(oh);
pr_debug("omap_hwmod: %s: _wait_target_ready: %d\n",
oh->name, r);
diff --git a/trunk/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c b/trunk/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c
index ce7e6068768f..c9e38200216b 100644
--- a/trunk/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c
+++ b/trunk/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c
@@ -100,9 +100,9 @@ static struct omap_hwmod omap3xxx_mpu_hwmod = {
/* IVA2 (IVA2) */
static struct omap_hwmod_rst_info omap3xxx_iva_resets[] = {
- { .name = "logic", .rst_shift = 0, .st_shift = 8 },
- { .name = "seq0", .rst_shift = 1, .st_shift = 9 },
- { .name = "seq1", .rst_shift = 2, .st_shift = 10 },
+ { .name = "logic", .rst_shift = 0 },
+ { .name = "seq0", .rst_shift = 1 },
+ { .name = "seq1", .rst_shift = 2 },
};
static struct omap_hwmod omap3xxx_iva_hwmod = {
@@ -112,15 +112,6 @@ static struct omap_hwmod omap3xxx_iva_hwmod = {
.rst_lines = omap3xxx_iva_resets,
.rst_lines_cnt = ARRAY_SIZE(omap3xxx_iva_resets),
.main_clk = "iva2_ck",
- .prcm = {
- .omap2 = {
- .module_offs = OMAP3430_IVA2_MOD,
- .prcm_reg_id = 1,
- .module_bit = OMAP3430_CM_FCLKEN_IVA2_EN_IVA2_SHIFT,
- .idlest_reg_id = 1,
- .idlest_idle_bit = OMAP3430_ST_IVA2_SHIFT,
- }
- },
};
/* timer class */
diff --git a/trunk/arch/arm/mach-omap2/omap_hwmod_44xx_data.c b/trunk/arch/arm/mach-omap2/omap_hwmod_44xx_data.c
index afb60917a948..242aee498ceb 100644
--- a/trunk/arch/arm/mach-omap2/omap_hwmod_44xx_data.c
+++ b/trunk/arch/arm/mach-omap2/omap_hwmod_44xx_data.c
@@ -4210,7 +4210,7 @@ static struct omap_hwmod_ocp_if omap44xx_dsp__iva = {
};
/* dsp -> sl2if */
-static struct omap_hwmod_ocp_if __maybe_unused omap44xx_dsp__sl2if = {
+static struct omap_hwmod_ocp_if omap44xx_dsp__sl2if = {
.master = &omap44xx_dsp_hwmod,
.slave = &omap44xx_sl2if_hwmod,
.clk = "dpll_iva_m5x2_ck",
@@ -4828,7 +4828,7 @@ static struct omap_hwmod_ocp_if omap44xx_l3_main_2__iss = {
};
/* iva -> sl2if */
-static struct omap_hwmod_ocp_if __maybe_unused omap44xx_iva__sl2if = {
+static struct omap_hwmod_ocp_if omap44xx_iva__sl2if = {
.master = &omap44xx_iva_hwmod,
.slave = &omap44xx_sl2if_hwmod,
.clk = "dpll_iva_m5x2_ck",
@@ -5362,7 +5362,7 @@ static struct omap_hwmod_ocp_if omap44xx_l4_wkup__scrm = {
};
/* l3_main_2 -> sl2if */
-static struct omap_hwmod_ocp_if __maybe_unused omap44xx_l3_main_2__sl2if = {
+static struct omap_hwmod_ocp_if omap44xx_l3_main_2__sl2if = {
.master = &omap44xx_l3_main_2_hwmod,
.slave = &omap44xx_sl2if_hwmod,
.clk = "l3_div_ck",
@@ -6032,7 +6032,7 @@ static struct omap_hwmod_ocp_if *omap44xx_hwmod_ocp_ifs[] __initdata = {
&omap44xx_l4_abe__dmic,
&omap44xx_l4_abe__dmic_dma,
&omap44xx_dsp__iva,
- /* &omap44xx_dsp__sl2if, */
+ &omap44xx_dsp__sl2if,
&omap44xx_l4_cfg__dsp,
&omap44xx_l3_main_2__dss,
&omap44xx_l4_per__dss,
@@ -6068,7 +6068,7 @@ static struct omap_hwmod_ocp_if *omap44xx_hwmod_ocp_ifs[] __initdata = {
&omap44xx_l4_per__i2c4,
&omap44xx_l3_main_2__ipu,
&omap44xx_l3_main_2__iss,
- /* &omap44xx_iva__sl2if, */
+ &omap44xx_iva__sl2if,
&omap44xx_l3_main_2__iva,
&omap44xx_l4_wkup__kbd,
&omap44xx_l4_cfg__mailbox,
@@ -6099,7 +6099,7 @@ static struct omap_hwmod_ocp_if *omap44xx_hwmod_ocp_ifs[] __initdata = {
&omap44xx_l4_cfg__cm_core,
&omap44xx_l4_wkup__prm,
&omap44xx_l4_wkup__scrm,
- /* &omap44xx_l3_main_2__sl2if, */
+ &omap44xx_l3_main_2__sl2if,
&omap44xx_l4_abe__slimbus1,
&omap44xx_l4_abe__slimbus1_dma,
&omap44xx_l4_per__slimbus2,
diff --git a/trunk/arch/arm/mach-omap2/timer.c b/trunk/arch/arm/mach-omap2/timer.c
index 2ba4f57dda86..2ff6d41ec6c6 100644
--- a/trunk/arch/arm/mach-omap2/timer.c
+++ b/trunk/arch/arm/mach-omap2/timer.c
@@ -260,7 +260,6 @@ static u32 notrace dmtimer_read_sched_clock(void)
return 0;
}
-#ifdef CONFIG_OMAP_32K_TIMER
/* Setup free-running counter for clocksource */
static int __init omap2_sync32k_clocksource_init(void)
{
@@ -300,12 +299,6 @@ static int __init omap2_sync32k_clocksource_init(void)
return ret;
}
-#else
-static inline int omap2_sync32k_clocksource_init(void)
-{
- return -ENODEV;
-}
-#endif
static void __init omap2_gptimer_clocksource_init(int gptimer_id,
const char *fck_source)
diff --git a/trunk/arch/arm/mach-shmobile/board-kzm9g.c b/trunk/arch/arm/mach-shmobile/board-kzm9g.c
index 3b8a0171c3cb..53b7ea92c32c 100644
--- a/trunk/arch/arm/mach-shmobile/board-kzm9g.c
+++ b/trunk/arch/arm/mach-shmobile/board-kzm9g.c
@@ -346,11 +346,11 @@ static struct resource sh_mmcif_resources[] = {
.flags = IORESOURCE_MEM,
},
[1] = {
- .start = gic_spi(140),
+ .start = gic_spi(141),
.flags = IORESOURCE_IRQ,
},
[2] = {
- .start = gic_spi(141),
+ .start = gic_spi(140),
.flags = IORESOURCE_IRQ,
},
};
diff --git a/trunk/arch/arm/mm/context.c b/trunk/arch/arm/mm/context.c
index 4e07eec1270d..119bc52ab93e 100644
--- a/trunk/arch/arm/mm/context.c
+++ b/trunk/arch/arm/mm/context.c
@@ -63,11 +63,10 @@ static int contextidr_notifier(struct notifier_block *unused, unsigned long cmd,
pid = task_pid_nr(thread->task) << ASID_BITS;
asm volatile(
" mrc p15, 0, %0, c13, c0, 1\n"
- " and %0, %0, %2\n"
- " orr %0, %0, %1\n"
- " mcr p15, 0, %0, c13, c0, 1\n"
+ " bfi %1, %0, #0, %2\n"
+ " mcr p15, 0, %1, c13, c0, 1\n"
: "=r" (contextidr), "+r" (pid)
- : "I" (~ASID_MASK));
+ : "I" (ASID_BITS));
isb();
return NOTIFY_OK;
diff --git a/trunk/arch/arm/mm/dma-mapping.c b/trunk/arch/arm/mm/dma-mapping.c
index e59c4ab71bcb..051204fc4617 100644
--- a/trunk/arch/arm/mm/dma-mapping.c
+++ b/trunk/arch/arm/mm/dma-mapping.c
@@ -489,7 +489,7 @@ static bool __in_atomic_pool(void *start, size_t size)
void *pool_start = pool->vaddr;
void *pool_end = pool->vaddr + pool->size;
- if (start < pool_start || start >= pool_end)
+ if (start < pool_start || start > pool_end)
return false;
if (end <= pool_end)
diff --git a/trunk/arch/arm/mm/mm.h b/trunk/arch/arm/mm/mm.h
index a8ee92da3544..6776160618ef 100644
--- a/trunk/arch/arm/mm/mm.h
+++ b/trunk/arch/arm/mm/mm.h
@@ -55,9 +55,6 @@ extern void __flush_dcache_page(struct address_space *mapping, struct page *page
/* permanent static mappings from iotable_init() */
#define VM_ARM_STATIC_MAPPING 0x40000000
-/* empty mapping */
-#define VM_ARM_EMPTY_MAPPING 0x20000000
-
/* mapping type (attributes) for permanent static mappings */
#define VM_ARM_MTYPE(mt) ((mt) << 20)
#define VM_ARM_MTYPE_MASK (0x1f << 20)
diff --git a/trunk/arch/arm/mm/mmu.c b/trunk/arch/arm/mm/mmu.c
index c2fa21d0103e..4c2d0451e84a 100644
--- a/trunk/arch/arm/mm/mmu.c
+++ b/trunk/arch/arm/mm/mmu.c
@@ -807,7 +807,7 @@ static void __init pmd_empty_section_gap(unsigned long addr)
vm = early_alloc_aligned(sizeof(*vm), __alignof__(*vm));
vm->addr = (void *)addr;
vm->size = SECTION_SIZE;
- vm->flags = VM_IOREMAP | VM_ARM_EMPTY_MAPPING;
+ vm->flags = VM_IOREMAP | VM_ARM_STATIC_MAPPING;
vm->caller = pmd_empty_section_gap;
vm_area_add_early(vm);
}
@@ -820,7 +820,7 @@ static void __init fill_pmd_gaps(void)
/* we're still single threaded hence no lock needed here */
for (vm = vmlist; vm; vm = vm->next) {
- if (!(vm->flags & (VM_ARM_STATIC_MAPPING | VM_ARM_EMPTY_MAPPING)))
+ if (!(vm->flags & VM_ARM_STATIC_MAPPING))
continue;
addr = (unsigned long)vm->addr;
if (addr < next)
@@ -961,8 +961,8 @@ void __init sanity_check_meminfo(void)
* Check whether this memory bank would partially overlap
* the vmalloc area.
*/
- if (__va(bank->start + bank->size - 1) >= vmalloc_min ||
- __va(bank->start + bank->size - 1) <= __va(bank->start)) {
+ if (__va(bank->start + bank->size) > vmalloc_min ||
+ __va(bank->start + bank->size) < __va(bank->start)) {
unsigned long newsize = vmalloc_min - __va(bank->start);
printk(KERN_NOTICE "Truncating RAM at %.8llx-%.8llx "
"to -%.8llx (vmalloc region overlap).\n",
diff --git a/trunk/arch/arm/plat-mxc/include/mach/mx25.h b/trunk/arch/arm/plat-mxc/include/mach/mx25.h
index ec466400a200..627d94f1b010 100644
--- a/trunk/arch/arm/plat-mxc/include/mach/mx25.h
+++ b/trunk/arch/arm/plat-mxc/include/mach/mx25.h
@@ -98,7 +98,6 @@
#define MX25_INT_UART1 (NR_IRQS_LEGACY + 45)
#define MX25_INT_GPIO2 (NR_IRQS_LEGACY + 51)
#define MX25_INT_GPIO1 (NR_IRQS_LEGACY + 52)
-#define MX25_INT_GPT1 (NR_IRQS_LEGACY + 54)
#define MX25_INT_FEC (NR_IRQS_LEGACY + 57)
#define MX25_DMA_REQ_SSI2_RX1 22
diff --git a/trunk/arch/arm/plat-omap/sram.c b/trunk/arch/arm/plat-omap/sram.c
index 024f3b08db29..766181cb5c95 100644
--- a/trunk/arch/arm/plat-omap/sram.c
+++ b/trunk/arch/arm/plat-omap/sram.c
@@ -68,7 +68,6 @@
static unsigned long omap_sram_start;
static void __iomem *omap_sram_base;
-static unsigned long omap_sram_skip;
static unsigned long omap_sram_size;
static void __iomem *omap_sram_ceil;
@@ -107,7 +106,6 @@ static int is_sram_locked(void)
*/
static void __init omap_detect_sram(void)
{
- omap_sram_skip = SRAM_BOOTLOADER_SZ;
if (cpu_class_is_omap2()) {
if (is_sram_locked()) {
if (cpu_is_omap34xx()) {
@@ -115,7 +113,6 @@ static void __init omap_detect_sram(void)
if ((omap_type() == OMAP2_DEVICE_TYPE_EMU) ||
(omap_type() == OMAP2_DEVICE_TYPE_SEC)) {
omap_sram_size = 0x7000; /* 28K */
- omap_sram_skip += SZ_16K;
} else {
omap_sram_size = 0x8000; /* 32K */
}
@@ -178,10 +175,8 @@ static void __init omap_map_sram(void)
return;
#ifdef CONFIG_OMAP4_ERRATA_I688
- if (cpu_is_omap44xx()) {
omap_sram_start += PAGE_SIZE;
omap_sram_size -= SZ_16K;
- }
#endif
if (cpu_is_omap34xx()) {
/*
@@ -208,8 +203,8 @@ static void __init omap_map_sram(void)
* Looks like we need to preserve some bootloader code at the
* beginning of SRAM for jumping to flash for reboot to work...
*/
- memset_io(omap_sram_base + omap_sram_skip, 0,
- omap_sram_size - omap_sram_skip);
+ memset_io(omap_sram_base + SRAM_BOOTLOADER_SZ, 0,
+ omap_sram_size - SRAM_BOOTLOADER_SZ);
}
/*
@@ -223,7 +218,7 @@ void *omap_sram_push_address(unsigned long size)
{
unsigned long available, new_ceil = (unsigned long)omap_sram_ceil;
- available = omap_sram_ceil - (omap_sram_base + omap_sram_skip);
+ available = omap_sram_ceil - (omap_sram_base + SRAM_BOOTLOADER_SZ);
if (size > available) {
pr_err("Not enough space in SRAM\n");
diff --git a/trunk/arch/arm/plat-samsung/clock.c b/trunk/arch/arm/plat-samsung/clock.c
index d1116e2dfbea..65c5eca475e7 100644
--- a/trunk/arch/arm/plat-samsung/clock.c
+++ b/trunk/arch/arm/plat-samsung/clock.c
@@ -144,7 +144,6 @@ long clk_round_rate(struct clk *clk, unsigned long rate)
int clk_set_rate(struct clk *clk, unsigned long rate)
{
- unsigned long flags;
int ret;
if (IS_ERR(clk))
@@ -160,9 +159,9 @@ int clk_set_rate(struct clk *clk, unsigned long rate)
if (clk->ops == NULL || clk->ops->set_rate == NULL)
return -EINVAL;
- spin_lock_irqsave(&clocks_lock, flags);
+ spin_lock(&clocks_lock);
ret = (clk->ops->set_rate)(clk, rate);
- spin_unlock_irqrestore(&clocks_lock, flags);
+ spin_unlock(&clocks_lock);
return ret;
}
@@ -174,18 +173,17 @@ struct clk *clk_get_parent(struct clk *clk)
int clk_set_parent(struct clk *clk, struct clk *parent)
{
- unsigned long flags;
int ret = 0;
if (IS_ERR(clk))
return -EINVAL;
- spin_lock_irqsave(&clocks_lock, flags);
+ spin_lock(&clocks_lock);
if (clk->ops && clk->ops->set_parent)
ret = (clk->ops->set_parent)(clk, parent);
- spin_unlock_irqrestore(&clocks_lock, flags);
+ spin_unlock(&clocks_lock);
return ret;
}
diff --git a/trunk/arch/m68k/platform/coldfire/clk.c b/trunk/arch/m68k/platform/coldfire/clk.c
index 9cd13b4ce42b..75f9ee967ea7 100644
--- a/trunk/arch/m68k/platform/coldfire/clk.c
+++ b/trunk/arch/m68k/platform/coldfire/clk.c
@@ -146,3 +146,9 @@ struct clk_ops clk_ops1 = {
};
#endif /* MCFPM_PPMCR1 */
#endif /* MCFPM_PPMCR0 */
+
+struct clk *devm_clk_get(struct device *dev, const char *id)
+{
+ return NULL;
+}
+EXPORT_SYMBOL(devm_clk_get);
diff --git a/trunk/arch/mips/kernel/smp-cmp.c b/trunk/arch/mips/kernel/smp-cmp.c
index afc379ca3753..e7e03ecf5495 100644
--- a/trunk/arch/mips/kernel/smp-cmp.c
+++ b/trunk/arch/mips/kernel/smp-cmp.c
@@ -102,7 +102,7 @@ static void cmp_init_secondary(void)
c->vpe_id = (read_c0_tcbind() >> TCBIND_CURVPE_SHIFT) & TCBIND_CURVPE;
#endif
#ifdef CONFIG_MIPS_MT_SMTC
- c->tc_id = (read_c0_tcbind() & TCBIND_CURTC) >> TCBIND_CURTC_SHIFT;
+ c->tc_id = (read_c0_tcbind() >> TCBIND_CURTC_SHIFT) & TCBIND_CURTC;
#endif
}
diff --git a/trunk/arch/mips/mm/gup.c b/trunk/arch/mips/mm/gup.c
index dcfd573871c1..33aadbcf170b 100644
--- a/trunk/arch/mips/mm/gup.c
+++ b/trunk/arch/mips/mm/gup.c
@@ -152,8 +152,6 @@ static int gup_huge_pud(pud_t pud, unsigned long addr, unsigned long end,
do {
VM_BUG_ON(compound_head(page) != head);
pages[*nr] = page;
- if (PageTail(page))
- get_huge_page_tail(page);
(*nr)++;
page++;
refs++;
diff --git a/trunk/arch/mips/mti-malta/malta-int.c b/trunk/arch/mips/mti-malta/malta-int.c
index fea823f18479..7b13a4caeea4 100644
--- a/trunk/arch/mips/mti-malta/malta-int.c
+++ b/trunk/arch/mips/mti-malta/malta-int.c
@@ -273,19 +273,16 @@ asmlinkage void plat_irq_dispatch(void)
unsigned int pending = read_c0_cause() & read_c0_status() & ST0_IM;
int irq;
- if (unlikely(!pending)) {
- spurious_interrupt();
- return;
- }
-
irq = irq_ffs(pending);
if (irq == MIPSCPU_INT_I8259A)
malta_hw0_irqdispatch();
else if (gic_present && ((1 << irq) & ipi_map[smp_processor_id()]))
malta_ipi_irqdispatch();
- else
+ else if (irq >= 0)
do_IRQ(MIPS_CPU_IRQ_BASE + irq);
+ else
+ spurious_interrupt();
}
#ifdef CONFIG_MIPS_MT_SMP
diff --git a/trunk/arch/mips/mti-malta/malta-platform.c b/trunk/arch/mips/mti-malta/malta-platform.c
index 80562b81f0f2..4c35301720e7 100644
--- a/trunk/arch/mips/mti-malta/malta-platform.c
+++ b/trunk/arch/mips/mti-malta/malta-platform.c
@@ -138,6 +138,11 @@ static int __init malta_add_devices(void)
if (err)
return err;
+ /*
+ * Set RTC to BCD mode to support current alarm code.
+ */
+ CMOS_WRITE(CMOS_READ(RTC_CONTROL) & ~RTC_DM_BINARY, RTC_CONTROL);
+
return 0;
}
diff --git a/trunk/arch/s390/include/asm/hugetlb.h b/trunk/arch/s390/include/asm/hugetlb.h
index 2d6e6e380564..799ed0f1643d 100644
--- a/trunk/arch/s390/include/asm/hugetlb.h
+++ b/trunk/arch/s390/include/asm/hugetlb.h
@@ -66,6 +66,16 @@ static inline pte_t huge_ptep_get(pte_t *ptep)
return pte;
}
+static inline pte_t huge_ptep_get_and_clear(struct mm_struct *mm,
+ unsigned long addr, pte_t *ptep)
+{
+ pte_t pte = huge_ptep_get(ptep);
+
+ mm->context.flush_mm = 1;
+ pmd_clear((pmd_t *) ptep);
+ return pte;
+}
+
static inline void __pmd_csp(pmd_t *pmdp)
{
register unsigned long reg2 asm("2") = pmd_val(*pmdp);
@@ -107,15 +117,6 @@ static inline void huge_ptep_invalidate(struct mm_struct *mm,
__pmd_csp(pmdp);
}
-static inline pte_t huge_ptep_get_and_clear(struct mm_struct *mm,
- unsigned long addr, pte_t *ptep)
-{
- pte_t pte = huge_ptep_get(ptep);
-
- huge_ptep_invalidate(mm, addr, ptep);
- return pte;
-}
-
#define huge_ptep_set_access_flags(__vma, __addr, __ptep, __entry, __dirty) \
({ \
int __changed = !pte_same(huge_ptep_get(__ptep), __entry); \
@@ -130,7 +131,10 @@ static inline pte_t huge_ptep_get_and_clear(struct mm_struct *mm,
({ \
pte_t __pte = huge_ptep_get(__ptep); \
if (pte_write(__pte)) { \
- huge_ptep_invalidate(__mm, __addr, __ptep); \
+ (__mm)->context.flush_mm = 1; \
+ if (atomic_read(&(__mm)->context.attach_count) > 1 || \
+ (__mm) != current->active_mm) \
+ huge_ptep_invalidate(__mm, __addr, __ptep); \
set_huge_pte_at(__mm, __addr, __ptep, \
huge_pte_wrprotect(__pte)); \
} \
diff --git a/trunk/arch/s390/include/asm/tlbflush.h b/trunk/arch/s390/include/asm/tlbflush.h
index 1d8fe2b17ef6..9fde315f3a7c 100644
--- a/trunk/arch/s390/include/asm/tlbflush.h
+++ b/trunk/arch/s390/include/asm/tlbflush.h
@@ -90,10 +90,12 @@ static inline void __tlb_flush_mm(struct mm_struct * mm)
static inline void __tlb_flush_mm_cond(struct mm_struct * mm)
{
+ spin_lock(&mm->page_table_lock);
if (mm->context.flush_mm) {
__tlb_flush_mm(mm);
mm->context.flush_mm = 0;
}
+ spin_unlock(&mm->page_table_lock);
}
/*
diff --git a/trunk/arch/s390/kernel/setup.c b/trunk/arch/s390/kernel/setup.c
index 40b57693de38..f86c81e13c37 100644
--- a/trunk/arch/s390/kernel/setup.c
+++ b/trunk/arch/s390/kernel/setup.c
@@ -974,13 +974,11 @@ static void __init setup_hwcaps(void)
if (MACHINE_HAS_HPAGE)
elf_hwcap |= HWCAP_S390_HPAGE;
-#if defined(CONFIG_64BIT)
/*
* 64-bit register support for 31-bit processes
* HWCAP_S390_HIGH_GPRS is bit 9.
*/
elf_hwcap |= HWCAP_S390_HIGH_GPRS;
-#endif
get_cpu_id(&cpu_id);
switch (cpu_id.machine) {
diff --git a/trunk/arch/s390/lib/uaccess_pt.c b/trunk/arch/s390/lib/uaccess_pt.c
index 2d37bb861faf..60ee2b883797 100644
--- a/trunk/arch/s390/lib/uaccess_pt.c
+++ b/trunk/arch/s390/lib/uaccess_pt.c
@@ -2,82 +2,69 @@
* User access functions based on page table walks for enhanced
* system layout without hardware support.
*
- * Copyright IBM Corp. 2006, 2012
+ * Copyright IBM Corp. 2006
* Author(s): Gerald Schaefer (gerald.schaefer@de.ibm.com)
*/
#include
#include
#include
-#include
#include
#include
#include "uaccess.h"
-
-/*
- * Returns kernel address for user virtual address. If the returned address is
- * >= -4095 (IS_ERR_VALUE(x) returns true), a fault has occured and the address
- * contains the (negative) exception code.
- */
-static __always_inline unsigned long follow_table(struct mm_struct *mm,
- unsigned long addr, int write)
+static inline pte_t *follow_table(struct mm_struct *mm, unsigned long addr)
{
pgd_t *pgd;
pud_t *pud;
pmd_t *pmd;
- pte_t *ptep;
pgd = pgd_offset(mm, addr);
if (pgd_none(*pgd) || unlikely(pgd_bad(*pgd)))
- return -0x3aUL;
+ return (pte_t *) 0x3a;
pud = pud_offset(pgd, addr);
if (pud_none(*pud) || unlikely(pud_bad(*pud)))
- return -0x3bUL;
+ return (pte_t *) 0x3b;
pmd = pmd_offset(pud, addr);
- if (pmd_none(*pmd))
- return -0x10UL;
- if (pmd_huge(*pmd)) {
- if (write && (pmd_val(*pmd) & _SEGMENT_ENTRY_RO))
- return -0x04UL;
- return (pmd_val(*pmd) & HPAGE_MASK) + (addr & ~HPAGE_MASK);
- }
- if (unlikely(pmd_bad(*pmd)))
- return -0x10UL;
-
- ptep = pte_offset_map(pmd, addr);
- if (!pte_present(*ptep))
- return -0x11UL;
- if (write && !pte_write(*ptep))
- return -0x04UL;
+ if (pmd_none(*pmd) || unlikely(pmd_bad(*pmd)))
+ return (pte_t *) 0x10;
- return (pte_val(*ptep) & PAGE_MASK) + (addr & ~PAGE_MASK);
+ return pte_offset_map(pmd, addr);
}
static __always_inline size_t __user_copy_pt(unsigned long uaddr, void *kptr,
size_t n, int write_user)
{
struct mm_struct *mm = current->mm;
- unsigned long offset, done, size, kaddr;
+ unsigned long offset, pfn, done, size;
+ pte_t *pte;
void *from, *to;
done = 0;
retry:
spin_lock(&mm->page_table_lock);
do {
- kaddr = follow_table(mm, uaddr, write_user);
- if (IS_ERR_VALUE(kaddr))
+ pte = follow_table(mm, uaddr);
+ if ((unsigned long) pte < 0x1000)
goto fault;
+ if (!pte_present(*pte)) {
+ pte = (pte_t *) 0x11;
+ goto fault;
+ } else if (write_user && !pte_write(*pte)) {
+ pte = (pte_t *) 0x04;
+ goto fault;
+ }
- offset = uaddr & ~PAGE_MASK;
+ pfn = pte_pfn(*pte);
+ offset = uaddr & (PAGE_SIZE - 1);
size = min(n - done, PAGE_SIZE - offset);
if (write_user) {
- to = (void *) kaddr;
+ to = (void *)((pfn << PAGE_SHIFT) + offset);
from = kptr + done;
} else {
- from = (void *) kaddr;
+ from = (void *)((pfn << PAGE_SHIFT) + offset);
to = kptr + done;
}
memcpy(to, from, size);
@@ -88,7 +75,7 @@ static __always_inline size_t __user_copy_pt(unsigned long uaddr, void *kptr,
return n - done;
fault:
spin_unlock(&mm->page_table_lock);
- if (__handle_fault(uaddr, -kaddr, write_user))
+ if (__handle_fault(uaddr, (unsigned long) pte, write_user))
return n - done;
goto retry;
}
@@ -97,22 +84,27 @@ static __always_inline size_t __user_copy_pt(unsigned long uaddr, void *kptr,
* Do DAT for user address by page table walk, return kernel address.
* This function needs to be called with current->mm->page_table_lock held.
*/
-static __always_inline unsigned long __dat_user_addr(unsigned long uaddr,
- int write)
+static __always_inline unsigned long __dat_user_addr(unsigned long uaddr)
{
struct mm_struct *mm = current->mm;
- unsigned long kaddr;
+ unsigned long pfn;
+ pte_t *pte;
int rc;
retry:
- kaddr = follow_table(mm, uaddr, write);
- if (IS_ERR_VALUE(kaddr))
+ pte = follow_table(mm, uaddr);
+ if ((unsigned long) pte < 0x1000)
+ goto fault;
+ if (!pte_present(*pte)) {
+ pte = (pte_t *) 0x11;
goto fault;
+ }
- return kaddr;
+ pfn = pte_pfn(*pte);
+ return (pfn << PAGE_SHIFT) + (uaddr & (PAGE_SIZE - 1));
fault:
spin_unlock(&mm->page_table_lock);
- rc = __handle_fault(uaddr, -kaddr, write);
+ rc = __handle_fault(uaddr, (unsigned long) pte, 0);
spin_lock(&mm->page_table_lock);
if (!rc)
goto retry;
@@ -167,9 +159,11 @@ static size_t clear_user_pt(size_t n, void __user *to)
static size_t strnlen_user_pt(size_t count, const char __user *src)
{
+ char *addr;
unsigned long uaddr = (unsigned long) src;
struct mm_struct *mm = current->mm;
- unsigned long offset, done, len, kaddr;
+ unsigned long offset, pfn, done, len;
+ pte_t *pte;
size_t len_str;
if (segment_eq(get_fs(), KERNEL_DS))
@@ -178,13 +172,19 @@ static size_t strnlen_user_pt(size_t count, const char __user *src)
retry:
spin_lock(&mm->page_table_lock);
do {
- kaddr = follow_table(mm, uaddr, 0);
- if (IS_ERR_VALUE(kaddr))
+ pte = follow_table(mm, uaddr);
+ if ((unsigned long) pte < 0x1000)
+ goto fault;
+ if (!pte_present(*pte)) {
+ pte = (pte_t *) 0x11;
goto fault;
+ }
- offset = uaddr & ~PAGE_MASK;
+ pfn = pte_pfn(*pte);
+ offset = uaddr & (PAGE_SIZE-1);
+ addr = (char *)(pfn << PAGE_SHIFT) + offset;
len = min(count - done, PAGE_SIZE - offset);
- len_str = strnlen((char *) kaddr, len);
+ len_str = strnlen(addr, len);
done += len_str;
uaddr += len_str;
} while ((len_str == len) && (done < count));
@@ -192,7 +192,7 @@ static size_t strnlen_user_pt(size_t count, const char __user *src)
return done + 1;
fault:
spin_unlock(&mm->page_table_lock);
- if (__handle_fault(uaddr, -kaddr, 0))
+ if (__handle_fault(uaddr, (unsigned long) pte, 0))
return 0;
goto retry;
}
@@ -225,10 +225,11 @@ static size_t copy_in_user_pt(size_t n, void __user *to,
const void __user *from)
{
struct mm_struct *mm = current->mm;
- unsigned long offset_max, uaddr, done, size, error_code;
+ unsigned long offset_from, offset_to, offset_max, pfn_from, pfn_to,
+ uaddr, done, size, error_code;
unsigned long uaddr_from = (unsigned long) from;
unsigned long uaddr_to = (unsigned long) to;
- unsigned long kaddr_to, kaddr_from;
+ pte_t *pte_from, *pte_to;
int write_user;
if (segment_eq(get_fs(), KERNEL_DS)) {
@@ -241,23 +242,38 @@ static size_t copy_in_user_pt(size_t n, void __user *to,
do {
write_user = 0;
uaddr = uaddr_from;
- kaddr_from = follow_table(mm, uaddr_from, 0);
- error_code = kaddr_from;
- if (IS_ERR_VALUE(error_code))
+ pte_from = follow_table(mm, uaddr_from);
+ error_code = (unsigned long) pte_from;
+ if (error_code < 0x1000)
+ goto fault;
+ if (!pte_present(*pte_from)) {
+ error_code = 0x11;
goto fault;
+ }
write_user = 1;
uaddr = uaddr_to;
- kaddr_to = follow_table(mm, uaddr_to, 1);
- error_code = (unsigned long) kaddr_to;
- if (IS_ERR_VALUE(error_code))
+ pte_to = follow_table(mm, uaddr_to);
+ error_code = (unsigned long) pte_to;
+ if (error_code < 0x1000)
+ goto fault;
+ if (!pte_present(*pte_to)) {
+ error_code = 0x11;
goto fault;
+ } else if (!pte_write(*pte_to)) {
+ error_code = 0x04;
+ goto fault;
+ }
- offset_max = max(uaddr_from & ~PAGE_MASK,
- uaddr_to & ~PAGE_MASK);
+ pfn_from = pte_pfn(*pte_from);
+ pfn_to = pte_pfn(*pte_to);
+ offset_from = uaddr_from & (PAGE_SIZE-1);
+ offset_to = uaddr_from & (PAGE_SIZE-1);
+ offset_max = max(offset_from, offset_to);
size = min(n - done, PAGE_SIZE - offset_max);
- memcpy((void *) kaddr_to, (void *) kaddr_from, size);
+ memcpy((void *)(pfn_to << PAGE_SHIFT) + offset_to,
+ (void *)(pfn_from << PAGE_SHIFT) + offset_from, size);
done += size;
uaddr_from += size;
uaddr_to += size;
@@ -266,7 +282,7 @@ static size_t copy_in_user_pt(size_t n, void __user *to,
return n - done;
fault:
spin_unlock(&mm->page_table_lock);
- if (__handle_fault(uaddr, -error_code, write_user))
+ if (__handle_fault(uaddr, error_code, write_user))
return n - done;
goto retry;
}
@@ -325,7 +341,7 @@ int futex_atomic_op_pt(int op, u32 __user *uaddr, int oparg, int *old)
return __futex_atomic_op_pt(op, uaddr, oparg, old);
spin_lock(¤t->mm->page_table_lock);
uaddr = (u32 __force __user *)
- __dat_user_addr((__force unsigned long) uaddr, 1);
+ __dat_user_addr((__force unsigned long) uaddr);
if (!uaddr) {
spin_unlock(¤t->mm->page_table_lock);
return -EFAULT;
@@ -362,7 +378,7 @@ int futex_atomic_cmpxchg_pt(u32 *uval, u32 __user *uaddr,
return __futex_atomic_cmpxchg_pt(uval, uaddr, oldval, newval);
spin_lock(¤t->mm->page_table_lock);
uaddr = (u32 __force __user *)
- __dat_user_addr((__force unsigned long) uaddr, 1);
+ __dat_user_addr((__force unsigned long) uaddr);
if (!uaddr) {
spin_unlock(¤t->mm->page_table_lock);
return -EFAULT;
diff --git a/trunk/arch/s390/oprofile/init.c b/trunk/arch/s390/oprofile/init.c
index 584b93674ea4..a1e9d69a9c90 100644
--- a/trunk/arch/s390/oprofile/init.c
+++ b/trunk/arch/s390/oprofile/init.c
@@ -169,7 +169,7 @@ static ssize_t hw_interval_write(struct file *file, char const __user *buf,
if (*offset)
return -EINVAL;
retval = oprofilefs_ulong_from_user(&val, buf, count);
- if (retval <= 0)
+ if (retval)
return retval;
if (val < oprofile_min_interval)
oprofile_hw_interval = oprofile_min_interval;
@@ -212,7 +212,7 @@ static ssize_t hwsampler_zero_write(struct file *file, char const __user *buf,
return -EINVAL;
retval = oprofilefs_ulong_from_user(&val, buf, count);
- if (retval <= 0)
+ if (retval)
return retval;
if (val != 0)
return -EINVAL;
@@ -243,7 +243,7 @@ static ssize_t hwsampler_kernel_write(struct file *file, char const __user *buf,
return -EINVAL;
retval = oprofilefs_ulong_from_user(&val, buf, count);
- if (retval <= 0)
+ if (retval)
return retval;
if (val != 0 && val != 1)
@@ -278,7 +278,7 @@ static ssize_t hwsampler_user_write(struct file *file, char const __user *buf,
return -EINVAL;
retval = oprofilefs_ulong_from_user(&val, buf, count);
- if (retval <= 0)
+ if (retval)
return retval;
if (val != 0 && val != 1)
@@ -317,7 +317,7 @@ static ssize_t timer_enabled_write(struct file *file, char const __user *buf,
return -EINVAL;
retval = oprofilefs_ulong_from_user(&val, buf, count);
- if (retval <= 0)
+ if (retval)
return retval;
if (val != 0 && val != 1)
diff --git a/trunk/arch/sh/kernel/cpu/sh5/entry.S b/trunk/arch/sh/kernel/cpu/sh5/entry.S
index 7e605b95592a..b7cf6a547f11 100644
--- a/trunk/arch/sh/kernel/cpu/sh5/entry.S
+++ b/trunk/arch/sh/kernel/cpu/sh5/entry.S
@@ -933,7 +933,7 @@ ret_with_reschedule:
pta restore_all, tr1
- movi (_TIF_SIGPENDING|_TIF_NOTIFY_RESUME), r8
+ movi _TIF_SIGPENDING, r8
and r8, r7, r8
pta work_notifysig, tr0
bne r8, ZERO, tr0
diff --git a/trunk/arch/sh/kernel/entry-common.S b/trunk/arch/sh/kernel/entry-common.S
index b96489d8b27d..f67601cb3f1f 100644
--- a/trunk/arch/sh/kernel/entry-common.S
+++ b/trunk/arch/sh/kernel/entry-common.S
@@ -139,7 +139,7 @@ work_pending:
! r8: current_thread_info
! t: result of "tst #_TIF_NEED_RESCHED, r0"
bf/s work_resched
- tst #(_TIF_SIGPENDING | _TIF_NOTIFY_RESUME), r0
+ tst #_TIF_SIGPENDING, r0
work_notifysig:
bt/s __restore_all
mov r15, r4
diff --git a/trunk/arch/sparc/kernel/module.c b/trunk/arch/sparc/kernel/module.c
index f1ddc0d23679..15e0a1693976 100644
--- a/trunk/arch/sparc/kernel/module.c
+++ b/trunk/arch/sparc/kernel/module.c
@@ -48,7 +48,9 @@ void *module_alloc(unsigned long size)
return NULL;
ret = module_map(size);
- if (ret)
+ if (!ret)
+ ret = ERR_PTR(-ENOMEM);
+ else
memset(ret, 0, size);
return ret;
@@ -114,10 +116,6 @@ int apply_relocate_add(Elf_Shdr *sechdrs,
v = sym->st_value + rel[i].r_addend;
switch (ELF_R_TYPE(rel[i].r_info) & 0xff) {
- case R_SPARC_DISP32:
- v -= (Elf_Addr) location;
- *loc32 = v;
- break;
#ifdef CONFIG_SPARC64
case R_SPARC_64:
location[0] = v >> 56;
@@ -130,6 +128,11 @@ int apply_relocate_add(Elf_Shdr *sechdrs,
location[7] = v >> 0;
break;
+ case R_SPARC_DISP32:
+ v -= (Elf_Addr) location;
+ *loc32 = v;
+ break;
+
case R_SPARC_WDISP19:
v -= (Elf_Addr) location;
*loc32 = (*loc32 & ~0x7ffff) |
diff --git a/trunk/arch/x86/Kconfig b/trunk/arch/x86/Kconfig
index 50a1d1f9b6d3..8ec3a1aa4abd 100644
--- a/trunk/arch/x86/Kconfig
+++ b/trunk/arch/x86/Kconfig
@@ -746,10 +746,10 @@ config SWIOTLB
def_bool y if X86_64
---help---
Support for software bounce buffers used on x86-64 systems
- which don't have a hardware IOMMU. Using this PCI devices
- which can only access 32-bits of memory can be used on systems
- with more than 3 GB of memory.
- If unsure, say Y.
+ which don't have a hardware IOMMU (e.g. the current generation
+ of Intel's x86-64 CPUs). Using this PCI devices which can only
+ access 32-bits of memory can be used on systems with more than
+ 3 GB of memory. If unsure, say Y.
config IOMMU_HELPER
def_bool (CALGARY_IOMMU || GART_IOMMU || SWIOTLB || AMD_IOMMU)
diff --git a/trunk/arch/x86/Makefile b/trunk/arch/x86/Makefile
index 474ca35b1bce..682e9c210baa 100644
--- a/trunk/arch/x86/Makefile
+++ b/trunk/arch/x86/Makefile
@@ -142,7 +142,7 @@ KBUILD_CFLAGS += $(call cc-option,-mno-avx,)
KBUILD_CFLAGS += $(mflags-y)
KBUILD_AFLAGS += $(mflags-y)
-archscripts: scripts_basic
+archscripts:
$(Q)$(MAKE) $(build)=arch/x86/tools relocs
###
diff --git a/trunk/arch/x86/include/asm/xen/page.h b/trunk/arch/x86/include/asm/xen/page.h
index 472b9b783019..93971e841dd5 100644
--- a/trunk/arch/x86/include/asm/xen/page.h
+++ b/trunk/arch/x86/include/asm/xen/page.h
@@ -51,8 +51,7 @@ extern unsigned long set_phys_range_identity(unsigned long pfn_s,
extern int m2p_add_override(unsigned long mfn, struct page *page,
struct gnttab_map_grant_ref *kmap_op);
-extern int m2p_remove_override(struct page *page,
- struct gnttab_map_grant_ref *kmap_op);
+extern int m2p_remove_override(struct page *page, bool clear_pte);
extern struct page *m2p_find_override(unsigned long mfn);
extern unsigned long m2p_find_override_pfn(unsigned long mfn, unsigned long pfn);
diff --git a/trunk/arch/x86/kernel/cpu/perf_event.h b/trunk/arch/x86/kernel/cpu/perf_event.h
index 8b6defe7eefc..6605a81ba339 100644
--- a/trunk/arch/x86/kernel/cpu/perf_event.h
+++ b/trunk/arch/x86/kernel/cpu/perf_event.h
@@ -586,8 +586,6 @@ extern struct event_constraint intel_westmere_pebs_event_constraints[];
extern struct event_constraint intel_snb_pebs_event_constraints[];
-extern struct event_constraint intel_ivb_pebs_event_constraints[];
-
struct event_constraint *intel_pebs_constraints(struct perf_event *event);
void intel_pmu_pebs_enable(struct perf_event *event);
diff --git a/trunk/arch/x86/kernel/cpu/perf_event_amd_ibs.c b/trunk/arch/x86/kernel/cpu/perf_event_amd_ibs.c
index eebd5ffe1bba..7bfb5bec8630 100644
--- a/trunk/arch/x86/kernel/cpu/perf_event_amd_ibs.c
+++ b/trunk/arch/x86/kernel/cpu/perf_event_amd_ibs.c
@@ -209,15 +209,6 @@ static int perf_ibs_precise_event(struct perf_event *event, u64 *config)
return -EOPNOTSUPP;
}
-static const struct perf_event_attr ibs_notsupp = {
- .exclude_user = 1,
- .exclude_kernel = 1,
- .exclude_hv = 1,
- .exclude_idle = 1,
- .exclude_host = 1,
- .exclude_guest = 1,
-};
-
static int perf_ibs_init(struct perf_event *event)
{
struct hw_perf_event *hwc = &event->hw;
@@ -238,9 +229,6 @@ static int perf_ibs_init(struct perf_event *event)
if (event->pmu != &perf_ibs->pmu)
return -ENOENT;
- if (perf_flags(&event->attr) & perf_flags(&ibs_notsupp))
- return -EINVAL;
-
if (config & ~perf_ibs->config_mask)
return -EINVAL;
diff --git a/trunk/arch/x86/kernel/cpu/perf_event_intel.c b/trunk/arch/x86/kernel/cpu/perf_event_intel.c
index 6bca492b8547..7f2739e03e79 100644
--- a/trunk/arch/x86/kernel/cpu/perf_event_intel.c
+++ b/trunk/arch/x86/kernel/cpu/perf_event_intel.c
@@ -2008,7 +2008,6 @@ __init int intel_pmu_init(void)
break;
case 28: /* Atom */
- case 54: /* Cedariew */
memcpy(hw_cache_event_ids, atom_hw_cache_event_ids,
sizeof(hw_cache_event_ids));
@@ -2048,6 +2047,7 @@ __init int intel_pmu_init(void)
case 42: /* SandyBridge */
case 45: /* SandyBridge, "Romely-EP" */
x86_add_quirk(intel_sandybridge_quirk);
+ case 58: /* IvyBridge */
memcpy(hw_cache_event_ids, snb_hw_cache_event_ids,
sizeof(hw_cache_event_ids));
memcpy(hw_cache_extra_regs, snb_hw_cache_extra_regs,
@@ -2072,29 +2072,6 @@ __init int intel_pmu_init(void)
pr_cont("SandyBridge events, ");
break;
- case 58: /* IvyBridge */
- memcpy(hw_cache_event_ids, snb_hw_cache_event_ids,
- sizeof(hw_cache_event_ids));
- memcpy(hw_cache_extra_regs, snb_hw_cache_extra_regs,
- sizeof(hw_cache_extra_regs));
-
- intel_pmu_lbr_init_snb();
-
- x86_pmu.event_constraints = intel_snb_event_constraints;
- x86_pmu.pebs_constraints = intel_ivb_pebs_event_constraints;
- x86_pmu.pebs_aliases = intel_pebs_aliases_snb;
- x86_pmu.extra_regs = intel_snb_extra_regs;
- /* all extra regs are per-cpu when HT is on */
- x86_pmu.er_flags |= ERF_HAS_RSP_1;
- x86_pmu.er_flags |= ERF_NO_HT_SHARING;
-
- /* UOPS_ISSUED.ANY,c=1,i=1 to count stall cycles */
- intel_perfmon_event_map[PERF_COUNT_HW_STALLED_CYCLES_FRONTEND] =
- X86_CONFIG(.event=0x0e, .umask=0x01, .inv=1, .cmask=1);
-
- pr_cont("IvyBridge events, ");
- break;
-
default:
switch (x86_pmu.version) {
diff --git a/trunk/arch/x86/kernel/cpu/perf_event_intel_ds.c b/trunk/arch/x86/kernel/cpu/perf_event_intel_ds.c
index 826054a4f2ee..e38d97bf4259 100644
--- a/trunk/arch/x86/kernel/cpu/perf_event_intel_ds.c
+++ b/trunk/arch/x86/kernel/cpu/perf_event_intel_ds.c
@@ -407,20 +407,6 @@ struct event_constraint intel_snb_pebs_event_constraints[] = {
EVENT_CONSTRAINT_END
};
-struct event_constraint intel_ivb_pebs_event_constraints[] = {
- INTEL_UEVENT_CONSTRAINT(0x01c0, 0x2), /* INST_RETIRED.PRECDIST */
- INTEL_UEVENT_CONSTRAINT(0x01c2, 0xf), /* UOPS_RETIRED.ALL */
- INTEL_UEVENT_CONSTRAINT(0x02c2, 0xf), /* UOPS_RETIRED.RETIRE_SLOTS */
- INTEL_EVENT_CONSTRAINT(0xc4, 0xf), /* BR_INST_RETIRED.* */
- INTEL_EVENT_CONSTRAINT(0xc5, 0xf), /* BR_MISP_RETIRED.* */
- INTEL_EVENT_CONSTRAINT(0xcd, 0x8), /* MEM_TRANS_RETIRED.* */
- INTEL_EVENT_CONSTRAINT(0xd0, 0xf), /* MEM_UOP_RETIRED.* */
- INTEL_EVENT_CONSTRAINT(0xd1, 0xf), /* MEM_LOAD_UOPS_RETIRED.* */
- INTEL_EVENT_CONSTRAINT(0xd2, 0xf), /* MEM_LOAD_UOPS_LLC_HIT_RETIRED.* */
- INTEL_EVENT_CONSTRAINT(0xd3, 0xf), /* MEM_LOAD_UOPS_LLC_MISS_RETIRED.* */
- EVENT_CONSTRAINT_END
-};
-
struct event_constraint *intel_pebs_constraints(struct perf_event *event)
{
struct event_constraint *c;
diff --git a/trunk/arch/x86/kernel/cpu/perf_event_intel_lbr.c b/trunk/arch/x86/kernel/cpu/perf_event_intel_lbr.c
index da02e9cc3754..520b4265fcd2 100644
--- a/trunk/arch/x86/kernel/cpu/perf_event_intel_lbr.c
+++ b/trunk/arch/x86/kernel/cpu/perf_event_intel_lbr.c
@@ -686,8 +686,7 @@ void intel_pmu_lbr_init_atom(void)
* to have an operational LBR which can freeze
* on PMU interrupt
*/
- if (boot_cpu_data.x86_model == 28
- && boot_cpu_data.x86_mask < 10) {
+ if (boot_cpu_data.x86_mask < 10) {
pr_cont("LBR disabled due to erratum");
return;
}
diff --git a/trunk/arch/x86/kernel/cpu/perf_event_intel_uncore.c b/trunk/arch/x86/kernel/cpu/perf_event_intel_uncore.c
index 38e4894165b9..0a5571080e74 100644
--- a/trunk/arch/x86/kernel/cpu/perf_event_intel_uncore.c
+++ b/trunk/arch/x86/kernel/cpu/perf_event_intel_uncore.c
@@ -661,11 +661,6 @@ static void snb_uncore_msr_init_box(struct intel_uncore_box *box)
}
}
-static struct uncore_event_desc snb_uncore_events[] = {
- INTEL_UNCORE_EVENT_DESC(clockticks, "event=0xff,umask=0x00"),
- { /* end: all zeroes */ },
-};
-
static struct attribute *snb_uncore_formats_attr[] = {
&format_attr_event.attr,
&format_attr_umask.attr,
@@ -709,7 +704,6 @@ static struct intel_uncore_type snb_uncore_cbox = {
.constraints = snb_uncore_cbox_constraints,
.ops = &snb_uncore_msr_ops,
.format_group = &snb_uncore_format_group,
- .event_descs = snb_uncore_events,
};
static struct intel_uncore_type *snb_msr_uncores[] = {
diff --git a/trunk/arch/x86/kernel/microcode_core.c b/trunk/arch/x86/kernel/microcode_core.c
index 9e5bcf1e2376..4873e62db6a1 100644
--- a/trunk/arch/x86/kernel/microcode_core.c
+++ b/trunk/arch/x86/kernel/microcode_core.c
@@ -225,9 +225,6 @@ static ssize_t microcode_write(struct file *file, const char __user *buf,
if (do_microcode_update(buf, len) == 0)
ret = (ssize_t)len;
- if (ret > 0)
- perf_check_microcode();
-
mutex_unlock(µcode_mutex);
put_online_cpus();
diff --git a/trunk/arch/x86/mm/init.c b/trunk/arch/x86/mm/init.c
index ab1f6a93b527..e0e6990723e9 100644
--- a/trunk/arch/x86/mm/init.c
+++ b/trunk/arch/x86/mm/init.c
@@ -319,7 +319,7 @@ unsigned long __init_refok init_memory_mapping(unsigned long start,
*/
int devmem_is_allowed(unsigned long pagenr)
{
- if (pagenr < 256)
+ if (pagenr <= 256)
return 1;
if (iomem_is_exclusive(pagenr << PAGE_SHIFT))
return 0;
diff --git a/trunk/arch/x86/xen/enlighten.c b/trunk/arch/x86/xen/enlighten.c
index 1fbe75a95f15..9642d4a38602 100644
--- a/trunk/arch/x86/xen/enlighten.c
+++ b/trunk/arch/x86/xen/enlighten.c
@@ -1452,10 +1452,6 @@ asmlinkage void __init xen_start_kernel(void)
pci_request_acs();
xen_acpi_sleep_register();
-
- /* Avoid searching for BIOS MP tables */
- x86_init.mpparse.find_smp_config = x86_init_noop;
- x86_init.mpparse.get_smp_config = x86_init_uint_noop;
}
#ifdef CONFIG_PCI
/* PCI BIOS service won't work from a PV guest. */
diff --git a/trunk/arch/x86/xen/p2m.c b/trunk/arch/x86/xen/p2m.c
index 72213da605f5..76ba0e97e530 100644
--- a/trunk/arch/x86/xen/p2m.c
+++ b/trunk/arch/x86/xen/p2m.c
@@ -828,6 +828,9 @@ int m2p_add_override(unsigned long mfn, struct page *page,
xen_mc_issue(PARAVIRT_LAZY_MMU);
}
+ /* let's use dev_bus_addr to record the old mfn instead */
+ kmap_op->dev_bus_addr = page->index;
+ page->index = (unsigned long) kmap_op;
}
spin_lock_irqsave(&m2p_override_lock, flags);
list_add(&page->lru, &m2p_overrides[mfn_hash(mfn)]);
@@ -854,8 +857,7 @@ int m2p_add_override(unsigned long mfn, struct page *page,
return 0;
}
EXPORT_SYMBOL_GPL(m2p_add_override);
-int m2p_remove_override(struct page *page,
- struct gnttab_map_grant_ref *kmap_op)
+int m2p_remove_override(struct page *page, bool clear_pte)
{
unsigned long flags;
unsigned long mfn;
@@ -885,8 +887,10 @@ int m2p_remove_override(struct page *page,
WARN_ON(!PagePrivate(page));
ClearPagePrivate(page);
- set_phys_to_machine(pfn, page->index);
- if (kmap_op != NULL) {
+ if (clear_pte) {
+ struct gnttab_map_grant_ref *map_op =
+ (struct gnttab_map_grant_ref *) page->index;
+ set_phys_to_machine(pfn, map_op->dev_bus_addr);
if (!PageHighMem(page)) {
struct multicall_space mcs;
struct gnttab_unmap_grant_ref *unmap_op;
@@ -898,13 +902,13 @@ int m2p_remove_override(struct page *page,
* issued. In this case handle is going to -1 because
* it hasn't been modified yet.
*/
- if (kmap_op->handle == -1)
+ if (map_op->handle == -1)
xen_mc_flush();
/*
- * Now if kmap_op->handle is negative it means that the
+ * Now if map_op->handle is negative it means that the
* hypercall actually returned an error.
*/
- if (kmap_op->handle == GNTST_general_error) {
+ if (map_op->handle == GNTST_general_error) {
printk(KERN_WARNING "m2p_remove_override: "
"pfn %lx mfn %lx, failed to modify kernel mappings",
pfn, mfn);
@@ -914,8 +918,8 @@ int m2p_remove_override(struct page *page,
mcs = xen_mc_entry(
sizeof(struct gnttab_unmap_grant_ref));
unmap_op = mcs.args;
- unmap_op->host_addr = kmap_op->host_addr;
- unmap_op->handle = kmap_op->handle;
+ unmap_op->host_addr = map_op->host_addr;
+ unmap_op->handle = map_op->handle;
unmap_op->dev_bus_addr = 0;
MULTI_grant_table_op(mcs.mc,
@@ -926,9 +930,10 @@ int m2p_remove_override(struct page *page,
set_pte_at(&init_mm, address, ptep,
pfn_pte(pfn, PAGE_KERNEL));
__flush_tlb_single(address);
- kmap_op->host_addr = 0;
+ map_op->host_addr = 0;
}
- }
+ } else
+ set_phys_to_machine(pfn, page->index);
/* p2m(m2p(mfn)) == FOREIGN_FRAME(mfn): the mfn is already present
* somewhere in this domain, even before being added to the
diff --git a/trunk/block/blk-core.c b/trunk/block/blk-core.c
index ee3cb3a5e278..4b4dbdfbca89 100644
--- a/trunk/block/blk-core.c
+++ b/trunk/block/blk-core.c
@@ -2254,11 +2254,9 @@ bool blk_update_request(struct request *req, int error, unsigned int nr_bytes)
error_type = "I/O";
break;
}
- printk_ratelimited(KERN_ERR "end_request: %s error, dev %s, sector %llu\n",
- error_type, req->rq_disk ?
- req->rq_disk->disk_name : "?",
- (unsigned long long)blk_rq_pos(req));
-
+ printk(KERN_ERR "end_request: %s error, dev %s, sector %llu\n",
+ error_type, req->rq_disk ? req->rq_disk->disk_name : "?",
+ (unsigned long long)blk_rq_pos(req));
}
blk_account_io_completion(req, nr_bytes);
diff --git a/trunk/block/ioctl.c b/trunk/block/ioctl.c
index 4a85096f5410..4476e0e85d16 100644
--- a/trunk/block/ioctl.c
+++ b/trunk/block/ioctl.c
@@ -41,7 +41,7 @@ static int blkpg_ioctl(struct block_device *bdev, struct blkpg_ioctl_arg __user
sizeof(long long) > sizeof(long)) {
long pstart = start, plength = length;
if (pstart != start || plength != length
- || pstart < 0 || plength < 0 || partno > 65535)
+ || pstart < 0 || plength < 0)
return -EINVAL;
}
diff --git a/trunk/drivers/acpi/bus.c b/trunk/drivers/acpi/bus.c
index e0596954290b..9628652e080c 100644
--- a/trunk/drivers/acpi/bus.c
+++ b/trunk/drivers/acpi/bus.c
@@ -237,16 +237,6 @@ static int __acpi_bus_get_power(struct acpi_device *device, int *state)
} else if (result == ACPI_STATE_D3_HOT) {
result = ACPI_STATE_D3;
}
-
- /*
- * If we were unsure about the device parent's power state up to this
- * point, the fact that the device is in D0 implies that the parent has
- * to be in D0 too.
- */
- if (device->parent && device->parent->power.state == ACPI_STATE_UNKNOWN
- && result == ACPI_STATE_D0)
- device->parent->power.state = ACPI_STATE_D0;
-
*state = result;
out:
diff --git a/trunk/drivers/acpi/power.c b/trunk/drivers/acpi/power.c
index 40e38a06ba85..fc1803414629 100644
--- a/trunk/drivers/acpi/power.c
+++ b/trunk/drivers/acpi/power.c
@@ -107,7 +107,6 @@ struct acpi_power_resource {
/* List of devices relying on this power resource */
struct acpi_power_resource_device *devices;
- struct mutex devices_lock;
};
static struct list_head acpi_power_resource_list;
@@ -226,6 +225,7 @@ static void acpi_power_on_device(struct acpi_power_managed_device *device)
static int __acpi_power_on(struct acpi_power_resource *resource)
{
+ struct acpi_power_resource_device *device_list = resource->devices;
acpi_status status = AE_OK;
status = acpi_evaluate_object(resource->device->handle, "_ON", NULL, NULL);
@@ -238,15 +238,19 @@ static int __acpi_power_on(struct acpi_power_resource *resource)
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Power resource [%s] turned on\n",
resource->name));
+ while (device_list) {
+ acpi_power_on_device(device_list->device);
+
+ device_list = device_list->next;
+ }
+
return 0;
}
static int acpi_power_on(acpi_handle handle)
{
int result = 0;
- bool resume_device = false;
struct acpi_power_resource *resource = NULL;
- struct acpi_power_resource_device *device_list;
result = acpi_power_get_context(handle, &resource);
if (result)
@@ -262,25 +266,10 @@ static int acpi_power_on(acpi_handle handle)
result = __acpi_power_on(resource);
if (result)
resource->ref_count--;
- else
- resume_device = true;
}
mutex_unlock(&resource->resource_lock);
- if (!resume_device)
- return result;
-
- mutex_lock(&resource->devices_lock);
-
- device_list = resource->devices;
- while (device_list) {
- acpi_power_on_device(device_list->device);
- device_list = device_list->next;
- }
-
- mutex_unlock(&resource->devices_lock);
-
return result;
}
@@ -366,7 +355,7 @@ static void __acpi_power_resource_unregister_device(struct device *dev,
if (acpi_power_get_context(res_handle, &resource))
return;
- mutex_lock(&resource->devices_lock);
+ mutex_lock(&resource->resource_lock);
prev = NULL;
curr = resource->devices;
while (curr) {
@@ -383,7 +372,7 @@ static void __acpi_power_resource_unregister_device(struct device *dev,
prev = curr;
curr = curr->next;
}
- mutex_unlock(&resource->devices_lock);
+ mutex_unlock(&resource->resource_lock);
}
/* Unlink dev from all power resources in _PR0 */
@@ -425,10 +414,10 @@ static int __acpi_power_resource_register_device(
power_resource_device->device = powered_device;
- mutex_lock(&resource->devices_lock);
+ mutex_lock(&resource->resource_lock);
power_resource_device->next = resource->devices;
resource->devices = power_resource_device;
- mutex_unlock(&resource->devices_lock);
+ mutex_unlock(&resource->resource_lock);
return 0;
}
@@ -473,7 +462,7 @@ int acpi_power_resource_register_device(struct device *dev, acpi_handle handle)
return ret;
no_power_resource:
- printk(KERN_DEBUG PREFIX "Invalid Power Resource to register!");
+ printk(KERN_WARNING PREFIX "Invalid Power Resource to register!");
return -ENODEV;
}
EXPORT_SYMBOL_GPL(acpi_power_resource_register_device);
@@ -732,7 +721,6 @@ static int acpi_power_add(struct acpi_device *device)
resource->device = device;
mutex_init(&resource->resource_lock);
- mutex_init(&resource->devices_lock);
strcpy(resource->name, device->pnp.bus_id);
strcpy(acpi_device_name(device), ACPI_POWER_DEVICE_NAME);
strcpy(acpi_device_class(device), ACPI_POWER_CLASS);
diff --git a/trunk/drivers/ata/ahci.c b/trunk/drivers/ata/ahci.c
index 7862d17976b7..50d5dea0ff59 100644
--- a/trunk/drivers/ata/ahci.c
+++ b/trunk/drivers/ata/ahci.c
@@ -268,9 +268,6 @@ static const struct pci_device_id ahci_pci_tbl[] = {
/* JMicron 360/1/3/5/6, match class to avoid IDE function */
{ PCI_VENDOR_ID_JMICRON, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
PCI_CLASS_STORAGE_SATA_AHCI, 0xffffff, board_ahci_ign_iferr },
- /* JMicron 362B and 362C have an AHCI function with IDE class code */
- { PCI_VDEVICE(JMICRON, 0x2362), board_ahci_ign_iferr },
- { PCI_VDEVICE(JMICRON, 0x236f), board_ahci_ign_iferr },
/* ATI */
{ PCI_VDEVICE(ATI, 0x4380), board_ahci_sb600 }, /* ATI SB600 */
@@ -396,8 +393,6 @@ static const struct pci_device_id ahci_pci_tbl[] = {
.driver_data = board_ahci_yes_fbs }, /* 88se9125 */
{ PCI_DEVICE(0x1b4b, 0x917a),
.driver_data = board_ahci_yes_fbs }, /* 88se9172 */
- { PCI_DEVICE(0x1b4b, 0x9192),
- .driver_data = board_ahci_yes_fbs }, /* 88se9172 on some Gigabyte */
{ PCI_DEVICE(0x1b4b, 0x91a3),
.driver_data = board_ahci_yes_fbs },
@@ -405,10 +400,7 @@ static const struct pci_device_id ahci_pci_tbl[] = {
{ PCI_VDEVICE(PROMISE, 0x3f20), board_ahci }, /* PDC42819 */
/* Asmedia */
- { PCI_VDEVICE(ASMEDIA, 0x0601), board_ahci }, /* ASM1060 */
- { PCI_VDEVICE(ASMEDIA, 0x0602), board_ahci }, /* ASM1060 */
- { PCI_VDEVICE(ASMEDIA, 0x0611), board_ahci }, /* ASM1061 */
- { PCI_VDEVICE(ASMEDIA, 0x0612), board_ahci }, /* ASM1062 */
+ { PCI_VDEVICE(ASMEDIA, 0x0612), board_ahci }, /* ASM1061 */
/* Generic, PCI class code for AHCI */
{ PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
diff --git a/trunk/drivers/block/aoe/aoecmd.c b/trunk/drivers/block/aoe/aoecmd.c
index 887f68f6d79a..de0435e63b02 100644
--- a/trunk/drivers/block/aoe/aoecmd.c
+++ b/trunk/drivers/block/aoe/aoecmd.c
@@ -35,7 +35,6 @@ new_skb(ulong len)
skb_reset_mac_header(skb);
skb_reset_network_header(skb);
skb->protocol = __constant_htons(ETH_P_AOE);
- skb_checksum_none_assert(skb);
}
return skb;
}
diff --git a/trunk/drivers/block/cciss_scsi.c b/trunk/drivers/block/cciss_scsi.c
index da3311129a0c..38aa6dda6b81 100644
--- a/trunk/drivers/block/cciss_scsi.c
+++ b/trunk/drivers/block/cciss_scsi.c
@@ -795,7 +795,6 @@ static void complete_scsi_command(CommandList_struct *c, int timeout,
}
break;
case CMD_PROTOCOL_ERR:
- cmd->result = DID_ERROR << 16;
dev_warn(&h->pdev->dev,
"%p has protocol error\n", c);
break;
diff --git a/trunk/drivers/block/mtip32xx/mtip32xx.c b/trunk/drivers/block/mtip32xx/mtip32xx.c
index f946d31d6917..a8fddeb3d638 100644
--- a/trunk/drivers/block/mtip32xx/mtip32xx.c
+++ b/trunk/drivers/block/mtip32xx/mtip32xx.c
@@ -1148,15 +1148,11 @@ static bool mtip_pause_ncq(struct mtip_port *port,
reply = port->rxfis + RX_FIS_D2H_REG;
task_file_data = readl(port->mmio+PORT_TFDATA);
- if (fis->command == ATA_CMD_SEC_ERASE_UNIT)
- clear_bit(MTIP_DDF_SEC_LOCK_BIT, &port->dd->dd_flag);
-
- if ((task_file_data & 1))
+ if ((task_file_data & 1) || (fis->command == ATA_CMD_SEC_ERASE_UNIT))
return false;
if (fis->command == ATA_CMD_SEC_ERASE_PREP) {
set_bit(MTIP_PF_SE_ACTIVE_BIT, &port->flags);
- set_bit(MTIP_DDF_SEC_LOCK_BIT, &port->dd->dd_flag);
port->ic_pause_timer = jiffies;
return true;
} else if ((fis->command == ATA_CMD_DOWNLOAD_MICRO) &&
@@ -1904,7 +1900,7 @@ static int exec_drive_command(struct mtip_port *port, u8 *command,
int rv = 0, xfer_sz = command[3];
if (xfer_sz) {
- if (!user_buffer)
+ if (user_buffer)
return -EFAULT;
buf = dmam_alloc_coherent(&port->dd->pdev->dev,
@@ -2047,7 +2043,7 @@ static void mtip_set_timeout(struct host_to_dev_fis *fis, unsigned int *timeout)
*timeout = 240000; /* 4 minutes */
break;
case ATA_CMD_STANDBYNOW1:
- *timeout = 120000; /* 2 minutes */
+ *timeout = 10000; /* 10 seconds */
break;
case 0xF7:
case 0xFA:
@@ -2592,6 +2588,9 @@ static ssize_t mtip_hw_read_registers(struct file *f, char __user *ubuf,
if (!len || size)
return 0;
+ if (size < 0)
+ return -EINVAL;
+
size += sprintf(&buf[size], "H/ S ACTive : [ 0x");
for (n = dd->slot_groups-1; n >= 0; n--)
@@ -2661,6 +2660,9 @@ static ssize_t mtip_hw_read_flags(struct file *f, char __user *ubuf,
if (!len || size)
return 0;
+ if (size < 0)
+ return -EINVAL;
+
size += sprintf(&buf[size], "Flag-port : [ %08lX ]\n",
dd->port->flags);
size += sprintf(&buf[size], "Flag-dd : [ %08lX ]\n",
@@ -3212,8 +3214,8 @@ static int mtip_hw_init(struct driver_data *dd)
"Unable to check write protect progress\n");
else
dev_info(&dd->pdev->dev,
- "Write protect progress: %u%% (%u blocks)\n",
- attr242.cur, le32_to_cpu(attr242.data));
+ "Write protect progress: %d%% (%d blocks)\n",
+ attr242.cur, attr242.data);
return rv;
out3:
@@ -3617,10 +3619,6 @@ static void mtip_make_request(struct request_queue *queue, struct bio *bio)
bio_endio(bio, -ENODATA);
return;
}
- if (unlikely(test_bit(MTIP_DDF_SEC_LOCK_BIT, &dd->dd_flag))) {
- bio_endio(bio, -ENODATA);
- return;
- }
}
if (unlikely(!bio_has_data(bio))) {
@@ -4170,13 +4168,7 @@ static void mtip_pci_shutdown(struct pci_dev *pdev)
/* Table of device ids supported by this driver. */
static DEFINE_PCI_DEVICE_TABLE(mtip_pci_tbl) = {
- { PCI_DEVICE(PCI_VENDOR_ID_MICRON, P320H_DEVICE_ID) },
- { PCI_DEVICE(PCI_VENDOR_ID_MICRON, P320M_DEVICE_ID) },
- { PCI_DEVICE(PCI_VENDOR_ID_MICRON, P320S_DEVICE_ID) },
- { PCI_DEVICE(PCI_VENDOR_ID_MICRON, P325M_DEVICE_ID) },
- { PCI_DEVICE(PCI_VENDOR_ID_MICRON, P420H_DEVICE_ID) },
- { PCI_DEVICE(PCI_VENDOR_ID_MICRON, P420M_DEVICE_ID) },
- { PCI_DEVICE(PCI_VENDOR_ID_MICRON, P425M_DEVICE_ID) },
+ { PCI_DEVICE(PCI_VENDOR_ID_MICRON, P320_DEVICE_ID) },
{ 0 }
};
@@ -4207,12 +4199,12 @@ static int __init mtip_init(void)
{
int error;
- pr_info(MTIP_DRV_NAME " Version " MTIP_DRV_VERSION "\n");
+ printk(KERN_INFO MTIP_DRV_NAME " Version " MTIP_DRV_VERSION "\n");
/* Allocate a major block device number to use with this driver. */
error = register_blkdev(0, MTIP_DRV_NAME);
if (error <= 0) {
- pr_err("Unable to register block device (%d)\n",
+ printk(KERN_ERR "Unable to register block device (%d)\n",
error);
return -EBUSY;
}
@@ -4221,7 +4213,7 @@ static int __init mtip_init(void)
if (!dfs_parent) {
dfs_parent = debugfs_create_dir("rssd", NULL);
if (IS_ERR_OR_NULL(dfs_parent)) {
- pr_warn("Error creating debugfs parent\n");
+ printk(KERN_WARNING "Error creating debugfs parent\n");
dfs_parent = NULL;
}
}
diff --git a/trunk/drivers/block/mtip32xx/mtip32xx.h b/trunk/drivers/block/mtip32xx/mtip32xx.h
index 18627a1d04c5..f51fc23d17bb 100644
--- a/trunk/drivers/block/mtip32xx/mtip32xx.h
+++ b/trunk/drivers/block/mtip32xx/mtip32xx.h
@@ -76,13 +76,7 @@
/* Micron Vendor ID & P320x SSD Device ID */
#define PCI_VENDOR_ID_MICRON 0x1344
-#define P320H_DEVICE_ID 0x5150
-#define P320M_DEVICE_ID 0x5151
-#define P320S_DEVICE_ID 0x5152
-#define P325M_DEVICE_ID 0x5153
-#define P420H_DEVICE_ID 0x5160
-#define P420M_DEVICE_ID 0x5161
-#define P425M_DEVICE_ID 0x5163
+#define P320_DEVICE_ID 0x5150
/* Driver name and version strings */
#define MTIP_DRV_NAME "mtip32xx"
@@ -137,12 +131,10 @@ enum {
MTIP_PF_SVC_THD_STOP_BIT = 8,
/* below are bit numbers in 'dd_flag' defined in driver_data */
- MTIP_DDF_SEC_LOCK_BIT = 0,
MTIP_DDF_REMOVE_PENDING_BIT = 1,
MTIP_DDF_OVER_TEMP_BIT = 2,
MTIP_DDF_WRITE_PROTECT_BIT = 3,
MTIP_DDF_STOP_IO = ((1 << MTIP_DDF_REMOVE_PENDING_BIT) | \
- (1 << MTIP_DDF_SEC_LOCK_BIT) | \
(1 << MTIP_DDF_OVER_TEMP_BIT) | \
(1 << MTIP_DDF_WRITE_PROTECT_BIT)),
diff --git a/trunk/drivers/block/nbd.c b/trunk/drivers/block/nbd.c
index 0c03411c59eb..d07c9f7fded6 100644
--- a/trunk/drivers/block/nbd.c
+++ b/trunk/drivers/block/nbd.c
@@ -449,14 +449,6 @@ static void nbd_clear_que(struct nbd_device *nbd)
req->errors++;
nbd_end_request(req);
}
-
- while (!list_empty(&nbd->waiting_queue)) {
- req = list_entry(nbd->waiting_queue.next, struct request,
- queuelist);
- list_del_init(&req->queuelist);
- req->errors++;
- nbd_end_request(req);
- }
}
@@ -606,7 +598,6 @@ static int __nbd_ioctl(struct block_device *bdev, struct nbd_device *nbd,
nbd->file = NULL;
nbd_clear_que(nbd);
BUG_ON(!list_empty(&nbd->queue_head));
- BUG_ON(!list_empty(&nbd->waiting_queue));
if (file)
fput(file);
return 0;
diff --git a/trunk/drivers/block/xen-blkback/blkback.c b/trunk/drivers/block/xen-blkback/blkback.c
index c6decb901e5e..73f196ca713f 100644
--- a/trunk/drivers/block/xen-blkback/blkback.c
+++ b/trunk/drivers/block/xen-blkback/blkback.c
@@ -337,7 +337,7 @@ static void xen_blkbk_unmap(struct pending_req *req)
invcount++;
}
- ret = gnttab_unmap_refs(unmap, NULL, pages, invcount);
+ ret = gnttab_unmap_refs(unmap, pages, invcount, false);
BUG_ON(ret);
}
diff --git a/trunk/drivers/bluetooth/ath3k.c b/trunk/drivers/bluetooth/ath3k.c
index fc2de5528dcc..11f36e502136 100644
--- a/trunk/drivers/bluetooth/ath3k.c
+++ b/trunk/drivers/bluetooth/ath3k.c
@@ -86,7 +86,6 @@ static struct usb_device_id ath3k_table[] = {
/* Atheros AR5BBU22 with sflash firmware */
{ USB_DEVICE(0x0489, 0xE03C) },
- { USB_DEVICE(0x0489, 0xE036) },
{ } /* Terminating entry */
};
@@ -110,7 +109,6 @@ static struct usb_device_id ath3k_blist_tbl[] = {
/* Atheros AR5BBU22 with sflash firmware */
{ USB_DEVICE(0x0489, 0xE03C), .driver_info = BTUSB_ATH3012 },
- { USB_DEVICE(0x0489, 0xE036), .driver_info = BTUSB_ATH3012 },
{ } /* Terminating entry */
};
diff --git a/trunk/drivers/bluetooth/btusb.c b/trunk/drivers/bluetooth/btusb.c
index 654e248763ef..cef3bac1a543 100644
--- a/trunk/drivers/bluetooth/btusb.c
+++ b/trunk/drivers/bluetooth/btusb.c
@@ -52,9 +52,6 @@ static struct usb_device_id btusb_table[] = {
/* Generic Bluetooth USB device */
{ USB_DEVICE_INFO(0xe0, 0x01, 0x01) },
- /* Apple-specific (Broadcom) devices */
- { USB_VENDOR_AND_INTERFACE_INFO(0x05ac, 0xff, 0x01, 0x01) },
-
/* Broadcom SoftSailing reporting vendor specific */
{ USB_DEVICE(0x0a5c, 0x21e1) },
@@ -97,14 +94,16 @@ static struct usb_device_id btusb_table[] = {
/* Broadcom BCM20702A0 */
{ USB_DEVICE(0x0489, 0xe042) },
+ { USB_DEVICE(0x0a5c, 0x21e3) },
+ { USB_DEVICE(0x0a5c, 0x21e6) },
+ { USB_DEVICE(0x0a5c, 0x21e8) },
+ { USB_DEVICE(0x0a5c, 0x21f3) },
+ { USB_DEVICE(0x0a5c, 0x21f4) },
{ USB_DEVICE(0x413c, 0x8197) },
/* Foxconn - Hon Hai */
{ USB_DEVICE(0x0489, 0xe033) },
- /*Broadcom devices with vendor specific id */
- { USB_VENDOR_AND_INTERFACE_INFO(0x0a5c, 0xff, 0x01, 0x01) },
-
{ } /* Terminating entry */
};
@@ -142,7 +141,6 @@ static struct usb_device_id blacklist_table[] = {
/* Atheros AR5BBU12 with sflash firmware */
{ USB_DEVICE(0x0489, 0xe03c), .driver_info = BTUSB_ATH3012 },
- { USB_DEVICE(0x0489, 0xe036), .driver_info = BTUSB_ATH3012 },
/* Broadcom BCM2035 */
{ USB_DEVICE(0x0a5c, 0x2035), .driver_info = BTUSB_WRONG_SCO_MTU },
diff --git a/trunk/drivers/char/agp/intel-gtt.c b/trunk/drivers/char/agp/intel-gtt.c
index e01f5eaaec82..58e32f7c3229 100644
--- a/trunk/drivers/char/agp/intel-gtt.c
+++ b/trunk/drivers/char/agp/intel-gtt.c
@@ -84,33 +84,40 @@ static struct _intel_private {
#define IS_IRONLAKE intel_private.driver->is_ironlake
#define HAS_PGTBL_EN intel_private.driver->has_pgtbl_enable
-static int intel_gtt_map_memory(struct page **pages,
- unsigned int num_entries,
- struct sg_table *st)
+int intel_gtt_map_memory(struct page **pages, unsigned int num_entries,
+ struct scatterlist **sg_list, int *num_sg)
{
+ struct sg_table st;
struct scatterlist *sg;
int i;
+ if (*sg_list)
+ return 0; /* already mapped (for e.g. resume */
+
DBG("try mapping %lu pages\n", (unsigned long)num_entries);
- if (sg_alloc_table(st, num_entries, GFP_KERNEL))
+ if (sg_alloc_table(&st, num_entries, GFP_KERNEL))
goto err;
- for_each_sg(st->sgl, sg, num_entries, i)
+ *sg_list = sg = st.sgl;
+
+ for (i = 0 ; i < num_entries; i++, sg = sg_next(sg))
sg_set_page(sg, pages[i], PAGE_SIZE, 0);
- if (!pci_map_sg(intel_private.pcidev,
- st->sgl, st->nents, PCI_DMA_BIDIRECTIONAL))
+ *num_sg = pci_map_sg(intel_private.pcidev, *sg_list,
+ num_entries, PCI_DMA_BIDIRECTIONAL);
+ if (unlikely(!*num_sg))
goto err;
return 0;
err:
- sg_free_table(st);
+ sg_free_table(&st);
return -ENOMEM;
}
+EXPORT_SYMBOL(intel_gtt_map_memory);
-static void intel_gtt_unmap_memory(struct scatterlist *sg_list, int num_sg)
+void intel_gtt_unmap_memory(struct scatterlist *sg_list, int num_sg)
{
struct sg_table st;
DBG("try unmapping %lu pages\n", (unsigned long)mem->page_count);
@@ -123,6 +130,7 @@ static void intel_gtt_unmap_memory(struct scatterlist *sg_list, int num_sg)
sg_free_table(&st);
}
+EXPORT_SYMBOL(intel_gtt_unmap_memory);
static void intel_fake_agp_enable(struct agp_bridge_data *bridge, u32 mode)
{
@@ -666,14 +674,9 @@ static int intel_gtt_init(void)
gtt_map_size = intel_private.base.gtt_total_entries * 4;
- intel_private.gtt = NULL;
- if (INTEL_GTT_GEN < 6)
- intel_private.gtt = ioremap_wc(intel_private.gtt_bus_addr,
- gtt_map_size);
- if (intel_private.gtt == NULL)
- intel_private.gtt = ioremap(intel_private.gtt_bus_addr,
- gtt_map_size);
- if (intel_private.gtt == NULL) {
+ intel_private.gtt = ioremap(intel_private.gtt_bus_addr,
+ gtt_map_size);
+ if (!intel_private.gtt) {
intel_private.driver->cleanup();
iounmap(intel_private.registers);
return -ENOMEM;
@@ -876,7 +879,8 @@ static bool i830_check_flags(unsigned int flags)
return false;
}
-void intel_gtt_insert_sg_entries(struct sg_table *st,
+void intel_gtt_insert_sg_entries(struct scatterlist *sg_list,
+ unsigned int sg_len,
unsigned int pg_start,
unsigned int flags)
{
@@ -888,11 +892,12 @@ void intel_gtt_insert_sg_entries(struct sg_table *st,
/* sg may merge pages, but we have to separate
* per-page addr for GTT */
- for_each_sg(st->sgl, sg, st->nents, i) {
+ for_each_sg(sg_list, sg, sg_len, i) {
len = sg_dma_len(sg) >> PAGE_SHIFT;
for (m = 0; m < len; m++) {
dma_addr_t addr = sg_dma_address(sg) + (m << PAGE_SHIFT);
- intel_private.driver->write_entry(addr, j, flags);
+ intel_private.driver->write_entry(addr,
+ j, flags);
j++;
}
}
@@ -900,10 +905,8 @@ void intel_gtt_insert_sg_entries(struct sg_table *st,
}
EXPORT_SYMBOL(intel_gtt_insert_sg_entries);
-static void intel_gtt_insert_pages(unsigned int first_entry,
- unsigned int num_entries,
- struct page **pages,
- unsigned int flags)
+void intel_gtt_insert_pages(unsigned int first_entry, unsigned int num_entries,
+ struct page **pages, unsigned int flags)
{
int i, j;
@@ -914,6 +917,7 @@ static void intel_gtt_insert_pages(unsigned int first_entry,
}
readl(intel_private.gtt+j-1);
}
+EXPORT_SYMBOL(intel_gtt_insert_pages);
static int intel_fake_agp_insert_entries(struct agp_memory *mem,
off_t pg_start, int type)
@@ -949,15 +953,13 @@ static int intel_fake_agp_insert_entries(struct agp_memory *mem,
global_cache_flush();
if (intel_private.base.needs_dmar) {
- struct sg_table st;
-
- ret = intel_gtt_map_memory(mem->pages, mem->page_count, &st);
+ ret = intel_gtt_map_memory(mem->pages, mem->page_count,
+ &mem->sg_list, &mem->num_sg);
if (ret != 0)
return ret;
- intel_gtt_insert_sg_entries(&st, pg_start, type);
- mem->sg_list = st.sgl;
- mem->num_sg = st.nents;
+ intel_gtt_insert_sg_entries(mem->sg_list, mem->num_sg,
+ pg_start, type);
} else
intel_gtt_insert_pages(pg_start, mem->page_count, mem->pages,
type);
diff --git a/trunk/drivers/clk/Makefile b/trunk/drivers/clk/Makefile
index 72ce247a0e8d..5869ea387054 100644
--- a/trunk/drivers/clk/Makefile
+++ b/trunk/drivers/clk/Makefile
@@ -1,5 +1,4 @@
# common clock types
-obj-$(CONFIG_HAVE_CLK) += clk-devres.o
obj-$(CONFIG_CLKDEV_LOOKUP) += clkdev.o
obj-$(CONFIG_COMMON_CLK) += clk.o clk-fixed-rate.o clk-gate.o \
clk-mux.o clk-divider.o clk-fixed-factor.o
diff --git a/trunk/drivers/clk/clk-devres.c b/trunk/drivers/clk/clk-devres.c
deleted file mode 100644
index 8f571548870f..000000000000
--- a/trunk/drivers/clk/clk-devres.c
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#include
-#include
-#include
-#include
-
-static void devm_clk_release(struct device *dev, void *res)
-{
- clk_put(*(struct clk **)res);
-}
-
-struct clk *devm_clk_get(struct device *dev, const char *id)
-{
- struct clk **ptr, *clk;
-
- ptr = devres_alloc(devm_clk_release, sizeof(*ptr), GFP_KERNEL);
- if (!ptr)
- return ERR_PTR(-ENOMEM);
-
- clk = clk_get(dev, id);
- if (!IS_ERR(clk)) {
- *ptr = clk;
- devres_add(dev, ptr);
- } else {
- devres_free(ptr);
- }
-
- return clk;
-}
-EXPORT_SYMBOL(devm_clk_get);
-
-static int devm_clk_match(struct device *dev, void *res, void *data)
-{
- struct clk **c = res;
- if (!c || !*c) {
- WARN_ON(!c || !*c);
- return 0;
- }
- return *c == data;
-}
-
-void devm_clk_put(struct device *dev, struct clk *clk)
-{
- int ret;
-
- ret = devres_release(dev, devm_clk_release, devm_clk_match, clk);
-
- WARN_ON(ret);
-}
-EXPORT_SYMBOL(devm_clk_put);
diff --git a/trunk/drivers/clk/clkdev.c b/trunk/drivers/clk/clkdev.c
index 442a31363873..d423c9bdd71a 100644
--- a/trunk/drivers/clk/clkdev.c
+++ b/trunk/drivers/clk/clkdev.c
@@ -171,6 +171,51 @@ void clk_put(struct clk *clk)
}
EXPORT_SYMBOL(clk_put);
+static void devm_clk_release(struct device *dev, void *res)
+{
+ clk_put(*(struct clk **)res);
+}
+
+struct clk *devm_clk_get(struct device *dev, const char *id)
+{
+ struct clk **ptr, *clk;
+
+ ptr = devres_alloc(devm_clk_release, sizeof(*ptr), GFP_KERNEL);
+ if (!ptr)
+ return ERR_PTR(-ENOMEM);
+
+ clk = clk_get(dev, id);
+ if (!IS_ERR(clk)) {
+ *ptr = clk;
+ devres_add(dev, ptr);
+ } else {
+ devres_free(ptr);
+ }
+
+ return clk;
+}
+EXPORT_SYMBOL(devm_clk_get);
+
+static int devm_clk_match(struct device *dev, void *res, void *data)
+{
+ struct clk **c = res;
+ if (!c || !*c) {
+ WARN_ON(!c || !*c);
+ return 0;
+ }
+ return *c == data;
+}
+
+void devm_clk_put(struct device *dev, struct clk *clk)
+{
+ int ret;
+
+ ret = devres_destroy(dev, devm_clk_release, devm_clk_match, clk);
+
+ WARN_ON(ret);
+}
+EXPORT_SYMBOL(devm_clk_put);
+
void clkdev_add(struct clk_lookup *cl)
{
mutex_lock(&clocks_mutex);
diff --git a/trunk/drivers/cpufreq/powernow-k8.c b/trunk/drivers/cpufreq/powernow-k8.c
index 1a40935c85fd..c0e816468e30 100644
--- a/trunk/drivers/cpufreq/powernow-k8.c
+++ b/trunk/drivers/cpufreq/powernow-k8.c
@@ -35,6 +35,7 @@
#include
#include
#include
+#include /* for current / set_cpus_allowed() */
#include
#include
@@ -1138,23 +1139,16 @@ static int transition_frequency_pstate(struct powernow_k8_data *data,
return res;
}
-struct powernowk8_target_arg {
- struct cpufreq_policy *pol;
- unsigned targfreq;
- unsigned relation;
-};
-
-static long powernowk8_target_fn(void *arg)
+/* Driver entry point to switch to the target frequency */
+static int powernowk8_target(struct cpufreq_policy *pol,
+ unsigned targfreq, unsigned relation)
{
- struct powernowk8_target_arg *pta = arg;
- struct cpufreq_policy *pol = pta->pol;
- unsigned targfreq = pta->targfreq;
- unsigned relation = pta->relation;
+ cpumask_var_t oldmask;
struct powernow_k8_data *data = per_cpu(powernow_data, pol->cpu);
u32 checkfid;
u32 checkvid;
unsigned int newstate;
- int ret;
+ int ret = -EIO;
if (!data)
return -EINVAL;
@@ -1162,16 +1156,29 @@ static long powernowk8_target_fn(void *arg)
checkfid = data->currfid;
checkvid = data->currvid;
+ /* only run on specific CPU from here on. */
+ /* This is poor form: use a workqueue or smp_call_function_single */
+ if (!alloc_cpumask_var(&oldmask, GFP_KERNEL))
+ return -ENOMEM;
+
+ cpumask_copy(oldmask, tsk_cpus_allowed(current));
+ set_cpus_allowed_ptr(current, cpumask_of(pol->cpu));
+
+ if (smp_processor_id() != pol->cpu) {
+ printk(KERN_ERR PFX "limiting to cpu %u failed\n", pol->cpu);
+ goto err_out;
+ }
+
if (pending_bit_stuck()) {
printk(KERN_ERR PFX "failing targ, change pending bit set\n");
- return -EIO;
+ goto err_out;
}
pr_debug("targ: cpu %d, %d kHz, min %d, max %d, relation %d\n",
pol->cpu, targfreq, pol->min, pol->max, relation);
if (query_current_values_with_pending_wait(data))
- return -EIO;
+ goto err_out;
if (cpu_family != CPU_HW_PSTATE) {
pr_debug("targ: curr fid 0x%x, vid 0x%x\n",
@@ -1189,7 +1196,7 @@ static long powernowk8_target_fn(void *arg)
if (cpufreq_frequency_table_target(pol, data->powernow_table,
targfreq, relation, &newstate))
- return -EIO;
+ goto err_out;
mutex_lock(&fidvid_mutex);
@@ -1202,8 +1209,9 @@ static long powernowk8_target_fn(void *arg)
ret = transition_frequency_fidvid(data, newstate);
if (ret) {
printk(KERN_ERR PFX "transition frequency failed\n");
+ ret = 1;
mutex_unlock(&fidvid_mutex);
- return 1;
+ goto err_out;
}
mutex_unlock(&fidvid_mutex);
@@ -1212,25 +1220,12 @@ static long powernowk8_target_fn(void *arg)
data->powernow_table[newstate].index);
else
pol->cur = find_khz_freq_from_fid(data->currfid);
+ ret = 0;
- return 0;
-}
-
-/* Driver entry point to switch to the target frequency */
-static int powernowk8_target(struct cpufreq_policy *pol,
- unsigned targfreq, unsigned relation)
-{
- struct powernowk8_target_arg pta = { .pol = pol, .targfreq = targfreq,
- .relation = relation };
-
- /*
- * Must run on @pol->cpu. cpufreq core is responsible for ensuring
- * that we're bound to the current CPU and pol->cpu stays online.
- */
- if (smp_processor_id() == pol->cpu)
- return powernowk8_target_fn(&pta);
- else
- return work_on_cpu(pol->cpu, powernowk8_target_fn, &pta);
+err_out:
+ set_cpus_allowed_ptr(current, oldmask);
+ free_cpumask_var(oldmask);
+ return ret;
}
/* Driver entry point to verify the policy and range of frequencies */
diff --git a/trunk/drivers/dma/at_hdmac.c b/trunk/drivers/dma/at_hdmac.c
index 7ab6e26664a7..3934fcc4e00b 100644
--- a/trunk/drivers/dma/at_hdmac.c
+++ b/trunk/drivers/dma/at_hdmac.c
@@ -661,7 +661,7 @@ atc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
flags);
if (unlikely(!atslave || !sg_len)) {
- dev_dbg(chan2dev(chan), "prep_slave_sg: sg length is zero!\n");
+ dev_dbg(chan2dev(chan), "prep_dma_memcpy: length is zero!\n");
return NULL;
}
@@ -689,11 +689,6 @@ atc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
mem = sg_dma_address(sg);
len = sg_dma_len(sg);
- if (unlikely(!len)) {
- dev_dbg(chan2dev(chan),
- "prep_slave_sg: sg(%d) data length is zero\n", i);
- goto err;
- }
mem_width = 2;
if (unlikely(mem & 3 || len & 3))
mem_width = 0;
@@ -729,11 +724,6 @@ atc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
mem = sg_dma_address(sg);
len = sg_dma_len(sg);
- if (unlikely(!len)) {
- dev_dbg(chan2dev(chan),
- "prep_slave_sg: sg(%d) data length is zero\n", i);
- goto err;
- }
mem_width = 2;
if (unlikely(mem & 3 || len & 3))
mem_width = 0;
@@ -767,7 +757,6 @@ atc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
err_desc_get:
dev_err(chan2dev(chan), "not enough descriptors available\n");
-err:
atc_desc_put(atchan, first);
return NULL;
}
diff --git a/trunk/drivers/dma/pl330.c b/trunk/drivers/dma/pl330.c
index f5843bc80baa..e4feba6b03c0 100644
--- a/trunk/drivers/dma/pl330.c
+++ b/trunk/drivers/dma/pl330.c
@@ -1567,19 +1567,17 @@ static int pl330_submit_req(void *ch_id, struct pl330_req *r)
goto xfer_exit;
}
+ /* Prefer Secure Channel */
+ if (!_manager_ns(thrd))
+ r->cfg->nonsecure = 0;
+ else
+ r->cfg->nonsecure = 1;
/* Use last settings, if not provided */
- if (r->cfg) {
- /* Prefer Secure Channel */
- if (!_manager_ns(thrd))
- r->cfg->nonsecure = 0;
- else
- r->cfg->nonsecure = 1;
-
+ if (r->cfg)
ccr = _prepare_ccr(r->cfg);
- } else {
+ else
ccr = readl(regs + CC(thrd->id));
- }
/* If this req doesn't have valid xfer settings */
if (!_is_valid(ccr)) {
@@ -2930,11 +2928,6 @@ pl330_probe(struct amba_device *adev, const struct amba_id *id)
num_chan = max_t(int, pi->pcfg.num_peri, pi->pcfg.num_chan);
pdmac->peripherals = kzalloc(num_chan * sizeof(*pch), GFP_KERNEL);
- if (!pdmac->peripherals) {
- ret = -ENOMEM;
- dev_err(&adev->dev, "unable to allocate pdmac->peripherals\n");
- goto probe_err5;
- }
for (i = 0; i < num_chan; i++) {
pch = &pdmac->peripherals[i];
diff --git a/trunk/drivers/edac/edac_mc.c b/trunk/drivers/edac/edac_mc.c
index d5dc9da7f99f..616d90bcb3a4 100644
--- a/trunk/drivers/edac/edac_mc.c
+++ b/trunk/drivers/edac/edac_mc.c
@@ -199,36 +199,6 @@ void *edac_align_ptr(void **p, unsigned size, int n_elems)
return (void *)(((unsigned long)ptr) + align - r);
}
-static void _edac_mc_free(struct mem_ctl_info *mci)
-{
- int i, chn, row;
- struct csrow_info *csr;
- const unsigned int tot_dimms = mci->tot_dimms;
- const unsigned int tot_channels = mci->num_cschannel;
- const unsigned int tot_csrows = mci->nr_csrows;
-
- if (mci->dimms) {
- for (i = 0; i < tot_dimms; i++)
- kfree(mci->dimms[i]);
- kfree(mci->dimms);
- }
- if (mci->csrows) {
- for (row = 0; row < tot_csrows; row++) {
- csr = mci->csrows[row];
- if (csr) {
- if (csr->channels) {
- for (chn = 0; chn < tot_channels; chn++)
- kfree(csr->channels[chn]);
- kfree(csr->channels);
- }
- kfree(csr);
- }
- }
- kfree(mci->csrows);
- }
- kfree(mci);
-}
-
/**
* edac_mc_alloc: Allocate and partially fill a struct mem_ctl_info structure
* @mc_num: Memory controller number
@@ -443,7 +413,24 @@ struct mem_ctl_info *edac_mc_alloc(unsigned mc_num,
return mci;
error:
- _edac_mc_free(mci);
+ if (mci->dimms) {
+ for (i = 0; i < tot_dimms; i++)
+ kfree(mci->dimms[i]);
+ kfree(mci->dimms);
+ }
+ if (mci->csrows) {
+ for (chn = 0; chn < tot_channels; chn++) {
+ csr = mci->csrows[chn];
+ if (csr) {
+ for (chn = 0; chn < tot_channels; chn++)
+ kfree(csr->channels[chn]);
+ kfree(csr);
+ }
+ kfree(mci->csrows[i]);
+ }
+ kfree(mci->csrows);
+ }
+ kfree(mci);
return NULL;
}
@@ -458,14 +445,6 @@ void edac_mc_free(struct mem_ctl_info *mci)
{
edac_dbg(1, "\n");
- /* If we're not yet registered with sysfs free only what was allocated
- * in edac_mc_alloc().
- */
- if (!device_is_registered(&mci->dev)) {
- _edac_mc_free(mci);
- return;
- }
-
/* the mci instance is freed here, when the sysfs object is dropped */
edac_unregister_sysfs(mci);
}
diff --git a/trunk/drivers/extcon/extcon-max77693.c b/trunk/drivers/extcon/extcon-max77693.c
index 38f9e52f358b..920a609b2c35 100644
--- a/trunk/drivers/extcon/extcon-max77693.c
+++ b/trunk/drivers/extcon/extcon-max77693.c
@@ -669,18 +669,13 @@ static int __devinit max77693_muic_probe(struct platform_device *pdev)
}
info->dev = &pdev->dev;
info->max77693 = max77693;
- if (info->max77693->regmap_muic)
- dev_dbg(&pdev->dev, "allocate register map\n");
- else {
- info->max77693->regmap_muic = devm_regmap_init_i2c(
- info->max77693->muic,
- &max77693_muic_regmap_config);
- if (IS_ERR(info->max77693->regmap_muic)) {
- ret = PTR_ERR(info->max77693->regmap_muic);
- dev_err(max77693->dev,
- "failed to allocate register map: %d\n", ret);
- goto err_regmap;
- }
+ info->max77693->regmap_muic = regmap_init_i2c(info->max77693->muic,
+ &max77693_muic_regmap_config);
+ if (IS_ERR(info->max77693->regmap_muic)) {
+ ret = PTR_ERR(info->max77693->regmap_muic);
+ dev_err(max77693->dev,
+ "failed to allocate register map: %d\n", ret);
+ goto err_regmap;
}
platform_set_drvdata(pdev, info);
mutex_init(&info->mutex);
diff --git a/trunk/drivers/gpu/drm/Kconfig b/trunk/drivers/gpu/drm/Kconfig
index 18321b68b880..90e28081712d 100644
--- a/trunk/drivers/gpu/drm/Kconfig
+++ b/trunk/drivers/gpu/drm/Kconfig
@@ -22,7 +22,7 @@ menuconfig DRM
config DRM_USB
tristate
depends on DRM
- depends on USB_SUPPORT && USB_ARCH_HAS_HCD
+ depends on USB_ARCH_HAS_HCD
select USB
config DRM_KMS_HELPER
@@ -54,21 +54,6 @@ config DRM_TTM
GPU memory types. Will be enabled automatically if a device driver
uses it.
-config DRM_GEM_CMA_HELPER
- bool
- depends on DRM
- help
- Choose this if you need the GEM CMA helper functions
-
-config DRM_KMS_CMA_HELPER
- bool
- select DRM_GEM_CMA_HELPER
- select FB_SYS_FILLRECT
- select FB_SYS_COPYAREA
- select FB_SYS_IMAGEBLIT
- help
- Choose this if you need the KMS CMA helper functions
-
config DRM_TDFX
tristate "3dfx Banshee/Voodoo3+"
depends on DRM && PCI
@@ -208,5 +193,3 @@ source "drivers/gpu/drm/ast/Kconfig"
source "drivers/gpu/drm/mgag200/Kconfig"
source "drivers/gpu/drm/cirrus/Kconfig"
-
-source "drivers/gpu/drm/shmobile/Kconfig"
diff --git a/trunk/drivers/gpu/drm/Makefile b/trunk/drivers/gpu/drm/Makefile
index 2ff5cefe9ead..f65f65ed0ddf 100644
--- a/trunk/drivers/gpu/drm/Makefile
+++ b/trunk/drivers/gpu/drm/Makefile
@@ -15,13 +15,11 @@ drm-y := drm_auth.o drm_buffer.o drm_bufs.o drm_cache.o \
drm_trace_points.o drm_global.o drm_prime.o
drm-$(CONFIG_COMPAT) += drm_ioc32.o
-drm-$(CONFIG_DRM_GEM_CMA_HELPER) += drm_gem_cma_helper.o
drm-usb-y := drm_usb.o
drm_kms_helper-y := drm_fb_helper.o drm_crtc_helper.o drm_dp_i2c_helper.o
drm_kms_helper-$(CONFIG_DRM_LOAD_EDID_FIRMWARE) += drm_edid_load.o
-drm_kms_helper-$(CONFIG_DRM_KMS_CMA_HELPER) += drm_fb_cma_helper.o
obj-$(CONFIG_DRM_KMS_HELPER) += drm_kms_helper.o
@@ -47,5 +45,4 @@ obj-$(CONFIG_DRM_EXYNOS) +=exynos/
obj-$(CONFIG_DRM_GMA500) += gma500/
obj-$(CONFIG_DRM_UDL) += udl/
obj-$(CONFIG_DRM_AST) += ast/
-obj-$(CONFIG_DRM_SHMOBILE) +=shmobile/
obj-y += i2c/
diff --git a/trunk/drivers/gpu/drm/ast/ast_drv.h b/trunk/drivers/gpu/drm/ast/ast_drv.h
index 20a437f88780..d4af9edcbb97 100644
--- a/trunk/drivers/gpu/drm/ast/ast_drv.h
+++ b/trunk/drivers/gpu/drm/ast/ast_drv.h
@@ -94,6 +94,7 @@ struct ast_private {
struct drm_global_reference mem_global_ref;
struct ttm_bo_global_ref bo_global_ref;
struct ttm_bo_device bdev;
+ atomic_t validate_sequence;
} ttm;
struct drm_gem_object *cursor_cache;
diff --git a/trunk/drivers/gpu/drm/ast/ast_mode.c b/trunk/drivers/gpu/drm/ast/ast_mode.c
index f3b2a7cce744..a712cafcfa1d 100644
--- a/trunk/drivers/gpu/drm/ast/ast_mode.c
+++ b/trunk/drivers/gpu/drm/ast/ast_mode.c
@@ -737,7 +737,6 @@ static int ast_get_modes(struct drm_connector *connector)
if (edid) {
drm_mode_connector_update_edid_property(&ast_connector->base, edid);
ret = drm_add_edid_modes(connector, edid);
- kfree(edid);
return ret;
} else
drm_mode_connector_update_edid_property(&ast_connector->base, NULL);
diff --git a/trunk/drivers/gpu/drm/cirrus/cirrus_drv.h b/trunk/drivers/gpu/drm/cirrus/cirrus_drv.h
index 5d045647a3fc..64ea597cb6d3 100644
--- a/trunk/drivers/gpu/drm/cirrus/cirrus_drv.h
+++ b/trunk/drivers/gpu/drm/cirrus/cirrus_drv.h
@@ -143,6 +143,7 @@ struct cirrus_device {
struct drm_global_reference mem_global_ref;
struct ttm_bo_global_ref bo_global_ref;
struct ttm_bo_device bdev;
+ atomic_t validate_sequence;
} ttm;
bool mm_inited;
};
diff --git a/trunk/drivers/gpu/drm/drm_cache.c b/trunk/drivers/gpu/drm/drm_cache.c
index 4a4274b348b6..08758e061478 100644
--- a/trunk/drivers/gpu/drm/drm_cache.c
+++ b/trunk/drivers/gpu/drm/drm_cache.c
@@ -37,13 +37,12 @@ drm_clflush_page(struct page *page)
{
uint8_t *page_virtual;
unsigned int i;
- const int size = boot_cpu_data.x86_clflush_size;
if (unlikely(page == NULL))
return;
page_virtual = kmap_atomic(page);
- for (i = 0; i < PAGE_SIZE; i += size)
+ for (i = 0; i < PAGE_SIZE; i += boot_cpu_data.x86_clflush_size)
clflush(page_virtual + i);
kunmap_atomic(page_virtual);
}
@@ -100,31 +99,6 @@ drm_clflush_pages(struct page *pages[], unsigned long num_pages)
}
EXPORT_SYMBOL(drm_clflush_pages);
-void
-drm_clflush_sg(struct sg_table *st)
-{
-#if defined(CONFIG_X86)
- if (cpu_has_clflush) {
- struct scatterlist *sg;
- int i;
-
- mb();
- for_each_sg(st->sgl, sg, st->nents, i)
- drm_clflush_page(sg_page(sg));
- mb();
-
- return;
- }
-
- if (on_each_cpu(drm_clflush_ipi_handler, NULL, 1) != 0)
- printk(KERN_ERR "Timed out waiting for cache flush.\n");
-#else
- printk(KERN_ERR "Architecture has no drm_cache.c support\n");
- WARN_ON_ONCE(1);
-#endif
-}
-EXPORT_SYMBOL(drm_clflush_sg);
-
void
drm_clflush_virt_range(char *addr, unsigned long length)
{
diff --git a/trunk/drivers/gpu/drm/drm_crtc.c b/trunk/drivers/gpu/drm/drm_crtc.c
index 9c346a50379f..6fbfc244748f 100644
--- a/trunk/drivers/gpu/drm/drm_crtc.c
+++ b/trunk/drivers/gpu/drm/drm_crtc.c
@@ -294,8 +294,6 @@ int drm_framebuffer_init(struct drm_device *dev, struct drm_framebuffer *fb,
{
int ret;
- kref_init(&fb->refcount);
-
ret = drm_mode_object_get(dev, &fb->base, DRM_MODE_OBJECT_FB);
if (ret)
return ret;
@@ -309,38 +307,6 @@ int drm_framebuffer_init(struct drm_device *dev, struct drm_framebuffer *fb,
}
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);
-}
-
-/**
- * drm_framebuffer_unreference - unref a framebuffer
- *
- * LOCKING:
- * Caller must hold mode config lock.
- */
-void drm_framebuffer_unreference(struct drm_framebuffer *fb)
-{
- struct drm_device *dev = fb->dev;
- DRM_DEBUG("FB ID: %d\n", fb->base.id);
- WARN_ON(!mutex_is_locked(&dev->mode_config.mutex));
- kref_put(&fb->refcount, drm_framebuffer_free);
-}
-EXPORT_SYMBOL(drm_framebuffer_unreference);
-
-/**
- * drm_framebuffer_reference - incr the fb refcnt
- */
-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);
-
/**
* drm_framebuffer_cleanup - remove a framebuffer object
* @fb: framebuffer to remove
@@ -352,32 +318,6 @@ EXPORT_SYMBOL(drm_framebuffer_reference);
* it, setting it to NULL.
*/
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);
- list_del(&fb->head);
- dev->mode_config.num_fb--;
-}
-EXPORT_SYMBOL(drm_framebuffer_cleanup);
-
-/**
- * drm_framebuffer_remove - remove and unreference a framebuffer object
- * @fb: framebuffer to remove
- *
- * LOCKING:
- * Caller must hold mode config lock.
- *
- * Scans all the CRTCs and planes in @dev's mode_config. If they're
- * using @fb, removes it, setting it to NULL.
- */
-void drm_framebuffer_remove(struct drm_framebuffer *fb)
{
struct drm_device *dev = fb->dev;
struct drm_crtc *crtc;
@@ -410,11 +350,11 @@ void drm_framebuffer_remove(struct drm_framebuffer *fb)
}
}
- list_del(&fb->filp_head);
-
- drm_framebuffer_unreference(fb);
+ drm_mode_object_put(dev, &fb->base);
+ list_del(&fb->head);
+ dev->mode_config.num_fb--;
}
-EXPORT_SYMBOL(drm_framebuffer_remove);
+EXPORT_SYMBOL(drm_framebuffer_cleanup);
/**
* drm_crtc_init - Initialise a new CRTC object
@@ -437,7 +377,6 @@ int drm_crtc_init(struct drm_device *dev, struct drm_crtc *crtc,
crtc->dev = dev;
crtc->funcs = funcs;
- crtc->invert_dimensions = false;
mutex_lock(&dev->mode_config.mutex);
@@ -1092,7 +1031,11 @@ void drm_mode_config_cleanup(struct drm_device *dev)
}
list_for_each_entry_safe(fb, fbt, &dev->mode_config.fb_list, head) {
- drm_framebuffer_remove(fb);
+ fb->funcs->destroy(fb);
+ }
+
+ list_for_each_entry_safe(crtc, ct, &dev->mode_config.crtc_list, head) {
+ crtc->funcs->destroy(crtc);
}
list_for_each_entry_safe(plane, plt, &dev->mode_config.plane_list,
@@ -1100,10 +1043,6 @@ void drm_mode_config_cleanup(struct drm_device *dev)
plane->funcs->destroy(plane);
}
- list_for_each_entry_safe(crtc, ct, &dev->mode_config.crtc_list, head) {
- crtc->funcs->destroy(crtc);
- }
-
idr_remove_all(&dev->mode_config.crtc_idr);
idr_destroy(&dev->mode_config.crtc_idr);
}
@@ -1913,7 +1852,6 @@ int drm_mode_setcrtc(struct drm_device *dev, void *data,
DRM_DEBUG_KMS("[CRTC:%d]\n", crtc->base.id);
if (crtc_req->mode_valid) {
- int hdisplay, vdisplay;
/* If we have a mode we need a framebuffer. */
/* If we pass -1, set the mode with the currently bound fb */
if (crtc_req->fb_id == -1) {
@@ -1949,20 +1887,14 @@ int drm_mode_setcrtc(struct drm_device *dev, void *data,
drm_mode_set_crtcinfo(mode, CRTC_INTERLACE_HALVE_V);
- hdisplay = mode->hdisplay;
- vdisplay = mode->vdisplay;
-
- if (crtc->invert_dimensions)
- swap(hdisplay, vdisplay);
-
- if (hdisplay > fb->width ||
- vdisplay > fb->height ||
- crtc_req->x > fb->width - hdisplay ||
- crtc_req->y > fb->height - vdisplay) {
- DRM_DEBUG_KMS("Invalid fb size %ux%u for CRTC viewport %ux%u+%d+%d%s.\n",
- fb->width, fb->height,
- hdisplay, vdisplay, crtc_req->x, crtc_req->y,
- crtc->invert_dimensions ? " (inverted)" : "");
+ if (mode->hdisplay > fb->width ||
+ mode->vdisplay > fb->height ||
+ crtc_req->x > fb->width - mode->hdisplay ||
+ crtc_req->y > fb->height - mode->vdisplay) {
+ DRM_DEBUG_KMS("Invalid CRTC viewport %ux%u+%u+%u for fb size %ux%u.\n",
+ mode->hdisplay, mode->vdisplay,
+ crtc_req->x, crtc_req->y,
+ fb->width, fb->height);
ret = -ENOSPC;
goto out;
}
@@ -2237,8 +2169,6 @@ static int format_check(const struct drm_mode_fb_cmd2 *r)
case DRM_FORMAT_NV21:
case DRM_FORMAT_NV16:
case DRM_FORMAT_NV61:
- case DRM_FORMAT_NV24:
- case DRM_FORMAT_NV42:
case DRM_FORMAT_YUV410:
case DRM_FORMAT_YVU410:
case DRM_FORMAT_YUV411:
@@ -2405,7 +2335,11 @@ int drm_mode_rmfb(struct drm_device *dev,
goto out;
}
- drm_framebuffer_remove(fb);
+ /* TODO release all crtc connected to the framebuffer */
+ /* TODO unhock the destructor from the buffer object */
+
+ list_del(&fb->filp_head);
+ fb->funcs->destroy(fb);
out:
mutex_unlock(&dev->mode_config.mutex);
@@ -2555,7 +2489,8 @@ void drm_fb_release(struct drm_file *priv)
mutex_lock(&dev->mode_config.mutex);
list_for_each_entry_safe(fb, tfb, &priv->fbs, filp_head) {
- drm_framebuffer_remove(fb);
+ list_del(&fb->filp_head);
+ fb->funcs->destroy(fb);
}
mutex_unlock(&dev->mode_config.mutex);
}
@@ -3554,7 +3489,6 @@ int drm_mode_page_flip_ioctl(struct drm_device *dev,
struct drm_framebuffer *fb;
struct drm_pending_vblank_event *e = NULL;
unsigned long flags;
- int hdisplay, vdisplay;
int ret = -EINVAL;
if (page_flip->flags & ~DRM_MODE_PAGE_FLIP_FLAGS ||
@@ -3584,19 +3518,14 @@ int drm_mode_page_flip_ioctl(struct drm_device *dev,
goto out;
fb = obj_to_fb(obj);
- hdisplay = crtc->mode.hdisplay;
- vdisplay = crtc->mode.vdisplay;
-
- if (crtc->invert_dimensions)
- swap(hdisplay, vdisplay);
-
- if (hdisplay > fb->width ||
- vdisplay > fb->height ||
- crtc->x > fb->width - hdisplay ||
- crtc->y > fb->height - vdisplay) {
- DRM_DEBUG_KMS("Invalid fb size %ux%u for CRTC viewport %ux%u+%d+%d%s.\n",
- fb->width, fb->height, hdisplay, vdisplay, crtc->x, crtc->y,
- crtc->invert_dimensions ? " (inverted)" : "");
+ if (crtc->mode.hdisplay > fb->width ||
+ crtc->mode.vdisplay > fb->height ||
+ crtc->x > fb->width - crtc->mode.hdisplay ||
+ crtc->y > fb->height - crtc->mode.vdisplay) {
+ DRM_DEBUG_KMS("Invalid fb size %ux%u for CRTC viewport %ux%u+%d+%d.\n",
+ fb->width, fb->height,
+ crtc->mode.hdisplay, crtc->mode.vdisplay,
+ crtc->x, crtc->y);
ret = -ENOSPC;
goto out;
}
@@ -3789,8 +3718,6 @@ int drm_format_num_planes(uint32_t format)
case DRM_FORMAT_NV21:
case DRM_FORMAT_NV16:
case DRM_FORMAT_NV61:
- case DRM_FORMAT_NV24:
- case DRM_FORMAT_NV42:
return 2;
default:
return 1;
@@ -3824,8 +3751,6 @@ int drm_format_plane_cpp(uint32_t format, int plane)
case DRM_FORMAT_NV21:
case DRM_FORMAT_NV16:
case DRM_FORMAT_NV61:
- case DRM_FORMAT_NV24:
- case DRM_FORMAT_NV42:
return plane ? 2 : 1;
case DRM_FORMAT_YUV410:
case DRM_FORMAT_YVU410:
diff --git a/trunk/drivers/gpu/drm/drm_drv.c b/trunk/drivers/gpu/drm/drm_drv.c
index a2c6eb6e0dd8..9238de4009fa 100644
--- a/trunk/drivers/gpu/drm/drm_drv.c
+++ b/trunk/drivers/gpu/drm/drm_drv.c
@@ -140,10 +140,10 @@ static struct drm_ioctl_desc drm_ioctls[] = {
DRM_IOCTL_DEF(DRM_IOCTL_PRIME_HANDLE_TO_FD, drm_prime_handle_to_fd_ioctl, DRM_AUTH|DRM_UNLOCKED),
DRM_IOCTL_DEF(DRM_IOCTL_PRIME_FD_TO_HANDLE, drm_prime_fd_to_handle_ioctl, DRM_AUTH|DRM_UNLOCKED),
- DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETPLANERESOURCES, drm_mode_getplane_res, DRM_CONTROL_ALLOW|DRM_UNLOCKED),
+ DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETPLANERESOURCES, drm_mode_getplane_res, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETCRTC, drm_mode_getcrtc, DRM_CONTROL_ALLOW|DRM_UNLOCKED),
DRM_IOCTL_DEF(DRM_IOCTL_MODE_SETCRTC, drm_mode_setcrtc, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
- DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETPLANE, drm_mode_getplane, DRM_CONTROL_ALLOW|DRM_UNLOCKED),
+ DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETPLANE, drm_mode_getplane, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
DRM_IOCTL_DEF(DRM_IOCTL_MODE_SETPLANE, drm_mode_setplane, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
DRM_IOCTL_DEF(DRM_IOCTL_MODE_CURSOR, drm_mode_cursor_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETGAMMA, drm_mode_gamma_get_ioctl, DRM_UNLOCKED),
@@ -152,19 +152,19 @@ static struct drm_ioctl_desc drm_ioctls[] = {
DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETCONNECTOR, drm_mode_getconnector, DRM_CONTROL_ALLOW|DRM_UNLOCKED),
DRM_IOCTL_DEF(DRM_IOCTL_MODE_ATTACHMODE, drm_mode_attachmode_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
DRM_IOCTL_DEF(DRM_IOCTL_MODE_DETACHMODE, drm_mode_detachmode_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
- DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETPROPERTY, drm_mode_getproperty_ioctl, DRM_CONTROL_ALLOW|DRM_UNLOCKED),
+ DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETPROPERTY, drm_mode_getproperty_ioctl, DRM_MASTER | DRM_CONTROL_ALLOW|DRM_UNLOCKED),
DRM_IOCTL_DEF(DRM_IOCTL_MODE_SETPROPERTY, drm_mode_connector_property_set_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
- DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETPROPBLOB, drm_mode_getblob_ioctl, DRM_CONTROL_ALLOW|DRM_UNLOCKED),
+ DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETPROPBLOB, drm_mode_getblob_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETFB, drm_mode_getfb, DRM_CONTROL_ALLOW|DRM_UNLOCKED),
- DRM_IOCTL_DEF(DRM_IOCTL_MODE_ADDFB, drm_mode_addfb, DRM_CONTROL_ALLOW|DRM_UNLOCKED),
- DRM_IOCTL_DEF(DRM_IOCTL_MODE_ADDFB2, drm_mode_addfb2, DRM_CONTROL_ALLOW|DRM_UNLOCKED),
- DRM_IOCTL_DEF(DRM_IOCTL_MODE_RMFB, drm_mode_rmfb, DRM_CONTROL_ALLOW|DRM_UNLOCKED),
+ DRM_IOCTL_DEF(DRM_IOCTL_MODE_ADDFB, drm_mode_addfb, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
+ DRM_IOCTL_DEF(DRM_IOCTL_MODE_ADDFB2, drm_mode_addfb2, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
+ DRM_IOCTL_DEF(DRM_IOCTL_MODE_RMFB, drm_mode_rmfb, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
DRM_IOCTL_DEF(DRM_IOCTL_MODE_PAGE_FLIP, drm_mode_page_flip_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
DRM_IOCTL_DEF(DRM_IOCTL_MODE_DIRTYFB, drm_mode_dirtyfb_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
- DRM_IOCTL_DEF(DRM_IOCTL_MODE_CREATE_DUMB, drm_mode_create_dumb_ioctl, DRM_CONTROL_ALLOW|DRM_UNLOCKED),
- DRM_IOCTL_DEF(DRM_IOCTL_MODE_MAP_DUMB, drm_mode_mmap_dumb_ioctl, DRM_CONTROL_ALLOW|DRM_UNLOCKED),
- DRM_IOCTL_DEF(DRM_IOCTL_MODE_DESTROY_DUMB, drm_mode_destroy_dumb_ioctl, DRM_CONTROL_ALLOW|DRM_UNLOCKED),
- DRM_IOCTL_DEF(DRM_IOCTL_MODE_OBJ_GETPROPERTIES, drm_mode_obj_get_properties_ioctl, DRM_CONTROL_ALLOW|DRM_UNLOCKED),
+ DRM_IOCTL_DEF(DRM_IOCTL_MODE_CREATE_DUMB, drm_mode_create_dumb_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
+ DRM_IOCTL_DEF(DRM_IOCTL_MODE_MAP_DUMB, drm_mode_mmap_dumb_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
+ DRM_IOCTL_DEF(DRM_IOCTL_MODE_DESTROY_DUMB, drm_mode_destroy_dumb_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
+ DRM_IOCTL_DEF(DRM_IOCTL_MODE_OBJ_GETPROPERTIES, drm_mode_obj_get_properties_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
DRM_IOCTL_DEF(DRM_IOCTL_MODE_OBJ_SETPROPERTY, drm_mode_obj_set_property_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
};
diff --git a/trunk/drivers/gpu/drm/drm_edid.c b/trunk/drivers/gpu/drm/drm_edid.c
index 289c9b18c0d3..b7ee230572b7 100644
--- a/trunk/drivers/gpu/drm/drm_edid.c
+++ b/trunk/drivers/gpu/drm/drm_edid.c
@@ -161,7 +161,7 @@ MODULE_PARM_DESC(edid_fixup,
* Sanity check the EDID block (base or extension). Return 0 if the block
* doesn't check out, or 1 if it's valid.
*/
-bool drm_edid_block_valid(u8 *raw_edid, int block, bool print_bad_edid)
+bool drm_edid_block_valid(u8 *raw_edid, int block)
{
int i;
u8 csum = 0;
@@ -184,9 +184,7 @@ bool drm_edid_block_valid(u8 *raw_edid, int block, bool print_bad_edid)
for (i = 0; i < EDID_LENGTH; i++)
csum += raw_edid[i];
if (csum) {
- if (print_bad_edid) {
- DRM_ERROR("EDID checksum is invalid, remainder is %d\n", csum);
- }
+ DRM_ERROR("EDID checksum is invalid, remainder is %d\n", csum);
/* allow CEA to slide through, switches mangle this */
if (raw_edid[0] != 0x02)
@@ -212,7 +210,7 @@ bool drm_edid_block_valid(u8 *raw_edid, int block, bool print_bad_edid)
return 1;
bad:
- if (raw_edid && print_bad_edid) {
+ if (raw_edid) {
printk(KERN_ERR "Raw EDID:\n");
print_hex_dump(KERN_ERR, " \t", DUMP_PREFIX_NONE, 16, 1,
raw_edid, EDID_LENGTH, false);
@@ -236,7 +234,7 @@ bool drm_edid_is_valid(struct edid *edid)
return false;
for (i = 0; i <= edid->extensions; i++)
- if (!drm_edid_block_valid(raw + i * EDID_LENGTH, i, true))
+ if (!drm_edid_block_valid(raw + i * EDID_LENGTH, i))
return false;
return true;
@@ -259,8 +257,6 @@ drm_do_probe_ddc_edid(struct i2c_adapter *adapter, unsigned char *buf,
int block, int len)
{
unsigned char start = block * EDID_LENGTH;
- unsigned char segment = block >> 1;
- unsigned char xfers = segment ? 3 : 2;
int ret, retries = 5;
/* The core i2c driver will automatically retry the transfer if the
@@ -272,11 +268,6 @@ drm_do_probe_ddc_edid(struct i2c_adapter *adapter, unsigned char *buf,
do {
struct i2c_msg msgs[] = {
{
- .addr = DDC_SEGMENT_ADDR,
- .flags = 0,
- .len = 1,
- .buf = &segment,
- }, {
.addr = DDC_ADDR,
.flags = 0,
.len = 1,
@@ -288,21 +279,15 @@ drm_do_probe_ddc_edid(struct i2c_adapter *adapter, unsigned char *buf,
.buf = buf,
}
};
-
- /*
- * Avoid sending the segment addr to not upset non-compliant ddc
- * monitors.
- */
- ret = i2c_transfer(adapter, &msgs[3 - xfers], xfers);
-
+ ret = i2c_transfer(adapter, msgs, 2);
if (ret == -ENXIO) {
DRM_DEBUG_KMS("drm: skipping non-existent adapter %s\n",
adapter->name);
break;
}
- } while (ret != xfers && --retries);
+ } while (ret != 2 && --retries);
- return ret == xfers ? 0 : -1;
+ return ret == 2 ? 0 : -1;
}
static bool drm_edid_is_zero(u8 *in_edid, int length)
@@ -321,7 +306,6 @@ drm_do_get_edid(struct drm_connector *connector, struct i2c_adapter *adapter)
{
int i, j = 0, valid_extensions = 0;
u8 *block, *new;
- bool print_bad_edid = !connector->bad_edid_counter || (drm_debug & DRM_UT_KMS);
if ((block = kmalloc(EDID_LENGTH, GFP_KERNEL)) == NULL)
return NULL;
@@ -330,7 +314,7 @@ drm_do_get_edid(struct drm_connector *connector, struct i2c_adapter *adapter)
for (i = 0; i < 4; i++) {
if (drm_do_probe_ddc_edid(adapter, block, 0, EDID_LENGTH))
goto out;
- if (drm_edid_block_valid(block, 0, print_bad_edid))
+ if (drm_edid_block_valid(block, 0))
break;
if (i == 0 && drm_edid_is_zero(block, EDID_LENGTH)) {
connector->null_edid_counter++;
@@ -355,7 +339,7 @@ drm_do_get_edid(struct drm_connector *connector, struct i2c_adapter *adapter)
block + (valid_extensions + 1) * EDID_LENGTH,
j, EDID_LENGTH))
goto out;
- if (drm_edid_block_valid(block + (valid_extensions + 1) * EDID_LENGTH, j, print_bad_edid)) {
+ if (drm_edid_block_valid(block + (valid_extensions + 1) * EDID_LENGTH, j)) {
valid_extensions++;
break;
}
@@ -378,11 +362,8 @@ drm_do_get_edid(struct drm_connector *connector, struct i2c_adapter *adapter)
return block;
carp:
- if (print_bad_edid) {
- dev_warn(connector->dev->dev, "%s: EDID block %d invalid.\n",
- drm_get_connector_name(connector), j);
- }
- connector->bad_edid_counter++;
+ dev_warn(connector->dev->dev, "%s: EDID block %d invalid.\n",
+ drm_get_connector_name(connector), j);
out:
kfree(block);
@@ -421,7 +402,10 @@ struct edid *drm_get_edid(struct drm_connector *connector,
if (drm_probe_ddc(adapter))
edid = (struct edid *)drm_do_get_edid(connector, adapter);
+ connector->display_info.raw_edid = (char *)edid;
+
return edid;
+
}
EXPORT_SYMBOL(drm_get_edid);
@@ -1538,40 +1522,6 @@ do_cea_modes (struct drm_connector *connector, u8 *db, u8 len)
return modes;
}
-static int
-cea_db_payload_len(const u8 *db)
-{
- return db[0] & 0x1f;
-}
-
-static int
-cea_db_tag(const u8 *db)
-{
- return db[0] >> 5;
-}
-
-static int
-cea_revision(const u8 *cea)
-{
- return cea[1];
-}
-
-static int
-cea_db_offsets(const u8 *cea, int *start, int *end)
-{
- /* Data block offset in CEA extension block */
- *start = 4;
- *end = cea[2];
- if (*end == 0)
- *end = 127;
- if (*end < 4 || *end > 127)
- return -ERANGE;
- return 0;
-}
-
-#define for_each_cea_db(cea, i, start, end) \
- for ((i) = (start); (i) < (end) && (i) + cea_db_payload_len(&(cea)[(i)]) < (end); (i) += cea_db_payload_len(&(cea)[(i)]) + 1)
-
static int
add_cea_modes(struct drm_connector *connector, struct edid *edid)
{
@@ -1579,17 +1529,10 @@ add_cea_modes(struct drm_connector *connector, struct edid *edid)
u8 * db, dbl;
int modes = 0;
- if (cea && cea_revision(cea) >= 3) {
- int i, start, end;
-
- if (cea_db_offsets(cea, &start, &end))
- return 0;
-
- for_each_cea_db(cea, i, start, end) {
- db = &cea[i];
- dbl = cea_db_payload_len(db);
-
- if (cea_db_tag(db) == VIDEO_BLOCK)
+ if (cea && cea[1] >= 3) {
+ for (db = cea + 4; db < cea + cea[2]; db += dbl + 1) {
+ dbl = db[0] & 0x1f;
+ if (((db[0] & 0xe0) >> 5) == VIDEO_BLOCK)
modes += do_cea_modes (connector, db+1, dbl);
}
}
@@ -1598,28 +1541,19 @@ add_cea_modes(struct drm_connector *connector, struct edid *edid)
}
static void
-parse_hdmi_vsdb(struct drm_connector *connector, const u8 *db)
+parse_hdmi_vsdb(struct drm_connector *connector, uint8_t *db)
{
- u8 len = cea_db_payload_len(db);
+ connector->eld[5] |= (db[6] >> 7) << 1; /* Supports_AI */
- if (len >= 6) {
- connector->eld[5] |= (db[6] >> 7) << 1; /* Supports_AI */
- connector->dvi_dual = db[6] & 1;
- }
- if (len >= 7)
- connector->max_tmds_clock = db[7] * 5;
- if (len >= 8) {
- connector->latency_present[0] = db[8] >> 7;
- connector->latency_present[1] = (db[8] >> 6) & 1;
- }
- if (len >= 9)
- connector->video_latency[0] = db[9];
- if (len >= 10)
- connector->audio_latency[0] = db[10];
- if (len >= 11)
- connector->video_latency[1] = db[11];
- if (len >= 12)
- connector->audio_latency[1] = db[12];
+ connector->dvi_dual = db[6] & 1;
+ connector->max_tmds_clock = db[7] * 5;
+
+ connector->latency_present[0] = db[8] >> 7;
+ connector->latency_present[1] = (db[8] >> 6) & 1;
+ connector->video_latency[0] = db[9];
+ connector->audio_latency[0] = db[10];
+ connector->video_latency[1] = db[11];
+ connector->audio_latency[1] = db[12];
DRM_LOG_KMS("HDMI: DVI dual %d, "
"max TMDS clock %d, "
@@ -1643,21 +1577,6 @@ monitor_name(struct detailed_timing *t, void *data)
*(u8 **)data = t->data.other_data.data.str.str;
}
-static bool cea_db_is_hdmi_vsdb(const u8 *db)
-{
- int hdmi_id;
-
- if (cea_db_tag(db) != VENDOR_BLOCK)
- return false;
-
- if (cea_db_payload_len(db) < 5)
- return false;
-
- hdmi_id = db[1] | (db[2] << 8) | (db[3] << 16);
-
- return hdmi_id == HDMI_IDENTIFIER;
-}
-
/**
* drm_edid_to_eld - build ELD from EDID
* @connector: connector corresponding to the HDMI/DP sink
@@ -1704,40 +1623,29 @@ void drm_edid_to_eld(struct drm_connector *connector, struct edid *edid)
eld[18] = edid->prod_code[0];
eld[19] = edid->prod_code[1];
- if (cea_revision(cea) >= 3) {
- int i, start, end;
-
- if (cea_db_offsets(cea, &start, &end)) {
- start = 0;
- end = 0;
- }
-
- for_each_cea_db(cea, i, start, end) {
- db = &cea[i];
- dbl = cea_db_payload_len(db);
-
- switch (cea_db_tag(db)) {
+ if (cea[1] >= 3)
+ for (db = cea + 4; db < cea + cea[2]; db += dbl + 1) {
+ dbl = db[0] & 0x1f;
+
+ switch ((db[0] & 0xe0) >> 5) {
case AUDIO_BLOCK:
/* Audio Data Block, contains SADs */
sad_count = dbl / 3;
- if (dbl >= 1)
- memcpy(eld + 20 + mnl, &db[1], dbl);
+ memcpy(eld + 20 + mnl, &db[1], dbl);
break;
case SPEAKER_BLOCK:
- /* Speaker Allocation Data Block */
- if (dbl >= 1)
- eld[7] = db[1];
+ /* Speaker Allocation Data Block */
+ eld[7] = db[1];
break;
case VENDOR_BLOCK:
/* HDMI Vendor-Specific Data Block */
- if (cea_db_is_hdmi_vsdb(db))
+ if (db[1] == 0x03 && db[2] == 0x0c && db[3] == 0)
parse_hdmi_vsdb(connector, db);
break;
default:
break;
}
}
- }
eld[5] |= sad_count << 4;
eld[2] = (20 + mnl + sad_count * 3 + 3) / 4;
@@ -1815,26 +1723,38 @@ EXPORT_SYMBOL(drm_select_eld);
bool drm_detect_hdmi_monitor(struct edid *edid)
{
u8 *edid_ext;
- int i;
+ int i, hdmi_id;
int start_offset, end_offset;
+ bool is_hdmi = false;
edid_ext = drm_find_cea_extension(edid);
if (!edid_ext)
- return false;
+ goto end;
- if (cea_db_offsets(edid_ext, &start_offset, &end_offset))
- return false;
+ /* Data block offset in CEA extension block */
+ start_offset = 4;
+ end_offset = edid_ext[2];
/*
* Because HDMI identifier is in Vendor Specific Block,
* search it from all data blocks of CEA extension.
*/
- for_each_cea_db(edid_ext, i, start_offset, end_offset) {
- if (cea_db_is_hdmi_vsdb(&edid_ext[i]))
- return true;
+ for (i = start_offset; i < end_offset;
+ /* Increased by data block len */
+ i += ((edid_ext[i] & 0x1f) + 1)) {
+ /* Find vendor specific block */
+ if ((edid_ext[i] >> 5) == VENDOR_BLOCK) {
+ hdmi_id = edid_ext[i + 1] | (edid_ext[i + 2] << 8) |
+ edid_ext[i + 3] << 16;
+ /* Find HDMI identifier */
+ if (hdmi_id == HDMI_IDENTIFIER)
+ is_hdmi = true;
+ break;
+ }
}
- return false;
+end:
+ return is_hdmi;
}
EXPORT_SYMBOL(drm_detect_hdmi_monitor);
@@ -1866,13 +1786,15 @@ bool drm_detect_monitor_audio(struct edid *edid)
goto end;
}
- if (cea_db_offsets(edid_ext, &start_offset, &end_offset))
- goto end;
+ /* Data block offset in CEA extension block */
+ start_offset = 4;
+ end_offset = edid_ext[2];
- for_each_cea_db(edid_ext, i, start_offset, end_offset) {
- if (cea_db_tag(&edid_ext[i]) == AUDIO_BLOCK) {
+ for (i = start_offset; i < end_offset;
+ i += ((edid_ext[i] & 0x1f) + 1)) {
+ if ((edid_ext[i] >> 5) == AUDIO_BLOCK) {
has_audio = true;
- for (j = 1; j < cea_db_payload_len(&edid_ext[i]) + 1; j += 3)
+ for (j = 1; j < (edid_ext[i] & 0x1f); j += 3)
DRM_DEBUG_KMS("CEA audio format %d\n",
(edid_ext[i + j] >> 3) & 0xf);
goto end;
diff --git a/trunk/drivers/gpu/drm/drm_edid_load.c b/trunk/drivers/gpu/drm/drm_edid_load.c
index ea9cdab3d431..0303935d10e2 100644
--- a/trunk/drivers/gpu/drm/drm_edid_load.c
+++ b/trunk/drivers/gpu/drm/drm_edid_load.c
@@ -114,8 +114,8 @@ static u8 generic_edid[GENERIC_EDIDS][128] = {
},
};
-static u8 *edid_load(struct drm_connector *connector, char *name,
- char *connector_name)
+static int edid_load(struct drm_connector *connector, char *name,
+ char *connector_name)
{
const struct firmware *fw;
struct platform_device *pdev;
@@ -123,7 +123,6 @@ static u8 *edid_load(struct drm_connector *connector, char *name,
int fwsize, expected;
int builtin = 0, err = 0;
int i, valid_extensions = 0;
- bool print_bad_edid = !connector->bad_edid_counter || (drm_debug & DRM_UT_KMS);
pdev = platform_device_register_simple(connector_name, -1, NULL, 0);
if (IS_ERR(pdev)) {
@@ -174,8 +173,7 @@ static u8 *edid_load(struct drm_connector *connector, char *name,
}
memcpy(edid, fwdata, fwsize);
- if (!drm_edid_block_valid(edid, 0, print_bad_edid)) {
- connector->bad_edid_counter++;
+ if (!drm_edid_block_valid(edid, 0)) {
DRM_ERROR("Base block of EDID firmware \"%s\" is invalid ",
name);
kfree(edid);
@@ -187,7 +185,7 @@ static u8 *edid_load(struct drm_connector *connector, char *name,
if (i != valid_extensions + 1)
memcpy(edid + (valid_extensions + 1) * EDID_LENGTH,
edid + i * EDID_LENGTH, EDID_LENGTH);
- if (drm_edid_block_valid(edid + i * EDID_LENGTH, i, print_bad_edid))
+ if (drm_edid_block_valid(edid + i * EDID_LENGTH, i))
valid_extensions++;
}
@@ -207,6 +205,7 @@ static u8 *edid_load(struct drm_connector *connector, char *name,
edid = new_edid;
}
+ connector->display_info.raw_edid = edid;
DRM_INFO("Got %s EDID base block and %d extension%s from "
"\"%s\" for connector \"%s\"\n", builtin ? "built-in" :
"external", valid_extensions, valid_extensions == 1 ? "" : "s",
@@ -216,10 +215,7 @@ static u8 *edid_load(struct drm_connector *connector, char *name,
release_firmware(fw);
out:
- if (err)
- return ERR_PTR(err);
-
- return edid;
+ return err;
}
int drm_load_edid_firmware(struct drm_connector *connector)
@@ -227,7 +223,6 @@ int drm_load_edid_firmware(struct drm_connector *connector)
char *connector_name = drm_get_connector_name(connector);
char *edidname = edid_firmware, *last, *colon;
int ret;
- struct edid *edid;
if (*edidname == '\0')
return 0;
@@ -245,13 +240,13 @@ int drm_load_edid_firmware(struct drm_connector *connector)
if (*last == '\n')
*last = '\0';
- edid = (struct edid *) edid_load(connector, edidname, connector_name);
- if (IS_ERR_OR_NULL(edid))
+ ret = edid_load(connector, edidname, connector_name);
+ if (ret)
return 0;
- drm_mode_connector_update_edid_property(connector, edid);
- ret = drm_add_edid_modes(connector, edid);
- kfree(edid);
+ drm_mode_connector_update_edid_property(connector,
+ (struct edid *) connector->display_info.raw_edid);
- return ret;
+ return drm_add_edid_modes(connector, (struct edid *)
+ connector->display_info.raw_edid);
}
diff --git a/trunk/drivers/gpu/drm/drm_edid_modes.h b/trunk/drivers/gpu/drm/drm_edid_modes.h
index 57459b316adc..ff98a7eb38dd 100644
--- a/trunk/drivers/gpu/drm/drm_edid_modes.h
+++ b/trunk/drivers/gpu/drm/drm_edid_modes.h
@@ -89,7 +89,7 @@ static const struct drm_display_mode drm_dmt_modes[] = {
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,
+ { DRM_MODE("1024x768", 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) },
@@ -395,7 +395,7 @@ static const struct drm_display_mode edid_est_modes[] = {
{ 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,
+ { DRM_MODE("1024x768", 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,
@@ -506,17 +506,17 @@ static const struct drm_display_mode edid_cea_modes[] = {
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,
+ { DRM_MODE("1920x1080", 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,
+ { DRM_MODE("1440x480", 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,
+ { DRM_MODE("1440x480", 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) },
@@ -531,12 +531,12 @@ static const struct drm_display_mode edid_cea_modes[] = {
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,
+ { DRM_MODE("2880x480", 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,
+ { DRM_MODE("2880x480", 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) },
@@ -573,17 +573,17 @@ static const struct drm_display_mode edid_cea_modes[] = {
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,
+ { DRM_MODE("1920x1080", 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,
+ { DRM_MODE("1440x576", 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,
+ { DRM_MODE("1440x576", 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) },
@@ -598,12 +598,12 @@ static const struct drm_display_mode edid_cea_modes[] = {
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,
+ { DRM_MODE("2880x576", 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,
+ { DRM_MODE("2880x576", 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) },
@@ -656,12 +656,12 @@ static const struct drm_display_mode edid_cea_modes[] = {
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,
+ { DRM_MODE("1920x1080", 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,
+ { DRM_MODE("1920x1080", 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) },
@@ -688,7 +688,7 @@ static const struct drm_display_mode edid_cea_modes[] = {
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,
+ { DRM_MODE("1920x1080", 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) },
@@ -705,12 +705,12 @@ static const struct drm_display_mode edid_cea_modes[] = {
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,
+ { DRM_MODE("1440x480", 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,
+ { DRM_MODE("1440x480", 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) },
@@ -723,12 +723,12 @@ static const struct drm_display_mode edid_cea_modes[] = {
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,
+ { DRM_MODE("1440x576", 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,
+ { DRM_MODE("1440x576", 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) },
@@ -741,12 +741,12 @@ static const struct drm_display_mode edid_cea_modes[] = {
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,
+ { DRM_MODE("1440x480", 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,
+ { DRM_MODE("1440x480", 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) },
diff --git a/trunk/drivers/gpu/drm/drm_fb_cma_helper.c b/trunk/drivers/gpu/drm/drm_fb_cma_helper.c
deleted file mode 100644
index 09e11a5d921a..000000000000
--- a/trunk/drivers/gpu/drm/drm_fb_cma_helper.c
+++ /dev/null
@@ -1,406 +0,0 @@
-/*
- * drm kms/fb cma (contiguous memory allocator) helper functions
- *
- * Copyright (C) 2012 Analog Device Inc.
- * Author: Lars-Peter Clausen
- *
- * Based on udl_fbdev.c
- * Copyright (C) 2012 Red Hat
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- */
-
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-
-struct drm_fb_cma {
- struct drm_framebuffer fb;
- struct drm_gem_cma_object *obj[4];
-};
-
-struct drm_fbdev_cma {
- struct drm_fb_helper fb_helper;
- struct drm_fb_cma *fb;
-};
-
-static inline struct drm_fbdev_cma *to_fbdev_cma(struct drm_fb_helper *helper)
-{
- return container_of(helper, struct drm_fbdev_cma, fb_helper);
-}
-
-static inline struct drm_fb_cma *to_fb_cma(struct drm_framebuffer *fb)
-{
- return container_of(fb, struct drm_fb_cma, fb);
-}
-
-static void drm_fb_cma_destroy(struct drm_framebuffer *fb)
-{
- struct drm_fb_cma *fb_cma = to_fb_cma(fb);
- int i;
-
- for (i = 0; i < 4; i++) {
- if (fb_cma->obj[i])
- drm_gem_object_unreference_unlocked(&fb_cma->obj[i]->base);
- }
-
- drm_framebuffer_cleanup(fb);
- kfree(fb_cma);
-}
-
-static int drm_fb_cma_create_handle(struct drm_framebuffer *fb,
- struct drm_file *file_priv, unsigned int *handle)
-{
- struct drm_fb_cma *fb_cma = to_fb_cma(fb);
-
- return drm_gem_handle_create(file_priv,
- &fb_cma->obj[0]->base, handle);
-}
-
-static struct drm_framebuffer_funcs drm_fb_cma_funcs = {
- .destroy = drm_fb_cma_destroy,
- .create_handle = drm_fb_cma_create_handle,
-};
-
-static struct drm_fb_cma *drm_fb_cma_alloc(struct drm_device *dev,
- struct drm_mode_fb_cmd2 *mode_cmd, struct drm_gem_cma_object **obj,
- unsigned int num_planes)
-{
- struct drm_fb_cma *fb_cma;
- int ret;
- int i;
-
- fb_cma = kzalloc(sizeof(*fb_cma), GFP_KERNEL);
- if (!fb_cma)
- return ERR_PTR(-ENOMEM);
-
- ret = drm_framebuffer_init(dev, &fb_cma->fb, &drm_fb_cma_funcs);
- if (ret) {
- dev_err(dev->dev, "Failed to initalize framebuffer: %d\n", ret);
- kfree(fb_cma);
- return ERR_PTR(ret);
- }
-
- drm_helper_mode_fill_fb_struct(&fb_cma->fb, mode_cmd);
-
- for (i = 0; i < num_planes; i++)
- fb_cma->obj[i] = obj[i];
-
- return fb_cma;
-}
-
-/**
- * drm_fb_cma_create() - (struct drm_mode_config_funcs *)->fb_create callback function
- *
- * If your hardware has special alignment or pitch requirements these should be
- * checked before calling this function.
- */
-struct drm_framebuffer *drm_fb_cma_create(struct drm_device *dev,
- struct drm_file *file_priv, struct drm_mode_fb_cmd2 *mode_cmd)
-{
- struct drm_fb_cma *fb_cma;
- struct drm_gem_cma_object *objs[4];
- struct drm_gem_object *obj;
- unsigned int hsub;
- unsigned int vsub;
- int ret;
- int i;
-
- hsub = drm_format_horz_chroma_subsampling(mode_cmd->pixel_format);
- vsub = drm_format_vert_chroma_subsampling(mode_cmd->pixel_format);
-
- for (i = 0; i < drm_format_num_planes(mode_cmd->pixel_format); i++) {
- unsigned int width = mode_cmd->width / (i ? hsub : 1);
- unsigned int height = mode_cmd->height / (i ? vsub : 1);
- unsigned int min_size;
-
- obj = drm_gem_object_lookup(dev, file_priv, mode_cmd->handles[i]);
- if (!obj) {
- dev_err(dev->dev, "Failed to lookup GEM object\n");
- ret = -ENXIO;
- goto err_gem_object_unreference;
- }
-
- min_size = (height - 1) * mode_cmd->pitches[i]
- + width * drm_format_plane_cpp(mode_cmd->pixel_format, i)
- + mode_cmd->offsets[i];
-
- if (obj->size < min_size) {
- drm_gem_object_unreference_unlocked(obj);
- ret = -EINVAL;
- goto err_gem_object_unreference;
- }
- objs[i] = to_drm_gem_cma_obj(obj);
- }
-
- fb_cma = drm_fb_cma_alloc(dev, mode_cmd, objs, i);
- if (IS_ERR(fb_cma)) {
- ret = PTR_ERR(fb_cma);
- goto err_gem_object_unreference;
- }
-
- return &fb_cma->fb;
-
-err_gem_object_unreference:
- for (i--; i >= 0; i--)
- drm_gem_object_unreference_unlocked(&objs[i]->base);
- return ERR_PTR(ret);
-}
-EXPORT_SYMBOL_GPL(drm_fb_cma_create);
-
-/**
- * drm_fb_cma_get_gem_obj() - Get CMA GEM object for framebuffer
- * @fb: The framebuffer
- * @plane: Which plane
- *
- * Return the CMA GEM object for given framebuffer.
- *
- * This function will usually be called from the CRTC callback functions.
- */
-struct drm_gem_cma_object *drm_fb_cma_get_gem_obj(struct drm_framebuffer *fb,
- unsigned int plane)
-{
- struct drm_fb_cma *fb_cma = to_fb_cma(fb);
-
- if (plane >= 4)
- return NULL;
-
- return fb_cma->obj[plane];
-}
-EXPORT_SYMBOL_GPL(drm_fb_cma_get_gem_obj);
-
-static struct fb_ops drm_fbdev_cma_ops = {
- .owner = THIS_MODULE,
- .fb_fillrect = sys_fillrect,
- .fb_copyarea = sys_copyarea,
- .fb_imageblit = sys_imageblit,
- .fb_check_var = drm_fb_helper_check_var,
- .fb_set_par = drm_fb_helper_set_par,
- .fb_blank = drm_fb_helper_blank,
- .fb_pan_display = drm_fb_helper_pan_display,
- .fb_setcmap = drm_fb_helper_setcmap,
-};
-
-static int drm_fbdev_cma_create(struct drm_fb_helper *helper,
- struct drm_fb_helper_surface_size *sizes)
-{
- struct drm_fbdev_cma *fbdev_cma = to_fbdev_cma(helper);
- struct drm_mode_fb_cmd2 mode_cmd = { 0 };
- struct drm_device *dev = helper->dev;
- struct drm_gem_cma_object *obj;
- struct drm_framebuffer *fb;
- unsigned int bytes_per_pixel;
- unsigned long offset;
- struct fb_info *fbi;
- size_t size;
- int ret;
-
- DRM_DEBUG_KMS("surface width(%d), height(%d) and bpp(%d\n",
- sizes->surface_width, sizes->surface_height,
- sizes->surface_bpp);
-
- bytes_per_pixel = DIV_ROUND_UP(sizes->surface_bpp, 8);
-
- mode_cmd.width = sizes->surface_width;
- mode_cmd.height = sizes->surface_height;
- mode_cmd.pitches[0] = sizes->surface_width * bytes_per_pixel;
- mode_cmd.pixel_format = drm_mode_legacy_fb_format(sizes->surface_bpp,
- sizes->surface_depth);
-
- size = mode_cmd.pitches[0] * mode_cmd.height;
- obj = drm_gem_cma_create(dev, size);
- if (!obj)
- return -ENOMEM;
-
- fbi = framebuffer_alloc(0, dev->dev);
- if (!fbi) {
- dev_err(dev->dev, "Failed to allocate framebuffer info.\n");
- ret = -ENOMEM;
- goto err_drm_gem_cma_free_object;
- }
-
- fbdev_cma->fb = drm_fb_cma_alloc(dev, &mode_cmd, &obj, 1);
- if (IS_ERR(fbdev_cma->fb)) {
- dev_err(dev->dev, "Failed to allocate DRM framebuffer.\n");
- ret = PTR_ERR(fbdev_cma->fb);
- goto err_framebuffer_release;
- }
-
- fb = &fbdev_cma->fb->fb;
- helper->fb = fb;
- helper->fbdev = fbi;
-
- fbi->par = helper;
- fbi->flags = FBINFO_FLAG_DEFAULT;
- fbi->fbops = &drm_fbdev_cma_ops;
-
- ret = fb_alloc_cmap(&fbi->cmap, 256, 0);
- if (ret) {
- dev_err(dev->dev, "Failed to allocate color map.\n");
- goto err_drm_fb_cma_destroy;
- }
-
- drm_fb_helper_fill_fix(fbi, fb->pitches[0], fb->depth);
- drm_fb_helper_fill_var(fbi, helper, fb->width, fb->height);
-
- offset = fbi->var.xoffset * bytes_per_pixel;
- offset += fbi->var.yoffset * fb->pitches[0];
-
- dev->mode_config.fb_base = (resource_size_t)obj->paddr;
- fbi->screen_base = obj->vaddr + offset;
- fbi->fix.smem_start = (unsigned long)(obj->paddr + offset);
- fbi->screen_size = size;
- fbi->fix.smem_len = size;
-
- return 0;
-
-err_drm_fb_cma_destroy:
- drm_fb_cma_destroy(fb);
-err_framebuffer_release:
- framebuffer_release(fbi);
-err_drm_gem_cma_free_object:
- drm_gem_cma_free_object(&obj->base);
- return ret;
-}
-
-static int drm_fbdev_cma_probe(struct drm_fb_helper *helper,
- struct drm_fb_helper_surface_size *sizes)
-{
- int ret = 0;
-
- if (!helper->fb) {
- ret = drm_fbdev_cma_create(helper, sizes);
- if (ret < 0)
- return ret;
- ret = 1;
- }
-
- return ret;
-}
-
-static struct drm_fb_helper_funcs drm_fb_cma_helper_funcs = {
- .fb_probe = drm_fbdev_cma_probe,
-};
-
-/**
- * drm_fbdev_cma_init() - Allocate and initializes a drm_fbdev_cma struct
- * @dev: DRM device
- * @preferred_bpp: Preferred bits per pixel for the device
- * @num_crtc: Number of CRTCs
- * @max_conn_count: Maximum number of connectors
- *
- * Returns a newly allocated drm_fbdev_cma struct or a ERR_PTR.
- */
-struct drm_fbdev_cma *drm_fbdev_cma_init(struct drm_device *dev,
- unsigned int preferred_bpp, unsigned int num_crtc,
- unsigned int max_conn_count)
-{
- struct drm_fbdev_cma *fbdev_cma;
- struct drm_fb_helper *helper;
- int ret;
-
- fbdev_cma = kzalloc(sizeof(*fbdev_cma), GFP_KERNEL);
- if (!fbdev_cma) {
- dev_err(dev->dev, "Failed to allocate drm fbdev.\n");
- return ERR_PTR(-ENOMEM);
- }
-
- fbdev_cma->fb_helper.funcs = &drm_fb_cma_helper_funcs;
- helper = &fbdev_cma->fb_helper;
-
- ret = drm_fb_helper_init(dev, helper, num_crtc, max_conn_count);
- if (ret < 0) {
- dev_err(dev->dev, "Failed to initialize drm fb helper.\n");
- goto err_free;
- }
-
- ret = drm_fb_helper_single_add_all_connectors(helper);
- if (ret < 0) {
- dev_err(dev->dev, "Failed to add connectors.\n");
- goto err_drm_fb_helper_fini;
-
- }
-
- ret = drm_fb_helper_initial_config(helper, preferred_bpp);
- if (ret < 0) {
- dev_err(dev->dev, "Failed to set inital hw configuration.\n");
- goto err_drm_fb_helper_fini;
- }
-
- return fbdev_cma;
-
-err_drm_fb_helper_fini:
- drm_fb_helper_fini(helper);
-err_free:
- kfree(fbdev_cma);
-
- return ERR_PTR(ret);
-}
-EXPORT_SYMBOL_GPL(drm_fbdev_cma_init);
-
-/**
- * drm_fbdev_cma_fini() - Free drm_fbdev_cma struct
- * @fbdev_cma: The drm_fbdev_cma struct
- */
-void drm_fbdev_cma_fini(struct drm_fbdev_cma *fbdev_cma)
-{
- if (fbdev_cma->fb_helper.fbdev) {
- struct fb_info *info;
- int ret;
-
- info = fbdev_cma->fb_helper.fbdev;
- ret = unregister_framebuffer(info);
- if (ret < 0)
- DRM_DEBUG_KMS("failed unregister_framebuffer()\n");
-
- if (info->cmap.len)
- fb_dealloc_cmap(&info->cmap);
-
- framebuffer_release(info);
- }
-
- if (fbdev_cma->fb)
- drm_fb_cma_destroy(&fbdev_cma->fb->fb);
-
- drm_fb_helper_fini(&fbdev_cma->fb_helper);
- kfree(fbdev_cma);
-}
-EXPORT_SYMBOL_GPL(drm_fbdev_cma_fini);
-
-/**
- * drm_fbdev_cma_restore_mode() - Restores initial framebuffer mode
- * @fbdev_cma: The drm_fbdev_cma struct, may be NULL
- *
- * This function is usually called from the DRM drivers lastclose callback.
- */
-void drm_fbdev_cma_restore_mode(struct drm_fbdev_cma *fbdev_cma)
-{
- if (fbdev_cma)
- drm_fb_helper_restore_fbdev_mode(&fbdev_cma->fb_helper);
-}
-EXPORT_SYMBOL_GPL(drm_fbdev_cma_restore_mode);
-
-/**
- * drm_fbdev_cma_hotplug_event() - Poll for hotpulug events
- * @fbdev_cma: The drm_fbdev_cma struct, may be NULL
- *
- * This function is usually called from the DRM drivers output_poll_changed
- * callback.
- */
-void drm_fbdev_cma_hotplug_event(struct drm_fbdev_cma *fbdev_cma)
-{
- if (fbdev_cma)
- drm_fb_helper_hotplug_event(&fbdev_cma->fb_helper);
-}
-EXPORT_SYMBOL_GPL(drm_fbdev_cma_hotplug_event);
diff --git a/trunk/drivers/gpu/drm/drm_fb_helper.c b/trunk/drivers/gpu/drm/drm_fb_helper.c
index b5d05f58c15a..f546d1e8af82 100644
--- a/trunk/drivers/gpu/drm/drm_fb_helper.c
+++ b/trunk/drivers/gpu/drm/drm_fb_helper.c
@@ -236,7 +236,7 @@ bool drm_fb_helper_restore_fbdev_mode(struct drm_fb_helper *fb_helper)
}
EXPORT_SYMBOL(drm_fb_helper_restore_fbdev_mode);
-static bool drm_fb_helper_force_kernel_mode(void)
+bool drm_fb_helper_force_kernel_mode(void)
{
bool ret, error = false;
struct drm_fb_helper *helper;
@@ -330,7 +330,7 @@ static void drm_fb_helper_dpms(struct fb_info *info, int dpms_mode)
/* Walk the connectors & encoders on this fb turning them on/off */
for (j = 0; j < fb_helper->connector_count; j++) {
connector = fb_helper->connector_info[j]->connector;
- connector->funcs->dpms(connector, dpms_mode);
+ drm_helper_connector_dpms(connector, dpms_mode);
drm_connector_property_set_value(connector,
dev->mode_config.dpms_property, dpms_mode);
}
@@ -1230,6 +1230,7 @@ static void drm_setup_crtcs(struct drm_fb_helper *fb_helper)
struct drm_device *dev = fb_helper->dev;
struct drm_fb_helper_crtc **crtcs;
struct drm_display_mode **modes;
+ struct drm_encoder *encoder;
struct drm_mode_set *modeset;
bool *enabled;
int width, height;
@@ -1240,6 +1241,11 @@ static void drm_setup_crtcs(struct drm_fb_helper *fb_helper)
width = dev->mode_config.max_width;
height = dev->mode_config.max_height;
+ /* clean out all the encoder/crtc combos */
+ list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
+ encoder->crtc = NULL;
+ }
+
crtcs = kcalloc(dev->mode_config.num_connector,
sizeof(struct drm_fb_helper_crtc *), GFP_KERNEL);
modes = kcalloc(dev->mode_config.num_connector,
diff --git a/trunk/drivers/gpu/drm/drm_gem_cma_helper.c b/trunk/drivers/gpu/drm/drm_gem_cma_helper.c
deleted file mode 100644
index 1aa8fee1e865..000000000000
--- a/trunk/drivers/gpu/drm/drm_gem_cma_helper.c
+++ /dev/null
@@ -1,251 +0,0 @@
-/*
- * drm gem CMA (contiguous memory allocator) helper functions
- *
- * Copyright (C) 2012 Sascha Hauer, Pengutronix
- *
- * Based on Samsung Exynos code
- *
- * Copyright (c) 2011 Samsung Electronics Co., Ltd.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- */
-
-#include
-#include
-#include
-#include
-#include
-
-#include
-#include
-#include
-
-static unsigned int get_gem_mmap_offset(struct drm_gem_object *obj)
-{
- return (unsigned int)obj->map_list.hash.key << PAGE_SHIFT;
-}
-
-static void drm_gem_cma_buf_destroy(struct drm_device *drm,
- struct drm_gem_cma_object *cma_obj)
-{
- dma_free_writecombine(drm->dev, cma_obj->base.size, cma_obj->vaddr,
- cma_obj->paddr);
-}
-
-/*
- * drm_gem_cma_create - allocate an object with the given size
- *
- * returns a struct drm_gem_cma_object* on success or ERR_PTR values
- * on failure.
- */
-struct drm_gem_cma_object *drm_gem_cma_create(struct drm_device *drm,
- unsigned int size)
-{
- struct drm_gem_cma_object *cma_obj;
- struct drm_gem_object *gem_obj;
- int ret;
-
- size = round_up(size, PAGE_SIZE);
-
- cma_obj = kzalloc(sizeof(*cma_obj), GFP_KERNEL);
- if (!cma_obj)
- return ERR_PTR(-ENOMEM);
-
- cma_obj->vaddr = dma_alloc_writecombine(drm->dev, size,
- &cma_obj->paddr, GFP_KERNEL | __GFP_NOWARN);
- if (!cma_obj->vaddr) {
- dev_err(drm->dev, "failed to allocate buffer with size %d\n", size);
- ret = -ENOMEM;
- goto err_dma_alloc;
- }
-
- gem_obj = &cma_obj->base;
-
- ret = drm_gem_object_init(drm, gem_obj, size);
- if (ret)
- goto err_obj_init;
-
- ret = drm_gem_create_mmap_offset(gem_obj);
- if (ret)
- goto err_create_mmap_offset;
-
- return cma_obj;
-
-err_create_mmap_offset:
- drm_gem_object_release(gem_obj);
-
-err_obj_init:
- drm_gem_cma_buf_destroy(drm, cma_obj);
-
-err_dma_alloc:
- kfree(cma_obj);
-
- return ERR_PTR(ret);
-}
-EXPORT_SYMBOL_GPL(drm_gem_cma_create);
-
-/*
- * drm_gem_cma_create_with_handle - allocate an object with the given
- * size and create a gem handle on it
- *
- * returns a struct drm_gem_cma_object* on success or ERR_PTR values
- * on failure.
- */
-static struct drm_gem_cma_object *drm_gem_cma_create_with_handle(
- struct drm_file *file_priv,
- struct drm_device *drm, unsigned int size,
- unsigned int *handle)
-{
- struct drm_gem_cma_object *cma_obj;
- struct drm_gem_object *gem_obj;
- int ret;
-
- cma_obj = drm_gem_cma_create(drm, size);
- if (IS_ERR(cma_obj))
- return cma_obj;
-
- gem_obj = &cma_obj->base;
-
- /*
- * allocate a id of idr table where the obj is registered
- * and handle has the id what user can see.
- */
- ret = drm_gem_handle_create(file_priv, gem_obj, handle);
- if (ret)
- goto err_handle_create;
-
- /* drop reference from allocate - handle holds it now. */
- drm_gem_object_unreference_unlocked(gem_obj);
-
- return cma_obj;
-
-err_handle_create:
- drm_gem_cma_free_object(gem_obj);
-
- return ERR_PTR(ret);
-}
-
-/*
- * drm_gem_cma_free_object - (struct drm_driver)->gem_free_object callback
- * function
- */
-void drm_gem_cma_free_object(struct drm_gem_object *gem_obj)
-{
- struct drm_gem_cma_object *cma_obj;
-
- if (gem_obj->map_list.map)
- drm_gem_free_mmap_offset(gem_obj);
-
- drm_gem_object_release(gem_obj);
-
- cma_obj = to_drm_gem_cma_obj(gem_obj);
-
- drm_gem_cma_buf_destroy(gem_obj->dev, cma_obj);
-
- kfree(cma_obj);
-}
-EXPORT_SYMBOL_GPL(drm_gem_cma_free_object);
-
-/*
- * drm_gem_cma_dumb_create - (struct drm_driver)->dumb_create callback
- * function
- *
- * This aligns the pitch and size arguments to the minimum required. wrap
- * this into your own function if you need bigger alignment.
- */
-int drm_gem_cma_dumb_create(struct drm_file *file_priv,
- struct drm_device *dev, struct drm_mode_create_dumb *args)
-{
- struct drm_gem_cma_object *cma_obj;
- int min_pitch = DIV_ROUND_UP(args->width * args->bpp, 8);
-
- if (args->pitch < min_pitch)
- args->pitch = min_pitch;
-
- if (args->size < args->pitch * args->height)
- args->size = args->pitch * args->height;
-
- cma_obj = drm_gem_cma_create_with_handle(file_priv, dev,
- args->size, &args->handle);
- if (IS_ERR(cma_obj))
- return PTR_ERR(cma_obj);
-
- return 0;
-}
-EXPORT_SYMBOL_GPL(drm_gem_cma_dumb_create);
-
-/*
- * drm_gem_cma_dumb_map_offset - (struct drm_driver)->dumb_map_offset callback
- * function
- */
-int drm_gem_cma_dumb_map_offset(struct drm_file *file_priv,
- struct drm_device *drm, uint32_t handle, uint64_t *offset)
-{
- struct drm_gem_object *gem_obj;
-
- mutex_lock(&drm->struct_mutex);
-
- gem_obj = drm_gem_object_lookup(drm, file_priv, handle);
- if (!gem_obj) {
- dev_err(drm->dev, "failed to lookup gem object\n");
- mutex_unlock(&drm->struct_mutex);
- return -EINVAL;
- }
-
- *offset = get_gem_mmap_offset(gem_obj);
-
- drm_gem_object_unreference(gem_obj);
-
- mutex_unlock(&drm->struct_mutex);
-
- return 0;
-}
-EXPORT_SYMBOL_GPL(drm_gem_cma_dumb_map_offset);
-
-const struct vm_operations_struct drm_gem_cma_vm_ops = {
- .open = drm_gem_vm_open,
- .close = drm_gem_vm_close,
-};
-EXPORT_SYMBOL_GPL(drm_gem_cma_vm_ops);
-
-/*
- * drm_gem_cma_mmap - (struct file_operation)->mmap callback function
- */
-int drm_gem_cma_mmap(struct file *filp, struct vm_area_struct *vma)
-{
- struct drm_gem_object *gem_obj;
- struct drm_gem_cma_object *cma_obj;
- int ret;
-
- ret = drm_gem_mmap(filp, vma);
- if (ret)
- return ret;
-
- gem_obj = vma->vm_private_data;
- cma_obj = to_drm_gem_cma_obj(gem_obj);
-
- ret = remap_pfn_range(vma, vma->vm_start, cma_obj->paddr >> PAGE_SHIFT,
- vma->vm_end - vma->vm_start, vma->vm_page_prot);
- if (ret)
- drm_gem_vm_close(vma);
-
- return ret;
-}
-EXPORT_SYMBOL_GPL(drm_gem_cma_mmap);
-
-/*
- * drm_gem_cma_dumb_destroy - (struct drm_driver)->dumb_destroy callback function
- */
-int drm_gem_cma_dumb_destroy(struct drm_file *file_priv,
- struct drm_device *drm, unsigned int handle)
-{
- return drm_gem_handle_delete(file_priv, handle);
-}
-EXPORT_SYMBOL_GPL(drm_gem_cma_dumb_destroy);
diff --git a/trunk/drivers/gpu/drm/drm_irq.c b/trunk/drivers/gpu/drm/drm_irq.c
index 076c4a86ff84..03f16f352fe2 100644
--- a/trunk/drivers/gpu/drm/drm_irq.c
+++ b/trunk/drivers/gpu/drm/drm_irq.c
@@ -1236,7 +1236,7 @@ int drm_wait_vblank(struct drm_device *dev, void *data,
return ret;
}
-static void drm_handle_vblank_events(struct drm_device *dev, int crtc)
+void drm_handle_vblank_events(struct drm_device *dev, int crtc)
{
struct drm_pending_vblank_event *e, *t;
struct timeval now;
diff --git a/trunk/drivers/gpu/drm/drm_vm.c b/trunk/drivers/gpu/drm/drm_vm.c
index 6fed21502313..961ee08927fe 100644
--- a/trunk/drivers/gpu/drm/drm_vm.c
+++ b/trunk/drivers/gpu/drm/drm_vm.c
@@ -62,7 +62,7 @@ static pgprot_t drm_io_prot(uint32_t map_type, struct vm_area_struct *vma)
tmp = pgprot_writecombine(tmp);
else
tmp = pgprot_noncached(tmp);
-#elif defined(__sparc__) || defined(__arm__) || defined(__mips__)
+#elif defined(__sparc__) || defined(__arm__)
tmp = pgprot_noncached(tmp);
#endif
return tmp;
@@ -619,11 +619,20 @@ int drm_mmap_locked(struct file *filp, struct vm_area_struct *vma)
offset = drm_core_get_reg_ofs(dev);
vma->vm_flags |= VM_IO; /* not in core dump */
vma->vm_page_prot = drm_io_prot(map->type, vma);
+#if !defined(__arm__)
if (io_remap_pfn_range(vma, vma->vm_start,
(map->offset + offset) >> PAGE_SHIFT,
vma->vm_end - vma->vm_start,
vma->vm_page_prot))
return -EAGAIN;
+#else
+ if (remap_pfn_range(vma, vma->vm_start,
+ (map->offset + offset) >> PAGE_SHIFT,
+ vma->vm_end - vma->vm_start,
+ vma->vm_page_prot))
+ return -EAGAIN;
+#endif
+
DRM_DEBUG(" Type = %d; start = 0x%lx, end = 0x%lx,"
" offset = 0x%llx\n",
map->type,
diff --git a/trunk/drivers/gpu/drm/exynos/exynos_drm_connector.c b/trunk/drivers/gpu/drm/exynos/exynos_drm_connector.c
index 9dce3b9c3896..d9568198c300 100644
--- a/trunk/drivers/gpu/drm/exynos/exynos_drm_connector.c
+++ b/trunk/drivers/gpu/drm/exynos/exynos_drm_connector.c
@@ -147,7 +147,9 @@ static int exynos_drm_connector_get_modes(struct drm_connector *connector)
drm_mode_connector_update_edid_property(connector, edid);
count = drm_add_edid_modes(connector, edid);
- kfree(edid);
+
+ kfree(connector->display_info.raw_edid);
+ connector->display_info.raw_edid = edid;
} else {
struct drm_display_mode *mode = drm_mode_create(connector->dev);
struct exynos_drm_panel_info *panel;
diff --git a/trunk/drivers/gpu/drm/exynos/exynos_drm_fbdev.c b/trunk/drivers/gpu/drm/exynos/exynos_drm_fbdev.c
index f4ac43356583..d5586cc75163 100644
--- a/trunk/drivers/gpu/drm/exynos/exynos_drm_fbdev.c
+++ b/trunk/drivers/gpu/drm/exynos/exynos_drm_fbdev.c
@@ -266,8 +266,8 @@ static void exynos_drm_fbdev_destroy(struct drm_device *dev,
/* release drm framebuffer and real buffer */
if (fb_helper->fb && fb_helper->fb->funcs) {
fb = fb_helper->fb;
- if (fb)
- drm_framebuffer_remove(fb);
+ if (fb && fb->funcs->destroy)
+ fb->funcs->destroy(fb);
}
/* release linux framebuffer */
diff --git a/trunk/drivers/gpu/drm/exynos/exynos_drm_vidi.c b/trunk/drivers/gpu/drm/exynos/exynos_drm_vidi.c
index e364165f1a2a..537027a74fd5 100644
--- a/trunk/drivers/gpu/drm/exynos/exynos_drm_vidi.c
+++ b/trunk/drivers/gpu/drm/exynos/exynos_drm_vidi.c
@@ -102,6 +102,7 @@ static int vidi_get_edid(struct device *dev, struct drm_connector *connector,
u8 *edid, int len)
{
struct vidi_context *ctx = get_vidi_context(dev);
+ struct edid *raw_edid;
DRM_DEBUG_KMS("%s\n", __FILE__);
@@ -114,6 +115,18 @@ static int vidi_get_edid(struct device *dev, struct drm_connector *connector,
return -EFAULT;
}
+ raw_edid = kzalloc(len, GFP_KERNEL);
+ if (!raw_edid) {
+ DRM_DEBUG_KMS("failed to allocate raw_edid.\n");
+ return -ENOMEM;
+ }
+
+ memcpy(raw_edid, ctx->raw_edid, min((1 + ctx->raw_edid->extensions)
+ * EDID_LENGTH, len));
+
+ /* attach the edid data to connector. */
+ connector->display_info.raw_edid = (char *)raw_edid;
+
memcpy(edid, ctx->raw_edid, min((1 + ctx->raw_edid->extensions)
* EDID_LENGTH, len));
diff --git a/trunk/drivers/gpu/drm/gma500/Makefile b/trunk/drivers/gpu/drm/gma500/Makefile
index 7a2d40a5c1e1..abfa2a93f0d0 100644
--- a/trunk/drivers/gpu/drm/gma500/Makefile
+++ b/trunk/drivers/gpu/drm/gma500/Makefile
@@ -3,7 +3,7 @@
#
ccflags-y += -I$(srctree)/include/drm
-gma500_gfx-y += \
+gma500_gfx-y += gem_glue.o \
accel_2d.o \
backlight.o \
framebuffer.o \
@@ -30,8 +30,7 @@ gma500_gfx-$(CONFIG_DRM_GMA3600) += cdv_device.o \
cdv_intel_crt.o \
cdv_intel_display.o \
cdv_intel_hdmi.o \
- cdv_intel_lvds.o \
- cdv_intel_dp.o
+ cdv_intel_lvds.o
gma500_gfx-$(CONFIG_DRM_GMA600) += oaktrail_device.o \
oaktrail_crtc.o \
diff --git a/trunk/drivers/gpu/drm/gma500/backlight.c b/trunk/drivers/gpu/drm/gma500/backlight.c
index 143eba3309c5..20793951fcac 100644
--- a/trunk/drivers/gpu/drm/gma500/backlight.c
+++ b/trunk/drivers/gpu/drm/gma500/backlight.c
@@ -26,55 +26,10 @@
#include "intel_bios.h"
#include "power.h"
-static void do_gma_backlight_set(struct drm_device *dev)
-{
-#ifdef CONFIG_BACKLIGHT_CLASS_DEVICE
- struct drm_psb_private *dev_priv = dev->dev_private;
- backlight_update_status(dev_priv->backlight_device);
-#endif
-}
-
-void gma_backlight_enable(struct drm_device *dev)
-{
-#ifdef CONFIG_BACKLIGHT_CLASS_DEVICE
- struct drm_psb_private *dev_priv = dev->dev_private;
- dev_priv->backlight_enabled = true;
- if (dev_priv->backlight_device) {
- dev_priv->backlight_device->props.brightness = dev_priv->backlight_level;
- do_gma_backlight_set(dev);
- }
-#endif
-}
-
-void gma_backlight_disable(struct drm_device *dev)
-{
-#ifdef CONFIG_BACKLIGHT_CLASS_DEVICE
- struct drm_psb_private *dev_priv = dev->dev_private;
- dev_priv->backlight_enabled = false;
- if (dev_priv->backlight_device) {
- dev_priv->backlight_device->props.brightness = 0;
- do_gma_backlight_set(dev);
- }
-#endif
-}
-
-void gma_backlight_set(struct drm_device *dev, int v)
-{
-#ifdef CONFIG_BACKLIGHT_CLASS_DEVICE
- struct drm_psb_private *dev_priv = dev->dev_private;
- dev_priv->backlight_level = v;
- if (dev_priv->backlight_device && dev_priv->backlight_enabled) {
- dev_priv->backlight_device->props.brightness = v;
- do_gma_backlight_set(dev);
- }
-#endif
-}
-
int gma_backlight_init(struct drm_device *dev)
{
#ifdef CONFIG_BACKLIGHT_CLASS_DEVICE
struct drm_psb_private *dev_priv = dev->dev_private;
- dev_priv->backlight_enabled = true;
return dev_priv->ops->backlight_init(dev);
#else
return 0;
diff --git a/trunk/drivers/gpu/drm/gma500/cdv_device.c b/trunk/drivers/gpu/drm/gma500/cdv_device.c
index bfc2f397019a..b7e7b49d8f62 100644
--- a/trunk/drivers/gpu/drm/gma500/cdv_device.c
+++ b/trunk/drivers/gpu/drm/gma500/cdv_device.c
@@ -58,17 +58,10 @@ static int cdv_output_init(struct drm_device *dev)
cdv_intel_lvds_init(dev, &dev_priv->mode_dev);
/* These bits indicate HDMI not SDVO on CDV */
- if (REG_READ(SDVOB) & SDVO_DETECTED) {
+ if (REG_READ(SDVOB) & SDVO_DETECTED)
cdv_hdmi_init(dev, &dev_priv->mode_dev, SDVOB);
- if (REG_READ(DP_B) & DP_DETECTED)
- cdv_intel_dp_init(dev, &dev_priv->mode_dev, DP_B);
- }
-
- if (REG_READ(SDVOC) & SDVO_DETECTED) {
+ if (REG_READ(SDVOC) & SDVO_DETECTED)
cdv_hdmi_init(dev, &dev_priv->mode_dev, SDVOC);
- if (REG_READ(DP_C) & DP_DETECTED)
- cdv_intel_dp_init(dev, &dev_priv->mode_dev, DP_C);
- }
return 0;
}
@@ -170,7 +163,6 @@ static int cdv_backlight_init(struct drm_device *dev)
cdv_get_brightness(cdv_backlight_device);
backlight_update_status(cdv_backlight_device);
dev_priv->backlight_device = cdv_backlight_device;
- dev_priv->backlight_enabled = true;
return 0;
}
@@ -457,7 +449,6 @@ static void cdv_get_core_freq(struct drm_device *dev)
case 6:
case 7:
dev_priv->core_freq = 266;
- break;
default:
dev_priv->core_freq = 0;
}
@@ -497,65 +488,6 @@ static void cdv_hotplug_enable(struct drm_device *dev, bool on)
}
}
-static const char *force_audio_names[] = {
- "off",
- "auto",
- "on",
-};
-
-void cdv_intel_attach_force_audio_property(struct drm_connector *connector)
-{
- struct drm_device *dev = connector->dev;
- struct drm_psb_private *dev_priv = dev->dev_private;
- struct drm_property *prop;
- int i;
-
- prop = dev_priv->force_audio_property;
- if (prop == NULL) {
- prop = drm_property_create(dev, DRM_MODE_PROP_ENUM,
- "audio",
- ARRAY_SIZE(force_audio_names));
- if (prop == NULL)
- return;
-
- for (i = 0; i < ARRAY_SIZE(force_audio_names); i++)
- drm_property_add_enum(prop, i, i-1, force_audio_names[i]);
-
- dev_priv->force_audio_property = prop;
- }
- drm_connector_attach_property(connector, prop, 0);
-}
-
-
-static const char *broadcast_rgb_names[] = {
- "Full",
- "Limited 16:235",
-};
-
-void cdv_intel_attach_broadcast_rgb_property(struct drm_connector *connector)
-{
- struct drm_device *dev = connector->dev;
- struct drm_psb_private *dev_priv = dev->dev_private;
- struct drm_property *prop;
- int i;
-
- prop = dev_priv->broadcast_rgb_property;
- if (prop == NULL) {
- prop = drm_property_create(dev, DRM_MODE_PROP_ENUM,
- "Broadcast RGB",
- ARRAY_SIZE(broadcast_rgb_names));
- if (prop == NULL)
- return;
-
- for (i = 0; i < ARRAY_SIZE(broadcast_rgb_names); i++)
- drm_property_add_enum(prop, i, i, broadcast_rgb_names[i]);
-
- dev_priv->broadcast_rgb_property = prop;
- }
-
- drm_connector_attach_property(connector, prop, 0);
-}
-
/* Cedarview */
static const struct psb_offset cdv_regmap[2] = {
{
diff --git a/trunk/drivers/gpu/drm/gma500/cdv_intel_display.c b/trunk/drivers/gpu/drm/gma500/cdv_intel_display.c
index 3cfd0931fbfb..a68509ba22a8 100644
--- a/trunk/drivers/gpu/drm/gma500/cdv_intel_display.c
+++ b/trunk/drivers/gpu/drm/gma500/cdv_intel_display.c
@@ -57,26 +57,15 @@ struct cdv_intel_clock_t {
struct cdv_intel_limit_t {
struct cdv_intel_range_t dot, vco, n, m, m1, m2, p, p1;
struct cdv_intel_p2_t p2;
- bool (*find_pll)(const struct cdv_intel_limit_t *, struct drm_crtc *,
- int, int, struct cdv_intel_clock_t *);
};
-static bool cdv_intel_find_best_PLL(const struct cdv_intel_limit_t *limit,
- struct drm_crtc *crtc, int target, int refclk,
- struct cdv_intel_clock_t *best_clock);
-static bool cdv_intel_find_dp_pll(const struct cdv_intel_limit_t *limit, struct drm_crtc *crtc, int target,
- int refclk,
- struct cdv_intel_clock_t *best_clock);
-
#define CDV_LIMIT_SINGLE_LVDS_96 0
#define CDV_LIMIT_SINGLE_LVDS_100 1
#define CDV_LIMIT_DAC_HDMI_27 2
#define CDV_LIMIT_DAC_HDMI_96 3
-#define CDV_LIMIT_DP_27 4
-#define CDV_LIMIT_DP_100 5
static const struct cdv_intel_limit_t cdv_intel_limits[] = {
- { /* CDV_SINGLE_LVDS_96MHz */
+ { /* CDV_SIGNLE_LVDS_96MHz */
.dot = {.min = 20000, .max = 115500},
.vco = {.min = 1800000, .max = 3600000},
.n = {.min = 2, .max = 6},
@@ -87,7 +76,6 @@ static const struct cdv_intel_limit_t cdv_intel_limits[] = {
.p1 = {.min = 2, .max = 10},
.p2 = {.dot_limit = 200000,
.p2_slow = 14, .p2_fast = 14},
- .find_pll = cdv_intel_find_best_PLL,
},
{ /* CDV_SINGLE_LVDS_100MHz */
.dot = {.min = 20000, .max = 115500},
@@ -102,7 +90,6 @@ static const struct cdv_intel_limit_t cdv_intel_limits[] = {
* is 80-224Mhz. Prefer single channel as much as possible.
*/
.p2 = {.dot_limit = 200000, .p2_slow = 14, .p2_fast = 14},
- .find_pll = cdv_intel_find_best_PLL,
},
{ /* CDV_DAC_HDMI_27MHz */
.dot = {.min = 20000, .max = 400000},
@@ -114,7 +101,6 @@ static const struct cdv_intel_limit_t cdv_intel_limits[] = {
.p = {.min = 5, .max = 90},
.p1 = {.min = 1, .max = 9},
.p2 = {.dot_limit = 225000, .p2_slow = 10, .p2_fast = 5},
- .find_pll = cdv_intel_find_best_PLL,
},
{ /* CDV_DAC_HDMI_96MHz */
.dot = {.min = 20000, .max = 400000},
@@ -126,32 +112,7 @@ static const struct cdv_intel_limit_t cdv_intel_limits[] = {
.p = {.min = 5, .max = 100},
.p1 = {.min = 1, .max = 10},
.p2 = {.dot_limit = 225000, .p2_slow = 10, .p2_fast = 5},
- .find_pll = cdv_intel_find_best_PLL,
- },
- { /* CDV_DP_27MHz */
- .dot = {.min = 160000, .max = 272000},
- .vco = {.min = 1809000, .max = 3564000},
- .n = {.min = 1, .max = 1},
- .m = {.min = 67, .max = 132},
- .m1 = {.min = 0, .max = 0},
- .m2 = {.min = 65, .max = 130},
- .p = {.min = 5, .max = 90},
- .p1 = {.min = 1, .max = 9},
- .p2 = {.dot_limit = 225000, .p2_slow = 10, .p2_fast = 10},
- .find_pll = cdv_intel_find_dp_pll,
},
- { /* CDV_DP_100MHz */
- .dot = {.min = 160000, .max = 272000},
- .vco = {.min = 1800000, .max = 3600000},
- .n = {.min = 2, .max = 6},
- .m = {.min = 60, .max = 164},
- .m1 = {.min = 0, .max = 0},
- .m2 = {.min = 58, .max = 162},
- .p = {.min = 5, .max = 100},
- .p1 = {.min = 1, .max = 10},
- .p2 = {.dot_limit = 225000, .p2_slow = 10, .p2_fast = 10},
- .find_pll = cdv_intel_find_dp_pll,
- }
};
#define _wait_for(COND, MS, W) ({ \
@@ -171,7 +132,7 @@ static const struct cdv_intel_limit_t cdv_intel_limits[] = {
#define wait_for(COND, MS) _wait_for(COND, MS, 1)
-int cdv_sb_read(struct drm_device *dev, u32 reg, u32 *val)
+static int cdv_sb_read(struct drm_device *dev, u32 reg, u32 *val)
{
int ret;
@@ -198,7 +159,7 @@ int cdv_sb_read(struct drm_device *dev, u32 reg, u32 *val)
return 0;
}
-int cdv_sb_write(struct drm_device *dev, u32 reg, u32 val)
+static int cdv_sb_write(struct drm_device *dev, u32 reg, u32 val)
{
int ret;
static bool dpio_debug = true;
@@ -240,7 +201,7 @@ int cdv_sb_write(struct drm_device *dev, u32 reg, u32 val)
/* Reset the DPIO configuration register. The BIOS does this at every
* mode set.
*/
-void cdv_sb_reset(struct drm_device *dev)
+static void cdv_sb_reset(struct drm_device *dev)
{
REG_WRITE(DPIO_CFG, 0);
@@ -255,7 +216,7 @@ void cdv_sb_reset(struct drm_device *dev)
*/
static int
cdv_dpll_set_clock_cdv(struct drm_device *dev, struct drm_crtc *crtc,
- struct cdv_intel_clock_t *clock, bool is_lvds, u32 ddi_select)
+ struct cdv_intel_clock_t *clock, bool is_lvds)
{
struct psb_intel_crtc *psb_crtc = to_psb_intel_crtc(crtc);
int pipe = psb_crtc->pipe;
@@ -298,7 +259,7 @@ cdv_dpll_set_clock_cdv(struct drm_device *dev, struct drm_crtc *crtc,
ref_value &= ~(REF_CLK_MASK);
/* use DPLL_A for pipeB on CRT/HDMI */
- if (pipe == 1 && !is_lvds && !(ddi_select & DP_MASK)) {
+ if (pipe == 1 && !is_lvds) {
DRM_DEBUG_KMS("use DPLLA for pipe B\n");
ref_value |= REF_CLK_DPLLA;
} else {
@@ -375,33 +336,30 @@ cdv_dpll_set_clock_cdv(struct drm_device *dev, struct drm_crtc *crtc,
if (ret)
return ret;
- if (ddi_select) {
- if ((ddi_select & DDI_MASK) == DDI0_SELECT) {
- lane_reg = PSB_LANE0;
- cdv_sb_read(dev, lane_reg, &lane_value);
- lane_value &= ~(LANE_PLL_MASK);
- lane_value |= LANE_PLL_ENABLE | LANE_PLL_PIPE(pipe);
- cdv_sb_write(dev, lane_reg, lane_value);
-
- lane_reg = PSB_LANE1;
- cdv_sb_read(dev, lane_reg, &lane_value);
- lane_value &= ~(LANE_PLL_MASK);
- lane_value |= LANE_PLL_ENABLE | LANE_PLL_PIPE(pipe);
- cdv_sb_write(dev, lane_reg, lane_value);
- } else {
- lane_reg = PSB_LANE2;
- cdv_sb_read(dev, lane_reg, &lane_value);
- lane_value &= ~(LANE_PLL_MASK);
- lane_value |= LANE_PLL_ENABLE | LANE_PLL_PIPE(pipe);
- cdv_sb_write(dev, lane_reg, lane_value);
-
- lane_reg = PSB_LANE3;
- cdv_sb_read(dev, lane_reg, &lane_value);
- lane_value &= ~(LANE_PLL_MASK);
- lane_value |= LANE_PLL_ENABLE | LANE_PLL_PIPE(pipe);
- cdv_sb_write(dev, lane_reg, lane_value);
- }
- }
+ lane_reg = PSB_LANE0;
+ cdv_sb_read(dev, lane_reg, &lane_value);
+ lane_value &= ~(LANE_PLL_MASK);
+ lane_value |= LANE_PLL_ENABLE | LANE_PLL_PIPE(pipe);
+ cdv_sb_write(dev, lane_reg, lane_value);
+
+ lane_reg = PSB_LANE1;
+ cdv_sb_read(dev, lane_reg, &lane_value);
+ lane_value &= ~(LANE_PLL_MASK);
+ lane_value |= LANE_PLL_ENABLE | LANE_PLL_PIPE(pipe);
+ cdv_sb_write(dev, lane_reg, lane_value);
+
+ lane_reg = PSB_LANE2;
+ cdv_sb_read(dev, lane_reg, &lane_value);
+ lane_value &= ~(LANE_PLL_MASK);
+ lane_value |= LANE_PLL_ENABLE | LANE_PLL_PIPE(pipe);
+ cdv_sb_write(dev, lane_reg, lane_value);
+
+ lane_reg = PSB_LANE3;
+ cdv_sb_read(dev, lane_reg, &lane_value);
+ lane_value &= ~(LANE_PLL_MASK);
+ lane_value |= LANE_PLL_ENABLE | LANE_PLL_PIPE(pipe);
+ cdv_sb_write(dev, lane_reg, lane_value);
+
return 0;
}
@@ -438,12 +396,6 @@ static const struct cdv_intel_limit_t *cdv_intel_limit(struct drm_crtc *crtc,
limit = &cdv_intel_limits[CDV_LIMIT_SINGLE_LVDS_96];
else
limit = &cdv_intel_limits[CDV_LIMIT_SINGLE_LVDS_100];
- } else if (psb_intel_pipe_has_type(crtc, INTEL_OUTPUT_DISPLAYPORT) ||
- psb_intel_pipe_has_type(crtc, INTEL_OUTPUT_EDP)) {
- if (refclk == 27000)
- limit = &cdv_intel_limits[CDV_LIMIT_DP_27];
- else
- limit = &cdv_intel_limits[CDV_LIMIT_DP_100];
} else {
if (refclk == 27000)
limit = &cdv_intel_limits[CDV_LIMIT_DAC_HDMI_27];
@@ -486,12 +438,13 @@ static bool cdv_intel_PLL_is_valid(struct drm_crtc *crtc,
return true;
}
-static bool cdv_intel_find_best_PLL(const struct cdv_intel_limit_t *limit,
- struct drm_crtc *crtc, int target, int refclk,
- struct cdv_intel_clock_t *best_clock)
+static bool cdv_intel_find_best_PLL(struct drm_crtc *crtc, int target,
+ int refclk,
+ struct cdv_intel_clock_t *best_clock)
{
struct drm_device *dev = crtc->dev;
struct cdv_intel_clock_t clock;
+ const struct cdv_intel_limit_t *limit = cdv_intel_limit(crtc, refclk);
int err = target;
@@ -545,49 +498,6 @@ static bool cdv_intel_find_best_PLL(const struct cdv_intel_limit_t *limit,
return err != target;
}
-static bool cdv_intel_find_dp_pll(const struct cdv_intel_limit_t *limit, struct drm_crtc *crtc, int target,
- int refclk,
- struct cdv_intel_clock_t *best_clock)
-{
- struct cdv_intel_clock_t clock;
- if (refclk == 27000) {
- if (target < 200000) {
- clock.p1 = 2;
- clock.p2 = 10;
- clock.n = 1;
- clock.m1 = 0;
- clock.m2 = 118;
- } else {
- clock.p1 = 1;
- clock.p2 = 10;
- clock.n = 1;
- clock.m1 = 0;
- clock.m2 = 98;
- }
- } else if (refclk == 100000) {
- if (target < 200000) {
- clock.p1 = 2;
- clock.p2 = 10;
- clock.n = 5;
- clock.m1 = 0;
- clock.m2 = 160;
- } else {
- clock.p1 = 1;
- clock.p2 = 10;
- clock.n = 5;
- clock.m1 = 0;
- clock.m2 = 133;
- }
- } else
- return false;
- clock.m = clock.m2 + 2;
- clock.p = clock.p1 * clock.p2;
- clock.vco = (refclk * clock.m) / clock.n;
- clock.dot = clock.vco / clock.p;
- memcpy(best_clock, &clock, sizeof(struct cdv_intel_clock_t));
- return true;
-}
-
static int cdv_intel_pipe_set_base(struct drm_crtc *crtc,
int x, int y, struct drm_framebuffer *old_fb)
{
@@ -881,7 +791,7 @@ static void cdv_intel_crtc_dpms(struct drm_crtc *crtc, int mode)
case DRM_MODE_DPMS_STANDBY:
case DRM_MODE_DPMS_SUSPEND:
if (psb_intel_crtc->active)
- break;
+ return;
psb_intel_crtc->active = true;
@@ -925,15 +835,17 @@ static void cdv_intel_crtc_dpms(struct drm_crtc *crtc, int mode)
REG_WRITE(map->status, temp);
REG_READ(map->status);
+ cdv_intel_update_watermark(dev, crtc);
cdv_intel_crtc_load_lut(crtc);
/* Give the overlay scaler a chance to enable
* if it's on this pipe */
/* psb_intel_crtc_dpms_video(crtc, true); TODO */
+ psb_intel_crtc->crtc_enable = true;
break;
case DRM_MODE_DPMS_OFF:
if (!psb_intel_crtc->active)
- break;
+ return;
psb_intel_crtc->active = false;
@@ -980,9 +892,10 @@ static void cdv_intel_crtc_dpms(struct drm_crtc *crtc, int mode)
/* Wait for the clocks to turn off. */
udelay(150);
+ cdv_intel_update_watermark(dev, crtc);
+ psb_intel_crtc->crtc_enable = false;
break;
}
- cdv_intel_update_watermark(dev, crtc);
/*Set FIFO Watermarks*/
REG_WRITE(DSPARB, 0x3F3E);
}
@@ -1039,12 +952,9 @@ static int cdv_intel_crtc_mode_set(struct drm_crtc *crtc,
u32 dpll = 0, dspcntr, pipeconf;
bool ok;
bool is_crt = false, is_lvds = false, is_tv = false;
- bool is_hdmi = false, is_dp = false;
+ bool is_hdmi = false;
struct drm_mode_config *mode_config = &dev->mode_config;
struct drm_connector *connector;
- const struct cdv_intel_limit_t *limit;
- u32 ddi_select = 0;
- bool is_edp = false;
list_for_each_entry(connector, &mode_config->connector_list, head) {
struct psb_intel_encoder *psb_intel_encoder =
@@ -1054,7 +964,6 @@ static int cdv_intel_crtc_mode_set(struct drm_crtc *crtc,
|| connector->encoder->crtc != crtc)
continue;
- ddi_select = psb_intel_encoder->ddi_select;
switch (psb_intel_encoder->type) {
case INTEL_OUTPUT_LVDS:
is_lvds = true;
@@ -1068,15 +977,6 @@ static int cdv_intel_crtc_mode_set(struct drm_crtc *crtc,
case INTEL_OUTPUT_HDMI:
is_hdmi = true;
break;
- case INTEL_OUTPUT_DISPLAYPORT:
- is_dp = true;
- break;
- case INTEL_OUTPUT_EDP:
- is_edp = true;
- break;
- default:
- DRM_ERROR("invalid output type.\n");
- return 0;
}
}
@@ -1086,20 +986,6 @@ static int cdv_intel_crtc_mode_set(struct drm_crtc *crtc,
else
/* high-end sku, 27/100 mhz */
refclk = 27000;
- if (is_dp || is_edp) {
- /*
- * Based on the spec the low-end SKU has only CRT/LVDS. So it is
- * unnecessary to consider it for DP/eDP.
- * On the high-end SKU, it will use the 27/100M reference clk
- * for DP/eDP. When using SSC clock, the ref clk is 100MHz.Otherwise
- * it will be 27MHz. From the VBIOS code it seems that the pipe A choose
- * 27MHz for DP/eDP while the Pipe B chooses the 100MHz.
- */
- if (pipe == 0)
- refclk = 27000;
- else
- refclk = 100000;
- }
if (is_lvds && dev_priv->lvds_use_ssc) {
refclk = dev_priv->lvds_ssc_freq * 1000;
@@ -1107,10 +993,8 @@ static int cdv_intel_crtc_mode_set(struct drm_crtc *crtc,
}
drm_mode_debug_printmodeline(adjusted_mode);
-
- limit = cdv_intel_limit(crtc, refclk);
- ok = limit->find_pll(limit, crtc, adjusted_mode->clock, refclk,
+ ok = cdv_intel_find_best_PLL(crtc, adjusted_mode->clock, refclk,
&clock);
if (!ok) {
dev_err(dev->dev, "Couldn't find PLL settings for mode!\n");
@@ -1125,15 +1009,6 @@ static int cdv_intel_crtc_mode_set(struct drm_crtc *crtc,
}
/* dpll |= PLL_REF_INPUT_DREFCLK; */
- if (is_dp || is_edp) {
- cdv_intel_dp_set_m_n(crtc, mode, adjusted_mode);
- } else {
- REG_WRITE(PIPE_GMCH_DATA_M(pipe), 0);
- REG_WRITE(PIPE_GMCH_DATA_N(pipe), 0);
- REG_WRITE(PIPE_DP_LINK_M(pipe), 0);
- REG_WRITE(PIPE_DP_LINK_N(pipe), 0);
- }
-
dpll |= DPLL_SYNCLOCK_ENABLE;
/* if (is_lvds)
dpll |= DPLLB_MODE_LVDS;
@@ -1144,31 +1019,6 @@ static int cdv_intel_crtc_mode_set(struct drm_crtc *crtc,
/* setup pipeconf */
pipeconf = REG_READ(map->conf);
- pipeconf &= ~(PIPE_BPC_MASK);
- if (is_edp) {
- switch (dev_priv->edp.bpp) {
- case 24:
- pipeconf |= PIPE_8BPC;
- break;
- case 18:
- pipeconf |= PIPE_6BPC;
- break;
- case 30:
- pipeconf |= PIPE_10BPC;
- break;
- default:
- pipeconf |= PIPE_8BPC;
- break;
- }
- } else if (is_lvds) {
- /* the BPC will be 6 if it is 18-bit LVDS panel */
- if ((REG_READ(LVDS) & LVDS_A3_POWER_MASK) == LVDS_A3_POWER_UP)
- pipeconf |= PIPE_8BPC;
- else
- pipeconf |= PIPE_6BPC;
- } else
- pipeconf |= PIPE_8BPC;
-
/* Set up the display plane register */
dspcntr = DISPPLANE_GAMMA_ENABLE;
@@ -1183,7 +1033,7 @@ static int cdv_intel_crtc_mode_set(struct drm_crtc *crtc,
REG_WRITE(map->dpll, dpll | DPLL_VGA_MODE_DIS | DPLL_SYNCLOCK_ENABLE);
REG_READ(map->dpll);
- cdv_dpll_set_clock_cdv(dev, crtc, &clock, is_lvds, ddi_select);
+ cdv_dpll_set_clock_cdv(dev, crtc, &clock, is_lvds);
udelay(150);
diff --git a/trunk/drivers/gpu/drm/gma500/cdv_intel_dp.c b/trunk/drivers/gpu/drm/gma500/cdv_intel_dp.c
deleted file mode 100644
index c9abc06ef680..000000000000
--- a/trunk/drivers/gpu/drm/gma500/cdv_intel_dp.c
+++ /dev/null
@@ -1,1951 +0,0 @@
-/*
- * Copyright © 2012 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:
- * Keith Packard
- *
- */
-
-#include
-#include
-#include "drmP.h"
-#include "drm.h"
-#include "drm_crtc.h"
-#include "drm_crtc_helper.h"
-#include "psb_drv.h"
-#include "psb_intel_drv.h"
-#include "psb_intel_reg.h"
-#include "drm_dp_helper.h"
-
-#define _wait_for(COND, MS, W) ({ \
- unsigned long timeout__ = jiffies + msecs_to_jiffies(MS); \
- int ret__ = 0; \
- while (! (COND)) { \
- if (time_after(jiffies, timeout__)) { \
- ret__ = -ETIMEDOUT; \
- break; \
- } \
- if (W && !in_dbg_master()) msleep(W); \
- } \
- ret__; \
-})
-
-#define wait_for(COND, MS) _wait_for(COND, MS, 1)
-
-#define DP_LINK_STATUS_SIZE 6
-#define DP_LINK_CHECK_TIMEOUT (10 * 1000)
-
-#define DP_LINK_CONFIGURATION_SIZE 9
-
-#define CDV_FAST_LINK_TRAIN 1
-
-struct cdv_intel_dp {
- uint32_t output_reg;
- uint32_t DP;
- uint8_t link_configuration[DP_LINK_CONFIGURATION_SIZE];
- bool has_audio;
- int force_audio;
- uint32_t color_range;
- uint8_t link_bw;
- uint8_t lane_count;
- uint8_t dpcd[4];
- struct psb_intel_encoder *encoder;
- struct i2c_adapter adapter;
- struct i2c_algo_dp_aux_data algo;
- uint8_t train_set[4];
- uint8_t link_status[DP_LINK_STATUS_SIZE];
- int panel_power_up_delay;
- int panel_power_down_delay;
- int panel_power_cycle_delay;
- int backlight_on_delay;
- int backlight_off_delay;
- struct drm_display_mode *panel_fixed_mode; /* for eDP */
- bool panel_on;
-};
-
-struct ddi_regoff {
- uint32_t PreEmph1;
- uint32_t PreEmph2;
- uint32_t VSwing1;
- uint32_t VSwing2;
- uint32_t VSwing3;
- uint32_t VSwing4;
- uint32_t VSwing5;
-};
-
-static struct ddi_regoff ddi_DP_train_table[] = {
- {.PreEmph1 = 0x812c, .PreEmph2 = 0x8124, .VSwing1 = 0x8154,
- .VSwing2 = 0x8148, .VSwing3 = 0x814C, .VSwing4 = 0x8150,
- .VSwing5 = 0x8158,},
- {.PreEmph1 = 0x822c, .PreEmph2 = 0x8224, .VSwing1 = 0x8254,
- .VSwing2 = 0x8248, .VSwing3 = 0x824C, .VSwing4 = 0x8250,
- .VSwing5 = 0x8258,},
-};
-
-static uint32_t dp_vswing_premph_table[] = {
- 0x55338954, 0x4000,
- 0x554d8954, 0x2000,
- 0x55668954, 0,
- 0x559ac0d4, 0x6000,
-};
-/**
- * is_edp - is the given port attached to an eDP panel (either CPU or PCH)
- * @intel_dp: DP struct
- *
- * If a CPU or PCH DP output is attached to an eDP panel, this function
- * will return true, and false otherwise.
- */
-static bool is_edp(struct psb_intel_encoder *encoder)
-{
- return encoder->type == INTEL_OUTPUT_EDP;
-}
-
-
-static void cdv_intel_dp_start_link_train(struct psb_intel_encoder *encoder);
-static void cdv_intel_dp_complete_link_train(struct psb_intel_encoder *encoder);
-static void cdv_intel_dp_link_down(struct psb_intel_encoder *encoder);
-
-static int
-cdv_intel_dp_max_lane_count(struct psb_intel_encoder *encoder)
-{
- struct cdv_intel_dp *intel_dp = encoder->dev_priv;
- int max_lane_count = 4;
-
- if (intel_dp->dpcd[DP_DPCD_REV] >= 0x11) {
- max_lane_count = intel_dp->dpcd[DP_MAX_LANE_COUNT] & 0x1f;
- switch (max_lane_count) {
- case 1: case 2: case 4:
- break;
- default:
- max_lane_count = 4;
- }
- }
- return max_lane_count;
-}
-
-static int
-cdv_intel_dp_max_link_bw(struct psb_intel_encoder *encoder)
-{
- struct cdv_intel_dp *intel_dp = encoder->dev_priv;
- int max_link_bw = intel_dp->dpcd[DP_MAX_LINK_RATE];
-
- switch (max_link_bw) {
- case DP_LINK_BW_1_62:
- case DP_LINK_BW_2_7:
- break;
- default:
- max_link_bw = DP_LINK_BW_1_62;
- break;
- }
- return max_link_bw;
-}
-
-static int
-cdv_intel_dp_link_clock(uint8_t link_bw)
-{
- if (link_bw == DP_LINK_BW_2_7)
- return 270000;
- else
- return 162000;
-}
-
-static int
-cdv_intel_dp_link_required(int pixel_clock, int bpp)
-{
- return (pixel_clock * bpp + 7) / 8;
-}
-
-static int
-cdv_intel_dp_max_data_rate(int max_link_clock, int max_lanes)
-{
- return (max_link_clock * max_lanes * 19) / 20;
-}
-
-static void cdv_intel_edp_panel_vdd_on(struct psb_intel_encoder *intel_encoder)
-{
- struct drm_device *dev = intel_encoder->base.dev;
- struct cdv_intel_dp *intel_dp = intel_encoder->dev_priv;
- u32 pp;
-
- if (intel_dp->panel_on) {
- DRM_DEBUG_KMS("Skip VDD on because of panel on\n");
- return;
- }
- DRM_DEBUG_KMS("\n");
-
- pp = REG_READ(PP_CONTROL);
-
- pp |= EDP_FORCE_VDD;
- REG_WRITE(PP_CONTROL, pp);
- REG_READ(PP_CONTROL);
- msleep(intel_dp->panel_power_up_delay);
-}
-
-static void cdv_intel_edp_panel_vdd_off(struct psb_intel_encoder *intel_encoder)
-{
- struct drm_device *dev = intel_encoder->base.dev;
- u32 pp;
-
- DRM_DEBUG_KMS("\n");
- pp = REG_READ(PP_CONTROL);
-
- pp &= ~EDP_FORCE_VDD;
- REG_WRITE(PP_CONTROL, pp);
- REG_READ(PP_CONTROL);
-
-}
-
-/* Returns true if the panel was already on when called */
-static bool cdv_intel_edp_panel_on(struct psb_intel_encoder *intel_encoder)
-{
- struct drm_device *dev = intel_encoder->base.dev;
- struct cdv_intel_dp *intel_dp = intel_encoder->dev_priv;
- u32 pp, idle_on_mask = PP_ON | PP_SEQUENCE_NONE;
-
- if (intel_dp->panel_on)
- return true;
-
- DRM_DEBUG_KMS("\n");
- pp = REG_READ(PP_CONTROL);
- pp &= ~PANEL_UNLOCK_MASK;
-
- pp |= (PANEL_UNLOCK_REGS | POWER_TARGET_ON);
- REG_WRITE(PP_CONTROL, pp);
- REG_READ(PP_CONTROL);
-
- if (wait_for(((REG_READ(PP_STATUS) & idle_on_mask) == idle_on_mask), 1000)) {
- DRM_DEBUG_KMS("Error in Powering up eDP panel, status %x\n", REG_READ(PP_STATUS));
- intel_dp->panel_on = false;
- } else
- intel_dp->panel_on = true;
- msleep(intel_dp->panel_power_up_delay);
-
- return false;
-}
-
-static void cdv_intel_edp_panel_off (struct psb_intel_encoder *intel_encoder)
-{
- struct drm_device *dev = intel_encoder->base.dev;
- u32 pp, idle_off_mask = PP_ON ;
- struct cdv_intel_dp *intel_dp = intel_encoder->dev_priv;
-
- DRM_DEBUG_KMS("\n");
-
- pp = REG_READ(PP_CONTROL);
-
- if ((pp & POWER_TARGET_ON) == 0)
- return;
-
- intel_dp->panel_on = false;
- pp &= ~PANEL_UNLOCK_MASK;
- /* ILK workaround: disable reset around power sequence */
-
- pp &= ~POWER_TARGET_ON;
- pp &= ~EDP_FORCE_VDD;
- pp &= ~EDP_BLC_ENABLE;
- REG_WRITE(PP_CONTROL, pp);
- REG_READ(PP_CONTROL);
- DRM_DEBUG_KMS("PP_STATUS %x\n", REG_READ(PP_STATUS));
-
- if (wait_for((REG_READ(PP_STATUS) & idle_off_mask) == 0, 1000)) {
- DRM_DEBUG_KMS("Error in turning off Panel\n");
- }
-
- msleep(intel_dp->panel_power_cycle_delay);
- DRM_DEBUG_KMS("Over\n");
-}
-
-static void cdv_intel_edp_backlight_on (struct psb_intel_encoder *intel_encoder)
-{
- struct drm_device *dev = intel_encoder->base.dev;
- u32 pp;
-
- DRM_DEBUG_KMS("\n");
- /*
- * If we enable the backlight right away following a panel power
- * on, we may see slight flicker as the panel syncs with the eDP
- * link. So delay a bit to make sure the image is solid before
- * allowing it to appear.
- */
- msleep(300);
- pp = REG_READ(PP_CONTROL);
-
- pp |= EDP_BLC_ENABLE;
- REG_WRITE(PP_CONTROL, pp);
- gma_backlight_enable(dev);
-}
-
-static void cdv_intel_edp_backlight_off (struct psb_intel_encoder *intel_encoder)
-{
- struct drm_device *dev = intel_encoder->base.dev;
- struct cdv_intel_dp *intel_dp = intel_encoder->dev_priv;
- u32 pp;
-
- DRM_DEBUG_KMS("\n");
- gma_backlight_disable(dev);
- msleep(10);
- pp = REG_READ(PP_CONTROL);
-
- pp &= ~EDP_BLC_ENABLE;
- REG_WRITE(PP_CONTROL, pp);
- msleep(intel_dp->backlight_off_delay);
-}
-
-static int
-cdv_intel_dp_mode_valid(struct drm_connector *connector,
- struct drm_display_mode *mode)
-{
- struct psb_intel_encoder *encoder = psb_intel_attached_encoder(connector);
- struct cdv_intel_dp *intel_dp = encoder->dev_priv;
- int max_link_clock = cdv_intel_dp_link_clock(cdv_intel_dp_max_link_bw(encoder));
- int max_lanes = cdv_intel_dp_max_lane_count(encoder);
- struct drm_psb_private *dev_priv = connector->dev->dev_private;
-
- if (is_edp(encoder) && intel_dp->panel_fixed_mode) {
- if (mode->hdisplay > intel_dp->panel_fixed_mode->hdisplay)
- return MODE_PANEL;
- if (mode->vdisplay > intel_dp->panel_fixed_mode->vdisplay)
- return MODE_PANEL;
- }
-
- /* only refuse the mode on non eDP since we have seen some weird eDP panels
- which are outside spec tolerances but somehow work by magic */
- if (!is_edp(encoder) &&
- (cdv_intel_dp_link_required(mode->clock, dev_priv->edp.bpp)
- > cdv_intel_dp_max_data_rate(max_link_clock, max_lanes)))
- return MODE_CLOCK_HIGH;
-
- if (is_edp(encoder)) {
- if (cdv_intel_dp_link_required(mode->clock, 24)
- > cdv_intel_dp_max_data_rate(max_link_clock, max_lanes))
- return MODE_CLOCK_HIGH;
-
- }
- if (mode->clock < 10000)
- return MODE_CLOCK_LOW;
-
- return MODE_OK;
-}
-
-static uint32_t
-pack_aux(uint8_t *src, int src_bytes)
-{
- int i;
- uint32_t v = 0;
-
- if (src_bytes > 4)
- src_bytes = 4;
- for (i = 0; i < src_bytes; i++)
- v |= ((uint32_t) src[i]) << ((3-i) * 8);
- return v;
-}
-
-static void
-unpack_aux(uint32_t src, uint8_t *dst, int dst_bytes)
-{
- int i;
- if (dst_bytes > 4)
- dst_bytes = 4;
- for (i = 0; i < dst_bytes; i++)
- dst[i] = src >> ((3-i) * 8);
-}
-
-static int
-cdv_intel_dp_aux_ch(struct psb_intel_encoder *encoder,
- uint8_t *send, int send_bytes,
- uint8_t *recv, int recv_size)
-{
- struct cdv_intel_dp *intel_dp = encoder->dev_priv;
- uint32_t output_reg = intel_dp->output_reg;
- struct drm_device *dev = encoder->base.dev;
- uint32_t ch_ctl = output_reg + 0x10;
- uint32_t ch_data = ch_ctl + 4;
- int i;
- int recv_bytes;
- uint32_t status;
- uint32_t aux_clock_divider;
- int try, precharge;
-
- /* The clock divider is based off the hrawclk,
- * and would like to run at 2MHz. So, take the
- * hrawclk value and divide by 2 and use that
- * On CDV platform it uses 200MHz as hrawclk.
- *
- */
- aux_clock_divider = 200 / 2;
-
- precharge = 4;
- if (is_edp(encoder))
- precharge = 10;
-
- if (REG_READ(ch_ctl) & DP_AUX_CH_CTL_SEND_BUSY) {
- DRM_ERROR("dp_aux_ch not started status 0x%08x\n",
- REG_READ(ch_ctl));
- return -EBUSY;
- }
-
- /* Must try at least 3 times according to DP spec */
- for (try = 0; try < 5; try++) {
- /* Load the send data into the aux channel data registers */
- for (i = 0; i < send_bytes; i += 4)
- REG_WRITE(ch_data + i,
- pack_aux(send + i, send_bytes - i));
-
- /* Send the command and wait for it to complete */
- REG_WRITE(ch_ctl,
- DP_AUX_CH_CTL_SEND_BUSY |
- DP_AUX_CH_CTL_TIME_OUT_400us |
- (send_bytes << DP_AUX_CH_CTL_MESSAGE_SIZE_SHIFT) |
- (precharge << DP_AUX_CH_CTL_PRECHARGE_2US_SHIFT) |
- (aux_clock_divider << DP_AUX_CH_CTL_BIT_CLOCK_2X_SHIFT) |
- DP_AUX_CH_CTL_DONE |
- DP_AUX_CH_CTL_TIME_OUT_ERROR |
- DP_AUX_CH_CTL_RECEIVE_ERROR);
- for (;;) {
- status = REG_READ(ch_ctl);
- if ((status & DP_AUX_CH_CTL_SEND_BUSY) == 0)
- break;
- udelay(100);
- }
-
- /* Clear done status and any errors */
- REG_WRITE(ch_ctl,
- status |
- DP_AUX_CH_CTL_DONE |
- DP_AUX_CH_CTL_TIME_OUT_ERROR |
- DP_AUX_CH_CTL_RECEIVE_ERROR);
- if (status & DP_AUX_CH_CTL_DONE)
- break;
- }
-
- if ((status & DP_AUX_CH_CTL_DONE) == 0) {
- DRM_ERROR("dp_aux_ch not done status 0x%08x\n", status);
- return -EBUSY;
- }
-
- /* Check for timeout or receive error.
- * Timeouts occur when the sink is not connected
- */
- if (status & DP_AUX_CH_CTL_RECEIVE_ERROR) {
- DRM_ERROR("dp_aux_ch receive error status 0x%08x\n", status);
- return -EIO;
- }
-
- /* 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;
- }
-
- /* Unload any bytes sent back from the other side */
- recv_bytes = ((status & DP_AUX_CH_CTL_MESSAGE_SIZE_MASK) >>
- DP_AUX_CH_CTL_MESSAGE_SIZE_SHIFT);
- if (recv_bytes > recv_size)
- recv_bytes = recv_size;
-
- for (i = 0; i < recv_bytes; i += 4)
- unpack_aux(REG_READ(ch_data + i),
- recv + i, recv_bytes - i);
-
- return recv_bytes;
-}
-
-/* Write data to the aux channel in native mode */
-static int
-cdv_intel_dp_aux_native_write(struct psb_intel_encoder *encoder,
- uint16_t address, uint8_t *send, int send_bytes)
-{
- int ret;
- uint8_t msg[20];
- int msg_bytes;
- uint8_t ack;
-
- if (send_bytes > 16)
- return -1;
- msg[0] = AUX_NATIVE_WRITE << 4;
- msg[1] = address >> 8;
- msg[2] = address & 0xff;
- msg[3] = send_bytes - 1;
- memcpy(&msg[4], send, send_bytes);
- msg_bytes = send_bytes + 4;
- for (;;) {
- ret = cdv_intel_dp_aux_ch(encoder, msg, msg_bytes, &ack, 1);
- if (ret < 0)
- return ret;
- if ((ack & AUX_NATIVE_REPLY_MASK) == AUX_NATIVE_REPLY_ACK)
- break;
- else if ((ack & AUX_NATIVE_REPLY_MASK) == AUX_NATIVE_REPLY_DEFER)
- udelay(100);
- else
- return -EIO;
- }
- return send_bytes;
-}
-
-/* Write a single byte to the aux channel in native mode */
-static int
-cdv_intel_dp_aux_native_write_1(struct psb_intel_encoder *encoder,
- uint16_t address, uint8_t byte)
-{
- return cdv_intel_dp_aux_native_write(encoder, address, &byte, 1);
-}
-
-/* read bytes from a native aux channel */
-static int
-cdv_intel_dp_aux_native_read(struct psb_intel_encoder *encoder,
- uint16_t address, uint8_t *recv, int recv_bytes)
-{
- uint8_t msg[4];
- int msg_bytes;
- uint8_t reply[20];
- int reply_bytes;
- uint8_t ack;
- int ret;
-
- msg[0] = AUX_NATIVE_READ << 4;
- msg[1] = address >> 8;
- msg[2] = address & 0xff;
- msg[3] = recv_bytes - 1;
-
- msg_bytes = 4;
- reply_bytes = recv_bytes + 1;
-
- for (;;) {
- ret = cdv_intel_dp_aux_ch(encoder, msg, msg_bytes,
- reply, reply_bytes);
- if (ret == 0)
- return -EPROTO;
- if (ret < 0)
- return ret;
- ack = reply[0];
- if ((ack & AUX_NATIVE_REPLY_MASK) == AUX_NATIVE_REPLY_ACK) {
- memcpy(recv, reply + 1, ret - 1);
- return ret - 1;
- }
- else if ((ack & AUX_NATIVE_REPLY_MASK) == AUX_NATIVE_REPLY_DEFER)
- udelay(100);
- else
- return -EIO;
- }
-}
-
-static int
-cdv_intel_dp_i2c_aux_ch(struct i2c_adapter *adapter, int mode,
- uint8_t write_byte, uint8_t *read_byte)
-{
- struct i2c_algo_dp_aux_data *algo_data = adapter->algo_data;
- struct cdv_intel_dp *intel_dp = container_of(adapter,
- struct cdv_intel_dp,
- adapter);
- struct psb_intel_encoder *encoder = intel_dp->encoder;
- uint16_t address = algo_data->address;
- uint8_t msg[5];
- uint8_t reply[2];
- unsigned retry;
- int msg_bytes;
- int reply_bytes;
- int ret;
-
- /* Set up the command byte */
- if (mode & MODE_I2C_READ)
- msg[0] = AUX_I2C_READ << 4;
- else
- msg[0] = AUX_I2C_WRITE << 4;
-
- if (!(mode & MODE_I2C_STOP))
- msg[0] |= AUX_I2C_MOT << 4;
-
- msg[1] = address >> 8;
- msg[2] = address;
-
- switch (mode) {
- case MODE_I2C_WRITE:
- msg[3] = 0;
- msg[4] = write_byte;
- msg_bytes = 5;
- reply_bytes = 1;
- break;
- case MODE_I2C_READ:
- msg[3] = 0;
- msg_bytes = 4;
- reply_bytes = 2;
- break;
- default:
- msg_bytes = 3;
- reply_bytes = 1;
- break;
- }
-
- for (retry = 0; retry < 5; retry++) {
- ret = cdv_intel_dp_aux_ch(encoder,
- msg, msg_bytes,
- reply, reply_bytes);
- if (ret < 0) {
- DRM_DEBUG_KMS("aux_ch failed %d\n", ret);
- return ret;
- }
-
- switch (reply[0] & AUX_NATIVE_REPLY_MASK) {
- case AUX_NATIVE_REPLY_ACK:
- /* I2C-over-AUX Reply field is only valid
- * when paired with AUX ACK.
- */
- break;
- case AUX_NATIVE_REPLY_NACK:
- DRM_DEBUG_KMS("aux_ch native nack\n");
- return -EREMOTEIO;
- case AUX_NATIVE_REPLY_DEFER:
- udelay(100);
- continue;
- default:
- DRM_ERROR("aux_ch invalid native reply 0x%02x\n",
- reply[0]);
- return -EREMOTEIO;
- }
-
- switch (reply[0] & AUX_I2C_REPLY_MASK) {
- case AUX_I2C_REPLY_ACK:
- if (mode == MODE_I2C_READ) {
- *read_byte = reply[1];
- }
- return reply_bytes - 1;
- case AUX_I2C_REPLY_NACK:
- DRM_DEBUG_KMS("aux_i2c nack\n");
- return -EREMOTEIO;
- case AUX_I2C_REPLY_DEFER:
- DRM_DEBUG_KMS("aux_i2c defer\n");
- udelay(100);
- break;
- default:
- DRM_ERROR("aux_i2c invalid reply 0x%02x\n", reply[0]);
- return -EREMOTEIO;
- }
- }
-
- DRM_ERROR("too many retries, giving up\n");
- return -EREMOTEIO;
-}
-
-static int
-cdv_intel_dp_i2c_init(struct psb_intel_connector *connector, struct psb_intel_encoder *encoder, const char *name)
-{
- struct cdv_intel_dp *intel_dp = encoder->dev_priv;
- int ret;
-
- DRM_DEBUG_KMS("i2c_init %s\n", name);
-
- intel_dp->algo.running = false;
- intel_dp->algo.address = 0;
- intel_dp->algo.aux_ch = cdv_intel_dp_i2c_aux_ch;
-
- memset(&intel_dp->adapter, '\0', sizeof (intel_dp->adapter));
- intel_dp->adapter.owner = THIS_MODULE;
- intel_dp->adapter.class = I2C_CLASS_DDC;
- strncpy (intel_dp->adapter.name, name, sizeof(intel_dp->adapter.name) - 1);
- intel_dp->adapter.name[sizeof(intel_dp->adapter.name) - 1] = '\0';
- intel_dp->adapter.algo_data = &intel_dp->algo;
- intel_dp->adapter.dev.parent = &connector->base.kdev;
-
- if (is_edp(encoder))
- cdv_intel_edp_panel_vdd_on(encoder);
- ret = i2c_dp_aux_add_bus(&intel_dp->adapter);
- if (is_edp(encoder))
- cdv_intel_edp_panel_vdd_off(encoder);
-
- return ret;
-}
-
-void cdv_intel_fixed_panel_mode(struct drm_display_mode *fixed_mode,
- struct drm_display_mode *adjusted_mode)
-{
- adjusted_mode->hdisplay = fixed_mode->hdisplay;
- adjusted_mode->hsync_start = fixed_mode->hsync_start;
- adjusted_mode->hsync_end = fixed_mode->hsync_end;
- adjusted_mode->htotal = fixed_mode->htotal;
-
- adjusted_mode->vdisplay = fixed_mode->vdisplay;
- adjusted_mode->vsync_start = fixed_mode->vsync_start;
- adjusted_mode->vsync_end = fixed_mode->vsync_end;
- adjusted_mode->vtotal = fixed_mode->vtotal;
-
- adjusted_mode->clock = fixed_mode->clock;
-
- drm_mode_set_crtcinfo(adjusted_mode, CRTC_INTERLACE_HALVE_V);
-}
-
-static bool
-cdv_intel_dp_mode_fixup(struct drm_encoder *encoder, const struct drm_display_mode *mode,
- struct drm_display_mode *adjusted_mode)
-{
- struct drm_psb_private *dev_priv = encoder->dev->dev_private;
- struct psb_intel_encoder *intel_encoder = to_psb_intel_encoder(encoder);
- struct cdv_intel_dp *intel_dp = intel_encoder->dev_priv;
- int lane_count, clock;
- int max_lane_count = cdv_intel_dp_max_lane_count(intel_encoder);
- int max_clock = cdv_intel_dp_max_link_bw(intel_encoder) == DP_LINK_BW_2_7 ? 1 : 0;
- static int bws[2] = { DP_LINK_BW_1_62, DP_LINK_BW_2_7 };
- int refclock = mode->clock;
- int bpp = 24;
-
- if (is_edp(intel_encoder) && intel_dp->panel_fixed_mode) {
- cdv_intel_fixed_panel_mode(intel_dp->panel_fixed_mode, adjusted_mode);
- refclock = intel_dp->panel_fixed_mode->clock;
- bpp = dev_priv->edp.bpp;
- }
-
- for (lane_count = 1; lane_count <= max_lane_count; lane_count <<= 1) {
- for (clock = max_clock; clock >= 0; clock--) {
- int link_avail = cdv_intel_dp_max_data_rate(cdv_intel_dp_link_clock(bws[clock]), lane_count);
-
- if (cdv_intel_dp_link_required(refclock, bpp) <= link_avail) {
- intel_dp->link_bw = bws[clock];
- intel_dp->lane_count = lane_count;
- adjusted_mode->clock = cdv_intel_dp_link_clock(intel_dp->link_bw);
- DRM_DEBUG_KMS("Display port link bw %02x lane "
- "count %d clock %d\n",
- intel_dp->link_bw, intel_dp->lane_count,
- adjusted_mode->clock);
- return true;
- }
- }
- }
- if (is_edp(intel_encoder)) {
- /* okay we failed just pick the highest */
- intel_dp->lane_count = max_lane_count;
- intel_dp->link_bw = bws[max_clock];
- adjusted_mode->clock = cdv_intel_dp_link_clock(intel_dp->link_bw);
- DRM_DEBUG_KMS("Force picking display port link bw %02x lane "
- "count %d clock %d\n",
- intel_dp->link_bw, intel_dp->lane_count,
- adjusted_mode->clock);
-
- return true;
- }
- return false;
-}
-
-struct cdv_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
-cdv_intel_reduce_ratio(uint32_t *num, uint32_t *den)
-{
- /*
- while (*num > 0xffffff || *den > 0xffffff) {
- *num >>= 1;
- *den >>= 1;
- }*/
- uint64_t value, m;
- m = *num;
- value = m * (0x800000);
- m = do_div(value, *den);
- *num = value;
- *den = 0x800000;
-}
-
-static void
-cdv_intel_dp_compute_m_n(int bpp,
- int nlanes,
- int pixel_clock,
- int link_clock,
- struct cdv_intel_dp_m_n *m_n)
-{
- m_n->tu = 64;
- m_n->gmch_m = (pixel_clock * bpp + 7) >> 3;
- m_n->gmch_n = link_clock * nlanes;
- cdv_intel_reduce_ratio(&m_n->gmch_m, &m_n->gmch_n);
- m_n->link_m = pixel_clock;
- m_n->link_n = link_clock;
- cdv_intel_reduce_ratio(&m_n->link_m, &m_n->link_n);
-}
-
-void
-cdv_intel_dp_set_m_n(struct drm_crtc *crtc, struct drm_display_mode *mode,
- struct drm_display_mode *adjusted_mode)
-{
- struct drm_device *dev = crtc->dev;
- struct drm_psb_private *dev_priv = dev->dev_private;
- struct drm_mode_config *mode_config = &dev->mode_config;
- struct drm_encoder *encoder;
- struct psb_intel_crtc *intel_crtc = to_psb_intel_crtc(crtc);
- int lane_count = 4, bpp = 24;
- struct cdv_intel_dp_m_n m_n;
- int pipe = intel_crtc->pipe;
-
- /*
- * Find the lane count in the intel_encoder private
- */
- list_for_each_entry(encoder, &mode_config->encoder_list, head) {
- struct psb_intel_encoder *intel_encoder;
- struct cdv_intel_dp *intel_dp;
-
- if (encoder->crtc != crtc)
- continue;
-
- intel_encoder = to_psb_intel_encoder(encoder);
- intel_dp = intel_encoder->dev_priv;
- if (intel_encoder->type == INTEL_OUTPUT_DISPLAYPORT) {
- lane_count = intel_dp->lane_count;
- break;
- } else if (is_edp(intel_encoder)) {
- lane_count = intel_dp->lane_count;
- bpp = dev_priv->edp.bpp;
- 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.
- */
- cdv_intel_dp_compute_m_n(bpp, lane_count,
- mode->clock, adjusted_mode->clock, &m_n);
-
- {
- REG_WRITE(PIPE_GMCH_DATA_M(pipe),
- ((m_n.tu - 1) << PIPE_GMCH_DATA_M_TU_SIZE_SHIFT) |
- m_n.gmch_m);
- REG_WRITE(PIPE_GMCH_DATA_N(pipe), m_n.gmch_n);
- REG_WRITE(PIPE_DP_LINK_M(pipe), m_n.link_m);
- REG_WRITE(PIPE_DP_LINK_N(pipe), m_n.link_n);
- }
-}
-
-static void
-cdv_intel_dp_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode,
- struct drm_display_mode *adjusted_mode)
-{
- struct psb_intel_encoder *intel_encoder = to_psb_intel_encoder(encoder);
- struct drm_crtc *crtc = encoder->crtc;
- struct psb_intel_crtc *intel_crtc = to_psb_intel_crtc(crtc);
- struct cdv_intel_dp *intel_dp = intel_encoder->dev_priv;
- struct drm_device *dev = encoder->dev;
-
- intel_dp->DP = DP_VOLTAGE_0_4 | DP_PRE_EMPHASIS_0;
- intel_dp->DP |= intel_dp->color_range;
-
- if (adjusted_mode->flags & DRM_MODE_FLAG_PHSYNC)
- intel_dp->DP |= DP_SYNC_HS_HIGH;
- if (adjusted_mode->flags & DRM_MODE_FLAG_PVSYNC)
- intel_dp->DP |= DP_SYNC_VS_HIGH;
-
- intel_dp->DP |= DP_LINK_TRAIN_OFF;
-
- switch (intel_dp->lane_count) {
- case 1:
- intel_dp->DP |= DP_PORT_WIDTH_1;
- break;
- case 2:
- intel_dp->DP |= DP_PORT_WIDTH_2;
- break;
- case 4:
- intel_dp->DP |= DP_PORT_WIDTH_4;
- break;
- }
- if (intel_dp->has_audio)
- intel_dp->DP |= DP_AUDIO_OUTPUT_ENABLE;
-
- memset(intel_dp->link_configuration, 0, DP_LINK_CONFIGURATION_SIZE);
- intel_dp->link_configuration[0] = intel_dp->link_bw;
- intel_dp->link_configuration[1] = intel_dp->lane_count;
-
- /*
- * Check for DPCD version > 1.1 and enhanced framing support
- */
- if (intel_dp->dpcd[DP_DPCD_REV] >= 0x11 &&
- (intel_dp->dpcd[DP_MAX_LANE_COUNT] & DP_ENHANCED_FRAME_CAP)) {
- intel_dp->link_configuration[1] |= DP_LANE_COUNT_ENHANCED_FRAME_EN;
- intel_dp->DP |= DP_ENHANCED_FRAMING;
- }
-
- /* CPT DP's pipe select is decided in TRANS_DP_CTL */
- if (intel_crtc->pipe == 1)
- intel_dp->DP |= DP_PIPEB_SELECT;
-
- REG_WRITE(intel_dp->output_reg, (intel_dp->DP | DP_PORT_EN));
- DRM_DEBUG_KMS("DP expected reg is %x\n", intel_dp->DP);
- if (is_edp(intel_encoder)) {
- uint32_t pfit_control;
- cdv_intel_edp_panel_on(intel_encoder);
-
- if (mode->hdisplay != adjusted_mode->hdisplay ||
- mode->vdisplay != adjusted_mode->vdisplay)
- pfit_control = PFIT_ENABLE;
- else
- pfit_control = 0;
-
- pfit_control |= intel_crtc->pipe << PFIT_PIPE_SHIFT;
-
- REG_WRITE(PFIT_CONTROL, pfit_control);
- }
-}
-
-
-/* If the sink supports it, try to set the power state appropriately */
-static void cdv_intel_dp_sink_dpms(struct psb_intel_encoder *encoder, int mode)
-{
- struct cdv_intel_dp *intel_dp = encoder->dev_priv;
- int ret, i;
-
- /* Should have a valid DPCD by this point */
- if (intel_dp->dpcd[DP_DPCD_REV] < 0x11)
- return;
-
- if (mode != DRM_MODE_DPMS_ON) {
- ret = cdv_intel_dp_aux_native_write_1(encoder, DP_SET_POWER,
- DP_SET_POWER_D3);
- if (ret != 1)
- DRM_DEBUG_DRIVER("failed to write sink power state\n");
- } else {
- /*
- * When turning on, we need to retry for 1ms to give the sink
- * time to wake up.
- */
- for (i = 0; i < 3; i++) {
- ret = cdv_intel_dp_aux_native_write_1(encoder,
- DP_SET_POWER,
- DP_SET_POWER_D0);
- if (ret == 1)
- break;
- udelay(1000);
- }
- }
-}
-
-static void cdv_intel_dp_prepare(struct drm_encoder *encoder)
-{
- struct psb_intel_encoder *intel_encoder = to_psb_intel_encoder(encoder);
- int edp = is_edp(intel_encoder);
-
- if (edp) {
- cdv_intel_edp_backlight_off(intel_encoder);
- cdv_intel_edp_panel_off(intel_encoder);
- cdv_intel_edp_panel_vdd_on(intel_encoder);
- }
- /* Wake up the sink first */
- cdv_intel_dp_sink_dpms(intel_encoder, DRM_MODE_DPMS_ON);
- cdv_intel_dp_link_down(intel_encoder);
- if (edp)
- cdv_intel_edp_panel_vdd_off(intel_encoder);
-}
-
-static void cdv_intel_dp_commit(struct drm_encoder *encoder)
-{
- struct psb_intel_encoder *intel_encoder = to_psb_intel_encoder(encoder);
- int edp = is_edp(intel_encoder);
-
- if (edp)
- cdv_intel_edp_panel_on(intel_encoder);
- cdv_intel_dp_start_link_train(intel_encoder);
- cdv_intel_dp_complete_link_train(intel_encoder);
- if (edp)
- cdv_intel_edp_backlight_on(intel_encoder);
-}
-
-static void
-cdv_intel_dp_dpms(struct drm_encoder *encoder, int mode)
-{
- struct psb_intel_encoder *intel_encoder = to_psb_intel_encoder(encoder);
- struct cdv_intel_dp *intel_dp = intel_encoder->dev_priv;
- struct drm_device *dev = encoder->dev;
- uint32_t dp_reg = REG_READ(intel_dp->output_reg);
- int edp = is_edp(intel_encoder);
-
- if (mode != DRM_MODE_DPMS_ON) {
- if (edp) {
- cdv_intel_edp_backlight_off(intel_encoder);
- cdv_intel_edp_panel_vdd_on(intel_encoder);
- }
- cdv_intel_dp_sink_dpms(intel_encoder, mode);
- cdv_intel_dp_link_down(intel_encoder);
- if (edp) {
- cdv_intel_edp_panel_vdd_off(intel_encoder);
- cdv_intel_edp_panel_off(intel_encoder);
- }
- } else {
- if (edp)
- cdv_intel_edp_panel_on(intel_encoder);
- cdv_intel_dp_sink_dpms(intel_encoder, mode);
- if (!(dp_reg & DP_PORT_EN)) {
- cdv_intel_dp_start_link_train(intel_encoder);
- cdv_intel_dp_complete_link_train(intel_encoder);
- }
- if (edp)
- cdv_intel_edp_backlight_on(intel_encoder);
- }
-}
-
-/*
- * Native read with retry for link status and receiver capability reads for
- * cases where the sink may still be asleep.
- */
-static bool
-cdv_intel_dp_aux_native_read_retry(struct psb_intel_encoder *encoder, uint16_t address,
- uint8_t *recv, int recv_bytes)
-{
- int ret, i;
-
- /*
- * Sinks are *supposed* to come up within 1ms from an off state,
- * but we're also supposed to retry 3 times per the spec.
- */
- for (i = 0; i < 3; i++) {
- ret = cdv_intel_dp_aux_native_read(encoder, address, recv,
- recv_bytes);
- if (ret == recv_bytes)
- return true;
- udelay(1000);
- }
-
- return false;
-}
-
-/*
- * Fetch AUX CH registers 0x202 - 0x207 which contain
- * link status information
- */
-static bool
-cdv_intel_dp_get_link_status(struct psb_intel_encoder *encoder)
-{
- struct cdv_intel_dp *intel_dp = encoder->dev_priv;
- return cdv_intel_dp_aux_native_read_retry(encoder,
- DP_LANE0_1_STATUS,
- intel_dp->link_status,
- DP_LINK_STATUS_SIZE);
-}
-
-static uint8_t
-cdv_intel_dp_link_status(uint8_t link_status[DP_LINK_STATUS_SIZE],
- int r)
-{
- return link_status[r - DP_LANE0_1_STATUS];
-}
-
-static uint8_t
-cdv_intel_get_adjust_request_voltage(uint8_t link_status[DP_LINK_STATUS_SIZE],
- int lane)
-{
- int i = DP_ADJUST_REQUEST_LANE0_1 + (lane >> 1);
- int s = ((lane & 1) ?
- DP_ADJUST_VOLTAGE_SWING_LANE1_SHIFT :
- DP_ADJUST_VOLTAGE_SWING_LANE0_SHIFT);
- uint8_t l = cdv_intel_dp_link_status(link_status, i);
-
- return ((l >> s) & 3) << DP_TRAIN_VOLTAGE_SWING_SHIFT;
-}
-
-static uint8_t
-cdv_intel_get_adjust_request_pre_emphasis(uint8_t link_status[DP_LINK_STATUS_SIZE],
- int lane)
-{
- int i = DP_ADJUST_REQUEST_LANE0_1 + (lane >> 1);
- int s = ((lane & 1) ?
- DP_ADJUST_PRE_EMPHASIS_LANE1_SHIFT :
- DP_ADJUST_PRE_EMPHASIS_LANE0_SHIFT);
- uint8_t l = cdv_intel_dp_link_status(link_status, i);
-
- return ((l >> s) & 3) << DP_TRAIN_PRE_EMPHASIS_SHIFT;
-}
-
-
-#if 0
-static char *voltage_names[] = {
- "0.4V", "0.6V", "0.8V", "1.2V"
-};
-static char *pre_emph_names[] = {
- "0dB", "3.5dB", "6dB", "9.5dB"
-};
-static char *link_train_names[] = {
- "pattern 1", "pattern 2", "idle", "off"
-};
-#endif
-
-#define CDV_DP_VOLTAGE_MAX DP_TRAIN_VOLTAGE_SWING_1200
-/*
-static uint8_t
-cdv_intel_dp_pre_emphasis_max(uint8_t voltage_swing)
-{
- switch (voltage_swing & DP_TRAIN_VOLTAGE_SWING_MASK) {
- case DP_TRAIN_VOLTAGE_SWING_400:
- return DP_TRAIN_PRE_EMPHASIS_6;
- case DP_TRAIN_VOLTAGE_SWING_600:
- return DP_TRAIN_PRE_EMPHASIS_6;
- case DP_TRAIN_VOLTAGE_SWING_800:
- return DP_TRAIN_PRE_EMPHASIS_3_5;
- case DP_TRAIN_VOLTAGE_SWING_1200:
- default:
- return DP_TRAIN_PRE_EMPHASIS_0;
- }
-}
-*/
-static void
-cdv_intel_get_adjust_train(struct psb_intel_encoder *encoder)
-{
- struct cdv_intel_dp *intel_dp = encoder->dev_priv;
- uint8_t v = 0;
- uint8_t p = 0;
- int lane;
-
- for (lane = 0; lane < intel_dp->lane_count; lane++) {
- uint8_t this_v = cdv_intel_get_adjust_request_voltage(intel_dp->link_status, lane);
- uint8_t this_p = cdv_intel_get_adjust_request_pre_emphasis(intel_dp->link_status, lane);
-
- if (this_v > v)
- v = this_v;
- if (this_p > p)
- p = this_p;
- }
-
- if (v >= CDV_DP_VOLTAGE_MAX)
- v = CDV_DP_VOLTAGE_MAX | DP_TRAIN_MAX_SWING_REACHED;
-
- if (p == DP_TRAIN_PRE_EMPHASIS_MASK)
- p |= DP_TRAIN_MAX_PRE_EMPHASIS_REACHED;
-
- for (lane = 0; lane < 4; lane++)
- intel_dp->train_set[lane] = v | p;
-}
-
-
-static uint8_t
-cdv_intel_get_lane_status(uint8_t link_status[DP_LINK_STATUS_SIZE],
- int lane)
-{
- int i = DP_LANE0_1_STATUS + (lane >> 1);
- int s = (lane & 1) * 4;
- uint8_t l = cdv_intel_dp_link_status(link_status, i);
-
- return (l >> s) & 0xf;
-}
-
-/* Check for clock recovery is done on all channels */
-static bool
-cdv_intel_clock_recovery_ok(uint8_t link_status[DP_LINK_STATUS_SIZE], int lane_count)
-{
- int lane;
- uint8_t lane_status;
-
- for (lane = 0; lane < lane_count; lane++) {
- lane_status = cdv_intel_get_lane_status(link_status, lane);
- if ((lane_status & DP_LANE_CR_DONE) == 0)
- return false;
- }
- return true;
-}
-
-/* Check to see if channel eq is done on all channels */
-#define CHANNEL_EQ_BITS (DP_LANE_CR_DONE|\
- DP_LANE_CHANNEL_EQ_DONE|\
- DP_LANE_SYMBOL_LOCKED)
-static bool
-cdv_intel_channel_eq_ok(struct psb_intel_encoder *encoder)
-{
- struct cdv_intel_dp *intel_dp = encoder->dev_priv;
- uint8_t lane_align;
- uint8_t lane_status;
- int lane;
-
- lane_align = cdv_intel_dp_link_status(intel_dp->link_status,
- DP_LANE_ALIGN_STATUS_UPDATED);
- if ((lane_align & DP_INTERLANE_ALIGN_DONE) == 0)
- return false;
- for (lane = 0; lane < intel_dp->lane_count; lane++) {
- lane_status = cdv_intel_get_lane_status(intel_dp->link_status, lane);
- if ((lane_status & CHANNEL_EQ_BITS) != CHANNEL_EQ_BITS)
- return false;
- }
- return true;
-}
-
-static bool
-cdv_intel_dp_set_link_train(struct psb_intel_encoder *encoder,
- uint32_t dp_reg_value,
- uint8_t dp_train_pat)
-{
-
- struct drm_device *dev = encoder->base.dev;
- int ret;
- struct cdv_intel_dp *intel_dp = encoder->dev_priv;
-
- REG_WRITE(intel_dp->output_reg, dp_reg_value);
- REG_READ(intel_dp->output_reg);
-
- ret = cdv_intel_dp_aux_native_write_1(encoder,
- DP_TRAINING_PATTERN_SET,
- dp_train_pat);
-
- if (ret != 1) {
- DRM_DEBUG_KMS("Failure in setting link pattern %x\n",
- dp_train_pat);
- return false;
- }
-
- return true;
-}
-
-
-static bool
-cdv_intel_dplink_set_level(struct psb_intel_encoder *encoder,
- uint8_t dp_train_pat)
-{
-
- int ret;
- struct cdv_intel_dp *intel_dp = encoder->dev_priv;
-
- ret = cdv_intel_dp_aux_native_write(encoder,
- DP_TRAINING_LANE0_SET,
- intel_dp->train_set,
- intel_dp->lane_count);
-
- if (ret != intel_dp->lane_count) {
- DRM_DEBUG_KMS("Failure in setting level %d, lane_cnt= %d\n",
- intel_dp->train_set[0], intel_dp->lane_count);
- return false;
- }
- return true;
-}
-
-static void
-cdv_intel_dp_set_vswing_premph(struct psb_intel_encoder *encoder, uint8_t signal_level)
-{
- struct drm_device *dev = encoder->base.dev;
- struct cdv_intel_dp *intel_dp = encoder->dev_priv;
- struct ddi_regoff *ddi_reg;
- int vswing, premph, index;
-
- if (intel_dp->output_reg == DP_B)
- ddi_reg = &ddi_DP_train_table[0];
- else
- ddi_reg = &ddi_DP_train_table[1];
-
- vswing = (signal_level & DP_TRAIN_VOLTAGE_SWING_MASK);
- premph = ((signal_level & DP_TRAIN_PRE_EMPHASIS_MASK)) >>
- DP_TRAIN_PRE_EMPHASIS_SHIFT;
-
- if (vswing + premph > 3)
- return;
-#ifdef CDV_FAST_LINK_TRAIN
- return;
-#endif
- DRM_DEBUG_KMS("Test2\n");
- //return ;
- cdv_sb_reset(dev);
- /* ;Swing voltage programming
- ;gfx_dpio_set_reg(0xc058, 0x0505313A) */
- cdv_sb_write(dev, ddi_reg->VSwing5, 0x0505313A);
-
- /* ;gfx_dpio_set_reg(0x8154, 0x43406055) */
- cdv_sb_write(dev, ddi_reg->VSwing1, 0x43406055);
-
- /* ;gfx_dpio_set_reg(0x8148, 0x55338954)
- * The VSwing_PreEmph table is also considered based on the vswing/premp
- */
- index = (vswing + premph) * 2;
- if (premph == 1 && vswing == 1) {
- cdv_sb_write(dev, ddi_reg->VSwing2, 0x055738954);
- } else
- cdv_sb_write(dev, ddi_reg->VSwing2, dp_vswing_premph_table[index]);
-
- /* ;gfx_dpio_set_reg(0x814c, 0x40802040) */
- if ((vswing + premph) == DP_TRAIN_VOLTAGE_SWING_1200)
- cdv_sb_write(dev, ddi_reg->VSwing3, 0x70802040);
- else
- cdv_sb_write(dev, ddi_reg->VSwing3, 0x40802040);
-
- /* ;gfx_dpio_set_reg(0x8150, 0x2b405555) */
- /* cdv_sb_write(dev, ddi_reg->VSwing4, 0x2b405555); */
-
- /* ;gfx_dpio_set_reg(0x8154, 0xc3406055) */
- cdv_sb_write(dev, ddi_reg->VSwing1, 0xc3406055);
-
- /* ;Pre emphasis programming
- * ;gfx_dpio_set_reg(0xc02c, 0x1f030040)
- */
- cdv_sb_write(dev, ddi_reg->PreEmph1, 0x1f030040);
-
- /* ;gfx_dpio_set_reg(0x8124, 0x00004000) */
- index = 2 * premph + 1;
- cdv_sb_write(dev, ddi_reg->PreEmph2, dp_vswing_premph_table[index]);
- return;
-}
-
-
-/* Enable corresponding port and start training pattern 1 */
-static void
-cdv_intel_dp_start_link_train(struct psb_intel_encoder *encoder)
-{
- struct drm_device *dev = encoder->base.dev;
- struct cdv_intel_dp *intel_dp = encoder->dev_priv;
- int i;
- uint8_t voltage;
- bool clock_recovery = false;
- int tries;
- u32 reg;
- uint32_t DP = intel_dp->DP;
-
- DP |= DP_PORT_EN;
- DP &= ~DP_LINK_TRAIN_MASK;
-
- reg = DP;
- reg |= DP_LINK_TRAIN_PAT_1;
- /* Enable output, wait for it to become active */
- REG_WRITE(intel_dp->output_reg, reg);
- REG_READ(intel_dp->output_reg);
- psb_intel_wait_for_vblank(dev);
-
- DRM_DEBUG_KMS("Link config\n");
- /* Write the link configuration data */
- cdv_intel_dp_aux_native_write(encoder, DP_LINK_BW_SET,
- intel_dp->link_configuration,
- 2);
-
- memset(intel_dp->train_set, 0, 4);
- voltage = 0;
- tries = 0;
- clock_recovery = false;
-
- DRM_DEBUG_KMS("Start train\n");
- reg = DP | DP_LINK_TRAIN_PAT_1;
-
-
- for (;;) {
- /* Use intel_dp->train_set[0] to set the voltage and pre emphasis values */
- DRM_DEBUG_KMS("DP Link Train Set %x, Link_config %x, %x\n",
- intel_dp->train_set[0],
- intel_dp->link_configuration[0],
- intel_dp->link_configuration[1]);
-
- if (!cdv_intel_dp_set_link_train(encoder, reg, DP_TRAINING_PATTERN_1)) {
- DRM_DEBUG_KMS("Failure in aux-transfer setting pattern 1\n");
- }
- cdv_intel_dp_set_vswing_premph(encoder, intel_dp->train_set[0]);
- /* Set training pattern 1 */
-
- cdv_intel_dplink_set_level(encoder, DP_TRAINING_PATTERN_1);
-
- udelay(200);
- if (!cdv_intel_dp_get_link_status(encoder))
- break;
-
- DRM_DEBUG_KMS("DP Link status %x, %x, %x, %x, %x, %x\n",
- intel_dp->link_status[0], intel_dp->link_status[1], intel_dp->link_status[2],
- intel_dp->link_status[3], intel_dp->link_status[4], intel_dp->link_status[5]);
-
- if (cdv_intel_clock_recovery_ok(intel_dp->link_status, intel_dp->lane_count)) {
- DRM_DEBUG_KMS("PT1 train is done\n");
- clock_recovery = true;
- break;
- }
-
- /* Check to see if we've tried the max voltage */
- 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)
- break;
-
- /* Check to see if we've tried the same voltage 5 times */
- if ((intel_dp->train_set[0] & DP_TRAIN_VOLTAGE_SWING_MASK) == voltage) {
- ++tries;
- if (tries == 5)
- break;
- } else
- tries = 0;
- voltage = intel_dp->train_set[0] & DP_TRAIN_VOLTAGE_SWING_MASK;
-
- /* Compute new intel_dp->train_set as requested by target */
- cdv_intel_get_adjust_train(encoder);
-
- }
-
- if (!clock_recovery) {
- DRM_DEBUG_KMS("failure in DP patter 1 training, train set %x\n", intel_dp->train_set[0]);
- }
-
- intel_dp->DP = DP;
-}
-
-static void
-cdv_intel_dp_complete_link_train(struct psb_intel_encoder *encoder)
-{
- struct drm_device *dev = encoder->base.dev;
- struct cdv_intel_dp *intel_dp = encoder->dev_priv;
- bool channel_eq = false;
- int tries, cr_tries;
- u32 reg;
- uint32_t DP = intel_dp->DP;
-
- /* channel equalization */
- tries = 0;
- cr_tries = 0;
- channel_eq = false;
-
- DRM_DEBUG_KMS("\n");
- reg = DP | DP_LINK_TRAIN_PAT_2;
-
- for (;;) {
-
- DRM_DEBUG_KMS("DP Link Train Set %x, Link_config %x, %x\n",
- intel_dp->train_set[0],
- intel_dp->link_configuration[0],
- intel_dp->link_configuration[1]);
- /* channel eq pattern */
-
- if (!cdv_intel_dp_set_link_train(encoder, reg,
- DP_TRAINING_PATTERN_2)) {
- DRM_DEBUG_KMS("Failure in aux-transfer setting pattern 2\n");
- }
- /* Use intel_dp->train_set[0] to set the voltage and pre emphasis values */
-
- if (cr_tries > 5) {
- DRM_ERROR("failed to train DP, aborting\n");
- cdv_intel_dp_link_down(encoder);
- break;
- }
-
- cdv_intel_dp_set_vswing_premph(encoder, intel_dp->train_set[0]);
-
- cdv_intel_dplink_set_level(encoder, DP_TRAINING_PATTERN_2);
-
- udelay(1000);
- if (!cdv_intel_dp_get_link_status(encoder))
- break;
-
- DRM_DEBUG_KMS("DP Link status %x, %x, %x, %x, %x, %x\n",
- intel_dp->link_status[0], intel_dp->link_status[1], intel_dp->link_status[2],
- intel_dp->link_status[3], intel_dp->link_status[4], intel_dp->link_status[5]);
-
- /* Make sure clock is still ok */
- if (!cdv_intel_clock_recovery_ok(intel_dp->link_status, intel_dp->lane_count)) {
- cdv_intel_dp_start_link_train(encoder);
- cr_tries++;
- continue;
- }
-
- if (cdv_intel_channel_eq_ok(encoder)) {
- DRM_DEBUG_KMS("PT2 train is done\n");
- channel_eq = true;
- break;
- }
-
- /* Try 5 times, then try clock recovery if that fails */
- if (tries > 5) {
- cdv_intel_dp_link_down(encoder);
- cdv_intel_dp_start_link_train(encoder);
- tries = 0;
- cr_tries++;
- continue;
- }
-
- /* Compute new intel_dp->train_set as requested by target */
- cdv_intel_get_adjust_train(encoder);
- ++tries;
-
- }
-
- reg = DP | DP_LINK_TRAIN_OFF;
-
- REG_WRITE(intel_dp->output_reg, reg);
- REG_READ(intel_dp->output_reg);
- cdv_intel_dp_aux_native_write_1(encoder,
- DP_TRAINING_PATTERN_SET, DP_TRAINING_PATTERN_DISABLE);
-}
-
-static void
-cdv_intel_dp_link_down(struct psb_intel_encoder *encoder)
-{
- struct drm_device *dev = encoder->base.dev;
- struct cdv_intel_dp *intel_dp = encoder->dev_priv;
- uint32_t DP = intel_dp->DP;
-
- if ((REG_READ(intel_dp->output_reg) & DP_PORT_EN) == 0)
- return;
-
- DRM_DEBUG_KMS("\n");
-
-
- {
- DP &= ~DP_LINK_TRAIN_MASK;
- REG_WRITE(intel_dp->output_reg, DP | DP_LINK_TRAIN_PAT_IDLE);
- }
- REG_READ(intel_dp->output_reg);
-
- msleep(17);
-
- REG_WRITE(intel_dp->output_reg, DP & ~DP_PORT_EN);
- REG_READ(intel_dp->output_reg);
-}
-
-static enum drm_connector_status
-cdv_dp_detect(struct psb_intel_encoder *encoder)
-{
- struct cdv_intel_dp *intel_dp = encoder->dev_priv;
- enum drm_connector_status status;
-
- status = connector_status_disconnected;
- if (cdv_intel_dp_aux_native_read(encoder, 0x000, intel_dp->dpcd,
- sizeof (intel_dp->dpcd)) == sizeof (intel_dp->dpcd))
- {
- if (intel_dp->dpcd[DP_DPCD_REV] != 0)
- status = connector_status_connected;
- }
- if (status == connector_status_connected)
- DRM_DEBUG_KMS("DPCD: Rev=%x LN_Rate=%x LN_CNT=%x LN_DOWNSP=%x\n",
- intel_dp->dpcd[0], intel_dp->dpcd[1],
- intel_dp->dpcd[2], intel_dp->dpcd[3]);
- return status;
-}
-
-/**
- * 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
-cdv_intel_dp_detect(struct drm_connector *connector, bool force)
-{
- struct psb_intel_encoder *encoder = psb_intel_attached_encoder(connector);
- struct cdv_intel_dp *intel_dp = encoder->dev_priv;
- enum drm_connector_status status;
- struct edid *edid = NULL;
- int edp = is_edp(encoder);
-
- intel_dp->has_audio = false;
-
- if (edp)
- cdv_intel_edp_panel_vdd_on(encoder);
- status = cdv_dp_detect(encoder);
- if (status != connector_status_connected) {
- if (edp)
- cdv_intel_edp_panel_vdd_off(encoder);
- return status;
- }
-
- if (intel_dp->force_audio) {
- intel_dp->has_audio = intel_dp->force_audio > 0;
- } else {
- edid = drm_get_edid(connector, &intel_dp->adapter);
- if (edid) {
- intel_dp->has_audio = drm_detect_monitor_audio(edid);
- kfree(edid);
- }
- }
- if (edp)
- cdv_intel_edp_panel_vdd_off(encoder);
-
- return connector_status_connected;
-}
-
-static int cdv_intel_dp_get_modes(struct drm_connector *connector)
-{
- struct psb_intel_encoder *intel_encoder = psb_intel_attached_encoder(connector);
- struct cdv_intel_dp *intel_dp = intel_encoder->dev_priv;
- struct edid *edid = NULL;
- int ret = 0;
- int edp = is_edp(intel_encoder);
-
-
- edid = drm_get_edid(connector, &intel_dp->adapter);
- if (edid) {
- drm_mode_connector_update_edid_property(connector, edid);
- ret = drm_add_edid_modes(connector, edid);
- kfree(edid);
- }
-
- if (is_edp(intel_encoder)) {
- struct drm_device *dev = connector->dev;
- struct drm_psb_private *dev_priv = dev->dev_private;
-
- cdv_intel_edp_panel_vdd_off(intel_encoder);
- if (ret) {
- if (edp && !intel_dp->panel_fixed_mode) {
- struct drm_display_mode *newmode;
- list_for_each_entry(newmode, &connector->probed_modes,
- head) {
- if (newmode->type & DRM_MODE_TYPE_PREFERRED) {
- intel_dp->panel_fixed_mode =
- drm_mode_duplicate(dev, newmode);
- break;
- }
- }
- }
-
- return ret;
- }
- if (!intel_dp->panel_fixed_mode && dev_priv->lfp_lvds_vbt_mode) {
- intel_dp->panel_fixed_mode =
- drm_mode_duplicate(dev, dev_priv->lfp_lvds_vbt_mode);
- if (intel_dp->panel_fixed_mode) {
- intel_dp->panel_fixed_mode->type |=
- DRM_MODE_TYPE_PREFERRED;
- }
- }
- if (intel_dp->panel_fixed_mode != NULL) {
- struct drm_display_mode *mode;
- mode = drm_mode_duplicate(dev, intel_dp->panel_fixed_mode);
- drm_mode_probed_add(connector, mode);
- return 1;
- }
- }
-
- return ret;
-}
-
-static bool
-cdv_intel_dp_detect_audio(struct drm_connector *connector)
-{
- struct psb_intel_encoder *encoder = psb_intel_attached_encoder(connector);
- struct cdv_intel_dp *intel_dp = encoder->dev_priv;
- struct edid *edid;
- bool has_audio = false;
- int edp = is_edp(encoder);
-
- if (edp)
- cdv_intel_edp_panel_vdd_on(encoder);
-
- edid = drm_get_edid(connector, &intel_dp->adapter);
- if (edid) {
- has_audio = drm_detect_monitor_audio(edid);
- kfree(edid);
- }
- if (edp)
- cdv_intel_edp_panel_vdd_off(encoder);
-
- return has_audio;
-}
-
-static int
-cdv_intel_dp_set_property(struct drm_connector *connector,
- struct drm_property *property,
- uint64_t val)
-{
- struct drm_psb_private *dev_priv = connector->dev->dev_private;
- struct psb_intel_encoder *encoder = psb_intel_attached_encoder(connector);
- struct cdv_intel_dp *intel_dp = encoder->dev_priv;
- int ret;
-
- ret = drm_connector_property_set_value(connector, property, val);
- if (ret)
- return ret;
-
- if (property == dev_priv->force_audio_property) {
- int i = val;
- bool has_audio;
-
- if (i == intel_dp->force_audio)
- return 0;
-
- intel_dp->force_audio = i;
-
- if (i == 0)
- has_audio = cdv_intel_dp_detect_audio(connector);
- else
- has_audio = i > 0;
-
- if (has_audio == intel_dp->has_audio)
- return 0;
-
- intel_dp->has_audio = has_audio;
- goto done;
- }
-
- 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;
- goto done;
- }
-
- return -EINVAL;
-
-done:
- if (encoder->base.crtc) {
- struct drm_crtc *crtc = encoder->base.crtc;
- drm_crtc_helper_set_mode(crtc, &crtc->mode,
- crtc->x, crtc->y,
- crtc->fb);
- }
-
- return 0;
-}
-
-static void
-cdv_intel_dp_destroy(struct drm_connector *connector)
-{
- struct psb_intel_encoder *psb_intel_encoder =
- psb_intel_attached_encoder(connector);
- struct cdv_intel_dp *intel_dp = psb_intel_encoder->dev_priv;
-
- if (is_edp(psb_intel_encoder)) {
- /* cdv_intel_panel_destroy_backlight(connector->dev); */
- if (intel_dp->panel_fixed_mode) {
- kfree(intel_dp->panel_fixed_mode);
- intel_dp->panel_fixed_mode = NULL;
- }
- }
- i2c_del_adapter(&intel_dp->adapter);
- drm_sysfs_connector_remove(connector);
- drm_connector_cleanup(connector);
- kfree(connector);
-}
-
-static void cdv_intel_dp_encoder_destroy(struct drm_encoder *encoder)
-{
- drm_encoder_cleanup(encoder);
-}
-
-static const struct drm_encoder_helper_funcs cdv_intel_dp_helper_funcs = {
- .dpms = cdv_intel_dp_dpms,
- .mode_fixup = cdv_intel_dp_mode_fixup,
- .prepare = cdv_intel_dp_prepare,
- .mode_set = cdv_intel_dp_mode_set,
- .commit = cdv_intel_dp_commit,
-};
-
-static const struct drm_connector_funcs cdv_intel_dp_connector_funcs = {
- .dpms = drm_helper_connector_dpms,
- .detect = cdv_intel_dp_detect,
- .fill_modes = drm_helper_probe_single_connector_modes,
- .set_property = cdv_intel_dp_set_property,
- .destroy = cdv_intel_dp_destroy,
-};
-
-static const struct drm_connector_helper_funcs cdv_intel_dp_connector_helper_funcs = {
- .get_modes = cdv_intel_dp_get_modes,
- .mode_valid = cdv_intel_dp_mode_valid,
- .best_encoder = psb_intel_best_encoder,
-};
-
-static const struct drm_encoder_funcs cdv_intel_dp_enc_funcs = {
- .destroy = cdv_intel_dp_encoder_destroy,
-};
-
-
-static void cdv_intel_dp_add_properties(struct drm_connector *connector)
-{
- cdv_intel_attach_force_audio_property(connector);
- cdv_intel_attach_broadcast_rgb_property(connector);
-}
-
-/* check the VBT to see whether the eDP is on DP-D port */
-static bool cdv_intel_dpc_is_edp(struct drm_device *dev)
-{
- struct drm_psb_private *dev_priv = dev->dev_private;
- struct child_device_config *p_child;
- int i;
-
- if (!dev_priv->child_dev_num)
- return false;
-
- for (i = 0; i < dev_priv->child_dev_num; i++) {
- p_child = dev_priv->child_dev + i;
-
- if (p_child->dvo_port == PORT_IDPC &&
- p_child->device_type == DEVICE_TYPE_eDP)
- return true;
- }
- return false;
-}
-
-/* Cedarview display clock gating
-
- We need this disable dot get correct behaviour while enabling
- DP/eDP. TODO - investigate if we can turn it back to normality
- after enabling */
-static void cdv_disable_intel_clock_gating(struct drm_device *dev)
-{
- u32 reg_value;
- reg_value = REG_READ(DSPCLK_GATE_D);
-
- reg_value |= (DPUNIT_PIPEB_GATE_DISABLE |
- DPUNIT_PIPEA_GATE_DISABLE |
- DPCUNIT_CLOCK_GATE_DISABLE |
- DPLSUNIT_CLOCK_GATE_DISABLE |
- DPOUNIT_CLOCK_GATE_DISABLE |
- DPIOUNIT_CLOCK_GATE_DISABLE);
-
- REG_WRITE(DSPCLK_GATE_D, reg_value);
-
- udelay(500);
-}
-
-void
-cdv_intel_dp_init(struct drm_device *dev, struct psb_intel_mode_device *mode_dev, int output_reg)
-{
- struct psb_intel_encoder *psb_intel_encoder;
- struct psb_intel_connector *psb_intel_connector;
- struct drm_connector *connector;
- struct drm_encoder *encoder;
- struct cdv_intel_dp *intel_dp;
- const char *name = NULL;
- int type = DRM_MODE_CONNECTOR_DisplayPort;
-
- psb_intel_encoder = kzalloc(sizeof(struct psb_intel_encoder), GFP_KERNEL);
- if (!psb_intel_encoder)
- return;
- psb_intel_connector = kzalloc(sizeof(struct psb_intel_connector), GFP_KERNEL);
- if (!psb_intel_connector)
- goto err_connector;
- intel_dp = kzalloc(sizeof(struct cdv_intel_dp), GFP_KERNEL);
- if (!intel_dp)
- goto err_priv;
-
- if ((output_reg == DP_C) && cdv_intel_dpc_is_edp(dev))
- type = DRM_MODE_CONNECTOR_eDP;
-
- connector = &psb_intel_connector->base;
- encoder = &psb_intel_encoder->base;
-
- drm_connector_init(dev, connector, &cdv_intel_dp_connector_funcs, type);
- drm_encoder_init(dev, encoder, &cdv_intel_dp_enc_funcs, DRM_MODE_ENCODER_TMDS);
-
- psb_intel_connector_attach_encoder(psb_intel_connector, psb_intel_encoder);
-
- if (type == DRM_MODE_CONNECTOR_DisplayPort)
- psb_intel_encoder->type = INTEL_OUTPUT_DISPLAYPORT;
- else
- psb_intel_encoder->type = INTEL_OUTPUT_EDP;
-
-
- psb_intel_encoder->dev_priv=intel_dp;
- intel_dp->encoder = psb_intel_encoder;
- intel_dp->output_reg = output_reg;
-
- drm_encoder_helper_add(encoder, &cdv_intel_dp_helper_funcs);
- drm_connector_helper_add(connector, &cdv_intel_dp_connector_helper_funcs);
-
- connector->polled = DRM_CONNECTOR_POLL_HPD;
- connector->interlace_allowed = false;
- connector->doublescan_allowed = false;
-
- drm_sysfs_connector_add(connector);
-
- /* Set up the DDC bus. */
- switch (output_reg) {
- case DP_B:
- name = "DPDDC-B";
- psb_intel_encoder->ddi_select = (DP_MASK | DDI0_SELECT);
- break;
- case DP_C:
- name = "DPDDC-C";
- psb_intel_encoder->ddi_select = (DP_MASK | DDI1_SELECT);
- break;
- }
-
- cdv_disable_intel_clock_gating(dev);
-
- cdv_intel_dp_i2c_init(psb_intel_connector, psb_intel_encoder, name);
- /* FIXME:fail check */
- cdv_intel_dp_add_properties(connector);
-
- if (is_edp(psb_intel_encoder)) {
- int ret;
- struct edp_power_seq cur;
- u32 pp_on, pp_off, pp_div;
- u32 pwm_ctrl;
-
- pp_on = REG_READ(PP_CONTROL);
- pp_on &= ~PANEL_UNLOCK_MASK;
- pp_on |= PANEL_UNLOCK_REGS;
-
- REG_WRITE(PP_CONTROL, pp_on);
-
- pwm_ctrl = REG_READ(BLC_PWM_CTL2);
- pwm_ctrl |= PWM_PIPE_B;
- REG_WRITE(BLC_PWM_CTL2, pwm_ctrl);
-
- pp_on = REG_READ(PP_ON_DELAYS);
- pp_off = REG_READ(PP_OFF_DELAYS);
- pp_div = REG_READ(PP_DIVISOR);
-
- /* Pull timing values out of registers */
- cur.t1_t3 = (pp_on & PANEL_POWER_UP_DELAY_MASK) >>
- PANEL_POWER_UP_DELAY_SHIFT;
-
- cur.t8 = (pp_on & PANEL_LIGHT_ON_DELAY_MASK) >>
- PANEL_LIGHT_ON_DELAY_SHIFT;
-
- cur.t9 = (pp_off & PANEL_LIGHT_OFF_DELAY_MASK) >>
- PANEL_LIGHT_OFF_DELAY_SHIFT;
-
- cur.t10 = (pp_off & PANEL_POWER_DOWN_DELAY_MASK) >>
- PANEL_POWER_DOWN_DELAY_SHIFT;
-
- cur.t11_t12 = ((pp_div & PANEL_POWER_CYCLE_DELAY_MASK) >>
- PANEL_POWER_CYCLE_DELAY_SHIFT);
-
- DRM_DEBUG_KMS("cur t1_t3 %d t8 %d t9 %d t10 %d t11_t12 %d\n",
- cur.t1_t3, cur.t8, cur.t9, cur.t10, cur.t11_t12);
-
-
- intel_dp->panel_power_up_delay = cur.t1_t3 / 10;
- intel_dp->backlight_on_delay = cur.t8 / 10;
- intel_dp->backlight_off_delay = cur.t9 / 10;
- intel_dp->panel_power_down_delay = cur.t10 / 10;
- intel_dp->panel_power_cycle_delay = (cur.t11_t12 - 1) * 100;
-
- DRM_DEBUG_KMS("panel power up delay %d, power down delay %d, power cycle delay %d\n",
- intel_dp->panel_power_up_delay, intel_dp->panel_power_down_delay,
- intel_dp->panel_power_cycle_delay);
-
- DRM_DEBUG_KMS("backlight on delay %d, off delay %d\n",
- intel_dp->backlight_on_delay, intel_dp->backlight_off_delay);
-
-
- cdv_intel_edp_panel_vdd_on(psb_intel_encoder);
- ret = cdv_intel_dp_aux_native_read(psb_intel_encoder, DP_DPCD_REV,
- intel_dp->dpcd,
- sizeof(intel_dp->dpcd));
- cdv_intel_edp_panel_vdd_off(psb_intel_encoder);
- if (ret == 0) {
- /* if this fails, presume the device is a ghost */
- DRM_INFO("failed to retrieve link info, disabling eDP\n");
- cdv_intel_dp_encoder_destroy(encoder);
- cdv_intel_dp_destroy(connector);
- goto err_priv;
- } else {
- DRM_DEBUG_KMS("DPCD: Rev=%x LN_Rate=%x LN_CNT=%x LN_DOWNSP=%x\n",
- intel_dp->dpcd[0], intel_dp->dpcd[1],
- intel_dp->dpcd[2], intel_dp->dpcd[3]);
-
- }
- /* The CDV reference driver moves pnale backlight setup into the displays that
- have a backlight: this is a good idea and one we should probably adopt, however
- we need to migrate all the drivers before we can do that */
- /*cdv_intel_panel_setup_backlight(dev); */
- }
- return;
-
-err_priv:
- kfree(psb_intel_connector);
-err_connector:
- kfree(psb_intel_encoder);
-}
diff --git a/trunk/drivers/gpu/drm/gma500/cdv_intel_hdmi.c b/trunk/drivers/gpu/drm/gma500/cdv_intel_hdmi.c
index 7272a461edfe..a86f87b9ddde 100644
--- a/trunk/drivers/gpu/drm/gma500/cdv_intel_hdmi.c
+++ b/trunk/drivers/gpu/drm/gma500/cdv_intel_hdmi.c
@@ -139,6 +139,8 @@ static enum drm_connector_status cdv_hdmi_detect(
{
struct psb_intel_encoder *psb_intel_encoder =
psb_intel_attached_encoder(connector);
+ struct psb_intel_connector *psb_intel_connector =
+ to_psb_intel_connector(connector);
struct mid_intel_hdmi_priv *hdmi_priv = psb_intel_encoder->dev_priv;
struct edid *edid = NULL;
enum drm_connector_status status = connector_status_disconnected;
@@ -155,6 +157,8 @@ static enum drm_connector_status cdv_hdmi_detect(
hdmi_priv->has_hdmi_audio =
drm_detect_monitor_audio(edid);
}
+
+ psb_intel_connector->base.display_info.raw_edid = NULL;
kfree(edid);
}
return status;
@@ -348,11 +352,9 @@ void cdv_hdmi_init(struct drm_device *dev,
switch (reg) {
case SDVOB:
ddc_bus = GPIOE;
- psb_intel_encoder->ddi_select = DDI0_SELECT;
break;
case SDVOC:
ddc_bus = GPIOD;
- psb_intel_encoder->ddi_select = DDI1_SELECT;
break;
default:
DRM_ERROR("unknown reg 0x%x for HDMI\n", reg);
diff --git a/trunk/drivers/gpu/drm/gma500/cdv_intel_lvds.c b/trunk/drivers/gpu/drm/gma500/cdv_intel_lvds.c
index b362dd39bf5a..c7f9468b74ba 100644
--- a/trunk/drivers/gpu/drm/gma500/cdv_intel_lvds.c
+++ b/trunk/drivers/gpu/drm/gma500/cdv_intel_lvds.c
@@ -506,8 +506,16 @@ static int cdv_intel_lvds_set_property(struct drm_connector *connector,
property,
value))
return -1;
- else
- gma_backlight_set(encoder->dev, value);
+ else {
+#ifdef CONFIG_BACKLIGHT_CLASS_DEVICE
+ struct drm_psb_private *dev_priv =
+ encoder->dev->dev_private;
+ struct backlight_device *bd =
+ dev_priv->backlight_device;
+ bd->props.brightness = value;
+ backlight_update_status(bd);
+#endif
+ }
} else if (!strcmp(property->name, "DPMS") && encoder) {
struct drm_encoder_helper_funcs *helpers =
encoder->helper_private;
diff --git a/trunk/drivers/gpu/drm/gma500/framebuffer.c b/trunk/drivers/gpu/drm/gma500/framebuffer.c
index 884ba73ac6ce..5732b5702e1c 100644
--- a/trunk/drivers/gpu/drm/gma500/framebuffer.c
+++ b/trunk/drivers/gpu/drm/gma500/framebuffer.c
@@ -764,13 +764,6 @@ static void psb_setup_outputs(struct drm_device *dev)
crtc_mask = dev_priv->ops->hdmi_mask;
clone_mask = (1 << INTEL_OUTPUT_HDMI);
break;
- case INTEL_OUTPUT_DISPLAYPORT:
- crtc_mask = (1 << 0) | (1 << 1);
- clone_mask = (1 << INTEL_OUTPUT_DISPLAYPORT);
- break;
- case INTEL_OUTPUT_EDP:
- crtc_mask = (1 << 1);
- clone_mask = (1 << INTEL_OUTPUT_EDP);
}
encoder->possible_crtcs = crtc_mask;
encoder->possible_clones =
diff --git a/trunk/drivers/gpu/drm/gma500/gem.c b/trunk/drivers/gpu/drm/gma500/gem.c
index df20546a2a34..fc7d144bc2d3 100644
--- a/trunk/drivers/gpu/drm/gma500/gem.c
+++ b/trunk/drivers/gpu/drm/gma500/gem.c
@@ -36,12 +36,7 @@ int psb_gem_init_object(struct drm_gem_object *obj)
void psb_gem_free_object(struct drm_gem_object *obj)
{
struct gtt_range *gtt = container_of(obj, struct gtt_range, gem);
-
- /* Remove the list map if one is present */
- if (obj->map_list.map)
- drm_gem_free_mmap_offset(obj);
- drm_gem_object_release(obj);
-
+ drm_gem_object_release_wrap(obj);
/* This must occur last as it frees up the memory of the GEM object */
psb_gtt_free_range(obj->dev, gtt);
}
@@ -82,7 +77,7 @@ int psb_gem_dumb_map_gtt(struct drm_file *file, struct drm_device *dev,
/* Make it mmapable */
if (!obj->map_list.map) {
- ret = drm_gem_create_mmap_offset(obj);
+ ret = gem_create_mmap_offset(obj);
if (ret)
goto out;
}
diff --git a/trunk/drivers/gpu/drm/gma500/gem_glue.c b/trunk/drivers/gpu/drm/gma500/gem_glue.c
new file mode 100644
index 000000000000..3c17634f6061
--- /dev/null
+++ b/trunk/drivers/gpu/drm/gma500/gem_glue.c
@@ -0,0 +1,90 @@
+/**************************************************************************
+ * Copyright (c) 2011, Intel Corporation.
+ * All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ **************************************************************************/
+
+#include
+#include
+#include "gem_glue.h"
+
+void drm_gem_object_release_wrap(struct drm_gem_object *obj)
+{
+ /* Remove the list map if one is present */
+ if (obj->map_list.map) {
+ struct drm_gem_mm *mm = obj->dev->mm_private;
+ struct drm_map_list *list = &obj->map_list;
+ drm_ht_remove_item(&mm->offset_hash, &list->hash);
+ drm_mm_put_block(list->file_offset_node);
+ kfree(list->map);
+ list->map = NULL;
+ }
+ drm_gem_object_release(obj);
+}
+
+/**
+ * gem_create_mmap_offset - invent an mmap offset
+ * @obj: our object
+ *
+ * Standard implementation of offset generation for mmap as is
+ * duplicated in several drivers. This belongs in GEM.
+ */
+int gem_create_mmap_offset(struct drm_gem_object *obj)
+{
+ struct drm_device *dev = obj->dev;
+ struct drm_gem_mm *mm = dev->mm_private;
+ struct drm_map_list *list;
+ struct drm_local_map *map;
+ int ret;
+
+ list = &obj->map_list;
+ list->map = kzalloc(sizeof(struct drm_map_list), GFP_KERNEL);
+ if (list->map == NULL)
+ return -ENOMEM;
+ map = list->map;
+ map->type = _DRM_GEM;
+ map->size = obj->size;
+ map->handle = obj;
+
+ list->file_offset_node = drm_mm_search_free(&mm->offset_manager,
+ obj->size / PAGE_SIZE, 0, 0);
+ if (!list->file_offset_node) {
+ dev_err(dev->dev, "failed to allocate offset for bo %d\n",
+ obj->name);
+ ret = -ENOSPC;
+ goto free_it;
+ }
+ list->file_offset_node = drm_mm_get_block(list->file_offset_node,
+ obj->size / PAGE_SIZE, 0);
+ if (!list->file_offset_node) {
+ ret = -ENOMEM;
+ goto free_it;
+ }
+ list->hash.key = list->file_offset_node->start;
+ ret = drm_ht_insert_item(&mm->offset_hash, &list->hash);
+ if (ret) {
+ dev_err(dev->dev, "failed to add to map hash\n");
+ goto free_mm;
+ }
+ return 0;
+
+free_mm:
+ drm_mm_put_block(list->file_offset_node);
+free_it:
+ kfree(list->map);
+ list->map = NULL;
+ return ret;
+}
diff --git a/trunk/drivers/gpu/drm/gma500/gem_glue.h b/trunk/drivers/gpu/drm/gma500/gem_glue.h
new file mode 100644
index 000000000000..ce5ce30f74db
--- /dev/null
+++ b/trunk/drivers/gpu/drm/gma500/gem_glue.h
@@ -0,0 +1,2 @@
+extern void drm_gem_object_release_wrap(struct drm_gem_object *obj);
+extern int gem_create_mmap_offset(struct drm_gem_object *obj);
diff --git a/trunk/drivers/gpu/drm/gma500/intel_bios.c b/trunk/drivers/gpu/drm/gma500/intel_bios.c
index 4fb79cf00ed8..8d7caf0f363e 100644
--- a/trunk/drivers/gpu/drm/gma500/intel_bios.c
+++ b/trunk/drivers/gpu/drm/gma500/intel_bios.c
@@ -54,98 +54,6 @@ static void *find_section(struct bdb_header *bdb, int section_id)
return NULL;
}
-static void
-parse_edp(struct drm_psb_private *dev_priv, struct bdb_header *bdb)
-{
- struct bdb_edp *edp;
- struct edp_power_seq *edp_pps;
- struct edp_link_params *edp_link_params;
- uint8_t panel_type;
-
- edp = find_section(bdb, BDB_EDP);
-
- dev_priv->edp.bpp = 18;
- if (!edp) {
- if (dev_priv->edp.support) {
- DRM_DEBUG_KMS("No eDP BDB found but eDP panel supported, assume %dbpp panel color depth.\n",
- dev_priv->edp.bpp);
- }
- return;
- }
-
- panel_type = dev_priv->panel_type;
- switch ((edp->color_depth >> (panel_type * 2)) & 3) {
- case EDP_18BPP:
- dev_priv->edp.bpp = 18;
- break;
- case EDP_24BPP:
- dev_priv->edp.bpp = 24;
- break;
- case EDP_30BPP:
- dev_priv->edp.bpp = 30;
- break;
- }
-
- /* Get the eDP sequencing and link info */
- edp_pps = &edp->power_seqs[panel_type];
- edp_link_params = &edp->link_params[panel_type];
-
- dev_priv->edp.pps = *edp_pps;
-
- DRM_DEBUG_KMS("EDP timing in vbt t1_t3 %d t8 %d t9 %d t10 %d t11_t12 %d\n",
- dev_priv->edp.pps.t1_t3, dev_priv->edp.pps.t8,
- dev_priv->edp.pps.t9, dev_priv->edp.pps.t10,
- dev_priv->edp.pps.t11_t12);
-
- dev_priv->edp.rate = edp_link_params->rate ? DP_LINK_BW_2_7 :
- DP_LINK_BW_1_62;
- switch (edp_link_params->lanes) {
- case 0:
- dev_priv->edp.lanes = 1;
- break;
- case 1:
- dev_priv->edp.lanes = 2;
- break;
- case 3:
- default:
- dev_priv->edp.lanes = 4;
- break;
- }
- DRM_DEBUG_KMS("VBT reports EDP: Lane_count %d, Lane_rate %d, Bpp %d\n",
- dev_priv->edp.lanes, dev_priv->edp.rate, dev_priv->edp.bpp);
-
- switch (edp_link_params->preemphasis) {
- case 0:
- dev_priv->edp.preemphasis = DP_TRAIN_PRE_EMPHASIS_0;
- break;
- case 1:
- dev_priv->edp.preemphasis = DP_TRAIN_PRE_EMPHASIS_3_5;
- break;
- case 2:
- dev_priv->edp.preemphasis = DP_TRAIN_PRE_EMPHASIS_6;
- break;
- case 3:
- dev_priv->edp.preemphasis = DP_TRAIN_PRE_EMPHASIS_9_5;
- break;
- }
- switch (edp_link_params->vswing) {
- case 0:
- dev_priv->edp.vswing = DP_TRAIN_VOLTAGE_SWING_400;
- break;
- case 1:
- dev_priv->edp.vswing = DP_TRAIN_VOLTAGE_SWING_600;
- break;
- case 2:
- dev_priv->edp.vswing = DP_TRAIN_VOLTAGE_SWING_800;
- break;
- case 3:
- dev_priv->edp.vswing = DP_TRAIN_VOLTAGE_SWING_1200;
- break;
- }
- DRM_DEBUG_KMS("VBT reports EDP: VSwing %d, Preemph %d\n",
- dev_priv->edp.vswing, dev_priv->edp.preemphasis);
-}
-
static u16
get_blocksize(void *p)
{
@@ -246,8 +154,6 @@ static void parse_lfp_panel_data(struct drm_psb_private *dev_priv,
return;
dev_priv->lvds_dither = lvds_options->pixel_dither;
- dev_priv->panel_type = lvds_options->panel_type;
-
if (lvds_options->panel_type == 0xff)
return;
@@ -434,9 +340,6 @@ parse_driver_features(struct drm_psb_private *dev_priv,
if (!driver)
return;
- if (driver->lvds_config == BDB_DRIVER_FEATURE_EDP)
- dev_priv->edp.support = 1;
-
/* This bit means to use 96Mhz for DPLL_A or not */
if (driver->primary_lfp_id)
dev_priv->dplla_96mhz = true;
@@ -534,9 +437,6 @@ int psb_intel_init_bios(struct drm_device *dev)
size_t size;
int i;
-
- dev_priv->panel_type = 0xff;
-
/* XXX Should this validation be moved to intel_opregion.c? */
if (dev_priv->opregion.vbt) {
struct vbt_header *vbt = dev_priv->opregion.vbt;
@@ -577,7 +477,6 @@ int psb_intel_init_bios(struct drm_device *dev)
parse_sdvo_device_mapping(dev_priv, bdb);
parse_device_mapping(dev_priv, bdb);
parse_backlight_data(dev_priv, bdb);
- parse_edp(dev_priv, bdb);
if (bios)
pci_unmap_rom(pdev, bios);
diff --git a/trunk/drivers/gpu/drm/gma500/intel_bios.h b/trunk/drivers/gpu/drm/gma500/intel_bios.h
index c6267c98c9e7..2e95523b84b1 100644
--- a/trunk/drivers/gpu/drm/gma500/intel_bios.h
+++ b/trunk/drivers/gpu/drm/gma500/intel_bios.h
@@ -23,7 +23,6 @@
#define _I830_BIOS_H_
#include
-#include
struct vbt_header {
u8 signature[20]; /**< Always starts with 'VBT$' */
@@ -94,7 +93,6 @@ struct vbios_data {
#define BDB_SDVO_LVDS_PNP_IDS 24
#define BDB_SDVO_LVDS_POWER_SEQ 25
#define BDB_TV_OPTIONS 26
-#define BDB_EDP 27
#define BDB_LVDS_OPTIONS 40
#define BDB_LVDS_LFP_DATA_PTRS 41
#define BDB_LVDS_LFP_DATA 42
@@ -393,11 +391,6 @@ struct bdb_sdvo_lvds_options {
u8 panel_misc_bits_4;
} __attribute__((packed));
-#define BDB_DRIVER_FEATURE_NO_LVDS 0
-#define BDB_DRIVER_FEATURE_INT_LVDS 1
-#define BDB_DRIVER_FEATURE_SDVO_LVDS 2
-#define BDB_DRIVER_FEATURE_EDP 3
-
struct bdb_driver_features {
u8 boot_dev_algorithm:1;
u8 block_display_switch:1;
@@ -438,45 +431,6 @@ struct bdb_driver_features {
u8 custom_vbt_version;
} __attribute__((packed));
-#define EDP_18BPP 0
-#define EDP_24BPP 1
-#define EDP_30BPP 2
-#define EDP_RATE_1_62 0
-#define EDP_RATE_2_7 1
-#define EDP_LANE_1 0
-#define EDP_LANE_2 1
-#define EDP_LANE_4 3
-#define EDP_PREEMPHASIS_NONE 0
-#define EDP_PREEMPHASIS_3_5dB 1
-#define EDP_PREEMPHASIS_6dB 2
-#define EDP_PREEMPHASIS_9_5dB 3
-#define EDP_VSWING_0_4V 0
-#define EDP_VSWING_0_6V 1
-#define EDP_VSWING_0_8V 2
-#define EDP_VSWING_1_2V 3
-
-struct edp_power_seq {
- u16 t1_t3;
- u16 t8;
- u16 t9;
- u16 t10;
- u16 t11_t12;
-} __attribute__ ((packed));
-
-struct edp_link_params {
- u8 rate:4;
- u8 lanes:4;
- u8 preemphasis:4;
- u8 vswing:4;
-} __attribute__ ((packed));
-
-struct bdb_edp {
- struct edp_power_seq power_seqs[16];
- u32 color_depth;
- u32 sdrrs_msa_timing_delay;
- struct edp_link_params link_params[16];
-} __attribute__ ((packed));
-
extern int psb_intel_init_bios(struct drm_device *dev);
extern void psb_intel_destroy_bios(struct drm_device *dev);
diff --git a/trunk/drivers/gpu/drm/gma500/mdfld_dsi_output.c b/trunk/drivers/gpu/drm/gma500/mdfld_dsi_output.c
index 32dba2ab53e1..5675d93b4205 100644
--- a/trunk/drivers/gpu/drm/gma500/mdfld_dsi_output.c
+++ b/trunk/drivers/gpu/drm/gma500/mdfld_dsi_output.c
@@ -299,8 +299,17 @@ static int mdfld_dsi_connector_set_property(struct drm_connector *connector,
if (drm_connector_property_set_value(connector, property,
value))
goto set_prop_error;
- else
- gma_backlight_set(encoder->dev, value);
+ else {
+#ifdef CONFIG_BACKLIGHT_CLASS_DEVICE
+ struct backlight_device *psb_bd;
+
+ psb_bd = mdfld_get_backlight_device();
+ if (psb_bd) {
+ psb_bd->props.brightness = value;
+ mdfld_set_brightness(psb_bd);
+ }
+#endif
+ }
}
set_prop_done:
return 0;
diff --git a/trunk/drivers/gpu/drm/gma500/mid_bios.c b/trunk/drivers/gpu/drm/gma500/mid_bios.c
index 850cd3fbb969..b2a790bd9899 100644
--- a/trunk/drivers/gpu/drm/gma500/mid_bios.c
+++ b/trunk/drivers/gpu/drm/gma500/mid_bios.c
@@ -118,20 +118,20 @@ static void mid_get_pci_revID(struct drm_psb_private *dev_priv)
dev_priv->platform_rev_id);
}
-struct mid_vbt_header {
+struct vbt_header {
u32 signature;
u8 revision;
} __packed;
/* The same for r0 and r1 */
struct vbt_r0 {
- struct mid_vbt_header vbt_header;
+ struct vbt_header vbt_header;
u8 size;
u8 checksum;
} __packed;
struct vbt_r10 {
- struct mid_vbt_header vbt_header;
+ struct vbt_header vbt_header;
u8 checksum;
u16 size;
u8 panel_count;
@@ -281,7 +281,7 @@ static void mid_get_vbt_data(struct drm_psb_private *dev_priv)
struct drm_device *dev = dev_priv->dev;
u32 addr;
u8 __iomem *vbt_virtual;
- struct mid_vbt_header vbt_header;
+ struct vbt_header vbt_header;
struct pci_dev *pci_gfx_root = pci_get_bus_and_slot(0, PCI_DEVFN(2, 0));
int ret = -1;
diff --git a/trunk/drivers/gpu/drm/gma500/oaktrail_hdmi.c b/trunk/drivers/gpu/drm/gma500/oaktrail_hdmi.c
index 69e51e903f35..2eb3dc4e9c9b 100644
--- a/trunk/drivers/gpu/drm/gma500/oaktrail_hdmi.c
+++ b/trunk/drivers/gpu/drm/gma500/oaktrail_hdmi.c
@@ -252,6 +252,7 @@ static int oaktrail_hdmi_get_modes(struct drm_connector *connector)
if (edid) {
drm_mode_connector_update_edid_property(connector, edid);
ret = drm_add_edid_modes(connector, edid);
+ connector->display_info.raw_edid = NULL;
}
/*
diff --git a/trunk/drivers/gpu/drm/gma500/opregion.c b/trunk/drivers/gpu/drm/gma500/opregion.c
index ad0d6de938f3..c430bd424681 100644
--- a/trunk/drivers/gpu/drm/gma500/opregion.c
+++ b/trunk/drivers/gpu/drm/gma500/opregion.c
@@ -166,7 +166,8 @@ static u32 asle_set_backlight(struct drm_device *dev, u32 bclp)
if (config_enabled(CONFIG_BACKLIGHT_CLASS_DEVICE)) {
int max = bd->props.max_brightness;
- gma_backlight_set(dev, bclp * max / 255);
+ bd->props.brightness = bclp * max / 255;
+ backlight_update_status(bd);
}
asle->cblv = (bclp * 0x64) / 0xff | ASLE_CBLV_VALID;
diff --git a/trunk/drivers/gpu/drm/gma500/psb_device.c b/trunk/drivers/gpu/drm/gma500/psb_device.c
index f1432f096e58..5971bc82b765 100644
--- a/trunk/drivers/gpu/drm/gma500/psb_device.c
+++ b/trunk/drivers/gpu/drm/gma500/psb_device.c
@@ -290,7 +290,6 @@ static void psb_get_core_freq(struct drm_device *dev)
case 6:
case 7:
dev_priv->core_freq = 266;
- break;
default:
dev_priv->core_freq = 0;
}
diff --git a/trunk/drivers/gpu/drm/gma500/psb_drv.h b/trunk/drivers/gpu/drm/gma500/psb_drv.h
index 223ff5b1b5c4..1bd115ecefe1 100644
--- a/trunk/drivers/gpu/drm/gma500/psb_drv.h
+++ b/trunk/drivers/gpu/drm/gma500/psb_drv.h
@@ -24,10 +24,10 @@
#include
#include "drm_global.h"
+#include "gem_glue.h"
#include "gma_drm.h"
#include "psb_reg.h"
#include "psb_intel_drv.h"
-#include "intel_bios.h"
#include "gtt.h"
#include "power.h"
#include "opregion.h"
@@ -613,8 +613,6 @@ struct drm_psb_private {
*/
struct backlight_device *backlight_device;
struct drm_property *backlight_property;
- bool backlight_enabled;
- int backlight_level;
uint32_t blc_adj1;
uint32_t blc_adj2;
@@ -642,19 +640,6 @@ struct drm_psb_private {
int mdfld_panel_id;
bool dplla_96mhz; /* DPLL data from the VBT */
-
- struct {
- int rate;
- int lanes;
- int preemphasis;
- int vswing;
-
- bool initialized;
- bool support;
- int bpp;
- struct edp_power_seq pps;
- } edp;
- uint8_t panel_type;
};
@@ -811,9 +796,6 @@ extern int psb_fbdev_init(struct drm_device *dev);
/* backlight.c */
int gma_backlight_init(struct drm_device *dev);
void gma_backlight_exit(struct drm_device *dev);
-void gma_backlight_disable(struct drm_device *dev);
-void gma_backlight_enable(struct drm_device *dev);
-void gma_backlight_set(struct drm_device *dev, int v);
/* oaktrail_crtc.c */
extern const struct drm_crtc_helper_funcs oaktrail_helper_funcs;
diff --git a/trunk/drivers/gpu/drm/gma500/psb_intel_drv.h b/trunk/drivers/gpu/drm/gma500/psb_intel_drv.h
index 90f2d11e686b..ebe1a28f60e1 100644
--- a/trunk/drivers/gpu/drm/gma500/psb_intel_drv.h
+++ b/trunk/drivers/gpu/drm/gma500/psb_intel_drv.h
@@ -29,6 +29,10 @@
* Display related stuff
*/
+/* store information about an Ixxx DVO */
+/* The i830->i865 use multiple DVOs with multiple i2cs */
+/* the i915, i945 have a single sDVO i2c bus - which is different */
+#define MAX_OUTPUTS 6
/* maximum connectors per crtcs in the mode set */
#define INTELFB_CONN_LIMIT 4
@@ -65,8 +69,6 @@
#define INTEL_OUTPUT_HDMI 6
#define INTEL_OUTPUT_MIPI 7
#define INTEL_OUTPUT_MIPI2 8
-#define INTEL_OUTPUT_DISPLAYPORT 9
-#define INTEL_OUTPUT_EDP 10
#define INTEL_DVO_CHIP_NONE 0
#define INTEL_DVO_CHIP_LVDS 1
@@ -131,11 +133,6 @@ struct psb_intel_encoder {
void (*hot_plug)(struct psb_intel_encoder *);
int crtc_mask;
int clone_mask;
- u32 ddi_select; /* Channel info */
-#define DDI0_SELECT 0x01
-#define DDI1_SELECT 0x02
-#define DP_MASK 0x8000
-#define DDI_MASK 0x03
void *dev_priv; /* For sdvo_priv, lvds_priv, etc... */
/* FIXME: Either make SDVO and LVDS store it's i2c here or give CDV it's
@@ -193,6 +190,7 @@ struct psb_intel_crtc {
u32 mode_flags;
bool active;
+ bool crtc_enable;
/* Saved Crtc HW states */
struct psb_intel_crtc_state *crtc_state;
@@ -287,20 +285,4 @@ extern void gma_intel_gmbus_set_speed(struct i2c_adapter *adapter, int speed);
extern void gma_intel_gmbus_force_bit(struct i2c_adapter *adapter, bool force_bit);
extern void gma_intel_teardown_gmbus(struct drm_device *dev);
-/* DP support */
-extern void cdv_intel_dp_init(struct drm_device *dev, struct psb_intel_mode_device *mode_dev, int output_reg);
-extern void cdv_intel_dp_set_m_n(struct drm_crtc *crtc,
- struct drm_display_mode *mode,
- struct drm_display_mode *adjusted_mode);
-
-extern void psb_intel_attach_force_audio_property(struct drm_connector *connector);
-extern void psb_intel_attach_broadcast_rgb_property(struct drm_connector *connector);
-
-extern int cdv_sb_read(struct drm_device *dev, u32 reg, u32 *val);
-extern int cdv_sb_write(struct drm_device *dev, u32 reg, u32 val);
-extern void cdv_sb_reset(struct drm_device *dev);
-
-extern void cdv_intel_attach_force_audio_property(struct drm_connector *connector);
-extern void cdv_intel_attach_broadcast_rgb_property(struct drm_connector *connector);
-
#endif /* __INTEL_DRV_H__ */
diff --git a/trunk/drivers/gpu/drm/gma500/psb_intel_lvds.c b/trunk/drivers/gpu/drm/gma500/psb_intel_lvds.c
index 2a4c3a9e33e3..37adc9edf974 100644
--- a/trunk/drivers/gpu/drm/gma500/psb_intel_lvds.c
+++ b/trunk/drivers/gpu/drm/gma500/psb_intel_lvds.c
@@ -630,8 +630,17 @@ int psb_intel_lvds_set_property(struct drm_connector *connector,
property,
value))
goto set_prop_error;
- else
- gma_backlight_set(encoder->dev, value);
+ else {
+#ifdef CONFIG_BACKLIGHT_CLASS_DEVICE
+ struct drm_psb_private *devp =
+ encoder->dev->dev_private;
+ struct backlight_device *bd = devp->backlight_device;
+ if (bd) {
+ bd->props.brightness = value;
+ backlight_update_status(bd);
+ }
+#endif
+ }
} else if (!strcmp(property->name, "DPMS")) {
struct drm_encoder_helper_funcs *hfuncs
= encoder->helper_private;
diff --git a/trunk/drivers/gpu/drm/gma500/psb_intel_reg.h b/trunk/drivers/gpu/drm/gma500/psb_intel_reg.h
index d914719c4b60..8e8c8efb0a89 100644
--- a/trunk/drivers/gpu/drm/gma500/psb_intel_reg.h
+++ b/trunk/drivers/gpu/drm/gma500/psb_intel_reg.h
@@ -173,46 +173,15 @@
#define PP_SEQUENCE_ON (1 << 28)
#define PP_SEQUENCE_OFF (2 << 28)
#define PP_SEQUENCE_MASK 0x30000000
-#define PP_CYCLE_DELAY_ACTIVE (1 << 27)
-#define PP_SEQUENCE_STATE_ON_IDLE (1 << 3)
-#define PP_SEQUENCE_STATE_MASK 0x0000000f
-
#define PP_CONTROL 0x61204
#define POWER_TARGET_ON (1 << 0)
-#define PANEL_UNLOCK_REGS (0xabcd << 16)
-#define PANEL_UNLOCK_MASK (0xffff << 16)
-#define EDP_FORCE_VDD (1 << 3)
-#define EDP_BLC_ENABLE (1 << 2)
-#define PANEL_POWER_RESET (1 << 1)
-#define PANEL_POWER_OFF (0 << 0)
-#define PANEL_POWER_ON (1 << 0)
-
-/* Poulsbo/Oaktrail */
+
#define LVDSPP_ON 0x61208
#define LVDSPP_OFF 0x6120c
#define PP_CYCLE 0x61210
-/* Cedartrail */
#define PP_ON_DELAYS 0x61208 /* Cedartrail */
-#define PANEL_PORT_SELECT_MASK (3 << 30)
-#define PANEL_PORT_SELECT_LVDS (0 << 30)
-#define PANEL_PORT_SELECT_EDP (1 << 30)
-#define PANEL_POWER_UP_DELAY_MASK (0x1fff0000)
-#define PANEL_POWER_UP_DELAY_SHIFT 16
-#define PANEL_LIGHT_ON_DELAY_MASK (0x1fff)
-#define PANEL_LIGHT_ON_DELAY_SHIFT 0
-
#define PP_OFF_DELAYS 0x6120c /* Cedartrail */
-#define PANEL_POWER_DOWN_DELAY_MASK (0x1fff0000)
-#define PANEL_POWER_DOWN_DELAY_SHIFT 16
-#define PANEL_LIGHT_OFF_DELAY_MASK (0x1fff)
-#define PANEL_LIGHT_OFF_DELAY_SHIFT 0
-
-#define PP_DIVISOR 0x61210 /* Cedartrail */
-#define PP_REFERENCE_DIVIDER_MASK (0xffffff00)
-#define PP_REFERENCE_DIVIDER_SHIFT 8
-#define PANEL_POWER_CYCLE_DELAY_MASK (0x1f)
-#define PANEL_POWER_CYCLE_DELAY_SHIFT 0
#define PFIT_CONTROL 0x61230
#define PFIT_ENABLE (1 << 31)
@@ -1313,10 +1282,6 @@ No status bits are changed.
# define VRHUNIT_CLOCK_GATE_DISABLE (1 << 28) /* Fixed value on CDV */
# define DPOUNIT_CLOCK_GATE_DISABLE (1 << 11)
# define DPIOUNIT_CLOCK_GATE_DISABLE (1 << 6)
-# define DPUNIT_PIPEB_GATE_DISABLE (1 << 30)
-# define DPUNIT_PIPEA_GATE_DISABLE (1 << 25)
-# define DPCUNIT_CLOCK_GATE_DISABLE (1 << 24)
-# define DPLSUNIT_CLOCK_GATE_DISABLE (1 << 13)
#define RAMCLK_GATE_D 0x6210
@@ -1382,165 +1347,5 @@ No status bits are changed.
#define LANE_PLL_ENABLE (0x3 << 20)
#define LANE_PLL_PIPE(p) (((p) == 0) ? (1 << 21) : (0 << 21))
-#define DP_B 0x64100
-#define DP_C 0x64200
-
-#define DP_PORT_EN (1 << 31)
-#define DP_PIPEB_SELECT (1 << 30)
-#define DP_PIPE_MASK (1 << 30)
-
-/* Link training mode - select a suitable mode for each stage */
-#define DP_LINK_TRAIN_PAT_1 (0 << 28)
-#define DP_LINK_TRAIN_PAT_2 (1 << 28)
-#define DP_LINK_TRAIN_PAT_IDLE (2 << 28)
-#define DP_LINK_TRAIN_OFF (3 << 28)
-#define DP_LINK_TRAIN_MASK (3 << 28)
-#define DP_LINK_TRAIN_SHIFT 28
-
-/* Signal voltages. These are mostly controlled by the other end */
-#define DP_VOLTAGE_0_4 (0 << 25)
-#define DP_VOLTAGE_0_6 (1 << 25)
-#define DP_VOLTAGE_0_8 (2 << 25)
-#define DP_VOLTAGE_1_2 (3 << 25)
-#define DP_VOLTAGE_MASK (7 << 25)
-#define DP_VOLTAGE_SHIFT 25
-
-/* Signal pre-emphasis levels, like voltages, the other end tells us what
- * they want
- */
-#define DP_PRE_EMPHASIS_0 (0 << 22)
-#define DP_PRE_EMPHASIS_3_5 (1 << 22)
-#define DP_PRE_EMPHASIS_6 (2 << 22)
-#define DP_PRE_EMPHASIS_9_5 (3 << 22)
-#define DP_PRE_EMPHASIS_MASK (7 << 22)
-#define DP_PRE_EMPHASIS_SHIFT 22
-
-/* How many wires to use. I guess 3 was too hard */
-#define DP_PORT_WIDTH_1 (0 << 19)
-#define DP_PORT_WIDTH_2 (1 << 19)
-#define DP_PORT_WIDTH_4 (3 << 19)
-#define DP_PORT_WIDTH_MASK (7 << 19)
-
-/* Mystic DPCD version 1.1 special mode */
-#define DP_ENHANCED_FRAMING (1 << 18)
-
-/** locked once port is enabled */
-#define DP_PORT_REVERSAL (1 << 15)
-
-/** sends the clock on lane 15 of the PEG for debug */
-#define DP_CLOCK_OUTPUT_ENABLE (1 << 13)
-
-#define DP_SCRAMBLING_DISABLE (1 << 12)
-#define DP_SCRAMBLING_DISABLE_IRONLAKE (1 << 7)
-
-/** limit RGB values to avoid confusing TVs */
-#define DP_COLOR_RANGE_16_235 (1 << 8)
-
-/** Turn on the audio link */
-#define DP_AUDIO_OUTPUT_ENABLE (1 << 6)
-
-/** vs and hs sync polarity */
-#define DP_SYNC_VS_HIGH (1 << 4)
-#define DP_SYNC_HS_HIGH (1 << 3)
-
-/** A fantasy */
-#define DP_DETECTED (1 << 2)
-
-/** The aux channel provides a way to talk to the
- * signal sink for DDC etc. Max packet size supported
- * is 20 bytes in each direction, hence the 5 fixed
- * data registers
- */
-#define DPB_AUX_CH_CTL 0x64110
-#define DPB_AUX_CH_DATA1 0x64114
-#define DPB_AUX_CH_DATA2 0x64118
-#define DPB_AUX_CH_DATA3 0x6411c
-#define DPB_AUX_CH_DATA4 0x64120
-#define DPB_AUX_CH_DATA5 0x64124
-
-#define DPC_AUX_CH_CTL 0x64210
-#define DPC_AUX_CH_DATA1 0x64214
-#define DPC_AUX_CH_DATA2 0x64218
-#define DPC_AUX_CH_DATA3 0x6421c
-#define DPC_AUX_CH_DATA4 0x64220
-#define DPC_AUX_CH_DATA5 0x64224
-
-#define DP_AUX_CH_CTL_SEND_BUSY (1 << 31)
-#define DP_AUX_CH_CTL_DONE (1 << 30)
-#define DP_AUX_CH_CTL_INTERRUPT (1 << 29)
-#define DP_AUX_CH_CTL_TIME_OUT_ERROR (1 << 28)
-#define DP_AUX_CH_CTL_TIME_OUT_400us (0 << 26)
-#define DP_AUX_CH_CTL_TIME_OUT_600us (1 << 26)
-#define DP_AUX_CH_CTL_TIME_OUT_800us (2 << 26)
-#define DP_AUX_CH_CTL_TIME_OUT_1600us (3 << 26)
-#define DP_AUX_CH_CTL_TIME_OUT_MASK (3 << 26)
-#define DP_AUX_CH_CTL_RECEIVE_ERROR (1 << 25)
-#define DP_AUX_CH_CTL_MESSAGE_SIZE_MASK (0x1f << 20)
-#define DP_AUX_CH_CTL_MESSAGE_SIZE_SHIFT 20
-#define DP_AUX_CH_CTL_PRECHARGE_2US_MASK (0xf << 16)
-#define DP_AUX_CH_CTL_PRECHARGE_2US_SHIFT 16
-#define DP_AUX_CH_CTL_AUX_AKSV_SELECT (1 << 15)
-#define DP_AUX_CH_CTL_MANCHESTER_TEST (1 << 14)
-#define DP_AUX_CH_CTL_SYNC_TEST (1 << 13)
-#define DP_AUX_CH_CTL_DEGLITCH_TEST (1 << 12)
-#define DP_AUX_CH_CTL_PRECHARGE_TEST (1 << 11)
-#define DP_AUX_CH_CTL_BIT_CLOCK_2X_MASK (0x7ff)
-#define DP_AUX_CH_CTL_BIT_CLOCK_2X_SHIFT 0
-
-/*
- * Computing GMCH M and N values for the Display Port link
- *
- * GMCH M/N = dot clock * bytes per pixel / ls_clk * # of lanes
- *
- * ls_clk (we assume) is the DP link clock (1.62 or 2.7 GHz)
- *
- * The GMCH value is used internally
- *
- * bytes_per_pixel is the number of bytes coming out of the plane,
- * which is after the LUTs, so we want the bytes for our color format.
- * For our current usage, this is always 3, one byte for R, G and B.
- */
-
-#define _PIPEA_GMCH_DATA_M 0x70050
-#define _PIPEB_GMCH_DATA_M 0x71050
-
-/* Transfer unit size for display port - 1, default is 0x3f (for TU size 64) */
-#define PIPE_GMCH_DATA_M_TU_SIZE_MASK (0x3f << 25)
-#define PIPE_GMCH_DATA_M_TU_SIZE_SHIFT 25
-
-#define PIPE_GMCH_DATA_M_MASK (0xffffff)
-
-#define _PIPEA_GMCH_DATA_N 0x70054
-#define _PIPEB_GMCH_DATA_N 0x71054
-#define PIPE_GMCH_DATA_N_MASK (0xffffff)
-
-/*
- * Computing Link M and N values for the Display Port link
- *
- * Link M / N = pixel_clock / ls_clk
- *
- * (the DP spec calls pixel_clock the 'strm_clk')
- *
- * The Link value is transmitted in the Main Stream
- * Attributes and VB-ID.
- */
-
-#define _PIPEA_DP_LINK_M 0x70060
-#define _PIPEB_DP_LINK_M 0x71060
-#define PIPEA_DP_LINK_M_MASK (0xffffff)
-
-#define _PIPEA_DP_LINK_N 0x70064
-#define _PIPEB_DP_LINK_N 0x71064
-#define PIPEA_DP_LINK_N_MASK (0xffffff)
-
-#define PIPE_GMCH_DATA_M(pipe) _PIPE(pipe, _PIPEA_GMCH_DATA_M, _PIPEB_GMCH_DATA_M)
-#define PIPE_GMCH_DATA_N(pipe) _PIPE(pipe, _PIPEA_GMCH_DATA_N, _PIPEB_GMCH_DATA_N)
-#define PIPE_DP_LINK_M(pipe) _PIPE(pipe, _PIPEA_DP_LINK_M, _PIPEB_DP_LINK_M)
-#define PIPE_DP_LINK_N(pipe) _PIPE(pipe, _PIPEA_DP_LINK_N, _PIPEB_DP_LINK_N)
-
-#define PIPE_BPC_MASK (7 << 5)
-#define PIPE_8BPC (0 << 5)
-#define PIPE_10BPC (1 << 5)
-#define PIPE_6BPC (2 << 5)
#endif
diff --git a/trunk/drivers/gpu/drm/gma500/psb_intel_sdvo.c b/trunk/drivers/gpu/drm/gma500/psb_intel_sdvo.c
index d35f93ba3a85..0466c7b985f8 100644
--- a/trunk/drivers/gpu/drm/gma500/psb_intel_sdvo.c
+++ b/trunk/drivers/gpu/drm/gma500/psb_intel_sdvo.c
@@ -1292,6 +1292,7 @@ psb_intel_sdvo_get_analog_edid(struct drm_connector *connector)
return drm_get_edid(connector,
&dev_priv->gmbus[dev_priv->crt_ddc_pin].adapter);
+ return NULL;
}
static enum drm_connector_status
@@ -1342,6 +1343,7 @@ psb_intel_sdvo_hdmi_sink_detect(struct drm_connector *connector)
}
} else
status = connector_status_disconnected;
+ connector->display_info.raw_edid = NULL;
kfree(edid);
}
@@ -1402,6 +1404,7 @@ psb_intel_sdvo_detect(struct drm_connector *connector, bool force)
ret = connector_status_disconnected;
else
ret = connector_status_connected;
+ connector->display_info.raw_edid = NULL;
kfree(edid);
} else
ret = connector_status_connected;
@@ -1450,6 +1453,7 @@ static void psb_intel_sdvo_get_ddc_modes(struct drm_connector *connector)
drm_add_edid_modes(connector, edid);
}
+ connector->display_info.raw_edid = NULL;
kfree(edid);
}
}
diff --git a/trunk/drivers/gpu/drm/i2c/ch7006_drv.c b/trunk/drivers/gpu/drm/i2c/ch7006_drv.c
index 599099fe76e3..36d952280c50 100644
--- a/trunk/drivers/gpu/drm/i2c/ch7006_drv.c
+++ b/trunk/drivers/gpu/drm/i2c/ch7006_drv.c
@@ -427,10 +427,15 @@ static int ch7006_remove(struct i2c_client *client)
return 0;
}
-static int ch7006_resume(struct device *dev)
+static int ch7006_suspend(struct i2c_client *client, pm_message_t mesg)
{
- struct i2c_client *client = to_i2c_client(dev);
+ ch7006_dbg(client, "\n");
+
+ return 0;
+}
+static int ch7006_resume(struct i2c_client *client)
+{
ch7006_dbg(client, "\n");
ch7006_write(client, 0x3d, 0x0);
@@ -494,18 +499,15 @@ static struct i2c_device_id ch7006_ids[] = {
};
MODULE_DEVICE_TABLE(i2c, ch7006_ids);
-static const struct dev_pm_ops ch7006_pm_ops = {
- .resume = ch7006_resume,
-};
-
static struct drm_i2c_encoder_driver ch7006_driver = {
.i2c_driver = {
.probe = ch7006_probe,
.remove = ch7006_remove,
+ .suspend = ch7006_suspend,
+ .resume = ch7006_resume,
.driver = {
.name = "ch7006",
- .pm = &ch7006_pm_ops,
},
.id_table = ch7006_ids,
diff --git a/trunk/drivers/gpu/drm/i915/Makefile b/trunk/drivers/gpu/drm/i915/Makefile
index 0f2c5493242b..b0bacdba6d7e 100644
--- a/trunk/drivers/gpu/drm/i915/Makefile
+++ b/trunk/drivers/gpu/drm/i915/Makefile
@@ -40,7 +40,6 @@ i915-y := i915_drv.o i915_dma.o i915_irq.o \
dvo_ivch.o \
dvo_tfp410.o \
dvo_sil164.o \
- dvo_ns2501.o \
i915_gem_dmabuf.o
i915-$(CONFIG_COMPAT) += i915_ioc32.o
diff --git a/trunk/drivers/gpu/drm/i915/dvo.h b/trunk/drivers/gpu/drm/i915/dvo.h
index 74b5efccfdb1..58914691a77b 100644
--- a/trunk/drivers/gpu/drm/i915/dvo.h
+++ b/trunk/drivers/gpu/drm/i915/dvo.h
@@ -58,12 +58,13 @@ struct intel_dvo_dev_ops {
void (*create_resources)(struct intel_dvo_device *dvo);
/*
- * Turn on/off output.
+ * Turn on/off output or set intermediate power levels if available.
*
- * Because none of our dvo drivers support an intermediate power levels,
- * we don't expose this in the interfac.
+ * Unsupported intermediate modes drop to the lower power setting.
+ * If the mode is DPMSModeOff, the output must be disabled,
+ * as the DPLL may be disabled afterwards.
*/
- void (*dpms)(struct intel_dvo_device *dvo, bool enable);
+ void (*dpms)(struct intel_dvo_device *dvo, int mode);
/*
* Callback for testing a video mode for a given output.
@@ -114,12 +115,6 @@ struct intel_dvo_dev_ops {
*/
enum drm_connector_status (*detect)(struct intel_dvo_device *dvo);
- /*
- * Probe the current hw status, returning true if the connected output
- * is active.
- */
- bool (*get_hw_state)(struct intel_dvo_device *dev);
-
/**
* Query the device for the modes it provides.
*
@@ -145,6 +140,5 @@ extern struct intel_dvo_dev_ops ch7xxx_ops;
extern struct intel_dvo_dev_ops ivch_ops;
extern struct intel_dvo_dev_ops tfp410_ops;
extern struct intel_dvo_dev_ops ch7017_ops;
-extern struct intel_dvo_dev_ops ns2501_ops;
#endif /* _INTEL_DVO_H */
diff --git a/trunk/drivers/gpu/drm/i915/dvo_ch7017.c b/trunk/drivers/gpu/drm/i915/dvo_ch7017.c
index 86b27d1d90c2..1ca799a1e1fc 100644
--- a/trunk/drivers/gpu/drm/i915/dvo_ch7017.c
+++ b/trunk/drivers/gpu/drm/i915/dvo_ch7017.c
@@ -163,7 +163,7 @@ struct ch7017_priv {
};
static void ch7017_dump_regs(struct intel_dvo_device *dvo);
-static void ch7017_dpms(struct intel_dvo_device *dvo, bool enable);
+static void ch7017_dpms(struct intel_dvo_device *dvo, int mode);
static bool ch7017_read(struct intel_dvo_device *dvo, u8 addr, u8 *val)
{
@@ -309,7 +309,7 @@ static void ch7017_mode_set(struct intel_dvo_device *dvo,
lvds_power_down = CH7017_LVDS_POWER_DOWN_DEFAULT_RESERVED |
(mode->hdisplay & 0x0700) >> 8;
- ch7017_dpms(dvo, false);
+ ch7017_dpms(dvo, DRM_MODE_DPMS_OFF);
ch7017_write(dvo, CH7017_HORIZONTAL_ACTIVE_PIXEL_INPUT,
horizontal_active_pixel_input);
ch7017_write(dvo, CH7017_HORIZONTAL_ACTIVE_PIXEL_OUTPUT,
@@ -331,7 +331,7 @@ static void ch7017_mode_set(struct intel_dvo_device *dvo,
}
/* set the CH7017 power state */
-static void ch7017_dpms(struct intel_dvo_device *dvo, bool enable)
+static void ch7017_dpms(struct intel_dvo_device *dvo, int mode)
{
uint8_t val;
@@ -345,7 +345,7 @@ static void ch7017_dpms(struct intel_dvo_device *dvo, bool enable)
CH7017_DAC3_POWER_DOWN |
CH7017_TV_POWER_DOWN_EN);
- if (enable) {
+ if (mode == DRM_MODE_DPMS_ON) {
/* Turn on the LVDS */
ch7017_write(dvo, CH7017_LVDS_POWER_DOWN,
val & ~CH7017_LVDS_POWER_DOWN_EN);
@@ -359,18 +359,6 @@ static void ch7017_dpms(struct intel_dvo_device *dvo, bool enable)
msleep(20);
}
-static bool ch7017_get_hw_state(struct intel_dvo_device *dvo)
-{
- uint8_t val;
-
- ch7017_read(dvo, CH7017_LVDS_POWER_DOWN, &val);
-
- if (val & CH7017_LVDS_POWER_DOWN_EN)
- return false;
- else
- return true;
-}
-
static void ch7017_dump_regs(struct intel_dvo_device *dvo)
{
uint8_t val;
@@ -408,7 +396,6 @@ struct intel_dvo_dev_ops ch7017_ops = {
.mode_valid = ch7017_mode_valid,
.mode_set = ch7017_mode_set,
.dpms = ch7017_dpms,
- .get_hw_state = ch7017_get_hw_state,
.dump_regs = ch7017_dump_regs,
.destroy = ch7017_destroy,
};
diff --git a/trunk/drivers/gpu/drm/i915/dvo_ch7xxx.c b/trunk/drivers/gpu/drm/i915/dvo_ch7xxx.c
index 38f3a6cb8c7d..4a036600e806 100644
--- a/trunk/drivers/gpu/drm/i915/dvo_ch7xxx.c
+++ b/trunk/drivers/gpu/drm/i915/dvo_ch7xxx.c
@@ -289,26 +289,14 @@ static void ch7xxx_mode_set(struct intel_dvo_device *dvo,
}
/* set the CH7xxx power state */
-static void ch7xxx_dpms(struct intel_dvo_device *dvo, bool enable)
+static void ch7xxx_dpms(struct intel_dvo_device *dvo, int mode)
{
- if (enable)
+ if (mode == DRM_MODE_DPMS_ON)
ch7xxx_writeb(dvo, CH7xxx_PM, CH7xxx_PM_DVIL | CH7xxx_PM_DVIP);
else
ch7xxx_writeb(dvo, CH7xxx_PM, CH7xxx_PM_FPD);
}
-static bool ch7xxx_get_hw_state(struct intel_dvo_device *dvo)
-{
- u8 val;
-
- ch7xxx_readb(dvo, CH7xxx_PM, &val);
-
- if (val & CH7xxx_PM_FPD)
- return false;
- else
- return true;
-}
-
static void ch7xxx_dump_regs(struct intel_dvo_device *dvo)
{
int i;
@@ -338,7 +326,6 @@ struct intel_dvo_dev_ops ch7xxx_ops = {
.mode_valid = ch7xxx_mode_valid,
.mode_set = ch7xxx_mode_set,
.dpms = ch7xxx_dpms,
- .get_hw_state = ch7xxx_get_hw_state,
.dump_regs = ch7xxx_dump_regs,
.destroy = ch7xxx_destroy,
};
diff --git a/trunk/drivers/gpu/drm/i915/dvo_ivch.c b/trunk/drivers/gpu/drm/i915/dvo_ivch.c
index baaf65bf0bdd..04f2893d5e3c 100644
--- a/trunk/drivers/gpu/drm/i915/dvo_ivch.c
+++ b/trunk/drivers/gpu/drm/i915/dvo_ivch.c
@@ -288,7 +288,7 @@ static enum drm_mode_status ivch_mode_valid(struct intel_dvo_device *dvo,
}
/** Sets the power state of the panel connected to the ivch */
-static void ivch_dpms(struct intel_dvo_device *dvo, bool enable)
+static void ivch_dpms(struct intel_dvo_device *dvo, int mode)
{
int i;
uint16_t vr01, vr30, backlight;
@@ -297,13 +297,13 @@ static void ivch_dpms(struct intel_dvo_device *dvo, bool enable)
if (!ivch_read(dvo, VR01, &vr01))
return;
- if (enable)
+ if (mode == DRM_MODE_DPMS_ON)
backlight = 1;
else
backlight = 0;
ivch_write(dvo, VR80, backlight);
- if (enable)
+ if (mode == DRM_MODE_DPMS_ON)
vr01 |= VR01_LCD_ENABLE | VR01_DVO_ENABLE;
else
vr01 &= ~(VR01_LCD_ENABLE | VR01_DVO_ENABLE);
@@ -315,7 +315,7 @@ static void ivch_dpms(struct intel_dvo_device *dvo, bool enable)
if (!ivch_read(dvo, VR30, &vr30))
break;
- if (((vr30 & VR30_PANEL_ON) != 0) == enable)
+ if (((vr30 & VR30_PANEL_ON) != 0) == (mode == DRM_MODE_DPMS_ON))
break;
udelay(1000);
}
@@ -323,20 +323,6 @@ static void ivch_dpms(struct intel_dvo_device *dvo, bool enable)
udelay(16 * 1000);
}
-static bool ivch_get_hw_state(struct intel_dvo_device *dvo)
-{
- uint16_t vr01;
-
- /* Set the new power state of the panel. */
- if (!ivch_read(dvo, VR01, &vr01))
- return false;
-
- if (vr01 & VR01_LCD_ENABLE)
- return true;
- else
- return false;
-}
-
static void ivch_mode_set(struct intel_dvo_device *dvo,
struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode)
@@ -427,7 +413,6 @@ static void ivch_destroy(struct intel_dvo_device *dvo)
struct intel_dvo_dev_ops ivch_ops = {
.init = ivch_init,
.dpms = ivch_dpms,
- .get_hw_state = ivch_get_hw_state,
.mode_valid = ivch_mode_valid,
.mode_set = ivch_mode_set,
.detect = ivch_detect,
diff --git a/trunk/drivers/gpu/drm/i915/dvo_ns2501.c b/trunk/drivers/gpu/drm/i915/dvo_ns2501.c
deleted file mode 100644
index c4a255be6979..000000000000
--- a/trunk/drivers/gpu/drm/i915/dvo_ns2501.c
+++ /dev/null
@@ -1,588 +0,0 @@
-/*
- *
- * Copyright (c) 2012 Gilles Dartiguelongue, Thomas Richter
- *
- * All Rights Reserved.
- *
- * 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, sub license, 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 NON-INFRINGEMENT.
- * IN NO EVENT SHALL THE AUTHOR 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.
- *
- */
-
-#include "dvo.h"
-#include "i915_reg.h"
-#include "i915_drv.h"
-
-#define NS2501_VID 0x1305
-#define NS2501_DID 0x6726
-
-#define NS2501_VID_LO 0x00
-#define NS2501_VID_HI 0x01
-#define NS2501_DID_LO 0x02
-#define NS2501_DID_HI 0x03
-#define NS2501_REV 0x04
-#define NS2501_RSVD 0x05
-#define NS2501_FREQ_LO 0x06
-#define NS2501_FREQ_HI 0x07
-
-#define NS2501_REG8 0x08
-#define NS2501_8_VEN (1<<5)
-#define NS2501_8_HEN (1<<4)
-#define NS2501_8_DSEL (1<<3)
-#define NS2501_8_BPAS (1<<2)
-#define NS2501_8_RSVD (1<<1)
-#define NS2501_8_PD (1<<0)
-
-#define NS2501_REG9 0x09
-#define NS2501_9_VLOW (1<<7)
-#define NS2501_9_MSEL_MASK (0x7<<4)
-#define NS2501_9_TSEL (1<<3)
-#define NS2501_9_RSEN (1<<2)
-#define NS2501_9_RSVD (1<<1)
-#define NS2501_9_MDI (1<<0)
-
-#define NS2501_REGC 0x0c
-
-struct ns2501_priv {
- //I2CDevRec d;
- bool quiet;
- int reg_8_shadow;
- int reg_8_set;
- // Shadow registers for i915
- int dvoc;
- int pll_a;
- int srcdim;
- int fw_blc;
-};
-
-#define NSPTR(d) ((NS2501Ptr)(d->DriverPrivate.ptr))
-
-/*
- * For reasons unclear to me, the ns2501 at least on the Fujitsu/Siemens
- * laptops does not react on the i2c bus unless
- * both the PLL is running and the display is configured in its native
- * resolution.
- * This function forces the DVO on, and stores the registers it touches.
- * Afterwards, registers are restored to regular values.
- *
- * This is pretty much a hack, though it works.
- * Without that, ns2501_readb and ns2501_writeb fail
- * when switching the resolution.
- */
-
-static void enable_dvo(struct intel_dvo_device *dvo)
-{
- struct ns2501_priv *ns = (struct ns2501_priv *)(dvo->dev_priv);
- struct i2c_adapter *adapter = dvo->i2c_bus;
- struct intel_gmbus *bus = container_of(adapter,
- struct intel_gmbus,
- adapter);
- struct drm_i915_private *dev_priv = bus->dev_priv;
-
- DRM_DEBUG_KMS("%s: Trying to re-enable the DVO\n", __FUNCTION__);
-
- ns->dvoc = I915_READ(DVO_C);
- ns->pll_a = I915_READ(_DPLL_A);
- ns->srcdim = I915_READ(DVOC_SRCDIM);
- ns->fw_blc = I915_READ(FW_BLC);
-
- I915_WRITE(DVOC, 0x10004084);
- I915_WRITE(_DPLL_A, 0xd0820000);
- I915_WRITE(DVOC_SRCDIM, 0x400300); // 1024x768
- I915_WRITE(FW_BLC, 0x1080304);
-
- I915_WRITE(DVOC, 0x90004084);
-}
-
-/*
- * Restore the I915 registers modified by the above
- * trigger function.
- */
-static void restore_dvo(struct intel_dvo_device *dvo)
-{
- struct i2c_adapter *adapter = dvo->i2c_bus;
- struct intel_gmbus *bus = container_of(adapter,
- struct intel_gmbus,
- adapter);
- struct drm_i915_private *dev_priv = bus->dev_priv;
- struct ns2501_priv *ns = (struct ns2501_priv *)(dvo->dev_priv);
-
- I915_WRITE(DVOC, ns->dvoc);
- I915_WRITE(_DPLL_A, ns->pll_a);
- I915_WRITE(DVOC_SRCDIM, ns->srcdim);
- I915_WRITE(FW_BLC, ns->fw_blc);
-}
-
-/*
-** Read a register from the ns2501.
-** Returns true if successful, false otherwise.
-** If it returns false, it might be wise to enable the
-** DVO with the above function.
-*/
-static bool ns2501_readb(struct intel_dvo_device *dvo, int addr, uint8_t * ch)
-{
- struct ns2501_priv *ns = dvo->dev_priv;
- struct i2c_adapter *adapter = dvo->i2c_bus;
- u8 out_buf[2];
- u8 in_buf[2];
-
- struct i2c_msg msgs[] = {
- {
- .addr = dvo->slave_addr,
- .flags = 0,
- .len = 1,
- .buf = out_buf,
- },
- {
- .addr = dvo->slave_addr,
- .flags = I2C_M_RD,
- .len = 1,
- .buf = in_buf,
- }
- };
-
- out_buf[0] = addr;
- out_buf[1] = 0;
-
- if (i2c_transfer(adapter, msgs, 2) == 2) {
- *ch = in_buf[0];
- return true;
- };
-
- if (!ns->quiet) {
- DRM_DEBUG_KMS
- ("Unable to read register 0x%02x from %s:0x%02x.\n", addr,
- adapter->name, dvo->slave_addr);
- }
-
- return false;
-}
-
-/*
-** Write a register to the ns2501.
-** Returns true if successful, false otherwise.
-** If it returns false, it might be wise to enable the
-** DVO with the above function.
-*/
-static bool ns2501_writeb(struct intel_dvo_device *dvo, int addr, uint8_t ch)
-{
- struct ns2501_priv *ns = dvo->dev_priv;
- struct i2c_adapter *adapter = dvo->i2c_bus;
- uint8_t out_buf[2];
-
- struct i2c_msg msg = {
- .addr = dvo->slave_addr,
- .flags = 0,
- .len = 2,
- .buf = out_buf,
- };
-
- out_buf[0] = addr;
- out_buf[1] = ch;
-
- if (i2c_transfer(adapter, &msg, 1) == 1) {
- return true;
- }
-
- if (!ns->quiet) {
- DRM_DEBUG_KMS("Unable to write register 0x%02x to %s:%d\n",
- addr, adapter->name, dvo->slave_addr);
- }
-
- return false;
-}
-
-/* National Semiconductor 2501 driver for chip on i2c bus
- * scan for the chip on the bus.
- * Hope the VBIOS initialized the PLL correctly so we can
- * talk to it. If not, it will not be seen and not detected.
- * Bummer!
- */
-static bool ns2501_init(struct intel_dvo_device *dvo,
- struct i2c_adapter *adapter)
-{
- /* this will detect the NS2501 chip on the specified i2c bus */
- struct ns2501_priv *ns;
- unsigned char ch;
-
- ns = kzalloc(sizeof(struct ns2501_priv), GFP_KERNEL);
- if (ns == NULL)
- return false;
-
- dvo->i2c_bus = adapter;
- dvo->dev_priv = ns;
- ns->quiet = true;
-
- if (!ns2501_readb(dvo, NS2501_VID_LO, &ch))
- goto out;
-
- if (ch != (NS2501_VID & 0xff)) {
- DRM_DEBUG_KMS("ns2501 not detected got %d: from %s Slave %d.\n",
- ch, adapter->name, dvo->slave_addr);
- goto out;
- }
-
- if (!ns2501_readb(dvo, NS2501_DID_LO, &ch))
- goto out;
-
- if (ch != (NS2501_DID & 0xff)) {
- DRM_DEBUG_KMS("ns2501 not detected got %d: from %s Slave %d.\n",
- ch, adapter->name, dvo->slave_addr);
- goto out;
- }
- ns->quiet = false;
- ns->reg_8_set = 0;
- ns->reg_8_shadow =
- NS2501_8_PD | NS2501_8_BPAS | NS2501_8_VEN | NS2501_8_HEN;
-
- DRM_DEBUG_KMS("init ns2501 dvo controller successfully!\n");
- return true;
-
-out:
- kfree(ns);
- return false;
-}
-
-static enum drm_connector_status ns2501_detect(struct intel_dvo_device *dvo)
-{
- /*
- * This is a Laptop display, it doesn't have hotplugging.
- * Even if not, the detection bit of the 2501 is unreliable as
- * it only works for some display types.
- * It is even more unreliable as the PLL must be active for
- * allowing reading from the chiop.
- */
- return connector_status_connected;
-}
-
-static enum drm_mode_status ns2501_mode_valid(struct intel_dvo_device *dvo,
- struct drm_display_mode *mode)
-{
- DRM_DEBUG_KMS
- ("%s: is mode valid (hdisplay=%d,htotal=%d,vdisplay=%d,vtotal=%d)\n",
- __FUNCTION__, mode->hdisplay, mode->htotal, mode->vdisplay,
- mode->vtotal);
-
- /*
- * Currently, these are all the modes I have data from.
- * More might exist. Unclear how to find the native resolution
- * of the panel in here so we could always accept it
- * by disabling the scaler.
- */
- if ((mode->hdisplay == 800 && mode->vdisplay == 600) ||
- (mode->hdisplay == 640 && mode->vdisplay == 480) ||
- (mode->hdisplay == 1024 && mode->vdisplay == 768)) {
- return MODE_OK;
- } else {
- return MODE_ONE_SIZE; /* Is this a reasonable error? */
- }
-}
-
-static void ns2501_mode_set(struct intel_dvo_device *dvo,
- struct drm_display_mode *mode,
- struct drm_display_mode *adjusted_mode)
-{
- bool ok;
- bool restore = false;
- struct ns2501_priv *ns = (struct ns2501_priv *)(dvo->dev_priv);
-
- DRM_DEBUG_KMS
- ("%s: set mode (hdisplay=%d,htotal=%d,vdisplay=%d,vtotal=%d).\n",
- __FUNCTION__, mode->hdisplay, mode->htotal, mode->vdisplay,
- mode->vtotal);
-
- /*
- * Where do I find the native resolution for which scaling is not required???
- *
- * First trigger the DVO on as otherwise the chip does not appear on the i2c
- * bus.
- */
- do {
- ok = true;
-
- if (mode->hdisplay == 800 && mode->vdisplay == 600) {
- /* mode 277 */
- ns->reg_8_shadow &= ~NS2501_8_BPAS;
- DRM_DEBUG_KMS("%s: switching to 800x600\n",
- __FUNCTION__);
-
- /*
- * No, I do not know where this data comes from.
- * It is just what the video bios left in the DVO, so
- * I'm just copying it here over.
- * This also means that I cannot support any other modes
- * except the ones supported by the bios.
- */
- ok &= ns2501_writeb(dvo, 0x11, 0xc8); // 0xc7 also works.
- ok &= ns2501_writeb(dvo, 0x1b, 0x19);
- ok &= ns2501_writeb(dvo, 0x1c, 0x62); // VBIOS left 0x64 here, but 0x62 works nicer
- ok &= ns2501_writeb(dvo, 0x1d, 0x02);
-
- ok &= ns2501_writeb(dvo, 0x34, 0x03);
- ok &= ns2501_writeb(dvo, 0x35, 0xff);
-
- ok &= ns2501_writeb(dvo, 0x80, 0x27);
- ok &= ns2501_writeb(dvo, 0x81, 0x03);
- ok &= ns2501_writeb(dvo, 0x82, 0x41);
- ok &= ns2501_writeb(dvo, 0x83, 0x05);
-
- ok &= ns2501_writeb(dvo, 0x8d, 0x02);
- ok &= ns2501_writeb(dvo, 0x8e, 0x04);
- ok &= ns2501_writeb(dvo, 0x8f, 0x00);
-
- ok &= ns2501_writeb(dvo, 0x90, 0xfe); /* vertical. VBIOS left 0xff here, but 0xfe works better */
- ok &= ns2501_writeb(dvo, 0x91, 0x07);
- ok &= ns2501_writeb(dvo, 0x94, 0x00);
- ok &= ns2501_writeb(dvo, 0x95, 0x00);
-
- ok &= ns2501_writeb(dvo, 0x96, 0x00);
-
- ok &= ns2501_writeb(dvo, 0x99, 0x00);
- ok &= ns2501_writeb(dvo, 0x9a, 0x88);
-
- ok &= ns2501_writeb(dvo, 0x9c, 0x23); /* Looks like first and last line of the image. */
- ok &= ns2501_writeb(dvo, 0x9d, 0x00);
- ok &= ns2501_writeb(dvo, 0x9e, 0x25);
- ok &= ns2501_writeb(dvo, 0x9f, 0x03);
-
- ok &= ns2501_writeb(dvo, 0xa4, 0x80);
-
- ok &= ns2501_writeb(dvo, 0xb6, 0x00);
-
- ok &= ns2501_writeb(dvo, 0xb9, 0xc8); /* horizontal? */
- ok &= ns2501_writeb(dvo, 0xba, 0x00); /* horizontal? */
-
- ok &= ns2501_writeb(dvo, 0xc0, 0x05); /* horizontal? */
- ok &= ns2501_writeb(dvo, 0xc1, 0xd7);
-
- ok &= ns2501_writeb(dvo, 0xc2, 0x00);
- ok &= ns2501_writeb(dvo, 0xc3, 0xf8);
-
- ok &= ns2501_writeb(dvo, 0xc4, 0x03);
- ok &= ns2501_writeb(dvo, 0xc5, 0x1a);
-
- ok &= ns2501_writeb(dvo, 0xc6, 0x00);
- ok &= ns2501_writeb(dvo, 0xc7, 0x73);
- ok &= ns2501_writeb(dvo, 0xc8, 0x02);
-
- } else if (mode->hdisplay == 640 && mode->vdisplay == 480) {
- /* mode 274 */
- DRM_DEBUG_KMS("%s: switching to 640x480\n",
- __FUNCTION__);
- /*
- * No, I do not know where this data comes from.
- * It is just what the video bios left in the DVO, so
- * I'm just copying it here over.
- * This also means that I cannot support any other modes
- * except the ones supported by the bios.
- */
- ns->reg_8_shadow &= ~NS2501_8_BPAS;
-
- ok &= ns2501_writeb(dvo, 0x11, 0xa0);
- ok &= ns2501_writeb(dvo, 0x1b, 0x11);
- ok &= ns2501_writeb(dvo, 0x1c, 0x54);
- ok &= ns2501_writeb(dvo, 0x1d, 0x03);
-
- ok &= ns2501_writeb(dvo, 0x34, 0x03);
- ok &= ns2501_writeb(dvo, 0x35, 0xff);
-
- ok &= ns2501_writeb(dvo, 0x80, 0xff);
- ok &= ns2501_writeb(dvo, 0x81, 0x07);
- ok &= ns2501_writeb(dvo, 0x82, 0x3d);
- ok &= ns2501_writeb(dvo, 0x83, 0x05);
-
- ok &= ns2501_writeb(dvo, 0x8d, 0x02);
- ok &= ns2501_writeb(dvo, 0x8e, 0x10);
- ok &= ns2501_writeb(dvo, 0x8f, 0x00);
-
- ok &= ns2501_writeb(dvo, 0x90, 0xff); /* vertical */
- ok &= ns2501_writeb(dvo, 0x91, 0x07);
- ok &= ns2501_writeb(dvo, 0x94, 0x00);
- ok &= ns2501_writeb(dvo, 0x95, 0x00);
-
- ok &= ns2501_writeb(dvo, 0x96, 0x05);
-
- ok &= ns2501_writeb(dvo, 0x99, 0x00);
- ok &= ns2501_writeb(dvo, 0x9a, 0x88);
-
- ok &= ns2501_writeb(dvo, 0x9c, 0x24);
- ok &= ns2501_writeb(dvo, 0x9d, 0x00);
- ok &= ns2501_writeb(dvo, 0x9e, 0x25);
- ok &= ns2501_writeb(dvo, 0x9f, 0x03);
-
- ok &= ns2501_writeb(dvo, 0xa4, 0x84);
-
- ok &= ns2501_writeb(dvo, 0xb6, 0x09);
-
- ok &= ns2501_writeb(dvo, 0xb9, 0xa0); /* horizontal? */
- ok &= ns2501_writeb(dvo, 0xba, 0x00); /* horizontal? */
-
- ok &= ns2501_writeb(dvo, 0xc0, 0x05); /* horizontal? */
- ok &= ns2501_writeb(dvo, 0xc1, 0x90);
-
- ok &= ns2501_writeb(dvo, 0xc2, 0x00);
- ok &= ns2501_writeb(dvo, 0xc3, 0x0f);
-
- ok &= ns2501_writeb(dvo, 0xc4, 0x03);
- ok &= ns2501_writeb(dvo, 0xc5, 0x16);
-
- ok &= ns2501_writeb(dvo, 0xc6, 0x00);
- ok &= ns2501_writeb(dvo, 0xc7, 0x02);
- ok &= ns2501_writeb(dvo, 0xc8, 0x02);
-
- } else if (mode->hdisplay == 1024 && mode->vdisplay == 768) {
- /* mode 280 */
- DRM_DEBUG_KMS("%s: switching to 1024x768\n",
- __FUNCTION__);
- /*
- * This might or might not work, actually. I'm silently
- * assuming here that the native panel resolution is
- * 1024x768. If not, then this leaves the scaler disabled
- * generating a picture that is likely not the expected.
- *
- * Problem is that I do not know where to take the panel
- * dimensions from.
- *
- * Enable the bypass, scaling not required.
- *
- * The scaler registers are irrelevant here....
- *
- */
- ns->reg_8_shadow |= NS2501_8_BPAS;
- ok &= ns2501_writeb(dvo, 0x37, 0x44);
- } else {
- /*
- * Data not known. Bummer!
- * Hopefully, the code should not go here
- * as mode_OK delivered no other modes.
- */
- ns->reg_8_shadow |= NS2501_8_BPAS;
- }
- ok &= ns2501_writeb(dvo, NS2501_REG8, ns->reg_8_shadow);
-
- if (!ok) {
- if (restore)
- restore_dvo(dvo);
- enable_dvo(dvo);
- restore = true;
- }
- } while (!ok);
- /*
- * Restore the old i915 registers before
- * forcing the ns2501 on.
- */
- if (restore)
- restore_dvo(dvo);
-}
-
-/* set the NS2501 power state */
-static bool ns2501_get_hw_state(struct intel_dvo_device *dvo)
-{
- unsigned char ch;
-
- if (!ns2501_readb(dvo, NS2501_REG8, &ch))
- return false;
-
- if (ch & NS2501_8_PD)
- return true;
- else
- return false;
-}
-
-/* set the NS2501 power state */
-static void ns2501_dpms(struct intel_dvo_device *dvo, bool enable)
-{
- bool ok;
- bool restore = false;
- struct ns2501_priv *ns = (struct ns2501_priv *)(dvo->dev_priv);
- unsigned char ch;
-
- DRM_DEBUG_KMS("%s: Trying set the dpms of the DVO to %i\n",
- __FUNCTION__, enable);
-
- ch = ns->reg_8_shadow;
-
- if (enable)
- ch |= NS2501_8_PD;
- else
- ch &= ~NS2501_8_PD;
-
- if (ns->reg_8_set == 0 || ns->reg_8_shadow != ch) {
- ns->reg_8_set = 1;
- ns->reg_8_shadow = ch;
-
- do {
- ok = true;
- ok &= ns2501_writeb(dvo, NS2501_REG8, ch);
- ok &=
- ns2501_writeb(dvo, 0x34,
- enable ? 0x03 : 0x00);
- ok &=
- ns2501_writeb(dvo, 0x35,
- enable ? 0xff : 0x00);
- if (!ok) {
- if (restore)
- restore_dvo(dvo);
- enable_dvo(dvo);
- restore = true;
- }
- } while (!ok);
-
- if (restore)
- restore_dvo(dvo);
- }
-}
-
-static void ns2501_dump_regs(struct intel_dvo_device *dvo)
-{
- uint8_t val;
-
- ns2501_readb(dvo, NS2501_FREQ_LO, &val);
- DRM_LOG_KMS("NS2501_FREQ_LO: 0x%02x\n", val);
- ns2501_readb(dvo, NS2501_FREQ_HI, &val);
- DRM_LOG_KMS("NS2501_FREQ_HI: 0x%02x\n", val);
- ns2501_readb(dvo, NS2501_REG8, &val);
- DRM_LOG_KMS("NS2501_REG8: 0x%02x\n", val);
- ns2501_readb(dvo, NS2501_REG9, &val);
- DRM_LOG_KMS("NS2501_REG9: 0x%02x\n", val);
- ns2501_readb(dvo, NS2501_REGC, &val);
- DRM_LOG_KMS("NS2501_REGC: 0x%02x\n", val);
-}
-
-static void ns2501_destroy(struct intel_dvo_device *dvo)
-{
- struct ns2501_priv *ns = dvo->dev_priv;
-
- if (ns) {
- kfree(ns);
- dvo->dev_priv = NULL;
- }
-}
-
-struct intel_dvo_dev_ops ns2501_ops = {
- .init = ns2501_init,
- .detect = ns2501_detect,
- .mode_valid = ns2501_mode_valid,
- .mode_set = ns2501_mode_set,
- .dpms = ns2501_dpms,
- .get_hw_state = ns2501_get_hw_state,
- .dump_regs = ns2501_dump_regs,
- .destroy = ns2501_destroy,
-};
diff --git a/trunk/drivers/gpu/drm/i915/dvo_sil164.c b/trunk/drivers/gpu/drm/i915/dvo_sil164.c
index 4debd32e3e4c..a0b13a6f619d 100644
--- a/trunk/drivers/gpu/drm/i915/dvo_sil164.c
+++ b/trunk/drivers/gpu/drm/i915/dvo_sil164.c
@@ -208,7 +208,7 @@ static void sil164_mode_set(struct intel_dvo_device *dvo,
}
/* set the SIL164 power state */
-static void sil164_dpms(struct intel_dvo_device *dvo, bool enable)
+static void sil164_dpms(struct intel_dvo_device *dvo, int mode)
{
int ret;
unsigned char ch;
@@ -217,7 +217,7 @@ static void sil164_dpms(struct intel_dvo_device *dvo, bool enable)
if (ret == false)
return;
- if (enable)
+ if (mode == DRM_MODE_DPMS_ON)
ch |= SIL164_8_PD;
else
ch &= ~SIL164_8_PD;
@@ -226,21 +226,6 @@ static void sil164_dpms(struct intel_dvo_device *dvo, bool enable)
return;
}
-static bool sil164_get_hw_state(struct intel_dvo_device *dvo)
-{
- int ret;
- unsigned char ch;
-
- ret = sil164_readb(dvo, SIL164_REG8, &ch);
- if (ret == false)
- return false;
-
- if (ch & SIL164_8_PD)
- return true;
- else
- return false;
-}
-
static void sil164_dump_regs(struct intel_dvo_device *dvo)
{
uint8_t val;
@@ -273,7 +258,6 @@ struct intel_dvo_dev_ops sil164_ops = {
.mode_valid = sil164_mode_valid,
.mode_set = sil164_mode_set,
.dpms = sil164_dpms,
- .get_hw_state = sil164_get_hw_state,
.dump_regs = sil164_dump_regs,
.destroy = sil164_destroy,
};
diff --git a/trunk/drivers/gpu/drm/i915/dvo_tfp410.c b/trunk/drivers/gpu/drm/i915/dvo_tfp410.c
index e17f1b07e915..aa2cd3ec54aa 100644
--- a/trunk/drivers/gpu/drm/i915/dvo_tfp410.c
+++ b/trunk/drivers/gpu/drm/i915/dvo_tfp410.c
@@ -234,14 +234,14 @@ static void tfp410_mode_set(struct intel_dvo_device *dvo,
}
/* set the tfp410 power state */
-static void tfp410_dpms(struct intel_dvo_device *dvo, bool enable)
+static void tfp410_dpms(struct intel_dvo_device *dvo, int mode)
{
uint8_t ctl1;
if (!tfp410_readb(dvo, TFP410_CTL_1, &ctl1))
return;
- if (enable)
+ if (mode == DRM_MODE_DPMS_ON)
ctl1 |= TFP410_CTL_1_PD;
else
ctl1 &= ~TFP410_CTL_1_PD;
@@ -249,19 +249,6 @@ static void tfp410_dpms(struct intel_dvo_device *dvo, bool enable)
tfp410_writeb(dvo, TFP410_CTL_1, ctl1);
}
-static bool tfp410_get_hw_state(struct intel_dvo_device *dvo)
-{
- uint8_t ctl1;
-
- if (!tfp410_readb(dvo, TFP410_CTL_1, &ctl1))
- return false;
-
- if (ctl1 & TFP410_CTL_1_PD)
- return true;
- else
- return false;
-}
-
static void tfp410_dump_regs(struct intel_dvo_device *dvo)
{
uint8_t val, val2;
@@ -312,7 +299,6 @@ struct intel_dvo_dev_ops tfp410_ops = {
.mode_valid = tfp410_mode_valid,
.mode_set = tfp410_mode_set,
.dpms = tfp410_dpms,
- .get_hw_state = tfp410_get_hw_state,
.dump_regs = tfp410_dump_regs,
.destroy = tfp410_destroy,
};
diff --git a/trunk/drivers/gpu/drm/i915/i915_debugfs.c b/trunk/drivers/gpu/drm/i915/i915_debugfs.c
index 7a4b3f3aad3f..359f6e8b9b00 100644
--- a/trunk/drivers/gpu/drm/i915/i915_debugfs.c
+++ b/trunk/drivers/gpu/drm/i915/i915_debugfs.c
@@ -44,6 +44,7 @@
enum {
ACTIVE_LIST,
+ FLUSHING_LIST,
INACTIVE_LIST,
PINNED_LIST,
};
@@ -61,11 +62,28 @@ static int i915_capabilities(struct seq_file *m, void *data)
seq_printf(m, "gen: %d\n", info->gen);
seq_printf(m, "pch: %d\n", INTEL_PCH_TYPE(dev));
-#define DEV_INFO_FLAG(x) seq_printf(m, #x ": %s\n", yesno(info->x))
-#define DEV_INFO_SEP ;
- DEV_INFO_FLAGS;
-#undef DEV_INFO_FLAG
-#undef DEV_INFO_SEP
+#define B(x) seq_printf(m, #x ": %s\n", yesno(info->x))
+ B(is_mobile);
+ B(is_i85x);
+ B(is_i915g);
+ B(is_i945gm);
+ B(is_g33);
+ B(need_gfx_hws);
+ B(is_g4x);
+ B(is_pineview);
+ B(is_broadwater);
+ B(is_crestline);
+ B(has_fbc);
+ B(has_pipe_cxsr);
+ B(has_hotplug);
+ B(cursor_needs_physical);
+ B(has_overlay);
+ B(overlay_needs_physical);
+ B(supports_tv);
+ B(has_bsd_ring);
+ B(has_blt_ring);
+ B(has_llc);
+#undef B
return 0;
}
@@ -103,23 +121,20 @@ static const char *cache_level_str(int type)
static void
describe_obj(struct seq_file *m, struct drm_i915_gem_object *obj)
{
- seq_printf(m, "%p: %s%s %8zdKiB %04x %04x %d %d %d%s%s%s",
+ seq_printf(m, "%p: %s%s %8zdKiB %04x %04x %d %d%s%s%s",
&obj->base,
get_pin_flag(obj),
get_tiling_flag(obj),
obj->base.size / 1024,
obj->base.read_domains,
obj->base.write_domain,
- obj->last_read_seqno,
- obj->last_write_seqno,
+ obj->last_rendering_seqno,
obj->last_fenced_seqno,
cache_level_str(obj->cache_level),
obj->dirty ? " dirty" : "",
obj->madv == I915_MADV_DONTNEED ? " purgeable" : "");
if (obj->base.name)
seq_printf(m, " (name: %d)", obj->base.name);
- if (obj->pin_count)
- seq_printf(m, " (pinned x %d)", obj->pin_count);
if (obj->fence_reg != I915_FENCE_REG_NONE)
seq_printf(m, " (fence: %d)", obj->fence_reg);
if (obj->gtt_space != NULL)
@@ -162,6 +177,10 @@ static int i915_gem_object_list_info(struct seq_file *m, void *data)
seq_printf(m, "Inactive:\n");
head = &dev_priv->mm.inactive_list;
break;
+ case FLUSHING_LIST:
+ seq_printf(m, "Flushing:\n");
+ head = &dev_priv->mm.flushing_list;
+ break;
default:
mutex_unlock(&dev->struct_mutex);
return -EINVAL;
@@ -199,8 +218,8 @@ static int i915_gem_object_info(struct seq_file *m, void* data)
struct drm_info_node *node = (struct drm_info_node *) m->private;
struct drm_device *dev = node->minor->dev;
struct drm_i915_private *dev_priv = dev->dev_private;
- u32 count, mappable_count, purgeable_count;
- size_t size, mappable_size, purgeable_size;
+ u32 count, mappable_count;
+ size_t size, mappable_size;
struct drm_i915_gem_object *obj;
int ret;
@@ -213,12 +232,13 @@ static int i915_gem_object_info(struct seq_file *m, void* data)
dev_priv->mm.object_memory);
size = count = mappable_size = mappable_count = 0;
- count_objects(&dev_priv->mm.bound_list, gtt_list);
+ count_objects(&dev_priv->mm.gtt_list, gtt_list);
seq_printf(m, "%u [%u] objects, %zu [%zu] bytes in gtt\n",
count, mappable_count, size, mappable_size);
size = count = mappable_size = mappable_count = 0;
count_objects(&dev_priv->mm.active_list, mm_list);
+ count_objects(&dev_priv->mm.flushing_list, mm_list);
seq_printf(m, " %u [%u] active objects, %zu [%zu] bytes\n",
count, mappable_count, size, mappable_size);
@@ -227,16 +247,8 @@ static int i915_gem_object_info(struct seq_file *m, void* data)
seq_printf(m, " %u [%u] inactive objects, %zu [%zu] bytes\n",
count, mappable_count, size, mappable_size);
- size = count = purgeable_size = purgeable_count = 0;
- list_for_each_entry(obj, &dev_priv->mm.unbound_list, gtt_list) {
- size += obj->base.size, ++count;
- if (obj->madv == I915_MADV_DONTNEED)
- purgeable_size += obj->base.size, ++purgeable_count;
- }
- seq_printf(m, "%u unbound objects, %zu bytes\n", count, size);
-
size = count = mappable_size = mappable_count = 0;
- list_for_each_entry(obj, &dev_priv->mm.bound_list, gtt_list) {
+ list_for_each_entry(obj, &dev_priv->mm.gtt_list, gtt_list) {
if (obj->fault_mappable) {
size += obj->gtt_space->size;
++count;
@@ -245,13 +257,7 @@ static int i915_gem_object_info(struct seq_file *m, void* data)
mappable_size += obj->gtt_space->size;
++mappable_count;
}
- if (obj->madv == I915_MADV_DONTNEED) {
- purgeable_size += obj->base.size;
- ++purgeable_count;
- }
}
- seq_printf(m, "%u purgeable objects, %zu bytes\n",
- purgeable_count, purgeable_size);
seq_printf(m, "%u pinned mappable objects, %zu bytes\n",
mappable_count, mappable_size);
seq_printf(m, "%u fault mappable objects, %zu bytes\n",
@@ -280,7 +286,7 @@ static int i915_gem_gtt_info(struct seq_file *m, void* data)
return ret;
total_obj_size = total_gtt_size = count = 0;
- list_for_each_entry(obj, &dev_priv->mm.bound_list, gtt_list) {
+ list_for_each_entry(obj, &dev_priv->mm.gtt_list, gtt_list) {
if (list == PINNED_LIST && obj->pin_count == 0)
continue;
@@ -353,22 +359,40 @@ static int i915_gem_request_info(struct seq_file *m, void *data)
struct drm_info_node *node = (struct drm_info_node *) m->private;
struct drm_device *dev = node->minor->dev;
drm_i915_private_t *dev_priv = dev->dev_private;
- struct intel_ring_buffer *ring;
struct drm_i915_gem_request *gem_request;
- int ret, count, i;
+ int ret, count;
ret = mutex_lock_interruptible(&dev->struct_mutex);
if (ret)
return ret;
count = 0;
- for_each_ring(ring, dev_priv, i) {
- if (list_empty(&ring->request_list))
- continue;
-
- seq_printf(m, "%s requests:\n", ring->name);
+ if (!list_empty(&dev_priv->ring[RCS].request_list)) {
+ seq_printf(m, "Render requests:\n");
+ list_for_each_entry(gem_request,
+ &dev_priv->ring[RCS].request_list,
+ list) {
+ seq_printf(m, " %d @ %d\n",
+ gem_request->seqno,
+ (int) (jiffies - gem_request->emitted_jiffies));
+ }
+ count++;
+ }
+ if (!list_empty(&dev_priv->ring[VCS].request_list)) {
+ seq_printf(m, "BSD requests:\n");
+ list_for_each_entry(gem_request,
+ &dev_priv->ring[VCS].request_list,
+ list) {
+ seq_printf(m, " %d @ %d\n",
+ gem_request->seqno,
+ (int) (jiffies - gem_request->emitted_jiffies));
+ }
+ count++;
+ }
+ if (!list_empty(&dev_priv->ring[BCS].request_list)) {
+ seq_printf(m, "BLT requests:\n");
list_for_each_entry(gem_request,
- &ring->request_list,
+ &dev_priv->ring[BCS].request_list,
list) {
seq_printf(m, " %d @ %d\n",
gem_request->seqno,
@@ -389,7 +413,7 @@ static void i915_ring_seqno_info(struct seq_file *m,
{
if (ring->get_seqno) {
seq_printf(m, "Current sequence (%s): %d\n",
- ring->name, ring->get_seqno(ring, false));
+ ring->name, ring->get_seqno(ring));
}
}
@@ -398,15 +422,14 @@ static int i915_gem_seqno_info(struct seq_file *m, void *data)
struct drm_info_node *node = (struct drm_info_node *) m->private;
struct drm_device *dev = node->minor->dev;
drm_i915_private_t *dev_priv = dev->dev_private;
- struct intel_ring_buffer *ring;
int ret, i;
ret = mutex_lock_interruptible(&dev->struct_mutex);
if (ret)
return ret;
- for_each_ring(ring, dev_priv, i)
- i915_ring_seqno_info(m, ring);
+ for (i = 0; i < I915_NUM_RINGS; i++)
+ i915_ring_seqno_info(m, &dev_priv->ring[i]);
mutex_unlock(&dev->struct_mutex);
@@ -419,7 +442,6 @@ static int i915_interrupt_info(struct seq_file *m, void *data)
struct drm_info_node *node = (struct drm_info_node *) m->private;
struct drm_device *dev = node->minor->dev;
drm_i915_private_t *dev_priv = dev->dev_private;
- struct intel_ring_buffer *ring;
int ret, i, pipe;
ret = mutex_lock_interruptible(&dev->struct_mutex);
@@ -497,13 +519,13 @@ static int i915_interrupt_info(struct seq_file *m, void *data)
}
seq_printf(m, "Interrupts received: %d\n",
atomic_read(&dev_priv->irq_received));
- for_each_ring(ring, dev_priv, i) {
+ for (i = 0; i < I915_NUM_RINGS; i++) {
if (IS_GEN6(dev) || IS_GEN7(dev)) {
- seq_printf(m,
- "Graphics Interrupt mask (%s): %08x\n",
- ring->name, I915_READ_IMR(ring));
+ seq_printf(m, "Graphics Interrupt mask (%s): %08x\n",
+ dev_priv->ring[i].name,
+ I915_READ_IMR(&dev_priv->ring[i]));
}
- i915_ring_seqno_info(m, ring);
+ i915_ring_seqno_info(m, &dev_priv->ring[i]);
}
mutex_unlock(&dev->struct_mutex);
@@ -526,8 +548,7 @@ static int i915_gem_fence_regs_info(struct seq_file *m, void *data)
for (i = 0; i < dev_priv->num_fence_regs; i++) {
struct drm_i915_gem_object *obj = dev_priv->fence_regs[i].obj;
- seq_printf(m, "Fence %d, pin count = %d, object = ",
- i, dev_priv->fence_regs[i].pin_count);
+ seq_printf(m, "Fenced object[%2d] = ", i);
if (obj == NULL)
seq_printf(m, "unused");
else
@@ -609,12 +630,12 @@ static void print_error_buffers(struct seq_file *m,
seq_printf(m, "%s [%d]:\n", name, count);
while (count--) {
- seq_printf(m, " %08x %8u %04x %04x %x %x%s%s%s%s%s%s%s",
+ seq_printf(m, " %08x %8u %04x %04x %08x%s%s%s%s%s%s%s",
err->gtt_offset,
err->size,
err->read_domains,
err->write_domain,
- err->rseqno, err->wseqno,
+ err->seqno,
pin_flag(err->pinned),
tiling_flag(err->tiling),
dirty_flag(err->dirty),
@@ -646,9 +667,10 @@ static void i915_ring_error_state(struct seq_file *m,
seq_printf(m, " IPEIR: 0x%08x\n", error->ipeir[ring]);
seq_printf(m, " IPEHR: 0x%08x\n", error->ipehr[ring]);
seq_printf(m, " INSTDONE: 0x%08x\n", error->instdone[ring]);
- if (ring == RCS && INTEL_INFO(dev)->gen >= 4)
+ if (ring == RCS && INTEL_INFO(dev)->gen >= 4) {
+ seq_printf(m, " INSTDONE1: 0x%08x\n", error->instdone1);
seq_printf(m, " BBADDR: 0x%08llx\n", error->bbaddr);
-
+ }
if (INTEL_INFO(dev)->gen >= 4)
seq_printf(m, " INSTPS: 0x%08x\n", error->instps[ring]);
seq_printf(m, " INSTPM: 0x%08x\n", error->instpm[ring]);
@@ -697,17 +719,11 @@ static int i915_error_state(struct seq_file *m, void *unused)
for (i = 0; i < dev_priv->num_fence_regs; i++)
seq_printf(m, " fence[%d] = %08llx\n", i, error->fence[i]);
- for (i = 0; i < ARRAY_SIZE(error->extra_instdone); i++)
- seq_printf(m, " INSTDONE_%d: 0x%08x\n", i, error->extra_instdone[i]);
-
if (INTEL_INFO(dev)->gen >= 6) {
seq_printf(m, "ERROR: 0x%08x\n", error->error);
seq_printf(m, "DONE_REG: 0x%08x\n", error->done_reg);
}
- if (INTEL_INFO(dev)->gen == 7)
- seq_printf(m, "ERR_INT: 0x%08x\n", error->err_int);
-
for_each_ring(ring, dev_priv, i)
i915_ring_error_state(m, dev, error, i);
@@ -783,14 +799,10 @@ i915_error_state_write(struct file *filp,
struct seq_file *m = filp->private_data;
struct i915_error_state_file_priv *error_priv = m->private;
struct drm_device *dev = error_priv->dev;
- int ret;
DRM_DEBUG_DRIVER("Resetting error state\n");
- ret = mutex_lock_interruptible(&dev->struct_mutex);
- if (ret)
- return ret;
-
+ mutex_lock(&dev->struct_mutex);
i915_destroy_error_state(dev);
mutex_unlock(&dev->struct_mutex);
@@ -914,7 +926,7 @@ static int i915_cur_delayinfo(struct seq_file *m, void *unused)
seq_printf(m, "Render p-state limit: %d\n",
rp_state_limits & 0xff);
seq_printf(m, "CAGF: %dMHz\n", ((rpstat & GEN6_CAGF_MASK) >>
- GEN6_CAGF_SHIFT) * GT_FREQUENCY_MULTIPLIER);
+ GEN6_CAGF_SHIFT) * 50);
seq_printf(m, "RP CUR UP EI: %dus\n", rpupei &
GEN6_CURICONT_MASK);
seq_printf(m, "RP CUR UP: %dus\n", rpcurup &
@@ -930,15 +942,15 @@ static int i915_cur_delayinfo(struct seq_file *m, void *unused)
max_freq = (rp_state_cap & 0xff0000) >> 16;
seq_printf(m, "Lowest (RPN) frequency: %dMHz\n",
- max_freq * GT_FREQUENCY_MULTIPLIER);
+ max_freq * 50);
max_freq = (rp_state_cap & 0xff00) >> 8;
seq_printf(m, "Nominal (RP1) frequency: %dMHz\n",
- max_freq * GT_FREQUENCY_MULTIPLIER);
+ max_freq * 50);
max_freq = rp_state_cap & 0xff;
seq_printf(m, "Max non-overclocked (RP0) frequency: %dMHz\n",
- max_freq * GT_FREQUENCY_MULTIPLIER);
+ max_freq * 50);
} else {
seq_printf(m, "no P-state info available\n");
}
@@ -1280,8 +1292,7 @@ static int i915_ring_freq_table(struct seq_file *m, void *unused)
seq_printf(m, "GPU freq (MHz)\tEffective CPU freq (MHz)\n");
- for (gpu_freq = dev_priv->rps.min_delay;
- gpu_freq <= dev_priv->rps.max_delay;
+ for (gpu_freq = dev_priv->min_delay; gpu_freq <= dev_priv->max_delay;
gpu_freq++) {
I915_WRITE(GEN6_PCODE_DATA, gpu_freq);
I915_WRITE(GEN6_PCODE_MAILBOX, GEN6_PCODE_READY |
@@ -1292,7 +1303,7 @@ static int i915_ring_freq_table(struct seq_file *m, void *unused)
continue;
}
ia_freq = I915_READ(GEN6_PCODE_DATA);
- seq_printf(m, "%d\t\t%d\n", gpu_freq * GT_FREQUENCY_MULTIPLIER, ia_freq * 100);
+ seq_printf(m, "%d\t\t%d\n", gpu_freq * 50, ia_freq * 100);
}
mutex_unlock(&dev->struct_mutex);
@@ -1461,12 +1472,8 @@ static int i915_swizzle_info(struct seq_file *m, void *data)
struct drm_info_node *node = (struct drm_info_node *) m->private;
struct drm_device *dev = node->minor->dev;
struct drm_i915_private *dev_priv = dev->dev_private;
- int ret;
-
- ret = mutex_lock_interruptible(&dev->struct_mutex);
- if (ret)
- return ret;
+ mutex_lock(&dev->struct_mutex);
seq_printf(m, "bit6 swizzle for X-tiling = %s\n",
swizzle_string(dev_priv->mm.bit_6_swizzle_x));
seq_printf(m, "bit6 swizzle for Y-tiling = %s\n",
@@ -1513,7 +1520,9 @@ static int i915_ppgtt_info(struct seq_file *m, void *data)
if (INTEL_INFO(dev)->gen == 6)
seq_printf(m, "GFX_MODE: 0x%08x\n", I915_READ(GFX_MODE));
- for_each_ring(ring, dev_priv, i) {
+ for (i = 0; i < I915_NUM_RINGS; i++) {
+ ring = &dev_priv->ring[i];
+
seq_printf(m, "%s\n", ring->name);
if (INTEL_INFO(dev)->gen == 7)
seq_printf(m, "GFX_MODE: 0x%08x\n", I915_READ(RING_MODE_GEN7(ring)));
@@ -1665,7 +1674,7 @@ i915_ring_stop_write(struct file *filp,
struct drm_device *dev = filp->private_data;
struct drm_i915_private *dev_priv = dev->dev_private;
char buf[20];
- int val = 0, ret;
+ int val = 0;
if (cnt > 0) {
if (cnt > sizeof(buf) - 1)
@@ -1680,10 +1689,7 @@ i915_ring_stop_write(struct file *filp,
DRM_DEBUG_DRIVER("Stopping rings 0x%08x\n", val);
- ret = mutex_lock_interruptible(&dev->struct_mutex);
- if (ret)
- return ret;
-
+ mutex_lock(&dev->struct_mutex);
dev_priv->stop_rings = val;
mutex_unlock(&dev->struct_mutex);
@@ -1707,18 +1713,10 @@ i915_max_freq_read(struct file *filp,
struct drm_device *dev = filp->private_data;
drm_i915_private_t *dev_priv = dev->dev_private;
char buf[80];
- int len, ret;
-
- if (!(IS_GEN6(dev) || IS_GEN7(dev)))
- return -ENODEV;
-
- ret = mutex_lock_interruptible(&dev->struct_mutex);
- if (ret)
- return ret;
+ int len;
len = snprintf(buf, sizeof(buf),
- "max freq: %d\n", dev_priv->rps.max_delay * GT_FREQUENCY_MULTIPLIER);
- mutex_unlock(&dev->struct_mutex);
+ "max freq: %d\n", dev_priv->max_delay * 50);
if (len > sizeof(buf))
len = sizeof(buf);
@@ -1735,10 +1733,7 @@ i915_max_freq_write(struct file *filp,
struct drm_device *dev = filp->private_data;
struct drm_i915_private *dev_priv = dev->dev_private;
char buf[20];
- int val = 1, ret;
-
- if (!(IS_GEN6(dev) || IS_GEN7(dev)))
- return -ENODEV;
+ int val = 1;
if (cnt > 0) {
if (cnt > sizeof(buf) - 1)
@@ -1753,17 +1748,12 @@ i915_max_freq_write(struct file *filp,
DRM_DEBUG_DRIVER("Manually setting max freq to %d\n", val);
- ret = mutex_lock_interruptible(&dev->struct_mutex);
- if (ret)
- return ret;
-
/*
* Turbo will still be enabled, but won't go above the set value.
*/
- dev_priv->rps.max_delay = val / GT_FREQUENCY_MULTIPLIER;
+ dev_priv->max_delay = val / 50;
- gen6_set_rps(dev, val / GT_FREQUENCY_MULTIPLIER);
- mutex_unlock(&dev->struct_mutex);
+ gen6_set_rps(dev, val / 50);
return cnt;
}
@@ -1783,18 +1773,10 @@ i915_min_freq_read(struct file *filp, char __user *ubuf, size_t max,
struct drm_device *dev = filp->private_data;
drm_i915_private_t *dev_priv = dev->dev_private;
char buf[80];
- int len, ret;
-
- if (!(IS_GEN6(dev) || IS_GEN7(dev)))
- return -ENODEV;
-
- ret = mutex_lock_interruptible(&dev->struct_mutex);
- if (ret)
- return ret;
+ int len;
len = snprintf(buf, sizeof(buf),
- "min freq: %d\n", dev_priv->rps.min_delay * GT_FREQUENCY_MULTIPLIER);
- mutex_unlock(&dev->struct_mutex);
+ "min freq: %d\n", dev_priv->min_delay * 50);
if (len > sizeof(buf))
len = sizeof(buf);
@@ -1809,10 +1791,7 @@ i915_min_freq_write(struct file *filp, const char __user *ubuf, size_t cnt,
struct drm_device *dev = filp->private_data;
struct drm_i915_private *dev_priv = dev->dev_private;
char buf[20];
- int val = 1, ret;
-
- if (!(IS_GEN6(dev) || IS_GEN7(dev)))
- return -ENODEV;
+ int val = 1;
if (cnt > 0) {
if (cnt > sizeof(buf) - 1)
@@ -1827,17 +1806,12 @@ i915_min_freq_write(struct file *filp, const char __user *ubuf, size_t cnt,
DRM_DEBUG_DRIVER("Manually setting min freq to %d\n", val);
- ret = mutex_lock_interruptible(&dev->struct_mutex);
- if (ret)
- return ret;
-
/*
* Turbo will still be enabled, but won't go below the set value.
*/
- dev_priv->rps.min_delay = val / GT_FREQUENCY_MULTIPLIER;
+ dev_priv->min_delay = val / 50;
- gen6_set_rps(dev, val / GT_FREQUENCY_MULTIPLIER);
- mutex_unlock(&dev->struct_mutex);
+ gen6_set_rps(dev, val / 50);
return cnt;
}
@@ -1860,15 +1834,9 @@ i915_cache_sharing_read(struct file *filp,
drm_i915_private_t *dev_priv = dev->dev_private;
char buf[80];
u32 snpcr;
- int len, ret;
-
- if (!(IS_GEN6(dev) || IS_GEN7(dev)))
- return -ENODEV;
-
- ret = mutex_lock_interruptible(&dev->struct_mutex);
- if (ret)
- return ret;
+ int len;
+ mutex_lock(&dev_priv->dev->struct_mutex);
snpcr = I915_READ(GEN6_MBCUNIT_SNPCR);
mutex_unlock(&dev_priv->dev->struct_mutex);
@@ -1894,9 +1862,6 @@ i915_cache_sharing_write(struct file *filp,
u32 snpcr;
int val = 1;
- if (!(IS_GEN6(dev) || IS_GEN7(dev)))
- return -ENODEV;
-
if (cnt > 0) {
if (cnt > sizeof(buf) - 1)
return -EINVAL;
@@ -1960,11 +1925,16 @@ static int i915_forcewake_open(struct inode *inode, struct file *file)
{
struct drm_device *dev = inode->i_private;
struct drm_i915_private *dev_priv = dev->dev_private;
+ int ret;
if (INTEL_INFO(dev)->gen < 6)
return 0;
+ ret = mutex_lock_interruptible(&dev->struct_mutex);
+ if (ret)
+ return ret;
gen6_gt_force_wake_get(dev_priv);
+ mutex_unlock(&dev->struct_mutex);
return 0;
}
@@ -1977,7 +1947,16 @@ static int i915_forcewake_release(struct inode *inode, struct file *file)
if (INTEL_INFO(dev)->gen < 6)
return 0;
+ /*
+ * It's bad that we can potentially hang userspace if struct_mutex gets
+ * forever stuck. However, if we cannot acquire this lock it means that
+ * almost certainly the driver has hung, is not unload-able. Therefore
+ * hanging here is probably a minor inconvenience not to be seen my
+ * almost every user.
+ */
+ mutex_lock(&dev->struct_mutex);
gen6_gt_force_wake_put(dev_priv);
+ mutex_unlock(&dev->struct_mutex);
return 0;
}
@@ -2027,6 +2006,7 @@ static struct drm_info_list i915_debugfs_list[] = {
{"i915_gem_gtt", i915_gem_gtt_info, 0},
{"i915_gem_pinned", i915_gem_gtt_info, 0, (void *) PINNED_LIST},
{"i915_gem_active", i915_gem_object_list_info, 0, (void *) ACTIVE_LIST},
+ {"i915_gem_flushing", i915_gem_object_list_info, 0, (void *) FLUSHING_LIST},
{"i915_gem_inactive", i915_gem_object_list_info, 0, (void *) INACTIVE_LIST},
{"i915_gem_pageflip", i915_gem_pageflip_info, 0},
{"i915_gem_request", i915_gem_request_info, 0},
@@ -2087,7 +2067,6 @@ int i915_debugfs_init(struct drm_minor *minor)
&i915_cache_sharing_fops);
if (ret)
return ret;
-
ret = i915_debugfs_create(minor->debugfs_root, minor,
"i915_ring_stop",
&i915_ring_stop_fops);
diff --git a/trunk/drivers/gpu/drm/i915/i915_dma.c b/trunk/drivers/gpu/drm/i915/i915_dma.c
index ffbc9156c792..914c0dfabe60 100644
--- a/trunk/drivers/gpu/drm/i915/i915_dma.c
+++ b/trunk/drivers/gpu/drm/i915/i915_dma.c
@@ -235,10 +235,10 @@ static int i915_initialize(struct drm_device * dev, drm_i915_init_t * init)
}
}
- dev_priv->dri1.cpp = init->cpp;
- dev_priv->dri1.back_offset = init->back_offset;
- dev_priv->dri1.front_offset = init->front_offset;
- dev_priv->dri1.current_page = 0;
+ dev_priv->cpp = init->cpp;
+ dev_priv->back_offset = init->back_offset;
+ dev_priv->front_offset = init->front_offset;
+ dev_priv->current_page = 0;
if (master_priv->sarea_priv)
master_priv->sarea_priv->pf_current_page = 0;
@@ -575,7 +575,7 @@ static int i915_dispatch_flip(struct drm_device * dev)
DRM_DEBUG_DRIVER("%s: page=%d pfCurrentPage=%d\n",
__func__,
- dev_priv->dri1.current_page,
+ dev_priv->current_page,
master_priv->sarea_priv->pf_current_page);
i915_kernel_lost_context(dev);
@@ -589,12 +589,12 @@ static int i915_dispatch_flip(struct drm_device * dev)
OUT_RING(CMD_OP_DISPLAYBUFFER_INFO | ASYNC_FLIP);
OUT_RING(0);
- if (dev_priv->dri1.current_page == 0) {
- OUT_RING(dev_priv->dri1.back_offset);
- dev_priv->dri1.current_page = 1;
+ if (dev_priv->current_page == 0) {
+ OUT_RING(dev_priv->back_offset);
+ dev_priv->current_page = 1;
} else {
- OUT_RING(dev_priv->dri1.front_offset);
- dev_priv->dri1.current_page = 0;
+ OUT_RING(dev_priv->front_offset);
+ dev_priv->current_page = 0;
}
OUT_RING(0);
@@ -613,7 +613,7 @@ static int i915_dispatch_flip(struct drm_device * dev)
ADVANCE_LP_RING();
}
- master_priv->sarea_priv->pf_current_page = dev_priv->dri1.current_page;
+ master_priv->sarea_priv->pf_current_page = dev_priv->current_page;
return 0;
}
@@ -1009,12 +1009,6 @@ static int i915_getparam(struct drm_device *dev, void *data,
case I915_PARAM_HAS_WAIT_TIMEOUT:
value = 1;
break;
- case I915_PARAM_HAS_SEMAPHORES:
- value = i915_semaphore_is_enabled(dev);
- break;
- case I915_PARAM_HAS_PRIME_VMAP_FLUSH:
- value = 1;
- break;
default:
DRM_DEBUG_DRIVER("Unknown parameter %d\n",
param->param);
@@ -1431,21 +1425,6 @@ static void i915_kick_out_firmware_fb(struct drm_i915_private *dev_priv)
kfree(ap);
}
-static void i915_dump_device_info(struct drm_i915_private *dev_priv)
-{
- const struct intel_device_info *info = dev_priv->info;
-
-#define DEV_INFO_FLAG(name) info->name ? #name "," : ""
-#define DEV_INFO_SEP ,
- DRM_DEBUG_DRIVER("i915 device info: gen=%i, pciid=0x%04x flags="
- "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s",
- info->gen,
- dev_priv->dev->pdev->device,
- DEV_INFO_FLAGS);
-#undef DEV_INFO_FLAG
-#undef DEV_INFO_SEP
-}
-
/**
* i915_driver_load - setup chip and create an initial config
* @dev: DRM device
@@ -1461,7 +1440,7 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
{
struct drm_i915_private *dev_priv;
struct intel_device_info *info;
- int ret = 0, mmio_bar, mmio_size;
+ int ret = 0, mmio_bar;
uint32_t aperture_size;
info = (struct intel_device_info *) flags;
@@ -1470,6 +1449,7 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
if (info->gen >= 6 && !drm_core_check_feature(dev, DRIVER_MODESET))
return -ENODEV;
+
/* i915 has 4 more counters */
dev->counters += 4;
dev->types[6] = _DRM_STAT_IRQ;
@@ -1485,8 +1465,6 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
dev_priv->dev = dev;
dev_priv->info = info;
- i915_dump_device_info(dev_priv);
-
if (i915_get_bridge_dev(dev)) {
ret = -EIO;
goto free_priv;
@@ -1526,19 +1504,7 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
dma_set_coherent_mask(&dev->pdev->dev, DMA_BIT_MASK(32));
mmio_bar = IS_GEN2(dev) ? 1 : 0;
- /* Before gen4, the registers and the GTT are behind different BARs.
- * However, from gen4 onwards, the registers and the GTT are shared
- * in the same BAR, so we want to restrict this ioremap from
- * clobbering the GTT which we want ioremap_wc instead. Fortunately,
- * the register BAR remains the same size for all the earlier
- * generations up to Ironlake.
- */
- if (info->gen < 5)
- mmio_size = 512*1024;
- else
- mmio_size = 2*1024*1024;
-
- dev_priv->regs = pci_iomap(dev->pdev, mmio_bar, mmio_size);
+ dev_priv->regs = pci_iomap(dev->pdev, mmio_bar, 0);
if (!dev_priv->regs) {
DRM_ERROR("failed to map registers\n");
ret = -EIO;
@@ -1570,9 +1536,11 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
*
* All tasks on the workqueue are expected to acquire the dev mutex
* so there is no point in running more than one instance of the
- * workqueue at any time. Use an ordered one.
+ * workqueue at any time: max_active = 1 and NON_REENTRANT.
*/
- dev_priv->wq = alloc_ordered_workqueue("i915", 0);
+ dev_priv->wq = alloc_workqueue("i915",
+ WQ_UNBOUND | WQ_NON_REENTRANT,
+ 1);
if (dev_priv->wq == NULL) {
DRM_ERROR("Failed to create our workqueue.\n");
ret = -ENOMEM;
@@ -1618,7 +1586,7 @@ 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->rps.lock);
+ spin_lock_init(&dev_priv->rps_lock);
spin_lock_init(&dev_priv->dpio_lock);
if (IS_IVYBRIDGE(dev) || IS_HASWELL(dev))
@@ -1868,8 +1836,6 @@ struct drm_ioctl_desc i915_ioctls[] = {
DRM_IOCTL_DEF_DRV(I915_GEM_PIN, i915_gem_pin_ioctl, DRM_AUTH|DRM_ROOT_ONLY|DRM_UNLOCKED),
DRM_IOCTL_DEF_DRV(I915_GEM_UNPIN, i915_gem_unpin_ioctl, DRM_AUTH|DRM_ROOT_ONLY|DRM_UNLOCKED),
DRM_IOCTL_DEF_DRV(I915_GEM_BUSY, i915_gem_busy_ioctl, DRM_AUTH|DRM_UNLOCKED),
- DRM_IOCTL_DEF_DRV(I915_GEM_SET_CACHING, i915_gem_set_caching_ioctl, DRM_UNLOCKED),
- DRM_IOCTL_DEF_DRV(I915_GEM_GET_CACHING, i915_gem_get_caching_ioctl, DRM_UNLOCKED),
DRM_IOCTL_DEF_DRV(I915_GEM_THROTTLE, i915_gem_throttle_ioctl, DRM_AUTH|DRM_UNLOCKED),
DRM_IOCTL_DEF_DRV(I915_GEM_ENTERVT, i915_gem_entervt_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY|DRM_UNLOCKED),
DRM_IOCTL_DEF_DRV(I915_GEM_LEAVEVT, i915_gem_leavevt_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY|DRM_UNLOCKED),
@@ -1892,7 +1858,6 @@ struct drm_ioctl_desc i915_ioctls[] = {
DRM_IOCTL_DEF_DRV(I915_GEM_WAIT, i915_gem_wait_ioctl, DRM_AUTH|DRM_UNLOCKED),
DRM_IOCTL_DEF_DRV(I915_GEM_CONTEXT_CREATE, i915_gem_context_create_ioctl, DRM_UNLOCKED),
DRM_IOCTL_DEF_DRV(I915_GEM_CONTEXT_DESTROY, i915_gem_context_destroy_ioctl, DRM_UNLOCKED),
- DRM_IOCTL_DEF_DRV(I915_REG_READ, i915_reg_read_ioctl, DRM_UNLOCKED),
};
int i915_max_ioctl = DRM_ARRAY_SIZE(i915_ioctls);
diff --git a/trunk/drivers/gpu/drm/i915/i915_drv.c b/trunk/drivers/gpu/drm/i915/i915_drv.c
index a7837e556945..a24ffbe97c01 100644
--- a/trunk/drivers/gpu/drm/i915/i915_drv.c
+++ b/trunk/drivers/gpu/drm/i915/i915_drv.c
@@ -470,9 +470,6 @@ static int i915_drm_freeze(struct drm_device *dev)
"GEM idle failed, resume might fail\n");
return error;
}
-
- intel_modeset_disable(dev);
-
drm_irq_uninstall(dev);
}
@@ -546,9 +543,13 @@ static int i915_drm_thaw(struct drm_device *dev)
mutex_unlock(&dev->struct_mutex);
intel_modeset_init_hw(dev);
- intel_modeset_setup_hw_state(dev);
drm_mode_config_reset(dev);
drm_irq_install(dev);
+
+ /* Resume the modeset for every activated CRTC */
+ mutex_lock(&dev->mode_config.mutex);
+ drm_helper_resume_force_mode(dev);
+ mutex_unlock(&dev->mode_config.mutex);
}
intel_opregion_init(dev);
@@ -1059,7 +1060,7 @@ static bool IS_DISPLAYREG(u32 reg)
* This should make it easier to transition modules over to the
* new register block scheme, since we can do it incrementally.
*/
- if (reg >= VLV_DISPLAY_BASE)
+ if (reg >= 0x180000)
return false;
if (reg >= RENDER_RING_BASE &&
@@ -1173,59 +1174,9 @@ void i915_write##x(struct drm_i915_private *dev_priv, u32 reg, u##x val) { \
if (unlikely(__fifo_ret)) { \
gen6_gt_check_fifodbg(dev_priv); \
} \
- if (IS_HASWELL(dev_priv->dev) && (I915_READ_NOTRACE(GEN7_ERR_INT) & ERR_INT_MMIO_UNCLAIMED)) { \
- DRM_ERROR("Unclaimed write to %x\n", reg); \
- writel(ERR_INT_MMIO_UNCLAIMED, dev_priv->regs + GEN7_ERR_INT); \
- } \
}
__i915_write(8, b)
__i915_write(16, w)
__i915_write(32, l)
__i915_write(64, q)
#undef __i915_write
-
-static const struct register_whitelist {
- uint64_t offset;
- uint32_t size;
- uint32_t gen_bitmask; /* support gens, 0x10 for 4, 0x30 for 4 and 5, etc. */
-} whitelist[] = {
- { RING_TIMESTAMP(RENDER_RING_BASE), 8, 0xF0 },
-};
-
-int i915_reg_read_ioctl(struct drm_device *dev,
- void *data, struct drm_file *file)
-{
- struct drm_i915_private *dev_priv = dev->dev_private;
- struct drm_i915_reg_read *reg = data;
- struct register_whitelist const *entry = whitelist;
- int i;
-
- for (i = 0; i < ARRAY_SIZE(whitelist); i++, entry++) {
- if (entry->offset == reg->offset &&
- (1 << INTEL_INFO(dev)->gen & entry->gen_bitmask))
- break;
- }
-
- if (i == ARRAY_SIZE(whitelist))
- return -EINVAL;
-
- switch (entry->size) {
- case 8:
- reg->val = I915_READ64(reg->offset);
- break;
- case 4:
- reg->val = I915_READ(reg->offset);
- break;
- case 2:
- reg->val = I915_READ16(reg->offset);
- break;
- case 1:
- reg->val = I915_READ8(reg->offset);
- break;
- default:
- WARN_ON(1);
- return -EINVAL;
- }
-
- return 0;
-}
diff --git a/trunk/drivers/gpu/drm/i915/i915_drv.h b/trunk/drivers/gpu/drm/i915/i915_drv.h
index 4f2831aa5fed..627fe35781b4 100644
--- a/trunk/drivers/gpu/drm/i915/i915_drv.h
+++ b/trunk/drivers/gpu/drm/i915/i915_drv.h
@@ -109,7 +109,6 @@ struct intel_pch_pll {
#define WATCH_COHERENCY 0
#define WATCH_LISTS 0
-#define WATCH_GTT 0
#define I915_GEM_PHYS_CURSOR_0 1
#define I915_GEM_PHYS_CURSOR_1 2
@@ -196,10 +195,9 @@ struct drm_i915_error_state {
u32 cpu_ring_head[I915_NUM_RINGS];
u32 cpu_ring_tail[I915_NUM_RINGS];
u32 error; /* gen6+ */
- u32 err_int; /* gen7 */
u32 instpm[I915_NUM_RINGS];
u32 instps[I915_NUM_RINGS];
- u32 extra_instdone[I915_NUM_INSTDONE_REG];
+ u32 instdone1;
u32 seqno[I915_NUM_RINGS];
u64 bbaddr;
u32 fault_reg[I915_NUM_RINGS];
@@ -223,7 +221,7 @@ struct drm_i915_error_state {
struct drm_i915_error_buffer {
u32 size;
u32 name;
- u32 rseqno, wseqno;
+ u32 seqno;
u32 gtt_offset;
u32 read_domains;
u32 write_domain;
@@ -241,6 +239,7 @@ struct drm_i915_error_state {
};
struct drm_i915_display_funcs {
+ void (*dpms)(struct drm_crtc *crtc, int mode);
bool (*fbc_enabled)(struct drm_device *dev);
void (*enable_fbc)(struct drm_crtc *crtc, unsigned long interval);
void (*disable_fbc)(struct drm_device *dev);
@@ -249,6 +248,7 @@ struct drm_i915_display_funcs {
void (*update_wm)(struct drm_device *dev);
void (*update_sprite_wm)(struct drm_device *dev, int pipe,
uint32_t sprite_width, int pixel_size);
+ void (*sanitize_pm)(struct drm_device *dev);
void (*update_linetime_wm)(struct drm_device *dev, int pipe,
struct drm_display_mode *mode);
int (*crtc_mode_set)(struct drm_crtc *crtc,
@@ -256,8 +256,6 @@ struct drm_i915_display_funcs {
struct drm_display_mode *adjusted_mode,
int x, int y,
struct drm_framebuffer *old_fb);
- void (*crtc_enable)(struct drm_crtc *crtc);
- void (*crtc_disable)(struct drm_crtc *crtc);
void (*off)(struct drm_crtc *crtc);
void (*write_eld)(struct drm_connector *connector,
struct drm_crtc *crtc);
@@ -281,32 +279,6 @@ struct drm_i915_gt_funcs {
void (*force_wake_put)(struct drm_i915_private *dev_priv);
};
-#define DEV_INFO_FLAGS \
- DEV_INFO_FLAG(is_mobile) DEV_INFO_SEP \
- DEV_INFO_FLAG(is_i85x) DEV_INFO_SEP \
- DEV_INFO_FLAG(is_i915g) DEV_INFO_SEP \
- DEV_INFO_FLAG(is_i945gm) DEV_INFO_SEP \
- DEV_INFO_FLAG(is_g33) DEV_INFO_SEP \
- DEV_INFO_FLAG(need_gfx_hws) DEV_INFO_SEP \
- DEV_INFO_FLAG(is_g4x) DEV_INFO_SEP \
- DEV_INFO_FLAG(is_pineview) DEV_INFO_SEP \
- DEV_INFO_FLAG(is_broadwater) DEV_INFO_SEP \
- DEV_INFO_FLAG(is_crestline) DEV_INFO_SEP \
- DEV_INFO_FLAG(is_ivybridge) DEV_INFO_SEP \
- DEV_INFO_FLAG(is_valleyview) DEV_INFO_SEP \
- DEV_INFO_FLAG(is_haswell) DEV_INFO_SEP \
- DEV_INFO_FLAG(has_force_wake) DEV_INFO_SEP \
- DEV_INFO_FLAG(has_fbc) DEV_INFO_SEP \
- DEV_INFO_FLAG(has_pipe_cxsr) DEV_INFO_SEP \
- DEV_INFO_FLAG(has_hotplug) DEV_INFO_SEP \
- DEV_INFO_FLAG(cursor_needs_physical) DEV_INFO_SEP \
- DEV_INFO_FLAG(has_overlay) DEV_INFO_SEP \
- DEV_INFO_FLAG(overlay_needs_physical) DEV_INFO_SEP \
- DEV_INFO_FLAG(supports_tv) DEV_INFO_SEP \
- DEV_INFO_FLAG(has_bsd_ring) DEV_INFO_SEP \
- DEV_INFO_FLAG(has_blt_ring) DEV_INFO_SEP \
- DEV_INFO_FLAG(has_llc)
-
struct intel_device_info {
u8 gen;
u8 is_mobile:1;
@@ -430,6 +402,12 @@ typedef struct drm_i915_private {
struct resource mch_res;
+ unsigned int cpp;
+ int back_offset;
+ int front_offset;
+ int current_page;
+ int page_flipping;
+
atomic_t irq_received;
/* protects the irq masks */
@@ -447,6 +425,7 @@ typedef struct drm_i915_private {
u32 hotplug_supported_mask;
struct work_struct hotplug_work;
+ unsigned int sr01, adpa, ppcr, dvob, dvoc, lvds;
int num_pipe;
int num_pch_pll;
@@ -455,7 +434,8 @@ typedef struct drm_i915_private {
struct timer_list hangcheck_timer;
int hangcheck_count;
uint32_t last_acthd[I915_NUM_RINGS];
- uint32_t prev_instdone[I915_NUM_INSTDONE_REG];
+ uint32_t last_instdone;
+ uint32_t last_instdone1;
unsigned int stop_rings;
@@ -686,13 +666,7 @@ typedef struct drm_i915_private {
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 list_head gtt_list;
/** Usable portion of the GTT for GEM */
unsigned long gtt_start;
@@ -721,6 +695,17 @@ typedef struct drm_i915_private {
*/
struct list_head active_list;
+ /**
+ * List of objects which are not in the ringbuffer but which
+ * still have a write_domain which needs to be flushed before
+ * unbinding.
+ *
+ * last_rendering_seqno is 0 while an object is in this list.
+ *
+ * A reference is held on the buffer while on this list.
+ */
+ struct list_head flushing_list;
+
/**
* LRU list of objects which are not in the ringbuffer and
* are ready to unbind, but are still in the GTT.
@@ -790,12 +775,6 @@ typedef struct drm_i915_private {
struct {
unsigned allow_batchbuffer : 1;
u32 __iomem *gfx_hws_cpu_addr;
-
- unsigned int cpp;
- int back_offset;
- int front_offset;
- int current_page;
- int page_flipping;
} dri1;
/* Kernel Modesetting */
@@ -817,6 +796,9 @@ typedef struct drm_i915_private {
bool lvds_downclock_avail;
/* indicates the reduced downclock for LVDS*/
int lvds_downclock;
+ struct work_struct idle_work;
+ struct timer_list idle_timer;
+ bool busy;
u16 orig_clock;
int child_dev_num;
struct child_device_config *child_dev;
@@ -825,41 +807,26 @@ typedef struct drm_i915_private {
bool mchbar_need_disable;
- /* gen6+ rps state */
- struct {
- struct work_struct work;
- u32 pm_iir;
- /* lock - irqsave spinlock that protectects the work_struct and
- * pm_iir. */
- spinlock_t lock;
-
- /* The below variables an all the rps hw state are protected by
- * dev->struct mutext. */
- u8 cur_delay;
- u8 min_delay;
- u8 max_delay;
- } rps;
-
- /* ilk-only ips/rps state. Everything in here is protected by the global
- * mchdev_lock in intel_pm.c */
- struct {
- u8 cur_delay;
- u8 min_delay;
- u8 max_delay;
- u8 fmax;
- u8 fstart;
-
- u64 last_count1;
- unsigned long last_time1;
- unsigned long chipset_power;
- u64 last_count2;
- struct timespec last_time2;
- unsigned long gfx_power;
- u8 corr;
-
- int c_m;
- int r_t;
- } ips;
+ struct work_struct rps_work;
+ spinlock_t rps_lock;
+ u32 pm_iir;
+
+ u8 cur_delay;
+ u8 min_delay;
+ u8 max_delay;
+ u8 fmax;
+ u8 fstart;
+
+ u64 last_count1;
+ unsigned long last_time1;
+ unsigned long chipset_power;
+ u64 last_count2;
+ struct timespec last_time2;
+ unsigned long gfx_power;
+ int c_m;
+ int r_t;
+ u8 corr;
+ spinlock_t *mchdev_lock;
enum no_fbc_reason no_fbc_reason;
@@ -894,48 +861,30 @@ enum hdmi_force_audio {
};
enum i915_cache_level {
- I915_CACHE_NONE = 0,
+ I915_CACHE_NONE,
I915_CACHE_LLC,
- I915_CACHE_LLC_MLC, /* gen6+, in docs at least! */
-};
-
-struct drm_i915_gem_object_ops {
- /* Interface between the GEM object and its backing storage.
- * get_pages() is called once prior to the use of the associated set
- * of pages before to binding them into the GTT, and put_pages() is
- * called after we no longer need them. As we expect there to be
- * associated cost with migrating pages between the backing storage
- * and making them available for the GPU (e.g. clflush), we may hold
- * onto the pages after they are no longer referenced by the GPU
- * in case they may be used again shortly (for example migrating the
- * pages to a different memory domain within the GTT). put_pages()
- * will therefore most likely be called when the object itself is
- * being released or under memory pressure (where we attempt to
- * reap pages for the shrinker).
- */
- int (*get_pages)(struct drm_i915_gem_object *);
- void (*put_pages)(struct drm_i915_gem_object *);
+ I915_CACHE_LLC_MLC, /* gen6+ */
};
struct drm_i915_gem_object {
struct drm_gem_object base;
- const struct drm_i915_gem_object_ops *ops;
-
/** Current space allocated to this object in the GTT, if any. */
struct drm_mm_node *gtt_space;
struct list_head gtt_list;
- /** This object's place on the active/inactive lists */
+ /** This object's place on the active/flushing/inactive lists */
struct list_head ring_list;
struct list_head mm_list;
+ /** This object's place on GPU write list */
+ struct list_head gpu_write_list;
/** This object's place in the batchbuffer or on the eviction list */
struct list_head exec_list;
/**
- * This is set if the object is on the active lists (has pending
- * rendering and so a non-zero seqno), and is not set if it i s on
- * inactive (ready to be unbound) list.
+ * This is set if the object is on the active or flushing lists
+ * (has pending rendering), and is not set if it's on inactive (ready
+ * to be unbound).
*/
unsigned int active:1;
@@ -945,6 +894,12 @@ struct drm_i915_gem_object {
*/
unsigned int dirty:1;
+ /**
+ * This is set if the object has been written to since the last
+ * GPU flush.
+ */
+ unsigned int pending_gpu_write:1;
+
/**
* Fence register bits (if any) for this object. Will be set
* as needed when mapped into the GTT.
@@ -1006,12 +961,17 @@ struct drm_i915_gem_object {
unsigned int has_aliasing_ppgtt_mapping:1;
unsigned int has_global_gtt_mapping:1;
- unsigned int has_dma_mapping:1;
- struct sg_table *pages;
- int pages_pin_count;
+ struct page **pages;
+
+ /**
+ * DMAR support
+ */
+ struct scatterlist *sg_list;
+ int num_sg;
/* prime dma-buf support */
+ struct sg_table *sg_table;
void *dma_buf_vmapping;
int vmapping_count;
@@ -1032,8 +992,7 @@ struct drm_i915_gem_object {
struct intel_ring_buffer *ring;
/** Breadcrumb of last rendering to the buffer. */
- uint32_t last_read_seqno;
- uint32_t last_write_seqno;
+ uint32_t last_rendering_seqno;
/** Breadcrumb of last fenced GPU access to the buffer. */
uint32_t last_fenced_seqno;
@@ -1176,10 +1135,6 @@ struct drm_i915_file_private {
#define HAS_FORCE_WAKE(dev) (INTEL_INFO(dev)->has_force_wake)
-#define HAS_L3_GPU_CACHE(dev) (IS_IVYBRIDGE(dev) || IS_HASWELL(dev))
-
-#define GT_FREQUENCY_MULTIPLIER 50
-
#include "i915_trace.h"
/**
@@ -1301,10 +1256,6 @@ int i915_gem_unpin_ioctl(struct drm_device *dev, void *data,
struct drm_file *file_priv);
int i915_gem_busy_ioctl(struct drm_device *dev, void *data,
struct drm_file *file_priv);
-int i915_gem_get_caching_ioctl(struct drm_device *dev, void *data,
- struct drm_file *file);
-int i915_gem_set_caching_ioctl(struct drm_device *dev, void *data,
- struct drm_file *file);
int i915_gem_throttle_ioctl(struct drm_device *dev, void *data,
struct drm_file *file_priv);
int i915_gem_madvise_ioctl(struct drm_device *dev, void *data,
@@ -1323,42 +1274,24 @@ int i915_gem_wait_ioctl(struct drm_device *dev, void *data,
struct drm_file *file_priv);
void i915_gem_load(struct drm_device *dev);
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);
+int __must_check i915_gem_flush_ring(struct intel_ring_buffer *ring,
+ uint32_t invalidate_domains,
+ uint32_t flush_domains);
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);
+ bool map_and_fenceable);
void i915_gem_object_unpin(struct drm_i915_gem_object *obj);
int __must_check i915_gem_object_unbind(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);
-int __must_check i915_gem_object_get_pages(struct drm_i915_gem_object *obj);
-static inline struct page *i915_gem_object_get_page(struct drm_i915_gem_object *obj, int n)
-{
- struct scatterlist *sg = obj->pages->sgl;
- while (n >= SG_MAX_SINGLE_ALLOC) {
- sg = sg_chain_ptr(sg + SG_MAX_SINGLE_ALLOC - 1);
- n -= SG_MAX_SINGLE_ALLOC - 1;
- }
- return sg_page(sg+n);
-}
-static inline void i915_gem_object_pin_pages(struct drm_i915_gem_object *obj)
-{
- BUG_ON(obj->pages == NULL);
- obj->pages_pin_count++;
-}
-static inline void i915_gem_object_unpin_pages(struct drm_i915_gem_object *obj)
-{
- BUG_ON(obj->pages_pin_count == 0);
- obj->pages_pin_count--;
-}
-
+int i915_gem_object_get_pages_gtt(struct drm_i915_gem_object *obj,
+ gfp_t gfpmask);
int __must_check i915_mutex_lock_interruptible(struct drm_device *dev);
+int __must_check i915_gem_object_wait_rendering(struct drm_i915_gem_object *obj);
int i915_gem_object_sync(struct drm_i915_gem_object *obj,
struct intel_ring_buffer *to);
void i915_gem_object_move_to_active(struct drm_i915_gem_object *obj,
@@ -1425,9 +1358,9 @@ void i915_gem_init_ppgtt(struct drm_device *dev);
void i915_gem_cleanup_ringbuffer(struct drm_device *dev);
int __must_check i915_gpu_idle(struct drm_device *dev);
int __must_check i915_gem_idle(struct drm_device *dev);
-int i915_add_request(struct intel_ring_buffer *ring,
- struct drm_file *file,
- struct drm_i915_gem_request *request);
+int __must_check i915_add_request(struct intel_ring_buffer *ring,
+ struct drm_file *file,
+ struct drm_i915_gem_request *request);
int __must_check i915_wait_seqno(struct intel_ring_buffer *ring,
uint32_t seqno);
int i915_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf);
@@ -1496,11 +1429,8 @@ void i915_gem_init_global_gtt(struct drm_device *dev,
/* i915_gem_evict.c */
int __must_check i915_gem_evict_something(struct drm_device *dev, int min_size,
- unsigned alignment,
- unsigned cache_level,
- bool mappable,
- bool nonblock);
-int i915_gem_evict_everything(struct drm_device *dev);
+ unsigned alignment, bool mappable);
+int i915_gem_evict_everything(struct drm_device *dev, bool purgeable_only);
/* i915_gem_stolen.c */
int i915_gem_init_stolen(struct drm_device *dev);
@@ -1589,7 +1519,6 @@ extern void intel_modeset_init(struct drm_device *dev);
extern void intel_modeset_gem_init(struct drm_device *dev);
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);
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);
@@ -1600,8 +1529,6 @@ extern int intel_trans_dp_port_sel(struct drm_crtc *crtc);
extern int intel_enable_rc6(const struct drm_device *dev);
extern bool i915_semaphore_is_enabled(struct drm_device *dev);
-int i915_reg_read_ioctl(struct drm_device *dev, void *data,
- struct drm_file *file);
/* overlay */
#ifdef CONFIG_DEBUG_FS
diff --git a/trunk/drivers/gpu/drm/i915/i915_gem.c b/trunk/drivers/gpu/drm/i915/i915_gem.c
index 365a7dc8a4a8..489e2b162b27 100644
--- a/trunk/drivers/gpu/drm/i915/i915_gem.c
+++ b/trunk/drivers/gpu/drm/i915/i915_gem.c
@@ -37,12 +37,12 @@
#include
#include
+static __must_check int i915_gem_object_flush_gpu_write_domain(struct drm_i915_gem_object *obj);
static void i915_gem_object_flush_gtt_write_domain(struct drm_i915_gem_object *obj);
static void i915_gem_object_flush_cpu_write_domain(struct drm_i915_gem_object *obj);
static __must_check int i915_gem_object_bind_to_gtt(struct drm_i915_gem_object *obj,
unsigned alignment,
- bool map_and_fenceable,
- bool nonblocking);
+ bool map_and_fenceable);
static int i915_gem_phys_pwrite(struct drm_device *dev,
struct drm_i915_gem_object *obj,
struct drm_i915_gem_pwrite *args,
@@ -56,8 +56,6 @@ static void i915_gem_object_update_fence(struct drm_i915_gem_object *obj,
static int i915_gem_inactive_shrink(struct shrinker *shrinker,
struct shrink_control *sc);
-static long i915_gem_purge(struct drm_i915_private *dev_priv, long target);
-static void i915_gem_shrink_all(struct drm_i915_private *dev_priv);
static void i915_gem_object_truncate(struct drm_i915_gem_object *obj);
static inline void i915_gem_object_fence_lost(struct drm_i915_gem_object *obj)
@@ -143,7 +141,7 @@ int i915_mutex_lock_interruptible(struct drm_device *dev)
static inline bool
i915_gem_object_is_inactive(struct drm_i915_gem_object *obj)
{
- return obj->gtt_space && !obj->active;
+ return !obj->active;
}
int
@@ -182,7 +180,7 @@ i915_gem_get_aperture_ioctl(struct drm_device *dev, void *data,
pinned = 0;
mutex_lock(&dev->struct_mutex);
- list_for_each_entry(obj, &dev_priv->mm.bound_list, gtt_list)
+ list_for_each_entry(obj, &dev_priv->mm.gtt_list, gtt_list)
if (obj->pin_count)
pinned += obj->gtt_space->size;
mutex_unlock(&dev->struct_mutex);
@@ -343,7 +341,7 @@ shmem_pread_fast(struct page *page, int shmem_page_offset, int page_length,
page_length);
kunmap_atomic(vaddr);
- return ret ? -EFAULT : 0;
+ return ret;
}
static void
@@ -394,7 +392,7 @@ shmem_pread_slow(struct page *page, int shmem_page_offset, int page_length,
page_length);
kunmap(page);
- return ret ? - EFAULT : 0;
+ return ret;
}
static int
@@ -403,6 +401,7 @@ i915_gem_shmem_pread(struct drm_device *dev,
struct drm_i915_gem_pread *args,
struct drm_file *file)
{
+ struct address_space *mapping = obj->base.filp->f_path.dentry->d_inode->i_mapping;
char __user *user_data;
ssize_t remain;
loff_t offset;
@@ -411,8 +410,7 @@ i915_gem_shmem_pread(struct drm_device *dev,
int hit_slowpath = 0;
int prefaulted = 0;
int needs_clflush = 0;
- struct scatterlist *sg;
- int i;
+ int release_page;
user_data = (char __user *) (uintptr_t) args->data_ptr;
remain = args->size;
@@ -426,30 +424,16 @@ i915_gem_shmem_pread(struct drm_device *dev,
* anyway again before the next pread happens. */
if (obj->cache_level == I915_CACHE_NONE)
needs_clflush = 1;
- if (obj->gtt_space) {
- ret = i915_gem_object_set_to_gtt_domain(obj, false);
- if (ret)
- return ret;
- }
+ ret = i915_gem_object_set_to_gtt_domain(obj, false);
+ if (ret)
+ return ret;
}
- ret = i915_gem_object_get_pages(obj);
- if (ret)
- return ret;
-
- i915_gem_object_pin_pages(obj);
-
offset = args->offset;
- for_each_sg(obj->pages->sgl, sg, obj->pages->nents, i) {
+ while (remain > 0) {
struct page *page;
- if (i < offset >> PAGE_SHIFT)
- continue;
-
- if (remain <= 0)
- break;
-
/* Operation in this page
*
* shmem_page_offset = offset within page in shmem file
@@ -460,7 +444,18 @@ i915_gem_shmem_pread(struct drm_device *dev,
if ((shmem_page_offset + page_length) > PAGE_SIZE)
page_length = PAGE_SIZE - shmem_page_offset;
- page = sg_page(sg);
+ if (obj->pages) {
+ page = obj->pages[offset >> PAGE_SHIFT];
+ release_page = 0;
+ } else {
+ page = shmem_read_mapping_page(mapping, offset >> PAGE_SHIFT);
+ if (IS_ERR(page)) {
+ ret = PTR_ERR(page);
+ goto out;
+ }
+ release_page = 1;
+ }
+
page_do_bit17_swizzling = obj_do_bit17_swizzling &&
(page_to_phys(page) & (1 << 17)) != 0;
@@ -471,6 +466,7 @@ i915_gem_shmem_pread(struct drm_device *dev,
goto next_page;
hit_slowpath = 1;
+ page_cache_get(page);
mutex_unlock(&dev->struct_mutex);
if (!prefaulted) {
@@ -488,12 +484,16 @@ i915_gem_shmem_pread(struct drm_device *dev,
needs_clflush);
mutex_lock(&dev->struct_mutex);
-
+ page_cache_release(page);
next_page:
mark_page_accessed(page);
+ if (release_page)
+ page_cache_release(page);
- if (ret)
+ if (ret) {
+ ret = -EFAULT;
goto out;
+ }
remain -= page_length;
user_data += page_length;
@@ -501,8 +501,6 @@ i915_gem_shmem_pread(struct drm_device *dev,
}
out:
- i915_gem_object_unpin_pages(obj);
-
if (hit_slowpath) {
/* Fixup: Kill any reinstated backing storage pages */
if (obj->madv == __I915_MADV_PURGED)
@@ -608,7 +606,7 @@ i915_gem_gtt_pwrite_fast(struct drm_device *dev,
char __user *user_data;
int page_offset, page_length, ret;
- ret = i915_gem_object_pin(obj, 0, true, true);
+ ret = i915_gem_object_pin(obj, 0, true);
if (ret)
goto out;
@@ -688,7 +686,7 @@ shmem_pwrite_fast(struct page *page, int shmem_page_offset, int page_length,
page_length);
kunmap_atomic(vaddr);
- return ret ? -EFAULT : 0;
+ return ret;
}
/* Only difference to the fast-path function is that this can handle bit17
@@ -722,7 +720,7 @@ shmem_pwrite_slow(struct page *page, int shmem_page_offset, int page_length,
page_do_bit17_swizzling);
kunmap(page);
- return ret ? -EFAULT : 0;
+ return ret;
}
static int
@@ -731,6 +729,7 @@ i915_gem_shmem_pwrite(struct drm_device *dev,
struct drm_i915_gem_pwrite *args,
struct drm_file *file)
{
+ struct address_space *mapping = obj->base.filp->f_path.dentry->d_inode->i_mapping;
ssize_t remain;
loff_t offset;
char __user *user_data;
@@ -739,8 +738,7 @@ i915_gem_shmem_pwrite(struct drm_device *dev,
int hit_slowpath = 0;
int needs_clflush_after = 0;
int needs_clflush_before = 0;
- int i;
- struct scatterlist *sg;
+ int release_page;
user_data = (char __user *) (uintptr_t) args->data_ptr;
remain = args->size;
@@ -754,11 +752,9 @@ i915_gem_shmem_pwrite(struct drm_device *dev,
* right away and we therefore have to clflush anyway. */
if (obj->cache_level == I915_CACHE_NONE)
needs_clflush_after = 1;
- if (obj->gtt_space) {
- ret = i915_gem_object_set_to_gtt_domain(obj, true);
- if (ret)
- return ret;
- }
+ ret = i915_gem_object_set_to_gtt_domain(obj, true);
+ if (ret)
+ return ret;
}
/* Same trick applies for invalidate partially written cachelines before
* writing. */
@@ -766,25 +762,13 @@ i915_gem_shmem_pwrite(struct drm_device *dev,
&& obj->cache_level == I915_CACHE_NONE)
needs_clflush_before = 1;
- ret = i915_gem_object_get_pages(obj);
- if (ret)
- return ret;
-
- i915_gem_object_pin_pages(obj);
-
offset = args->offset;
obj->dirty = 1;
- for_each_sg(obj->pages->sgl, sg, obj->pages->nents, i) {
+ while (remain > 0) {
struct page *page;
int partial_cacheline_write;
- if (i < offset >> PAGE_SHIFT)
- continue;
-
- if (remain <= 0)
- break;
-
/* Operation in this page
*
* shmem_page_offset = offset within page in shmem file
@@ -803,7 +787,18 @@ i915_gem_shmem_pwrite(struct drm_device *dev,
((shmem_page_offset | page_length)
& (boot_cpu_data.x86_clflush_size - 1));
- page = sg_page(sg);
+ if (obj->pages) {
+ page = obj->pages[offset >> PAGE_SHIFT];
+ release_page = 0;
+ } else {
+ page = shmem_read_mapping_page(mapping, offset >> PAGE_SHIFT);
+ if (IS_ERR(page)) {
+ ret = PTR_ERR(page);
+ goto out;
+ }
+ release_page = 1;
+ }
+
page_do_bit17_swizzling = obj_do_bit17_swizzling &&
(page_to_phys(page) & (1 << 17)) != 0;
@@ -815,20 +810,26 @@ i915_gem_shmem_pwrite(struct drm_device *dev,
goto next_page;
hit_slowpath = 1;
+ page_cache_get(page);
mutex_unlock(&dev->struct_mutex);
+
ret = shmem_pwrite_slow(page, shmem_page_offset, page_length,
user_data, page_do_bit17_swizzling,
partial_cacheline_write,
needs_clflush_after);
mutex_lock(&dev->struct_mutex);
-
+ page_cache_release(page);
next_page:
set_page_dirty(page);
mark_page_accessed(page);
+ if (release_page)
+ page_cache_release(page);
- if (ret)
+ if (ret) {
+ ret = -EFAULT;
goto out;
+ }
remain -= page_length;
user_data += page_length;
@@ -836,8 +837,6 @@ i915_gem_shmem_pwrite(struct drm_device *dev,
}
out:
- i915_gem_object_unpin_pages(obj);
-
if (hit_slowpath) {
/* Fixup: Kill any reinstated backing storage pages */
if (obj->madv == __I915_MADV_PURGED)
@@ -921,8 +920,10 @@ i915_gem_pwrite_ioctl(struct drm_device *dev, void *data,
goto out;
}
- if (obj->cache_level == I915_CACHE_NONE &&
+ if (obj->gtt_space &&
+ obj->cache_level == I915_CACHE_NONE &&
obj->tiling_mode == I915_TILING_NONE &&
+ obj->map_and_fenceable &&
obj->base.write_domain != I915_GEM_DOMAIN_CPU) {
ret = i915_gem_gtt_pwrite_fast(dev, obj, args, file);
/* Note that the gtt paths might fail with non-page-backed user
@@ -930,7 +931,7 @@ i915_gem_pwrite_ioctl(struct drm_device *dev, void *data,
* textures). Fallback to the shmem path in that case. */
}
- if (ret == -EFAULT || ret == -ENOSPC)
+ if (ret == -EFAULT)
ret = i915_gem_shmem_pwrite(dev, obj, args, file);
out:
@@ -940,240 +941,6 @@ i915_gem_pwrite_ioctl(struct drm_device *dev, void *data,
return ret;
}
-int
-i915_gem_check_wedge(struct drm_i915_private *dev_priv,
- 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);
-
- /* 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)
- return -EIO;
-
- return -EAGAIN;
- }
-
- return 0;
-}
-
-/*
- * Compare seqno against outstanding lazy request. Emit a request if they are
- * equal.
- */
-static int
-i915_gem_check_olr(struct intel_ring_buffer *ring, u32 seqno)
-{
- int ret;
-
- BUG_ON(!mutex_is_locked(&ring->dev->struct_mutex));
-
- ret = 0;
- if (seqno == ring->outstanding_lazy_request)
- ret = i915_add_request(ring, NULL, NULL);
-
- return ret;
-}
-
-/**
- * __wait_seqno - wait until execution of seqno has finished
- * @ring: the ring expected to report seqno
- * @seqno: duh!
- * @interruptible: do an interruptible wait (normally yes)
- * @timeout: in - how long to wait (NULL forever); out - how much time remaining
- *
- * 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,
- bool interruptible, struct timespec *timeout)
-{
- drm_i915_private_t *dev_priv = ring->dev->dev_private;
- struct timespec before, now, wait_time={1,0};
- unsigned long timeout_jiffies;
- long end;
- bool wait_forever = true;
- int ret;
-
- if (i915_seqno_passed(ring->get_seqno(ring, true), seqno))
- return 0;
-
- trace_i915_gem_request_wait_begin(ring, seqno);
-
- if (timeout != NULL) {
- wait_time = *timeout;
- wait_forever = false;
- }
-
- timeout_jiffies = timespec_to_jiffies(&wait_time);
-
- if (WARN_ON(!ring->irq_get(ring)))
- return -ENODEV;
-
- /* Record current time in case interrupted by signal, or wedged * */
- getrawmonotonic(&before);
-
-#define EXIT_COND \
- (i915_seqno_passed(ring->get_seqno(ring, false), seqno) || \
- atomic_read(&dev_priv->mm.wedged))
- do {
- if (interruptible)
- end = wait_event_interruptible_timeout(ring->irq_queue,
- EXIT_COND,
- timeout_jiffies);
- else
- end = wait_event_timeout(ring->irq_queue, EXIT_COND,
- timeout_jiffies);
-
- ret = i915_gem_check_wedge(dev_priv, interruptible);
- if (ret)
- end = ret;
- } while (end == 0 && wait_forever);
-
- getrawmonotonic(&now);
-
- ring->irq_put(ring);
- trace_i915_gem_request_wait_end(ring, seqno);
-#undef EXIT_COND
-
- if (timeout) {
- struct timespec sleep_time = timespec_sub(now, before);
- *timeout = timespec_sub(*timeout, sleep_time);
- }
-
- switch (end) {
- case -EIO:
- case -EAGAIN: /* Wedged */
- case -ERESTARTSYS: /* Signal */
- return (int)end;
- case 0: /* Timeout */
- if (timeout)
- set_normalized_timespec(timeout, 0, 0);
- return -ETIME;
- default: /* Completed */
- WARN_ON(end < 0); /* We're not aware of other errors */
- return 0;
- }
-}
-
-/**
- * Waits for a sequence number to be signaled, and cleans up the
- * request and object lists appropriately for that event.
- */
-int
-i915_wait_seqno(struct intel_ring_buffer *ring, uint32_t seqno)
-{
- struct drm_device *dev = ring->dev;
- struct drm_i915_private *dev_priv = dev->dev_private;
- bool interruptible = dev_priv->mm.interruptible;
- int ret;
-
- BUG_ON(!mutex_is_locked(&dev->struct_mutex));
- BUG_ON(seqno == 0);
-
- ret = i915_gem_check_wedge(dev_priv, interruptible);
- if (ret)
- return ret;
-
- ret = i915_gem_check_olr(ring, seqno);
- if (ret)
- return ret;
-
- return __wait_seqno(ring, seqno, interruptible, NULL);
-}
-
-/**
- * Ensures that all rendering to the object has completed and the object is
- * safe to unbind from the GTT or access from the CPU.
- */
-static __must_check int
-i915_gem_object_wait_rendering(struct drm_i915_gem_object *obj,
- bool readonly)
-{
- struct intel_ring_buffer *ring = obj->ring;
- u32 seqno;
- int ret;
-
- seqno = readonly ? obj->last_write_seqno : obj->last_read_seqno;
- if (seqno == 0)
- return 0;
-
- ret = i915_wait_seqno(ring, seqno);
- if (ret)
- return ret;
-
- i915_gem_retire_requests_ring(ring);
-
- /* Manually manage the write flush as we may have not yet
- * retired the buffer.
- */
- if (obj->last_write_seqno &&
- i915_seqno_passed(seqno, obj->last_write_seqno)) {
- obj->last_write_seqno = 0;
- obj->base.write_domain &= ~I915_GEM_GPU_DOMAINS;
- }
-
- return 0;
-}
-
-/* A nonblocking variant of the above wait. This is a highly dangerous routine
- * as the object state may change during this call.
- */
-static __must_check int
-i915_gem_object_wait_rendering__nonblocking(struct drm_i915_gem_object *obj,
- bool readonly)
-{
- struct drm_device *dev = obj->base.dev;
- struct drm_i915_private *dev_priv = dev->dev_private;
- struct intel_ring_buffer *ring = obj->ring;
- u32 seqno;
- int ret;
-
- BUG_ON(!mutex_is_locked(&dev->struct_mutex));
- BUG_ON(!dev_priv->mm.interruptible);
-
- seqno = readonly ? obj->last_write_seqno : obj->last_read_seqno;
- if (seqno == 0)
- return 0;
-
- ret = i915_gem_check_wedge(dev_priv, true);
- if (ret)
- return ret;
-
- ret = i915_gem_check_olr(ring, seqno);
- if (ret)
- return ret;
-
- mutex_unlock(&dev->struct_mutex);
- ret = __wait_seqno(ring, seqno, true, NULL);
- mutex_lock(&dev->struct_mutex);
-
- i915_gem_retire_requests_ring(ring);
-
- /* Manually manage the write flush as we may have not yet
- * retired the buffer.
- */
- if (obj->last_write_seqno &&
- i915_seqno_passed(seqno, obj->last_write_seqno)) {
- obj->last_write_seqno = 0;
- obj->base.write_domain &= ~I915_GEM_GPU_DOMAINS;
- }
-
- return ret;
-}
-
/**
* Called when user space prepares to use an object with the CPU, either
* through the mmap ioctl's mapping or a GTT mapping.
@@ -1211,14 +978,6 @@ i915_gem_set_domain_ioctl(struct drm_device *dev, void *data,
goto unlock;
}
- /* Try to flush the object off the GPU without holding the lock.
- * We will repeat the flush holding the lock in the normal manner
- * to catch cases where we are gazumped.
- */
- ret = i915_gem_object_wait_rendering__nonblocking(obj, !write_domain);
- if (ret)
- goto unref;
-
if (read_domains & I915_GEM_DOMAIN_GTT) {
ret = i915_gem_object_set_to_gtt_domain(obj, write_domain != 0);
@@ -1232,7 +991,6 @@ i915_gem_set_domain_ioctl(struct drm_device *dev, void *data,
ret = i915_gem_object_set_to_cpu_domain(obj, write_domain != 0);
}
-unref:
drm_gem_object_unreference(&obj->base);
unlock:
mutex_unlock(&dev->struct_mutex);
@@ -1352,7 +1110,7 @@ int i915_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
goto unlock;
}
if (!obj->gtt_space) {
- ret = i915_gem_object_bind_to_gtt(obj, 0, true, false);
+ ret = i915_gem_object_bind_to_gtt(obj, 0, true);
if (ret)
goto unlock;
@@ -1513,42 +1271,6 @@ i915_gem_get_unfenced_gtt_alignment(struct drm_device *dev,
return i915_gem_get_gtt_size(dev, size, tiling_mode);
}
-static int i915_gem_object_create_mmap_offset(struct drm_i915_gem_object *obj)
-{
- struct drm_i915_private *dev_priv = obj->base.dev->dev_private;
- int ret;
-
- if (obj->base.map_list.map)
- return 0;
-
- ret = drm_gem_create_mmap_offset(&obj->base);
- if (ret != -ENOSPC)
- return ret;
-
- /* Badly fragmented mmap space? The only way we can recover
- * space is by destroying unwanted objects. We can't randomly release
- * mmap_offsets as userspace expects them to be persistent for the
- * lifetime of the objects. The closest we can is to release the
- * offsets on purgeable objects by truncating it and marking it purged,
- * which prevents userspace from ever using that object again.
- */
- i915_gem_purge(dev_priv, obj->base.size >> PAGE_SHIFT);
- ret = drm_gem_create_mmap_offset(&obj->base);
- if (ret != -ENOSPC)
- return ret;
-
- i915_gem_shrink_all(dev_priv);
- return drm_gem_create_mmap_offset(&obj->base);
-}
-
-static void i915_gem_object_free_mmap_offset(struct drm_i915_gem_object *obj)
-{
- if (!obj->base.map_list.map)
- return;
-
- drm_gem_free_mmap_offset(&obj->base);
-}
-
int
i915_gem_mmap_gtt(struct drm_file *file,
struct drm_device *dev,
@@ -1580,9 +1302,11 @@ i915_gem_mmap_gtt(struct drm_file *file,
goto out;
}
- ret = i915_gem_object_create_mmap_offset(obj);
- if (ret)
- goto out;
+ if (!obj->base.map_list.map) {
+ ret = drm_gem_create_mmap_offset(&obj->base);
+ if (ret)
+ goto out;
+ }
*offset = (u64)obj->base.map_list.hash.key << PAGE_SHIFT;
@@ -1617,52 +1341,63 @@ i915_gem_mmap_gtt_ioctl(struct drm_device *dev, void *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)
+int
+i915_gem_object_get_pages_gtt(struct drm_i915_gem_object *obj,
+ gfp_t gfpmask)
{
+ int page_count, i;
+ struct address_space *mapping;
struct inode *inode;
+ struct page *page;
- i915_gem_object_free_mmap_offset(obj);
-
- if (obj->base.filp == NULL)
- return;
+ if (obj->pages || obj->sg_table)
+ return 0;
- /* Our goal here is to return as much of the memory as
- * is possible back to the system as we are called from OOM.
- * To do this we must instruct the shmfs to drop all of its
- * backing pages, *now*.
+ /* Get the list of pages out of our struct file. They'll be pinned
+ * at this point until we release them.
*/
+ page_count = obj->base.size / PAGE_SIZE;
+ BUG_ON(obj->pages != NULL);
+ obj->pages = drm_malloc_ab(page_count, sizeof(struct page *));
+ if (obj->pages == NULL)
+ return -ENOMEM;
+
inode = obj->base.filp->f_path.dentry->d_inode;
- shmem_truncate_range(inode, 0, (loff_t)-1);
+ mapping = inode->i_mapping;
+ gfpmask |= mapping_gfp_mask(mapping);
- obj->madv = __I915_MADV_PURGED;
-}
+ for (i = 0; i < page_count; i++) {
+ page = shmem_read_mapping_page_gfp(mapping, i, gfpmask);
+ if (IS_ERR(page))
+ goto err_pages;
-static inline int
-i915_gem_object_is_purgeable(struct drm_i915_gem_object *obj)
-{
- return obj->madv == I915_MADV_DONTNEED;
+ obj->pages[i] = page;
+ }
+
+ if (i915_gem_object_needs_bit17_swizzle(obj))
+ i915_gem_object_do_bit_17_swizzle(obj);
+
+ return 0;
+
+err_pages:
+ while (i--)
+ page_cache_release(obj->pages[i]);
+
+ drm_free_large(obj->pages);
+ obj->pages = NULL;
+ return PTR_ERR(page);
}
static void
i915_gem_object_put_pages_gtt(struct drm_i915_gem_object *obj)
{
int page_count = obj->base.size / PAGE_SIZE;
- struct scatterlist *sg;
- int ret, i;
+ int i;
- BUG_ON(obj->madv == __I915_MADV_PURGED);
+ if (!obj->pages)
+ return;
- ret = i915_gem_object_set_to_cpu_domain(obj, true);
- if (ret) {
- /* In the event of a disaster, abandon all caches and
- * hope for the best.
- */
- WARN_ON(ret != -EIO);
- i915_gem_clflush_object(obj);
- obj->base.read_domains = obj->base.write_domain = I915_GEM_DOMAIN_CPU;
- }
+ BUG_ON(obj->madv == __I915_MADV_PURGED);
if (i915_gem_object_needs_bit17_swizzle(obj))
i915_gem_object_save_bit_17_swizzle(obj);
@@ -1670,192 +1405,19 @@ i915_gem_object_put_pages_gtt(struct drm_i915_gem_object *obj)
if (obj->madv == I915_MADV_DONTNEED)
obj->dirty = 0;
- for_each_sg(obj->pages->sgl, sg, page_count, i) {
- struct page *page = sg_page(sg);
-
+ for (i = 0; i < page_count; i++) {
if (obj->dirty)
- set_page_dirty(page);
+ set_page_dirty(obj->pages[i]);
if (obj->madv == I915_MADV_WILLNEED)
- mark_page_accessed(page);
+ mark_page_accessed(obj->pages[i]);
- page_cache_release(page);
+ page_cache_release(obj->pages[i]);
}
obj->dirty = 0;
- sg_free_table(obj->pages);
- kfree(obj->pages);
-}
-
-static int
-i915_gem_object_put_pages(struct drm_i915_gem_object *obj)
-{
- const struct drm_i915_gem_object_ops *ops = obj->ops;
-
- if (obj->pages == NULL)
- return 0;
-
- BUG_ON(obj->gtt_space);
-
- if (obj->pages_pin_count)
- return -EBUSY;
-
- ops->put_pages(obj);
+ drm_free_large(obj->pages);
obj->pages = NULL;
-
- list_del(&obj->gtt_list);
- if (i915_gem_object_is_purgeable(obj))
- i915_gem_object_truncate(obj);
-
- return 0;
-}
-
-static long
-i915_gem_purge(struct drm_i915_private *dev_priv, long target)
-{
- struct drm_i915_gem_object *obj, *next;
- long count = 0;
-
- list_for_each_entry_safe(obj, next,
- &dev_priv->mm.unbound_list,
- gtt_list) {
- if (i915_gem_object_is_purgeable(obj) &&
- i915_gem_object_put_pages(obj) == 0) {
- count += obj->base.size >> PAGE_SHIFT;
- if (count >= target)
- return count;
- }
- }
-
- list_for_each_entry_safe(obj, next,
- &dev_priv->mm.inactive_list,
- mm_list) {
- if (i915_gem_object_is_purgeable(obj) &&
- i915_gem_object_unbind(obj) == 0 &&
- i915_gem_object_put_pages(obj) == 0) {
- count += obj->base.size >> PAGE_SHIFT;
- if (count >= target)
- return count;
- }
- }
-
- return count;
-}
-
-static void
-i915_gem_shrink_all(struct drm_i915_private *dev_priv)
-{
- struct drm_i915_gem_object *obj, *next;
-
- i915_gem_evict_everything(dev_priv->dev);
-
- list_for_each_entry_safe(obj, next, &dev_priv->mm.unbound_list, gtt_list)
- i915_gem_object_put_pages(obj);
-}
-
-static int
-i915_gem_object_get_pages_gtt(struct drm_i915_gem_object *obj)
-{
- struct drm_i915_private *dev_priv = obj->base.dev->dev_private;
- int page_count, i;
- struct address_space *mapping;
- struct sg_table *st;
- struct scatterlist *sg;
- struct page *page;
- gfp_t gfp;
-
- /* Assert that the object is not currently in any GPU domain. As it
- * wasn't in the GTT, there shouldn't be any way it could have been in
- * a GPU cache
- */
- BUG_ON(obj->base.read_domains & I915_GEM_GPU_DOMAINS);
- BUG_ON(obj->base.write_domain & I915_GEM_GPU_DOMAINS);
-
- st = kmalloc(sizeof(*st), GFP_KERNEL);
- if (st == NULL)
- return -ENOMEM;
-
- page_count = obj->base.size / PAGE_SIZE;
- if (sg_alloc_table(st, page_count, GFP_KERNEL)) {
- sg_free_table(st);
- kfree(st);
- return -ENOMEM;
- }
-
- /* Get the list of pages out of our struct file. They'll be pinned
- * at this point until we release them.
- *
- * Fail silently without starting the shrinker
- */
- mapping = obj->base.filp->f_path.dentry->d_inode->i_mapping;
- gfp = mapping_gfp_mask(mapping);
- gfp |= __GFP_NORETRY | __GFP_NOWARN;
- gfp &= ~(__GFP_IO | __GFP_WAIT);
- for_each_sg(st->sgl, sg, page_count, i) {
- page = shmem_read_mapping_page_gfp(mapping, i, gfp);
- if (IS_ERR(page)) {
- i915_gem_purge(dev_priv, page_count);
- page = shmem_read_mapping_page_gfp(mapping, i, gfp);
- }
- if (IS_ERR(page)) {
- /* We've tried hard to allocate the memory by reaping
- * our own buffer, now let the real VM do its job and
- * go down in flames if truly OOM.
- */
- gfp &= ~(__GFP_NORETRY | __GFP_NOWARN);
- gfp |= __GFP_IO | __GFP_WAIT;
-
- i915_gem_shrink_all(dev_priv);
- page = shmem_read_mapping_page_gfp(mapping, i, gfp);
- if (IS_ERR(page))
- goto err_pages;
-
- gfp |= __GFP_NORETRY | __GFP_NOWARN;
- gfp &= ~(__GFP_IO | __GFP_WAIT);
- }
-
- sg_set_page(sg, page, PAGE_SIZE, 0);
- }
-
- if (i915_gem_object_needs_bit17_swizzle(obj))
- i915_gem_object_do_bit_17_swizzle(obj);
-
- obj->pages = st;
- return 0;
-
-err_pages:
- for_each_sg(st->sgl, sg, i, page_count)
- page_cache_release(sg_page(sg));
- sg_free_table(st);
- kfree(st);
- return PTR_ERR(page);
-}
-
-/* Ensure that the associated pages are gathered from the backing storage
- * and pinned into our object. i915_gem_object_get_pages() may be called
- * multiple times before they are released by a single call to
- * i915_gem_object_put_pages() - once the pages are no longer referenced
- * either as a result of memory pressure (reaping pages under the shrinker)
- * or as the object is itself released.
- */
-int
-i915_gem_object_get_pages(struct drm_i915_gem_object *obj)
-{
- struct drm_i915_private *dev_priv = obj->base.dev->dev_private;
- const struct drm_i915_gem_object_ops *ops = obj->ops;
- int ret;
-
- if (obj->pages)
- return 0;
-
- BUG_ON(obj->pages_pin_count);
-
- ret = ops->get_pages(obj);
- if (ret)
- return ret;
-
- list_add_tail(&obj->gtt_list, &dev_priv->mm.unbound_list);
- return 0;
}
void
@@ -1879,7 +1441,7 @@ i915_gem_object_move_to_active(struct drm_i915_gem_object *obj,
list_move_tail(&obj->mm_list, &dev_priv->mm.active_list);
list_move_tail(&obj->ring_list, &ring->active_list);
- obj->last_read_seqno = seqno;
+ obj->last_rendering_seqno = seqno;
if (obj->fenced_gpu_access) {
obj->last_fenced_seqno = seqno;
@@ -1896,35 +1458,97 @@ i915_gem_object_move_to_active(struct drm_i915_gem_object *obj,
}
static void
-i915_gem_object_move_to_inactive(struct drm_i915_gem_object *obj)
+i915_gem_object_move_off_active(struct drm_i915_gem_object *obj)
+{
+ list_del_init(&obj->ring_list);
+ obj->last_rendering_seqno = 0;
+ obj->last_fenced_seqno = 0;
+}
+
+static void
+i915_gem_object_move_to_flushing(struct drm_i915_gem_object *obj)
{
struct drm_device *dev = obj->base.dev;
- struct drm_i915_private *dev_priv = dev->dev_private;
+ drm_i915_private_t *dev_priv = dev->dev_private;
- BUG_ON(obj->base.write_domain & ~I915_GEM_GPU_DOMAINS);
BUG_ON(!obj->active);
+ list_move_tail(&obj->mm_list, &dev_priv->mm.flushing_list);
- if (obj->pin_count) /* are we a framebuffer? */
- intel_mark_fb_idle(obj);
+ i915_gem_object_move_off_active(obj);
+}
+
+static void
+i915_gem_object_move_to_inactive(struct drm_i915_gem_object *obj)
+{
+ struct drm_device *dev = obj->base.dev;
+ struct drm_i915_private *dev_priv = dev->dev_private;
list_move_tail(&obj->mm_list, &dev_priv->mm.inactive_list);
- list_del_init(&obj->ring_list);
+ BUG_ON(!list_empty(&obj->gpu_write_list));
+ BUG_ON(!obj->active);
obj->ring = NULL;
- obj->last_read_seqno = 0;
- obj->last_write_seqno = 0;
- obj->base.write_domain = 0;
-
- obj->last_fenced_seqno = 0;
+ i915_gem_object_move_off_active(obj);
obj->fenced_gpu_access = false;
obj->active = 0;
+ obj->pending_gpu_write = false;
drm_gem_object_unreference(&obj->base);
WARN_ON(i915_verify_lists(dev));
}
+/* Immediately discard the backing storage */
+static void
+i915_gem_object_truncate(struct drm_i915_gem_object *obj)
+{
+ struct inode *inode;
+
+ /* Our goal here is to return as much of the memory as
+ * is possible back to the system as we are called from OOM.
+ * To do this we must instruct the shmfs to drop all of its
+ * backing pages, *now*.
+ */
+ inode = obj->base.filp->f_path.dentry->d_inode;
+ shmem_truncate_range(inode, 0, (loff_t)-1);
+
+ if (obj->base.map_list.map)
+ drm_gem_free_mmap_offset(&obj->base);
+
+ obj->madv = __I915_MADV_PURGED;
+}
+
+static inline int
+i915_gem_object_is_purgeable(struct drm_i915_gem_object *obj)
+{
+ return obj->madv == I915_MADV_DONTNEED;
+}
+
+static void
+i915_gem_process_flushing_list(struct intel_ring_buffer *ring,
+ uint32_t flush_domains)
+{
+ struct drm_i915_gem_object *obj, *next;
+
+ list_for_each_entry_safe(obj, next,
+ &ring->gpu_write_list,
+ gpu_write_list) {
+ if (obj->base.write_domain & flush_domains) {
+ uint32_t old_write_domain = obj->base.write_domain;
+
+ obj->base.write_domain = 0;
+ list_del_init(&obj->gpu_write_list);
+ i915_gem_object_move_to_active(obj, ring,
+ i915_gem_next_request_seqno(ring));
+
+ trace_i915_gem_object_change_domain(obj,
+ obj->base.read_domains,
+ old_write_domain);
+ }
+ }
+}
+
static u32
i915_gem_get_seqno(struct drm_device *dev)
{
@@ -1965,16 +1589,15 @@ i915_add_request(struct intel_ring_buffer *ring,
* is that the flush _must_ happen before the next request, no matter
* what.
*/
- ret = intel_ring_flush_all_caches(ring);
- if (ret)
- return ret;
+ if (ring->gpu_caches_dirty) {
+ ret = i915_gem_flush_ring(ring, 0, I915_GEM_GPU_DOMAINS);
+ if (ret)
+ return ret;
- if (request == NULL) {
- request = kmalloc(sizeof(*request), GFP_KERNEL);
- if (request == NULL)
- return -ENOMEM;
+ ring->gpu_caches_dirty = false;
}
+ BUG_ON(request == NULL);
seqno = i915_gem_next_request_seqno(ring);
/* Record the position of the start of the request so that
@@ -1985,10 +1608,8 @@ i915_add_request(struct intel_ring_buffer *ring,
request_ring_position = intel_ring_get_tail(ring);
ret = ring->add_request(ring, &seqno);
- if (ret) {
- kfree(request);
- return ret;
- }
+ if (ret)
+ return ret;
trace_i915_gem_request_add(ring, seqno);
@@ -1998,7 +1619,6 @@ i915_add_request(struct intel_ring_buffer *ring,
request->emitted_jiffies = jiffies;
was_empty = list_empty(&ring->request_list);
list_add_tail(&request->list, &ring->request_list);
- request->file_priv = NULL;
if (file) {
struct drm_i915_file_private *file_priv = file->driver_priv;
@@ -2018,13 +1638,13 @@ i915_add_request(struct intel_ring_buffer *ring,
jiffies +
msecs_to_jiffies(DRM_I915_HANGCHECK_PERIOD));
}
- if (was_empty) {
+ if (was_empty)
queue_delayed_work(dev_priv->wq,
&dev_priv->mm.retire_work, HZ);
- intel_mark_busy(dev_priv->dev);
- }
}
+ WARN_ON(!list_empty(&ring->gpu_write_list));
+
return 0;
}
@@ -2066,6 +1686,8 @@ static void i915_gem_reset_ring_lists(struct drm_i915_private *dev_priv,
struct drm_i915_gem_object,
ring_list);
+ obj->base.write_domain = 0;
+ list_del_init(&obj->gpu_write_list);
i915_gem_object_move_to_inactive(obj);
}
}
@@ -2101,6 +1723,20 @@ void i915_gem_reset(struct drm_device *dev)
for_each_ring(ring, dev_priv, i)
i915_gem_reset_ring_lists(dev_priv, ring);
+ /* Remove anything from the flushing lists. The GPU cache is likely
+ * to be lost on reset along with the data, so simply move the
+ * lost bo to the inactive list.
+ */
+ while (!list_empty(&dev_priv->mm.flushing_list)) {
+ obj = list_first_entry(&dev_priv->mm.flushing_list,
+ struct drm_i915_gem_object,
+ mm_list);
+
+ obj->base.write_domain = 0;
+ list_del_init(&obj->gpu_write_list);
+ i915_gem_object_move_to_inactive(obj);
+ }
+
/* Move everything out of the GPU domains to ensure we do any
* necessary invalidation upon reuse.
*/
@@ -2129,7 +1765,7 @@ i915_gem_retire_requests_ring(struct intel_ring_buffer *ring)
WARN_ON(i915_verify_lists(ring->dev));
- seqno = ring->get_seqno(ring, true);
+ seqno = ring->get_seqno(ring);
for (i = 0; i < ARRAY_SIZE(ring->sync_seqno); i++)
if (seqno >= ring->sync_seqno[i])
@@ -2168,10 +1804,13 @@ i915_gem_retire_requests_ring(struct intel_ring_buffer *ring)
struct drm_i915_gem_object,
ring_list);
- if (!i915_seqno_passed(seqno, obj->last_read_seqno))
+ if (!i915_seqno_passed(seqno, obj->last_rendering_seqno))
break;
- i915_gem_object_move_to_inactive(obj);
+ if (obj->base.write_domain != 0)
+ i915_gem_object_move_to_flushing(obj);
+ else
+ i915_gem_object_move_to_inactive(obj);
}
if (unlikely(ring->trace_irq_seqno &&
@@ -2215,23 +1854,219 @@ i915_gem_retire_work_handler(struct work_struct *work)
i915_gem_retire_requests(dev);
- /* Send a periodic flush down the ring so we don't hold onto GEM
- * objects indefinitely.
+ /* Send a periodic flush down the ring so we don't hold onto GEM
+ * objects indefinitely.
+ */
+ idle = true;
+ for_each_ring(ring, dev_priv, i) {
+ if (ring->gpu_caches_dirty) {
+ struct drm_i915_gem_request *request;
+
+ request = kzalloc(sizeof(*request), GFP_KERNEL);
+ if (request == NULL ||
+ i915_add_request(ring, NULL, request))
+ kfree(request);
+ }
+
+ idle &= list_empty(&ring->request_list);
+ }
+
+ if (!dev_priv->mm.suspended && !idle)
+ queue_delayed_work(dev_priv->wq, &dev_priv->mm.retire_work, HZ);
+
+ mutex_unlock(&dev->struct_mutex);
+}
+
+int
+i915_gem_check_wedge(struct drm_i915_private *dev_priv,
+ 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);
+
+ /* 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)
+ return -EIO;
+
+ return -EAGAIN;
+ }
+
+ return 0;
+}
+
+/*
+ * Compare seqno against outstanding lazy request. Emit a request if they are
+ * equal.
+ */
+static int
+i915_gem_check_olr(struct intel_ring_buffer *ring, u32 seqno)
+{
+ int ret = 0;
+
+ BUG_ON(!mutex_is_locked(&ring->dev->struct_mutex));
+
+ if (seqno == ring->outstanding_lazy_request) {
+ struct drm_i915_gem_request *request;
+
+ request = kzalloc(sizeof(*request), GFP_KERNEL);
+ if (request == NULL)
+ return -ENOMEM;
+
+ ret = i915_add_request(ring, NULL, request);
+ if (ret) {
+ kfree(request);
+ return ret;
+ }
+
+ BUG_ON(seqno != request->seqno);
+ }
+
+ return ret;
+}
+
+/**
+ * __wait_seqno - wait until execution of seqno has finished
+ * @ring: the ring expected to report seqno
+ * @seqno: duh!
+ * @interruptible: do an interruptible wait (normally yes)
+ * @timeout: in - how long to wait (NULL forever); out - how much time remaining
+ *
+ * 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,
+ bool interruptible, struct timespec *timeout)
+{
+ drm_i915_private_t *dev_priv = ring->dev->dev_private;
+ struct timespec before, now, wait_time={1,0};
+ unsigned long timeout_jiffies;
+ long end;
+ bool wait_forever = true;
+ int ret;
+
+ if (i915_seqno_passed(ring->get_seqno(ring), seqno))
+ return 0;
+
+ trace_i915_gem_request_wait_begin(ring, seqno);
+
+ if (timeout != NULL) {
+ wait_time = *timeout;
+ wait_forever = false;
+ }
+
+ timeout_jiffies = timespec_to_jiffies(&wait_time);
+
+ if (WARN_ON(!ring->irq_get(ring)))
+ return -ENODEV;
+
+ /* Record current time in case interrupted by signal, or wedged * */
+ getrawmonotonic(&before);
+
+#define EXIT_COND \
+ (i915_seqno_passed(ring->get_seqno(ring), seqno) || \
+ atomic_read(&dev_priv->mm.wedged))
+ do {
+ if (interruptible)
+ end = wait_event_interruptible_timeout(ring->irq_queue,
+ EXIT_COND,
+ timeout_jiffies);
+ else
+ end = wait_event_timeout(ring->irq_queue, EXIT_COND,
+ timeout_jiffies);
+
+ ret = i915_gem_check_wedge(dev_priv, interruptible);
+ if (ret)
+ end = ret;
+ } while (end == 0 && wait_forever);
+
+ getrawmonotonic(&now);
+
+ ring->irq_put(ring);
+ trace_i915_gem_request_wait_end(ring, seqno);
+#undef EXIT_COND
+
+ if (timeout) {
+ struct timespec sleep_time = timespec_sub(now, before);
+ *timeout = timespec_sub(*timeout, sleep_time);
+ }
+
+ switch (end) {
+ case -EIO:
+ case -EAGAIN: /* Wedged */
+ case -ERESTARTSYS: /* Signal */
+ return (int)end;
+ case 0: /* Timeout */
+ if (timeout)
+ set_normalized_timespec(timeout, 0, 0);
+ return -ETIME;
+ default: /* Completed */
+ WARN_ON(end < 0); /* We're not aware of other errors */
+ return 0;
+ }
+}
+
+/**
+ * Waits for a sequence number to be signaled, and cleans up the
+ * request and object lists appropriately for that event.
+ */
+int
+i915_wait_seqno(struct intel_ring_buffer *ring, uint32_t seqno)
+{
+ drm_i915_private_t *dev_priv = ring->dev->dev_private;
+ int ret = 0;
+
+ BUG_ON(seqno == 0);
+
+ ret = i915_gem_check_wedge(dev_priv, dev_priv->mm.interruptible);
+ if (ret)
+ return ret;
+
+ ret = i915_gem_check_olr(ring, seqno);
+ if (ret)
+ return ret;
+
+ ret = __wait_seqno(ring, seqno, dev_priv->mm.interruptible, NULL);
+
+ return ret;
+}
+
+/**
+ * Ensures that all rendering to the object has completed and the object is
+ * safe to unbind from the GTT or access from the CPU.
+ */
+int
+i915_gem_object_wait_rendering(struct drm_i915_gem_object *obj)
+{
+ int ret;
+
+ /* This function only exists to support waiting for existing rendering,
+ * not for emitting required flushes.
*/
- idle = true;
- for_each_ring(ring, dev_priv, i) {
- if (ring->gpu_caches_dirty)
- i915_add_request(ring, NULL, NULL);
+ BUG_ON((obj->base.write_domain & I915_GEM_GPU_DOMAINS) != 0);
- idle &= list_empty(&ring->request_list);
+ /* If there is rendering queued on the buffer being evicted, wait for
+ * it.
+ */
+ if (obj->active) {
+ ret = i915_wait_seqno(obj->ring, obj->last_rendering_seqno);
+ if (ret)
+ return ret;
+ i915_gem_retire_requests_ring(obj->ring);
}
- if (!dev_priv->mm.suspended && !idle)
- queue_delayed_work(dev_priv->wq, &dev_priv->mm.retire_work, HZ);
- if (idle)
- intel_mark_idle(dev);
-
- mutex_unlock(&dev->struct_mutex);
+ return 0;
}
/**
@@ -2245,10 +2080,14 @@ i915_gem_object_flush_active(struct drm_i915_gem_object *obj)
int ret;
if (obj->active) {
- ret = i915_gem_check_olr(obj->ring, obj->last_read_seqno);
+ ret = i915_gem_object_flush_gpu_write_domain(obj);
if (ret)
return ret;
+ ret = i915_gem_check_olr(obj->ring,
+ obj->last_rendering_seqno);
+ if (ret)
+ return ret;
i915_gem_retire_requests_ring(obj->ring);
}
@@ -2308,7 +2147,7 @@ i915_gem_wait_ioctl(struct drm_device *dev, void *data, struct drm_file *file)
goto out;
if (obj->active) {
- seqno = obj->last_read_seqno;
+ seqno = obj->last_rendering_seqno;
ring = obj->ring;
}
@@ -2363,11 +2202,11 @@ i915_gem_object_sync(struct drm_i915_gem_object *obj,
return 0;
if (to == NULL || !i915_semaphore_is_enabled(obj->base.dev))
- return i915_gem_object_wait_rendering(obj, false);
+ return i915_gem_object_wait_rendering(obj);
idx = intel_ring_sync_index(from, to);
- seqno = obj->last_read_seqno;
+ seqno = obj->last_rendering_seqno;
if (seqno <= from->sync_seqno[idx])
return 0;
@@ -2421,8 +2260,6 @@ i915_gem_object_unbind(struct drm_i915_gem_object *obj)
if (obj->pin_count)
return -EBUSY;
- BUG_ON(obj->pages == NULL);
-
ret = i915_gem_object_finish_gpu(obj);
if (ret)
return ret;
@@ -2433,6 +2270,22 @@ i915_gem_object_unbind(struct drm_i915_gem_object *obj)
i915_gem_object_finish_gtt(obj);
+ /* Move the object to the CPU domain to ensure that
+ * any possible CPU writes while it's not in the GTT
+ * are flushed when we go to remap it.
+ */
+ if (ret == 0)
+ ret = i915_gem_object_set_to_cpu_domain(obj, 1);
+ if (ret == -ERESTARTSYS)
+ return ret;
+ if (ret) {
+ /* In the event of a disaster, abandon all caches and
+ * hope for the best.
+ */
+ i915_gem_clflush_object(obj);
+ obj->base.read_domains = obj->base.write_domain = I915_GEM_DOMAIN_CPU;
+ }
+
/* release the fence reg _after_ flushing */
ret = i915_gem_object_put_fence(obj);
if (ret)
@@ -2448,8 +2301,10 @@ i915_gem_object_unbind(struct drm_i915_gem_object *obj)
}
i915_gem_gtt_finish_object(obj);
- list_del(&obj->mm_list);
- list_move_tail(&obj->gtt_list, &dev_priv->mm.unbound_list);
+ i915_gem_object_put_pages_gtt(obj);
+
+ list_del_init(&obj->gtt_list);
+ list_del_init(&obj->mm_list);
/* Avoid an unnecessary call to unbind on rebind. */
obj->map_and_fenceable = true;
@@ -2457,14 +2312,48 @@ i915_gem_object_unbind(struct drm_i915_gem_object *obj)
obj->gtt_space = NULL;
obj->gtt_offset = 0;
+ if (i915_gem_object_is_purgeable(obj))
+ i915_gem_object_truncate(obj);
+
+ return ret;
+}
+
+int
+i915_gem_flush_ring(struct intel_ring_buffer *ring,
+ uint32_t invalidate_domains,
+ uint32_t flush_domains)
+{
+ int ret;
+
+ if (((invalidate_domains | flush_domains) & I915_GEM_GPU_DOMAINS) == 0)
+ return 0;
+
+ trace_i915_gem_ring_flush(ring, invalidate_domains, flush_domains);
+
+ ret = ring->flush(ring, invalidate_domains, flush_domains);
+ if (ret)
+ return ret;
+
+ if (flush_domains & I915_GEM_GPU_DOMAINS)
+ i915_gem_process_flushing_list(ring, flush_domains);
+
return 0;
}
static int i915_ring_idle(struct intel_ring_buffer *ring)
{
- if (list_empty(&ring->active_list))
+ int ret;
+
+ if (list_empty(&ring->gpu_write_list) && list_empty(&ring->active_list))
return 0;
+ if (!list_empty(&ring->gpu_write_list)) {
+ ret = i915_gem_flush_ring(ring,
+ I915_GEM_GPU_DOMAINS, I915_GEM_GPU_DOMAINS);
+ if (ret)
+ return ret;
+ }
+
return i915_wait_seqno(ring, i915_gem_next_request_seqno(ring));
}
@@ -2483,6 +2372,10 @@ int i915_gpu_idle(struct drm_device *dev)
ret = i915_ring_idle(ring);
if (ret)
return ret;
+
+ /* Is the device fubar? */
+ if (WARN_ON(!list_empty(&ring->gpu_write_list)))
+ return -EBUSY;
}
return 0;
@@ -2655,8 +2548,21 @@ 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)
{
+ int ret;
+
+ if (obj->fenced_gpu_access) {
+ if (obj->base.write_domain & I915_GEM_GPU_DOMAINS) {
+ ret = i915_gem_flush_ring(obj->ring,
+ 0, obj->base.write_domain);
+ if (ret)
+ return ret;
+ }
+
+ obj->fenced_gpu_access = false;
+ }
+
if (obj->last_fenced_seqno) {
- int ret = i915_wait_seqno(obj->ring, obj->last_fenced_seqno);
+ ret = i915_wait_seqno(obj->ring, obj->last_fenced_seqno);
if (ret)
return ret;
@@ -2669,7 +2575,6 @@ i915_gem_object_flush_fence(struct drm_i915_gem_object *obj)
if (obj->base.read_domains & I915_GEM_DOMAIN_GTT)
mb();
- obj->fenced_gpu_access = false;
return 0;
}
@@ -2789,88 +2694,18 @@ i915_gem_object_get_fence(struct drm_i915_gem_object *obj)
return 0;
}
-static bool i915_gem_valid_gtt_space(struct drm_device *dev,
- struct drm_mm_node *gtt_space,
- unsigned long cache_level)
-{
- struct drm_mm_node *other;
-
- /* 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.
- */
- if (HAS_LLC(dev))
- return true;
-
- if (gtt_space == NULL)
- return true;
-
- if (list_empty(>t_space->node_list))
- return true;
-
- other = list_entry(gtt_space->node_list.prev, struct drm_mm_node, node_list);
- if (other->allocated && !other->hole_follows && other->color != cache_level)
- return false;
-
- other = list_entry(gtt_space->node_list.next, struct drm_mm_node, node_list);
- if (other->allocated && !gtt_space->hole_follows && other->color != cache_level)
- return false;
-
- return true;
-}
-
-static void i915_gem_verify_gtt(struct drm_device *dev)
-{
-#if WATCH_GTT
- struct drm_i915_private *dev_priv = dev->dev_private;
- struct drm_i915_gem_object *obj;
- int err = 0;
-
- list_for_each_entry(obj, &dev_priv->mm.gtt_list, gtt_list) {
- if (obj->gtt_space == NULL) {
- printk(KERN_ERR "object found on GTT list with no space reserved\n");
- err++;
- continue;
- }
-
- if (obj->cache_level != obj->gtt_space->color) {
- printk(KERN_ERR "object reserved space [%08lx, %08lx] with wrong color, cache_level=%x, color=%lx\n",
- obj->gtt_space->start,
- obj->gtt_space->start + obj->gtt_space->size,
- obj->cache_level,
- obj->gtt_space->color);
- err++;
- continue;
- }
-
- if (!i915_gem_valid_gtt_space(dev,
- obj->gtt_space,
- obj->cache_level)) {
- printk(KERN_ERR "invalid GTT space found at [%08lx, %08lx] - color=%x\n",
- obj->gtt_space->start,
- obj->gtt_space->start + obj->gtt_space->size,
- obj->cache_level);
- err++;
- continue;
- }
- }
-
- WARN_ON(err);
-#endif
-}
-
/**
* Finds free space in the GTT aperture and binds the object there.
*/
static int
i915_gem_object_bind_to_gtt(struct drm_i915_gem_object *obj,
unsigned alignment,
- bool map_and_fenceable,
- bool nonblocking)
+ bool map_and_fenceable)
{
struct drm_device *dev = obj->base.dev;
drm_i915_private_t *dev_priv = dev->dev_private;
struct drm_mm_node *free_space;
+ gfp_t gfpmask = __GFP_NORETRY | __GFP_NOWARN;
u32 size, fence_size, fence_alignment, unfenced_alignment;
bool mappable, fenceable;
int ret;
@@ -2910,67 +2745,89 @@ i915_gem_object_bind_to_gtt(struct drm_i915_gem_object *obj,
return -E2BIG;
}
- ret = i915_gem_object_get_pages(obj);
- if (ret)
- return ret;
-
search_free:
if (map_and_fenceable)
free_space =
- drm_mm_search_free_in_range_color(&dev_priv->mm.gtt_space,
- size, alignment, obj->cache_level,
- 0, dev_priv->mm.gtt_mappable_end,
- false);
+ drm_mm_search_free_in_range(&dev_priv->mm.gtt_space,
+ size, alignment,
+ 0, dev_priv->mm.gtt_mappable_end,
+ 0);
else
- free_space = drm_mm_search_free_color(&dev_priv->mm.gtt_space,
- size, alignment, obj->cache_level,
- false);
+ free_space = drm_mm_search_free(&dev_priv->mm.gtt_space,
+ size, alignment, 0);
if (free_space != NULL) {
if (map_and_fenceable)
obj->gtt_space =
drm_mm_get_block_range_generic(free_space,
- size, alignment, obj->cache_level,
+ size, alignment, 0,
0, dev_priv->mm.gtt_mappable_end,
- false);
+ 0);
else
obj->gtt_space =
- drm_mm_get_block_generic(free_space,
- size, alignment, obj->cache_level,
- false);
+ drm_mm_get_block(free_space, size, alignment);
}
if (obj->gtt_space == NULL) {
+ /* If the gtt is empty and we're still having trouble
+ * fitting our object in, we're out of memory.
+ */
ret = i915_gem_evict_something(dev, size, alignment,
- obj->cache_level,
- map_and_fenceable,
- nonblocking);
+ map_and_fenceable);
if (ret)
return ret;
goto search_free;
}
- if (WARN_ON(!i915_gem_valid_gtt_space(dev,
- obj->gtt_space,
- obj->cache_level))) {
+
+ ret = i915_gem_object_get_pages_gtt(obj, gfpmask);
+ if (ret) {
drm_mm_put_block(obj->gtt_space);
obj->gtt_space = NULL;
- return -EINVAL;
- }
+ if (ret == -ENOMEM) {
+ /* first try to reclaim some memory by clearing the GTT */
+ ret = i915_gem_evict_everything(dev, false);
+ if (ret) {
+ /* now try to shrink everyone else */
+ if (gfpmask) {
+ gfpmask = 0;
+ goto search_free;
+ }
+
+ return -ENOMEM;
+ }
+
+ goto search_free;
+ }
+
+ return ret;
+ }
ret = i915_gem_gtt_prepare_object(obj);
if (ret) {
+ i915_gem_object_put_pages_gtt(obj);
drm_mm_put_block(obj->gtt_space);
obj->gtt_space = NULL;
- return ret;
+
+ if (i915_gem_evict_everything(dev, false))
+ return ret;
+
+ goto search_free;
}
if (!dev_priv->mm.aliasing_ppgtt)
i915_gem_gtt_bind_object(obj, obj->cache_level);
- list_move_tail(&obj->gtt_list, &dev_priv->mm.bound_list);
+ list_add_tail(&obj->gtt_list, &dev_priv->mm.gtt_list);
list_add_tail(&obj->mm_list, &dev_priv->mm.inactive_list);
+ /* Assert that the object is not currently in any GPU domain. As it
+ * wasn't in the GTT, there shouldn't be any way it could have been in
+ * a GPU cache
+ */
+ BUG_ON(obj->base.read_domains & I915_GEM_GPU_DOMAINS);
+ BUG_ON(obj->base.write_domain & I915_GEM_GPU_DOMAINS);
+
obj->gtt_offset = obj->gtt_space->start;
fenceable =
@@ -2983,7 +2840,6 @@ i915_gem_object_bind_to_gtt(struct drm_i915_gem_object *obj,
obj->map_and_fenceable = mappable && fenceable;
trace_i915_gem_object_bind(obj, map_and_fenceable);
- i915_gem_verify_gtt(dev);
return 0;
}
@@ -3010,7 +2866,18 @@ i915_gem_clflush_object(struct drm_i915_gem_object *obj)
trace_i915_gem_object_clflush(obj);
- drm_clflush_sg(obj->pages);
+ drm_clflush_pages(obj->pages, obj->base.size / PAGE_SIZE);
+}
+
+/** Flushes any GPU write domain for the object if it's dirty. */
+static int
+i915_gem_object_flush_gpu_write_domain(struct drm_i915_gem_object *obj)
+{
+ if ((obj->base.write_domain & I915_GEM_GPU_DOMAINS) == 0)
+ return 0;
+
+ /* Queue the GPU write cache flushing we need. */
+ return i915_gem_flush_ring(obj->ring, 0, obj->base.write_domain);
}
/** Flushes the GTT write domain for the object if it's dirty. */
@@ -3079,10 +2946,16 @@ i915_gem_object_set_to_gtt_domain(struct drm_i915_gem_object *obj, bool write)
if (obj->base.write_domain == I915_GEM_DOMAIN_GTT)
return 0;
- ret = i915_gem_object_wait_rendering(obj, !write);
+ ret = i915_gem_object_flush_gpu_write_domain(obj);
if (ret)
return ret;
+ if (obj->pending_gpu_write || write) {
+ ret = i915_gem_object_wait_rendering(obj);
+ if (ret)
+ return ret;
+ }
+
i915_gem_object_flush_cpu_write_domain(obj);
old_write_domain = obj->base.write_domain;
@@ -3125,12 +2998,6 @@ int i915_gem_object_set_cache_level(struct drm_i915_gem_object *obj,
return -EBUSY;
}
- if (!i915_gem_valid_gtt_space(dev, obj->gtt_space, cache_level)) {
- ret = i915_gem_object_unbind(obj);
- if (ret)
- return ret;
- }
-
if (obj->gtt_space) {
ret = i915_gem_object_finish_gpu(obj);
if (ret)
@@ -3142,7 +3009,7 @@ int i915_gem_object_set_cache_level(struct drm_i915_gem_object *obj,
* registers with snooped memory, so relinquish any fences
* currently pointing to our region in the aperture.
*/
- if (INTEL_INFO(dev)->gen < 6) {
+ if (INTEL_INFO(obj->base.dev)->gen < 6) {
ret = i915_gem_object_put_fence(obj);
if (ret)
return ret;
@@ -3153,8 +3020,6 @@ int i915_gem_object_set_cache_level(struct drm_i915_gem_object *obj,
if (obj->has_aliasing_ppgtt_mapping)
i915_ppgtt_bind_object(dev_priv->mm.aliasing_ppgtt,
obj, cache_level);
-
- obj->gtt_space->color = cache_level;
}
if (cache_level == I915_CACHE_NONE) {
@@ -3181,72 +3046,9 @@ int i915_gem_object_set_cache_level(struct drm_i915_gem_object *obj,
}
obj->cache_level = cache_level;
- i915_gem_verify_gtt(dev);
return 0;
}
-int i915_gem_get_caching_ioctl(struct drm_device *dev, void *data,
- struct drm_file *file)
-{
- struct drm_i915_gem_caching *args = data;
- struct drm_i915_gem_object *obj;
- int ret;
-
- ret = i915_mutex_lock_interruptible(dev);
- if (ret)
- return ret;
-
- obj = to_intel_bo(drm_gem_object_lookup(dev, file, args->handle));
- if (&obj->base == NULL) {
- ret = -ENOENT;
- goto unlock;
- }
-
- args->caching = obj->cache_level != I915_CACHE_NONE;
-
- drm_gem_object_unreference(&obj->base);
-unlock:
- mutex_unlock(&dev->struct_mutex);
- return ret;
-}
-
-int i915_gem_set_caching_ioctl(struct drm_device *dev, void *data,
- struct drm_file *file)
-{
- struct drm_i915_gem_caching *args = data;
- struct drm_i915_gem_object *obj;
- enum i915_cache_level level;
- int ret;
-
- ret = i915_mutex_lock_interruptible(dev);
- if (ret)
- return ret;
-
- switch (args->caching) {
- case I915_CACHING_NONE:
- level = I915_CACHE_NONE;
- break;
- case I915_CACHING_CACHED:
- level = I915_CACHE_LLC;
- break;
- default:
- return -EINVAL;
- }
-
- obj = to_intel_bo(drm_gem_object_lookup(dev, file, args->handle));
- if (&obj->base == NULL) {
- ret = -ENOENT;
- goto unlock;
- }
-
- ret = i915_gem_object_set_cache_level(obj, level);
-
- drm_gem_object_unreference(&obj->base);
-unlock:
- mutex_unlock(&dev->struct_mutex);
- return ret;
-}
-
/*
* Prepare buffer for display plane (scanout, cursors, etc).
* Can be called from an uninterruptible phase (modesetting) and allows
@@ -3260,6 +3062,10 @@ i915_gem_object_pin_to_display_plane(struct drm_i915_gem_object *obj,
u32 old_read_domains, old_write_domain;
int ret;
+ ret = i915_gem_object_flush_gpu_write_domain(obj);
+ if (ret)
+ return ret;
+
if (pipelined != obj->ring) {
ret = i915_gem_object_sync(obj, pipelined);
if (ret)
@@ -3283,7 +3089,7 @@ i915_gem_object_pin_to_display_plane(struct drm_i915_gem_object *obj,
* (e.g. libkms for the bootup splash), we have to ensure that we
* always use map_and_fenceable for all scanout buffers.
*/
- ret = i915_gem_object_pin(obj, alignment, true, false);
+ ret = i915_gem_object_pin(obj, alignment, true);
if (ret)
return ret;
@@ -3295,7 +3101,7 @@ i915_gem_object_pin_to_display_plane(struct drm_i915_gem_object *obj,
/* It should now be out of any other write domains, and we can update
* the domain values for our changes.
*/
- obj->base.write_domain = 0;
+ BUG_ON((obj->base.write_domain & ~I915_GEM_DOMAIN_GTT) != 0);
obj->base.read_domains |= I915_GEM_DOMAIN_GTT;
trace_i915_gem_object_change_domain(obj,
@@ -3313,7 +3119,13 @@ i915_gem_object_finish_gpu(struct drm_i915_gem_object *obj)
if ((obj->base.read_domains & I915_GEM_GPU_DOMAINS) == 0)
return 0;
- ret = i915_gem_object_wait_rendering(obj, false);
+ if (obj->base.write_domain & I915_GEM_GPU_DOMAINS) {
+ ret = i915_gem_flush_ring(obj->ring, 0, obj->base.write_domain);
+ if (ret)
+ return ret;
+ }
+
+ ret = i915_gem_object_wait_rendering(obj);
if (ret)
return ret;
@@ -3337,10 +3149,16 @@ i915_gem_object_set_to_cpu_domain(struct drm_i915_gem_object *obj, bool write)
if (obj->base.write_domain == I915_GEM_DOMAIN_CPU)
return 0;
- ret = i915_gem_object_wait_rendering(obj, !write);
+ ret = i915_gem_object_flush_gpu_write_domain(obj);
if (ret)
return ret;
+ if (write || obj->pending_gpu_write) {
+ ret = i915_gem_object_wait_rendering(obj);
+ if (ret)
+ return ret;
+ }
+
i915_gem_object_flush_gtt_write_domain(obj);
old_write_domain = obj->base.write_domain;
@@ -3420,13 +3238,11 @@ i915_gem_ring_throttle(struct drm_device *dev, struct drm_file *file)
int
i915_gem_object_pin(struct drm_i915_gem_object *obj,
uint32_t alignment,
- bool map_and_fenceable,
- bool nonblocking)
+ bool map_and_fenceable)
{
int ret;
- if (WARN_ON(obj->pin_count == DRM_I915_GEM_OBJECT_MAX_PIN_COUNT))
- return -EBUSY;
+ BUG_ON(obj->pin_count == DRM_I915_GEM_OBJECT_MAX_PIN_COUNT);
if (obj->gtt_space != NULL) {
if ((alignment && obj->gtt_offset & (alignment - 1)) ||
@@ -3446,8 +3262,7 @@ i915_gem_object_pin(struct drm_i915_gem_object *obj,
if (obj->gtt_space == NULL) {
ret = i915_gem_object_bind_to_gtt(obj, alignment,
- map_and_fenceable,
- nonblocking);
+ map_and_fenceable);
if (ret)
return ret;
}
@@ -3505,7 +3320,7 @@ i915_gem_pin_ioctl(struct drm_device *dev, void *data,
obj->user_pin_count++;
obj->pin_filp = file;
if (obj->user_pin_count == 1) {
- ret = i915_gem_object_pin(obj, args->alignment, true, false);
+ ret = i915_gem_object_pin(obj, args->alignment, true);
if (ret)
goto out;
}
@@ -3585,10 +3400,6 @@ i915_gem_busy_ioctl(struct drm_device *dev, void *data,
ret = i915_gem_object_flush_active(obj);
args->busy = obj->active;
- if (obj->ring) {
- BUILD_BUG_ON(I915_NUM_RINGS > 16);
- args->busy |= intel_ring_flag(obj->ring) << 16;
- }
drm_gem_object_unreference(&obj->base);
unlock:
@@ -3637,8 +3448,9 @@ i915_gem_madvise_ioctl(struct drm_device *dev, void *data,
if (obj->madv != __I915_MADV_PURGED)
obj->madv = args->madv;
- /* if the object is no longer attached, discard its backing storage */
- if (i915_gem_object_is_purgeable(obj) && obj->pages == NULL)
+ /* if the object is no longer bound, discard its backing storage */
+ if (i915_gem_object_is_purgeable(obj) &&
+ obj->gtt_space == NULL)
i915_gem_object_truncate(obj);
args->retained = obj->madv != __I915_MADV_PURGED;
@@ -3650,32 +3462,10 @@ i915_gem_madvise_ioctl(struct drm_device *dev, void *data,
return ret;
}
-void i915_gem_object_init(struct drm_i915_gem_object *obj,
- const struct drm_i915_gem_object_ops *ops)
-{
- INIT_LIST_HEAD(&obj->mm_list);
- INIT_LIST_HEAD(&obj->gtt_list);
- INIT_LIST_HEAD(&obj->ring_list);
- INIT_LIST_HEAD(&obj->exec_list);
-
- obj->ops = ops;
-
- obj->fence_reg = I915_FENCE_REG_NONE;
- obj->madv = I915_MADV_WILLNEED;
- /* Avoid an unnecessary call to unbind on the first bind. */
- obj->map_and_fenceable = true;
-
- i915_gem_info_add_obj(obj->base.dev->dev_private, obj->base.size);
-}
-
-static const struct drm_i915_gem_object_ops i915_gem_object_ops = {
- .get_pages = i915_gem_object_get_pages_gtt,
- .put_pages = i915_gem_object_put_pages_gtt,
-};
-
struct drm_i915_gem_object *i915_gem_alloc_object(struct drm_device *dev,
size_t size)
{
+ struct drm_i915_private *dev_priv = dev->dev_private;
struct drm_i915_gem_object *obj;
struct address_space *mapping;
u32 mask;
@@ -3699,7 +3489,7 @@ struct drm_i915_gem_object *i915_gem_alloc_object(struct drm_device *dev,
mapping = obj->base.filp->f_path.dentry->d_inode->i_mapping;
mapping_set_gfp_mask(mapping, mask);
- i915_gem_object_init(obj, &i915_gem_object_ops);
+ i915_gem_info_add_obj(dev_priv, size);
obj->base.write_domain = I915_GEM_DOMAIN_CPU;
obj->base.read_domains = I915_GEM_DOMAIN_CPU;
@@ -3721,6 +3511,17 @@ struct drm_i915_gem_object *i915_gem_alloc_object(struct drm_device *dev,
} else
obj->cache_level = I915_CACHE_NONE;
+ obj->base.driver_private = NULL;
+ obj->fence_reg = I915_FENCE_REG_NONE;
+ INIT_LIST_HEAD(&obj->mm_list);
+ INIT_LIST_HEAD(&obj->gtt_list);
+ INIT_LIST_HEAD(&obj->ring_list);
+ INIT_LIST_HEAD(&obj->exec_list);
+ INIT_LIST_HEAD(&obj->gpu_write_list);
+ obj->madv = I915_MADV_WILLNEED;
+ /* Avoid an unnecessary call to unbind on the first bind. */
+ obj->map_and_fenceable = true;
+
return obj;
}
@@ -3739,6 +3540,9 @@ void i915_gem_free_object(struct drm_gem_object *gem_obj)
trace_i915_gem_object_destroy(obj);
+ if (gem_obj->import_attach)
+ drm_prime_gem_destroy(gem_obj, obj->sg_table);
+
if (obj->phys_obj)
i915_gem_detach_phys_object(dev, obj);
@@ -3754,14 +3558,8 @@ void i915_gem_free_object(struct drm_gem_object *gem_obj)
dev_priv->mm.interruptible = was_interruptible;
}
- obj->pages_pin_count = 0;
- i915_gem_object_put_pages(obj);
- i915_gem_object_free_mmap_offset(obj);
-
- BUG_ON(obj->pages);
-
- if (obj->base.import_attach)
- drm_prime_gem_destroy(&obj->base, NULL);
+ if (obj->base.map_list.map)
+ drm_gem_free_mmap_offset(&obj->base);
drm_gem_object_release(&obj->base);
i915_gem_info_remove_obj(dev_priv, obj->base.size);
@@ -3792,7 +3590,7 @@ i915_gem_idle(struct drm_device *dev)
/* Under UMS, be paranoid and evict. */
if (!drm_core_check_feature(dev, DRIVER_MODESET))
- i915_gem_evict_everything(dev);
+ i915_gem_evict_everything(dev, false);
i915_gem_reset_fences(dev);
@@ -4093,6 +3891,7 @@ i915_gem_entervt_ioctl(struct drm_device *dev, void *data,
}
BUG_ON(!list_empty(&dev_priv->mm.active_list));
+ BUG_ON(!list_empty(&dev_priv->mm.flushing_list));
BUG_ON(!list_empty(&dev_priv->mm.inactive_list));
mutex_unlock(&dev->struct_mutex);
@@ -4140,6 +3939,7 @@ init_ring_lists(struct intel_ring_buffer *ring)
{
INIT_LIST_HEAD(&ring->active_list);
INIT_LIST_HEAD(&ring->request_list);
+ INIT_LIST_HEAD(&ring->gpu_write_list);
}
void
@@ -4149,10 +3949,10 @@ i915_gem_load(struct drm_device *dev)
drm_i915_private_t *dev_priv = dev->dev_private;
INIT_LIST_HEAD(&dev_priv->mm.active_list);
+ INIT_LIST_HEAD(&dev_priv->mm.flushing_list);
INIT_LIST_HEAD(&dev_priv->mm.inactive_list);
- INIT_LIST_HEAD(&dev_priv->mm.unbound_list);
- INIT_LIST_HEAD(&dev_priv->mm.bound_list);
INIT_LIST_HEAD(&dev_priv->mm.fence_list);
+ INIT_LIST_HEAD(&dev_priv->mm.gtt_list);
for (i = 0; i < I915_NUM_RINGS; i++)
init_ring_lists(&dev_priv->ring[i]);
for (i = 0; i < I915_MAX_NUM_FENCES; i++)
@@ -4396,6 +4196,18 @@ void i915_gem_release(struct drm_device *dev, struct drm_file *file)
spin_unlock(&file_priv->mm.lock);
}
+static int
+i915_gpu_is_active(struct drm_device *dev)
+{
+ drm_i915_private_t *dev_priv = dev->dev_private;
+ int lists_empty;
+
+ lists_empty = list_empty(&dev_priv->mm.flushing_list) &&
+ list_empty(&dev_priv->mm.active_list);
+
+ return !lists_empty;
+}
+
static int
i915_gem_inactive_shrink(struct shrinker *shrinker, struct shrink_control *sc)
{
@@ -4404,27 +4216,60 @@ i915_gem_inactive_shrink(struct shrinker *shrinker, struct shrink_control *sc)
struct drm_i915_private,
mm.inactive_shrinker);
struct drm_device *dev = dev_priv->dev;
- struct drm_i915_gem_object *obj;
+ struct drm_i915_gem_object *obj, *next;
int nr_to_scan = sc->nr_to_scan;
int cnt;
if (!mutex_trylock(&dev->struct_mutex))
return 0;
- if (nr_to_scan) {
- nr_to_scan -= i915_gem_purge(dev_priv, nr_to_scan);
- if (nr_to_scan > 0)
- i915_gem_shrink_all(dev_priv);
+ /* "fast-path" to count number of available objects */
+ if (nr_to_scan == 0) {
+ cnt = 0;
+ list_for_each_entry(obj,
+ &dev_priv->mm.inactive_list,
+ mm_list)
+ cnt++;
+ mutex_unlock(&dev->struct_mutex);
+ return cnt / 100 * sysctl_vfs_cache_pressure;
+ }
+
+rescan:
+ /* first scan for clean buffers */
+ i915_gem_retire_requests(dev);
+
+ list_for_each_entry_safe(obj, next,
+ &dev_priv->mm.inactive_list,
+ mm_list) {
+ if (i915_gem_object_is_purgeable(obj)) {
+ if (i915_gem_object_unbind(obj) == 0 &&
+ --nr_to_scan == 0)
+ break;
+ }
}
+ /* second pass, evict/count anything still on the inactive list */
cnt = 0;
- list_for_each_entry(obj, &dev_priv->mm.unbound_list, gtt_list)
- if (obj->pages_pin_count == 0)
- cnt += obj->base.size >> PAGE_SHIFT;
- list_for_each_entry(obj, &dev_priv->mm.bound_list, gtt_list)
- if (obj->pin_count == 0 && obj->pages_pin_count == 0)
- cnt += obj->base.size >> PAGE_SHIFT;
+ list_for_each_entry_safe(obj, next,
+ &dev_priv->mm.inactive_list,
+ mm_list) {
+ if (nr_to_scan &&
+ i915_gem_object_unbind(obj) == 0)
+ nr_to_scan--;
+ else
+ cnt++;
+ }
+ if (nr_to_scan && i915_gpu_is_active(dev)) {
+ /*
+ * We are desperate for pages, so as a last resort, wait
+ * for the GPU to finish and discard whatever we can.
+ * This has a dramatic impact to reduce the number of
+ * OOM-killer events whilst running the GPU aggressively.
+ */
+ if (i915_gpu_idle(dev) == 0)
+ goto rescan;
+ }
mutex_unlock(&dev->struct_mutex);
- return cnt;
+ return cnt / 100 * sysctl_vfs_cache_pressure;
}
diff --git a/trunk/drivers/gpu/drm/i915/i915_gem_context.c b/trunk/drivers/gpu/drm/i915/i915_gem_context.c
index 4aa7ecf77ede..a9d58d72bb4d 100644
--- a/trunk/drivers/gpu/drm/i915/i915_gem_context.c
+++ b/trunk/drivers/gpu/drm/i915/i915_gem_context.c
@@ -97,7 +97,8 @@
static struct i915_hw_context *
i915_gem_context_get(struct drm_i915_file_private *file_priv, u32 id);
-static int do_switch(struct i915_hw_context *to);
+static int do_switch(struct drm_i915_gem_object *from_obj,
+ struct i915_hw_context *to, u32 seqno);
static int get_context_size(struct drm_device *dev)
{
@@ -112,10 +113,7 @@ static int get_context_size(struct drm_device *dev)
break;
case 7:
reg = I915_READ(GEN7_CXT_SIZE);
- if (IS_HASWELL(dev))
- ret = HSW_CXT_TOTAL_SIZE(reg) * 64;
- else
- ret = GEN7_CXT_TOTAL_SIZE(reg) * 64;
+ ret = GEN7_CXT_TOTAL_SIZE(reg) * 64;
break;
default:
BUG();
@@ -221,21 +219,20 @@ static int create_default_context(struct drm_i915_private *dev_priv)
* default context.
*/
dev_priv->ring[RCS].default_context = ctx;
- ret = i915_gem_object_pin(ctx->obj, CONTEXT_ALIGN, false, false);
- if (ret)
- goto err_destroy;
-
- ret = do_switch(ctx);
- if (ret)
- goto err_unpin;
+ ret = i915_gem_object_pin(ctx->obj, CONTEXT_ALIGN, false);
+ if (ret) {
+ do_destroy(ctx);
+ return ret;
+ }
- DRM_DEBUG_DRIVER("Default HW context loaded\n");
- return 0;
+ ret = do_switch(NULL, ctx, 0);
+ if (ret) {
+ i915_gem_object_unpin(ctx->obj);
+ do_destroy(ctx);
+ } else {
+ DRM_DEBUG_DRIVER("Default HW context loaded\n");
+ }
-err_unpin:
- i915_gem_object_unpin(ctx->obj);
-err_destroy:
- do_destroy(ctx);
return ret;
}
@@ -362,19 +359,18 @@ mi_set_context(struct intel_ring_buffer *ring,
return ret;
}
-static int do_switch(struct i915_hw_context *to)
+static int do_switch(struct drm_i915_gem_object *from_obj,
+ struct i915_hw_context *to,
+ u32 seqno)
{
- struct intel_ring_buffer *ring = to->ring;
- struct drm_i915_gem_object *from_obj = ring->last_context_obj;
+ struct intel_ring_buffer *ring = NULL;
u32 hw_flags = 0;
int ret;
+ BUG_ON(to == NULL);
BUG_ON(from_obj != NULL && from_obj->pin_count == 0);
- if (from_obj == to->obj)
- return 0;
-
- ret = i915_gem_object_pin(to->obj, CONTEXT_ALIGN, false, false);
+ ret = i915_gem_object_pin(to->obj, CONTEXT_ALIGN, false);
if (ret)
return ret;
@@ -397,6 +393,7 @@ static int do_switch(struct i915_hw_context *to)
else if (WARN_ON_ONCE(from_obj == to->obj)) /* not yet expected */
hw_flags |= MI_FORCE_RESTORE;
+ ring = to->ring;
ret = mi_set_context(ring, to, hw_flags);
if (ret) {
i915_gem_object_unpin(to->obj);
@@ -410,7 +407,6 @@ static int do_switch(struct i915_hw_context *to)
* MI_SET_CONTEXT instead of when the next seqno has completed.
*/
if (from_obj != NULL) {
- u32 seqno = i915_gem_next_request_seqno(ring);
from_obj->base.read_domains = I915_GEM_DOMAIN_INSTRUCTION;
i915_gem_object_move_to_active(from_obj, ring, seqno);
/* As long as MI_SET_CONTEXT is serializing, ie. it flushes the
@@ -421,7 +417,7 @@ static int do_switch(struct i915_hw_context *to)
* swapped, but there is no way to do that yet.
*/
from_obj->dirty = 1;
- BUG_ON(from_obj->ring != ring);
+ BUG_ON(from_obj->ring != to->ring);
i915_gem_object_unpin(from_obj);
drm_gem_object_unreference(&from_obj->base);
@@ -452,7 +448,9 @@ int i915_switch_context(struct intel_ring_buffer *ring,
int to_id)
{
struct drm_i915_private *dev_priv = ring->dev->dev_private;
+ struct drm_i915_file_private *file_priv = NULL;
struct i915_hw_context *to;
+ struct drm_i915_gem_object *from_obj = ring->last_context_obj;
if (dev_priv->hw_contexts_disabled)
return 0;
@@ -460,18 +458,21 @@ int i915_switch_context(struct intel_ring_buffer *ring,
if (ring != &dev_priv->ring[RCS])
return 0;
+ if (file)
+ file_priv = file->driver_priv;
+
if (to_id == DEFAULT_CONTEXT_ID) {
to = ring->default_context;
} else {
- if (file == NULL)
- return -EINVAL;
-
- to = i915_gem_context_get(file->driver_priv, to_id);
+ to = i915_gem_context_get(file_priv, to_id);
if (to == NULL)
return -ENOENT;
}
- return do_switch(to);
+ if (from_obj == to->obj)
+ return 0;
+
+ return do_switch(from_obj, to, i915_gem_next_request_seqno(to->ring));
}
int i915_gem_context_create_ioctl(struct drm_device *dev, void *data,
diff --git a/trunk/drivers/gpu/drm/i915/i915_gem_dmabuf.c b/trunk/drivers/gpu/drm/i915/i915_gem_dmabuf.c
index ca3497e1108c..aa308e1337db 100644
--- a/trunk/drivers/gpu/drm/i915/i915_gem_dmabuf.c
+++ b/trunk/drivers/gpu/drm/i915/i915_gem_dmabuf.c
@@ -28,62 +28,35 @@
#include
static struct sg_table *i915_gem_map_dma_buf(struct dma_buf_attachment *attachment,
- enum dma_data_direction dir)
+ enum dma_data_direction dir)
{
struct drm_i915_gem_object *obj = attachment->dmabuf->priv;
- struct sg_table *st;
- struct scatterlist *src, *dst;
- int ret, i;
+ struct drm_device *dev = obj->base.dev;
+ int npages = obj->base.size / PAGE_SIZE;
+ struct sg_table *sg = NULL;
+ int ret;
+ int nents;
- ret = i915_mutex_lock_interruptible(obj->base.dev);
+ ret = i915_mutex_lock_interruptible(dev);
if (ret)
return ERR_PTR(ret);
- ret = i915_gem_object_get_pages(obj);
- if (ret) {
- st = ERR_PTR(ret);
- goto out;
- }
-
- /* Copy sg so that we make an independent mapping */
- st = kmalloc(sizeof(struct sg_table), GFP_KERNEL);
- if (st == NULL) {
- st = ERR_PTR(-ENOMEM);
- goto out;
+ if (!obj->pages) {
+ ret = i915_gem_object_get_pages_gtt(obj, __GFP_NORETRY | __GFP_NOWARN);
+ if (ret)
+ goto out;
}
- ret = sg_alloc_table(st, obj->pages->nents, GFP_KERNEL);
- if (ret) {
- kfree(st);
- st = ERR_PTR(ret);
- goto out;
- }
-
- src = obj->pages->sgl;
- dst = st->sgl;
- for (i = 0; i < obj->pages->nents; i++) {
- sg_set_page(dst, sg_page(src), PAGE_SIZE, 0);
- dst = sg_next(dst);
- src = sg_next(src);
- }
-
- if (!dma_map_sg(attachment->dev, st->sgl, st->nents, dir)) {
- sg_free_table(st);
- kfree(st);
- st = ERR_PTR(-ENOMEM);
- goto out;
- }
-
- i915_gem_object_pin_pages(obj);
-
+ /* link the pages into an SG then map the sg */
+ sg = drm_prime_pages_to_sg(obj->pages, npages);
+ nents = dma_map_sg(attachment->dev, sg->sgl, sg->nents, dir);
out:
- mutex_unlock(&obj->base.dev->struct_mutex);
- return st;
+ mutex_unlock(&dev->struct_mutex);
+ return sg;
}
static void i915_gem_unmap_dma_buf(struct dma_buf_attachment *attachment,
- struct sg_table *sg,
- enum dma_data_direction dir)
+ struct sg_table *sg, enum dma_data_direction dir)
{
dma_unmap_sg(attachment->dev, sg->sgl, sg->nents, dir);
sg_free_table(sg);
@@ -105,9 +78,7 @@ static void *i915_gem_dmabuf_vmap(struct dma_buf *dma_buf)
{
struct drm_i915_gem_object *obj = dma_buf->priv;
struct drm_device *dev = obj->base.dev;
- struct scatterlist *sg;
- struct page **pages;
- int ret, i;
+ int ret;
ret = i915_mutex_lock_interruptible(dev);
if (ret)
@@ -118,34 +89,24 @@ static void *i915_gem_dmabuf_vmap(struct dma_buf *dma_buf)
goto out_unlock;
}
- ret = i915_gem_object_get_pages(obj);
- if (ret)
- goto error;
-
- ret = -ENOMEM;
-
- pages = drm_malloc_ab(obj->pages->nents, sizeof(struct page *));
- if (pages == NULL)
- goto error;
-
- for_each_sg(obj->pages->sgl, sg, obj->pages->nents, i)
- pages[i] = sg_page(sg);
-
- obj->dma_buf_vmapping = vmap(pages, obj->pages->nents, 0, PAGE_KERNEL);
- drm_free_large(pages);
+ if (!obj->pages) {
+ ret = i915_gem_object_get_pages_gtt(obj, __GFP_NORETRY | __GFP_NOWARN);
+ if (ret) {
+ mutex_unlock(&dev->struct_mutex);
+ return ERR_PTR(ret);
+ }
+ }
- if (!obj->dma_buf_vmapping)
- goto error;
+ obj->dma_buf_vmapping = vmap(obj->pages, obj->base.size / PAGE_SIZE, 0, PAGE_KERNEL);
+ if (!obj->dma_buf_vmapping) {
+ DRM_ERROR("failed to vmap object\n");
+ goto out_unlock;
+ }
obj->vmapping_count = 1;
- i915_gem_object_pin_pages(obj);
out_unlock:
mutex_unlock(&dev->struct_mutex);
return obj->dma_buf_vmapping;
-
-error:
- mutex_unlock(&dev->struct_mutex);
- return ERR_PTR(ret);
}
static void i915_gem_dmabuf_vunmap(struct dma_buf *dma_buf, void *vaddr)
@@ -158,11 +119,10 @@ static void i915_gem_dmabuf_vunmap(struct dma_buf *dma_buf, void *vaddr)
if (ret)
return;
- if (--obj->vmapping_count == 0) {
+ --obj->vmapping_count;
+ if (obj->vmapping_count == 0) {
vunmap(obj->dma_buf_vmapping);
obj->dma_buf_vmapping = NULL;
-
- i915_gem_object_unpin_pages(obj);
}
mutex_unlock(&dev->struct_mutex);
}
@@ -191,22 +151,6 @@ static int i915_gem_dmabuf_mmap(struct dma_buf *dma_buf, struct vm_area_struct *
return -EINVAL;
}
-static int i915_gem_begin_cpu_access(struct dma_buf *dma_buf, size_t start, size_t length, enum dma_data_direction direction)
-{
- struct drm_i915_gem_object *obj = dma_buf->priv;
- struct drm_device *dev = obj->base.dev;
- int ret;
- bool write = (direction == DMA_BIDIRECTIONAL || direction == DMA_TO_DEVICE);
-
- ret = i915_mutex_lock_interruptible(dev);
- if (ret)
- return ret;
-
- ret = i915_gem_object_set_to_cpu_domain(obj, write);
- mutex_unlock(&dev->struct_mutex);
- return ret;
-}
-
static const struct dma_buf_ops i915_dmabuf_ops = {
.map_dma_buf = i915_gem_map_dma_buf,
.unmap_dma_buf = i915_gem_unmap_dma_buf,
@@ -218,47 +162,25 @@ static const struct dma_buf_ops i915_dmabuf_ops = {
.mmap = i915_gem_dmabuf_mmap,
.vmap = i915_gem_dmabuf_vmap,
.vunmap = i915_gem_dmabuf_vunmap,
- .begin_cpu_access = i915_gem_begin_cpu_access,
};
struct dma_buf *i915_gem_prime_export(struct drm_device *dev,
- struct drm_gem_object *gem_obj, int flags)
+ struct drm_gem_object *gem_obj, int flags)
{
struct drm_i915_gem_object *obj = to_intel_bo(gem_obj);
- return dma_buf_export(obj, &i915_dmabuf_ops, obj->base.size, 0600);
-}
-
-static int i915_gem_object_get_pages_dmabuf(struct drm_i915_gem_object *obj)
-{
- struct sg_table *sg;
-
- sg = dma_buf_map_attachment(obj->base.import_attach, DMA_BIDIRECTIONAL);
- if (IS_ERR(sg))
- return PTR_ERR(sg);
-
- obj->pages = sg;
- obj->has_dma_mapping = true;
- return 0;
+ return dma_buf_export(obj, &i915_dmabuf_ops,
+ obj->base.size, 0600);
}
-static void i915_gem_object_put_pages_dmabuf(struct drm_i915_gem_object *obj)
-{
- dma_buf_unmap_attachment(obj->base.import_attach,
- obj->pages, DMA_BIDIRECTIONAL);
- obj->has_dma_mapping = false;
-}
-
-static const struct drm_i915_gem_object_ops i915_gem_object_dmabuf_ops = {
- .get_pages = i915_gem_object_get_pages_dmabuf,
- .put_pages = i915_gem_object_put_pages_dmabuf,
-};
-
struct drm_gem_object *i915_gem_prime_import(struct drm_device *dev,
- struct dma_buf *dma_buf)
+ struct dma_buf *dma_buf)
{
struct dma_buf_attachment *attach;
+ struct sg_table *sg;
struct drm_i915_gem_object *obj;
+ int npages;
+ int size;
int ret;
/* is this one of own objects? */
@@ -276,24 +198,34 @@ struct drm_gem_object *i915_gem_prime_import(struct drm_device *dev,
if (IS_ERR(attach))
return ERR_CAST(attach);
+ sg = dma_buf_map_attachment(attach, DMA_BIDIRECTIONAL);
+ if (IS_ERR(sg)) {
+ ret = PTR_ERR(sg);
+ goto fail_detach;
+ }
+
+ size = dma_buf->size;
+ npages = size / PAGE_SIZE;
obj = kzalloc(sizeof(*obj), GFP_KERNEL);
if (obj == NULL) {
ret = -ENOMEM;
- goto fail_detach;
+ goto fail_unmap;
}
- ret = drm_gem_private_object_init(dev, &obj->base, dma_buf->size);
+ ret = drm_gem_private_object_init(dev, &obj->base, size);
if (ret) {
kfree(obj);
- goto fail_detach;
+ goto fail_unmap;
}
- i915_gem_object_init(obj, &i915_gem_object_dmabuf_ops);
+ obj->sg_table = sg;
obj->base.import_attach = attach;
return &obj->base;
+fail_unmap:
+ dma_buf_unmap_attachment(attach, sg, DMA_BIDIRECTIONAL);
fail_detach:
dma_buf_detach(dma_buf, attach);
return ERR_PTR(ret);
diff --git a/trunk/drivers/gpu/drm/i915/i915_gem_evict.c b/trunk/drivers/gpu/drm/i915/i915_gem_evict.c
index a2d8acde8550..eba0308f10e3 100644
--- a/trunk/drivers/gpu/drm/i915/i915_gem_evict.c
+++ b/trunk/drivers/gpu/drm/i915/i915_gem_evict.c
@@ -44,8 +44,7 @@ mark_free(struct drm_i915_gem_object *obj, struct list_head *unwind)
int
i915_gem_evict_something(struct drm_device *dev, int min_size,
- unsigned alignment, unsigned cache_level,
- bool mappable, bool nonblocking)
+ unsigned alignment, bool mappable)
{
drm_i915_private_t *dev_priv = dev->dev_private;
struct list_head eviction_list, unwind_list;
@@ -80,11 +79,11 @@ i915_gem_evict_something(struct drm_device *dev, int min_size,
INIT_LIST_HEAD(&unwind_list);
if (mappable)
drm_mm_init_scan_with_range(&dev_priv->mm.gtt_space,
- min_size, alignment, cache_level,
+ min_size, alignment, 0,
0, dev_priv->mm.gtt_mappable_end);
else
drm_mm_init_scan(&dev_priv->mm.gtt_space,
- min_size, alignment, cache_level);
+ min_size, alignment, 0);
/* First see if there is a large enough contiguous idle region... */
list_for_each_entry(obj, &dev_priv->mm.inactive_list, mm_list) {
@@ -92,16 +91,29 @@ i915_gem_evict_something(struct drm_device *dev, int min_size,
goto found;
}
- if (nonblocking)
- goto none;
-
/* Now merge in the soon-to-be-expired objects... */
list_for_each_entry(obj, &dev_priv->mm.active_list, mm_list) {
+ /* Does the object require an outstanding flush? */
+ if (obj->base.write_domain)
+ continue;
+
+ if (mark_free(obj, &unwind_list))
+ goto found;
+ }
+
+ /* Finally add anything with a pending flush (in order of retirement) */
+ list_for_each_entry(obj, &dev_priv->mm.flushing_list, mm_list) {
+ if (mark_free(obj, &unwind_list))
+ goto found;
+ }
+ list_for_each_entry(obj, &dev_priv->mm.active_list, mm_list) {
+ if (!obj->base.write_domain)
+ continue;
+
if (mark_free(obj, &unwind_list))
goto found;
}
-none:
/* Nothing found, clean up and bail out! */
while (!list_empty(&unwind_list)) {
obj = list_first_entry(&unwind_list,
@@ -152,7 +164,7 @@ i915_gem_evict_something(struct drm_device *dev, int min_size,
}
int
-i915_gem_evict_everything(struct drm_device *dev)
+i915_gem_evict_everything(struct drm_device *dev, bool purgeable_only)
{
drm_i915_private_t *dev_priv = dev->dev_private;
struct drm_i915_gem_object *obj, *next;
@@ -160,11 +172,12 @@ i915_gem_evict_everything(struct drm_device *dev)
int ret;
lists_empty = (list_empty(&dev_priv->mm.inactive_list) &&
+ list_empty(&dev_priv->mm.flushing_list) &&
list_empty(&dev_priv->mm.active_list));
if (lists_empty)
return -ENOSPC;
- trace_i915_gem_evict_everything(dev);
+ trace_i915_gem_evict_everything(dev, purgeable_only);
/* The gpu_idle will flush everything in the write domain to the
* active list. Then we must move everything off the active list
@@ -176,11 +189,16 @@ i915_gem_evict_everything(struct drm_device *dev)
i915_gem_retire_requests(dev);
+ BUG_ON(!list_empty(&dev_priv->mm.flushing_list));
+
/* Having flushed everything, unbind() should never raise an error */
list_for_each_entry_safe(obj, next,
- &dev_priv->mm.inactive_list, mm_list)
- if (obj->pin_count == 0)
- WARN_ON(i915_gem_object_unbind(obj));
+ &dev_priv->mm.inactive_list, mm_list) {
+ if (!purgeable_only || obj->madv != I915_MADV_WILLNEED) {
+ if (obj->pin_count == 0)
+ WARN_ON(i915_gem_object_unbind(obj));
+ }
+ }
return 0;
}
diff --git a/trunk/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/trunk/drivers/gpu/drm/i915/i915_gem_execbuffer.c
index 6a2f3e50c714..ff2819ea0813 100644
--- a/trunk/drivers/gpu/drm/i915/i915_gem_execbuffer.c
+++ b/trunk/drivers/gpu/drm/i915/i915_gem_execbuffer.c
@@ -34,6 +34,180 @@
#include "intel_drv.h"
#include
+struct change_domains {
+ uint32_t invalidate_domains;
+ uint32_t flush_domains;
+ uint32_t flush_rings;
+ uint32_t flips;
+};
+
+/*
+ * Set the next domain for the specified object. This
+ * may not actually perform the necessary flushing/invaliding though,
+ * as that may want to be batched with other set_domain operations
+ *
+ * This is (we hope) the only really tricky part of gem. The goal
+ * is fairly simple -- track which caches hold bits of the object
+ * and make sure they remain coherent. A few concrete examples may
+ * help to explain how it works. For shorthand, we use the notation
+ * (read_domains, write_domain), e.g. (CPU, CPU) to indicate the
+ * a pair of read and write domain masks.
+ *
+ * Case 1: the batch buffer
+ *
+ * 1. Allocated
+ * 2. Written by CPU
+ * 3. Mapped to GTT
+ * 4. Read by GPU
+ * 5. Unmapped from GTT
+ * 6. Freed
+ *
+ * Let's take these a step at a time
+ *
+ * 1. Allocated
+ * Pages allocated from the kernel may still have
+ * cache contents, so we set them to (CPU, CPU) always.
+ * 2. Written by CPU (using pwrite)
+ * The pwrite function calls set_domain (CPU, CPU) and
+ * this function does nothing (as nothing changes)
+ * 3. Mapped by GTT
+ * This function asserts that the object is not
+ * currently in any GPU-based read or write domains
+ * 4. Read by GPU
+ * i915_gem_execbuffer calls set_domain (COMMAND, 0).
+ * As write_domain is zero, this function adds in the
+ * current read domains (CPU+COMMAND, 0).
+ * flush_domains is set to CPU.
+ * invalidate_domains is set to COMMAND
+ * clflush is run to get data out of the CPU caches
+ * then i915_dev_set_domain calls i915_gem_flush to
+ * emit an MI_FLUSH and drm_agp_chipset_flush
+ * 5. Unmapped from GTT
+ * i915_gem_object_unbind calls set_domain (CPU, CPU)
+ * flush_domains and invalidate_domains end up both zero
+ * so no flushing/invalidating happens
+ * 6. Freed
+ * yay, done
+ *
+ * Case 2: The shared render buffer
+ *
+ * 1. Allocated
+ * 2. Mapped to GTT
+ * 3. Read/written by GPU
+ * 4. set_domain to (CPU,CPU)
+ * 5. Read/written by CPU
+ * 6. Read/written by GPU
+ *
+ * 1. Allocated
+ * Same as last example, (CPU, CPU)
+ * 2. Mapped to GTT
+ * Nothing changes (assertions find that it is not in the GPU)
+ * 3. Read/written by GPU
+ * execbuffer calls set_domain (RENDER, RENDER)
+ * flush_domains gets CPU
+ * invalidate_domains gets GPU
+ * clflush (obj)
+ * MI_FLUSH and drm_agp_chipset_flush
+ * 4. set_domain (CPU, CPU)
+ * flush_domains gets GPU
+ * invalidate_domains gets CPU
+ * wait_rendering (obj) to make sure all drawing is complete.
+ * This will include an MI_FLUSH to get the data from GPU
+ * to memory
+ * clflush (obj) to invalidate the CPU cache
+ * Another MI_FLUSH in i915_gem_flush (eliminate this somehow?)
+ * 5. Read/written by CPU
+ * cache lines are loaded and dirtied
+ * 6. Read written by GPU
+ * Same as last GPU access
+ *
+ * Case 3: The constant buffer
+ *
+ * 1. Allocated
+ * 2. Written by CPU
+ * 3. Read by GPU
+ * 4. Updated (written) by CPU again
+ * 5. Read by GPU
+ *
+ * 1. Allocated
+ * (CPU, CPU)
+ * 2. Written by CPU
+ * (CPU, CPU)
+ * 3. Read by GPU
+ * (CPU+RENDER, 0)
+ * flush_domains = CPU
+ * invalidate_domains = RENDER
+ * clflush (obj)
+ * MI_FLUSH
+ * drm_agp_chipset_flush
+ * 4. Updated (written) by CPU again
+ * (CPU, CPU)
+ * flush_domains = 0 (no previous write domain)
+ * invalidate_domains = 0 (no new read domains)
+ * 5. Read by GPU
+ * (CPU+RENDER, 0)
+ * flush_domains = CPU
+ * invalidate_domains = RENDER
+ * clflush (obj)
+ * MI_FLUSH
+ * drm_agp_chipset_flush
+ */
+static void
+i915_gem_object_set_to_gpu_domain(struct drm_i915_gem_object *obj,
+ struct intel_ring_buffer *ring,
+ struct change_domains *cd)
+{
+ uint32_t invalidate_domains = 0, flush_domains = 0;
+
+ /*
+ * If the object isn't moving to a new write domain,
+ * let the object stay in multiple read domains
+ */
+ if (obj->base.pending_write_domain == 0)
+ obj->base.pending_read_domains |= obj->base.read_domains;
+
+ /*
+ * Flush the current write domain if
+ * the new read domains don't match. Invalidate
+ * any read domains which differ from the old
+ * write domain
+ */
+ if (obj->base.write_domain &&
+ (((obj->base.write_domain != obj->base.pending_read_domains ||
+ obj->ring != ring)) ||
+ (obj->fenced_gpu_access && !obj->pending_fenced_gpu_access))) {
+ flush_domains |= obj->base.write_domain;
+ invalidate_domains |=
+ obj->base.pending_read_domains & ~obj->base.write_domain;
+ }
+ /*
+ * Invalidate any read caches which may have
+ * stale data. That is, any new read domains.
+ */
+ invalidate_domains |= obj->base.pending_read_domains & ~obj->base.read_domains;
+ if ((flush_domains | invalidate_domains) & I915_GEM_DOMAIN_CPU)
+ i915_gem_clflush_object(obj);
+
+ if (obj->base.pending_write_domain)
+ cd->flips |= atomic_read(&obj->pending_flip);
+
+ /* The actual obj->write_domain will be updated with
+ * pending_write_domain after we emit the accumulated flush for all
+ * of our domain changes in execbuffers (which clears objects'
+ * write_domains). So if we have a current write domain that we
+ * aren't changing, set pending_write_domain to that.
+ */
+ if (flush_domains == 0 && obj->base.pending_write_domain == 0)
+ obj->base.pending_write_domain = obj->base.write_domain;
+
+ cd->invalidate_domains |= invalidate_domains;
+ cd->flush_domains |= flush_domains;
+ if (flush_domains & I915_GEM_GPU_DOMAINS)
+ cd->flush_rings |= intel_ring_flag(obj->ring);
+ if (invalidate_domains & I915_GEM_GPU_DOMAINS)
+ cd->flush_rings |= intel_ring_flag(ring);
+}
+
struct eb_objects {
int and;
struct hlist_head buckets[0];
@@ -44,7 +218,6 @@ eb_create(int size)
{
struct eb_objects *eb;
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)
count >>= 1;
eb = kzalloc(count*sizeof(struct hlist_head) +
@@ -96,7 +269,6 @@ eb_destroy(struct eb_objects *eb)
static inline int use_cpu_reloc(struct drm_i915_gem_object *obj)
{
return (obj->base.write_domain == I915_GEM_DOMAIN_CPU ||
- !obj->map_and_fenceable ||
obj->cache_level != I915_CACHE_NONE);
}
@@ -211,8 +383,7 @@ i915_gem_execbuffer_relocate_entry(struct drm_i915_gem_object *obj,
if (ret)
return ret;
- vaddr = kmap_atomic(i915_gem_object_get_page(obj,
- reloc->offset >> PAGE_SHIFT));
+ vaddr = kmap_atomic(obj->pages[reloc->offset >> PAGE_SHIFT]);
*(uint32_t *)(vaddr + page_offset) = reloc->delta;
kunmap_atomic(vaddr);
} else {
@@ -333,8 +504,7 @@ i915_gem_execbuffer_relocate(struct drm_device *dev,
return ret;
}
-#define __EXEC_OBJECT_HAS_PIN (1<<31)
-#define __EXEC_OBJECT_HAS_FENCE (1<<30)
+#define __EXEC_OBJECT_HAS_FENCE (1<<31)
static int
need_reloc_mappable(struct drm_i915_gem_object *obj)
@@ -344,10 +514,9 @@ 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)
+pin_and_fence_object(struct drm_i915_gem_object *obj,
+ struct intel_ring_buffer *ring)
{
- struct drm_i915_private *dev_priv = obj->base.dev->dev_private;
struct drm_i915_gem_exec_object2 *entry = obj->exec_entry;
bool has_fenced_gpu_access = INTEL_INFO(ring->dev)->gen < 4;
bool need_fence, need_mappable;
@@ -359,17 +528,15 @@ i915_gem_execbuffer_reserve_object(struct drm_i915_gem_object *obj,
obj->tiling_mode != I915_TILING_NONE;
need_mappable = need_fence || need_reloc_mappable(obj);
- ret = i915_gem_object_pin(obj, entry->alignment, need_mappable, false);
+ ret = i915_gem_object_pin(obj, entry->alignment, need_mappable);
if (ret)
return ret;
- entry->flags |= __EXEC_OBJECT_HAS_PIN;
-
if (has_fenced_gpu_access) {
if (entry->flags & EXEC_OBJECT_NEEDS_FENCE) {
ret = i915_gem_object_get_fence(obj);
if (ret)
- return ret;
+ goto err_unpin;
if (i915_gem_object_pin_fence(obj))
entry->flags |= __EXEC_OBJECT_HAS_FENCE;
@@ -378,35 +545,12 @@ i915_gem_execbuffer_reserve_object(struct drm_i915_gem_object *obj,
}
}
- /* Ensure ppgtt mapping exists if needed */
- if (dev_priv->mm.aliasing_ppgtt && !obj->has_aliasing_ppgtt_mapping) {
- i915_ppgtt_bind_object(dev_priv->mm.aliasing_ppgtt,
- obj, obj->cache_level);
-
- obj->has_aliasing_ppgtt_mapping = 1;
- }
-
entry->offset = obj->gtt_offset;
return 0;
-}
-
-static void
-i915_gem_execbuffer_unreserve_object(struct drm_i915_gem_object *obj)
-{
- struct drm_i915_gem_exec_object2 *entry;
-
- if (!obj->gtt_space)
- return;
-
- entry = obj->exec_entry;
-
- if (entry->flags & __EXEC_OBJECT_HAS_FENCE)
- i915_gem_object_unpin_fence(obj);
- if (entry->flags & __EXEC_OBJECT_HAS_PIN)
- i915_gem_object_unpin(obj);
-
- entry->flags &= ~(__EXEC_OBJECT_HAS_FENCE | __EXEC_OBJECT_HAS_PIN);
+err_unpin:
+ i915_gem_object_unpin(obj);
+ return ret;
}
static int
@@ -414,10 +558,11 @@ i915_gem_execbuffer_reserve(struct intel_ring_buffer *ring,
struct drm_file *file,
struct list_head *objects)
{
+ drm_i915_private_t *dev_priv = ring->dev->dev_private;
struct drm_i915_gem_object *obj;
- struct list_head ordered_objects;
+ int ret, retry;
bool has_fenced_gpu_access = INTEL_INFO(ring->dev)->gen < 4;
- int retry;
+ struct list_head ordered_objects;
INIT_LIST_HEAD(&ordered_objects);
while (!list_empty(objects)) {
@@ -442,7 +587,6 @@ i915_gem_execbuffer_reserve(struct intel_ring_buffer *ring,
obj->base.pending_read_domains = 0;
obj->base.pending_write_domain = 0;
- obj->pending_fenced_gpu_access = false;
}
list_splice(&ordered_objects, objects);
@@ -455,12 +599,12 @@ i915_gem_execbuffer_reserve(struct intel_ring_buffer *ring,
* 2. Bind new objects.
* 3. Decrement pin count.
*
- * This avoid unnecessary unbinding of later objects in order to make
+ * This avoid unnecessary unbinding of later objects in order to makr
* room for the earlier objects *unless* we need to defragment.
*/
retry = 0;
do {
- int ret = 0;
+ ret = 0;
/* Unbind any ill-fitting objects or pin. */
list_for_each_entry(obj, objects, exec_list) {
@@ -480,7 +624,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 = pin_and_fence_object(obj, ring);
if (ret)
goto err;
}
@@ -490,22 +634,77 @@ i915_gem_execbuffer_reserve(struct intel_ring_buffer *ring,
if (obj->gtt_space)
continue;
- ret = i915_gem_execbuffer_reserve_object(obj, ring);
- if (ret)
- goto err;
+ ret = pin_and_fence_object(obj, ring);
+ if (ret) {
+ int ret_ignore;
+
+ /* This can potentially raise a harmless
+ * -EINVAL if we failed to bind in the above
+ * call. It cannot raise -EINTR since we know
+ * that the bo is freshly bound and so will
+ * not need to be flushed or waited upon.
+ */
+ ret_ignore = i915_gem_object_unbind(obj);
+ (void)ret_ignore;
+ WARN_ON(obj->gtt_space);
+ break;
+ }
}
-err: /* Decrement pin count for bound objects */
- list_for_each_entry(obj, objects, exec_list)
- i915_gem_execbuffer_unreserve_object(obj);
+ /* Decrement pin count for bound objects */
+ list_for_each_entry(obj, objects, exec_list) {
+ struct drm_i915_gem_exec_object2 *entry;
+
+ if (!obj->gtt_space)
+ continue;
+
+ entry = obj->exec_entry;
+ if (entry->flags & __EXEC_OBJECT_HAS_FENCE) {
+ i915_gem_object_unpin_fence(obj);
+ entry->flags &= ~__EXEC_OBJECT_HAS_FENCE;
+ }
+
+ i915_gem_object_unpin(obj);
+
+ /* ... and ensure ppgtt mapping exist if needed. */
+ if (dev_priv->mm.aliasing_ppgtt && !obj->has_aliasing_ppgtt_mapping) {
+ i915_ppgtt_bind_object(dev_priv->mm.aliasing_ppgtt,
+ obj, obj->cache_level);
- if (ret != -ENOSPC || retry++)
+ obj->has_aliasing_ppgtt_mapping = 1;
+ }
+ }
+
+ if (ret != -ENOSPC || retry > 1)
return ret;
- ret = i915_gem_evict_everything(ring->dev);
+ /* First attempt, just clear anything that is purgeable.
+ * Second attempt, clear the entire GTT.
+ */
+ ret = i915_gem_evict_everything(ring->dev, retry == 0);
if (ret)
return ret;
+
+ retry++;
} while (1);
+
+err:
+ list_for_each_entry_continue_reverse(obj, objects, exec_list) {
+ struct drm_i915_gem_exec_object2 *entry;
+
+ if (!obj->gtt_space)
+ continue;
+
+ entry = obj->exec_entry;
+ if (entry->flags & __EXEC_OBJECT_HAS_FENCE) {
+ i915_gem_object_unpin_fence(obj);
+ entry->flags &= ~__EXEC_OBJECT_HAS_FENCE;
+ }
+
+ i915_gem_object_unpin(obj);
+ }
+
+ return ret;
}
static int
@@ -611,6 +810,18 @@ i915_gem_execbuffer_relocate_slow(struct drm_device *dev,
return ret;
}
+static void
+i915_gem_execbuffer_flush(struct drm_device *dev,
+ uint32_t invalidate_domains,
+ uint32_t flush_domains)
+{
+ if (flush_domains & I915_GEM_DOMAIN_CPU)
+ intel_gtt_chipset_flush();
+
+ if (flush_domains & I915_GEM_DOMAIN_GTT)
+ wmb();
+}
+
static int
i915_gem_execbuffer_wait_for_flips(struct intel_ring_buffer *ring, u32 flips)
{
@@ -643,45 +854,48 @@ i915_gem_execbuffer_wait_for_flips(struct intel_ring_buffer *ring, u32 flips)
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;
+ struct change_domains cd;
int ret;
- list_for_each_entry(obj, objects, exec_list) {
- ret = i915_gem_object_sync(obj, ring);
- if (ret)
- return ret;
+ memset(&cd, 0, sizeof(cd));
+ list_for_each_entry(obj, objects, exec_list)
+ i915_gem_object_set_to_gpu_domain(obj, ring, &cd);
- 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 (cd.invalidate_domains | cd.flush_domains) {
+ i915_gem_execbuffer_flush(ring->dev,
+ cd.invalidate_domains,
+ cd.flush_domains);
}
- if (flips) {
- ret = i915_gem_execbuffer_wait_for_flips(ring, flips);
+ if (cd.flips) {
+ ret = i915_gem_execbuffer_wait_for_flips(ring, cd.flips);
if (ret)
return ret;
}
- if (flush_domains & I915_GEM_DOMAIN_CPU)
- intel_gtt_chipset_flush();
-
- if (flush_domains & I915_GEM_DOMAIN_GTT)
- wmb();
+ list_for_each_entry(obj, objects, exec_list) {
+ ret = i915_gem_object_sync(obj, ring);
+ if (ret)
+ return ret;
+ }
/* Unconditionally invalidate gpu caches and ensure that we do flush
* any residual writes from the previous batch.
*/
- return intel_ring_invalidate_all_caches(ring);
+ ret = i915_gem_flush_ring(ring,
+ I915_GEM_GPU_DOMAINS,
+ ring->gpu_caches_dirty ? I915_GEM_GPU_DOMAINS : 0);
+ if (ret)
+ return ret;
+
+ ring->gpu_caches_dirty = false;
+ return 0;
}
static bool
@@ -729,8 +943,9 @@ i915_gem_execbuffer_move_to_active(struct list_head *objects,
struct drm_i915_gem_object *obj;
list_for_each_entry(obj, objects, exec_list) {
- u32 old_read = obj->base.read_domains;
- u32 old_write = obj->base.write_domain;
+ 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;
@@ -739,13 +954,17 @@ i915_gem_execbuffer_move_to_active(struct list_head *objects,
i915_gem_object_move_to_active(obj, ring, seqno);
if (obj->base.write_domain) {
obj->dirty = 1;
- obj->last_write_seqno = seqno;
+ obj->pending_gpu_write = true;
+ list_move_tail(&obj->gpu_write_list,
+ &ring->gpu_write_list);
if (obj->pin_count) /* check for potential scanout */
- intel_mark_fb_busy(obj);
+ intel_mark_busy(ring->dev, obj);
}
trace_i915_gem_object_change_domain(obj, old_read, old_write);
}
+
+ intel_mark_busy(ring->dev, NULL);
}
static void
@@ -753,11 +972,16 @@ i915_gem_execbuffer_retire_commands(struct drm_device *dev,
struct drm_file *file,
struct intel_ring_buffer *ring)
{
+ struct drm_i915_gem_request *request;
+
/* Unconditionally force add_request to emit a full flush. */
ring->gpu_caches_dirty = true;
/* Add a breadcrumb for the completion of the batch buffer */
- (void)i915_add_request(ring, file, NULL);
+ request = kzalloc(sizeof(*request), GFP_KERNEL);
+ if (request == NULL || i915_add_request(ring, file, request)) {
+ kfree(request);
+ }
}
static int
@@ -1103,7 +1327,8 @@ i915_gem_execbuffer(struct drm_device *dev, void *data,
return -ENOMEM;
}
ret = copy_from_user(exec_list,
- (void __user *)(uintptr_t)args->buffers_ptr,
+ (struct drm_i915_relocation_entry __user *)
+ (uintptr_t) args->buffers_ptr,
sizeof(*exec_list) * args->buffer_count);
if (ret != 0) {
DRM_DEBUG("copy %d exec entries failed %d\n",
@@ -1142,7 +1367,8 @@ i915_gem_execbuffer(struct drm_device *dev, void *data,
for (i = 0; i < args->buffer_count; i++)
exec_list[i].offset = exec2_list[i].offset;
/* ... and back out to userspace */
- ret = copy_to_user((void __user *)(uintptr_t)args->buffers_ptr,
+ ret = copy_to_user((struct drm_i915_relocation_entry __user *)
+ (uintptr_t) args->buffers_ptr,
exec_list,
sizeof(*exec_list) * args->buffer_count);
if (ret) {
@@ -1196,7 +1422,8 @@ i915_gem_execbuffer2(struct drm_device *dev, void *data,
ret = i915_gem_do_execbuffer(dev, data, file, args, exec2_list);
if (!ret) {
/* Copy the new buffer offsets back to the user's exec list. */
- ret = copy_to_user((void __user *)(uintptr_t)args->buffers_ptr,
+ ret = copy_to_user((struct drm_i915_relocation_entry __user *)
+ (uintptr_t) args->buffers_ptr,
exec2_list,
sizeof(*exec2_list) * args->buffer_count);
if (ret) {
diff --git a/trunk/drivers/gpu/drm/i915/i915_gem_gtt.c b/trunk/drivers/gpu/drm/i915/i915_gem_gtt.c
index 47e427e4bc67..60815b861ec2 100644
--- a/trunk/drivers/gpu/drm/i915/i915_gem_gtt.c
+++ b/trunk/drivers/gpu/drm/i915/i915_gem_gtt.c
@@ -167,7 +167,8 @@ void i915_gem_cleanup_aliasing_ppgtt(struct drm_device *dev)
}
static void i915_ppgtt_insert_sg_entries(struct i915_hw_ppgtt *ppgtt,
- const struct sg_table *pages,
+ struct scatterlist *sg_list,
+ unsigned sg_len,
unsigned first_entry,
uint32_t pte_flags)
{
@@ -179,12 +180,12 @@ static void i915_ppgtt_insert_sg_entries(struct i915_hw_ppgtt *ppgtt,
struct scatterlist *sg;
/* init sg walking */
- sg = pages->sgl;
+ sg = sg_list;
i = 0;
segment_len = sg_dma_len(sg) >> PAGE_SHIFT;
m = 0;
- while (i < pages->nents) {
+ while (i < sg_len) {
pt_vaddr = kmap_atomic(ppgtt->pt_pages[act_pd]);
for (j = first_pte; j < I915_PPGTT_PT_ENTRIES; j++) {
@@ -193,11 +194,13 @@ static void i915_ppgtt_insert_sg_entries(struct i915_hw_ppgtt *ppgtt,
pt_vaddr[j] = pte | pte_flags;
/* grab the next page */
- if (++m == segment_len) {
- if (++i == pages->nents)
+ m++;
+ if (m == segment_len) {
+ sg = sg_next(sg);
+ i++;
+ if (i == sg_len)
break;
- sg = sg_next(sg);
segment_len = sg_dma_len(sg) >> PAGE_SHIFT;
m = 0;
}
@@ -210,10 +213,44 @@ static void i915_ppgtt_insert_sg_entries(struct i915_hw_ppgtt *ppgtt,
}
}
+static void i915_ppgtt_insert_pages(struct i915_hw_ppgtt *ppgtt,
+ unsigned first_entry, unsigned num_entries,
+ struct page **pages, uint32_t pte_flags)
+{
+ uint32_t *pt_vaddr, pte;
+ unsigned act_pd = first_entry / I915_PPGTT_PT_ENTRIES;
+ unsigned first_pte = first_entry % I915_PPGTT_PT_ENTRIES;
+ unsigned last_pte, i;
+ dma_addr_t page_addr;
+
+ while (num_entries) {
+ last_pte = first_pte + num_entries;
+ last_pte = min_t(unsigned, last_pte, I915_PPGTT_PT_ENTRIES);
+
+ pt_vaddr = kmap_atomic(ppgtt->pt_pages[act_pd]);
+
+ for (i = first_pte; i < last_pte; i++) {
+ page_addr = page_to_phys(*pages);
+ pte = GEN6_PTE_ADDR_ENCODE(page_addr);
+ pt_vaddr[i] = pte | pte_flags;
+
+ pages++;
+ }
+
+ kunmap_atomic(pt_vaddr);
+
+ num_entries -= last_pte - first_pte;
+ first_pte = 0;
+ act_pd++;
+ }
+}
+
void i915_ppgtt_bind_object(struct i915_hw_ppgtt *ppgtt,
struct drm_i915_gem_object *obj,
enum i915_cache_level cache_level)
{
+ struct drm_device *dev = obj->base.dev;
+ struct drm_i915_private *dev_priv = dev->dev_private;
uint32_t pte_flags = GEN6_PTE_VALID;
switch (cache_level) {
@@ -224,7 +261,7 @@ void i915_ppgtt_bind_object(struct i915_hw_ppgtt *ppgtt,
pte_flags |= GEN6_PTE_CACHE_LLC;
break;
case I915_CACHE_NONE:
- if (IS_HASWELL(obj->base.dev))
+ if (IS_HASWELL(dev))
pte_flags |= HSW_PTE_UNCACHED;
else
pte_flags |= GEN6_PTE_UNCACHED;
@@ -233,10 +270,26 @@ void i915_ppgtt_bind_object(struct i915_hw_ppgtt *ppgtt,
BUG();
}
- i915_ppgtt_insert_sg_entries(ppgtt,
- obj->pages,
- obj->gtt_space->start >> PAGE_SHIFT,
- pte_flags);
+ if (obj->sg_table) {
+ i915_ppgtt_insert_sg_entries(ppgtt,
+ obj->sg_table->sgl,
+ obj->sg_table->nents,
+ obj->gtt_space->start >> PAGE_SHIFT,
+ pte_flags);
+ } else if (dev_priv->mm.gtt->needs_dmar) {
+ BUG_ON(!obj->sg_list);
+
+ i915_ppgtt_insert_sg_entries(ppgtt,
+ obj->sg_list,
+ obj->num_sg,
+ obj->gtt_space->start >> PAGE_SHIFT,
+ pte_flags);
+ } else
+ i915_ppgtt_insert_pages(ppgtt,
+ obj->gtt_space->start >> PAGE_SHIFT,
+ obj->base.size >> PAGE_SHIFT,
+ obj->pages,
+ pte_flags);
}
void i915_ppgtt_unbind_object(struct i915_hw_ppgtt *ppgtt,
@@ -298,7 +351,7 @@ void i915_gem_restore_gtt_mappings(struct drm_device *dev)
intel_gtt_clear_range(dev_priv->mm.gtt_start / PAGE_SIZE,
(dev_priv->mm.gtt_end - dev_priv->mm.gtt_start) / PAGE_SIZE);
- list_for_each_entry(obj, &dev_priv->mm.bound_list, gtt_list) {
+ list_for_each_entry(obj, &dev_priv->mm.gtt_list, gtt_list) {
i915_gem_clflush_object(obj);
i915_gem_gtt_bind_object(obj, obj->cache_level);
}
@@ -308,26 +361,44 @@ void i915_gem_restore_gtt_mappings(struct drm_device *dev)
int i915_gem_gtt_prepare_object(struct drm_i915_gem_object *obj)
{
- if (obj->has_dma_mapping)
- return 0;
-
- if (!dma_map_sg(&obj->base.dev->pdev->dev,
- obj->pages->sgl, obj->pages->nents,
- PCI_DMA_BIDIRECTIONAL))
- return -ENOSPC;
+ struct drm_device *dev = obj->base.dev;
+ struct drm_i915_private *dev_priv = dev->dev_private;
- return 0;
+ /* don't map imported dma buf objects */
+ if (dev_priv->mm.gtt->needs_dmar && !obj->sg_table)
+ return intel_gtt_map_memory(obj->pages,
+ obj->base.size >> PAGE_SHIFT,
+ &obj->sg_list,
+ &obj->num_sg);
+ else
+ return 0;
}
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;
+ struct drm_i915_private *dev_priv = dev->dev_private;
unsigned int agp_type = cache_level_to_agp_type(dev, cache_level);
- intel_gtt_insert_sg_entries(obj->pages,
- obj->gtt_space->start >> PAGE_SHIFT,
- agp_type);
+ if (obj->sg_table) {
+ intel_gtt_insert_sg_entries(obj->sg_table->sgl,
+ obj->sg_table->nents,
+ obj->gtt_space->start >> PAGE_SHIFT,
+ agp_type);
+ } else if (dev_priv->mm.gtt->needs_dmar) {
+ BUG_ON(!obj->sg_list);
+
+ intel_gtt_insert_sg_entries(obj->sg_list,
+ obj->num_sg,
+ obj->gtt_space->start >> PAGE_SHIFT,
+ agp_type);
+ } else
+ intel_gtt_insert_pages(obj->gtt_space->start >> PAGE_SHIFT,
+ obj->base.size >> PAGE_SHIFT,
+ obj->pages,
+ agp_type);
+
obj->has_global_gtt_mapping = 1;
}
@@ -347,31 +418,14 @@ 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->sg_list) {
+ intel_gtt_unmap_memory(obj->sg_list, obj->num_sg);
+ obj->sg_list = NULL;
+ }
undo_idling(dev_priv, interruptible);
}
-static void i915_gtt_color_adjust(struct drm_mm_node *node,
- unsigned long color,
- unsigned long *start,
- unsigned long *end)
-{
- if (node->color != color)
- *start += 4096;
-
- if (!list_empty(&node->node_list)) {
- node = list_entry(node->node_list.next,
- struct drm_mm_node,
- node_list);
- if (node->allocated && node->color != color)
- *end -= 4096;
- }
-}
-
void i915_gem_init_global_gtt(struct drm_device *dev,
unsigned long start,
unsigned long mappable_end,
@@ -381,8 +435,6 @@ void i915_gem_init_global_gtt(struct drm_device *dev,
/* Substract 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;
diff --git a/trunk/drivers/gpu/drm/i915/i915_gem_tiling.c b/trunk/drivers/gpu/drm/i915/i915_gem_tiling.c
index 8093ecd2ea31..b964df51cec7 100644
--- a/trunk/drivers/gpu/drm/i915/i915_gem_tiling.c
+++ b/trunk/drivers/gpu/drm/i915/i915_gem_tiling.c
@@ -470,20 +470,18 @@ i915_gem_swizzle_page(struct page *page)
void
i915_gem_object_do_bit_17_swizzle(struct drm_i915_gem_object *obj)
{
- struct scatterlist *sg;
int page_count = obj->base.size >> PAGE_SHIFT;
int i;
if (obj->bit_17 == NULL)
return;
- for_each_sg(obj->pages->sgl, sg, page_count, i) {
- struct page *page = sg_page(sg);
- char new_bit_17 = page_to_phys(page) >> 17;
+ for (i = 0; i < page_count; i++) {
+ char new_bit_17 = page_to_phys(obj->pages[i]) >> 17;
if ((new_bit_17 & 0x1) !=
(test_bit(i, obj->bit_17) != 0)) {
- i915_gem_swizzle_page(page);
- set_page_dirty(page);
+ i915_gem_swizzle_page(obj->pages[i]);
+ set_page_dirty(obj->pages[i]);
}
}
}
@@ -491,7 +489,6 @@ 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)
{
- struct scatterlist *sg;
int page_count = obj->base.size >> PAGE_SHIFT;
int i;
@@ -505,9 +502,8 @@ i915_gem_object_save_bit_17_swizzle(struct drm_i915_gem_object *obj)
}
}
- for_each_sg(obj->pages->sgl, sg, page_count, i) {
- struct page *page = sg_page(sg);
- if (page_to_phys(page) & (1 << 17))
+ for (i = 0; i < page_count; i++) {
+ if (page_to_phys(obj->pages[i]) & (1 << 17))
__set_bit(i, obj->bit_17);
else
__clear_bit(i, obj->bit_17);
diff --git a/trunk/drivers/gpu/drm/i915/i915_irq.c b/trunk/drivers/gpu/drm/i915/i915_irq.c
index d7f0066538a9..5249640cce13 100644
--- a/trunk/drivers/gpu/drm/i915/i915_irq.c
+++ b/trunk/drivers/gpu/drm/i915/i915_irq.c
@@ -296,21 +296,11 @@ static void i915_hotplug_work_func(struct work_struct *work)
drm_helper_hpd_irq_event(dev);
}
-/* defined intel_pm.c */
-extern spinlock_t mchdev_lock;
-
-static void ironlake_handle_rps_change(struct drm_device *dev)
+static void i915_handle_rps_change(struct drm_device *dev)
{
drm_i915_private_t *dev_priv = dev->dev_private;
u32 busy_up, busy_down, max_avg, min_avg;
- u8 new_delay;
- unsigned long flags;
-
- spin_lock_irqsave(&mchdev_lock, flags);
-
- I915_WRITE16(MEMINTRSTS, I915_READ(MEMINTRSTS));
-
- new_delay = dev_priv->ips.cur_delay;
+ u8 new_delay = dev_priv->cur_delay;
I915_WRITE16(MEMINTRSTS, MEMINT_EVAL_CHG);
busy_up = I915_READ(RCPREVBSYTUPAVG);
@@ -320,21 +310,19 @@ static void ironlake_handle_rps_change(struct drm_device *dev)
/* Handle RCS change request from hw */
if (busy_up > max_avg) {
- if (dev_priv->ips.cur_delay != dev_priv->ips.max_delay)
- new_delay = dev_priv->ips.cur_delay - 1;
- if (new_delay < dev_priv->ips.max_delay)
- new_delay = dev_priv->ips.max_delay;
+ if (dev_priv->cur_delay != dev_priv->max_delay)
+ new_delay = dev_priv->cur_delay - 1;
+ if (new_delay < dev_priv->max_delay)
+ new_delay = dev_priv->max_delay;
} else if (busy_down < min_avg) {
- if (dev_priv->ips.cur_delay != dev_priv->ips.min_delay)
- new_delay = dev_priv->ips.cur_delay + 1;
- if (new_delay > dev_priv->ips.min_delay)
- new_delay = dev_priv->ips.min_delay;
+ if (dev_priv->cur_delay != dev_priv->min_delay)
+ new_delay = dev_priv->cur_delay + 1;
+ if (new_delay > dev_priv->min_delay)
+ new_delay = dev_priv->min_delay;
}
if (ironlake_set_drps(dev, new_delay))
- dev_priv->ips.cur_delay = new_delay;
-
- spin_unlock_irqrestore(&mchdev_lock, flags);
+ dev_priv->cur_delay = new_delay;
return;
}
@@ -347,7 +335,7 @@ static void notify_ring(struct drm_device *dev,
if (ring->obj == NULL)
return;
- trace_i915_gem_request_complete(ring, ring->get_seqno(ring, false));
+ trace_i915_gem_request_complete(ring, ring->get_seqno(ring));
wake_up_all(&ring->irq_queue);
if (i915_enable_hangcheck) {
@@ -361,16 +349,16 @@ static void notify_ring(struct drm_device *dev,
static void gen6_pm_rps_work(struct work_struct *work)
{
drm_i915_private_t *dev_priv = container_of(work, drm_i915_private_t,
- rps.work);
+ rps_work);
u32 pm_iir, pm_imr;
u8 new_delay;
- spin_lock_irq(&dev_priv->rps.lock);
- pm_iir = dev_priv->rps.pm_iir;
- dev_priv->rps.pm_iir = 0;
+ spin_lock_irq(&dev_priv->rps_lock);
+ pm_iir = dev_priv->pm_iir;
+ dev_priv->pm_iir = 0;
pm_imr = I915_READ(GEN6_PMIMR);
I915_WRITE(GEN6_PMIMR, 0);
- spin_unlock_irq(&dev_priv->rps.lock);
+ spin_unlock_irq(&dev_priv->rps_lock);
if ((pm_iir & GEN6_PM_DEFERRED_EVENTS) == 0)
return;
@@ -378,17 +366,11 @@ static void gen6_pm_rps_work(struct work_struct *work)
mutex_lock(&dev_priv->dev->struct_mutex);
if (pm_iir & GEN6_PM_RP_UP_THRESHOLD)
- new_delay = dev_priv->rps.cur_delay + 1;
+ new_delay = dev_priv->cur_delay + 1;
else
- new_delay = dev_priv->rps.cur_delay - 1;
+ new_delay = dev_priv->cur_delay - 1;
- /* sysfs frequency interfaces may have snuck in while servicing the
- * interrupt
- */
- if (!(new_delay > dev_priv->rps.max_delay ||
- new_delay < dev_priv->rps.min_delay)) {
- gen6_set_rps(dev_priv->dev, new_delay);
- }
+ gen6_set_rps(dev_priv->dev, new_delay);
mutex_unlock(&dev_priv->dev->struct_mutex);
}
@@ -462,7 +444,7 @@ static void ivybridge_handle_parity_error(struct drm_device *dev)
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
unsigned long flags;
- if (!HAS_L3_GPU_CACHE(dev))
+ if (!IS_IVYBRIDGE(dev))
return;
spin_lock_irqsave(&dev_priv->irq_lock, flags);
@@ -506,19 +488,19 @@ static void gen6_queue_rps_work(struct drm_i915_private *dev_priv,
* IIR bits should never already be set because IMR should
* prevent an interrupt from being shown in IIR. The warning
* displays a case where we've unsafely cleared
- * dev_priv->rps.pm_iir. Although missing an interrupt of the same
+ * dev_priv->pm_iir. Although missing an interrupt of the same
* type is not a problem, it displays a problem in the logic.
*
- * The mask bit in IMR is cleared by dev_priv->rps.work.
+ * The mask bit in IMR is cleared by rps_work.
*/
- spin_lock_irqsave(&dev_priv->rps.lock, flags);
- dev_priv->rps.pm_iir |= pm_iir;
- I915_WRITE(GEN6_PMIMR, dev_priv->rps.pm_iir);
+ spin_lock_irqsave(&dev_priv->rps_lock, flags);
+ dev_priv->pm_iir |= pm_iir;
+ I915_WRITE(GEN6_PMIMR, dev_priv->pm_iir);
POSTING_READ(GEN6_PMIMR);
- spin_unlock_irqrestore(&dev_priv->rps.lock, flags);
+ spin_unlock_irqrestore(&dev_priv->rps_lock, flags);
- queue_work(dev_priv->wq, &dev_priv->rps.work);
+ queue_work(dev_priv->wq, &dev_priv->rps_work);
}
static irqreturn_t valleyview_irq_handler(DRM_IRQ_ARGS)
@@ -811,8 +793,10 @@ static irqreturn_t ironlake_irq_handler(DRM_IRQ_ARGS)
ibx_irq_handler(dev, pch_iir);
}
- if (IS_GEN5(dev) && de_iir & DE_PCU_EVENT)
- ironlake_handle_rps_change(dev);
+ if (de_iir & DE_PCU_EVENT) {
+ I915_WRITE16(MEMINTRSTS, I915_READ(MEMINTRSTS));
+ i915_handle_rps_change(dev);
+ }
if (IS_GEN6(dev) && pm_iir & GEN6_PM_DEFERRED_EVENTS)
gen6_queue_rps_work(dev_priv, pm_iir);
@@ -859,55 +843,26 @@ static void i915_error_work_func(struct work_struct *work)
}
}
-/* NB: please notice the memset */
-static void i915_get_extra_instdone(struct drm_device *dev,
- uint32_t *instdone)
-{
- struct drm_i915_private *dev_priv = dev->dev_private;
- memset(instdone, 0, sizeof(*instdone) * I915_NUM_INSTDONE_REG);
-
- switch(INTEL_INFO(dev)->gen) {
- case 2:
- case 3:
- instdone[0] = I915_READ(INSTDONE);
- break;
- case 4:
- case 5:
- case 6:
- instdone[0] = I915_READ(INSTDONE_I965);
- instdone[1] = I915_READ(INSTDONE1);
- break;
- default:
- WARN_ONCE(1, "Unsupported platform\n");
- case 7:
- instdone[0] = I915_READ(GEN7_INSTDONE_1);
- instdone[1] = I915_READ(GEN7_SC_INSTDONE);
- instdone[2] = I915_READ(GEN7_SAMPLER_INSTDONE);
- instdone[3] = I915_READ(GEN7_ROW_INSTDONE);
- break;
- }
-}
-
#ifdef CONFIG_DEBUG_FS
static struct drm_i915_error_object *
i915_error_object_create(struct drm_i915_private *dev_priv,
struct drm_i915_gem_object *src)
{
struct drm_i915_error_object *dst;
- int i, count;
+ int page, page_count;
u32 reloc_offset;
if (src == NULL || src->pages == NULL)
return NULL;
- count = src->base.size / PAGE_SIZE;
+ page_count = src->base.size / PAGE_SIZE;
- dst = kmalloc(sizeof(*dst) + count * sizeof(u32 *), GFP_ATOMIC);
+ dst = kmalloc(sizeof(*dst) + page_count * sizeof(u32 *), GFP_ATOMIC);
if (dst == NULL)
return NULL;
reloc_offset = src->gtt_offset;
- for (i = 0; i < count; i++) {
+ for (page = 0; page < page_count; page++) {
unsigned long flags;
void *d;
@@ -930,33 +885,30 @@ i915_error_object_create(struct drm_i915_private *dev_priv,
memcpy_fromio(d, s, PAGE_SIZE);
io_mapping_unmap_atomic(s);
} else {
- struct page *page;
void *s;
- page = i915_gem_object_get_page(src, i);
-
- drm_clflush_pages(&page, 1);
+ drm_clflush_pages(&src->pages[page], 1);
- s = kmap_atomic(page);
+ s = kmap_atomic(src->pages[page]);
memcpy(d, s, PAGE_SIZE);
kunmap_atomic(s);
- drm_clflush_pages(&page, 1);
+ drm_clflush_pages(&src->pages[page], 1);
}
local_irq_restore(flags);
- dst->pages[i] = d;
+ dst->pages[page] = d;
reloc_offset += PAGE_SIZE;
}
- dst->page_count = count;
+ dst->page_count = page_count;
dst->gtt_offset = src->gtt_offset;
return dst;
unwind:
- while (i--)
- kfree(dst->pages[i]);
+ while (page--)
+ kfree(dst->pages[page]);
kfree(dst);
return NULL;
}
@@ -997,8 +949,7 @@ static void capture_bo(struct drm_i915_error_buffer *err,
{
err->size = obj->base.size;
err->name = obj->base.name;
- err->rseqno = obj->last_read_seqno;
- err->wseqno = obj->last_write_seqno;
+ err->seqno = obj->last_rendering_seqno;
err->gtt_offset = obj->gtt_offset;
err->read_domains = obj->base.read_domains;
err->write_domain = obj->base.write_domain;
@@ -1088,12 +1039,12 @@ i915_error_first_batchbuffer(struct drm_i915_private *dev_priv,
if (!ring->get_seqno)
return NULL;
- seqno = ring->get_seqno(ring, false);
+ seqno = ring->get_seqno(ring);
list_for_each_entry(obj, &dev_priv->mm.active_list, mm_list) {
if (obj->ring != ring)
continue;
- if (i915_seqno_passed(seqno, obj->last_read_seqno))
+ if (i915_seqno_passed(seqno, obj->last_rendering_seqno))
continue;
if ((obj->base.read_domains & I915_GEM_DOMAIN_COMMAND) == 0)
@@ -1129,8 +1080,10 @@ static void i915_record_ring_state(struct drm_device *dev,
error->ipehr[ring->id] = I915_READ(RING_IPEHR(ring->mmio_base));
error->instdone[ring->id] = I915_READ(RING_INSTDONE(ring->mmio_base));
error->instps[ring->id] = I915_READ(RING_INSTPS(ring->mmio_base));
- if (ring->id == RCS)
+ if (ring->id == RCS) {
+ error->instdone1 = I915_READ(INSTDONE1);
error->bbaddr = I915_READ64(BB_ADDR);
+ }
} else {
error->faddr[ring->id] = I915_READ(DMA_FADD_I8XX);
error->ipeir[ring->id] = I915_READ(IPEIR);
@@ -1140,7 +1093,7 @@ static void i915_record_ring_state(struct drm_device *dev,
error->waiting[ring->id] = waitqueue_active(&ring->irq_queue);
error->instpm[ring->id] = I915_READ(RING_INSTPM(ring->mmio_base));
- error->seqno[ring->id] = ring->get_seqno(ring, false);
+ error->seqno[ring->id] = ring->get_seqno(ring);
error->acthd[ring->id] = intel_ring_get_active_head(ring);
error->head[ring->id] = I915_READ_HEAD(ring);
error->tail[ring->id] = I915_READ_TAIL(ring);
@@ -1246,11 +1199,6 @@ static void i915_capture_error_state(struct drm_device *dev)
error->done_reg = I915_READ(DONE_REG);
}
- if (INTEL_INFO(dev)->gen == 7)
- error->err_int = I915_READ(GEN7_ERR_INT);
-
- i915_get_extra_instdone(dev, error->extra_instdone);
-
i915_gem_record_fences(dev, error);
i915_gem_record_rings(dev, error);
@@ -1262,7 +1210,7 @@ static void i915_capture_error_state(struct drm_device *dev)
list_for_each_entry(obj, &dev_priv->mm.active_list, mm_list)
i++;
error->active_bo_count = i;
- list_for_each_entry(obj, &dev_priv->mm.bound_list, gtt_list)
+ list_for_each_entry(obj, &dev_priv->mm.gtt_list, gtt_list)
if (obj->pin_count)
i++;
error->pinned_bo_count = i - error->active_bo_count;
@@ -1287,7 +1235,7 @@ static void i915_capture_error_state(struct drm_device *dev)
error->pinned_bo_count =
capture_pinned_bo(error->pinned_bo,
error->pinned_bo_count,
- &dev_priv->mm.bound_list);
+ &dev_priv->mm.gtt_list);
do_gettimeofday(&error->time);
@@ -1326,26 +1274,24 @@ void i915_destroy_error_state(struct drm_device *dev)
static void i915_report_and_clear_eir(struct drm_device *dev)
{
struct drm_i915_private *dev_priv = dev->dev_private;
- uint32_t instdone[I915_NUM_INSTDONE_REG];
u32 eir = I915_READ(EIR);
- int pipe, i;
+ int pipe;
if (!eir)
return;
pr_err("render error detected, EIR: 0x%08x\n", eir);
- i915_get_extra_instdone(dev, instdone);
-
if (IS_G4X(dev)) {
if (eir & (GM45_ERROR_MEM_PRIV | GM45_ERROR_CP_PRIV)) {
u32 ipeir = I915_READ(IPEIR_I965);
pr_err(" IPEIR: 0x%08x\n", I915_READ(IPEIR_I965));
pr_err(" IPEHR: 0x%08x\n", I915_READ(IPEHR_I965));
- for (i = 0; i < ARRAY_SIZE(instdone); i++)
- pr_err(" INSTDONE_%d: 0x%08x\n", i, instdone[i]);
+ pr_err(" INSTDONE: 0x%08x\n",
+ I915_READ(INSTDONE_I965));
pr_err(" INSTPS: 0x%08x\n", I915_READ(INSTPS));
+ pr_err(" INSTDONE1: 0x%08x\n", I915_READ(INSTDONE1));
pr_err(" ACTHD: 0x%08x\n", I915_READ(ACTHD_I965));
I915_WRITE(IPEIR_I965, ipeir);
POSTING_READ(IPEIR_I965);
@@ -1379,13 +1325,12 @@ static void i915_report_and_clear_eir(struct drm_device *dev)
if (eir & I915_ERROR_INSTRUCTION) {
pr_err("instruction error\n");
pr_err(" INSTPM: 0x%08x\n", I915_READ(INSTPM));
- for (i = 0; i < ARRAY_SIZE(instdone); i++)
- pr_err(" INSTDONE_%d: 0x%08x\n", i, instdone[i]);
if (INTEL_INFO(dev)->gen < 4) {
u32 ipeir = I915_READ(IPEIR);
pr_err(" IPEIR: 0x%08x\n", I915_READ(IPEIR));
pr_err(" IPEHR: 0x%08x\n", I915_READ(IPEHR));
+ pr_err(" INSTDONE: 0x%08x\n", I915_READ(INSTDONE));
pr_err(" ACTHD: 0x%08x\n", I915_READ(ACTHD));
I915_WRITE(IPEIR, ipeir);
POSTING_READ(IPEIR);
@@ -1394,7 +1339,10 @@ static void i915_report_and_clear_eir(struct drm_device *dev)
pr_err(" IPEIR: 0x%08x\n", I915_READ(IPEIR_I965));
pr_err(" IPEHR: 0x%08x\n", I915_READ(IPEHR_I965));
+ pr_err(" INSTDONE: 0x%08x\n",
+ I915_READ(INSTDONE_I965));
pr_err(" INSTPS: 0x%08x\n", I915_READ(INSTPS));
+ pr_err(" INSTDONE1: 0x%08x\n", I915_READ(INSTDONE1));
pr_err(" ACTHD: 0x%08x\n", I915_READ(ACTHD_I965));
I915_WRITE(IPEIR_I965, ipeir);
POSTING_READ(IPEIR_I965);
@@ -1642,8 +1590,7 @@ ring_last_seqno(struct intel_ring_buffer *ring)
static bool i915_hangcheck_ring_idle(struct intel_ring_buffer *ring, bool *err)
{
if (list_empty(&ring->request_list) ||
- i915_seqno_passed(ring->get_seqno(ring, false),
- ring_last_seqno(ring))) {
+ i915_seqno_passed(ring->get_seqno(ring), ring_last_seqno(ring))) {
/* Issue a wake-up to catch stuck h/w. */
if (waitqueue_active(&ring->irq_queue)) {
DRM_ERROR("Hangcheck timer elapsed... %s idle\n",
@@ -1709,7 +1656,7 @@ void i915_hangcheck_elapsed(unsigned long data)
{
struct drm_device *dev = (struct drm_device *)data;
drm_i915_private_t *dev_priv = dev->dev_private;
- uint32_t acthd[I915_NUM_RINGS], instdone[I915_NUM_INSTDONE_REG];
+ uint32_t acthd[I915_NUM_RINGS], instdone, instdone1;
struct intel_ring_buffer *ring;
bool err = false, idle;
int i;
@@ -1737,16 +1684,25 @@ void i915_hangcheck_elapsed(unsigned long data)
return;
}
- i915_get_extra_instdone(dev, instdone);
+ if (INTEL_INFO(dev)->gen < 4) {
+ instdone = I915_READ(INSTDONE);
+ instdone1 = 0;
+ } else {
+ instdone = I915_READ(INSTDONE_I965);
+ instdone1 = I915_READ(INSTDONE1);
+ }
+
if (memcmp(dev_priv->last_acthd, acthd, sizeof(acthd)) == 0 &&
- memcmp(dev_priv->prev_instdone, instdone, sizeof(instdone)) == 0) {
+ dev_priv->last_instdone == instdone &&
+ dev_priv->last_instdone1 == instdone1) {
if (i915_hangcheck_hung(dev))
return;
} else {
dev_priv->hangcheck_count = 0;
memcpy(dev_priv->last_acthd, acthd, sizeof(acthd));
- memcpy(dev_priv->prev_instdone, instdone, sizeof(instdone));
+ dev_priv->last_instdone = instdone;
+ dev_priv->last_instdone1 = instdone1;
}
repeat:
@@ -2691,7 +2647,7 @@ void intel_irq_init(struct drm_device *dev)
INIT_WORK(&dev_priv->hotplug_work, i915_hotplug_work_func);
INIT_WORK(&dev_priv->error_work, i915_error_work_func);
- INIT_WORK(&dev_priv->rps.work, gen6_pm_rps_work);
+ INIT_WORK(&dev_priv->rps_work, gen6_pm_rps_work);
INIT_WORK(&dev_priv->parity_error_work, ivybridge_parity_work);
dev->driver->get_vblank_counter = i915_get_vblank_counter;
diff --git a/trunk/drivers/gpu/drm/i915/i915_reg.h b/trunk/drivers/gpu/drm/i915/i915_reg.h
index 7637824c6a7d..28725ce5b82c 100644
--- a/trunk/drivers/gpu/drm/i915/i915_reg.h
+++ b/trunk/drivers/gpu/drm/i915/i915_reg.h
@@ -450,7 +450,6 @@
#define RING_ACTHD(base) ((base)+0x74)
#define RING_NOPID(base) ((base)+0x94)
#define RING_IMR(base) ((base)+0xa8)
-#define RING_TIMESTAMP(base) ((base)+0x358)
#define TAIL_ADDR 0x001FFFF8
#define HEAD_WRAP_COUNT 0xFFE00000
#define HEAD_WRAP_ONE 0x00200000
@@ -479,11 +478,6 @@
#define IPEIR_I965 0x02064
#define IPEHR_I965 0x02068
#define INSTDONE_I965 0x0206c
-#define GEN7_INSTDONE_1 0x0206c
-#define GEN7_SC_INSTDONE 0x07100
-#define GEN7_SAMPLER_INSTDONE 0x0e160
-#define GEN7_ROW_INSTDONE 0x0e164
-#define I915_NUM_INSTDONE_REG 4
#define RING_IPEIR(base) ((base)+0x64)
#define RING_IPEHR(base) ((base)+0x68)
#define RING_INSTDONE(base) ((base)+0x6c)
@@ -506,8 +500,6 @@
#define DMA_FADD_I8XX 0x020d0
#define ERROR_GEN6 0x040a0
-#define GEN7_ERR_INT 0x44040
-#define ERR_INT_MMIO_UNCLAIMED (1<<13)
/* GM45+ chicken bits -- debug workaround bits that may be required
* for various sorts of correct behavior. The top 16 bits of each are
@@ -537,8 +529,6 @@
#define GFX_PSMI_GRANULARITY (1<<10)
#define GFX_PPGTT_ENABLE (1<<9)
-#define VLV_DISPLAY_BASE 0x180000
-
#define SCPD0 0x0209c /* 915+ only */
#define IER 0x020a0
#define IIR 0x020a4
@@ -1506,14 +1496,6 @@
GEN7_CXT_EXTENDED_SIZE(ctx_reg) + \
GEN7_CXT_GT1_SIZE(ctx_reg) + \
GEN7_CXT_VFSTATE_SIZE(ctx_reg))
-#define HSW_CXT_POWER_SIZE(ctx_reg) ((ctx_reg >> 26) & 0x3f)
-#define HSW_CXT_RING_SIZE(ctx_reg) ((ctx_reg >> 23) & 0x7)
-#define HSW_CXT_RENDER_SIZE(ctx_reg) ((ctx_reg >> 15) & 0xff)
-#define HSW_CXT_TOTAL_SIZE(ctx_reg) (HSW_CXT_POWER_SIZE(ctx_reg) + \
- HSW_CXT_RING_SIZE(ctx_reg) + \
- HSW_CXT_RENDER_SIZE(ctx_reg) + \
- GEN7_CXT_VFSTATE_SIZE(ctx_reg))
-
/*
* Overlay regs
@@ -1567,35 +1549,12 @@
/* VGA port control */
#define ADPA 0x61100
-#define PCH_ADPA 0xe1100
-#define VLV_ADPA (VLV_DISPLAY_BASE + ADPA)
-
#define ADPA_DAC_ENABLE (1<<31)
#define ADPA_DAC_DISABLE 0
#define ADPA_PIPE_SELECT_MASK (1<<30)
#define ADPA_PIPE_A_SELECT 0
#define ADPA_PIPE_B_SELECT (1<<30)
#define ADPA_PIPE_SELECT(pipe) ((pipe) << 30)
-/* CPT uses bits 29:30 for pch transcoder select */
-#define ADPA_CRT_HOTPLUG_MASK 0x03ff0000 /* bit 25-16 */
-#define ADPA_CRT_HOTPLUG_MONITOR_NONE (0<<24)
-#define ADPA_CRT_HOTPLUG_MONITOR_MASK (3<<24)
-#define ADPA_CRT_HOTPLUG_MONITOR_COLOR (3<<24)
-#define ADPA_CRT_HOTPLUG_MONITOR_MONO (2<<24)
-#define ADPA_CRT_HOTPLUG_ENABLE (1<<23)
-#define ADPA_CRT_HOTPLUG_PERIOD_64 (0<<22)
-#define ADPA_CRT_HOTPLUG_PERIOD_128 (1<<22)
-#define ADPA_CRT_HOTPLUG_WARMUP_5MS (0<<21)
-#define ADPA_CRT_HOTPLUG_WARMUP_10MS (1<<21)
-#define ADPA_CRT_HOTPLUG_SAMPLE_2S (0<<20)
-#define ADPA_CRT_HOTPLUG_SAMPLE_4S (1<<20)
-#define ADPA_CRT_HOTPLUG_VOLTAGE_40 (0<<18)
-#define ADPA_CRT_HOTPLUG_VOLTAGE_50 (1<<18)
-#define ADPA_CRT_HOTPLUG_VOLTAGE_60 (2<<18)
-#define ADPA_CRT_HOTPLUG_VOLTAGE_70 (3<<18)
-#define ADPA_CRT_HOTPLUG_VOLREF_325MV (0<<17)
-#define ADPA_CRT_HOTPLUG_VOLREF_475MV (1<<17)
-#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)
@@ -1794,10 +1753,6 @@
/* Video Data Island Packet control */
#define VIDEO_DIP_DATA 0x61178
-/* Read the description of VIDEO_DIP_DATA (before Haswel) or VIDEO_DIP_ECC
- * (Haswell and newer) to see which VIDEO_DIP_DATA byte corresponds to each byte
- * of the infoframe structure specified by CEA-861. */
-#define VIDEO_DIP_DATA_SIZE 32
#define VIDEO_DIP_CTL 0x61170
/* Pre HSW: */
#define VIDEO_DIP_ENABLE (1 << 31)
@@ -3934,6 +3889,31 @@
#define FDI_PLL_CTL_1 0xfe000
#define FDI_PLL_CTL_2 0xfe004
+/* CRT */
+#define PCH_ADPA 0xe1100
+#define ADPA_TRANS_SELECT_MASK (1<<30)
+#define ADPA_TRANS_A_SELECT 0
+#define ADPA_TRANS_B_SELECT (1<<30)
+#define ADPA_CRT_HOTPLUG_MASK 0x03ff0000 /* bit 25-16 */
+#define ADPA_CRT_HOTPLUG_MONITOR_NONE (0<<24)
+#define ADPA_CRT_HOTPLUG_MONITOR_MASK (3<<24)
+#define ADPA_CRT_HOTPLUG_MONITOR_COLOR (3<<24)
+#define ADPA_CRT_HOTPLUG_MONITOR_MONO (2<<24)
+#define ADPA_CRT_HOTPLUG_ENABLE (1<<23)
+#define ADPA_CRT_HOTPLUG_PERIOD_64 (0<<22)
+#define ADPA_CRT_HOTPLUG_PERIOD_128 (1<<22)
+#define ADPA_CRT_HOTPLUG_WARMUP_5MS (0<<21)
+#define ADPA_CRT_HOTPLUG_WARMUP_10MS (1<<21)
+#define ADPA_CRT_HOTPLUG_SAMPLE_2S (0<<20)
+#define ADPA_CRT_HOTPLUG_SAMPLE_4S (1<<20)
+#define ADPA_CRT_HOTPLUG_VOLTAGE_40 (0<<18)
+#define ADPA_CRT_HOTPLUG_VOLTAGE_50 (1<<18)
+#define ADPA_CRT_HOTPLUG_VOLTAGE_60 (2<<18)
+#define ADPA_CRT_HOTPLUG_VOLTAGE_70 (3<<18)
+#define ADPA_CRT_HOTPLUG_VOLREF_325MV (0<<17)
+#define ADPA_CRT_HOTPLUG_VOLREF_475MV (1<<17)
+#define ADPA_CRT_HOTPLUG_FORCE_TRIGGER (1<<16)
+
/* or SDVOB */
#define HDMIB 0xe1140
#define PORT_ENABLE (1 << 31)
@@ -4041,8 +4021,6 @@
#define PORT_TRANS_C_SEL_CPT (2<<29)
#define PORT_TRANS_SEL_MASK (3<<29)
#define PORT_TRANS_SEL_CPT(pipe) ((pipe) << 29)
-#define PORT_TO_PIPE(val) (((val) & (1<<30)) >> 30)
-#define PORT_TO_PIPE_CPT(val) (((val) & PORT_TRANS_SEL_MASK) >> 29)
#define TRANS_DP_CTL_A 0xe0300
#define TRANS_DP_CTL_B 0xe1300
@@ -4261,15 +4239,7 @@
#define G4X_HDMIW_HDMIEDID 0x6210C
#define IBX_HDMIW_HDMIEDID_A 0xE2050
-#define IBX_HDMIW_HDMIEDID_B 0xE2150
-#define IBX_HDMIW_HDMIEDID(pipe) _PIPE(pipe, \
- IBX_HDMIW_HDMIEDID_A, \
- IBX_HDMIW_HDMIEDID_B)
#define IBX_AUD_CNTL_ST_A 0xE20B4
-#define IBX_AUD_CNTL_ST_B 0xE21B4
-#define IBX_AUD_CNTL_ST(pipe) _PIPE(pipe, \
- IBX_AUD_CNTL_ST_A, \
- IBX_AUD_CNTL_ST_B)
#define IBX_ELD_BUFFER_SIZE (0x1f << 10)
#define IBX_ELD_ADDRESS (0x1f << 5)
#define IBX_ELD_ACK (1 << 4)
@@ -4278,15 +4248,7 @@
#define IBX_CP_READYB (1 << 1)
#define CPT_HDMIW_HDMIEDID_A 0xE5050
-#define CPT_HDMIW_HDMIEDID_B 0xE5150
-#define CPT_HDMIW_HDMIEDID(pipe) _PIPE(pipe, \
- CPT_HDMIW_HDMIEDID_A, \
- CPT_HDMIW_HDMIEDID_B)
#define CPT_AUD_CNTL_ST_A 0xE50B4
-#define CPT_AUD_CNTL_ST_B 0xE51B4
-#define CPT_AUD_CNTL_ST(pipe) _PIPE(pipe, \
- CPT_AUD_CNTL_ST_A, \
- CPT_AUD_CNTL_ST_B)
#define CPT_AUD_CNTRL_ST2 0xE50C0
/* These are the 4 32-bit write offset registers for each stream
@@ -4296,15 +4258,7 @@
#define GEN7_SO_WRITE_OFFSET(n) (0x5280 + (n) * 4)
#define IBX_AUD_CONFIG_A 0xe2000
-#define IBX_AUD_CONFIG_B 0xe2100
-#define IBX_AUD_CFG(pipe) _PIPE(pipe, \
- IBX_AUD_CONFIG_A, \
- IBX_AUD_CONFIG_B)
#define CPT_AUD_CONFIG_A 0xe5000
-#define CPT_AUD_CONFIG_B 0xe5100
-#define CPT_AUD_CFG(pipe) _PIPE(pipe, \
- CPT_AUD_CONFIG_A, \
- CPT_AUD_CONFIG_B)
#define AUD_CONFIG_N_VALUE_INDEX (1 << 29)
#define AUD_CONFIG_N_PROG_ENABLE (1 << 28)
#define AUD_CONFIG_UPPER_N_SHIFT 20
@@ -4315,233 +4269,195 @@
#define AUD_CONFIG_PIXEL_CLOCK_HDMI (0xf << 16)
#define AUD_CONFIG_DISABLE_NCTS (1 << 3)
-/* HSW Audio */
-#define HSW_AUD_CONFIG_A 0x65000 /* Audio Configuration Transcoder A */
-#define HSW_AUD_CONFIG_B 0x65100 /* Audio Configuration Transcoder B */
-#define HSW_AUD_CFG(pipe) _PIPE(pipe, \
- HSW_AUD_CONFIG_A, \
- HSW_AUD_CONFIG_B)
-
-#define HSW_AUD_MISC_CTRL_A 0x65010 /* Audio Misc Control Convert 1 */
-#define HSW_AUD_MISC_CTRL_B 0x65110 /* Audio Misc Control Convert 2 */
-#define HSW_AUD_MISC_CTRL(pipe) _PIPE(pipe, \
- HSW_AUD_MISC_CTRL_A, \
- HSW_AUD_MISC_CTRL_B)
-
-#define HSW_AUD_DIP_ELD_CTRL_ST_A 0x650b4 /* Audio DIP and ELD Control State Transcoder A */
-#define HSW_AUD_DIP_ELD_CTRL_ST_B 0x651b4 /* Audio DIP and ELD Control State Transcoder B */
-#define HSW_AUD_DIP_ELD_CTRL(pipe) _PIPE(pipe, \
- HSW_AUD_DIP_ELD_CTRL_ST_A, \
- HSW_AUD_DIP_ELD_CTRL_ST_B)
-
-/* Audio Digital Converter */
-#define HSW_AUD_DIG_CNVT_1 0x65080 /* Audio Converter 1 */
-#define HSW_AUD_DIG_CNVT_2 0x65180 /* Audio Converter 1 */
-#define AUD_DIG_CNVT(pipe) _PIPE(pipe, \
- HSW_AUD_DIG_CNVT_1, \
- HSW_AUD_DIG_CNVT_2)
-#define DIP_PORT_SEL_MASK 0x3
-
-#define HSW_AUD_EDID_DATA_A 0x65050
-#define HSW_AUD_EDID_DATA_B 0x65150
-#define HSW_AUD_EDID_DATA(pipe) _PIPE(pipe, \
- HSW_AUD_EDID_DATA_A, \
- HSW_AUD_EDID_DATA_B)
-
-#define HSW_AUD_PIPE_CONV_CFG 0x6507c /* Audio pipe and converter configs */
-#define HSW_AUD_PIN_ELD_CP_VLD 0x650c0 /* Audio ELD and CP Ready Status */
-#define AUDIO_INACTIVE_C (1<<11)
-#define AUDIO_INACTIVE_B (1<<7)
-#define AUDIO_INACTIVE_A (1<<3)
-#define AUDIO_OUTPUT_ENABLE_A (1<<2)
-#define AUDIO_OUTPUT_ENABLE_B (1<<6)
-#define AUDIO_OUTPUT_ENABLE_C (1<<10)
-#define AUDIO_ELD_VALID_A (1<<0)
-#define AUDIO_ELD_VALID_B (1<<4)
-#define AUDIO_ELD_VALID_C (1<<8)
-#define AUDIO_CP_READY_A (1<<1)
-#define AUDIO_CP_READY_B (1<<5)
-#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_ENABLE (1<<31)
-#define HSW_PWR_WELL_STATE (1<<30)
-#define HSW_PWR_WELL_CTL5 0x45410
+#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_ENABLE (1<<31)
+#define HSW_PWR_WELL_STATE (1<<30)
+#define HSW_PWR_WELL_CTL5 0x45410
#define HSW_PWR_WELL_ENABLE_SINGLE_STEP (1<<31)
#define HSW_PWR_WELL_PWR_GATE_OVERRIDE (1<<20)
-#define HSW_PWR_WELL_FORCE_ON (1<<19)
-#define HSW_PWR_WELL_CTL6 0x45414
+#define HSW_PWR_WELL_FORCE_ON (1<<19)
+#define HSW_PWR_WELL_CTL6 0x45414
/* Per-pipe DDI Function Control */
-#define PIPE_DDI_FUNC_CTL_A 0x60400
-#define PIPE_DDI_FUNC_CTL_B 0x61400
-#define PIPE_DDI_FUNC_CTL_C 0x62400
+#define PIPE_DDI_FUNC_CTL_A 0x60400
+#define PIPE_DDI_FUNC_CTL_B 0x61400
+#define PIPE_DDI_FUNC_CTL_C 0x62400
#define PIPE_DDI_FUNC_CTL_EDP 0x6F400
-#define DDI_FUNC_CTL(pipe) _PIPE(pipe, PIPE_DDI_FUNC_CTL_A, \
- PIPE_DDI_FUNC_CTL_B)
+#define DDI_FUNC_CTL(pipe) _PIPE(pipe, \
+ PIPE_DDI_FUNC_CTL_A, \
+ PIPE_DDI_FUNC_CTL_B)
#define PIPE_DDI_FUNC_ENABLE (1<<31)
/* Those bits are ignored by pipe EDP since it can only connect to DDI A */
-#define PIPE_DDI_PORT_MASK (7<<28)
-#define PIPE_DDI_SELECT_PORT(x) ((x)<<28)
-#define PIPE_DDI_MODE_SELECT_MASK (7<<24)
-#define PIPE_DDI_MODE_SELECT_HDMI (0<<24)
-#define PIPE_DDI_MODE_SELECT_DVI (1<<24)
+#define PIPE_DDI_PORT_MASK (7<<28)
+#define PIPE_DDI_SELECT_PORT(x) ((x)<<28)
+#define PIPE_DDI_MODE_SELECT_HDMI (0<<24)
+#define PIPE_DDI_MODE_SELECT_DVI (1<<24)
#define PIPE_DDI_MODE_SELECT_DP_SST (2<<24)
#define PIPE_DDI_MODE_SELECT_DP_MST (3<<24)
-#define PIPE_DDI_MODE_SELECT_FDI (4<<24)
-#define PIPE_DDI_BPC_MASK (7<<20)
-#define PIPE_DDI_BPC_8 (0<<20)
-#define PIPE_DDI_BPC_10 (1<<20)
-#define PIPE_DDI_BPC_6 (2<<20)
-#define PIPE_DDI_BPC_12 (3<<20)
-#define PIPE_DDI_PVSYNC (1<<17)
-#define PIPE_DDI_PHSYNC (1<<16)
-#define PIPE_DDI_BFI_ENABLE (1<<4)
-#define PIPE_DDI_PORT_WIDTH_X1 (0<<1)
-#define PIPE_DDI_PORT_WIDTH_X2 (1<<1)
-#define PIPE_DDI_PORT_WIDTH_X4 (3<<1)
+#define PIPE_DDI_MODE_SELECT_FDI (4<<24)
+#define PIPE_DDI_BPC_8 (0<<20)
+#define PIPE_DDI_BPC_10 (1<<20)
+#define PIPE_DDI_BPC_6 (2<<20)
+#define PIPE_DDI_BPC_12 (3<<20)
+#define PIPE_DDI_BFI_ENABLE (1<<4)
+#define PIPE_DDI_PORT_WIDTH_X1 (0<<1)
+#define PIPE_DDI_PORT_WIDTH_X2 (1<<1)
+#define PIPE_DDI_PORT_WIDTH_X4 (3<<1)
/* DisplayPort Transport Control */
#define DP_TP_CTL_A 0x64040
#define DP_TP_CTL_B 0x64140
-#define DP_TP_CTL(port) _PORT(port, DP_TP_CTL_A, DP_TP_CTL_B)
-#define DP_TP_CTL_ENABLE (1<<31)
-#define DP_TP_CTL_MODE_SST (0<<27)
-#define DP_TP_CTL_MODE_MST (1<<27)
+#define DP_TP_CTL(port) _PORT(port, \
+ DP_TP_CTL_A, \
+ DP_TP_CTL_B)
+#define DP_TP_CTL_ENABLE (1<<31)
+#define DP_TP_CTL_MODE_SST (0<<27)
+#define DP_TP_CTL_MODE_MST (1<<27)
#define DP_TP_CTL_ENHANCED_FRAME_ENABLE (1<<18)
-#define DP_TP_CTL_FDI_AUTOTRAIN (1<<15)
+#define DP_TP_CTL_FDI_AUTOTRAIN (1<<15)
#define DP_TP_CTL_LINK_TRAIN_MASK (7<<8)
#define DP_TP_CTL_LINK_TRAIN_PAT1 (0<<8)
#define DP_TP_CTL_LINK_TRAIN_PAT2 (1<<8)
-#define DP_TP_CTL_LINK_TRAIN_NORMAL (3<<8)
+#define DP_TP_CTL_LINK_TRAIN_NORMAL (3<<8)
/* DisplayPort Transport Status */
#define DP_TP_STATUS_A 0x64044
#define DP_TP_STATUS_B 0x64144
-#define DP_TP_STATUS(port) _PORT(port, DP_TP_STATUS_A, DP_TP_STATUS_B)
+#define DP_TP_STATUS(port) _PORT(port, \
+ DP_TP_STATUS_A, \
+ DP_TP_STATUS_B)
#define DP_TP_STATUS_AUTOTRAIN_DONE (1<<12)
/* DDI Buffer Control */
#define DDI_BUF_CTL_A 0x64000
#define DDI_BUF_CTL_B 0x64100
-#define DDI_BUF_CTL(port) _PORT(port, DDI_BUF_CTL_A, DDI_BUF_CTL_B)
-#define DDI_BUF_CTL_ENABLE (1<<31)
+#define DDI_BUF_CTL(port) _PORT(port, \
+ DDI_BUF_CTL_A, \
+ DDI_BUF_CTL_B)
+#define DDI_BUF_CTL_ENABLE (1<<31)
#define DDI_BUF_EMP_400MV_0DB_HSW (0<<24) /* Sel0 */
-#define DDI_BUF_EMP_400MV_3_5DB_HSW (1<<24) /* Sel1 */
+#define DDI_BUF_EMP_400MV_3_5DB_HSW (1<<24) /* Sel1 */
#define DDI_BUF_EMP_400MV_6DB_HSW (2<<24) /* Sel2 */
-#define DDI_BUF_EMP_400MV_9_5DB_HSW (3<<24) /* Sel3 */
+#define DDI_BUF_EMP_400MV_9_5DB_HSW (3<<24) /* Sel3 */
#define DDI_BUF_EMP_600MV_0DB_HSW (4<<24) /* Sel4 */
-#define DDI_BUF_EMP_600MV_3_5DB_HSW (5<<24) /* Sel5 */
+#define DDI_BUF_EMP_600MV_3_5DB_HSW (5<<24) /* Sel5 */
#define DDI_BUF_EMP_600MV_6DB_HSW (6<<24) /* Sel6 */
#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_IS_IDLE (1<<7)
-#define DDI_PORT_WIDTH_X1 (0<<1)
-#define DDI_PORT_WIDTH_X2 (1<<1)
-#define DDI_PORT_WIDTH_X4 (3<<1)
+#define DDI_BUF_EMP_800MV_3_5DB_HSW (8<<24) /* Sel8 */
+#define DDI_BUF_EMP_MASK (0xf<<24)
+#define DDI_BUF_IS_IDLE (1<<7)
+#define DDI_PORT_WIDTH_X1 (0<<1)
+#define DDI_PORT_WIDTH_X2 (1<<1)
+#define DDI_PORT_WIDTH_X4 (3<<1)
#define DDI_INIT_DISPLAY_DETECTED (1<<0)
/* DDI Buffer Translations */
#define DDI_BUF_TRANS_A 0x64E00
#define DDI_BUF_TRANS_B 0x64E60
-#define DDI_BUF_TRANS(port) _PORT(port, DDI_BUF_TRANS_A, DDI_BUF_TRANS_B)
+#define DDI_BUF_TRANS(port) _PORT(port, \
+ DDI_BUF_TRANS_A, \
+ DDI_BUF_TRANS_B)
/* Sideband Interface (SBI) is programmed indirectly, via
* SBI_ADDR, which contains the register offset; and SBI_DATA,
* which contains the payload */
-#define SBI_ADDR 0xC6000
-#define SBI_DATA 0xC6004
+#define SBI_ADDR 0xC6000
+#define SBI_DATA 0xC6004
#define SBI_CTL_STAT 0xC6008
#define SBI_CTL_OP_CRRD (0x6<<8)
#define SBI_CTL_OP_CRWR (0x7<<8)
#define SBI_RESPONSE_FAIL (0x1<<1)
-#define SBI_RESPONSE_SUCCESS (0x0<<1)
-#define SBI_BUSY (0x1<<0)
-#define SBI_READY (0x0<<0)
+#define SBI_RESPONSE_SUCCESS (0x0<<1)
+#define SBI_BUSY (0x1<<0)
+#define SBI_READY (0x0<<0)
/* SBI offsets */
-#define SBI_SSCDIVINTPHASE6 0x0600
+#define SBI_SSCDIVINTPHASE6 0x0600
#define SBI_SSCDIVINTPHASE_DIVSEL_MASK ((0x7f)<<1)
#define SBI_SSCDIVINTPHASE_DIVSEL(x) ((x)<<1)
#define SBI_SSCDIVINTPHASE_INCVAL_MASK ((0x7f)<<8)
#define SBI_SSCDIVINTPHASE_INCVAL(x) ((x)<<8)
-#define SBI_SSCDIVINTPHASE_DIR(x) ((x)<<15)
+#define SBI_SSCDIVINTPHASE_DIR(x) ((x)<<15)
#define SBI_SSCDIVINTPHASE_PROPAGATE (1<<0)
-#define SBI_SSCCTL 0x020c
+#define SBI_SSCCTL 0x020c
#define SBI_SSCCTL6 0x060C
-#define SBI_SSCCTL_DISABLE (1<<0)
+#define SBI_SSCCTL_DISABLE (1<<0)
#define SBI_SSCAUXDIV6 0x0610
#define SBI_SSCAUXDIV_FINALDIV2SEL(x) ((x)<<4)
-#define SBI_DBUFF0 0x2a00
+#define SBI_DBUFF0 0x2a00
/* LPT PIXCLK_GATE */
-#define PIXCLK_GATE 0xC6020
-#define PIXCLK_GATE_UNGATE (1<<0)
-#define PIXCLK_GATE_GATE (0<<0)
+#define PIXCLK_GATE 0xC6020
+#define PIXCLK_GATE_UNGATE 1<<0
+#define PIXCLK_GATE_GATE 0<<0
/* SPLL */
-#define SPLL_CTL 0x46020
+#define SPLL_CTL 0x46020
#define SPLL_PLL_ENABLE (1<<31)
#define SPLL_PLL_SCC (1<<28)
#define SPLL_PLL_NON_SCC (2<<28)
-#define SPLL_PLL_FREQ_810MHz (0<<26)
-#define SPLL_PLL_FREQ_1350MHz (1<<26)
+#define SPLL_PLL_FREQ_810MHz (0<<26)
+#define SPLL_PLL_FREQ_1350MHz (1<<26)
/* WRPLL */
-#define WRPLL_CTL1 0x46040
-#define WRPLL_CTL2 0x46060
-#define WRPLL_PLL_ENABLE (1<<31)
-#define WRPLL_PLL_SELECT_SSC (0x01<<28)
-#define WRPLL_PLL_SELECT_NON_SCC (0x02<<28)
+#define WRPLL_CTL1 0x46040
+#define WRPLL_CTL2 0x46060
+#define WRPLL_PLL_ENABLE (1<<31)
+#define WRPLL_PLL_SELECT_SSC (0x01<<28)
+#define WRPLL_PLL_SELECT_NON_SCC (0x02<<28)
#define WRPLL_PLL_SELECT_LCPLL_2700 (0x03<<28)
/* WRPLL divider programming */
-#define WRPLL_DIVIDER_REFERENCE(x) ((x)<<0)
-#define WRPLL_DIVIDER_POST(x) ((x)<<8)
-#define WRPLL_DIVIDER_FEEDBACK(x) ((x)<<16)
+#define WRPLL_DIVIDER_REFERENCE(x) ((x)<<0)
+#define WRPLL_DIVIDER_POST(x) ((x)<<8)
+#define WRPLL_DIVIDER_FEEDBACK(x) ((x)<<16)
/* Port clock selection */
#define PORT_CLK_SEL_A 0x46100
#define PORT_CLK_SEL_B 0x46104
-#define PORT_CLK_SEL(port) _PORT(port, PORT_CLK_SEL_A, PORT_CLK_SEL_B)
+#define PORT_CLK_SEL(port) _PORT(port, \
+ PORT_CLK_SEL_A, \
+ PORT_CLK_SEL_B)
#define PORT_CLK_SEL_LCPLL_2700 (0<<29)
#define PORT_CLK_SEL_LCPLL_1350 (1<<29)
#define PORT_CLK_SEL_LCPLL_810 (2<<29)
-#define PORT_CLK_SEL_SPLL (3<<29)
+#define PORT_CLK_SEL_SPLL (3<<29)
#define PORT_CLK_SEL_WRPLL1 (4<<29)
#define PORT_CLK_SEL_WRPLL2 (5<<29)
/* Pipe clock selection */
#define PIPE_CLK_SEL_A 0x46140
#define PIPE_CLK_SEL_B 0x46144
-#define PIPE_CLK_SEL(pipe) _PIPE(pipe, PIPE_CLK_SEL_A, PIPE_CLK_SEL_B)
+#define PIPE_CLK_SEL(pipe) _PIPE(pipe, \
+ PIPE_CLK_SEL_A, \
+ PIPE_CLK_SEL_B)
/* For each pipe, we need to select the corresponding port clock */
-#define PIPE_CLK_SEL_DISABLED (0x0<<29)
-#define PIPE_CLK_SEL_PORT(x) ((x+1)<<29)
+#define PIPE_CLK_SEL_DISABLED (0x0<<29)
+#define PIPE_CLK_SEL_PORT(x) ((x+1)<<29)
/* LCPLL Control */
-#define LCPLL_CTL 0x130040
+#define LCPLL_CTL 0x130040
#define LCPLL_PLL_DISABLE (1<<31)
#define LCPLL_PLL_LOCK (1<<30)
-#define LCPLL_CD_CLOCK_DISABLE (1<<25)
+#define LCPLL_CD_CLOCK_DISABLE (1<<25)
#define LCPLL_CD2X_CLOCK_DISABLE (1<<23)
/* Pipe WM_LINETIME - watermark line time */
#define PIPE_WM_LINETIME_A 0x45270
#define PIPE_WM_LINETIME_B 0x45274
-#define PIPE_WM_LINETIME(pipe) _PIPE(pipe, PIPE_WM_LINETIME_A, \
- PIPE_WM_LINETIME_B)
-#define PIPE_WM_LINETIME_MASK (0x1ff)
-#define PIPE_WM_LINETIME_TIME(x) ((x))
+#define PIPE_WM_LINETIME(pipe) _PIPE(pipe, \
+ PIPE_WM_LINETIME_A, \
+ PIPE_WM_LINETIME_B)
+#define PIPE_WM_LINETIME_MASK (0x1ff)
+#define PIPE_WM_LINETIME_TIME(x) ((x))
#define PIPE_WM_LINETIME_IPS_LINETIME_MASK (0x1ff<<16)
-#define PIPE_WM_LINETIME_IPS_LINETIME(x) ((x)<<16)
+#define PIPE_WM_LINETIME_IPS_LINETIME(x) ((x)<<16)
/* SFUSE_STRAP */
-#define SFUSE_STRAP 0xc2014
+#define SFUSE_STRAP 0xc2014
#define SFUSE_STRAP_DDIB_DETECTED (1<<2)
#define SFUSE_STRAP_DDIC_DETECTED (1<<1)
#define SFUSE_STRAP_DDID_DETECTED (1<<0)
diff --git a/trunk/drivers/gpu/drm/i915/i915_sysfs.c b/trunk/drivers/gpu/drm/i915/i915_sysfs.c
index 903eebd2117a..7631807a2788 100644
--- a/trunk/drivers/gpu/drm/i915/i915_sysfs.c
+++ b/trunk/drivers/gpu/drm/i915/i915_sysfs.c
@@ -46,32 +46,32 @@ static u32 calc_residency(struct drm_device *dev, const u32 reg)
}
static ssize_t
-show_rc6_mask(struct device *kdev, struct device_attribute *attr, char *buf)
+show_rc6_mask(struct device *dev, struct device_attribute *attr, char *buf)
{
- struct drm_minor *dminor = container_of(kdev, struct drm_minor, kdev);
+ struct drm_minor *dminor = container_of(dev, struct drm_minor, kdev);
return snprintf(buf, PAGE_SIZE, "%x", intel_enable_rc6(dminor->dev));
}
static ssize_t
-show_rc6_ms(struct device *kdev, struct device_attribute *attr, char *buf)
+show_rc6_ms(struct device *dev, struct device_attribute *attr, char *buf)
{
- struct drm_minor *dminor = container_of(kdev, struct drm_minor, kdev);
+ struct drm_minor *dminor = container_of(dev, struct drm_minor, kdev);
u32 rc6_residency = calc_residency(dminor->dev, GEN6_GT_GFX_RC6);
return snprintf(buf, PAGE_SIZE, "%u", rc6_residency);
}
static ssize_t
-show_rc6p_ms(struct device *kdev, struct device_attribute *attr, char *buf)
+show_rc6p_ms(struct device *dev, struct device_attribute *attr, char *buf)
{
- struct drm_minor *dminor = container_of(kdev, struct drm_minor, kdev);
+ struct drm_minor *dminor = container_of(dev, struct drm_minor, kdev);
u32 rc6p_residency = calc_residency(dminor->dev, GEN6_GT_GFX_RC6p);
return snprintf(buf, PAGE_SIZE, "%u", rc6p_residency);
}
static ssize_t
-show_rc6pp_ms(struct device *kdev, struct device_attribute *attr, char *buf)
+show_rc6pp_ms(struct device *dev, struct device_attribute *attr, char *buf)
{
- struct drm_minor *dminor = container_of(kdev, struct drm_minor, kdev);
+ struct drm_minor *dminor = container_of(dev, struct drm_minor, kdev);
u32 rc6pp_residency = calc_residency(dminor->dev, GEN6_GT_GFX_RC6pp);
return snprintf(buf, PAGE_SIZE, "%u", rc6pp_residency);
}
@@ -93,7 +93,6 @@ static struct attribute_group rc6_attr_group = {
.name = power_group_name,
.attrs = rc6_attrs
};
-#endif
static int l3_access_valid(struct drm_device *dev, loff_t offset)
{
@@ -203,214 +202,37 @@ static struct bin_attribute dpf_attrs = {
.mmap = NULL
};
-static ssize_t gt_cur_freq_mhz_show(struct device *kdev,
- struct device_attribute *attr, char *buf)
-{
- struct drm_minor *minor = container_of(kdev, struct drm_minor, kdev);
- struct drm_device *dev = minor->dev;
- struct drm_i915_private *dev_priv = dev->dev_private;
- int ret;
-
- ret = i915_mutex_lock_interruptible(dev);
- if (ret)
- return ret;
-
- ret = dev_priv->rps.cur_delay * GT_FREQUENCY_MULTIPLIER;
- mutex_unlock(&dev->struct_mutex);
-
- return snprintf(buf, PAGE_SIZE, "%d", ret);
-}
-
-static ssize_t gt_max_freq_mhz_show(struct device *kdev, struct device_attribute *attr, char *buf)
-{
- struct drm_minor *minor = container_of(kdev, struct drm_minor, kdev);
- struct drm_device *dev = minor->dev;
- struct drm_i915_private *dev_priv = dev->dev_private;
- int ret;
-
- ret = i915_mutex_lock_interruptible(dev);
- if (ret)
- return ret;
-
- ret = dev_priv->rps.max_delay * GT_FREQUENCY_MULTIPLIER;
- mutex_unlock(&dev->struct_mutex);
-
- return snprintf(buf, PAGE_SIZE, "%d", ret);
-}
-
-static ssize_t gt_max_freq_mhz_store(struct device *kdev,
- struct device_attribute *attr,
- const char *buf, size_t count)
-{
- struct drm_minor *minor = container_of(kdev, struct drm_minor, kdev);
- struct drm_device *dev = minor->dev;
- struct drm_i915_private *dev_priv = dev->dev_private;
- u32 val, rp_state_cap, hw_max, hw_min;
- ssize_t ret;
-
- ret = kstrtou32(buf, 0, &val);
- if (ret)
- return ret;
-
- val /= GT_FREQUENCY_MULTIPLIER;
-
- ret = mutex_lock_interruptible(&dev->struct_mutex);
- if (ret)
- return ret;
-
- rp_state_cap = I915_READ(GEN6_RP_STATE_CAP);
- hw_max = (rp_state_cap & 0xff);
- hw_min = ((rp_state_cap & 0xff0000) >> 16);
-
- if (val < hw_min || val > hw_max || val < dev_priv->rps.min_delay) {
- mutex_unlock(&dev->struct_mutex);
- return -EINVAL;
- }
-
- if (dev_priv->rps.cur_delay > val)
- gen6_set_rps(dev_priv->dev, val);
-
- dev_priv->rps.max_delay = val;
-
- mutex_unlock(&dev->struct_mutex);
-
- return count;
-}
-
-static ssize_t gt_min_freq_mhz_show(struct device *kdev, struct device_attribute *attr, char *buf)
-{
- struct drm_minor *minor = container_of(kdev, struct drm_minor, kdev);
- struct drm_device *dev = minor->dev;
- struct drm_i915_private *dev_priv = dev->dev_private;
- int ret;
-
- ret = i915_mutex_lock_interruptible(dev);
- if (ret)
- return ret;
-
- ret = dev_priv->rps.min_delay * GT_FREQUENCY_MULTIPLIER;
- mutex_unlock(&dev->struct_mutex);
-
- return snprintf(buf, PAGE_SIZE, "%d", ret);
-}
-
-static ssize_t gt_min_freq_mhz_store(struct device *kdev,
- struct device_attribute *attr,
- const char *buf, size_t count)
-{
- struct drm_minor *minor = container_of(kdev, struct drm_minor, kdev);
- struct drm_device *dev = minor->dev;
- struct drm_i915_private *dev_priv = dev->dev_private;
- u32 val, rp_state_cap, hw_max, hw_min;
- ssize_t ret;
-
- ret = kstrtou32(buf, 0, &val);
- if (ret)
- return ret;
-
- val /= GT_FREQUENCY_MULTIPLIER;
-
- ret = mutex_lock_interruptible(&dev->struct_mutex);
- if (ret)
- return ret;
-
- rp_state_cap = I915_READ(GEN6_RP_STATE_CAP);
- hw_max = (rp_state_cap & 0xff);
- hw_min = ((rp_state_cap & 0xff0000) >> 16);
-
- if (val < hw_min || val > hw_max || val > dev_priv->rps.max_delay) {
- mutex_unlock(&dev->struct_mutex);
- return -EINVAL;
- }
-
- if (dev_priv->rps.cur_delay < val)
- gen6_set_rps(dev_priv->dev, val);
-
- dev_priv->rps.min_delay = val;
-
- mutex_unlock(&dev->struct_mutex);
-
- return count;
-
-}
-
-static DEVICE_ATTR(gt_cur_freq_mhz, S_IRUGO, gt_cur_freq_mhz_show, NULL);
-static DEVICE_ATTR(gt_max_freq_mhz, S_IRUGO | S_IWUSR, gt_max_freq_mhz_show, gt_max_freq_mhz_store);
-static DEVICE_ATTR(gt_min_freq_mhz, S_IRUGO | S_IWUSR, gt_min_freq_mhz_show, gt_min_freq_mhz_store);
-
-
-static ssize_t gt_rp_mhz_show(struct device *kdev, struct device_attribute *attr, char *buf);
-static DEVICE_ATTR(gt_RP0_freq_mhz, S_IRUGO, gt_rp_mhz_show, NULL);
-static DEVICE_ATTR(gt_RP1_freq_mhz, S_IRUGO, gt_rp_mhz_show, NULL);
-static DEVICE_ATTR(gt_RPn_freq_mhz, S_IRUGO, gt_rp_mhz_show, NULL);
-
-/* For now we have a static number of RP states */
-static ssize_t gt_rp_mhz_show(struct device *kdev, struct device_attribute *attr, char *buf)
-{
- struct drm_minor *minor = container_of(kdev, struct drm_minor, kdev);
- struct drm_device *dev = minor->dev;
- struct drm_i915_private *dev_priv = dev->dev_private;
- u32 val, rp_state_cap;
- ssize_t ret;
-
- ret = mutex_lock_interruptible(&dev->struct_mutex);
- if (ret)
- return ret;
- rp_state_cap = I915_READ(GEN6_RP_STATE_CAP);
- mutex_unlock(&dev->struct_mutex);
-
- if (attr == &dev_attr_gt_RP0_freq_mhz) {
- val = ((rp_state_cap & 0x0000ff) >> 0) * GT_FREQUENCY_MULTIPLIER;
- } else if (attr == &dev_attr_gt_RP1_freq_mhz) {
- val = ((rp_state_cap & 0x00ff00) >> 8) * GT_FREQUENCY_MULTIPLIER;
- } else if (attr == &dev_attr_gt_RPn_freq_mhz) {
- val = ((rp_state_cap & 0xff0000) >> 16) * GT_FREQUENCY_MULTIPLIER;
- } else {
- BUG();
- }
- return snprintf(buf, PAGE_SIZE, "%d", val);
-}
-
-static const struct attribute *gen6_attrs[] = {
- &dev_attr_gt_cur_freq_mhz.attr,
- &dev_attr_gt_max_freq_mhz.attr,
- &dev_attr_gt_min_freq_mhz.attr,
- &dev_attr_gt_RP0_freq_mhz.attr,
- &dev_attr_gt_RP1_freq_mhz.attr,
- &dev_attr_gt_RPn_freq_mhz.attr,
- NULL,
-};
-
void i915_setup_sysfs(struct drm_device *dev)
{
int ret;
-#ifdef CONFIG_PM
if (INTEL_INFO(dev)->gen >= 6) {
ret = sysfs_merge_group(&dev->primary->kdev.kobj,
&rc6_attr_group);
if (ret)
DRM_ERROR("RC6 residency sysfs setup failed\n");
}
-#endif
- if (HAS_L3_GPU_CACHE(dev)) {
+
+ if (IS_IVYBRIDGE(dev)) {
ret = device_create_bin_file(&dev->primary->kdev, &dpf_attrs);
if (ret)
DRM_ERROR("l3 parity sysfs setup failed\n");
}
-
- if (INTEL_INFO(dev)->gen >= 6) {
- ret = sysfs_create_files(&dev->primary->kdev.kobj, gen6_attrs);
- if (ret)
- DRM_ERROR("gen6 sysfs setup failed\n");
- }
}
void i915_teardown_sysfs(struct drm_device *dev)
{
- sysfs_remove_files(&dev->primary->kdev.kobj, gen6_attrs);
device_remove_bin_file(&dev->primary->kdev, &dpf_attrs);
-#ifdef CONFIG_PM
sysfs_unmerge_group(&dev->primary->kdev.kobj, &rc6_attr_group);
-#endif
}
+#else
+void i915_setup_sysfs(struct drm_device *dev)
+{
+ return;
+}
+
+void i915_teardown_sysfs(struct drm_device *dev)
+{
+ return;
+}
+#endif /* CONFIG_PM */
diff --git a/trunk/drivers/gpu/drm/i915/i915_trace.h b/trunk/drivers/gpu/drm/i915/i915_trace.h
index 8134421b89a6..fe90b3a84a6d 100644
--- a/trunk/drivers/gpu/drm/i915/i915_trace.h
+++ b/trunk/drivers/gpu/drm/i915/i915_trace.h
@@ -214,18 +214,22 @@ TRACE_EVENT(i915_gem_evict,
);
TRACE_EVENT(i915_gem_evict_everything,
- TP_PROTO(struct drm_device *dev),
- TP_ARGS(dev),
+ TP_PROTO(struct drm_device *dev, bool purgeable),
+ TP_ARGS(dev, purgeable),
TP_STRUCT__entry(
__field(u32, dev)
+ __field(bool, purgeable)
),
TP_fast_assign(
__entry->dev = dev->primary->index;
+ __entry->purgeable = purgeable;
),
- TP_printk("dev=%d", __entry->dev)
+ TP_printk("dev=%d%s",
+ __entry->dev,
+ __entry->purgeable ? ", purgeable only" : "")
);
TRACE_EVENT(i915_gem_ring_dispatch,
@@ -430,21 +434,6 @@ TRACE_EVENT(i915_reg_rw,
(u32)(__entry->val >> 32))
);
-TRACE_EVENT(intel_gpu_freq_change,
- TP_PROTO(u32 freq),
- TP_ARGS(freq),
-
- TP_STRUCT__entry(
- __field(u32, freq)
- ),
-
- TP_fast_assign(
- __entry->freq = freq;
- ),
-
- TP_printk("new_freq=%u", __entry->freq)
-);
-
#endif /* _I915_TRACE_H_ */
/* This part must be outside protection */
diff --git a/trunk/drivers/gpu/drm/i915/intel_crt.c b/trunk/drivers/gpu/drm/i915/intel_crt.c
index c42b9809f86d..23bdc8cd1458 100644
--- a/trunk/drivers/gpu/drm/i915/intel_crt.c
+++ b/trunk/drivers/gpu/drm/i915/intel_crt.c
@@ -47,7 +47,6 @@
struct intel_crt {
struct intel_encoder base;
bool force_hotplug_required;
- u32 adpa_reg;
};
static struct intel_crt *intel_attached_crt(struct drm_connector *connector)
@@ -56,68 +55,42 @@ static struct intel_crt *intel_attached_crt(struct drm_connector *connector)
struct intel_crt, base);
}
-static struct intel_crt *intel_encoder_to_crt(struct intel_encoder *encoder)
-{
- return container_of(encoder, struct intel_crt, base);
-}
-
-static bool intel_crt_get_hw_state(struct intel_encoder *encoder,
- enum pipe *pipe)
+static void pch_crt_dpms(struct drm_encoder *encoder, int mode)
{
- struct drm_device *dev = encoder->base.dev;
+ struct drm_device *dev = encoder->dev;
struct drm_i915_private *dev_priv = dev->dev_private;
- struct intel_crt *crt = intel_encoder_to_crt(encoder);
- u32 tmp;
-
- tmp = I915_READ(crt->adpa_reg);
-
- if (!(tmp & ADPA_DAC_ENABLE))
- return false;
-
- if (HAS_PCH_CPT(dev))
- *pipe = PORT_TO_PIPE_CPT(tmp);
- else
- *pipe = PORT_TO_PIPE(tmp);
-
- 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 = I915_READ(PCH_ADPA);
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;
+ switch (mode) {
+ case DRM_MODE_DPMS_ON:
+ temp |= ADPA_DAC_ENABLE;
+ break;
+ case DRM_MODE_DPMS_STANDBY:
+ case DRM_MODE_DPMS_SUSPEND:
+ case DRM_MODE_DPMS_OFF:
+ /* Just leave port enable cleared */
+ break;
+ }
- temp = I915_READ(crt->adpa_reg);
- temp |= ADPA_DAC_ENABLE;
- I915_WRITE(crt->adpa_reg, temp);
+ I915_WRITE(PCH_ADPA, 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)
+static void gmch_crt_dpms(struct drm_encoder *encoder, int mode)
{
- struct drm_device *dev = encoder->base.dev;
+ struct drm_device *dev = encoder->dev;
struct drm_i915_private *dev_priv = dev->dev_private;
- struct intel_crt *crt = intel_encoder_to_crt(encoder);
u32 temp;
- temp = I915_READ(crt->adpa_reg);
+ temp = I915_READ(ADPA);
temp &= ~(ADPA_HSYNC_CNTL_DISABLE | ADPA_VSYNC_CNTL_DISABLE);
temp &= ~ADPA_DAC_ENABLE;
+ if (IS_VALLEYVIEW(dev) && mode != DRM_MODE_DPMS_ON)
+ mode = DRM_MODE_DPMS_OFF;
+
switch (mode) {
case DRM_MODE_DPMS_ON:
temp |= ADPA_DAC_ENABLE;
@@ -133,51 +106,7 @@ static void intel_crt_set_dpms(struct intel_encoder *encoder, int mode)
break;
}
- I915_WRITE(crt->adpa_reg, temp);
-}
-
-static void intel_crt_dpms(struct drm_connector *connector, int mode)
-{
- struct drm_device *dev = connector->dev;
- struct intel_encoder *encoder = intel_attached_encoder(connector);
- struct drm_crtc *crtc;
- int old_dpms;
-
- /* PCH platforms and VLV only support on/off. */
- if (INTEL_INFO(dev)->gen < 5 && mode != DRM_MODE_DPMS_ON)
- mode = DRM_MODE_DPMS_OFF;
-
- if (mode == connector->dpms)
- return;
-
- old_dpms = connector->dpms;
- connector->dpms = mode;
-
- /* Only need to change hw state when actually enabled */
- crtc = encoder->base.crtc;
- if (!crtc) {
- encoder->connectors_active = false;
- return;
- }
-
- /* We need the pipe to run for anything but OFF. */
- if (mode == DRM_MODE_DPMS_OFF)
- encoder->connectors_active = false;
- else
- encoder->connectors_active = true;
-
- if (mode < old_dpms) {
- /* From off to on, enable the pipe first. */
- intel_crtc_update_dpms(crtc);
-
- intel_crt_set_dpms(encoder, mode);
- } else {
- intel_crt_set_dpms(encoder, mode);
-
- intel_crtc_update_dpms(crtc);
- }
-
- intel_modeset_check_state(connector->dev);
+ I915_WRITE(ADPA, temp);
}
static int intel_crt_mode_valid(struct drm_connector *connector,
@@ -216,15 +145,19 @@ static void intel_crt_mode_set(struct drm_encoder *encoder,
struct drm_device *dev = encoder->dev;
struct drm_crtc *crtc = encoder->crtc;
- struct intel_crt *crt =
- intel_encoder_to_crt(to_intel_encoder(encoder));
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
struct drm_i915_private *dev_priv = dev->dev_private;
int dpll_md_reg;
u32 adpa, dpll_md;
+ u32 adpa_reg;
dpll_md_reg = DPLL_MD(intel_crtc->pipe);
+ if (HAS_PCH_SPLIT(dev))
+ adpa_reg = PCH_ADPA;
+ else
+ adpa_reg = ADPA;
+
/*
* Disable separate mode multiplier used when cloning SDVO to CRT
* XXX this needs to be adjusted when we really are cloning
@@ -252,7 +185,7 @@ static void intel_crt_mode_set(struct drm_encoder *encoder,
if (!HAS_PCH_SPLIT(dev))
I915_WRITE(BCLRPAT(intel_crtc->pipe), 0);
- I915_WRITE(crt->adpa_reg, adpa);
+ I915_WRITE(adpa_reg, adpa);
}
static bool intel_ironlake_crt_detect_hotplug(struct drm_connector *connector)
@@ -612,12 +545,14 @@ intel_crt_detect(struct drm_connector *connector, bool force)
return connector->status;
/* for pre-945g platforms use load detect */
- if (intel_get_load_detect_pipe(connector, NULL, &tmp)) {
+ if (intel_get_load_detect_pipe(&crt->base, connector, NULL,
+ &tmp)) {
if (intel_crt_detect_ddc(connector))
status = connector_status_connected;
else
status = intel_crt_load_detect(crt);
- intel_release_load_detect_pipe(connector, &tmp);
+ intel_release_load_detect_pipe(&crt->base, connector,
+ &tmp);
} else
status = connector_status_unknown;
@@ -668,15 +603,25 @@ static void intel_crt_reset(struct drm_connector *connector)
* Routines for controlling stuff on the analog port
*/
-static const struct drm_encoder_helper_funcs crt_encoder_funcs = {
+static const struct drm_encoder_helper_funcs pch_encoder_funcs = {
.mode_fixup = intel_crt_mode_fixup,
+ .prepare = intel_encoder_prepare,
+ .commit = intel_encoder_commit,
.mode_set = intel_crt_mode_set,
- .disable = intel_encoder_noop,
+ .dpms = pch_crt_dpms,
+};
+
+static const struct drm_encoder_helper_funcs gmch_encoder_funcs = {
+ .mode_fixup = intel_crt_mode_fixup,
+ .prepare = intel_encoder_prepare,
+ .commit = intel_encoder_commit,
+ .mode_set = intel_crt_mode_set,
+ .dpms = gmch_crt_dpms,
};
static const struct drm_connector_funcs intel_crt_connector_funcs = {
.reset = intel_crt_reset,
- .dpms = intel_crt_dpms,
+ .dpms = drm_helper_connector_dpms,
.detect = intel_crt_detect,
.fill_modes = drm_helper_probe_single_connector_modes,
.destroy = intel_crt_destroy,
@@ -717,6 +662,7 @@ void intel_crt_init(struct drm_device *dev)
struct intel_crt *crt;
struct intel_connector *intel_connector;
struct drm_i915_private *dev_priv = dev->dev_private;
+ const struct drm_encoder_helper_funcs *encoder_helper_funcs;
/* Skip machines without VGA that falsely report hotplug events */
if (dmi_check_system(intel_no_crt))
@@ -742,11 +688,13 @@ void intel_crt_init(struct drm_device *dev)
intel_connector_attach_encoder(intel_connector, &crt->base);
crt->base.type = INTEL_OUTPUT_ANALOG;
- crt->base.cloneable = true;
+ crt->base.clone_mask = (1 << INTEL_SDVO_NON_TV_CLONE_BIT |
+ 1 << INTEL_ANALOG_CLONE_BIT |
+ 1 << INTEL_SDVO_LVDS_CLONE_BIT);
if (IS_HASWELL(dev))
crt->base.crtc_mask = (1 << 0);
else
- crt->base.crtc_mask = (1 << 0) | (1 << 1) | (1 << 2);
+ crt->base.crtc_mask = (1 << 0) | (1 << 1);
if (IS_GEN2(dev))
connector->interlace_allowed = 0;
@@ -755,18 +703,11 @@ void intel_crt_init(struct drm_device *dev)
connector->doublescan_allowed = 0;
if (HAS_PCH_SPLIT(dev))
- crt->adpa_reg = PCH_ADPA;
- else if (IS_VALLEYVIEW(dev))
- crt->adpa_reg = VLV_ADPA;
+ encoder_helper_funcs = &pch_encoder_funcs;
else
- crt->adpa_reg = ADPA;
-
- crt->base.disable = intel_disable_crt;
- crt->base.enable = intel_enable_crt;
- crt->base.get_hw_state = intel_crt_get_hw_state;
- intel_connector->get_hw_state = intel_connector_get_hw_state;
+ encoder_helper_funcs = &gmch_encoder_funcs;
- drm_encoder_helper_add(&crt->base.base, &crt_encoder_funcs);
+ drm_encoder_helper_add(&crt->base.base, encoder_helper_funcs);
drm_connector_helper_add(connector, &intel_crt_connector_helper_funcs);
drm_sysfs_connector_add(connector);
diff --git a/trunk/drivers/gpu/drm/i915/intel_ddi.c b/trunk/drivers/gpu/drm/i915/intel_ddi.c
index bfe375466a0e..933c74859172 100644
--- a/trunk/drivers/gpu/drm/i915/intel_ddi.c
+++ b/trunk/drivers/gpu/drm/i915/intel_ddi.c
@@ -250,7 +250,7 @@ void intel_ddi_init(struct drm_device *dev, enum port port)
case PORT_B:
case PORT_C:
case PORT_D:
- intel_hdmi_init(dev, DDI_BUF_CTL(port), port);
+ intel_hdmi_init(dev, DDI_BUF_CTL(port));
break;
default:
DRM_DEBUG_DRIVER("No handlers defined for port %d, skipping DDI initialization\n",
@@ -267,8 +267,7 @@ struct wrpll_tmds_clock {
u16 r2; /* Reference divider */
};
-/* Table of matching values for WRPLL clocks programming for each frequency.
- * The code assumes this table is sorted. */
+/* Table of matching values for WRPLL clocks programming for each frequency */
static const struct wrpll_tmds_clock wrpll_tmds_clock_table[] = {
{19750, 38, 25, 18},
{20000, 48, 32, 18},
@@ -278,6 +277,7 @@ static const struct wrpll_tmds_clock wrpll_tmds_clock_table[] = {
{23000, 36, 23, 15},
{23500, 40, 40, 23},
{23750, 26, 16, 14},
+ {23750, 26, 16, 14},
{24000, 36, 24, 15},
{25000, 36, 25, 15},
{25175, 26, 40, 33},
@@ -437,6 +437,7 @@ static const struct wrpll_tmds_clock wrpll_tmds_clock_table[] = {
{108000, 8, 24, 15},
{108108, 8, 173, 108},
{109000, 6, 23, 19},
+ {109000, 6, 23, 19},
{110000, 6, 22, 18},
{110013, 6, 22, 18},
{110250, 8, 49, 30},
@@ -613,6 +614,7 @@ static const struct wrpll_tmds_clock wrpll_tmds_clock_table[] = {
{218250, 4, 42, 26},
{218750, 4, 34, 21},
{219000, 4, 47, 29},
+ {219000, 4, 47, 29},
{220000, 4, 44, 27},
{220640, 4, 49, 30},
{220750, 4, 36, 22},
@@ -656,7 +658,7 @@ void intel_ddi_mode_set(struct drm_encoder *encoder,
struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder);
int port = intel_hdmi->ddi_port;
int pipe = intel_crtc->pipe;
- int p, n2, r2;
+ int p, n2, r2, valid=0;
u32 temp, i;
/* On Haswell, we need to enable the clocks and prepare DDI function to
@@ -664,23 +666,26 @@ void intel_ddi_mode_set(struct drm_encoder *encoder,
*/
DRM_DEBUG_KMS("Preparing HDMI DDI mode for Haswell on port %c, pipe %c\n", port_name(port), pipe_name(pipe));
- for (i = 0; i < ARRAY_SIZE(wrpll_tmds_clock_table); i++)
- if (crtc->mode.clock <= wrpll_tmds_clock_table[i].clock)
- break;
-
- if (i == ARRAY_SIZE(wrpll_tmds_clock_table))
- i--;
+ for (i=0; i < ARRAY_SIZE(wrpll_tmds_clock_table); i++) {
+ if (crtc->mode.clock == wrpll_tmds_clock_table[i].clock) {
+ p = wrpll_tmds_clock_table[i].p;
+ n2 = wrpll_tmds_clock_table[i].n2;
+ r2 = wrpll_tmds_clock_table[i].r2;
- p = wrpll_tmds_clock_table[i].p;
- n2 = wrpll_tmds_clock_table[i].n2;
- r2 = wrpll_tmds_clock_table[i].r2;
+ DRM_DEBUG_KMS("WR PLL clock: found settings for %dKHz refresh rate: p=%d, n2=%d, r2=%d\n",
+ crtc->mode.clock,
+ p, n2, r2);
- if (wrpll_tmds_clock_table[i].clock != crtc->mode.clock)
- DRM_INFO("WR PLL: using settings for %dKHz on %dKHz mode\n",
- wrpll_tmds_clock_table[i].clock, crtc->mode.clock);
+ valid = 1;
+ break;
+ }
+ }
- DRM_DEBUG_KMS("WR PLL: %dKHz refresh rate with p=%d, n2=%d r2=%d\n",
- crtc->mode.clock, p, n2, r2);
+ if (!valid) {
+ DRM_ERROR("Unable to find WR PLL clock settings for %dKHz refresh rate\n",
+ crtc->mode.clock);
+ return;
+ }
/* Enable LCPLL if disabled */
temp = I915_READ(LCPLL_CTL);
@@ -713,107 +718,46 @@ void intel_ddi_mode_set(struct drm_encoder *encoder,
/* Proper support for digital audio needs a new logic and a new set
* of registers, so we leave it for future patch bombing.
*/
- DRM_DEBUG_DRIVER("HDMI audio on pipe %c on DDI\n",
+ DRM_DEBUG_DRIVER("HDMI audio on pipe %c not yet supported on DDI\n",
pipe_name(intel_crtc->pipe));
-
- /* write eld */
- DRM_DEBUG_DRIVER("HDMI audio: write eld information\n");
- intel_write_eld(encoder, adjusted_mode);
}
/* Enable PIPE_DDI_FUNC_CTL for the pipe to work in HDMI mode */
- temp = PIPE_DDI_FUNC_ENABLE | PIPE_DDI_SELECT_PORT(port);
-
- switch (intel_crtc->bpp) {
- case 18:
- temp |= PIPE_DDI_BPC_6;
- break;
- case 24:
- temp |= PIPE_DDI_BPC_8;
- break;
- case 30:
- temp |= PIPE_DDI_BPC_10;
- break;
- case 36:
- temp |= PIPE_DDI_BPC_12;
- break;
- default:
- WARN(1, "%d bpp unsupported by pipe DDI function\n",
- intel_crtc->bpp);
- }
-
- if (intel_hdmi->has_hdmi_sink)
- temp |= PIPE_DDI_MODE_SELECT_HDMI;
- else
- temp |= PIPE_DDI_MODE_SELECT_DVI;
-
- if (adjusted_mode->flags & DRM_MODE_FLAG_PVSYNC)
- temp |= PIPE_DDI_PVSYNC;
- if (adjusted_mode->flags & DRM_MODE_FLAG_PHSYNC)
- temp |= PIPE_DDI_PHSYNC;
+ temp = I915_READ(DDI_FUNC_CTL(pipe));
+ temp &= ~PIPE_DDI_PORT_MASK;
+ temp &= ~PIPE_DDI_BPC_12;
+ temp |= PIPE_DDI_SELECT_PORT(port) |
+ PIPE_DDI_MODE_SELECT_HDMI |
+ ((intel_crtc->bpp > 24) ?
+ PIPE_DDI_BPC_12 :
+ PIPE_DDI_BPC_8) |
+ PIPE_DDI_FUNC_ENABLE;
I915_WRITE(DDI_FUNC_CTL(pipe), temp);
intel_hdmi->set_infoframes(encoder, adjusted_mode);
}
-bool intel_ddi_get_hw_state(struct intel_encoder *encoder,
- enum pipe *pipe)
+void intel_ddi_dpms(struct drm_encoder *encoder, int mode)
{
- struct drm_device *dev = encoder->base.dev;
- struct drm_i915_private *dev_priv = dev->dev_private;
- struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&encoder->base);
- u32 tmp;
- int i;
-
- tmp = I915_READ(DDI_BUF_CTL(intel_hdmi->ddi_port));
-
- if (!(tmp & DDI_BUF_CTL_ENABLE))
- return false;
-
- for_each_pipe(i) {
- tmp = I915_READ(DDI_FUNC_CTL(i));
-
- if ((tmp & PIPE_DDI_PORT_MASK)
- == PIPE_DDI_SELECT_PORT(intel_hdmi->ddi_port)) {
- *pipe = i;
- return true;
- }
- }
-
- DRM_DEBUG_KMS("No pipe for ddi port %i found\n", intel_hdmi->ddi_port);
-
- return true;
-}
-
-void intel_enable_ddi(struct intel_encoder *encoder)
-{
- struct drm_device *dev = encoder->base.dev;
+ struct drm_device *dev = encoder->dev;
struct drm_i915_private *dev_priv = dev->dev_private;
- struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&encoder->base);
+ struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder);
int port = intel_hdmi->ddi_port;
u32 temp;
temp = I915_READ(DDI_BUF_CTL(port));
- temp |= DDI_BUF_CTL_ENABLE;
+
+ if (mode != DRM_MODE_DPMS_ON) {
+ temp &= ~DDI_BUF_CTL_ENABLE;
+ } else {
+ temp |= DDI_BUF_CTL_ENABLE;
+ }
/* Enable DDI_BUF_CTL. 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), temp);
-}
-
-void intel_disable_ddi(struct intel_encoder *encoder)
-{
- struct drm_device *dev = encoder->base.dev;
- struct drm_i915_private *dev_priv = dev->dev_private;
- struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&encoder->base);
- int port = intel_hdmi->ddi_port;
- u32 temp;
-
- temp = I915_READ(DDI_BUF_CTL(port));
- temp &= ~DDI_BUF_CTL_ENABLE;
-
- I915_WRITE(DDI_BUF_CTL(port), temp);
+ I915_WRITE(DDI_BUF_CTL(port),
+ temp);
}
diff --git a/trunk/drivers/gpu/drm/i915/intel_display.c b/trunk/drivers/gpu/drm/i915/intel_display.c
index 6f5aafa1b633..bc2ad348e5d8 100644
--- a/trunk/drivers/gpu/drm/i915/intel_display.c
+++ b/trunk/drivers/gpu/drm/i915/intel_display.c
@@ -1006,7 +1006,7 @@ void intel_wait_for_pipe_off(struct drm_device *dev, int pipe)
/* Wait for the Pipe State to go off */
if (wait_for((I915_READ(reg) & I965_PIPECONF_ACTIVE) == 0,
100))
- WARN(1, "pipe_off wait timed out\n");
+ DRM_DEBUG_KMS("pipe_off wait timed out\n");
} else {
u32 last_line, line_mask;
int reg = PIPEDSL(pipe);
@@ -1024,7 +1024,7 @@ void intel_wait_for_pipe_off(struct drm_device *dev, int pipe)
} while (((I915_READ(reg) & line_mask) != last_line) &&
time_after(timeout, jiffies));
if (time_after(jiffies, timeout))
- WARN(1, "pipe_off wait timed out\n");
+ DRM_DEBUG_KMS("pipe_off wait timed out\n");
}
}
@@ -1431,8 +1431,6 @@ static void assert_pch_ports_disabled(struct drm_i915_private *dev_priv,
* protect mechanism may be enabled.
*
* Note! This is for pre-ILK only.
- *
- * Unfortunately needed by dvo_ns2501 since the dvo depends on it running.
*/
static void intel_enable_pll(struct drm_i915_private *dev_priv, enum pipe pipe)
{
@@ -1862,6 +1860,59 @@ static void intel_disable_plane(struct drm_i915_private *dev_priv,
intel_wait_for_vblank(dev_priv->dev, pipe);
}
+static void disable_pch_dp(struct drm_i915_private *dev_priv,
+ enum pipe pipe, int reg, u32 port_sel)
+{
+ u32 val = I915_READ(reg);
+ if (dp_pipe_enabled(dev_priv, pipe, port_sel, val)) {
+ DRM_DEBUG_KMS("Disabling pch dp %x on pipe %d\n", reg, pipe);
+ I915_WRITE(reg, val & ~DP_PORT_EN);
+ }
+}
+
+static void disable_pch_hdmi(struct drm_i915_private *dev_priv,
+ enum pipe pipe, int reg)
+{
+ u32 val = I915_READ(reg);
+ if (hdmi_pipe_enabled(dev_priv, pipe, val)) {
+ DRM_DEBUG_KMS("Disabling pch HDMI %x on pipe %d\n",
+ reg, pipe);
+ I915_WRITE(reg, val & ~PORT_ENABLE);
+ }
+}
+
+/* Disable any ports connected to this transcoder */
+static void intel_disable_pch_ports(struct drm_i915_private *dev_priv,
+ enum pipe pipe)
+{
+ u32 reg, val;
+
+ val = I915_READ(PCH_PP_CONTROL);
+ I915_WRITE(PCH_PP_CONTROL, val | PANEL_UNLOCK_REGS);
+
+ disable_pch_dp(dev_priv, pipe, PCH_DP_B, TRANS_DP_PORT_SEL_B);
+ disable_pch_dp(dev_priv, pipe, PCH_DP_C, TRANS_DP_PORT_SEL_C);
+ disable_pch_dp(dev_priv, pipe, PCH_DP_D, TRANS_DP_PORT_SEL_D);
+
+ reg = PCH_ADPA;
+ val = I915_READ(reg);
+ if (adpa_pipe_enabled(dev_priv, pipe, val))
+ I915_WRITE(reg, val & ~ADPA_DAC_ENABLE);
+
+ reg = PCH_LVDS;
+ val = I915_READ(reg);
+ if (lvds_pipe_enabled(dev_priv, pipe, val)) {
+ DRM_DEBUG_KMS("disable lvds on pipe %d val 0x%08x\n", pipe, val);
+ I915_WRITE(reg, val & ~LVDS_PORT_EN);
+ POSTING_READ(reg);
+ udelay(100);
+ }
+
+ disable_pch_hdmi(dev_priv, pipe, HDMIB);
+ disable_pch_hdmi(dev_priv, pipe, HDMIC);
+ disable_pch_hdmi(dev_priv, pipe, HDMID);
+}
+
int
intel_pin_and_fence_fb_obj(struct drm_device *dev,
struct drm_i915_gem_object *obj,
@@ -2150,17 +2201,16 @@ intel_finish_fb(struct drm_framebuffer *old_fb)
static int
intel_pipe_set_base(struct drm_crtc *crtc, int x, int y,
- struct drm_framebuffer *fb)
+ struct drm_framebuffer *old_fb)
{
struct drm_device *dev = crtc->dev;
struct drm_i915_private *dev_priv = dev->dev_private;
struct drm_i915_master_private *master_priv;
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
- struct drm_framebuffer *old_fb;
int ret;
/* no fb bound */
- if (!fb) {
+ if (!crtc->fb) {
DRM_ERROR("No FB bound\n");
return 0;
}
@@ -2174,7 +2224,7 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y,
mutex_lock(&dev->struct_mutex);
ret = intel_pin_and_fence_fb_obj(dev,
- to_intel_framebuffer(fb)->obj,
+ to_intel_framebuffer(crtc->fb)->obj,
NULL);
if (ret != 0) {
mutex_unlock(&dev->struct_mutex);
@@ -2182,22 +2232,17 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y,
return ret;
}
- if (crtc->fb)
- intel_finish_fb(crtc->fb);
+ if (old_fb)
+ intel_finish_fb(old_fb);
- ret = dev_priv->display.update_plane(crtc, fb, x, y);
+ ret = dev_priv->display.update_plane(crtc, crtc->fb, x, y);
if (ret) {
- intel_unpin_fb_obj(to_intel_framebuffer(fb)->obj);
+ intel_unpin_fb_obj(to_intel_framebuffer(crtc->fb)->obj);
mutex_unlock(&dev->struct_mutex);
DRM_ERROR("failed to update base address\n");
return ret;
}
- old_fb = crtc->fb;
- crtc->fb = fb;
- crtc->x = x;
- crtc->y = y;
-
if (old_fb) {
intel_wait_for_vblank(dev, intel_crtc->pipe);
intel_unpin_fb_obj(to_intel_framebuffer(old_fb)->obj);
@@ -2664,10 +2709,11 @@ static void ivb_manual_fdi_link_train(struct drm_crtc *crtc)
DRM_DEBUG_KMS("FDI train done.\n");
}
-static void ironlake_fdi_pll_enable(struct intel_crtc *intel_crtc)
+static void ironlake_fdi_pll_enable(struct drm_crtc *crtc)
{
- struct drm_device *dev = intel_crtc->base.dev;
+ 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 reg, temp;
@@ -2708,35 +2754,6 @@ static void ironlake_fdi_pll_enable(struct intel_crtc *intel_crtc)
}
}
-static void ironlake_fdi_pll_disable(struct intel_crtc *intel_crtc)
-{
- struct drm_device *dev = intel_crtc->base.dev;
- struct drm_i915_private *dev_priv = dev->dev_private;
- int pipe = intel_crtc->pipe;
- u32 reg, temp;
-
- /* Switch from PCDclk to Rawclk */
- reg = FDI_RX_CTL(pipe);
- temp = I915_READ(reg);
- I915_WRITE(reg, temp & ~FDI_PCDCLK);
-
- /* Disable CPU FDI TX PLL */
- reg = FDI_TX_CTL(pipe);
- temp = I915_READ(reg);
- I915_WRITE(reg, temp & ~FDI_TX_PLL_ENABLE);
-
- POSTING_READ(reg);
- udelay(100);
-
- reg = FDI_RX_CTL(pipe);
- temp = I915_READ(reg);
- I915_WRITE(reg, temp & ~FDI_RX_PLL_ENABLE);
-
- /* Wait for the clocks to turn off. */
- POSTING_READ(reg);
- udelay(100);
-}
-
static void cpt_phase_pointer_disable(struct drm_device *dev, int pipe)
{
struct drm_i915_private *dev_priv = dev->dev_private;
@@ -2821,13 +2838,13 @@ static void intel_crtc_wait_for_pending_flips(struct drm_crtc *crtc)
static bool intel_crtc_driving_pch(struct drm_crtc *crtc)
{
struct drm_device *dev = crtc->dev;
- struct intel_encoder *intel_encoder;
+ struct intel_encoder *encoder;
/*
* If there's a non-PCH eDP on this crtc, it must be DP_A, and that
* must be driven by its own crtc; no sharing is possible.
*/
- for_each_encoder_on_crtc(dev, crtc, intel_encoder) {
+ for_each_encoder_on_crtc(dev, crtc, encoder) {
/* On Haswell, LPT PCH handles the VGA connection via FDI, and Haswell
* CPU handles all others */
@@ -2835,19 +2852,19 @@ static bool intel_crtc_driving_pch(struct drm_crtc *crtc)
/* It is still unclear how this will work on PPT, so throw up a warning */
WARN_ON(!HAS_PCH_LPT(dev));
- if (intel_encoder->type == INTEL_OUTPUT_ANALOG) {
+ if (encoder->type == DRM_MODE_ENCODER_DAC) {
DRM_DEBUG_KMS("Haswell detected DAC encoder, assuming is PCH\n");
return true;
} else {
DRM_DEBUG_KMS("Haswell detected encoder %d, assuming is CPU\n",
- intel_encoder->type);
+ encoder->type);
return false;
}
}
- switch (intel_encoder->type) {
+ switch (encoder->type) {
case INTEL_OUTPUT_EDP:
- if (!intel_encoder_is_pch_edp(&intel_encoder->base))
+ if (!intel_encoder_is_pch_edp(&encoder->base))
return false;
continue;
}
@@ -3164,14 +3181,11 @@ static void ironlake_crtc_enable(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;
int plane = intel_crtc->plane;
u32 temp;
bool is_pch_port;
- WARN_ON(!crtc->enabled);
-
if (intel_crtc->active)
return;
@@ -3186,16 +3200,10 @@ static void ironlake_crtc_enable(struct drm_crtc *crtc)
is_pch_port = intel_crtc_driving_pch(crtc);
- if (is_pch_port) {
- ironlake_fdi_pll_enable(intel_crtc);
- } else {
- assert_fdi_tx_disabled(dev_priv, pipe);
- assert_fdi_rx_disabled(dev_priv, pipe);
- }
-
- for_each_encoder_on_crtc(dev, crtc, encoder)
- if (encoder->pre_enable)
- encoder->pre_enable(encoder);
+ if (is_pch_port)
+ ironlake_fdi_pll_enable(crtc);
+ else
+ ironlake_fdi_disable(crtc);
/* Enable panel fitting for LVDS */
if (dev_priv->pch_pf_size &&
@@ -3226,12 +3234,6 @@ static void ironlake_crtc_enable(struct drm_crtc *crtc)
mutex_unlock(&dev->struct_mutex);
intel_crtc_update_cursor(crtc, true);
-
- for_each_encoder_on_crtc(dev, crtc, encoder)
- encoder->enable(encoder);
-
- if (HAS_PCH_CPT(dev))
- intel_cpt_verify_modeset(dev, intel_crtc->pipe);
}
static void ironlake_crtc_disable(struct drm_crtc *crtc)
@@ -3239,18 +3241,13 @@ static void ironlake_crtc_disable(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;
int plane = intel_crtc->plane;
u32 reg, temp;
-
if (!intel_crtc->active)
return;
- for_each_encoder_on_crtc(dev, crtc, encoder)
- encoder->disable(encoder);
-
intel_crtc_wait_for_pending_flips(crtc);
drm_vblank_off(dev, pipe);
intel_crtc_update_cursor(crtc, false);
@@ -3266,12 +3263,15 @@ static void ironlake_crtc_disable(struct drm_crtc *crtc)
I915_WRITE(PF_CTL(pipe), 0);
I915_WRITE(PF_WIN_SZ(pipe), 0);
- for_each_encoder_on_crtc(dev, crtc, encoder)
- if (encoder->post_disable)
- encoder->post_disable(encoder);
-
ironlake_fdi_disable(crtc);
+ /* This is a horrible layering violation; we should be doing this in
+ * the connector/encoder ->prepare instead, but we don't always have
+ * enough information there about the config to know whether it will
+ * actually be necessary or just cause undesired flicker.
+ */
+ intel_disable_pch_ports(dev_priv, pipe);
+
intel_disable_transcoder(dev_priv, pipe);
if (HAS_PCH_CPT(dev)) {
@@ -3304,7 +3304,26 @@ static void ironlake_crtc_disable(struct drm_crtc *crtc)
/* disable PCH DPLL */
intel_disable_pch_pll(intel_crtc);
- ironlake_fdi_pll_disable(intel_crtc);
+ /* Switch from PCDclk to Rawclk */
+ reg = FDI_RX_CTL(pipe);
+ temp = I915_READ(reg);
+ I915_WRITE(reg, temp & ~FDI_PCDCLK);
+
+ /* Disable CPU FDI TX PLL */
+ reg = FDI_TX_CTL(pipe);
+ temp = I915_READ(reg);
+ I915_WRITE(reg, temp & ~FDI_TX_PLL_ENABLE);
+
+ POSTING_READ(reg);
+ udelay(100);
+
+ reg = FDI_RX_CTL(pipe);
+ temp = I915_READ(reg);
+ I915_WRITE(reg, temp & ~FDI_RX_PLL_ENABLE);
+
+ /* Wait for the clocks to turn off. */
+ POSTING_READ(reg);
+ udelay(100);
intel_crtc->active = false;
intel_update_watermarks(dev);
@@ -3314,6 +3333,30 @@ static void ironlake_crtc_disable(struct drm_crtc *crtc)
mutex_unlock(&dev->struct_mutex);
}
+static void ironlake_crtc_dpms(struct drm_crtc *crtc, int mode)
+{
+ struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+ int pipe = intel_crtc->pipe;
+ int plane = intel_crtc->plane;
+
+ /* XXX: When our outputs are all unaware of DPMS modes other than off
+ * and on, we should map those modes to DRM_MODE_DPMS_OFF in the CRTC.
+ */
+ switch (mode) {
+ case DRM_MODE_DPMS_ON:
+ case DRM_MODE_DPMS_STANDBY:
+ case DRM_MODE_DPMS_SUSPEND:
+ DRM_DEBUG_KMS("crtc %d/%d dpms on\n", pipe, plane);
+ ironlake_crtc_enable(crtc);
+ break;
+
+ case DRM_MODE_DPMS_OFF:
+ DRM_DEBUG_KMS("crtc %d/%d dpms off\n", pipe, plane);
+ ironlake_crtc_disable(crtc);
+ break;
+ }
+}
+
static void ironlake_crtc_off(struct drm_crtc *crtc)
{
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
@@ -3343,12 +3386,9 @@ static void i9xx_crtc_enable(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;
int plane = intel_crtc->plane;
- WARN_ON(!crtc->enabled);
-
if (intel_crtc->active)
return;
@@ -3365,9 +3405,6 @@ static void i9xx_crtc_enable(struct drm_crtc *crtc)
/* Give the overlay scaler a chance to enable if it's on this pipe */
intel_crtc_dpms_overlay(intel_crtc, true);
intel_crtc_update_cursor(crtc, true);
-
- for_each_encoder_on_crtc(dev, crtc, encoder)
- encoder->enable(encoder);
}
static void i9xx_crtc_disable(struct drm_crtc *crtc)
@@ -3375,17 +3412,12 @@ static void i9xx_crtc_disable(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;
int plane = intel_crtc->plane;
-
if (!intel_crtc->active)
return;
- for_each_encoder_on_crtc(dev, crtc, encoder)
- encoder->disable(encoder);
-
/* Give the overlay scaler a chance to disable if it's on this pipe */
intel_crtc_wait_for_pending_flips(crtc);
drm_vblank_off(dev, pipe);
@@ -3404,17 +3436,45 @@ static void i9xx_crtc_disable(struct drm_crtc *crtc)
intel_update_watermarks(dev);
}
+static void i9xx_crtc_dpms(struct drm_crtc *crtc, int mode)
+{
+ /* XXX: When our outputs are all unaware of DPMS modes other than off
+ * and on, we should map those modes to DRM_MODE_DPMS_OFF in the CRTC.
+ */
+ switch (mode) {
+ case DRM_MODE_DPMS_ON:
+ case DRM_MODE_DPMS_STANDBY:
+ case DRM_MODE_DPMS_SUSPEND:
+ i9xx_crtc_enable(crtc);
+ break;
+ case DRM_MODE_DPMS_OFF:
+ i9xx_crtc_disable(crtc);
+ break;
+ }
+}
+
static void i9xx_crtc_off(struct drm_crtc *crtc)
{
}
-static void intel_crtc_update_sarea(struct drm_crtc *crtc,
- bool enabled)
+/**
+ * Sets the power management mode of the pipe and plane.
+ */
+static void intel_crtc_dpms(struct drm_crtc *crtc, int mode)
{
struct drm_device *dev = crtc->dev;
+ struct drm_i915_private *dev_priv = dev->dev_private;
struct drm_i915_master_private *master_priv;
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
int pipe = intel_crtc->pipe;
+ bool enabled;
+
+ if (intel_crtc->dpms_mode == mode)
+ return;
+
+ intel_crtc->dpms_mode = mode;
+
+ dev_priv->display.dpms(crtc, mode);
if (!dev->primary->master)
return;
@@ -3423,6 +3483,8 @@ static void intel_crtc_update_sarea(struct drm_crtc *crtc,
if (!master_priv->sarea_priv)
return;
+ enabled = crtc->enabled && mode != DRM_MODE_DPMS_OFF;
+
switch (pipe) {
case 0:
master_priv->sarea_priv->pipeA_w = enabled ? crtc->mode.hdisplay : 0;
@@ -3438,42 +3500,13 @@ static void intel_crtc_update_sarea(struct drm_crtc *crtc,
}
}
-/**
- * Sets the power management mode of the pipe and plane.
- */
-void intel_crtc_update_dpms(struct drm_crtc *crtc)
-{
- struct drm_device *dev = crtc->dev;
- struct drm_i915_private *dev_priv = dev->dev_private;
- struct intel_encoder *intel_encoder;
- bool enable = false;
-
- for_each_encoder_on_crtc(dev, crtc, intel_encoder)
- enable |= intel_encoder->connectors_active;
-
- if (enable)
- dev_priv->display.crtc_enable(crtc);
- else
- dev_priv->display.crtc_disable(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_crtc_helper_funcs *crtc_funcs = crtc->helper_private;
struct drm_device *dev = crtc->dev;
- struct drm_connector *connector;
struct drm_i915_private *dev_priv = dev->dev_private;
- /* crtc should still be enabled when we disable it. */
- WARN_ON(!crtc->enabled);
-
- dev_priv->display.crtc_disable(crtc);
- intel_crtc_update_sarea(crtc, false);
+ crtc_funcs->dpms(crtc, DRM_MODE_DPMS_OFF);
dev_priv->display.off(crtc);
assert_plane_disabled(dev->dev_private, to_intel_crtc(crtc)->plane);
@@ -3483,128 +3516,63 @@ static void intel_crtc_disable(struct drm_crtc *crtc)
mutex_lock(&dev->struct_mutex);
intel_unpin_fb_obj(to_intel_framebuffer(crtc->fb)->obj);
mutex_unlock(&dev->struct_mutex);
- crtc->fb = NULL;
- }
-
- /* Update computed state. */
- list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
- if (!connector->encoder || !connector->encoder->crtc)
- continue;
-
- if (connector->encoder->crtc != crtc)
- continue;
-
- connector->dpms = DRM_MODE_DPMS_OFF;
- to_intel_encoder(connector->encoder)->connectors_active = false;
}
}
-void intel_modeset_disable(struct drm_device *dev)
+/* Prepare for a mode set.
+ *
+ * Note we could be a lot smarter here. We need to figure out which outputs
+ * will be enabled, which disabled (in short, how the config will changes)
+ * and perform the minimum necessary steps to accomplish that, e.g. updating
+ * watermarks, FBC configuration, making sure PLLs are programmed correctly,
+ * panel fitting is in the proper state, etc.
+ */
+static void i9xx_crtc_prepare(struct drm_crtc *crtc)
{
- struct drm_crtc *crtc;
-
- list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
- if (crtc->enabled)
- intel_crtc_disable(crtc);
- }
+ i9xx_crtc_disable(crtc);
}
-void intel_encoder_noop(struct drm_encoder *encoder)
+static void i9xx_crtc_commit(struct drm_crtc *crtc)
{
+ i9xx_crtc_enable(crtc);
}
-void intel_encoder_destroy(struct drm_encoder *encoder)
+static void ironlake_crtc_prepare(struct drm_crtc *crtc)
{
- struct intel_encoder *intel_encoder = to_intel_encoder(encoder);
-
- drm_encoder_cleanup(encoder);
- kfree(intel_encoder);
+ ironlake_crtc_disable(crtc);
}
-/* Simple dpms helper for encodres with just one connector, no cloning and only
- * one kind of off state. It clamps all !ON modes to fully OFF and changes the
- * state of the entire output pipe. */
-void intel_encoder_dpms(struct intel_encoder *encoder, int mode)
+static void ironlake_crtc_commit(struct drm_crtc *crtc)
{
- if (mode == DRM_MODE_DPMS_ON) {
- encoder->connectors_active = true;
-
- intel_crtc_update_dpms(encoder->base.crtc);
- } else {
- encoder->connectors_active = false;
-
- intel_crtc_update_dpms(encoder->base.crtc);
- }
+ ironlake_crtc_enable(crtc);
}
-/* Cross check the actual hw state with our own modeset state tracking (and it's
- * internal consistency). */
-static void intel_connector_check_state(struct intel_connector *connector)
+void intel_encoder_prepare(struct drm_encoder *encoder)
{
- if (connector->get_hw_state(connector)) {
- struct intel_encoder *encoder = connector->encoder;
- struct drm_crtc *crtc;
- bool encoder_enabled;
- enum pipe pipe;
-
- DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n",
- connector->base.base.id,
- drm_get_connector_name(&connector->base));
-
- WARN(connector->base.dpms == DRM_MODE_DPMS_OFF,
- "wrong connector dpms state\n");
- WARN(connector->base.encoder != &encoder->base,
- "active connector not linked to encoder\n");
- WARN(!encoder->connectors_active,
- "encoder->connectors_active not set\n");
-
- encoder_enabled = encoder->get_hw_state(encoder, &pipe);
- WARN(!encoder_enabled, "encoder not enabled\n");
- if (WARN_ON(!encoder->base.crtc))
- return;
-
- crtc = encoder->base.crtc;
-
- WARN(!crtc->enabled, "crtc not enabled\n");
- WARN(!to_intel_crtc(crtc)->active, "crtc not active\n");
- WARN(pipe != to_intel_crtc(crtc)->pipe,
- "encoder active on the wrong pipe\n");
- }
+ struct drm_encoder_helper_funcs *encoder_funcs = encoder->helper_private;
+ /* lvds has its own version of prepare see intel_lvds_prepare */
+ encoder_funcs->dpms(encoder, DRM_MODE_DPMS_OFF);
}
-/* Even simpler default implementation, if there's really no special case to
- * consider. */
-void intel_connector_dpms(struct drm_connector *connector, int mode)
+void intel_encoder_commit(struct drm_encoder *encoder)
{
- struct intel_encoder *encoder = intel_attached_encoder(connector);
-
- /* All the simple cases only support two dpms states. */
- if (mode != DRM_MODE_DPMS_ON)
- mode = DRM_MODE_DPMS_OFF;
-
- if (mode == connector->dpms)
- return;
-
- connector->dpms = mode;
+ struct drm_encoder_helper_funcs *encoder_funcs = encoder->helper_private;
+ struct drm_device *dev = encoder->dev;
+ struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc);
- /* Only need to change hw state when actually enabled */
- if (encoder->base.crtc)
- intel_encoder_dpms(encoder, mode);
- else
- WARN_ON(encoder->connectors_active != false);
+ /* lvds has its own version of commit see intel_lvds_commit */
+ encoder_funcs->dpms(encoder, DRM_MODE_DPMS_ON);
- intel_modeset_check_state(connector->dev);
+ if (HAS_PCH_CPT(dev))
+ intel_cpt_verify_modeset(dev, intel_crtc->pipe);
}
-/* Simple connector->get_hw_state implementation for encoders that support only
- * one connector and no cloning and hence the encoder state determines the state
- * of the connector. */
-bool intel_connector_get_hw_state(struct intel_connector *connector)
+void intel_encoder_destroy(struct drm_encoder *encoder)
{
- enum pipe pipe = 0;
- struct intel_encoder *encoder = connector->encoder;
+ struct intel_encoder *intel_encoder = to_intel_encoder(encoder);
- return encoder->get_hw_state(encoder, &pipe);
+ drm_encoder_cleanup(encoder);
+ kfree(intel_encoder);
}
static bool intel_crtc_mode_fixup(struct drm_crtc *crtc,
@@ -3625,13 +3593,6 @@ static bool intel_crtc_mode_fixup(struct drm_crtc *crtc,
if (!(adjusted_mode->private_flags & INTEL_MODE_CRTC_TIMINGS_SET))
drm_mode_set_crtcinfo(adjusted_mode, 0);
- /* WaPruneModeWithIncorrectHsyncOffset: Cantiga+ cannot handle modes
- * with a hsync front porch of 0.
- */
- if ((INTEL_INFO(dev)->gen > 4 || IS_G4X(dev)) &&
- adjusted_mode->hsync_start == adjusted_mode->hdisplay)
- return false;
-
return true;
}
@@ -3767,7 +3728,6 @@ static inline bool intel_panel_use_ssc(struct drm_i915_private *dev_priv)
* true if they don't match).
*/
static bool intel_choose_pipe_bpp_dither(struct drm_crtc *crtc,
- struct drm_framebuffer *fb,
unsigned int *pipe_bpp,
struct drm_display_mode *mode)
{
@@ -3837,7 +3797,7 @@ static bool intel_choose_pipe_bpp_dither(struct drm_crtc *crtc,
* also stays within the max display bpc discovered above.
*/
- switch (fb->depth) {
+ switch (crtc->fb->depth) {
case 8:
bpc = 8; /* since we go through a colormap */
break;
@@ -4231,6 +4191,12 @@ static void i8xx_update_pll(struct drm_crtc *crtc,
POSTING_READ(DPLL(pipe));
udelay(150);
+ I915_WRITE(DPLL(pipe), dpll);
+
+ /* Wait for the clocks to stabilize. */
+ 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.
@@ -4238,12 +4204,6 @@ static void i8xx_update_pll(struct drm_crtc *crtc,
if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS))
intel_update_lvds(crtc, clock, adjusted_mode);
- I915_WRITE(DPLL(pipe), dpll);
-
- /* Wait for the clocks to stabilize. */
- POSTING_READ(DPLL(pipe));
- udelay(150);
-
/* The pixel multiplier can only be updated once the
* DPLL is enabled and the clocks are stable.
*
@@ -4256,7 +4216,7 @@ static int i9xx_crtc_mode_set(struct drm_crtc *crtc,
struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode,
int x, int y,
- struct drm_framebuffer *fb)
+ struct drm_framebuffer *old_fb)
{
struct drm_device *dev = crtc->dev;
struct drm_i915_private *dev_priv = dev->dev_private;
@@ -4446,7 +4406,7 @@ static int i9xx_crtc_mode_set(struct drm_crtc *crtc,
I915_WRITE(DSPCNTR(plane), dspcntr);
POSTING_READ(DSPCNTR(plane));
- ret = intel_pipe_set_base(crtc, x, y, fb);
+ ret = intel_pipe_set_base(crtc, x, y, old_fb);
intel_update_watermarks(dev);
@@ -4600,130 +4560,24 @@ static int ironlake_get_refclk(struct drm_crtc *crtc)
return 120000;
}
-static void ironlake_set_pipeconf(struct drm_crtc *crtc,
+static int ironlake_crtc_mode_set(struct drm_crtc *crtc,
+ struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode,
- bool dither)
-{
- struct drm_i915_private *dev_priv = crtc->dev->dev_private;
- struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
- int pipe = intel_crtc->pipe;
- uint32_t val;
-
- val = I915_READ(PIPECONF(pipe));
-
- val &= ~PIPE_BPC_MASK;
- switch (intel_crtc->bpp) {
- case 18:
- val |= PIPE_6BPC;
- break;
- case 24:
- val |= PIPE_8BPC;
- break;
- case 30:
- val |= PIPE_10BPC;
- break;
- case 36:
- val |= PIPE_12BPC;
- break;
- default:
- val |= PIPE_8BPC;
- break;
- }
-
- val &= ~(PIPECONF_DITHER_EN | PIPECONF_DITHER_TYPE_MASK);
- if (dither)
- val |= (PIPECONF_DITHER_EN | PIPECONF_DITHER_TYPE_SP);
-
- val &= ~PIPECONF_INTERLACE_MASK;
- if (adjusted_mode->flags & DRM_MODE_FLAG_INTERLACE)
- val |= PIPECONF_INTERLACED_ILK;
- else
- val |= PIPECONF_PROGRESSIVE;
-
- I915_WRITE(PIPECONF(pipe), val);
- POSTING_READ(PIPECONF(pipe));
-}
-
-static bool ironlake_compute_clocks(struct drm_crtc *crtc,
- struct drm_display_mode *adjusted_mode,
- intel_clock_t *clock,
- bool *has_reduced_clock,
- intel_clock_t *reduced_clock)
+ int x, int y,
+ struct drm_framebuffer *old_fb)
{
struct drm_device *dev = crtc->dev;
struct drm_i915_private *dev_priv = dev->dev_private;
- struct intel_encoder *intel_encoder;
- int refclk;
+ struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+ int pipe = intel_crtc->pipe;
+ int plane = intel_crtc->plane;
+ int refclk, num_connectors = 0;
+ intel_clock_t clock, reduced_clock;
+ u32 dpll, fp = 0, fp2 = 0, dspcntr, pipeconf;
+ bool ok, has_reduced_clock = false, is_sdvo = false;
+ bool is_crt = false, is_lvds = false, is_tv = false, is_dp = false;
+ struct intel_encoder *encoder, *edp_encoder = NULL;
const intel_limit_t *limit;
- bool ret, is_sdvo = false, is_tv = false, is_lvds = false;
-
- for_each_encoder_on_crtc(dev, crtc, intel_encoder) {
- switch (intel_encoder->type) {
- case INTEL_OUTPUT_LVDS:
- is_lvds = true;
- break;
- case INTEL_OUTPUT_SDVO:
- case INTEL_OUTPUT_HDMI:
- is_sdvo = true;
- if (intel_encoder->needs_tv_clock)
- is_tv = true;
- break;
- case INTEL_OUTPUT_TVOUT:
- is_tv = true;
- break;
- }
- }
-
- refclk = ironlake_get_refclk(crtc);
-
- /*
- * Returns a set of divisors for the desired target clock with the given
- * refclk, or FALSE. The returned values represent the clock equation:
- * reflck * (5 * (m1 + 2) + (m2 + 2)) / (n + 2) / p1 / p2.
- */
- limit = intel_limit(crtc, refclk);
- ret = limit->find_pll(limit, crtc, adjusted_mode->clock, refclk, NULL,
- clock);
- if (!ret)
- return false;
-
- if (is_lvds && dev_priv->lvds_downclock_avail) {
- /*
- * Ensure we match the reduced clock's P to the target clock.
- * If the clocks don't match, we can't switch the display clock
- * by using the FP0/FP1. In such case we will disable the LVDS
- * downclock feature.
- */
- *has_reduced_clock = limit->find_pll(limit, crtc,
- dev_priv->lvds_downclock,
- refclk,
- clock,
- reduced_clock);
- }
-
- if (is_sdvo && is_tv)
- i9xx_adjust_sdvo_tv_clock(adjusted_mode, clock);
-
- return true;
-}
-
-static int ironlake_crtc_mode_set(struct drm_crtc *crtc,
- struct drm_display_mode *mode,
- struct drm_display_mode *adjusted_mode,
- int x, int y,
- struct drm_framebuffer *fb)
-{
- struct drm_device *dev = crtc->dev;
- struct drm_i915_private *dev_priv = dev->dev_private;
- struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
- int pipe = intel_crtc->pipe;
- int plane = intel_crtc->plane;
- int num_connectors = 0;
- intel_clock_t clock, reduced_clock;
- u32 dpll, fp = 0, fp2 = 0;
- bool ok, has_reduced_clock = false, is_sdvo = false;
- bool is_crt = false, is_lvds = false, is_tv = false, is_dp = false;
- struct intel_encoder *encoder, *edp_encoder = NULL;
int ret;
struct fdi_m_n m_n = {0};
u32 temp;
@@ -4765,8 +4619,16 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc,
num_connectors++;
}
- ok = ironlake_compute_clocks(crtc, adjusted_mode, &clock,
- &has_reduced_clock, &reduced_clock);
+ refclk = ironlake_get_refclk(crtc);
+
+ /*
+ * Returns a set of divisors for the desired target clock with the given
+ * refclk, or FALSE. The returned values represent the clock equation:
+ * reflck * (5 * (m1 + 2) + (m2 + 2)) / (n + 2) / p1 / p2.
+ */
+ limit = intel_limit(crtc, refclk);
+ ok = limit->find_pll(limit, crtc, adjusted_mode->clock, refclk, NULL,
+ &clock);
if (!ok) {
DRM_ERROR("Couldn't find PLL settings for mode!\n");
return -EINVAL;
@@ -4775,6 +4637,24 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc,
/* Ensure that the cursor is valid for the new mode before changing... */
intel_crtc_update_cursor(crtc, true);
+ if (is_lvds && dev_priv->lvds_downclock_avail) {
+ /*
+ * Ensure we match the reduced clock's P to the target clock.
+ * If the clocks don't match, we can't switch the display clock
+ * by using the FP0/FP1. In such case we will disable the LVDS
+ * downclock feature.
+ */
+ has_reduced_clock = limit->find_pll(limit, crtc,
+ dev_priv->lvds_downclock,
+ refclk,
+ &clock,
+ &reduced_clock);
+ }
+
+ if (is_sdvo && is_tv)
+ i9xx_adjust_sdvo_tv_clock(adjusted_mode, &clock);
+
+
/* FDI link */
pixel_multiplier = intel_mode_get_pixel_multiplier(adjusted_mode);
lane = 0;
@@ -4802,17 +4682,32 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc,
target_clock = adjusted_mode->clock;
/* determine panel color depth */
- dither = intel_choose_pipe_bpp_dither(crtc, fb, &pipe_bpp, mode);
- if (is_lvds && dev_priv->lvds_dither)
- dither = true;
-
- if (pipe_bpp != 18 && pipe_bpp != 24 && pipe_bpp != 30 &&
- pipe_bpp != 36) {
+ temp = I915_READ(PIPECONF(pipe));
+ temp &= ~PIPE_BPC_MASK;
+ dither = intel_choose_pipe_bpp_dither(crtc, &pipe_bpp, mode);
+ switch (pipe_bpp) {
+ case 18:
+ temp |= PIPE_6BPC;
+ break;
+ case 24:
+ temp |= PIPE_8BPC;
+ break;
+ case 30:
+ temp |= PIPE_10BPC;
+ break;
+ case 36:
+ temp |= PIPE_12BPC;
+ break;
+ default:
WARN(1, "intel_choose_pipe_bpp returned invalid value %d\n",
- pipe_bpp);
+ pipe_bpp);
+ temp |= PIPE_8BPC;
pipe_bpp = 24;
+ break;
}
+
intel_crtc->bpp = pipe_bpp;
+ I915_WRITE(PIPECONF(pipe), temp);
if (!lane) {
/*
@@ -4896,6 +4791,12 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc,
else
dpll |= PLL_REF_INPUT_DREFCLK;
+ /* setup pipeconf */
+ pipeconf = I915_READ(PIPECONF(pipe));
+
+ /* Set up the display plane register */
+ dspcntr = DISPPLANE_GAMMA_ENABLE;
+
DRM_DEBUG_KMS("Mode for pipe %d:\n", pipe);
drm_mode_debug_printmodeline(mode);
@@ -4955,6 +4856,12 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc,
I915_WRITE(PCH_LVDS, temp);
}
+ pipeconf &= ~PIPECONF_DITHER_EN;
+ pipeconf &= ~PIPECONF_DITHER_TYPE_MASK;
+ if ((is_lvds && dev_priv->lvds_dither) || dither) {
+ pipeconf |= PIPECONF_DITHER_EN;
+ pipeconf |= PIPECONF_DITHER_TYPE_SP;
+ }
if (is_dp && !is_cpu_edp) {
intel_dp_set_m_n(crtc, mode, adjusted_mode);
} else {
@@ -4990,7 +4897,9 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc,
}
}
+ pipeconf &= ~PIPECONF_INTERLACE_MASK;
if (adjusted_mode->flags & DRM_MODE_FLAG_INTERLACE) {
+ pipeconf |= PIPECONF_INTERLACED_ILK;
/* the chip adds 2 halflines automatically */
adjusted_mode->crtc_vtotal -= 1;
adjusted_mode->crtc_vblank_end -= 1;
@@ -4998,6 +4907,7 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc,
adjusted_mode->crtc_hsync_start
- adjusted_mode->crtc_htotal/2);
} else {
+ pipeconf |= PIPECONF_PROGRESSIVE;
I915_WRITE(VSYNCSHIFT(pipe), 0);
}
@@ -5035,15 +4945,15 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc,
if (is_cpu_edp)
ironlake_set_pll_edp(crtc, adjusted_mode->clock);
- ironlake_set_pipeconf(crtc, adjusted_mode, dither);
+ I915_WRITE(PIPECONF(pipe), pipeconf);
+ POSTING_READ(PIPECONF(pipe));
intel_wait_for_vblank(dev, pipe);
- /* Set up the display plane register */
- I915_WRITE(DSPCNTR(plane), DISPPLANE_GAMMA_ENABLE);
+ I915_WRITE(DSPCNTR(plane), dspcntr);
POSTING_READ(DSPCNTR(plane));
- ret = intel_pipe_set_base(crtc, x, y, fb);
+ ret = intel_pipe_set_base(crtc, x, y, old_fb);
intel_update_watermarks(dev);
@@ -5056,7 +4966,7 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode,
int x, int y,
- struct drm_framebuffer *fb)
+ struct drm_framebuffer *old_fb)
{
struct drm_device *dev = crtc->dev;
struct drm_i915_private *dev_priv = dev->dev_private;
@@ -5067,9 +4977,14 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
drm_vblank_pre_modeset(dev, pipe);
ret = dev_priv->display.crtc_mode_set(crtc, mode, adjusted_mode,
- x, y, fb);
+ x, y, old_fb);
drm_vblank_post_modeset(dev, pipe);
+ if (ret)
+ intel_crtc->dpms_mode = DRM_MODE_DPMS_OFF;
+ else
+ intel_crtc->dpms_mode = DRM_MODE_DPMS_ON;
+
return ret;
}
@@ -5142,91 +5057,6 @@ static void g4x_write_eld(struct drm_connector *connector,
I915_WRITE(G4X_AUD_CNTL_ST, i);
}
-static void haswell_write_eld(struct drm_connector *connector,
- struct drm_crtc *crtc)
-{
- struct drm_i915_private *dev_priv = connector->dev->dev_private;
- uint8_t *eld = connector->eld;
- struct drm_device *dev = crtc->dev;
- uint32_t eldv;
- uint32_t i;
- int len;
- int pipe = to_intel_crtc(crtc)->pipe;
- int tmp;
-
- int hdmiw_hdmiedid = HSW_AUD_EDID_DATA(pipe);
- int aud_cntl_st = HSW_AUD_DIP_ELD_CTRL(pipe);
- int aud_config = HSW_AUD_CFG(pipe);
- int aud_cntrl_st2 = HSW_AUD_PIN_ELD_CP_VLD;
-
-
- DRM_DEBUG_DRIVER("HDMI: Haswell Audio initialize....\n");
-
- /* Audio output enable */
- DRM_DEBUG_DRIVER("HDMI audio: enable codec\n");
- tmp = I915_READ(aud_cntrl_st2);
- tmp |= (AUDIO_OUTPUT_ENABLE_A << (pipe * 4));
- I915_WRITE(aud_cntrl_st2, tmp);
-
- /* Wait for 1 vertical blank */
- intel_wait_for_vblank(dev, pipe);
-
- /* Set ELD valid state */
- tmp = I915_READ(aud_cntrl_st2);
- DRM_DEBUG_DRIVER("HDMI audio: pin eld vld status=0x%8x\n", tmp);
- tmp |= (AUDIO_ELD_VALID_A << (pipe * 4));
- I915_WRITE(aud_cntrl_st2, tmp);
- tmp = I915_READ(aud_cntrl_st2);
- DRM_DEBUG_DRIVER("HDMI audio: eld vld status=0x%8x\n", tmp);
-
- /* Enable HDMI mode */
- tmp = I915_READ(aud_config);
- DRM_DEBUG_DRIVER("HDMI audio: audio conf: 0x%8x\n", tmp);
- /* clear N_programing_enable and N_value_index */
- tmp &= ~(AUD_CONFIG_N_VALUE_INDEX | AUD_CONFIG_N_PROG_ENABLE);
- I915_WRITE(aud_config, tmp);
-
- DRM_DEBUG_DRIVER("ELD on pipe %c\n", pipe_name(pipe));
-
- eldv = AUDIO_ELD_VALID_A << (pipe * 4);
-
- if (intel_pipe_has_type(crtc, INTEL_OUTPUT_DISPLAYPORT)) {
- DRM_DEBUG_DRIVER("ELD: DisplayPort detected\n");
- eld[5] |= (1 << 2); /* Conn_Type, 0x1 = DisplayPort */
- I915_WRITE(aud_config, AUD_CONFIG_N_VALUE_INDEX); /* 0x1 = DP */
- } else
- I915_WRITE(aud_config, 0);
-
- if (intel_eld_uptodate(connector,
- aud_cntrl_st2, eldv,
- aud_cntl_st, IBX_ELD_ADDRESS,
- hdmiw_hdmiedid))
- return;
-
- i = I915_READ(aud_cntrl_st2);
- i &= ~eldv;
- I915_WRITE(aud_cntrl_st2, i);
-
- if (!eld[0])
- return;
-
- i = I915_READ(aud_cntl_st);
- i &= ~IBX_ELD_ADDRESS;
- I915_WRITE(aud_cntl_st, i);
- i = (i >> 29) & DIP_PORT_SEL_MASK; /* DIP_Port_Select, 0x1 = PortB */
- DRM_DEBUG_DRIVER("port num:%d\n", i);
-
- len = min_t(uint8_t, eld[2], 21); /* 84 bytes of hw ELD buffer */
- DRM_DEBUG_DRIVER("ELD size %d\n", len);
- for (i = 0; i < len; i++)
- I915_WRITE(hdmiw_hdmiedid, *((uint32_t *)eld + i));
-
- i = I915_READ(aud_cntrl_st2);
- i |= eldv;
- I915_WRITE(aud_cntrl_st2, i);
-
-}
-
static void ironlake_write_eld(struct drm_connector *connector,
struct drm_crtc *crtc)
{
@@ -5239,24 +5069,28 @@ static void ironlake_write_eld(struct drm_connector *connector,
int aud_config;
int aud_cntl_st;
int aud_cntrl_st2;
- int pipe = to_intel_crtc(crtc)->pipe;
if (HAS_PCH_IBX(connector->dev)) {
- hdmiw_hdmiedid = IBX_HDMIW_HDMIEDID(pipe);
- aud_config = IBX_AUD_CFG(pipe);
- aud_cntl_st = IBX_AUD_CNTL_ST(pipe);
+ hdmiw_hdmiedid = IBX_HDMIW_HDMIEDID_A;
+ aud_config = IBX_AUD_CONFIG_A;
+ aud_cntl_st = IBX_AUD_CNTL_ST_A;
aud_cntrl_st2 = IBX_AUD_CNTL_ST2;
} else {
- hdmiw_hdmiedid = CPT_HDMIW_HDMIEDID(pipe);
- aud_config = CPT_AUD_CFG(pipe);
- aud_cntl_st = CPT_AUD_CNTL_ST(pipe);
+ hdmiw_hdmiedid = CPT_HDMIW_HDMIEDID_A;
+ aud_config = CPT_AUD_CONFIG_A;
+ aud_cntl_st = CPT_AUD_CNTL_ST_A;
aud_cntrl_st2 = CPT_AUD_CNTRL_ST2;
}
- DRM_DEBUG_DRIVER("ELD on pipe %c\n", pipe_name(pipe));
+ i = to_intel_crtc(crtc)->pipe;
+ hdmiw_hdmiedid += i * 0x100;
+ aud_cntl_st += i * 0x100;
+ aud_config += i * 0x100;
+
+ DRM_DEBUG_DRIVER("ELD on pipe %c\n", pipe_name(i));
i = I915_READ(aud_cntl_st);
- i = (i >> 29) & DIP_PORT_SEL_MASK; /* DIP_Port_Select, 0x1 = PortB */
+ i = (i >> 29) & 0x3; /* DIP_Port_Select, 0x1 = PortB */
if (!i) {
DRM_DEBUG_DRIVER("Audio directed to unknown port\n");
/* operate blindly on all ports */
@@ -5503,6 +5337,8 @@ static int intel_crtc_cursor_set(struct drm_crtc *crtc,
uint32_t addr;
int ret;
+ DRM_DEBUG_KMS("\n");
+
/* if we want to turn off the cursor ignore width and height */
if (!handle) {
DRM_DEBUG_KMS("cursor off\n");
@@ -5748,18 +5584,17 @@ mode_fits_in_fbdev(struct drm_device *dev,
return fb;
}
-bool intel_get_load_detect_pipe(struct drm_connector *connector,
+bool intel_get_load_detect_pipe(struct intel_encoder *intel_encoder,
+ struct drm_connector *connector,
struct drm_display_mode *mode,
struct intel_load_detect_pipe *old)
{
struct intel_crtc *intel_crtc;
- struct intel_encoder *intel_encoder =
- intel_attached_encoder(connector);
struct drm_crtc *possible_crtc;
struct drm_encoder *encoder = &intel_encoder->base;
struct drm_crtc *crtc = NULL;
struct drm_device *dev = encoder->dev;
- struct drm_framebuffer *fb;
+ struct drm_framebuffer *old_fb;
int i = -1;
DRM_DEBUG_KMS("[CONNECTOR:%d:%s], [ENCODER:%d:%s]\n",
@@ -5780,12 +5615,21 @@ bool intel_get_load_detect_pipe(struct drm_connector *connector,
if (encoder->crtc) {
crtc = encoder->crtc;
- old->dpms_mode = connector->dpms;
+ intel_crtc = to_intel_crtc(crtc);
+ old->dpms_mode = intel_crtc->dpms_mode;
old->load_detect_temp = false;
/* Make sure the crtc and connector are running */
- if (connector->dpms != DRM_MODE_DPMS_ON)
- connector->funcs->dpms(connector, DRM_MODE_DPMS_ON);
+ if (intel_crtc->dpms_mode != DRM_MODE_DPMS_ON) {
+ struct drm_encoder_helper_funcs *encoder_funcs;
+ struct drm_crtc_helper_funcs *crtc_funcs;
+
+ crtc_funcs = crtc->helper_private;
+ crtc_funcs->dpms(crtc, DRM_MODE_DPMS_ON);
+
+ encoder_funcs = encoder->helper_private;
+ encoder_funcs->dpms(encoder, DRM_MODE_DPMS_ON);
+ }
return true;
}
@@ -5809,17 +5653,19 @@ bool intel_get_load_detect_pipe(struct drm_connector *connector,
return false;
}
- intel_encoder->new_crtc = to_intel_crtc(crtc);
- to_intel_connector(connector)->new_encoder = intel_encoder;
+ encoder->crtc = crtc;
+ connector->encoder = encoder;
intel_crtc = to_intel_crtc(crtc);
- old->dpms_mode = connector->dpms;
+ old->dpms_mode = intel_crtc->dpms_mode;
old->load_detect_temp = true;
old->release_fb = NULL;
if (!mode)
mode = &load_detect_mode;
+ old_fb = crtc->fb;
+
/* We need a framebuffer large enough to accommodate all accesses
* that the plane may generate whilst we perform load detection.
* We can not rely on the fbcon either being present (we get called
@@ -5827,52 +5673,50 @@ bool intel_get_load_detect_pipe(struct drm_connector *connector,
* not even exist) or that it is large enough to satisfy the
* requested mode.
*/
- fb = mode_fits_in_fbdev(dev, mode);
- if (fb == NULL) {
+ crtc->fb = mode_fits_in_fbdev(dev, mode);
+ if (crtc->fb == NULL) {
DRM_DEBUG_KMS("creating tmp fb for load-detection\n");
- fb = intel_framebuffer_create_for_mode(dev, mode, 24, 32);
- old->release_fb = fb;
+ crtc->fb = intel_framebuffer_create_for_mode(dev, mode, 24, 32);
+ old->release_fb = crtc->fb;
} else
DRM_DEBUG_KMS("reusing fbdev for load-detection framebuffer\n");
- if (IS_ERR(fb)) {
+ if (IS_ERR(crtc->fb)) {
DRM_DEBUG_KMS("failed to allocate framebuffer for load-detection\n");
- goto fail;
+ crtc->fb = old_fb;
+ return false;
}
- if (!intel_set_mode(crtc, mode, 0, 0, fb)) {
+ if (!drm_crtc_helper_set_mode(crtc, mode, 0, 0, old_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);
- goto fail;
+ crtc->fb = old_fb;
+ return false;
}
/* let the connector get through one full cycle before testing */
intel_wait_for_vblank(dev, intel_crtc->pipe);
return true;
-fail:
- connector->encoder = NULL;
- encoder->crtc = NULL;
- return false;
}
-void intel_release_load_detect_pipe(struct drm_connector *connector,
+void intel_release_load_detect_pipe(struct intel_encoder *intel_encoder,
+ struct drm_connector *connector,
struct intel_load_detect_pipe *old)
{
- struct intel_encoder *intel_encoder =
- intel_attached_encoder(connector);
struct drm_encoder *encoder = &intel_encoder->base;
+ struct drm_device *dev = encoder->dev;
+ struct drm_crtc *crtc = encoder->crtc;
+ struct drm_encoder_helper_funcs *encoder_funcs = encoder->helper_private;
+ struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private;
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);
+ connector->encoder = NULL;
+ drm_helper_disable_unused_functions(dev);
if (old->release_fb)
old->release_fb->funcs->destroy(old->release_fb);
@@ -5881,8 +5725,10 @@ void intel_release_load_detect_pipe(struct drm_connector *connector,
}
/* Switch crtc and encoder back off if necessary */
- if (old->dpms_mode != DRM_MODE_DPMS_ON)
- connector->funcs->dpms(connector, old->dpms_mode);
+ if (old->dpms_mode != DRM_MODE_DPMS_ON) {
+ encoder_funcs->dpms(encoder, old->dpms_mode);
+ crtc_funcs->dpms(crtc, old->dpms_mode);
+ }
}
/* Returns the clock of the currently programmed mode of the given pipe. */
@@ -6004,6 +5850,46 @@ struct drm_display_mode *intel_crtc_mode_get(struct drm_device *dev,
return mode;
}
+#define GPU_IDLE_TIMEOUT 500 /* ms */
+
+/* When this timer fires, we've been idle for awhile */
+static void intel_gpu_idle_timer(unsigned long arg)
+{
+ struct drm_device *dev = (struct drm_device *)arg;
+ drm_i915_private_t *dev_priv = dev->dev_private;
+
+ if (!list_empty(&dev_priv->mm.active_list)) {
+ /* Still processing requests, so just re-arm the timer. */
+ mod_timer(&dev_priv->idle_timer, jiffies +
+ msecs_to_jiffies(GPU_IDLE_TIMEOUT));
+ return;
+ }
+
+ dev_priv->busy = false;
+ queue_work(dev_priv->wq, &dev_priv->idle_work);
+}
+
+#define CRTC_IDLE_TIMEOUT 1000 /* ms */
+
+static void intel_crtc_idle_timer(unsigned long arg)
+{
+ struct intel_crtc *intel_crtc = (struct intel_crtc *)arg;
+ struct drm_crtc *crtc = &intel_crtc->base;
+ drm_i915_private_t *dev_priv = crtc->dev->dev_private;
+ struct intel_framebuffer *intel_fb;
+
+ intel_fb = to_intel_framebuffer(crtc->fb);
+ if (intel_fb && intel_fb->obj->active) {
+ /* The framebuffer is still being accessed by the GPU. */
+ mod_timer(&intel_crtc->idle_timer, jiffies +
+ msecs_to_jiffies(CRTC_IDLE_TIMEOUT));
+ return;
+ }
+
+ intel_crtc->busy = false;
+ queue_work(dev_priv->wq, &dev_priv->idle_work);
+}
+
static void intel_increase_pllclock(struct drm_crtc *crtc)
{
struct drm_device *dev = crtc->dev;
@@ -6033,6 +5919,10 @@ static void intel_increase_pllclock(struct drm_crtc *crtc)
if (dpll & DISPLAY_RATE_SELECT_FPA1)
DRM_DEBUG_DRIVER("failed to upclock LVDS!\n");
}
+
+ /* Schedule downclock */
+ mod_timer(&intel_crtc->idle_timer, jiffies +
+ msecs_to_jiffies(CRTC_IDLE_TIMEOUT));
}
static void intel_decrease_pllclock(struct drm_crtc *crtc)
@@ -6071,46 +5961,89 @@ static void intel_decrease_pllclock(struct drm_crtc *crtc)
}
-void intel_mark_busy(struct drm_device *dev)
-{
- i915_update_gfx_val(dev->dev_private);
-}
-
-void intel_mark_idle(struct drm_device *dev)
-{
-}
-
-void intel_mark_fb_busy(struct drm_i915_gem_object *obj)
+/**
+ * intel_idle_update - adjust clocks for idleness
+ * @work: work struct
+ *
+ * Either the GPU or display (or both) went idle. Check the busy status
+ * here and adjust the CRTC and GPU clocks as necessary.
+ */
+static void intel_idle_update(struct work_struct *work)
{
- struct drm_device *dev = obj->base.dev;
+ drm_i915_private_t *dev_priv = container_of(work, drm_i915_private_t,
+ idle_work);
+ struct drm_device *dev = dev_priv->dev;
struct drm_crtc *crtc;
+ struct intel_crtc *intel_crtc;
if (!i915_powersave)
return;
+ mutex_lock(&dev->struct_mutex);
+
+ i915_update_gfx_val(dev_priv);
+
list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
+ /* Skip inactive CRTCs */
if (!crtc->fb)
continue;
- if (to_intel_framebuffer(crtc->fb)->obj == obj)
- intel_increase_pllclock(crtc);
+ intel_crtc = to_intel_crtc(crtc);
+ if (!intel_crtc->busy)
+ intel_decrease_pllclock(crtc);
}
+
+
+ mutex_unlock(&dev->struct_mutex);
}
-void intel_mark_fb_idle(struct drm_i915_gem_object *obj)
+/**
+ * intel_mark_busy - mark the GPU and possibly the display busy
+ * @dev: drm device
+ * @obj: object we're operating on
+ *
+ * Callers can use this function to indicate that the GPU is busy processing
+ * commands. If @obj matches one of the CRTC objects (i.e. it's a scanout
+ * buffer), we'll also mark the display as busy, so we know to increase its
+ * clock frequency.
+ */
+void intel_mark_busy(struct drm_device *dev, struct drm_i915_gem_object *obj)
{
- struct drm_device *dev = obj->base.dev;
- struct drm_crtc *crtc;
+ drm_i915_private_t *dev_priv = dev->dev_private;
+ struct drm_crtc *crtc = NULL;
+ struct intel_framebuffer *intel_fb;
+ struct intel_crtc *intel_crtc;
- if (!i915_powersave)
+ if (!drm_core_check_feature(dev, DRIVER_MODESET))
+ return;
+
+ if (!dev_priv->busy) {
+ intel_sanitize_pm(dev);
+ dev_priv->busy = true;
+ } else
+ mod_timer(&dev_priv->idle_timer, jiffies +
+ msecs_to_jiffies(GPU_IDLE_TIMEOUT));
+
+ if (obj == NULL)
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);
+ intel_crtc = to_intel_crtc(crtc);
+ intel_fb = to_intel_framebuffer(crtc->fb);
+ if (intel_fb->obj == obj) {
+ if (!intel_crtc->busy) {
+ /* Non-busy -> busy, upclock */
+ intel_increase_pllclock(crtc);
+ intel_crtc->busy = true;
+ } else {
+ /* Busy -> busy, put off timer */
+ mod_timer(&intel_crtc->idle_timer, jiffies +
+ msecs_to_jiffies(CRTC_IDLE_TIMEOUT));
+ }
+ }
}
}
@@ -6461,7 +6394,7 @@ static int intel_gen7_queue_flip(struct drm_device *dev,
default:
WARN_ONCE(1, "unknown plane in flip command\n");
ret = -ENODEV;
- goto err_unpin;
+ goto err;
}
ret = intel_ring_begin(ring, 4);
@@ -6569,7 +6502,7 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc,
goto cleanup_pending;
intel_disable_fbc(dev);
- intel_mark_fb_busy(obj);
+ intel_mark_busy(dev, obj);
mutex_unlock(&dev->struct_mutex);
trace_i915_flip_request(intel_crtc->plane, obj);
@@ -6594,807 +6527,81 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc,
return ret;
}
-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)
+static void intel_sanitize_modesetting(struct drm_device *dev,
+ int pipe, int plane)
{
- struct intel_encoder *other_encoder;
- struct drm_crtc *crtc = &encoder->new_crtc->base;
-
- if (WARN_ON(!crtc))
- return false;
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ u32 reg, val;
+ int i;
- list_for_each_entry(other_encoder,
- &crtc->dev->mode_config.encoder_list,
- base.head) {
-
- if (&other_encoder->new_crtc->base != crtc ||
- encoder == other_encoder)
- continue;
- else
- return true;
- }
-
- return false;
-}
-
-static bool intel_encoder_crtc_ok(struct drm_encoder *encoder,
- struct drm_crtc *crtc)
-{
- struct drm_device *dev;
- struct drm_crtc *tmp;
- int crtc_mask = 1;
-
- WARN(!crtc, "checking null crtc?\n");
-
- dev = crtc->dev;
-
- list_for_each_entry(tmp, &dev->mode_config.crtc_list, head) {
- if (tmp == crtc)
- break;
- crtc_mask <<= 1;
- }
-
- if (encoder->possible_crtcs & crtc_mask)
- return true;
- return false;
-}
-
-/**
- * intel_modeset_update_staged_output_state
- *
- * Updates the staged output configuration state, e.g. after we've read out the
- * current hw state.
- */
-static void intel_modeset_update_staged_output_state(struct drm_device *dev)
-{
- struct intel_encoder *encoder;
- struct intel_connector *connector;
-
- list_for_each_entry(connector, &dev->mode_config.connector_list,
- base.head) {
- connector->new_encoder =
- to_intel_encoder(connector->base.encoder);
- }
-
- list_for_each_entry(encoder, &dev->mode_config.encoder_list,
- base.head) {
- encoder->new_crtc =
- to_intel_crtc(encoder->base.crtc);
- }
-}
-
-/**
- * intel_modeset_commit_output_state
- *
- * This function copies the stage display pipe configuration to the real one.
- */
-static void intel_modeset_commit_output_state(struct drm_device *dev)
-{
- struct intel_encoder *encoder;
- struct intel_connector *connector;
-
- list_for_each_entry(connector, &dev->mode_config.connector_list,
- base.head) {
- connector->base.encoder = &connector->new_encoder->base;
- }
-
- list_for_each_entry(encoder, &dev->mode_config.encoder_list,
- base.head) {
- encoder->base.crtc = &encoder->new_crtc->base;
- }
-}
-
-static struct drm_display_mode *
-intel_modeset_adjusted_mode(struct drm_crtc *crtc,
- struct drm_display_mode *mode)
-{
- struct drm_device *dev = crtc->dev;
- struct drm_display_mode *adjusted_mode;
- struct drm_encoder_helper_funcs *encoder_funcs;
- struct intel_encoder *encoder;
-
- adjusted_mode = drm_mode_duplicate(dev, mode);
- if (!adjusted_mode)
- return ERR_PTR(-ENOMEM);
-
- /* Pass our mode to the connectors and the CRTC to give them a chance to
- * adjust it according to limitations or connector properties, and also
- * a chance to reject the mode entirely.
- */
- list_for_each_entry(encoder, &dev->mode_config.encoder_list,
- base.head) {
-
- if (&encoder->new_crtc->base != crtc)
- continue;
- encoder_funcs = encoder->base.helper_private;
- if (!(encoder_funcs->mode_fixup(&encoder->base, mode,
- adjusted_mode))) {
- DRM_DEBUG_KMS("Encoder fixup failed\n");
- goto fail;
- }
- }
-
- if (!(intel_crtc_mode_fixup(crtc, mode, adjusted_mode))) {
- DRM_DEBUG_KMS("CRTC fixup failed\n");
- goto fail;
- }
- DRM_DEBUG_KMS("[CRTC:%d]\n", crtc->base.id);
-
- return adjusted_mode;
-fail:
- drm_mode_destroy(dev, adjusted_mode);
- return ERR_PTR(-EINVAL);
-}
-
-/* Computes which crtcs are affected and sets the relevant bits in the mask. For
- * simplicity we use the crtc's pipe number (because it's easier to obtain). */
-static void
-intel_modeset_affected_pipes(struct drm_crtc *crtc, unsigned *modeset_pipes,
- unsigned *prepare_pipes, unsigned *disable_pipes)
-{
- struct intel_crtc *intel_crtc;
- struct drm_device *dev = crtc->dev;
- struct intel_encoder *encoder;
- struct intel_connector *connector;
- struct drm_crtc *tmp_crtc;
-
- *disable_pipes = *modeset_pipes = *prepare_pipes = 0;
-
- /* Check which crtcs have changed outputs connected to them, these need
- * to be part of the prepare_pipes mask. We don't (yet) support global
- * modeset across multiple crtcs, so modeset_pipes will only have one
- * bit set at most. */
- list_for_each_entry(connector, &dev->mode_config.connector_list,
- base.head) {
- if (connector->base.encoder == &connector->new_encoder->base)
- continue;
-
- if (connector->base.encoder) {
- tmp_crtc = connector->base.encoder->crtc;
-
- *prepare_pipes |= 1 << to_intel_crtc(tmp_crtc)->pipe;
- }
-
- if (connector->new_encoder)
- *prepare_pipes |=
- 1 << connector->new_encoder->new_crtc->pipe;
- }
-
- list_for_each_entry(encoder, &dev->mode_config.encoder_list,
- base.head) {
- if (encoder->base.crtc == &encoder->new_crtc->base)
- continue;
-
- if (encoder->base.crtc) {
- tmp_crtc = encoder->base.crtc;
-
- *prepare_pipes |= 1 << to_intel_crtc(tmp_crtc)->pipe;
- }
-
- if (encoder->new_crtc)
- *prepare_pipes |= 1 << encoder->new_crtc->pipe;
- }
-
- /* Check for any pipes that will be fully disabled ... */
- list_for_each_entry(intel_crtc, &dev->mode_config.crtc_list,
- base.head) {
- bool used = false;
-
- /* Don't try to disable disabled crtcs. */
- if (!intel_crtc->base.enabled)
- continue;
-
- list_for_each_entry(encoder, &dev->mode_config.encoder_list,
- base.head) {
- if (encoder->new_crtc == intel_crtc)
- used = true;
- }
-
- if (!used)
- *disable_pipes |= 1 << intel_crtc->pipe;
+ /* Clear any frame start delays used for debugging left by the BIOS */
+ for_each_pipe(i) {
+ reg = PIPECONF(i);
+ I915_WRITE(reg, I915_READ(reg) & ~PIPECONF_FRAME_START_DELAY_MASK);
}
+ if (HAS_PCH_SPLIT(dev))
+ return;
- /* set_mode is also used to update properties on life display pipes. */
- intel_crtc = to_intel_crtc(crtc);
- if (crtc->enabled)
- *prepare_pipes |= 1 << intel_crtc->pipe;
-
- /* We only support modeset on one single crtc, hence we need to do that
- * only for the passed in crtc iff we change anything else than just
- * disable crtcs.
+ /* Who knows what state these registers were left in by the BIOS or
+ * grub?
*
- * This is actually not true, to be fully compatible with the old crtc
- * helper we automatically disable _any_ output (i.e. doesn't need to be
- * connected to the crtc we're modesetting on) if it's disconnected.
- * Which is a rather nutty api (since changed the output configuration
- * without userspace's explicit request can lead to confusion), but
- * alas. Hence we currently need to modeset on all pipes we prepare. */
- if (*prepare_pipes)
- *modeset_pipes = *prepare_pipes;
-
- /* ... and mask these out. */
- *modeset_pipes &= ~(*disable_pipes);
- *prepare_pipes &= ~(*disable_pipes);
-}
-
-static bool intel_crtc_in_use(struct drm_crtc *crtc)
-{
- struct drm_encoder *encoder;
- struct drm_device *dev = crtc->dev;
-
- list_for_each_entry(encoder, &dev->mode_config.encoder_list, head)
- if (encoder->crtc == crtc)
- return true;
-
- return false;
-}
-
-static void
-intel_modeset_update_state(struct drm_device *dev, unsigned prepare_pipes)
-{
- struct intel_encoder *intel_encoder;
- struct intel_crtc *intel_crtc;
- struct drm_connector *connector;
-
- list_for_each_entry(intel_encoder, &dev->mode_config.encoder_list,
- base.head) {
- if (!intel_encoder->base.crtc)
- continue;
-
- intel_crtc = to_intel_crtc(intel_encoder->base.crtc);
-
- if (prepare_pipes & (1 << intel_crtc->pipe))
- intel_encoder->connectors_active = false;
- }
-
- intel_modeset_commit_output_state(dev);
-
- /* Update computed state. */
- list_for_each_entry(intel_crtc, &dev->mode_config.crtc_list,
- base.head) {
- intel_crtc->base.enabled = intel_crtc_in_use(&intel_crtc->base);
- }
-
- list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
- if (!connector->encoder || !connector->encoder->crtc)
- continue;
-
- intel_crtc = to_intel_crtc(connector->encoder->crtc);
-
- if (prepare_pipes & (1 << intel_crtc->pipe)) {
- struct drm_property *dpms_property =
- dev->mode_config.dpms_property;
-
- connector->dpms = DRM_MODE_DPMS_ON;
- drm_connector_property_set_value(connector,
- dpms_property,
- DRM_MODE_DPMS_ON);
-
- intel_encoder = to_intel_encoder(connector->encoder);
- intel_encoder->connectors_active = true;
- }
- }
-
-}
-
-#define for_each_intel_crtc_masked(dev, mask, intel_crtc) \
- list_for_each_entry((intel_crtc), \
- &(dev)->mode_config.crtc_list, \
- base.head) \
- if (mask & (1 <<(intel_crtc)->pipe)) \
-
-void
-intel_modeset_check_state(struct drm_device *dev)
-{
- struct intel_crtc *crtc;
- struct intel_encoder *encoder;
- struct intel_connector *connector;
-
- list_for_each_entry(connector, &dev->mode_config.connector_list,
- base.head) {
- /* This also checks the encoder/connector hw state with the
- * ->get_hw_state callbacks. */
- intel_connector_check_state(connector);
-
- WARN(&connector->new_encoder->base != connector->base.encoder,
- "connector's staged encoder doesn't match current encoder\n");
- }
-
- list_for_each_entry(encoder, &dev->mode_config.encoder_list,
- base.head) {
- bool enabled = false;
- bool active = false;
- enum pipe pipe, tracked_pipe;
-
- DRM_DEBUG_KMS("[ENCODER:%d:%s]\n",
- encoder->base.base.id,
- drm_get_encoder_name(&encoder->base));
-
- WARN(&encoder->new_crtc->base != encoder->base.crtc,
- "encoder's stage crtc doesn't match current crtc\n");
- WARN(encoder->connectors_active && !encoder->base.crtc,
- "encoder's active_connectors set, but no crtc\n");
-
- list_for_each_entry(connector, &dev->mode_config.connector_list,
- base.head) {
- if (connector->base.encoder != &encoder->base)
- continue;
- enabled = true;
- if (connector->base.dpms != DRM_MODE_DPMS_OFF)
- active = true;
- }
- WARN(!!encoder->base.crtc != enabled,
- "encoder's enabled state mismatch "
- "(expected %i, found %i)\n",
- !!encoder->base.crtc, enabled);
- WARN(active && !encoder->base.crtc,
- "active encoder with no crtc\n");
-
- WARN(encoder->connectors_active != active,
- "encoder's computed active state doesn't match tracked active state "
- "(expected %i, found %i)\n", active, encoder->connectors_active);
-
- active = encoder->get_hw_state(encoder, &pipe);
- WARN(active != encoder->connectors_active,
- "encoder's hw state doesn't match sw tracking "
- "(expected %i, found %i)\n",
- encoder->connectors_active, active);
-
- if (!encoder->base.crtc)
- continue;
-
- tracked_pipe = to_intel_crtc(encoder->base.crtc)->pipe;
- WARN(active && pipe != tracked_pipe,
- "active encoder's pipe doesn't match"
- "(expected %i, found %i)\n",
- tracked_pipe, pipe);
-
- }
-
- list_for_each_entry(crtc, &dev->mode_config.crtc_list,
- base.head) {
- bool enabled = false;
- bool active = false;
+ * If we leave the registers in a conflicting state (e.g. with the
+ * display plane reading from the other pipe than the one we intend
+ * to use) then when we attempt to teardown the active mode, we will
+ * not disable the pipes and planes in the correct order -- leaving
+ * a plane reading from a disabled pipe and possibly leading to
+ * undefined behaviour.
+ */
- DRM_DEBUG_KMS("[CRTC:%d]\n",
- crtc->base.base.id);
+ reg = DSPCNTR(plane);
+ val = I915_READ(reg);
- WARN(crtc->active && !crtc->base.enabled,
- "active crtc, but not enabled in sw tracking\n");
+ if ((val & DISPLAY_PLANE_ENABLE) == 0)
+ return;
+ if (!!(val & DISPPLANE_SEL_PIPE_MASK) == pipe)
+ return;
- list_for_each_entry(encoder, &dev->mode_config.encoder_list,
- base.head) {
- if (encoder->base.crtc != &crtc->base)
- continue;
- enabled = true;
- if (encoder->connectors_active)
- active = true;
- }
- WARN(active != crtc->active,
- "crtc's computed active state doesn't match tracked active state "
- "(expected %i, found %i)\n", active, crtc->active);
- WARN(enabled != crtc->base.enabled,
- "crtc's computed enabled state doesn't match tracked enabled state "
- "(expected %i, found %i)\n", enabled, crtc->base.enabled);
+ /* This display plane is active and attached to the other CPU pipe. */
+ pipe = !pipe;
- assert_pipe(dev->dev_private, crtc->pipe, crtc->active);
- }
+ /* Disable the plane and wait for it to stop reading from the pipe. */
+ intel_disable_plane(dev_priv, plane, pipe);
+ intel_disable_pipe(dev_priv, pipe);
}
-bool intel_set_mode(struct drm_crtc *crtc,
- struct drm_display_mode *mode,
- int x, int y, struct drm_framebuffer *fb)
+static void intel_crtc_reset(struct drm_crtc *crtc)
{
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_encoder_helper_funcs *encoder_funcs;
- struct drm_encoder *encoder;
- struct intel_crtc *intel_crtc;
- unsigned disable_pipes, prepare_pipes, modeset_pipes;
- bool ret = true;
-
- intel_modeset_affected_pipes(crtc, &modeset_pipes,
- &prepare_pipes, &disable_pipes);
-
- DRM_DEBUG_KMS("set mode pipe masks: modeset: %x, prepare: %x, disable: %x\n",
- modeset_pipes, prepare_pipes, disable_pipes);
-
- for_each_intel_crtc_masked(dev, disable_pipes, intel_crtc)
- intel_crtc_disable(&intel_crtc->base);
-
- 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.
- * Hence simply check whether any bit is set in modeset_pipes in all the
- * pieces of code that are not yet converted to deal with mutliple crtcs
- * changing their mode at the same time. */
- adjusted_mode = NULL;
- if (modeset_pipes) {
- adjusted_mode = intel_modeset_adjusted_mode(crtc, mode);
- if (IS_ERR(adjusted_mode)) {
- return false;
- }
- }
-
- for_each_intel_crtc_masked(dev, prepare_pipes, intel_crtc) {
- if (intel_crtc->base.enabled)
- dev_priv->display.crtc_disable(&intel_crtc->base);
- }
+ struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
- /* crtc->mode is already used by the ->mode_set callbacks, hence we need
- * to set it here already despite that we pass it down the callchain.
+ /* Reset flags back to the 'unknown' status so that they
+ * will be correctly set on the initial modeset.
*/
- if (modeset_pipes)
- crtc->mode = *mode;
-
- /* Only after disabling all output pipelines that will be changed can we
- * update the the output configuration. */
- intel_modeset_update_state(dev, prepare_pipes);
+ intel_crtc->dpms_mode = -1;
- /* Set up the DPLL and any encoders state that needs to adjust or depend
- * on the DPLL.
+ /* We need to fix up any BIOS configuration that conflicts with
+ * our expectations.
*/
- for_each_intel_crtc_masked(dev, modeset_pipes, intel_crtc) {
- ret = !intel_crtc_mode_set(&intel_crtc->base,
- mode, adjusted_mode,
- x, y, fb);
- if (!ret)
- goto done;
-
- list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
-
- if (encoder->crtc != &intel_crtc->base)
- continue;
-
- DRM_DEBUG_KMS("[ENCODER:%d:%s] set [MODE:%d:%s]\n",
- encoder->base.id, drm_get_encoder_name(encoder),
- mode->base.id, mode->name);
- encoder_funcs = encoder->helper_private;
- encoder_funcs->mode_set(encoder, mode, adjusted_mode);
- }
- }
-
- /* Now enable the clocks, plane, pipe, and connectors that we set up. */
- for_each_intel_crtc_masked(dev, prepare_pipes, intel_crtc)
- dev_priv->display.crtc_enable(&intel_crtc->base);
-
- if (modeset_pipes) {
- /* Store real post-adjustment hardware mode. */
- crtc->hwmode = *adjusted_mode;
-
- /* Calculate and store various constants which
- * are later needed by vblank and swap-completion
- * timestamping. They are derived from true hwmode.
- */
- drm_calc_timestamping_constants(crtc);
- }
-
- /* FIXME: add subpixel order */
-done:
- drm_mode_destroy(dev, adjusted_mode);
- if (!ret && crtc->enabled) {
- crtc->hwmode = saved_hwmode;
- crtc->mode = saved_mode;
- } else {
- intel_modeset_check_state(dev);
- }
-
- return ret;
-}
-
-#undef for_each_intel_crtc_masked
-
-static void intel_set_config_free(struct intel_set_config *config)
-{
- if (!config)
- return;
-
- kfree(config->save_connector_encoders);
- kfree(config->save_encoder_crtcs);
- kfree(config);
+ intel_sanitize_modesetting(dev, intel_crtc->pipe, intel_crtc->plane);
}
-static int intel_set_config_save_state(struct drm_device *dev,
- struct intel_set_config *config)
-{
- struct drm_encoder *encoder;
- struct drm_connector *connector;
- int count;
-
- config->save_encoder_crtcs =
- kcalloc(dev->mode_config.num_encoder,
- sizeof(struct drm_crtc *), GFP_KERNEL);
- if (!config->save_encoder_crtcs)
- return -ENOMEM;
-
- config->save_connector_encoders =
- kcalloc(dev->mode_config.num_connector,
- sizeof(struct drm_encoder *), GFP_KERNEL);
- if (!config->save_connector_encoders)
- return -ENOMEM;
-
- /* Copy data. Note that driver private data is not affected.
- * Should anything bad happen only the expected state is
- * restored, not the drivers personal bookkeeping.
- */
- count = 0;
- list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
- config->save_encoder_crtcs[count++] = encoder->crtc;
- }
-
- count = 0;
- list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
- config->save_connector_encoders[count++] = connector->encoder;
- }
-
- return 0;
-}
-
-static void intel_set_config_restore_state(struct drm_device *dev,
- struct intel_set_config *config)
-{
- struct intel_encoder *encoder;
- struct intel_connector *connector;
- int count;
-
- count = 0;
- list_for_each_entry(encoder, &dev->mode_config.encoder_list, base.head) {
- encoder->new_crtc =
- to_intel_crtc(config->save_encoder_crtcs[count++]);
- }
-
- count = 0;
- list_for_each_entry(connector, &dev->mode_config.connector_list, base.head) {
- connector->new_encoder =
- to_intel_encoder(config->save_connector_encoders[count++]);
- }
-}
-
-static void
-intel_set_config_compute_mode_changes(struct drm_mode_set *set,
- struct intel_set_config *config)
-{
-
- /* We should be able to check here if the fb has the same properties
- * and then just flip_or_move it */
- if (set->crtc->fb != set->fb) {
- /* If we have no fb then treat it as a full mode set */
- if (set->crtc->fb == NULL) {
- DRM_DEBUG_KMS("crtc has no fb, full mode set\n");
- config->mode_changed = true;
- } else if (set->fb == NULL) {
- config->mode_changed = true;
- } else if (set->fb->depth != set->crtc->fb->depth) {
- config->mode_changed = true;
- } else if (set->fb->bits_per_pixel !=
- set->crtc->fb->bits_per_pixel) {
- config->mode_changed = true;
- } else
- config->fb_changed = true;
- }
-
- if (set->fb && (set->x != set->crtc->x || set->y != set->crtc->y))
- config->fb_changed = true;
-
- if (set->mode && !drm_mode_equal(set->mode, &set->crtc->mode)) {
- DRM_DEBUG_KMS("modes are different, full mode set\n");
- drm_mode_debug_printmodeline(&set->crtc->mode);
- drm_mode_debug_printmodeline(set->mode);
- config->mode_changed = true;
- }
-}
-
-static int
-intel_modeset_stage_output_state(struct drm_device *dev,
- struct drm_mode_set *set,
- struct intel_set_config *config)
-{
- struct drm_crtc *new_crtc;
- struct intel_connector *connector;
- struct intel_encoder *encoder;
- int count, ro;
-
- /* The upper layers ensure that we either disabl 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));
-
- count = 0;
- list_for_each_entry(connector, &dev->mode_config.connector_list,
- base.head) {
- /* Otherwise traverse passed in connector list and get encoders
- * for them. */
- for (ro = 0; ro < set->num_connectors; ro++) {
- if (set->connectors[ro] == &connector->base) {
- connector->new_encoder = connector->encoder;
- break;
- }
- }
-
- /* If we disable the crtc, disable all its connectors. Also, if
- * the connector is on the changing crtc but not on the new
- * connector list, disable it. */
- if ((!set->fb || ro == set->num_connectors) &&
- connector->base.encoder &&
- connector->base.encoder->crtc == set->crtc) {
- connector->new_encoder = NULL;
-
- DRM_DEBUG_KMS("[CONNECTOR:%d:%s] to [NOCRTC]\n",
- connector->base.base.id,
- drm_get_connector_name(&connector->base));
- }
-
-
- if (&connector->new_encoder->base != connector->base.encoder) {
- DRM_DEBUG_KMS("encoder changed, full mode switch\n");
- config->mode_changed = true;
- }
-
- /* Disable all disconnected encoders. */
- if (connector->base.status == connector_status_disconnected)
- connector->new_encoder = NULL;
- }
- /* connector->new_encoder is now updated for all connectors. */
-
- /* Update crtc of enabled connectors. */
- count = 0;
- list_for_each_entry(connector, &dev->mode_config.connector_list,
- base.head) {
- if (!connector->new_encoder)
- continue;
-
- new_crtc = connector->new_encoder->base.crtc;
-
- for (ro = 0; ro < set->num_connectors; ro++) {
- if (set->connectors[ro] == &connector->base)
- new_crtc = set->crtc;
- }
-
- /* Make sure the new CRTC will work with the encoder */
- if (!intel_encoder_crtc_ok(&connector->new_encoder->base,
- new_crtc)) {
- return -EINVAL;
- }
- connector->encoder->new_crtc = to_intel_crtc(new_crtc);
-
- DRM_DEBUG_KMS("[CONNECTOR:%d:%s] to [CRTC:%d]\n",
- connector->base.base.id,
- drm_get_connector_name(&connector->base),
- new_crtc->base.id);
- }
-
- /* Check for any encoders that needs to be disabled. */
- list_for_each_entry(encoder, &dev->mode_config.encoder_list,
- base.head) {
- list_for_each_entry(connector,
- &dev->mode_config.connector_list,
- base.head) {
- if (connector->new_encoder == encoder) {
- WARN_ON(!connector->new_encoder->new_crtc);
-
- goto next_encoder;
- }
- }
- encoder->new_crtc = NULL;
-next_encoder:
- /* Only now check for crtc changes so we don't miss encoders
- * that will be disabled. */
- if (&encoder->new_crtc->base != encoder->base.crtc) {
- DRM_DEBUG_KMS("crtc changed, full mode switch\n");
- config->mode_changed = true;
- }
- }
- /* Now we've also updated encoder->new_crtc for all encoders. */
-
- return 0;
-}
-
-static int intel_crtc_set_config(struct drm_mode_set *set)
-{
- struct drm_device *dev;
- struct drm_mode_set save_set;
- struct intel_set_config *config;
- int ret;
-
- BUG_ON(!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;
-
- if (set->fb) {
- DRM_DEBUG_KMS("[CRTC:%d] [FB:%d] #connectors=%d (x y) (%i %i)\n",
- set->crtc->base.id, set->fb->base.id,
- (int)set->num_connectors, set->x, set->y);
- } else {
- DRM_DEBUG_KMS("[CRTC:%d] [NOFB]\n", set->crtc->base.id);
- }
-
- dev = set->crtc->dev;
-
- ret = -ENOMEM;
- config = kzalloc(sizeof(*config), GFP_KERNEL);
- if (!config)
- goto out_config;
-
- ret = intel_set_config_save_state(dev, config);
- if (ret)
- goto out_config;
-
- save_set.crtc = set->crtc;
- save_set.mode = &set->crtc->mode;
- save_set.x = set->crtc->x;
- save_set.y = set->crtc->y;
- save_set.fb = set->crtc->fb;
-
- /* Compute whether we need a full modeset, only an fb base update or no
- * change at all. In the future we might also check whether only the
- * mode changed, e.g. for LVDS where we only change the panel fitter in
- * such cases. */
- intel_set_config_compute_mode_changes(set, config);
-
- ret = intel_modeset_stage_output_state(dev, set, config);
- if (ret)
- goto fail;
-
- if (config->mode_changed) {
- if (set->mode) {
- DRM_DEBUG_KMS("attempting to set mode from"
- " userspace\n");
- 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;
- goto fail;
- }
- } else if (config->fb_changed) {
- ret = intel_pipe_set_base(set->crtc,
- set->x, set->y, set->fb);
- }
-
- intel_set_config_free(config);
-
- return 0;
-
-fail:
- intel_set_config_restore_state(dev, config);
-
- /* Try to restore the config */
- if (config->mode_changed &&
- !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");
-
-out_config:
- intel_set_config_free(config);
- return ret;
-}
+static struct drm_crtc_helper_funcs intel_helper_funcs = {
+ .dpms = intel_crtc_dpms,
+ .mode_fixup = intel_crtc_mode_fixup,
+ .mode_set = intel_crtc_mode_set,
+ .mode_set_base = intel_pipe_set_base,
+ .mode_set_base_atomic = intel_pipe_set_base_atomic,
+ .load_lut = intel_crtc_load_lut,
+ .disable = intel_crtc_disable,
+};
static const struct drm_crtc_funcs intel_crtc_funcs = {
+ .reset = intel_crtc_reset,
.cursor_set = intel_crtc_cursor_set,
.cursor_move = intel_crtc_cursor_move,
.gamma_set = intel_crtc_gamma_set,
- .set_config = intel_crtc_set_config,
+ .set_config = drm_crtc_helper_set_config,
.destroy = intel_crtc_destroy,
.page_flip = intel_crtc_page_flip,
};
@@ -7448,9 +6655,24 @@ static void intel_crtc_init(struct drm_device *dev, int pipe)
dev_priv->plane_to_crtc_mapping[intel_crtc->plane] = &intel_crtc->base;
dev_priv->pipe_to_crtc_mapping[intel_crtc->pipe] = &intel_crtc->base;
+ intel_crtc_reset(&intel_crtc->base);
+ intel_crtc->active = true; /* force the pipe off on setup_init_config */
intel_crtc->bpp = 24; /* default for pre-Ironlake */
+ if (HAS_PCH_SPLIT(dev)) {
+ intel_helper_funcs.prepare = ironlake_crtc_prepare;
+ intel_helper_funcs.commit = ironlake_crtc_commit;
+ } else {
+ intel_helper_funcs.prepare = i9xx_crtc_prepare;
+ intel_helper_funcs.commit = i9xx_crtc_commit;
+ }
+
drm_crtc_helper_add(&intel_crtc->base, &intel_helper_funcs);
+
+ intel_crtc->busy = false;
+
+ setup_timer(&intel_crtc->idle_timer, intel_crtc_idle_timer,
+ (unsigned long)intel_crtc);
}
int intel_get_pipe_from_crtc_id(struct drm_device *dev, void *data,
@@ -7477,23 +6699,15 @@ int intel_get_pipe_from_crtc_id(struct drm_device *dev, void *data,
return 0;
}
-static int intel_encoder_clones(struct intel_encoder *encoder)
+static int intel_encoder_clones(struct drm_device *dev, int type_mask)
{
- struct drm_device *dev = encoder->base.dev;
- struct intel_encoder *source_encoder;
+ struct intel_encoder *encoder;
int index_mask = 0;
int entry = 0;
- list_for_each_entry(source_encoder,
- &dev->mode_config.encoder_list, base.head) {
-
- if (encoder == source_encoder)
- index_mask |= (1 << entry);
-
- /* Intel hw has only one MUX where enocoders could be cloned. */
- if (encoder->cloneable && source_encoder->cloneable)
+ list_for_each_entry(encoder, &dev->mode_config.encoder_list, base.head) {
+ if (type_mask & encoder->clone_mask)
index_mask |= (1 << entry);
-
entry++;
}
@@ -7534,10 +6748,10 @@ static void intel_setup_outputs(struct drm_device *dev)
dpd_is_edp = intel_dpd_is_edp(dev);
if (has_edp_a(dev))
- intel_dp_init(dev, DP_A, PORT_A);
+ intel_dp_init(dev, DP_A);
if (dpd_is_edp && (I915_READ(PCH_DP_D) & DP_DETECTED))
- intel_dp_init(dev, PCH_DP_D, PORT_D);
+ intel_dp_init(dev, PCH_DP_D);
}
intel_crt_init(dev);
@@ -7568,22 +6782,22 @@ static void intel_setup_outputs(struct drm_device *dev)
/* PCH SDVOB multiplex with HDMIB */
found = intel_sdvo_init(dev, PCH_SDVOB, true);
if (!found)
- intel_hdmi_init(dev, HDMIB, PORT_B);
+ intel_hdmi_init(dev, HDMIB);
if (!found && (I915_READ(PCH_DP_B) & DP_DETECTED))
- intel_dp_init(dev, PCH_DP_B, PORT_B);
+ intel_dp_init(dev, PCH_DP_B);
}
if (I915_READ(HDMIC) & PORT_DETECTED)
- intel_hdmi_init(dev, HDMIC, PORT_C);
+ intel_hdmi_init(dev, HDMIC);
if (!dpd_is_edp && I915_READ(HDMID) & PORT_DETECTED)
- intel_hdmi_init(dev, HDMID, PORT_D);
+ intel_hdmi_init(dev, HDMID);
if (I915_READ(PCH_DP_C) & DP_DETECTED)
- intel_dp_init(dev, PCH_DP_C, PORT_C);
+ intel_dp_init(dev, PCH_DP_C);
if (!dpd_is_edp && (I915_READ(PCH_DP_D) & DP_DETECTED))
- intel_dp_init(dev, PCH_DP_D, PORT_D);
+ intel_dp_init(dev, PCH_DP_D);
} else if (IS_VALLEYVIEW(dev)) {
int found;
@@ -7591,17 +6805,17 @@ static void intel_setup_outputs(struct drm_device *dev)
/* SDVOB multiplex with HDMIB */
found = intel_sdvo_init(dev, SDVOB, true);
if (!found)
- intel_hdmi_init(dev, SDVOB, PORT_B);
+ intel_hdmi_init(dev, SDVOB);
if (!found && (I915_READ(DP_B) & DP_DETECTED))
- intel_dp_init(dev, DP_B, PORT_B);
+ intel_dp_init(dev, DP_B);
}
if (I915_READ(SDVOC) & PORT_DETECTED)
- intel_hdmi_init(dev, SDVOC, PORT_C);
+ intel_hdmi_init(dev, SDVOC);
/* Shares lanes with HDMI on SDVOC */
if (I915_READ(DP_C) & DP_DETECTED)
- intel_dp_init(dev, DP_C, PORT_C);
+ intel_dp_init(dev, DP_C);
} else if (SUPPORTS_DIGITAL_OUTPUTS(dev)) {
bool found = false;
@@ -7610,12 +6824,12 @@ static void intel_setup_outputs(struct drm_device *dev)
found = intel_sdvo_init(dev, SDVOB, true);
if (!found && SUPPORTS_INTEGRATED_HDMI(dev)) {
DRM_DEBUG_KMS("probing HDMI on SDVOB\n");
- intel_hdmi_init(dev, SDVOB, PORT_B);
+ intel_hdmi_init(dev, SDVOB);
}
if (!found && SUPPORTS_INTEGRATED_DP(dev)) {
DRM_DEBUG_KMS("probing DP_B\n");
- intel_dp_init(dev, DP_B, PORT_B);
+ intel_dp_init(dev, DP_B);
}
}
@@ -7630,18 +6844,18 @@ static void intel_setup_outputs(struct drm_device *dev)
if (SUPPORTS_INTEGRATED_HDMI(dev)) {
DRM_DEBUG_KMS("probing HDMI on SDVOC\n");
- intel_hdmi_init(dev, SDVOC, PORT_C);
+ intel_hdmi_init(dev, SDVOC);
}
if (SUPPORTS_INTEGRATED_DP(dev)) {
DRM_DEBUG_KMS("probing DP_C\n");
- intel_dp_init(dev, DP_C, PORT_C);
+ intel_dp_init(dev, DP_C);
}
}
if (SUPPORTS_INTEGRATED_DP(dev) &&
(I915_READ(DP_D) & DP_DETECTED)) {
DRM_DEBUG_KMS("probing DP_D\n");
- intel_dp_init(dev, DP_D, PORT_D);
+ intel_dp_init(dev, DP_D);
}
} else if (IS_GEN2(dev))
intel_dvo_init(dev);
@@ -7652,9 +6866,12 @@ static void intel_setup_outputs(struct drm_device *dev)
list_for_each_entry(encoder, &dev->mode_config.encoder_list, base.head) {
encoder->base.possible_crtcs = encoder->crtc_mask;
encoder->base.possible_clones =
- intel_encoder_clones(encoder);
+ intel_encoder_clones(dev, encoder->clone_mask);
}
+ /* disable all the possible outputs/crtcs before entering KMS mode */
+ drm_helper_disable_unused_functions(dev);
+
if (HAS_PCH_IBX(dev) || HAS_PCH_CPT(dev))
ironlake_init_pch_refclk(dev);
}
@@ -7756,15 +6973,13 @@ static void intel_init_display(struct drm_device *dev)
/* We always want a DPMS function */
if (HAS_PCH_SPLIT(dev)) {
+ dev_priv->display.dpms = ironlake_crtc_dpms;
dev_priv->display.crtc_mode_set = ironlake_crtc_mode_set;
- dev_priv->display.crtc_enable = ironlake_crtc_enable;
- dev_priv->display.crtc_disable = ironlake_crtc_disable;
dev_priv->display.off = ironlake_crtc_off;
dev_priv->display.update_plane = ironlake_update_plane;
} else {
+ dev_priv->display.dpms = i9xx_crtc_dpms;
dev_priv->display.crtc_mode_set = i9xx_crtc_mode_set;
- dev_priv->display.crtc_enable = i9xx_crtc_enable;
- dev_priv->display.crtc_disable = i9xx_crtc_disable;
dev_priv->display.off = i9xx_crtc_off;
dev_priv->display.update_plane = i9xx_update_plane;
}
@@ -7808,7 +7023,7 @@ static void intel_init_display(struct drm_device *dev)
dev_priv->display.write_eld = ironlake_write_eld;
} else if (IS_HASWELL(dev)) {
dev_priv->display.fdi_link_train = hsw_fdi_link_train;
- dev_priv->display.write_eld = haswell_write_eld;
+ dev_priv->display.write_eld = ironlake_write_eld;
} else
dev_priv->display.update_wm = NULL;
} else if (IS_G4X(dev)) {
@@ -7886,16 +7101,21 @@ static struct intel_quirk intel_quirks[] = {
/* HP Mini needs pipe A force quirk (LP: #322104) */
{ 0x27ae, 0x103c, 0x361a, quirk_pipea_force },
+ /* Thinkpad R31 needs pipe A force quirk */
+ { 0x3577, 0x1014, 0x0505, quirk_pipea_force },
/* Toshiba Protege R-205, S-209 needs pipe A force quirk */
{ 0x2592, 0x1179, 0x0001, quirk_pipea_force },
+ /* ThinkPad X30 needs pipe A force quirk (LP: #304614) */
+ { 0x3577, 0x1014, 0x0513, quirk_pipea_force },
+ /* ThinkPad X40 needs pipe A force quirk */
+
/* ThinkPad T60 needs pipe A force quirk (bug #16494) */
{ 0x2782, 0x17aa, 0x201a, quirk_pipea_force },
/* 855 & before need to leave pipe A & dpll A up */
{ 0x3582, PCI_ANY_ID, PCI_ANY_ID, quirk_pipea_force },
{ 0x2562, PCI_ANY_ID, PCI_ANY_ID, quirk_pipea_force },
- { 0x3577, PCI_ANY_ID, PCI_ANY_ID, quirk_pipea_force },
/* Lenovo U160 cannot use SSC on LVDS */
{ 0x0046, 0x17aa, 0x3920, quirk_ssc_force_disable },
@@ -8011,251 +7231,10 @@ void intel_modeset_init(struct drm_device *dev)
/* Just disable it once at startup */
i915_disable_vga(dev);
intel_setup_outputs(dev);
-}
-
-static void
-intel_connector_break_all_links(struct intel_connector *connector)
-{
- connector->base.dpms = DRM_MODE_DPMS_OFF;
- connector->base.encoder = NULL;
- connector->encoder->connectors_active = false;
- connector->encoder->base.crtc = NULL;
-}
-
-static void intel_enable_pipe_a(struct drm_device *dev)
-{
- struct intel_connector *connector;
- struct drm_connector *crt = NULL;
- struct intel_load_detect_pipe load_detect_temp;
-
- /* We can't just switch on the pipe A, we need to set things up with a
- * proper mode and output configuration. As a gross hack, enable pipe A
- * by enabling the load detect pipe once. */
- list_for_each_entry(connector,
- &dev->mode_config.connector_list,
- base.head) {
- if (connector->encoder->type == INTEL_OUTPUT_ANALOG) {
- crt = &connector->base;
- break;
- }
- }
-
- if (!crt)
- return;
-
- if (intel_get_load_detect_pipe(crt, NULL, &load_detect_temp))
- intel_release_load_detect_pipe(crt, &load_detect_temp);
-
-
-}
-
-static void intel_sanitize_crtc(struct intel_crtc *crtc)
-{
- struct drm_device *dev = crtc->base.dev;
- struct drm_i915_private *dev_priv = dev->dev_private;
- u32 reg, val;
-
- /* Clear any frame start delays used for debugging left by the BIOS */
- reg = PIPECONF(crtc->pipe);
- I915_WRITE(reg, I915_READ(reg) & ~PIPECONF_FRAME_START_DELAY_MASK);
-
- /* We need to sanitize the plane -> pipe mapping first because this will
- * disable the crtc (and hence change the state) if it is wrong. */
- if (!HAS_PCH_SPLIT(dev)) {
- struct intel_connector *connector;
- bool plane;
-
- reg = DSPCNTR(crtc->plane);
- val = I915_READ(reg);
-
- if ((val & DISPLAY_PLANE_ENABLE) == 0 &&
- (!!(val & DISPPLANE_SEL_PIPE_MASK) == crtc->pipe))
- goto ok;
-
- DRM_DEBUG_KMS("[CRTC:%d] wrong plane connection detected!\n",
- crtc->base.base.id);
-
- /* Pipe has the wrong plane attached and the plane is active.
- * Temporarily change the plane mapping and disable everything
- * ... */
- plane = crtc->plane;
- crtc->plane = !plane;
- dev_priv->display.crtc_disable(&crtc->base);
- crtc->plane = plane;
-
- /* ... and break all links. */
- list_for_each_entry(connector, &dev->mode_config.connector_list,
- base.head) {
- if (connector->encoder->base.crtc != &crtc->base)
- continue;
-
- intel_connector_break_all_links(connector);
- }
-
- WARN_ON(crtc->active);
- crtc->base.enabled = false;
- }
-ok:
-
- if (dev_priv->quirks & QUIRK_PIPEA_FORCE &&
- crtc->pipe == PIPE_A && !crtc->active) {
- /* BIOS forgot to enable pipe A, this mostly happens after
- * resume. Force-enable the pipe to fix this, the update_dpms
- * call below we restore the pipe to the right state, but leave
- * the required bits on. */
- intel_enable_pipe_a(dev);
- }
-
- /* Adjust the state of the output pipe according to whether we
- * have active connectors/encoders. */
- intel_crtc_update_dpms(&crtc->base);
-
- if (crtc->active != crtc->base.enabled) {
- struct intel_encoder *encoder;
-
- /* This can happen either due to bugs in the get_hw_state
- * functions or because the pipe is force-enabled due to the
- * pipe A quirk. */
- DRM_DEBUG_KMS("[CRTC:%d] hw state adjusted, was %s, now %s\n",
- crtc->base.base.id,
- crtc->base.enabled ? "enabled" : "disabled",
- crtc->active ? "enabled" : "disabled");
-
- crtc->base.enabled = crtc->active;
-
- /* Because we only establish the connector -> encoder ->
- * crtc links if something is active, this means the
- * crtc is now deactivated. Break the links. connector
- * -> encoder links are only establish when things are
- * actually up, hence no need to break them. */
- WARN_ON(crtc->active);
-
- for_each_encoder_on_crtc(dev, &crtc->base, encoder) {
- WARN_ON(encoder->connectors_active);
- encoder->base.crtc = NULL;
- }
- }
-}
-
-static void intel_sanitize_encoder(struct intel_encoder *encoder)
-{
- struct intel_connector *connector;
- struct drm_device *dev = encoder->base.dev;
-
- /* We need to check both for a crtc link (meaning that the
- * encoder is active and trying to read from a pipe) and the
- * pipe itself being active. */
- bool has_active_crtc = encoder->base.crtc &&
- to_intel_crtc(encoder->base.crtc)->active;
-
- if (encoder->connectors_active && !has_active_crtc) {
- DRM_DEBUG_KMS("[ENCODER:%d:%s] has active connectors but no active pipe!\n",
- encoder->base.base.id,
- drm_get_encoder_name(&encoder->base));
-
- /* Connector is active, but has no active pipe. This is
- * fallout from our resume register restoring. Disable
- * the encoder manually again. */
- if (encoder->base.crtc) {
- DRM_DEBUG_KMS("[ENCODER:%d:%s] manually disabled\n",
- encoder->base.base.id,
- drm_get_encoder_name(&encoder->base));
- encoder->disable(encoder);
- }
-
- /* Inconsistent output/port/pipe state happens presumably due to
- * a bug in one of the get_hw_state functions. Or someplace else
- * in our code, like the register restore mess on resume. Clamp
- * things to off as a safer default. */
- list_for_each_entry(connector,
- &dev->mode_config.connector_list,
- base.head) {
- if (connector->encoder != encoder)
- continue;
- intel_connector_break_all_links(connector);
- }
- }
- /* Enabled encoders without active connectors will be fixed in
- * the crtc fixup. */
-}
-
-/* Scan out the current hw modeset state, sanitizes it and maps it into the drm
- * and i915 state tracking structures. */
-void intel_modeset_setup_hw_state(struct drm_device *dev)
-{
- struct drm_i915_private *dev_priv = dev->dev_private;
- enum pipe pipe;
- u32 tmp;
- struct intel_crtc *crtc;
- struct intel_encoder *encoder;
- struct intel_connector *connector;
-
- for_each_pipe(pipe) {
- crtc = to_intel_crtc(dev_priv->pipe_to_crtc_mapping[pipe]);
-
- tmp = I915_READ(PIPECONF(pipe));
- if (tmp & PIPECONF_ENABLE)
- crtc->active = true;
- else
- crtc->active = false;
-
- crtc->base.enabled = crtc->active;
-
- DRM_DEBUG_KMS("[CRTC:%d] hw state readout: %s\n",
- crtc->base.base.id,
- crtc->active ? "enabled" : "disabled");
- }
-
- list_for_each_entry(encoder, &dev->mode_config.encoder_list,
- base.head) {
- pipe = 0;
-
- if (encoder->get_hw_state(encoder, &pipe)) {
- encoder->base.crtc =
- dev_priv->pipe_to_crtc_mapping[pipe];
- } else {
- encoder->base.crtc = NULL;
- }
-
- encoder->connectors_active = false;
- DRM_DEBUG_KMS("[ENCODER:%d:%s] hw state readout: %s, pipe=%i\n",
- encoder->base.base.id,
- drm_get_encoder_name(&encoder->base),
- encoder->base.crtc ? "enabled" : "disabled",
- pipe);
- }
-
- list_for_each_entry(connector, &dev->mode_config.connector_list,
- base.head) {
- if (connector->get_hw_state(connector)) {
- connector->base.dpms = DRM_MODE_DPMS_ON;
- connector->encoder->connectors_active = true;
- connector->base.encoder = &connector->encoder->base;
- } else {
- connector->base.dpms = DRM_MODE_DPMS_OFF;
- connector->base.encoder = NULL;
- }
- DRM_DEBUG_KMS("[CONNECTOR:%d:%s] hw state readout: %s\n",
- connector->base.base.id,
- drm_get_connector_name(&connector->base),
- connector->base.encoder ? "enabled" : "disabled");
- }
-
- /* HW state is read out, now we need to sanitize this mess. */
- list_for_each_entry(encoder, &dev->mode_config.encoder_list,
- base.head) {
- intel_sanitize_encoder(encoder);
- }
-
- for_each_pipe(pipe) {
- crtc = to_intel_crtc(dev_priv->pipe_to_crtc_mapping[pipe]);
- intel_sanitize_crtc(crtc);
- }
-
- intel_modeset_update_staged_output_state(dev);
-
- intel_modeset_check_state(dev);
+ INIT_WORK(&dev_priv->idle_work, intel_idle_update);
+ setup_timer(&dev_priv->idle_timer, intel_gpu_idle_timer,
+ (unsigned long)dev);
}
void intel_modeset_gem_init(struct drm_device *dev)
@@ -8263,8 +7242,6 @@ void intel_modeset_gem_init(struct drm_device *dev)
intel_modeset_init_hw(dev);
intel_setup_overlay(dev);
-
- intel_modeset_setup_hw_state(dev);
}
void intel_modeset_cleanup(struct drm_device *dev)
@@ -8303,11 +7280,19 @@ void intel_modeset_cleanup(struct drm_device *dev)
* enqueue unpin/hotplug work. */
drm_irq_uninstall(dev);
cancel_work_sync(&dev_priv->hotplug_work);
- cancel_work_sync(&dev_priv->rps.work);
+ cancel_work_sync(&dev_priv->rps_work);
/* flush any delayed tasks or pending work */
flush_scheduled_work();
+ /* Shut off idle work before the crtcs get freed. */
+ list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
+ intel_crtc = to_intel_crtc(crtc);
+ del_timer_sync(&intel_crtc->idle_timer);
+ }
+ del_timer_sync(&dev_priv->idle_timer);
+ cancel_work_sync(&dev_priv->idle_work);
+
drm_mode_config_cleanup(dev);
}
@@ -8353,7 +7338,7 @@ struct intel_display_error_state {
u32 position;
u32 base;
u32 size;
- } cursor[I915_MAX_PIPES];
+ } cursor[2];
struct intel_pipe_error_state {
u32 conf;
@@ -8365,7 +7350,7 @@ struct intel_display_error_state {
u32 vtotal;
u32 vblank;
u32 vsync;
- } pipe[I915_MAX_PIPES];
+ } pipe[2];
struct intel_plane_error_state {
u32 control;
@@ -8375,7 +7360,7 @@ struct intel_display_error_state {
u32 addr;
u32 surface;
u32 tile_offset;
- } plane[I915_MAX_PIPES];
+ } plane[2];
};
struct intel_display_error_state *
@@ -8389,7 +7374,7 @@ intel_display_capture_error_state(struct drm_device *dev)
if (error == NULL)
return NULL;
- for_each_pipe(i) {
+ for (i = 0; i < 2; i++) {
error->cursor[i].control = I915_READ(CURCNTR(i));
error->cursor[i].position = I915_READ(CURPOS(i));
error->cursor[i].base = I915_READ(CURBASE(i));
@@ -8422,11 +7407,9 @@ intel_display_print_error_state(struct seq_file *m,
struct drm_device *dev,
struct intel_display_error_state *error)
{
- drm_i915_private_t *dev_priv = dev->dev_private;
int i;
- seq_printf(m, "Num Pipes: %d\n", dev_priv->num_pipe);
- for_each_pipe(i) {
+ for (i = 0; i < 2; i++) {
seq_printf(m, "Pipe [%d]:\n", i);
seq_printf(m, " CONF: %08x\n", error->pipe[i].conf);
seq_printf(m, " SRC: %08x\n", error->pipe[i].source);
diff --git a/trunk/drivers/gpu/drm/i915/intel_dp.c b/trunk/drivers/gpu/drm/i915/intel_dp.c
index 1474f84fdbd0..ace757af9133 100644
--- a/trunk/drivers/gpu/drm/i915/intel_dp.c
+++ b/trunk/drivers/gpu/drm/i915/intel_dp.c
@@ -36,10 +36,42 @@
#include "intel_drv.h"
#include "i915_drm.h"
#include "i915_drv.h"
+#include "drm_dp_helper.h"
+#define DP_RECEIVER_CAP_SIZE 0xf
#define DP_LINK_STATUS_SIZE 6
#define DP_LINK_CHECK_TIMEOUT (10 * 1000)
+#define DP_LINK_CONFIGURATION_SIZE 9
+
+struct intel_dp {
+ struct intel_encoder base;
+ uint32_t output_reg;
+ uint32_t DP;
+ uint8_t link_configuration[DP_LINK_CONFIGURATION_SIZE];
+ bool has_audio;
+ enum hdmi_force_audio force_audio;
+ uint32_t color_range;
+ int dpms_mode;
+ uint8_t link_bw;
+ uint8_t lane_count;
+ uint8_t dpcd[DP_RECEIVER_CAP_SIZE];
+ struct i2c_adapter adapter;
+ struct i2c_algo_dp_aux_data algo;
+ bool is_pch_edp;
+ uint8_t train_set[4];
+ int panel_power_up_delay;
+ int panel_power_down_delay;
+ int panel_power_cycle_delay;
+ int backlight_on_delay;
+ int backlight_off_delay;
+ struct drm_display_mode *panel_fixed_mode; /* for eDP */
+ struct delayed_work panel_vdd_work;
+ bool want_panel_vdd;
+ struct edid *edid; /* cached EDID for eDP */
+ int edid_mode_count;
+};
+
/**
* is_edp - is the given port attached to an eDP panel (either CPU or PCH)
* @intel_dp: DP struct
@@ -808,6 +840,9 @@ intel_dp_set_m_n(struct drm_crtc *crtc, struct drm_display_mode *mode,
}
}
+static void ironlake_edp_pll_on(struct drm_encoder *encoder);
+static void ironlake_edp_pll_off(struct drm_encoder *encoder);
+
static void
intel_dp_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode)
@@ -818,6 +853,14 @@ intel_dp_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode,
struct drm_crtc *crtc = intel_dp->base.base.crtc;
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+ /* Turn on the eDP PLL if needed */
+ if (is_edp(intel_dp)) {
+ if (!is_pch_edp(intel_dp))
+ ironlake_edp_pll_on(encoder);
+ else
+ ironlake_edp_pll_off(encoder);
+ }
+
/*
* There are four kinds of DP registers:
*
@@ -839,8 +882,10 @@ intel_dp_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode,
* supposed to be read-only.
*/
intel_dp->DP = I915_READ(intel_dp->output_reg) & DP_DETECTED;
+ intel_dp->DP |= DP_VOLTAGE_0_4 | DP_PRE_EMPHASIS_0;
/* Handle DP bits in common between all three register formats */
+
intel_dp->DP |= DP_VOLTAGE_0_4 | DP_PRE_EMPHASIS_0;
switch (intel_dp->lane_count) {
@@ -887,6 +932,7 @@ intel_dp_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode,
intel_dp->DP |= intel_crtc->pipe << 29;
/* don't miss out required setting for eDP */
+ intel_dp->DP |= DP_PLL_ENABLE;
if (adjusted_mode->clock < 200000)
intel_dp->DP |= DP_PLL_FREQ_160MHZ;
else
@@ -908,6 +954,7 @@ intel_dp_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode,
if (is_cpu_edp(intel_dp)) {
/* don't miss out required setting for eDP */
+ intel_dp->DP |= DP_PLL_ENABLE;
if (adjusted_mode->clock < 200000)
intel_dp->DP |= DP_PLL_FREQ_160MHZ;
else
@@ -1178,49 +1225,27 @@ static void ironlake_edp_backlight_off(struct intel_dp *intel_dp)
msleep(intel_dp->backlight_off_delay);
}
-static void ironlake_edp_pll_on(struct intel_dp *intel_dp)
+static void ironlake_edp_pll_on(struct drm_encoder *encoder)
{
- struct drm_device *dev = intel_dp->base.base.dev;
- struct drm_crtc *crtc = intel_dp->base.base.crtc;
+ struct drm_device *dev = encoder->dev;
struct drm_i915_private *dev_priv = dev->dev_private;
u32 dpa_ctl;
- assert_pipe_disabled(dev_priv,
- to_intel_crtc(crtc)->pipe);
-
DRM_DEBUG_KMS("\n");
dpa_ctl = I915_READ(DP_A);
- WARN(dpa_ctl & DP_PLL_ENABLE, "dp pll on, should be off\n");
- WARN(dpa_ctl & DP_PORT_EN, "dp port still on, should be off\n");
-
- /* We don't adjust intel_dp->DP while tearing down the link, to
- * facilitate link retraining (e.g. after hotplug). Hence clear all
- * enable bits here to ensure that we don't enable too much. */
- intel_dp->DP &= ~(DP_PORT_EN | DP_AUDIO_OUTPUT_ENABLE);
- intel_dp->DP |= DP_PLL_ENABLE;
- I915_WRITE(DP_A, intel_dp->DP);
+ dpa_ctl |= DP_PLL_ENABLE;
+ I915_WRITE(DP_A, dpa_ctl);
POSTING_READ(DP_A);
udelay(200);
}
-static void ironlake_edp_pll_off(struct intel_dp *intel_dp)
+static void ironlake_edp_pll_off(struct drm_encoder *encoder)
{
- struct drm_device *dev = intel_dp->base.base.dev;
- struct drm_crtc *crtc = intel_dp->base.base.crtc;
+ struct drm_device *dev = encoder->dev;
struct drm_i915_private *dev_priv = dev->dev_private;
u32 dpa_ctl;
- assert_pipe_disabled(dev_priv,
- to_intel_crtc(crtc)->pipe);
-
dpa_ctl = I915_READ(DP_A);
- WARN((dpa_ctl & DP_PLL_ENABLE) == 0,
- "dp pll off, should be on\n");
- WARN(dpa_ctl & DP_PORT_EN, "dp port still on, should be off\n");
-
- /* We can't rely on the value tracked for the DP register in
- * intel_dp->DP because link_down must not change that (otherwise link
- * re-training will fail. */
dpa_ctl &= ~DP_PLL_ENABLE;
I915_WRITE(DP_A, dpa_ctl);
POSTING_READ(DP_A);
@@ -1257,57 +1282,10 @@ static void intel_dp_sink_dpms(struct intel_dp *intel_dp, int mode)
}
}
-static bool intel_dp_get_hw_state(struct intel_encoder *encoder,
- enum pipe *pipe)
+static void intel_dp_prepare(struct drm_encoder *encoder)
{
- struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
- struct drm_device *dev = encoder->base.dev;
- struct drm_i915_private *dev_priv = dev->dev_private;
- u32 tmp = I915_READ(intel_dp->output_reg);
-
- if (!(tmp & DP_PORT_EN))
- return false;
-
- if (is_cpu_edp(intel_dp) && IS_GEN7(dev)) {
- *pipe = PORT_TO_PIPE_CPT(tmp);
- } else if (!HAS_PCH_CPT(dev) || is_cpu_edp(intel_dp)) {
- *pipe = PORT_TO_PIPE(tmp);
- } else {
- u32 trans_sel;
- u32 trans_dp;
- int i;
-
- switch (intel_dp->output_reg) {
- case PCH_DP_B:
- trans_sel = TRANS_DP_PORT_SEL_B;
- break;
- case PCH_DP_C:
- trans_sel = TRANS_DP_PORT_SEL_C;
- break;
- case PCH_DP_D:
- trans_sel = TRANS_DP_PORT_SEL_D;
- break;
- default:
- return true;
- }
-
- for_each_pipe(i) {
- trans_dp = I915_READ(TRANS_DP_CTL(i));
- if ((trans_dp & TRANS_DP_PORT_SEL_MASK) == trans_sel) {
- *pipe = i;
- return true;
- }
- }
- }
-
- DRM_DEBUG_KMS("No pipe for dp port 0x%x found\n", intel_dp->output_reg);
-
- return true;
-}
+ struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
-static void intel_disable_dp(struct intel_encoder *encoder)
-{
- struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
/* Make sure the panel is off before trying to change the mode. But also
* ensure that we have vdd while we switch off the panel. */
@@ -1315,31 +1293,14 @@ static void intel_disable_dp(struct intel_encoder *encoder)
ironlake_edp_backlight_off(intel_dp);
intel_dp_sink_dpms(intel_dp, DRM_MODE_DPMS_ON);
ironlake_edp_panel_off(intel_dp);
-
- /* cpu edp my only be disable _after_ the cpu pipe/plane is disabled. */
- if (!is_cpu_edp(intel_dp))
- intel_dp_link_down(intel_dp);
+ intel_dp_link_down(intel_dp);
}
-static void intel_post_disable_dp(struct intel_encoder *encoder)
+static void intel_dp_commit(struct drm_encoder *encoder)
{
- struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
-
- if (is_cpu_edp(intel_dp)) {
- intel_dp_link_down(intel_dp);
- ironlake_edp_pll_off(intel_dp);
- }
-}
-
-static void intel_enable_dp(struct intel_encoder *encoder)
-{
- struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
- struct drm_device *dev = encoder->base.dev;
- struct drm_i915_private *dev_priv = dev->dev_private;
- uint32_t dp_reg = I915_READ(intel_dp->output_reg);
-
- if (WARN_ON(dp_reg & DP_PORT_EN))
- return;
+ struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
+ struct drm_device *dev = encoder->dev;
+ struct intel_crtc *intel_crtc = to_intel_crtc(intel_dp->base.base.crtc);
ironlake_edp_panel_vdd_on(intel_dp);
intel_dp_sink_dpms(intel_dp, DRM_MODE_DPMS_ON);
@@ -1348,14 +1309,47 @@ static void intel_enable_dp(struct intel_encoder *encoder)
ironlake_edp_panel_vdd_off(intel_dp, true);
intel_dp_complete_link_train(intel_dp);
ironlake_edp_backlight_on(intel_dp);
+
+ intel_dp->dpms_mode = DRM_MODE_DPMS_ON;
+
+ if (HAS_PCH_CPT(dev))
+ intel_cpt_verify_modeset(dev, intel_crtc->pipe);
}
-static void intel_pre_enable_dp(struct intel_encoder *encoder)
+static void
+intel_dp_dpms(struct drm_encoder *encoder, int mode)
{
- struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
+ struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
+ struct drm_device *dev = encoder->dev;
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ uint32_t dp_reg = I915_READ(intel_dp->output_reg);
- if (is_cpu_edp(intel_dp))
- ironlake_edp_pll_on(intel_dp);
+ if (mode != DRM_MODE_DPMS_ON) {
+ /* Switching the panel off requires vdd. */
+ ironlake_edp_panel_vdd_on(intel_dp);
+ ironlake_edp_backlight_off(intel_dp);
+ intel_dp_sink_dpms(intel_dp, mode);
+ ironlake_edp_panel_off(intel_dp);
+ intel_dp_link_down(intel_dp);
+
+ if (is_cpu_edp(intel_dp))
+ ironlake_edp_pll_off(encoder);
+ } else {
+ if (is_cpu_edp(intel_dp))
+ ironlake_edp_pll_on(encoder);
+
+ ironlake_edp_panel_vdd_on(intel_dp);
+ intel_dp_sink_dpms(intel_dp, mode);
+ if (!(dp_reg & DP_PORT_EN)) {
+ intel_dp_start_link_train(intel_dp);
+ ironlake_edp_panel_on(intel_dp);
+ ironlake_edp_panel_vdd_off(intel_dp, true);
+ intel_dp_complete_link_train(intel_dp);
+ } else
+ ironlake_edp_panel_vdd_off(intel_dp, false);
+ ironlake_edp_backlight_on(intel_dp);
+ }
+ intel_dp->dpms_mode = mode;
}
/*
@@ -1674,45 +1668,6 @@ intel_dp_set_link_train(struct intel_dp *intel_dp,
struct drm_i915_private *dev_priv = dev->dev_private;
int ret;
- if (HAS_PCH_CPT(dev) && (IS_GEN7(dev) || !is_cpu_edp(intel_dp))) {
- dp_reg_value &= ~DP_LINK_TRAIN_MASK_CPT;
-
- switch (dp_train_pat & DP_TRAINING_PATTERN_MASK) {
- case DP_TRAINING_PATTERN_DISABLE:
- dp_reg_value |= DP_LINK_TRAIN_OFF_CPT;
- break;
- case DP_TRAINING_PATTERN_1:
- dp_reg_value |= DP_LINK_TRAIN_PAT_1_CPT;
- break;
- case DP_TRAINING_PATTERN_2:
- dp_reg_value |= DP_LINK_TRAIN_PAT_2_CPT;
- break;
- case DP_TRAINING_PATTERN_3:
- DRM_ERROR("DP training pattern 3 not supported\n");
- dp_reg_value |= DP_LINK_TRAIN_PAT_2_CPT;
- break;
- }
-
- } else {
- dp_reg_value &= ~DP_LINK_TRAIN_MASK;
-
- switch (dp_train_pat & DP_TRAINING_PATTERN_MASK) {
- case DP_TRAINING_PATTERN_DISABLE:
- dp_reg_value |= DP_LINK_TRAIN_OFF;
- break;
- case DP_TRAINING_PATTERN_1:
- dp_reg_value |= DP_LINK_TRAIN_PAT_1;
- break;
- case DP_TRAINING_PATTERN_2:
- dp_reg_value |= DP_LINK_TRAIN_PAT_2;
- break;
- case DP_TRAINING_PATTERN_3:
- DRM_ERROR("DP training pattern 3 not supported\n");
- dp_reg_value |= DP_LINK_TRAIN_PAT_2;
- break;
- }
- }
-
I915_WRITE(intel_dp->output_reg, dp_reg_value);
POSTING_READ(intel_dp->output_reg);
@@ -1720,15 +1675,12 @@ intel_dp_set_link_train(struct intel_dp *intel_dp,
DP_TRAINING_PATTERN_SET,
dp_train_pat);
- if ((dp_train_pat & DP_TRAINING_PATTERN_MASK) !=
- DP_TRAINING_PATTERN_DISABLE) {
- ret = intel_dp_aux_native_write(intel_dp,
- DP_TRAINING_LANE0_SET,
- intel_dp->train_set,
- intel_dp->lane_count);
- if (ret != intel_dp->lane_count)
- return false;
- }
+ ret = intel_dp_aux_native_write(intel_dp,
+ DP_TRAINING_LANE0_SET,
+ intel_dp->train_set,
+ intel_dp->lane_count);
+ if (ret != intel_dp->lane_count)
+ return false;
return true;
}
@@ -1738,12 +1690,26 @@ static void
intel_dp_start_link_train(struct intel_dp *intel_dp)
{
struct drm_device *dev = intel_dp->base.base.dev;
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ struct intel_crtc *intel_crtc = to_intel_crtc(intel_dp->base.base.crtc);
int i;
uint8_t voltage;
bool clock_recovery = false;
int voltage_tries, loop_tries;
+ u32 reg;
uint32_t DP = intel_dp->DP;
+ /*
+ * On CPT we have to enable the port in training pattern 1, which
+ * will happen below in intel_dp_set_link_train. Otherwise, enable
+ * the port and wait for it to become active.
+ */
+ if (!HAS_PCH_CPT(dev)) {
+ I915_WRITE(intel_dp->output_reg, intel_dp->DP);
+ POSTING_READ(intel_dp->output_reg);
+ intel_wait_for_vblank(dev, intel_crtc->pipe);
+ }
+
/* Write the link configuration data */
intel_dp_aux_native_write(intel_dp, DP_LINK_BW_SET,
intel_dp->link_configuration,
@@ -1751,6 +1717,10 @@ intel_dp_start_link_train(struct intel_dp *intel_dp)
DP |= DP_PORT_EN;
+ if (HAS_PCH_CPT(dev) && (IS_GEN7(dev) || !is_cpu_edp(intel_dp)))
+ DP &= ~DP_LINK_TRAIN_MASK_CPT;
+ else
+ DP &= ~DP_LINK_TRAIN_MASK;
memset(intel_dp->train_set, 0, 4);
voltage = 0xff;
voltage_tries = 0;
@@ -1774,7 +1744,12 @@ intel_dp_start_link_train(struct intel_dp *intel_dp)
DP = (DP & ~(DP_VOLTAGE_MASK|DP_PRE_EMPHASIS_MASK)) | signal_levels;
}
- if (!intel_dp_set_link_train(intel_dp, DP,
+ if (HAS_PCH_CPT(dev) && (IS_GEN7(dev) || !is_cpu_edp(intel_dp)))
+ reg = DP | DP_LINK_TRAIN_PAT_1_CPT;
+ else
+ reg = DP | DP_LINK_TRAIN_PAT_1;
+
+ if (!intel_dp_set_link_train(intel_dp, reg,
DP_TRAINING_PATTERN_1 |
DP_LINK_SCRAMBLING_DISABLE))
break;
@@ -1829,8 +1804,10 @@ static void
intel_dp_complete_link_train(struct intel_dp *intel_dp)
{
struct drm_device *dev = intel_dp->base.base.dev;
+ struct drm_i915_private *dev_priv = dev->dev_private;
bool channel_eq = false;
int tries, cr_tries;
+ u32 reg;
uint32_t DP = intel_dp->DP;
/* channel equalization */
@@ -1859,8 +1836,13 @@ intel_dp_complete_link_train(struct intel_dp *intel_dp)
DP = (DP & ~(DP_VOLTAGE_MASK|DP_PRE_EMPHASIS_MASK)) | signal_levels;
}
+ if (HAS_PCH_CPT(dev) && (IS_GEN7(dev) || !is_cpu_edp(intel_dp)))
+ reg = DP | DP_LINK_TRAIN_PAT_2_CPT;
+ else
+ reg = DP | DP_LINK_TRAIN_PAT_2;
+
/* channel eq pattern */
- if (!intel_dp_set_link_train(intel_dp, DP,
+ if (!intel_dp_set_link_train(intel_dp, reg,
DP_TRAINING_PATTERN_2 |
DP_LINK_SCRAMBLING_DISABLE))
break;
@@ -1895,7 +1877,15 @@ intel_dp_complete_link_train(struct intel_dp *intel_dp)
++tries;
}
- intel_dp_set_link_train(intel_dp, DP, DP_TRAINING_PATTERN_DISABLE);
+ if (HAS_PCH_CPT(dev) && (IS_GEN7(dev) || !is_cpu_edp(intel_dp)))
+ reg = DP | DP_LINK_TRAIN_OFF_CPT;
+ else
+ reg = DP | DP_LINK_TRAIN_OFF;
+
+ I915_WRITE(intel_dp->output_reg, reg);
+ POSTING_READ(intel_dp->output_reg);
+ intel_dp_aux_native_write_1(intel_dp,
+ DP_TRAINING_PATTERN_SET, DP_TRAINING_PATTERN_DISABLE);
}
static void
@@ -1905,11 +1895,18 @@ intel_dp_link_down(struct intel_dp *intel_dp)
struct drm_i915_private *dev_priv = dev->dev_private;
uint32_t DP = intel_dp->DP;
- if (WARN_ON((I915_READ(intel_dp->output_reg) & DP_PORT_EN) == 0))
+ if ((I915_READ(intel_dp->output_reg) & DP_PORT_EN) == 0)
return;
DRM_DEBUG_KMS("\n");
+ if (is_edp(intel_dp)) {
+ DP &= ~DP_PLL_ENABLE;
+ I915_WRITE(intel_dp->output_reg, DP);
+ POSTING_READ(intel_dp->output_reg);
+ udelay(100);
+ }
+
if (HAS_PCH_CPT(dev) && (IS_GEN7(dev) || !is_cpu_edp(intel_dp))) {
DP &= ~DP_LINK_TRAIN_MASK_CPT;
I915_WRITE(intel_dp->output_reg, DP | DP_LINK_TRAIN_PAT_IDLE_CPT);
@@ -1921,6 +1918,13 @@ intel_dp_link_down(struct intel_dp *intel_dp)
msleep(17);
+ if (is_edp(intel_dp)) {
+ if (HAS_PCH_CPT(dev) && (IS_GEN7(dev) || !is_cpu_edp(intel_dp)))
+ DP |= DP_LINK_TRAIN_OFF_CPT;
+ else
+ DP |= DP_LINK_TRAIN_OFF;
+ }
+
if (HAS_PCH_IBX(dev) &&
I915_READ(intel_dp->output_reg) & DP_PIPEB_SELECT) {
struct drm_crtc *crtc = intel_dp->base.base.crtc;
@@ -2029,10 +2033,10 @@ intel_dp_check_link_status(struct intel_dp *intel_dp)
u8 sink_irq_vector;
u8 link_status[DP_LINK_STATUS_SIZE];
- if (!intel_dp->base.connectors_active)
+ if (intel_dp->dpms_mode != DRM_MODE_DPMS_ON)
return;
- if (WARN_ON(!intel_dp->base.base.crtc))
+ if (!intel_dp->base.base.crtc)
return;
/* Try to read receiver status if the link appears to be up */
@@ -2156,6 +2160,7 @@ intel_dp_get_edid_modes(struct drm_connector *connector, struct i2c_adapter *ada
ret = drm_add_edid_modes(connector, intel_dp->edid);
drm_edid_to_eld(connector,
intel_dp->edid);
+ connector->display_info.raw_edid = NULL;
return intel_dp->edid_mode_count;
}
@@ -2201,6 +2206,7 @@ intel_dp_detect(struct drm_connector *connector, bool force)
edid = intel_dp_get_edid(connector, &intel_dp->adapter);
if (edid) {
intel_dp->has_audio = drm_detect_monitor_audio(edid);
+ connector->display_info.raw_edid = NULL;
kfree(edid);
}
}
@@ -2265,6 +2271,8 @@ intel_dp_detect_audio(struct drm_connector *connector)
edid = intel_dp_get_edid(connector, &intel_dp->adapter);
if (edid) {
has_audio = drm_detect_monitor_audio(edid);
+
+ connector->display_info.raw_edid = NULL;
kfree(edid);
}
@@ -2318,8 +2326,9 @@ intel_dp_set_property(struct drm_connector *connector,
done:
if (intel_dp->base.base.crtc) {
struct drm_crtc *crtc = intel_dp->base.base.crtc;
- intel_set_mode(crtc, &crtc->mode,
- crtc->x, crtc->y, crtc->fb);
+ drm_crtc_helper_set_mode(crtc, &crtc->mode,
+ crtc->x, crtc->y,
+ crtc->fb);
}
return 0;
@@ -2353,13 +2362,15 @@ static void intel_dp_encoder_destroy(struct drm_encoder *encoder)
}
static const struct drm_encoder_helper_funcs intel_dp_helper_funcs = {
+ .dpms = intel_dp_dpms,
.mode_fixup = intel_dp_mode_fixup,
+ .prepare = intel_dp_prepare,
.mode_set = intel_dp_mode_set,
- .disable = intel_encoder_noop,
+ .commit = intel_dp_commit,
};
static const struct drm_connector_funcs intel_dp_connector_funcs = {
- .dpms = intel_connector_dpms,
+ .dpms = drm_helper_connector_dpms,
.detect = intel_dp_detect,
.fill_modes = drm_helper_probe_single_connector_modes,
.set_property = intel_dp_set_property,
@@ -2430,7 +2441,7 @@ intel_dp_add_properties(struct intel_dp *intel_dp, struct drm_connector *connect
}
void
-intel_dp_init(struct drm_device *dev, int output_reg, enum port port)
+intel_dp_init(struct drm_device *dev, int output_reg)
{
struct drm_i915_private *dev_priv = dev->dev_private;
struct drm_connector *connector;
@@ -2445,9 +2456,7 @@ intel_dp_init(struct drm_device *dev, int output_reg, enum port port)
return;
intel_dp->output_reg = output_reg;
- intel_dp->port = port;
- /* Preserve the current hw state. */
- intel_dp->DP = I915_READ(intel_dp->output_reg);
+ intel_dp->dpms_mode = -1;
intel_connector = kzalloc(sizeof(struct intel_connector), GFP_KERNEL);
if (!intel_connector) {
@@ -2474,10 +2483,18 @@ intel_dp_init(struct drm_device *dev, int output_reg, enum port port)
connector->polled = DRM_CONNECTOR_POLL_HPD;
- intel_encoder->cloneable = false;
+ if (output_reg == DP_B || output_reg == PCH_DP_B)
+ intel_encoder->clone_mask = (1 << INTEL_DP_B_CLONE_BIT);
+ else if (output_reg == DP_C || output_reg == PCH_DP_C)
+ intel_encoder->clone_mask = (1 << INTEL_DP_C_CLONE_BIT);
+ else if (output_reg == DP_D || output_reg == PCH_DP_D)
+ intel_encoder->clone_mask = (1 << INTEL_DP_D_CLONE_BIT);
- INIT_DELAYED_WORK(&intel_dp->panel_vdd_work,
- ironlake_panel_vdd_work);
+ if (is_edp(intel_dp)) {
+ intel_encoder->clone_mask = (1 << INTEL_EDP_CLONE_BIT);
+ INIT_DELAYED_WORK(&intel_dp->panel_vdd_work,
+ ironlake_panel_vdd_work);
+ }
intel_encoder->crtc_mask = (1 << 0) | (1 << 1) | (1 << 2);
@@ -2491,33 +2508,29 @@ intel_dp_init(struct drm_device *dev, int output_reg, enum port port)
intel_connector_attach_encoder(intel_connector, intel_encoder);
drm_sysfs_connector_add(connector);
- intel_encoder->enable = intel_enable_dp;
- intel_encoder->pre_enable = intel_pre_enable_dp;
- intel_encoder->disable = intel_disable_dp;
- intel_encoder->post_disable = intel_post_disable_dp;
- intel_encoder->get_hw_state = intel_dp_get_hw_state;
- intel_connector->get_hw_state = intel_connector_get_hw_state;
-
/* Set up the DDC bus. */
- switch (port) {
- case PORT_A:
- name = "DPDDC-A";
- break;
- case PORT_B:
- dev_priv->hotplug_supported_mask |= DPB_HOTPLUG_INT_STATUS;
- name = "DPDDC-B";
- break;
- case PORT_C:
- dev_priv->hotplug_supported_mask |= DPC_HOTPLUG_INT_STATUS;
- name = "DPDDC-C";
- break;
- case PORT_D:
- dev_priv->hotplug_supported_mask |= DPD_HOTPLUG_INT_STATUS;
- name = "DPDDC-D";
- break;
- default:
- WARN(1, "Invalid port %c\n", port_name(port));
- break;
+ switch (output_reg) {
+ case DP_A:
+ name = "DPDDC-A";
+ break;
+ case DP_B:
+ case PCH_DP_B:
+ dev_priv->hotplug_supported_mask |=
+ DPB_HOTPLUG_INT_STATUS;
+ name = "DPDDC-B";
+ break;
+ case DP_C:
+ case PCH_DP_C:
+ dev_priv->hotplug_supported_mask |=
+ DPC_HOTPLUG_INT_STATUS;
+ name = "DPDDC-C";
+ break;
+ case DP_D:
+ case PCH_DP_D:
+ dev_priv->hotplug_supported_mask |=
+ DPD_HOTPLUG_INT_STATUS;
+ name = "DPDDC-D";
+ break;
}
/* Cache some DPCD data in the eDP case */
diff --git a/trunk/drivers/gpu/drm/i915/intel_drv.h b/trunk/drivers/gpu/drm/i915/intel_drv.h
index 351fd7179cd7..cd54cf88a28f 100644
--- a/trunk/drivers/gpu/drm/i915/intel_drv.h
+++ b/trunk/drivers/gpu/drm/i915/intel_drv.h
@@ -31,7 +31,6 @@
#include "drm_crtc.h"
#include "drm_crtc_helper.h"
#include "drm_fb_helper.h"
-#include "drm_dp_helper.h"
#define _wait_for(COND, MS, W) ({ \
unsigned long timeout__ = jiffies + msecs_to_jiffies(MS); \
@@ -41,11 +40,7 @@
ret__ = -ETIMEDOUT; \
break; \
} \
- if (W && drm_can_sleep()) { \
- msleep(W); \
- } else { \
- cpu_relax(); \
- } \
+ if (W && drm_can_sleep()) msleep(W); \
} \
ret__; \
})
@@ -95,6 +90,25 @@
#define INTEL_OUTPUT_DISPLAYPORT 7
#define INTEL_OUTPUT_EDP 8
+/* Intel Pipe Clone Bit */
+#define INTEL_HDMIB_CLONE_BIT 1
+#define INTEL_HDMIC_CLONE_BIT 2
+#define INTEL_HDMID_CLONE_BIT 3
+#define INTEL_HDMIE_CLONE_BIT 4
+#define INTEL_HDMIF_CLONE_BIT 5
+#define INTEL_SDVO_NON_TV_CLONE_BIT 6
+#define INTEL_SDVO_TV_CLONE_BIT 7
+#define INTEL_SDVO_LVDS_CLONE_BIT 8
+#define INTEL_ANALOG_CLONE_BIT 9
+#define INTEL_TV_CLONE_BIT 10
+#define INTEL_DP_B_CLONE_BIT 11
+#define INTEL_DP_C_CLONE_BIT 12
+#define INTEL_DP_D_CLONE_BIT 13
+#define INTEL_LVDS_CLONE_BIT 14
+#define INTEL_DVO_TMDS_CLONE_BIT 15
+#define INTEL_DVO_LVDS_CLONE_BIT 16
+#define INTEL_EDP_CLONE_BIT 17
+
#define INTEL_DVO_CHIP_NONE 0
#define INTEL_DVO_CHIP_LVDS 1
#define INTEL_DVO_CHIP_TMDS 2
@@ -137,48 +151,16 @@ struct intel_fbdev {
struct intel_encoder {
struct drm_encoder base;
- /*
- * The new crtc this encoder will be driven from. Only differs from
- * base->crtc while a modeset is in progress.
- */
- struct intel_crtc *new_crtc;
-
int type;
bool needs_tv_clock;
- /*
- * Intel hw has only one MUX where encoders could be clone, hence a
- * simple flag is enough to compute the possible_clones mask.
- */
- bool cloneable;
- bool connectors_active;
void (*hot_plug)(struct intel_encoder *);
- void (*pre_enable)(struct intel_encoder *);
- void (*enable)(struct intel_encoder *);
- void (*disable)(struct intel_encoder *);
- void (*post_disable)(struct intel_encoder *);
- /* Read out the current hw state of this connector, returning true if
- * the encoder is active. If the encoder is enabled it also set the pipe
- * it is connected to in the pipe parameter. */
- bool (*get_hw_state)(struct intel_encoder *, enum pipe *pipe);
int crtc_mask;
+ int clone_mask;
};
struct intel_connector {
struct drm_connector base;
- /*
- * The fixed encoder this connector is connected to.
- */
struct intel_encoder *encoder;
-
- /*
- * The new encoder this connector will be driven. Only differs from
- * encoder while a modeset is in progress.
- */
- struct intel_encoder *new_encoder;
-
- /* Reads out the current hw, returning true if the connector is enabled
- * and active (i.e. dpms ON state). */
- bool (*get_hw_state)(struct intel_connector *);
};
struct intel_crtc {
@@ -186,13 +168,11 @@ struct intel_crtc {
enum pipe pipe;
enum plane plane;
u8 lut_r[256], lut_g[256], lut_b[256];
- /*
- * Whether the crtc and the connected output pipeline is active. Implies
- * that crtc->enabled is set, i.e. the current mode configuration has
- * some outputs connected to this crtc.
- */
- bool active;
+ int dpms_mode;
+ bool active; /* is the crtc on? independent of the dpms mode */
bool primary_disabled; /* is the crtc obscured by a plane? */
+ bool busy; /* is scanout buffer being updated frequently? */
+ struct timer_list idle_timer;
bool lowfreq_avail;
struct intel_overlay *overlay;
struct intel_unpin_work *unpin_work;
@@ -331,37 +311,6 @@ struct intel_hdmi {
struct drm_display_mode *adjusted_mode);
};
-#define DP_RECEIVER_CAP_SIZE 0xf
-#define DP_LINK_CONFIGURATION_SIZE 9
-
-struct intel_dp {
- struct intel_encoder base;
- uint32_t output_reg;
- uint32_t DP;
- uint8_t link_configuration[DP_LINK_CONFIGURATION_SIZE];
- bool has_audio;
- enum hdmi_force_audio force_audio;
- enum port port;
- uint32_t color_range;
- uint8_t link_bw;
- uint8_t lane_count;
- uint8_t dpcd[DP_RECEIVER_CAP_SIZE];
- struct i2c_adapter adapter;
- struct i2c_algo_dp_aux_data algo;
- bool is_pch_edp;
- uint8_t train_set[4];
- int panel_power_up_delay;
- int panel_power_down_delay;
- int panel_power_cycle_delay;
- int backlight_on_delay;
- int backlight_off_delay;
- struct drm_display_mode *panel_fixed_mode; /* for eDP */
- struct delayed_work panel_vdd_work;
- bool want_panel_vdd;
- struct edid *edid; /* cached EDID for eDP */
- int edid_mode_count;
-};
-
static inline struct drm_crtc *
intel_get_crtc_for_pipe(struct drm_device *dev, int pipe)
{
@@ -401,21 +350,17 @@ extern void intel_attach_force_audio_property(struct drm_connector *connector);
extern void intel_attach_broadcast_rgb_property(struct drm_connector *connector);
extern void intel_crt_init(struct drm_device *dev);
-extern void intel_hdmi_init(struct drm_device *dev,
- int sdvox_reg, enum port port);
+extern void intel_hdmi_init(struct drm_device *dev, int sdvox_reg);
extern struct intel_hdmi *enc_to_intel_hdmi(struct drm_encoder *encoder);
extern void intel_dip_infoframe_csum(struct dip_infoframe *avi_if);
extern bool intel_sdvo_init(struct drm_device *dev, uint32_t sdvo_reg,
bool is_sdvob);
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_busy(struct drm_device *dev,
+ struct drm_i915_gem_object *obj);
extern bool intel_lvds_init(struct drm_device *dev);
-extern void intel_dp_init(struct drm_device *dev, int output_reg,
- enum port port);
+extern void intel_dp_init(struct drm_device *dev, int dp_reg);
void
intel_dp_set_m_n(struct drm_crtc *crtc, struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode);
@@ -428,6 +373,8 @@ extern int intel_plane_init(struct drm_device *dev, enum pipe pipe);
extern void intel_flush_display_plane(struct drm_i915_private *dev_priv,
enum plane plane);
+void intel_sanitize_pm(struct drm_device *dev);
+
/* intel_panel.c */
extern void intel_fixed_panel_mode(struct drm_display_mode *fixed_mode,
struct drm_display_mode *adjusted_mode);
@@ -444,27 +391,10 @@ extern void intel_panel_disable_backlight(struct drm_device *dev);
extern void intel_panel_destroy_backlight(struct drm_device *dev);
extern enum drm_connector_status intel_panel_detect(struct drm_device *dev);
-struct intel_set_config {
- struct drm_encoder **save_connector_encoders;
- struct drm_crtc **save_encoder_crtcs;
-
- bool fb_changed;
- bool mode_changed;
-};
-
-extern bool 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_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_prepare(struct drm_encoder *encoder);
+extern void intel_encoder_commit(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);
-extern void intel_connector_dpms(struct drm_connector *, int mode);
-extern bool intel_connector_get_hw_state(struct intel_connector *connector);
-extern void intel_modeset_check_state(struct drm_device *dev);
-
static inline struct intel_encoder *intel_attached_encoder(struct drm_connector *connector)
{
@@ -487,10 +417,12 @@ struct intel_load_detect_pipe {
bool load_detect_temp;
int dpms_mode;
};
-extern bool intel_get_load_detect_pipe(struct drm_connector *connector,
+extern bool intel_get_load_detect_pipe(struct intel_encoder *intel_encoder,
+ struct drm_connector *connector,
struct drm_display_mode *mode,
struct intel_load_detect_pipe *old);
-extern void intel_release_load_detect_pipe(struct drm_connector *connector,
+extern void intel_release_load_detect_pipe(struct intel_encoder *intel_encoder,
+ struct drm_connector *connector,
struct intel_load_detect_pipe *old);
extern void intelfb_restore(void);
@@ -571,10 +503,7 @@ extern void intel_disable_gt_powersave(struct drm_device *dev);
extern void gen6_gt_check_fifodbg(struct drm_i915_private *dev_priv);
extern void ironlake_teardown_rc6(struct drm_device *dev);
-extern void intel_enable_ddi(struct intel_encoder *encoder);
-extern void intel_disable_ddi(struct intel_encoder *encoder);
-extern bool intel_ddi_get_hw_state(struct intel_encoder *encoder,
- enum pipe *pipe);
+extern void intel_ddi_dpms(struct drm_encoder *encoder, int mode);
extern void intel_ddi_mode_set(struct drm_encoder *encoder,
struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode);
diff --git a/trunk/drivers/gpu/drm/i915/intel_dvo.c b/trunk/drivers/gpu/drm/i915/intel_dvo.c
index 4f1fdcc44005..36c542e5036b 100644
--- a/trunk/drivers/gpu/drm/i915/intel_dvo.c
+++ b/trunk/drivers/gpu/drm/i915/intel_dvo.c
@@ -37,7 +37,6 @@
#define SIL164_ADDR 0x38
#define CH7xxx_ADDR 0x76
#define TFP410_ADDR 0x38
-#define NS2501_ADDR 0x38
static const struct intel_dvo_device intel_dvo_devices[] = {
{
@@ -75,14 +74,7 @@ static const struct intel_dvo_device intel_dvo_devices[] = {
.slave_addr = 0x75,
.gpio = GMBUS_PORT_DPB,
.dev_ops = &ch7017_ops,
- },
- {
- .type = INTEL_DVO_CHIP_TMDS,
- .name = "ns2501",
- .dvo_reg = DVOC,
- .slave_addr = NS2501_ADDR,
- .dev_ops = &ns2501_ops,
- }
+ }
};
struct intel_dvo {
@@ -105,91 +97,22 @@ static struct intel_dvo *intel_attached_dvo(struct drm_connector *connector)
struct intel_dvo, base);
}
-static bool intel_dvo_connector_get_hw_state(struct intel_connector *connector)
-{
- struct intel_dvo *intel_dvo = intel_attached_dvo(&connector->base);
-
- return intel_dvo->dev.dev_ops->get_hw_state(&intel_dvo->dev);
-}
-
-static bool intel_dvo_get_hw_state(struct intel_encoder *encoder,
- enum pipe *pipe)
-{
- struct drm_device *dev = encoder->base.dev;
- struct drm_i915_private *dev_priv = dev->dev_private;
- struct intel_dvo *intel_dvo = enc_to_intel_dvo(&encoder->base);
- u32 tmp;
-
- tmp = I915_READ(intel_dvo->dev.dvo_reg);
-
- if (!(tmp & DVO_ENABLE))
- return false;
-
- *pipe = PORT_TO_PIPE(tmp);
-
- return true;
-}
-
-static void intel_disable_dvo(struct intel_encoder *encoder)
-{
- struct drm_i915_private *dev_priv = encoder->base.dev->dev_private;
- struct intel_dvo *intel_dvo = enc_to_intel_dvo(&encoder->base);
- u32 dvo_reg = intel_dvo->dev.dvo_reg;
- u32 temp = I915_READ(dvo_reg);
-
- intel_dvo->dev.dev_ops->dpms(&intel_dvo->dev, false);
- I915_WRITE(dvo_reg, temp & ~DVO_ENABLE);
- I915_READ(dvo_reg);
-}
-
-static void intel_enable_dvo(struct intel_encoder *encoder)
+static void intel_dvo_dpms(struct drm_encoder *encoder, int mode)
{
- struct drm_i915_private *dev_priv = encoder->base.dev->dev_private;
- struct intel_dvo *intel_dvo = enc_to_intel_dvo(&encoder->base);
+ struct drm_i915_private *dev_priv = encoder->dev->dev_private;
+ struct intel_dvo *intel_dvo = enc_to_intel_dvo(encoder);
u32 dvo_reg = intel_dvo->dev.dvo_reg;
u32 temp = I915_READ(dvo_reg);
- I915_WRITE(dvo_reg, temp | DVO_ENABLE);
- I915_READ(dvo_reg);
- intel_dvo->dev.dev_ops->dpms(&intel_dvo->dev, true);
-}
-
-static void intel_dvo_dpms(struct drm_connector *connector, int mode)
-{
- struct intel_dvo *intel_dvo = intel_attached_dvo(connector);
- struct drm_crtc *crtc;
-
- /* dvo supports only 2 dpms states. */
- if (mode != DRM_MODE_DPMS_ON)
- mode = DRM_MODE_DPMS_OFF;
-
- if (mode == connector->dpms)
- return;
-
- connector->dpms = mode;
-
- /* Only need to change hw state when actually enabled */
- crtc = intel_dvo->base.base.crtc;
- if (!crtc) {
- intel_dvo->base.connectors_active = false;
- return;
- }
-
if (mode == DRM_MODE_DPMS_ON) {
- intel_dvo->base.connectors_active = true;
-
- intel_crtc_update_dpms(crtc);
-
- intel_dvo->dev.dev_ops->dpms(&intel_dvo->dev, true);
+ I915_WRITE(dvo_reg, temp | DVO_ENABLE);
+ I915_READ(dvo_reg);
+ intel_dvo->dev.dev_ops->dpms(&intel_dvo->dev, mode);
} else {
- intel_dvo->dev.dev_ops->dpms(&intel_dvo->dev, false);
-
- intel_dvo->base.connectors_active = false;
-
- intel_crtc_update_dpms(crtc);
+ intel_dvo->dev.dev_ops->dpms(&intel_dvo->dev, mode);
+ I915_WRITE(dvo_reg, temp & ~DVO_ENABLE);
+ I915_READ(dvo_reg);
}
-
- intel_modeset_check_state(connector->dev);
}
static int intel_dvo_mode_valid(struct drm_connector *connector,
@@ -344,13 +267,15 @@ static void intel_dvo_destroy(struct drm_connector *connector)
}
static const struct drm_encoder_helper_funcs intel_dvo_helper_funcs = {
+ .dpms = intel_dvo_dpms,
.mode_fixup = intel_dvo_mode_fixup,
+ .prepare = intel_encoder_prepare,
.mode_set = intel_dvo_mode_set,
- .disable = intel_encoder_noop,
+ .commit = intel_encoder_commit,
};
static const struct drm_connector_funcs intel_dvo_connector_funcs = {
- .dpms = intel_dvo_dpms,
+ .dpms = drm_helper_connector_dpms,
.detect = intel_dvo_detect,
.destroy = intel_dvo_destroy,
.fill_modes = drm_helper_probe_single_connector_modes,
@@ -439,11 +364,6 @@ void intel_dvo_init(struct drm_device *dev)
drm_encoder_init(dev, &intel_encoder->base,
&intel_dvo_enc_funcs, encoder_type);
- intel_encoder->disable = intel_disable_dvo;
- intel_encoder->enable = intel_enable_dvo;
- intel_encoder->get_hw_state = intel_dvo_get_hw_state;
- intel_connector->get_hw_state = intel_dvo_connector_get_hw_state;
-
/* Now, try to find a controller */
for (i = 0; i < ARRAY_SIZE(intel_dvo_devices); i++) {
struct drm_connector *connector = &intel_connector->base;
@@ -476,14 +396,17 @@ void intel_dvo_init(struct drm_device *dev)
intel_encoder->crtc_mask = (1 << 0) | (1 << 1);
switch (dvo->type) {
case INTEL_DVO_CHIP_TMDS:
- intel_encoder->cloneable = true;
+ intel_encoder->clone_mask =
+ (1 << INTEL_DVO_TMDS_CLONE_BIT) |
+ (1 << INTEL_ANALOG_CLONE_BIT);
drm_connector_init(dev, connector,
&intel_dvo_connector_funcs,
DRM_MODE_CONNECTOR_DVII);
encoder_type = DRM_MODE_ENCODER_TMDS;
break;
case INTEL_DVO_CHIP_LVDS:
- intel_encoder->cloneable = false;
+ intel_encoder->clone_mask =
+ (1 << INTEL_DVO_LVDS_CLONE_BIT);
drm_connector_init(dev, connector,
&intel_dvo_connector_funcs,
DRM_MODE_CONNECTOR_LVDS);
diff --git a/trunk/drivers/gpu/drm/i915/intel_hdmi.c b/trunk/drivers/gpu/drm/i915/intel_hdmi.c
index 08f2b63d740a..98f602427eb8 100644
--- a/trunk/drivers/gpu/drm/i915/intel_hdmi.c
+++ b/trunk/drivers/gpu/drm/i915/intel_hdmi.c
@@ -151,9 +151,6 @@ static void g4x_write_infoframe(struct drm_encoder *encoder,
I915_WRITE(VIDEO_DIP_DATA, *data);
data++;
}
- /* Write every possible data byte to force correct ECC calculation. */
- for (; i < VIDEO_DIP_DATA_SIZE; i += 4)
- I915_WRITE(VIDEO_DIP_DATA, 0);
mmiowb();
val |= g4x_infoframe_enable(frame);
@@ -189,9 +186,6 @@ static void ibx_write_infoframe(struct drm_encoder *encoder,
I915_WRITE(TVIDEO_DIP_DATA(intel_crtc->pipe), *data);
data++;
}
- /* Write every possible data byte to force correct ECC calculation. */
- for (; i < VIDEO_DIP_DATA_SIZE; i += 4)
- I915_WRITE(TVIDEO_DIP_DATA(intel_crtc->pipe), 0);
mmiowb();
val |= g4x_infoframe_enable(frame);
@@ -230,9 +224,6 @@ static void cpt_write_infoframe(struct drm_encoder *encoder,
I915_WRITE(TVIDEO_DIP_DATA(intel_crtc->pipe), *data);
data++;
}
- /* Write every possible data byte to force correct ECC calculation. */
- for (; i < VIDEO_DIP_DATA_SIZE; i += 4)
- I915_WRITE(TVIDEO_DIP_DATA(intel_crtc->pipe), 0);
mmiowb();
val |= g4x_infoframe_enable(frame);
@@ -268,9 +259,6 @@ static void vlv_write_infoframe(struct drm_encoder *encoder,
I915_WRITE(VLV_TVIDEO_DIP_DATA(intel_crtc->pipe), *data);
data++;
}
- /* Write every possible data byte to force correct ECC calculation. */
- for (; i < VIDEO_DIP_DATA_SIZE; i += 4)
- I915_WRITE(VLV_TVIDEO_DIP_DATA(intel_crtc->pipe), 0);
mmiowb();
val |= g4x_infoframe_enable(frame);
@@ -304,9 +292,6 @@ static void hsw_write_infoframe(struct drm_encoder *encoder,
I915_WRITE(data_reg + i, *data);
data++;
}
- /* Write every possible data byte to force correct ECC calculation. */
- for (; i < VIDEO_DIP_DATA_SIZE; i += 4)
- I915_WRITE(data_reg + i, 0);
mmiowb();
val |= hsw_infoframe_enable(frame);
@@ -392,7 +377,6 @@ static void g4x_set_infoframes(struct drm_encoder *encoder,
port = VIDEO_DIP_PORT_C;
break;
default:
- BUG();
return;
}
@@ -451,7 +435,6 @@ static void ibx_set_infoframes(struct drm_encoder *encoder,
port = VIDEO_DIP_PORT_D;
break;
default:
- BUG();
return;
}
@@ -618,32 +601,11 @@ static void intel_hdmi_mode_set(struct drm_encoder *encoder,
intel_hdmi->set_infoframes(encoder, adjusted_mode);
}
-static bool intel_hdmi_get_hw_state(struct intel_encoder *encoder,
- enum pipe *pipe)
-{
- struct drm_device *dev = encoder->base.dev;
- struct drm_i915_private *dev_priv = dev->dev_private;
- struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&encoder->base);
- u32 tmp;
-
- tmp = I915_READ(intel_hdmi->sdvox_reg);
-
- if (!(tmp & SDVO_ENABLE))
- return false;
-
- if (HAS_PCH_CPT(dev))
- *pipe = PORT_TO_PIPE_CPT(tmp);
- else
- *pipe = PORT_TO_PIPE(tmp);
-
- return true;
-}
-
-static void intel_enable_hdmi(struct intel_encoder *encoder)
+static void intel_hdmi_dpms(struct drm_encoder *encoder, int mode)
{
- struct drm_device *dev = encoder->base.dev;
+ struct drm_device *dev = encoder->dev;
struct drm_i915_private *dev_priv = dev->dev_private;
- struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&encoder->base);
+ struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder);
u32 temp;
u32 enable_bits = SDVO_ENABLE;
@@ -655,67 +617,30 @@ static void intel_enable_hdmi(struct intel_encoder *encoder)
/* HW workaround for IBX, we need to move the port to transcoder A
* before disabling it. */
if (HAS_PCH_IBX(dev)) {
- struct drm_crtc *crtc = encoder->base.crtc;
- int pipe = crtc ? to_intel_crtc(crtc)->pipe : -1;
-
- /* Restore the transcoder select bit. */
- if (pipe == PIPE_B)
- enable_bits |= SDVO_PIPE_B_SELECT;
- }
-
- /* HW workaround, need to toggle enable bit off and on for 12bpc, but
- * we do this anyway which shows more stable in testing.
- */
- if (HAS_PCH_SPLIT(dev)) {
- I915_WRITE(intel_hdmi->sdvox_reg, temp & ~SDVO_ENABLE);
- POSTING_READ(intel_hdmi->sdvox_reg);
- }
-
- temp |= enable_bits;
-
- I915_WRITE(intel_hdmi->sdvox_reg, temp);
- POSTING_READ(intel_hdmi->sdvox_reg);
-
- /* HW workaround, need to write this twice for issue that may result
- * in first write getting masked.
- */
- if (HAS_PCH_SPLIT(dev)) {
- I915_WRITE(intel_hdmi->sdvox_reg, temp);
- POSTING_READ(intel_hdmi->sdvox_reg);
- }
-}
-
-static void intel_disable_hdmi(struct intel_encoder *encoder)
-{
- struct drm_device *dev = encoder->base.dev;
- struct drm_i915_private *dev_priv = dev->dev_private;
- struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&encoder->base);
- u32 temp;
- u32 enable_bits = SDVO_ENABLE | SDVO_AUDIO_ENABLE;
-
- temp = I915_READ(intel_hdmi->sdvox_reg);
-
- /* HW workaround for IBX, we need to move the port to transcoder A
- * before disabling it. */
- if (HAS_PCH_IBX(dev)) {
- struct drm_crtc *crtc = encoder->base.crtc;
+ struct drm_crtc *crtc = encoder->crtc;
int pipe = crtc ? to_intel_crtc(crtc)->pipe : -1;
- if (temp & SDVO_PIPE_B_SELECT) {
- temp &= ~SDVO_PIPE_B_SELECT;
- I915_WRITE(intel_hdmi->sdvox_reg, temp);
- POSTING_READ(intel_hdmi->sdvox_reg);
-
- /* Again we need to write this twice. */
- I915_WRITE(intel_hdmi->sdvox_reg, temp);
- POSTING_READ(intel_hdmi->sdvox_reg);
-
- /* Transcoder selection bits only update
- * effectively on vblank. */
- if (crtc)
- intel_wait_for_vblank(dev, pipe);
- else
- msleep(50);
+ if (mode != DRM_MODE_DPMS_ON) {
+ if (temp & SDVO_PIPE_B_SELECT) {
+ temp &= ~SDVO_PIPE_B_SELECT;
+ I915_WRITE(intel_hdmi->sdvox_reg, temp);
+ POSTING_READ(intel_hdmi->sdvox_reg);
+
+ /* Again we need to write this twice. */
+ I915_WRITE(intel_hdmi->sdvox_reg, temp);
+ POSTING_READ(intel_hdmi->sdvox_reg);
+
+ /* Transcoder selection bits only update
+ * effectively on vblank. */
+ if (crtc)
+ intel_wait_for_vblank(dev, pipe);
+ else
+ msleep(50);
+ }
+ } else {
+ /* Restore the transcoder select bit. */
+ if (pipe == PIPE_B)
+ enable_bits |= SDVO_PIPE_B_SELECT;
}
}
@@ -727,7 +652,11 @@ static void intel_disable_hdmi(struct intel_encoder *encoder)
POSTING_READ(intel_hdmi->sdvox_reg);
}
- temp &= ~enable_bits;
+ if (mode != DRM_MODE_DPMS_ON) {
+ temp &= ~enable_bits;
+ } else {
+ temp |= enable_bits;
+ }
I915_WRITE(intel_hdmi->sdvox_reg, temp);
POSTING_READ(intel_hdmi->sdvox_reg);
@@ -808,6 +737,7 @@ intel_hdmi_detect(struct drm_connector *connector, bool force)
drm_detect_hdmi_monitor(edid);
intel_hdmi->has_audio = drm_detect_monitor_audio(edid);
}
+ connector->display_info.raw_edid = NULL;
kfree(edid);
}
@@ -848,6 +778,8 @@ intel_hdmi_detect_audio(struct drm_connector *connector)
if (edid) {
if (edid->input & DRM_EDID_INPUT_DIGITAL)
has_audio = drm_detect_monitor_audio(edid);
+
+ connector->display_info.raw_edid = NULL;
kfree(edid);
}
@@ -901,8 +833,9 @@ intel_hdmi_set_property(struct drm_connector *connector,
done:
if (intel_hdmi->base.base.crtc) {
struct drm_crtc *crtc = intel_hdmi->base.base.crtc;
- intel_set_mode(crtc, &crtc->mode,
- crtc->x, crtc->y, crtc->fb);
+ drm_crtc_helper_set_mode(crtc, &crtc->mode,
+ crtc->x, crtc->y,
+ crtc->fb);
}
return 0;
@@ -916,19 +849,23 @@ static void intel_hdmi_destroy(struct drm_connector *connector)
}
static const struct drm_encoder_helper_funcs intel_hdmi_helper_funcs_hsw = {
+ .dpms = intel_ddi_dpms,
.mode_fixup = intel_hdmi_mode_fixup,
+ .prepare = intel_encoder_prepare,
.mode_set = intel_ddi_mode_set,
- .disable = intel_encoder_noop,
+ .commit = intel_encoder_commit,
};
static const struct drm_encoder_helper_funcs intel_hdmi_helper_funcs = {
+ .dpms = intel_hdmi_dpms,
.mode_fixup = intel_hdmi_mode_fixup,
+ .prepare = intel_encoder_prepare,
.mode_set = intel_hdmi_mode_set,
- .disable = intel_encoder_noop,
+ .commit = intel_encoder_commit,
};
static const struct drm_connector_funcs intel_hdmi_connector_funcs = {
- .dpms = intel_connector_dpms,
+ .dpms = drm_helper_connector_dpms,
.detect = intel_hdmi_detect,
.fill_modes = drm_helper_probe_single_connector_modes,
.set_property = intel_hdmi_set_property,
@@ -952,7 +889,7 @@ intel_hdmi_add_properties(struct intel_hdmi *intel_hdmi, struct drm_connector *c
intel_attach_broadcast_rgb_property(connector);
}
-void intel_hdmi_init(struct drm_device *dev, int sdvox_reg, enum port port)
+void intel_hdmi_init(struct drm_device *dev, int sdvox_reg)
{
struct drm_i915_private *dev_priv = dev->dev_private;
struct drm_connector *connector;
@@ -986,25 +923,48 @@ void intel_hdmi_init(struct drm_device *dev, int sdvox_reg, enum port port)
connector->doublescan_allowed = 0;
intel_encoder->crtc_mask = (1 << 0) | (1 << 1) | (1 << 2);
- intel_encoder->cloneable = false;
-
- intel_hdmi->ddi_port = port;
- switch (port) {
- case PORT_B:
+ /* Set up the DDC bus. */
+ if (sdvox_reg == SDVOB) {
+ intel_encoder->clone_mask = (1 << INTEL_HDMIB_CLONE_BIT);
intel_hdmi->ddc_bus = GMBUS_PORT_DPB;
dev_priv->hotplug_supported_mask |= HDMIB_HOTPLUG_INT_STATUS;
- break;
- case PORT_C:
+ } else if (sdvox_reg == SDVOC) {
+ intel_encoder->clone_mask = (1 << INTEL_HDMIC_CLONE_BIT);
intel_hdmi->ddc_bus = GMBUS_PORT_DPC;
dev_priv->hotplug_supported_mask |= HDMIC_HOTPLUG_INT_STATUS;
- break;
- case PORT_D:
+ } else if (sdvox_reg == HDMIB) {
+ intel_encoder->clone_mask = (1 << INTEL_HDMID_CLONE_BIT);
+ intel_hdmi->ddc_bus = GMBUS_PORT_DPB;
+ dev_priv->hotplug_supported_mask |= HDMIB_HOTPLUG_INT_STATUS;
+ } else if (sdvox_reg == HDMIC) {
+ intel_encoder->clone_mask = (1 << INTEL_HDMIE_CLONE_BIT);
+ intel_hdmi->ddc_bus = GMBUS_PORT_DPC;
+ dev_priv->hotplug_supported_mask |= HDMIC_HOTPLUG_INT_STATUS;
+ } else if (sdvox_reg == HDMID) {
+ intel_encoder->clone_mask = (1 << INTEL_HDMIF_CLONE_BIT);
intel_hdmi->ddc_bus = GMBUS_PORT_DPD;
dev_priv->hotplug_supported_mask |= HDMID_HOTPLUG_INT_STATUS;
- break;
- case PORT_A:
- /* Internal port only for eDP. */
- default:
+ } else if (sdvox_reg == DDI_BUF_CTL(PORT_B)) {
+ DRM_DEBUG_DRIVER("LPT: detected output on DDI B\n");
+ intel_encoder->clone_mask = (1 << INTEL_HDMIB_CLONE_BIT);
+ intel_hdmi->ddc_bus = GMBUS_PORT_DPB;
+ intel_hdmi->ddi_port = PORT_B;
+ dev_priv->hotplug_supported_mask |= HDMIB_HOTPLUG_INT_STATUS;
+ } else if (sdvox_reg == DDI_BUF_CTL(PORT_C)) {
+ DRM_DEBUG_DRIVER("LPT: detected output on DDI C\n");
+ intel_encoder->clone_mask = (1 << INTEL_HDMIC_CLONE_BIT);
+ intel_hdmi->ddc_bus = GMBUS_PORT_DPC;
+ intel_hdmi->ddi_port = PORT_C;
+ dev_priv->hotplug_supported_mask |= HDMIC_HOTPLUG_INT_STATUS;
+ } else if (sdvox_reg == DDI_BUF_CTL(PORT_D)) {
+ DRM_DEBUG_DRIVER("LPT: detected output on DDI D\n");
+ intel_encoder->clone_mask = (1 << INTEL_HDMID_CLONE_BIT);
+ intel_hdmi->ddc_bus = GMBUS_PORT_DPD;
+ intel_hdmi->ddi_port = PORT_D;
+ dev_priv->hotplug_supported_mask |= HDMID_HOTPLUG_INT_STATUS;
+ } else {
+ /* If we got an unknown sdvox_reg, things are pretty much broken
+ * in a way that we should let the kernel know about it */
BUG();
}
@@ -1027,21 +987,10 @@ void intel_hdmi_init(struct drm_device *dev, int sdvox_reg, enum port port)
intel_hdmi->set_infoframes = cpt_set_infoframes;
}
- if (IS_HASWELL(dev)) {
- intel_encoder->enable = intel_enable_ddi;
- intel_encoder->disable = intel_disable_ddi;
- intel_encoder->get_hw_state = intel_ddi_get_hw_state;
- drm_encoder_helper_add(&intel_encoder->base,
- &intel_hdmi_helper_funcs_hsw);
- } else {
- intel_encoder->enable = intel_enable_hdmi;
- intel_encoder->disable = intel_disable_hdmi;
- intel_encoder->get_hw_state = intel_hdmi_get_hw_state;
- drm_encoder_helper_add(&intel_encoder->base,
- &intel_hdmi_helper_funcs);
- }
- intel_connector->get_hw_state = intel_connector_get_hw_state;
-
+ if (IS_HASWELL(dev))
+ drm_encoder_helper_add(&intel_encoder->base, &intel_hdmi_helper_funcs_hsw);
+ else
+ drm_encoder_helper_add(&intel_encoder->base, &intel_hdmi_helper_funcs);
intel_hdmi_add_properties(intel_hdmi, connector);
diff --git a/trunk/drivers/gpu/drm/i915/intel_lvds.c b/trunk/drivers/gpu/drm/i915/intel_lvds.c
index 40d72bd64e11..e9a6f6aaed85 100644
--- a/trunk/drivers/gpu/drm/i915/intel_lvds.c
+++ b/trunk/drivers/gpu/drm/i915/intel_lvds.c
@@ -65,40 +65,13 @@ static struct intel_lvds *intel_attached_lvds(struct drm_connector *connector)
struct intel_lvds, base);
}
-static bool intel_lvds_get_hw_state(struct intel_encoder *encoder,
- enum pipe *pipe)
-{
- struct drm_device *dev = encoder->base.dev;
- struct drm_i915_private *dev_priv = dev->dev_private;
- u32 lvds_reg, tmp;
-
- if (HAS_PCH_SPLIT(dev)) {
- lvds_reg = PCH_LVDS;
- } else {
- lvds_reg = LVDS;
- }
-
- tmp = I915_READ(lvds_reg);
-
- if (!(tmp & LVDS_PORT_EN))
- return false;
-
- if (HAS_PCH_CPT(dev))
- *pipe = PORT_TO_PIPE_CPT(tmp);
- else
- *pipe = PORT_TO_PIPE(tmp);
-
- return true;
-}
-
/**
* Sets the power state for the panel.
*/
-static void intel_enable_lvds(struct intel_encoder *encoder)
+static void intel_lvds_enable(struct intel_lvds *intel_lvds)
{
- struct drm_device *dev = encoder->base.dev;
- struct intel_lvds *intel_lvds = to_intel_lvds(&encoder->base);
- struct intel_crtc *intel_crtc = to_intel_crtc(encoder->base.crtc);
+ struct drm_device *dev = intel_lvds->base.base.dev;
+ struct intel_crtc *intel_crtc = to_intel_crtc(intel_lvds->base.base.crtc);
struct drm_i915_private *dev_priv = dev->dev_private;
u32 ctl_reg, lvds_reg, stat_reg;
@@ -138,10 +111,9 @@ static void intel_enable_lvds(struct intel_encoder *encoder)
intel_panel_enable_backlight(dev, intel_crtc->pipe);
}
-static void intel_disable_lvds(struct intel_encoder *encoder)
+static void intel_lvds_disable(struct intel_lvds *intel_lvds)
{
- struct drm_device *dev = encoder->base.dev;
- struct intel_lvds *intel_lvds = to_intel_lvds(&encoder->base);
+ struct drm_device *dev = intel_lvds->base.base.dev;
struct drm_i915_private *dev_priv = dev->dev_private;
u32 ctl_reg, lvds_reg, stat_reg;
@@ -170,6 +142,18 @@ static void intel_disable_lvds(struct intel_encoder *encoder)
POSTING_READ(lvds_reg);
}
+static void intel_lvds_dpms(struct drm_encoder *encoder, int mode)
+{
+ struct intel_lvds *intel_lvds = to_intel_lvds(encoder);
+
+ if (mode == DRM_MODE_DPMS_ON)
+ intel_lvds_enable(intel_lvds);
+ else
+ intel_lvds_disable(intel_lvds);
+
+ /* XXX: We never power down the LVDS pairs. */
+}
+
static int intel_lvds_mode_valid(struct drm_connector *connector,
struct drm_display_mode *mode)
{
@@ -250,8 +234,9 @@ static bool intel_lvds_mode_fixup(struct drm_encoder *encoder,
{
struct drm_device *dev = encoder->dev;
struct drm_i915_private *dev_priv = dev->dev_private;
+ struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc);
struct intel_lvds *intel_lvds = to_intel_lvds(encoder);
- struct intel_crtc *intel_crtc = intel_lvds->base.new_crtc;
+ struct intel_encoder *tmp_encoder;
u32 pfit_control = 0, pfit_pgm_ratios = 0, border = 0;
int pipe;
@@ -261,8 +246,14 @@ static bool intel_lvds_mode_fixup(struct drm_encoder *encoder,
return false;
}
- if (intel_encoder_check_is_cloned(&intel_lvds->base))
- return false;
+ /* Should never happen!! */
+ for_each_encoder_on_crtc(dev, encoder->crtc, tmp_encoder) {
+ if (&tmp_encoder->base != encoder) {
+ DRM_ERROR("Can't enable LVDS and another "
+ "encoder on the same pipe\n");
+ return false;
+ }
+ }
/*
* We have timings from the BIOS for the panel, put them in
@@ -414,6 +405,23 @@ static bool intel_lvds_mode_fixup(struct drm_encoder *encoder,
return true;
}
+static void intel_lvds_prepare(struct drm_encoder *encoder)
+{
+ struct intel_lvds *intel_lvds = to_intel_lvds(encoder);
+
+ intel_lvds_disable(intel_lvds);
+}
+
+static void intel_lvds_commit(struct drm_encoder *encoder)
+{
+ struct intel_lvds *intel_lvds = to_intel_lvds(encoder);
+
+ /* Always do a full power on as we do not know what state
+ * we were left in.
+ */
+ intel_lvds_enable(intel_lvds);
+}
+
static void intel_lvds_mode_set(struct drm_encoder *encoder,
struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode)
@@ -527,7 +535,7 @@ static int intel_lid_notify(struct notifier_block *nb, unsigned long val,
dev_priv->modeset_on_lid = 0;
mutex_lock(&dev->mode_config.mutex);
- intel_modeset_check_state(dev);
+ drm_helper_resume_force_mode(dev);
mutex_unlock(&dev->mode_config.mutex);
return NOTIFY_OK;
@@ -579,8 +587,8 @@ 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);
+ drm_crtc_helper_set_mode(crtc, &crtc->mode,
+ crtc->x, crtc->y, crtc->fb);
}
}
@@ -588,9 +596,11 @@ static int intel_lvds_set_property(struct drm_connector *connector,
}
static const struct drm_encoder_helper_funcs intel_lvds_helper_funcs = {
+ .dpms = intel_lvds_dpms,
.mode_fixup = intel_lvds_mode_fixup,
+ .prepare = intel_lvds_prepare,
.mode_set = intel_lvds_mode_set,
- .disable = intel_encoder_noop,
+ .commit = intel_lvds_commit,
};
static const struct drm_connector_helper_funcs intel_lvds_connector_helper_funcs = {
@@ -600,7 +610,7 @@ static const struct drm_connector_helper_funcs intel_lvds_connector_helper_funcs
};
static const struct drm_connector_funcs intel_lvds_connector_funcs = {
- .dpms = intel_connector_dpms,
+ .dpms = drm_helper_connector_dpms,
.detect = intel_lvds_detect,
.fill_modes = drm_helper_probe_single_connector_modes,
.set_property = intel_lvds_set_property,
@@ -962,15 +972,10 @@ bool intel_lvds_init(struct drm_device *dev)
drm_encoder_init(dev, &intel_encoder->base, &intel_lvds_enc_funcs,
DRM_MODE_ENCODER_LVDS);
- intel_encoder->enable = intel_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;
-
intel_connector_attach_encoder(intel_connector, intel_encoder);
intel_encoder->type = INTEL_OUTPUT_LVDS;
- intel_encoder->cloneable = false;
+ intel_encoder->clone_mask = (1 << INTEL_LVDS_CLONE_BIT);
if (HAS_PCH_SPLIT(dev))
intel_encoder->crtc_mask = (1 << 0) | (1 << 1) | (1 << 2);
else if (IS_GEN4(dev))
diff --git a/trunk/drivers/gpu/drm/i915/intel_modes.c b/trunk/drivers/gpu/drm/i915/intel_modes.c
index 4bc1c0fc342a..29b72593fbb2 100644
--- a/trunk/drivers/gpu/drm/i915/intel_modes.c
+++ b/trunk/drivers/gpu/drm/i915/intel_modes.c
@@ -45,6 +45,7 @@ int intel_connector_update_modes(struct drm_connector *connector,
drm_mode_connector_update_edid_property(connector, edid);
ret = drm_add_edid_modes(connector, edid);
drm_edid_to_eld(connector, edid);
+ connector->display_info.raw_edid = NULL;
kfree(edid);
return ret;
diff --git a/trunk/drivers/gpu/drm/i915/intel_opregion.c b/trunk/drivers/gpu/drm/i915/intel_opregion.c
index e27c17012628..18bd0af855dc 100644
--- a/trunk/drivers/gpu/drm/i915/intel_opregion.c
+++ b/trunk/drivers/gpu/drm/i915/intel_opregion.c
@@ -427,25 +427,6 @@ static void intel_didl_outputs(struct drm_device *dev)
goto end;
}
-static void intel_setup_cadls(struct drm_device *dev)
-{
- struct drm_i915_private *dev_priv = dev->dev_private;
- struct intel_opregion *opregion = &dev_priv->opregion;
- int i = 0;
- u32 disp_id;
-
- /* Initialize the CADL field by duplicating the DIDL values.
- * Technically, this is not always correct as display outputs may exist,
- * but not active. This initialization is necessary for some Clevo
- * laptops that check this field before processing the brightness and
- * display switching hotkeys. Just like DIDL, CADL is NULL-terminated if
- * there are less than eight devices. */
- do {
- disp_id = ioread32(&opregion->acpi->didl[i]);
- iowrite32(disp_id, &opregion->acpi->cadl[i]);
- } while (++i < 8 && disp_id != 0);
-}
-
void intel_opregion_init(struct drm_device *dev)
{
struct drm_i915_private *dev_priv = dev->dev_private;
@@ -455,10 +436,8 @@ void intel_opregion_init(struct drm_device *dev)
return;
if (opregion->acpi) {
- if (drm_core_check_feature(dev, DRIVER_MODESET)) {
+ if (drm_core_check_feature(dev, DRIVER_MODESET))
intel_didl_outputs(dev);
- intel_setup_cadls(dev);
- }
/* Notify BIOS we are ready to handle ACPI video ext notifs.
* Right now, all the events are handled by the ACPI video module.
diff --git a/trunk/drivers/gpu/drm/i915/intel_overlay.c b/trunk/drivers/gpu/drm/i915/intel_overlay.c
index afd0f30ab882..830d0dd610e1 100644
--- a/trunk/drivers/gpu/drm/i915/intel_overlay.c
+++ b/trunk/drivers/gpu/drm/i915/intel_overlay.c
@@ -235,6 +235,54 @@ static int intel_overlay_do_wait_request(struct intel_overlay *overlay,
return 0;
}
+/* Workaround for i830 bug where pipe a must be enable to change control regs */
+static int
+i830_activate_pipe_a(struct drm_device *dev)
+{
+ drm_i915_private_t *dev_priv = dev->dev_private;
+ struct intel_crtc *crtc;
+ struct drm_crtc_helper_funcs *crtc_funcs;
+ struct drm_display_mode vesa_640x480 = {
+ 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)
+ }, *mode;
+
+ crtc = to_intel_crtc(dev_priv->pipe_to_crtc_mapping[0]);
+ if (crtc->dpms_mode == DRM_MODE_DPMS_ON)
+ return 0;
+
+ /* most i8xx have pipe a forced on, so don't trust dpms mode */
+ if (I915_READ(_PIPEACONF) & PIPECONF_ENABLE)
+ return 0;
+
+ crtc_funcs = crtc->base.helper_private;
+ if (crtc_funcs->dpms == NULL)
+ return 0;
+
+ DRM_DEBUG_DRIVER("Enabling pipe A in order to enable overlay\n");
+
+ mode = drm_mode_duplicate(dev, &vesa_640x480);
+
+ if (!drm_crtc_helper_set_mode(&crtc->base, mode,
+ crtc->base.x, crtc->base.y,
+ crtc->base.fb))
+ return 0;
+
+ crtc_funcs->dpms(&crtc->base, DRM_MODE_DPMS_ON);
+ return 1;
+}
+
+static void
+i830_deactivate_pipe_a(struct drm_device *dev)
+{
+ drm_i915_private_t *dev_priv = dev->dev_private;
+ struct drm_crtc *crtc = dev_priv->pipe_to_crtc_mapping[0];
+ struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private;
+
+ crtc_funcs->dpms(crtc, DRM_MODE_DPMS_OFF);
+}
+
/* overlay needs to be disable in OCMD reg */
static int intel_overlay_on(struct intel_overlay *overlay)
{
@@ -242,12 +290,17 @@ static int intel_overlay_on(struct intel_overlay *overlay)
struct drm_i915_private *dev_priv = dev->dev_private;
struct intel_ring_buffer *ring = &dev_priv->ring[RCS];
struct drm_i915_gem_request *request;
+ int pipe_a_quirk = 0;
int ret;
BUG_ON(overlay->active);
overlay->active = 1;
- WARN_ON(IS_I830(dev) && !(dev_priv->quirks & QUIRK_PIPEA_FORCE));
+ if (IS_I830(dev)) {
+ pipe_a_quirk = i830_activate_pipe_a(dev);
+ if (pipe_a_quirk < 0)
+ return pipe_a_quirk;
+ }
request = kzalloc(sizeof(*request), GFP_KERNEL);
if (request == NULL) {
@@ -269,6 +322,9 @@ static int intel_overlay_on(struct intel_overlay *overlay)
ret = intel_overlay_do_wait_request(overlay, request, NULL);
out:
+ if (pipe_a_quirk)
+ i830_deactivate_pipe_a(dev);
+
return ret;
}
@@ -1383,7 +1439,7 @@ void intel_setup_overlay(struct drm_device *dev)
}
overlay->flip_addr = reg_bo->phys_obj->handle->busaddr;
} else {
- ret = i915_gem_object_pin(reg_bo, PAGE_SIZE, true, false);
+ ret = i915_gem_object_pin(reg_bo, PAGE_SIZE, true);
if (ret) {
DRM_ERROR("failed to pin overlay register bo\n");
goto out_free_bo;
diff --git a/trunk/drivers/gpu/drm/i915/intel_pm.c b/trunk/drivers/gpu/drm/i915/intel_pm.c
index d69f8f49beb5..ba8a27b1757a 100644
--- a/trunk/drivers/gpu/drm/i915/intel_pm.c
+++ b/trunk/drivers/gpu/drm/i915/intel_pm.c
@@ -31,8 +31,6 @@
#include "../../../platform/x86/intel_ips.h"
#include
-#define FORCEWAKE_ACK_TIMEOUT_MS 2
-
/* FBC, or Frame Buffer Compression, is a technique employed to compress the
* framebuffer contents in-memory, aiming at reducing the required bandwidth
* during in-memory transfers and, therefore, reduce the power packet.
@@ -595,7 +593,7 @@ static void i915_ironlake_get_mem_freq(struct drm_device *dev)
break;
}
- dev_priv->ips.r_t = dev_priv->mem_freq;
+ dev_priv->r_t = dev_priv->mem_freq;
switch (csipll & 0x3ff) {
case 0x00c:
@@ -627,11 +625,11 @@ static void i915_ironlake_get_mem_freq(struct drm_device *dev)
}
if (dev_priv->fsb_freq == 3200) {
- dev_priv->ips.c_m = 0;
+ dev_priv->c_m = 0;
} else if (dev_priv->fsb_freq > 3200 && dev_priv->fsb_freq <= 4800) {
- dev_priv->ips.c_m = 1;
+ dev_priv->c_m = 1;
} else {
- dev_priv->ips.c_m = 2;
+ dev_priv->c_m = 2;
}
}
@@ -2140,7 +2138,7 @@ intel_alloc_context_page(struct drm_device *dev)
return NULL;
}
- ret = i915_gem_object_pin(ctx, 4096, true, false);
+ ret = i915_gem_object_pin(ctx, 4096, true);
if (ret) {
DRM_ERROR("failed to pin power context: %d\n", ret);
goto err_unref;
@@ -2162,22 +2160,11 @@ intel_alloc_context_page(struct drm_device *dev)
return NULL;
}
-/**
- * Lock protecting IPS related data structures
- */
-DEFINE_SPINLOCK(mchdev_lock);
-
-/* Global for IPS driver to get at the current i915 device. Protected by
- * mchdev_lock. */
-static struct drm_i915_private *i915_mch_dev;
-
bool ironlake_set_drps(struct drm_device *dev, u8 val)
{
struct drm_i915_private *dev_priv = dev->dev_private;
u16 rgvswctl;
- assert_spin_locked(&mchdev_lock);
-
rgvswctl = I915_READ16(MEMSWCTL);
if (rgvswctl & MEMCTL_CMD_STS) {
DRM_DEBUG("gpu busy, RCS change rejected\n");
@@ -2201,8 +2188,6 @@ static void ironlake_enable_drps(struct drm_device *dev)
u32 rgvmodectl = I915_READ(MEMMODECTL);
u8 fmax, fmin, fstart, vstart;
- spin_lock_irq(&mchdev_lock);
-
/* Enable temp reporting */
I915_WRITE16(PMMISC, I915_READ(PMMISC) | MCPPCE_EN);
I915_WRITE16(TSC1, I915_READ(TSC1) | TSE);
@@ -2226,12 +2211,12 @@ static void ironlake_enable_drps(struct drm_device *dev)
vstart = (I915_READ(PXVFREQ_BASE + (fstart * 4)) & PXVFREQ_PX_MASK) >>
PXVFREQ_PX_SHIFT;
- dev_priv->ips.fmax = fmax; /* IPS callback will increase this */
- dev_priv->ips.fstart = fstart;
+ dev_priv->fmax = fmax; /* IPS callback will increase this */
+ dev_priv->fstart = fstart;
- dev_priv->ips.max_delay = fstart;
- dev_priv->ips.min_delay = fmin;
- dev_priv->ips.cur_delay = fstart;
+ dev_priv->max_delay = fstart;
+ dev_priv->min_delay = fmin;
+ dev_priv->cur_delay = fstart;
DRM_DEBUG_DRIVER("fmax: %d, fmin: %d, fstart: %d\n",
fmax, fmin, fstart);
@@ -2248,29 +2233,23 @@ static void ironlake_enable_drps(struct drm_device *dev)
rgvmodectl |= MEMMODE_SWMODE_EN;
I915_WRITE(MEMMODECTL, rgvmodectl);
- if (wait_for_atomic((I915_READ(MEMSWCTL) & MEMCTL_CMD_STS) == 0, 10))
+ if (wait_for((I915_READ(MEMSWCTL) & MEMCTL_CMD_STS) == 0, 10))
DRM_ERROR("stuck trying to change perf mode\n");
- mdelay(1);
+ msleep(1);
ironlake_set_drps(dev, fstart);
- dev_priv->ips.last_count1 = I915_READ(0x112e4) + I915_READ(0x112e8) +
+ dev_priv->last_count1 = I915_READ(0x112e4) + I915_READ(0x112e8) +
I915_READ(0x112e0);
- dev_priv->ips.last_time1 = jiffies_to_msecs(jiffies);
- dev_priv->ips.last_count2 = I915_READ(0x112f4);
- getrawmonotonic(&dev_priv->ips.last_time2);
-
- spin_unlock_irq(&mchdev_lock);
+ dev_priv->last_time1 = jiffies_to_msecs(jiffies);
+ dev_priv->last_count2 = I915_READ(0x112f4);
+ getrawmonotonic(&dev_priv->last_time2);
}
static void ironlake_disable_drps(struct drm_device *dev)
{
struct drm_i915_private *dev_priv = dev->dev_private;
- u16 rgvswctl;
-
- spin_lock_irq(&mchdev_lock);
-
- rgvswctl = I915_READ16(MEMSWCTL);
+ u16 rgvswctl = I915_READ16(MEMSWCTL);
/* Ack interrupts, disable EFC interrupt */
I915_WRITE(MEMINTREN, I915_READ(MEMINTREN) & ~MEMINT_EVAL_CHG_EN);
@@ -2280,54 +2259,31 @@ static void ironlake_disable_drps(struct drm_device *dev)
I915_WRITE(DEIMR, I915_READ(DEIMR) | DE_PCU_EVENT);
/* Go back to the starting frequency */
- ironlake_set_drps(dev, dev_priv->ips.fstart);
- mdelay(1);
+ ironlake_set_drps(dev, dev_priv->fstart);
+ msleep(1);
rgvswctl |= MEMCTL_CMD_STS;
I915_WRITE(MEMSWCTL, rgvswctl);
- mdelay(1);
+ msleep(1);
- spin_unlock_irq(&mchdev_lock);
}
-/* There's a funny hw issue where the hw returns all 0 when reading from
- * GEN6_RP_INTERRUPT_LIMITS. Hence we always need to compute the desired value
- * ourselves, instead of doing a rmw cycle (which might result in us clearing
- * all limits and the gpu stuck at whatever frequency it is at atm).
- */
-static u32 gen6_rps_limits(struct drm_i915_private *dev_priv, u8 *val)
+void gen6_set_rps(struct drm_device *dev, u8 val)
{
+ struct drm_i915_private *dev_priv = dev->dev_private;
u32 limits;
limits = 0;
+ if (val >= dev_priv->max_delay)
+ val = dev_priv->max_delay;
+ else
+ limits |= dev_priv->max_delay << 24;
- if (*val >= dev_priv->rps.max_delay)
- *val = dev_priv->rps.max_delay;
- limits |= dev_priv->rps.max_delay << 24;
-
- /* Only set the down limit when we've reached the lowest level to avoid
- * getting more interrupts, otherwise leave this clear. This prevents a
- * race in the hw when coming out of rc6: There's a tiny window where
- * the hw runs at the minimal clock before selecting the desired
- * frequency, if the down threshold expires in that window we will not
- * receive a down interrupt. */
- if (*val <= dev_priv->rps.min_delay) {
- *val = dev_priv->rps.min_delay;
- limits |= dev_priv->rps.min_delay << 16;
- }
-
- return limits;
-}
-
-void gen6_set_rps(struct drm_device *dev, u8 val)
-{
- struct drm_i915_private *dev_priv = dev->dev_private;
- u32 limits = gen6_rps_limits(dev_priv, &val);
-
- WARN_ON(!mutex_is_locked(&dev->struct_mutex));
- WARN_ON(val > dev_priv->rps.max_delay);
- WARN_ON(val < dev_priv->rps.min_delay);
+ if (val <= dev_priv->min_delay)
+ val = dev_priv->min_delay;
+ else
+ limits |= dev_priv->min_delay << 16;
- if (val == dev_priv->rps.cur_delay)
+ if (val == dev_priv->cur_delay)
return;
I915_WRITE(GEN6_RPNSWREQ,
@@ -2340,11 +2296,7 @@ void gen6_set_rps(struct drm_device *dev, u8 val)
*/
I915_WRITE(GEN6_RP_INTERRUPT_LIMITS, limits);
- POSTING_READ(GEN6_RPNSWREQ);
-
- dev_priv->rps.cur_delay = val;
-
- trace_intel_gpu_freq_change(val * 50);
+ dev_priv->cur_delay = val;
}
static void gen6_disable_rps(struct drm_device *dev)
@@ -2360,40 +2312,40 @@ static void gen6_disable_rps(struct drm_device *dev)
* register (PMIMR) to mask PM interrupts. The only risk is in leaving
* stale bits in PMIIR and PMIMR which gen6_enable_rps will clean up. */
- spin_lock_irq(&dev_priv->rps.lock);
- dev_priv->rps.pm_iir = 0;
- spin_unlock_irq(&dev_priv->rps.lock);
+ spin_lock_irq(&dev_priv->rps_lock);
+ dev_priv->pm_iir = 0;
+ spin_unlock_irq(&dev_priv->rps_lock);
I915_WRITE(GEN6_PMIIR, I915_READ(GEN6_PMIIR));
}
int intel_enable_rc6(const struct drm_device *dev)
{
- /* Respect the kernel parameter if it is set */
+ /*
+ * Respect the kernel parameter if it is set
+ */
if (i915_enable_rc6 >= 0)
return i915_enable_rc6;
- if (INTEL_INFO(dev)->gen == 5) {
-#ifdef CONFIG_INTEL_IOMMU
- /* Disable rc6 on ilk if VT-d is on. */
- if (intel_iommu_gfx_mapped)
- return false;
-#endif
- DRM_DEBUG_DRIVER("Ironlake: only RC6 available\n");
- return INTEL_RC6_ENABLE;
- }
+ /*
+ * Disable RC6 on Ironlake
+ */
+ if (INTEL_INFO(dev)->gen == 5)
+ return 0;
- if (IS_HASWELL(dev)) {
- DRM_DEBUG_DRIVER("Haswell: only RC6 available\n");
+ /* On Haswell, only RC6 is available. So let's enable it by default to
+ * provide better testing and coverage since the beginning.
+ */
+ if (IS_HASWELL(dev))
return INTEL_RC6_ENABLE;
- }
- /* snb/ivb have more than one rc6 state. */
+ /*
+ * Disable rc6 on Sandybridge
+ */
if (INTEL_INFO(dev)->gen == 6) {
DRM_DEBUG_DRIVER("Sandybridge: deep RC6 disabled\n");
return INTEL_RC6_ENABLE;
}
-
DRM_DEBUG_DRIVER("RC6 and deep RC6 enabled\n");
return (INTEL_RC6_ENABLE | INTEL_RC6p_ENABLE);
}
@@ -2431,9 +2383,9 @@ static void gen6_enable_rps(struct drm_device *dev)
gt_perf_status = I915_READ(GEN6_GT_PERF_STATUS);
/* In units of 100MHz */
- dev_priv->rps.max_delay = rp_state_cap & 0xff;
- dev_priv->rps.min_delay = (rp_state_cap & 0xff0000) >> 16;
- dev_priv->rps.cur_delay = 0;
+ dev_priv->max_delay = rp_state_cap & 0xff;
+ dev_priv->min_delay = (rp_state_cap & 0xff0000) >> 16;
+ dev_priv->cur_delay = 0;
/* disable the counters and set deterministic thresholds */
I915_WRITE(GEN6_RC_CONTROL, 0);
@@ -2486,8 +2438,8 @@ static void gen6_enable_rps(struct drm_device *dev)
I915_WRITE(GEN6_RP_DOWN_TIMEOUT, 1000000);
I915_WRITE(GEN6_RP_INTERRUPT_LIMITS,
- dev_priv->rps.max_delay << 24 |
- dev_priv->rps.min_delay << 16);
+ dev_priv->max_delay << 24 |
+ dev_priv->min_delay << 16);
I915_WRITE(GEN6_RP_UP_THRESHOLD, 59400);
I915_WRITE(GEN6_RP_DOWN_THRESHOLD, 245000);
@@ -2525,7 +2477,7 @@ static void gen6_enable_rps(struct drm_device *dev)
500))
DRM_ERROR("timeout waiting for pcode mailbox to finish\n");
if (pcu_mbox & (1<<31)) { /* OC supported */
- dev_priv->rps.max_delay = pcu_mbox & 0xff;
+ dev_priv->max_delay = pcu_mbox & 0xff;
DRM_DEBUG_DRIVER("overclocking supported, adjusting frequency max to %dMHz\n", pcu_mbox * 50);
}
@@ -2533,10 +2485,10 @@ static void gen6_enable_rps(struct drm_device *dev)
/* requires MSI enabled */
I915_WRITE(GEN6_PMIER, GEN6_PM_DEFERRED_EVENTS);
- spin_lock_irq(&dev_priv->rps.lock);
- WARN_ON(dev_priv->rps.pm_iir != 0);
+ spin_lock_irq(&dev_priv->rps_lock);
+ WARN_ON(dev_priv->pm_iir != 0);
I915_WRITE(GEN6_PMIMR, 0);
- spin_unlock_irq(&dev_priv->rps.lock);
+ spin_unlock_irq(&dev_priv->rps_lock);
/* enable all PM interrupts */
I915_WRITE(GEN6_PMINTRMSK, 0);
@@ -2568,9 +2520,9 @@ static void gen6_update_ring_freq(struct drm_device *dev)
* to use for memory access. We do this by specifying the IA frequency
* the PCU should use as a reference to determine the ring frequency.
*/
- for (gpu_freq = dev_priv->rps.max_delay; gpu_freq >= dev_priv->rps.min_delay;
+ for (gpu_freq = dev_priv->max_delay; gpu_freq >= dev_priv->min_delay;
gpu_freq--) {
- int diff = dev_priv->rps.max_delay - gpu_freq;
+ int diff = dev_priv->max_delay - gpu_freq;
/*
* For GPU frequencies less than 750MHz, just use the lowest
@@ -2734,16 +2686,14 @@ static const struct cparams {
{ 0, 800, 231, 23784 },
};
-static unsigned long __i915_chipset_val(struct drm_i915_private *dev_priv)
+unsigned long i915_chipset_val(struct drm_i915_private *dev_priv)
{
u64 total_count, diff, ret;
u32 count1, count2, count3, m = 0, c = 0;
unsigned long now = jiffies_to_msecs(jiffies), diff1;
int i;
- assert_spin_locked(&mchdev_lock);
-
- diff1 = now - dev_priv->ips.last_time1;
+ diff1 = now - dev_priv->last_time1;
/* Prevent division-by-zero if we are asking too fast.
* Also, we don't get interesting results if we are polling
@@ -2751,7 +2701,7 @@ static unsigned long __i915_chipset_val(struct drm_i915_private *dev_priv)
* in such cases.
*/
if (diff1 <= 10)
- return dev_priv->ips.chipset_power;
+ return dev_priv->chipset_power;
count1 = I915_READ(DMIEC);
count2 = I915_READ(DDREC);
@@ -2760,16 +2710,16 @@ static unsigned long __i915_chipset_val(struct drm_i915_private *dev_priv)
total_count = count1 + count2 + count3;
/* FIXME: handle per-counter overflow */
- if (total_count < dev_priv->ips.last_count1) {
- diff = ~0UL - dev_priv->ips.last_count1;
+ if (total_count < dev_priv->last_count1) {
+ diff = ~0UL - dev_priv->last_count1;
diff += total_count;
} else {
- diff = total_count - dev_priv->ips.last_count1;
+ diff = total_count - dev_priv->last_count1;
}
for (i = 0; i < ARRAY_SIZE(cparams); i++) {
- if (cparams[i].i == dev_priv->ips.c_m &&
- cparams[i].t == dev_priv->ips.r_t) {
+ if (cparams[i].i == dev_priv->c_m &&
+ cparams[i].t == dev_priv->r_t) {
m = cparams[i].m;
c = cparams[i].c;
break;
@@ -2780,30 +2730,14 @@ static unsigned long __i915_chipset_val(struct drm_i915_private *dev_priv)
ret = ((m * diff) + c);
ret = div_u64(ret, 10);
- dev_priv->ips.last_count1 = total_count;
- dev_priv->ips.last_time1 = now;
+ dev_priv->last_count1 = total_count;
+ dev_priv->last_time1 = now;
- dev_priv->ips.chipset_power = ret;
+ dev_priv->chipset_power = ret;
return ret;
}
-unsigned long i915_chipset_val(struct drm_i915_private *dev_priv)
-{
- unsigned long val;
-
- if (dev_priv->info->gen != 5)
- return 0;
-
- spin_lock_irq(&mchdev_lock);
-
- val = __i915_chipset_val(dev_priv);
-
- spin_unlock_irq(&mchdev_lock);
-
- return val;
-}
-
unsigned long i915_mch_val(struct drm_i915_private *dev_priv)
{
unsigned long m, x, b;
@@ -2960,17 +2894,18 @@ static u16 pvid_to_extvid(struct drm_i915_private *dev_priv, u8 pxvid)
return v_table[pxvid].vd;
}
-static void __i915_update_gfx_val(struct drm_i915_private *dev_priv)
+void i915_update_gfx_val(struct drm_i915_private *dev_priv)
{
struct timespec now, diff1;
u64 diff;
unsigned long diffms;
u32 count;
- assert_spin_locked(&mchdev_lock);
+ if (dev_priv->info->gen != 5)
+ return;
getrawmonotonic(&now);
- diff1 = timespec_sub(now, dev_priv->ips.last_time2);
+ diff1 = timespec_sub(now, dev_priv->last_time2);
/* Don't divide by 0 */
diffms = diff1.tv_sec * 1000 + diff1.tv_nsec / 1000000;
@@ -2979,42 +2914,28 @@ static void __i915_update_gfx_val(struct drm_i915_private *dev_priv)
count = I915_READ(GFXEC);
- if (count < dev_priv->ips.last_count2) {
- diff = ~0UL - dev_priv->ips.last_count2;
+ if (count < dev_priv->last_count2) {
+ diff = ~0UL - dev_priv->last_count2;
diff += count;
} else {
- diff = count - dev_priv->ips.last_count2;
+ diff = count - dev_priv->last_count2;
}
- dev_priv->ips.last_count2 = count;
- dev_priv->ips.last_time2 = now;
+ dev_priv->last_count2 = count;
+ dev_priv->last_time2 = now;
/* More magic constants... */
diff = diff * 1181;
diff = div_u64(diff, diffms * 10);
- dev_priv->ips.gfx_power = diff;
-}
-
-void i915_update_gfx_val(struct drm_i915_private *dev_priv)
-{
- if (dev_priv->info->gen != 5)
- return;
-
- spin_lock_irq(&mchdev_lock);
-
- __i915_update_gfx_val(dev_priv);
-
- spin_unlock_irq(&mchdev_lock);
+ dev_priv->gfx_power = diff;
}
-static unsigned long __i915_gfx_val(struct drm_i915_private *dev_priv)
+unsigned long i915_gfx_val(struct drm_i915_private *dev_priv)
{
unsigned long t, corr, state1, corr2, state2;
u32 pxvid, ext_v;
- assert_spin_locked(&mchdev_lock);
-
- pxvid = I915_READ(PXVFREQ_BASE + (dev_priv->rps.cur_delay * 4));
+ pxvid = I915_READ(PXVFREQ_BASE + (dev_priv->cur_delay * 4));
pxvid = (pxvid >> 24) & 0x7f;
ext_v = pvid_to_extvid(dev_priv, pxvid);
@@ -3034,31 +2955,27 @@ static unsigned long __i915_gfx_val(struct drm_i915_private *dev_priv)
corr = corr * ((150142 * state1) / 10000 - 78642);
corr /= 100000;
- corr2 = (corr * dev_priv->ips.corr);
+ corr2 = (corr * dev_priv->corr);
state2 = (corr2 * state1) / 10000;
state2 /= 100; /* convert to mW */
- __i915_update_gfx_val(dev_priv);
+ i915_update_gfx_val(dev_priv);
- return dev_priv->ips.gfx_power + state2;
+ return dev_priv->gfx_power + state2;
}
-unsigned long i915_gfx_val(struct drm_i915_private *dev_priv)
-{
- unsigned long val;
-
- if (dev_priv->info->gen != 5)
- return 0;
-
- spin_lock_irq(&mchdev_lock);
-
- val = __i915_gfx_val(dev_priv);
-
- spin_unlock_irq(&mchdev_lock);
-
- return val;
-}
+/* Global for IPS driver to get at the current i915 device */
+static struct drm_i915_private *i915_mch_dev;
+/*
+ * Lock protecting IPS related data structures
+ * - i915_mch_dev
+ * - dev_priv->max_delay
+ * - dev_priv->min_delay
+ * - dev_priv->fmax
+ * - dev_priv->gpu_busy
+ */
+static DEFINE_SPINLOCK(mchdev_lock);
/**
* i915_read_mch_val - return value for IPS use
@@ -3071,18 +2988,18 @@ unsigned long i915_read_mch_val(void)
struct drm_i915_private *dev_priv;
unsigned long chipset_val, graphics_val, ret = 0;
- spin_lock_irq(&mchdev_lock);
+ spin_lock(&mchdev_lock);
if (!i915_mch_dev)
goto out_unlock;
dev_priv = i915_mch_dev;
- chipset_val = __i915_chipset_val(dev_priv);
- graphics_val = __i915_gfx_val(dev_priv);
+ chipset_val = i915_chipset_val(dev_priv);
+ graphics_val = i915_gfx_val(dev_priv);
ret = chipset_val + graphics_val;
out_unlock:
- spin_unlock_irq(&mchdev_lock);
+ spin_unlock(&mchdev_lock);
return ret;
}
@@ -3098,18 +3015,18 @@ bool i915_gpu_raise(void)
struct drm_i915_private *dev_priv;
bool ret = true;
- spin_lock_irq(&mchdev_lock);
+ spin_lock(&mchdev_lock);
if (!i915_mch_dev) {
ret = false;
goto out_unlock;
}
dev_priv = i915_mch_dev;
- if (dev_priv->ips.max_delay > dev_priv->ips.fmax)
- dev_priv->ips.max_delay--;
+ if (dev_priv->max_delay > dev_priv->fmax)
+ dev_priv->max_delay--;
out_unlock:
- spin_unlock_irq(&mchdev_lock);
+ spin_unlock(&mchdev_lock);
return ret;
}
@@ -3126,18 +3043,18 @@ bool i915_gpu_lower(void)
struct drm_i915_private *dev_priv;
bool ret = true;
- spin_lock_irq(&mchdev_lock);
+ spin_lock(&mchdev_lock);
if (!i915_mch_dev) {
ret = false;
goto out_unlock;
}
dev_priv = i915_mch_dev;
- if (dev_priv->ips.max_delay < dev_priv->ips.min_delay)
- dev_priv->ips.max_delay++;
+ if (dev_priv->max_delay < dev_priv->min_delay)
+ dev_priv->max_delay++;
out_unlock:
- spin_unlock_irq(&mchdev_lock);
+ spin_unlock(&mchdev_lock);
return ret;
}
@@ -3151,20 +3068,17 @@ EXPORT_SYMBOL_GPL(i915_gpu_lower);
bool i915_gpu_busy(void)
{
struct drm_i915_private *dev_priv;
- struct intel_ring_buffer *ring;
bool ret = false;
- int i;
- spin_lock_irq(&mchdev_lock);
+ spin_lock(&mchdev_lock);
if (!i915_mch_dev)
goto out_unlock;
dev_priv = i915_mch_dev;
- for_each_ring(ring, dev_priv, i)
- ret |= !list_empty(&ring->request_list);
+ ret = dev_priv->busy;
out_unlock:
- spin_unlock_irq(&mchdev_lock);
+ spin_unlock(&mchdev_lock);
return ret;
}
@@ -3181,20 +3095,20 @@ bool i915_gpu_turbo_disable(void)
struct drm_i915_private *dev_priv;
bool ret = true;
- spin_lock_irq(&mchdev_lock);
+ spin_lock(&mchdev_lock);
if (!i915_mch_dev) {
ret = false;
goto out_unlock;
}
dev_priv = i915_mch_dev;
- dev_priv->ips.max_delay = dev_priv->ips.fstart;
+ dev_priv->max_delay = dev_priv->fstart;
- if (!ironlake_set_drps(dev_priv->dev, dev_priv->ips.fstart))
+ if (!ironlake_set_drps(dev_priv->dev, dev_priv->fstart))
ret = false;
out_unlock:
- spin_unlock_irq(&mchdev_lock);
+ spin_unlock(&mchdev_lock);
return ret;
}
@@ -3222,20 +3136,19 @@ ips_ping_for_i915_load(void)
void intel_gpu_ips_init(struct drm_i915_private *dev_priv)
{
- /* We only register the i915 ips part with intel-ips once everything is
- * set up, to avoid intel-ips sneaking in and reading bogus values. */
- spin_lock_irq(&mchdev_lock);
+ spin_lock(&mchdev_lock);
i915_mch_dev = dev_priv;
- spin_unlock_irq(&mchdev_lock);
+ dev_priv->mchdev_lock = &mchdev_lock;
+ spin_unlock(&mchdev_lock);
ips_ping_for_i915_load();
}
void intel_gpu_ips_teardown(void)
{
- spin_lock_irq(&mchdev_lock);
+ spin_lock(&mchdev_lock);
i915_mch_dev = NULL;
- spin_unlock_irq(&mchdev_lock);
+ spin_unlock(&mchdev_lock);
}
static void intel_init_emon(struct drm_device *dev)
{
@@ -3305,7 +3218,7 @@ static void intel_init_emon(struct drm_device *dev)
lcfuse = I915_READ(LCFUSE02);
- dev_priv->ips.corr = (lcfuse & LCFUSE_HIV_MASK);
+ dev_priv->corr = (lcfuse & LCFUSE_HIV_MASK);
}
void intel_disable_gt_powersave(struct drm_device *dev)
@@ -3818,6 +3731,42 @@ void intel_init_clock_gating(struct drm_device *dev)
dev_priv->display.init_pch_clock_gating(dev);
}
+static void gen6_sanitize_pm(struct drm_device *dev)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ u32 limits, delay, old;
+
+ gen6_gt_force_wake_get(dev_priv);
+
+ old = limits = I915_READ(GEN6_RP_INTERRUPT_LIMITS);
+ /* Make sure we continue to get interrupts
+ * until we hit the minimum or maximum frequencies.
+ */
+ limits &= ~(0x3f << 16 | 0x3f << 24);
+ delay = dev_priv->cur_delay;
+ if (delay < dev_priv->max_delay)
+ limits |= (dev_priv->max_delay & 0x3f) << 24;
+ if (delay > dev_priv->min_delay)
+ limits |= (dev_priv->min_delay & 0x3f) << 16;
+
+ if (old != limits) {
+ /* Note that the known failure case is to read back 0. */
+ DRM_DEBUG_DRIVER("Power management discrepancy: GEN6_RP_INTERRUPT_LIMITS "
+ "expected %08x, was %08x\n", limits, old);
+ I915_WRITE(GEN6_RP_INTERRUPT_LIMITS, limits);
+ }
+
+ gen6_gt_force_wake_put(dev_priv);
+}
+
+void intel_sanitize_pm(struct drm_device *dev)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+
+ if (dev_priv->display.sanitize_pm)
+ dev_priv->display.sanitize_pm(dev);
+}
+
/* Starting with Haswell, we have different power wells for
* different parts of the GPU. This attempts to enable them all.
*/
@@ -3903,6 +3852,7 @@ void intel_init_pm(struct drm_device *dev)
dev_priv->display.update_wm = NULL;
}
dev_priv->display.init_clock_gating = gen6_init_clock_gating;
+ dev_priv->display.sanitize_pm = gen6_sanitize_pm;
} else if (IS_IVYBRIDGE(dev)) {
/* FIXME: detect B0+ stepping and use auto training */
if (SNB_READ_WM0_LATENCY()) {
@@ -3914,6 +3864,7 @@ void intel_init_pm(struct drm_device *dev)
dev_priv->display.update_wm = NULL;
}
dev_priv->display.init_clock_gating = ivybridge_init_clock_gating;
+ dev_priv->display.sanitize_pm = gen6_sanitize_pm;
} else if (IS_HASWELL(dev)) {
if (SNB_READ_WM0_LATENCY()) {
dev_priv->display.update_wm = sandybridge_update_wm;
@@ -3925,6 +3876,7 @@ void intel_init_pm(struct drm_device *dev)
dev_priv->display.update_wm = NULL;
}
dev_priv->display.init_clock_gating = haswell_init_clock_gating;
+ dev_priv->display.sanitize_pm = gen6_sanitize_pm;
} else
dev_priv->display.update_wm = NULL;
} else if (IS_VALLEYVIEW(dev)) {
@@ -4003,16 +3955,14 @@ static void __gen6_gt_force_wake_get(struct drm_i915_private *dev_priv)
else
forcewake_ack = FORCEWAKE_ACK;
- if (wait_for_atomic((I915_READ_NOTRACE(forcewake_ack) & 1) == 0,
- FORCEWAKE_ACK_TIMEOUT_MS))
- DRM_ERROR("Timed out waiting for forcewake old ack to clear.\n");
+ if (wait_for_atomic_us((I915_READ_NOTRACE(forcewake_ack) & 1) == 0, 500))
+ DRM_ERROR("Force wake wait timed out\n");
I915_WRITE_NOTRACE(FORCEWAKE, 1);
- POSTING_READ(ECOBUS); /* something from same cacheline, but !FORCEWAKE */
+ POSTING_READ(FORCEWAKE);
- if (wait_for_atomic((I915_READ_NOTRACE(forcewake_ack) & 1),
- FORCEWAKE_ACK_TIMEOUT_MS))
- DRM_ERROR("Timed out waiting for forcewake to ack request.\n");
+ if (wait_for_atomic_us((I915_READ_NOTRACE(forcewake_ack) & 1), 500))
+ DRM_ERROR("Force wake wait timed out\n");
__gen6_gt_wait_for_thread_c0(dev_priv);
}
@@ -4026,16 +3976,14 @@ static void __gen6_gt_force_wake_mt_get(struct drm_i915_private *dev_priv)
else
forcewake_ack = FORCEWAKE_MT_ACK;
- if (wait_for_atomic((I915_READ_NOTRACE(forcewake_ack) & 1) == 0,
- FORCEWAKE_ACK_TIMEOUT_MS))
- DRM_ERROR("Timed out waiting for forcewake old ack to clear.\n");
+ if (wait_for_atomic_us((I915_READ_NOTRACE(forcewake_ack) & 1) == 0, 500))
+ DRM_ERROR("Force wake wait timed out\n");
I915_WRITE_NOTRACE(FORCEWAKE_MT, _MASKED_BIT_ENABLE(1));
- POSTING_READ(ECOBUS); /* something from same cacheline, but !FORCEWAKE */
+ POSTING_READ(FORCEWAKE_MT);
- if (wait_for_atomic((I915_READ_NOTRACE(forcewake_ack) & 1),
- FORCEWAKE_ACK_TIMEOUT_MS))
- DRM_ERROR("Timed out waiting for forcewake to ack request.\n");
+ if (wait_for_atomic_us((I915_READ_NOTRACE(forcewake_ack) & 1), 500))
+ DRM_ERROR("Force wake wait timed out\n");
__gen6_gt_wait_for_thread_c0(dev_priv);
}
@@ -4068,14 +4016,14 @@ void gen6_gt_check_fifodbg(struct drm_i915_private *dev_priv)
static void __gen6_gt_force_wake_put(struct drm_i915_private *dev_priv)
{
I915_WRITE_NOTRACE(FORCEWAKE, 0);
- /* gen6_gt_check_fifodbg doubles as the POSTING_READ */
+ POSTING_READ(FORCEWAKE);
gen6_gt_check_fifodbg(dev_priv);
}
static void __gen6_gt_force_wake_mt_put(struct drm_i915_private *dev_priv)
{
I915_WRITE_NOTRACE(FORCEWAKE_MT, _MASKED_BIT_DISABLE(1));
- /* gen6_gt_check_fifodbg doubles as the POSTING_READ */
+ POSTING_READ(FORCEWAKE_MT);
gen6_gt_check_fifodbg(dev_priv);
}
@@ -4114,24 +4062,24 @@ int __gen6_gt_wait_for_fifo(struct drm_i915_private *dev_priv)
static void vlv_force_wake_get(struct drm_i915_private *dev_priv)
{
- if (wait_for_atomic((I915_READ_NOTRACE(FORCEWAKE_ACK_VLV) & 1) == 0,
- FORCEWAKE_ACK_TIMEOUT_MS))
- DRM_ERROR("Timed out waiting for forcewake old ack to clear.\n");
+ /* Already awake? */
+ if ((I915_READ(0x130094) & 0xa1) == 0xa1)
+ return;
- I915_WRITE_NOTRACE(FORCEWAKE_VLV, _MASKED_BIT_ENABLE(1));
+ I915_WRITE_NOTRACE(FORCEWAKE_VLV, 0xffffffff);
+ POSTING_READ(FORCEWAKE_VLV);
- if (wait_for_atomic((I915_READ_NOTRACE(FORCEWAKE_ACK_VLV) & 1),
- FORCEWAKE_ACK_TIMEOUT_MS))
- DRM_ERROR("Timed out waiting for forcewake to ack request.\n");
+ if (wait_for_atomic_us((I915_READ_NOTRACE(FORCEWAKE_ACK_VLV) & 1), 500))
+ DRM_ERROR("Force wake wait timed out\n");
__gen6_gt_wait_for_thread_c0(dev_priv);
}
static void vlv_force_wake_put(struct drm_i915_private *dev_priv)
{
- I915_WRITE_NOTRACE(FORCEWAKE_VLV, _MASKED_BIT_DISABLE(1));
- /* The below doubles as a POSTING_READ */
- gen6_gt_check_fifodbg(dev_priv);
+ I915_WRITE_NOTRACE(FORCEWAKE_VLV, 0xffff0000);
+ /* FIXME: confirm VLV behavior with Punit folks */
+ POSTING_READ(FORCEWAKE_VLV);
}
void intel_gt_init(struct drm_device *dev)
diff --git a/trunk/drivers/gpu/drm/i915/intel_ringbuffer.c b/trunk/drivers/gpu/drm/i915/intel_ringbuffer.c
index 984a0c5fbf5d..e2a73b38abe9 100644
--- a/trunk/drivers/gpu/drm/i915/intel_ringbuffer.c
+++ b/trunk/drivers/gpu/drm/i915/intel_ringbuffer.c
@@ -262,83 +262,6 @@ gen6_render_ring_flush(struct intel_ring_buffer *ring,
return 0;
}
-static int
-gen7_render_ring_cs_stall_wa(struct intel_ring_buffer *ring)
-{
- int ret;
-
- ret = intel_ring_begin(ring, 4);
- if (ret)
- return ret;
-
- intel_ring_emit(ring, GFX_OP_PIPE_CONTROL(4));
- intel_ring_emit(ring, PIPE_CONTROL_CS_STALL |
- PIPE_CONTROL_STALL_AT_SCOREBOARD);
- intel_ring_emit(ring, 0);
- intel_ring_emit(ring, 0);
- intel_ring_advance(ring);
-
- return 0;
-}
-
-static int
-gen7_render_ring_flush(struct intel_ring_buffer *ring,
- u32 invalidate_domains, u32 flush_domains)
-{
- u32 flags = 0;
- struct pipe_control *pc = ring->private;
- u32 scratch_addr = pc->gtt_offset + 128;
- int ret;
-
- /*
- * Ensure that any following seqno writes only happen when the render
- * cache is indeed flushed.
- *
- * Workaround: 4th PIPE_CONTROL command (except the ones with only
- * read-cache invalidate bits set) must have the CS_STALL bit set. We
- * don't try to be clever and just set it unconditionally.
- */
- flags |= PIPE_CONTROL_CS_STALL;
-
- /* Just flush everything. Experiments have shown that reducing the
- * number of bits based on the write domains has little performance
- * impact.
- */
- if (flush_domains) {
- flags |= PIPE_CONTROL_RENDER_TARGET_CACHE_FLUSH;
- flags |= PIPE_CONTROL_DEPTH_CACHE_FLUSH;
- }
- if (invalidate_domains) {
- flags |= PIPE_CONTROL_TLB_INVALIDATE;
- flags |= PIPE_CONTROL_INSTRUCTION_CACHE_INVALIDATE;
- flags |= PIPE_CONTROL_TEXTURE_CACHE_INVALIDATE;
- flags |= PIPE_CONTROL_VF_CACHE_INVALIDATE;
- flags |= PIPE_CONTROL_CONST_CACHE_INVALIDATE;
- flags |= PIPE_CONTROL_STATE_CACHE_INVALIDATE;
- /*
- * TLB invalidate requires a post-sync write.
- */
- flags |= PIPE_CONTROL_QW_WRITE;
-
- /* Workaround: we must issue a pipe_control with CS-stall bit
- * set before a pipe_control command that has the state cache
- * invalidate bit set. */
- gen7_render_ring_cs_stall_wa(ring);
- }
-
- ret = intel_ring_begin(ring, 4);
- if (ret)
- return ret;
-
- 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, 0);
- intel_ring_advance(ring);
-
- return 0;
-}
-
static void ring_write_tail(struct intel_ring_buffer *ring,
u32 value)
{
@@ -459,12 +382,12 @@ init_pipe_control(struct intel_ring_buffer *ring)
i915_gem_object_set_cache_level(obj, I915_CACHE_LLC);
- ret = i915_gem_object_pin(obj, 4096, true, false);
+ ret = i915_gem_object_pin(obj, 4096, true);
if (ret)
goto err_unref;
pc->gtt_offset = obj->gtt_offset;
- pc->cpu_page = kmap(sg_page(obj->pages->sgl));
+ pc->cpu_page = kmap(obj->pages[0]);
if (pc->cpu_page == NULL)
goto err_unpin;
@@ -491,8 +414,7 @@ cleanup_pipe_control(struct intel_ring_buffer *ring)
return;
obj = pc->obj;
-
- kunmap(sg_page(obj->pages->sgl));
+ kunmap(obj->pages[0]);
i915_gem_object_unpin(obj);
drm_gem_object_unreference(&obj->base);
@@ -540,7 +462,7 @@ static int init_render_ring(struct intel_ring_buffer *ring)
if (INTEL_INFO(dev)->gen >= 6)
I915_WRITE(INSTPM, _MASKED_BIT_ENABLE(INSTPM_FORCE_ORDERING));
- if (HAS_L3_GPU_CACHE(dev))
+ if (IS_IVYBRIDGE(dev))
I915_WRITE_IMR(ring, ~GEN6_RENDER_L3_PARITY_ERROR);
return ret;
@@ -706,24 +628,26 @@ pc_render_add_request(struct intel_ring_buffer *ring,
}
static u32
-gen6_ring_get_seqno(struct intel_ring_buffer *ring, bool lazy_coherency)
+gen6_ring_get_seqno(struct intel_ring_buffer *ring)
{
+ struct drm_device *dev = ring->dev;
+
/* Workaround to force correct ordering between irq and seqno writes on
* ivb (and maybe also on snb) by reading from a CS register (like
* ACTHD) before reading the status page. */
- if (!lazy_coherency)
+ if (IS_GEN6(dev) || IS_GEN7(dev))
intel_ring_get_active_head(ring);
return intel_read_status_page(ring, I915_GEM_HWS_INDEX);
}
static u32
-ring_get_seqno(struct intel_ring_buffer *ring, bool lazy_coherency)
+ring_get_seqno(struct intel_ring_buffer *ring)
{
return intel_read_status_page(ring, I915_GEM_HWS_INDEX);
}
static u32
-pc_render_get_seqno(struct intel_ring_buffer *ring, bool lazy_coherency)
+pc_render_get_seqno(struct intel_ring_buffer *ring)
{
struct pipe_control *pc = ring->private;
return pc->cpu_page[0];
@@ -928,7 +852,7 @@ gen6_ring_get_irq(struct intel_ring_buffer *ring)
spin_lock_irqsave(&dev_priv->irq_lock, flags);
if (ring->irq_refcount++ == 0) {
- if (HAS_L3_GPU_CACHE(dev) && ring->id == RCS)
+ if (IS_IVYBRIDGE(dev) && ring->id == RCS)
I915_WRITE_IMR(ring, ~(ring->irq_enable_mask |
GEN6_RENDER_L3_PARITY_ERROR));
else
@@ -951,7 +875,7 @@ gen6_ring_put_irq(struct intel_ring_buffer *ring)
spin_lock_irqsave(&dev_priv->irq_lock, flags);
if (--ring->irq_refcount == 0) {
- if (HAS_L3_GPU_CACHE(dev) && ring->id == RCS)
+ if (IS_IVYBRIDGE(dev) && ring->id == RCS)
I915_WRITE_IMR(ring, ~GEN6_RENDER_L3_PARITY_ERROR);
else
I915_WRITE_IMR(ring, ~0);
@@ -1027,7 +951,7 @@ static void cleanup_status_page(struct intel_ring_buffer *ring)
if (obj == NULL)
return;
- kunmap(sg_page(obj->pages->sgl));
+ kunmap(obj->pages[0]);
i915_gem_object_unpin(obj);
drm_gem_object_unreference(&obj->base);
ring->status_page.obj = NULL;
@@ -1048,13 +972,13 @@ static int init_status_page(struct intel_ring_buffer *ring)
i915_gem_object_set_cache_level(obj, I915_CACHE_LLC);
- ret = i915_gem_object_pin(obj, 4096, true, false);
+ ret = i915_gem_object_pin(obj, 4096, true);
if (ret != 0) {
goto err_unref;
}
ring->status_page.gfx_addr = obj->gtt_offset;
- ring->status_page.page_addr = kmap(sg_page(obj->pages->sgl));
+ ring->status_page.page_addr = kmap(obj->pages[0]);
if (ring->status_page.page_addr == NULL) {
ret = -ENOMEM;
goto err_unpin;
@@ -1086,6 +1010,7 @@ static int intel_init_ring_buffer(struct drm_device *dev,
ring->dev = dev;
INIT_LIST_HEAD(&ring->active_list);
INIT_LIST_HEAD(&ring->request_list);
+ INIT_LIST_HEAD(&ring->gpu_write_list);
ring->size = 32 * PAGE_SIZE;
init_waitqueue_head(&ring->irq_queue);
@@ -1105,7 +1030,7 @@ static int intel_init_ring_buffer(struct drm_device *dev,
ring->obj = obj;
- ret = i915_gem_object_pin(obj, PAGE_SIZE, true, false);
+ ret = i915_gem_object_pin(obj, PAGE_SIZE, true);
if (ret)
goto err_unref;
@@ -1454,9 +1379,7 @@ int intel_init_render_ring_buffer(struct drm_device *dev)
if (INTEL_INFO(dev)->gen >= 6) {
ring->add_request = gen6_add_request;
- ring->flush = gen7_render_ring_flush;
- if (INTEL_INFO(dev)->gen == 6)
- ring->flush = gen6_render_ring_flush;
+ ring->flush = gen6_render_ring_flush;
ring->irq_get = gen6_ring_get_irq;
ring->irq_put = gen6_ring_put_irq;
ring->irq_enable_mask = GT_USER_INTERRUPT;
@@ -1558,6 +1481,7 @@ int intel_render_ring_init_dri(struct drm_device *dev, u64 start, u32 size)
ring->dev = dev;
INIT_LIST_HEAD(&ring->active_list);
INIT_LIST_HEAD(&ring->request_list);
+ INIT_LIST_HEAD(&ring->gpu_write_list);
ring->size = size;
ring->effective_size = ring->size;
@@ -1650,41 +1574,3 @@ int intel_init_blt_ring_buffer(struct drm_device *dev)
return intel_init_ring_buffer(dev, ring);
}
-
-int
-intel_ring_flush_all_caches(struct intel_ring_buffer *ring)
-{
- int ret;
-
- if (!ring->gpu_caches_dirty)
- return 0;
-
- ret = ring->flush(ring, 0, I915_GEM_GPU_DOMAINS);
- if (ret)
- return ret;
-
- trace_i915_gem_ring_flush(ring, 0, I915_GEM_GPU_DOMAINS);
-
- ring->gpu_caches_dirty = false;
- return 0;
-}
-
-int
-intel_ring_invalidate_all_caches(struct intel_ring_buffer *ring)
-{
- uint32_t flush_domains;
- int ret;
-
- flush_domains = 0;
- if (ring->gpu_caches_dirty)
- flush_domains = I915_GEM_GPU_DOMAINS;
-
- ret = ring->flush(ring, I915_GEM_GPU_DOMAINS, flush_domains);
- if (ret)
- return ret;
-
- trace_i915_gem_ring_flush(ring, I915_GEM_GPU_DOMAINS, flush_domains);
-
- ring->gpu_caches_dirty = false;
- return 0;
-}
diff --git a/trunk/drivers/gpu/drm/i915/intel_ringbuffer.h b/trunk/drivers/gpu/drm/i915/intel_ringbuffer.h
index 2ea7a311a1f0..1d3c81fdad92 100644
--- a/trunk/drivers/gpu/drm/i915/intel_ringbuffer.h
+++ b/trunk/drivers/gpu/drm/i915/intel_ringbuffer.h
@@ -72,14 +72,7 @@ struct intel_ring_buffer {
u32 flush_domains);
int (*add_request)(struct intel_ring_buffer *ring,
u32 *seqno);
- /* Some chipsets are not quite as coherent as advertised and need
- * an expensive kick to force a true read of the up-to-date seqno.
- * However, the up-to-date seqno is not always required and the last
- * seen value is good enough. Note that the seqno will always be
- * monotonic, even if not coherent.
- */
- u32 (*get_seqno)(struct intel_ring_buffer *ring,
- bool lazy_coherency);
+ u32 (*get_seqno)(struct intel_ring_buffer *ring);
int (*dispatch_execbuffer)(struct intel_ring_buffer *ring,
u32 offset, u32 length);
void (*cleanup)(struct intel_ring_buffer *ring);
@@ -107,6 +100,15 @@ struct intel_ring_buffer {
*/
struct list_head request_list;
+ /**
+ * List of objects currently pending a GPU write flush.
+ *
+ * All elements on this list will belong to either the
+ * active_list or flushing_list, last_rendering_seqno can
+ * be used to differentiate between the two elements.
+ */
+ struct list_head gpu_write_list;
+
/**
* Do we have some not yet emitted requests outstanding?
*/
@@ -202,8 +204,6 @@ static inline void intel_ring_emit(struct intel_ring_buffer *ring,
void intel_ring_advance(struct intel_ring_buffer *ring);
u32 intel_ring_get_seqno(struct intel_ring_buffer *ring);
-int intel_ring_flush_all_caches(struct intel_ring_buffer *ring);
-int intel_ring_invalidate_all_caches(struct intel_ring_buffer *ring);
int intel_init_render_ring_buffer(struct drm_device *dev);
int intel_init_bsd_ring_buffer(struct drm_device *dev);
diff --git a/trunk/drivers/gpu/drm/i915/intel_sdvo.c b/trunk/drivers/gpu/drm/i915/intel_sdvo.c
index 39c319827f91..123afd357611 100644
--- a/trunk/drivers/gpu/drm/i915/intel_sdvo.c
+++ b/trunk/drivers/gpu/drm/i915/intel_sdvo.c
@@ -97,7 +97,7 @@ struct intel_sdvo {
/*
* Hotplug activation bits for this device
*/
- uint16_t hotplug_active;
+ uint8_t hotplug_active[2];
/**
* This is used to select the color range of RBG outputs in HDMI mode.
@@ -628,14 +628,6 @@ static bool intel_sdvo_set_active_outputs(struct intel_sdvo *intel_sdvo,
&outputs, sizeof(outputs));
}
-static bool intel_sdvo_get_active_outputs(struct intel_sdvo *intel_sdvo,
- u16 *outputs)
-{
- return intel_sdvo_get_value(intel_sdvo,
- SDVO_CMD_GET_ACTIVE_OUTPUTS,
- outputs, sizeof(*outputs));
-}
-
static bool intel_sdvo_set_encoder_power_state(struct intel_sdvo *intel_sdvo,
int mode)
{
@@ -1150,132 +1142,51 @@ static void intel_sdvo_mode_set(struct drm_encoder *encoder,
intel_sdvo_write_sdvox(intel_sdvo, sdvox);
}
-static bool intel_sdvo_connector_get_hw_state(struct intel_connector *connector)
-{
- struct intel_sdvo_connector *intel_sdvo_connector =
- to_intel_sdvo_connector(&connector->base);
- struct intel_sdvo *intel_sdvo = intel_attached_sdvo(&connector->base);
- u16 active_outputs;
-
- intel_sdvo_get_active_outputs(intel_sdvo, &active_outputs);
-
- if (active_outputs & intel_sdvo_connector->output_flag)
- return true;
- else
- return false;
-}
-
-static bool intel_sdvo_get_hw_state(struct intel_encoder *encoder,
- enum pipe *pipe)
+static void intel_sdvo_dpms(struct drm_encoder *encoder, int mode)
{
- struct drm_device *dev = encoder->base.dev;
- struct drm_i915_private *dev_priv = dev->dev_private;
- struct intel_sdvo *intel_sdvo = to_intel_sdvo(&encoder->base);
- u32 tmp;
-
- tmp = I915_READ(intel_sdvo->sdvo_reg);
-
- if (!(tmp & SDVO_ENABLE))
- return false;
-
- if (HAS_PCH_CPT(dev))
- *pipe = PORT_TO_PIPE_CPT(tmp);
- else
- *pipe = PORT_TO_PIPE(tmp);
-
- return true;
-}
-
-static void intel_disable_sdvo(struct intel_encoder *encoder)
-{
- struct drm_i915_private *dev_priv = encoder->base.dev->dev_private;
- struct intel_sdvo *intel_sdvo = to_intel_sdvo(&encoder->base);
- u32 temp;
-
- intel_sdvo_set_active_outputs(intel_sdvo, 0);
- if (0)
- intel_sdvo_set_encoder_power_state(intel_sdvo,
- DRM_MODE_DPMS_OFF);
-
- temp = I915_READ(intel_sdvo->sdvo_reg);
- if ((temp & SDVO_ENABLE) != 0) {
- intel_sdvo_write_sdvox(intel_sdvo, temp & ~SDVO_ENABLE);
- }
-}
-
-static void intel_enable_sdvo(struct intel_encoder *encoder)
-{
- struct drm_device *dev = encoder->base.dev;
+ struct drm_device *dev = encoder->dev;
struct drm_i915_private *dev_priv = dev->dev_private;
- struct intel_sdvo *intel_sdvo = to_intel_sdvo(&encoder->base);
- struct intel_crtc *intel_crtc = to_intel_crtc(encoder->base.crtc);
+ struct intel_sdvo *intel_sdvo = to_intel_sdvo(encoder);
+ struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc);
u32 temp;
- bool input1, input2;
- int i;
- u8 status;
-
- temp = I915_READ(intel_sdvo->sdvo_reg);
- if ((temp & SDVO_ENABLE) == 0)
- intel_sdvo_write_sdvox(intel_sdvo, temp | SDVO_ENABLE);
- for (i = 0; i < 2; i++)
- intel_wait_for_vblank(dev, intel_crtc->pipe);
-
- status = intel_sdvo_get_trained_inputs(intel_sdvo, &input1, &input2);
- /* Warn if the device reported failure to sync.
- * A lot of SDVO devices fail to notify of sync, but it's
- * a given it the status is a success, we succeeded.
- */
- if (status == SDVO_CMD_STATUS_SUCCESS && !input1) {
- DRM_DEBUG_KMS("First %s output reported failure to "
- "sync\n", SDVO_NAME(intel_sdvo));
- }
-
- if (0)
- intel_sdvo_set_encoder_power_state(intel_sdvo,
- DRM_MODE_DPMS_ON);
- intel_sdvo_set_active_outputs(intel_sdvo, intel_sdvo->attached_output);
-}
-
-static void intel_sdvo_dpms(struct drm_connector *connector, int mode)
-{
- struct drm_crtc *crtc;
- struct intel_sdvo *intel_sdvo = intel_attached_sdvo(connector);
-
- /* dvo supports only 2 dpms states. */
- if (mode != DRM_MODE_DPMS_ON)
- mode = DRM_MODE_DPMS_OFF;
-
- if (mode == connector->dpms)
- return;
-
- connector->dpms = mode;
-
- /* Only need to change hw state when actually enabled */
- crtc = intel_sdvo->base.base.crtc;
- if (!crtc) {
- intel_sdvo->base.connectors_active = false;
- return;
- }
if (mode != DRM_MODE_DPMS_ON) {
intel_sdvo_set_active_outputs(intel_sdvo, 0);
if (0)
intel_sdvo_set_encoder_power_state(intel_sdvo, mode);
- intel_sdvo->base.connectors_active = false;
-
- intel_crtc_update_dpms(crtc);
+ if (mode == DRM_MODE_DPMS_OFF) {
+ temp = I915_READ(intel_sdvo->sdvo_reg);
+ if ((temp & SDVO_ENABLE) != 0) {
+ intel_sdvo_write_sdvox(intel_sdvo, temp & ~SDVO_ENABLE);
+ }
+ }
} else {
- intel_sdvo->base.connectors_active = true;
-
- intel_crtc_update_dpms(crtc);
+ bool input1, input2;
+ int i;
+ u8 status;
+
+ temp = I915_READ(intel_sdvo->sdvo_reg);
+ if ((temp & SDVO_ENABLE) == 0)
+ intel_sdvo_write_sdvox(intel_sdvo, temp | SDVO_ENABLE);
+ for (i = 0; i < 2; i++)
+ intel_wait_for_vblank(dev, intel_crtc->pipe);
+
+ status = intel_sdvo_get_trained_inputs(intel_sdvo, &input1, &input2);
+ /* Warn if the device reported failure to sync.
+ * A lot of SDVO devices fail to notify of sync, but it's
+ * a given it the status is a success, we succeeded.
+ */
+ if (status == SDVO_CMD_STATUS_SUCCESS && !input1) {
+ DRM_DEBUG_KMS("First %s output reported failure to "
+ "sync\n", SDVO_NAME(intel_sdvo));
+ }
if (0)
intel_sdvo_set_encoder_power_state(intel_sdvo, mode);
intel_sdvo_set_active_outputs(intel_sdvo, intel_sdvo->attached_output);
}
-
- intel_modeset_check_state(connector->dev);
+ return;
}
static int intel_sdvo_mode_valid(struct drm_connector *connector,
@@ -1340,29 +1251,25 @@ static bool intel_sdvo_get_capabilities(struct intel_sdvo *intel_sdvo, struct in
return true;
}
-static uint16_t intel_sdvo_get_hotplug_support(struct intel_sdvo *intel_sdvo)
+static int intel_sdvo_supports_hotplug(struct intel_sdvo *intel_sdvo)
{
struct drm_device *dev = intel_sdvo->base.base.dev;
- uint16_t hotplug;
+ u8 response[2];
/* HW Erratum: SDVO Hotplug is broken on all i945G chips, there's noise
* on the line. */
if (IS_I945G(dev) || IS_I945GM(dev))
- return 0;
-
- if (!intel_sdvo_get_value(intel_sdvo, SDVO_CMD_GET_HOT_PLUG_SUPPORT,
- &hotplug, sizeof(hotplug)))
- return 0;
+ return false;
- return hotplug;
+ return intel_sdvo_get_value(intel_sdvo, SDVO_CMD_GET_HOT_PLUG_SUPPORT,
+ &response, 2) && response[0];
}
static void intel_sdvo_enable_hotplug(struct intel_encoder *encoder)
{
struct intel_sdvo *intel_sdvo = to_intel_sdvo(&encoder->base);
- intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_SET_ACTIVE_HOT_PLUG,
- &intel_sdvo->hotplug_active, 2);
+ intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_SET_ACTIVE_HOT_PLUG, &intel_sdvo->hotplug_active, 2);
}
static bool
@@ -1438,6 +1345,7 @@ intel_sdvo_tmds_sink_detect(struct drm_connector *connector)
}
} else
status = connector_status_disconnected;
+ connector->display_info.raw_edid = NULL;
kfree(edid);
}
@@ -1511,6 +1419,7 @@ intel_sdvo_detect(struct drm_connector *connector, bool force)
else
ret = connector_status_disconnected;
+ connector->display_info.raw_edid = NULL;
kfree(edid);
} else
ret = connector_status_connected;
@@ -1556,6 +1465,7 @@ static void intel_sdvo_get_ddc_modes(struct drm_connector *connector)
drm_add_edid_modes(connector, edid);
}
+ connector->display_info.raw_edid = NULL;
kfree(edid);
}
}
@@ -1927,8 +1837,8 @@ intel_sdvo_set_property(struct drm_connector *connector,
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);
+ drm_crtc_helper_set_mode(crtc, &crtc->mode, crtc->x,
+ crtc->y, crtc->fb);
}
return 0;
@@ -1936,13 +1846,15 @@ intel_sdvo_set_property(struct drm_connector *connector,
}
static const struct drm_encoder_helper_funcs intel_sdvo_helper_funcs = {
+ .dpms = intel_sdvo_dpms,
.mode_fixup = intel_sdvo_mode_fixup,
+ .prepare = intel_encoder_prepare,
.mode_set = intel_sdvo_mode_set,
- .disable = intel_encoder_noop,
+ .commit = intel_encoder_commit,
};
static const struct drm_connector_funcs intel_sdvo_connector_funcs = {
- .dpms = intel_sdvo_dpms,
+ .dpms = drm_helper_connector_dpms,
.detect = intel_sdvo_detect,
.fill_modes = drm_helper_probe_single_connector_modes,
.set_property = intel_sdvo_set_property,
@@ -2114,7 +2026,6 @@ intel_sdvo_connector_init(struct intel_sdvo_connector *connector,
connector->base.base.interlace_allowed = 1;
connector->base.base.doublescan_allowed = 0;
connector->base.base.display_info.subpixel_order = SubPixelHorizontalRGB;
- connector->base.get_hw_state = intel_sdvo_connector_get_hw_state;
intel_connector_attach_encoder(&connector->base, &encoder->base);
drm_sysfs_connector_add(&connector->base.base);
@@ -2153,18 +2064,17 @@ intel_sdvo_dvi_init(struct intel_sdvo *intel_sdvo, int device)
intel_connector = &intel_sdvo_connector->base;
connector = &intel_connector->base;
- if (intel_sdvo_get_hotplug_support(intel_sdvo) &
- intel_sdvo_connector->output_flag) {
+ if (intel_sdvo_supports_hotplug(intel_sdvo) & (1 << device)) {
connector->polled = DRM_CONNECTOR_POLL_HPD;
- intel_sdvo->hotplug_active |= intel_sdvo_connector->output_flag;
+ intel_sdvo->hotplug_active[0] |= 1 << device;
/* Some SDVO devices have one-shot hotplug interrupts.
* Ensure that they get re-enabled when an interrupt happens.
*/
intel_encoder->hot_plug = intel_sdvo_enable_hotplug;
intel_sdvo_enable_hotplug(intel_encoder);
- } else {
- connector->polled = DRM_CONNECTOR_POLL_CONNECT | DRM_CONNECTOR_POLL_DISCONNECT;
}
+ else
+ connector->polled = DRM_CONNECTOR_POLL_CONNECT | DRM_CONNECTOR_POLL_DISCONNECT;
encoder->encoder_type = DRM_MODE_ENCODER_TMDS;
connector->connector_type = DRM_MODE_CONNECTOR_DVID;
@@ -2172,7 +2082,8 @@ intel_sdvo_dvi_init(struct intel_sdvo *intel_sdvo, int device)
connector->connector_type = DRM_MODE_CONNECTOR_HDMIA;
intel_sdvo->is_hdmi = true;
}
- intel_sdvo->base.cloneable = true;
+ intel_sdvo->base.clone_mask = ((1 << INTEL_SDVO_NON_TV_CLONE_BIT) |
+ (1 << INTEL_ANALOG_CLONE_BIT));
intel_sdvo_connector_init(intel_sdvo_connector, intel_sdvo);
if (intel_sdvo->is_hdmi)
@@ -2203,7 +2114,7 @@ intel_sdvo_tv_init(struct intel_sdvo *intel_sdvo, int type)
intel_sdvo->is_tv = true;
intel_sdvo->base.needs_tv_clock = true;
- intel_sdvo->base.cloneable = false;
+ intel_sdvo->base.clone_mask = 1 << INTEL_SDVO_TV_CLONE_BIT;
intel_sdvo_connector_init(intel_sdvo_connector, intel_sdvo);
@@ -2246,7 +2157,8 @@ intel_sdvo_analog_init(struct intel_sdvo *intel_sdvo, int device)
intel_sdvo_connector->output_flag = SDVO_OUTPUT_RGB1;
}
- intel_sdvo->base.cloneable = true;
+ intel_sdvo->base.clone_mask = ((1 << INTEL_SDVO_NON_TV_CLONE_BIT) |
+ (1 << INTEL_ANALOG_CLONE_BIT));
intel_sdvo_connector_init(intel_sdvo_connector,
intel_sdvo);
@@ -2278,10 +2190,8 @@ intel_sdvo_lvds_init(struct intel_sdvo *intel_sdvo, int device)
intel_sdvo_connector->output_flag = SDVO_OUTPUT_LVDS1;
}
- /* SDVO LVDS is cloneable because the SDVO encoder does the upscaling,
- * as opposed to native LVDS, where we upscale with the panel-fitter
- * (and hence only the native LVDS resolution could be cloned). */
- intel_sdvo->base.cloneable = true;
+ intel_sdvo->base.clone_mask = ((1 << INTEL_ANALOG_CLONE_BIT) |
+ (1 << INTEL_SDVO_LVDS_CLONE_BIT));
intel_sdvo_connector_init(intel_sdvo_connector, intel_sdvo);
if (!intel_sdvo_create_enhance_property(intel_sdvo, intel_sdvo_connector))
@@ -2666,10 +2576,6 @@ bool intel_sdvo_init(struct drm_device *dev, uint32_t sdvo_reg, bool is_sdvob)
drm_encoder_helper_add(&intel_encoder->base, &intel_sdvo_helper_funcs);
- intel_encoder->disable = intel_disable_sdvo;
- intel_encoder->enable = intel_enable_sdvo;
- intel_encoder->get_hw_state = intel_sdvo_get_hw_state;
-
/* In default case sdvo lvds is false */
if (!intel_sdvo_get_capabilities(intel_sdvo, &intel_sdvo->caps))
goto err;
@@ -2684,7 +2590,7 @@ bool intel_sdvo_init(struct drm_device *dev, uint32_t sdvo_reg, bool is_sdvob)
/* Only enable the hotplug irq if we need it, to work around noisy
* hotplug lines.
*/
- if (intel_sdvo->hotplug_active)
+ if (intel_sdvo->hotplug_active[0])
dev_priv->hotplug_supported_mask |= hotplug_mask;
intel_sdvo_select_ddc_bus(dev_priv, intel_sdvo, sdvo_reg);
diff --git a/trunk/drivers/gpu/drm/i915/intel_tv.c b/trunk/drivers/gpu/drm/i915/intel_tv.c
index d2c5c8f3baf3..befce6c49704 100644
--- a/trunk/drivers/gpu/drm/i915/intel_tv.c
+++ b/trunk/drivers/gpu/drm/i915/intel_tv.c
@@ -836,37 +836,22 @@ static struct intel_tv *intel_attached_tv(struct drm_connector *connector)
base);
}
-static bool
-intel_tv_get_hw_state(struct intel_encoder *encoder, enum pipe *pipe)
-{
- struct drm_device *dev = encoder->base.dev;
- struct drm_i915_private *dev_priv = dev->dev_private;
- u32 tmp = I915_READ(TV_CTL);
-
- if (!(tmp & TV_ENC_ENABLE))
- return false;
-
- *pipe = PORT_TO_PIPE(tmp);
-
- return true;
-}
-
static void
-intel_enable_tv(struct intel_encoder *encoder)
+intel_tv_dpms(struct drm_encoder *encoder, int mode)
{
- struct drm_device *dev = encoder->base.dev;
- struct drm_i915_private *dev_priv = dev->dev_private;
-
- I915_WRITE(TV_CTL, I915_READ(TV_CTL) | TV_ENC_ENABLE);
-}
-
-static void
-intel_disable_tv(struct intel_encoder *encoder)
-{
- struct drm_device *dev = encoder->base.dev;
+ struct drm_device *dev = encoder->dev;
struct drm_i915_private *dev_priv = dev->dev_private;
- I915_WRITE(TV_CTL, I915_READ(TV_CTL) & ~TV_ENC_ENABLE);
+ switch (mode) {
+ case DRM_MODE_DPMS_ON:
+ I915_WRITE(TV_CTL, I915_READ(TV_CTL) | TV_ENC_ENABLE);
+ break;
+ case DRM_MODE_DPMS_STANDBY:
+ case DRM_MODE_DPMS_SUSPEND:
+ case DRM_MODE_DPMS_OFF:
+ I915_WRITE(TV_CTL, I915_READ(TV_CTL) & ~TV_ENC_ENABLE);
+ break;
+ }
}
static const struct tv_mode *
@@ -910,14 +895,17 @@ intel_tv_mode_fixup(struct drm_encoder *encoder,
const struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode)
{
+ struct drm_device *dev = encoder->dev;
struct intel_tv *intel_tv = enc_to_intel_tv(encoder);
const struct tv_mode *tv_mode = intel_tv_mode_find(intel_tv);
+ struct intel_encoder *other_encoder;
if (!tv_mode)
return false;
- if (intel_encoder_check_is_cloned(&intel_tv->base))
- return false;
+ for_each_encoder_on_crtc(dev, encoder->crtc, other_encoder)
+ if (&other_encoder->base != encoder)
+ return false;
adjusted_mode->clock = tv_mode->clock;
return true;
@@ -1315,9 +1303,12 @@ intel_tv_detect(struct drm_connector *connector, bool force)
if (force) {
struct intel_load_detect_pipe tmp;
- if (intel_get_load_detect_pipe(connector, &mode, &tmp)) {
+ if (intel_get_load_detect_pipe(&intel_tv->base, connector,
+ &mode, &tmp)) {
type = intel_tv_detect_type(intel_tv, connector);
- intel_release_load_detect_pipe(connector, &tmp);
+ intel_release_load_detect_pipe(&intel_tv->base,
+ connector,
+ &tmp);
} else
return connector_status_unknown;
} else
@@ -1483,20 +1474,22 @@ intel_tv_set_property(struct drm_connector *connector, struct drm_property *prop
}
if (changed && crtc)
- intel_set_mode(crtc, &crtc->mode,
- crtc->x, crtc->y, crtc->fb);
+ drm_crtc_helper_set_mode(crtc, &crtc->mode, crtc->x,
+ crtc->y, crtc->fb);
out:
return ret;
}
static const struct drm_encoder_helper_funcs intel_tv_helper_funcs = {
+ .dpms = intel_tv_dpms,
.mode_fixup = intel_tv_mode_fixup,
+ .prepare = intel_encoder_prepare,
.mode_set = intel_tv_mode_set,
- .disable = intel_encoder_noop,
+ .commit = intel_encoder_commit,
};
static const struct drm_connector_funcs intel_tv_connector_funcs = {
- .dpms = intel_connector_dpms,
+ .dpms = drm_helper_connector_dpms,
.detect = intel_tv_detect,
.destroy = intel_tv_destroy,
.set_property = intel_tv_set_property,
@@ -1626,15 +1619,10 @@ intel_tv_init(struct drm_device *dev)
drm_encoder_init(dev, &intel_encoder->base, &intel_tv_enc_funcs,
DRM_MODE_ENCODER_TVDAC);
- intel_encoder->enable = intel_enable_tv;
- intel_encoder->disable = intel_disable_tv;
- intel_encoder->get_hw_state = intel_tv_get_hw_state;
- intel_connector->get_hw_state = intel_connector_get_hw_state;
-
intel_connector_attach_encoder(intel_connector, intel_encoder);
intel_encoder->type = INTEL_OUTPUT_TVOUT;
intel_encoder->crtc_mask = (1 << 0) | (1 << 1);
- intel_encoder->cloneable = false;
+ intel_encoder->clone_mask = (1 << INTEL_TV_CLONE_BIT);
intel_encoder->base.possible_crtcs = ((1 << 0) | (1 << 1));
intel_encoder->base.possible_clones = (1 << INTEL_OUTPUT_TVOUT);
intel_tv->type = DRM_MODE_CONNECTOR_Unknown;
diff --git a/trunk/drivers/gpu/drm/mgag200/mgag200_drv.h b/trunk/drivers/gpu/drm/mgag200/mgag200_drv.h
index d22cbbf3a202..6f13b3563234 100644
--- a/trunk/drivers/gpu/drm/mgag200/mgag200_drv.h
+++ b/trunk/drivers/gpu/drm/mgag200/mgag200_drv.h
@@ -195,6 +195,7 @@ struct mga_device {
struct drm_global_reference mem_global_ref;
struct ttm_bo_global_ref bo_global_ref;
struct ttm_bo_device bdev;
+ atomic_t validate_sequence;
} ttm;
u32 reg_1e24; /* SE model number */
diff --git a/trunk/drivers/gpu/drm/mgag200/mgag200_mode.c b/trunk/drivers/gpu/drm/mgag200/mgag200_mode.c
index c7420e83c0b9..b69642d5d850 100644
--- a/trunk/drivers/gpu/drm/mgag200/mgag200_mode.c
+++ b/trunk/drivers/gpu/drm/mgag200/mgag200_mode.c
@@ -1399,6 +1399,7 @@ static int mga_vga_get_modes(struct drm_connector *connector)
if (edid) {
drm_mode_connector_update_edid_property(connector, edid);
ret = drm_add_edid_modes(connector, edid);
+ connector->display_info.raw_edid = NULL;
kfree(edid);
}
return ret;
diff --git a/trunk/drivers/gpu/drm/nouveau/nouveau_dp.c b/trunk/drivers/gpu/drm/nouveau/nouveau_dp.c
index e754aa32edf1..7e289d2ad8e4 100644
--- a/trunk/drivers/gpu/drm/nouveau/nouveau_dp.c
+++ b/trunk/drivers/gpu/drm/nouveau/nouveau_dp.c
@@ -289,7 +289,9 @@ dp_link_train_update(struct drm_device *dev, struct dp_state *dp, u32 delay)
if (ret)
return ret;
- NV_DEBUG_KMS(dev, "status %*ph\n", 6, dp->stat);
+ NV_DEBUG_KMS(dev, "status %02x %02x %02x %02x %02x %02x\n",
+ dp->stat[0], dp->stat[1], dp->stat[2], dp->stat[3],
+ dp->stat[4], dp->stat[5]);
return 0;
}
diff --git a/trunk/drivers/gpu/drm/nouveau/nv50_gpio.c b/trunk/drivers/gpu/drm/nouveau/nv50_gpio.c
index c399d510b27a..f03490534893 100644
--- a/trunk/drivers/gpu/drm/nouveau/nv50_gpio.c
+++ b/trunk/drivers/gpu/drm/nouveau/nv50_gpio.c
@@ -22,7 +22,6 @@
* Authors: Ben Skeggs
*/
-#include
#include "drmP.h"
#include "nouveau_drv.h"
#include "nouveau_hw.h"
@@ -111,25 +110,13 @@ nv50_gpio_isr(struct drm_device *dev)
nv_wr32(dev, 0xe074, intr1);
}
-static struct dmi_system_id gpio_reset_ids[] = {
- {
- .ident = "Apple Macbook 10,1",
- .matches = {
- DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
- DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro10,1"),
- }
- },
- { }
-};
-
int
nv50_gpio_init(struct drm_device *dev)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
/* initialise gpios and routing to vbios defaults */
- if (dmi_check_system(gpio_reset_ids))
- nouveau_gpio_reset(dev);
+ nouveau_gpio_reset(dev);
/* disable, and ack any pending gpio interrupts */
nv_wr32(dev, 0xe050, 0x00000000);
diff --git a/trunk/drivers/gpu/drm/radeon/atombios_dp.c b/trunk/drivers/gpu/drm/radeon/atombios_dp.c
index d48224b0d6b4..3623b98ed3fe 100644
--- a/trunk/drivers/gpu/drm/radeon/atombios_dp.c
+++ b/trunk/drivers/gpu/drm/radeon/atombios_dp.c
@@ -653,7 +653,9 @@ static bool radeon_dp_get_link_status(struct radeon_connector *radeon_connector,
return false;
}
- DRM_DEBUG_KMS("link status %*ph\n", 6, link_status);
+ DRM_DEBUG_KMS("link status %02x %02x %02x %02x %02x %02x\n",
+ link_status[0], link_status[1], link_status[2],
+ link_status[3], link_status[4], link_status[5]);
return true;
}
diff --git a/trunk/drivers/gpu/drm/radeon/evergreen.c b/trunk/drivers/gpu/drm/radeon/evergreen.c
index e93b80a6d4e9..0c79d9eb2ce4 100644
--- a/trunk/drivers/gpu/drm/radeon/evergreen.c
+++ b/trunk/drivers/gpu/drm/radeon/evergreen.c
@@ -37,6 +37,16 @@
#define EVERGREEN_PFP_UCODE_SIZE 1120
#define EVERGREEN_PM4_UCODE_SIZE 1376
+static const u32 crtc_offsets[6] =
+{
+ EVERGREEN_CRTC0_REGISTER_OFFSET,
+ EVERGREEN_CRTC1_REGISTER_OFFSET,
+ EVERGREEN_CRTC2_REGISTER_OFFSET,
+ EVERGREEN_CRTC3_REGISTER_OFFSET,
+ EVERGREEN_CRTC4_REGISTER_OFFSET,
+ EVERGREEN_CRTC5_REGISTER_OFFSET
+};
+
static void evergreen_gpu_init(struct radeon_device *rdev);
void evergreen_fini(struct radeon_device *rdev);
void evergreen_pcie_gen2_enable(struct radeon_device *rdev);
@@ -109,17 +119,19 @@ void evergreen_fix_pci_max_read_req_size(struct radeon_device *rdev)
*/
void dce4_wait_for_vblank(struct radeon_device *rdev, int crtc)
{
- struct radeon_crtc *radeon_crtc = rdev->mode_info.crtcs[crtc];
int i;
- if (RREG32(EVERGREEN_CRTC_CONTROL + radeon_crtc->crtc_offset) & EVERGREEN_CRTC_MASTER_EN) {
+ if (crtc >= rdev->num_crtc)
+ return;
+
+ if (RREG32(EVERGREEN_CRTC_CONTROL + crtc_offsets[crtc]) & EVERGREEN_CRTC_MASTER_EN) {
for (i = 0; i < rdev->usec_timeout; i++) {
- if (!(RREG32(EVERGREEN_CRTC_STATUS + radeon_crtc->crtc_offset) & EVERGREEN_CRTC_V_BLANK))
+ if (!(RREG32(EVERGREEN_CRTC_STATUS + crtc_offsets[crtc]) & EVERGREEN_CRTC_V_BLANK))
break;
udelay(1);
}
for (i = 0; i < rdev->usec_timeout; i++) {
- if (RREG32(EVERGREEN_CRTC_STATUS + radeon_crtc->crtc_offset) & EVERGREEN_CRTC_V_BLANK)
+ if (RREG32(EVERGREEN_CRTC_STATUS + crtc_offsets[crtc]) & EVERGREEN_CRTC_V_BLANK)
break;
udelay(1);
}
diff --git a/trunk/drivers/gpu/drm/shmobile/Kconfig b/trunk/drivers/gpu/drm/shmobile/Kconfig
deleted file mode 100644
index 7e7d52b2a2fc..000000000000
--- a/trunk/drivers/gpu/drm/shmobile/Kconfig
+++ /dev/null
@@ -1,10 +0,0 @@
-config DRM_SHMOBILE
- tristate "DRM Support for SH Mobile"
- depends on DRM && (SUPERH || ARCH_SHMOBILE)
- select DRM_KMS_HELPER
- select DRM_KMS_CMA_HELPER
- select DRM_GEM_CMA_HELPER
- help
- Choose this option if you have an SH Mobile chipset.
- If M is selected the module will be called shmob-drm.
-
diff --git a/trunk/drivers/gpu/drm/shmobile/Makefile b/trunk/drivers/gpu/drm/shmobile/Makefile
deleted file mode 100644
index 4c3eeb355630..000000000000
--- a/trunk/drivers/gpu/drm/shmobile/Makefile
+++ /dev/null
@@ -1,7 +0,0 @@
-shmob-drm-y := shmob_drm_backlight.o \
- shmob_drm_crtc.o \
- shmob_drm_drv.o \
- shmob_drm_kms.o \
- shmob_drm_plane.o
-
-obj-$(CONFIG_DRM_SHMOBILE) += shmob-drm.o
diff --git a/trunk/drivers/gpu/drm/shmobile/shmob_drm_backlight.c b/trunk/drivers/gpu/drm/shmobile/shmob_drm_backlight.c
deleted file mode 100644
index 463aee18f774..000000000000
--- a/trunk/drivers/gpu/drm/shmobile/shmob_drm_backlight.c
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
- * shmob_drm_backlight.c -- SH Mobile DRM Backlight
- *
- * Copyright (C) 2012 Renesas Corporation
- *
- * Laurent Pinchart (laurent.pinchart@ideasonboard.com)
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- */
-
-#include
-
-#include "shmob_drm_backlight.h"
-#include "shmob_drm_crtc.h"
-#include "shmob_drm_drv.h"
-
-static int shmob_drm_backlight_update(struct backlight_device *bdev)
-{
- struct shmob_drm_connector *scon = bl_get_data(bdev);
- struct shmob_drm_device *sdev = scon->connector.dev->dev_private;
- const struct shmob_drm_backlight_data *bdata = &sdev->pdata->backlight;
- int brightness = bdev->props.brightness;
-
- if (bdev->props.power != FB_BLANK_UNBLANK ||
- bdev->props.state & BL_CORE_SUSPENDED)
- brightness = 0;
-
- return bdata->set_brightness(brightness);
-}
-
-static int shmob_drm_backlight_get_brightness(struct backlight_device *bdev)
-{
- struct shmob_drm_connector *scon = bl_get_data(bdev);
- struct shmob_drm_device *sdev = scon->connector.dev->dev_private;
- const struct shmob_drm_backlight_data *bdata = &sdev->pdata->backlight;
-
- return bdata->get_brightness();
-}
-
-static const struct backlight_ops shmob_drm_backlight_ops = {
- .options = BL_CORE_SUSPENDRESUME,
- .update_status = shmob_drm_backlight_update,
- .get_brightness = shmob_drm_backlight_get_brightness,
-};
-
-void shmob_drm_backlight_dpms(struct shmob_drm_connector *scon, int mode)
-{
- if (scon->backlight == NULL)
- return;
-
- scon->backlight->props.power = mode == DRM_MODE_DPMS_ON
- ? FB_BLANK_UNBLANK : FB_BLANK_POWERDOWN;
- backlight_update_status(scon->backlight);
-}
-
-int shmob_drm_backlight_init(struct shmob_drm_connector *scon)
-{
- struct shmob_drm_device *sdev = scon->connector.dev->dev_private;
- const struct shmob_drm_backlight_data *bdata = &sdev->pdata->backlight;
- struct drm_connector *connector = &scon->connector;
- struct drm_device *dev = connector->dev;
- struct backlight_device *backlight;
-
- if (!bdata->max_brightness)
- return 0;
-
- backlight = backlight_device_register(bdata->name, dev->dev, scon,
- &shmob_drm_backlight_ops, NULL);
- if (IS_ERR(backlight)) {
- dev_err(dev->dev, "unable to register backlight device: %ld\n",
- PTR_ERR(backlight));
- return PTR_ERR(backlight);
- }
-
- backlight->props.max_brightness = bdata->max_brightness;
- backlight->props.brightness = bdata->max_brightness;
- backlight->props.power = FB_BLANK_POWERDOWN;
- backlight_update_status(backlight);
-
- scon->backlight = backlight;
- return 0;
-}
-
-void shmob_drm_backlight_exit(struct shmob_drm_connector *scon)
-{
- backlight_device_unregister(scon->backlight);
-}
diff --git a/trunk/drivers/gpu/drm/shmobile/shmob_drm_backlight.h b/trunk/drivers/gpu/drm/shmobile/shmob_drm_backlight.h
deleted file mode 100644
index 9477595d2ff3..000000000000
--- a/trunk/drivers/gpu/drm/shmobile/shmob_drm_backlight.h
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
- * shmob_drm_backlight.h -- SH Mobile DRM Backlight
- *
- * Copyright (C) 2012 Renesas Corporation
- *
- * Laurent Pinchart (laurent.pinchart@ideasonboard.com)
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- */
-
-#ifndef __SHMOB_DRM_BACKLIGHT_H__
-#define __SHMOB_DRM_BACKLIGHT_H__
-
-struct shmob_drm_connector;
-
-void shmob_drm_backlight_dpms(struct shmob_drm_connector *scon, int mode);
-int shmob_drm_backlight_init(struct shmob_drm_connector *scon);
-void shmob_drm_backlight_exit(struct shmob_drm_connector *scon);
-
-#endif /* __SHMOB_DRM_BACKLIGHT_H__ */
diff --git a/trunk/drivers/gpu/drm/shmobile/shmob_drm_crtc.c b/trunk/drivers/gpu/drm/shmobile/shmob_drm_crtc.c
deleted file mode 100644
index 0e7a9306bd0c..000000000000
--- a/trunk/drivers/gpu/drm/shmobile/shmob_drm_crtc.c
+++ /dev/null
@@ -1,763 +0,0 @@
-/*
- * shmob_drm_crtc.c -- SH Mobile DRM CRTCs
- *
- * Copyright (C) 2012 Renesas Corporation
- *
- * Laurent Pinchart (laurent.pinchart@ideasonboard.com)
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- */
-
-#include
-#include
-
-#include
-#include
-#include
-#include
-#include
-
-#include