Commit fffddfd6 authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'drm-next' of git://people.freedesktop.org/~airlied/linux

Pull drm merge from Dave Airlie:
 "Highlights:

   - TI LCD controller KMS driver

   - TI OMAP KMS driver merged from staging

   - drop gma500 stub driver

   - the fbcon locking fixes

   - the vgacon dirty like zebra fix.

   - open firmware videomode and hdmi common code helpers

   - major locking rework for kms object handling - pageflip/cursor
     won't block on polling anymore!

   - fbcon helper and prime helper cleanups

   - i915: all over the map, haswell power well enhancements, valleyview
     macro horrors cleaned up, killing lots of legacy GTT code,

   - radeon: CS ioctl unification, deprecated UMS support, gpu reset
     rework, VM fixes

   - nouveau: reworked thermal code, external dp/tmds encoder support
     (anx9805), fences sleep instead of polling,

   - exynos: all over the driver fixes."

Lovely conflict in radeon/evergreen_cs.c between commit de0babd6
("drm/radeon: enforce use of radeon_get_ib_value when reading user cmd")
and the new changes that modified that evergreen_dma_cs_parse()
function.

* 'drm-next' of git://people.freedesktop.org/~airlied/linux: (508 commits)
  drm/tilcdc: only build on arm
  drm/i915: Revert hdmi HDP pin checks
  drm/tegra: Add list of framebuffers to debugfs
  drm/tegra: Fix color expansion
  drm/tegra: Split DC_CMD_STATE_CONTROL register write
  drm/tegra: Implement page-flipping support
  drm/tegra: Implement VBLANK support
  drm/tegra: Implement .mode_set_base()
  drm/tegra: Add plane support
  drm/tegra: Remove bogus tegra_framebuffer structure
  drm: Add consistency check for page-flipping
  drm/radeon: Use generic HDMI infoframe helpers
  drm/tegra: Use generic HDMI infoframe helpers
  drm: Add EDID helper documentation
  drm: Add HDMI infoframe helpers
  video: Add generic HDMI infoframe helpers
  drm: Add some missing forward declarations
  drm: Move mode tables to drm_edid.c
  drm: Remove duplicate drm_mode_cea_vic()
  gma500: Fix n, m1 and m2 clock limits for sdvo and lvds
  ...
