mirror of
https://github.com/suyu-emu/horinux.git
synced 2026-09-21 14:15:21 -07:00
Merge branch 'drm-next' of git://people.freedesktop.org/~airlied/linux
Pull drm tree changes from Dave Airlie:
"This is the main drm pull request, I have some overlap with sound and
arm-soc, the sound patch is acked and may conflict based on -next
reports but should be a trivial fixup, which I'll leave to you!
Highlights:
- new drivers:
MSM driver from Rob Clark
- non-drm:
switcheroo and hdmi audio driver support for secondary GPU
poweroff, so drivers can use runtime PM to poweroff the GPUs. This
can save 5 or 6W on some optimus laptops.
- drm core:
combined GEM and TTM VMA manager
per-filp mmap permission tracking
initial rendernode support (via a runtime enable for now, until we get api stable),
remove old proc support,
lots of cleanups of legacy code
hdmi vendor infoframes and 4k modes
lots of gem/prime locking and races fixes
async pageflip scaffolding
drm bridge objects
- i915:
Haswell PC8+ support and eLLC support, HDMI 4K support, initial
per-process VMA pieces, watermark reworks, convert to generic hdmi
infoframes, encoder reworking, fastboot support,
- radeon:
CIK PM support, remove 3d blit code in favour of DMA engines,
Berlin GPU support, HDMI audio fixes
- nouveau:
secondary GPU power down support for optimus laptops, lots of
fixes, use MSI, VP3 engine support
- exynos:
runtime pm support for g2d, DT support, remove non-DT,
- tda998x i2c driver:
lots of fixes for sync issues
- gma500:
lots of cleanups
- rcar:
add LVDS support, fbdev emulation,
- tegra:
just minor fixes"
* 'drm-next' of git://people.freedesktop.org/~airlied/linux: (684 commits)
drm/exynos: Fix build error with exynos_drm_connector.c
drm/exynos: Remove non-DT support in exynos_drm_fimd
drm/exynos: Remove non-DT support in exynos_hdmi
drm/exynos: Remove non-DT support in exynos_drm_g2d
drm/exynos: Remove non-DT support in exynos_hdmiphy
drm/exynos: Remove non-DT support in exynos_ddc
drm/exynos: Make Exynos DRM drivers depend on OF
drm/exynos: Consider fallback option to allocation fail
drm/exynos: fimd: move platform data parsing to separate function
drm/exynos: fimd: get signal polarities from device tree
drm/exynos: fimd: replace struct fb_videomode with videomode
drm/exynos: check a pixel format to a particular window layer
drm/exynos: fix fimd pixel format setting
drm/exynos: Add NULL pointer check
drm/exynos: Remove redundant error messages
drm/exynos: Add missing of.h header include
drm/exynos: Remove redundant NULL check in exynos_drm_buf
drm/exynos: add device tree support for rotator
drm/exynos: Add missing includes
drm/exynos: add runtime pm interfaces to g2d driver
...
This commit is contained in:
@@ -155,13 +155,6 @@
|
||||
will become a fatal error.
|
||||
</para></listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>DRIVER_USE_MTRR</term>
|
||||
<listitem><para>
|
||||
Driver uses MTRR interface for mapping memory, the DRM core will
|
||||
manage MTRR resources. Deprecated.
|
||||
</para></listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>DRIVER_PCI_DMA</term>
|
||||
<listitem><para>
|
||||
@@ -194,28 +187,6 @@
|
||||
support shared IRQs (note that this is required of PCI drivers).
|
||||
</para></listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>DRIVER_IRQ_VBL</term>
|
||||
<listitem><para>Unused. Deprecated.</para></listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>DRIVER_DMA_QUEUE</term>
|
||||
<listitem><para>
|
||||
Should be set if the driver queues DMA requests and completes them
|
||||
asynchronously. Deprecated.
|
||||
</para></listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>DRIVER_FB_DMA</term>
|
||||
<listitem><para>
|
||||
Driver supports DMA to/from the framebuffer, mapping of frambuffer
|
||||
DMA buffers to userspace will be supported. Deprecated.
|
||||
</para></listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>DRIVER_IRQ_VBL2</term>
|
||||
<listitem><para>Unused. Deprecated.</para></listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>DRIVER_GEM</term>
|
||||
<listitem><para>
|
||||
@@ -234,6 +205,12 @@
|
||||
Driver implements DRM PRIME buffer sharing.
|
||||
</para></listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>DRIVER_RENDER</term>
|
||||
<listitem><para>
|
||||
Driver supports dedicated render nodes.
|
||||
</para></listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
</sect3>
|
||||
<sect3>
|
||||
@@ -2212,6 +2189,18 @@ void intel_crt_init(struct drm_device *dev)
|
||||
!Iinclude/drm/drm_rect.h
|
||||
!Edrivers/gpu/drm/drm_rect.c
|
||||
</sect2>
|
||||
<sect2>
|
||||
<title>Flip-work Helper Reference</title>
|
||||
!Pinclude/drm/drm_flip_work.h flip utils
|
||||
!Iinclude/drm/drm_flip_work.h
|
||||
!Edrivers/gpu/drm/drm_flip_work.c
|
||||
</sect2>
|
||||
<sect2>
|
||||
<title>VMA Offset Manager</title>
|
||||
!Pdrivers/gpu/drm/drm_vma_manager.c vma offset manager
|
||||
!Edrivers/gpu/drm/drm_vma_manager.c
|
||||
!Iinclude/drm/drm_vma_manager.h
|
||||
</sect2>
|
||||
</sect1>
|
||||
|
||||
<!-- Internals: kms properties -->
|
||||
@@ -2422,18 +2411,18 @@ void (*postclose) (struct drm_device *, struct drm_file *);</synopsis>
|
||||
</abstract>
|
||||
<para>
|
||||
The <methodname>firstopen</methodname> method is called by the DRM core
|
||||
when an application opens a device that has no other opened file handle.
|
||||
Similarly the <methodname>lastclose</methodname> 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
|
||||
<methodname>load</methodname> and <methodname>unload</methodname>
|
||||
methods for KMS drivers.
|
||||
for legacy UMS (User Mode Setting) drivers only when an application
|
||||
opens a device that has no other opened file handle. UMS drivers can
|
||||
implement it to acquire device resources. KMS drivers can't use the
|
||||
method and must acquire resources in the <methodname>load</methodname>
|
||||
method instead.
|
||||
</para>
|
||||
<para>
|
||||
Note that the <methodname>lastclose</methodname> method is also called
|
||||
at module unload time or, for hot-pluggable devices, when the device is
|
||||
unplugged. The <methodname>firstopen</methodname> and
|
||||
Similarly the <methodname>lastclose</methodname> method is called when
|
||||
the last application holding a file handle opened on the device closes
|
||||
it, for both UMS and KMS drivers. Additionally, the method is also
|
||||
called at module unload time or, for hot-pluggable devices, when the
|
||||
device is unplugged. The <methodname>firstopen</methodname> and
|
||||
<methodname>lastclose</methodname> calls can thus be unbalanced.
|
||||
</para>
|
||||
<para>
|
||||
@@ -2462,7 +2451,12 @@ void (*postclose) (struct drm_device *, struct drm_file *);</synopsis>
|
||||
<para>
|
||||
The <methodname>lastclose</methodname> 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.
|
||||
device will not inherit state from the previous user. It can also be
|
||||
used to execute delayed power switching state changes, e.g. in
|
||||
conjunction with the vga-switcheroo infrastructure. Beyond that KMS
|
||||
drivers should not do any further cleanup. Only legacy UMS drivers might
|
||||
need to clean up device state so that the vga console or an independent
|
||||
fbdev driver could take over.
|
||||
</para>
|
||||
</sect2>
|
||||
<sect2>
|
||||
@@ -2498,7 +2492,6 @@ void (*postclose) (struct drm_device *, struct drm_file *);</synopsis>
|
||||
<programlisting>
|
||||
.poll = drm_poll,
|
||||
.read = drm_read,
|
||||
.fasync = drm_fasync,
|
||||
.llseek = no_llseek,
|
||||
</programlisting>
|
||||
</para>
|
||||
@@ -2657,6 +2650,69 @@ int (*resume) (struct drm_device *);</synopsis>
|
||||
info, since man pages should cover the rest.
|
||||
</para>
|
||||
|
||||
<!-- External: render nodes -->
|
||||
|
||||
<sect1>
|
||||
<title>Render nodes</title>
|
||||
<para>
|
||||
DRM core provides multiple character-devices for user-space to use.
|
||||
Depending on which device is opened, user-space can perform a different
|
||||
set of operations (mainly ioctls). The primary node is always created
|
||||
and called <term>card<num></term>. Additionally, a currently
|
||||
unused control node, called <term>controlD<num></term> is also
|
||||
created. The primary node provides all legacy operations and
|
||||
historically was the only interface used by userspace. With KMS, the
|
||||
control node was introduced. However, the planned KMS control interface
|
||||
has never been written and so the control node stays unused to date.
|
||||
</para>
|
||||
<para>
|
||||
With the increased use of offscreen renderers and GPGPU applications,
|
||||
clients no longer require running compositors or graphics servers to
|
||||
make use of a GPU. But the DRM API required unprivileged clients to
|
||||
authenticate to a DRM-Master prior to getting GPU access. To avoid this
|
||||
step and to grant clients GPU access without authenticating, render
|
||||
nodes were introduced. Render nodes solely serve render clients, that
|
||||
is, no modesetting or privileged ioctls can be issued on render nodes.
|
||||
Only non-global rendering commands are allowed. If a driver supports
|
||||
render nodes, it must advertise it via the <term>DRIVER_RENDER</term>
|
||||
DRM driver capability. If not supported, the primary node must be used
|
||||
for render clients together with the legacy drmAuth authentication
|
||||
procedure.
|
||||
</para>
|
||||
<para>
|
||||
If a driver advertises render node support, DRM core will create a
|
||||
separate render node called <term>renderD<num></term>. There will
|
||||
be one render node per device. No ioctls except PRIME-related ioctls
|
||||
will be allowed on this node. Especially <term>GEM_OPEN</term> will be
|
||||
explicitly prohibited. Render nodes are designed to avoid the
|
||||
buffer-leaks, which occur if clients guess the flink names or mmap
|
||||
offsets on the legacy interface. Additionally to this basic interface,
|
||||
drivers must mark their driver-dependent render-only ioctls as
|
||||
<term>DRM_RENDER_ALLOW</term> so render clients can use them. Driver
|
||||
authors must be careful not to allow any privileged ioctls on render
|
||||
nodes.
|
||||
</para>
|
||||
<para>
|
||||
With render nodes, user-space can now control access to the render node
|
||||
via basic file-system access-modes. A running graphics server which
|
||||
authenticates clients on the privileged primary/legacy node is no longer
|
||||
required. Instead, a client can open the render node and is immediately
|
||||
granted GPU access. Communication between clients (or servers) is done
|
||||
via PRIME. FLINK from render node to legacy node is not supported. New
|
||||
clients must not use the insecure FLINK interface.
|
||||
</para>
|
||||
<para>
|
||||
Besides dropping all modeset/global ioctls, render nodes also drop the
|
||||
DRM-Master concept. There is no reason to associate render clients with
|
||||
a DRM-Master as they are independent of any graphics server. Besides,
|
||||
they must work without any running master, anyway.
|
||||
Drivers must be able to run without a master object if they support
|
||||
render nodes. If, on the other hand, a driver requires shared state
|
||||
between clients which is visible to user-space and accessible beyond
|
||||
open-file boundaries, they cannot support render nodes.
|
||||
</para>
|
||||
</sect1>
|
||||
|
||||
<!-- External: vblank handling -->
|
||||
|
||||
<sect1>
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
* Samsung Image Rotator
|
||||
|
||||
Required properties:
|
||||
- compatible : value should be one of the following:
|
||||
(a) "samsung,exynos4210-rotator" for Rotator IP in Exynos4210
|
||||
(b) "samsung,exynos4212-rotator" for Rotator IP in Exynos4212/4412
|
||||
(c) "samsung,exynos5250-rotator" for Rotator IP in Exynos5250
|
||||
|
||||
- reg : Physical base address of the IP registers and length of memory
|
||||
mapped region.
|
||||
|
||||
- interrupts : Interrupt specifier for rotator interrupt, according to format
|
||||
specific to interrupt parent.
|
||||
|
||||
- clocks : Clock specifier for rotator clock, according to generic clock
|
||||
bindings. (See Documentation/devicetree/bindings/clock/exynos*.txt)
|
||||
|
||||
- clock-names : Names of clocks. For exynos rotator, it should be "rotator".
|
||||
|
||||
Example:
|
||||
rotator@12810000 {
|
||||
compatible = "samsung,exynos4210-rotator";
|
||||
reg = <0x12810000 0x1000>;
|
||||
interrupts = <0 83 0>;
|
||||
clocks = <&clock 278>;
|
||||
clock-names = "rotator";
|
||||
};
|
||||
+14
-1
@@ -6,7 +6,7 @@
|
||||
#
|
||||
menuconfig DRM
|
||||
tristate "Direct Rendering Manager (XFree86 4.1.0 and higher DRI support)"
|
||||
depends on (AGP || AGP=n) && !EMULATED_CMPXCHG && MMU
|
||||
depends on (AGP || AGP=n) && !EMULATED_CMPXCHG && MMU && HAS_DMA
|
||||
select HDMI
|
||||
select I2C
|
||||
select I2C_ALGOBIT
|
||||
@@ -168,6 +168,17 @@ config DRM_I915_KMS
|
||||
the driver to bind to PCI devices, which precludes loading things
|
||||
like intelfb.
|
||||
|
||||
config DRM_I915_PRELIMINARY_HW_SUPPORT
|
||||
bool "Enable preliminary support for prerelease Intel hardware by default"
|
||||
depends on DRM_I915
|
||||
help
|
||||
Choose this option if you have prerelease Intel hardware and want the
|
||||
i915 driver to support it by default. You can enable such support at
|
||||
runtime with the module option i915.preliminary_hw_support=1; this
|
||||
option changes the default for that module option.
|
||||
|
||||
If in doubt, say "N".
|
||||
|
||||
config DRM_MGA
|
||||
tristate "Matrox g200/g400"
|
||||
depends on DRM && PCI
|
||||
@@ -223,3 +234,5 @@ source "drivers/gpu/drm/omapdrm/Kconfig"
|
||||
source "drivers/gpu/drm/tilcdc/Kconfig"
|
||||
|
||||
source "drivers/gpu/drm/qxl/Kconfig"
|
||||
|
||||
source "drivers/gpu/drm/msm/Kconfig"
|
||||
|
||||
@@ -7,13 +7,13 @@ ccflags-y := -Iinclude/drm
|
||||
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_lock.o drm_memory.o drm_stub.o drm_vm.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 \
|
||||
drm_trace_points.o drm_global.o drm_prime.o \
|
||||
drm_rect.o
|
||||
drm_rect.o drm_vma_manager.o drm_flip_work.o
|
||||
|
||||
drm-$(CONFIG_COMPAT) += drm_ioc32.o
|
||||
drm-$(CONFIG_DRM_GEM_CMA_HELPER) += drm_gem_cma_helper.o
|
||||
@@ -54,4 +54,5 @@ obj-$(CONFIG_DRM_SHMOBILE) +=shmobile/
|
||||
obj-$(CONFIG_DRM_OMAP) += omapdrm/
|
||||
obj-$(CONFIG_DRM_TILCDC) += tilcdc/
|
||||
obj-$(CONFIG_DRM_QXL) += qxl/
|
||||
obj-$(CONFIG_DRM_MSM) += msm/
|
||||
obj-y += i2c/
|
||||
|
||||
@@ -190,7 +190,6 @@ static const struct file_operations ast_fops = {
|
||||
.unlocked_ioctl = drm_ioctl,
|
||||
.mmap = ast_mmap,
|
||||
.poll = drm_poll,
|
||||
.fasync = drm_fasync,
|
||||
#ifdef CONFIG_COMPAT
|
||||
.compat_ioctl = drm_compat_ioctl,
|
||||
#endif
|
||||
@@ -198,7 +197,7 @@ static const struct file_operations ast_fops = {
|
||||
};
|
||||
|
||||
static struct drm_driver driver = {
|
||||
.driver_features = DRIVER_USE_MTRR | DRIVER_MODESET | DRIVER_GEM,
|
||||
.driver_features = DRIVER_MODESET | DRIVER_GEM,
|
||||
.dev_priv_size = 0,
|
||||
|
||||
.load = ast_driver_load,
|
||||
@@ -216,7 +215,7 @@ static struct drm_driver driver = {
|
||||
.gem_free_object = ast_gem_free_object,
|
||||
.dumb_create = ast_dumb_create,
|
||||
.dumb_map_offset = ast_dumb_mmap_offset,
|
||||
.dumb_destroy = ast_dumb_destroy,
|
||||
.dumb_destroy = drm_gem_dumb_destroy,
|
||||
|
||||
};
|
||||
|
||||
|
||||
@@ -322,9 +322,6 @@ ast_bo(struct ttm_buffer_object *bo)
|
||||
extern int ast_dumb_create(struct drm_file *file,
|
||||
struct drm_device *dev,
|
||||
struct drm_mode_create_dumb *args);
|
||||
extern int ast_dumb_destroy(struct drm_file *file,
|
||||
struct drm_device *dev,
|
||||
uint32_t handle);
|
||||
|
||||
extern int ast_gem_init_object(struct drm_gem_object *obj);
|
||||
extern void ast_gem_free_object(struct drm_gem_object *obj);
|
||||
|
||||
@@ -449,13 +449,6 @@ int ast_dumb_create(struct drm_file *file,
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ast_dumb_destroy(struct drm_file *file,
|
||||
struct drm_device *dev,
|
||||
uint32_t handle)
|
||||
{
|
||||
return drm_gem_handle_delete(file, handle);
|
||||
}
|
||||
|
||||
int ast_gem_init_object(struct drm_gem_object *obj)
|
||||
{
|
||||
BUG();
|
||||
@@ -487,7 +480,7 @@ void ast_gem_free_object(struct drm_gem_object *obj)
|
||||
|
||||
static inline u64 ast_bo_mmap_offset(struct ast_bo *bo)
|
||||
{
|
||||
return bo->bo.addr_space_offset;
|
||||
return drm_vma_node_offset_addr(&bo->bo.vma_node);
|
||||
}
|
||||
int
|
||||
ast_dumb_mmap_offset(struct drm_file *file,
|
||||
|
||||
@@ -148,7 +148,9 @@ ast_bo_evict_flags(struct ttm_buffer_object *bo, struct ttm_placement *pl)
|
||||
|
||||
static int ast_bo_verify_access(struct ttm_buffer_object *bo, struct file *filp)
|
||||
{
|
||||
return 0;
|
||||
struct ast_bo *astbo = ast_bo(bo);
|
||||
|
||||
return drm_vma_node_verify_access(&astbo->gem.vma_node, filp);
|
||||
}
|
||||
|
||||
static int ast_ttm_io_mem_reserve(struct ttm_bo_device *bdev,
|
||||
@@ -321,7 +323,6 @@ int ast_bo_create(struct drm_device *dev, int size, int align,
|
||||
return ret;
|
||||
}
|
||||
|
||||
astbo->gem.driver_private = NULL;
|
||||
astbo->bo.bdev = &ast->ttm.bdev;
|
||||
astbo->bo.bdev->dev_mapping = dev->dev_mapping;
|
||||
|
||||
|
||||
@@ -85,10 +85,9 @@ static const struct file_operations cirrus_driver_fops = {
|
||||
#ifdef CONFIG_COMPAT
|
||||
.compat_ioctl = drm_compat_ioctl,
|
||||
#endif
|
||||
.fasync = drm_fasync,
|
||||
};
|
||||
static struct drm_driver driver = {
|
||||
.driver_features = DRIVER_MODESET | DRIVER_GEM | DRIVER_USE_MTRR,
|
||||
.driver_features = DRIVER_MODESET | DRIVER_GEM,
|
||||
.load = cirrus_driver_load,
|
||||
.unload = cirrus_driver_unload,
|
||||
.fops = &cirrus_driver_fops,
|
||||
@@ -102,7 +101,7 @@ static struct drm_driver driver = {
|
||||
.gem_free_object = cirrus_gem_free_object,
|
||||
.dumb_create = cirrus_dumb_create,
|
||||
.dumb_map_offset = cirrus_dumb_mmap_offset,
|
||||
.dumb_destroy = cirrus_dumb_destroy,
|
||||
.dumb_destroy = drm_gem_dumb_destroy,
|
||||
};
|
||||
|
||||
static struct pci_driver cirrus_pci_driver = {
|
||||
|
||||
@@ -203,9 +203,6 @@ int cirrus_gem_create(struct drm_device *dev,
|
||||
int cirrus_dumb_create(struct drm_file *file,
|
||||
struct drm_device *dev,
|
||||
struct drm_mode_create_dumb *args);
|
||||
int cirrus_dumb_destroy(struct drm_file *file,
|
||||
struct drm_device *dev,
|
||||
uint32_t handle);
|
||||
|
||||
int cirrus_framebuffer_init(struct drm_device *dev,
|
||||
struct cirrus_framebuffer *gfb,
|
||||
|
||||
@@ -255,13 +255,6 @@ int cirrus_dumb_create(struct drm_file *file,
|
||||
return 0;
|
||||
}
|
||||
|
||||
int cirrus_dumb_destroy(struct drm_file *file,
|
||||
struct drm_device *dev,
|
||||
uint32_t handle)
|
||||
{
|
||||
return drm_gem_handle_delete(file, handle);
|
||||
}
|
||||
|
||||
int cirrus_gem_init_object(struct drm_gem_object *obj)
|
||||
{
|
||||
BUG();
|
||||
@@ -294,7 +287,7 @@ void cirrus_gem_free_object(struct drm_gem_object *obj)
|
||||
|
||||
static inline u64 cirrus_bo_mmap_offset(struct cirrus_bo *bo)
|
||||
{
|
||||
return bo->bo.addr_space_offset;
|
||||
return drm_vma_node_offset_addr(&bo->bo.vma_node);
|
||||
}
|
||||
|
||||
int
|
||||
|
||||
@@ -148,7 +148,9 @@ cirrus_bo_evict_flags(struct ttm_buffer_object *bo, struct ttm_placement *pl)
|
||||
|
||||
static int cirrus_bo_verify_access(struct ttm_buffer_object *bo, struct file *filp)
|
||||
{
|
||||
return 0;
|
||||
struct cirrus_bo *cirrusbo = cirrus_bo(bo);
|
||||
|
||||
return drm_vma_node_verify_access(&cirrusbo->gem.vma_node, filp);
|
||||
}
|
||||
|
||||
static int cirrus_ttm_io_mem_reserve(struct ttm_bo_device *bdev,
|
||||
@@ -326,7 +328,6 @@ int cirrus_bo_create(struct drm_device *dev, int size, int align,
|
||||
return ret;
|
||||
}
|
||||
|
||||
cirrusbo->gem.driver_private = NULL;
|
||||
cirrusbo->bo.bdev = &cirrus->ttm.bdev;
|
||||
cirrusbo->bo.bdev->dev_mapping = dev->dev_mapping;
|
||||
|
||||
|
||||
@@ -423,6 +423,57 @@ struct drm_agp_head *drm_agp_init(struct drm_device *dev)
|
||||
return head;
|
||||
}
|
||||
|
||||
/**
|
||||
* drm_agp_clear - Clear AGP resource list
|
||||
* @dev: DRM device
|
||||
*
|
||||
* Iterate over all AGP resources and remove them. But keep the AGP head
|
||||
* intact so it can still be used. It is safe to call this if AGP is disabled or
|
||||
* was already removed.
|
||||
*
|
||||
* If DRIVER_MODESET is active, nothing is done to protect the modesetting
|
||||
* resources from getting destroyed. Drivers are responsible of cleaning them up
|
||||
* during device shutdown.
|
||||
*/
|
||||
void drm_agp_clear(struct drm_device *dev)
|
||||
{
|
||||
struct drm_agp_mem *entry, *tempe;
|
||||
|
||||
if (!drm_core_has_AGP(dev) || !dev->agp)
|
||||
return;
|
||||
if (drm_core_check_feature(dev, DRIVER_MODESET))
|
||||
return;
|
||||
|
||||
list_for_each_entry_safe(entry, tempe, &dev->agp->memory, head) {
|
||||
if (entry->bound)
|
||||
drm_unbind_agp(entry->memory);
|
||||
drm_free_agp(entry->memory, entry->pages);
|
||||
kfree(entry);
|
||||
}
|
||||
INIT_LIST_HEAD(&dev->agp->memory);
|
||||
|
||||
if (dev->agp->acquired)
|
||||
drm_agp_release(dev);
|
||||
|
||||
dev->agp->acquired = 0;
|
||||
dev->agp->enabled = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* drm_agp_destroy - Destroy AGP head
|
||||
* @dev: DRM device
|
||||
*
|
||||
* Destroy resources that were previously allocated via drm_agp_initp. Caller
|
||||
* must ensure to clean up all AGP resources before calling this. See
|
||||
* drm_agp_clear().
|
||||
*
|
||||
* Call this to destroy AGP heads allocated via drm_agp_init().
|
||||
*/
|
||||
void drm_agp_destroy(struct drm_agp_head *agp)
|
||||
{
|
||||
kfree(agp);
|
||||
}
|
||||
|
||||
/**
|
||||
* Binds a collection of pages into AGP memory at the given offset, returning
|
||||
* the AGP memory structure containing them.
|
||||
|
||||
+49
-191
@@ -207,12 +207,10 @@ static int drm_addmap_core(struct drm_device * dev, resource_size_t offset,
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (drm_core_has_MTRR(dev)) {
|
||||
if (map->type == _DRM_FRAME_BUFFER ||
|
||||
(map->flags & _DRM_WRITE_COMBINING)) {
|
||||
map->mtrr =
|
||||
arch_phys_wc_add(map->offset, map->size);
|
||||
}
|
||||
if (map->type == _DRM_FRAME_BUFFER ||
|
||||
(map->flags & _DRM_WRITE_COMBINING)) {
|
||||
map->mtrr =
|
||||
arch_phys_wc_add(map->offset, map->size);
|
||||
}
|
||||
if (map->type == _DRM_REGISTERS) {
|
||||
if (map->flags & _DRM_WRITE_COMBINING)
|
||||
@@ -243,7 +241,7 @@ static int drm_addmap_core(struct drm_device * dev, resource_size_t offset,
|
||||
}
|
||||
map->handle = vmalloc_user(map->size);
|
||||
DRM_DEBUG("%lu %d %p\n",
|
||||
map->size, drm_order(map->size), map->handle);
|
||||
map->size, order_base_2(map->size), map->handle);
|
||||
if (!map->handle) {
|
||||
kfree(map);
|
||||
return -ENOMEM;
|
||||
@@ -464,8 +462,7 @@ int drm_rmmap_locked(struct drm_device *dev, struct drm_local_map *map)
|
||||
iounmap(map->handle);
|
||||
/* FALLTHROUGH */
|
||||
case _DRM_FRAME_BUFFER:
|
||||
if (drm_core_has_MTRR(dev))
|
||||
arch_phys_wc_del(map->mtrr);
|
||||
arch_phys_wc_del(map->mtrr);
|
||||
break;
|
||||
case _DRM_SHM:
|
||||
vfree(map->handle);
|
||||
@@ -630,7 +627,7 @@ int drm_addbufs_agp(struct drm_device * dev, struct drm_buf_desc * request)
|
||||
return -EINVAL;
|
||||
|
||||
count = request->count;
|
||||
order = drm_order(request->size);
|
||||
order = order_base_2(request->size);
|
||||
size = 1 << order;
|
||||
|
||||
alignment = (request->flags & _DRM_PAGE_ALIGN)
|
||||
@@ -800,7 +797,7 @@ int drm_addbufs_pci(struct drm_device * dev, struct drm_buf_desc * request)
|
||||
return -EPERM;
|
||||
|
||||
count = request->count;
|
||||
order = drm_order(request->size);
|
||||
order = order_base_2(request->size);
|
||||
size = 1 << order;
|
||||
|
||||
DRM_DEBUG("count=%d, size=%d (%d), order=%d\n",
|
||||
@@ -1002,7 +999,7 @@ static int drm_addbufs_sg(struct drm_device * dev, struct drm_buf_desc * request
|
||||
return -EPERM;
|
||||
|
||||
count = request->count;
|
||||
order = drm_order(request->size);
|
||||
order = order_base_2(request->size);
|
||||
size = 1 << order;
|
||||
|
||||
alignment = (request->flags & _DRM_PAGE_ALIGN)
|
||||
@@ -1130,161 +1127,6 @@ static int drm_addbufs_sg(struct drm_device * dev, struct drm_buf_desc * request
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int drm_addbufs_fb(struct drm_device * dev, struct drm_buf_desc * request)
|
||||
{
|
||||
struct drm_device_dma *dma = dev->dma;
|
||||
struct drm_buf_entry *entry;
|
||||
struct drm_buf *buf;
|
||||
unsigned long offset;
|
||||
unsigned long agp_offset;
|
||||
int count;
|
||||
int order;
|
||||
int size;
|
||||
int alignment;
|
||||
int page_order;
|
||||
int total;
|
||||
int byte_count;
|
||||
int i;
|
||||
struct drm_buf **temp_buflist;
|
||||
|
||||
if (!drm_core_check_feature(dev, DRIVER_FB_DMA))
|
||||
return -EINVAL;
|
||||
|
||||
if (!dma)
|
||||
return -EINVAL;
|
||||
|
||||
if (!capable(CAP_SYS_ADMIN))
|
||||
return -EPERM;
|
||||
|
||||
count = request->count;
|
||||
order = drm_order(request->size);
|
||||
size = 1 << order;
|
||||
|
||||
alignment = (request->flags & _DRM_PAGE_ALIGN)
|
||||
? PAGE_ALIGN(size) : size;
|
||||
page_order = order - PAGE_SHIFT > 0 ? order - PAGE_SHIFT : 0;
|
||||
total = PAGE_SIZE << page_order;
|
||||
|
||||
byte_count = 0;
|
||||
agp_offset = request->agp_start;
|
||||
|
||||
DRM_DEBUG("count: %d\n", count);
|
||||
DRM_DEBUG("order: %d\n", order);
|
||||
DRM_DEBUG("size: %d\n", size);
|
||||
DRM_DEBUG("agp_offset: %lu\n", agp_offset);
|
||||
DRM_DEBUG("alignment: %d\n", alignment);
|
||||
DRM_DEBUG("page_order: %d\n", page_order);
|
||||
DRM_DEBUG("total: %d\n", total);
|
||||
|
||||
if (order < DRM_MIN_ORDER || order > DRM_MAX_ORDER)
|
||||
return -EINVAL;
|
||||
|
||||
spin_lock(&dev->count_lock);
|
||||
if (dev->buf_use) {
|
||||
spin_unlock(&dev->count_lock);
|
||||
return -EBUSY;
|
||||
}
|
||||
atomic_inc(&dev->buf_alloc);
|
||||
spin_unlock(&dev->count_lock);
|
||||
|
||||
mutex_lock(&dev->struct_mutex);
|
||||
entry = &dma->bufs[order];
|
||||
if (entry->buf_count) {
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
atomic_dec(&dev->buf_alloc);
|
||||
return -ENOMEM; /* May only call once for each order */
|
||||
}
|
||||
|
||||
if (count < 0 || count > 4096) {
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
atomic_dec(&dev->buf_alloc);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
entry->buflist = kzalloc(count * sizeof(*entry->buflist),
|
||||
GFP_KERNEL);
|
||||
if (!entry->buflist) {
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
atomic_dec(&dev->buf_alloc);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
entry->buf_size = size;
|
||||
entry->page_order = page_order;
|
||||
|
||||
offset = 0;
|
||||
|
||||
while (entry->buf_count < count) {
|
||||
buf = &entry->buflist[entry->buf_count];
|
||||
buf->idx = dma->buf_count + entry->buf_count;
|
||||
buf->total = alignment;
|
||||
buf->order = order;
|
||||
buf->used = 0;
|
||||
|
||||
buf->offset = (dma->byte_count + offset);
|
||||
buf->bus_address = agp_offset + offset;
|
||||
buf->address = (void *)(agp_offset + offset);
|
||||
buf->next = NULL;
|
||||
buf->waiting = 0;
|
||||
buf->pending = 0;
|
||||
buf->file_priv = NULL;
|
||||
|
||||
buf->dev_priv_size = dev->driver->dev_priv_size;
|
||||
buf->dev_private = kzalloc(buf->dev_priv_size, GFP_KERNEL);
|
||||
if (!buf->dev_private) {
|
||||
/* Set count correctly so we free the proper amount. */
|
||||
entry->buf_count = count;
|
||||
drm_cleanup_buf_error(dev, entry);
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
atomic_dec(&dev->buf_alloc);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
DRM_DEBUG("buffer %d @ %p\n", entry->buf_count, buf->address);
|
||||
|
||||
offset += alignment;
|
||||
entry->buf_count++;
|
||||
byte_count += PAGE_SIZE << page_order;
|
||||
}
|
||||
|
||||
DRM_DEBUG("byte_count: %d\n", byte_count);
|
||||
|
||||
temp_buflist = krealloc(dma->buflist,
|
||||
(dma->buf_count + entry->buf_count) *
|
||||
sizeof(*dma->buflist), GFP_KERNEL);
|
||||
if (!temp_buflist) {
|
||||
/* Free the entry because it isn't valid */
|
||||
drm_cleanup_buf_error(dev, entry);
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
atomic_dec(&dev->buf_alloc);
|
||||
return -ENOMEM;
|
||||
}
|
||||
dma->buflist = temp_buflist;
|
||||
|
||||
for (i = 0; i < entry->buf_count; i++) {
|
||||
dma->buflist[i + dma->buf_count] = &entry->buflist[i];
|
||||
}
|
||||
|
||||
dma->buf_count += entry->buf_count;
|
||||
dma->seg_count += entry->seg_count;
|
||||
dma->page_count += byte_count >> PAGE_SHIFT;
|
||||
dma->byte_count += byte_count;
|
||||
|
||||
DRM_DEBUG("dma->buf_count : %d\n", dma->buf_count);
|
||||
DRM_DEBUG("entry->buf_count : %d\n", entry->buf_count);
|
||||
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
|
||||
request->count = entry->buf_count;
|
||||
request->size = size;
|
||||
|
||||
dma->flags = _DRM_DMA_USE_FB;
|
||||
|
||||
atomic_dec(&dev->buf_alloc);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Add buffers for DMA transfers (ioctl).
|
||||
*
|
||||
@@ -1305,6 +1147,9 @@ int drm_addbufs(struct drm_device *dev, void *data,
|
||||
struct drm_buf_desc *request = data;
|
||||
int ret;
|
||||
|
||||
if (drm_core_check_feature(dev, DRIVER_MODESET))
|
||||
return -EINVAL;
|
||||
|
||||
if (!drm_core_check_feature(dev, DRIVER_HAVE_DMA))
|
||||
return -EINVAL;
|
||||
|
||||
@@ -1316,7 +1161,7 @@ int drm_addbufs(struct drm_device *dev, void *data,
|
||||
if (request->flags & _DRM_SG_BUFFER)
|
||||
ret = drm_addbufs_sg(dev, request);
|
||||
else if (request->flags & _DRM_FB_BUFFER)
|
||||
ret = drm_addbufs_fb(dev, request);
|
||||
ret = -EINVAL;
|
||||
else
|
||||
ret = drm_addbufs_pci(dev, request);
|
||||
|
||||
@@ -1348,6 +1193,9 @@ int drm_infobufs(struct drm_device *dev, void *data,
|
||||
int i;
|
||||
int count;
|
||||
|
||||
if (drm_core_check_feature(dev, DRIVER_MODESET))
|
||||
return -EINVAL;
|
||||
|
||||
if (!drm_core_check_feature(dev, DRIVER_HAVE_DMA))
|
||||
return -EINVAL;
|
||||
|
||||
@@ -1427,6 +1275,9 @@ int drm_markbufs(struct drm_device *dev, void *data,
|
||||
int order;
|
||||
struct drm_buf_entry *entry;
|
||||
|
||||
if (drm_core_check_feature(dev, DRIVER_MODESET))
|
||||
return -EINVAL;
|
||||
|
||||
if (!drm_core_check_feature(dev, DRIVER_HAVE_DMA))
|
||||
return -EINVAL;
|
||||
|
||||
@@ -1435,7 +1286,7 @@ int drm_markbufs(struct drm_device *dev, void *data,
|
||||
|
||||
DRM_DEBUG("%d, %d, %d\n",
|
||||
request->size, request->low_mark, request->high_mark);
|
||||
order = drm_order(request->size);
|
||||
order = order_base_2(request->size);
|
||||
if (order < DRM_MIN_ORDER || order > DRM_MAX_ORDER)
|
||||
return -EINVAL;
|
||||
entry = &dma->bufs[order];
|
||||
@@ -1472,6 +1323,9 @@ int drm_freebufs(struct drm_device *dev, void *data,
|
||||
int idx;
|
||||
struct drm_buf *buf;
|
||||
|
||||
if (drm_core_check_feature(dev, DRIVER_MODESET))
|
||||
return -EINVAL;
|
||||
|
||||
if (!drm_core_check_feature(dev, DRIVER_HAVE_DMA))
|
||||
return -EINVAL;
|
||||
|
||||
@@ -1524,6 +1378,9 @@ int drm_mapbufs(struct drm_device *dev, void *data,
|
||||
struct drm_buf_map *request = data;
|
||||
int i;
|
||||
|
||||
if (drm_core_check_feature(dev, DRIVER_MODESET))
|
||||
return -EINVAL;
|
||||
|
||||
if (!drm_core_check_feature(dev, DRIVER_HAVE_DMA))
|
||||
return -EINVAL;
|
||||
|
||||
@@ -1541,9 +1398,7 @@ int drm_mapbufs(struct drm_device *dev, void *data,
|
||||
if (request->count >= dma->buf_count) {
|
||||
if ((drm_core_has_AGP(dev) && (dma->flags & _DRM_DMA_USE_AGP))
|
||||
|| (drm_core_check_feature(dev, DRIVER_SG)
|
||||
&& (dma->flags & _DRM_DMA_USE_SG))
|
||||
|| (drm_core_check_feature(dev, DRIVER_FB_DMA)
|
||||
&& (dma->flags & _DRM_DMA_USE_FB))) {
|
||||
&& (dma->flags & _DRM_DMA_USE_SG))) {
|
||||
struct drm_local_map *map = dev->agp_buffer_map;
|
||||
unsigned long token = dev->agp_buffer_token;
|
||||
|
||||
@@ -1600,25 +1455,28 @@ int drm_mapbufs(struct drm_device *dev, void *data,
|
||||
return retcode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute size order. Returns the exponent of the smaller power of two which
|
||||
* is greater or equal to given number.
|
||||
*
|
||||
* \param size size.
|
||||
* \return order.
|
||||
*
|
||||
* \todo Can be made faster.
|
||||
*/
|
||||
int drm_order(unsigned long size)
|
||||
int drm_dma_ioctl(struct drm_device *dev, void *data,
|
||||
struct drm_file *file_priv)
|
||||
{
|
||||
int order;
|
||||
unsigned long tmp;
|
||||
if (drm_core_check_feature(dev, DRIVER_MODESET))
|
||||
return -EINVAL;
|
||||
|
||||
for (order = 0, tmp = size >> 1; tmp; tmp >>= 1, order++) ;
|
||||
|
||||
if (size & (size - 1))
|
||||
++order;
|
||||
|
||||
return order;
|
||||
if (dev->driver->dma_ioctl)
|
||||
return dev->driver->dma_ioctl(dev, data, file_priv);
|
||||
else
|
||||
return -EINVAL;
|
||||
}
|
||||
EXPORT_SYMBOL(drm_order);
|
||||
|
||||
struct drm_local_map *drm_getsarea(struct drm_device *dev)
|
||||
{
|
||||
struct drm_map_list *entry;
|
||||
|
||||
list_for_each_entry(entry, &dev->maplist, head) {
|
||||
if (entry->map && entry->map->type == _DRM_SHM &&
|
||||
(entry->map->flags & _DRM_CONTAINS_LOCK)) {
|
||||
return entry->map;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
EXPORT_SYMBOL(drm_getsarea);
|
||||
|
||||
@@ -42,10 +42,6 @@
|
||||
|
||||
#include <drm/drmP.h>
|
||||
|
||||
/******************************************************************/
|
||||
/** \name Context bitmap support */
|
||||
/*@{*/
|
||||
|
||||
/**
|
||||
* Free a handle from the context bitmap.
|
||||
*
|
||||
@@ -56,13 +52,48 @@
|
||||
* in drm_device::ctx_idr, while holding the drm_device::struct_mutex
|
||||
* lock.
|
||||
*/
|
||||
void drm_ctxbitmap_free(struct drm_device * dev, int ctx_handle)
|
||||
static void drm_ctxbitmap_free(struct drm_device * dev, int ctx_handle)
|
||||
{
|
||||
if (drm_core_check_feature(dev, DRIVER_MODESET))
|
||||
return;
|
||||
|
||||
mutex_lock(&dev->struct_mutex);
|
||||
idr_remove(&dev->ctx_idr, ctx_handle);
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
}
|
||||
|
||||
/******************************************************************/
|
||||
/** \name Context bitmap support */
|
||||
/*@{*/
|
||||
|
||||
void drm_legacy_ctxbitmap_release(struct drm_device *dev,
|
||||
struct drm_file *file_priv)
|
||||
{
|
||||
if (drm_core_check_feature(dev, DRIVER_MODESET))
|
||||
return;
|
||||
|
||||
mutex_lock(&dev->ctxlist_mutex);
|
||||
if (!list_empty(&dev->ctxlist)) {
|
||||
struct drm_ctx_list *pos, *n;
|
||||
|
||||
list_for_each_entry_safe(pos, n, &dev->ctxlist, head) {
|
||||
if (pos->tag == file_priv &&
|
||||
pos->handle != DRM_KERNEL_CONTEXT) {
|
||||
if (dev->driver->context_dtor)
|
||||
dev->driver->context_dtor(dev,
|
||||
pos->handle);
|
||||
|
||||
drm_ctxbitmap_free(dev, pos->handle);
|
||||
|
||||
list_del(&pos->head);
|
||||
kfree(pos);
|
||||
--dev->ctx_count;
|
||||
}
|
||||
}
|
||||
}
|
||||
mutex_unlock(&dev->ctxlist_mutex);
|
||||
}
|
||||
|
||||
/**
|
||||
* Context bitmap allocation.
|
||||
*
|
||||
@@ -90,10 +121,12 @@ static int drm_ctxbitmap_next(struct drm_device * dev)
|
||||
*
|
||||
* Initialise the drm_device::ctx_idr
|
||||
*/
|
||||
int drm_ctxbitmap_init(struct drm_device * dev)
|
||||
void drm_legacy_ctxbitmap_init(struct drm_device * dev)
|
||||
{
|
||||
if (drm_core_check_feature(dev, DRIVER_MODESET))
|
||||
return;
|
||||
|
||||
idr_init(&dev->ctx_idr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -104,7 +137,7 @@ int drm_ctxbitmap_init(struct drm_device * dev)
|
||||
* Free all idr members using drm_ctx_sarea_free helper function
|
||||
* while holding the drm_device::struct_mutex lock.
|
||||
*/
|
||||
void drm_ctxbitmap_cleanup(struct drm_device * dev)
|
||||
void drm_legacy_ctxbitmap_cleanup(struct drm_device * dev)
|
||||
{
|
||||
mutex_lock(&dev->struct_mutex);
|
||||
idr_destroy(&dev->ctx_idr);
|
||||
@@ -136,6 +169,9 @@ int drm_getsareactx(struct drm_device *dev, void *data,
|
||||
struct drm_local_map *map;
|
||||
struct drm_map_list *_entry;
|
||||
|
||||
if (drm_core_check_feature(dev, DRIVER_MODESET))
|
||||
return -EINVAL;
|
||||
|
||||
mutex_lock(&dev->struct_mutex);
|
||||
|
||||
map = idr_find(&dev->ctx_idr, request->ctx_id);
|
||||
@@ -180,6 +216,9 @@ int drm_setsareactx(struct drm_device *dev, void *data,
|
||||
struct drm_local_map *map = NULL;
|
||||
struct drm_map_list *r_list = NULL;
|
||||
|
||||
if (drm_core_check_feature(dev, DRIVER_MODESET))
|
||||
return -EINVAL;
|
||||
|
||||
mutex_lock(&dev->struct_mutex);
|
||||
list_for_each_entry(r_list, &dev->maplist, head) {
|
||||
if (r_list->map
|
||||
@@ -251,7 +290,6 @@ static int drm_context_switch_complete(struct drm_device *dev,
|
||||
struct drm_file *file_priv, int new)
|
||||
{
|
||||
dev->last_context = new; /* PRE/POST: This is the _only_ writer. */
|
||||
dev->last_switch = jiffies;
|
||||
|
||||
if (!_DRM_LOCK_IS_HELD(file_priv->master->lock.hw_lock->lock)) {
|
||||
DRM_ERROR("Lock isn't held after context switch\n");
|
||||
@@ -261,7 +299,6 @@ static int drm_context_switch_complete(struct drm_device *dev,
|
||||
when the kernel holds the lock, release
|
||||
that lock here. */
|
||||
clear_bit(0, &dev->context_flag);
|
||||
wake_up(&dev->context_wait);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -282,6 +319,9 @@ int drm_resctx(struct drm_device *dev, void *data,
|
||||
struct drm_ctx ctx;
|
||||
int i;
|
||||
|
||||
if (drm_core_check_feature(dev, DRIVER_MODESET))
|
||||
return -EINVAL;
|
||||
|
||||
if (res->count >= DRM_RESERVED_CONTEXTS) {
|
||||
memset(&ctx, 0, sizeof(ctx));
|
||||
for (i = 0; i < DRM_RESERVED_CONTEXTS; i++) {
|
||||
@@ -312,6 +352,9 @@ int drm_addctx(struct drm_device *dev, void *data,
|
||||
struct drm_ctx_list *ctx_entry;
|
||||
struct drm_ctx *ctx = data;
|
||||
|
||||
if (drm_core_check_feature(dev, DRIVER_MODESET))
|
||||
return -EINVAL;
|
||||
|
||||
ctx->handle = drm_ctxbitmap_next(dev);
|
||||
if (ctx->handle == DRM_KERNEL_CONTEXT) {
|
||||
/* Skip kernel's context and get a new one. */
|
||||
@@ -342,12 +385,6 @@ int drm_addctx(struct drm_device *dev, void *data,
|
||||
return 0;
|
||||
}
|
||||
|
||||
int drm_modctx(struct drm_device *dev, void *data, struct drm_file *file_priv)
|
||||
{
|
||||
/* This does nothing */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get context.
|
||||
*
|
||||
@@ -361,6 +398,9 @@ int drm_getctx(struct drm_device *dev, void *data, struct drm_file *file_priv)
|
||||
{
|
||||
struct drm_ctx *ctx = data;
|
||||
|
||||
if (drm_core_check_feature(dev, DRIVER_MODESET))
|
||||
return -EINVAL;
|
||||
|
||||
/* This is 0, because we don't handle any context flags */
|
||||
ctx->flags = 0;
|
||||
|
||||
@@ -383,6 +423,9 @@ int drm_switchctx(struct drm_device *dev, void *data,
|
||||
{
|
||||
struct drm_ctx *ctx = data;
|
||||
|
||||
if (drm_core_check_feature(dev, DRIVER_MODESET))
|
||||
return -EINVAL;
|
||||
|
||||
DRM_DEBUG("%d\n", ctx->handle);
|
||||
return drm_context_switch(dev, dev->last_context, ctx->handle);
|
||||
}
|
||||
@@ -403,6 +446,9 @@ int drm_newctx(struct drm_device *dev, void *data,
|
||||
{
|
||||
struct drm_ctx *ctx = data;
|
||||
|
||||
if (drm_core_check_feature(dev, DRIVER_MODESET))
|
||||
return -EINVAL;
|
||||
|
||||
DRM_DEBUG("%d\n", ctx->handle);
|
||||
drm_context_switch_complete(dev, file_priv, ctx->handle);
|
||||
|
||||
@@ -425,6 +471,9 @@ int drm_rmctx(struct drm_device *dev, void *data,
|
||||
{
|
||||
struct drm_ctx *ctx = data;
|
||||
|
||||
if (drm_core_check_feature(dev, DRIVER_MODESET))
|
||||
return -EINVAL;
|
||||
|
||||
DRM_DEBUG("%d\n", ctx->handle);
|
||||
if (ctx->handle != DRM_KERNEL_CONTEXT) {
|
||||
if (dev->driver->context_dtor)
|
||||
|
||||
+116
-57
@@ -125,13 +125,6 @@ static const struct drm_prop_enum_list drm_scaling_mode_enum_list[] =
|
||||
{ DRM_MODE_SCALE_ASPECT, "Full aspect" },
|
||||
};
|
||||
|
||||
static const struct drm_prop_enum_list drm_dithering_mode_enum_list[] =
|
||||
{
|
||||
{ DRM_MODE_DITHERING_OFF, "Off" },
|
||||
{ DRM_MODE_DITHERING_ON, "On" },
|
||||
{ DRM_MODE_DITHERING_AUTO, "Automatic" },
|
||||
};
|
||||
|
||||
/*
|
||||
* Non-global properties, but "required" for certain connectors.
|
||||
*/
|
||||
@@ -186,29 +179,29 @@ static const struct drm_prop_enum_list drm_dirty_info_enum_list[] = {
|
||||
struct drm_conn_prop_enum_list {
|
||||
int type;
|
||||
const char *name;
|
||||
int count;
|
||||
struct ida ida;
|
||||
};
|
||||
|
||||
/*
|
||||
* Connector and encoder types.
|
||||
*/
|
||||
static struct drm_conn_prop_enum_list drm_connector_enum_list[] =
|
||||
{ { DRM_MODE_CONNECTOR_Unknown, "Unknown", 0 },
|
||||
{ DRM_MODE_CONNECTOR_VGA, "VGA", 0 },
|
||||
{ DRM_MODE_CONNECTOR_DVII, "DVI-I", 0 },
|
||||
{ DRM_MODE_CONNECTOR_DVID, "DVI-D", 0 },
|
||||
{ DRM_MODE_CONNECTOR_DVIA, "DVI-A", 0 },
|
||||
{ DRM_MODE_CONNECTOR_Composite, "Composite", 0 },
|
||||
{ DRM_MODE_CONNECTOR_SVIDEO, "SVIDEO", 0 },
|
||||
{ DRM_MODE_CONNECTOR_LVDS, "LVDS", 0 },
|
||||
{ DRM_MODE_CONNECTOR_Component, "Component", 0 },
|
||||
{ DRM_MODE_CONNECTOR_9PinDIN, "DIN", 0 },
|
||||
{ DRM_MODE_CONNECTOR_DisplayPort, "DP", 0 },
|
||||
{ DRM_MODE_CONNECTOR_HDMIA, "HDMI-A", 0 },
|
||||
{ DRM_MODE_CONNECTOR_HDMIB, "HDMI-B", 0 },
|
||||
{ DRM_MODE_CONNECTOR_TV, "TV", 0 },
|
||||
{ DRM_MODE_CONNECTOR_eDP, "eDP", 0 },
|
||||
{ DRM_MODE_CONNECTOR_VIRTUAL, "Virtual", 0},
|
||||
{ { DRM_MODE_CONNECTOR_Unknown, "Unknown" },
|
||||
{ DRM_MODE_CONNECTOR_VGA, "VGA" },
|
||||
{ DRM_MODE_CONNECTOR_DVII, "DVI-I" },
|
||||
{ DRM_MODE_CONNECTOR_DVID, "DVI-D" },
|
||||
{ DRM_MODE_CONNECTOR_DVIA, "DVI-A" },
|
||||
{ DRM_MODE_CONNECTOR_Composite, "Composite" },
|
||||
{ DRM_MODE_CONNECTOR_SVIDEO, "SVIDEO" },
|
||||
{ DRM_MODE_CONNECTOR_LVDS, "LVDS" },
|
||||
{ DRM_MODE_CONNECTOR_Component, "Component" },
|
||||
{ DRM_MODE_CONNECTOR_9PinDIN, "DIN" },
|
||||
{ DRM_MODE_CONNECTOR_DisplayPort, "DP" },
|
||||
{ DRM_MODE_CONNECTOR_HDMIA, "HDMI-A" },
|
||||
{ DRM_MODE_CONNECTOR_HDMIB, "HDMI-B" },
|
||||
{ DRM_MODE_CONNECTOR_TV, "TV" },
|
||||
{ DRM_MODE_CONNECTOR_eDP, "eDP" },
|
||||
{ DRM_MODE_CONNECTOR_VIRTUAL, "Virtual" },
|
||||
};
|
||||
|
||||
static const struct drm_prop_enum_list drm_encoder_enum_list[] =
|
||||
@@ -220,6 +213,22 @@ static const struct drm_prop_enum_list drm_encoder_enum_list[] =
|
||||
{ DRM_MODE_ENCODER_VIRTUAL, "Virtual" },
|
||||
};
|
||||
|
||||
void drm_connector_ida_init(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(drm_connector_enum_list); i++)
|
||||
ida_init(&drm_connector_enum_list[i].ida);
|
||||
}
|
||||
|
||||
void drm_connector_ida_destroy(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(drm_connector_enum_list); i++)
|
||||
ida_destroy(&drm_connector_enum_list[i].ida);
|
||||
}
|
||||
|
||||
const char *drm_get_encoder_name(const struct drm_encoder *encoder)
|
||||
{
|
||||
static char buf[32];
|
||||
@@ -677,20 +686,19 @@ void drm_mode_probed_add(struct drm_connector *connector,
|
||||
}
|
||||
EXPORT_SYMBOL(drm_mode_probed_add);
|
||||
|
||||
/**
|
||||
/*
|
||||
* drm_mode_remove - remove and free a mode
|
||||
* @connector: connector list to modify
|
||||
* @mode: mode to remove
|
||||
*
|
||||
* Remove @mode from @connector's mode list, then free it.
|
||||
*/
|
||||
void drm_mode_remove(struct drm_connector *connector,
|
||||
struct drm_display_mode *mode)
|
||||
static void drm_mode_remove(struct drm_connector *connector,
|
||||
struct drm_display_mode *mode)
|
||||
{
|
||||
list_del(&mode->head);
|
||||
drm_mode_destroy(connector->dev, mode);
|
||||
}
|
||||
EXPORT_SYMBOL(drm_mode_remove);
|
||||
|
||||
/**
|
||||
* drm_connector_init - Init a preallocated connector
|
||||
@@ -711,6 +719,8 @@ int drm_connector_init(struct drm_device *dev,
|
||||
int connector_type)
|
||||
{
|
||||
int ret;
|
||||
struct ida *connector_ida =
|
||||
&drm_connector_enum_list[connector_type].ida;
|
||||
|
||||
drm_modeset_lock_all(dev);
|
||||
|
||||
@@ -723,7 +733,12 @@ int drm_connector_init(struct drm_device *dev,
|
||||
connector->funcs = funcs;
|
||||
connector->connector_type = connector_type;
|
||||
connector->connector_type_id =
|
||||
++drm_connector_enum_list[connector_type].count; /* TODO */
|
||||
ida_simple_get(connector_ida, 1, 0, GFP_KERNEL);
|
||||
if (connector->connector_type_id < 0) {
|
||||
ret = connector->connector_type_id;
|
||||
drm_mode_object_put(dev, &connector->base);
|
||||
goto out;
|
||||
}
|
||||
INIT_LIST_HEAD(&connector->probed_modes);
|
||||
INIT_LIST_HEAD(&connector->modes);
|
||||
connector->edid_blob_ptr = NULL;
|
||||
@@ -764,6 +779,9 @@ void drm_connector_cleanup(struct drm_connector *connector)
|
||||
list_for_each_entry_safe(mode, t, &connector->modes, head)
|
||||
drm_mode_remove(connector, mode);
|
||||
|
||||
ida_remove(&drm_connector_enum_list[connector->connector_type].ida,
|
||||
connector->connector_type_id);
|
||||
|
||||
drm_mode_object_put(dev, &connector->base);
|
||||
list_del(&connector->head);
|
||||
dev->mode_config.num_connector--;
|
||||
@@ -781,6 +799,41 @@ void drm_connector_unplug_all(struct drm_device *dev)
|
||||
}
|
||||
EXPORT_SYMBOL(drm_connector_unplug_all);
|
||||
|
||||
int drm_bridge_init(struct drm_device *dev, struct drm_bridge *bridge,
|
||||
const struct drm_bridge_funcs *funcs)
|
||||
{
|
||||
int ret;
|
||||
|
||||
drm_modeset_lock_all(dev);
|
||||
|
||||
ret = drm_mode_object_get(dev, &bridge->base, DRM_MODE_OBJECT_BRIDGE);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
bridge->dev = dev;
|
||||
bridge->funcs = funcs;
|
||||
|
||||
list_add_tail(&bridge->head, &dev->mode_config.bridge_list);
|
||||
dev->mode_config.num_bridge++;
|
||||
|
||||
out:
|
||||
drm_modeset_unlock_all(dev);
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(drm_bridge_init);
|
||||
|
||||
void drm_bridge_cleanup(struct drm_bridge *bridge)
|
||||
{
|
||||
struct drm_device *dev = bridge->dev;
|
||||
|
||||
drm_modeset_lock_all(dev);
|
||||
drm_mode_object_put(dev, &bridge->base);
|
||||
list_del(&bridge->head);
|
||||
dev->mode_config.num_bridge--;
|
||||
drm_modeset_unlock_all(dev);
|
||||
}
|
||||
EXPORT_SYMBOL(drm_bridge_cleanup);
|
||||
|
||||
int drm_encoder_init(struct drm_device *dev,
|
||||
struct drm_encoder *encoder,
|
||||
const struct drm_encoder_funcs *funcs,
|
||||
@@ -1134,30 +1187,6 @@ int drm_mode_create_scaling_mode_property(struct drm_device *dev)
|
||||
}
|
||||
EXPORT_SYMBOL(drm_mode_create_scaling_mode_property);
|
||||
|
||||
/**
|
||||
* drm_mode_create_dithering_property - create dithering property
|
||||
* @dev: DRM device
|
||||
*
|
||||
* Called by a driver the first time it's needed, must be attached to desired
|
||||
* connectors.
|
||||
*/
|
||||
int drm_mode_create_dithering_property(struct drm_device *dev)
|
||||
{
|
||||
struct drm_property *dithering_mode;
|
||||
|
||||
if (dev->mode_config.dithering_mode_property)
|
||||
return 0;
|
||||
|
||||
dithering_mode =
|
||||
drm_property_create_enum(dev, 0, "dithering",
|
||||
drm_dithering_mode_enum_list,
|
||||
ARRAY_SIZE(drm_dithering_mode_enum_list));
|
||||
dev->mode_config.dithering_mode_property = dithering_mode;
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(drm_mode_create_dithering_property);
|
||||
|
||||
/**
|
||||
* drm_mode_create_dirty_property - create dirty property
|
||||
* @dev: DRM device
|
||||
@@ -1190,6 +1219,7 @@ static int drm_mode_group_init(struct drm_device *dev, struct drm_mode_group *gr
|
||||
total_objects += dev->mode_config.num_crtc;
|
||||
total_objects += dev->mode_config.num_connector;
|
||||
total_objects += dev->mode_config.num_encoder;
|
||||
total_objects += dev->mode_config.num_bridge;
|
||||
|
||||
group->id_list = kzalloc(total_objects * sizeof(uint32_t), GFP_KERNEL);
|
||||
if (!group->id_list)
|
||||
@@ -1198,6 +1228,7 @@ static int drm_mode_group_init(struct drm_device *dev, struct drm_mode_group *gr
|
||||
group->num_crtcs = 0;
|
||||
group->num_connectors = 0;
|
||||
group->num_encoders = 0;
|
||||
group->num_bridges = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1207,6 +1238,7 @@ int drm_mode_group_init_legacy_group(struct drm_device *dev,
|
||||
struct drm_crtc *crtc;
|
||||
struct drm_encoder *encoder;
|
||||
struct drm_connector *connector;
|
||||
struct drm_bridge *bridge;
|
||||
int ret;
|
||||
|
||||
if ((ret = drm_mode_group_init(dev, group)))
|
||||
@@ -1223,6 +1255,11 @@ int drm_mode_group_init_legacy_group(struct drm_device *dev,
|
||||
group->id_list[group->num_crtcs + group->num_encoders +
|
||||
group->num_connectors++] = connector->base.id;
|
||||
|
||||
list_for_each_entry(bridge, &dev->mode_config.bridge_list, head)
|
||||
group->id_list[group->num_crtcs + group->num_encoders +
|
||||
group->num_connectors + group->num_bridges++] =
|
||||
bridge->base.id;
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(drm_mode_group_init_legacy_group);
|
||||
@@ -2604,10 +2641,22 @@ int drm_mode_getfb(struct drm_device *dev,
|
||||
r->depth = fb->depth;
|
||||
r->bpp = fb->bits_per_pixel;
|
||||
r->pitch = fb->pitches[0];
|
||||
if (fb->funcs->create_handle)
|
||||
ret = fb->funcs->create_handle(fb, file_priv, &r->handle);
|
||||
else
|
||||
if (fb->funcs->create_handle) {
|
||||
if (file_priv->is_master || capable(CAP_SYS_ADMIN)) {
|
||||
ret = fb->funcs->create_handle(fb, file_priv,
|
||||
&r->handle);
|
||||
} else {
|
||||
/* GET_FB() is an unprivileged ioctl so we must not
|
||||
* return a buffer-handle to non-master processes! For
|
||||
* backwards-compatibility reasons, we cannot make
|
||||
* GET_FB() privileged, so just return an invalid handle
|
||||
* for non-masters. */
|
||||
r->handle = 0;
|
||||
ret = 0;
|
||||
}
|
||||
} else {
|
||||
ret = -ENODEV;
|
||||
}
|
||||
|
||||
drm_framebuffer_unreference(fb);
|
||||
|
||||
@@ -3514,6 +3563,9 @@ int drm_mode_page_flip_ioctl(struct drm_device *dev,
|
||||
page_flip->reserved != 0)
|
||||
return -EINVAL;
|
||||
|
||||
if ((page_flip->flags & DRM_MODE_PAGE_FLIP_ASYNC) && !dev->mode_config.async_page_flip)
|
||||
return -EINVAL;
|
||||
|
||||
obj = drm_mode_object_find(dev, page_flip->crtc_id, DRM_MODE_OBJECT_CRTC);
|
||||
if (!obj)
|
||||
return -EINVAL;
|
||||
@@ -3587,7 +3639,7 @@ int drm_mode_page_flip_ioctl(struct drm_device *dev,
|
||||
}
|
||||
|
||||
old_fb = crtc->fb;
|
||||
ret = crtc->funcs->page_flip(crtc, fb, e);
|
||||
ret = crtc->funcs->page_flip(crtc, fb, e, page_flip->flags);
|
||||
if (ret) {
|
||||
if (page_flip->flags & DRM_MODE_PAGE_FLIP_EVENT) {
|
||||
spin_lock_irqsave(&dev->event_lock, flags);
|
||||
@@ -3905,6 +3957,7 @@ void drm_mode_config_init(struct drm_device *dev)
|
||||
INIT_LIST_HEAD(&dev->mode_config.fb_list);
|
||||
INIT_LIST_HEAD(&dev->mode_config.crtc_list);
|
||||
INIT_LIST_HEAD(&dev->mode_config.connector_list);
|
||||
INIT_LIST_HEAD(&dev->mode_config.bridge_list);
|
||||
INIT_LIST_HEAD(&dev->mode_config.encoder_list);
|
||||
INIT_LIST_HEAD(&dev->mode_config.property_list);
|
||||
INIT_LIST_HEAD(&dev->mode_config.property_blob_list);
|
||||
@@ -3941,6 +3994,7 @@ void drm_mode_config_cleanup(struct drm_device *dev)
|
||||
struct drm_connector *connector, *ot;
|
||||
struct drm_crtc *crtc, *ct;
|
||||
struct drm_encoder *encoder, *enct;
|
||||
struct drm_bridge *bridge, *brt;
|
||||
struct drm_framebuffer *fb, *fbt;
|
||||
struct drm_property *property, *pt;
|
||||
struct drm_property_blob *blob, *bt;
|
||||
@@ -3951,6 +4005,11 @@ void drm_mode_config_cleanup(struct drm_device *dev)
|
||||
encoder->funcs->destroy(encoder);
|
||||
}
|
||||
|
||||
list_for_each_entry_safe(bridge, brt,
|
||||
&dev->mode_config.bridge_list, head) {
|
||||
bridge->funcs->destroy(bridge);
|
||||
}
|
||||
|
||||
list_for_each_entry_safe(connector, ot,
|
||||
&dev->mode_config.connector_list, head) {
|
||||
connector->funcs->destroy(connector);
|
||||
|
||||
@@ -257,10 +257,16 @@ drm_encoder_disable(struct drm_encoder *encoder)
|
||||
{
|
||||
struct drm_encoder_helper_funcs *encoder_funcs = encoder->helper_private;
|
||||
|
||||
if (encoder->bridge)
|
||||
encoder->bridge->funcs->disable(encoder->bridge);
|
||||
|
||||
if (encoder_funcs->disable)
|
||||
(*encoder_funcs->disable)(encoder);
|
||||
else
|
||||
(*encoder_funcs->dpms)(encoder, DRM_MODE_DPMS_OFF);
|
||||
|
||||
if (encoder->bridge)
|
||||
encoder->bridge->funcs->post_disable(encoder->bridge);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -424,6 +430,16 @@ bool drm_crtc_helper_set_mode(struct drm_crtc *crtc,
|
||||
|
||||
if (encoder->crtc != crtc)
|
||||
continue;
|
||||
|
||||
if (encoder->bridge && encoder->bridge->funcs->mode_fixup) {
|
||||
ret = encoder->bridge->funcs->mode_fixup(
|
||||
encoder->bridge, mode, adjusted_mode);
|
||||
if (!ret) {
|
||||
DRM_DEBUG_KMS("Bridge fixup failed\n");
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
|
||||
encoder_funcs = encoder->helper_private;
|
||||
if (!(ret = encoder_funcs->mode_fixup(encoder, mode,
|
||||
adjusted_mode))) {
|
||||
@@ -443,9 +459,16 @@ bool drm_crtc_helper_set_mode(struct drm_crtc *crtc,
|
||||
|
||||
if (encoder->crtc != crtc)
|
||||
continue;
|
||||
|
||||
if (encoder->bridge)
|
||||
encoder->bridge->funcs->disable(encoder->bridge);
|
||||
|
||||
encoder_funcs = encoder->helper_private;
|
||||
/* Disable the encoders as the first thing we do. */
|
||||
encoder_funcs->prepare(encoder);
|
||||
|
||||
if (encoder->bridge)
|
||||
encoder->bridge->funcs->post_disable(encoder->bridge);
|
||||
}
|
||||
|
||||
drm_crtc_prepare_encoders(dev);
|
||||
@@ -469,6 +492,10 @@ bool drm_crtc_helper_set_mode(struct drm_crtc *crtc,
|
||||
mode->base.id, mode->name);
|
||||
encoder_funcs = encoder->helper_private;
|
||||
encoder_funcs->mode_set(encoder, mode, adjusted_mode);
|
||||
|
||||
if (encoder->bridge && encoder->bridge->funcs->mode_set)
|
||||
encoder->bridge->funcs->mode_set(encoder->bridge, mode,
|
||||
adjusted_mode);
|
||||
}
|
||||
|
||||
/* Now enable the clocks, plane, pipe, and connectors that we set up. */
|
||||
@@ -479,9 +506,14 @@ bool drm_crtc_helper_set_mode(struct drm_crtc *crtc,
|
||||
if (encoder->crtc != crtc)
|
||||
continue;
|
||||
|
||||
if (encoder->bridge)
|
||||
encoder->bridge->funcs->pre_enable(encoder->bridge);
|
||||
|
||||
encoder_funcs = encoder->helper_private;
|
||||
encoder_funcs->commit(encoder);
|
||||
|
||||
if (encoder->bridge)
|
||||
encoder->bridge->funcs->enable(encoder->bridge);
|
||||
}
|
||||
|
||||
/* Store real post-adjustment hardware mode. */
|
||||
@@ -830,6 +862,31 @@ static int drm_helper_choose_encoder_dpms(struct drm_encoder *encoder)
|
||||
return dpms;
|
||||
}
|
||||
|
||||
/* Helper which handles bridge ordering around encoder dpms */
|
||||
static void drm_helper_encoder_dpms(struct drm_encoder *encoder, int mode)
|
||||
{
|
||||
struct drm_bridge *bridge = encoder->bridge;
|
||||
struct drm_encoder_helper_funcs *encoder_funcs;
|
||||
|
||||
if (bridge) {
|
||||
if (mode == DRM_MODE_DPMS_ON)
|
||||
bridge->funcs->pre_enable(bridge);
|
||||
else
|
||||
bridge->funcs->disable(bridge);
|
||||
}
|
||||
|
||||
encoder_funcs = encoder->helper_private;
|
||||
if (encoder_funcs->dpms)
|
||||
encoder_funcs->dpms(encoder, mode);
|
||||
|
||||
if (bridge) {
|
||||
if (mode == DRM_MODE_DPMS_ON)
|
||||
bridge->funcs->enable(bridge);
|
||||
else
|
||||
bridge->funcs->post_disable(bridge);
|
||||
}
|
||||
}
|
||||
|
||||
static int drm_helper_choose_crtc_dpms(struct drm_crtc *crtc)
|
||||
{
|
||||
int dpms = DRM_MODE_DPMS_OFF;
|
||||
@@ -857,7 +914,7 @@ void drm_helper_connector_dpms(struct drm_connector *connector, int mode)
|
||||
{
|
||||
struct drm_encoder *encoder = connector->encoder;
|
||||
struct drm_crtc *crtc = encoder ? encoder->crtc : NULL;
|
||||
int old_dpms;
|
||||
int old_dpms, encoder_dpms = DRM_MODE_DPMS_OFF;
|
||||
|
||||
if (mode == connector->dpms)
|
||||
return;
|
||||
@@ -865,6 +922,9 @@ void drm_helper_connector_dpms(struct drm_connector *connector, int mode)
|
||||
old_dpms = connector->dpms;
|
||||
connector->dpms = mode;
|
||||
|
||||
if (encoder)
|
||||
encoder_dpms = drm_helper_choose_encoder_dpms(encoder);
|
||||
|
||||
/* from off to on, do crtc then encoder */
|
||||
if (mode < old_dpms) {
|
||||
if (crtc) {
|
||||
@@ -873,22 +933,14 @@ void drm_helper_connector_dpms(struct drm_connector *connector, int mode)
|
||||
(*crtc_funcs->dpms) (crtc,
|
||||
drm_helper_choose_crtc_dpms(crtc));
|
||||
}
|
||||
if (encoder) {
|
||||
struct drm_encoder_helper_funcs *encoder_funcs = encoder->helper_private;
|
||||
if (encoder_funcs->dpms)
|
||||
(*encoder_funcs->dpms) (encoder,
|
||||
drm_helper_choose_encoder_dpms(encoder));
|
||||
}
|
||||
if (encoder)
|
||||
drm_helper_encoder_dpms(encoder, encoder_dpms);
|
||||
}
|
||||
|
||||
/* from on to off, do encoder then crtc */
|
||||
if (mode > old_dpms) {
|
||||
if (encoder) {
|
||||
struct drm_encoder_helper_funcs *encoder_funcs = encoder->helper_private;
|
||||
if (encoder_funcs->dpms)
|
||||
(*encoder_funcs->dpms) (encoder,
|
||||
drm_helper_choose_encoder_dpms(encoder));
|
||||
}
|
||||
if (encoder)
|
||||
drm_helper_encoder_dpms(encoder, encoder_dpms);
|
||||
if (crtc) {
|
||||
struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private;
|
||||
if (crtc_funcs->dpms)
|
||||
@@ -924,9 +976,8 @@ int drm_helper_resume_force_mode(struct drm_device *dev)
|
||||
{
|
||||
struct drm_crtc *crtc;
|
||||
struct drm_encoder *encoder;
|
||||
struct drm_encoder_helper_funcs *encoder_funcs;
|
||||
struct drm_crtc_helper_funcs *crtc_funcs;
|
||||
int ret;
|
||||
int ret, encoder_dpms;
|
||||
|
||||
list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
|
||||
|
||||
@@ -946,10 +997,10 @@ int drm_helper_resume_force_mode(struct drm_device *dev)
|
||||
if(encoder->crtc != crtc)
|
||||
continue;
|
||||
|
||||
encoder_funcs = encoder->helper_private;
|
||||
if (encoder_funcs->dpms)
|
||||
(*encoder_funcs->dpms) (encoder,
|
||||
drm_helper_choose_encoder_dpms(encoder));
|
||||
encoder_dpms = drm_helper_choose_encoder_dpms(
|
||||
encoder);
|
||||
|
||||
drm_helper_encoder_dpms(encoder, encoder_dpms);
|
||||
}
|
||||
|
||||
crtc_funcs = crtc->helper_private;
|
||||
|
||||
@@ -44,10 +44,18 @@
|
||||
*
|
||||
* Allocate and initialize a drm_device_dma structure.
|
||||
*/
|
||||
int drm_dma_setup(struct drm_device *dev)
|
||||
int drm_legacy_dma_setup(struct drm_device *dev)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (!drm_core_check_feature(dev, DRIVER_HAVE_DMA) ||
|
||||
drm_core_check_feature(dev, DRIVER_MODESET)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
dev->buf_use = 0;
|
||||
atomic_set(&dev->buf_alloc, 0);
|
||||
|
||||
dev->dma = kzalloc(sizeof(*dev->dma), GFP_KERNEL);
|
||||
if (!dev->dma)
|
||||
return -ENOMEM;
|
||||
@@ -66,11 +74,16 @@ int drm_dma_setup(struct drm_device *dev)
|
||||
* Free all pages associated with DMA buffers, the buffers and pages lists, and
|
||||
* finally the drm_device::dma structure itself.
|
||||
*/
|
||||
void drm_dma_takedown(struct drm_device *dev)
|
||||
void drm_legacy_dma_takedown(struct drm_device *dev)
|
||||
{
|
||||
struct drm_device_dma *dma = dev->dma;
|
||||
int i, j;
|
||||
|
||||
if (!drm_core_check_feature(dev, DRIVER_HAVE_DMA) ||
|
||||
drm_core_check_feature(dev, DRIVER_MODESET)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!dma)
|
||||
return;
|
||||
|
||||
|
||||
+42
-64
@@ -68,7 +68,7 @@ static const struct drm_ioctl_desc drm_ioctls[] = {
|
||||
DRM_IOCTL_DEF(DRM_IOCTL_GET_MAP, drm_getmap, DRM_UNLOCKED),
|
||||
DRM_IOCTL_DEF(DRM_IOCTL_GET_CLIENT, drm_getclient, DRM_UNLOCKED),
|
||||
DRM_IOCTL_DEF(DRM_IOCTL_GET_STATS, drm_getstats, DRM_UNLOCKED),
|
||||
DRM_IOCTL_DEF(DRM_IOCTL_GET_CAP, drm_getcap, DRM_UNLOCKED),
|
||||
DRM_IOCTL_DEF(DRM_IOCTL_GET_CAP, drm_getcap, DRM_UNLOCKED|DRM_RENDER_ALLOW),
|
||||
DRM_IOCTL_DEF(DRM_IOCTL_SET_VERSION, drm_setversion, DRM_MASTER),
|
||||
|
||||
DRM_IOCTL_DEF(DRM_IOCTL_SET_UNIQUE, drm_setunique, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
|
||||
@@ -87,7 +87,7 @@ static const struct drm_ioctl_desc drm_ioctls[] = {
|
||||
|
||||
DRM_IOCTL_DEF(DRM_IOCTL_ADD_CTX, drm_addctx, DRM_AUTH|DRM_ROOT_ONLY),
|
||||
DRM_IOCTL_DEF(DRM_IOCTL_RM_CTX, drm_rmctx, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
|
||||
DRM_IOCTL_DEF(DRM_IOCTL_MOD_CTX, drm_modctx, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
|
||||
DRM_IOCTL_DEF(DRM_IOCTL_MOD_CTX, drm_noop, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
|
||||
DRM_IOCTL_DEF(DRM_IOCTL_GET_CTX, drm_getctx, DRM_AUTH),
|
||||
DRM_IOCTL_DEF(DRM_IOCTL_SWITCH_CTX, drm_switchctx, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
|
||||
DRM_IOCTL_DEF(DRM_IOCTL_NEW_CTX, drm_newctx, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
|
||||
@@ -106,8 +106,7 @@ static const struct drm_ioctl_desc drm_ioctls[] = {
|
||||
DRM_IOCTL_DEF(DRM_IOCTL_INFO_BUFS, drm_infobufs, DRM_AUTH),
|
||||
DRM_IOCTL_DEF(DRM_IOCTL_MAP_BUFS, drm_mapbufs, DRM_AUTH),
|
||||
DRM_IOCTL_DEF(DRM_IOCTL_FREE_BUFS, drm_freebufs, DRM_AUTH),
|
||||
/* The DRM_IOCTL_DMA ioctl should be defined by the driver. */
|
||||
DRM_IOCTL_DEF(DRM_IOCTL_DMA, NULL, DRM_AUTH),
|
||||
DRM_IOCTL_DEF(DRM_IOCTL_DMA, drm_dma_ioctl, DRM_AUTH),
|
||||
|
||||
DRM_IOCTL_DEF(DRM_IOCTL_CONTROL, drm_control, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
|
||||
|
||||
@@ -122,7 +121,7 @@ static const struct drm_ioctl_desc drm_ioctls[] = {
|
||||
DRM_IOCTL_DEF(DRM_IOCTL_AGP_UNBIND, drm_agp_unbind_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
|
||||
#endif
|
||||
|
||||
DRM_IOCTL_DEF(DRM_IOCTL_SG_ALLOC, drm_sg_alloc_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
|
||||
DRM_IOCTL_DEF(DRM_IOCTL_SG_ALLOC, drm_sg_alloc, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
|
||||
DRM_IOCTL_DEF(DRM_IOCTL_SG_FREE, drm_sg_free, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
|
||||
|
||||
DRM_IOCTL_DEF(DRM_IOCTL_WAIT_VBLANK, drm_wait_vblank, DRM_UNLOCKED),
|
||||
@@ -131,14 +130,14 @@ static const struct drm_ioctl_desc drm_ioctls[] = {
|
||||
|
||||
DRM_IOCTL_DEF(DRM_IOCTL_UPDATE_DRAW, drm_noop, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
|
||||
|
||||
DRM_IOCTL_DEF(DRM_IOCTL_GEM_CLOSE, drm_gem_close_ioctl, DRM_UNLOCKED),
|
||||
DRM_IOCTL_DEF(DRM_IOCTL_GEM_CLOSE, drm_gem_close_ioctl, DRM_UNLOCKED|DRM_RENDER_ALLOW),
|
||||
DRM_IOCTL_DEF(DRM_IOCTL_GEM_FLINK, drm_gem_flink_ioctl, DRM_AUTH|DRM_UNLOCKED),
|
||||
DRM_IOCTL_DEF(DRM_IOCTL_GEM_OPEN, drm_gem_open_ioctl, DRM_AUTH|DRM_UNLOCKED),
|
||||
|
||||
DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETRESOURCES, drm_mode_getresources, DRM_CONTROL_ALLOW|DRM_UNLOCKED),
|
||||
|
||||
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_PRIME_HANDLE_TO_FD, drm_prime_handle_to_fd_ioctl, DRM_AUTH|DRM_UNLOCKED|DRM_RENDER_ALLOW),
|
||||
DRM_IOCTL_DEF(DRM_IOCTL_PRIME_FD_TO_HANDLE, drm_prime_fd_to_handle_ioctl, DRM_AUTH|DRM_UNLOCKED|DRM_RENDER_ALLOW),
|
||||
|
||||
DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETPLANERESOURCES, drm_mode_getplane_res, DRM_CONTROL_ALLOW|DRM_UNLOCKED),
|
||||
DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETCRTC, drm_mode_getcrtc, DRM_CONTROL_ALLOW|DRM_UNLOCKED),
|
||||
@@ -171,6 +170,31 @@ static const struct drm_ioctl_desc drm_ioctls[] = {
|
||||
|
||||
#define DRM_CORE_IOCTL_COUNT ARRAY_SIZE( drm_ioctls )
|
||||
|
||||
/**
|
||||
* drm_legacy_dev_reinit
|
||||
*
|
||||
* Reinitializes a legacy/ums drm device in it's lastclose function.
|
||||
*/
|
||||
static void drm_legacy_dev_reinit(struct drm_device *dev)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (drm_core_check_feature(dev, DRIVER_MODESET))
|
||||
return;
|
||||
|
||||
atomic_set(&dev->ioctl_count, 0);
|
||||
atomic_set(&dev->vma_count, 0);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(dev->counts); i++)
|
||||
atomic_set(&dev->counts[i], 0);
|
||||
|
||||
dev->sigdata.lock = NULL;
|
||||
|
||||
dev->context_flag = 0;
|
||||
dev->last_context = 0;
|
||||
dev->if_version = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Take down the DRM device.
|
||||
*
|
||||
@@ -195,32 +219,9 @@ int drm_lastclose(struct drm_device * dev)
|
||||
|
||||
mutex_lock(&dev->struct_mutex);
|
||||
|
||||
/* Clear AGP information */
|
||||
if (drm_core_has_AGP(dev) && dev->agp &&
|
||||
!drm_core_check_feature(dev, DRIVER_MODESET)) {
|
||||
struct drm_agp_mem *entry, *tempe;
|
||||
drm_agp_clear(dev);
|
||||
|
||||
/* Remove AGP resources, but leave dev->agp
|
||||
intact until drv_cleanup is called. */
|
||||
list_for_each_entry_safe(entry, tempe, &dev->agp->memory, head) {
|
||||
if (entry->bound)
|
||||
drm_unbind_agp(entry->memory);
|
||||
drm_free_agp(entry->memory, entry->pages);
|
||||
kfree(entry);
|
||||
}
|
||||
INIT_LIST_HEAD(&dev->agp->memory);
|
||||
|
||||
if (dev->agp->acquired)
|
||||
drm_agp_release(dev);
|
||||
|
||||
dev->agp->acquired = 0;
|
||||
dev->agp->enabled = 0;
|
||||
}
|
||||
if (drm_core_check_feature(dev, DRIVER_SG) && dev->sg &&
|
||||
!drm_core_check_feature(dev, DRIVER_MODESET)) {
|
||||
drm_sg_cleanup(dev->sg);
|
||||
dev->sg = NULL;
|
||||
}
|
||||
drm_legacy_sg_cleanup(dev);
|
||||
|
||||
/* Clear vma list (only built for debugging) */
|
||||
list_for_each_entry_safe(vma, vma_temp, &dev->vmalist, head) {
|
||||
@@ -228,13 +229,13 @@ int drm_lastclose(struct drm_device * dev)
|
||||
kfree(vma);
|
||||
}
|
||||
|
||||
if (drm_core_check_feature(dev, DRIVER_HAVE_DMA) &&
|
||||
!drm_core_check_feature(dev, DRIVER_MODESET))
|
||||
drm_dma_takedown(dev);
|
||||
drm_legacy_dma_takedown(dev);
|
||||
|
||||
dev->dev_mapping = NULL;
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
|
||||
drm_legacy_dev_reinit(dev);
|
||||
|
||||
DRM_DEBUG("lastclose completed\n");
|
||||
return 0;
|
||||
}
|
||||
@@ -251,6 +252,7 @@ static int __init drm_core_init(void)
|
||||
int ret = -ENOMEM;
|
||||
|
||||
drm_global_init();
|
||||
drm_connector_ida_init();
|
||||
idr_init(&drm_minors_idr);
|
||||
|
||||
if (register_chrdev(DRM_MAJOR, "drm", &drm_stub_fops))
|
||||
@@ -263,13 +265,6 @@ static int __init drm_core_init(void)
|
||||
goto err_p2;
|
||||
}
|
||||
|
||||
drm_proc_root = proc_mkdir("dri", NULL);
|
||||
if (!drm_proc_root) {
|
||||
DRM_ERROR("Cannot create /proc/dri\n");
|
||||
ret = -1;
|
||||
goto err_p3;
|
||||
}
|
||||
|
||||
drm_debugfs_root = debugfs_create_dir("dri", NULL);
|
||||
if (!drm_debugfs_root) {
|
||||
DRM_ERROR("Cannot create /sys/kernel/debug/dri\n");
|
||||
@@ -292,12 +287,12 @@ err_p1:
|
||||
|
||||
static void __exit drm_core_exit(void)
|
||||
{
|
||||
remove_proc_entry("dri", NULL);
|
||||
debugfs_remove(drm_debugfs_root);
|
||||
drm_sysfs_destroy();
|
||||
|
||||
unregister_chrdev(DRM_MAJOR, "drm");
|
||||
|
||||
drm_connector_ida_destroy();
|
||||
idr_destroy(&drm_minors_idr);
|
||||
}
|
||||
|
||||
@@ -420,17 +415,15 @@ long drm_ioctl(struct file *filp,
|
||||
|
||||
/* Do not trust userspace, use our own definition */
|
||||
func = ioctl->func;
|
||||
/* is there a local override? */
|
||||
if ((nr == DRM_IOCTL_NR(DRM_IOCTL_DMA)) && dev->driver->dma_ioctl)
|
||||
func = dev->driver->dma_ioctl;
|
||||
|
||||
if (!func) {
|
||||
DRM_DEBUG("no function\n");
|
||||
retcode = -EINVAL;
|
||||
} else if (((ioctl->flags & DRM_ROOT_ONLY) && !capable(CAP_SYS_ADMIN)) ||
|
||||
((ioctl->flags & DRM_AUTH) && !file_priv->authenticated) ||
|
||||
((ioctl->flags & DRM_AUTH) && !drm_is_render_client(file_priv) && !file_priv->authenticated) ||
|
||||
((ioctl->flags & DRM_MASTER) && !file_priv->is_master) ||
|
||||
(!(ioctl->flags & DRM_CONTROL_ALLOW) && (file_priv->minor->type == DRM_MINOR_CONTROL))) {
|
||||
(!(ioctl->flags & DRM_CONTROL_ALLOW) && (file_priv->minor->type == DRM_MINOR_CONTROL)) ||
|
||||
(!(ioctl->flags & DRM_RENDER_ALLOW) && drm_is_render_client(file_priv))) {
|
||||
retcode = -EACCES;
|
||||
} else {
|
||||
if (cmd & (IOC_IN | IOC_OUT)) {
|
||||
@@ -485,19 +478,4 @@ long drm_ioctl(struct file *filp,
|
||||
DRM_DEBUG("ret = %d\n", retcode);
|
||||
return retcode;
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(drm_ioctl);
|
||||
|
||||
struct drm_local_map *drm_getsarea(struct drm_device *dev)
|
||||
{
|
||||
struct drm_map_list *entry;
|
||||
|
||||
list_for_each_entry(entry, &dev->maplist, head) {
|
||||
if (entry->map && entry->map->type == _DRM_SHM &&
|
||||
(entry->map->flags & _DRM_CONTAINS_LOCK)) {
|
||||
return entry->map;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
EXPORT_SYMBOL(drm_getsarea);
|
||||
|
||||
+274
-32
@@ -125,6 +125,9 @@ static struct edid_quirk {
|
||||
|
||||
/* ViewSonic VA2026w */
|
||||
{ "VSC", 5020, EDID_QUIRK_FORCE_REDUCED_BLANKING },
|
||||
|
||||
/* Medion MD 30217 PG */
|
||||
{ "MED", 0x7b8, EDID_QUIRK_PREFER_LARGE_75 },
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -931,6 +934,36 @@ static const struct drm_display_mode edid_cea_modes[] = {
|
||||
.vrefresh = 100, },
|
||||
};
|
||||
|
||||
/*
|
||||
* HDMI 1.4 4k modes.
|
||||
*/
|
||||
static const struct drm_display_mode edid_4k_modes[] = {
|
||||
/* 1 - 3840x2160@30Hz */
|
||||
{ DRM_MODE("3840x2160", DRM_MODE_TYPE_DRIVER, 297000,
|
||||
3840, 4016, 4104, 4400, 0,
|
||||
2160, 2168, 2178, 2250, 0,
|
||||
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
|
||||
.vrefresh = 30, },
|
||||
/* 2 - 3840x2160@25Hz */
|
||||
{ DRM_MODE("3840x2160", DRM_MODE_TYPE_DRIVER, 297000,
|
||||
3840, 4896, 4984, 5280, 0,
|
||||
2160, 2168, 2178, 2250, 0,
|
||||
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
|
||||
.vrefresh = 25, },
|
||||
/* 3 - 3840x2160@24Hz */
|
||||
{ DRM_MODE("3840x2160", DRM_MODE_TYPE_DRIVER, 297000,
|
||||
3840, 5116, 5204, 5500, 0,
|
||||
2160, 2168, 2178, 2250, 0,
|
||||
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
|
||||
.vrefresh = 24, },
|
||||
/* 4 - 4096x2160@24Hz (SMPTE) */
|
||||
{ DRM_MODE("4096x2160", DRM_MODE_TYPE_DRIVER, 297000,
|
||||
4096, 5116, 5204, 5500, 0,
|
||||
2160, 2168, 2178, 2250, 0,
|
||||
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
|
||||
.vrefresh = 24, },
|
||||
};
|
||||
|
||||
/*** DDC fetch and block validation ***/
|
||||
|
||||
static const u8 edid_header[] = {
|
||||
@@ -2287,7 +2320,6 @@ add_detailed_modes(struct drm_connector *connector, struct edid *edid,
|
||||
return closure.modes;
|
||||
}
|
||||
|
||||
#define HDMI_IDENTIFIER 0x000C03
|
||||
#define AUDIO_BLOCK 0x01
|
||||
#define VIDEO_BLOCK 0x02
|
||||
#define VENDOR_BLOCK 0x03
|
||||
@@ -2298,10 +2330,10 @@ add_detailed_modes(struct drm_connector *connector, struct edid *edid,
|
||||
#define EDID_CEA_YCRCB422 (1 << 4)
|
||||
#define EDID_CEA_VCDB_QS (1 << 6)
|
||||
|
||||
/**
|
||||
/*
|
||||
* Search EDID for CEA extension block.
|
||||
*/
|
||||
u8 *drm_find_cea_extension(struct edid *edid)
|
||||
static u8 *drm_find_cea_extension(struct edid *edid)
|
||||
{
|
||||
u8 *edid_ext = NULL;
|
||||
int i;
|
||||
@@ -2322,7 +2354,6 @@ u8 *drm_find_cea_extension(struct edid *edid)
|
||||
|
||||
return edid_ext;
|
||||
}
|
||||
EXPORT_SYMBOL(drm_find_cea_extension);
|
||||
|
||||
/*
|
||||
* Calculate the alternate clock for the CEA mode
|
||||
@@ -2380,6 +2411,54 @@ u8 drm_match_cea_mode(const struct drm_display_mode *to_match)
|
||||
}
|
||||
EXPORT_SYMBOL(drm_match_cea_mode);
|
||||
|
||||
/*
|
||||
* Calculate the alternate clock for HDMI modes (those from the HDMI vendor
|
||||
* specific block).
|
||||
*
|
||||
* It's almost like cea_mode_alternate_clock(), we just need to add an
|
||||
* exception for the VIC 4 mode (4096x2160@24Hz): no alternate clock for this
|
||||
* one.
|
||||
*/
|
||||
static unsigned int
|
||||
hdmi_mode_alternate_clock(const struct drm_display_mode *hdmi_mode)
|
||||
{
|
||||
if (hdmi_mode->vdisplay == 4096 && hdmi_mode->hdisplay == 2160)
|
||||
return hdmi_mode->clock;
|
||||
|
||||
return cea_mode_alternate_clock(hdmi_mode);
|
||||
}
|
||||
|
||||
/*
|
||||
* drm_match_hdmi_mode - look for a HDMI mode matching given mode
|
||||
* @to_match: display mode
|
||||
*
|
||||
* An HDMI mode is one defined in the HDMI vendor specific block.
|
||||
*
|
||||
* Returns the HDMI Video ID (VIC) of the mode or 0 if it isn't one.
|
||||
*/
|
||||
static u8 drm_match_hdmi_mode(const struct drm_display_mode *to_match)
|
||||
{
|
||||
u8 mode;
|
||||
|
||||
if (!to_match->clock)
|
||||
return 0;
|
||||
|
||||
for (mode = 0; mode < ARRAY_SIZE(edid_4k_modes); mode++) {
|
||||
const struct drm_display_mode *hdmi_mode = &edid_4k_modes[mode];
|
||||
unsigned int clock1, clock2;
|
||||
|
||||
/* Make sure to also match alternate clocks */
|
||||
clock1 = hdmi_mode->clock;
|
||||
clock2 = hdmi_mode_alternate_clock(hdmi_mode);
|
||||
|
||||
if ((KHZ2PICOS(to_match->clock) == KHZ2PICOS(clock1) ||
|
||||
KHZ2PICOS(to_match->clock) == KHZ2PICOS(clock2)) &&
|
||||
drm_mode_equal_no_clocks(to_match, hdmi_mode))
|
||||
return mode + 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
add_alternate_cea_modes(struct drm_connector *connector, struct edid *edid)
|
||||
{
|
||||
@@ -2397,18 +2476,26 @@ add_alternate_cea_modes(struct drm_connector *connector, struct edid *edid)
|
||||
* with the alternate clock for certain CEA modes.
|
||||
*/
|
||||
list_for_each_entry(mode, &connector->probed_modes, head) {
|
||||
const struct drm_display_mode *cea_mode;
|
||||
const struct drm_display_mode *cea_mode = NULL;
|
||||
struct drm_display_mode *newmode;
|
||||
u8 cea_mode_idx = drm_match_cea_mode(mode) - 1;
|
||||
u8 mode_idx = drm_match_cea_mode(mode) - 1;
|
||||
unsigned int clock1, clock2;
|
||||
|
||||
if (cea_mode_idx >= ARRAY_SIZE(edid_cea_modes))
|
||||
if (mode_idx < ARRAY_SIZE(edid_cea_modes)) {
|
||||
cea_mode = &edid_cea_modes[mode_idx];
|
||||
clock2 = cea_mode_alternate_clock(cea_mode);
|
||||
} else {
|
||||
mode_idx = drm_match_hdmi_mode(mode) - 1;
|
||||
if (mode_idx < ARRAY_SIZE(edid_4k_modes)) {
|
||||
cea_mode = &edid_4k_modes[mode_idx];
|
||||
clock2 = hdmi_mode_alternate_clock(cea_mode);
|
||||
}
|
||||
}
|
||||
|
||||
if (!cea_mode)
|
||||
continue;
|
||||
|
||||
cea_mode = &edid_cea_modes[cea_mode_idx];
|
||||
|
||||
clock1 = cea_mode->clock;
|
||||
clock2 = cea_mode_alternate_clock(cea_mode);
|
||||
|
||||
if (clock1 == clock2)
|
||||
continue;
|
||||
@@ -2442,10 +2529,11 @@ add_alternate_cea_modes(struct drm_connector *connector, struct edid *edid)
|
||||
}
|
||||
|
||||
static int
|
||||
do_cea_modes (struct drm_connector *connector, u8 *db, u8 len)
|
||||
do_cea_modes(struct drm_connector *connector, const u8 *db, u8 len)
|
||||
{
|
||||
struct drm_device *dev = connector->dev;
|
||||
u8 * mode, cea_mode;
|
||||
const u8 *mode;
|
||||
u8 cea_mode;
|
||||
int modes = 0;
|
||||
|
||||
for (mode = db; mode < db + len; mode++) {
|
||||
@@ -2465,6 +2553,68 @@ do_cea_modes (struct drm_connector *connector, u8 *db, u8 len)
|
||||
return modes;
|
||||
}
|
||||
|
||||
/*
|
||||
* do_hdmi_vsdb_modes - Parse the HDMI Vendor Specific data block
|
||||
* @connector: connector corresponding to the HDMI sink
|
||||
* @db: start of the CEA vendor specific block
|
||||
* @len: length of the CEA block payload, ie. one can access up to db[len]
|
||||
*
|
||||
* Parses the HDMI VSDB looking for modes to add to @connector.
|
||||
*/
|
||||
static int
|
||||
do_hdmi_vsdb_modes(struct drm_connector *connector, const u8 *db, u8 len)
|
||||
{
|
||||
struct drm_device *dev = connector->dev;
|
||||
int modes = 0, offset = 0, i;
|
||||
u8 vic_len;
|
||||
|
||||
if (len < 8)
|
||||
goto out;
|
||||
|
||||
/* no HDMI_Video_Present */
|
||||
if (!(db[8] & (1 << 5)))
|
||||
goto out;
|
||||
|
||||
/* Latency_Fields_Present */
|
||||
if (db[8] & (1 << 7))
|
||||
offset += 2;
|
||||
|
||||
/* I_Latency_Fields_Present */
|
||||
if (db[8] & (1 << 6))
|
||||
offset += 2;
|
||||
|
||||
/* the declared length is not long enough for the 2 first bytes
|
||||
* of additional video format capabilities */
|
||||
offset += 2;
|
||||
if (len < (8 + offset))
|
||||
goto out;
|
||||
|
||||
vic_len = db[8 + offset] >> 5;
|
||||
|
||||
for (i = 0; i < vic_len && len >= (9 + offset + i); i++) {
|
||||
struct drm_display_mode *newmode;
|
||||
u8 vic;
|
||||
|
||||
vic = db[9 + offset + i];
|
||||
|
||||
vic--; /* VICs start at 1 */
|
||||
if (vic >= ARRAY_SIZE(edid_4k_modes)) {
|
||||
DRM_ERROR("Unknown HDMI VIC: %d\n", vic);
|
||||
continue;
|
||||
}
|
||||
|
||||
newmode = drm_mode_duplicate(dev, &edid_4k_modes[vic]);
|
||||
if (!newmode)
|
||||
continue;
|
||||
|
||||
drm_mode_probed_add(connector, newmode);
|
||||
modes++;
|
||||
}
|
||||
|
||||
out:
|
||||
return modes;
|
||||
}
|
||||
|
||||
static int
|
||||
cea_db_payload_len(const u8 *db)
|
||||
{
|
||||
@@ -2496,14 +2646,30 @@ cea_db_offsets(const u8 *cea, int *start, int *end)
|
||||
return 0;
|
||||
}
|
||||
|
||||
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_IEEE_OUI;
|
||||
}
|
||||
|
||||
#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)
|
||||
{
|
||||
u8 * cea = drm_find_cea_extension(edid);
|
||||
u8 * db, dbl;
|
||||
const u8 *cea = drm_find_cea_extension(edid);
|
||||
const u8 *db;
|
||||
u8 dbl;
|
||||
int modes = 0;
|
||||
|
||||
if (cea && cea_revision(cea) >= 3) {
|
||||
@@ -2517,7 +2683,9 @@ add_cea_modes(struct drm_connector *connector, struct edid *edid)
|
||||
dbl = cea_db_payload_len(db);
|
||||
|
||||
if (cea_db_tag(db) == VIDEO_BLOCK)
|
||||
modes += do_cea_modes (connector, db+1, dbl);
|
||||
modes += do_cea_modes(connector, db + 1, dbl);
|
||||
else if (cea_db_is_hdmi_vsdb(db))
|
||||
modes += do_hdmi_vsdb_modes(connector, db, dbl);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2570,21 +2738,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
|
||||
@@ -2731,6 +2884,58 @@ int drm_edid_to_sad(struct edid *edid, struct cea_sad **sads)
|
||||
}
|
||||
EXPORT_SYMBOL(drm_edid_to_sad);
|
||||
|
||||
/**
|
||||
* drm_edid_to_speaker_allocation - extracts Speaker Allocation Data Blocks from EDID
|
||||
* @edid: EDID to parse
|
||||
* @sadb: pointer to the speaker block
|
||||
*
|
||||
* Looks for CEA EDID block and extracts the Speaker Allocation Data Block from it.
|
||||
* Note: returned pointer needs to be kfreed
|
||||
*
|
||||
* Return number of found Speaker Allocation Blocks or negative number on error.
|
||||
*/
|
||||
int drm_edid_to_speaker_allocation(struct edid *edid, u8 **sadb)
|
||||
{
|
||||
int count = 0;
|
||||
int i, start, end, dbl;
|
||||
const u8 *cea;
|
||||
|
||||
cea = drm_find_cea_extension(edid);
|
||||
if (!cea) {
|
||||
DRM_DEBUG_KMS("SAD: no CEA Extension found\n");
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
if (cea_revision(cea) < 3) {
|
||||
DRM_DEBUG_KMS("SAD: wrong CEA revision\n");
|
||||
return -ENOTSUPP;
|
||||
}
|
||||
|
||||
if (cea_db_offsets(cea, &start, &end)) {
|
||||
DRM_DEBUG_KMS("SAD: invalid data block offsets\n");
|
||||
return -EPROTO;
|
||||
}
|
||||
|
||||
for_each_cea_db(cea, i, start, end) {
|
||||
const u8 *db = &cea[i];
|
||||
|
||||
if (cea_db_tag(db) == SPEAKER_BLOCK) {
|
||||
dbl = cea_db_payload_len(db);
|
||||
|
||||
/* Speaker Allocation Data Block */
|
||||
if (dbl == 3) {
|
||||
*sadb = kmalloc(dbl, GFP_KERNEL);
|
||||
memcpy(*sadb, &db[1], dbl);
|
||||
count = dbl;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
EXPORT_SYMBOL(drm_edid_to_speaker_allocation);
|
||||
|
||||
/**
|
||||
* drm_av_sync_delay - HDMI/DP sink audio-video sync delay in millisecond
|
||||
* @connector: connector associated with the HDMI/DP sink
|
||||
@@ -3102,9 +3307,10 @@ drm_hdmi_avi_infoframe_from_display_mode(struct hdmi_avi_infoframe *frame,
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
if (mode->flags & DRM_MODE_FLAG_DBLCLK)
|
||||
frame->pixel_repeat = 1;
|
||||
|
||||
frame->video_code = drm_match_cea_mode(mode);
|
||||
if (!frame->video_code)
|
||||
return 0;
|
||||
|
||||
frame->picture_aspect = HDMI_PICTURE_ASPECT_NONE;
|
||||
frame->active_aspect = HDMI_ACTIVE_ASPECT_PICTURE;
|
||||
@@ -3112,3 +3318,39 @@ drm_hdmi_avi_infoframe_from_display_mode(struct hdmi_avi_infoframe *frame,
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(drm_hdmi_avi_infoframe_from_display_mode);
|
||||
|
||||
/**
|
||||
* drm_hdmi_vendor_infoframe_from_display_mode() - fill an HDMI infoframe with
|
||||
* data from a DRM display mode
|
||||
* @frame: HDMI vendor infoframe
|
||||
* @mode: DRM display mode
|
||||
*
|
||||
* Note that there's is a need to send HDMI vendor infoframes only when using a
|
||||
* 4k or stereoscopic 3D mode. So when giving any other mode as input this
|
||||
* function will return -EINVAL, error that can be safely ignored.
|
||||
*
|
||||
* Returns 0 on success or a negative error code on failure.
|
||||
*/
|
||||
int
|
||||
drm_hdmi_vendor_infoframe_from_display_mode(struct hdmi_vendor_infoframe *frame,
|
||||
const struct drm_display_mode *mode)
|
||||
{
|
||||
int err;
|
||||
u8 vic;
|
||||
|
||||
if (!frame || !mode)
|
||||
return -EINVAL;
|
||||
|
||||
vic = drm_match_hdmi_mode(mode);
|
||||
if (!vic)
|
||||
return -EINVAL;
|
||||
|
||||
err = hdmi_vendor_infoframe_init(frame);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
frame->vic = vic;
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(drm_hdmi_vendor_infoframe_from_display_mode);
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user