You've already forked linux-apfs
mirror of
https://github.com/linux-apfs/linux-apfs.git
synced 2026-05-01 15:00:59 -07:00
Merge branch 'drm-next' of git://people.freedesktop.org/~airlied/linux
Pull DRM updates from Dave Airlie:
"This is the one and only next pull for 3.8, we had a regression we
found last week, so I was waiting for that to resolve itself, and I
ended up with some Intel fixes on top as well.
Highlights:
- new driver: nvidia tegra 20/30/hdmi support
- radeon: add support for previously unused DMA engines, more HDMI
regs, eviction speeds ups and fixes
- i915: HSW support enable, agp removal on GEN6, seqno wrapping
- exynos: IPP subsystem support (image post proc), HDMI
- nouveau: display class reworking, nv20->40 z compression
- ttm: start of locking fixes, rcu usage for lookups,
- core: documentation updates, docbook integration, monotonic clock
usage, move from connector to object properties"
* 'drm-next' of git://people.freedesktop.org/~airlied/linux: (590 commits)
drm/exynos: add gsc ipp driver
drm/exynos: add rotator ipp driver
drm/exynos: add fimc ipp driver
drm/exynos: add iommu support for ipp
drm/exynos: add ipp subsystem
drm/exynos: support device tree for fimd
radeon: fix regression with eviction since evict caching changes
drm/radeon: add more pedantic checks in the CP DMA checker
drm/radeon: bump version for CS ioctl support for async DMA
drm/radeon: enable the async DMA rings in the CS ioctl
drm/radeon: add VM CS parser support for async DMA on cayman/TN/SI
drm/radeon/kms: add evergreen/cayman CS parser for async DMA (v2)
drm/radeon/kms: add 6xx/7xx CS parser for async DMA (v2)
drm/radeon: fix htile buffer size computation for command stream checker
drm/radeon: fix fence locking in the pageflip callback
drm/radeon: make indirect register access concurrency-safe
drm/radeon: add W|RREG32_IDX for MM_INDEX|DATA based mmio accesss
drm/exynos: support extended screen coordinate of fimd
drm/exynos: fix x, y coordinates for right bottom pixel
drm/exynos: fix fb offset calculation for plane
...
This commit is contained in:
@@ -91,3 +91,12 @@ transferred to 'device' domain. This attribute can be also used for
|
||||
dma_unmap_{single,page,sg} functions family to force buffer to stay in
|
||||
device domain after releasing a mapping for it. Use this attribute with
|
||||
care!
|
||||
|
||||
DMA_ATTR_FORCE_CONTIGUOUS
|
||||
-------------------------
|
||||
|
||||
By default DMA-mapping subsystem is allowed to assemble the buffer
|
||||
allocated by dma_alloc_attrs() function from individual pages if it can
|
||||
be mapped as contiguous chunk into device dma address space. By
|
||||
specifing this attribute the allocated buffer is forced to be contiguous
|
||||
also in physical memory.
|
||||
|
||||
@@ -1141,23 +1141,13 @@ int max_width, max_height;</synopsis>
|
||||
the <methodname>page_flip</methodname> operation will be called with a
|
||||
non-NULL <parameter>event</parameter> argument pointing to a
|
||||
<structname>drm_pending_vblank_event</structname> instance. Upon page
|
||||
flip completion the driver must fill the
|
||||
<parameter>event</parameter>::<structfield>event</structfield>
|
||||
<structfield>sequence</structfield>, <structfield>tv_sec</structfield>
|
||||
and <structfield>tv_usec</structfield> fields with the associated
|
||||
vertical blanking count and timestamp, add the event to the
|
||||
<parameter>drm_file</parameter> list of events to be signaled, and wake
|
||||
up any waiting process. This can be performed with
|
||||
flip completion the driver must call <methodname>drm_send_vblank_event</methodname>
|
||||
to fill in the event and send to wake up any waiting processes.
|
||||
This can be performed with
|
||||
<programlisting><![CDATA[
|
||||
struct timeval now;
|
||||
|
||||
event->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);
|
||||
...
|
||||
drm_send_vblank_event(dev, pipe, event);
|
||||
spin_unlock_irqrestore(&dev->event_lock, flags);
|
||||
]]></programlisting>
|
||||
</para>
|
||||
@@ -1621,10 +1611,10 @@ void intel_crt_init(struct drm_device *dev)
|
||||
</sect2>
|
||||
</sect1>
|
||||
|
||||
<!-- Internals: mid-layer helper functions -->
|
||||
<!-- Internals: kms helper functions -->
|
||||
|
||||
<sect1>
|
||||
<title>Mid-layer Helper Functions</title>
|
||||
<title>Mode Setting Helper Functions</title>
|
||||
<para>
|
||||
The CRTC, encoder and connector functions provided by the drivers
|
||||
implement the DRM API. They're called by the DRM core and ioctl handlers
|
||||
@@ -2106,6 +2096,21 @@ void intel_crt_init(struct drm_device *dev)
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
</sect2>
|
||||
<sect2>
|
||||
<title>Modeset Helper Functions Reference</title>
|
||||
!Edrivers/gpu/drm/drm_crtc_helper.c
|
||||
</sect2>
|
||||
<sect2>
|
||||
<title>fbdev Helper Functions Reference</title>
|
||||
!Pdrivers/gpu/drm/drm_fb_helper.c fbdev helpers
|
||||
!Edrivers/gpu/drm/drm_fb_helper.c
|
||||
</sect2>
|
||||
<sect2>
|
||||
<title>Display Port Helper Functions Reference</title>
|
||||
!Pdrivers/gpu/drm/drm_dp_helper.c dp helpers
|
||||
!Iinclude/drm/drm_dp_helper.h
|
||||
!Edrivers/gpu/drm/drm_dp_helper.c
|
||||
</sect2>
|
||||
</sect1>
|
||||
|
||||
<!-- Internals: vertical blanking -->
|
||||
|
||||
@@ -0,0 +1,191 @@
|
||||
NVIDIA Tegra host1x
|
||||
|
||||
Required properties:
|
||||
- compatible: "nvidia,tegra<chip>-host1x"
|
||||
- reg: Physical base address and length of the controller's registers.
|
||||
- interrupts: The interrupt outputs from the controller.
|
||||
- #address-cells: The number of cells used to represent physical base addresses
|
||||
in the host1x address space. Should be 1.
|
||||
- #size-cells: The number of cells used to represent the size of an address
|
||||
range in the host1x address space. Should be 1.
|
||||
- ranges: The mapping of the host1x address space to the CPU address space.
|
||||
|
||||
The host1x top-level node defines a number of children, each representing one
|
||||
of the following host1x client modules:
|
||||
|
||||
- mpe: video encoder
|
||||
|
||||
Required properties:
|
||||
- compatible: "nvidia,tegra<chip>-mpe"
|
||||
- reg: Physical base address and length of the controller's registers.
|
||||
- interrupts: The interrupt outputs from the controller.
|
||||
|
||||
- vi: video input
|
||||
|
||||
Required properties:
|
||||
- compatible: "nvidia,tegra<chip>-vi"
|
||||
- reg: Physical base address and length of the controller's registers.
|
||||
- interrupts: The interrupt outputs from the controller.
|
||||
|
||||
- epp: encoder pre-processor
|
||||
|
||||
Required properties:
|
||||
- compatible: "nvidia,tegra<chip>-epp"
|
||||
- reg: Physical base address and length of the controller's registers.
|
||||
- interrupts: The interrupt outputs from the controller.
|
||||
|
||||
- isp: image signal processor
|
||||
|
||||
Required properties:
|
||||
- compatible: "nvidia,tegra<chip>-isp"
|
||||
- reg: Physical base address and length of the controller's registers.
|
||||
- interrupts: The interrupt outputs from the controller.
|
||||
|
||||
- gr2d: 2D graphics engine
|
||||
|
||||
Required properties:
|
||||
- compatible: "nvidia,tegra<chip>-gr2d"
|
||||
- reg: Physical base address and length of the controller's registers.
|
||||
- interrupts: The interrupt outputs from the controller.
|
||||
|
||||
- gr3d: 3D graphics engine
|
||||
|
||||
Required properties:
|
||||
- compatible: "nvidia,tegra<chip>-gr3d"
|
||||
- reg: Physical base address and length of the controller's registers.
|
||||
|
||||
- dc: display controller
|
||||
|
||||
Required properties:
|
||||
- compatible: "nvidia,tegra<chip>-dc"
|
||||
- reg: Physical base address and length of the controller's registers.
|
||||
- interrupts: The interrupt outputs from the controller.
|
||||
|
||||
Each display controller node has a child node, named "rgb", that represents
|
||||
the RGB output associated with the controller. It can take the following
|
||||
optional properties:
|
||||
- nvidia,ddc-i2c-bus: phandle of an I2C controller used for DDC EDID probing
|
||||
- nvidia,hpd-gpio: specifies a GPIO used for hotplug detection
|
||||
- nvidia,edid: supplies a binary EDID blob
|
||||
|
||||
- hdmi: High Definition Multimedia Interface
|
||||
|
||||
Required properties:
|
||||
- compatible: "nvidia,tegra<chip>-hdmi"
|
||||
- reg: Physical base address and length of the controller's registers.
|
||||
- interrupts: The interrupt outputs from the controller.
|
||||
- vdd-supply: regulator for supply voltage
|
||||
- pll-supply: regulator for PLL
|
||||
|
||||
Optional properties:
|
||||
- nvidia,ddc-i2c-bus: phandle of an I2C controller used for DDC EDID probing
|
||||
- nvidia,hpd-gpio: specifies a GPIO used for hotplug detection
|
||||
- nvidia,edid: supplies a binary EDID blob
|
||||
|
||||
- tvo: TV encoder output
|
||||
|
||||
Required properties:
|
||||
- compatible: "nvidia,tegra<chip>-tvo"
|
||||
- reg: Physical base address and length of the controller's registers.
|
||||
- interrupts: The interrupt outputs from the controller.
|
||||
|
||||
- dsi: display serial interface
|
||||
|
||||
Required properties:
|
||||
- compatible: "nvidia,tegra<chip>-dsi"
|
||||
- reg: Physical base address and length of the controller's registers.
|
||||
|
||||
Example:
|
||||
|
||||
/ {
|
||||
...
|
||||
|
||||
host1x {
|
||||
compatible = "nvidia,tegra20-host1x", "simple-bus";
|
||||
reg = <0x50000000 0x00024000>;
|
||||
interrupts = <0 65 0x04 /* mpcore syncpt */
|
||||
0 67 0x04>; /* mpcore general */
|
||||
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
|
||||
ranges = <0x54000000 0x54000000 0x04000000>;
|
||||
|
||||
mpe {
|
||||
compatible = "nvidia,tegra20-mpe";
|
||||
reg = <0x54040000 0x00040000>;
|
||||
interrupts = <0 68 0x04>;
|
||||
};
|
||||
|
||||
vi {
|
||||
compatible = "nvidia,tegra20-vi";
|
||||
reg = <0x54080000 0x00040000>;
|
||||
interrupts = <0 69 0x04>;
|
||||
};
|
||||
|
||||
epp {
|
||||
compatible = "nvidia,tegra20-epp";
|
||||
reg = <0x540c0000 0x00040000>;
|
||||
interrupts = <0 70 0x04>;
|
||||
};
|
||||
|
||||
isp {
|
||||
compatible = "nvidia,tegra20-isp";
|
||||
reg = <0x54100000 0x00040000>;
|
||||
interrupts = <0 71 0x04>;
|
||||
};
|
||||
|
||||
gr2d {
|
||||
compatible = "nvidia,tegra20-gr2d";
|
||||
reg = <0x54140000 0x00040000>;
|
||||
interrupts = <0 72 0x04>;
|
||||
};
|
||||
|
||||
gr3d {
|
||||
compatible = "nvidia,tegra20-gr3d";
|
||||
reg = <0x54180000 0x00040000>;
|
||||
};
|
||||
|
||||
dc@54200000 {
|
||||
compatible = "nvidia,tegra20-dc";
|
||||
reg = <0x54200000 0x00040000>;
|
||||
interrupts = <0 73 0x04>;
|
||||
|
||||
rgb {
|
||||
status = "disabled";
|
||||
};
|
||||
};
|
||||
|
||||
dc@54240000 {
|
||||
compatible = "nvidia,tegra20-dc";
|
||||
reg = <0x54240000 0x00040000>;
|
||||
interrupts = <0 74 0x04>;
|
||||
|
||||
rgb {
|
||||
status = "disabled";
|
||||
};
|
||||
};
|
||||
|
||||
hdmi {
|
||||
compatible = "nvidia,tegra20-hdmi";
|
||||
reg = <0x54280000 0x00040000>;
|
||||
interrupts = <0 75 0x04>;
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
tvo {
|
||||
compatible = "nvidia,tegra20-tvo";
|
||||
reg = <0x542c0000 0x00040000>;
|
||||
interrupts = <0 76 0x04>;
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
dsi {
|
||||
compatible = "nvidia,tegra20-dsi";
|
||||
reg = <0x54300000 0x00040000>;
|
||||
status = "disabled";
|
||||
};
|
||||
};
|
||||
|
||||
...
|
||||
};
|
||||
@@ -213,3 +213,91 @@ presentation on krefs, which can be found at:
|
||||
and:
|
||||
http://www.kroah.com/linux/talks/ols_2004_kref_talk/
|
||||
|
||||
|
||||
The above example could also be optimized using kref_get_unless_zero() in
|
||||
the following way:
|
||||
|
||||
static struct my_data *get_entry()
|
||||
{
|
||||
struct my_data *entry = NULL;
|
||||
mutex_lock(&mutex);
|
||||
if (!list_empty(&q)) {
|
||||
entry = container_of(q.next, struct my_data, link);
|
||||
if (!kref_get_unless_zero(&entry->refcount))
|
||||
entry = NULL;
|
||||
}
|
||||
mutex_unlock(&mutex);
|
||||
return entry;
|
||||
}
|
||||
|
||||
static void release_entry(struct kref *ref)
|
||||
{
|
||||
struct my_data *entry = container_of(ref, struct my_data, refcount);
|
||||
|
||||
mutex_lock(&mutex);
|
||||
list_del(&entry->link);
|
||||
mutex_unlock(&mutex);
|
||||
kfree(entry);
|
||||
}
|
||||
|
||||
static void put_entry(struct my_data *entry)
|
||||
{
|
||||
kref_put(&entry->refcount, release_entry);
|
||||
}
|
||||
|
||||
Which is useful to remove the mutex lock around kref_put() in put_entry(), but
|
||||
it's important that kref_get_unless_zero is enclosed in the same critical
|
||||
section that finds the entry in the lookup table,
|
||||
otherwise kref_get_unless_zero may reference already freed memory.
|
||||
Note that it is illegal to use kref_get_unless_zero without checking its
|
||||
return value. If you are sure (by already having a valid pointer) that
|
||||
kref_get_unless_zero() will return true, then use kref_get() instead.
|
||||
|
||||
The function kref_get_unless_zero also makes it possible to use rcu
|
||||
locking for lookups in the above example:
|
||||
|
||||
struct my_data
|
||||
{
|
||||
struct rcu_head rhead;
|
||||
.
|
||||
struct kref refcount;
|
||||
.
|
||||
.
|
||||
};
|
||||
|
||||
static struct my_data *get_entry_rcu()
|
||||
{
|
||||
struct my_data *entry = NULL;
|
||||
rcu_read_lock();
|
||||
if (!list_empty(&q)) {
|
||||
entry = container_of(q.next, struct my_data, link);
|
||||
if (!kref_get_unless_zero(&entry->refcount))
|
||||
entry = NULL;
|
||||
}
|
||||
rcu_read_unlock();
|
||||
return entry;
|
||||
}
|
||||
|
||||
static void release_entry_rcu(struct kref *ref)
|
||||
{
|
||||
struct my_data *entry = container_of(ref, struct my_data, refcount);
|
||||
|
||||
mutex_lock(&mutex);
|
||||
list_del_rcu(&entry->link);
|
||||
mutex_unlock(&mutex);
|
||||
kfree_rcu(entry, rhead);
|
||||
}
|
||||
|
||||
static void put_entry(struct my_data *entry)
|
||||
{
|
||||
kref_put(&entry->refcount, release_entry_rcu);
|
||||
}
|
||||
|
||||
But note that the struct kref member needs to remain in valid memory for a
|
||||
rcu grace period after release_entry_rcu was called. That can be accomplished
|
||||
by using kfree_rcu(entry, rhead) as done above, or by calling synchronize_rcu()
|
||||
before using kfree, but note that synchronize_rcu() may sleep for a
|
||||
substantial amount of time.
|
||||
|
||||
|
||||
Thomas Hellstrom <thellstrom@vmware.com>
|
||||
|
||||
@@ -2549,6 +2549,15 @@ S: Supported
|
||||
F: drivers/gpu/drm/exynos
|
||||
F: include/drm/exynos*
|
||||
|
||||
DRM DRIVERS FOR NVIDIA TEGRA
|
||||
M: Thierry Reding <thierry.reding@avionic-design.de>
|
||||
L: dri-devel@lists.freedesktop.org
|
||||
L: linux-tegra@vger.kernel.org
|
||||
T: git git://gitorious.org/thierryreding/linux.git
|
||||
S: Maintained
|
||||
F: drivers/gpu/drm/tegra/
|
||||
F: Documentation/devicetree/bindings/gpu/nvidia,tegra20-host1x.txt
|
||||
|
||||
DSCC4 DRIVER
|
||||
M: Francois Romieu <romieu@fr.zoreil.com>
|
||||
L: netdev@vger.kernel.org
|
||||
|
||||
@@ -1034,7 +1034,8 @@ static inline void __free_iova(struct dma_iommu_mapping *mapping,
|
||||
spin_unlock_irqrestore(&mapping->lock, flags);
|
||||
}
|
||||
|
||||
static struct page **__iommu_alloc_buffer(struct device *dev, size_t size, gfp_t gfp)
|
||||
static struct page **__iommu_alloc_buffer(struct device *dev, size_t size,
|
||||
gfp_t gfp, struct dma_attrs *attrs)
|
||||
{
|
||||
struct page **pages;
|
||||
int count = size >> PAGE_SHIFT;
|
||||
@@ -1048,6 +1049,23 @@ static struct page **__iommu_alloc_buffer(struct device *dev, size_t size, gfp_t
|
||||
if (!pages)
|
||||
return NULL;
|
||||
|
||||
if (dma_get_attr(DMA_ATTR_FORCE_CONTIGUOUS, attrs))
|
||||
{
|
||||
unsigned long order = get_order(size);
|
||||
struct page *page;
|
||||
|
||||
page = dma_alloc_from_contiguous(dev, count, order);
|
||||
if (!page)
|
||||
goto error;
|
||||
|
||||
__dma_clear_buffer(page, size);
|
||||
|
||||
for (i = 0; i < count; i++)
|
||||
pages[i] = page + i;
|
||||
|
||||
return pages;
|
||||
}
|
||||
|
||||
while (count) {
|
||||
int j, order = __fls(count);
|
||||
|
||||
@@ -1081,14 +1099,21 @@ error:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int __iommu_free_buffer(struct device *dev, struct page **pages, size_t size)
|
||||
static int __iommu_free_buffer(struct device *dev, struct page **pages,
|
||||
size_t size, struct dma_attrs *attrs)
|
||||
{
|
||||
int count = size >> PAGE_SHIFT;
|
||||
int array_size = count * sizeof(struct page *);
|
||||
int i;
|
||||
for (i = 0; i < count; i++)
|
||||
if (pages[i])
|
||||
__free_pages(pages[i], 0);
|
||||
|
||||
if (dma_get_attr(DMA_ATTR_FORCE_CONTIGUOUS, attrs)) {
|
||||
dma_release_from_contiguous(dev, pages[0], count);
|
||||
} else {
|
||||
for (i = 0; i < count; i++)
|
||||
if (pages[i])
|
||||
__free_pages(pages[i], 0);
|
||||
}
|
||||
|
||||
if (array_size <= PAGE_SIZE)
|
||||
kfree(pages);
|
||||
else
|
||||
@@ -1250,7 +1275,7 @@ static void *arm_iommu_alloc_attrs(struct device *dev, size_t size,
|
||||
if (gfp & GFP_ATOMIC)
|
||||
return __iommu_alloc_atomic(dev, size, handle);
|
||||
|
||||
pages = __iommu_alloc_buffer(dev, size, gfp);
|
||||
pages = __iommu_alloc_buffer(dev, size, gfp, attrs);
|
||||
if (!pages)
|
||||
return NULL;
|
||||
|
||||
@@ -1271,7 +1296,7 @@ static void *arm_iommu_alloc_attrs(struct device *dev, size_t size,
|
||||
err_mapping:
|
||||
__iommu_remove_mapping(dev, *handle, size);
|
||||
err_buffer:
|
||||
__iommu_free_buffer(dev, pages, size);
|
||||
__iommu_free_buffer(dev, pages, size, attrs);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -1327,7 +1352,7 @@ void arm_iommu_free_attrs(struct device *dev, size_t size, void *cpu_addr,
|
||||
}
|
||||
|
||||
__iommu_remove_mapping(dev, handle, size);
|
||||
__iommu_free_buffer(dev, pages, size);
|
||||
__iommu_free_buffer(dev, pages, size, attrs);
|
||||
}
|
||||
|
||||
static int arm_iommu_get_sgtable(struct device *dev, struct sg_table *sgt,
|
||||
|
||||
@@ -62,12 +62,6 @@
|
||||
#define I810_PTE_LOCAL 0x00000002
|
||||
#define I810_PTE_VALID 0x00000001
|
||||
#define I830_PTE_SYSTEM_CACHED 0x00000006
|
||||
/* GT PTE cache control fields */
|
||||
#define GEN6_PTE_UNCACHED 0x00000002
|
||||
#define HSW_PTE_UNCACHED 0x00000000
|
||||
#define GEN6_PTE_LLC 0x00000004
|
||||
#define GEN6_PTE_LLC_MLC 0x00000006
|
||||
#define GEN6_PTE_GFDT 0x00000008
|
||||
|
||||
#define I810_SMRAM_MISCC 0x70
|
||||
#define I810_GFX_MEM_WIN_SIZE 0x00010000
|
||||
@@ -97,7 +91,6 @@
|
||||
#define G4x_GMCH_SIZE_VT_2M (G4x_GMCH_SIZE_2M | G4x_GMCH_SIZE_VT_EN)
|
||||
|
||||
#define GFX_FLSH_CNTL 0x2170 /* 915+ */
|
||||
#define GFX_FLSH_CNTL_VLV 0x101008
|
||||
|
||||
#define I810_DRAM_CTL 0x3000
|
||||
#define I810_DRAM_ROW_0 0x00000001
|
||||
@@ -148,29 +141,6 @@
|
||||
#define INTEL_I7505_AGPCTRL 0x70
|
||||
#define INTEL_I7505_MCHCFG 0x50
|
||||
|
||||
#define SNB_GMCH_CTRL 0x50
|
||||
#define SNB_GMCH_GMS_STOLEN_MASK 0xF8
|
||||
#define SNB_GMCH_GMS_STOLEN_32M (1 << 3)
|
||||
#define SNB_GMCH_GMS_STOLEN_64M (2 << 3)
|
||||
#define SNB_GMCH_GMS_STOLEN_96M (3 << 3)
|
||||
#define SNB_GMCH_GMS_STOLEN_128M (4 << 3)
|
||||
#define SNB_GMCH_GMS_STOLEN_160M (5 << 3)
|
||||
#define SNB_GMCH_GMS_STOLEN_192M (6 << 3)
|
||||
#define SNB_GMCH_GMS_STOLEN_224M (7 << 3)
|
||||
#define SNB_GMCH_GMS_STOLEN_256M (8 << 3)
|
||||
#define SNB_GMCH_GMS_STOLEN_288M (9 << 3)
|
||||
#define SNB_GMCH_GMS_STOLEN_320M (0xa << 3)
|
||||
#define SNB_GMCH_GMS_STOLEN_352M (0xb << 3)
|
||||
#define SNB_GMCH_GMS_STOLEN_384M (0xc << 3)
|
||||
#define SNB_GMCH_GMS_STOLEN_416M (0xd << 3)
|
||||
#define SNB_GMCH_GMS_STOLEN_448M (0xe << 3)
|
||||
#define SNB_GMCH_GMS_STOLEN_480M (0xf << 3)
|
||||
#define SNB_GMCH_GMS_STOLEN_512M (0x10 << 3)
|
||||
#define SNB_GTT_SIZE_0M (0 << 8)
|
||||
#define SNB_GTT_SIZE_1M (1 << 8)
|
||||
#define SNB_GTT_SIZE_2M (2 << 8)
|
||||
#define SNB_GTT_SIZE_MASK (3 << 8)
|
||||
|
||||
/* pci devices ids */
|
||||
#define PCI_DEVICE_ID_INTEL_E7221_HB 0x2588
|
||||
#define PCI_DEVICE_ID_INTEL_E7221_IG 0x258a
|
||||
@@ -219,66 +189,5 @@
|
||||
#define PCI_DEVICE_ID_INTEL_IRONLAKE_MA_HB 0x0062
|
||||
#define PCI_DEVICE_ID_INTEL_IRONLAKE_MC2_HB 0x006a
|
||||
#define PCI_DEVICE_ID_INTEL_IRONLAKE_M_IG 0x0046
|
||||
#define PCI_DEVICE_ID_INTEL_SANDYBRIDGE_HB 0x0100 /* Desktop */
|
||||
#define PCI_DEVICE_ID_INTEL_SANDYBRIDGE_GT1_IG 0x0102
|
||||
#define PCI_DEVICE_ID_INTEL_SANDYBRIDGE_GT2_IG 0x0112
|
||||
#define PCI_DEVICE_ID_INTEL_SANDYBRIDGE_GT2_PLUS_IG 0x0122
|
||||
#define PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_HB 0x0104 /* Mobile */
|
||||
#define PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_GT1_IG 0x0106
|
||||
#define PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_GT2_IG 0x0116
|
||||
#define PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_GT2_PLUS_IG 0x0126
|
||||
#define PCI_DEVICE_ID_INTEL_SANDYBRIDGE_S_HB 0x0108 /* Server */
|
||||
#define PCI_DEVICE_ID_INTEL_SANDYBRIDGE_S_IG 0x010A
|
||||
#define PCI_DEVICE_ID_INTEL_IVYBRIDGE_HB 0x0150 /* Desktop */
|
||||
#define PCI_DEVICE_ID_INTEL_IVYBRIDGE_GT1_IG 0x0152
|
||||
#define PCI_DEVICE_ID_INTEL_IVYBRIDGE_GT2_IG 0x0162
|
||||
#define PCI_DEVICE_ID_INTEL_IVYBRIDGE_M_HB 0x0154 /* Mobile */
|
||||
#define PCI_DEVICE_ID_INTEL_IVYBRIDGE_M_GT1_IG 0x0156
|
||||
#define PCI_DEVICE_ID_INTEL_IVYBRIDGE_M_GT2_IG 0x0166
|
||||
#define PCI_DEVICE_ID_INTEL_IVYBRIDGE_S_HB 0x0158 /* Server */
|
||||
#define PCI_DEVICE_ID_INTEL_IVYBRIDGE_S_GT1_IG 0x015A
|
||||
#define PCI_DEVICE_ID_INTEL_IVYBRIDGE_S_GT2_IG 0x016A
|
||||
#define PCI_DEVICE_ID_INTEL_VALLEYVIEW_HB 0x0F00 /* VLV1 */
|
||||
#define PCI_DEVICE_ID_INTEL_VALLEYVIEW_IG 0x0F30
|
||||
#define PCI_DEVICE_ID_INTEL_HASWELL_HB 0x0400 /* Desktop */
|
||||
#define PCI_DEVICE_ID_INTEL_HASWELL_D_GT1_IG 0x0402
|
||||
#define PCI_DEVICE_ID_INTEL_HASWELL_D_GT2_IG 0x0412
|
||||
#define PCI_DEVICE_ID_INTEL_HASWELL_D_GT2_PLUS_IG 0x0422
|
||||
#define PCI_DEVICE_ID_INTEL_HASWELL_M_HB 0x0404 /* Mobile */
|
||||
#define PCI_DEVICE_ID_INTEL_HASWELL_M_GT1_IG 0x0406
|
||||
#define PCI_DEVICE_ID_INTEL_HASWELL_M_GT2_IG 0x0416
|
||||
#define PCI_DEVICE_ID_INTEL_HASWELL_M_GT2_PLUS_IG 0x0426
|
||||
#define PCI_DEVICE_ID_INTEL_HASWELL_S_HB 0x0408 /* Server */
|
||||
#define PCI_DEVICE_ID_INTEL_HASWELL_S_GT1_IG 0x040a
|
||||
#define PCI_DEVICE_ID_INTEL_HASWELL_S_GT2_IG 0x041a
|
||||
#define PCI_DEVICE_ID_INTEL_HASWELL_S_GT2_PLUS_IG 0x042a
|
||||
#define PCI_DEVICE_ID_INTEL_HASWELL_E_HB 0x0c04
|
||||
#define PCI_DEVICE_ID_INTEL_HASWELL_SDV_D_GT1_IG 0x0C02
|
||||
#define PCI_DEVICE_ID_INTEL_HASWELL_SDV_D_GT2_IG 0x0C12
|
||||
#define PCI_DEVICE_ID_INTEL_HASWELL_SDV_D_GT2_PLUS_IG 0x0C22
|
||||
#define PCI_DEVICE_ID_INTEL_HASWELL_SDV_M_GT1_IG 0x0C06
|
||||
#define PCI_DEVICE_ID_INTEL_HASWELL_SDV_M_GT2_IG 0x0C16
|
||||
#define PCI_DEVICE_ID_INTEL_HASWELL_SDV_M_GT2_PLUS_IG 0x0C26
|
||||
#define PCI_DEVICE_ID_INTEL_HASWELL_SDV_S_GT1_IG 0x0C0A
|
||||
#define PCI_DEVICE_ID_INTEL_HASWELL_SDV_S_GT2_IG 0x0C1A
|
||||
#define PCI_DEVICE_ID_INTEL_HASWELL_SDV_S_GT2_PLUS_IG 0x0C2A
|
||||
#define PCI_DEVICE_ID_INTEL_HASWELL_ULT_D_GT1_IG 0x0A02
|
||||
#define PCI_DEVICE_ID_INTEL_HASWELL_ULT_D_GT2_IG 0x0A12
|
||||
#define PCI_DEVICE_ID_INTEL_HASWELL_ULT_D_GT2_PLUS_IG 0x0A22
|
||||
#define PCI_DEVICE_ID_INTEL_HASWELL_ULT_M_GT1_IG 0x0A06
|
||||
#define PCI_DEVICE_ID_INTEL_HASWELL_ULT_M_GT2_IG 0x0A16
|
||||
#define PCI_DEVICE_ID_INTEL_HASWELL_ULT_M_GT2_PLUS_IG 0x0A26
|
||||
#define PCI_DEVICE_ID_INTEL_HASWELL_ULT_S_GT1_IG 0x0A0A
|
||||
#define PCI_DEVICE_ID_INTEL_HASWELL_ULT_S_GT2_IG 0x0A1A
|
||||
#define PCI_DEVICE_ID_INTEL_HASWELL_ULT_S_GT2_PLUS_IG 0x0A2A
|
||||
#define PCI_DEVICE_ID_INTEL_HASWELL_CRW_D_GT1_IG 0x0D12
|
||||
#define PCI_DEVICE_ID_INTEL_HASWELL_CRW_D_GT2_IG 0x0D22
|
||||
#define PCI_DEVICE_ID_INTEL_HASWELL_CRW_D_GT2_PLUS_IG 0x0D32
|
||||
#define PCI_DEVICE_ID_INTEL_HASWELL_CRW_M_GT1_IG 0x0D16
|
||||
#define PCI_DEVICE_ID_INTEL_HASWELL_CRW_M_GT2_IG 0x0D26
|
||||
#define PCI_DEVICE_ID_INTEL_HASWELL_CRW_M_GT2_PLUS_IG 0x0D36
|
||||
#define PCI_DEVICE_ID_INTEL_HASWELL_CRW_S_GT1_IG 0x0D1A
|
||||
#define PCI_DEVICE_ID_INTEL_HASWELL_CRW_S_GT2_IG 0x0D2A
|
||||
#define PCI_DEVICE_ID_INTEL_HASWELL_CRW_S_GT2_PLUS_IG 0x0D3A
|
||||
|
||||
#endif
|
||||
|
||||
+12
-308
@@ -367,62 +367,6 @@ static unsigned int intel_gtt_stolen_size(void)
|
||||
stolen_size = 0;
|
||||
break;
|
||||
}
|
||||
} else if (INTEL_GTT_GEN == 6) {
|
||||
/*
|
||||
* SandyBridge has new memory control reg at 0x50.w
|
||||
*/
|
||||
u16 snb_gmch_ctl;
|
||||
pci_read_config_word(intel_private.pcidev, SNB_GMCH_CTRL, &snb_gmch_ctl);
|
||||
switch (snb_gmch_ctl & SNB_GMCH_GMS_STOLEN_MASK) {
|
||||
case SNB_GMCH_GMS_STOLEN_32M:
|
||||
stolen_size = MB(32);
|
||||
break;
|
||||
case SNB_GMCH_GMS_STOLEN_64M:
|
||||
stolen_size = MB(64);
|
||||
break;
|
||||
case SNB_GMCH_GMS_STOLEN_96M:
|
||||
stolen_size = MB(96);
|
||||
break;
|
||||
case SNB_GMCH_GMS_STOLEN_128M:
|
||||
stolen_size = MB(128);
|
||||
break;
|
||||
case SNB_GMCH_GMS_STOLEN_160M:
|
||||
stolen_size = MB(160);
|
||||
break;
|
||||
case SNB_GMCH_GMS_STOLEN_192M:
|
||||
stolen_size = MB(192);
|
||||
break;
|
||||
case SNB_GMCH_GMS_STOLEN_224M:
|
||||
stolen_size = MB(224);
|
||||
break;
|
||||
case SNB_GMCH_GMS_STOLEN_256M:
|
||||
stolen_size = MB(256);
|
||||
break;
|
||||
case SNB_GMCH_GMS_STOLEN_288M:
|
||||
stolen_size = MB(288);
|
||||
break;
|
||||
case SNB_GMCH_GMS_STOLEN_320M:
|
||||
stolen_size = MB(320);
|
||||
break;
|
||||
case SNB_GMCH_GMS_STOLEN_352M:
|
||||
stolen_size = MB(352);
|
||||
break;
|
||||
case SNB_GMCH_GMS_STOLEN_384M:
|
||||
stolen_size = MB(384);
|
||||
break;
|
||||
case SNB_GMCH_GMS_STOLEN_416M:
|
||||
stolen_size = MB(416);
|
||||
break;
|
||||
case SNB_GMCH_GMS_STOLEN_448M:
|
||||
stolen_size = MB(448);
|
||||
break;
|
||||
case SNB_GMCH_GMS_STOLEN_480M:
|
||||
stolen_size = MB(480);
|
||||
break;
|
||||
case SNB_GMCH_GMS_STOLEN_512M:
|
||||
stolen_size = MB(512);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
switch (gmch_ctrl & I855_GMCH_GMS_MASK) {
|
||||
case I855_GMCH_GMS_STOLEN_1M:
|
||||
@@ -556,29 +500,9 @@ static unsigned int i965_gtt_total_entries(void)
|
||||
|
||||
static unsigned int intel_gtt_total_entries(void)
|
||||
{
|
||||
int size;
|
||||
|
||||
if (IS_G33 || INTEL_GTT_GEN == 4 || INTEL_GTT_GEN == 5)
|
||||
return i965_gtt_total_entries();
|
||||
else if (INTEL_GTT_GEN == 6) {
|
||||
u16 snb_gmch_ctl;
|
||||
|
||||
pci_read_config_word(intel_private.pcidev, SNB_GMCH_CTRL, &snb_gmch_ctl);
|
||||
switch (snb_gmch_ctl & SNB_GTT_SIZE_MASK) {
|
||||
default:
|
||||
case SNB_GTT_SIZE_0M:
|
||||
printk(KERN_ERR "Bad GTT size mask: 0x%04x.\n", snb_gmch_ctl);
|
||||
size = MB(0);
|
||||
break;
|
||||
case SNB_GTT_SIZE_1M:
|
||||
size = MB(1);
|
||||
break;
|
||||
case SNB_GTT_SIZE_2M:
|
||||
size = MB(2);
|
||||
break;
|
||||
}
|
||||
return size/4;
|
||||
} else {
|
||||
else {
|
||||
/* On previous hardware, the GTT size was just what was
|
||||
* required to map the aperture.
|
||||
*/
|
||||
@@ -778,9 +702,6 @@ bool intel_enable_gtt(void)
|
||||
{
|
||||
u8 __iomem *reg;
|
||||
|
||||
if (INTEL_GTT_GEN >= 6)
|
||||
return true;
|
||||
|
||||
if (INTEL_GTT_GEN == 2) {
|
||||
u16 gmch_ctrl;
|
||||
|
||||
@@ -1149,85 +1070,6 @@ static void i965_write_entry(dma_addr_t addr,
|
||||
writel(addr | pte_flags, intel_private.gtt + entry);
|
||||
}
|
||||
|
||||
static bool gen6_check_flags(unsigned int flags)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
static void haswell_write_entry(dma_addr_t addr, unsigned int entry,
|
||||
unsigned int flags)
|
||||
{
|
||||
unsigned int type_mask = flags & ~AGP_USER_CACHED_MEMORY_GFDT;
|
||||
unsigned int gfdt = flags & AGP_USER_CACHED_MEMORY_GFDT;
|
||||
u32 pte_flags;
|
||||
|
||||
if (type_mask == AGP_USER_MEMORY)
|
||||
pte_flags = HSW_PTE_UNCACHED | I810_PTE_VALID;
|
||||
else if (type_mask == AGP_USER_CACHED_MEMORY_LLC_MLC) {
|
||||
pte_flags = GEN6_PTE_LLC_MLC | I810_PTE_VALID;
|
||||
if (gfdt)
|
||||
pte_flags |= GEN6_PTE_GFDT;
|
||||
} else { /* set 'normal'/'cached' to LLC by default */
|
||||
pte_flags = GEN6_PTE_LLC | I810_PTE_VALID;
|
||||
if (gfdt)
|
||||
pte_flags |= GEN6_PTE_GFDT;
|
||||
}
|
||||
|
||||
/* gen6 has bit11-4 for physical addr bit39-32 */
|
||||
addr |= (addr >> 28) & 0xff0;
|
||||
writel(addr | pte_flags, intel_private.gtt + entry);
|
||||
}
|
||||
|
||||
static void gen6_write_entry(dma_addr_t addr, unsigned int entry,
|
||||
unsigned int flags)
|
||||
{
|
||||
unsigned int type_mask = flags & ~AGP_USER_CACHED_MEMORY_GFDT;
|
||||
unsigned int gfdt = flags & AGP_USER_CACHED_MEMORY_GFDT;
|
||||
u32 pte_flags;
|
||||
|
||||
if (type_mask == AGP_USER_MEMORY)
|
||||
pte_flags = GEN6_PTE_UNCACHED | I810_PTE_VALID;
|
||||
else if (type_mask == AGP_USER_CACHED_MEMORY_LLC_MLC) {
|
||||
pte_flags = GEN6_PTE_LLC_MLC | I810_PTE_VALID;
|
||||
if (gfdt)
|
||||
pte_flags |= GEN6_PTE_GFDT;
|
||||
} else { /* set 'normal'/'cached' to LLC by default */
|
||||
pte_flags = GEN6_PTE_LLC | I810_PTE_VALID;
|
||||
if (gfdt)
|
||||
pte_flags |= GEN6_PTE_GFDT;
|
||||
}
|
||||
|
||||
/* gen6 has bit11-4 for physical addr bit39-32 */
|
||||
addr |= (addr >> 28) & 0xff0;
|
||||
writel(addr | pte_flags, intel_private.gtt + entry);
|
||||
}
|
||||
|
||||
static void valleyview_write_entry(dma_addr_t addr, unsigned int entry,
|
||||
unsigned int flags)
|
||||
{
|
||||
unsigned int type_mask = flags & ~AGP_USER_CACHED_MEMORY_GFDT;
|
||||
unsigned int gfdt = flags & AGP_USER_CACHED_MEMORY_GFDT;
|
||||
u32 pte_flags;
|
||||
|
||||
if (type_mask == AGP_USER_MEMORY)
|
||||
pte_flags = GEN6_PTE_UNCACHED | I810_PTE_VALID;
|
||||
else {
|
||||
pte_flags = GEN6_PTE_LLC | I810_PTE_VALID;
|
||||
if (gfdt)
|
||||
pte_flags |= GEN6_PTE_GFDT;
|
||||
}
|
||||
|
||||
/* gen6 has bit11-4 for physical addr bit39-32 */
|
||||
addr |= (addr >> 28) & 0xff0;
|
||||
writel(addr | pte_flags, intel_private.gtt + entry);
|
||||
|
||||
writel(1, intel_private.registers + GFX_FLSH_CNTL_VLV);
|
||||
}
|
||||
|
||||
static void gen6_cleanup(void)
|
||||
{
|
||||
}
|
||||
|
||||
/* Certain Gen5 chipsets require require idling the GPU before
|
||||
* unmapping anything from the GTT when VT-d is enabled.
|
||||
*/
|
||||
@@ -1249,41 +1091,29 @@ static inline int needs_idle_maps(void)
|
||||
|
||||
static int i9xx_setup(void)
|
||||
{
|
||||
u32 reg_addr;
|
||||
u32 reg_addr, gtt_addr;
|
||||
int size = KB(512);
|
||||
|
||||
pci_read_config_dword(intel_private.pcidev, I915_MMADDR, ®_addr);
|
||||
|
||||
reg_addr &= 0xfff80000;
|
||||
|
||||
if (INTEL_GTT_GEN >= 7)
|
||||
size = MB(2);
|
||||
|
||||
intel_private.registers = ioremap(reg_addr, size);
|
||||
if (!intel_private.registers)
|
||||
return -ENOMEM;
|
||||
|
||||
if (INTEL_GTT_GEN == 3) {
|
||||
u32 gtt_addr;
|
||||
|
||||
switch (INTEL_GTT_GEN) {
|
||||
case 3:
|
||||
pci_read_config_dword(intel_private.pcidev,
|
||||
I915_PTEADDR, >t_addr);
|
||||
intel_private.gtt_bus_addr = gtt_addr;
|
||||
} else {
|
||||
u32 gtt_offset;
|
||||
|
||||
switch (INTEL_GTT_GEN) {
|
||||
case 5:
|
||||
case 6:
|
||||
case 7:
|
||||
gtt_offset = MB(2);
|
||||
break;
|
||||
case 4:
|
||||
default:
|
||||
gtt_offset = KB(512);
|
||||
break;
|
||||
}
|
||||
intel_private.gtt_bus_addr = reg_addr + gtt_offset;
|
||||
break;
|
||||
case 5:
|
||||
intel_private.gtt_bus_addr = reg_addr + MB(2);
|
||||
break;
|
||||
default:
|
||||
intel_private.gtt_bus_addr = reg_addr + KB(512);
|
||||
break;
|
||||
}
|
||||
|
||||
if (needs_idle_maps())
|
||||
@@ -1395,32 +1225,6 @@ static const struct intel_gtt_driver ironlake_gtt_driver = {
|
||||
.check_flags = i830_check_flags,
|
||||
.chipset_flush = i9xx_chipset_flush,
|
||||
};
|
||||
static const struct intel_gtt_driver sandybridge_gtt_driver = {
|
||||
.gen = 6,
|
||||
.setup = i9xx_setup,
|
||||
.cleanup = gen6_cleanup,
|
||||
.write_entry = gen6_write_entry,
|
||||
.dma_mask_size = 40,
|
||||
.check_flags = gen6_check_flags,
|
||||
.chipset_flush = i9xx_chipset_flush,
|
||||
};
|
||||
static const struct intel_gtt_driver haswell_gtt_driver = {
|
||||
.gen = 6,
|
||||
.setup = i9xx_setup,
|
||||
.cleanup = gen6_cleanup,
|
||||
.write_entry = haswell_write_entry,
|
||||
.dma_mask_size = 40,
|
||||
.check_flags = gen6_check_flags,
|
||||
.chipset_flush = i9xx_chipset_flush,
|
||||
};
|
||||
static const struct intel_gtt_driver valleyview_gtt_driver = {
|
||||
.gen = 7,
|
||||
.setup = i9xx_setup,
|
||||
.cleanup = gen6_cleanup,
|
||||
.write_entry = valleyview_write_entry,
|
||||
.dma_mask_size = 40,
|
||||
.check_flags = gen6_check_flags,
|
||||
};
|
||||
|
||||
/* Table to describe Intel GMCH and AGP/PCIE GART drivers. At least one of
|
||||
* driver and gmch_driver must be non-null, and find_gmch will determine
|
||||
@@ -1501,106 +1305,6 @@ static const struct intel_gtt_driver_description {
|
||||
"HD Graphics", &ironlake_gtt_driver },
|
||||
{ PCI_DEVICE_ID_INTEL_IRONLAKE_M_IG,
|
||||
"HD Graphics", &ironlake_gtt_driver },
|
||||
{ PCI_DEVICE_ID_INTEL_SANDYBRIDGE_GT1_IG,
|
||||
"Sandybridge", &sandybridge_gtt_driver },
|
||||
{ PCI_DEVICE_ID_INTEL_SANDYBRIDGE_GT2_IG,
|
||||
"Sandybridge", &sandybridge_gtt_driver },
|
||||
{ PCI_DEVICE_ID_INTEL_SANDYBRIDGE_GT2_PLUS_IG,
|
||||
"Sandybridge", &sandybridge_gtt_driver },
|
||||
{ PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_GT1_IG,
|
||||
"Sandybridge", &sandybridge_gtt_driver },
|
||||
{ PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_GT2_IG,
|
||||
"Sandybridge", &sandybridge_gtt_driver },
|
||||
{ PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_GT2_PLUS_IG,
|
||||
"Sandybridge", &sandybridge_gtt_driver },
|
||||
{ PCI_DEVICE_ID_INTEL_SANDYBRIDGE_S_IG,
|
||||
"Sandybridge", &sandybridge_gtt_driver },
|
||||
{ PCI_DEVICE_ID_INTEL_IVYBRIDGE_GT1_IG,
|
||||
"Ivybridge", &sandybridge_gtt_driver },
|
||||
{ PCI_DEVICE_ID_INTEL_IVYBRIDGE_GT2_IG,
|
||||
"Ivybridge", &sandybridge_gtt_driver },
|
||||
{ PCI_DEVICE_ID_INTEL_IVYBRIDGE_M_GT1_IG,
|
||||
"Ivybridge", &sandybridge_gtt_driver },
|
||||
{ PCI_DEVICE_ID_INTEL_IVYBRIDGE_M_GT2_IG,
|
||||
"Ivybridge", &sandybridge_gtt_driver },
|
||||
{ PCI_DEVICE_ID_INTEL_IVYBRIDGE_S_GT1_IG,
|
||||
"Ivybridge", &sandybridge_gtt_driver },
|
||||
{ PCI_DEVICE_ID_INTEL_IVYBRIDGE_S_GT2_IG,
|
||||
"Ivybridge", &sandybridge_gtt_driver },
|
||||
{ PCI_DEVICE_ID_INTEL_VALLEYVIEW_IG,
|
||||
"ValleyView", &valleyview_gtt_driver },
|
||||
{ PCI_DEVICE_ID_INTEL_HASWELL_D_GT1_IG,
|
||||
"Haswell", &haswell_gtt_driver },
|
||||
{ PCI_DEVICE_ID_INTEL_HASWELL_D_GT2_IG,
|
||||
"Haswell", &haswell_gtt_driver },
|
||||
{ PCI_DEVICE_ID_INTEL_HASWELL_D_GT2_PLUS_IG,
|
||||
"Haswell", &haswell_gtt_driver },
|
||||
{ PCI_DEVICE_ID_INTEL_HASWELL_M_GT1_IG,
|
||||
"Haswell", &haswell_gtt_driver },
|
||||
{ PCI_DEVICE_ID_INTEL_HASWELL_M_GT2_IG,
|
||||
"Haswell", &haswell_gtt_driver },
|
||||
{ PCI_DEVICE_ID_INTEL_HASWELL_M_GT2_PLUS_IG,
|
||||
"Haswell", &haswell_gtt_driver },
|
||||
{ PCI_DEVICE_ID_INTEL_HASWELL_S_GT1_IG,
|
||||
"Haswell", &haswell_gtt_driver },
|
||||
{ PCI_DEVICE_ID_INTEL_HASWELL_S_GT2_IG,
|
||||
"Haswell", &haswell_gtt_driver },
|
||||
{ PCI_DEVICE_ID_INTEL_HASWELL_S_GT2_PLUS_IG,
|
||||
"Haswell", &haswell_gtt_driver },
|
||||
{ PCI_DEVICE_ID_INTEL_HASWELL_SDV_D_GT1_IG,
|
||||
"Haswell", &haswell_gtt_driver },
|
||||
{ PCI_DEVICE_ID_INTEL_HASWELL_SDV_D_GT2_IG,
|
||||
"Haswell", &haswell_gtt_driver },
|
||||
{ PCI_DEVICE_ID_INTEL_HASWELL_SDV_D_GT2_PLUS_IG,
|
||||
"Haswell", &haswell_gtt_driver },
|
||||
{ PCI_DEVICE_ID_INTEL_HASWELL_SDV_M_GT1_IG,
|
||||
"Haswell", &haswell_gtt_driver },
|
||||
{ PCI_DEVICE_ID_INTEL_HASWELL_SDV_M_GT2_IG,
|
||||
"Haswell", &haswell_gtt_driver },
|
||||
{ PCI_DEVICE_ID_INTEL_HASWELL_SDV_M_GT2_PLUS_IG,
|
||||
"Haswell", &haswell_gtt_driver },
|
||||
{ PCI_DEVICE_ID_INTEL_HASWELL_SDV_S_GT1_IG,
|
||||
"Haswell", &haswell_gtt_driver },
|
||||
{ PCI_DEVICE_ID_INTEL_HASWELL_SDV_S_GT2_IG,
|
||||
"Haswell", &haswell_gtt_driver },
|
||||
{ PCI_DEVICE_ID_INTEL_HASWELL_SDV_S_GT2_PLUS_IG,
|
||||
"Haswell", &haswell_gtt_driver },
|
||||
{ PCI_DEVICE_ID_INTEL_HASWELL_ULT_D_GT1_IG,
|
||||
"Haswell", &haswell_gtt_driver },
|
||||
{ PCI_DEVICE_ID_INTEL_HASWELL_ULT_D_GT2_IG,
|
||||
"Haswell", &haswell_gtt_driver },
|
||||
{ PCI_DEVICE_ID_INTEL_HASWELL_ULT_D_GT2_PLUS_IG,
|
||||
"Haswell", &haswell_gtt_driver },
|
||||
{ PCI_DEVICE_ID_INTEL_HASWELL_ULT_M_GT1_IG,
|
||||
"Haswell", &haswell_gtt_driver },
|
||||
{ PCI_DEVICE_ID_INTEL_HASWELL_ULT_M_GT2_IG,
|
||||
"Haswell", &haswell_gtt_driver },
|
||||
{ PCI_DEVICE_ID_INTEL_HASWELL_ULT_M_GT2_PLUS_IG,
|
||||
"Haswell", &haswell_gtt_driver },
|
||||
{ PCI_DEVICE_ID_INTEL_HASWELL_ULT_S_GT1_IG,
|
||||
"Haswell", &haswell_gtt_driver },
|
||||
{ PCI_DEVICE_ID_INTEL_HASWELL_ULT_S_GT2_IG,
|
||||
"Haswell", &haswell_gtt_driver },
|
||||
{ PCI_DEVICE_ID_INTEL_HASWELL_ULT_S_GT2_PLUS_IG,
|
||||
"Haswell", &haswell_gtt_driver },
|
||||
{ PCI_DEVICE_ID_INTEL_HASWELL_CRW_D_GT1_IG,
|
||||
"Haswell", &haswell_gtt_driver },
|
||||
{ PCI_DEVICE_ID_INTEL_HASWELL_CRW_D_GT2_IG,
|
||||
"Haswell", &haswell_gtt_driver },
|
||||
{ PCI_DEVICE_ID_INTEL_HASWELL_CRW_D_GT2_PLUS_IG,
|
||||
"Haswell", &haswell_gtt_driver },
|
||||
{ PCI_DEVICE_ID_INTEL_HASWELL_CRW_M_GT1_IG,
|
||||
"Haswell", &haswell_gtt_driver },
|
||||
{ PCI_DEVICE_ID_INTEL_HASWELL_CRW_M_GT2_IG,
|
||||
"Haswell", &haswell_gtt_driver },
|
||||
{ PCI_DEVICE_ID_INTEL_HASWELL_CRW_M_GT2_PLUS_IG,
|
||||
"Haswell", &haswell_gtt_driver },
|
||||
{ PCI_DEVICE_ID_INTEL_HASWELL_CRW_S_GT1_IG,
|
||||
"Haswell", &haswell_gtt_driver },
|
||||
{ PCI_DEVICE_ID_INTEL_HASWELL_CRW_S_GT2_IG,
|
||||
"Haswell", &haswell_gtt_driver },
|
||||
{ PCI_DEVICE_ID_INTEL_HASWELL_CRW_S_GT2_PLUS_IG,
|
||||
"Haswell", &haswell_gtt_driver },
|
||||
{ 0, NULL, NULL }
|
||||
};
|
||||
|
||||
@@ -1686,7 +1390,7 @@ int intel_gmch_probe(struct pci_dev *bridge_pdev, struct pci_dev *gpu_pdev,
|
||||
}
|
||||
EXPORT_SYMBOL(intel_gmch_probe);
|
||||
|
||||
const struct intel_gtt *intel_gtt_get(void)
|
||||
struct intel_gtt *intel_gtt_get(void)
|
||||
{
|
||||
return &intel_private.base;
|
||||
}
|
||||
|
||||
@@ -210,3 +210,5 @@ source "drivers/gpu/drm/mgag200/Kconfig"
|
||||
source "drivers/gpu/drm/cirrus/Kconfig"
|
||||
|
||||
source "drivers/gpu/drm/shmobile/Kconfig"
|
||||
|
||||
source "drivers/gpu/drm/tegra/Kconfig"
|
||||
|
||||
@@ -8,7 +8,7 @@ drm-y := drm_auth.o drm_buffer.o drm_bufs.o drm_cache.o \
|
||||
drm_context.o drm_dma.o \
|
||||
drm_drv.o drm_fops.o drm_gem.o drm_ioctl.o drm_irq.o \
|
||||
drm_lock.o drm_memory.o drm_proc.o drm_stub.o drm_vm.o \
|
||||
drm_agpsupport.o drm_scatter.o ati_pcigart.o drm_pci.o \
|
||||
drm_agpsupport.o drm_scatter.o drm_pci.o \
|
||||
drm_platform.o drm_sysfs.o drm_hashtab.o drm_mm.o \
|
||||
drm_crtc.o drm_modes.o drm_edid.o \
|
||||
drm_info.o drm_debugfs.o drm_encoder_slave.o \
|
||||
@@ -16,10 +16,11 @@ drm-y := drm_auth.o drm_buffer.o drm_bufs.o drm_cache.o \
|
||||
|
||||
drm-$(CONFIG_COMPAT) += drm_ioc32.o
|
||||
drm-$(CONFIG_DRM_GEM_CMA_HELPER) += drm_gem_cma_helper.o
|
||||
drm-$(CONFIG_PCI) += ati_pcigart.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-y := drm_fb_helper.o drm_crtc_helper.o drm_dp_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
|
||||
|
||||
@@ -48,4 +49,5 @@ obj-$(CONFIG_DRM_GMA500) += gma500/
|
||||
obj-$(CONFIG_DRM_UDL) += udl/
|
||||
obj-$(CONFIG_DRM_AST) += ast/
|
||||
obj-$(CONFIG_DRM_SHMOBILE) +=shmobile/
|
||||
obj-$(CONFIG_DRM_TEGRA) += tegra/
|
||||
obj-y += i2c/
|
||||
|
||||
@@ -186,11 +186,11 @@ static void ast_ttm_io_mem_free(struct ttm_bo_device *bdev, struct ttm_mem_reg *
|
||||
|
||||
static int ast_bo_move(struct ttm_buffer_object *bo,
|
||||
bool evict, bool interruptible,
|
||||
bool no_wait_reserve, bool no_wait_gpu,
|
||||
bool no_wait_gpu,
|
||||
struct ttm_mem_reg *new_mem)
|
||||
{
|
||||
int r;
|
||||
r = ttm_bo_move_memcpy(bo, evict, no_wait_reserve, no_wait_gpu, new_mem);
|
||||
r = ttm_bo_move_memcpy(bo, evict, no_wait_gpu, new_mem);
|
||||
return r;
|
||||
}
|
||||
|
||||
@@ -356,7 +356,7 @@ int ast_bo_create(struct drm_device *dev, int size, int align,
|
||||
|
||||
ret = ttm_bo_init(&ast->ttm.bdev, &astbo->bo, size,
|
||||
ttm_bo_type_device, &astbo->placement,
|
||||
align >> PAGE_SHIFT, 0, false, NULL, acc_size,
|
||||
align >> PAGE_SHIFT, false, NULL, acc_size,
|
||||
NULL, ast_bo_ttm_destroy);
|
||||
if (ret)
|
||||
return ret;
|
||||
@@ -383,7 +383,7 @@ int ast_bo_pin(struct ast_bo *bo, u32 pl_flag, u64 *gpu_addr)
|
||||
ast_ttm_placement(bo, pl_flag);
|
||||
for (i = 0; i < bo->placement.num_placement; i++)
|
||||
bo->placements[i] |= TTM_PL_FLAG_NO_EVICT;
|
||||
ret = ttm_bo_validate(&bo->bo, &bo->placement, false, false, false);
|
||||
ret = ttm_bo_validate(&bo->bo, &bo->placement, false, false);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
@@ -406,7 +406,7 @@ int ast_bo_unpin(struct ast_bo *bo)
|
||||
|
||||
for (i = 0; i < bo->placement.num_placement ; i++)
|
||||
bo->placements[i] &= ~TTM_PL_FLAG_NO_EVICT;
|
||||
ret = ttm_bo_validate(&bo->bo, &bo->placement, false, false, false);
|
||||
ret = ttm_bo_validate(&bo->bo, &bo->placement, false, false);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
@@ -431,7 +431,7 @@ int ast_bo_push_sysram(struct ast_bo *bo)
|
||||
for (i = 0; i < bo->placement.num_placement ; i++)
|
||||
bo->placements[i] |= TTM_PL_FLAG_NO_EVICT;
|
||||
|
||||
ret = ttm_bo_validate(&bo->bo, &bo->placement, false, false, false);
|
||||
ret = ttm_bo_validate(&bo->bo, &bo->placement, false, false);
|
||||
if (ret) {
|
||||
DRM_ERROR("pushing to VRAM failed\n");
|
||||
return ret;
|
||||
|
||||
@@ -35,12 +35,15 @@ static DEFINE_PCI_DEVICE_TABLE(pciidlist) = {
|
||||
};
|
||||
|
||||
|
||||
static void cirrus_kick_out_firmware_fb(struct pci_dev *pdev)
|
||||
static int cirrus_kick_out_firmware_fb(struct pci_dev *pdev)
|
||||
{
|
||||
struct apertures_struct *ap;
|
||||
bool primary = false;
|
||||
|
||||
ap = alloc_apertures(1);
|
||||
if (!ap)
|
||||
return -ENOMEM;
|
||||
|
||||
ap->ranges[0].base = pci_resource_start(pdev, 0);
|
||||
ap->ranges[0].size = pci_resource_len(pdev, 0);
|
||||
|
||||
@@ -49,12 +52,18 @@ static void cirrus_kick_out_firmware_fb(struct pci_dev *pdev)
|
||||
#endif
|
||||
remove_conflicting_framebuffers(ap, "cirrusdrmfb", primary);
|
||||
kfree(ap);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __devinit
|
||||
cirrus_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
|
||||
{
|
||||
cirrus_kick_out_firmware_fb(pdev);
|
||||
int ret;
|
||||
|
||||
ret = cirrus_kick_out_firmware_fb(pdev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return drm_get_pci_dev(pdev, ent, &driver);
|
||||
}
|
||||
|
||||
@@ -186,11 +186,11 @@ static void cirrus_ttm_io_mem_free(struct ttm_bo_device *bdev, struct ttm_mem_re
|
||||
|
||||
static int cirrus_bo_move(struct ttm_buffer_object *bo,
|
||||
bool evict, bool interruptible,
|
||||
bool no_wait_reserve, bool no_wait_gpu,
|
||||
bool no_wait_gpu,
|
||||
struct ttm_mem_reg *new_mem)
|
||||
{
|
||||
int r;
|
||||
r = ttm_bo_move_memcpy(bo, evict, no_wait_reserve, no_wait_gpu, new_mem);
|
||||
r = ttm_bo_move_memcpy(bo, evict, no_wait_gpu, new_mem);
|
||||
return r;
|
||||
}
|
||||
|
||||
@@ -361,7 +361,7 @@ int cirrus_bo_create(struct drm_device *dev, int size, int align,
|
||||
|
||||
ret = ttm_bo_init(&cirrus->ttm.bdev, &cirrusbo->bo, size,
|
||||
ttm_bo_type_device, &cirrusbo->placement,
|
||||
align >> PAGE_SHIFT, 0, false, NULL, acc_size,
|
||||
align >> PAGE_SHIFT, false, NULL, acc_size,
|
||||
NULL, cirrus_bo_ttm_destroy);
|
||||
if (ret)
|
||||
return ret;
|
||||
@@ -388,7 +388,7 @@ int cirrus_bo_pin(struct cirrus_bo *bo, u32 pl_flag, u64 *gpu_addr)
|
||||
cirrus_ttm_placement(bo, pl_flag);
|
||||
for (i = 0; i < bo->placement.num_placement; i++)
|
||||
bo->placements[i] |= TTM_PL_FLAG_NO_EVICT;
|
||||
ret = ttm_bo_validate(&bo->bo, &bo->placement, false, false, false);
|
||||
ret = ttm_bo_validate(&bo->bo, &bo->placement, false, false);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
@@ -411,7 +411,7 @@ int cirrus_bo_unpin(struct cirrus_bo *bo)
|
||||
|
||||
for (i = 0; i < bo->placement.num_placement ; i++)
|
||||
bo->placements[i] &= ~TTM_PL_FLAG_NO_EVICT;
|
||||
ret = ttm_bo_validate(&bo->bo, &bo->placement, false, false, false);
|
||||
ret = ttm_bo_validate(&bo->bo, &bo->placement, false, false);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
@@ -436,7 +436,7 @@ int cirrus_bo_push_sysram(struct cirrus_bo *bo)
|
||||
for (i = 0; i < bo->placement.num_placement ; i++)
|
||||
bo->placements[i] |= TTM_PL_FLAG_NO_EVICT;
|
||||
|
||||
ret = ttm_bo_validate(&bo->bo, &bo->placement, false, false, false);
|
||||
ret = ttm_bo_validate(&bo->bo, &bo->placement, false, false);
|
||||
if (ret) {
|
||||
DRM_ERROR("pushing to VRAM failed\n");
|
||||
return ret;
|
||||
|
||||
+31
-32
@@ -470,10 +470,8 @@ void drm_crtc_cleanup(struct drm_crtc *crtc)
|
||||
{
|
||||
struct drm_device *dev = crtc->dev;
|
||||
|
||||
if (crtc->gamma_store) {
|
||||
kfree(crtc->gamma_store);
|
||||
crtc->gamma_store = NULL;
|
||||
}
|
||||
kfree(crtc->gamma_store);
|
||||
crtc->gamma_store = NULL;
|
||||
|
||||
drm_mode_object_put(dev, &crtc->base);
|
||||
list_del(&crtc->head);
|
||||
@@ -555,16 +553,17 @@ int drm_connector_init(struct drm_device *dev,
|
||||
INIT_LIST_HEAD(&connector->probed_modes);
|
||||
INIT_LIST_HEAD(&connector->modes);
|
||||
connector->edid_blob_ptr = NULL;
|
||||
connector->status = connector_status_unknown;
|
||||
|
||||
list_add_tail(&connector->head, &dev->mode_config.connector_list);
|
||||
dev->mode_config.num_connector++;
|
||||
|
||||
if (connector_type != DRM_MODE_CONNECTOR_VIRTUAL)
|
||||
drm_connector_attach_property(connector,
|
||||
drm_object_attach_property(&connector->base,
|
||||
dev->mode_config.edid_property,
|
||||
0);
|
||||
|
||||
drm_connector_attach_property(connector,
|
||||
drm_object_attach_property(&connector->base,
|
||||
dev->mode_config.dpms_property, 0);
|
||||
|
||||
out:
|
||||
@@ -2280,13 +2279,21 @@ static int framebuffer_check(const struct drm_mode_fb_cmd2 *r)
|
||||
|
||||
for (i = 0; i < num_planes; i++) {
|
||||
unsigned int width = r->width / (i != 0 ? hsub : 1);
|
||||
unsigned int height = r->height / (i != 0 ? vsub : 1);
|
||||
unsigned int cpp = drm_format_plane_cpp(r->pixel_format, i);
|
||||
|
||||
if (!r->handles[i]) {
|
||||
DRM_DEBUG_KMS("no buffer object handle for plane %d\n", i);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (r->pitches[i] < drm_format_plane_cpp(r->pixel_format, i) * width) {
|
||||
if ((uint64_t) width * cpp > UINT_MAX)
|
||||
return -ERANGE;
|
||||
|
||||
if ((uint64_t) height * r->pitches[i] + r->offsets[i] > UINT_MAX)
|
||||
return -ERANGE;
|
||||
|
||||
if (r->pitches[i] < width * cpp) {
|
||||
DRM_DEBUG_KMS("bad pitch %u for plane %d\n", r->pitches[i], i);
|
||||
return -EINVAL;
|
||||
}
|
||||
@@ -2323,6 +2330,11 @@ int drm_mode_addfb2(struct drm_device *dev,
|
||||
if (!drm_core_check_feature(dev, DRIVER_MODESET))
|
||||
return -EINVAL;
|
||||
|
||||
if (r->flags & ~DRM_MODE_FB_INTERLACED) {
|
||||
DRM_DEBUG_KMS("bad framebuffer flags 0x%08x\n", r->flags);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if ((config->min_width > r->width) || (r->width > config->max_width)) {
|
||||
DRM_DEBUG_KMS("bad framebuffer width %d, should be >= %d && <= %d\n",
|
||||
r->width, config->min_width, config->max_width);
|
||||
@@ -2916,27 +2928,6 @@ void drm_property_destroy(struct drm_device *dev, struct drm_property *property)
|
||||
}
|
||||
EXPORT_SYMBOL(drm_property_destroy);
|
||||
|
||||
void drm_connector_attach_property(struct drm_connector *connector,
|
||||
struct drm_property *property, uint64_t init_val)
|
||||
{
|
||||
drm_object_attach_property(&connector->base, property, init_val);
|
||||
}
|
||||
EXPORT_SYMBOL(drm_connector_attach_property);
|
||||
|
||||
int drm_connector_property_set_value(struct drm_connector *connector,
|
||||
struct drm_property *property, uint64_t value)
|
||||
{
|
||||
return drm_object_property_set_value(&connector->base, property, value);
|
||||
}
|
||||
EXPORT_SYMBOL(drm_connector_property_set_value);
|
||||
|
||||
int drm_connector_property_get_value(struct drm_connector *connector,
|
||||
struct drm_property *property, uint64_t *val)
|
||||
{
|
||||
return drm_object_property_get_value(&connector->base, property, val);
|
||||
}
|
||||
EXPORT_SYMBOL(drm_connector_property_get_value);
|
||||
|
||||
void drm_object_attach_property(struct drm_mode_object *obj,
|
||||
struct drm_property *property,
|
||||
uint64_t init_val)
|
||||
@@ -3173,15 +3164,17 @@ int drm_mode_connector_update_edid_property(struct drm_connector *connector,
|
||||
/* Delete edid, when there is none. */
|
||||
if (!edid) {
|
||||
connector->edid_blob_ptr = NULL;
|
||||
ret = drm_connector_property_set_value(connector, dev->mode_config.edid_property, 0);
|
||||
ret = drm_object_property_set_value(&connector->base, dev->mode_config.edid_property, 0);
|
||||
return ret;
|
||||
}
|
||||
|
||||
size = EDID_LENGTH * (1 + edid->extensions);
|
||||
connector->edid_blob_ptr = drm_property_create_blob(connector->dev,
|
||||
size, edid);
|
||||
if (!connector->edid_blob_ptr)
|
||||
return -EINVAL;
|
||||
|
||||
ret = drm_connector_property_set_value(connector,
|
||||
ret = drm_object_property_set_value(&connector->base,
|
||||
dev->mode_config.edid_property,
|
||||
connector->edid_blob_ptr->base.id);
|
||||
|
||||
@@ -3204,6 +3197,9 @@ static bool drm_property_change_is_valid(struct drm_property *property,
|
||||
for (i = 0; i < property->num_values; i++)
|
||||
valid_mask |= (1ULL << property->values[i]);
|
||||
return !(value & ~valid_mask);
|
||||
} else if (property->flags & DRM_MODE_PROP_BLOB) {
|
||||
/* Only the driver knows */
|
||||
return true;
|
||||
} else {
|
||||
int i;
|
||||
for (i = 0; i < property->num_values; i++)
|
||||
@@ -3245,7 +3241,7 @@ static int drm_mode_connector_set_obj_prop(struct drm_mode_object *obj,
|
||||
|
||||
/* store the property value if successful */
|
||||
if (!ret)
|
||||
drm_connector_property_set_value(connector, property, value);
|
||||
drm_object_property_set_value(&connector->base, property, value);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -3656,9 +3652,12 @@ void drm_mode_config_reset(struct drm_device *dev)
|
||||
if (encoder->funcs->reset)
|
||||
encoder->funcs->reset(encoder);
|
||||
|
||||
list_for_each_entry(connector, &dev->mode_config.connector_list, head)
|
||||
list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
|
||||
connector->status = connector_status_unknown;
|
||||
|
||||
if (connector->funcs->reset)
|
||||
connector->funcs->reset(connector);
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL(drm_mode_config_reset);
|
||||
|
||||
|
||||
@@ -39,6 +39,35 @@
|
||||
#include <drm/drm_fb_helper.h>
|
||||
#include <drm/drm_edid.h>
|
||||
|
||||
/**
|
||||
* drm_helper_move_panel_connectors_to_head() - move panels to the front in the
|
||||
* connector list
|
||||
* @dev: drm device to operate on
|
||||
*
|
||||
* Some userspace presumes that the first connected connector is the main
|
||||
* display, where it's supposed to display e.g. the login screen. For
|
||||
* laptops, this should be the main panel. Use this function to sort all
|
||||
* (eDP/LVDS) panels to the front of the connector list, instead of
|
||||
* painstakingly trying to initialize them in the right order.
|
||||
*/
|
||||
void drm_helper_move_panel_connectors_to_head(struct drm_device *dev)
|
||||
{
|
||||
struct drm_connector *connector, *tmp;
|
||||
struct list_head panel_list;
|
||||
|
||||
INIT_LIST_HEAD(&panel_list);
|
||||
|
||||
list_for_each_entry_safe(connector, tmp,
|
||||
&dev->mode_config.connector_list, head) {
|
||||
if (connector->connector_type == DRM_MODE_CONNECTOR_LVDS ||
|
||||
connector->connector_type == DRM_MODE_CONNECTOR_eDP)
|
||||
list_move_tail(&connector->head, &panel_list);
|
||||
}
|
||||
|
||||
list_splice(&panel_list, &dev->mode_config.connector_list);
|
||||
}
|
||||
EXPORT_SYMBOL(drm_helper_move_panel_connectors_to_head);
|
||||
|
||||
static bool drm_kms_helper_poll = true;
|
||||
module_param_named(poll, drm_kms_helper_poll, bool, 0600);
|
||||
|
||||
@@ -64,22 +93,21 @@ static void drm_mode_validate_flag(struct drm_connector *connector,
|
||||
|
||||
/**
|
||||
* drm_helper_probe_single_connector_modes - get complete set of display modes
|
||||
* @dev: DRM device
|
||||
* @connector: connector to probe
|
||||
* @maxX: max width for modes
|
||||
* @maxY: max height for modes
|
||||
*
|
||||
* LOCKING:
|
||||
* Caller must hold mode config lock.
|
||||
*
|
||||
* Based on @dev's mode_config layout, scan all the connectors and try to detect
|
||||
* modes on them. Modes will first be added to the connector's probed_modes
|
||||
* list, then culled (based on validity and the @maxX, @maxY parameters) and
|
||||
* put into the normal modes list.
|
||||
* Based on the helper callbacks implemented by @connector try to detect all
|
||||
* valid modes. Modes will first be added to the connector's probed_modes list,
|
||||
* then culled (based on validity and the @maxX, @maxY parameters) and put into
|
||||
* the normal modes list.
|
||||
*
|
||||
* Intended to be used either at bootup time or when major configuration
|
||||
* changes have occurred.
|
||||
*
|
||||
* FIXME: take into account monitor limits
|
||||
* Intended to be use as a generic implementation of the ->probe() @connector
|
||||
* callback for drivers that use the crtc helpers for output mode filtering and
|
||||
* detection.
|
||||
*
|
||||
* RETURNS:
|
||||
* Number of modes found on @connector.
|
||||
@@ -109,9 +137,14 @@ int drm_helper_probe_single_connector_modes(struct drm_connector *connector,
|
||||
connector->funcs->force(connector);
|
||||
} else {
|
||||
connector->status = connector->funcs->detect(connector, true);
|
||||
drm_kms_helper_poll_enable(dev);
|
||||
}
|
||||
|
||||
/* Re-enable polling in case the global poll config changed. */
|
||||
if (drm_kms_helper_poll != dev->mode_config.poll_running)
|
||||
drm_kms_helper_poll_enable(dev);
|
||||
|
||||
dev->mode_config.poll_running = drm_kms_helper_poll;
|
||||
|
||||
if (connector->status == connector_status_disconnected) {
|
||||
DRM_DEBUG_KMS("[CONNECTOR:%d:%s] disconnected\n",
|
||||
connector->base.id, drm_get_connector_name(connector));
|
||||
@@ -325,17 +358,24 @@ drm_crtc_prepare_encoders(struct drm_device *dev)
|
||||
}
|
||||
|
||||
/**
|
||||
* drm_crtc_set_mode - set a mode
|
||||
* drm_crtc_helper_set_mode - internal helper to set a mode
|
||||
* @crtc: CRTC to program
|
||||
* @mode: mode to use
|
||||
* @x: width of mode
|
||||
* @y: height of mode
|
||||
* @x: horizontal offset into the surface
|
||||
* @y: vertical offset into the surface
|
||||
* @old_fb: old framebuffer, for cleanup
|
||||
*
|
||||
* LOCKING:
|
||||
* Caller must hold mode config lock.
|
||||
*
|
||||
* Try to set @mode on @crtc. Give @crtc and its associated connectors a chance
|
||||
* to fixup or reject the mode prior to trying to set it.
|
||||
* to fixup or reject the mode prior to trying to set it. This is an internal
|
||||
* helper that drivers could e.g. use to update properties that require the
|
||||
* entire output pipe to be disabled and re-enabled in a new configuration. For
|
||||
* example for changing whether audio is enabled on a hdmi link or for changing
|
||||
* panel fitter or dither attributes. It is also called by the
|
||||
* drm_crtc_helper_set_config() helper function to drive the mode setting
|
||||
* sequence.
|
||||
*
|
||||
* RETURNS:
|
||||
* True if the mode was set successfully, or false otherwise.
|
||||
@@ -491,20 +531,19 @@ drm_crtc_helper_disable(struct drm_crtc *crtc)
|
||||
|
||||
/**
|
||||
* drm_crtc_helper_set_config - set a new config from userspace
|
||||
* @crtc: CRTC to setup
|
||||
* @crtc_info: user provided configuration
|
||||
* @new_mode: new mode to set
|
||||
* @connector_set: set of connectors for the new config
|
||||
* @fb: new framebuffer
|
||||
* @set: mode set configuration
|
||||
*
|
||||
* LOCKING:
|
||||
* Caller must hold mode config lock.
|
||||
*
|
||||
* Setup a new configuration, provided by the user in @crtc_info, and enable
|
||||
* it.
|
||||
* Setup a new configuration, provided by the upper layers (either an ioctl call
|
||||
* from userspace or internally e.g. from the fbdev suppport code) in @set, and
|
||||
* enable it. This is the main helper functions for drivers that implement
|
||||
* kernel mode setting with the crtc helper functions and the assorted
|
||||
* ->prepare(), ->modeset() and ->commit() helper callbacks.
|
||||
*
|
||||
* RETURNS:
|
||||
* Zero. (FIXME)
|
||||
* Returns 0 on success, -ERRNO on failure.
|
||||
*/
|
||||
int drm_crtc_helper_set_config(struct drm_mode_set *set)
|
||||
{
|
||||
@@ -800,12 +839,14 @@ static int drm_helper_choose_crtc_dpms(struct drm_crtc *crtc)
|
||||
}
|
||||
|
||||
/**
|
||||
* drm_helper_connector_dpms
|
||||
* @connector affected connector
|
||||
* @mode DPMS mode
|
||||
* drm_helper_connector_dpms() - connector dpms helper implementation
|
||||
* @connector: affected connector
|
||||
* @mode: DPMS mode
|
||||
*
|
||||
* Calls the low-level connector DPMS function, then
|
||||
* calls appropriate encoder and crtc DPMS functions as well
|
||||
* This is the main helper function provided by the crtc helper framework for
|
||||
* implementing the DPMS connector attribute. It computes the new desired DPMS
|
||||
* state for all encoders and crtcs in the output mesh and calls the ->dpms()
|
||||
* callback provided by the driver appropriately.
|
||||
*/
|
||||
void drm_helper_connector_dpms(struct drm_connector *connector, int mode)
|
||||
{
|
||||
@@ -918,6 +959,15 @@ int drm_helper_resume_force_mode(struct drm_device *dev)
|
||||
}
|
||||
EXPORT_SYMBOL(drm_helper_resume_force_mode);
|
||||
|
||||
void drm_kms_helper_hotplug_event(struct drm_device *dev)
|
||||
{
|
||||
/* send a uevent + call fbdev */
|
||||
drm_sysfs_hotplug_event(dev);
|
||||
if (dev->mode_config.funcs->output_poll_changed)
|
||||
dev->mode_config.funcs->output_poll_changed(dev);
|
||||
}
|
||||
EXPORT_SYMBOL(drm_kms_helper_hotplug_event);
|
||||
|
||||
#define DRM_OUTPUT_POLL_PERIOD (10*HZ)
|
||||
static void output_poll_execute(struct work_struct *work)
|
||||
{
|
||||
@@ -933,20 +983,22 @@ static void output_poll_execute(struct work_struct *work)
|
||||
mutex_lock(&dev->mode_config.mutex);
|
||||
list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
|
||||
|
||||
/* if this is HPD or polled don't check it -
|
||||
TV out for instance */
|
||||
if (!connector->polled)
|
||||
/* Ignore forced connectors. */
|
||||
if (connector->force)
|
||||
continue;
|
||||
|
||||
else if (connector->polled & (DRM_CONNECTOR_POLL_CONNECT | DRM_CONNECTOR_POLL_DISCONNECT))
|
||||
repoll = true;
|
||||
/* Ignore HPD capable connectors and connectors where we don't
|
||||
* want any hotplug detection at all for polling. */
|
||||
if (!connector->polled || connector->polled == DRM_CONNECTOR_POLL_HPD)
|
||||
continue;
|
||||
|
||||
repoll = true;
|
||||
|
||||
old_status = connector->status;
|
||||
/* if we are connected and don't want to poll for disconnect
|
||||
skip it */
|
||||
if (old_status == connector_status_connected &&
|
||||
!(connector->polled & DRM_CONNECTOR_POLL_DISCONNECT) &&
|
||||
!(connector->polled & DRM_CONNECTOR_POLL_HPD))
|
||||
!(connector->polled & DRM_CONNECTOR_POLL_DISCONNECT))
|
||||
continue;
|
||||
|
||||
connector->status = connector->funcs->detect(connector, false);
|
||||
@@ -960,12 +1012,8 @@ static void output_poll_execute(struct work_struct *work)
|
||||
|
||||
mutex_unlock(&dev->mode_config.mutex);
|
||||
|
||||
if (changed) {
|
||||
/* send a uevent + call fbdev */
|
||||
drm_sysfs_hotplug_event(dev);
|
||||
if (dev->mode_config.funcs->output_poll_changed)
|
||||
dev->mode_config.funcs->output_poll_changed(dev);
|
||||
}
|
||||
if (changed)
|
||||
drm_kms_helper_hotplug_event(dev);
|
||||
|
||||
if (repoll)
|
||||
schedule_delayed_work(delayed_work, DRM_OUTPUT_POLL_PERIOD);
|
||||
@@ -988,7 +1036,8 @@ void drm_kms_helper_poll_enable(struct drm_device *dev)
|
||||
return;
|
||||
|
||||
list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
|
||||
if (connector->polled)
|
||||
if (connector->polled & (DRM_CONNECTOR_POLL_CONNECT |
|
||||
DRM_CONNECTOR_POLL_DISCONNECT))
|
||||
poll = true;
|
||||
}
|
||||
|
||||
@@ -1014,12 +1063,34 @@ EXPORT_SYMBOL(drm_kms_helper_poll_fini);
|
||||
|
||||
void drm_helper_hpd_irq_event(struct drm_device *dev)
|
||||
{
|
||||
struct drm_connector *connector;
|
||||
enum drm_connector_status old_status;
|
||||
bool changed = false;
|
||||
|
||||
if (!dev->mode_config.poll_enabled)
|
||||
return;
|
||||
|
||||
/* kill timer and schedule immediate execution, this doesn't block */
|
||||
cancel_delayed_work(&dev->mode_config.output_poll_work);
|
||||
if (drm_kms_helper_poll)
|
||||
schedule_delayed_work(&dev->mode_config.output_poll_work, 0);
|
||||
mutex_lock(&dev->mode_config.mutex);
|
||||
list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
|
||||
|
||||
/* Only handle HPD capable connectors. */
|
||||
if (!(connector->polled & DRM_CONNECTOR_POLL_HPD))
|
||||
continue;
|
||||
|
||||
old_status = connector->status;
|
||||
|
||||
connector->status = connector->funcs->detect(connector, false);
|
||||
DRM_DEBUG_KMS("[CONNECTOR:%d:%s] status updated from %d to %d\n",
|
||||
connector->base.id,
|
||||
drm_get_connector_name(connector),
|
||||
old_status, connector->status);
|
||||
if (old_status != connector->status)
|
||||
changed = true;
|
||||
}
|
||||
|
||||
mutex_unlock(&dev->mode_config.mutex);
|
||||
|
||||
if (changed)
|
||||
drm_kms_helper_hotplug_event(dev);
|
||||
}
|
||||
EXPORT_SYMBOL(drm_helper_hpd_irq_event);
|
||||
|
||||
@@ -30,6 +30,15 @@
|
||||
#include <drm/drm_dp_helper.h>
|
||||
#include <drm/drmP.h>
|
||||
|
||||
/**
|
||||
* DOC: dp helpers
|
||||
*
|
||||
* These functions contain some common logic and helpers at various abstraction
|
||||
* levels to deal with Display Port sink devices and related things like DP aux
|
||||
* channel transfers, EDID reading over DP aux channels, decoding certain DPCD
|
||||
* blocks, ...
|
||||
*/
|
||||
|
||||
/* Run a single AUX_CH I2C transaction, writing/reading data as necessary */
|
||||
static int
|
||||
i2c_algo_dp_aux_transaction(struct i2c_adapter *adapter, int mode,
|
||||
@@ -37,7 +46,7 @@ i2c_algo_dp_aux_transaction(struct i2c_adapter *adapter, int mode,
|
||||
{
|
||||
struct i2c_algo_dp_aux_data *algo_data = adapter->algo_data;
|
||||
int ret;
|
||||
|
||||
|
||||
ret = (*algo_data->aux_ch)(adapter, mode,
|
||||
write_byte, read_byte);
|
||||
return ret;
|
||||
@@ -182,7 +191,6 @@ i2c_dp_aux_reset_bus(struct i2c_adapter *adapter)
|
||||
{
|
||||
(void) i2c_algo_dp_aux_address(adapter, 0, false);
|
||||
(void) i2c_algo_dp_aux_stop(adapter, false);
|
||||
|
||||
}
|
||||
|
||||
static int
|
||||
@@ -194,11 +202,23 @@ i2c_dp_aux_prepare_bus(struct i2c_adapter *adapter)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* i2c_dp_aux_add_bus() - register an i2c adapter using the aux ch helper
|
||||
* @adapter: i2c adapter to register
|
||||
*
|
||||
* This registers an i2c adapater that uses dp aux channel as it's underlaying
|
||||
* transport. The driver needs to fill out the &i2c_algo_dp_aux_data structure
|
||||
* and store it in the algo_data member of the @adapter argument. This will be
|
||||
* used by the i2c over dp aux algorithm to drive the hardware.
|
||||
*
|
||||
* RETURNS:
|
||||
* 0 on success, -ERRNO on failure.
|
||||
*/
|
||||
int
|
||||
i2c_dp_aux_add_bus(struct i2c_adapter *adapter)
|
||||
{
|
||||
int error;
|
||||
|
||||
|
||||
error = i2c_dp_aux_prepare_bus(adapter);
|
||||
if (error)
|
||||
return error;
|
||||
@@ -206,3 +226,123 @@ i2c_dp_aux_add_bus(struct i2c_adapter *adapter)
|
||||
return error;
|
||||
}
|
||||
EXPORT_SYMBOL(i2c_dp_aux_add_bus);
|
||||
|
||||
/* Helpers for DP link training */
|
||||
static u8 dp_link_status(u8 link_status[DP_LINK_STATUS_SIZE], int r)
|
||||
{
|
||||
return link_status[r - DP_LANE0_1_STATUS];
|
||||
}
|
||||
|
||||
static u8 dp_get_lane_status(u8 link_status[DP_LINK_STATUS_SIZE],
|
||||
int lane)
|
||||
{
|
||||
int i = DP_LANE0_1_STATUS + (lane >> 1);
|
||||
int s = (lane & 1) * 4;
|
||||
u8 l = dp_link_status(link_status, i);
|
||||
return (l >> s) & 0xf;
|
||||
}
|
||||
|
||||
bool drm_dp_channel_eq_ok(u8 link_status[DP_LINK_STATUS_SIZE],
|
||||
int lane_count)
|
||||
{
|
||||
u8 lane_align;
|
||||
u8 lane_status;
|
||||
int lane;
|
||||
|
||||
lane_align = dp_link_status(link_status,
|
||||
DP_LANE_ALIGN_STATUS_UPDATED);
|
||||
if ((lane_align & DP_INTERLANE_ALIGN_DONE) == 0)
|
||||
return false;
|
||||
for (lane = 0; lane < lane_count; lane++) {
|
||||
lane_status = dp_get_lane_status(link_status, lane);
|
||||
if ((lane_status & DP_CHANNEL_EQ_BITS) != DP_CHANNEL_EQ_BITS)
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
EXPORT_SYMBOL(drm_dp_channel_eq_ok);
|
||||
|
||||
bool drm_dp_clock_recovery_ok(u8 link_status[DP_LINK_STATUS_SIZE],
|
||||
int lane_count)
|
||||
{
|
||||
int lane;
|
||||
u8 lane_status;
|
||||
|
||||
for (lane = 0; lane < lane_count; lane++) {
|
||||
lane_status = dp_get_lane_status(link_status, lane);
|
||||
if ((lane_status & DP_LANE_CR_DONE) == 0)
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
EXPORT_SYMBOL(drm_dp_clock_recovery_ok);
|
||||
|
||||
u8 drm_dp_get_adjust_request_voltage(u8 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);
|
||||
u8 l = dp_link_status(link_status, i);
|
||||
|
||||
return ((l >> s) & 0x3) << DP_TRAIN_VOLTAGE_SWING_SHIFT;
|
||||
}
|
||||
EXPORT_SYMBOL(drm_dp_get_adjust_request_voltage);
|
||||
|
||||
u8 drm_dp_get_adjust_request_pre_emphasis(u8 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);
|
||||
u8 l = dp_link_status(link_status, i);
|
||||
|
||||
return ((l >> s) & 0x3) << DP_TRAIN_PRE_EMPHASIS_SHIFT;
|
||||
}
|
||||
EXPORT_SYMBOL(drm_dp_get_adjust_request_pre_emphasis);
|
||||
|
||||
void drm_dp_link_train_clock_recovery_delay(u8 dpcd[DP_RECEIVER_CAP_SIZE]) {
|
||||
if (dpcd[DP_TRAINING_AUX_RD_INTERVAL] == 0)
|
||||
udelay(100);
|
||||
else
|
||||
mdelay(dpcd[DP_TRAINING_AUX_RD_INTERVAL] * 4);
|
||||
}
|
||||
EXPORT_SYMBOL(drm_dp_link_train_clock_recovery_delay);
|
||||
|
||||
void drm_dp_link_train_channel_eq_delay(u8 dpcd[DP_RECEIVER_CAP_SIZE]) {
|
||||
if (dpcd[DP_TRAINING_AUX_RD_INTERVAL] == 0)
|
||||
udelay(400);
|
||||
else
|
||||
mdelay(dpcd[DP_TRAINING_AUX_RD_INTERVAL] * 4);
|
||||
}
|
||||
EXPORT_SYMBOL(drm_dp_link_train_channel_eq_delay);
|
||||
|
||||
u8 drm_dp_link_rate_to_bw_code(int link_rate)
|
||||
{
|
||||
switch (link_rate) {
|
||||
case 162000:
|
||||
default:
|
||||
return DP_LINK_BW_1_62;
|
||||
case 270000:
|
||||
return DP_LINK_BW_2_7;
|
||||
case 540000:
|
||||
return DP_LINK_BW_5_4;
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL(drm_dp_link_rate_to_bw_code);
|
||||
|
||||
int drm_dp_bw_code_to_link_rate(u8 link_bw)
|
||||
{
|
||||
switch (link_bw) {
|
||||
case DP_LINK_BW_1_62:
|
||||
default:
|
||||
return 162000;
|
||||
case DP_LINK_BW_2_7:
|
||||
return 270000;
|
||||
case DP_LINK_BW_5_4:
|
||||
return 540000;
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL(drm_dp_bw_code_to_link_rate);
|
||||
@@ -307,12 +307,9 @@ drm_do_probe_ddc_edid(struct i2c_adapter *adapter, unsigned char *buf,
|
||||
|
||||
static bool drm_edid_is_zero(u8 *in_edid, int length)
|
||||
{
|
||||
int i;
|
||||
u32 *raw_edid = (u32 *)in_edid;
|
||||
if (memchr_inv(in_edid, 0, length))
|
||||
return false;
|
||||
|
||||
for (i = 0; i < length / 4; i++)
|
||||
if (*(raw_edid + i) != 0)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -1516,6 +1513,26 @@ u8 *drm_find_cea_extension(struct edid *edid)
|
||||
}
|
||||
EXPORT_SYMBOL(drm_find_cea_extension);
|
||||
|
||||
/*
|
||||
* Looks for a CEA mode matching given drm_display_mode.
|
||||
* Returns its CEA Video ID code, or 0 if not found.
|
||||
*/
|
||||
u8 drm_match_cea_mode(struct drm_display_mode *to_match)
|
||||
{
|
||||
struct drm_display_mode *cea_mode;
|
||||
u8 mode;
|
||||
|
||||
for (mode = 0; mode < drm_num_cea_modes; mode++) {
|
||||
cea_mode = (struct drm_display_mode *)&edid_cea_modes[mode];
|
||||
|
||||
if (drm_mode_equal(to_match, cea_mode))
|
||||
return mode + 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(drm_match_cea_mode);
|
||||
|
||||
|
||||
static int
|
||||
do_cea_modes (struct drm_connector *connector, u8 *db, u8 len)
|
||||
{
|
||||
@@ -1622,7 +1639,7 @@ parse_hdmi_vsdb(struct drm_connector *connector, const u8 *db)
|
||||
if (len >= 12)
|
||||
connector->audio_latency[1] = db[12];
|
||||
|
||||
DRM_LOG_KMS("HDMI: DVI dual %d, "
|
||||
DRM_DEBUG_KMS("HDMI: DVI dual %d, "
|
||||
"max TMDS clock %d, "
|
||||
"latency present %d %d, "
|
||||
"video latency %d %d, "
|
||||
@@ -2062,3 +2079,22 @@ int drm_add_modes_noedid(struct drm_connector *connector,
|
||||
return num_modes;
|
||||
}
|
||||
EXPORT_SYMBOL(drm_add_modes_noedid);
|
||||
|
||||
/**
|
||||
* drm_mode_cea_vic - return the CEA-861 VIC of a given mode
|
||||
* @mode: mode
|
||||
*
|
||||
* RETURNS:
|
||||
* The VIC number, 0 in case it's not a CEA-861 mode.
|
||||
*/
|
||||
uint8_t drm_mode_cea_vic(const struct drm_display_mode *mode)
|
||||
{
|
||||
uint8_t i;
|
||||
|
||||
for (i = 0; i < drm_num_cea_modes; i++)
|
||||
if (drm_mode_equal(mode, &edid_cea_modes[i]))
|
||||
return i + 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(drm_mode_cea_vic);
|
||||
|
||||
@@ -27,6 +27,8 @@
|
||||
* Dave Airlie <airlied@linux.ie>
|
||||
* Jesse Barnes <jesse.barnes@intel.com>
|
||||
*/
|
||||
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/sysrq.h>
|
||||
#include <linux/slab.h>
|
||||
@@ -43,6 +45,15 @@ MODULE_LICENSE("GPL and additional rights");
|
||||
|
||||
static LIST_HEAD(kernel_fb_helper_list);
|
||||
|
||||
/**
|
||||
* DOC: fbdev helpers
|
||||
*
|
||||
* The fb helper functions are useful to provide an fbdev on top of a drm kernel
|
||||
* mode setting driver. They can be used mostly independantely from the crtc
|
||||
* helper functions used by many drivers to implement the kernel mode setting
|
||||
* interfaces.
|
||||
*/
|
||||
|
||||
/* simple single crtc case helper function */
|
||||
int drm_fb_helper_single_add_all_connectors(struct drm_fb_helper *fb_helper)
|
||||
{
|
||||
@@ -95,10 +106,16 @@ static int drm_fb_helper_parse_command_line(struct drm_fb_helper *fb_helper)
|
||||
if (mode->force) {
|
||||
const char *s;
|
||||
switch (mode->force) {
|
||||
case DRM_FORCE_OFF: s = "OFF"; break;
|
||||
case DRM_FORCE_ON_DIGITAL: s = "ON - dig"; break;
|
||||
case DRM_FORCE_OFF:
|
||||
s = "OFF";
|
||||
break;
|
||||
case DRM_FORCE_ON_DIGITAL:
|
||||
s = "ON - dig";
|
||||
break;
|
||||
default:
|
||||
case DRM_FORCE_ON: s = "ON"; break;
|
||||
case DRM_FORCE_ON:
|
||||
s = "ON";
|
||||
break;
|
||||
}
|
||||
|
||||
DRM_INFO("forcing %s connector %s\n",
|
||||
@@ -265,7 +282,7 @@ int drm_fb_helper_panic(struct notifier_block *n, unsigned long ununsed,
|
||||
if (panic_timeout < 0)
|
||||
return 0;
|
||||
|
||||
printk(KERN_ERR "panic occurred, switching back to text console\n");
|
||||
pr_err("panic occurred, switching back to text console\n");
|
||||
return drm_fb_helper_force_kernel_mode();
|
||||
}
|
||||
EXPORT_SYMBOL(drm_fb_helper_panic);
|
||||
@@ -331,7 +348,7 @@ static void drm_fb_helper_dpms(struct fb_info *info, int dpms_mode)
|
||||
for (j = 0; j < fb_helper->connector_count; j++) {
|
||||
connector = fb_helper->connector_info[j]->connector;
|
||||
connector->funcs->dpms(connector, dpms_mode);
|
||||
drm_connector_property_set_value(connector,
|
||||
drm_object_property_set_value(&connector->base,
|
||||
dev->mode_config.dpms_property, dpms_mode);
|
||||
}
|
||||
}
|
||||
@@ -433,7 +450,7 @@ void drm_fb_helper_fini(struct drm_fb_helper *fb_helper)
|
||||
if (!list_empty(&fb_helper->kernel_fb_list)) {
|
||||
list_del(&fb_helper->kernel_fb_list);
|
||||
if (list_empty(&kernel_fb_helper_list)) {
|
||||
printk(KERN_INFO "drm: unregistered panic notifier\n");
|
||||
pr_info("drm: unregistered panic notifier\n");
|
||||
atomic_notifier_chain_unregister(&panic_notifier_list,
|
||||
&paniced);
|
||||
unregister_sysrq_key('v', &sysrq_drm_fb_helper_restore_op);
|
||||
@@ -724,9 +741,9 @@ int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper,
|
||||
|
||||
/* if driver picks 8 or 16 by default use that
|
||||
for both depth/bpp */
|
||||
if (preferred_bpp != sizes.surface_bpp) {
|
||||
if (preferred_bpp != sizes.surface_bpp)
|
||||
sizes.surface_depth = sizes.surface_bpp = preferred_bpp;
|
||||
}
|
||||
|
||||
/* first up get a count of crtcs now in use and new min/maxes width/heights */
|
||||
for (i = 0; i < fb_helper->connector_count; i++) {
|
||||
struct drm_fb_helper_connector *fb_helper_conn = fb_helper->connector_info[i];
|
||||
@@ -794,18 +811,16 @@ int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper,
|
||||
info = fb_helper->fbdev;
|
||||
|
||||
/* set the fb pointer */
|
||||
for (i = 0; i < fb_helper->crtc_count; i++) {
|
||||
for (i = 0; i < fb_helper->crtc_count; i++)
|
||||
fb_helper->crtc_info[i].mode_set.fb = fb_helper->fb;
|
||||
}
|
||||
|
||||
if (new_fb) {
|
||||
info->var.pixclock = 0;
|
||||
if (register_framebuffer(info) < 0) {
|
||||
if (register_framebuffer(info) < 0)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
printk(KERN_INFO "fb%d: %s frame buffer device\n", info->node,
|
||||
info->fix.id);
|
||||
dev_info(fb_helper->dev->dev, "fb%d: %s frame buffer device\n",
|
||||
info->node, info->fix.id);
|
||||
|
||||
} else {
|
||||
drm_fb_helper_set_par(info);
|
||||
@@ -814,7 +829,7 @@ int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper,
|
||||
/* Switch back to kernel console on panic */
|
||||
/* multi card linked list maybe */
|
||||
if (list_empty(&kernel_fb_helper_list)) {
|
||||
printk(KERN_INFO "drm: registered panic notifier\n");
|
||||
dev_info(fb_helper->dev->dev, "registered panic notifier\n");
|
||||
atomic_notifier_chain_register(&panic_notifier_list,
|
||||
&paniced);
|
||||
register_sysrq_key('v', &sysrq_drm_fb_helper_restore_op);
|
||||
@@ -1002,11 +1017,11 @@ static bool drm_connector_enabled(struct drm_connector *connector, bool strict)
|
||||
{
|
||||
bool enable;
|
||||
|
||||
if (strict) {
|
||||
if (strict)
|
||||
enable = connector->status == connector_status_connected;
|
||||
} else {
|
||||
else
|
||||
enable = connector->status != connector_status_disconnected;
|
||||
}
|
||||
|
||||
return enable;
|
||||
}
|
||||
|
||||
@@ -1191,9 +1206,8 @@ static int drm_pick_crtcs(struct drm_fb_helper *fb_helper,
|
||||
for (c = 0; c < fb_helper->crtc_count; c++) {
|
||||
crtc = &fb_helper->crtc_info[c];
|
||||
|
||||
if ((encoder->possible_crtcs & (1 << c)) == 0) {
|
||||
if ((encoder->possible_crtcs & (1 << c)) == 0)
|
||||
continue;
|
||||
}
|
||||
|
||||
for (o = 0; o < n; o++)
|
||||
if (best_crtcs[o] == crtc)
|
||||
@@ -1246,6 +1260,11 @@ static void drm_setup_crtcs(struct drm_fb_helper *fb_helper)
|
||||
sizeof(struct drm_display_mode *), GFP_KERNEL);
|
||||
enabled = kcalloc(dev->mode_config.num_connector,
|
||||
sizeof(bool), GFP_KERNEL);
|
||||
if (!crtcs || !modes || !enabled) {
|
||||
DRM_ERROR("Memory allocation failed\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
|
||||
drm_enable_connectors(fb_helper, enabled);
|
||||
|
||||
@@ -1284,6 +1303,7 @@ static void drm_setup_crtcs(struct drm_fb_helper *fb_helper)
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
kfree(crtcs);
|
||||
kfree(modes);
|
||||
kfree(enabled);
|
||||
@@ -1291,12 +1311,14 @@ static void drm_setup_crtcs(struct drm_fb_helper *fb_helper)
|
||||
|
||||
/**
|
||||
* drm_helper_initial_config - setup a sane initial connector configuration
|
||||
* @dev: DRM device
|
||||
* @fb_helper: fb_helper device struct
|
||||
* @bpp_sel: bpp value to use for the framebuffer configuration
|
||||
*
|
||||
* LOCKING:
|
||||
* Called at init time, must take mode config lock.
|
||||
* Called at init time by the driver to set up the @fb_helper initial
|
||||
* configuration, must take the mode config lock.
|
||||
*
|
||||
* Scan the CRTCs and connectors and try to put together an initial setup.
|
||||
* Scans the CRTCs and connectors and tries to put together an initial setup.
|
||||
* At the moment, this is a cloned configuration across all heads with
|
||||
* a new framebuffer object as the backing store.
|
||||
*
|
||||
@@ -1319,9 +1341,9 @@ bool drm_fb_helper_initial_config(struct drm_fb_helper *fb_helper, int bpp_sel)
|
||||
/*
|
||||
* we shouldn't end up with no modes here.
|
||||
*/
|
||||
if (count == 0) {
|
||||
printk(KERN_INFO "No connectors reported connected with modes\n");
|
||||
}
|
||||
if (count == 0)
|
||||
dev_info(fb_helper->dev->dev, "No connectors reported connected with modes\n");
|
||||
|
||||
drm_setup_crtcs(fb_helper);
|
||||
|
||||
return drm_fb_helper_single_fb_probe(fb_helper, bpp_sel);
|
||||
@@ -1330,7 +1352,7 @@ EXPORT_SYMBOL(drm_fb_helper_initial_config);
|
||||
|
||||
/**
|
||||
* drm_fb_helper_hotplug_event - respond to a hotplug notification by
|
||||
* probing all the outputs attached to the fb.
|
||||
* probing all the outputs attached to the fb
|
||||
* @fb_helper: the drm_fb_helper
|
||||
*
|
||||
* LOCKING:
|
||||
|
||||
@@ -67,10 +67,8 @@ void drm_ht_verbose_list(struct drm_open_hash *ht, unsigned long key)
|
||||
hashed_key = hash_long(key, ht->order);
|
||||
DRM_DEBUG("Key is 0x%08lx, Hashed key is 0x%08x\n", key, hashed_key);
|
||||
h_list = &ht->table[hashed_key];
|
||||
hlist_for_each(list, h_list) {
|
||||
entry = hlist_entry(list, struct drm_hash_item, head);
|
||||
hlist_for_each_entry(entry, list, h_list, head)
|
||||
DRM_DEBUG("count %d, key: 0x%08lx\n", count++, entry->key);
|
||||
}
|
||||
}
|
||||
|
||||
static struct hlist_node *drm_ht_find_key(struct drm_open_hash *ht,
|
||||
@@ -83,8 +81,7 @@ static struct hlist_node *drm_ht_find_key(struct drm_open_hash *ht,
|
||||
|
||||
hashed_key = hash_long(key, ht->order);
|
||||
h_list = &ht->table[hashed_key];
|
||||
hlist_for_each(list, h_list) {
|
||||
entry = hlist_entry(list, struct drm_hash_item, head);
|
||||
hlist_for_each_entry(entry, list, h_list, head) {
|
||||
if (entry->key == key)
|
||||
return list;
|
||||
if (entry->key > key)
|
||||
@@ -93,6 +90,24 @@ static struct hlist_node *drm_ht_find_key(struct drm_open_hash *ht,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static struct hlist_node *drm_ht_find_key_rcu(struct drm_open_hash *ht,
|
||||
unsigned long key)
|
||||
{
|
||||
struct drm_hash_item *entry;
|
||||
struct hlist_head *h_list;
|
||||
struct hlist_node *list;
|
||||
unsigned int hashed_key;
|
||||
|
||||
hashed_key = hash_long(key, ht->order);
|
||||
h_list = &ht->table[hashed_key];
|
||||
hlist_for_each_entry_rcu(entry, list, h_list, head) {
|
||||
if (entry->key == key)
|
||||
return list;
|
||||
if (entry->key > key)
|
||||
break;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int drm_ht_insert_item(struct drm_open_hash *ht, struct drm_hash_item *item)
|
||||
{
|
||||
@@ -105,8 +120,7 @@ int drm_ht_insert_item(struct drm_open_hash *ht, struct drm_hash_item *item)
|
||||
hashed_key = hash_long(key, ht->order);
|
||||
h_list = &ht->table[hashed_key];
|
||||
parent = NULL;
|
||||
hlist_for_each(list, h_list) {
|
||||
entry = hlist_entry(list, struct drm_hash_item, head);
|
||||
hlist_for_each_entry(entry, list, h_list, head) {
|
||||
if (entry->key == key)
|
||||
return -EINVAL;
|
||||
if (entry->key > key)
|
||||
@@ -114,9 +128,9 @@ int drm_ht_insert_item(struct drm_open_hash *ht, struct drm_hash_item *item)
|
||||
parent = list;
|
||||
}
|
||||
if (parent) {
|
||||
hlist_add_after(parent, &item->head);
|
||||
hlist_add_after_rcu(parent, &item->head);
|
||||
} else {
|
||||
hlist_add_head(&item->head, h_list);
|
||||
hlist_add_head_rcu(&item->head, h_list);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -156,7 +170,7 @@ int drm_ht_find_item(struct drm_open_hash *ht, unsigned long key,
|
||||
{
|
||||
struct hlist_node *list;
|
||||
|
||||
list = drm_ht_find_key(ht, key);
|
||||
list = drm_ht_find_key_rcu(ht, key);
|
||||
if (!list)
|
||||
return -EINVAL;
|
||||
|
||||
@@ -171,7 +185,7 @@ int drm_ht_remove_key(struct drm_open_hash *ht, unsigned long key)
|
||||
|
||||
list = drm_ht_find_key(ht, key);
|
||||
if (list) {
|
||||
hlist_del_init(list);
|
||||
hlist_del_init_rcu(list);
|
||||
return 0;
|
||||
}
|
||||
return -EINVAL;
|
||||
@@ -179,7 +193,7 @@ int drm_ht_remove_key(struct drm_open_hash *ht, unsigned long key)
|
||||
|
||||
int drm_ht_remove_item(struct drm_open_hash *ht, struct drm_hash_item *item)
|
||||
{
|
||||
hlist_del_init(&item->head);
|
||||
hlist_del_init_rcu(&item->head);
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(drm_ht_remove_item);
|
||||
|
||||
@@ -287,6 +287,9 @@ int drm_getcap(struct drm_device *dev, void *data, struct drm_file *file_priv)
|
||||
req->value |= dev->driver->prime_fd_to_handle ? DRM_PRIME_CAP_IMPORT : 0;
|
||||
req->value |= dev->driver->prime_handle_to_fd ? DRM_PRIME_CAP_EXPORT : 0;
|
||||
break;
|
||||
case DRM_CAP_TIMESTAMP_MONOTONIC:
|
||||
req->value = drm_timestamp_monotonic;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user