parents 69086a78 be88298b
......@@ -743,6 +743,10 @@ char *date;</synopsis>
These two operations are mandatory for GEM drivers that support DRM
PRIME.
</para>
<sect4>
<title>DRM PRIME Helper Functions Reference</title>
!Pdrivers/gpu/drm/drm_prime.c PRIME Helpers
</sect4>
</sect3>
<sect3 id="drm-gem-objects-mapping">
<title>GEM Objects Mapping</title>
......@@ -978,10 +982,25 @@ int max_width, max_height;</synopsis>
If the parameters are deemed valid, drivers then create, initialize and
return an instance of struct <structname>drm_framebuffer</structname>.
If desired the instance can be embedded in a larger driver-specific
structure. The new instance is initialized with a call to
<function>drm_framebuffer_init</function> which takes a pointer to DRM
frame buffer operations (struct
<structname>drm_framebuffer_funcs</structname>). Frame buffer operations are
structure. Drivers must fill its <structfield>width</structfield>,
<structfield>height</structfield>, <structfield>pitches</structfield>,
<structfield>offsets</structfield>, <structfield>depth</structfield>,
<structfield>bits_per_pixel</structfield> and
<structfield>pixel_format</structfield> fields from the values passed
through the <parameter>drm_mode_fb_cmd2</parameter> argument. They
should call the <function>drm_helper_mode_fill_fb_struct</function>
helper function to do so.
</para>
<para>
The initailization of the new framebuffer instance is finalized with a
call to <function>drm_framebuffer_init</function> which takes a pointer
to DRM frame buffer operations (struct
<structname>drm_framebuffer_funcs</structname>). Note that this function
publishes the framebuffer and so from this point on it can be accessed
concurrently from other threads. Hence it must be the last step in the
driver's framebuffer initialization sequence. Frame buffer operations
are
<itemizedlist>
<listitem>
<synopsis>int (*create_handle)(struct drm_framebuffer *fb,
......@@ -1022,16 +1041,16 @@ int max_width, max_height;</synopsis>
</itemizedlist>
</para>
<para>
After initializing the <structname>drm_framebuffer</structname>
instance drivers must fill its <structfield>width</structfield>,
<structfield>height</structfield>, <structfield>pitches</structfield>,
<structfield>offsets</structfield>, <structfield>depth</structfield>,
<structfield>bits_per_pixel</structfield> and
<structfield>pixel_format</structfield> fields from the values passed
through the <parameter>drm_mode_fb_cmd2</parameter> argument. They
should call the <function>drm_helper_mode_fill_fb_struct</function>
helper function to do so.
</para>
The lifetime of a drm framebuffer is controlled with a reference count,
drivers can grab additional references with
<function>drm_framebuffer_reference</function> </para> and drop them
again with <function>drm_framebuffer_unreference</function>. For
driver-private framebuffers for which the last reference is never
dropped (e.g. for the fbdev framebuffer when the struct
<structname>drm_framebuffer</structname> is embedded into the fbdev
helper struct) drivers can manually clean up a framebuffer at module
unload time with
<function>drm_framebuffer_unregister_private</function>.
</sect2>
<sect2>
<title>Output Polling</title>
......@@ -1043,6 +1062,22 @@ int max_width, max_height;</synopsis>
operation.
</para>
</sect2>
<sect2>
<title>Locking</title>
<para>
Beside some lookup structures with their own locking (which is hidden
behind the interface functions) most of the modeset state is protected
by the <code>dev-&lt;mode_config.lock</code> mutex and additionally
per-crtc locks to allow cursor updates, pageflips and similar operations
to occur concurrently with background tasks like output detection.
Operations which cross domains like a full modeset always grab all
locks. Drivers there need to protect resources shared between crtcs with
additional locking. They also need to be careful to always grab the
relevant crtc locks if a modset functions touches crtc state, e.g. for
load detection (which does only grab the <code>mode_config.lock</code>
to allow concurrent screen updates on live crtcs).
</para>
</sect2>
</sect1>
<!-- Internals: kms initialization and cleanup -->
......@@ -1125,6 +1160,12 @@ int max_width, max_height;</synopsis>
without waiting for rendering or page flip to complete and must block
any new rendering to the frame buffer until the page flip completes.
</para>
<para>
If a page flip can be successfully scheduled the driver must set the
<code>drm_crtc-&lt;fb</code> field to the new framebuffer pointed to
by <code>fb</code>. This is important so that the reference counting
on framebuffers stays balanced.
</para>
<para>
If a page flip is already pending, the
<methodname>page_flip</methodname> operation must return
......@@ -1609,6 +1650,10 @@ void intel_crt_init(struct drm_device *dev)
make its properties available to applications.
</para>
</sect2>
<sect2>
<title>KMS API Functions</title>
!Edrivers/gpu/drm/drm_crtc.c
</sect2>
</sect1>
<!-- Internals: kms helper functions -->
......@@ -2104,6 +2149,7 @@ void intel_crt_init(struct drm_device *dev)
<title>fbdev Helper Functions Reference</title>
!Pdrivers/gpu/drm/drm_fb_helper.c fbdev helpers
!Edrivers/gpu/drm/drm_fb_helper.c
!Iinclude/drm/drm_fb_helper.h
</sect2>
<sect2>
<title>Display Port Helper Functions Reference</title>
......@@ -2111,6 +2157,10 @@ void intel_crt_init(struct drm_device *dev)
!Iinclude/drm/drm_dp_helper.h
!Edrivers/gpu/drm/drm_dp_helper.c
</sect2>
<sect2>
<title>EDID Helper Functions Reference</title>
!Edrivers/gpu/drm/drm_edid.c
</sect2>
</sect1>
<!-- Internals: vertical blanking -->
......
......@@ -28,11 +28,30 @@ Makefile environment are given here.
To create binary EDID and C source code files from the existing data
material, simply type "make".
If you want to create your own EDID file, copy the file 1024x768.S and
replace the settings with your own data. The CRC value in the last line
If you want to create your own EDID file, copy the file 1024x768.S,
replace the settings with your own data and add a new target to the
Makefile. Please note that the EDID data structure expects the timing
values in a different way as compared to the standard X11 format.
X11:
HTimings: hdisp hsyncstart hsyncend htotal
VTimings: vdisp vsyncstart vsyncend vtotal
EDID:
#define XPIX hdisp
#define XBLANK htotal-hdisp
#define XOFFSET hsyncstart-hdisp
#define XPULSE hsyncend-hsyncstart
#define YPIX vdisp
#define YBLANK vtotal-vdisp
#define YOFFSET (63+(vsyncstart-vdisp))
#define YPULSE (63+(vsyncend-vsyncstart))
The CRC value in the last line
#define CRC 0x55
is a bit tricky. After a first version of the binary data set is
created, it must be be checked with the "edid-decode" utility which will
also is a bit tricky. After a first version of the binary data set is
created, it must be checked with the "edid-decode" utility which will
most probably complain about a wrong CRC. Fortunately, the utility also
displays the correct CRC which must then be inserted into the source
file. After the make procedure is repeated, the EDID data set is ready
......
Device-Tree bindings for tilcdc DRM generic panel output driver
Required properties:
- compatible: value should be "ti,tilcdc,panel".
- panel-info: configuration info to configure LCDC correctly for the panel
- ac-bias: AC Bias Pin Frequency
- ac-bias-intrpt: AC Bias Pin Transitions per Interrupt
- dma-burst-sz: DMA burst size
- bpp: Bits per pixel
- fdd: FIFO DMA Request Delay
- sync-edge: Horizontal and Vertical Sync Edge: 0=rising 1=falling
- sync-ctrl: Horizontal and Vertical Sync: Control: 0=ignore
- raster-order: Raster Data Order Select: 1=Most-to-least 0=Least-to-most
- fifo-th: DMA FIFO threshold
- display-timings: typical videomode of lcd panel. Multiple video modes
can be listed if the panel supports multiple timings, but the 'native-mode'
should be the preferred/default resolution. Refer to
Documentation/devicetree/bindings/video/display-timing.txt for display
timing binding details.
Recommended properties:
- pinctrl-names, pinctrl-0: the pincontrol settings to configure
muxing properly for pins that connect to TFP410 device
Example:
/* Settings for CDTech_S035Q01 / LCD3 cape: */
lcd3 {
compatible = "ti,tilcdc,panel";
pinctrl-names = "default";
pinctrl-0 = <&bone_lcd3_cape_lcd_pins>;
panel-info {
ac-bias = <255>;
ac-bias-intrpt = <0>;
dma-burst-sz = <16>;
bpp = <16>;
fdd = <0x80>;
sync-edge = <0>;
sync-ctrl = <1>;
raster-order = <0>;
fifo-th = <0>;
};
display-timings {
native-mode = <&timing0>;
timing0: 320x240 {
hactive = <320>;
vactive = <240>;
hback-porch = <21>;
hfront-porch = <58>;
hsync-len = <47>;
vback-porch = <11>;
vfront-porch = <23>;
vsync-len = <2>;
clock-frequency = <8000000>;
hsync-active = <0>;
vsync-active = <0>;
};
};
};
Device-Tree bindings for tilcdc DRM encoder slave output driver
Required properties:
- compatible: value should be "ti,tilcdc,slave".
- i2c: the phandle for the i2c device the encoder slave is connected to
Recommended properties:
- pinctrl-names, pinctrl-0: the pincontrol settings to configure
muxing properly for pins that connect to TFP410 device
Example:
hdmi {
compatible = "ti,tilcdc,slave";
i2c = <&i2c0>;
pinctrl-names = "default";
pinctrl-0 = <&nxp_hdmi_bonelt_pins>;
};
Device-Tree bindings for tilcdc DRM TFP410 output driver
Required properties:
- compatible: value should be "ti,tilcdc,tfp410".
- i2c: the phandle for the i2c device to use for DDC
Recommended properties:
- pinctrl-names, pinctrl-0: the pincontrol settings to configure
muxing properly for pins that connect to TFP410 device
- powerdn-gpio: the powerdown GPIO, pulled low to power down the
TFP410 device (for DPMS_OFF)
Example:
dvicape {
compatible = "ti,tilcdc,tfp410";
i2c = <&i2c2>;
pinctrl-names = "default";
pinctrl-0 = <&bone_dvi_cape_dvi_00A1_pins>;
powerdn-gpio = <&gpio2 31 0>;
};
Device-Tree bindings for tilcdc DRM driver
Required properties:
- compatible: value should be "ti,am33xx-tilcdc".
- interrupts: the interrupt number
- reg: base address and size of the LCDC device
Recommended properties:
- interrupt-parent: the phandle for the interrupt controller that
services interrupts for this device.
- ti,hwmods: Name of the hwmod associated to the LCDC
Example:
fb: fb@4830e000 {
compatible = "ti,am33xx-tilcdc";
reg = <0x4830e000 0x1000>;
interrupt-parent = <&intc>;
interrupts = <36>;
ti,hwmods = "lcdc";
};
display-timing bindings
=======================
display-timings node
--------------------
required properties:
- none
optional properties:
- native-mode: The native mode for the display, in case multiple modes are
provided. When omitted, assume the first node is the native.
timing subnode
--------------
required properties:
- hactive, vactive: display resolution
- hfront-porch, hback-porch, hsync-len: horizontal display timing parameters
in pixels
vfront-porch, vback-porch, vsync-len: vertical display timing parameters in
lines
- clock-frequency: display clock in Hz
optional properties:
- hsync-active: hsync pulse is active low/high/ignored
- vsync-active: vsync pulse is active low/high/ignored
- de-active: data-enable pulse is active low/high/ignored
- pixelclk-active: with
- active high = drive pixel data on rising edge/
sample data on falling edge
- active low = drive pixel data on falling edge/
sample data on rising edge
- ignored = ignored
- interlaced (bool): boolean to enable interlaced mode
- doublescan (bool): boolean to enable doublescan mode
All the optional properties that are not bool follow the following logic:
<1>: high active
<0>: low active
omitted: not used on hardware
There are different ways of describing the capabilities of a display. The
devicetree representation corresponds to the one commonly found in datasheets
for displays. If a display supports multiple signal timings, the native-mode
can be specified.
The parameters are defined as:
+----------+-------------------------------------+----------+-------+
| | ↑ | | |
| | |vback_porch | | |
| | ↓ | | |
+----------#######################################----------+-------+
| # ↑ # | |
| # | # | |
| hback # | # hfront | hsync |
| porch # | hactive # porch | len |
|<-------->#<-------+--------------------------->#<-------->|<----->|
| # | # | |
| # |vactive # | |
| # | # | |
| # ↓ # | |
+----------#######################################----------+-------+
| | ↑ | | |
| | |vfront_porch | | |
| | ↓ | | |
+----------+-------------------------------------+----------+-------+
| | ↑ | | |
| | |vsync_len | | |
| | ↓ | | |
+----------+-------------------------------------+----------+-------+
Example:
display-timings {
native-mode = <&timing0>;
timing0: 1080p24 {
/* 1920x1080p24 */
clock-frequency = <52000000>;
hactive = <1920>;
vactive = <1080>;
hfront-porch = <25>;
hback-porch = <25>;
hsync-len = <25>;
vback-porch = <2>;
vfront-porch = <2>;
vsync-len = <2>;
hsync-active = <1>;
};
};
Every required property also supports the use of ranges, so the commonly used
datasheet description with minimum, typical and maximum values can be used.
Example:
timing1: timing {
/* 1920x1080p24 */
clock-frequency = <148500000>;
hactive = <1920>;
vactive = <1080>;
hsync-len = <0 44 60>;
hfront-porch = <80 88 95>;
hback-porch = <100 148 160>;
vfront-porch = <0 4 6>;
vback-porch = <0 36 50>;
vsync-len = <0 5 6>;
};
Kernel driver nouveau
===================
Supported chips:
* NV43+
Authors: Martin Peres (mupuf) <martin.peres@labri.fr>
Description
---------
This driver allows to read the GPU core temperature, drive the GPU fan and
set temperature alarms.
Currently, due to the absence of in-kernel API to access HWMON drivers, Nouveau
cannot access any of the i2c external monitoring chips it may find. If you
have one of those, temperature and/or fan management through Nouveau's HWMON
interface is likely not to work. This document may then not cover your situation
entirely.
Temperature management
--------------------
Temperature is exposed under as a read-only HWMON attribute temp1_input.
In order to protect the GPU from overheating, Nouveau supports 4 configurable
temperature thresholds:
* Fan_boost: Fan speed is set to 100% when reaching this temperature;
* Downclock: The GPU will be downclocked to reduce its power dissipation;
* Critical: The GPU is put on hold to further lower power dissipation;
* Shutdown: Shut the computer down to protect your GPU.
WARNING: Some of these thresholds may not be used by Nouveau depending
on your chipset.
The default value for these thresholds comes from the GPU's vbios. These
thresholds can be configured thanks to the following HWMON attributes:
* Fan_boost: temp1_auto_point1_temp and temp1_auto_point1_temp_hyst;
* Downclock: temp1_max and temp1_max_hyst;
* Critical: temp1_crit and temp1_crit_hyst;
* Shutdown: temp1_emergency and temp1_emergency_hyst.
NOTE: Remember that the values are stored as milli degrees Celcius. Don't forget
to multiply!
Fan management
------------
Not all cards have a drivable fan. If you do, then the following HWMON
attributes should be available:
* pwm1_enable: Current fan management mode (NONE, MANUAL or AUTO);
* pwm1: Current PWM value (power percentage);
* pwm1_min: The minimum PWM speed allowed;
* pwm1_max: The maximum PWM speed allowed (bypassed when hitting Fan_boost);
You may also have the following attribute:
* fan1_input: Speed in RPM of your fan.
Your fan can be driven in different modes:
* 0: The fan is left untouched;
* 1: The fan can be driven in manual (use pwm1 to change the speed);
* 2; The fan is driven automatically depending on the temperature.
NOTE: Be sure to use the manual mode if you want to drive the fan speed manually
NOTE2: Not all fan management modes may be supported on all chipsets. We are
working on it.
Bug reports
---------
Thermal management on Nouveau is new and may not work on all cards. If you have
inquiries, please ping mupuf on IRC (#nouveau, freenode).
Bug reports should be filled on Freedesktop's bug tracker. Please follow
http://nouveau.freedesktop.org/wiki/Bugs
......@@ -60,7 +60,6 @@ struct intel_gtt_driver {
};
static struct _intel_private {
struct intel_gtt base;
const struct intel_gtt_driver *driver;
struct pci_dev *pcidev; /* device one */
struct pci_dev *bridge_dev;
......@@ -75,7 +74,18 @@ static struct _intel_private {
struct resource ifp_resource;
int resource_valid;
struct page *scratch_page;
phys_addr_t scratch_page_dma;
int refcount;
/* Whether i915 needs to use the dmar apis or not. */
unsigned int needs_dmar : 1;
phys_addr_t gma_bus_addr;
/* Size of memory reserved for graphics by the BIOS */
unsigned int stolen_size;
/* Total number of gtt entries. */
unsigned int gtt_total_entries;
/* Part of the gtt that is mappable by the cpu, for those chips where
* this is not the full gtt. */
unsigned int gtt_mappable_entries;
} intel_private;
#define INTEL_GTT_GEN intel_private.driver->gen
......@@ -291,15 +301,15 @@ static int intel_gtt_setup_scratch_page(void)
get_page(page);
set_pages_uc(page, 1);
if (intel_private.base.needs_dmar) {
if (intel_private.needs_dmar) {
dma_addr = pci_map_page(intel_private.pcidev, page, 0,
PAGE_SIZE, PCI_DMA_BIDIRECTIONAL);
if (pci_dma_mapping_error(intel_private.pcidev, dma_addr))
return -EINVAL;
intel_private.base.scratch_page_dma = dma_addr;
intel_private.scratch_page_dma = dma_addr;
} else
intel_private.base.scratch_page_dma = page_to_phys(page);
intel_private.scratch_page_dma = page_to_phys(page);
intel_private.scratch_page = page;
......@@ -506,7 +516,7 @@ static unsigned int intel_gtt_total_entries(void)
/* On previous hardware, the GTT size was just what was
* required to map the aperture.
*/
return intel_private.base.gtt_mappable_entries;
return intel_private.gtt_mappable_entries;
}
}
......@@ -546,7 +556,7 @@ static unsigned int intel_gtt_mappable_entries(void)
static void intel_gtt_teardown_scratch_page(void)
{
set_pages_wb(intel_private.scratch_page, 1);
pci_unmap_page(intel_private.pcidev, intel_private.base.scratch_page_dma,
pci_unmap_page(intel_private.pcidev, intel_private.scratch_page_dma,
PAGE_SIZE, PCI_DMA_BIDIRECTIONAL);
put_page(intel_private.scratch_page);
__free_page(intel_private.scratch_page);
......@@ -562,6 +572,40 @@ static void intel_gtt_cleanup(void)
intel_gtt_teardown_scratch_page();
}
/* Certain Gen5 chipsets require require idling the GPU before
* unmapping anything from the GTT when VT-d is enabled.
*/
static inline int needs_ilk_vtd_wa(void)
{
#ifdef CONFIG_INTEL_IOMMU
const unsigned short gpu_devid = intel_private.pcidev->device;
/* Query intel_iommu to see if we need the workaround. Presumably that
* was loaded first.
*/
if ((gpu_devid == PCI_DEVICE_ID_INTEL_IRONLAKE_M_HB ||
gpu_devid == PCI_DEVICE_ID_INTEL_IRONLAKE_M_IG) &&
intel_iommu_gfx_mapped)
return 1;
#endif
return 0;
}
static bool intel_gtt_can_wc(void)
{
if (INTEL_GTT_GEN <= 2)
return false;
if (INTEL_GTT_GEN >= 6)
return false;
/* Reports of major corruption with ILK vt'd enabled */
if (needs_ilk_vtd_wa())
return false;
return true;
}
static int intel_gtt_init(void)
{
u32 gma_addr;
......@@ -572,8 +616,8 @@ static int intel_gtt_init(void)
if (ret != 0)
return ret;
intel_private.base.gtt_mappable_entries = intel_gtt_mappable_entries();
intel_private.base.gtt_total_entries = intel_gtt_total_entries();
intel_private.gtt_mappable_entries = intel_gtt_mappable_entries();
intel_private.gtt_total_entries = intel_gtt_total_entries();
/* save the PGETBL reg for resume */
intel_private.PGETBL_save =
......@@ -585,13 +629,13 @@ static int intel_gtt_init(void)
dev_info(&intel_private.bridge_dev->dev,
"detected gtt size: %dK total, %dK mappable\n",
intel_private.base.gtt_total_entries * 4,
intel_private.base.gtt_mappable_entries * 4);
intel_private.gtt_total_entries * 4,
intel_private.gtt_mappable_entries * 4);
gtt_map_size = intel_private.base.gtt_total_entries * 4;
gtt_map_size = intel_private.gtt_total_entries * 4;
intel_private.gtt = NULL;
if (INTEL_GTT_GEN < 6 && INTEL_GTT_GEN > 2)
if (intel_gtt_can_wc())
intel_private.gtt = ioremap_wc(intel_private.gtt_bus_addr,
gtt_map_size);
if (intel_private.gtt == NULL)
......@@ -602,13 +646,12 @@ static int intel_gtt_init(void)
iounmap(intel_private.registers);
return -ENOMEM;
}
intel_private.base.gtt = intel_private.gtt;
global_cache_flush(); /* FIXME: ? */
intel_private.base.stolen_size = intel_gtt_stolen_size();
intel_private.stolen_size = intel_gtt_stolen_size();
intel_private.base.needs_dmar = USE_PCI_DMA_API && INTEL_GTT_GEN > 2;
intel_private.needs_dmar = USE_PCI_DMA_API && INTEL_GTT_GEN > 2;
ret = intel_gtt_setup_scratch_page();
if (ret != 0) {
......@@ -623,7 +666,7 @@ static int intel_gtt_init(void)
pci_read_config_dword(intel_private.pcidev, I915_GMADDR,
&gma_addr);
intel_private.base.gma_bus_addr = (gma_addr & PCI_BASE_ADDRESS_MEM_MASK);
intel_private.gma_bus_addr = (gma_addr & PCI_BASE_ADDRESS_MEM_MASK);
return 0;
}
......@@ -634,8 +677,7 @@ static int intel_fake_agp_fetch_size(void)
unsigned int aper_size;
int i;
aper_size = (intel_private.base.gtt_mappable_entries << PAGE_SHIFT)
/ MB(1);
aper_size = (intel_private.gtt_mappable_entries << PAGE_SHIFT) / MB(1);
for (i = 0; i < num_sizes; i++) {
if (aper_size == intel_fake_agp_sizes[i].size) {
......@@ -779,7 +821,7 @@ static int intel_fake_agp_configure(void)
return -EIO;
intel_private.clear_fake_agp = true;
agp_bridge->gart_bus_addr = intel_private.base.gma_bus_addr;
agp_bridge->gart_bus_addr = intel_private.gma_bus_addr;
return 0;
}
......@@ -841,12 +883,9 @@ static int intel_fake_agp_insert_entries(struct agp_memory *mem,
{
int ret = -EINVAL;
if (intel_private.base.do_idle_maps)
return -ENODEV;
if (intel_private.clear_fake_agp) {
int start = intel_private.base.stolen_size / PAGE_SIZE;
int end = intel_private.base.gtt_mappable_entries;
int start = intel_private.stolen_size / PAGE_SIZE;
int end = intel_private.gtt_mappable_entries;
intel_gtt_clear_range(start, end - start);
intel_private.clear_fake_agp = false;
}
......@@ -857,7 +896,7 @@ static int intel_fake_agp_insert_entries(struct agp_memory *mem,
if (mem->page_count == 0)
goto out;
if (pg_start + mem->page_count > intel_private.base.gtt_total_entries)
if (pg_start + mem->page_count > intel_private.gtt_total_entries)
goto out_err;
if (type != mem->type)
......@@ -869,7 +908,7 @@ static int intel_fake_agp_insert_entries(struct agp_memory *mem,
if (!mem->is_flushed)
global_cache_flush();
if (intel_private.base.needs_dmar) {
if (intel_private.needs_dmar) {
struct sg_table st;
ret = intel_gtt_map_memory(mem->pages, mem->page_count, &st);
......@@ -895,7 +934,7 @@ void intel_gtt_clear_range(unsigned int first_entry, unsigned int num_entries)
unsigned int i;
for (i = first_entry; i < (first_entry + num_entries); i++) {
intel_private.driver->write_entry(intel_private.base.scratch_page_dma,
intel_private.driver->write_entry(intel_private.scratch_page_dma,
i, 0);
}
readl(intel_private.gtt+i-1);
......@@ -908,12 +947,9 @@ static int intel_fake_agp_remove_entries(struct agp_memory *mem,
if (mem->page_count == 0)
return 0;
if (intel_private.base.do_idle_maps)
return -ENODEV;
intel_gtt_clear_range(pg_start, mem->page_count);
if (intel_private.base.needs_dmar) {
if (intel_private.needs_dmar) {
intel_gtt_unmap_memory(mem->sg_list, mem->num_sg);
mem->sg_list = NULL;
mem->num_sg = 0;
......@@ -1070,25 +1106,6 @@ static void i965_write_entry(dma_addr_t addr,
writel(addr | pte_flags, intel_private.gtt + entry);
}
/* Certain Gen5 chipsets require require idling the GPU before
* unmapping anything from the GTT when VT-d is enabled.
*/
static inline int needs_idle_maps(void)
{
#ifdef CONFIG_INTEL_IOMMU
const unsigned short gpu_devid = intel_private.pcidev->device;
/* Query intel_iommu to see if we need the workaround. Presumably that
* was loaded first.
*/
if ((gpu_devid == PCI_DEVICE_ID_INTEL_IRONLAKE_M_HB ||
gpu_devid == PCI_DEVICE_ID_INTEL_IRONLAKE_M_IG) &&
intel_iommu_gfx_mapped)
return 1;
#endif
return 0;
}
static int i9xx_setup(void)
{
u32 reg_addr, gtt_addr;
......@@ -1116,9 +1133,6 @@ static int i9xx_setup(void)
break;
}
if (needs_idle_maps())
intel_private.base.do_idle_maps = 1;
intel_i9xx_setup_flush();
return 0;
......@@ -1390,9 +1404,13 @@ int intel_gmch_probe(struct pci_dev *bridge_pdev, struct pci_dev *gpu_pdev,
}
EXPORT_SYMBOL(intel_gmch_probe);
struct intel_gtt *intel_gtt_get(void)
void intel_gtt_get(size_t *gtt_total, size_t *stolen_size,
phys_addr_t *mappable_base, unsigned long *mappable_end)
{
return &intel_private.base;
*gtt_total = intel_private.gtt_total_entries << PAGE_SHIFT;
*stolen_size = intel_private.stolen_size;
*mappable_base = intel_private.gma_bus_addr;
*mappable_end = intel_private.gtt_mappable_entries << PAGE_SHIFT;
}
EXPORT_SYMBOL(intel_gtt_get);
......
obj-y += drm/ vga/ stub/
obj-y += drm/ vga/
......@@ -7,6 +7,7 @@
menuconfig DRM
tristate "Direct Rendering Manager (XFree86 4.1.0 and higher DRI support)"
depends on (AGP || AGP=n) && !EMULATED_CMPXCHG && MMU
select HDMI
select I2C
select I2C_ALGOBIT
select DMA_SHARED_BUFFER
......@@ -69,6 +70,8 @@ config DRM_KMS_CMA_HELPER
help
Choose this if you need the KMS CMA helper functions
source "drivers/gpu/drm/i2c/Kconfig"
config DRM_TDFX
tristate "3dfx Banshee/Voodoo3+"
depends on DRM && PCI
......@@ -96,6 +99,7 @@ config DRM_RADEON
select DRM_TTM
select POWER_SUPPLY
select HWMON
select BACKLIGHT_CLASS_DEVICE
help
Choose this option if you have an ATI Radeon graphics card. There
are both PCI and AGP versions. You don't need to choose this to
......@@ -212,3 +216,7 @@ source "drivers/gpu/drm/cirrus/Kconfig"
source "drivers/gpu/drm/shmobile/Kconfig"
source "drivers/gpu/drm/tegra/Kconfig"
source "drivers/gpu/drm/omapdrm/Kconfig"
source "drivers/gpu/drm/tilcdc/Kconfig"
......@@ -50,4 +50,6 @@ obj-$(CONFIG_DRM_UDL) += udl/
obj-$(CONFIG_DRM_AST) += ast/
obj-$(CONFIG_DRM_SHMOBILE) +=shmobile/
obj-$(CONFIG_DRM_TEGRA) += tegra/
obj-$(CONFIG_DRM_OMAP) += omapdrm/
obj-$(CONFIG_DRM_TILCDC) += tilcdc/
obj-y += i2c/
......@@ -94,9 +94,9 @@ static int ast_drm_thaw(struct drm_device *dev)
ast_post_gpu(dev);
drm_mode_config_reset(dev);
mutex_lock(&dev->mode_config.mutex);
drm_modeset_lock_all(dev);
drm_helper_resume_force_mode(dev);
mutex_unlock(&dev->mode_config.mutex);
drm_modeset_unlock_all(dev);
console_lock();
ast_fbdev_set_suspend(dev, 0);
......
......@@ -98,6 +98,8 @@ struct ast_private {
struct drm_gem_object *cursor_cache;
uint64_t cursor_cache_gpu_addr;
/* Acces to this cache is protected by the crtc->mutex of the only crtc
* we have. */
struct ttm_bo_kmap_obj cache_kmap;
int next_cursor;
};
......
......@@ -40,6 +40,7 @@
#include <drm/drmP.h>
#include <drm/drm_crtc.h>
#include <drm/drm_fb_helper.h>
#include <drm/drm_crtc_helper.h>
#include "ast_drv.h"
static void ast_dirty_update(struct ast_fbdev *afbdev,
......@@ -145,9 +146,10 @@ static int astfb_create_object(struct ast_fbdev *afbdev,
return ret;
}
static int astfb_create(struct ast_fbdev *afbdev,
static int astfb_create(struct drm_fb_helper *helper,
struct drm_fb_helper_surface_size *sizes)
{
struct ast_fbdev *afbdev = (struct ast_fbdev *)helper;
struct drm_device *dev = afbdev->helper.dev;
struct drm_mode_fb_cmd2 mode_cmd;
struct drm_framebuffer *fb;
......@@ -248,26 +250,10 @@ static void ast_fb_gamma_get(struct drm_crtc *crtc, u16 *red, u16 *green,
*blue = ast_crtc->lut_b[regno] << 8;
}
static int ast_find_or_create_single(struct drm_fb_helper *helper,
struct drm_fb_helper_surface_size *sizes)
{
struct ast_fbdev *afbdev = (struct ast_fbdev *)helper;
int new_fb = 0;
int ret;
if (!helper->fb) {
ret = astfb_create(afbdev, sizes);
if (ret)
return ret;
new_fb = 1;
}
return new_fb;
}
static struct drm_fb_helper_funcs ast_fb_helper_funcs = {
.gamma_set = ast_fb_gamma_set,
.gamma_get = ast_fb_gamma_get,
.fb_probe = ast_find_or_create_single,
.fb_probe = astfb_create,
};
static void ast_fbdev_destroy(struct drm_device *dev,
......@@ -290,6 +276,7 @@ static void ast_fbdev_destroy(struct drm_device *dev,
drm_fb_helper_fini(&afbdev->helper);
vfree(afbdev->sysram);
drm_framebuffer_unregister_private(&afb->base);
drm_framebuffer_cleanup(&afb->base);
}
......@@ -313,6 +300,10 @@ int ast_fbdev_init(struct drm_device *dev)
}
drm_fb_helper_single_add_all_connectors(&afbdev->helper);
/* disable all the possible outputs/crtcs before entering KMS mode */
drm_helper_disable_unused_functions(dev);
drm_fb_helper_initial_config(&afbdev->helper, 32);
return 0;
}
......
......@@ -246,16 +246,8 @@ static void ast_user_framebuffer_destroy(struct drm_framebuffer *fb)
kfree(fb);
}
static int ast_user_framebuffer_create_handle(struct drm_framebuffer *fb,
struct drm_file *file,
unsigned int *handle)
{
return -EINVAL;
}
static const struct drm_framebuffer_funcs ast_fb_funcs = {
.destroy = ast_user_framebuffer_destroy,
.create_handle = ast_user_framebuffer_create_handle,
};
......@@ -266,13 +258,13 @@ int ast_framebuffer_init(struct drm_device *dev,
{
int ret;
drm_helper_mode_fill_fb_struct(&ast_fb->base, mode_cmd);
ast_fb->obj = obj;
ret = drm_framebuffer_init(dev, &ast_fb->base, &ast_fb_funcs);
if (ret) {
DRM_ERROR("framebuffer init failed %d\n", ret);
return ret;
}
drm_helper_mode_fill_fb_struct(&ast_fb->base, mode_cmd);
ast_fb->obj = obj;
return 0;
}
......
......@@ -11,6 +11,7 @@
#include <linux/module.h>
#include <drm/drmP.h>
#include <drm/drm_fb_helper.h>
#include <drm/drm_crtc_helper.h>
#include <linux/fb.h>
......@@ -120,9 +121,10 @@ static int cirrusfb_create_object(struct cirrus_fbdev *afbdev,
return ret;
}
static int cirrusfb_create(struct cirrus_fbdev *gfbdev,
static int cirrusfb_create(struct drm_fb_helper *helper,
struct drm_fb_helper_surface_size *sizes)
{
struct cirrus_fbdev *gfbdev = (struct cirrus_fbdev *)helper;
struct drm_device *dev = gfbdev->helper.dev;
struct cirrus_device *cdev = gfbdev->helper.dev->dev_private;
struct fb_info *info;
......@@ -219,23 +221,6 @@ static int cirrusfb_create(struct cirrus_fbdev *gfbdev,
return ret;
}
static int cirrus_fb_find_or_create_single(struct drm_fb_helper *helper,
struct drm_fb_helper_surface_size
*sizes)
{
struct cirrus_fbdev *gfbdev = (struct cirrus_fbdev *)helper;
int new_fb = 0;
int ret;
if (!helper->fb) {
ret = cirrusfb_create(gfbdev, sizes);
if (ret)
return ret;
new_fb = 1;
}
return new_fb;
}
static int cirrus_fbdev_destroy(struct drm_device *dev,
struct cirrus_fbdev *gfbdev)
{
......@@ -258,6 +243,7 @@ static int cirrus_fbdev_destroy(struct drm_device *dev,
vfree(gfbdev->sysram);
drm_fb_helper_fini(&gfbdev->helper);
drm_framebuffer_unregister_private(&gfb->base);
drm_framebuffer_cleanup(&gfb->base);
return 0;
......@@ -266,7 +252,7 @@ static int cirrus_fbdev_destroy(struct drm_device *dev,
static struct drm_fb_helper_funcs cirrus_fb_helper_funcs = {
.gamma_set = cirrus_crtc_fb_gamma_set,
.gamma_get = cirrus_crtc_fb_gamma_get,
.fb_probe = cirrus_fb_find_or_create_single,
.fb_probe = cirrusfb_create,
};
int cirrus_fbdev_init(struct cirrus_device *cdev)
......@@ -290,6 +276,9 @@ int cirrus_fbdev_init(struct cirrus_device *cdev)
return ret;
}
drm_fb_helper_single_add_all_connectors(&gfbdev->helper);
/* disable all the possible outputs/crtcs before entering KMS mode */
drm_helper_disable_unused_functions(cdev->dev);
drm_fb_helper_initial_config(&gfbdev->helper, bpp_sel);
return 0;
......
......@@ -23,16 +23,8 @@ static void cirrus_user_framebuffer_destroy(struct drm_framebuffer *fb)
kfree(fb);
}
static int cirrus_user_framebuffer_create_handle(struct drm_framebuffer *fb,
struct drm_file *file_priv,
unsigned int *handle)
{
return 0;
}
static const struct drm_framebuffer_funcs cirrus_fb_funcs = {
.destroy = cirrus_user_framebuffer_destroy,
.create_handle = cirrus_user_framebuffer_create_handle,
};
int cirrus_framebuffer_init(struct drm_device *dev,
......@@ -42,13 +34,13 @@ int cirrus_framebuffer_init(struct drm_device *dev,
{
int ret;
drm_helper_mode_fill_fb_struct(&gfb->base, mode_cmd);
gfb->obj = obj;
ret = drm_framebuffer_init(dev, &gfb->base, &cirrus_fb_funcs);
if (ret) {
DRM_ERROR("drm_framebuffer_init failed: %d\n", ret);
return ret;
}
drm_helper_mode_fill_fb_struct(&gfb->base, mode_cmd);
gfb->obj = obj;
return 0;
}
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
......@@ -123,3 +123,66 @@ void drm_i2c_encoder_destroy(struct drm_encoder *drm_encoder)
module_put(module);
}
EXPORT_SYMBOL(drm_i2c_encoder_destroy);
/*
* Wrapper fxns which can be plugged in to drm_encoder_helper_funcs:
*/
static inline struct drm_encoder_slave_funcs *
get_slave_funcs(struct drm_encoder *enc)
{
return to_encoder_slave(enc)->slave_funcs;
}
void drm_i2c_encoder_dpms(struct drm_encoder *encoder, int mode)
{
get_slave_funcs(encoder)->dpms(encoder, mode);
}
EXPORT_SYMBOL(drm_i2c_encoder_dpms);
bool drm_i2c_encoder_mode_fixup(struct drm_encoder *encoder,
const struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode)
{
return get_slave_funcs(encoder)->mode_fixup(encoder, mode, adjusted_mode);
}
EXPORT_SYMBOL(drm_i2c_encoder_mode_fixup);
void drm_i2c_encoder_prepare(struct drm_encoder *encoder)
{
drm_i2c_encoder_dpms(encoder, DRM_MODE_DPMS_OFF);
}
EXPORT_SYMBOL(drm_i2c_encoder_prepare);
void drm_i2c_encoder_commit(struct drm_encoder *encoder)
{
drm_i2c_encoder_dpms(encoder, DRM_MODE_DPMS_ON);
}
EXPORT_SYMBOL(drm_i2c_encoder_commit);
void drm_i2c_encoder_mode_set(struct drm_encoder *encoder,
struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode)
{
get_slave_funcs(encoder)->mode_set(encoder, mode, adjusted_mode);
}
EXPORT_SYMBOL(drm_i2c_encoder_mode_set);
enum drm_connector_status drm_i2c_encoder_detect(struct drm_encoder *encoder,
struct drm_connector *connector)
{
return get_slave_funcs(encoder)->detect(encoder, connector);
}
EXPORT_SYMBOL(drm_i2c_encoder_detect);
void drm_i2c_encoder_save(struct drm_encoder *encoder)
{
get_slave_funcs(encoder)->save(encoder);
}
EXPORT_SYMBOL(drm_i2c_encoder_save);
void drm_i2c_encoder_restore(struct drm_encoder *encoder)
{
get_slave_funcs(encoder)->restore(encoder);
}
EXPORT_SYMBOL(drm_i2c_encoder_restore);
......@@ -85,6 +85,11 @@ static struct drm_fb_cma *drm_fb_cma_alloc(struct drm_device *dev,
if (!fb_cma)
return ERR_PTR(-ENOMEM);
drm_helper_mode_fill_fb_struct(&fb_cma->fb, mode_cmd);
for (i = 0; i < num_planes; i++)
fb_cma->obj[i] = obj[i];
ret = drm_framebuffer_init(dev, &fb_cma->fb, &drm_fb_cma_funcs);
if (ret) {
dev_err(dev->dev, "Failed to initalize framebuffer: %d\n", ret);
......@@ -92,11 +97,6 @@ static struct drm_fb_cma *drm_fb_cma_alloc(struct drm_device *dev,
return ERR_PTR(ret);
}
drm_helper_mode_fill_fb_struct(&fb_cma->fb, mode_cmd);
for (i = 0; i < num_planes; i++)
fb_cma->obj[i] = obj[i];
return fb_cma;
}
......@@ -180,6 +180,59 @@ struct drm_gem_cma_object *drm_fb_cma_get_gem_obj(struct drm_framebuffer *fb,
}
EXPORT_SYMBOL_GPL(drm_fb_cma_get_gem_obj);
#ifdef CONFIG_DEBUG_FS
/**
* drm_fb_cma_describe() - Helper to dump information about a single
* CMA framebuffer object
*/
void drm_fb_cma_describe(struct drm_framebuffer *fb, struct seq_file *m)
{
struct drm_fb_cma *fb_cma = to_fb_cma(fb);
int i, n = drm_format_num_planes(fb->pixel_format);
seq_printf(m, "fb: %dx%d@%4.4s\n", fb->width, fb->height,
(char *)&fb->pixel_format);
for (i = 0; i < n; i++) {
seq_printf(m, " %d: offset=%d pitch=%d, obj: ",
i, fb->offsets[i], fb->pitches[i]);
drm_gem_cma_describe(fb_cma->obj[i], m);
}
}
EXPORT_SYMBOL_GPL(drm_fb_cma_describe);
/**
* drm_fb_cma_debugfs_show() - Helper to list CMA framebuffer objects
* in debugfs.
*/
int drm_fb_cma_debugfs_show(struct seq_file *m, void *arg)
{
struct drm_info_node *node = (struct drm_info_node *) m->private;
struct drm_device *dev = node->minor->dev;
struct drm_framebuffer *fb;
int ret;
ret = mutex_lock_interruptible(&dev->mode_config.mutex);
if (ret)
return ret;
ret = mutex_lock_interruptible(&dev->struct_mutex);
if (ret) {
mutex_unlock(&dev->mode_config.mutex);
return ret;
}
list_for_each_entry(fb, &dev->mode_config.fb_list, head)
drm_fb_cma_describe(fb, m);
mutex_unlock(&dev->struct_mutex);
mutex_unlock(&dev->mode_config.mutex);
return 0;
}
EXPORT_SYMBOL_GPL(drm_fb_cma_debugfs_show);
#endif
static struct fb_ops drm_fbdev_cma_ops = {
.owner = THIS_MODULE,
.fb_fillrect = sys_fillrect,
......@@ -266,6 +319,7 @@ static int drm_fbdev_cma_create(struct drm_fb_helper *helper,
return 0;
err_drm_fb_cma_destroy:
drm_framebuffer_unregister_private(fb);
drm_fb_cma_destroy(fb);
err_framebuffer_release:
framebuffer_release(fbi);
......@@ -274,23 +328,8 @@ static int drm_fbdev_cma_create(struct drm_fb_helper *helper,
return ret;
}
static int drm_fbdev_cma_probe(struct drm_fb_helper *helper,
struct drm_fb_helper_surface_size *sizes)
{
int ret = 0;
if (!helper->fb) {
ret = drm_fbdev_cma_create(helper, sizes);
if (ret < 0)
return ret;
ret = 1;
}
return ret;
}
static struct drm_fb_helper_funcs drm_fb_cma_helper_funcs = {
.fb_probe = drm_fbdev_cma_probe,
.fb_probe = drm_fbdev_cma_create,
};
/**
......@@ -332,6 +371,9 @@ struct drm_fbdev_cma *drm_fbdev_cma_init(struct drm_device *dev,
}
/* disable all the possible outputs/crtcs before entering KMS mode */
drm_helper_disable_unused_functions(dev);
ret = drm_fb_helper_initial_config(helper, preferred_bpp);
if (ret < 0) {
dev_err(dev->dev, "Failed to set inital hw configuration.\n");
......@@ -370,8 +412,10 @@ void drm_fbdev_cma_fini(struct drm_fbdev_cma *fbdev_cma)
framebuffer_release(info);
}
if (fbdev_cma->fb)
if (fbdev_cma->fb) {
drm_framebuffer_unregister_private(&fbdev_cma->fb->fb);
drm_fb_cma_destroy(&fbdev_cma->fb->fb);
}
drm_fb_helper_fini(&fbdev_cma->fb_helper);
kfree(fbdev_cma);
......@@ -386,8 +430,13 @@ EXPORT_SYMBOL_GPL(drm_fbdev_cma_fini);
*/
void drm_fbdev_cma_restore_mode(struct drm_fbdev_cma *fbdev_cma)
{
if (fbdev_cma)
if (fbdev_cma) {
struct drm_device *dev = fbdev_cma->fb_helper.dev;
drm_modeset_lock_all(dev);
drm_fb_helper_restore_fbdev_mode(&fbdev_cma->fb_helper);
drm_modeset_unlock_all(dev);
}
}
EXPORT_SYMBOL_GPL(drm_fbdev_cma_restore_mode);
......
This diff is collapsed.
......@@ -276,6 +276,7 @@ static int drm_open_helper(struct inode *inode, struct file *filp,
INIT_LIST_HEAD(&priv->lhead);
INIT_LIST_HEAD(&priv->fbs);
mutex_init(&priv->fbs_lock);
INIT_LIST_HEAD(&priv->event_list);
init_waitqueue_head(&priv->event_wait);
priv->event_space = 4096; /* set aside 4k for event buffer */
......
......@@ -249,3 +249,24 @@ int drm_gem_cma_dumb_destroy(struct drm_file *file_priv,
return drm_gem_handle_delete(file_priv, handle);
}
EXPORT_SYMBOL_GPL(drm_gem_cma_dumb_destroy);
#ifdef CONFIG_DEBUG_FS
void drm_gem_cma_describe(struct drm_gem_cma_object *cma_obj, struct seq_file *m)
{
struct drm_gem_object *obj = &cma_obj->base;
struct drm_device *dev = obj->dev;
uint64_t off = 0;
WARN_ON(!mutex_is_locked(&dev->struct_mutex));
if (obj->map_list.map)
off = (uint64_t)obj->map_list.hash.key;
seq_printf(m, "%2d (%2d) %08llx %08Zx %p %d",
obj->name, obj->refcount.refcount.counter,
off, cma_obj->paddr, cma_obj->vaddr, obj->size);
seq_printf(m, "\n");
}
EXPORT_SYMBOL_GPL(drm_gem_cma_describe);
#endif
......@@ -505,6 +505,7 @@ void drm_calc_timestamping_constants(struct drm_crtc *crtc)
/* Valid dotclock? */
if (dotclock > 0) {
int frame_size;
/* Convert scanline length in pixels and video dot clock to
* line duration, frame duration and pixel duration in
* nanoseconds:
......@@ -512,7 +513,10 @@ void drm_calc_timestamping_constants(struct drm_crtc *crtc)
pixeldur_ns = (s64) div64_u64(1000000000, dotclock);
linedur_ns = (s64) div64_u64(((u64) crtc->hwmode.crtc_htotal *
1000000000), dotclock);
framedur_ns = (s64) crtc->hwmode.crtc_vtotal * linedur_ns;
frame_size = crtc->hwmode.crtc_htotal *
crtc->hwmode.crtc_vtotal;
framedur_ns = (s64) div64_u64((u64) frame_size * 1000000000,
dotclock);
} else
DRM_ERROR("crtc %d: Can't calculate constants, dotclock = 0!\n",
crtc->base.id);
......@@ -863,6 +867,7 @@ void drm_send_vblank_event(struct drm_device *dev, int crtc,
now = get_drm_timestamp();
}
e->pipe = crtc;
send_vblank_event(dev, e, seq, &now);
}
EXPORT_SYMBOL(drm_send_vblank_event);
......@@ -1218,8 +1223,9 @@ int drm_wait_vblank(struct drm_device *dev, void *data,
int ret;
unsigned int flags, seq, crtc, high_crtc;
if ((!drm_dev_to_irq(dev)) || (!dev->irq_enabled))
return -EINVAL;
if (drm_core_check_feature(dev, DRIVER_HAVE_IRQ))
if ((!drm_dev_to_irq(dev)) || (!dev->irq_enabled))
return -EINVAL;
if (vblwait->request.type & _DRM_VBLANK_SIGNAL)
return -EINVAL;
......
......@@ -102,20 +102,6 @@ int drm_mm_pre_get(struct drm_mm *mm)
}
EXPORT_SYMBOL(drm_mm_pre_get);
static inline unsigned long drm_mm_hole_node_start(struct drm_mm_node *hole_node)
{
return hole_node->start + hole_node->size;
}
static inline unsigned long drm_mm_hole_node_end(struct drm_mm_node *hole_node)
{
struct drm_mm_node *next_node =
list_entry(hole_node->node_list.next, struct drm_mm_node,
node_list);
return next_node->start;
}
static void drm_mm_insert_helper(struct drm_mm_node *hole_node,
struct drm_mm_node *node,
unsigned long size, unsigned alignment,
......@@ -127,7 +113,7 @@ static void drm_mm_insert_helper(struct drm_mm_node *hole_node,
unsigned long adj_start = hole_start;
unsigned long adj_end = hole_end;
BUG_ON(!hole_node->hole_follows || node->allocated);
BUG_ON(node->allocated);
if (mm->color_adjust)
mm->color_adjust(hole_node, color, &adj_start, &adj_end);
......@@ -155,12 +141,57 @@ static void drm_mm_insert_helper(struct drm_mm_node *hole_node,
BUG_ON(node->start + node->size > adj_end);
node->hole_follows = 0;
if (node->start + node->size < hole_end) {
if (__drm_mm_hole_node_start(node) < hole_end) {
list_add(&node->hole_stack, &mm->hole_stack);
node->hole_follows = 1;
}
}
struct drm_mm_node *drm_mm_create_block(struct drm_mm *mm,
unsigned long start,
unsigned long size,
bool atomic)
{
struct drm_mm_node *hole, *node;
unsigned long end = start + size;
unsigned long hole_start;
unsigned long hole_end;
drm_mm_for_each_hole(hole, mm, hole_start, hole_end) {
if (hole_start > start || hole_end < end)
continue;
node = drm_mm_kmalloc(mm, atomic);
if (unlikely(node == NULL))
return NULL;
node->start = start;
node->size = size;
node->mm = mm;
node->allocated = 1;
INIT_LIST_HEAD(&node->hole_stack);
list_add(&node->node_list, &hole->node_list);
if (start == hole_start) {
hole->hole_follows = 0;
list_del_init(&hole->hole_stack);
}
node->hole_follows = 0;
if (end != hole_end) {
list_add(&node->hole_stack, &mm->hole_stack);
node->hole_follows = 1;
}
return node;
}
WARN(1, "no hole found for block 0x%lx + 0x%lx\n", start, size);
return NULL;
}
EXPORT_SYMBOL(drm_mm_create_block);
struct drm_mm_node *drm_mm_get_block_generic(struct drm_mm_node *hole_node,
unsigned long size,
unsigned alignment,
......@@ -253,7 +284,7 @@ static void drm_mm_insert_helper_range(struct drm_mm_node *hole_node,
BUG_ON(node->start + node->size > end);
node->hole_follows = 0;
if (node->start + node->size < hole_end) {
if (__drm_mm_hole_node_start(node) < hole_end) {
list_add(&node->hole_stack, &mm->hole_stack);
node->hole_follows = 1;
}
......@@ -327,12 +358,13 @@ void drm_mm_remove_node(struct drm_mm_node *node)
list_entry(node->node_list.prev, struct drm_mm_node, node_list);
if (node->hole_follows) {
BUG_ON(drm_mm_hole_node_start(node)
== drm_mm_hole_node_end(node));
BUG_ON(__drm_mm_hole_node_start(node) ==
__drm_mm_hole_node_end(node));
list_del(&node->hole_stack);
} else
BUG_ON(drm_mm_hole_node_start(node)
!= drm_mm_hole_node_end(node));
BUG_ON(__drm_mm_hole_node_start(node) !=
__drm_mm_hole_node_end(node));
if (!prev_node->hole_follows) {
prev_node->hole_follows = 1;
......@@ -390,6 +422,8 @@ struct drm_mm_node *drm_mm_search_free_generic(const struct drm_mm *mm,
{
struct drm_mm_node *entry;
struct drm_mm_node *best;
unsigned long adj_start;
unsigned long adj_end;
unsigned long best_size;
BUG_ON(mm->scanned_blocks);
......@@ -397,17 +431,13 @@ struct drm_mm_node *drm_mm_search_free_generic(const struct drm_mm *mm,
best = NULL;
best_size = ~0UL;
list_for_each_entry(entry, &mm->hole_stack, hole_stack) {
unsigned long adj_start = drm_mm_hole_node_start(entry);
unsigned long adj_end = drm_mm_hole_node_end(entry);
drm_mm_for_each_hole(entry, mm, adj_start, adj_end) {
if (mm->color_adjust) {
mm->color_adjust(entry, color, &adj_start, &adj_end);
if (adj_end <= adj_start)
continue;
}
BUG_ON(!entry->hole_follows);
if (!check_free_hole(adj_start, adj_end, size, alignment))
continue;
......@@ -434,6 +464,8 @@ struct drm_mm_node *drm_mm_search_free_in_range_generic(const struct drm_mm *mm,
{
struct drm_mm_node *entry;
struct drm_mm_node *best;
unsigned long adj_start;
unsigned long adj_end;
unsigned long best_size;
BUG_ON(mm->scanned_blocks);
......@@ -441,13 +473,11 @@ struct drm_mm_node *drm_mm_search_free_in_range_generic(const struct drm_mm *mm,
best = NULL;
best_size = ~0UL;
list_for_each_entry(entry, &mm->hole_stack, hole_stack) {
unsigned long adj_start = drm_mm_hole_node_start(entry) < start ?
start : drm_mm_hole_node_start(entry);
unsigned long adj_end = drm_mm_hole_node_end(entry) > end ?
end : drm_mm_hole_node_end(entry);
BUG_ON(!entry->hole_follows);
drm_mm_for_each_hole(entry, mm, adj_start, adj_end) {
if (adj_start < start)
adj_start = start;
if (adj_end > end)
adj_end = end;
if (mm->color_adjust) {
mm->color_adjust(entry, color, &adj_start, &adj_end);
......
......@@ -35,6 +35,8 @@
#include <linux/export.h>
#include <drm/drmP.h>
#include <drm/drm_crtc.h>
#include <video/of_videomode.h>
#include <video/videomode.h>
/**
* drm_mode_debug_printmodeline - debug print a mode
......@@ -504,6 +506,74 @@ drm_gtf_mode(struct drm_device *dev, int hdisplay, int vdisplay, int vrefresh,
}
EXPORT_SYMBOL(drm_gtf_mode);
#if IS_ENABLED(CONFIG_VIDEOMODE)
int drm_display_mode_from_videomode(const struct videomode *vm,
struct drm_display_mode *dmode)
{
dmode->hdisplay = vm->hactive;
dmode->hsync_start = dmode->hdisplay + vm->hfront_porch;
dmode->hsync_end = dmode->hsync_start + vm->hsync_len;
dmode->htotal = dmode->hsync_end + vm->hback_porch;
dmode->vdisplay = vm->vactive;
dmode->vsync_start = dmode->vdisplay + vm->vfront_porch;
dmode->vsync_end = dmode->vsync_start + vm->vsync_len;
dmode->vtotal = dmode->vsync_end + vm->vback_porch;
dmode->clock = vm->pixelclock / 1000;
dmode->flags = 0;
if (vm->dmt_flags & VESA_DMT_HSYNC_HIGH)
dmode->flags |= DRM_MODE_FLAG_PHSYNC;
else if (vm->dmt_flags & VESA_DMT_HSYNC_LOW)
dmode->flags |= DRM_MODE_FLAG_NHSYNC;
if (vm->dmt_flags & VESA_DMT_VSYNC_HIGH)
dmode->flags |= DRM_MODE_FLAG_PVSYNC;
else if (vm->dmt_flags & VESA_DMT_VSYNC_LOW)
dmode->flags |= DRM_MODE_FLAG_NVSYNC;
if (vm->data_flags & DISPLAY_FLAGS_INTERLACED)
dmode->flags |= DRM_MODE_FLAG_INTERLACE;
if (vm->data_flags & DISPLAY_FLAGS_DOUBLESCAN)
dmode->flags |= DRM_MODE_FLAG_DBLSCAN;
drm_mode_set_name(dmode);
return 0;
}
EXPORT_SYMBOL_GPL(drm_display_mode_from_videomode);
#endif
#if IS_ENABLED(CONFIG_OF_VIDEOMODE)
/**
* of_get_drm_display_mode - get a drm_display_mode from devicetree
* @np: device_node with the timing specification
* @dmode: will be set to the return value
* @index: index into the list of display timings in devicetree
*
* This function is expensive and should only be used, if only one mode is to be
* read from DT. To get multiple modes start with of_get_display_timings and
* work with that instead.
*/
int of_get_drm_display_mode(struct device_node *np,
struct drm_display_mode *dmode, int index)
{
struct videomode vm;
int ret;
ret = of_get_videomode(np, &vm, index);
if (ret)
return ret;
drm_display_mode_from_videomode(&vm, dmode);
pr_debug("%s: got %dx%d display mode from %s\n",
of_node_full_name(np), vm.hactive, vm.vactive, np->name);
drm_mode_debug_printmodeline(dmode);
return 0;
}
EXPORT_SYMBOL_GPL(of_get_drm_display_mode);
#endif
/**
* drm_mode_set_name - set the name on a mode
* @mode: name will be set in this mode
......
......@@ -439,78 +439,67 @@ int drm_pci_init(struct drm_driver *driver, struct pci_driver *pdriver)
return 0;
}
#else
int drm_pci_init(struct drm_driver *driver, struct pci_driver *pdriver)
{
return -1;
}
#endif
EXPORT_SYMBOL(drm_pci_init);
/*@}*/
void drm_pci_exit(struct drm_driver *driver, struct pci_driver *pdriver)
{
struct drm_device *dev, *tmp;
DRM_DEBUG("\n");
if (driver->driver_features & DRIVER_MODESET) {
pci_unregister_driver(pdriver);
} else {
list_for_each_entry_safe(dev, tmp, &driver->device_list, driver_item)
drm_put_dev(dev);
}
DRM_INFO("Module unloaded\n");
}
EXPORT_SYMBOL(drm_pci_exit);
int drm_pcie_get_speed_cap_mask(struct drm_device *dev, u32 *mask)
{
struct pci_dev *root;
int pos;
u32 lnkcap = 0, lnkcap2 = 0;
u32 lnkcap, lnkcap2;
*mask = 0;
if (!dev->pdev)
return -EINVAL;
if (!pci_is_pcie(dev->pdev))
return -EINVAL;
root = dev->pdev->bus->self;
pos = pci_pcie_cap(root);
if (!pos)
return -EINVAL;
/* we've been informed via and serverworks don't make the cut */
if (root->vendor == PCI_VENDOR_ID_VIA ||
root->vendor == PCI_VENDOR_ID_SERVERWORKS)
return -EINVAL;
pci_read_config_dword(root, pos + PCI_EXP_LNKCAP, &lnkcap);
pci_read_config_dword(root, pos + PCI_EXP_LNKCAP2, &lnkcap2);
pcie_capability_read_dword(root, PCI_EXP_LNKCAP, &lnkcap);
pcie_capability_read_dword(root, PCI_EXP_LNKCAP2, &lnkcap2);
lnkcap &= PCI_EXP_LNKCAP_SLS;
lnkcap2 &= 0xfe;
if (lnkcap2) { /* PCIE GEN 3.0 */
if (lnkcap2) { /* PCIe r3.0-compliant */
if (lnkcap2 & PCI_EXP_LNKCAP2_SLS_2_5GB)
*mask |= DRM_PCIE_SPEED_25;
if (lnkcap2 & PCI_EXP_LNKCAP2_SLS_5_0GB)
*mask |= DRM_PCIE_SPEED_50;
if (lnkcap2 & PCI_EXP_LNKCAP2_SLS_8_0GB)
*mask |= DRM_PCIE_SPEED_80;
} else {
if (lnkcap & 1)
} else { /* pre-r3.0 */
if (lnkcap & PCI_EXP_LNKCAP_SLS_2_5GB)
*mask |= DRM_PCIE_SPEED_25;
if (lnkcap & 2)
*mask |= DRM_PCIE_SPEED_50;
if (lnkcap & PCI_EXP_LNKCAP_SLS_5_0GB)
*mask |= (DRM_PCIE_SPEED_25 | DRM_PCIE_SPEED_50);
}
DRM_INFO("probing gen 2 caps for device %x:%x = %x/%x\n", root->vendor, root->device, lnkcap, lnkcap2);
return 0;
}
EXPORT_SYMBOL(drm_pcie_get_speed_cap_mask);
#else
int drm_pci_init(struct drm_driver *driver, struct pci_driver *pdriver)
{
return -1;
}
#endif
EXPORT_SYMBOL(drm_pci_init);
/*@}*/
void drm_pci_exit(struct drm_driver *driver, struct pci_driver *pdriver)
{
struct drm_device *dev, *tmp;
DRM_DEBUG("\n");
if (driver->driver_features & DRIVER_MODESET) {
pci_unregister_driver(pdriver);
} else {
list_for_each_entry_safe(dev, tmp, &driver->device_list, driver_item)
drm_put_dev(dev);
}
DRM_INFO("Module unloaded\n");
}
EXPORT_SYMBOL(drm_pci_exit);
This diff is collapsed.
......@@ -18,7 +18,7 @@ int drm_get_usb_dev(struct usb_interface *interface,
usbdev = interface_to_usbdev(interface);
dev->usbdev = usbdev;
dev->dev = &usbdev->dev;
dev->dev = &interface->dev;
mutex_lock(&drm_global_mutex);
......
This diff is collapsed.
This diff is collapsed.
......@@ -19,6 +19,7 @@
#include <linux/workqueue.h>
#include <linux/dma-mapping.h>
#include <linux/dma-attrs.h>
#include <linux/of.h>
#include <drm/drmP.h>
#include <drm/exynos_drm.h>
......@@ -429,7 +430,7 @@ static dma_addr_t *g2d_userptr_get_dma_addr(struct drm_device *drm_dev,
g2d_userptr->pages = pages;
sgt = kzalloc(sizeof *sgt, GFP_KERNEL);
sgt = kzalloc(sizeof(*sgt), GFP_KERNEL);
if (!sgt) {
DRM_ERROR("failed to allocate sg table.\n");
ret = -ENOMEM;
......@@ -1239,6 +1240,14 @@ static int g2d_resume(struct device *dev)
static SIMPLE_DEV_PM_OPS(g2d_pm_ops, g2d_suspend, g2d_resume);
#ifdef CONFIG_OF
static const struct of_device_id exynos_g2d_match[] = {
{ .compatible = "samsung,exynos5250-g2d" },
{},
};
MODULE_DEVICE_TABLE(of, exynos_g2d_match);
#endif
struct platform_driver g2d_driver = {
.probe = g2d_probe,
.remove = g2d_remove,
......@@ -1246,5 +1255,6 @@ struct platform_driver g2d_driver = {
.name = "s5p-g2d",
.owner = THIS_MODULE,
.pm = &g2d_pm_ops,
.of_match_table = of_match_ptr(exynos_g2d_match),
},
};
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
......@@ -5,3 +5,6 @@ obj-$(CONFIG_DRM_I2C_CH7006) += ch7006.o
sil164-y := sil164_drv.o
obj-$(CONFIG_DRM_I2C_SIL164) += sil164.o
tda998x-y := tda998x_drv.o
obj-$(CONFIG_DRM_I2C_NXP_TDA998X) += tda998x.o
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment