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 de0babd60d
("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
...
This commit is contained in:
commit
fffddfd6c8
@ -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-<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-<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
|
||||
|
59
Documentation/devicetree/bindings/drm/tilcdc/panel.txt
Normal file
59
Documentation/devicetree/bindings/drm/tilcdc/panel.txt
Normal file
@ -0,0 +1,59 @@
|
||||
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>;
|
||||
};
|
||||
};
|
||||
};
|
18
Documentation/devicetree/bindings/drm/tilcdc/slave.txt
Normal file
18
Documentation/devicetree/bindings/drm/tilcdc/slave.txt
Normal file
@ -0,0 +1,18 @@
|
||||
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>;
|
||||
};
|
21
Documentation/devicetree/bindings/drm/tilcdc/tfp410.txt
Normal file
21
Documentation/devicetree/bindings/drm/tilcdc/tfp410.txt
Normal file
@ -0,0 +1,21 @@
|
||||
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>;
|
||||
};
|
21
Documentation/devicetree/bindings/drm/tilcdc/tilcdc.txt
Normal file
21
Documentation/devicetree/bindings/drm/tilcdc/tilcdc.txt
Normal file
@ -0,0 +1,21 @@
|
||||
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";
|
||||
};
|
109
Documentation/devicetree/bindings/video/display-timing.txt
Normal file
109
Documentation/devicetree/bindings/video/display-timing.txt
Normal file
@ -0,0 +1,109 @@
|
||||
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>;
|
||||
};
|
81
Documentation/thermal/nouveau_thermal
Normal file
81
Documentation/thermal/nouveau_thermal
Normal file
@ -0,0 +1,81 @@
|
||||
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);
|
||||
|
||||
|
@ -1 +1 @@
|
||||
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 @@ out_iounmap:
|
||||
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;
|
||||
}
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -29,11 +29,11 @@
|
||||
*/
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/hdmi.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/module.h>
|
||||
#include <drm/drmP.h>
|
||||
#include <drm/drm_edid.h>
|
||||
#include "drm_edid_modes.h"
|
||||
|
||||
#define version_greater(edid, maj, min) \
|
||||
(((edid)->version > (maj)) || \
|
||||
@ -87,9 +87,6 @@ static struct edid_quirk {
|
||||
int product_id;
|
||||
u32 quirks;
|
||||
} edid_quirk_list[] = {
|
||||
/* ASUS VW222S */
|
||||
{ "ACI", 0x22a2, EDID_QUIRK_FORCE_REDUCED_BLANKING },
|
||||
|
||||
/* Acer AL1706 */
|
||||
{ "ACR", 44358, EDID_QUIRK_PREFER_LARGE_60 },
|
||||
/* Acer F51 */
|
||||
@ -130,6 +127,746 @@ static struct edid_quirk {
|
||||
{ "VSC", 5020, EDID_QUIRK_FORCE_REDUCED_BLANKING },
|
||||
};
|
||||
|
||||
/*
|
||||
* Autogenerated from the DMT spec.
|
||||
* This table is copied from xfree86/modes/xf86EdidModes.c.
|
||||
*/
|
||||
static const struct drm_display_mode drm_dmt_modes[] = {
|
||||
/* 640x350@85Hz */
|
||||
{ DRM_MODE("640x350", DRM_MODE_TYPE_DRIVER, 31500, 640, 672,
|
||||
736, 832, 0, 350, 382, 385, 445, 0,
|
||||
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC) },
|
||||
/* 640x400@85Hz */
|
||||
{ DRM_MODE("640x400", DRM_MODE_TYPE_DRIVER, 31500, 640, 672,
|
||||
736, 832, 0, 400, 401, 404, 445, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
|
||||
/* 720x400@85Hz */
|
||||
{ DRM_MODE("720x400", DRM_MODE_TYPE_DRIVER, 35500, 720, 756,
|
||||
828, 936, 0, 400, 401, 404, 446, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
|
||||
/* 640x480@60Hz */
|
||||
{ DRM_MODE("640x480", DRM_MODE_TYPE_DRIVER, 25175, 640, 656,
|
||||
752, 800, 0, 480, 489, 492, 525, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
|
||||
/* 640x480@72Hz */
|
||||
{ DRM_MODE("640x480", DRM_MODE_TYPE_DRIVER, 31500, 640, 664,
|
||||
704, 832, 0, 480, 489, 492, 520, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
|
||||
/* 640x480@75Hz */
|
||||
{ DRM_MODE("640x480", DRM_MODE_TYPE_DRIVER, 31500, 640, 656,
|
||||
720, 840, 0, 480, 481, 484, 500, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
|
||||
/* 640x480@85Hz */
|
||||
{ DRM_MODE("640x480", DRM_MODE_TYPE_DRIVER, 36000, 640, 696,
|
||||
752, 832, 0, 480, 481, 484, 509, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
|
||||
/* 800x600@56Hz */
|
||||
{ DRM_MODE("800x600", DRM_MODE_TYPE_DRIVER, 36000, 800, 824,
|
||||
896, 1024, 0, 600, 601, 603, 625, 0,
|
||||
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
|
||||
/* 800x600@60Hz */
|
||||
{ DRM_MODE("800x600", DRM_MODE_TYPE_DRIVER, 40000, 800, 840,
|
||||
968, 1056, 0, 600, 601, 605, 628, 0,
|
||||
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
|
||||
/* 800x600@72Hz */
|
||||
{ DRM_MODE("800x600", DRM_MODE_TYPE_DRIVER, 50000, 800, 856,
|
||||
976, 1040, 0, 600, 637, 643, 666, 0,
|
||||
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
|
||||
/* 800x600@75Hz */
|
||||
{ DRM_MODE("800x600", DRM_MODE_TYPE_DRIVER, 49500, 800, 816,
|
||||
896, 1056, 0, 600, 601, 604, 625, 0,
|
||||
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
|
||||
/* 800x600@85Hz */
|
||||
{ DRM_MODE("800x600", DRM_MODE_TYPE_DRIVER, 56250, 800, 832,
|
||||
896, 1048, 0, 600, 601, 604, 631, 0,
|
||||
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
|
||||
/* 800x600@120Hz RB */
|
||||
{ DRM_MODE("800x600", DRM_MODE_TYPE_DRIVER, 73250, 800, 848,
|
||||
880, 960, 0, 600, 603, 607, 636, 0,
|
||||
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC) },
|
||||
/* 848x480@60Hz */
|
||||
{ DRM_MODE("848x480", DRM_MODE_TYPE_DRIVER, 33750, 848, 864,
|
||||
976, 1088, 0, 480, 486, 494, 517, 0,
|
||||
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
|
||||
/* 1024x768@43Hz, interlace */
|
||||
{ DRM_MODE("1024x768i", DRM_MODE_TYPE_DRIVER, 44900, 1024, 1032,
|
||||
1208, 1264, 0, 768, 768, 772, 817, 0,
|
||||
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC |
|
||||
DRM_MODE_FLAG_INTERLACE) },
|
||||
/* 1024x768@60Hz */
|
||||
{ DRM_MODE("1024x768", DRM_MODE_TYPE_DRIVER, 65000, 1024, 1048,
|
||||
1184, 1344, 0, 768, 771, 777, 806, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
|
||||
/* 1024x768@70Hz */
|
||||
{ DRM_MODE("1024x768", DRM_MODE_TYPE_DRIVER, 75000, 1024, 1048,
|
||||
1184, 1328, 0, 768, 771, 777, 806, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
|
||||
/* 1024x768@75Hz */
|
||||
{ DRM_MODE("1024x768", DRM_MODE_TYPE_DRIVER, 78750, 1024, 1040,
|
||||
1136, 1312, 0, 768, 769, 772, 800, 0,
|
||||
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
|
||||
/* 1024x768@85Hz */
|
||||
{ DRM_MODE("1024x768", DRM_MODE_TYPE_DRIVER, 94500, 1024, 1072,
|
||||
1168, 1376, 0, 768, 769, 772, 808, 0,
|
||||
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
|
||||
/* 1024x768@120Hz RB */
|
||||
{ DRM_MODE("1024x768", DRM_MODE_TYPE_DRIVER, 115500, 1024, 1072,
|
||||
1104, 1184, 0, 768, 771, 775, 813, 0,
|
||||
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC) },
|
||||
/* 1152x864@75Hz */
|
||||
{ DRM_MODE("1152x864", DRM_MODE_TYPE_DRIVER, 108000, 1152, 1216,
|
||||
1344, 1600, 0, 864, 865, 868, 900, 0,
|
||||
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
|
||||
/* 1280x768@60Hz RB */
|
||||
{ DRM_MODE("1280x768", DRM_MODE_TYPE_DRIVER, 68250, 1280, 1328,
|
||||
1360, 1440, 0, 768, 771, 778, 790, 0,
|
||||
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC) },
|
||||
/* 1280x768@60Hz */
|
||||
{ DRM_MODE("1280x768", DRM_MODE_TYPE_DRIVER, 79500, 1280, 1344,
|
||||
1472, 1664, 0, 768, 771, 778, 798, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
|
||||
/* 1280x768@75Hz */
|
||||
{ DRM_MODE("1280x768", DRM_MODE_TYPE_DRIVER, 102250, 1280, 1360,
|
||||
1488, 1696, 0, 768, 771, 778, 805, 0,
|
||||
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC) },
|
||||
/* 1280x768@85Hz */
|
||||
{ DRM_MODE("1280x768", DRM_MODE_TYPE_DRIVER, 117500, 1280, 1360,
|
||||
1496, 1712, 0, 768, 771, 778, 809, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
|
||||
/* 1280x768@120Hz RB */
|
||||
{ DRM_MODE("1280x768", DRM_MODE_TYPE_DRIVER, 140250, 1280, 1328,
|
||||
1360, 1440, 0, 768, 771, 778, 813, 0,
|
||||
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC) },
|
||||
/* 1280x800@60Hz RB */
|
||||
{ DRM_MODE("1280x800", DRM_MODE_TYPE_DRIVER, 71000, 1280, 1328,
|
||||
1360, 1440, 0, 800, 803, 809, 823, 0,
|
||||
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC) },
|
||||
/* 1280x800@60Hz */
|
||||
{ DRM_MODE("1280x800", DRM_MODE_TYPE_DRIVER, 83500, 1280, 1352,
|
||||
1480, 1680, 0, 800, 803, 809, 831, 0,
|
||||
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC) },
|
||||
/* 1280x800@75Hz */
|
||||
{ DRM_MODE("1280x800", DRM_MODE_TYPE_DRIVER, 106500, 1280, 1360,
|
||||
1488, 1696, 0, 800, 803, 809, 838, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
|
||||
/* 1280x800@85Hz */
|
||||
{ DRM_MODE("1280x800", DRM_MODE_TYPE_DRIVER, 122500, 1280, 1360,
|
||||
1496, 1712, 0, 800, 803, 809, 843, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
|
||||
/* 1280x800@120Hz RB */
|
||||
{ DRM_MODE("1280x800", DRM_MODE_TYPE_DRIVER, 146250, 1280, 1328,
|
||||
1360, 1440, 0, 800, 803, 809, 847, 0,
|
||||
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC) },
|
||||
/* 1280x960@60Hz */
|
||||
{ DRM_MODE("1280x960", DRM_MODE_TYPE_DRIVER, 108000, 1280, 1376,
|
||||
1488, 1800, 0, 960, 961, 964, 1000, 0,
|
||||
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
|
||||
/* 1280x960@85Hz */
|
||||
{ DRM_MODE("1280x960", DRM_MODE_TYPE_DRIVER, 148500, 1280, 1344,
|
||||
1504, 1728, 0, 960, 961, 964, 1011, 0,
|
||||
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
|
||||
/* 1280x960@120Hz RB */
|
||||
{ DRM_MODE("1280x960", DRM_MODE_TYPE_DRIVER, 175500, 1280, 1328,
|
||||
1360, 1440, 0, 960, 963, 967, 1017, 0,
|
||||
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC) },
|
||||
/* 1280x1024@60Hz */
|
||||
{ DRM_MODE("1280x1024", DRM_MODE_TYPE_DRIVER, 108000, 1280, 1328,
|
||||
1440, 1688, 0, 1024, 1025, 1028, 1066, 0,
|
||||
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
|
||||
/* 1280x1024@75Hz */
|
||||
{ DRM_MODE("1280x1024", DRM_MODE_TYPE_DRIVER, 135000, 1280, 1296,
|
||||
1440, 1688, 0, 1024, 1025, 1028, 1066, 0,
|
||||
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
|
||||
/* 1280x1024@85Hz */
|
||||
{ DRM_MODE("1280x1024", DRM_MODE_TYPE_DRIVER, 157500, 1280, 1344,
|
||||
1504, 1728, 0, 1024, 1025, 1028, 1072, 0,
|
||||
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
|
||||
/* 1280x1024@120Hz RB */
|
||||
{ DRM_MODE("1280x1024", DRM_MODE_TYPE_DRIVER, 187250, 1280, 1328,
|
||||
1360, 1440, 0, 1024, 1027, 1034, 1084, 0,
|
||||
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC) },
|
||||
/* 1360x768@60Hz */
|
||||
{ DRM_MODE("1360x768", DRM_MODE_TYPE_DRIVER, 85500, 1360, 1424,
|
||||
1536, 1792, 0, 768, 771, 777, 795, 0,
|
||||
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
|
||||
/* 1360x768@120Hz RB */
|
||||
{ DRM_MODE("1360x768", DRM_MODE_TYPE_DRIVER, 148250, 1360, 1408,
|
||||
1440, 1520, 0, 768, 771, 776, 813, 0,
|
||||
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC) },
|
||||
/* 1400x1050@60Hz RB */
|
||||
{ DRM_MODE("1400x1050", DRM_MODE_TYPE_DRIVER, 101000, 1400, 1448,
|
||||
1480, 1560, 0, 1050, 1053, 1057, 1080, 0,
|
||||
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC) },
|
||||
/* 1400x1050@60Hz */
|
||||
{ DRM_MODE("1400x1050", DRM_MODE_TYPE_DRIVER, 121750, 1400, 1488,
|
||||
1632, 1864, 0, 1050, 1053, 1057, 1089, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
|
||||
/* 1400x1050@75Hz */
|
||||
{ DRM_MODE("1400x1050", DRM_MODE_TYPE_DRIVER, 156000, 1400, 1504,
|
||||
1648, 1896, 0, 1050, 1053, 1057, 1099, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
|
||||
/* 1400x1050@85Hz */
|
||||
{ DRM_MODE("1400x1050", DRM_MODE_TYPE_DRIVER, 179500, 1400, 1504,
|
||||
1656, 1912, 0, 1050, 1053, 1057, 1105, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
|
||||
/* 1400x1050@120Hz RB */
|
||||
{ DRM_MODE("1400x1050", DRM_MODE_TYPE_DRIVER, 208000, 1400, 1448,
|
||||
1480, 1560, 0, 1050, 1053, 1057, 1112, 0,
|
||||
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC) },
|
||||
/* 1440x900@60Hz RB */
|
||||
{ DRM_MODE("1440x900", DRM_MODE_TYPE_DRIVER, 88750, 1440, 1488,
|
||||
1520, 1600, 0, 900, 903, 909, 926, 0,
|
||||
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC) },
|
||||
/* 1440x900@60Hz */
|
||||
{ DRM_MODE("1440x900", DRM_MODE_TYPE_DRIVER, 106500, 1440, 1520,
|
||||
1672, 1904, 0, 900, 903, 909, 934, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
|
||||
/* 1440x900@75Hz */
|
||||
{ DRM_MODE("1440x900", DRM_MODE_TYPE_DRIVER, 136750, 1440, 1536,
|
||||
1688, 1936, 0, 900, 903, 909, 942, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
|
||||
/* 1440x900@85Hz */
|
||||
{ DRM_MODE("1440x900", DRM_MODE_TYPE_DRIVER, 157000, 1440, 1544,
|
||||
1696, 1952, 0, 900, 903, 909, 948, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
|
||||
/* 1440x900@120Hz RB */
|
||||
{ DRM_MODE("1440x900", DRM_MODE_TYPE_DRIVER, 182750, 1440, 1488,
|
||||
1520, 1600, 0, 900, 903, 909, 953, 0,
|
||||
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC) },
|
||||
/* 1600x1200@60Hz */
|
||||
{ DRM_MODE("1600x1200", DRM_MODE_TYPE_DRIVER, 162000, 1600, 1664,
|
||||
1856, 2160, 0, 1200, 1201, 1204, 1250, 0,
|
||||
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
|
||||
/* 1600x1200@65Hz */
|
||||
{ DRM_MODE("1600x1200", DRM_MODE_TYPE_DRIVER, 175500, 1600, 1664,
|
||||
1856, 2160, 0, 1200, 1201, 1204, 1250, 0,
|
||||
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
|
||||
/* 1600x1200@70Hz */
|
||||
{ DRM_MODE("1600x1200", DRM_MODE_TYPE_DRIVER, 189000, 1600, 1664,
|
||||
1856, 2160, 0, 1200, 1201, 1204, 1250, 0,
|
||||
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
|
||||
/* 1600x1200@75Hz */
|
||||
{ DRM_MODE("1600x1200", DRM_MODE_TYPE_DRIVER, 202500, 1600, 1664,
|
||||
1856, 2160, 0, 1200, 1201, 1204, 1250, 0,
|
||||
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
|
||||
/* 1600x1200@85Hz */
|
||||
{ DRM_MODE("1600x1200", DRM_MODE_TYPE_DRIVER, 229500, 1600, 1664,
|
||||
1856, 2160, 0, 1200, 1201, 1204, 1250, 0,
|
||||
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
|
||||
/* 1600x1200@120Hz RB */
|
||||
{ DRM_MODE("1600x1200", DRM_MODE_TYPE_DRIVER, 268250, 1600, 1648,
|
||||
1680, 1760, 0, 1200, 1203, 1207, 1271, 0,
|
||||
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC) },
|
||||
/* 1680x1050@60Hz RB */
|
||||
{ DRM_MODE("1680x1050", DRM_MODE_TYPE_DRIVER, 119000, 1680, 1728,
|
||||
1760, 1840, 0, 1050, 1053, 1059, 1080, 0,
|
||||
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC) },
|
||||
/* 1680x1050@60Hz */
|
||||
{ DRM_MODE("1680x1050", DRM_MODE_TYPE_DRIVER, 146250, 1680, 1784,
|
||||
1960, 2240, 0, 1050, 1053, 1059, 1089, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
|
||||
/* 1680x1050@75Hz */
|
||||
{ DRM_MODE("1680x1050", DRM_MODE_TYPE_DRIVER, 187000, 1680, 1800,
|
||||
1976, 2272, 0, 1050, 1053, 1059, 1099, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
|
||||
/* 1680x1050@85Hz */
|
||||
{ DRM_MODE("1680x1050", DRM_MODE_TYPE_DRIVER, 214750, 1680, 1808,
|
||||
1984, 2288, 0, 1050, 1053, 1059, 1105, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
|
||||
/* 1680x1050@120Hz RB */
|
||||
{ DRM_MODE("1680x1050", DRM_MODE_TYPE_DRIVER, 245500, 1680, 1728,
|
||||
1760, 1840, 0, 1050, 1053, 1059, 1112, 0,
|
||||
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC) },
|
||||
/* 1792x1344@60Hz */
|
||||
{ DRM_MODE("1792x1344", DRM_MODE_TYPE_DRIVER, 204750, 1792, 1920,
|
||||
2120, 2448, 0, 1344, 1345, 1348, 1394, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
|
||||
/* 1792x1344@75Hz */
|
||||
{ DRM_MODE("1792x1344", DRM_MODE_TYPE_DRIVER, 261000, 1792, 1888,
|
||||
2104, 2456, 0, 1344, 1345, 1348, 1417, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
|
||||
/* 1792x1344@120Hz RB */
|
||||
{ DRM_MODE("1792x1344", DRM_MODE_TYPE_DRIVER, 333250, 1792, 1840,
|
||||
1872, 1952, 0, 1344, 1347, 1351, 1423, 0,
|
||||
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC) },
|
||||
/* 1856x1392@60Hz */
|
||||
{ DRM_MODE("1856x1392", DRM_MODE_TYPE_DRIVER, 218250, 1856, 1952,
|
||||
2176, 2528, 0, 1392, 1393, 1396, 1439, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
|
||||
/* 1856x1392@75Hz */
|
||||
{ DRM_MODE("1856x1392", DRM_MODE_TYPE_DRIVER, 288000, 1856, 1984,
|
||||
2208, 2560, 0, 1392, 1395, 1399, 1500, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
|
||||
/* 1856x1392@120Hz RB */
|
||||
{ DRM_MODE("1856x1392", DRM_MODE_TYPE_DRIVER, 356500, 1856, 1904,
|
||||
1936, 2016, 0, 1392, 1395, 1399, 1474, 0,
|
||||
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC) },
|
||||
/* 1920x1200@60Hz RB */
|
||||
{ DRM_MODE("1920x1200", DRM_MODE_TYPE_DRIVER, 154000, 1920, 1968,
|
||||
2000, 2080, 0, 1200, 1203, 1209, 1235, 0,
|
||||
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC) },
|
||||
/* 1920x1200@60Hz */
|
||||
{ DRM_MODE("1920x1200", DRM_MODE_TYPE_DRIVER, 193250, 1920, 2056,
|
||||
2256, 2592, 0, 1200, 1203, 1209, 1245, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
|
||||
/* 1920x1200@75Hz */
|
||||
{ DRM_MODE("1920x1200", DRM_MODE_TYPE_DRIVER, 245250, 1920, 2056,
|
||||
2264, 2608, 0, 1200, 1203, 1209, 1255, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
|
||||
/* 1920x1200@85Hz */
|
||||
{ DRM_MODE("1920x1200", DRM_MODE_TYPE_DRIVER, 281250, 1920, 2064,
|
||||
2272, 2624, 0, 1200, 1203, 1209, 1262, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
|
||||
/* 1920x1200@120Hz RB */
|
||||
{ DRM_MODE("1920x1200", DRM_MODE_TYPE_DRIVER, 317000, 1920, 1968,
|
||||
2000, 2080, 0, 1200, 1203, 1209, 1271, 0,
|
||||
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC) },
|
||||
/* 1920x1440@60Hz */
|
||||
{ DRM_MODE("1920x1440", DRM_MODE_TYPE_DRIVER, 234000, 1920, 2048,
|
||||
2256, 2600, 0, 1440, 1441, 1444, 1500, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
|
||||
/* 1920x1440@75Hz */
|
||||
{ DRM_MODE("1920x1440", DRM_MODE_TYPE_DRIVER, 297000, 1920, 2064,
|
||||
2288, 2640, 0, 1440, 1441, 1444, 1500, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
|
||||
/* 1920x1440@120Hz RB */
|
||||
{ DRM_MODE("1920x1440", DRM_MODE_TYPE_DRIVER, 380500, 1920, 1968,
|
||||
2000, 2080, 0, 1440, 1443, 1447, 1525, 0,
|
||||
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC) },
|
||||
/* 2560x1600@60Hz RB */
|
||||
{ DRM_MODE("2560x1600", DRM_MODE_TYPE_DRIVER, 268500, 2560, 2608,
|
||||
2640, 2720, 0, 1600, 1603, 1609, 1646, 0,
|
||||
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC) },
|
||||
/* 2560x1600@60Hz */
|
||||
{ DRM_MODE("2560x1600", DRM_MODE_TYPE_DRIVER, 348500, 2560, 2752,
|
||||
3032, 3504, 0, 1600, 1603, 1609, 1658, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
|
||||
/* 2560x1600@75HZ */
|
||||
{ DRM_MODE("2560x1600", DRM_MODE_TYPE_DRIVER, 443250, 2560, 2768,
|
||||
3048, 3536, 0, 1600, 1603, 1609, 1672, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
|
||||
/* 2560x1600@85HZ */
|
||||
{ DRM_MODE("2560x1600", DRM_MODE_TYPE_DRIVER, 505250, 2560, 2768,
|
||||
3048, 3536, 0, 1600, 1603, 1609, 1682, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
|
||||
/* 2560x1600@120Hz RB */
|
||||
{ DRM_MODE("2560x1600", DRM_MODE_TYPE_DRIVER, 552750, 2560, 2608,
|
||||
2640, 2720, 0, 1600, 1603, 1609, 1694, 0,
|
||||
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC) },
|
||||
};
|
||||
|
||||
static const struct drm_display_mode edid_est_modes[] = {
|
||||
{ DRM_MODE("800x600", DRM_MODE_TYPE_DRIVER, 40000, 800, 840,
|
||||
968, 1056, 0, 600, 601, 605, 628, 0,
|
||||
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, /* 800x600@60Hz */
|
||||
{ DRM_MODE("800x600", DRM_MODE_TYPE_DRIVER, 36000, 800, 824,
|
||||
896, 1024, 0, 600, 601, 603, 625, 0,
|
||||
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, /* 800x600@56Hz */
|
||||
{ DRM_MODE("640x480", DRM_MODE_TYPE_DRIVER, 31500, 640, 656,
|
||||
720, 840, 0, 480, 481, 484, 500, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, /* 640x480@75Hz */
|
||||
{ DRM_MODE("640x480", DRM_MODE_TYPE_DRIVER, 31500, 640, 664,
|
||||
704, 832, 0, 480, 489, 491, 520, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, /* 640x480@72Hz */
|
||||
{ DRM_MODE("640x480", DRM_MODE_TYPE_DRIVER, 30240, 640, 704,
|
||||
768, 864, 0, 480, 483, 486, 525, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, /* 640x480@67Hz */
|
||||
{ DRM_MODE("640x480", DRM_MODE_TYPE_DRIVER, 25200, 640, 656,
|
||||
752, 800, 0, 480, 490, 492, 525, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, /* 640x480@60Hz */
|
||||
{ DRM_MODE("720x400", DRM_MODE_TYPE_DRIVER, 35500, 720, 738,
|
||||
846, 900, 0, 400, 421, 423, 449, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, /* 720x400@88Hz */
|
||||
{ DRM_MODE("720x400", DRM_MODE_TYPE_DRIVER, 28320, 720, 738,
|
||||
846, 900, 0, 400, 412, 414, 449, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) }, /* 720x400@70Hz */
|
||||
{ DRM_MODE("1280x1024", DRM_MODE_TYPE_DRIVER, 135000, 1280, 1296,
|
||||
1440, 1688, 0, 1024, 1025, 1028, 1066, 0,
|
||||
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, /* 1280x1024@75Hz */
|
||||
{ DRM_MODE("1024x768", DRM_MODE_TYPE_DRIVER, 78800, 1024, 1040,
|
||||
1136, 1312, 0, 768, 769, 772, 800, 0,
|
||||
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, /* 1024x768@75Hz */
|
||||
{ DRM_MODE("1024x768", DRM_MODE_TYPE_DRIVER, 75000, 1024, 1048,
|
||||
1184, 1328, 0, 768, 771, 777, 806, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, /* 1024x768@70Hz */
|
||||
{ DRM_MODE("1024x768", DRM_MODE_TYPE_DRIVER, 65000, 1024, 1048,
|
||||
1184, 1344, 0, 768, 771, 777, 806, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, /* 1024x768@60Hz */
|
||||
{ DRM_MODE("1024x768i", DRM_MODE_TYPE_DRIVER,44900, 1024, 1032,
|
||||
1208, 1264, 0, 768, 768, 776, 817, 0,
|
||||
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC | DRM_MODE_FLAG_INTERLACE) }, /* 1024x768@43Hz */
|
||||
{ DRM_MODE("832x624", DRM_MODE_TYPE_DRIVER, 57284, 832, 864,
|
||||
928, 1152, 0, 624, 625, 628, 667, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, /* 832x624@75Hz */
|
||||
{ DRM_MODE("800x600", DRM_MODE_TYPE_DRIVER, 49500, 800, 816,
|
||||
896, 1056, 0, 600, 601, 604, 625, 0,
|
||||
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, /* 800x600@75Hz */
|
||||
{ DRM_MODE("800x600", DRM_MODE_TYPE_DRIVER, 50000, 800, 856,
|
||||
976, 1040, 0, 600, 637, 643, 666, 0,
|
||||
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, /* 800x600@72Hz */
|
||||
{ DRM_MODE("1152x864", DRM_MODE_TYPE_DRIVER, 108000, 1152, 1216,
|
||||
1344, 1600, 0, 864, 865, 868, 900, 0,
|
||||
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, /* 1152x864@75Hz */
|
||||
};
|
||||
|
||||
struct minimode {
|
||||
short w;
|
||||
short h;
|
||||
short r;
|
||||
short rb;
|
||||
};
|
||||
|
||||
static const struct minimode est3_modes[] = {
|
||||
/* byte 6 */
|
||||
{ 640, 350, 85, 0 },
|
||||
{ 640, 400, 85, 0 },
|
||||
{ 720, 400, 85, 0 },
|
||||
{ 640, 480, 85, 0 },
|
||||
{ 848, 480, 60, 0 },
|
||||
{ 800, 600, 85, 0 },
|
||||
{ 1024, 768, 85, 0 },
|
||||
{ 1152, 864, 75, 0 },
|
||||
/* byte 7 */
|
||||
{ 1280, 768, 60, 1 },
|
||||
{ 1280, 768, 60, 0 },
|
||||
{ 1280, 768, 75, 0 },
|
||||
{ 1280, 768, 85, 0 },
|
||||
{ 1280, 960, 60, 0 },
|
||||
{ 1280, 960, 85, 0 },
|
||||
{ 1280, 1024, 60, 0 },
|
||||
{ 1280, 1024, 85, 0 },
|
||||
/* byte 8 */
|
||||
{ 1360, 768, 60, 0 },
|
||||
{ 1440, 900, 60, 1 },
|
||||
{ 1440, 900, 60, 0 },
|
||||
{ 1440, 900, 75, 0 },
|
||||
{ 1440, 900, 85, 0 },
|
||||
{ 1400, 1050, 60, 1 },
|
||||
{ 1400, 1050, 60, 0 },
|
||||
{ 1400, 1050, 75, 0 },
|
||||
/* byte 9 */
|
||||
{ 1400, 1050, 85, 0 },
|
||||
{ 1680, 1050, 60, 1 },
|
||||
{ 1680, 1050, 60, 0 },
|
||||
{ 1680, 1050, 75, 0 },
|
||||
{ 1680, 1050, 85, 0 },
|
||||
{ 1600, 1200, 60, 0 },
|
||||
{ 1600, 1200, 65, 0 },
|
||||
{ 1600, 1200, 70, 0 },
|
||||
/* byte 10 */
|
||||
{ 1600, 1200, 75, 0 },
|
||||
{ 1600, 1200, 85, 0 },
|
||||
{ 1792, 1344, 60, 0 },
|
||||
{ 1792, 1344, 85, 0 },
|
||||
{ 1856, 1392, 60, 0 },
|
||||
{ 1856, 1392, 75, 0 },
|
||||
{ 1920, 1200, 60, 1 },
|
||||
{ 1920, 1200, 60, 0 },
|
||||
/* byte 11 */
|
||||
{ 1920, 1200, 75, 0 },
|
||||
{ 1920, 1200, 85, 0 },
|
||||
{ 1920, 1440, 60, 0 },
|
||||
{ 1920, 1440, 75, 0 },
|
||||
};
|
||||
|
||||
static const struct minimode extra_modes[] = {
|
||||
{ 1024, 576, 60, 0 },
|
||||
{ 1366, 768, 60, 0 },
|
||||
{ 1600, 900, 60, 0 },
|
||||
{ 1680, 945, 60, 0 },
|
||||
{ 1920, 1080, 60, 0 },
|
||||
{ 2048, 1152, 60, 0 },
|
||||
{ 2048, 1536, 60, 0 },
|
||||
};
|
||||
|
||||
/*
|
||||
* Probably taken from CEA-861 spec.
|
||||
* This table is converted from xorg's hw/xfree86/modes/xf86EdidModes.c.
|
||||
*/
|
||||
static const struct drm_display_mode edid_cea_modes[] = {
|
||||
/* 1 - 640x480@60Hz */
|
||||
{ DRM_MODE("640x480", DRM_MODE_TYPE_DRIVER, 25175, 640, 656,
|
||||
752, 800, 0, 480, 490, 492, 525, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
|
||||
/* 2 - 720x480@60Hz */
|
||||
{ DRM_MODE("720x480", DRM_MODE_TYPE_DRIVER, 27000, 720, 736,
|
||||
798, 858, 0, 480, 489, 495, 525, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
|
||||
/* 3 - 720x480@60Hz */
|
||||
{ DRM_MODE("720x480", DRM_MODE_TYPE_DRIVER, 27000, 720, 736,
|
||||
798, 858, 0, 480, 489, 495, 525, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
|
||||
/* 4 - 1280x720@60Hz */
|
||||
{ DRM_MODE("1280x720", DRM_MODE_TYPE_DRIVER, 74250, 1280, 1390,
|
||||
1430, 1650, 0, 720, 725, 730, 750, 0,
|
||||
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
|
||||
/* 5 - 1920x1080i@60Hz */
|
||||
{ DRM_MODE("1920x1080i", DRM_MODE_TYPE_DRIVER, 74250, 1920, 2008,
|
||||
2052, 2200, 0, 1080, 1084, 1094, 1125, 0,
|
||||
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC |
|
||||
DRM_MODE_FLAG_INTERLACE) },
|
||||
/* 6 - 1440x480i@60Hz */
|
||||
{ DRM_MODE("1440x480i", DRM_MODE_TYPE_DRIVER, 27000, 1440, 1478,
|
||||
1602, 1716, 0, 480, 488, 494, 525, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC |
|
||||
DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK) },
|
||||
/* 7 - 1440x480i@60Hz */
|
||||
{ DRM_MODE("1440x480i", DRM_MODE_TYPE_DRIVER, 27000, 1440, 1478,
|
||||
1602, 1716, 0, 480, 488, 494, 525, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC |
|
||||
DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK) },
|
||||
/* 8 - 1440x240@60Hz */
|
||||
{ DRM_MODE("1440x240", DRM_MODE_TYPE_DRIVER, 27000, 1440, 1478,
|
||||
1602, 1716, 0, 240, 244, 247, 262, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC |
|
||||
DRM_MODE_FLAG_DBLCLK) },
|
||||
/* 9 - 1440x240@60Hz */
|
||||
{ DRM_MODE("1440x240", DRM_MODE_TYPE_DRIVER, 27000, 1440, 1478,
|
||||
1602, 1716, 0, 240, 244, 247, 262, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC |
|
||||
DRM_MODE_FLAG_DBLCLK) },
|
||||
/* 10 - 2880x480i@60Hz */
|
||||
{ DRM_MODE("2880x480i", DRM_MODE_TYPE_DRIVER, 54000, 2880, 2956,
|
||||
3204, 3432, 0, 480, 488, 494, 525, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC |
|
||||
DRM_MODE_FLAG_INTERLACE) },
|
||||
/* 11 - 2880x480i@60Hz */
|
||||
{ DRM_MODE("2880x480i", DRM_MODE_TYPE_DRIVER, 54000, 2880, 2956,
|
||||
3204, 3432, 0, 480, 488, 494, 525, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC |
|
||||
DRM_MODE_FLAG_INTERLACE) },
|
||||
/* 12 - 2880x240@60Hz */
|
||||
{ DRM_MODE("2880x240", DRM_MODE_TYPE_DRIVER, 54000, 2880, 2956,
|
||||
3204, 3432, 0, 240, 244, 247, 262, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
|
||||
/* 13 - 2880x240@60Hz */
|
||||
{ DRM_MODE("2880x240", DRM_MODE_TYPE_DRIVER, 54000, 2880, 2956,
|
||||
3204, 3432, 0, 240, 244, 247, 262, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
|
||||
/* 14 - 1440x480@60Hz */
|
||||
{ DRM_MODE("1440x480", DRM_MODE_TYPE_DRIVER, 54000, 1440, 1472,
|
||||
1596, 1716, 0, 480, 489, 495, 525, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
|
||||
/* 15 - 1440x480@60Hz */
|
||||
{ DRM_MODE("1440x480", DRM_MODE_TYPE_DRIVER, 54000, 1440, 1472,
|
||||
1596, 1716, 0, 480, 489, 495, 525, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
|
||||
/* 16 - 1920x1080@60Hz */
|
||||
{ DRM_MODE("1920x1080", DRM_MODE_TYPE_DRIVER, 148500, 1920, 2008,
|
||||
2052, 2200, 0, 1080, 1084, 1089, 1125, 0,
|
||||
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
|
||||
/* 17 - 720x576@50Hz */
|
||||
{ DRM_MODE("720x576", DRM_MODE_TYPE_DRIVER, 27000, 720, 732,
|
||||
796, 864, 0, 576, 581, 586, 625, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
|
||||
/* 18 - 720x576@50Hz */
|
||||
{ DRM_MODE("720x576", DRM_MODE_TYPE_DRIVER, 27000, 720, 732,
|
||||
796, 864, 0, 576, 581, 586, 625, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
|
||||
/* 19 - 1280x720@50Hz */
|
||||
{ DRM_MODE("1280x720", DRM_MODE_TYPE_DRIVER, 74250, 1280, 1720,
|
||||
1760, 1980, 0, 720, 725, 730, 750, 0,
|
||||
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
|
||||
/* 20 - 1920x1080i@50Hz */
|
||||
{ DRM_MODE("1920x1080i", DRM_MODE_TYPE_DRIVER, 74250, 1920, 2448,
|
||||
2492, 2640, 0, 1080, 1084, 1094, 1125, 0,
|
||||
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC |
|
||||
DRM_MODE_FLAG_INTERLACE) },
|
||||
/* 21 - 1440x576i@50Hz */
|
||||
{ DRM_MODE("1440x576i", DRM_MODE_TYPE_DRIVER, 27000, 1440, 1464,
|
||||
1590, 1728, 0, 576, 580, 586, 625, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC |
|
||||
DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK) },
|
||||
/* 22 - 1440x576i@50Hz */
|
||||
{ DRM_MODE("1440x576i", DRM_MODE_TYPE_DRIVER, 27000, 1440, 1464,
|
||||
1590, 1728, 0, 576, 580, 586, 625, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC |
|
||||
DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK) },
|
||||
/* 23 - 1440x288@50Hz */
|
||||
{ DRM_MODE("1440x288", DRM_MODE_TYPE_DRIVER, 27000, 1440, 1464,
|
||||
1590, 1728, 0, 288, 290, 293, 312, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC |
|
||||
DRM_MODE_FLAG_DBLCLK) },
|
||||
/* 24 - 1440x288@50Hz */
|
||||
{ DRM_MODE("1440x288", DRM_MODE_TYPE_DRIVER, 27000, 1440, 1464,
|
||||
1590, 1728, 0, 288, 290, 293, 312, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC |
|
||||
DRM_MODE_FLAG_DBLCLK) },
|
||||
/* 25 - 2880x576i@50Hz */
|
||||
{ DRM_MODE("2880x576i", DRM_MODE_TYPE_DRIVER, 54000, 2880, 2928,
|
||||
3180, 3456, 0, 576, 580, 586, 625, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC |
|
||||
DRM_MODE_FLAG_INTERLACE) },
|
||||
/* 26 - 2880x576i@50Hz */
|
||||
{ DRM_MODE("2880x576i", DRM_MODE_TYPE_DRIVER, 54000, 2880, 2928,
|
||||
3180, 3456, 0, 576, 580, 586, 625, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC |
|
||||
DRM_MODE_FLAG_INTERLACE) },
|
||||
/* 27 - 2880x288@50Hz */
|
||||
{ DRM_MODE("2880x288", DRM_MODE_TYPE_DRIVER, 54000, 2880, 2928,
|
||||
3180, 3456, 0, 288, 290, 293, 312, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
|
||||
/* 28 - 2880x288@50Hz */
|
||||
{ DRM_MODE("2880x288", DRM_MODE_TYPE_DRIVER, 54000, 2880, 2928,
|
||||
3180, 3456, 0, 288, 290, 293, 312, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
|
||||
/* 29 - 1440x576@50Hz */
|
||||
{ DRM_MODE("1440x576", DRM_MODE_TYPE_DRIVER, 54000, 1440, 1464,
|
||||
1592, 1728, 0, 576, 581, 586, 625, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
|
||||
/* 30 - 1440x576@50Hz */
|
||||
{ DRM_MODE("1440x576", DRM_MODE_TYPE_DRIVER, 54000, 1440, 1464,
|
||||
1592, 1728, 0, 576, 581, 586, 625, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
|
||||
/* 31 - 1920x1080@50Hz */
|
||||
{ DRM_MODE("1920x1080", DRM_MODE_TYPE_DRIVER, 148500, 1920, 2448,
|
||||
2492, 2640, 0, 1080, 1084, 1089, 1125, 0,
|
||||
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
|
||||
/* 32 - 1920x1080@24Hz */
|
||||
{ DRM_MODE("1920x1080", DRM_MODE_TYPE_DRIVER, 74250, 1920, 2558,
|
||||
2602, 2750, 0, 1080, 1084, 1089, 1125, 0,
|
||||
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
|
||||
/* 33 - 1920x1080@25Hz */
|
||||
{ DRM_MODE("1920x1080", DRM_MODE_TYPE_DRIVER, 74250, 1920, 2448,
|
||||
2492, 2640, 0, 1080, 1084, 1089, 1125, 0,
|
||||
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
|
||||
/* 34 - 1920x1080@30Hz */
|
||||
{ DRM_MODE("1920x1080", DRM_MODE_TYPE_DRIVER, 74250, 1920, 2008,
|
||||
2052, 2200, 0, 1080, 1084, 1089, 1125, 0,
|
||||
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
|
||||
/* 35 - 2880x480@60Hz */
|
||||
{ DRM_MODE("2880x480", DRM_MODE_TYPE_DRIVER, 108000, 2880, 2944,
|
||||
3192, 3432, 0, 480, 489, 495, 525, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
|
||||
/* 36 - 2880x480@60Hz */
|
||||
{ DRM_MODE("2880x480", DRM_MODE_TYPE_DRIVER, 108000, 2880, 2944,
|
||||
3192, 3432, 0, 480, 489, 495, 525, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
|
||||
/* 37 - 2880x576@50Hz */
|
||||
{ DRM_MODE("2880x576", DRM_MODE_TYPE_DRIVER, 108000, 2880, 2928,
|
||||
3184, 3456, 0, 576, 581, 586, 625, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
|
||||
/* 38 - 2880x576@50Hz */
|
||||
{ DRM_MODE("2880x576", DRM_MODE_TYPE_DRIVER, 108000, 2880, 2928,
|
||||
3184, 3456, 0, 576, 581, 586, 625, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
|
||||
/* 39 - 1920x1080i@50Hz */
|
||||
{ DRM_MODE("1920x1080i", DRM_MODE_TYPE_DRIVER, 72000, 1920, 1952,
|
||||
2120, 2304, 0, 1080, 1126, 1136, 1250, 0,
|
||||
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC |
|
||||
DRM_MODE_FLAG_INTERLACE) },
|
||||
/* 40 - 1920x1080i@100Hz */
|
||||
{ DRM_MODE("1920x1080i", DRM_MODE_TYPE_DRIVER, 148500, 1920, 2448,
|
||||
2492, 2640, 0, 1080, 1084, 1094, 1125, 0,
|
||||
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC |
|
||||
DRM_MODE_FLAG_INTERLACE) },
|
||||
/* 41 - 1280x720@100Hz */
|
||||
{ DRM_MODE("1280x720", DRM_MODE_TYPE_DRIVER, 148500, 1280, 1720,
|
||||
1760, 1980, 0, 720, 725, 730, 750, 0,
|
||||
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
|
||||
/* 42 - 720x576@100Hz */
|
||||
{ DRM_MODE("720x576", DRM_MODE_TYPE_DRIVER, 54000, 720, 732,
|
||||
796, 864, 0, 576, 581, 586, 625, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
|
||||
/* 43 - 720x576@100Hz */
|
||||
{ DRM_MODE("720x576", DRM_MODE_TYPE_DRIVER, 54000, 720, 732,
|
||||
796, 864, 0, 576, 581, 586, 625, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
|
||||
/* 44 - 1440x576i@100Hz */
|
||||
{ DRM_MODE("1440x576", DRM_MODE_TYPE_DRIVER, 54000, 1440, 1464,
|
||||
1590, 1728, 0, 576, 580, 586, 625, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC |
|
||||
DRM_MODE_FLAG_DBLCLK) },
|
||||
/* 45 - 1440x576i@100Hz */
|
||||
{ DRM_MODE("1440x576", DRM_MODE_TYPE_DRIVER, 54000, 1440, 1464,
|
||||
1590, 1728, 0, 576, 580, 586, 625, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC |
|
||||
DRM_MODE_FLAG_DBLCLK) },
|
||||
/* 46 - 1920x1080i@120Hz */
|
||||
{ DRM_MODE("1920x1080i", DRM_MODE_TYPE_DRIVER, 148500, 1920, 2008,
|
||||
2052, 2200, 0, 1080, 1084, 1094, 1125, 0,
|
||||
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC |
|
||||
DRM_MODE_FLAG_INTERLACE) },
|
||||
/* 47 - 1280x720@120Hz */
|
||||
{ DRM_MODE("1280x720", DRM_MODE_TYPE_DRIVER, 148500, 1280, 1390,
|
||||
1430, 1650, 0, 720, 725, 730, 750, 0,
|
||||
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
|
||||
/* 48 - 720x480@120Hz */
|
||||
{ DRM_MODE("720x480", DRM_MODE_TYPE_DRIVER, 54000, 720, 736,
|
||||
798, 858, 0, 480, 489, 495, 525, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
|
||||
/* 49 - 720x480@120Hz */
|
||||
{ DRM_MODE("720x480", DRM_MODE_TYPE_DRIVER, 54000, 720, 736,
|
||||
798, 858, 0, 480, 489, 495, 525, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
|
||||
/* 50 - 1440x480i@120Hz */
|
||||
{ DRM_MODE("1440x480i", DRM_MODE_TYPE_DRIVER, 54000, 1440, 1478,
|
||||
1602, 1716, 0, 480, 488, 494, 525, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC |
|
||||
DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK) },
|
||||
/* 51 - 1440x480i@120Hz */
|
||||
{ DRM_MODE("1440x480i", DRM_MODE_TYPE_DRIVER, 54000, 1440, 1478,
|
||||
1602, 1716, 0, 480, 488, 494, 525, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC |
|
||||
DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK) },
|
||||
/* 52 - 720x576@200Hz */
|
||||
{ DRM_MODE("720x576", DRM_MODE_TYPE_DRIVER, 108000, 720, 732,
|
||||
796, 864, 0, 576, 581, 586, 625, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
|
||||
/* 53 - 720x576@200Hz */
|
||||
{ DRM_MODE("720x576", DRM_MODE_TYPE_DRIVER, 108000, 720, 732,
|
||||
796, 864, 0, 576, 581, 586, 625, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
|
||||
/* 54 - 1440x576i@200Hz */
|
||||
{ DRM_MODE("1440x576i", DRM_MODE_TYPE_DRIVER, 108000, 1440, 1464,
|
||||
1590, 1728, 0, 576, 580, 586, 625, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC |
|
||||
DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK) },
|
||||
/* 55 - 1440x576i@200Hz */
|
||||
{ DRM_MODE("1440x576i", DRM_MODE_TYPE_DRIVER, 108000, 1440, 1464,
|
||||
1590, 1728, 0, 576, 580, 586, 625, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC |
|
||||
DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK) },
|
||||
/* 56 - 720x480@240Hz */
|
||||
{ DRM_MODE("720x480", DRM_MODE_TYPE_DRIVER, 108000, 720, 736,
|
||||
798, 858, 0, 480, 489, 495, 525, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
|
||||
/* 57 - 720x480@240Hz */
|
||||
{ DRM_MODE("720x480", DRM_MODE_TYPE_DRIVER, 108000, 720, 736,
|
||||
798, 858, 0, 480, 489, 495, 525, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
|
||||
/* 58 - 1440x480i@240 */
|
||||
{ DRM_MODE("1440x480i", DRM_MODE_TYPE_DRIVER, 108000, 1440, 1478,
|
||||
1602, 1716, 0, 480, 488, 494, 525, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC |
|
||||
DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK) },
|
||||
/* 59 - 1440x480i@240 */
|
||||
{ DRM_MODE("1440x480i", DRM_MODE_TYPE_DRIVER, 108000, 1440, 1478,
|
||||
1602, 1716, 0, 480, 488, 494, 525, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC |
|
||||
DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK) },
|
||||
/* 60 - 1280x720@24Hz */
|
||||
{ DRM_MODE("1280x720", DRM_MODE_TYPE_DRIVER, 59400, 1280, 3040,
|
||||
3080, 3300, 0, 720, 725, 730, 750, 0,
|
||||
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
|
||||
/* 61 - 1280x720@25Hz */
|
||||
{ DRM_MODE("1280x720", DRM_MODE_TYPE_DRIVER, 74250, 1280, 3700,
|
||||
3740, 3960, 0, 720, 725, 730, 750, 0,
|
||||
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
|
||||
/* 62 - 1280x720@30Hz */
|
||||
{ DRM_MODE("1280x720", DRM_MODE_TYPE_DRIVER, 74250, 1280, 3040,
|
||||
3080, 3300, 0, 720, 725, 730, 750, 0,
|
||||
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
|
||||
/* 63 - 1920x1080@120Hz */
|
||||
{ DRM_MODE("1920x1080", DRM_MODE_TYPE_DRIVER, 297000, 1920, 2008,
|
||||
2052, 2200, 0, 1080, 1084, 1089, 1125, 0,
|
||||
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
|
||||
/* 64 - 1920x1080@100Hz */
|
||||
{ DRM_MODE("1920x1080", DRM_MODE_TYPE_DRIVER, 297000, 1920, 2448,
|
||||
2492, 2640, 0, 1080, 1084, 1094, 1125, 0,
|
||||
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
|
||||
};
|
||||
|
||||
/*** DDC fetch and block validation ***/
|
||||
|
||||
static const u8 edid_header[] = {
|
||||
@ -357,10 +1094,14 @@ drm_do_get_edid(struct drm_connector *connector, struct i2c_adapter *adapter)
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (i == 4)
|
||||
|
||||
if (i == 4 && print_bad_edid) {
|
||||
dev_warn(connector->dev->dev,
|
||||
"%s: Ignoring invalid EDID block %d.\n",
|
||||
drm_get_connector_name(connector), j);
|
||||
|
||||
connector->bad_edid_counter++;
|
||||
}
|
||||
}
|
||||
|
||||
if (valid_extensions != block[0x7e]) {
|
||||
@ -541,7 +1282,7 @@ struct drm_display_mode *drm_mode_find_dmt(struct drm_device *dev,
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < drm_num_dmt_modes; i++) {
|
||||
for (i = 0; i < ARRAY_SIZE(drm_dmt_modes); i++) {
|
||||
const struct drm_display_mode *ptr = &drm_dmt_modes[i];
|
||||
if (hsize != ptr->hdisplay)
|
||||
continue;
|
||||
@ -1082,7 +1823,7 @@ drm_dmt_modes_for_range(struct drm_connector *connector, struct edid *edid,
|
||||
struct drm_display_mode *newmode;
|
||||
struct drm_device *dev = connector->dev;
|
||||
|
||||
for (i = 0; i < drm_num_dmt_modes; i++) {
|
||||
for (i = 0; i < ARRAY_SIZE(drm_dmt_modes); i++) {
|
||||
if (mode_in_range(drm_dmt_modes + i, edid, timing) &&
|
||||
valid_inferred_mode(connector, drm_dmt_modes + i)) {
|
||||
newmode = drm_mode_duplicate(dev, &drm_dmt_modes[i]);
|
||||
@ -1117,7 +1858,7 @@ drm_gtf_modes_for_range(struct drm_connector *connector, struct edid *edid,
|
||||
struct drm_display_mode *newmode;
|
||||
struct drm_device *dev = connector->dev;
|
||||
|
||||
for (i = 0; i < num_extra_modes; i++) {
|
||||
for (i = 0; i < ARRAY_SIZE(extra_modes); i++) {
|
||||
const struct minimode *m = &extra_modes[i];
|
||||
newmode = drm_gtf_mode(dev, m->w, m->h, m->r, 0, 0);
|
||||
if (!newmode)
|
||||
@ -1146,7 +1887,7 @@ drm_cvt_modes_for_range(struct drm_connector *connector, struct edid *edid,
|
||||
struct drm_device *dev = connector->dev;
|
||||
bool rb = drm_monitor_supports_rb(edid);
|
||||
|
||||
for (i = 0; i < num_extra_modes; i++) {
|
||||
for (i = 0; i < ARRAY_SIZE(extra_modes); i++) {
|
||||
const struct minimode *m = &extra_modes[i];
|
||||
newmode = drm_cvt_mode(dev, m->w, m->h, m->r, rb, 0, 0);
|
||||
if (!newmode)
|
||||
@ -1483,9 +2224,11 @@ add_detailed_modes(struct drm_connector *connector, struct edid *edid,
|
||||
#define VIDEO_BLOCK 0x02
|
||||
#define VENDOR_BLOCK 0x03
|
||||
#define SPEAKER_BLOCK 0x04
|
||||
#define VIDEO_CAPABILITY_BLOCK 0x07
|
||||
#define EDID_BASIC_AUDIO (1 << 6)
|
||||
#define EDID_CEA_YCRCB444 (1 << 5)
|
||||
#define EDID_CEA_YCRCB422 (1 << 4)
|
||||
#define EDID_CEA_VCDB_QS (1 << 6)
|
||||
|
||||
/**
|
||||
* Search EDID for CEA extension block.
|
||||
@ -1513,16 +2256,19 @@ u8 *drm_find_cea_extension(struct edid *edid)
|
||||
}
|
||||
EXPORT_SYMBOL(drm_find_cea_extension);
|
||||
|
||||
/*
|
||||
* Looks for a CEA mode matching given drm_display_mode.
|
||||
* Returns its CEA Video ID code, or 0 if not found.
|
||||
/**
|
||||
* drm_match_cea_mode - look for a CEA mode matching given mode
|
||||
* @to_match: display mode
|
||||
*
|
||||
* Returns the CEA Video ID (VIC) of the mode or 0 if it isn't a CEA-861
|
||||
* mode.
|
||||
*/
|
||||
u8 drm_match_cea_mode(struct drm_display_mode *to_match)
|
||||
u8 drm_match_cea_mode(const struct drm_display_mode *to_match)
|
||||
{
|
||||
struct drm_display_mode *cea_mode;
|
||||
u8 mode;
|
||||
|
||||
for (mode = 0; mode < drm_num_cea_modes; mode++) {
|
||||
for (mode = 0; mode < ARRAY_SIZE(edid_cea_modes); mode++) {
|
||||
cea_mode = (struct drm_display_mode *)&edid_cea_modes[mode];
|
||||
|
||||
if (drm_mode_equal(to_match, cea_mode))
|
||||
@ -1542,7 +2288,7 @@ do_cea_modes (struct drm_connector *connector, u8 *db, u8 len)
|
||||
|
||||
for (mode = db; mode < db + len; mode++) {
|
||||
cea_mode = (*mode & 127) - 1; /* CEA modes are numbered 1..127 */
|
||||
if (cea_mode < drm_num_cea_modes) {
|
||||
if (cea_mode < ARRAY_SIZE(edid_cea_modes)) {
|
||||
struct drm_display_mode *newmode;
|
||||
newmode = drm_mode_duplicate(dev,
|
||||
&edid_cea_modes[cea_mode]);
|
||||
@ -1901,6 +2647,37 @@ end:
|
||||
}
|
||||
EXPORT_SYMBOL(drm_detect_monitor_audio);
|
||||
|
||||
/**
|
||||
* drm_rgb_quant_range_selectable - is RGB quantization range selectable?
|
||||
*
|
||||
* Check whether the monitor reports the RGB quantization range selection
|
||||
* as supported. The AVI infoframe can then be used to inform the monitor
|
||||
* which quantization range (full or limited) is used.
|
||||
*/
|
||||
bool drm_rgb_quant_range_selectable(struct edid *edid)
|
||||
{
|
||||
u8 *edid_ext;
|
||||
int i, start, end;
|
||||
|
||||
edid_ext = drm_find_cea_extension(edid);
|
||||
if (!edid_ext)
|
||||
return false;
|
||||
|
||||
if (cea_db_offsets(edid_ext, &start, &end))
|
||||
return false;
|
||||
|
||||
for_each_cea_db(edid_ext, i, start, end) {
|
||||
if (cea_db_tag(&edid_ext[i]) == VIDEO_CAPABILITY_BLOCK &&
|
||||
cea_db_payload_len(&edid_ext[i]) == 2) {
|
||||
DRM_DEBUG_KMS("CEA VCDB 0x%02x\n", edid_ext[i + 2]);
|
||||
return edid_ext[i + 2] & EDID_CEA_VCDB_QS;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
EXPORT_SYMBOL(drm_rgb_quant_range_selectable);
|
||||
|
||||
/**
|
||||
* drm_add_display_info - pull display info out if present
|
||||
* @edid: EDID data
|
||||
@ -2020,7 +2797,8 @@ int drm_add_edid_modes(struct drm_connector *connector, struct edid *edid)
|
||||
num_modes += add_cvt_modes(connector, edid);
|
||||
num_modes += add_standard_modes(connector, edid);
|
||||
num_modes += add_established_modes(connector, edid);
|
||||
num_modes += add_inferred_modes(connector, edid);
|
||||
if (edid->features & DRM_EDID_FEATURE_DEFAULT_GTF)
|
||||
num_modes += add_inferred_modes(connector, edid);
|
||||
num_modes += add_cea_modes(connector, edid);
|
||||
|
||||
if (quirks & (EDID_QUIRK_PREFER_LARGE_60 | EDID_QUIRK_PREFER_LARGE_75))
|
||||
@ -2081,20 +2859,33 @@ int drm_add_modes_noedid(struct drm_connector *connector,
|
||||
EXPORT_SYMBOL(drm_add_modes_noedid);
|
||||
|
||||
/**
|
||||
* drm_mode_cea_vic - return the CEA-861 VIC of a given mode
|
||||
* @mode: mode
|
||||
* drm_hdmi_avi_infoframe_from_display_mode() - fill an HDMI AVI infoframe with
|
||||
* data from a DRM display mode
|
||||
* @frame: HDMI AVI infoframe
|
||||
* @mode: DRM display mode
|
||||
*
|
||||
* RETURNS:
|
||||
* The VIC number, 0 in case it's not a CEA-861 mode.
|
||||
* Returns 0 on success or a negative error code on failure.
|
||||
*/
|
||||
uint8_t drm_mode_cea_vic(const struct drm_display_mode *mode)
|
||||
int
|
||||
drm_hdmi_avi_infoframe_from_display_mode(struct hdmi_avi_infoframe *frame,
|
||||
const struct drm_display_mode *mode)
|
||||
{
|
||||
uint8_t i;
|
||||
int err;
|
||||
|
||||
for (i = 0; i < drm_num_cea_modes; i++)
|
||||
if (drm_mode_equal(mode, &edid_cea_modes[i]))
|
||||
return i + 1;
|
||||
if (!frame || !mode)
|
||||
return -EINVAL;
|
||||
|
||||
err = hdmi_avi_infoframe_init(frame);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
frame->video_code = drm_match_cea_mode(mode);
|
||||
if (!frame->video_code)
|
||||
return 0;
|
||||
|
||||
frame->picture_aspect = HDMI_PICTURE_ASPECT_NONE;
|
||||
frame->active_aspect = HDMI_ACTIVE_ASPECT_PICTURE;
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(drm_mode_cea_vic);
|
||||
EXPORT_SYMBOL(drm_hdmi_avi_infoframe_from_display_mode);
|
||||
|
@ -1,774 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2007-2008 Intel Corporation
|
||||
* Jesse Barnes <jesse.barnes@intel.com>
|
||||
* Copyright 2010 Red Hat, Inc.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sub license,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice (including the
|
||||
* next paragraph) shall be included in all copies or substantial portions
|
||||
* of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <drm/drmP.h>
|
||||
#include <drm/drm_edid.h>
|
||||
|
||||
/*
|
||||
* Autogenerated from the DMT spec.
|
||||
* This table is copied from xfree86/modes/xf86EdidModes.c.
|
||||
*/
|
||||
static const struct drm_display_mode drm_dmt_modes[] = {
|
||||
/* 640x350@85Hz */
|
||||
{ DRM_MODE("640x350", DRM_MODE_TYPE_DRIVER, 31500, 640, 672,
|
||||
736, 832, 0, 350, 382, 385, 445, 0,
|
||||
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC) },
|
||||
/* 640x400@85Hz */
|
||||
{ DRM_MODE("640x400", DRM_MODE_TYPE_DRIVER, 31500, 640, 672,
|
||||
736, 832, 0, 400, 401, 404, 445, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
|
||||
/* 720x400@85Hz */
|
||||
{ DRM_MODE("720x400", DRM_MODE_TYPE_DRIVER, 35500, 720, 756,
|
||||
828, 936, 0, 400, 401, 404, 446, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
|
||||
/* 640x480@60Hz */
|
||||
{ DRM_MODE("640x480", DRM_MODE_TYPE_DRIVER, 25175, 640, 656,
|
||||
752, 800, 0, 480, 489, 492, 525, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
|
||||
/* 640x480@72Hz */
|
||||
{ DRM_MODE("640x480", DRM_MODE_TYPE_DRIVER, 31500, 640, 664,
|
||||
704, 832, 0, 480, 489, 492, 520, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
|
||||
/* 640x480@75Hz */
|
||||
{ DRM_MODE("640x480", DRM_MODE_TYPE_DRIVER, 31500, 640, 656,
|
||||
720, 840, 0, 480, 481, 484, 500, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
|
||||
/* 640x480@85Hz */
|
||||
{ DRM_MODE("640x480", DRM_MODE_TYPE_DRIVER, 36000, 640, 696,
|
||||
752, 832, 0, 480, 481, 484, 509, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
|
||||
/* 800x600@56Hz */
|
||||
{ DRM_MODE("800x600", DRM_MODE_TYPE_DRIVER, 36000, 800, 824,
|
||||
896, 1024, 0, 600, 601, 603, 625, 0,
|
||||
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
|
||||
/* 800x600@60Hz */
|
||||
{ DRM_MODE("800x600", DRM_MODE_TYPE_DRIVER, 40000, 800, 840,
|
||||
968, 1056, 0, 600, 601, 605, 628, 0,
|
||||
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
|
||||
/* 800x600@72Hz */
|
||||
{ DRM_MODE("800x600", DRM_MODE_TYPE_DRIVER, 50000, 800, 856,
|
||||
976, 1040, 0, 600, 637, 643, 666, 0,
|
||||
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
|
||||
/* 800x600@75Hz */
|
||||
{ DRM_MODE("800x600", DRM_MODE_TYPE_DRIVER, 49500, 800, 816,
|
||||
896, 1056, 0, 600, 601, 604, 625, 0,
|
||||
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
|
||||
/* 800x600@85Hz */
|
||||
{ DRM_MODE("800x600", DRM_MODE_TYPE_DRIVER, 56250, 800, 832,
|
||||
896, 1048, 0, 600, 601, 604, 631, 0,
|
||||
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
|
||||
/* 800x600@120Hz RB */
|
||||
{ DRM_MODE("800x600", DRM_MODE_TYPE_DRIVER, 73250, 800, 848,
|
||||
880, 960, 0, 600, 603, 607, 636, 0,
|
||||
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC) },
|
||||
/* 848x480@60Hz */
|
||||
{ DRM_MODE("848x480", DRM_MODE_TYPE_DRIVER, 33750, 848, 864,
|
||||
976, 1088, 0, 480, 486, 494, 517, 0,
|
||||
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
|
||||
/* 1024x768@43Hz, interlace */
|
||||
{ DRM_MODE("1024x768i", DRM_MODE_TYPE_DRIVER, 44900, 1024, 1032,
|
||||
1208, 1264, 0, 768, 768, 772, 817, 0,
|
||||
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC |
|
||||
DRM_MODE_FLAG_INTERLACE) },
|
||||
/* 1024x768@60Hz */
|
||||
{ DRM_MODE("1024x768", DRM_MODE_TYPE_DRIVER, 65000, 1024, 1048,
|
||||
1184, 1344, 0, 768, 771, 777, 806, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
|
||||
/* 1024x768@70Hz */
|
||||
{ DRM_MODE("1024x768", DRM_MODE_TYPE_DRIVER, 75000, 1024, 1048,
|
||||
1184, 1328, 0, 768, 771, 777, 806, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
|
||||
/* 1024x768@75Hz */
|
||||
{ DRM_MODE("1024x768", DRM_MODE_TYPE_DRIVER, 78750, 1024, 1040,
|
||||
1136, 1312, 0, 768, 769, 772, 800, 0,
|
||||
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
|
||||
/* 1024x768@85Hz */
|
||||
{ DRM_MODE("1024x768", DRM_MODE_TYPE_DRIVER, 94500, 1024, 1072,
|
||||
1168, 1376, 0, 768, 769, 772, 808, 0,
|
||||
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
|
||||
/* 1024x768@120Hz RB */
|
||||
{ DRM_MODE("1024x768", DRM_MODE_TYPE_DRIVER, 115500, 1024, 1072,
|
||||
1104, 1184, 0, 768, 771, 775, 813, 0,
|
||||
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC) },
|
||||
/* 1152x864@75Hz */
|
||||
{ DRM_MODE("1152x864", DRM_MODE_TYPE_DRIVER, 108000, 1152, 1216,
|
||||
1344, 1600, 0, 864, 865, 868, 900, 0,
|
||||
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
|
||||
/* 1280x768@60Hz RB */
|
||||
{ DRM_MODE("1280x768", DRM_MODE_TYPE_DRIVER, 68250, 1280, 1328,
|
||||
1360, 1440, 0, 768, 771, 778, 790, 0,
|
||||
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC) },
|
||||
/* 1280x768@60Hz */
|
||||
{ DRM_MODE("1280x768", DRM_MODE_TYPE_DRIVER, 79500, 1280, 1344,
|
||||
1472, 1664, 0, 768, 771, 778, 798, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
|
||||
/* 1280x768@75Hz */
|
||||
{ DRM_MODE("1280x768", DRM_MODE_TYPE_DRIVER, 102250, 1280, 1360,
|
||||
1488, 1696, 0, 768, 771, 778, 805, 0,
|
||||
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC) },
|
||||
/* 1280x768@85Hz */
|
||||
{ DRM_MODE("1280x768", DRM_MODE_TYPE_DRIVER, 117500, 1280, 1360,
|
||||
1496, 1712, 0, 768, 771, 778, 809, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
|
||||
/* 1280x768@120Hz RB */
|
||||
{ DRM_MODE("1280x768", DRM_MODE_TYPE_DRIVER, 140250, 1280, 1328,
|
||||
1360, 1440, 0, 768, 771, 778, 813, 0,
|
||||
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC) },
|
||||
/* 1280x800@60Hz RB */
|
||||
{ DRM_MODE("1280x800", DRM_MODE_TYPE_DRIVER, 71000, 1280, 1328,
|
||||
1360, 1440, 0, 800, 803, 809, 823, 0,
|
||||
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC) },
|
||||
/* 1280x800@60Hz */
|
||||
{ DRM_MODE("1280x800", DRM_MODE_TYPE_DRIVER, 83500, 1280, 1352,
|
||||
1480, 1680, 0, 800, 803, 809, 831, 0,
|
||||
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC) },
|
||||
/* 1280x800@75Hz */
|
||||
{ DRM_MODE("1280x800", DRM_MODE_TYPE_DRIVER, 106500, 1280, 1360,
|
||||
1488, 1696, 0, 800, 803, 809, 838, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
|
||||
/* 1280x800@85Hz */
|
||||
{ DRM_MODE("1280x800", DRM_MODE_TYPE_DRIVER, 122500, 1280, 1360,
|
||||
1496, 1712, 0, 800, 803, 809, 843, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
|
||||
/* 1280x800@120Hz RB */
|
||||
{ DRM_MODE("1280x800", DRM_MODE_TYPE_DRIVER, 146250, 1280, 1328,
|
||||
1360, 1440, 0, 800, 803, 809, 847, 0,
|
||||
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC) },
|
||||
/* 1280x960@60Hz */
|
||||
{ DRM_MODE("1280x960", DRM_MODE_TYPE_DRIVER, 108000, 1280, 1376,
|
||||
1488, 1800, 0, 960, 961, 964, 1000, 0,
|
||||
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
|
||||
/* 1280x960@85Hz */
|
||||
{ DRM_MODE("1280x960", DRM_MODE_TYPE_DRIVER, 148500, 1280, 1344,
|
||||
1504, 1728, 0, 960, 961, 964, 1011, 0,
|
||||
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
|
||||
/* 1280x960@120Hz RB */
|
||||
{ DRM_MODE("1280x960", DRM_MODE_TYPE_DRIVER, 175500, 1280, 1328,
|
||||
1360, 1440, 0, 960, 963, 967, 1017, 0,
|
||||
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC) },
|
||||
/* 1280x1024@60Hz */
|
||||
{ DRM_MODE("1280x1024", DRM_MODE_TYPE_DRIVER, 108000, 1280, 1328,
|
||||
1440, 1688, 0, 1024, 1025, 1028, 1066, 0,
|
||||
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
|
||||
/* 1280x1024@75Hz */
|
||||
{ DRM_MODE("1280x1024", DRM_MODE_TYPE_DRIVER, 135000, 1280, 1296,
|
||||
1440, 1688, 0, 1024, 1025, 1028, 1066, 0,
|
||||
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
|
||||
/* 1280x1024@85Hz */
|
||||
{ DRM_MODE("1280x1024", DRM_MODE_TYPE_DRIVER, 157500, 1280, 1344,
|
||||
1504, 1728, 0, 1024, 1025, 1028, 1072, 0,
|
||||
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
|
||||
/* 1280x1024@120Hz RB */
|
||||
{ DRM_MODE("1280x1024", DRM_MODE_TYPE_DRIVER, 187250, 1280, 1328,
|
||||
1360, 1440, 0, 1024, 1027, 1034, 1084, 0,
|
||||
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC) },
|
||||
/* 1360x768@60Hz */
|
||||
{ DRM_MODE("1360x768", DRM_MODE_TYPE_DRIVER, 85500, 1360, 1424,
|
||||
1536, 1792, 0, 768, 771, 777, 795, 0,
|
||||
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
|
||||
/* 1360x768@120Hz RB */
|
||||
{ DRM_MODE("1360x768", DRM_MODE_TYPE_DRIVER, 148250, 1360, 1408,
|
||||
1440, 1520, 0, 768, 771, 776, 813, 0,
|
||||
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC) },
|
||||
/* 1400x1050@60Hz RB */
|
||||
{ DRM_MODE("1400x1050", DRM_MODE_TYPE_DRIVER, 101000, 1400, 1448,
|
||||
1480, 1560, 0, 1050, 1053, 1057, 1080, 0,
|
||||
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC) },
|
||||
/* 1400x1050@60Hz */
|
||||
{ DRM_MODE("1400x1050", DRM_MODE_TYPE_DRIVER, 121750, 1400, 1488,
|
||||
1632, 1864, 0, 1050, 1053, 1057, 1089, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
|
||||
/* 1400x1050@75Hz */
|
||||
{ DRM_MODE("1400x1050", DRM_MODE_TYPE_DRIVER, 156000, 1400, 1504,
|
||||
1648, 1896, 0, 1050, 1053, 1057, 1099, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
|
||||
/* 1400x1050@85Hz */
|
||||
{ DRM_MODE("1400x1050", DRM_MODE_TYPE_DRIVER, 179500, 1400, 1504,
|
||||
1656, 1912, 0, 1050, 1053, 1057, 1105, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
|
||||
/* 1400x1050@120Hz RB */
|
||||
{ DRM_MODE("1400x1050", DRM_MODE_TYPE_DRIVER, 208000, 1400, 1448,
|
||||
1480, 1560, 0, 1050, 1053, 1057, 1112, 0,
|
||||
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC) },
|
||||
/* 1440x900@60Hz RB */
|
||||
{ DRM_MODE("1440x900", DRM_MODE_TYPE_DRIVER, 88750, 1440, 1488,
|
||||
1520, 1600, 0, 900, 903, 909, 926, 0,
|
||||
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC) },
|
||||
/* 1440x900@60Hz */
|
||||
{ DRM_MODE("1440x900", DRM_MODE_TYPE_DRIVER, 106500, 1440, 1520,
|
||||
1672, 1904, 0, 900, 903, 909, 934, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
|
||||
/* 1440x900@75Hz */
|
||||
{ DRM_MODE("1440x900", DRM_MODE_TYPE_DRIVER, 136750, 1440, 1536,
|
||||
1688, 1936, 0, 900, 903, 909, 942, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
|
||||
/* 1440x900@85Hz */
|
||||
{ DRM_MODE("1440x900", DRM_MODE_TYPE_DRIVER, 157000, 1440, 1544,
|
||||
1696, 1952, 0, 900, 903, 909, 948, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
|
||||
/* 1440x900@120Hz RB */
|
||||
{ DRM_MODE("1440x900", DRM_MODE_TYPE_DRIVER, 182750, 1440, 1488,
|
||||
1520, 1600, 0, 900, 903, 909, 953, 0,
|
||||
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC) },
|
||||
/* 1600x1200@60Hz */
|
||||
{ DRM_MODE("1600x1200", DRM_MODE_TYPE_DRIVER, 162000, 1600, 1664,
|
||||
1856, 2160, 0, 1200, 1201, 1204, 1250, 0,
|
||||
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
|
||||
/* 1600x1200@65Hz */
|
||||
{ DRM_MODE("1600x1200", DRM_MODE_TYPE_DRIVER, 175500, 1600, 1664,
|
||||
1856, 2160, 0, 1200, 1201, 1204, 1250, 0,
|
||||
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
|
||||
/* 1600x1200@70Hz */
|
||||
{ DRM_MODE("1600x1200", DRM_MODE_TYPE_DRIVER, 189000, 1600, 1664,
|
||||
1856, 2160, 0, 1200, 1201, 1204, 1250, 0,
|
||||
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
|
||||
/* 1600x1200@75Hz */
|
||||
{ DRM_MODE("1600x1200", DRM_MODE_TYPE_DRIVER, 202500, 1600, 1664,
|
||||
1856, 2160, 0, 1200, 1201, 1204, 1250, 0,
|
||||
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
|
||||
/* 1600x1200@85Hz */
|
||||
{ DRM_MODE("1600x1200", DRM_MODE_TYPE_DRIVER, 229500, 1600, 1664,
|
||||
1856, 2160, 0, 1200, 1201, 1204, 1250, 0,
|
||||
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
|
||||
/* 1600x1200@120Hz RB */
|
||||
{ DRM_MODE("1600x1200", DRM_MODE_TYPE_DRIVER, 268250, 1600, 1648,
|
||||
1680, 1760, 0, 1200, 1203, 1207, 1271, 0,
|
||||
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC) },
|
||||
/* 1680x1050@60Hz RB */
|
||||
{ DRM_MODE("1680x1050", DRM_MODE_TYPE_DRIVER, 119000, 1680, 1728,
|
||||
1760, 1840, 0, 1050, 1053, 1059, 1080, 0,
|
||||
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC) },
|
||||
/* 1680x1050@60Hz */
|
||||
{ DRM_MODE("1680x1050", DRM_MODE_TYPE_DRIVER, 146250, 1680, 1784,
|
||||
1960, 2240, 0, 1050, 1053, 1059, 1089, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
|
||||
/* 1680x1050@75Hz */
|
||||
{ DRM_MODE("1680x1050", DRM_MODE_TYPE_DRIVER, 187000, 1680, 1800,
|
||||
1976, 2272, 0, 1050, 1053, 1059, 1099, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
|
||||
/* 1680x1050@85Hz */
|
||||
{ DRM_MODE("1680x1050", DRM_MODE_TYPE_DRIVER, 214750, 1680, 1808,
|
||||
1984, 2288, 0, 1050, 1053, 1059, 1105, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
|
||||
/* 1680x1050@120Hz RB */
|
||||
{ DRM_MODE("1680x1050", DRM_MODE_TYPE_DRIVER, 245500, 1680, 1728,
|
||||
1760, 1840, 0, 1050, 1053, 1059, 1112, 0,
|
||||
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC) },
|
||||
/* 1792x1344@60Hz */
|
||||
{ DRM_MODE("1792x1344", DRM_MODE_TYPE_DRIVER, 204750, 1792, 1920,
|
||||
2120, 2448, 0, 1344, 1345, 1348, 1394, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
|
||||
/* 1792x1344@75Hz */
|
||||
{ DRM_MODE("1792x1344", DRM_MODE_TYPE_DRIVER, 261000, 1792, 1888,
|
||||
2104, 2456, 0, 1344, 1345, 1348, 1417, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
|
||||
/* 1792x1344@120Hz RB */
|
||||
{ DRM_MODE("1792x1344", DRM_MODE_TYPE_DRIVER, 333250, 1792, 1840,
|
||||
1872, 1952, 0, 1344, 1347, 1351, 1423, 0,
|
||||
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC) },
|
||||
/* 1856x1392@60Hz */
|
||||
{ DRM_MODE("1856x1392", DRM_MODE_TYPE_DRIVER, 218250, 1856, 1952,
|
||||
2176, 2528, 0, 1392, 1393, 1396, 1439, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
|
||||
/* 1856x1392@75Hz */
|
||||
{ DRM_MODE("1856x1392", DRM_MODE_TYPE_DRIVER, 288000, 1856, 1984,
|
||||
2208, 2560, 0, 1392, 1395, 1399, 1500, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
|
||||
/* 1856x1392@120Hz RB */
|
||||
{ DRM_MODE("1856x1392", DRM_MODE_TYPE_DRIVER, 356500, 1856, 1904,
|
||||
1936, 2016, 0, 1392, 1395, 1399, 1474, 0,
|
||||
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC) },
|
||||
/* 1920x1200@60Hz RB */
|
||||
{ DRM_MODE("1920x1200", DRM_MODE_TYPE_DRIVER, 154000, 1920, 1968,
|
||||
2000, 2080, 0, 1200, 1203, 1209, 1235, 0,
|
||||
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC) },
|
||||
/* 1920x1200@60Hz */
|
||||
{ DRM_MODE("1920x1200", DRM_MODE_TYPE_DRIVER, 193250, 1920, 2056,
|
||||
2256, 2592, 0, 1200, 1203, 1209, 1245, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
|
||||
/* 1920x1200@75Hz */
|
||||
{ DRM_MODE("1920x1200", DRM_MODE_TYPE_DRIVER, 245250, 1920, 2056,
|
||||
2264, 2608, 0, 1200, 1203, 1209, 1255, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
|
||||
/* 1920x1200@85Hz */
|
||||
{ DRM_MODE("1920x1200", DRM_MODE_TYPE_DRIVER, 281250, 1920, 2064,
|
||||
2272, 2624, 0, 1200, 1203, 1209, 1262, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
|
||||
/* 1920x1200@120Hz RB */
|
||||
{ DRM_MODE("1920x1200", DRM_MODE_TYPE_DRIVER, 317000, 1920, 1968,
|
||||
2000, 2080, 0, 1200, 1203, 1209, 1271, 0,
|
||||
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC) },
|
||||
/* 1920x1440@60Hz */
|
||||
{ DRM_MODE("1920x1440", DRM_MODE_TYPE_DRIVER, 234000, 1920, 2048,
|
||||
2256, 2600, 0, 1440, 1441, 1444, 1500, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
|
||||
/* 1920x1440@75Hz */
|
||||
{ DRM_MODE("1920x1440", DRM_MODE_TYPE_DRIVER, 297000, 1920, 2064,
|
||||
2288, 2640, 0, 1440, 1441, 1444, 1500, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
|
||||
/* 1920x1440@120Hz RB */
|
||||
{ DRM_MODE("1920x1440", DRM_MODE_TYPE_DRIVER, 380500, 1920, 1968,
|
||||
2000, 2080, 0, 1440, 1443, 1447, 1525, 0,
|
||||
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC) },
|
||||
/* 2560x1600@60Hz RB */
|
||||
{ DRM_MODE("2560x1600", DRM_MODE_TYPE_DRIVER, 268500, 2560, 2608,
|
||||
2640, 2720, 0, 1600, 1603, 1609, 1646, 0,
|
||||
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC) },
|
||||
/* 2560x1600@60Hz */
|
||||
{ DRM_MODE("2560x1600", DRM_MODE_TYPE_DRIVER, 348500, 2560, 2752,
|
||||
3032, 3504, 0, 1600, 1603, 1609, 1658, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
|
||||
/* 2560x1600@75HZ */
|
||||
{ DRM_MODE("2560x1600", DRM_MODE_TYPE_DRIVER, 443250, 2560, 2768,
|
||||
3048, 3536, 0, 1600, 1603, 1609, 1672, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
|
||||
/* 2560x1600@85HZ */
|
||||
{ DRM_MODE("2560x1600", DRM_MODE_TYPE_DRIVER, 505250, 2560, 2768,
|
||||
3048, 3536, 0, 1600, 1603, 1609, 1682, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
|
||||
/* 2560x1600@120Hz RB */
|
||||
{ DRM_MODE("2560x1600", DRM_MODE_TYPE_DRIVER, 552750, 2560, 2608,
|
||||
2640, 2720, 0, 1600, 1603, 1609, 1694, 0,
|
||||
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC) },
|
||||
|
||||
};
|
||||
static const int drm_num_dmt_modes =
|
||||
sizeof(drm_dmt_modes) / sizeof(struct drm_display_mode);
|
||||
|
||||
static const struct drm_display_mode edid_est_modes[] = {
|
||||
{ DRM_MODE("800x600", DRM_MODE_TYPE_DRIVER, 40000, 800, 840,
|
||||
968, 1056, 0, 600, 601, 605, 628, 0,
|
||||
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, /* 800x600@60Hz */
|
||||
{ DRM_MODE("800x600", DRM_MODE_TYPE_DRIVER, 36000, 800, 824,
|
||||
896, 1024, 0, 600, 601, 603, 625, 0,
|
||||
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, /* 800x600@56Hz */
|
||||
{ DRM_MODE("640x480", DRM_MODE_TYPE_DRIVER, 31500, 640, 656,
|
||||
720, 840, 0, 480, 481, 484, 500, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, /* 640x480@75Hz */
|
||||
{ DRM_MODE("640x480", DRM_MODE_TYPE_DRIVER, 31500, 640, 664,
|
||||
704, 832, 0, 480, 489, 491, 520, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, /* 640x480@72Hz */
|
||||
{ DRM_MODE("640x480", DRM_MODE_TYPE_DRIVER, 30240, 640, 704,
|
||||
768, 864, 0, 480, 483, 486, 525, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, /* 640x480@67Hz */
|
||||
{ DRM_MODE("640x480", DRM_MODE_TYPE_DRIVER, 25200, 640, 656,
|
||||
752, 800, 0, 480, 490, 492, 525, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, /* 640x480@60Hz */
|
||||
{ DRM_MODE("720x400", DRM_MODE_TYPE_DRIVER, 35500, 720, 738,
|
||||
846, 900, 0, 400, 421, 423, 449, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, /* 720x400@88Hz */
|
||||
{ DRM_MODE("720x400", DRM_MODE_TYPE_DRIVER, 28320, 720, 738,
|
||||
846, 900, 0, 400, 412, 414, 449, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) }, /* 720x400@70Hz */
|
||||
{ DRM_MODE("1280x1024", DRM_MODE_TYPE_DRIVER, 135000, 1280, 1296,
|
||||
1440, 1688, 0, 1024, 1025, 1028, 1066, 0,
|
||||
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, /* 1280x1024@75Hz */
|
||||
{ DRM_MODE("1024x768", DRM_MODE_TYPE_DRIVER, 78800, 1024, 1040,
|
||||
1136, 1312, 0, 768, 769, 772, 800, 0,
|
||||
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, /* 1024x768@75Hz */
|
||||
{ DRM_MODE("1024x768", DRM_MODE_TYPE_DRIVER, 75000, 1024, 1048,
|
||||
1184, 1328, 0, 768, 771, 777, 806, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, /* 1024x768@70Hz */
|
||||
{ DRM_MODE("1024x768", DRM_MODE_TYPE_DRIVER, 65000, 1024, 1048,
|
||||
1184, 1344, 0, 768, 771, 777, 806, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, /* 1024x768@60Hz */
|
||||
{ DRM_MODE("1024x768i", DRM_MODE_TYPE_DRIVER,44900, 1024, 1032,
|
||||
1208, 1264, 0, 768, 768, 776, 817, 0,
|
||||
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC | DRM_MODE_FLAG_INTERLACE) }, /* 1024x768@43Hz */
|
||||
{ DRM_MODE("832x624", DRM_MODE_TYPE_DRIVER, 57284, 832, 864,
|
||||
928, 1152, 0, 624, 625, 628, 667, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, /* 832x624@75Hz */
|
||||
{ DRM_MODE("800x600", DRM_MODE_TYPE_DRIVER, 49500, 800, 816,
|
||||
896, 1056, 0, 600, 601, 604, 625, 0,
|
||||
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, /* 800x600@75Hz */
|
||||
{ DRM_MODE("800x600", DRM_MODE_TYPE_DRIVER, 50000, 800, 856,
|
||||
976, 1040, 0, 600, 637, 643, 666, 0,
|
||||
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, /* 800x600@72Hz */
|
||||
{ DRM_MODE("1152x864", DRM_MODE_TYPE_DRIVER, 108000, 1152, 1216,
|
||||
1344, 1600, 0, 864, 865, 868, 900, 0,
|
||||
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, /* 1152x864@75Hz */
|
||||
};
|
||||
|
||||
struct minimode {
|
||||
short w;
|
||||
short h;
|
||||
short r;
|
||||
short rb;
|
||||
};
|
||||
|
||||
static const struct minimode est3_modes[] = {
|
||||
/* byte 6 */
|
||||
{ 640, 350, 85, 0 },
|
||||
{ 640, 400, 85, 0 },
|
||||
{ 720, 400, 85, 0 },
|
||||
{ 640, 480, 85, 0 },
|
||||
{ 848, 480, 60, 0 },
|
||||
{ 800, 600, 85, 0 },
|
||||
{ 1024, 768, 85, 0 },
|
||||
{ 1152, 864, 75, 0 },
|
||||
/* byte 7 */
|
||||
{ 1280, 768, 60, 1 },
|
||||
{ 1280, 768, 60, 0 },
|
||||
{ 1280, 768, 75, 0 },
|
||||
{ 1280, 768, 85, 0 },
|
||||
{ 1280, 960, 60, 0 },
|
||||
{ 1280, 960, 85, 0 },
|
||||
{ 1280, 1024, 60, 0 },
|
||||
{ 1280, 1024, 85, 0 },
|
||||
/* byte 8 */
|
||||
{ 1360, 768, 60, 0 },
|
||||
{ 1440, 900, 60, 1 },
|
||||
{ 1440, 900, 60, 0 },
|
||||
{ 1440, 900, 75, 0 },
|
||||
{ 1440, 900, 85, 0 },
|
||||
{ 1400, 1050, 60, 1 },
|
||||
{ 1400, 1050, 60, 0 },
|
||||
{ 1400, 1050, 75, 0 },
|
||||
/* byte 9 */
|
||||
{ 1400, 1050, 85, 0 },
|
||||
{ 1680, 1050, 60, 1 },
|
||||
{ 1680, 1050, 60, 0 },
|
||||
{ 1680, 1050, 75, 0 },
|
||||
{ 1680, 1050, 85, 0 },
|
||||
{ 1600, 1200, 60, 0 },
|
||||
{ 1600, 1200, 65, 0 },
|
||||
{ 1600, 1200, 70, 0 },
|
||||
/* byte 10 */
|
||||
{ 1600, 1200, 75, 0 },
|
||||
{ 1600, 1200, 85, 0 },
|
||||
{ 1792, 1344, 60, 0 },
|
||||
{ 1792, 1344, 85, 0 },
|
||||
{ 1856, 1392, 60, 0 },
|
||||
{ 1856, 1392, 75, 0 },
|
||||
{ 1920, 1200, 60, 1 },
|
||||
{ 1920, 1200, 60, 0 },
|
||||
/* byte 11 */
|
||||
{ 1920, 1200, 75, 0 },
|
||||
{ 1920, 1200, 85, 0 },
|
||||
{ 1920, 1440, 60, 0 },
|
||||
{ 1920, 1440, 75, 0 },
|
||||
};
|
||||
static const int num_est3_modes = ARRAY_SIZE(est3_modes);
|
||||
|
||||
static const struct minimode extra_modes[] = {
|
||||
{ 1024, 576, 60, 0 },
|
||||
{ 1366, 768, 60, 0 },
|
||||
{ 1600, 900, 60, 0 },
|
||||
{ 1680, 945, 60, 0 },
|
||||
{ 1920, 1080, 60, 0 },
|
||||
{ 2048, 1152, 60, 0 },
|
||||
{ 2048, 1536, 60, 0 },
|
||||
};
|
||||
static const int num_extra_modes = ARRAY_SIZE(extra_modes);
|
||||
|
||||
/*
|
||||
* Probably taken from CEA-861 spec.
|
||||
* This table is converted from xorg's hw/xfree86/modes/xf86EdidModes.c.
|
||||
*/
|
||||
static const struct drm_display_mode edid_cea_modes[] = {
|
||||
/* 1 - 640x480@60Hz */
|
||||
{ DRM_MODE("640x480", DRM_MODE_TYPE_DRIVER, 25175, 640, 656,
|
||||
752, 800, 0, 480, 490, 492, 525, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
|
||||
/* 2 - 720x480@60Hz */
|
||||
{ DRM_MODE("720x480", DRM_MODE_TYPE_DRIVER, 27000, 720, 736,
|
||||
798, 858, 0, 480, 489, 495, 525, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
|
||||
/* 3 - 720x480@60Hz */
|
||||
{ DRM_MODE("720x480", DRM_MODE_TYPE_DRIVER, 27000, 720, 736,
|
||||
798, 858, 0, 480, 489, 495, 525, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
|
||||
/* 4 - 1280x720@60Hz */
|
||||
{ DRM_MODE("1280x720", DRM_MODE_TYPE_DRIVER, 74250, 1280, 1390,
|
||||
1430, 1650, 0, 720, 725, 730, 750, 0,
|
||||
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
|
||||
/* 5 - 1920x1080i@60Hz */
|
||||
{ DRM_MODE("1920x1080i", DRM_MODE_TYPE_DRIVER, 74250, 1920, 2008,
|
||||
2052, 2200, 0, 1080, 1084, 1094, 1125, 0,
|
||||
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC |
|
||||
DRM_MODE_FLAG_INTERLACE) },
|
||||
/* 6 - 1440x480i@60Hz */
|
||||
{ DRM_MODE("1440x480i", DRM_MODE_TYPE_DRIVER, 27000, 1440, 1478,
|
||||
1602, 1716, 0, 480, 488, 494, 525, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC |
|
||||
DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK) },
|
||||
/* 7 - 1440x480i@60Hz */
|
||||
{ DRM_MODE("1440x480i", DRM_MODE_TYPE_DRIVER, 27000, 1440, 1478,
|
||||
1602, 1716, 0, 480, 488, 494, 525, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC |
|
||||
DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK) },
|
||||
/* 8 - 1440x240@60Hz */
|
||||
{ DRM_MODE("1440x240", DRM_MODE_TYPE_DRIVER, 27000, 1440, 1478,
|
||||
1602, 1716, 0, 240, 244, 247, 262, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC |
|
||||
DRM_MODE_FLAG_DBLCLK) },
|
||||
/* 9 - 1440x240@60Hz */
|
||||
{ DRM_MODE("1440x240", DRM_MODE_TYPE_DRIVER, 27000, 1440, 1478,
|
||||
1602, 1716, 0, 240, 244, 247, 262, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC |
|
||||
DRM_MODE_FLAG_DBLCLK) },
|
||||
/* 10 - 2880x480i@60Hz */
|
||||
{ DRM_MODE("2880x480i", DRM_MODE_TYPE_DRIVER, 54000, 2880, 2956,
|
||||
3204, 3432, 0, 480, 488, 494, 525, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC |
|
||||
DRM_MODE_FLAG_INTERLACE) },
|
||||
/* 11 - 2880x480i@60Hz */
|
||||
{ DRM_MODE("2880x480i", DRM_MODE_TYPE_DRIVER, 54000, 2880, 2956,
|
||||
3204, 3432, 0, 480, 488, 494, 525, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC |
|
||||
DRM_MODE_FLAG_INTERLACE) },
|
||||
/* 12 - 2880x240@60Hz */
|
||||
{ DRM_MODE("2880x240", DRM_MODE_TYPE_DRIVER, 54000, 2880, 2956,
|
||||
3204, 3432, 0, 240, 244, 247, 262, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
|
||||
/* 13 - 2880x240@60Hz */
|
||||
{ DRM_MODE("2880x240", DRM_MODE_TYPE_DRIVER, 54000, 2880, 2956,
|
||||
3204, 3432, 0, 240, 244, 247, 262, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
|
||||
/* 14 - 1440x480@60Hz */
|
||||
{ DRM_MODE("1440x480", DRM_MODE_TYPE_DRIVER, 54000, 1440, 1472,
|
||||
1596, 1716, 0, 480, 489, 495, 525, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
|
||||
/* 15 - 1440x480@60Hz */
|
||||
{ DRM_MODE("1440x480", DRM_MODE_TYPE_DRIVER, 54000, 1440, 1472,
|
||||
1596, 1716, 0, 480, 489, 495, 525, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
|
||||
/* 16 - 1920x1080@60Hz */
|
||||
{ DRM_MODE("1920x1080", DRM_MODE_TYPE_DRIVER, 148500, 1920, 2008,
|
||||
2052, 2200, 0, 1080, 1084, 1089, 1125, 0,
|
||||
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
|
||||
/* 17 - 720x576@50Hz */
|
||||
{ DRM_MODE("720x576", DRM_MODE_TYPE_DRIVER, 27000, 720, 732,
|
||||
796, 864, 0, 576, 581, 586, 625, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
|
||||
/* 18 - 720x576@50Hz */
|
||||
{ DRM_MODE("720x576", DRM_MODE_TYPE_DRIVER, 27000, 720, 732,
|
||||
796, 864, 0, 576, 581, 586, 625, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
|
||||
/* 19 - 1280x720@50Hz */
|
||||
{ DRM_MODE("1280x720", DRM_MODE_TYPE_DRIVER, 74250, 1280, 1720,
|
||||
1760, 1980, 0, 720, 725, 730, 750, 0,
|
||||
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
|
||||
/* 20 - 1920x1080i@50Hz */
|
||||
{ DRM_MODE("1920x1080i", DRM_MODE_TYPE_DRIVER, 74250, 1920, 2448,
|
||||
2492, 2640, 0, 1080, 1084, 1094, 1125, 0,
|
||||
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC |
|
||||
DRM_MODE_FLAG_INTERLACE) },
|
||||
/* 21 - 1440x576i@50Hz */
|
||||
{ DRM_MODE("1440x576i", DRM_MODE_TYPE_DRIVER, 27000, 1440, 1464,
|
||||
1590, 1728, 0, 576, 580, 586, 625, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC |
|
||||
DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK) },
|
||||
/* 22 - 1440x576i@50Hz */
|
||||
{ DRM_MODE("1440x576i", DRM_MODE_TYPE_DRIVER, 27000, 1440, 1464,
|
||||
1590, 1728, 0, 576, 580, 586, 625, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC |
|
||||
DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK) },
|
||||
/* 23 - 1440x288@50Hz */
|
||||
{ DRM_MODE("1440x288", DRM_MODE_TYPE_DRIVER, 27000, 1440, 1464,
|
||||
1590, 1728, 0, 288, 290, 293, 312, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC |
|
||||
DRM_MODE_FLAG_DBLCLK) },
|
||||
/* 24 - 1440x288@50Hz */
|
||||
{ DRM_MODE("1440x288", DRM_MODE_TYPE_DRIVER, 27000, 1440, 1464,
|
||||
1590, 1728, 0, 288, 290, 293, 312, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC |
|
||||
DRM_MODE_FLAG_DBLCLK) },
|
||||
/* 25 - 2880x576i@50Hz */
|
||||
{ DRM_MODE("2880x576i", DRM_MODE_TYPE_DRIVER, 54000, 2880, 2928,
|
||||
3180, 3456, 0, 576, 580, 586, 625, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC |
|
||||
DRM_MODE_FLAG_INTERLACE) },
|
||||
/* 26 - 2880x576i@50Hz */
|
||||
{ DRM_MODE("2880x576i", DRM_MODE_TYPE_DRIVER, 54000, 2880, 2928,
|
||||
3180, 3456, 0, 576, 580, 586, 625, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC |
|
||||
DRM_MODE_FLAG_INTERLACE) },
|
||||
/* 27 - 2880x288@50Hz */
|
||||
{ DRM_MODE("2880x288", DRM_MODE_TYPE_DRIVER, 54000, 2880, 2928,
|
||||
3180, 3456, 0, 288, 290, 293, 312, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
|
||||
/* 28 - 2880x288@50Hz */
|
||||
{ DRM_MODE("2880x288", DRM_MODE_TYPE_DRIVER, 54000, 2880, 2928,
|
||||
3180, 3456, 0, 288, 290, 293, 312, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
|
||||
/* 29 - 1440x576@50Hz */
|
||||
{ DRM_MODE("1440x576", DRM_MODE_TYPE_DRIVER, 54000, 1440, 1464,
|
||||
1592, 1728, 0, 576, 581, 586, 625, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
|
||||
/* 30 - 1440x576@50Hz */
|
||||
{ DRM_MODE("1440x576", DRM_MODE_TYPE_DRIVER, 54000, 1440, 1464,
|
||||
1592, 1728, 0, 576, 581, 586, 625, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
|
||||
/* 31 - 1920x1080@50Hz */
|
||||
{ DRM_MODE("1920x1080", DRM_MODE_TYPE_DRIVER, 148500, 1920, 2448,
|
||||
2492, 2640, 0, 1080, 1084, 1089, 1125, 0,
|
||||
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
|
||||
/* 32 - 1920x1080@24Hz */
|
||||
{ DRM_MODE("1920x1080", DRM_MODE_TYPE_DRIVER, 74250, 1920, 2558,
|
||||
2602, 2750, 0, 1080, 1084, 1089, 1125, 0,
|
||||
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
|
||||
/* 33 - 1920x1080@25Hz */
|
||||
{ DRM_MODE("1920x1080", DRM_MODE_TYPE_DRIVER, 74250, 1920, 2448,
|
||||
2492, 2640, 0, 1080, 1084, 1089, 1125, 0,
|
||||
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
|
||||
/* 34 - 1920x1080@30Hz */
|
||||
{ DRM_MODE("1920x1080", DRM_MODE_TYPE_DRIVER, 74250, 1920, 2008,
|
||||
2052, 2200, 0, 1080, 1084, 1089, 1125, 0,
|
||||
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
|
||||
/* 35 - 2880x480@60Hz */
|
||||
{ DRM_MODE("2880x480", DRM_MODE_TYPE_DRIVER, 108000, 2880, 2944,
|
||||
3192, 3432, 0, 480, 489, 495, 525, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
|
||||
/* 36 - 2880x480@60Hz */
|
||||
{ DRM_MODE("2880x480", DRM_MODE_TYPE_DRIVER, 108000, 2880, 2944,
|
||||
3192, 3432, 0, 480, 489, 495, 525, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
|
||||
/* 37 - 2880x576@50Hz */
|
||||
{ DRM_MODE("2880x576", DRM_MODE_TYPE_DRIVER, 108000, 2880, 2928,
|
||||
3184, 3456, 0, 576, 581, 586, 625, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
|
||||
/* 38 - 2880x576@50Hz */
|
||||
{ DRM_MODE("2880x576", DRM_MODE_TYPE_DRIVER, 108000, 2880, 2928,
|
||||
3184, 3456, 0, 576, 581, 586, 625, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
|
||||
/* 39 - 1920x1080i@50Hz */
|
||||
{ DRM_MODE("1920x1080i", DRM_MODE_TYPE_DRIVER, 72000, 1920, 1952,
|
||||
2120, 2304, 0, 1080, 1126, 1136, 1250, 0,
|
||||
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC |
|
||||
DRM_MODE_FLAG_INTERLACE) },
|
||||
/* 40 - 1920x1080i@100Hz */
|
||||
{ DRM_MODE("1920x1080i", DRM_MODE_TYPE_DRIVER, 148500, 1920, 2448,
|
||||
2492, 2640, 0, 1080, 1084, 1094, 1125, 0,
|
||||
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC |
|
||||
DRM_MODE_FLAG_INTERLACE) },
|
||||
/* 41 - 1280x720@100Hz */
|
||||
{ DRM_MODE("1280x720", DRM_MODE_TYPE_DRIVER, 148500, 1280, 1720,
|
||||
1760, 1980, 0, 720, 725, 730, 750, 0,
|
||||
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
|
||||
/* 42 - 720x576@100Hz */
|
||||
{ DRM_MODE("720x576", DRM_MODE_TYPE_DRIVER, 54000, 720, 732,
|
||||
796, 864, 0, 576, 581, 586, 625, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
|
||||
/* 43 - 720x576@100Hz */
|
||||
{ DRM_MODE("720x576", DRM_MODE_TYPE_DRIVER, 54000, 720, 732,
|
||||
796, 864, 0, 576, 581, 586, 625, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
|
||||
/* 44 - 1440x576i@100Hz */
|
||||
{ DRM_MODE("1440x576", DRM_MODE_TYPE_DRIVER, 54000, 1440, 1464,
|
||||
1590, 1728, 0, 576, 580, 586, 625, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC |
|
||||
DRM_MODE_FLAG_DBLCLK) },
|
||||
/* 45 - 1440x576i@100Hz */
|
||||
{ DRM_MODE("1440x576", DRM_MODE_TYPE_DRIVER, 54000, 1440, 1464,
|
||||
1590, 1728, 0, 576, 580, 586, 625, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC |
|
||||
DRM_MODE_FLAG_DBLCLK) },
|
||||
/* 46 - 1920x1080i@120Hz */
|
||||
{ DRM_MODE("1920x1080i", DRM_MODE_TYPE_DRIVER, 148500, 1920, 2008,
|
||||
2052, 2200, 0, 1080, 1084, 1094, 1125, 0,
|
||||
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC |
|
||||
DRM_MODE_FLAG_INTERLACE) },
|
||||
/* 47 - 1280x720@120Hz */
|
||||
{ DRM_MODE("1280x720", DRM_MODE_TYPE_DRIVER, 148500, 1280, 1390,
|
||||
1430, 1650, 0, 720, 725, 730, 750, 0,
|
||||
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
|
||||
/* 48 - 720x480@120Hz */
|
||||
{ DRM_MODE("720x480", DRM_MODE_TYPE_DRIVER, 54000, 720, 736,
|
||||
798, 858, 0, 480, 489, 495, 525, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
|
||||
/* 49 - 720x480@120Hz */
|
||||
{ DRM_MODE("720x480", DRM_MODE_TYPE_DRIVER, 54000, 720, 736,
|
||||
798, 858, 0, 480, 489, 495, 525, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
|
||||
/* 50 - 1440x480i@120Hz */
|
||||
{ DRM_MODE("1440x480i", DRM_MODE_TYPE_DRIVER, 54000, 1440, 1478,
|
||||
1602, 1716, 0, 480, 488, 494, 525, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC |
|
||||
DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK) },
|
||||
/* 51 - 1440x480i@120Hz */
|
||||
{ DRM_MODE("1440x480i", DRM_MODE_TYPE_DRIVER, 54000, 1440, 1478,
|
||||
1602, 1716, 0, 480, 488, 494, 525, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC |
|
||||
DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK) },
|
||||
/* 52 - 720x576@200Hz */
|
||||
{ DRM_MODE("720x576", DRM_MODE_TYPE_DRIVER, 108000, 720, 732,
|
||||
796, 864, 0, 576, 581, 586, 625, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
|
||||
/* 53 - 720x576@200Hz */
|
||||
{ DRM_MODE("720x576", DRM_MODE_TYPE_DRIVER, 108000, 720, 732,
|
||||
796, 864, 0, 576, 581, 586, 625, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
|
||||
/* 54 - 1440x576i@200Hz */
|
||||
{ DRM_MODE("1440x576i", DRM_MODE_TYPE_DRIVER, 108000, 1440, 1464,
|
||||
1590, 1728, 0, 576, 580, 586, 625, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC |
|
||||
DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK) },
|
||||
/* 55 - 1440x576i@200Hz */
|
||||
{ DRM_MODE("1440x576i", DRM_MODE_TYPE_DRIVER, 108000, 1440, 1464,
|
||||
1590, 1728, 0, 576, 580, 586, 625, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC |
|
||||
DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK) },
|
||||
/* 56 - 720x480@240Hz */
|
||||
{ DRM_MODE("720x480", DRM_MODE_TYPE_DRIVER, 108000, 720, 736,
|
||||
798, 858, 0, 480, 489, 495, 525, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
|
||||
/* 57 - 720x480@240Hz */
|
||||
{ DRM_MODE("720x480", DRM_MODE_TYPE_DRIVER, 108000, 720, 736,
|
||||
798, 858, 0, 480, 489, 495, 525, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
|
||||
/* 58 - 1440x480i@240 */
|
||||
{ DRM_MODE("1440x480i", DRM_MODE_TYPE_DRIVER, 108000, 1440, 1478,
|
||||
1602, 1716, 0, 480, 488, 494, 525, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC |
|
||||
DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK) },
|
||||
/* 59 - 1440x480i@240 */
|
||||
{ DRM_MODE("1440x480i", DRM_MODE_TYPE_DRIVER, 108000, 1440, 1478,
|
||||
1602, 1716, 0, 480, 488, 494, 525, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC |
|
||||
DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK) },
|
||||
/* 60 - 1280x720@24Hz */
|
||||
{ DRM_MODE("1280x720", DRM_MODE_TYPE_DRIVER, 59400, 1280, 3040,
|
||||
3080, 3300, 0, 720, 725, 730, 750, 0,
|
||||
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
|
||||
/* 61 - 1280x720@25Hz */
|
||||
{ DRM_MODE("1280x720", DRM_MODE_TYPE_DRIVER, 74250, 1280, 3700,
|
||||
3740, 3960, 0, 720, 725, 730, 750, 0,
|
||||
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
|
||||
/* 62 - 1280x720@30Hz */
|
||||
{ DRM_MODE("1280x720", DRM_MODE_TYPE_DRIVER, 74250, 1280, 3040,
|
||||
3080, 3300, 0, 720, 725, 730, 750, 0,
|
||||
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
|
||||
/* 63 - 1920x1080@120Hz */
|
||||
{ DRM_MODE("1920x1080", DRM_MODE_TYPE_DRIVER, 297000, 1920, 2008,
|
||||
2052, 2200, 0, 1080, 1084, 1089, 1125, 0,
|
||||
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
|
||||
/* 64 - 1920x1080@100Hz */
|
||||
{ DRM_MODE("1920x1080", DRM_MODE_TYPE_DRIVER, 297000, 1920, 2448,
|
||||
2492, 2640, 0, 1080, 1084, 1094, 1125, 0,
|
||||
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
|
||||
};
|
||||
static const int drm_num_cea_modes = ARRAY_SIZE(edid_cea_modes);
|
@ -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 @@ err_drm_gem_cma_free_object:
|
||||
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);
|
||||
|
||||
|
@ -52,9 +52,36 @@ static LIST_HEAD(kernel_fb_helper_list);
|
||||
* mode setting driver. They can be used mostly independantely from the crtc
|
||||
* helper functions used by many drivers to implement the kernel mode setting
|
||||
* interfaces.
|
||||
*
|
||||
* Initialization is done as a three-step process with drm_fb_helper_init(),
|
||||
* drm_fb_helper_single_add_all_connectors() and drm_fb_helper_initial_config().
|
||||
* Drivers with fancier requirements than the default beheviour can override the
|
||||
* second step with their own code. Teardown is done with drm_fb_helper_fini().
|
||||
*
|
||||
* At runtime drivers should restore the fbdev console by calling
|
||||
* drm_fb_helper_restore_fbdev_mode() from their ->lastclose callback. They
|
||||
* should also notify the fb helper code from updates to the output
|
||||
* configuration by calling drm_fb_helper_hotplug_event(). For easier
|
||||
* integration with the output polling code in drm_crtc_helper.c the modeset
|
||||
* code proves a ->output_poll_changed callback.
|
||||
*
|
||||
* All other functions exported by the fb helper library can be used to
|
||||
* implement the fbdev driver interface by the driver.
|
||||
*/
|
||||
|
||||
/* simple single crtc case helper function */
|
||||
/**
|
||||
* drm_fb_helper_single_add_all_connectors() - add all connectors to fbdev
|
||||
* emulation helper
|
||||
* @fb_helper: fbdev initialized with drm_fb_helper_init
|
||||
*
|
||||
* This functions adds all the available connectors for use with the given
|
||||
* fb_helper. This is a separate step to allow drivers to freely assign
|
||||
* connectors to the fbdev, e.g. if some are reserved for special purposes or
|
||||
* not adequate to be used for the fbcon.
|
||||
*
|
||||
* Since this is part of the initial setup before the fbdev is published, no
|
||||
* locking is required.
|
||||
*/
|
||||
int drm_fb_helper_single_add_all_connectors(struct drm_fb_helper *fb_helper)
|
||||
{
|
||||
struct drm_device *dev = fb_helper->dev;
|
||||
@ -163,6 +190,10 @@ static void drm_fb_helper_restore_lut_atomic(struct drm_crtc *crtc)
|
||||
crtc->funcs->gamma_set(crtc, r_base, g_base, b_base, 0, crtc->gamma_size);
|
||||
}
|
||||
|
||||
/**
|
||||
* drm_fb_helper_debug_enter - implementation for ->fb_debug_enter
|
||||
* @info: fbdev registered by the helper
|
||||
*/
|
||||
int drm_fb_helper_debug_enter(struct fb_info *info)
|
||||
{
|
||||
struct drm_fb_helper *helper = info->par;
|
||||
@ -208,6 +239,10 @@ static struct drm_framebuffer *drm_mode_config_fb(struct drm_crtc *crtc)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* drm_fb_helper_debug_leave - implementation for ->fb_debug_leave
|
||||
* @info: fbdev registered by the helper
|
||||
*/
|
||||
int drm_fb_helper_debug_leave(struct fb_info *info)
|
||||
{
|
||||
struct drm_fb_helper *helper = info->par;
|
||||
@ -239,13 +274,24 @@ int drm_fb_helper_debug_leave(struct fb_info *info)
|
||||
}
|
||||
EXPORT_SYMBOL(drm_fb_helper_debug_leave);
|
||||
|
||||
/**
|
||||
* drm_fb_helper_restore_fbdev_mode - restore fbdev configuration
|
||||
* @fb_helper: fbcon to restore
|
||||
*
|
||||
* This should be called from driver's drm ->lastclose callback
|
||||
* when implementing an fbcon on top of kms using this helper. This ensures that
|
||||
* the user isn't greeted with a black screen when e.g. X dies.
|
||||
*/
|
||||
bool drm_fb_helper_restore_fbdev_mode(struct drm_fb_helper *fb_helper)
|
||||
{
|
||||
bool error = false;
|
||||
int i, ret;
|
||||
|
||||
drm_warn_on_modeset_not_all_locked(fb_helper->dev);
|
||||
|
||||
for (i = 0; i < fb_helper->crtc_count; i++) {
|
||||
struct drm_mode_set *mode_set = &fb_helper->crtc_info[i].mode_set;
|
||||
ret = mode_set->crtc->funcs->set_config(mode_set);
|
||||
ret = drm_mode_set_config_internal(mode_set);
|
||||
if (ret)
|
||||
error = true;
|
||||
}
|
||||
@ -253,6 +299,10 @@ bool drm_fb_helper_restore_fbdev_mode(struct drm_fb_helper *fb_helper)
|
||||
}
|
||||
EXPORT_SYMBOL(drm_fb_helper_restore_fbdev_mode);
|
||||
|
||||
/*
|
||||
* restore fbcon display for all kms driver's using this helper, used for sysrq
|
||||
* and panic handling.
|
||||
*/
|
||||
static bool drm_fb_helper_force_kernel_mode(void)
|
||||
{
|
||||
bool ret, error = false;
|
||||
@ -272,7 +322,7 @@ static bool drm_fb_helper_force_kernel_mode(void)
|
||||
return error;
|
||||
}
|
||||
|
||||
int drm_fb_helper_panic(struct notifier_block *n, unsigned long ununsed,
|
||||
static int drm_fb_helper_panic(struct notifier_block *n, unsigned long ununsed,
|
||||
void *panic_str)
|
||||
{
|
||||
/*
|
||||
@ -285,31 +335,37 @@ int drm_fb_helper_panic(struct notifier_block *n, unsigned long ununsed,
|
||||
pr_err("panic occurred, switching back to text console\n");
|
||||
return drm_fb_helper_force_kernel_mode();
|
||||
}
|
||||
EXPORT_SYMBOL(drm_fb_helper_panic);
|
||||
|
||||
static struct notifier_block paniced = {
|
||||
.notifier_call = drm_fb_helper_panic,
|
||||
};
|
||||
|
||||
/**
|
||||
* drm_fb_helper_restore - restore the framebuffer console (kernel) config
|
||||
*
|
||||
* Restore's the kernel's fbcon mode, used for lastclose & panic paths.
|
||||
*/
|
||||
void drm_fb_helper_restore(void)
|
||||
static bool drm_fb_helper_is_bound(struct drm_fb_helper *fb_helper)
|
||||
{
|
||||
struct drm_device *dev = fb_helper->dev;
|
||||
struct drm_crtc *crtc;
|
||||
int bound = 0, crtcs_bound = 0;
|
||||
|
||||
list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
|
||||
if (crtc->fb)
|
||||
crtcs_bound++;
|
||||
if (crtc->fb == fb_helper->fb)
|
||||
bound++;
|
||||
}
|
||||
|
||||
if (bound < crtcs_bound)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_MAGIC_SYSRQ
|
||||
static void drm_fb_helper_restore_work_fn(struct work_struct *ignored)
|
||||
{
|
||||
bool ret;
|
||||
ret = drm_fb_helper_force_kernel_mode();
|
||||
if (ret == true)
|
||||
DRM_ERROR("Failed to restore crtc configuration\n");
|
||||
}
|
||||
EXPORT_SYMBOL(drm_fb_helper_restore);
|
||||
|
||||
#ifdef CONFIG_MAGIC_SYSRQ
|
||||
static void drm_fb_helper_restore_work_fn(struct work_struct *ignored)
|
||||
{
|
||||
drm_fb_helper_restore();
|
||||
}
|
||||
static DECLARE_WORK(drm_fb_helper_restore_work, drm_fb_helper_restore_work_fn);
|
||||
|
||||
static void drm_fb_helper_sysrq(int dummy1)
|
||||
@ -334,10 +390,23 @@ static void drm_fb_helper_dpms(struct fb_info *info, int dpms_mode)
|
||||
struct drm_connector *connector;
|
||||
int i, j;
|
||||
|
||||
/*
|
||||
* fbdev->blank can be called from irq context in case of a panic.
|
||||
* Since we already have our own special panic handler which will
|
||||
* restore the fbdev console mode completely, just bail out early.
|
||||
*/
|
||||
if (oops_in_progress)
|
||||
return;
|
||||
|
||||
/*
|
||||
* For each CRTC in this fb, turn the connectors on/off.
|
||||
*/
|
||||
mutex_lock(&dev->mode_config.mutex);
|
||||
drm_modeset_lock_all(dev);
|
||||
if (!drm_fb_helper_is_bound(fb_helper)) {
|
||||
drm_modeset_unlock_all(dev);
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0; i < fb_helper->crtc_count; i++) {
|
||||
crtc = fb_helper->crtc_info[i].mode_set.crtc;
|
||||
|
||||
@ -352,9 +421,14 @@ static void drm_fb_helper_dpms(struct fb_info *info, int dpms_mode)
|
||||
dev->mode_config.dpms_property, dpms_mode);
|
||||
}
|
||||
}
|
||||
mutex_unlock(&dev->mode_config.mutex);
|
||||
drm_modeset_unlock_all(dev);
|
||||
}
|
||||
|
||||
/**
|
||||
* drm_fb_helper_blank - implementation for ->fb_blank
|
||||
* @blank: desired blanking state
|
||||
* @info: fbdev registered by the helper
|
||||
*/
|
||||
int drm_fb_helper_blank(int blank, struct fb_info *info)
|
||||
{
|
||||
switch (blank) {
|
||||
@ -398,6 +472,24 @@ static void drm_fb_helper_crtc_free(struct drm_fb_helper *helper)
|
||||
kfree(helper->crtc_info);
|
||||
}
|
||||
|
||||
/**
|
||||
* drm_fb_helper_init - initialize a drm_fb_helper structure
|
||||
* @dev: drm device
|
||||
* @fb_helper: driver-allocated fbdev helper structure to initialize
|
||||
* @crtc_count: maximum number of crtcs to support in this fbdev emulation
|
||||
* @max_conn_count: max connector count
|
||||
*
|
||||
* This allocates the structures for the fbdev helper with the given limits.
|
||||
* Note that this won't yet touch the hardware (through the driver interfaces)
|
||||
* nor register the fbdev. This is only done in drm_fb_helper_initial_config()
|
||||
* to allow driver writes more control over the exact init sequence.
|
||||
*
|
||||
* Drivers must set fb_helper->funcs before calling
|
||||
* drm_fb_helper_initial_config().
|
||||
*
|
||||
* RETURNS:
|
||||
* Zero if everything went ok, nonzero otherwise.
|
||||
*/
|
||||
int drm_fb_helper_init(struct drm_device *dev,
|
||||
struct drm_fb_helper *fb_helper,
|
||||
int crtc_count, int max_conn_count)
|
||||
@ -526,6 +618,11 @@ static int setcolreg(struct drm_crtc *crtc, u16 red, u16 green,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* drm_fb_helper_setcmap - implementation for ->fb_setcmap
|
||||
* @cmap: cmap to set
|
||||
* @info: fbdev registered by the helper
|
||||
*/
|
||||
int drm_fb_helper_setcmap(struct fb_cmap *cmap, struct fb_info *info)
|
||||
{
|
||||
struct drm_fb_helper *fb_helper = info->par;
|
||||
@ -565,6 +662,11 @@ int drm_fb_helper_setcmap(struct fb_cmap *cmap, struct fb_info *info)
|
||||
}
|
||||
EXPORT_SYMBOL(drm_fb_helper_setcmap);
|
||||
|
||||
/**
|
||||
* drm_fb_helper_check_var - implementation for ->fb_check_var
|
||||
* @var: screeninfo to check
|
||||
* @info: fbdev registered by the helper
|
||||
*/
|
||||
int drm_fb_helper_check_var(struct fb_var_screeninfo *var,
|
||||
struct fb_info *info)
|
||||
{
|
||||
@ -657,13 +759,19 @@ int drm_fb_helper_check_var(struct fb_var_screeninfo *var,
|
||||
}
|
||||
EXPORT_SYMBOL(drm_fb_helper_check_var);
|
||||
|
||||
/* this will let fbcon do the mode init */
|
||||
/**
|
||||
* drm_fb_helper_set_par - implementation for ->fb_set_par
|
||||
* @info: fbdev registered by the helper
|
||||
*
|
||||
* This will let fbcon do the mode init and is called at initialization time by
|
||||
* the fbdev core when registering the driver, and later on through the hotplug
|
||||
* callback.
|
||||
*/
|
||||
int drm_fb_helper_set_par(struct fb_info *info)
|
||||
{
|
||||
struct drm_fb_helper *fb_helper = info->par;
|
||||
struct drm_device *dev = fb_helper->dev;
|
||||
struct fb_var_screeninfo *var = &info->var;
|
||||
struct drm_crtc *crtc;
|
||||
int ret;
|
||||
int i;
|
||||
|
||||
@ -672,16 +780,15 @@ int drm_fb_helper_set_par(struct fb_info *info)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
mutex_lock(&dev->mode_config.mutex);
|
||||
drm_modeset_lock_all(dev);
|
||||
for (i = 0; i < fb_helper->crtc_count; i++) {
|
||||
crtc = fb_helper->crtc_info[i].mode_set.crtc;
|
||||
ret = crtc->funcs->set_config(&fb_helper->crtc_info[i].mode_set);
|
||||
ret = drm_mode_set_config_internal(&fb_helper->crtc_info[i].mode_set);
|
||||
if (ret) {
|
||||
mutex_unlock(&dev->mode_config.mutex);
|
||||
drm_modeset_unlock_all(dev);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
mutex_unlock(&dev->mode_config.mutex);
|
||||
drm_modeset_unlock_all(dev);
|
||||
|
||||
if (fb_helper->delayed_hotplug) {
|
||||
fb_helper->delayed_hotplug = false;
|
||||
@ -691,6 +798,11 @@ int drm_fb_helper_set_par(struct fb_info *info)
|
||||
}
|
||||
EXPORT_SYMBOL(drm_fb_helper_set_par);
|
||||
|
||||
/**
|
||||
* drm_fb_helper_pan_display - implementation for ->fb_pan_display
|
||||
* @var: updated screen information
|
||||
* @info: fbdev registered by the helper
|
||||
*/
|
||||
int drm_fb_helper_pan_display(struct fb_var_screeninfo *var,
|
||||
struct fb_info *info)
|
||||
{
|
||||
@ -701,7 +813,12 @@ int drm_fb_helper_pan_display(struct fb_var_screeninfo *var,
|
||||
int ret = 0;
|
||||
int i;
|
||||
|
||||
mutex_lock(&dev->mode_config.mutex);
|
||||
drm_modeset_lock_all(dev);
|
||||
if (!drm_fb_helper_is_bound(fb_helper)) {
|
||||
drm_modeset_unlock_all(dev);
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
for (i = 0; i < fb_helper->crtc_count; i++) {
|
||||
crtc = fb_helper->crtc_info[i].mode_set.crtc;
|
||||
|
||||
@ -711,22 +828,27 @@ int drm_fb_helper_pan_display(struct fb_var_screeninfo *var,
|
||||
modeset->y = var->yoffset;
|
||||
|
||||
if (modeset->num_connectors) {
|
||||
ret = crtc->funcs->set_config(modeset);
|
||||
ret = drm_mode_set_config_internal(modeset);
|
||||
if (!ret) {
|
||||
info->var.xoffset = var->xoffset;
|
||||
info->var.yoffset = var->yoffset;
|
||||
}
|
||||
}
|
||||
}
|
||||
mutex_unlock(&dev->mode_config.mutex);
|
||||
drm_modeset_unlock_all(dev);
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(drm_fb_helper_pan_display);
|
||||
|
||||
int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper,
|
||||
int preferred_bpp)
|
||||
/*
|
||||
* Allocates the backing storage and sets up the fbdev info structure through
|
||||
* the ->fb_probe callback and then registers the fbdev and sets up the panic
|
||||
* notifier.
|
||||
*/
|
||||
static int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper,
|
||||
int preferred_bpp)
|
||||
{
|
||||
int new_fb = 0;
|
||||
int ret = 0;
|
||||
int crtc_count = 0;
|
||||
int i;
|
||||
struct fb_info *info;
|
||||
@ -804,27 +926,30 @@ int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper,
|
||||
}
|
||||
|
||||
/* push down into drivers */
|
||||
new_fb = (*fb_helper->funcs->fb_probe)(fb_helper, &sizes);
|
||||
if (new_fb < 0)
|
||||
return new_fb;
|
||||
ret = (*fb_helper->funcs->fb_probe)(fb_helper, &sizes);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
info = fb_helper->fbdev;
|
||||
|
||||
/* set the fb pointer */
|
||||
/*
|
||||
* Set the fb pointer - usually drm_setup_crtcs does this for hotplug
|
||||
* events, but at init time drm_setup_crtcs needs to be called before
|
||||
* the fb is allocated (since we need to figure out the desired size of
|
||||
* the fb before we can allocate it ...). Hence we need to fix things up
|
||||
* here again.
|
||||
*/
|
||||
for (i = 0; i < fb_helper->crtc_count; i++)
|
||||
fb_helper->crtc_info[i].mode_set.fb = fb_helper->fb;
|
||||
if (fb_helper->crtc_info[i].mode_set.num_connectors)
|
||||
fb_helper->crtc_info[i].mode_set.fb = fb_helper->fb;
|
||||
|
||||
if (new_fb) {
|
||||
info->var.pixclock = 0;
|
||||
if (register_framebuffer(info) < 0)
|
||||
return -EINVAL;
|
||||
|
||||
dev_info(fb_helper->dev->dev, "fb%d: %s frame buffer device\n",
|
||||
info->node, info->fix.id);
|
||||
info->var.pixclock = 0;
|
||||
if (register_framebuffer(info) < 0)
|
||||
return -EINVAL;
|
||||
|
||||
} else {
|
||||
drm_fb_helper_set_par(info);
|
||||
}
|
||||
dev_info(fb_helper->dev->dev, "fb%d: %s frame buffer device\n",
|
||||
info->node, info->fix.id);
|
||||
|
||||
/* Switch back to kernel console on panic */
|
||||
/* multi card linked list maybe */
|
||||
@ -834,13 +959,25 @@ int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper,
|
||||
&paniced);
|
||||
register_sysrq_key('v', &sysrq_drm_fb_helper_restore_op);
|
||||
}
|
||||
if (new_fb)
|
||||
list_add(&fb_helper->kernel_fb_list, &kernel_fb_helper_list);
|
||||
|
||||
list_add(&fb_helper->kernel_fb_list, &kernel_fb_helper_list);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(drm_fb_helper_single_fb_probe);
|
||||
|
||||
/**
|
||||
* drm_fb_helper_fill_fix - initializes fixed fbdev information
|
||||
* @info: fbdev registered by the helper
|
||||
* @pitch: desired pitch
|
||||
* @depth: desired depth
|
||||
*
|
||||
* Helper to fill in the fixed fbdev information useful for a non-accelerated
|
||||
* fbdev emulations. Drivers which support acceleration methods which impose
|
||||
* additional constraints need to set up their own limits.
|
||||
*
|
||||
* Drivers should call this (or their equivalent setup code) from their
|
||||
* ->fb_probe callback.
|
||||
*/
|
||||
void drm_fb_helper_fill_fix(struct fb_info *info, uint32_t pitch,
|
||||
uint32_t depth)
|
||||
{
|
||||
@ -861,6 +998,20 @@ void drm_fb_helper_fill_fix(struct fb_info *info, uint32_t pitch,
|
||||
}
|
||||
EXPORT_SYMBOL(drm_fb_helper_fill_fix);
|
||||
|
||||
/**
|
||||
* drm_fb_helper_fill_var - initalizes variable fbdev information
|
||||
* @info: fbdev instance to set up
|
||||
* @fb_helper: fb helper instance to use as template
|
||||
* @fb_width: desired fb width
|
||||
* @fb_height: desired fb height
|
||||
*
|
||||
* Sets up the variable fbdev metainformation from the given fb helper instance
|
||||
* and the drm framebuffer allocated in fb_helper->fb.
|
||||
*
|
||||
* Drivers should call this (or their equivalent setup code) from their
|
||||
* ->fb_probe callback after having allocated the fbdev backing
|
||||
* storage framebuffer.
|
||||
*/
|
||||
void drm_fb_helper_fill_var(struct fb_info *info, struct drm_fb_helper *fb_helper,
|
||||
uint32_t fb_width, uint32_t fb_height)
|
||||
{
|
||||
@ -1284,6 +1435,7 @@ static void drm_setup_crtcs(struct drm_fb_helper *fb_helper)
|
||||
for (i = 0; i < fb_helper->crtc_count; i++) {
|
||||
modeset = &fb_helper->crtc_info[i].mode_set;
|
||||
modeset->num_connectors = 0;
|
||||
modeset->fb = NULL;
|
||||
}
|
||||
|
||||
for (i = 0; i < fb_helper->connector_count; i++) {
|
||||
@ -1300,9 +1452,21 @@ static void drm_setup_crtcs(struct drm_fb_helper *fb_helper)
|
||||
modeset->mode = drm_mode_duplicate(dev,
|
||||
fb_crtc->desired_mode);
|
||||
modeset->connectors[modeset->num_connectors++] = fb_helper->connector_info[i]->connector;
|
||||
modeset->fb = fb_helper->fb;
|
||||
}
|
||||
}
|
||||
|
||||
/* Clear out any old modes if there are no more connected outputs. */
|
||||
for (i = 0; i < fb_helper->crtc_count; i++) {
|
||||
modeset = &fb_helper->crtc_info[i].mode_set;
|
||||
if (modeset->num_connectors == 0) {
|
||||
BUG_ON(modeset->fb);
|
||||
BUG_ON(modeset->num_connectors);
|
||||
if (modeset->mode)
|
||||
drm_mode_destroy(dev, modeset->mode);
|
||||
modeset->mode = NULL;
|
||||
}
|
||||
}
|
||||
out:
|
||||
kfree(crtcs);
|
||||
kfree(modes);
|
||||
@ -1310,18 +1474,23 @@ out:
|
||||
}
|
||||
|
||||
/**
|
||||
* drm_helper_initial_config - setup a sane initial connector configuration
|
||||
* drm_fb_helper_initial_config - setup a sane initial connector configuration
|
||||
* @fb_helper: fb_helper device struct
|
||||
* @bpp_sel: bpp value to use for the framebuffer configuration
|
||||
*
|
||||
* LOCKING:
|
||||
* Called at init time by the driver to set up the @fb_helper initial
|
||||
* configuration, must take the mode config lock.
|
||||
*
|
||||
* Scans the CRTCs and connectors and tries to put together an initial setup.
|
||||
* At the moment, this is a cloned configuration across all heads with
|
||||
* a new framebuffer object as the backing store.
|
||||
*
|
||||
* Note that this also registers the fbdev and so allows userspace to call into
|
||||
* the driver through the fbdev interfaces.
|
||||
*
|
||||
* This function will call down into the ->fb_probe callback to let
|
||||
* the driver allocate and initialize the fbdev info structure and the drm
|
||||
* framebuffer used to back the fbdev. drm_fb_helper_fill_var() and
|
||||
* drm_fb_helper_fill_fix() are provided as helpers to setup simple default
|
||||
* values for the fbdev info structure.
|
||||
*
|
||||
* RETURNS:
|
||||
* Zero if everything went ok, nonzero otherwise.
|
||||
*/
|
||||
@ -1330,9 +1499,6 @@ bool drm_fb_helper_initial_config(struct drm_fb_helper *fb_helper, int bpp_sel)
|
||||
struct drm_device *dev = fb_helper->dev;
|
||||
int count = 0;
|
||||
|
||||
/* disable all the possible outputs/crtcs before entering KMS mode */
|
||||
drm_helper_disable_unused_functions(fb_helper->dev);
|
||||
|
||||
drm_fb_helper_parse_command_line(fb_helper);
|
||||
|
||||
count = drm_fb_helper_probe_connector_modes(fb_helper,
|
||||
@ -1355,12 +1521,17 @@ EXPORT_SYMBOL(drm_fb_helper_initial_config);
|
||||
* probing all the outputs attached to the fb
|
||||
* @fb_helper: the drm_fb_helper
|
||||
*
|
||||
* LOCKING:
|
||||
* Called at runtime, must take mode config lock.
|
||||
*
|
||||
* Scan the connectors attached to the fb_helper and try to put together a
|
||||
* setup after *notification of a change in output configuration.
|
||||
*
|
||||
* Called at runtime, takes the mode config locks to be able to check/change the
|
||||
* modeset configuration. Must be run from process context (which usually means
|
||||
* either the output polling work or a work item launched from the driver's
|
||||
* hotplug interrupt).
|
||||
*
|
||||
* Note that the driver must ensure that this is only called _after_ the fb has
|
||||
* been fully set up, i.e. after the call to drm_fb_helper_initial_config.
|
||||
*
|
||||
* RETURNS:
|
||||
* 0 on success and a non-zero error code otherwise.
|
||||
*/
|
||||
@ -1369,23 +1540,14 @@ int drm_fb_helper_hotplug_event(struct drm_fb_helper *fb_helper)
|
||||
struct drm_device *dev = fb_helper->dev;
|
||||
int count = 0;
|
||||
u32 max_width, max_height, bpp_sel;
|
||||
int bound = 0, crtcs_bound = 0;
|
||||
struct drm_crtc *crtc;
|
||||
|
||||
if (!fb_helper->fb)
|
||||
return 0;
|
||||
|
||||
mutex_lock(&dev->mode_config.mutex);
|
||||
list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
|
||||
if (crtc->fb)
|
||||
crtcs_bound++;
|
||||
if (crtc->fb == fb_helper->fb)
|
||||
bound++;
|
||||
}
|
||||
|
||||
if (bound < crtcs_bound) {
|
||||
drm_modeset_lock_all(dev);
|
||||
if (!drm_fb_helper_is_bound(fb_helper)) {
|
||||
fb_helper->delayed_hotplug = true;
|
||||
mutex_unlock(&dev->mode_config.mutex);
|
||||
drm_modeset_unlock_all(dev);
|
||||
return 0;
|
||||
}
|
||||
DRM_DEBUG_KMS("\n");
|
||||
@ -1397,9 +1559,11 @@ int drm_fb_helper_hotplug_event(struct drm_fb_helper *fb_helper)
|
||||
count = drm_fb_helper_probe_connector_modes(fb_helper, max_width,
|
||||
max_height);
|
||||
drm_setup_crtcs(fb_helper);
|
||||
mutex_unlock(&dev->mode_config.mutex);
|
||||
drm_modeset_unlock_all(dev);
|
||||
|
||||
return drm_fb_helper_single_fb_probe(fb_helper, bpp_sel);
|
||||
drm_fb_helper_set_par(fb_helper->fbdev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(drm_fb_helper_hotplug_event);
|
||||
|
||||
|
@ -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,6 +439,44 @@ int drm_pci_init(struct drm_driver *driver, struct pci_driver *pdriver)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int drm_pcie_get_speed_cap_mask(struct drm_device *dev, u32 *mask)
|
||||
{
|
||||
struct pci_dev *root;
|
||||
u32 lnkcap, lnkcap2;
|
||||
|
||||
*mask = 0;
|
||||
if (!dev->pdev)
|
||||
return -EINVAL;
|
||||
|
||||
root = dev->pdev->bus->self;
|
||||
|
||||
/* we've been informed via and serverworks don't make the cut */
|
||||
if (root->vendor == PCI_VENDOR_ID_VIA ||
|
||||
root->vendor == PCI_VENDOR_ID_SERVERWORKS)
|
||||
return -EINVAL;
|
||||
|
||||
pcie_capability_read_dword(root, PCI_EXP_LNKCAP, &lnkcap);
|
||||
pcie_capability_read_dword(root, PCI_EXP_LNKCAP2, &lnkcap2);
|
||||
|
||||
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 { /* pre-r3.0 */
|
||||
if (lnkcap & PCI_EXP_LNKCAP_SLS_2_5GB)
|
||||
*mask |= DRM_PCIE_SPEED_25;
|
||||
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)
|
||||
@ -465,52 +503,3 @@ void drm_pci_exit(struct drm_driver *driver, struct pci_driver *pdriver)
|
||||
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;
|
||||
|
||||
*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);
|
||||
|
||||
lnkcap &= PCI_EXP_LNKCAP_SLS;
|
||||
lnkcap2 &= 0xfe;
|
||||
|
||||
if (lnkcap2) { /* PCIE GEN 3.0 */
|
||||
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)
|
||||
*mask |= DRM_PCIE_SPEED_25;
|
||||
if (lnkcap & 2)
|
||||
*mask |= 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);
|
||||
|
@ -53,7 +53,8 @@
|
||||
* Self-importing: if userspace is using PRIME as a replacement for flink
|
||||
* then it will get a fd->handle request for a GEM object that it created.
|
||||
* Drivers should detect this situation and return back the gem object
|
||||
* from the dma-buf private.
|
||||
* from the dma-buf private. Prime will do this automatically for drivers that
|
||||
* use the drm_gem_prime_{import,export} helpers.
|
||||
*/
|
||||
|
||||
struct drm_prime_member {
|
||||
@ -62,6 +63,137 @@ struct drm_prime_member {
|
||||
uint32_t handle;
|
||||
};
|
||||
|
||||
static struct sg_table *drm_gem_map_dma_buf(struct dma_buf_attachment *attach,
|
||||
enum dma_data_direction dir)
|
||||
{
|
||||
struct drm_gem_object *obj = attach->dmabuf->priv;
|
||||
struct sg_table *sgt;
|
||||
|
||||
mutex_lock(&obj->dev->struct_mutex);
|
||||
|
||||
sgt = obj->dev->driver->gem_prime_get_sg_table(obj);
|
||||
|
||||
if (!IS_ERR_OR_NULL(sgt))
|
||||
dma_map_sg(attach->dev, sgt->sgl, sgt->nents, dir);
|
||||
|
||||
mutex_unlock(&obj->dev->struct_mutex);
|
||||
return sgt;
|
||||
}
|
||||
|
||||
static void drm_gem_unmap_dma_buf(struct dma_buf_attachment *attach,
|
||||
struct sg_table *sgt, enum dma_data_direction dir)
|
||||
{
|
||||
dma_unmap_sg(attach->dev, sgt->sgl, sgt->nents, dir);
|
||||
sg_free_table(sgt);
|
||||
kfree(sgt);
|
||||
}
|
||||
|
||||
static void drm_gem_dmabuf_release(struct dma_buf *dma_buf)
|
||||
{
|
||||
struct drm_gem_object *obj = dma_buf->priv;
|
||||
|
||||
if (obj->export_dma_buf == dma_buf) {
|
||||
/* drop the reference on the export fd holds */
|
||||
obj->export_dma_buf = NULL;
|
||||
drm_gem_object_unreference_unlocked(obj);
|
||||
}
|
||||
}
|
||||
|
||||
static void *drm_gem_dmabuf_vmap(struct dma_buf *dma_buf)
|
||||
{
|
||||
struct drm_gem_object *obj = dma_buf->priv;
|
||||
struct drm_device *dev = obj->dev;
|
||||
|
||||
return dev->driver->gem_prime_vmap(obj);
|
||||
}
|
||||
|
||||
static void drm_gem_dmabuf_vunmap(struct dma_buf *dma_buf, void *vaddr)
|
||||
{
|
||||
struct drm_gem_object *obj = dma_buf->priv;
|
||||
struct drm_device *dev = obj->dev;
|
||||
|
||||
dev->driver->gem_prime_vunmap(obj, vaddr);
|
||||
}
|
||||
|
||||
static void *drm_gem_dmabuf_kmap_atomic(struct dma_buf *dma_buf,
|
||||
unsigned long page_num)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void drm_gem_dmabuf_kunmap_atomic(struct dma_buf *dma_buf,
|
||||
unsigned long page_num, void *addr)
|
||||
{
|
||||
|
||||
}
|
||||
static void *drm_gem_dmabuf_kmap(struct dma_buf *dma_buf,
|
||||
unsigned long page_num)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void drm_gem_dmabuf_kunmap(struct dma_buf *dma_buf,
|
||||
unsigned long page_num, void *addr)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
static int drm_gem_dmabuf_mmap(struct dma_buf *dma_buf,
|
||||
struct vm_area_struct *vma)
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static const struct dma_buf_ops drm_gem_prime_dmabuf_ops = {
|
||||
.map_dma_buf = drm_gem_map_dma_buf,
|
||||
.unmap_dma_buf = drm_gem_unmap_dma_buf,
|
||||
.release = drm_gem_dmabuf_release,
|
||||
.kmap = drm_gem_dmabuf_kmap,
|
||||
.kmap_atomic = drm_gem_dmabuf_kmap_atomic,
|
||||
.kunmap = drm_gem_dmabuf_kunmap,
|
||||
.kunmap_atomic = drm_gem_dmabuf_kunmap_atomic,
|
||||
.mmap = drm_gem_dmabuf_mmap,
|
||||
.vmap = drm_gem_dmabuf_vmap,
|
||||
.vunmap = drm_gem_dmabuf_vunmap,
|
||||
};
|
||||
|
||||
/**
|
||||
* DOC: PRIME Helpers
|
||||
*
|
||||
* Drivers can implement @gem_prime_export and @gem_prime_import in terms of
|
||||
* simpler APIs by using the helper functions @drm_gem_prime_export and
|
||||
* @drm_gem_prime_import. These functions implement dma-buf support in terms of
|
||||
* five lower-level driver callbacks:
|
||||
*
|
||||
* Export callbacks:
|
||||
*
|
||||
* - @gem_prime_pin (optional): prepare a GEM object for exporting
|
||||
*
|
||||
* - @gem_prime_get_sg_table: provide a scatter/gather table of pinned pages
|
||||
*
|
||||
* - @gem_prime_vmap: vmap a buffer exported by your driver
|
||||
*
|
||||
* - @gem_prime_vunmap: vunmap a buffer exported by your driver
|
||||
*
|
||||
* Import callback:
|
||||
*
|
||||
* - @gem_prime_import_sg_table (import): produce a GEM object from another
|
||||
* driver's scatter/gather table
|
||||
*/
|
||||
|
||||
struct dma_buf *drm_gem_prime_export(struct drm_device *dev,
|
||||
struct drm_gem_object *obj, int flags)
|
||||
{
|
||||
if (dev->driver->gem_prime_pin) {
|
||||
int ret = dev->driver->gem_prime_pin(obj);
|
||||
if (ret)
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
return dma_buf_export(obj, &drm_gem_prime_dmabuf_ops, obj->size,
|
||||
0600);
|
||||
}
|
||||
EXPORT_SYMBOL(drm_gem_prime_export);
|
||||
|
||||
int drm_gem_prime_handle_to_fd(struct drm_device *dev,
|
||||
struct drm_file *file_priv, uint32_t handle, uint32_t flags,
|
||||
int *prime_fd)
|
||||
@ -117,6 +249,58 @@ int drm_gem_prime_handle_to_fd(struct drm_device *dev,
|
||||
}
|
||||
EXPORT_SYMBOL(drm_gem_prime_handle_to_fd);
|
||||
|
||||
struct drm_gem_object *drm_gem_prime_import(struct drm_device *dev,
|
||||
struct dma_buf *dma_buf)
|
||||
{
|
||||
struct dma_buf_attachment *attach;
|
||||
struct sg_table *sgt;
|
||||
struct drm_gem_object *obj;
|
||||
int ret;
|
||||
|
||||
if (!dev->driver->gem_prime_import_sg_table)
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
||||
if (dma_buf->ops == &drm_gem_prime_dmabuf_ops) {
|
||||
obj = dma_buf->priv;
|
||||
if (obj->dev == dev) {
|
||||
/*
|
||||
* Importing dmabuf exported from out own gem increases
|
||||
* refcount on gem itself instead of f_count of dmabuf.
|
||||
*/
|
||||
drm_gem_object_reference(obj);
|
||||
dma_buf_put(dma_buf);
|
||||
return obj;
|
||||
}
|
||||
}
|
||||
|
||||
attach = dma_buf_attach(dma_buf, dev->dev);
|
||||
if (IS_ERR(attach))
|
||||
return ERR_PTR(PTR_ERR(attach));
|
||||
|
||||
sgt = dma_buf_map_attachment(attach, DMA_BIDIRECTIONAL);
|
||||
if (IS_ERR_OR_NULL(sgt)) {
|
||||
ret = PTR_ERR(sgt);
|
||||
goto fail_detach;
|
||||
}
|
||||
|
||||
obj = dev->driver->gem_prime_import_sg_table(dev, dma_buf->size, sgt);
|
||||
if (IS_ERR(obj)) {
|
||||
ret = PTR_ERR(obj);
|
||||
goto fail_unmap;
|
||||
}
|
||||
|
||||
obj->import_attach = attach;
|
||||
|
||||
return obj;
|
||||
|
||||
fail_unmap:
|
||||
dma_buf_unmap_attachment(attach, sgt, DMA_BIDIRECTIONAL);
|
||||
fail_detach:
|
||||
dma_buf_detach(dma_buf, attach);
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
EXPORT_SYMBOL(drm_gem_prime_import);
|
||||
|
||||
int drm_gem_prime_fd_to_handle(struct drm_device *dev,
|
||||
struct drm_file *file_priv, int prime_fd, uint32_t *handle)
|
||||
{
|
||||
|
@ -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);
|
||||
|
||||
|
@ -99,6 +99,10 @@ static int exynos_drm_fb_create_handle(struct drm_framebuffer *fb,
|
||||
|
||||
DRM_DEBUG_KMS("%s\n", __FILE__);
|
||||
|
||||
/* This fb should have only one gem object. */
|
||||
if (WARN_ON(exynos_fb->buf_cnt != 1))
|
||||
return -EINVAL;
|
||||
|
||||
return drm_gem_handle_create(file_priv,
|
||||
&exynos_fb->exynos_gem_obj[0]->base, handle);
|
||||
}
|
||||
@ -217,23 +221,25 @@ exynos_user_fb_create(struct drm_device *dev, struct drm_file *file_priv,
|
||||
struct drm_mode_fb_cmd2 *mode_cmd)
|
||||
{
|
||||
struct drm_gem_object *obj;
|
||||
struct exynos_drm_gem_obj *exynos_gem_obj;
|
||||
struct exynos_drm_fb *exynos_fb;
|
||||
int i, ret;
|
||||
|
||||
DRM_DEBUG_KMS("%s\n", __FILE__);
|
||||
|
||||
obj = drm_gem_object_lookup(dev, file_priv, mode_cmd->handles[0]);
|
||||
if (!obj) {
|
||||
DRM_ERROR("failed to lookup gem object\n");
|
||||
return ERR_PTR(-ENOENT);
|
||||
}
|
||||
|
||||
exynos_fb = kzalloc(sizeof(*exynos_fb), GFP_KERNEL);
|
||||
if (!exynos_fb) {
|
||||
DRM_ERROR("failed to allocate exynos drm framebuffer\n");
|
||||
return ERR_PTR(-ENOMEM);
|
||||
}
|
||||
|
||||
obj = drm_gem_object_lookup(dev, file_priv, mode_cmd->handles[0]);
|
||||
if (!obj) {
|
||||
DRM_ERROR("failed to lookup gem object\n");
|
||||
ret = -ENOENT;
|
||||
goto err_free;
|
||||
}
|
||||
|
||||
drm_helper_mode_fill_fb_struct(&exynos_fb->fb, mode_cmd);
|
||||
exynos_fb->exynos_gem_obj[0] = to_exynos_gem_obj(obj);
|
||||
exynos_fb->buf_cnt = exynos_drm_format_num_buffers(mode_cmd);
|
||||
@ -241,43 +247,44 @@ exynos_user_fb_create(struct drm_device *dev, struct drm_file *file_priv,
|
||||
DRM_DEBUG_KMS("buf_cnt = %d\n", exynos_fb->buf_cnt);
|
||||
|
||||
for (i = 1; i < exynos_fb->buf_cnt; i++) {
|
||||
struct exynos_drm_gem_obj *exynos_gem_obj;
|
||||
int ret;
|
||||
|
||||
obj = drm_gem_object_lookup(dev, file_priv,
|
||||
mode_cmd->handles[i]);
|
||||
if (!obj) {
|
||||
DRM_ERROR("failed to lookup gem object\n");
|
||||
kfree(exynos_fb);
|
||||
return ERR_PTR(-ENOENT);
|
||||
ret = -ENOENT;
|
||||
exynos_fb->buf_cnt = i;
|
||||
goto err_unreference;
|
||||
}
|
||||
|
||||
exynos_gem_obj = to_exynos_gem_obj(obj);
|
||||
exynos_fb->exynos_gem_obj[i] = exynos_gem_obj;
|
||||
|
||||
ret = check_fb_gem_memory_type(dev, exynos_gem_obj);
|
||||
if (ret < 0) {
|
||||
DRM_ERROR("cannot use this gem memory type for fb.\n");
|
||||
kfree(exynos_fb);
|
||||
return ERR_PTR(ret);
|
||||
goto err_unreference;
|
||||
}
|
||||
|
||||
exynos_fb->exynos_gem_obj[i] = to_exynos_gem_obj(obj);
|
||||
}
|
||||
|
||||
ret = drm_framebuffer_init(dev, &exynos_fb->fb, &exynos_drm_fb_funcs);
|
||||
if (ret) {
|
||||
for (i = 0; i < exynos_fb->buf_cnt; i++) {
|
||||
struct exynos_drm_gem_obj *gem_obj;
|
||||
|
||||
gem_obj = exynos_fb->exynos_gem_obj[i];
|
||||
drm_gem_object_unreference_unlocked(&gem_obj->base);
|
||||
}
|
||||
|
||||
kfree(exynos_fb);
|
||||
return ERR_PTR(ret);
|
||||
DRM_ERROR("failed to init framebuffer.\n");
|
||||
goto err_unreference;
|
||||
}
|
||||
|
||||
return &exynos_fb->fb;
|
||||
|
||||
err_unreference:
|
||||
for (i = 0; i < exynos_fb->buf_cnt; i++) {
|
||||
struct drm_gem_object *obj;
|
||||
|
||||
obj = &exynos_fb->exynos_gem_obj[i]->base;
|
||||
if (obj)
|
||||
drm_gem_object_unreference_unlocked(obj);
|
||||
}
|
||||
err_free:
|
||||
kfree(exynos_fb);
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
|
||||
struct exynos_drm_gem_buf *exynos_drm_fb_buffer(struct drm_framebuffer *fb,
|
||||
|
@ -226,36 +226,8 @@ out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int exynos_drm_fbdev_probe(struct drm_fb_helper *helper,
|
||||
struct drm_fb_helper_surface_size *sizes)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
DRM_DEBUG_KMS("%s\n", __FILE__);
|
||||
|
||||
/*
|
||||
* with !helper->fb, it means that this funcion is called first time
|
||||
* and after that, the helper->fb would be used as clone mode.
|
||||
*/
|
||||
if (!helper->fb) {
|
||||
ret = exynos_drm_fbdev_create(helper, sizes);
|
||||
if (ret < 0) {
|
||||
DRM_ERROR("failed to create fbdev.\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* fb_helper expects a value more than 1 if succeed
|
||||
* because register_framebuffer() should be called.
|
||||
*/
|
||||
ret = 1;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static struct drm_fb_helper_funcs exynos_drm_fb_helper_funcs = {
|
||||
.fb_probe = exynos_drm_fbdev_probe,
|
||||
.fb_probe = exynos_drm_fbdev_create,
|
||||
};
|
||||
|
||||
int exynos_drm_fbdev_init(struct drm_device *dev)
|
||||
@ -295,6 +267,9 @@ int exynos_drm_fbdev_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) {
|
||||
DRM_ERROR("failed to set up hw configuration.\n");
|
||||
@ -326,8 +301,10 @@ static void exynos_drm_fbdev_destroy(struct drm_device *dev,
|
||||
/* release drm framebuffer and real buffer */
|
||||
if (fb_helper->fb && fb_helper->fb->funcs) {
|
||||
fb = fb_helper->fb;
|
||||
if (fb)
|
||||
if (fb) {
|
||||
drm_framebuffer_unregister_private(fb);
|
||||
drm_framebuffer_remove(fb);
|
||||
}
|
||||
}
|
||||
|
||||
/* release linux framebuffer */
|
||||
@ -374,5 +351,7 @@ void exynos_drm_fbdev_restore_mode(struct drm_device *dev)
|
||||
if (!private || !private->fb_helper)
|
||||
return;
|
||||
|
||||
drm_modeset_lock_all(dev);
|
||||
drm_fb_helper_restore_fbdev_mode(private->fb_helper);
|
||||
drm_modeset_unlock_all(dev);
|
||||
}
|
||||
|
@ -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),
|
||||
},
|
||||
};
|
||||
|
@ -329,17 +329,11 @@ static struct drm_file *exynos_drm_find_drm_file(struct drm_device *drm_dev,
|
||||
{
|
||||
struct drm_file *file_priv;
|
||||
|
||||
mutex_lock(&drm_dev->struct_mutex);
|
||||
|
||||
/* find current process's drm_file from filelist. */
|
||||
list_for_each_entry(file_priv, &drm_dev->filelist, lhead) {
|
||||
if (file_priv->filp == filp) {
|
||||
mutex_unlock(&drm_dev->struct_mutex);
|
||||
list_for_each_entry(file_priv, &drm_dev->filelist, lhead)
|
||||
if (file_priv->filp == filp)
|
||||
return file_priv;
|
||||
}
|
||||
}
|
||||
|
||||
mutex_unlock(&drm_dev->struct_mutex);
|
||||
WARN_ON(1);
|
||||
|
||||
return ERR_PTR(-EFAULT);
|
||||
@ -400,9 +394,7 @@ static int exynos_drm_gem_mmap_buffer(struct file *filp,
|
||||
*/
|
||||
drm_gem_object_reference(obj);
|
||||
|
||||
mutex_lock(&drm_dev->struct_mutex);
|
||||
drm_vm_open_locked(drm_dev, vma);
|
||||
mutex_unlock(&drm_dev->struct_mutex);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -431,6 +423,16 @@ int exynos_drm_gem_mmap_ioctl(struct drm_device *dev, void *data,
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/*
|
||||
* We have to use gem object and its fops for specific mmaper,
|
||||
* but vm_mmap() can deliver only filp. So we have to change
|
||||
* filp->f_op and filp->private_data temporarily, then restore
|
||||
* again. So it is important to keep lock until restoration the
|
||||
* settings to prevent others from misuse of filp->f_op or
|
||||
* filp->private_data.
|
||||
*/
|
||||
mutex_lock(&dev->struct_mutex);
|
||||
|
||||
/*
|
||||
* Set specific mmper's fops. And it will be restored by
|
||||
* exynos_drm_gem_mmap_buffer to dev->driver->fops.
|
||||
@ -448,13 +450,20 @@ int exynos_drm_gem_mmap_ioctl(struct drm_device *dev, void *data,
|
||||
addr = vm_mmap(file_priv->filp, 0, args->size,
|
||||
PROT_READ | PROT_WRITE, MAP_SHARED, 0);
|
||||
|
||||
drm_gem_object_unreference_unlocked(obj);
|
||||
drm_gem_object_unreference(obj);
|
||||
|
||||
if (IS_ERR((void *)addr)) {
|
||||
file_priv->filp->private_data = file_priv;
|
||||
/* check filp->f_op, filp->private_data are restored */
|
||||
if (file_priv->filp->f_op == &exynos_drm_gem_fops) {
|
||||
file_priv->filp->f_op = fops_get(dev->driver->fops);
|
||||
file_priv->filp->private_data = file_priv;
|
||||
}
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
return PTR_ERR((void *)addr);
|
||||
}
|
||||
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
|
||||
args->mapped = addr;
|
||||
|
||||
DRM_DEBUG_KMS("mapped = 0x%lx\n", (unsigned long)args->mapped);
|
||||
|
@ -124,9 +124,21 @@ static struct edid *drm_hdmi_get_edid(struct device *dev,
|
||||
static int drm_hdmi_check_timing(struct device *dev, void *timing)
|
||||
{
|
||||
struct drm_hdmi_context *ctx = to_context(dev);
|
||||
int ret = 0;
|
||||
|
||||
DRM_DEBUG_KMS("%s\n", __FILE__);
|
||||
|
||||
/*
|
||||
* Both, mixer and hdmi should be able to handle the requested mode.
|
||||
* If any of the two fails, return mode as BAD.
|
||||
*/
|
||||
|
||||
if (mixer_ops && mixer_ops->check_timing)
|
||||
ret = mixer_ops->check_timing(ctx->mixer_ctx->ctx, timing);
|
||||
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (hdmi_ops && hdmi_ops->check_timing)
|
||||
return hdmi_ops->check_timing(ctx->hdmi_ctx->ctx, timing);
|
||||
|
||||
|
@ -32,7 +32,7 @@ struct exynos_hdmi_ops {
|
||||
bool (*is_connected)(void *ctx);
|
||||
struct edid *(*get_edid)(void *ctx,
|
||||
struct drm_connector *connector);
|
||||
int (*check_timing)(void *ctx, void *timing);
|
||||
int (*check_timing)(void *ctx, struct fb_videomode *timing);
|
||||
int (*power_on)(void *ctx, int mode);
|
||||
|
||||
/* manager */
|
||||
@ -58,6 +58,9 @@ struct exynos_mixer_ops {
|
||||
void (*win_mode_set)(void *ctx, struct exynos_drm_overlay *overlay);
|
||||
void (*win_commit)(void *ctx, int zpos);
|
||||
void (*win_disable)(void *ctx, int zpos);
|
||||
|
||||
/* display */
|
||||
int (*check_timing)(void *ctx, struct fb_videomode *timing);
|
||||
};
|
||||
|
||||
void exynos_hdmi_drv_attach(struct exynos_drm_hdmi_context *ctx);
|
||||
|
@ -14,7 +14,7 @@
|
||||
|
||||
#define EXYNOS_DEV_ADDR_START 0x20000000
|
||||
#define EXYNOS_DEV_ADDR_SIZE 0x40000000
|
||||
#define EXYNOS_DEV_ADDR_ORDER 0x4
|
||||
#define EXYNOS_DEV_ADDR_ORDER 0x0
|
||||
|
||||
#ifdef CONFIG_DRM_EXYNOS_IOMMU
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -284,13 +284,13 @@ static void mixer_cfg_scan(struct mixer_context *ctx, unsigned int height)
|
||||
MXR_CFG_SCAN_PROGRASSIVE);
|
||||
|
||||
/* choosing between porper HD and SD mode */
|
||||
if (height == 480)
|
||||
if (height <= 480)
|
||||
val |= MXR_CFG_SCAN_NTSC | MXR_CFG_SCAN_SD;
|
||||
else if (height == 576)
|
||||
else if (height <= 576)
|
||||
val |= MXR_CFG_SCAN_PAL | MXR_CFG_SCAN_SD;
|
||||
else if (height == 720)
|
||||
else if (height <= 720)
|
||||
val |= MXR_CFG_SCAN_HD_720 | MXR_CFG_SCAN_HD;
|
||||
else if (height == 1080)
|
||||
else if (height <= 1080)
|
||||
val |= MXR_CFG_SCAN_HD_1080 | MXR_CFG_SCAN_HD;
|
||||
else
|
||||
val |= MXR_CFG_SCAN_HD_720 | MXR_CFG_SCAN_HD;
|
||||
@ -818,6 +818,29 @@ static void mixer_win_disable(void *ctx, int win)
|
||||
mixer_ctx->win_data[win].enabled = false;
|
||||
}
|
||||
|
||||
int mixer_check_timing(void *ctx, struct fb_videomode *timing)
|
||||
{
|
||||
struct mixer_context *mixer_ctx = ctx;
|
||||
u32 w, h;
|
||||
|
||||
w = timing->xres;
|
||||
h = timing->yres;
|
||||
|
||||
DRM_DEBUG_KMS("%s : xres=%d, yres=%d, refresh=%d, intl=%d\n",
|
||||
__func__, timing->xres, timing->yres,
|
||||
timing->refresh, (timing->vmode &
|
||||
FB_VMODE_INTERLACED) ? true : false);
|
||||
|
||||
if (mixer_ctx->mxr_ver == MXR_VER_0_0_0_16)
|
||||
return 0;
|
||||
|
||||
if ((w >= 464 && w <= 720 && h >= 261 && h <= 576) ||
|
||||
(w >= 1024 && w <= 1280 && h >= 576 && h <= 720) ||
|
||||
(w >= 1664 && w <= 1920 && h >= 936 && h <= 1080))
|
||||
return 0;
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
static void mixer_wait_for_vblank(void *ctx)
|
||||
{
|
||||
struct mixer_context *mixer_ctx = ctx;
|
||||
@ -955,6 +978,9 @@ static struct exynos_mixer_ops mixer_ops = {
|
||||
.win_mode_set = mixer_win_mode_set,
|
||||
.win_commit = mixer_win_commit,
|
||||
.win_disable = mixer_win_disable,
|
||||
|
||||
/* display */
|
||||
.check_timing = mixer_check_timing,
|
||||
};
|
||||
|
||||
static irqreturn_t mixer_irq_handler(int irq, void *arg)
|
||||
|
@ -260,13 +260,13 @@ static int psb_framebuffer_init(struct drm_device *dev,
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
drm_helper_mode_fill_fb_struct(&fb->base, mode_cmd);
|
||||
fb->gtt = gt;
|
||||
ret = drm_framebuffer_init(dev, &fb->base, &psb_fb_funcs);
|
||||
if (ret) {
|
||||
dev_err(dev->dev, "framebuffer init failed: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
drm_helper_mode_fill_fb_struct(&fb->base, mode_cmd);
|
||||
fb->gtt = gt;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -545,9 +545,7 @@ static int psbfb_probe(struct drm_fb_helper *helper,
|
||||
struct psb_fbdev *psb_fbdev = (struct psb_fbdev *)helper;
|
||||
struct drm_device *dev = psb_fbdev->psb_fb_helper.dev;
|
||||
struct drm_psb_private *dev_priv = dev->dev_private;
|
||||
int new_fb = 0;
|
||||
int bytespp;
|
||||
int ret;
|
||||
|
||||
bytespp = sizes->surface_bpp / 8;
|
||||
if (bytespp == 3) /* no 24bit packed */
|
||||
@ -562,13 +560,7 @@ static int psbfb_probe(struct drm_fb_helper *helper,
|
||||
sizes->surface_depth = 16;
|
||||
}
|
||||
|
||||
if (!helper->fb) {
|
||||
ret = psbfb_create(psb_fbdev, sizes);
|
||||
if (ret)
|
||||
return ret;
|
||||
new_fb = 1;
|
||||
}
|
||||
return new_fb;
|
||||
return psbfb_create(psb_fbdev, sizes);
|
||||
}
|
||||
|
||||
static struct drm_fb_helper_funcs psb_fb_helper_funcs = {
|
||||
@ -590,6 +582,7 @@ static int psb_fbdev_destroy(struct drm_device *dev, struct psb_fbdev *fbdev)
|
||||
framebuffer_release(info);
|
||||
}
|
||||
drm_fb_helper_fini(&fbdev->psb_fb_helper);
|
||||
drm_framebuffer_unregister_private(&psbfb->base);
|
||||
drm_framebuffer_cleanup(&psbfb->base);
|
||||
|
||||
if (psbfb->gtt)
|
||||
@ -615,6 +608,10 @@ int psb_fbdev_init(struct drm_device *dev)
|
||||
INTELFB_CONN_LIMIT);
|
||||
|
||||
drm_fb_helper_single_add_all_connectors(&fbdev->psb_fb_helper);
|
||||
|
||||
/* disable all the possible outputs/crtcs before entering KMS mode */
|
||||
drm_helper_disable_unused_functions(dev);
|
||||
|
||||
drm_fb_helper_initial_config(&fbdev->psb_fb_helper, 32);
|
||||
return 0;
|
||||
}
|
||||
@ -668,30 +665,6 @@ static void psb_user_framebuffer_destroy(struct drm_framebuffer *fb)
|
||||
{
|
||||
struct psb_framebuffer *psbfb = to_psb_fb(fb);
|
||||
struct gtt_range *r = psbfb->gtt;
|
||||
struct drm_device *dev = fb->dev;
|
||||
struct drm_psb_private *dev_priv = dev->dev_private;
|
||||
struct psb_fbdev *fbdev = dev_priv->fbdev;
|
||||
struct drm_crtc *crtc;
|
||||
int reset = 0;
|
||||
|
||||
/* Should never get stolen memory for a user fb */
|
||||
WARN_ON(r->stolen);
|
||||
|
||||
/* Check if we are erroneously live */
|
||||
list_for_each_entry(crtc, &dev->mode_config.crtc_list, head)
|
||||
if (crtc->fb == fb)
|
||||
reset = 1;
|
||||
|
||||
if (reset)
|
||||
/*
|
||||
* Now force a sane response before we permit the DRM CRTC
|
||||
* layer to do stupid things like blank the display. Instead
|
||||
* we reset this framebuffer as if the user had forced a reset.
|
||||
* We must do this before the cleanup so that the DRM layer
|
||||
* doesn't get a chance to stick its oar in where it isn't
|
||||
* wanted.
|
||||
*/
|
||||
drm_fb_helper_restore_fbdev_mode(&fbdev->psb_fb_helper);
|
||||
|
||||
/* Let DRM do its clean up */
|
||||
drm_framebuffer_cleanup(fb);
|
||||
|
@ -194,7 +194,7 @@ static int psb_save_display_registers(struct drm_device *dev)
|
||||
regs->saveCHICKENBIT = PSB_RVDC32(DSPCHICKENBIT);
|
||||
|
||||
/* Save crtc and output state */
|
||||
mutex_lock(&dev->mode_config.mutex);
|
||||
drm_modeset_lock_all(dev);
|
||||
list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
|
||||
if (drm_helper_crtc_in_use(crtc))
|
||||
crtc->funcs->save(crtc);
|
||||
@ -204,7 +204,7 @@ static int psb_save_display_registers(struct drm_device *dev)
|
||||
if (connector->funcs->save)
|
||||
connector->funcs->save(connector);
|
||||
|
||||
mutex_unlock(&dev->mode_config.mutex);
|
||||
drm_modeset_unlock_all(dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -234,7 +234,7 @@ static int psb_restore_display_registers(struct drm_device *dev)
|
||||
/*make sure VGA plane is off. it initializes to on after reset!*/
|
||||
PSB_WVDC32(0x80000000, VGACNTRL);
|
||||
|
||||
mutex_lock(&dev->mode_config.mutex);
|
||||
drm_modeset_lock_all(dev);
|
||||
list_for_each_entry(crtc, &dev->mode_config.crtc_list, head)
|
||||
if (drm_helper_crtc_in_use(crtc))
|
||||
crtc->funcs->restore(crtc);
|
||||
@ -243,7 +243,7 @@ static int psb_restore_display_registers(struct drm_device *dev)
|
||||
if (connector->funcs->restore)
|
||||
connector->funcs->restore(connector);
|
||||
|
||||
mutex_unlock(&dev->mode_config.mutex);
|
||||
drm_modeset_unlock_all(dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -149,6 +149,16 @@ static struct drm_ioctl_desc psb_ioctls[] = {
|
||||
|
||||
static void psb_lastclose(struct drm_device *dev)
|
||||
{
|
||||
int ret;
|
||||
struct drm_psb_private *dev_priv = dev->dev_private;
|
||||
struct psb_fbdev *fbdev = dev_priv->fbdev;
|
||||
|
||||
drm_modeset_lock_all(dev);
|
||||
ret = drm_fb_helper_restore_fbdev_mode(&fbdev->psb_fb_helper);
|
||||
if (ret)
|
||||
DRM_DEBUG("failed to restore crtc mode\n");
|
||||
drm_modeset_unlock_all(dev);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@ -476,7 +486,7 @@ static int psb_mode_operation_ioctl(struct drm_device *dev, void *data,
|
||||
case PSB_MODE_OPERATION_MODE_VALID:
|
||||
umode = &arg->mode;
|
||||
|
||||
mutex_lock(&dev->mode_config.mutex);
|
||||
drm_modeset_lock_all(dev);
|
||||
|
||||
obj = drm_mode_object_find(dev, obj_id,
|
||||
DRM_MODE_OBJECT_CONNECTOR);
|
||||
@ -525,7 +535,7 @@ static int psb_mode_operation_ioctl(struct drm_device *dev, void *data,
|
||||
if (mode)
|
||||
drm_mode_destroy(dev, mode);
|
||||
mode_op_out:
|
||||
mutex_unlock(&dev->mode_config.mutex);
|
||||
drm_modeset_unlock_all(dev);
|
||||
return ret;
|
||||
|
||||
default:
|
||||
|
@ -85,14 +85,14 @@ struct psb_intel_limit_t {
|
||||
#define I9XX_DOT_MAX 400000
|
||||
#define I9XX_VCO_MIN 1400000
|
||||
#define I9XX_VCO_MAX 2800000
|
||||
#define I9XX_N_MIN 3
|
||||
#define I9XX_N_MAX 8
|
||||
#define I9XX_N_MIN 1
|
||||
#define I9XX_N_MAX 6
|
||||
#define I9XX_M_MIN 70
|
||||
#define I9XX_M_MAX 120
|
||||
#define I9XX_M1_MIN 10
|
||||
#define I9XX_M1_MAX 20
|
||||
#define I9XX_M2_MIN 5
|
||||
#define I9XX_M2_MAX 9
|
||||
#define I9XX_M1_MIN 8
|
||||
#define I9XX_M1_MAX 18
|
||||
#define I9XX_M2_MIN 3
|
||||
#define I9XX_M2_MAX 7
|
||||
#define I9XX_P_SDVO_DAC_MIN 5
|
||||
#define I9XX_P_SDVO_DAC_MAX 80
|
||||
#define I9XX_P_LVDS_MIN 7
|
||||
|
28
drivers/gpu/drm/i2c/Kconfig
Normal file
28
drivers/gpu/drm/i2c/Kconfig
Normal file
@ -0,0 +1,28 @@
|
||||
menu "I2C encoder or helper chips"
|
||||
depends on DRM && DRM_KMS_HELPER && I2C
|
||||
|
||||
config DRM_I2C_CH7006
|
||||
tristate "Chrontel ch7006 TV encoder"
|
||||
default m if DRM_NOUVEAU
|
||||
help
|
||||
Support for Chrontel ch7006 and similar TV encoders, found
|
||||
on some nVidia video cards.
|
||||
|
||||
This driver is currently only useful if you're also using
|
||||
the nouveau driver.
|
||||
|
||||
config DRM_I2C_SIL164
|
||||
tristate "Silicon Image sil164 TMDS transmitter"
|
||||
default m if DRM_NOUVEAU
|
||||
help
|
||||
Support for sil164 and similar single-link (or dual-link
|
||||
when used in pairs) TMDS transmitters, used in some nVidia
|
||||
video cards.
|
||||
|
||||
config DRM_I2C_NXP_TDA998X
|
||||
tristate "NXP Semiconductors TDA998X HDMI encoder"
|
||||
default m if DRM_TILCDC
|
||||
help
|
||||
Support for NXP Semiconductors TDA998X HDMI encoders.
|
||||
|
||||
endmenu
|
@ -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
|
||||
|
@ -364,7 +364,7 @@ static int ch7006_encoder_set_property(struct drm_encoder *encoder,
|
||||
.crtc = crtc,
|
||||
};
|
||||
|
||||
crtc->funcs->set_config(&modeset);
|
||||
drm_mode_set_config_internal(&modeset);
|
||||
}
|
||||
}
|
||||
|
||||
|
906
drivers/gpu/drm/i2c/tda998x_drv.c
Normal file
906
drivers/gpu/drm/i2c/tda998x_drv.c
Normal file
@ -0,0 +1,906 @@
|
||||
/*
|
||||
* Copyright (C) 2012 Texas Instruments
|
||||
* Author: Rob Clark <robdclark@gmail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 as published by
|
||||
* the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
#include <linux/module.h>
|
||||
|
||||
#include <drm/drmP.h>
|
||||
#include <drm/drm_crtc_helper.h>
|
||||
#include <drm/drm_encoder_slave.h>
|
||||
#include <drm/drm_edid.h>
|
||||
|
||||
|
||||
#define DBG(fmt, ...) DRM_DEBUG(fmt"\n", ##__VA_ARGS__)
|
||||
|
||||
struct tda998x_priv {
|
||||
struct i2c_client *cec;
|
||||
uint16_t rev;
|
||||
uint8_t current_page;
|
||||
int dpms;
|
||||
};
|
||||
|
||||
#define to_tda998x_priv(x) ((struct tda998x_priv *)to_encoder_slave(x)->slave_priv)
|
||||
|
||||
/* The TDA9988 series of devices use a paged register scheme.. to simplify
|
||||
* things we encode the page # in upper bits of the register #. To read/
|
||||
* write a given register, we need to make sure CURPAGE register is set
|
||||
* appropriately. Which implies reads/writes are not atomic. Fun!
|
||||
*/
|
||||
|
||||
#define REG(page, addr) (((page) << 8) | (addr))
|
||||
#define REG2ADDR(reg) ((reg) & 0xff)
|
||||
#define REG2PAGE(reg) (((reg) >> 8) & 0xff)
|
||||
|
||||
#define REG_CURPAGE 0xff /* write */
|
||||
|
||||
|
||||
/* Page 00h: General Control */
|
||||
#define REG_VERSION_LSB REG(0x00, 0x00) /* read */
|
||||
#define REG_MAIN_CNTRL0 REG(0x00, 0x01) /* read/write */
|
||||
# define MAIN_CNTRL0_SR (1 << 0)
|
||||
# define MAIN_CNTRL0_DECS (1 << 1)
|
||||
# define MAIN_CNTRL0_DEHS (1 << 2)
|
||||
# define MAIN_CNTRL0_CECS (1 << 3)
|
||||
# define MAIN_CNTRL0_CEHS (1 << 4)
|
||||
# define MAIN_CNTRL0_SCALER (1 << 7)
|
||||
#define REG_VERSION_MSB REG(0x00, 0x02) /* read */
|
||||
#define REG_SOFTRESET REG(0x00, 0x0a) /* write */
|
||||
# define SOFTRESET_AUDIO (1 << 0)
|
||||
# define SOFTRESET_I2C_MASTER (1 << 1)
|
||||
#define REG_DDC_DISABLE REG(0x00, 0x0b) /* read/write */
|
||||
#define REG_CCLK_ON REG(0x00, 0x0c) /* read/write */
|
||||
#define REG_I2C_MASTER REG(0x00, 0x0d) /* read/write */
|
||||
# define I2C_MASTER_DIS_MM (1 << 0)
|
||||
# define I2C_MASTER_DIS_FILT (1 << 1)
|
||||
# define I2C_MASTER_APP_STRT_LAT (1 << 2)
|
||||
#define REG_INT_FLAGS_0 REG(0x00, 0x0f) /* read/write */
|
||||
#define REG_INT_FLAGS_1 REG(0x00, 0x10) /* read/write */
|
||||
#define REG_INT_FLAGS_2 REG(0x00, 0x11) /* read/write */
|
||||
# define INT_FLAGS_2_EDID_BLK_RD (1 << 1)
|
||||
#define REG_ENA_VP_0 REG(0x00, 0x18) /* read/write */
|
||||
#define REG_ENA_VP_1 REG(0x00, 0x19) /* read/write */
|
||||
#define REG_ENA_VP_2 REG(0x00, 0x1a) /* read/write */
|
||||
#define REG_ENA_AP REG(0x00, 0x1e) /* read/write */
|
||||
#define REG_VIP_CNTRL_0 REG(0x00, 0x20) /* write */
|
||||
# define VIP_CNTRL_0_MIRR_A (1 << 7)
|
||||
# define VIP_CNTRL_0_SWAP_A(x) (((x) & 7) << 4)
|
||||
# define VIP_CNTRL_0_MIRR_B (1 << 3)
|
||||
# define VIP_CNTRL_0_SWAP_B(x) (((x) & 7) << 0)
|
||||
#define REG_VIP_CNTRL_1 REG(0x00, 0x21) /* write */
|
||||
# define VIP_CNTRL_1_MIRR_C (1 << 7)
|
||||
# define VIP_CNTRL_1_SWAP_C(x) (((x) & 7) << 4)
|
||||
# define VIP_CNTRL_1_MIRR_D (1 << 3)
|
||||
# define VIP_CNTRL_1_SWAP_D(x) (((x) & 7) << 0)
|
||||
#define REG_VIP_CNTRL_2 REG(0x00, 0x22) /* write */
|
||||
# define VIP_CNTRL_2_MIRR_E (1 << 7)
|
||||
# define VIP_CNTRL_2_SWAP_E(x) (((x) & 7) << 4)
|
||||
# define VIP_CNTRL_2_MIRR_F (1 << 3)
|
||||
# define VIP_CNTRL_2_SWAP_F(x) (((x) & 7) << 0)
|
||||
#define REG_VIP_CNTRL_3 REG(0x00, 0x23) /* write */
|
||||
# define VIP_CNTRL_3_X_TGL (1 << 0)
|
||||
# define VIP_CNTRL_3_H_TGL (1 << 1)
|
||||
# define VIP_CNTRL_3_V_TGL (1 << 2)
|
||||
# define VIP_CNTRL_3_EMB (1 << 3)
|
||||
# define VIP_CNTRL_3_SYNC_DE (1 << 4)
|
||||
# define VIP_CNTRL_3_SYNC_HS (1 << 5)
|
||||
# define VIP_CNTRL_3_DE_INT (1 << 6)
|
||||
# define VIP_CNTRL_3_EDGE (1 << 7)
|
||||
#define REG_VIP_CNTRL_4 REG(0x00, 0x24) /* write */
|
||||
# define VIP_CNTRL_4_BLC(x) (((x) & 3) << 0)
|
||||
# define VIP_CNTRL_4_BLANKIT(x) (((x) & 3) << 2)
|
||||
# define VIP_CNTRL_4_CCIR656 (1 << 4)
|
||||
# define VIP_CNTRL_4_656_ALT (1 << 5)
|
||||
# define VIP_CNTRL_4_TST_656 (1 << 6)
|
||||
# define VIP_CNTRL_4_TST_PAT (1 << 7)
|
||||
#define REG_VIP_CNTRL_5 REG(0x00, 0x25) /* write */
|
||||
# define VIP_CNTRL_5_CKCASE (1 << 0)
|
||||
# define VIP_CNTRL_5_SP_CNT(x) (((x) & 3) << 1)
|
||||
#define REG_MAT_CONTRL REG(0x00, 0x80) /* write */
|
||||
# define MAT_CONTRL_MAT_SC(x) (((x) & 3) << 0)
|
||||
# define MAT_CONTRL_MAT_BP (1 << 2)
|
||||
#define REG_VIDFORMAT REG(0x00, 0xa0) /* write */
|
||||
#define REG_REFPIX_MSB REG(0x00, 0xa1) /* write */
|
||||
#define REG_REFPIX_LSB REG(0x00, 0xa2) /* write */
|
||||
#define REG_REFLINE_MSB REG(0x00, 0xa3) /* write */
|
||||
#define REG_REFLINE_LSB REG(0x00, 0xa4) /* write */
|
||||
#define REG_NPIX_MSB REG(0x00, 0xa5) /* write */
|
||||
#define REG_NPIX_LSB REG(0x00, 0xa6) /* write */
|
||||
#define REG_NLINE_MSB REG(0x00, 0xa7) /* write */
|
||||
#define REG_NLINE_LSB REG(0x00, 0xa8) /* write */
|
||||
#define REG_VS_LINE_STRT_1_MSB REG(0x00, 0xa9) /* write */
|
||||
#define REG_VS_LINE_STRT_1_LSB REG(0x00, 0xaa) /* write */
|
||||
#define REG_VS_PIX_STRT_1_MSB REG(0x00, 0xab) /* write */
|
||||
#define REG_VS_PIX_STRT_1_LSB REG(0x00, 0xac) /* write */
|
||||
#define REG_VS_LINE_END_1_MSB REG(0x00, 0xad) /* write */
|
||||
#define REG_VS_LINE_END_1_LSB REG(0x00, 0xae) /* write */
|
||||
#define REG_VS_PIX_END_1_MSB REG(0x00, 0xaf) /* write */
|
||||
#define REG_VS_PIX_END_1_LSB REG(0x00, 0xb0) /* write */
|
||||
#define REG_VS_PIX_STRT_2_MSB REG(0x00, 0xb3) /* write */
|
||||
#define REG_VS_PIX_STRT_2_LSB REG(0x00, 0xb4) /* write */
|
||||
#define REG_VS_PIX_END_2_MSB REG(0x00, 0xb7) /* write */
|
||||
#define REG_VS_PIX_END_2_LSB REG(0x00, 0xb8) /* write */
|
||||
#define REG_HS_PIX_START_MSB REG(0x00, 0xb9) /* write */
|
||||
#define REG_HS_PIX_START_LSB REG(0x00, 0xba) /* write */
|
||||
#define REG_HS_PIX_STOP_MSB REG(0x00, 0xbb) /* write */
|
||||
#define REG_HS_PIX_STOP_LSB REG(0x00, 0xbc) /* write */
|
||||
#define REG_VWIN_START_1_MSB REG(0x00, 0xbd) /* write */
|
||||
#define REG_VWIN_START_1_LSB REG(0x00, 0xbe) /* write */
|
||||
#define REG_VWIN_END_1_MSB REG(0x00, 0xbf) /* write */
|
||||
#define REG_VWIN_END_1_LSB REG(0x00, 0xc0) /* write */
|
||||
#define REG_DE_START_MSB REG(0x00, 0xc5) /* write */
|
||||
#define REG_DE_START_LSB REG(0x00, 0xc6) /* write */
|
||||
#define REG_DE_STOP_MSB REG(0x00, 0xc7) /* write */
|
||||
#define REG_DE_STOP_LSB REG(0x00, 0xc8) /* write */
|
||||
#define REG_TBG_CNTRL_0 REG(0x00, 0xca) /* write */
|
||||
# define TBG_CNTRL_0_FRAME_DIS (1 << 5)
|
||||
# define TBG_CNTRL_0_SYNC_MTHD (1 << 6)
|
||||
# define TBG_CNTRL_0_SYNC_ONCE (1 << 7)
|
||||
#define REG_TBG_CNTRL_1 REG(0x00, 0xcb) /* write */
|
||||
# define TBG_CNTRL_1_VH_TGL_0 (1 << 0)
|
||||
# define TBG_CNTRL_1_VH_TGL_1 (1 << 1)
|
||||
# define TBG_CNTRL_1_VH_TGL_2 (1 << 2)
|
||||
# define TBG_CNTRL_1_VHX_EXT_DE (1 << 3)
|
||||
# define TBG_CNTRL_1_VHX_EXT_HS (1 << 4)
|
||||
# define TBG_CNTRL_1_VHX_EXT_VS (1 << 5)
|
||||
# define TBG_CNTRL_1_DWIN_DIS (1 << 6)
|
||||
#define REG_ENABLE_SPACE REG(0x00, 0xd6) /* write */
|
||||
#define REG_HVF_CNTRL_0 REG(0x00, 0xe4) /* write */
|
||||
# define HVF_CNTRL_0_SM (1 << 7)
|
||||
# define HVF_CNTRL_0_RWB (1 << 6)
|
||||
# define HVF_CNTRL_0_PREFIL(x) (((x) & 3) << 2)
|
||||
# define HVF_CNTRL_0_INTPOL(x) (((x) & 3) << 0)
|
||||
#define REG_HVF_CNTRL_1 REG(0x00, 0xe5) /* write */
|
||||
# define HVF_CNTRL_1_FOR (1 << 0)
|
||||
# define HVF_CNTRL_1_YUVBLK (1 << 1)
|
||||
# define HVF_CNTRL_1_VQR(x) (((x) & 3) << 2)
|
||||
# define HVF_CNTRL_1_PAD(x) (((x) & 3) << 4)
|
||||
# define HVF_CNTRL_1_SEMI_PLANAR (1 << 6)
|
||||
#define REG_RPT_CNTRL REG(0x00, 0xf0) /* write */
|
||||
|
||||
|
||||
/* Page 02h: PLL settings */
|
||||
#define REG_PLL_SERIAL_1 REG(0x02, 0x00) /* read/write */
|
||||
# define PLL_SERIAL_1_SRL_FDN (1 << 0)
|
||||
# define PLL_SERIAL_1_SRL_IZ(x) (((x) & 3) << 1)
|
||||
# define PLL_SERIAL_1_SRL_MAN_IZ (1 << 6)
|
||||
#define REG_PLL_SERIAL_2 REG(0x02, 0x01) /* read/write */
|
||||
# define PLL_SERIAL_2_SRL_NOSC(x) (((x) & 3) << 0)
|
||||
# define PLL_SERIAL_2_SRL_PR(x) (((x) & 0xf) << 4)
|
||||
#define REG_PLL_SERIAL_3 REG(0x02, 0x02) /* read/write */
|
||||
# define PLL_SERIAL_3_SRL_CCIR (1 << 0)
|
||||
# define PLL_SERIAL_3_SRL_DE (1 << 2)
|
||||
# define PLL_SERIAL_3_SRL_PXIN_SEL (1 << 4)
|
||||
#define REG_SERIALIZER REG(0x02, 0x03) /* read/write */
|
||||
#define REG_BUFFER_OUT REG(0x02, 0x04) /* read/write */
|
||||
#define REG_PLL_SCG1 REG(0x02, 0x05) /* read/write */
|
||||
#define REG_PLL_SCG2 REG(0x02, 0x06) /* read/write */
|
||||
#define REG_PLL_SCGN1 REG(0x02, 0x07) /* read/write */
|
||||
#define REG_PLL_SCGN2 REG(0x02, 0x08) /* read/write */
|
||||
#define REG_PLL_SCGR1 REG(0x02, 0x09) /* read/write */
|
||||
#define REG_PLL_SCGR2 REG(0x02, 0x0a) /* read/write */
|
||||
#define REG_AUDIO_DIV REG(0x02, 0x0e) /* read/write */
|
||||
#define REG_SEL_CLK REG(0x02, 0x11) /* read/write */
|
||||
# define SEL_CLK_SEL_CLK1 (1 << 0)
|
||||
# define SEL_CLK_SEL_VRF_CLK(x) (((x) & 3) << 1)
|
||||
# define SEL_CLK_ENA_SC_CLK (1 << 3)
|
||||
#define REG_ANA_GENERAL REG(0x02, 0x12) /* read/write */
|
||||
|
||||
|
||||
/* Page 09h: EDID Control */
|
||||
#define REG_EDID_DATA_0 REG(0x09, 0x00) /* read */
|
||||
/* next 127 successive registers are the EDID block */
|
||||
#define REG_EDID_CTRL REG(0x09, 0xfa) /* read/write */
|
||||
#define REG_DDC_ADDR REG(0x09, 0xfb) /* read/write */
|
||||
#define REG_DDC_OFFS REG(0x09, 0xfc) /* read/write */
|
||||
#define REG_DDC_SEGM_ADDR REG(0x09, 0xfd) /* read/write */
|
||||
#define REG_DDC_SEGM REG(0x09, 0xfe) /* read/write */
|
||||
|
||||
|
||||
/* Page 10h: information frames and packets */
|
||||
|
||||
|
||||
/* Page 11h: audio settings and content info packets */
|
||||
#define REG_AIP_CNTRL_0 REG(0x11, 0x00) /* read/write */
|
||||
# define AIP_CNTRL_0_RST_FIFO (1 << 0)
|
||||
# define AIP_CNTRL_0_SWAP (1 << 1)
|
||||
# define AIP_CNTRL_0_LAYOUT (1 << 2)
|
||||
# define AIP_CNTRL_0_ACR_MAN (1 << 5)
|
||||
# define AIP_CNTRL_0_RST_CTS (1 << 6)
|
||||
#define REG_ENC_CNTRL REG(0x11, 0x0d) /* read/write */
|
||||
# define ENC_CNTRL_RST_ENC (1 << 0)
|
||||
# define ENC_CNTRL_RST_SEL (1 << 1)
|
||||
# define ENC_CNTRL_CTL_CODE(x) (((x) & 3) << 2)
|
||||
|
||||
|
||||
/* Page 12h: HDCP and OTP */
|
||||
#define REG_TX3 REG(0x12, 0x9a) /* read/write */
|
||||
#define REG_TX33 REG(0x12, 0xb8) /* read/write */
|
||||
# define TX33_HDMI (1 << 1)
|
||||
|
||||
|
||||
/* Page 13h: Gamut related metadata packets */
|
||||
|
||||
|
||||
|
||||
/* CEC registers: (not paged)
|
||||
*/
|
||||
#define REG_CEC_FRO_IM_CLK_CTRL 0xfb /* read/write */
|
||||
# define CEC_FRO_IM_CLK_CTRL_GHOST_DIS (1 << 7)
|
||||
# define CEC_FRO_IM_CLK_CTRL_ENA_OTP (1 << 6)
|
||||
# define CEC_FRO_IM_CLK_CTRL_IMCLK_SEL (1 << 1)
|
||||
# define CEC_FRO_IM_CLK_CTRL_FRO_DIV (1 << 0)
|
||||
#define REG_CEC_RXSHPDLEV 0xfe /* read */
|
||||
# define CEC_RXSHPDLEV_RXSENS (1 << 0)
|
||||
# define CEC_RXSHPDLEV_HPD (1 << 1)
|
||||
|
||||
#define REG_CEC_ENAMODS 0xff /* read/write */
|
||||
# define CEC_ENAMODS_DIS_FRO (1 << 6)
|
||||
# define CEC_ENAMODS_DIS_CCLK (1 << 5)
|
||||
# define CEC_ENAMODS_EN_RXSENS (1 << 2)
|
||||
# define CEC_ENAMODS_EN_HDMI (1 << 1)
|
||||
# define CEC_ENAMODS_EN_CEC (1 << 0)
|
||||
|
||||
|
||||
/* Device versions: */
|
||||
#define TDA9989N2 0x0101
|
||||
#define TDA19989 0x0201
|
||||
#define TDA19989N2 0x0202
|
||||
#define TDA19988 0x0301
|
||||
|
||||
static void
|
||||
cec_write(struct drm_encoder *encoder, uint16_t addr, uint8_t val)
|
||||
{
|
||||
struct i2c_client *client = to_tda998x_priv(encoder)->cec;
|
||||
uint8_t buf[] = {addr, val};
|
||||
int ret;
|
||||
|
||||
ret = i2c_master_send(client, buf, ARRAY_SIZE(buf));
|
||||
if (ret < 0)
|
||||
dev_err(&client->dev, "Error %d writing to cec:0x%x\n", ret, addr);
|
||||
}
|
||||
|
||||
static uint8_t
|
||||
cec_read(struct drm_encoder *encoder, uint8_t addr)
|
||||
{
|
||||
struct i2c_client *client = to_tda998x_priv(encoder)->cec;
|
||||
uint8_t val;
|
||||
int ret;
|
||||
|
||||
ret = i2c_master_send(client, &addr, sizeof(addr));
|
||||
if (ret < 0)
|
||||
goto fail;
|
||||
|
||||
ret = i2c_master_recv(client, &val, sizeof(val));
|
||||
if (ret < 0)
|
||||
goto fail;
|
||||
|
||||
return val;
|
||||
|
||||
fail:
|
||||
dev_err(&client->dev, "Error %d reading from cec:0x%x\n", ret, addr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
set_page(struct drm_encoder *encoder, uint16_t reg)
|
||||
{
|
||||
struct tda998x_priv *priv = to_tda998x_priv(encoder);
|
||||
|
||||
if (REG2PAGE(reg) != priv->current_page) {
|
||||
struct i2c_client *client = drm_i2c_encoder_get_client(encoder);
|
||||
uint8_t buf[] = {
|
||||
REG_CURPAGE, REG2PAGE(reg)
|
||||
};
|
||||
int ret = i2c_master_send(client, buf, sizeof(buf));
|
||||
if (ret < 0)
|
||||
dev_err(&client->dev, "Error %d writing to REG_CURPAGE\n", ret);
|
||||
|
||||
priv->current_page = REG2PAGE(reg);
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
reg_read_range(struct drm_encoder *encoder, uint16_t reg, char *buf, int cnt)
|
||||
{
|
||||
struct i2c_client *client = drm_i2c_encoder_get_client(encoder);
|
||||
uint8_t addr = REG2ADDR(reg);
|
||||
int ret;
|
||||
|
||||
set_page(encoder, reg);
|
||||
|
||||
ret = i2c_master_send(client, &addr, sizeof(addr));
|
||||
if (ret < 0)
|
||||
goto fail;
|
||||
|
||||
ret = i2c_master_recv(client, buf, cnt);
|
||||
if (ret < 0)
|
||||
goto fail;
|
||||
|
||||
return ret;
|
||||
|
||||
fail:
|
||||
dev_err(&client->dev, "Error %d reading from 0x%x\n", ret, reg);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static uint8_t
|
||||
reg_read(struct drm_encoder *encoder, uint16_t reg)
|
||||
{
|
||||
uint8_t val = 0;
|
||||
reg_read_range(encoder, reg, &val, sizeof(val));
|
||||
return val;
|
||||
}
|
||||
|
||||
static void
|
||||
reg_write(struct drm_encoder *encoder, uint16_t reg, uint8_t val)
|
||||
{
|
||||
struct i2c_client *client = drm_i2c_encoder_get_client(encoder);
|
||||
uint8_t buf[] = {REG2ADDR(reg), val};
|
||||
int ret;
|
||||
|
||||
set_page(encoder, reg);
|
||||
|
||||
ret = i2c_master_send(client, buf, ARRAY_SIZE(buf));
|
||||
if (ret < 0)
|
||||
dev_err(&client->dev, "Error %d writing to 0x%x\n", ret, reg);
|
||||
}
|
||||
|
||||
static void
|
||||
reg_write16(struct drm_encoder *encoder, uint16_t reg, uint16_t val)
|
||||
{
|
||||
struct i2c_client *client = drm_i2c_encoder_get_client(encoder);
|
||||
uint8_t buf[] = {REG2ADDR(reg), val >> 8, val};
|
||||
int ret;
|
||||
|
||||
set_page(encoder, reg);
|
||||
|
||||
ret = i2c_master_send(client, buf, ARRAY_SIZE(buf));
|
||||
if (ret < 0)
|
||||
dev_err(&client->dev, "Error %d writing to 0x%x\n", ret, reg);
|
||||
}
|
||||
|
||||
static void
|
||||
reg_set(struct drm_encoder *encoder, uint16_t reg, uint8_t val)
|
||||
{
|
||||
reg_write(encoder, reg, reg_read(encoder, reg) | val);
|
||||
}
|
||||
|
||||
static void
|
||||
reg_clear(struct drm_encoder *encoder, uint16_t reg, uint8_t val)
|
||||
{
|
||||
reg_write(encoder, reg, reg_read(encoder, reg) & ~val);
|
||||
}
|
||||
|
||||
static void
|
||||
tda998x_reset(struct drm_encoder *encoder)
|
||||
{
|
||||
/* reset audio and i2c master: */
|
||||
reg_set(encoder, REG_SOFTRESET, SOFTRESET_AUDIO | SOFTRESET_I2C_MASTER);
|
||||
msleep(50);
|
||||
reg_clear(encoder, REG_SOFTRESET, SOFTRESET_AUDIO | SOFTRESET_I2C_MASTER);
|
||||
msleep(50);
|
||||
|
||||
/* reset transmitter: */
|
||||
reg_set(encoder, REG_MAIN_CNTRL0, MAIN_CNTRL0_SR);
|
||||
reg_clear(encoder, REG_MAIN_CNTRL0, MAIN_CNTRL0_SR);
|
||||
|
||||
/* PLL registers common configuration */
|
||||
reg_write(encoder, REG_PLL_SERIAL_1, 0x00);
|
||||
reg_write(encoder, REG_PLL_SERIAL_2, PLL_SERIAL_2_SRL_NOSC(1));
|
||||
reg_write(encoder, REG_PLL_SERIAL_3, 0x00);
|
||||
reg_write(encoder, REG_SERIALIZER, 0x00);
|
||||
reg_write(encoder, REG_BUFFER_OUT, 0x00);
|
||||
reg_write(encoder, REG_PLL_SCG1, 0x00);
|
||||
reg_write(encoder, REG_AUDIO_DIV, 0x03);
|
||||
reg_write(encoder, REG_SEL_CLK, SEL_CLK_SEL_CLK1 | SEL_CLK_ENA_SC_CLK);
|
||||
reg_write(encoder, REG_PLL_SCGN1, 0xfa);
|
||||
reg_write(encoder, REG_PLL_SCGN2, 0x00);
|
||||
reg_write(encoder, REG_PLL_SCGR1, 0x5b);
|
||||
reg_write(encoder, REG_PLL_SCGR2, 0x00);
|
||||
reg_write(encoder, REG_PLL_SCG2, 0x10);
|
||||
}
|
||||
|
||||
/* DRM encoder functions */
|
||||
|
||||
static void
|
||||
tda998x_encoder_set_config(struct drm_encoder *encoder, void *params)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
tda998x_encoder_dpms(struct drm_encoder *encoder, int mode)
|
||||
{
|
||||
struct tda998x_priv *priv = to_tda998x_priv(encoder);
|
||||
|
||||
/* we only care about on or off: */
|
||||
if (mode != DRM_MODE_DPMS_ON)
|
||||
mode = DRM_MODE_DPMS_OFF;
|
||||
|
||||
if (mode == priv->dpms)
|
||||
return;
|
||||
|
||||
switch (mode) {
|
||||
case DRM_MODE_DPMS_ON:
|
||||
/* enable audio and video ports */
|
||||
reg_write(encoder, REG_ENA_AP, 0xff);
|
||||
reg_write(encoder, REG_ENA_VP_0, 0xff);
|
||||
reg_write(encoder, REG_ENA_VP_1, 0xff);
|
||||
reg_write(encoder, REG_ENA_VP_2, 0xff);
|
||||
/* set muxing after enabling ports: */
|
||||
reg_write(encoder, REG_VIP_CNTRL_0,
|
||||
VIP_CNTRL_0_SWAP_A(2) | VIP_CNTRL_0_SWAP_B(3));
|
||||
reg_write(encoder, REG_VIP_CNTRL_1,
|
||||
VIP_CNTRL_1_SWAP_C(0) | VIP_CNTRL_1_SWAP_D(1));
|
||||
reg_write(encoder, REG_VIP_CNTRL_2,
|
||||
VIP_CNTRL_2_SWAP_E(4) | VIP_CNTRL_2_SWAP_F(5));
|
||||
break;
|
||||
case DRM_MODE_DPMS_OFF:
|
||||
/* disable audio and video ports */
|
||||
reg_write(encoder, REG_ENA_AP, 0x00);
|
||||
reg_write(encoder, REG_ENA_VP_0, 0x00);
|
||||
reg_write(encoder, REG_ENA_VP_1, 0x00);
|
||||
reg_write(encoder, REG_ENA_VP_2, 0x00);
|
||||
break;
|
||||
}
|
||||
|
||||
priv->dpms = mode;
|
||||
}
|
||||
|
||||
static void
|
||||
tda998x_encoder_save(struct drm_encoder *encoder)
|
||||
{
|
||||
DBG("");
|
||||
}
|
||||
|
||||
static void
|
||||
tda998x_encoder_restore(struct drm_encoder *encoder)
|
||||
{
|
||||
DBG("");
|
||||
}
|
||||
|
||||
static bool
|
||||
tda998x_encoder_mode_fixup(struct drm_encoder *encoder,
|
||||
const struct drm_display_mode *mode,
|
||||
struct drm_display_mode *adjusted_mode)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
static int
|
||||
tda998x_encoder_mode_valid(struct drm_encoder *encoder,
|
||||
struct drm_display_mode *mode)
|
||||
{
|
||||
return MODE_OK;
|
||||
}
|
||||
|
||||
static void
|
||||
tda998x_encoder_mode_set(struct drm_encoder *encoder,
|
||||
struct drm_display_mode *mode,
|
||||
struct drm_display_mode *adjusted_mode)
|
||||
{
|
||||
struct tda998x_priv *priv = to_tda998x_priv(encoder);
|
||||
uint16_t hs_start, hs_end, line_start, line_end;
|
||||
uint16_t vwin_start, vwin_end, de_start, de_end;
|
||||
uint16_t ref_pix, ref_line, pix_start2;
|
||||
uint8_t reg, div, rep;
|
||||
|
||||
hs_start = mode->hsync_start - mode->hdisplay;
|
||||
hs_end = mode->hsync_end - mode->hdisplay;
|
||||
line_start = 1;
|
||||
line_end = 1 + mode->vsync_end - mode->vsync_start;
|
||||
vwin_start = mode->vtotal - mode->vsync_start;
|
||||
vwin_end = vwin_start + mode->vdisplay;
|
||||
de_start = mode->htotal - mode->hdisplay;
|
||||
de_end = mode->htotal;
|
||||
|
||||
pix_start2 = 0;
|
||||
if (mode->flags & DRM_MODE_FLAG_INTERLACE)
|
||||
pix_start2 = (mode->htotal / 2) + hs_start;
|
||||
|
||||
/* TODO how is this value calculated? It is 2 for all common
|
||||
* formats in the tables in out of tree nxp driver (assuming
|
||||
* I've properly deciphered their byzantine table system)
|
||||
*/
|
||||
ref_line = 2;
|
||||
|
||||
/* this might changes for other color formats from the CRTC: */
|
||||
ref_pix = 3 + hs_start;
|
||||
|
||||
div = 148500 / mode->clock;
|
||||
|
||||
DBG("clock=%d, div=%u", mode->clock, div);
|
||||
DBG("hs_start=%u, hs_end=%u, line_start=%u, line_end=%u",
|
||||
hs_start, hs_end, line_start, line_end);
|
||||
DBG("vwin_start=%u, vwin_end=%u, de_start=%u, de_end=%u",
|
||||
vwin_start, vwin_end, de_start, de_end);
|
||||
DBG("ref_line=%u, ref_pix=%u, pix_start2=%u",
|
||||
ref_line, ref_pix, pix_start2);
|
||||
|
||||
/* mute the audio FIFO: */
|
||||
reg_set(encoder, REG_AIP_CNTRL_0, AIP_CNTRL_0_RST_FIFO);
|
||||
|
||||
/* set HDMI HDCP mode off: */
|
||||
reg_set(encoder, REG_TBG_CNTRL_1, TBG_CNTRL_1_DWIN_DIS);
|
||||
reg_clear(encoder, REG_TX33, TX33_HDMI);
|
||||
|
||||
reg_write(encoder, REG_ENC_CNTRL, ENC_CNTRL_CTL_CODE(0));
|
||||
/* no pre-filter or interpolator: */
|
||||
reg_write(encoder, REG_HVF_CNTRL_0, HVF_CNTRL_0_PREFIL(0) |
|
||||
HVF_CNTRL_0_INTPOL(0));
|
||||
reg_write(encoder, REG_VIP_CNTRL_5, VIP_CNTRL_5_SP_CNT(0));
|
||||
reg_write(encoder, REG_VIP_CNTRL_4, VIP_CNTRL_4_BLANKIT(0) |
|
||||
VIP_CNTRL_4_BLC(0));
|
||||
reg_clear(encoder, REG_PLL_SERIAL_3, PLL_SERIAL_3_SRL_CCIR);
|
||||
|
||||
reg_clear(encoder, REG_PLL_SERIAL_1, PLL_SERIAL_1_SRL_MAN_IZ);
|
||||
reg_clear(encoder, REG_PLL_SERIAL_3, PLL_SERIAL_3_SRL_DE);
|
||||
reg_write(encoder, REG_SERIALIZER, 0);
|
||||
reg_write(encoder, REG_HVF_CNTRL_1, HVF_CNTRL_1_VQR(0));
|
||||
|
||||
/* TODO enable pixel repeat for pixel rates less than 25Msamp/s */
|
||||
rep = 0;
|
||||
reg_write(encoder, REG_RPT_CNTRL, 0);
|
||||
reg_write(encoder, REG_SEL_CLK, SEL_CLK_SEL_VRF_CLK(0) |
|
||||
SEL_CLK_SEL_CLK1 | SEL_CLK_ENA_SC_CLK);
|
||||
|
||||
reg_write(encoder, REG_PLL_SERIAL_2, PLL_SERIAL_2_SRL_NOSC(div) |
|
||||
PLL_SERIAL_2_SRL_PR(rep));
|
||||
|
||||
reg_write16(encoder, REG_VS_PIX_STRT_2_MSB, pix_start2);
|
||||
reg_write16(encoder, REG_VS_PIX_END_2_MSB, pix_start2);
|
||||
|
||||
/* set color matrix bypass flag: */
|
||||
reg_set(encoder, REG_MAT_CONTRL, MAT_CONTRL_MAT_BP);
|
||||
|
||||
/* set BIAS tmds value: */
|
||||
reg_write(encoder, REG_ANA_GENERAL, 0x09);
|
||||
|
||||
reg_clear(encoder, REG_TBG_CNTRL_0, TBG_CNTRL_0_SYNC_MTHD);
|
||||
|
||||
reg_write(encoder, REG_VIP_CNTRL_3, 0);
|
||||
reg_set(encoder, REG_VIP_CNTRL_3, VIP_CNTRL_3_SYNC_HS);
|
||||
if (mode->flags & DRM_MODE_FLAG_NVSYNC)
|
||||
reg_set(encoder, REG_VIP_CNTRL_3, VIP_CNTRL_3_V_TGL);
|
||||
|
||||
if (mode->flags & DRM_MODE_FLAG_NHSYNC)
|
||||
reg_set(encoder, REG_VIP_CNTRL_3, VIP_CNTRL_3_H_TGL);
|
||||
|
||||
reg_write(encoder, REG_VIDFORMAT, 0x00);
|
||||
reg_write16(encoder, REG_NPIX_MSB, mode->hdisplay - 1);
|
||||
reg_write16(encoder, REG_NLINE_MSB, mode->vdisplay - 1);
|
||||
reg_write16(encoder, REG_VS_LINE_STRT_1_MSB, line_start);
|
||||
reg_write16(encoder, REG_VS_LINE_END_1_MSB, line_end);
|
||||
reg_write16(encoder, REG_VS_PIX_STRT_1_MSB, hs_start);
|
||||
reg_write16(encoder, REG_VS_PIX_END_1_MSB, hs_start);
|
||||
reg_write16(encoder, REG_HS_PIX_START_MSB, hs_start);
|
||||
reg_write16(encoder, REG_HS_PIX_STOP_MSB, hs_end);
|
||||
reg_write16(encoder, REG_VWIN_START_1_MSB, vwin_start);
|
||||
reg_write16(encoder, REG_VWIN_END_1_MSB, vwin_end);
|
||||
reg_write16(encoder, REG_DE_START_MSB, de_start);
|
||||
reg_write16(encoder, REG_DE_STOP_MSB, de_end);
|
||||
|
||||
if (priv->rev == TDA19988) {
|
||||
/* let incoming pixels fill the active space (if any) */
|
||||
reg_write(encoder, REG_ENABLE_SPACE, 0x01);
|
||||
}
|
||||
|
||||
reg_write16(encoder, REG_REFPIX_MSB, ref_pix);
|
||||
reg_write16(encoder, REG_REFLINE_MSB, ref_line);
|
||||
|
||||
reg = TBG_CNTRL_1_VHX_EXT_DE |
|
||||
TBG_CNTRL_1_VHX_EXT_HS |
|
||||
TBG_CNTRL_1_VHX_EXT_VS |
|
||||
TBG_CNTRL_1_DWIN_DIS | /* HDCP off */
|
||||
TBG_CNTRL_1_VH_TGL_2;
|
||||
if (mode->flags & (DRM_MODE_FLAG_NVSYNC | DRM_MODE_FLAG_NHSYNC))
|
||||
reg |= TBG_CNTRL_1_VH_TGL_0;
|
||||
reg_set(encoder, REG_TBG_CNTRL_1, reg);
|
||||
|
||||
/* must be last register set: */
|
||||
reg_clear(encoder, REG_TBG_CNTRL_0, TBG_CNTRL_0_SYNC_ONCE);
|
||||
}
|
||||
|
||||
static enum drm_connector_status
|
||||
tda998x_encoder_detect(struct drm_encoder *encoder,
|
||||
struct drm_connector *connector)
|
||||
{
|
||||
uint8_t val = cec_read(encoder, REG_CEC_RXSHPDLEV);
|
||||
return (val & CEC_RXSHPDLEV_HPD) ? connector_status_connected :
|
||||
connector_status_disconnected;
|
||||
}
|
||||
|
||||
static int
|
||||
read_edid_block(struct drm_encoder *encoder, uint8_t *buf, int blk)
|
||||
{
|
||||
uint8_t offset, segptr;
|
||||
int ret, i;
|
||||
|
||||
/* enable EDID read irq: */
|
||||
reg_set(encoder, REG_INT_FLAGS_2, INT_FLAGS_2_EDID_BLK_RD);
|
||||
|
||||
offset = (blk & 1) ? 128 : 0;
|
||||
segptr = blk / 2;
|
||||
|
||||
reg_write(encoder, REG_DDC_ADDR, 0xa0);
|
||||
reg_write(encoder, REG_DDC_OFFS, offset);
|
||||
reg_write(encoder, REG_DDC_SEGM_ADDR, 0x60);
|
||||
reg_write(encoder, REG_DDC_SEGM, segptr);
|
||||
|
||||
/* enable reading EDID: */
|
||||
reg_write(encoder, REG_EDID_CTRL, 0x1);
|
||||
|
||||
/* flag must be cleared by sw: */
|
||||
reg_write(encoder, REG_EDID_CTRL, 0x0);
|
||||
|
||||
/* wait for block read to complete: */
|
||||
for (i = 100; i > 0; i--) {
|
||||
uint8_t val = reg_read(encoder, REG_INT_FLAGS_2);
|
||||
if (val & INT_FLAGS_2_EDID_BLK_RD)
|
||||
break;
|
||||
msleep(1);
|
||||
}
|
||||
|
||||
if (i == 0)
|
||||
return -ETIMEDOUT;
|
||||
|
||||
ret = reg_read_range(encoder, REG_EDID_DATA_0, buf, EDID_LENGTH);
|
||||
if (ret != EDID_LENGTH) {
|
||||
dev_err(encoder->dev->dev, "failed to read edid block %d: %d",
|
||||
blk, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
reg_clear(encoder, REG_INT_FLAGS_2, INT_FLAGS_2_EDID_BLK_RD);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static uint8_t *
|
||||
do_get_edid(struct drm_encoder *encoder)
|
||||
{
|
||||
int j = 0, valid_extensions = 0;
|
||||
uint8_t *block, *new;
|
||||
bool print_bad_edid = drm_debug & DRM_UT_KMS;
|
||||
|
||||
if ((block = kmalloc(EDID_LENGTH, GFP_KERNEL)) == NULL)
|
||||
return NULL;
|
||||
|
||||
/* base block fetch */
|
||||
if (read_edid_block(encoder, block, 0))
|
||||
goto fail;
|
||||
|
||||
if (!drm_edid_block_valid(block, 0, print_bad_edid))
|
||||
goto fail;
|
||||
|
||||
/* if there's no extensions, we're done */
|
||||
if (block[0x7e] == 0)
|
||||
return block;
|
||||
|
||||
new = krealloc(block, (block[0x7e] + 1) * EDID_LENGTH, GFP_KERNEL);
|
||||
if (!new)
|
||||
goto fail;
|
||||
block = new;
|
||||
|
||||
for (j = 1; j <= block[0x7e]; j++) {
|
||||
uint8_t *ext_block = block + (valid_extensions + 1) * EDID_LENGTH;
|
||||
if (read_edid_block(encoder, ext_block, j))
|
||||
goto fail;
|
||||
|
||||
if (!drm_edid_block_valid(ext_block, j, print_bad_edid))
|
||||
goto fail;
|
||||
|
||||
valid_extensions++;
|
||||
}
|
||||
|
||||
if (valid_extensions != block[0x7e]) {
|
||||
block[EDID_LENGTH-1] += block[0x7e] - valid_extensions;
|
||||
block[0x7e] = valid_extensions;
|
||||
new = krealloc(block, (valid_extensions + 1) * EDID_LENGTH, GFP_KERNEL);
|
||||
if (!new)
|
||||
goto fail;
|
||||
block = new;
|
||||
}
|
||||
|
||||
return block;
|
||||
|
||||
fail:
|
||||
dev_warn(encoder->dev->dev, "failed to read EDID\n");
|
||||
kfree(block);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int
|
||||
tda998x_encoder_get_modes(struct drm_encoder *encoder,
|
||||
struct drm_connector *connector)
|
||||
{
|
||||
struct edid *edid = (struct edid *)do_get_edid(encoder);
|
||||
int n = 0;
|
||||
|
||||
if (edid) {
|
||||
drm_mode_connector_update_edid_property(connector, edid);
|
||||
n = drm_add_edid_modes(connector, edid);
|
||||
kfree(edid);
|
||||
}
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
static int
|
||||
tda998x_encoder_create_resources(struct drm_encoder *encoder,
|
||||
struct drm_connector *connector)
|
||||
{
|
||||
DBG("");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
tda998x_encoder_set_property(struct drm_encoder *encoder,
|
||||
struct drm_connector *connector,
|
||||
struct drm_property *property,
|
||||
uint64_t val)
|
||||
{
|
||||
DBG("");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
tda998x_encoder_destroy(struct drm_encoder *encoder)
|
||||
{
|
||||
struct tda998x_priv *priv = to_tda998x_priv(encoder);
|
||||
drm_i2c_encoder_destroy(encoder);
|
||||
kfree(priv);
|
||||
}
|
||||
|
||||
static struct drm_encoder_slave_funcs tda998x_encoder_funcs = {
|
||||
.set_config = tda998x_encoder_set_config,
|
||||
.destroy = tda998x_encoder_destroy,
|
||||
.dpms = tda998x_encoder_dpms,
|
||||
.save = tda998x_encoder_save,
|
||||
.restore = tda998x_encoder_restore,
|
||||
.mode_fixup = tda998x_encoder_mode_fixup,
|
||||
.mode_valid = tda998x_encoder_mode_valid,
|
||||
.mode_set = tda998x_encoder_mode_set,
|
||||
.detect = tda998x_encoder_detect,
|
||||
.get_modes = tda998x_encoder_get_modes,
|
||||
.create_resources = tda998x_encoder_create_resources,
|
||||
.set_property = tda998x_encoder_set_property,
|
||||
};
|
||||
|
||||
/* I2C driver functions */
|
||||
|
||||
static int
|
||||
tda998x_probe(struct i2c_client *client, const struct i2c_device_id *id)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
tda998x_remove(struct i2c_client *client)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
tda998x_encoder_init(struct i2c_client *client,
|
||||
struct drm_device *dev,
|
||||
struct drm_encoder_slave *encoder_slave)
|
||||
{
|
||||
struct drm_encoder *encoder = &encoder_slave->base;
|
||||
struct tda998x_priv *priv;
|
||||
|
||||
priv = kzalloc(sizeof(*priv), GFP_KERNEL);
|
||||
if (!priv)
|
||||
return -ENOMEM;
|
||||
|
||||
priv->current_page = 0;
|
||||
priv->cec = i2c_new_dummy(client->adapter, 0x34);
|
||||
priv->dpms = DRM_MODE_DPMS_OFF;
|
||||
|
||||
encoder_slave->slave_priv = priv;
|
||||
encoder_slave->slave_funcs = &tda998x_encoder_funcs;
|
||||
|
||||
/* wake up the device: */
|
||||
cec_write(encoder, REG_CEC_ENAMODS,
|
||||
CEC_ENAMODS_EN_RXSENS | CEC_ENAMODS_EN_HDMI);
|
||||
|
||||
tda998x_reset(encoder);
|
||||
|
||||
/* read version: */
|
||||
priv->rev = reg_read(encoder, REG_VERSION_LSB) |
|
||||
reg_read(encoder, REG_VERSION_MSB) << 8;
|
||||
|
||||
/* mask off feature bits: */
|
||||
priv->rev &= ~0x30; /* not-hdcp and not-scalar bit */
|
||||
|
||||
switch (priv->rev) {
|
||||
case TDA9989N2: dev_info(dev->dev, "found TDA9989 n2"); break;
|
||||
case TDA19989: dev_info(dev->dev, "found TDA19989"); break;
|
||||
case TDA19989N2: dev_info(dev->dev, "found TDA19989 n2"); break;
|
||||
case TDA19988: dev_info(dev->dev, "found TDA19988"); break;
|
||||
default:
|
||||
DBG("found unsupported device: %04x", priv->rev);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* after reset, enable DDC: */
|
||||
reg_write(encoder, REG_DDC_DISABLE, 0x00);
|
||||
|
||||
/* set clock on DDC channel: */
|
||||
reg_write(encoder, REG_TX3, 39);
|
||||
|
||||
/* if necessary, disable multi-master: */
|
||||
if (priv->rev == TDA19989)
|
||||
reg_set(encoder, REG_I2C_MASTER, I2C_MASTER_DIS_MM);
|
||||
|
||||
cec_write(encoder, REG_CEC_FRO_IM_CLK_CTRL,
|
||||
CEC_FRO_IM_CLK_CTRL_GHOST_DIS | CEC_FRO_IM_CLK_CTRL_IMCLK_SEL);
|
||||
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
/* if encoder_init fails, the encoder slave is never registered,
|
||||
* so cleanup here:
|
||||
*/
|
||||
if (priv->cec)
|
||||
i2c_unregister_device(priv->cec);
|
||||
kfree(priv);
|
||||
encoder_slave->slave_priv = NULL;
|
||||
encoder_slave->slave_funcs = NULL;
|
||||
return -ENXIO;
|
||||
}
|
||||
|
||||
static struct i2c_device_id tda998x_ids[] = {
|
||||
{ "tda998x", 0 },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, tda998x_ids);
|
||||
|
||||
static struct drm_i2c_encoder_driver tda998x_driver = {
|
||||
.i2c_driver = {
|
||||
.probe = tda998x_probe,
|
||||
.remove = tda998x_remove,
|
||||
.driver = {
|
||||
.name = "tda998x",
|
||||
},
|
||||
.id_table = tda998x_ids,
|
||||
},
|
||||
.encoder_init = tda998x_encoder_init,
|
||||
};
|
||||
|
||||
/* Module initialization */
|
||||
|
||||
static int __init
|
||||
tda998x_init(void)
|
||||
{
|
||||
DBG("");
|
||||
return drm_i2c_encoder_register(THIS_MODULE, &tda998x_driver);
|
||||
}
|
||||
|
||||
static void __exit
|
||||
tda998x_exit(void)
|
||||
{
|
||||
DBG("");
|
||||
drm_i2c_encoder_unregister(&tda998x_driver);
|
||||
}
|
||||
|
||||
MODULE_AUTHOR("Rob Clark <robdclark@gmail.com");
|
||||
MODULE_DESCRIPTION("NXP Semiconductors TDA998X HDMI Encoder");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
module_init(tda998x_init);
|
||||
module_exit(tda998x_exit);
|
@ -16,6 +16,7 @@ i915-y := i915_drv.o i915_dma.o i915_irq.o \
|
||||
i915_gem_tiling.o \
|
||||
i915_sysfs.o \
|
||||
i915_trace_points.o \
|
||||
i915_ums.o \
|
||||
intel_display.o \
|
||||
intel_crt.o \
|
||||
intel_lvds.o \
|
||||
|
@ -103,7 +103,7 @@ static const char *cache_level_str(int type)
|
||||
static void
|
||||
describe_obj(struct seq_file *m, struct drm_i915_gem_object *obj)
|
||||
{
|
||||
seq_printf(m, "%p: %s%s %8zdKiB %04x %04x %d %d %d%s%s%s",
|
||||
seq_printf(m, "%p: %s%s %8zdKiB %02x %02x %d %d %d%s%s%s",
|
||||
&obj->base,
|
||||
get_pin_flag(obj),
|
||||
get_tiling_flag(obj),
|
||||
@ -125,6 +125,8 @@ describe_obj(struct seq_file *m, struct drm_i915_gem_object *obj)
|
||||
if (obj->gtt_space != NULL)
|
||||
seq_printf(m, " (gtt offset: %08x, size: %08x)",
|
||||
obj->gtt_offset, (unsigned int)obj->gtt_space->size);
|
||||
if (obj->stolen)
|
||||
seq_printf(m, " (stolen: %08lx)", obj->stolen->start);
|
||||
if (obj->pin_mappable || obj->fault_mappable) {
|
||||
char s[3], *t = s;
|
||||
if (obj->pin_mappable)
|
||||
@ -257,8 +259,9 @@ static int i915_gem_object_info(struct seq_file *m, void* data)
|
||||
seq_printf(m, "%u fault mappable objects, %zu bytes\n",
|
||||
count, size);
|
||||
|
||||
seq_printf(m, "%zu [%zu] gtt total\n",
|
||||
dev_priv->mm.gtt_total, dev_priv->mm.mappable_gtt_total);
|
||||
seq_printf(m, "%zu [%lu] gtt total\n",
|
||||
dev_priv->gtt.total,
|
||||
dev_priv->gtt.mappable_end - dev_priv->gtt.start);
|
||||
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
|
||||
@ -388,7 +391,7 @@ static void i915_ring_seqno_info(struct seq_file *m,
|
||||
struct intel_ring_buffer *ring)
|
||||
{
|
||||
if (ring->get_seqno) {
|
||||
seq_printf(m, "Current sequence (%s): %d\n",
|
||||
seq_printf(m, "Current sequence (%s): %u\n",
|
||||
ring->name, ring->get_seqno(ring, false));
|
||||
}
|
||||
}
|
||||
@ -545,11 +548,11 @@ static int i915_hws_info(struct seq_file *m, void *data)
|
||||
struct drm_device *dev = node->minor->dev;
|
||||
drm_i915_private_t *dev_priv = dev->dev_private;
|
||||
struct intel_ring_buffer *ring;
|
||||
const volatile u32 __iomem *hws;
|
||||
const u32 *hws;
|
||||
int i;
|
||||
|
||||
ring = &dev_priv->ring[(uintptr_t)node->info_ent->data];
|
||||
hws = (volatile u32 __iomem *)ring->status_page.page_addr;
|
||||
hws = ring->status_page.page_addr;
|
||||
if (hws == NULL)
|
||||
return 0;
|
||||
|
||||
@ -609,7 +612,7 @@ static void print_error_buffers(struct seq_file *m,
|
||||
seq_printf(m, "%s [%d]:\n", name, count);
|
||||
|
||||
while (count--) {
|
||||
seq_printf(m, " %08x %8u %04x %04x %x %x%s%s%s%s%s%s%s",
|
||||
seq_printf(m, " %08x %8u %02x %02x %x %x%s%s%s%s%s%s%s",
|
||||
err->gtt_offset,
|
||||
err->size,
|
||||
err->read_domains,
|
||||
@ -691,7 +694,7 @@ static int i915_error_state(struct seq_file *m, void *unused)
|
||||
|
||||
seq_printf(m, "Time: %ld s %ld us\n", error->time.tv_sec,
|
||||
error->time.tv_usec);
|
||||
seq_printf(m, "Kernel: " UTS_RELEASE);
|
||||
seq_printf(m, "Kernel: " UTS_RELEASE "\n");
|
||||
seq_printf(m, "PCI ID: 0x%04x\n", dev->pci_device);
|
||||
seq_printf(m, "EIR: 0x%08x\n", error->eir);
|
||||
seq_printf(m, "IER: 0x%08x\n", error->ier);
|
||||
@ -816,11 +819,11 @@ static int i915_error_state_open(struct inode *inode, struct file *file)
|
||||
|
||||
error_priv->dev = dev;
|
||||
|
||||
spin_lock_irqsave(&dev_priv->error_lock, flags);
|
||||
error_priv->error = dev_priv->first_error;
|
||||
spin_lock_irqsave(&dev_priv->gpu_error.lock, flags);
|
||||
error_priv->error = dev_priv->gpu_error.first_error;
|
||||
if (error_priv->error)
|
||||
kref_get(&error_priv->error->ref);
|
||||
spin_unlock_irqrestore(&dev_priv->error_lock, flags);
|
||||
spin_unlock_irqrestore(&dev_priv->gpu_error.lock, flags);
|
||||
|
||||
return single_open(file, i915_error_state, error_priv);
|
||||
}
|
||||
@ -846,6 +849,77 @@ static const struct file_operations i915_error_state_fops = {
|
||||
.release = i915_error_state_release,
|
||||
};
|
||||
|
||||
static ssize_t
|
||||
i915_next_seqno_read(struct file *filp,
|
||||
char __user *ubuf,
|
||||
size_t max,
|
||||
loff_t *ppos)
|
||||
{
|
||||
struct drm_device *dev = filp->private_data;
|
||||
drm_i915_private_t *dev_priv = dev->dev_private;
|
||||
char buf[80];
|
||||
int len;
|
||||
int ret;
|
||||
|
||||
ret = mutex_lock_interruptible(&dev->struct_mutex);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
len = snprintf(buf, sizeof(buf),
|
||||
"next_seqno : 0x%x\n",
|
||||
dev_priv->next_seqno);
|
||||
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
|
||||
if (len > sizeof(buf))
|
||||
len = sizeof(buf);
|
||||
|
||||
return simple_read_from_buffer(ubuf, max, ppos, buf, len);
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
i915_next_seqno_write(struct file *filp,
|
||||
const char __user *ubuf,
|
||||
size_t cnt,
|
||||
loff_t *ppos)
|
||||
{
|
||||
struct drm_device *dev = filp->private_data;
|
||||
char buf[20];
|
||||
u32 val = 1;
|
||||
int ret;
|
||||
|
||||
if (cnt > 0) {
|
||||
if (cnt > sizeof(buf) - 1)
|
||||
return -EINVAL;
|
||||
|
||||
if (copy_from_user(buf, ubuf, cnt))
|
||||
return -EFAULT;
|
||||
buf[cnt] = 0;
|
||||
|
||||
ret = kstrtouint(buf, 0, &val);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = mutex_lock_interruptible(&dev->struct_mutex);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = i915_gem_set_seqno(dev, val);
|
||||
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
|
||||
return ret ?: cnt;
|
||||
}
|
||||
|
||||
static const struct file_operations i915_next_seqno_fops = {
|
||||
.owner = THIS_MODULE,
|
||||
.open = simple_open,
|
||||
.read = i915_next_seqno_read,
|
||||
.write = i915_next_seqno_write,
|
||||
.llseek = default_llseek,
|
||||
};
|
||||
|
||||
static int i915_rstdby_delays(struct seq_file *m, void *unused)
|
||||
{
|
||||
struct drm_info_node *node = (struct drm_info_node *) m->private;
|
||||
@ -888,7 +962,7 @@ static int i915_cur_delayinfo(struct seq_file *m, void *unused)
|
||||
u32 gt_perf_status = I915_READ(GEN6_GT_PERF_STATUS);
|
||||
u32 rp_state_limits = I915_READ(GEN6_RP_STATE_LIMITS);
|
||||
u32 rp_state_cap = I915_READ(GEN6_RP_STATE_CAP);
|
||||
u32 rpstat;
|
||||
u32 rpstat, cagf;
|
||||
u32 rpupei, rpcurup, rpprevup;
|
||||
u32 rpdownei, rpcurdown, rpprevdown;
|
||||
int max_freq;
|
||||
@ -907,6 +981,11 @@ static int i915_cur_delayinfo(struct seq_file *m, void *unused)
|
||||
rpdownei = I915_READ(GEN6_RP_CUR_DOWN_EI);
|
||||
rpcurdown = I915_READ(GEN6_RP_CUR_DOWN);
|
||||
rpprevdown = I915_READ(GEN6_RP_PREV_DOWN);
|
||||
if (IS_HASWELL(dev))
|
||||
cagf = (rpstat & HSW_CAGF_MASK) >> HSW_CAGF_SHIFT;
|
||||
else
|
||||
cagf = (rpstat & GEN6_CAGF_MASK) >> GEN6_CAGF_SHIFT;
|
||||
cagf *= GT_FREQUENCY_MULTIPLIER;
|
||||
|
||||
gen6_gt_force_wake_put(dev_priv);
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
@ -919,8 +998,7 @@ static int i915_cur_delayinfo(struct seq_file *m, void *unused)
|
||||
gt_perf_status & 0xff);
|
||||
seq_printf(m, "Render p-state limit: %d\n",
|
||||
rp_state_limits & 0xff);
|
||||
seq_printf(m, "CAGF: %dMHz\n", ((rpstat & GEN6_CAGF_MASK) >>
|
||||
GEN6_CAGF_SHIFT) * GT_FREQUENCY_MULTIPLIER);
|
||||
seq_printf(m, "CAGF: %dMHz\n", cagf);
|
||||
seq_printf(m, "RP CUR UP EI: %dus\n", rpupei &
|
||||
GEN6_CURICONT_MASK);
|
||||
seq_printf(m, "RP CUR UP: %dus\n", rpcurup &
|
||||
@ -1372,28 +1450,31 @@ static int i915_gem_framebuffer_info(struct seq_file *m, void *data)
|
||||
ifbdev = dev_priv->fbdev;
|
||||
fb = to_intel_framebuffer(ifbdev->helper.fb);
|
||||
|
||||
seq_printf(m, "fbcon size: %d x %d, depth %d, %d bpp, obj ",
|
||||
seq_printf(m, "fbcon size: %d x %d, depth %d, %d bpp, refcount %d, obj ",
|
||||
fb->base.width,
|
||||
fb->base.height,
|
||||
fb->base.depth,
|
||||
fb->base.bits_per_pixel);
|
||||
fb->base.bits_per_pixel,
|
||||
atomic_read(&fb->base.refcount.refcount));
|
||||
describe_obj(m, fb->obj);
|
||||
seq_printf(m, "\n");
|
||||
mutex_unlock(&dev->mode_config.mutex);
|
||||
|
||||
mutex_lock(&dev->mode_config.fb_lock);
|
||||
list_for_each_entry(fb, &dev->mode_config.fb_list, base.head) {
|
||||
if (&fb->base == ifbdev->helper.fb)
|
||||
continue;
|
||||
|
||||
seq_printf(m, "user size: %d x %d, depth %d, %d bpp, obj ",
|
||||
seq_printf(m, "user size: %d x %d, depth %d, %d bpp, refcount %d, obj ",
|
||||
fb->base.width,
|
||||
fb->base.height,
|
||||
fb->base.depth,
|
||||
fb->base.bits_per_pixel);
|
||||
fb->base.bits_per_pixel,
|
||||
atomic_read(&fb->base.refcount.refcount));
|
||||
describe_obj(m, fb->obj);
|
||||
seq_printf(m, "\n");
|
||||
}
|
||||
|
||||
mutex_unlock(&dev->mode_config.mutex);
|
||||
mutex_unlock(&dev->mode_config.fb_lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -1403,7 +1484,8 @@ static int i915_context_status(struct seq_file *m, void *unused)
|
||||
struct drm_info_node *node = (struct drm_info_node *) m->private;
|
||||
struct drm_device *dev = node->minor->dev;
|
||||
drm_i915_private_t *dev_priv = dev->dev_private;
|
||||
int ret;
|
||||
struct intel_ring_buffer *ring;
|
||||
int ret, i;
|
||||
|
||||
ret = mutex_lock_interruptible(&dev->mode_config.mutex);
|
||||
if (ret)
|
||||
@ -1421,6 +1503,14 @@ static int i915_context_status(struct seq_file *m, void *unused)
|
||||
seq_printf(m, "\n");
|
||||
}
|
||||
|
||||
for_each_ring(ring, dev_priv, i) {
|
||||
if (ring->default_context) {
|
||||
seq_printf(m, "HW default context %s ring ", ring->name);
|
||||
describe_obj(m, ring->default_context->obj);
|
||||
seq_printf(m, "\n");
|
||||
}
|
||||
}
|
||||
|
||||
mutex_unlock(&dev->mode_config.mutex);
|
||||
|
||||
return 0;
|
||||
@ -1556,7 +1646,7 @@ static int i915_dpio_info(struct seq_file *m, void *data)
|
||||
return 0;
|
||||
}
|
||||
|
||||
ret = mutex_lock_interruptible(&dev->mode_config.mutex);
|
||||
ret = mutex_lock_interruptible(&dev_priv->dpio_lock);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
@ -1585,7 +1675,7 @@ static int i915_dpio_info(struct seq_file *m, void *data)
|
||||
seq_printf(m, "DPIO_FASTCLK_DISABLE: 0x%08x\n",
|
||||
intel_dpio_read(dev_priv, DPIO_FASTCLK_DISABLE));
|
||||
|
||||
mutex_unlock(&dev->mode_config.mutex);
|
||||
mutex_unlock(&dev_priv->dpio_lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -1603,7 +1693,7 @@ i915_wedged_read(struct file *filp,
|
||||
|
||||
len = snprintf(buf, sizeof(buf),
|
||||
"wedged : %d\n",
|
||||
atomic_read(&dev_priv->mm.wedged));
|
||||
atomic_read(&dev_priv->gpu_error.reset_counter));
|
||||
|
||||
if (len > sizeof(buf))
|
||||
len = sizeof(buf);
|
||||
@ -1658,7 +1748,7 @@ i915_ring_stop_read(struct file *filp,
|
||||
int len;
|
||||
|
||||
len = snprintf(buf, sizeof(buf),
|
||||
"0x%08x\n", dev_priv->stop_rings);
|
||||
"0x%08x\n", dev_priv->gpu_error.stop_rings);
|
||||
|
||||
if (len > sizeof(buf))
|
||||
len = sizeof(buf);
|
||||
@ -1694,7 +1784,7 @@ i915_ring_stop_write(struct file *filp,
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
dev_priv->stop_rings = val;
|
||||
dev_priv->gpu_error.stop_rings = val;
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
|
||||
return cnt;
|
||||
@ -1708,6 +1798,102 @@ static const struct file_operations i915_ring_stop_fops = {
|
||||
.llseek = default_llseek,
|
||||
};
|
||||
|
||||
#define DROP_UNBOUND 0x1
|
||||
#define DROP_BOUND 0x2
|
||||
#define DROP_RETIRE 0x4
|
||||
#define DROP_ACTIVE 0x8
|
||||
#define DROP_ALL (DROP_UNBOUND | \
|
||||
DROP_BOUND | \
|
||||
DROP_RETIRE | \
|
||||
DROP_ACTIVE)
|
||||
static ssize_t
|
||||
i915_drop_caches_read(struct file *filp,
|
||||
char __user *ubuf,
|
||||
size_t max,
|
||||
loff_t *ppos)
|
||||
{
|
||||
char buf[20];
|
||||
int len;
|
||||
|
||||
len = snprintf(buf, sizeof(buf), "0x%08x\n", DROP_ALL);
|
||||
if (len > sizeof(buf))
|
||||
len = sizeof(buf);
|
||||
|
||||
return simple_read_from_buffer(ubuf, max, ppos, buf, len);
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
i915_drop_caches_write(struct file *filp,
|
||||
const char __user *ubuf,
|
||||
size_t cnt,
|
||||
loff_t *ppos)
|
||||
{
|
||||
struct drm_device *dev = filp->private_data;
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
struct drm_i915_gem_object *obj, *next;
|
||||
char buf[20];
|
||||
int val = 0, ret;
|
||||
|
||||
if (cnt > 0) {
|
||||
if (cnt > sizeof(buf) - 1)
|
||||
return -EINVAL;
|
||||
|
||||
if (copy_from_user(buf, ubuf, cnt))
|
||||
return -EFAULT;
|
||||
buf[cnt] = 0;
|
||||
|
||||
val = simple_strtoul(buf, NULL, 0);
|
||||
}
|
||||
|
||||
DRM_DEBUG_DRIVER("Dropping caches: 0x%08x\n", val);
|
||||
|
||||
/* No need to check and wait for gpu resets, only libdrm auto-restarts
|
||||
* on ioctls on -EAGAIN. */
|
||||
ret = mutex_lock_interruptible(&dev->struct_mutex);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (val & DROP_ACTIVE) {
|
||||
ret = i915_gpu_idle(dev);
|
||||
if (ret)
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
if (val & (DROP_RETIRE | DROP_ACTIVE))
|
||||
i915_gem_retire_requests(dev);
|
||||
|
||||
if (val & DROP_BOUND) {
|
||||
list_for_each_entry_safe(obj, next, &dev_priv->mm.inactive_list, mm_list)
|
||||
if (obj->pin_count == 0) {
|
||||
ret = i915_gem_object_unbind(obj);
|
||||
if (ret)
|
||||
goto unlock;
|
||||
}
|
||||
}
|
||||
|
||||
if (val & DROP_UNBOUND) {
|
||||
list_for_each_entry_safe(obj, next, &dev_priv->mm.unbound_list, gtt_list)
|
||||
if (obj->pages_pin_count == 0) {
|
||||
ret = i915_gem_object_put_pages(obj);
|
||||
if (ret)
|
||||
goto unlock;
|
||||
}
|
||||
}
|
||||
|
||||
unlock:
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
|
||||
return ret ?: cnt;
|
||||
}
|
||||
|
||||
static const struct file_operations i915_drop_caches_fops = {
|
||||
.owner = THIS_MODULE,
|
||||
.open = simple_open,
|
||||
.read = i915_drop_caches_read,
|
||||
.write = i915_drop_caches_write,
|
||||
.llseek = default_llseek,
|
||||
};
|
||||
|
||||
static ssize_t
|
||||
i915_max_freq_read(struct file *filp,
|
||||
char __user *ubuf,
|
||||
@ -2104,12 +2290,24 @@ int i915_debugfs_init(struct drm_minor *minor)
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = i915_debugfs_create(minor->debugfs_root, minor,
|
||||
"i915_gem_drop_caches",
|
||||
&i915_drop_caches_fops);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = i915_debugfs_create(minor->debugfs_root, minor,
|
||||
"i915_error_state",
|
||||
&i915_error_state_fops);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = i915_debugfs_create(minor->debugfs_root, minor,
|
||||
"i915_next_seqno",
|
||||
&i915_next_seqno_fops);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return drm_debugfs_create_files(i915_debugfs_list,
|
||||
I915_DEBUGFS_ENTRIES,
|
||||
minor->debugfs_root, minor);
|
||||
@ -2129,10 +2327,14 @@ void i915_debugfs_cleanup(struct drm_minor *minor)
|
||||
1, minor);
|
||||
drm_debugfs_remove_files((struct drm_info_list *) &i915_cache_sharing_fops,
|
||||
1, minor);
|
||||
drm_debugfs_remove_files((struct drm_info_list *) &i915_drop_caches_fops,
|
||||
1, minor);
|
||||
drm_debugfs_remove_files((struct drm_info_list *) &i915_ring_stop_fops,
|
||||
1, minor);
|
||||
drm_debugfs_remove_files((struct drm_info_list *) &i915_error_state_fops,
|
||||
1, minor);
|
||||
drm_debugfs_remove_files((struct drm_info_list *) &i915_next_seqno_fops,
|
||||
1, minor);
|
||||
}
|
||||
|
||||
#endif /* CONFIG_DEBUG_FS */
|
||||
|
@ -992,6 +992,12 @@ static int i915_getparam(struct drm_device *dev, void *data,
|
||||
case I915_PARAM_HAS_PINNED_BATCHES:
|
||||
value = 1;
|
||||
break;
|
||||
case I915_PARAM_HAS_EXEC_NO_RELOC:
|
||||
value = 1;
|
||||
break;
|
||||
case I915_PARAM_HAS_EXEC_HANDLE_LUT:
|
||||
value = 1;
|
||||
break;
|
||||
default:
|
||||
DRM_DEBUG_DRIVER("Unknown parameter %d\n",
|
||||
param->param);
|
||||
@ -1070,7 +1076,7 @@ static int i915_set_status_page(struct drm_device *dev, void *data,
|
||||
ring->status_page.gfx_addr = hws->addr & (0x1ffff<<12);
|
||||
|
||||
dev_priv->dri1.gfx_hws_cpu_addr =
|
||||
ioremap_wc(dev_priv->mm.gtt_base_addr + hws->addr, 4096);
|
||||
ioremap_wc(dev_priv->gtt.mappable_base + hws->addr, 4096);
|
||||
if (dev_priv->dri1.gfx_hws_cpu_addr == NULL) {
|
||||
i915_dma_cleanup(dev);
|
||||
ring->status_page.gfx_addr = 0;
|
||||
@ -1297,19 +1303,21 @@ static int i915_load_modeset_init(struct drm_device *dev)
|
||||
if (ret)
|
||||
goto cleanup_vga_switcheroo;
|
||||
|
||||
ret = drm_irq_install(dev);
|
||||
if (ret)
|
||||
goto cleanup_gem_stolen;
|
||||
|
||||
/* Important: The output setup functions called by modeset_init need
|
||||
* working irqs for e.g. gmbus and dp aux transfers. */
|
||||
intel_modeset_init(dev);
|
||||
|
||||
ret = i915_gem_init(dev);
|
||||
if (ret)
|
||||
goto cleanup_gem_stolen;
|
||||
|
||||
intel_modeset_gem_init(dev);
|
||||
goto cleanup_irq;
|
||||
|
||||
INIT_WORK(&dev_priv->console_resume_work, intel_console_resume);
|
||||
|
||||
ret = drm_irq_install(dev);
|
||||
if (ret)
|
||||
goto cleanup_gem;
|
||||
intel_modeset_gem_init(dev);
|
||||
|
||||
/* Always safe in the mode setting case. */
|
||||
/* FIXME: do pre/post-mode set stuff in core KMS code */
|
||||
@ -1317,7 +1325,25 @@ static int i915_load_modeset_init(struct drm_device *dev)
|
||||
|
||||
ret = intel_fbdev_init(dev);
|
||||
if (ret)
|
||||
goto cleanup_irq;
|
||||
goto cleanup_gem;
|
||||
|
||||
/* Only enable hotplug handling once the fbdev is fully set up. */
|
||||
intel_hpd_init(dev);
|
||||
|
||||
/*
|
||||
* Some ports require correctly set-up hpd registers for detection to
|
||||
* work properly (leading to ghost connected connector status), e.g. VGA
|
||||
* on gm45. Hence we can only set up the initial fbdev config after hpd
|
||||
* irqs are fully enabled. Now we should scan for the initial config
|
||||
* only once hotplug handling is enabled, but due to screwed-up locking
|
||||
* around kms/fbdev init we can't protect the fdbev initial config
|
||||
* scanning against hotplug events. Hence do this first and ignore the
|
||||
* tiny window where we will loose hotplug notifactions.
|
||||
*/
|
||||
intel_fbdev_initial_config(dev);
|
||||
|
||||
/* Only enable hotplug handling once the fbdev is fully set up. */
|
||||
dev_priv->enable_hotplug_processing = true;
|
||||
|
||||
drm_kms_helper_poll_init(dev);
|
||||
|
||||
@ -1326,13 +1352,13 @@ static int i915_load_modeset_init(struct drm_device *dev)
|
||||
|
||||
return 0;
|
||||
|
||||
cleanup_irq:
|
||||
drm_irq_uninstall(dev);
|
||||
cleanup_gem:
|
||||
mutex_lock(&dev->struct_mutex);
|
||||
i915_gem_cleanup_ringbuffer(dev);
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
i915_gem_cleanup_aliasing_ppgtt(dev);
|
||||
cleanup_irq:
|
||||
drm_irq_uninstall(dev);
|
||||
cleanup_gem_stolen:
|
||||
i915_gem_cleanup_stolen(dev);
|
||||
cleanup_vga_switcheroo:
|
||||
@ -1400,9 +1426,9 @@ static void i915_kick_out_firmware_fb(struct drm_i915_private *dev_priv)
|
||||
if (!ap)
|
||||
return;
|
||||
|
||||
ap->ranges[0].base = dev_priv->mm.gtt->gma_bus_addr;
|
||||
ap->ranges[0].size =
|
||||
dev_priv->mm.gtt->gtt_mappable_entries << PAGE_SHIFT;
|
||||
ap->ranges[0].base = dev_priv->gtt.mappable_base;
|
||||
ap->ranges[0].size = dev_priv->gtt.mappable_end - dev_priv->gtt.start;
|
||||
|
||||
primary =
|
||||
pdev->resource[PCI_ROM_RESOURCE].flags & IORESOURCE_ROM_SHADOW;
|
||||
|
||||
@ -1516,18 +1542,17 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
|
||||
goto put_gmch;
|
||||
}
|
||||
|
||||
aperture_size = dev_priv->mm.gtt->gtt_mappable_entries << PAGE_SHIFT;
|
||||
dev_priv->mm.gtt_base_addr = dev_priv->mm.gtt->gma_bus_addr;
|
||||
aperture_size = dev_priv->gtt.mappable_end;
|
||||
|
||||
dev_priv->mm.gtt_mapping =
|
||||
io_mapping_create_wc(dev_priv->mm.gtt_base_addr,
|
||||
dev_priv->gtt.mappable =
|
||||
io_mapping_create_wc(dev_priv->gtt.mappable_base,
|
||||
aperture_size);
|
||||
if (dev_priv->mm.gtt_mapping == NULL) {
|
||||
if (dev_priv->gtt.mappable == NULL) {
|
||||
ret = -EIO;
|
||||
goto out_rmmap;
|
||||
}
|
||||
|
||||
i915_mtrr_setup(dev_priv, dev_priv->mm.gtt_base_addr,
|
||||
i915_mtrr_setup(dev_priv, dev_priv->gtt.mappable_base,
|
||||
aperture_size);
|
||||
|
||||
/* The i915 workqueue is primarily used for batched retirement of
|
||||
@ -1580,11 +1605,12 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
|
||||
pci_enable_msi(dev->pdev);
|
||||
|
||||
spin_lock_init(&dev_priv->irq_lock);
|
||||
spin_lock_init(&dev_priv->error_lock);
|
||||
spin_lock_init(&dev_priv->gpu_error.lock);
|
||||
spin_lock_init(&dev_priv->rps.lock);
|
||||
spin_lock_init(&dev_priv->dpio_lock);
|
||||
mutex_init(&dev_priv->dpio_lock);
|
||||
|
||||
mutex_init(&dev_priv->rps.hw_lock);
|
||||
mutex_init(&dev_priv->modeset_restore_lock);
|
||||
|
||||
if (IS_IVYBRIDGE(dev) || IS_HASWELL(dev))
|
||||
dev_priv->num_pipe = 3;
|
||||
@ -1614,9 +1640,6 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
|
||||
intel_opregion_init(dev);
|
||||
acpi_video_register();
|
||||
|
||||
setup_timer(&dev_priv->hangcheck_timer, i915_hangcheck_elapsed,
|
||||
(unsigned long) dev);
|
||||
|
||||
if (IS_GEN5(dev))
|
||||
intel_gpu_ips_init(dev_priv);
|
||||
|
||||
@ -1635,15 +1658,15 @@ out_gem_unload:
|
||||
out_mtrrfree:
|
||||
if (dev_priv->mm.gtt_mtrr >= 0) {
|
||||
mtrr_del(dev_priv->mm.gtt_mtrr,
|
||||
dev_priv->mm.gtt_base_addr,
|
||||
dev_priv->gtt.mappable_base,
|
||||
aperture_size);
|
||||
dev_priv->mm.gtt_mtrr = -1;
|
||||
}
|
||||
io_mapping_free(dev_priv->mm.gtt_mapping);
|
||||
io_mapping_free(dev_priv->gtt.mappable);
|
||||
out_rmmap:
|
||||
pci_iounmap(dev->pdev, dev_priv->regs);
|
||||
put_gmch:
|
||||
i915_gem_gtt_fini(dev);
|
||||
dev_priv->gtt.gtt_remove(dev);
|
||||
put_bridge:
|
||||
pci_dev_put(dev_priv->bridge_dev);
|
||||
free_priv:
|
||||
@ -1673,11 +1696,11 @@ int i915_driver_unload(struct drm_device *dev)
|
||||
/* Cancel the retire work handler, which should be idle now. */
|
||||
cancel_delayed_work_sync(&dev_priv->mm.retire_work);
|
||||
|
||||
io_mapping_free(dev_priv->mm.gtt_mapping);
|
||||
io_mapping_free(dev_priv->gtt.mappable);
|
||||
if (dev_priv->mm.gtt_mtrr >= 0) {
|
||||
mtrr_del(dev_priv->mm.gtt_mtrr,
|
||||
dev_priv->mm.gtt_base_addr,
|
||||
dev_priv->mm.gtt->gtt_mappable_entries * PAGE_SIZE);
|
||||
dev_priv->gtt.mappable_base,
|
||||
dev_priv->gtt.mappable_end);
|
||||
dev_priv->mm.gtt_mtrr = -1;
|
||||
}
|
||||
|
||||
@ -1703,8 +1726,8 @@ int i915_driver_unload(struct drm_device *dev)
|
||||
}
|
||||
|
||||
/* Free error state after interrupts are fully disabled. */
|
||||
del_timer_sync(&dev_priv->hangcheck_timer);
|
||||
cancel_work_sync(&dev_priv->error_work);
|
||||
del_timer_sync(&dev_priv->gpu_error.hangcheck_timer);
|
||||
cancel_work_sync(&dev_priv->gpu_error.work);
|
||||
i915_destroy_error_state(dev);
|
||||
|
||||
if (dev->pdev->msi_enabled)
|
||||
@ -1723,9 +1746,6 @@ int i915_driver_unload(struct drm_device *dev)
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
i915_gem_cleanup_aliasing_ppgtt(dev);
|
||||
i915_gem_cleanup_stolen(dev);
|
||||
drm_mm_takedown(&dev_priv->mm.stolen);
|
||||
|
||||
intel_cleanup_overlay(dev);
|
||||
|
||||
if (!I915_NEED_GFX_HWS(dev))
|
||||
i915_free_hws(dev);
|
||||
@ -1738,6 +1758,10 @@ int i915_driver_unload(struct drm_device *dev)
|
||||
intel_teardown_mchbar(dev);
|
||||
|
||||
destroy_workqueue(dev_priv->wq);
|
||||
pm_qos_remove_request(&dev_priv->pm_qos);
|
||||
|
||||
if (dev_priv->slab)
|
||||
kmem_cache_destroy(dev_priv->slab);
|
||||
|
||||
pci_dev_put(dev_priv->bridge_dev);
|
||||
kfree(dev->dev_private);
|
||||
|
@ -276,6 +276,7 @@ static const struct intel_device_info intel_valleyview_m_info = {
|
||||
.has_bsd_ring = 1,
|
||||
.has_blt_ring = 1,
|
||||
.is_valleyview = 1,
|
||||
.display_mmio_offset = VLV_DISPLAY_BASE,
|
||||
};
|
||||
|
||||
static const struct intel_device_info intel_valleyview_d_info = {
|
||||
@ -285,6 +286,7 @@ static const struct intel_device_info intel_valleyview_d_info = {
|
||||
.has_bsd_ring = 1,
|
||||
.has_blt_ring = 1,
|
||||
.is_valleyview = 1,
|
||||
.display_mmio_offset = VLV_DISPLAY_BASE,
|
||||
};
|
||||
|
||||
static const struct intel_device_info intel_haswell_d_info = {
|
||||
@ -468,6 +470,13 @@ static int i915_drm_freeze(struct drm_device *dev)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
|
||||
/* ignore lid events during suspend */
|
||||
mutex_lock(&dev_priv->modeset_restore_lock);
|
||||
dev_priv->modeset_restore = MODESET_SUSPENDED;
|
||||
mutex_unlock(&dev_priv->modeset_restore_lock);
|
||||
|
||||
intel_set_power_well(dev, true);
|
||||
|
||||
drm_kms_helper_poll_disable(dev);
|
||||
|
||||
pci_save_state(dev->pdev);
|
||||
@ -492,9 +501,6 @@ static int i915_drm_freeze(struct drm_device *dev)
|
||||
|
||||
intel_opregion_fini(dev);
|
||||
|
||||
/* Modeset on resume, not lid events */
|
||||
dev_priv->modeset_on_lid = 0;
|
||||
|
||||
console_lock();
|
||||
intel_fbdev_set_suspend(dev, 1);
|
||||
console_unlock();
|
||||
@ -565,12 +571,11 @@ static int __i915_drm_thaw(struct drm_device *dev)
|
||||
intel_modeset_init_hw(dev);
|
||||
intel_modeset_setup_hw_state(dev, false);
|
||||
drm_irq_install(dev);
|
||||
intel_hpd_init(dev);
|
||||
}
|
||||
|
||||
intel_opregion_init(dev);
|
||||
|
||||
dev_priv->modeset_on_lid = 0;
|
||||
|
||||
/*
|
||||
* The console lock can be pretty contented on resume due
|
||||
* to all the printk activity. Try to keep it out of the hot
|
||||
@ -583,6 +588,9 @@ static int __i915_drm_thaw(struct drm_device *dev)
|
||||
schedule_work(&dev_priv->console_resume_work);
|
||||
}
|
||||
|
||||
mutex_lock(&dev_priv->modeset_restore_lock);
|
||||
dev_priv->modeset_restore = MODESET_DONE;
|
||||
mutex_unlock(&dev_priv->modeset_restore_lock);
|
||||
return error;
|
||||
}
|
||||
|
||||
@ -778,9 +786,9 @@ int intel_gpu_reset(struct drm_device *dev)
|
||||
}
|
||||
|
||||
/* Also reset the gpu hangman. */
|
||||
if (dev_priv->stop_rings) {
|
||||
if (dev_priv->gpu_error.stop_rings) {
|
||||
DRM_DEBUG("Simulated gpu hang, resetting stop_rings\n");
|
||||
dev_priv->stop_rings = 0;
|
||||
dev_priv->gpu_error.stop_rings = 0;
|
||||
if (ret == -ENODEV) {
|
||||
DRM_ERROR("Reset not implemented, but ignoring "
|
||||
"error for simulated gpu hangs\n");
|
||||
@ -819,12 +827,12 @@ int i915_reset(struct drm_device *dev)
|
||||
i915_gem_reset(dev);
|
||||
|
||||
ret = -ENODEV;
|
||||
if (get_seconds() - dev_priv->last_gpu_reset < 5)
|
||||
if (get_seconds() - dev_priv->gpu_error.last_reset < 5)
|
||||
DRM_ERROR("GPU hanging too fast, declaring wedged!\n");
|
||||
else
|
||||
ret = intel_gpu_reset(dev);
|
||||
|
||||
dev_priv->last_gpu_reset = get_seconds();
|
||||
dev_priv->gpu_error.last_reset = get_seconds();
|
||||
if (ret) {
|
||||
DRM_ERROR("Failed to reset chip.\n");
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
@ -870,6 +878,7 @@ int i915_reset(struct drm_device *dev)
|
||||
|
||||
drm_irq_uninstall(dev);
|
||||
drm_irq_install(dev);
|
||||
intel_hpd_init(dev);
|
||||
} else {
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
}
|
||||
@ -1113,102 +1122,6 @@ MODULE_LICENSE("GPL and additional rights");
|
||||
((HAS_FORCE_WAKE((dev_priv)->dev)) && \
|
||||
((reg) < 0x40000) && \
|
||||
((reg) != FORCEWAKE))
|
||||
|
||||
static bool IS_DISPLAYREG(u32 reg)
|
||||
{
|
||||
/*
|
||||
* This should make it easier to transition modules over to the
|
||||
* new register block scheme, since we can do it incrementally.
|
||||
*/
|
||||
if (reg >= VLV_DISPLAY_BASE)
|
||||
return false;
|
||||
|
||||
if (reg >= RENDER_RING_BASE &&
|
||||
reg < RENDER_RING_BASE + 0xff)
|
||||
return false;
|
||||
if (reg >= GEN6_BSD_RING_BASE &&
|
||||
reg < GEN6_BSD_RING_BASE + 0xff)
|
||||
return false;
|
||||
if (reg >= BLT_RING_BASE &&
|
||||
reg < BLT_RING_BASE + 0xff)
|
||||
return false;
|
||||
|
||||
if (reg == PGTBL_ER)
|
||||
return false;
|
||||
|
||||
if (reg >= IPEIR_I965 &&
|
||||
reg < HWSTAM)
|
||||
return false;
|
||||
|
||||
if (reg == MI_MODE)
|
||||
return false;
|
||||
|
||||
if (reg == GFX_MODE_GEN7)
|
||||
return false;
|
||||
|
||||
if (reg == RENDER_HWS_PGA_GEN7 ||
|
||||
reg == BSD_HWS_PGA_GEN7 ||
|
||||
reg == BLT_HWS_PGA_GEN7)
|
||||
return false;
|
||||
|
||||
if (reg == GEN6_BSD_SLEEP_PSMI_CONTROL ||
|
||||
reg == GEN6_BSD_RNCID)
|
||||
return false;
|
||||
|
||||
if (reg == GEN6_BLITTER_ECOSKPD)
|
||||
return false;
|
||||
|
||||
if (reg >= 0x4000c &&
|
||||
reg <= 0x4002c)
|
||||
return false;
|
||||
|
||||
if (reg >= 0x4f000 &&
|
||||
reg <= 0x4f08f)
|
||||
return false;
|
||||
|
||||
if (reg >= 0x4f100 &&
|
||||
reg <= 0x4f11f)
|
||||
return false;
|
||||
|
||||
if (reg >= VLV_MASTER_IER &&
|
||||
reg <= GEN6_PMIER)
|
||||
return false;
|
||||
|
||||
if (reg >= FENCE_REG_SANDYBRIDGE_0 &&
|
||||
reg < (FENCE_REG_SANDYBRIDGE_0 + (16*8)))
|
||||
return false;
|
||||
|
||||
if (reg >= VLV_IIR_RW &&
|
||||
reg <= VLV_ISR)
|
||||
return false;
|
||||
|
||||
if (reg == FORCEWAKE_VLV ||
|
||||
reg == FORCEWAKE_ACK_VLV)
|
||||
return false;
|
||||
|
||||
if (reg == GEN6_GDRST)
|
||||
return false;
|
||||
|
||||
switch (reg) {
|
||||
case _3D_CHICKEN3:
|
||||
case IVB_CHICKEN3:
|
||||
case GEN7_COMMON_SLICE_CHICKEN1:
|
||||
case GEN7_L3CNTLREG1:
|
||||
case GEN7_L3_CHICKEN_MODE_REGISTER:
|
||||
case GEN7_ROW_CHICKEN2:
|
||||
case GEN7_L3SQCREG4:
|
||||
case GEN7_SQ_CHICKEN_MBCUNIT_CONFIG:
|
||||
case GEN7_HALF_SLICE_CHICKEN1:
|
||||
case GEN6_MBCTL:
|
||||
case GEN6_UCGCTL2:
|
||||
return false;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void
|
||||
ilk_dummy_write(struct drm_i915_private *dev_priv)
|
||||
{
|
||||
@ -1232,8 +1145,6 @@ u##x i915_read##x(struct drm_i915_private *dev_priv, u32 reg) { \
|
||||
if (dev_priv->forcewake_count == 0) \
|
||||
dev_priv->gt.force_wake_put(dev_priv); \
|
||||
spin_unlock_irqrestore(&dev_priv->gt_lock, irqflags); \
|
||||
} else if (IS_VALLEYVIEW(dev_priv->dev) && IS_DISPLAYREG(reg)) { \
|
||||
val = read##y(dev_priv->regs + reg + 0x180000); \
|
||||
} else { \
|
||||
val = read##y(dev_priv->regs + reg); \
|
||||
} \
|
||||
@ -1260,11 +1171,7 @@ void i915_write##x(struct drm_i915_private *dev_priv, u32 reg, u##x val) { \
|
||||
DRM_ERROR("Unknown unclaimed register before writing to %x\n", reg); \
|
||||
I915_WRITE_NOTRACE(GEN7_ERR_INT, ERR_INT_MMIO_UNCLAIMED); \
|
||||
} \
|
||||
if (IS_VALLEYVIEW(dev_priv->dev) && IS_DISPLAYREG(reg)) { \
|
||||
write##y(val, dev_priv->regs + reg + 0x180000); \
|
||||
} else { \
|
||||
write##y(val, dev_priv->regs + reg); \
|
||||
} \
|
||||
write##y(val, dev_priv->regs + reg); \
|
||||
if (unlikely(__fifo_ret)) { \
|
||||
gen6_gt_check_fifodbg(dev_priv); \
|
||||
} \
|
||||
|
@ -30,6 +30,8 @@
|
||||
#ifndef _I915_DRV_H_
|
||||
#define _I915_DRV_H_
|
||||
|
||||
#include <uapi/drm/i915_drm.h>
|
||||
|
||||
#include "i915_reg.h"
|
||||
#include "intel_bios.h"
|
||||
#include "intel_ringbuffer.h"
|
||||
@ -40,6 +42,7 @@
|
||||
#include <linux/backlight.h>
|
||||
#include <linux/intel-iommu.h>
|
||||
#include <linux/kref.h>
|
||||
#include <linux/pm_qos.h>
|
||||
|
||||
/* General customization:
|
||||
*/
|
||||
@ -83,7 +86,12 @@ enum port {
|
||||
};
|
||||
#define port_name(p) ((p) + 'A')
|
||||
|
||||
#define I915_GEM_GPU_DOMAINS (~(I915_GEM_DOMAIN_CPU | I915_GEM_DOMAIN_GTT))
|
||||
#define I915_GEM_GPU_DOMAINS \
|
||||
(I915_GEM_DOMAIN_RENDER | \
|
||||
I915_GEM_DOMAIN_SAMPLER | \
|
||||
I915_GEM_DOMAIN_COMMAND | \
|
||||
I915_GEM_DOMAIN_INSTRUCTION | \
|
||||
I915_GEM_DOMAIN_VERTEX)
|
||||
|
||||
#define for_each_pipe(p) for ((p) = 0; (p) < dev_priv->num_pipe; (p)++)
|
||||
|
||||
@ -101,6 +109,19 @@ struct intel_pch_pll {
|
||||
};
|
||||
#define I915_NUM_PLLS 2
|
||||
|
||||
/* Used by dp and fdi links */
|
||||
struct intel_link_m_n {
|
||||
uint32_t tu;
|
||||
uint32_t gmch_m;
|
||||
uint32_t gmch_n;
|
||||
uint32_t link_m;
|
||||
uint32_t link_n;
|
||||
};
|
||||
|
||||
void intel_link_compute_m_n(int bpp, int nlanes,
|
||||
int pixel_clock, int link_clock,
|
||||
struct intel_link_m_n *m_n);
|
||||
|
||||
struct intel_ddi_plls {
|
||||
int spll_refcount;
|
||||
int wrpll1_refcount;
|
||||
@ -279,6 +300,7 @@ struct drm_i915_display_funcs {
|
||||
struct drm_i915_gem_object *obj);
|
||||
int (*update_plane)(struct drm_crtc *crtc, struct drm_framebuffer *fb,
|
||||
int x, int y);
|
||||
void (*hpd_irq_setup)(struct drm_device *dev);
|
||||
/* clock updates for mode set */
|
||||
/* cursor updates */
|
||||
/* render clock increase/decrease */
|
||||
@ -318,6 +340,7 @@ struct drm_i915_gt_funcs {
|
||||
DEV_INFO_FLAG(has_llc)
|
||||
|
||||
struct intel_device_info {
|
||||
u32 display_mmio_offset;
|
||||
u8 gen;
|
||||
u8 is_mobile:1;
|
||||
u8 is_i85x:1;
|
||||
@ -345,6 +368,50 @@ struct intel_device_info {
|
||||
u8 has_llc:1;
|
||||
};
|
||||
|
||||
enum i915_cache_level {
|
||||
I915_CACHE_NONE = 0,
|
||||
I915_CACHE_LLC,
|
||||
I915_CACHE_LLC_MLC, /* gen6+, in docs at least! */
|
||||
};
|
||||
|
||||
/* The Graphics Translation Table is the way in which GEN hardware translates a
|
||||
* Graphics Virtual Address into a Physical Address. In addition to the normal
|
||||
* collateral associated with any va->pa translations GEN hardware also has a
|
||||
* portion of the GTT which can be mapped by the CPU and remain both coherent
|
||||
* and correct (in cases like swizzling). That region is referred to as GMADR in
|
||||
* the spec.
|
||||
*/
|
||||
struct i915_gtt {
|
||||
unsigned long start; /* Start offset of used GTT */
|
||||
size_t total; /* Total size GTT can map */
|
||||
size_t stolen_size; /* Total size of stolen memory */
|
||||
|
||||
unsigned long mappable_end; /* End offset that we can CPU map */
|
||||
struct io_mapping *mappable; /* Mapping to our CPU mappable region */
|
||||
phys_addr_t mappable_base; /* PA of our GMADR */
|
||||
|
||||
/** "Graphics Stolen Memory" holds the global PTEs */
|
||||
void __iomem *gsm;
|
||||
|
||||
bool do_idle_maps;
|
||||
dma_addr_t scratch_page_dma;
|
||||
struct page *scratch_page;
|
||||
|
||||
/* global gtt ops */
|
||||
int (*gtt_probe)(struct drm_device *dev, size_t *gtt_total,
|
||||
size_t *stolen, phys_addr_t *mappable_base,
|
||||
unsigned long *mappable_end);
|
||||
void (*gtt_remove)(struct drm_device *dev);
|
||||
void (*gtt_clear_range)(struct drm_device *dev,
|
||||
unsigned int first_entry,
|
||||
unsigned int num_entries);
|
||||
void (*gtt_insert_entries)(struct drm_device *dev,
|
||||
struct sg_table *st,
|
||||
unsigned int pg_start,
|
||||
enum i915_cache_level cache_level);
|
||||
};
|
||||
#define gtt_total_entries(gtt) ((gtt).total >> PAGE_SHIFT)
|
||||
|
||||
#define I915_PPGTT_PD_ENTRIES 512
|
||||
#define I915_PPGTT_PT_ENTRIES 1024
|
||||
struct i915_hw_ppgtt {
|
||||
@ -354,6 +421,16 @@ struct i915_hw_ppgtt {
|
||||
uint32_t pd_offset;
|
||||
dma_addr_t *pt_dma_addr;
|
||||
dma_addr_t scratch_page_dma_addr;
|
||||
|
||||
/* pte functions, mirroring the interface of the global gtt. */
|
||||
void (*clear_range)(struct i915_hw_ppgtt *ppgtt,
|
||||
unsigned int first_entry,
|
||||
unsigned int num_entries);
|
||||
void (*insert_entries)(struct i915_hw_ppgtt *ppgtt,
|
||||
struct sg_table *st,
|
||||
unsigned int pg_start,
|
||||
enum i915_cache_level cache_level);
|
||||
void (*cleanup)(struct i915_hw_ppgtt *ppgtt);
|
||||
};
|
||||
|
||||
|
||||
@ -580,6 +657,9 @@ struct intel_gen6_power_mgmt {
|
||||
struct mutex hw_lock;
|
||||
};
|
||||
|
||||
/* defined intel_pm.c */
|
||||
extern spinlock_t mchdev_lock;
|
||||
|
||||
struct intel_ilk_power_mgmt {
|
||||
u8 cur_delay;
|
||||
u8 min_delay;
|
||||
@ -620,8 +700,162 @@ struct intel_l3_parity {
|
||||
struct work_struct error_work;
|
||||
};
|
||||
|
||||
struct i915_gem_mm {
|
||||
/** Memory allocator for GTT stolen memory */
|
||||
struct drm_mm stolen;
|
||||
/** Memory allocator for GTT */
|
||||
struct drm_mm gtt_space;
|
||||
/** List of all objects in gtt_space. Used to restore gtt
|
||||
* mappings on resume */
|
||||
struct list_head bound_list;
|
||||
/**
|
||||
* List of objects which are not bound to the GTT (thus
|
||||
* are idle and not used by the GPU) but still have
|
||||
* (presumably uncached) pages still attached.
|
||||
*/
|
||||
struct list_head unbound_list;
|
||||
|
||||
/** Usable portion of the GTT for GEM */
|
||||
unsigned long stolen_base; /* limited to low memory (32-bit) */
|
||||
|
||||
int gtt_mtrr;
|
||||
|
||||
/** PPGTT used for aliasing the PPGTT with the GTT */
|
||||
struct i915_hw_ppgtt *aliasing_ppgtt;
|
||||
|
||||
struct shrinker inactive_shrinker;
|
||||
bool shrinker_no_lock_stealing;
|
||||
|
||||
/**
|
||||
* List of objects currently involved in rendering.
|
||||
*
|
||||
* Includes buffers having the contents of their GPU caches
|
||||
* flushed, not necessarily primitives. last_rendering_seqno
|
||||
* represents when the rendering involved will be completed.
|
||||
*
|
||||
* A reference is held on the buffer while on this list.
|
||||
*/
|
||||
struct list_head active_list;
|
||||
|
||||
/**
|
||||
* LRU list of objects which are not in the ringbuffer and
|
||||
* are ready to unbind, but are still in the GTT.
|
||||
*
|
||||
* last_rendering_seqno is 0 while an object is in this list.
|
||||
*
|
||||
* A reference is not held on the buffer while on this list,
|
||||
* as merely being GTT-bound shouldn't prevent its being
|
||||
* freed, and we'll pull it off the list in the free path.
|
||||
*/
|
||||
struct list_head inactive_list;
|
||||
|
||||
/** LRU list of objects with fence regs on them. */
|
||||
struct list_head fence_list;
|
||||
|
||||
/**
|
||||
* We leave the user IRQ off as much as possible,
|
||||
* but this means that requests will finish and never
|
||||
* be retired once the system goes idle. Set a timer to
|
||||
* fire periodically while the ring is running. When it
|
||||
* fires, go retire requests.
|
||||
*/
|
||||
struct delayed_work retire_work;
|
||||
|
||||
/**
|
||||
* Are we in a non-interruptible section of code like
|
||||
* modesetting?
|
||||
*/
|
||||
bool interruptible;
|
||||
|
||||
/**
|
||||
* Flag if the X Server, and thus DRM, is not currently in
|
||||
* control of the device.
|
||||
*
|
||||
* This is set between LeaveVT and EnterVT. It needs to be
|
||||
* replaced with a semaphore. It also needs to be
|
||||
* transitioned away from for kernel modesetting.
|
||||
*/
|
||||
int suspended;
|
||||
|
||||
/** Bit 6 swizzling required for X tiling */
|
||||
uint32_t bit_6_swizzle_x;
|
||||
/** Bit 6 swizzling required for Y tiling */
|
||||
uint32_t bit_6_swizzle_y;
|
||||
|
||||
/* storage for physical objects */
|
||||
struct drm_i915_gem_phys_object *phys_objs[I915_MAX_PHYS_OBJECT];
|
||||
|
||||
/* accounting, useful for userland debugging */
|
||||
size_t object_memory;
|
||||
u32 object_count;
|
||||
};
|
||||
|
||||
struct i915_gpu_error {
|
||||
/* For hangcheck timer */
|
||||
#define DRM_I915_HANGCHECK_PERIOD 1500 /* in ms */
|
||||
#define DRM_I915_HANGCHECK_JIFFIES msecs_to_jiffies(DRM_I915_HANGCHECK_PERIOD)
|
||||
struct timer_list hangcheck_timer;
|
||||
int hangcheck_count;
|
||||
uint32_t last_acthd[I915_NUM_RINGS];
|
||||
uint32_t prev_instdone[I915_NUM_INSTDONE_REG];
|
||||
|
||||
/* For reset and error_state handling. */
|
||||
spinlock_t lock;
|
||||
/* Protected by the above dev->gpu_error.lock. */
|
||||
struct drm_i915_error_state *first_error;
|
||||
struct work_struct work;
|
||||
|
||||
unsigned long last_reset;
|
||||
|
||||
/**
|
||||
* State variable and reset counter controlling the reset flow
|
||||
*
|
||||
* Upper bits are for the reset counter. This counter is used by the
|
||||
* wait_seqno code to race-free noticed that a reset event happened and
|
||||
* that it needs to restart the entire ioctl (since most likely the
|
||||
* seqno it waited for won't ever signal anytime soon).
|
||||
*
|
||||
* This is important for lock-free wait paths, where no contended lock
|
||||
* naturally enforces the correct ordering between the bail-out of the
|
||||
* waiter and the gpu reset work code.
|
||||
*
|
||||
* Lowest bit controls the reset state machine: Set means a reset is in
|
||||
* progress. This state will (presuming we don't have any bugs) decay
|
||||
* into either unset (successful reset) or the special WEDGED value (hw
|
||||
* terminally sour). All waiters on the reset_queue will be woken when
|
||||
* that happens.
|
||||
*/
|
||||
atomic_t reset_counter;
|
||||
|
||||
/**
|
||||
* Special values/flags for reset_counter
|
||||
*
|
||||
* Note that the code relies on
|
||||
* I915_WEDGED & I915_RESET_IN_PROGRESS_FLAG
|
||||
* being true.
|
||||
*/
|
||||
#define I915_RESET_IN_PROGRESS_FLAG 1
|
||||
#define I915_WEDGED 0xffffffff
|
||||
|
||||
/**
|
||||
* Waitqueue to signal when the reset has completed. Used by clients
|
||||
* that wait for dev_priv->mm.wedged to settle.
|
||||
*/
|
||||
wait_queue_head_t reset_queue;
|
||||
|
||||
/* For gpu hang simulation. */
|
||||
unsigned int stop_rings;
|
||||
};
|
||||
|
||||
enum modeset_restore {
|
||||
MODESET_ON_LID_OPEN,
|
||||
MODESET_DONE,
|
||||
MODESET_SUSPENDED,
|
||||
};
|
||||
|
||||
typedef struct drm_i915_private {
|
||||
struct drm_device *dev;
|
||||
struct kmem_cache *slab;
|
||||
|
||||
const struct intel_device_info *info;
|
||||
|
||||
@ -636,10 +870,11 @@ typedef struct drm_i915_private {
|
||||
/** forcewake_count is protected by gt_lock */
|
||||
unsigned forcewake_count;
|
||||
/** gt_lock is also taken in irq contexts. */
|
||||
struct spinlock gt_lock;
|
||||
spinlock_t gt_lock;
|
||||
|
||||
struct intel_gmbus gmbus[GMBUS_NUM_PORTS];
|
||||
|
||||
|
||||
/** gmbus_mutex protects against concurrent usage of the single hw gmbus
|
||||
* controller on different i2c buses. */
|
||||
struct mutex gmbus_mutex;
|
||||
@ -649,9 +884,11 @@ typedef struct drm_i915_private {
|
||||
*/
|
||||
uint32_t gpio_mmio_base;
|
||||
|
||||
wait_queue_head_t gmbus_wait_queue;
|
||||
|
||||
struct pci_dev *bridge_dev;
|
||||
struct intel_ring_buffer ring[I915_NUM_RINGS];
|
||||
uint32_t next_seqno;
|
||||
uint32_t last_seqno, next_seqno;
|
||||
|
||||
drm_dma_handle_t *status_page_dmah;
|
||||
struct resource mch_res;
|
||||
@ -661,31 +898,24 @@ typedef struct drm_i915_private {
|
||||
/* protects the irq masks */
|
||||
spinlock_t irq_lock;
|
||||
|
||||
/* To control wakeup latency, e.g. for irq-driven dp aux transfers. */
|
||||
struct pm_qos_request pm_qos;
|
||||
|
||||
/* DPIO indirect register protection */
|
||||
spinlock_t dpio_lock;
|
||||
struct mutex dpio_lock;
|
||||
|
||||
/** Cached value of IMR to avoid reads in updating the bitfield */
|
||||
u32 pipestat[2];
|
||||
u32 irq_mask;
|
||||
u32 gt_irq_mask;
|
||||
u32 pch_irq_mask;
|
||||
|
||||
u32 hotplug_supported_mask;
|
||||
struct work_struct hotplug_work;
|
||||
bool enable_hotplug_processing;
|
||||
|
||||
int num_pipe;
|
||||
int num_pch_pll;
|
||||
|
||||
/* For hangcheck timer */
|
||||
#define DRM_I915_HANGCHECK_PERIOD 1500 /* in ms */
|
||||
#define DRM_I915_HANGCHECK_JIFFIES msecs_to_jiffies(DRM_I915_HANGCHECK_PERIOD)
|
||||
struct timer_list hangcheck_timer;
|
||||
int hangcheck_count;
|
||||
uint32_t last_acthd[I915_NUM_RINGS];
|
||||
uint32_t prev_instdone[I915_NUM_INSTDONE_REG];
|
||||
|
||||
unsigned int stop_rings;
|
||||
|
||||
unsigned long cfb_size;
|
||||
unsigned int cfb_fb;
|
||||
enum plane cfb_plane;
|
||||
@ -696,7 +926,7 @@ typedef struct drm_i915_private {
|
||||
|
||||
/* overlay */
|
||||
struct intel_overlay *overlay;
|
||||
bool sprite_scaling_enabled;
|
||||
unsigned int sprite_scaling_enabled;
|
||||
|
||||
/* LVDS info */
|
||||
int backlight_level; /* restore backlight to this value */
|
||||
@ -713,7 +943,6 @@ typedef struct drm_i915_private {
|
||||
unsigned int display_clock_mode:1;
|
||||
int lvds_ssc_freq;
|
||||
unsigned int bios_lvds_val; /* initial [PCH_]LVDS reg val in VBIOS */
|
||||
unsigned int lvds_val; /* used for checking LVDS channel mode */
|
||||
struct {
|
||||
int rate;
|
||||
int lanes;
|
||||
@ -734,11 +963,6 @@ typedef struct drm_i915_private {
|
||||
|
||||
unsigned int fsb_freq, mem_freq, is_ddr3;
|
||||
|
||||
spinlock_t error_lock;
|
||||
/* Protected by dev->error_lock. */
|
||||
struct drm_i915_error_state *first_error;
|
||||
struct work_struct error_work;
|
||||
struct completion error_completion;
|
||||
struct workqueue_struct *wq;
|
||||
|
||||
/* Display functions */
|
||||
@ -750,115 +974,12 @@ typedef struct drm_i915_private {
|
||||
|
||||
unsigned long quirks;
|
||||
|
||||
/* Register state */
|
||||
bool modeset_on_lid;
|
||||
enum modeset_restore modeset_restore;
|
||||
struct mutex modeset_restore_lock;
|
||||
|
||||
struct {
|
||||
/** Bridge to intel-gtt-ko */
|
||||
struct intel_gtt *gtt;
|
||||
/** Memory allocator for GTT stolen memory */
|
||||
struct drm_mm stolen;
|
||||
/** Memory allocator for GTT */
|
||||
struct drm_mm gtt_space;
|
||||
/** List of all objects in gtt_space. Used to restore gtt
|
||||
* mappings on resume */
|
||||
struct list_head bound_list;
|
||||
/**
|
||||
* List of objects which are not bound to the GTT (thus
|
||||
* are idle and not used by the GPU) but still have
|
||||
* (presumably uncached) pages still attached.
|
||||
*/
|
||||
struct list_head unbound_list;
|
||||
struct i915_gtt gtt;
|
||||
|
||||
/** Usable portion of the GTT for GEM */
|
||||
unsigned long gtt_start;
|
||||
unsigned long gtt_mappable_end;
|
||||
unsigned long gtt_end;
|
||||
|
||||
struct io_mapping *gtt_mapping;
|
||||
phys_addr_t gtt_base_addr;
|
||||
int gtt_mtrr;
|
||||
|
||||
/** PPGTT used for aliasing the PPGTT with the GTT */
|
||||
struct i915_hw_ppgtt *aliasing_ppgtt;
|
||||
|
||||
struct shrinker inactive_shrinker;
|
||||
bool shrinker_no_lock_stealing;
|
||||
|
||||
/**
|
||||
* List of objects currently involved in rendering.
|
||||
*
|
||||
* Includes buffers having the contents of their GPU caches
|
||||
* flushed, not necessarily primitives. last_rendering_seqno
|
||||
* represents when the rendering involved will be completed.
|
||||
*
|
||||
* A reference is held on the buffer while on this list.
|
||||
*/
|
||||
struct list_head active_list;
|
||||
|
||||
/**
|
||||
* LRU list of objects which are not in the ringbuffer and
|
||||
* are ready to unbind, but are still in the GTT.
|
||||
*
|
||||
* last_rendering_seqno is 0 while an object is in this list.
|
||||
*
|
||||
* A reference is not held on the buffer while on this list,
|
||||
* as merely being GTT-bound shouldn't prevent its being
|
||||
* freed, and we'll pull it off the list in the free path.
|
||||
*/
|
||||
struct list_head inactive_list;
|
||||
|
||||
/** LRU list of objects with fence regs on them. */
|
||||
struct list_head fence_list;
|
||||
|
||||
/**
|
||||
* We leave the user IRQ off as much as possible,
|
||||
* but this means that requests will finish and never
|
||||
* be retired once the system goes idle. Set a timer to
|
||||
* fire periodically while the ring is running. When it
|
||||
* fires, go retire requests.
|
||||
*/
|
||||
struct delayed_work retire_work;
|
||||
|
||||
/**
|
||||
* Are we in a non-interruptible section of code like
|
||||
* modesetting?
|
||||
*/
|
||||
bool interruptible;
|
||||
|
||||
/**
|
||||
* Flag if the X Server, and thus DRM, is not currently in
|
||||
* control of the device.
|
||||
*
|
||||
* This is set between LeaveVT and EnterVT. It needs to be
|
||||
* replaced with a semaphore. It also needs to be
|
||||
* transitioned away from for kernel modesetting.
|
||||
*/
|
||||
int suspended;
|
||||
|
||||
/**
|
||||
* Flag if the hardware appears to be wedged.
|
||||
*
|
||||
* This is set when attempts to idle the device timeout.
|
||||
* It prevents command submission from occurring and makes
|
||||
* every pending request fail
|
||||
*/
|
||||
atomic_t wedged;
|
||||
|
||||
/** Bit 6 swizzling required for X tiling */
|
||||
uint32_t bit_6_swizzle_x;
|
||||
/** Bit 6 swizzling required for Y tiling */
|
||||
uint32_t bit_6_swizzle_y;
|
||||
|
||||
/* storage for physical objects */
|
||||
struct drm_i915_gem_phys_object *phys_objs[I915_MAX_PHYS_OBJECT];
|
||||
|
||||
/* accounting, useful for userland debugging */
|
||||
size_t gtt_total;
|
||||
size_t mappable_gtt_total;
|
||||
size_t object_memory;
|
||||
u32 object_count;
|
||||
} mm;
|
||||
struct i915_gem_mm mm;
|
||||
|
||||
/* Kernel Modesetting */
|
||||
|
||||
@ -900,7 +1021,7 @@ typedef struct drm_i915_private {
|
||||
struct drm_mm_node *compressed_fb;
|
||||
struct drm_mm_node *compressed_llb;
|
||||
|
||||
unsigned long last_gpu_reset;
|
||||
struct i915_gpu_error gpu_error;
|
||||
|
||||
/* list of fbdev register on this device */
|
||||
struct intel_fbdev *fbdev;
|
||||
@ -919,7 +1040,7 @@ typedef struct drm_i915_private {
|
||||
bool hw_contexts_disabled;
|
||||
uint32_t hw_context_size;
|
||||
|
||||
bool fdi_rx_polarity_reversed;
|
||||
u32 fdi_rx_config;
|
||||
|
||||
struct i915_suspend_saved_registers regfile;
|
||||
|
||||
@ -940,11 +1061,7 @@ enum hdmi_force_audio {
|
||||
HDMI_AUDIO_ON, /* force turn on HDMI audio */
|
||||
};
|
||||
|
||||
enum i915_cache_level {
|
||||
I915_CACHE_NONE = 0,
|
||||
I915_CACHE_LLC,
|
||||
I915_CACHE_LLC_MLC, /* gen6+, in docs at least! */
|
||||
};
|
||||
#define I915_GTT_RESERVED ((struct drm_mm_node *)0x1)
|
||||
|
||||
struct drm_i915_gem_object_ops {
|
||||
/* Interface between the GEM object and its backing storage.
|
||||
@ -971,6 +1088,8 @@ struct drm_i915_gem_object {
|
||||
|
||||
/** Current space allocated to this object in the GTT, if any. */
|
||||
struct drm_mm_node *gtt_space;
|
||||
/** Stolen memory for this object, instead of being backed by shmem. */
|
||||
struct drm_mm_node *stolen;
|
||||
struct list_head gtt_list;
|
||||
|
||||
/** This object's place on the active/inactive lists */
|
||||
@ -1096,13 +1215,6 @@ struct drm_i915_gem_object {
|
||||
|
||||
/** for phy allocated objects */
|
||||
struct drm_i915_gem_phys_object *phys_obj;
|
||||
|
||||
/**
|
||||
* Number of crtcs where this object is currently the fb, but
|
||||
* will be page flipped away on the next vblank. When it
|
||||
* reaches 0, dev_priv->pending_flip_queue will be woken up.
|
||||
*/
|
||||
atomic_t pending_flip;
|
||||
};
|
||||
#define to_gem_object(obj) (&((struct drm_i915_gem_object *)(obj))->base)
|
||||
|
||||
@ -1141,7 +1253,7 @@ struct drm_i915_gem_request {
|
||||
|
||||
struct drm_i915_file_private {
|
||||
struct {
|
||||
struct spinlock lock;
|
||||
spinlock_t lock;
|
||||
struct list_head request_list;
|
||||
} mm;
|
||||
struct idr context_idr;
|
||||
@ -1227,6 +1339,8 @@ struct drm_i915_file_private {
|
||||
|
||||
#define HAS_PIPE_CONTROL(dev) (INTEL_INFO(dev)->gen >= 5)
|
||||
|
||||
#define HAS_DDI(dev) (IS_HASWELL(dev))
|
||||
|
||||
#define INTEL_PCH_DEVICE_ID_MASK 0xff00
|
||||
#define INTEL_PCH_IBX_DEVICE_ID_TYPE 0x3b00
|
||||
#define INTEL_PCH_CPT_DEVICE_ID_TYPE 0x1c00
|
||||
@ -1323,6 +1437,7 @@ void i915_hangcheck_elapsed(unsigned long data);
|
||||
void i915_handle_error(struct drm_device *dev, bool wedged);
|
||||
|
||||
extern void intel_irq_init(struct drm_device *dev);
|
||||
extern void intel_hpd_init(struct drm_device *dev);
|
||||
extern void intel_gt_init(struct drm_device *dev);
|
||||
extern void intel_gt_reset(struct drm_device *dev);
|
||||
|
||||
@ -1391,18 +1506,22 @@ int i915_gem_get_aperture_ioctl(struct drm_device *dev, void *data,
|
||||
int i915_gem_wait_ioctl(struct drm_device *dev, void *data,
|
||||
struct drm_file *file_priv);
|
||||
void i915_gem_load(struct drm_device *dev);
|
||||
void *i915_gem_object_alloc(struct drm_device *dev);
|
||||
void i915_gem_object_free(struct drm_i915_gem_object *obj);
|
||||
int i915_gem_init_object(struct drm_gem_object *obj);
|
||||
void i915_gem_object_init(struct drm_i915_gem_object *obj,
|
||||
const struct drm_i915_gem_object_ops *ops);
|
||||
struct drm_i915_gem_object *i915_gem_alloc_object(struct drm_device *dev,
|
||||
size_t size);
|
||||
void i915_gem_free_object(struct drm_gem_object *obj);
|
||||
|
||||
int __must_check i915_gem_object_pin(struct drm_i915_gem_object *obj,
|
||||
uint32_t alignment,
|
||||
bool map_and_fenceable,
|
||||
bool nonblocking);
|
||||
void i915_gem_object_unpin(struct drm_i915_gem_object *obj);
|
||||
int __must_check i915_gem_object_unbind(struct drm_i915_gem_object *obj);
|
||||
int i915_gem_object_put_pages(struct drm_i915_gem_object *obj);
|
||||
void i915_gem_release_mmap(struct drm_i915_gem_object *obj);
|
||||
void i915_gem_lastclose(struct drm_device *dev);
|
||||
|
||||
@ -1454,8 +1573,8 @@ i915_seqno_passed(uint32_t seq1, uint32_t seq2)
|
||||
return (int32_t)(seq1 - seq2) >= 0;
|
||||
}
|
||||
|
||||
extern int i915_gem_get_seqno(struct drm_device *dev, u32 *seqno);
|
||||
|
||||
int __must_check i915_gem_get_seqno(struct drm_device *dev, u32 *seqno);
|
||||
int __must_check i915_gem_set_seqno(struct drm_device *dev, u32 seqno);
|
||||
int __must_check i915_gem_object_get_fence(struct drm_i915_gem_object *obj);
|
||||
int __must_check i915_gem_object_put_fence(struct drm_i915_gem_object *obj);
|
||||
|
||||
@ -1481,8 +1600,18 @@ i915_gem_object_unpin_fence(struct drm_i915_gem_object *obj)
|
||||
|
||||
void i915_gem_retire_requests(struct drm_device *dev);
|
||||
void i915_gem_retire_requests_ring(struct intel_ring_buffer *ring);
|
||||
int __must_check i915_gem_check_wedge(struct drm_i915_private *dev_priv,
|
||||
int __must_check i915_gem_check_wedge(struct i915_gpu_error *error,
|
||||
bool interruptible);
|
||||
static inline bool i915_reset_in_progress(struct i915_gpu_error *error)
|
||||
{
|
||||
return unlikely(atomic_read(&error->reset_counter)
|
||||
& I915_RESET_IN_PROGRESS_FLAG);
|
||||
}
|
||||
|
||||
static inline bool i915_terminally_wedged(struct i915_gpu_error *error)
|
||||
{
|
||||
return atomic_read(&error->reset_counter) == I915_WEDGED;
|
||||
}
|
||||
|
||||
void i915_gem_reset(struct drm_device *dev);
|
||||
void i915_gem_clflush_object(struct drm_i915_gem_object *obj);
|
||||
@ -1523,9 +1652,10 @@ void i915_gem_free_all_phys_object(struct drm_device *dev);
|
||||
void i915_gem_release(struct drm_device *dev, struct drm_file *file);
|
||||
|
||||
uint32_t
|
||||
i915_gem_get_unfenced_gtt_alignment(struct drm_device *dev,
|
||||
uint32_t size,
|
||||
int tiling_mode);
|
||||
i915_gem_get_gtt_size(struct drm_device *dev, uint32_t size, int tiling_mode);
|
||||
uint32_t
|
||||
i915_gem_get_gtt_alignment(struct drm_device *dev, uint32_t size,
|
||||
int tiling_mode, bool fenced);
|
||||
|
||||
int i915_gem_object_set_cache_level(struct drm_i915_gem_object *obj,
|
||||
enum i915_cache_level cache_level);
|
||||
@ -1548,7 +1678,6 @@ int i915_gem_context_destroy_ioctl(struct drm_device *dev, void *data,
|
||||
struct drm_file *file);
|
||||
|
||||
/* i915_gem_gtt.c */
|
||||
int __must_check i915_gem_init_aliasing_ppgtt(struct drm_device *dev);
|
||||
void i915_gem_cleanup_aliasing_ppgtt(struct drm_device *dev);
|
||||
void i915_ppgtt_bind_object(struct i915_hw_ppgtt *ppgtt,
|
||||
struct drm_i915_gem_object *obj,
|
||||
@ -1562,12 +1691,10 @@ void i915_gem_gtt_bind_object(struct drm_i915_gem_object *obj,
|
||||
enum i915_cache_level cache_level);
|
||||
void i915_gem_gtt_unbind_object(struct drm_i915_gem_object *obj);
|
||||
void i915_gem_gtt_finish_object(struct drm_i915_gem_object *obj);
|
||||
void i915_gem_init_global_gtt(struct drm_device *dev,
|
||||
unsigned long start,
|
||||
unsigned long mappable_end,
|
||||
unsigned long end);
|
||||
void i915_gem_init_global_gtt(struct drm_device *dev);
|
||||
void i915_gem_setup_global_gtt(struct drm_device *dev, unsigned long start,
|
||||
unsigned long mappable_end, unsigned long end);
|
||||
int i915_gem_gtt_init(struct drm_device *dev);
|
||||
void i915_gem_gtt_fini(struct drm_device *dev);
|
||||
static inline void i915_gem_chipset_flush(struct drm_device *dev)
|
||||
{
|
||||
if (INTEL_INFO(dev)->gen < 6)
|
||||
@ -1585,9 +1712,22 @@ int i915_gem_evict_everything(struct drm_device *dev);
|
||||
|
||||
/* i915_gem_stolen.c */
|
||||
int i915_gem_init_stolen(struct drm_device *dev);
|
||||
int i915_gem_stolen_setup_compression(struct drm_device *dev, int size);
|
||||
void i915_gem_stolen_cleanup_compression(struct drm_device *dev);
|
||||
void i915_gem_cleanup_stolen(struct drm_device *dev);
|
||||
struct drm_i915_gem_object *
|
||||
i915_gem_object_create_stolen(struct drm_device *dev, u32 size);
|
||||
void i915_gem_object_release_stolen(struct drm_i915_gem_object *obj);
|
||||
|
||||
/* i915_gem_tiling.c */
|
||||
inline static bool i915_gem_object_needs_bit17_swizzle(struct drm_i915_gem_object *obj)
|
||||
{
|
||||
drm_i915_private_t *dev_priv = obj->base.dev->dev_private;
|
||||
|
||||
return dev_priv->mm.bit_6_swizzle_x == I915_BIT_6_SWIZZLE_9_10_17 &&
|
||||
obj->tiling_mode != I915_TILING_NONE;
|
||||
}
|
||||
|
||||
void i915_gem_detect_bit_6_swizzle(struct drm_device *dev);
|
||||
void i915_gem_object_do_bit_17_swizzle(struct drm_i915_gem_object *obj);
|
||||
void i915_gem_object_save_bit_17_swizzle(struct drm_i915_gem_object *obj);
|
||||
@ -1613,9 +1753,9 @@ void i915_debugfs_cleanup(struct drm_minor *minor);
|
||||
extern int i915_save_state(struct drm_device *dev);
|
||||
extern int i915_restore_state(struct drm_device *dev);
|
||||
|
||||
/* i915_suspend.c */
|
||||
extern int i915_save_state(struct drm_device *dev);
|
||||
extern int i915_restore_state(struct drm_device *dev);
|
||||
/* i915_ums.c */
|
||||
void i915_save_display_reg(struct drm_device *dev);
|
||||
void i915_restore_display_reg(struct drm_device *dev);
|
||||
|
||||
/* i915_sysfs.c */
|
||||
void i915_setup_sysfs(struct drm_device *dev_priv);
|
||||
@ -1672,6 +1812,7 @@ extern void intel_modeset_cleanup(struct drm_device *dev);
|
||||
extern int intel_modeset_vga_set_state(struct drm_device *dev, bool state);
|
||||
extern void intel_modeset_setup_hw_state(struct drm_device *dev,
|
||||
bool force_restore);
|
||||
extern void i915_redisable_vga(struct drm_device *dev);
|
||||
extern bool intel_fbc_enabled(struct drm_device *dev);
|
||||
extern void intel_disable_fbc(struct drm_device *dev);
|
||||
extern bool ironlake_set_drps(struct drm_device *dev, u8 val);
|
||||
@ -1744,5 +1885,19 @@ __i915_write(64, q)
|
||||
#define POSTING_READ(reg) (void)I915_READ_NOTRACE(reg)
|
||||
#define POSTING_READ16(reg) (void)I915_READ16_NOTRACE(reg)
|
||||
|
||||
/* "Broadcast RGB" property */
|
||||
#define INTEL_BROADCAST_RGB_AUTO 0
|
||||
#define INTEL_BROADCAST_RGB_FULL 1
|
||||
#define INTEL_BROADCAST_RGB_LIMITED 2
|
||||
|
||||
static inline uint32_t i915_vgacntrl_reg(struct drm_device *dev)
|
||||
{
|
||||
if (HAS_PCH_SPLIT(dev))
|
||||
return CPU_VGACNTRL;
|
||||
else if (IS_VALLEYVIEW(dev))
|
||||
return VLV_VGACNTRL;
|
||||
else
|
||||
return VGACNTRL;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -126,13 +126,8 @@ static int get_context_size(struct drm_device *dev)
|
||||
|
||||
static void do_destroy(struct i915_hw_context *ctx)
|
||||
{
|
||||
struct drm_device *dev = ctx->obj->base.dev;
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
|
||||
if (ctx->file_priv)
|
||||
idr_remove(&ctx->file_priv->context_idr, ctx->id);
|
||||
else
|
||||
BUG_ON(ctx != dev_priv->ring[RCS].default_context);
|
||||
|
||||
drm_gem_object_unreference(&ctx->obj->base);
|
||||
kfree(ctx);
|
||||
@ -242,7 +237,6 @@ err_destroy:
|
||||
void i915_gem_context_init(struct drm_device *dev)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
uint32_t ctx_size;
|
||||
|
||||
if (!HAS_HW_CONTEXTS(dev)) {
|
||||
dev_priv->hw_contexts_disabled = true;
|
||||
@ -254,11 +248,9 @@ void i915_gem_context_init(struct drm_device *dev)
|
||||
dev_priv->ring[RCS].default_context)
|
||||
return;
|
||||
|
||||
ctx_size = get_context_size(dev);
|
||||
dev_priv->hw_context_size = get_context_size(dev);
|
||||
dev_priv->hw_context_size = round_up(dev_priv->hw_context_size, 4096);
|
||||
dev_priv->hw_context_size = round_up(get_context_size(dev), 4096);
|
||||
|
||||
if (ctx_size <= 0 || ctx_size > (1<<20)) {
|
||||
if (dev_priv->hw_context_size > (1<<20)) {
|
||||
dev_priv->hw_contexts_disabled = true;
|
||||
return;
|
||||
}
|
||||
|
@ -281,8 +281,7 @@ struct drm_gem_object *i915_gem_prime_import(struct drm_device *dev,
|
||||
if (IS_ERR(attach))
|
||||
return ERR_CAST(attach);
|
||||
|
||||
|
||||
obj = kzalloc(sizeof(*obj), GFP_KERNEL);
|
||||
obj = i915_gem_object_alloc(dev);
|
||||
if (obj == NULL) {
|
||||
ret = -ENOMEM;
|
||||
goto fail_detach;
|
||||
@ -290,7 +289,7 @@ struct drm_gem_object *i915_gem_prime_import(struct drm_device *dev,
|
||||
|
||||
ret = drm_gem_private_object_init(dev, &obj->base, dma_buf->size);
|
||||
if (ret) {
|
||||
kfree(obj);
|
||||
i915_gem_object_free(obj);
|
||||
goto fail_detach;
|
||||
}
|
||||
|
||||
|
@ -80,7 +80,7 @@ i915_gem_evict_something(struct drm_device *dev, int min_size,
|
||||
if (mappable)
|
||||
drm_mm_init_scan_with_range(&dev_priv->mm.gtt_space,
|
||||
min_size, alignment, cache_level,
|
||||
0, dev_priv->mm.gtt_mappable_end);
|
||||
0, dev_priv->gtt.mappable_end);
|
||||
else
|
||||
drm_mm_init_scan(&dev_priv->mm.gtt_space,
|
||||
min_size, alignment, cache_level);
|
||||
|
@ -34,61 +34,133 @@
|
||||
#include <linux/dma_remapping.h>
|
||||
|
||||
struct eb_objects {
|
||||
struct list_head objects;
|
||||
int and;
|
||||
struct hlist_head buckets[0];
|
||||
union {
|
||||
struct drm_i915_gem_object *lut[0];
|
||||
struct hlist_head buckets[0];
|
||||
};
|
||||
};
|
||||
|
||||
static struct eb_objects *
|
||||
eb_create(int size)
|
||||
eb_create(struct drm_i915_gem_execbuffer2 *args)
|
||||
{
|
||||
struct eb_objects *eb;
|
||||
int count = PAGE_SIZE / sizeof(struct hlist_head) / 2;
|
||||
BUILD_BUG_ON(!is_power_of_2(PAGE_SIZE / sizeof(struct hlist_head)));
|
||||
while (count > size)
|
||||
count >>= 1;
|
||||
eb = kzalloc(count*sizeof(struct hlist_head) +
|
||||
sizeof(struct eb_objects),
|
||||
GFP_KERNEL);
|
||||
if (eb == NULL)
|
||||
return eb;
|
||||
struct eb_objects *eb = NULL;
|
||||
|
||||
eb->and = count - 1;
|
||||
if (args->flags & I915_EXEC_HANDLE_LUT) {
|
||||
int size = args->buffer_count;
|
||||
size *= sizeof(struct drm_i915_gem_object *);
|
||||
size += sizeof(struct eb_objects);
|
||||
eb = kmalloc(size, GFP_TEMPORARY | __GFP_NOWARN | __GFP_NORETRY);
|
||||
}
|
||||
|
||||
if (eb == NULL) {
|
||||
int size = args->buffer_count;
|
||||
int count = PAGE_SIZE / sizeof(struct hlist_head) / 2;
|
||||
BUILD_BUG_ON(!is_power_of_2(PAGE_SIZE / sizeof(struct hlist_head)));
|
||||
while (count > 2*size)
|
||||
count >>= 1;
|
||||
eb = kzalloc(count*sizeof(struct hlist_head) +
|
||||
sizeof(struct eb_objects),
|
||||
GFP_TEMPORARY);
|
||||
if (eb == NULL)
|
||||
return eb;
|
||||
|
||||
eb->and = count - 1;
|
||||
} else
|
||||
eb->and = -args->buffer_count;
|
||||
|
||||
INIT_LIST_HEAD(&eb->objects);
|
||||
return eb;
|
||||
}
|
||||
|
||||
static void
|
||||
eb_reset(struct eb_objects *eb)
|
||||
{
|
||||
memset(eb->buckets, 0, (eb->and+1)*sizeof(struct hlist_head));
|
||||
if (eb->and >= 0)
|
||||
memset(eb->buckets, 0, (eb->and+1)*sizeof(struct hlist_head));
|
||||
}
|
||||
|
||||
static void
|
||||
eb_add_object(struct eb_objects *eb, struct drm_i915_gem_object *obj)
|
||||
static int
|
||||
eb_lookup_objects(struct eb_objects *eb,
|
||||
struct drm_i915_gem_exec_object2 *exec,
|
||||
const struct drm_i915_gem_execbuffer2 *args,
|
||||
struct drm_file *file)
|
||||
{
|
||||
hlist_add_head(&obj->exec_node,
|
||||
&eb->buckets[obj->exec_handle & eb->and]);
|
||||
int i;
|
||||
|
||||
spin_lock(&file->table_lock);
|
||||
for (i = 0; i < args->buffer_count; i++) {
|
||||
struct drm_i915_gem_object *obj;
|
||||
|
||||
obj = to_intel_bo(idr_find(&file->object_idr, exec[i].handle));
|
||||
if (obj == NULL) {
|
||||
spin_unlock(&file->table_lock);
|
||||
DRM_DEBUG("Invalid object handle %d at index %d\n",
|
||||
exec[i].handle, i);
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
if (!list_empty(&obj->exec_list)) {
|
||||
spin_unlock(&file->table_lock);
|
||||
DRM_DEBUG("Object %p [handle %d, index %d] appears more than once in object list\n",
|
||||
obj, exec[i].handle, i);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
drm_gem_object_reference(&obj->base);
|
||||
list_add_tail(&obj->exec_list, &eb->objects);
|
||||
|
||||
obj->exec_entry = &exec[i];
|
||||
if (eb->and < 0) {
|
||||
eb->lut[i] = obj;
|
||||
} else {
|
||||
uint32_t handle = args->flags & I915_EXEC_HANDLE_LUT ? i : exec[i].handle;
|
||||
obj->exec_handle = handle;
|
||||
hlist_add_head(&obj->exec_node,
|
||||
&eb->buckets[handle & eb->and]);
|
||||
}
|
||||
}
|
||||
spin_unlock(&file->table_lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct drm_i915_gem_object *
|
||||
eb_get_object(struct eb_objects *eb, unsigned long handle)
|
||||
{
|
||||
struct hlist_head *head;
|
||||
struct hlist_node *node;
|
||||
struct drm_i915_gem_object *obj;
|
||||
if (eb->and < 0) {
|
||||
if (handle >= -eb->and)
|
||||
return NULL;
|
||||
return eb->lut[handle];
|
||||
} else {
|
||||
struct hlist_head *head;
|
||||
struct hlist_node *node;
|
||||
|
||||
head = &eb->buckets[handle & eb->and];
|
||||
hlist_for_each(node, head) {
|
||||
obj = hlist_entry(node, struct drm_i915_gem_object, exec_node);
|
||||
if (obj->exec_handle == handle)
|
||||
return obj;
|
||||
head = &eb->buckets[handle & eb->and];
|
||||
hlist_for_each(node, head) {
|
||||
struct drm_i915_gem_object *obj;
|
||||
|
||||
obj = hlist_entry(node, struct drm_i915_gem_object, exec_node);
|
||||
if (obj->exec_handle == handle)
|
||||
return obj;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
eb_destroy(struct eb_objects *eb)
|
||||
{
|
||||
while (!list_empty(&eb->objects)) {
|
||||
struct drm_i915_gem_object *obj;
|
||||
|
||||
obj = list_first_entry(&eb->objects,
|
||||
struct drm_i915_gem_object,
|
||||
exec_list);
|
||||
list_del_init(&obj->exec_list);
|
||||
drm_gem_object_unreference(&obj->base);
|
||||
}
|
||||
kfree(eb);
|
||||
}
|
||||
|
||||
@ -150,17 +222,6 @@ i915_gem_execbuffer_relocate_entry(struct drm_i915_gem_object *obj,
|
||||
reloc->write_domain);
|
||||
return ret;
|
||||
}
|
||||
if (unlikely(reloc->write_domain && target_obj->pending_write_domain &&
|
||||
reloc->write_domain != target_obj->pending_write_domain)) {
|
||||
DRM_DEBUG("Write domain conflict: "
|
||||
"obj %p target %d offset %d "
|
||||
"new %08x old %08x\n",
|
||||
obj, reloc->target_handle,
|
||||
(int) reloc->offset,
|
||||
reloc->write_domain,
|
||||
target_obj->pending_write_domain);
|
||||
return ret;
|
||||
}
|
||||
|
||||
target_obj->pending_read_domains |= reloc->read_domains;
|
||||
target_obj->pending_write_domain |= reloc->write_domain;
|
||||
@ -220,7 +281,7 @@ i915_gem_execbuffer_relocate_entry(struct drm_i915_gem_object *obj,
|
||||
|
||||
/* Map the page containing the relocation we're going to perform. */
|
||||
reloc->offset += obj->gtt_offset;
|
||||
reloc_page = io_mapping_map_atomic_wc(dev_priv->mm.gtt_mapping,
|
||||
reloc_page = io_mapping_map_atomic_wc(dev_priv->gtt.mappable,
|
||||
reloc->offset & PAGE_MASK);
|
||||
reloc_entry = (uint32_t __iomem *)
|
||||
(reloc_page + (reloc->offset & ~PAGE_MASK));
|
||||
@ -299,8 +360,7 @@ i915_gem_execbuffer_relocate_object_slow(struct drm_i915_gem_object *obj,
|
||||
|
||||
static int
|
||||
i915_gem_execbuffer_relocate(struct drm_device *dev,
|
||||
struct eb_objects *eb,
|
||||
struct list_head *objects)
|
||||
struct eb_objects *eb)
|
||||
{
|
||||
struct drm_i915_gem_object *obj;
|
||||
int ret = 0;
|
||||
@ -313,7 +373,7 @@ i915_gem_execbuffer_relocate(struct drm_device *dev,
|
||||
* lockdep complains vehemently.
|
||||
*/
|
||||
pagefault_disable();
|
||||
list_for_each_entry(obj, objects, exec_list) {
|
||||
list_for_each_entry(obj, &eb->objects, exec_list) {
|
||||
ret = i915_gem_execbuffer_relocate_object(obj, eb);
|
||||
if (ret)
|
||||
break;
|
||||
@ -335,7 +395,8 @@ need_reloc_mappable(struct drm_i915_gem_object *obj)
|
||||
|
||||
static int
|
||||
i915_gem_execbuffer_reserve_object(struct drm_i915_gem_object *obj,
|
||||
struct intel_ring_buffer *ring)
|
||||
struct intel_ring_buffer *ring,
|
||||
bool *need_reloc)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = obj->base.dev->dev_private;
|
||||
struct drm_i915_gem_exec_object2 *entry = obj->exec_entry;
|
||||
@ -376,7 +437,20 @@ i915_gem_execbuffer_reserve_object(struct drm_i915_gem_object *obj,
|
||||
obj->has_aliasing_ppgtt_mapping = 1;
|
||||
}
|
||||
|
||||
entry->offset = obj->gtt_offset;
|
||||
if (entry->offset != obj->gtt_offset) {
|
||||
entry->offset = obj->gtt_offset;
|
||||
*need_reloc = true;
|
||||
}
|
||||
|
||||
if (entry->flags & EXEC_OBJECT_WRITE) {
|
||||
obj->base.pending_read_domains = I915_GEM_DOMAIN_RENDER;
|
||||
obj->base.pending_write_domain = I915_GEM_DOMAIN_RENDER;
|
||||
}
|
||||
|
||||
if (entry->flags & EXEC_OBJECT_NEEDS_GTT &&
|
||||
!obj->has_global_gtt_mapping)
|
||||
i915_gem_gtt_bind_object(obj, obj->cache_level);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -402,7 +476,8 @@ i915_gem_execbuffer_unreserve_object(struct drm_i915_gem_object *obj)
|
||||
static int
|
||||
i915_gem_execbuffer_reserve(struct intel_ring_buffer *ring,
|
||||
struct drm_file *file,
|
||||
struct list_head *objects)
|
||||
struct list_head *objects,
|
||||
bool *need_relocs)
|
||||
{
|
||||
struct drm_i915_gem_object *obj;
|
||||
struct list_head ordered_objects;
|
||||
@ -430,7 +505,7 @@ i915_gem_execbuffer_reserve(struct intel_ring_buffer *ring,
|
||||
else
|
||||
list_move_tail(&obj->exec_list, &ordered_objects);
|
||||
|
||||
obj->base.pending_read_domains = 0;
|
||||
obj->base.pending_read_domains = I915_GEM_GPU_DOMAINS & ~I915_GEM_DOMAIN_COMMAND;
|
||||
obj->base.pending_write_domain = 0;
|
||||
obj->pending_fenced_gpu_access = false;
|
||||
}
|
||||
@ -470,7 +545,7 @@ i915_gem_execbuffer_reserve(struct intel_ring_buffer *ring,
|
||||
(need_mappable && !obj->map_and_fenceable))
|
||||
ret = i915_gem_object_unbind(obj);
|
||||
else
|
||||
ret = i915_gem_execbuffer_reserve_object(obj, ring);
|
||||
ret = i915_gem_execbuffer_reserve_object(obj, ring, need_relocs);
|
||||
if (ret)
|
||||
goto err;
|
||||
}
|
||||
@ -480,7 +555,7 @@ i915_gem_execbuffer_reserve(struct intel_ring_buffer *ring,
|
||||
if (obj->gtt_space)
|
||||
continue;
|
||||
|
||||
ret = i915_gem_execbuffer_reserve_object(obj, ring);
|
||||
ret = i915_gem_execbuffer_reserve_object(obj, ring, need_relocs);
|
||||
if (ret)
|
||||
goto err;
|
||||
}
|
||||
@ -500,21 +575,22 @@ err: /* Decrement pin count for bound objects */
|
||||
|
||||
static int
|
||||
i915_gem_execbuffer_relocate_slow(struct drm_device *dev,
|
||||
struct drm_i915_gem_execbuffer2 *args,
|
||||
struct drm_file *file,
|
||||
struct intel_ring_buffer *ring,
|
||||
struct list_head *objects,
|
||||
struct eb_objects *eb,
|
||||
struct drm_i915_gem_exec_object2 *exec,
|
||||
int count)
|
||||
struct drm_i915_gem_exec_object2 *exec)
|
||||
{
|
||||
struct drm_i915_gem_relocation_entry *reloc;
|
||||
struct drm_i915_gem_object *obj;
|
||||
bool need_relocs;
|
||||
int *reloc_offset;
|
||||
int i, total, ret;
|
||||
int count = args->buffer_count;
|
||||
|
||||
/* We may process another execbuffer during the unlock... */
|
||||
while (!list_empty(objects)) {
|
||||
obj = list_first_entry(objects,
|
||||
while (!list_empty(&eb->objects)) {
|
||||
obj = list_first_entry(&eb->objects,
|
||||
struct drm_i915_gem_object,
|
||||
exec_list);
|
||||
list_del_init(&obj->exec_list);
|
||||
@ -582,27 +658,16 @@ i915_gem_execbuffer_relocate_slow(struct drm_device *dev,
|
||||
|
||||
/* reacquire the objects */
|
||||
eb_reset(eb);
|
||||
for (i = 0; i < count; i++) {
|
||||
obj = to_intel_bo(drm_gem_object_lookup(dev, file,
|
||||
exec[i].handle));
|
||||
if (&obj->base == NULL) {
|
||||
DRM_DEBUG("Invalid object handle %d at index %d\n",
|
||||
exec[i].handle, i);
|
||||
ret = -ENOENT;
|
||||
goto err;
|
||||
}
|
||||
|
||||
list_add_tail(&obj->exec_list, objects);
|
||||
obj->exec_handle = exec[i].handle;
|
||||
obj->exec_entry = &exec[i];
|
||||
eb_add_object(eb, obj);
|
||||
}
|
||||
|
||||
ret = i915_gem_execbuffer_reserve(ring, file, objects);
|
||||
ret = eb_lookup_objects(eb, exec, args, file);
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
list_for_each_entry(obj, objects, exec_list) {
|
||||
need_relocs = (args->flags & I915_EXEC_NO_RELOC) == 0;
|
||||
ret = i915_gem_execbuffer_reserve(ring, file, &eb->objects, &need_relocs);
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
list_for_each_entry(obj, &eb->objects, exec_list) {
|
||||
int offset = obj->exec_entry - exec;
|
||||
ret = i915_gem_execbuffer_relocate_object_slow(obj, eb,
|
||||
reloc + reloc_offset[offset]);
|
||||
@ -622,45 +687,12 @@ err:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int
|
||||
i915_gem_execbuffer_wait_for_flips(struct intel_ring_buffer *ring, u32 flips)
|
||||
{
|
||||
u32 plane, flip_mask;
|
||||
int ret;
|
||||
|
||||
/* Check for any pending flips. As we only maintain a flip queue depth
|
||||
* of 1, we can simply insert a WAIT for the next display flip prior
|
||||
* to executing the batch and avoid stalling the CPU.
|
||||
*/
|
||||
|
||||
for (plane = 0; flips >> plane; plane++) {
|
||||
if (((flips >> plane) & 1) == 0)
|
||||
continue;
|
||||
|
||||
if (plane)
|
||||
flip_mask = MI_WAIT_FOR_PLANE_B_FLIP;
|
||||
else
|
||||
flip_mask = MI_WAIT_FOR_PLANE_A_FLIP;
|
||||
|
||||
ret = intel_ring_begin(ring, 2);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
intel_ring_emit(ring, MI_WAIT_FOR_EVENT | flip_mask);
|
||||
intel_ring_emit(ring, MI_NOOP);
|
||||
intel_ring_advance(ring);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
i915_gem_execbuffer_move_to_gpu(struct intel_ring_buffer *ring,
|
||||
struct list_head *objects)
|
||||
{
|
||||
struct drm_i915_gem_object *obj;
|
||||
uint32_t flush_domains = 0;
|
||||
uint32_t flips = 0;
|
||||
int ret;
|
||||
|
||||
list_for_each_entry(obj, objects, exec_list) {
|
||||
@ -671,18 +703,9 @@ i915_gem_execbuffer_move_to_gpu(struct intel_ring_buffer *ring,
|
||||
if (obj->base.write_domain & I915_GEM_DOMAIN_CPU)
|
||||
i915_gem_clflush_object(obj);
|
||||
|
||||
if (obj->base.pending_write_domain)
|
||||
flips |= atomic_read(&obj->pending_flip);
|
||||
|
||||
flush_domains |= obj->base.write_domain;
|
||||
}
|
||||
|
||||
if (flips) {
|
||||
ret = i915_gem_execbuffer_wait_for_flips(ring, flips);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (flush_domains & I915_GEM_DOMAIN_CPU)
|
||||
i915_gem_chipset_flush(ring->dev);
|
||||
|
||||
@ -698,6 +721,9 @@ i915_gem_execbuffer_move_to_gpu(struct intel_ring_buffer *ring,
|
||||
static bool
|
||||
i915_gem_check_execbuffer(struct drm_i915_gem_execbuffer2 *exec)
|
||||
{
|
||||
if (exec->flags & __I915_EXEC_UNKNOWN_FLAGS)
|
||||
return false;
|
||||
|
||||
return ((exec->batch_start_offset | exec->batch_len) & 0x7) == 0;
|
||||
}
|
||||
|
||||
@ -711,6 +737,9 @@ validate_exec_list(struct drm_i915_gem_exec_object2 *exec,
|
||||
char __user *ptr = (char __user *)(uintptr_t)exec[i].relocs_ptr;
|
||||
int length; /* limited by fault_in_pages_readable() */
|
||||
|
||||
if (exec[i].flags & __EXEC_OBJECT_UNKNOWN_FLAGS)
|
||||
return -EINVAL;
|
||||
|
||||
/* First check for malicious input causing overflow */
|
||||
if (exec[i].relocation_count >
|
||||
INT_MAX / sizeof(struct drm_i915_gem_relocation_entry))
|
||||
@ -718,9 +747,6 @@ validate_exec_list(struct drm_i915_gem_exec_object2 *exec,
|
||||
|
||||
length = exec[i].relocation_count *
|
||||
sizeof(struct drm_i915_gem_relocation_entry);
|
||||
if (!access_ok(VERIFY_READ, ptr, length))
|
||||
return -EFAULT;
|
||||
|
||||
/* we may also need to update the presumed offsets */
|
||||
if (!access_ok(VERIFY_WRITE, ptr, length))
|
||||
return -EFAULT;
|
||||
@ -742,8 +768,10 @@ i915_gem_execbuffer_move_to_active(struct list_head *objects,
|
||||
u32 old_read = obj->base.read_domains;
|
||||
u32 old_write = obj->base.write_domain;
|
||||
|
||||
obj->base.read_domains = obj->base.pending_read_domains;
|
||||
obj->base.write_domain = obj->base.pending_write_domain;
|
||||
if (obj->base.write_domain == 0)
|
||||
obj->base.pending_read_domains |= obj->base.read_domains;
|
||||
obj->base.read_domains = obj->base.pending_read_domains;
|
||||
obj->fenced_gpu_access = obj->pending_fenced_gpu_access;
|
||||
|
||||
i915_gem_object_move_to_active(obj, ring);
|
||||
@ -802,21 +830,18 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data,
|
||||
struct drm_i915_gem_exec_object2 *exec)
|
||||
{
|
||||
drm_i915_private_t *dev_priv = dev->dev_private;
|
||||
struct list_head objects;
|
||||
struct eb_objects *eb;
|
||||
struct drm_i915_gem_object *batch_obj;
|
||||
struct drm_clip_rect *cliprects = NULL;
|
||||
struct intel_ring_buffer *ring;
|
||||
u32 ctx_id = i915_execbuffer2_get_context_id(*args);
|
||||
u32 exec_start, exec_len;
|
||||
u32 mask;
|
||||
u32 flags;
|
||||
u32 mask, flags;
|
||||
int ret, mode, i;
|
||||
bool need_relocs;
|
||||
|
||||
if (!i915_gem_check_execbuffer(args)) {
|
||||
DRM_DEBUG("execbuf with invalid offset/length\n");
|
||||
if (!i915_gem_check_execbuffer(args))
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = validate_exec_list(exec, args->buffer_count);
|
||||
if (ret)
|
||||
@ -937,7 +962,7 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data,
|
||||
goto pre_mutex_err;
|
||||
}
|
||||
|
||||
eb = eb_create(args->buffer_count);
|
||||
eb = eb_create(args);
|
||||
if (eb == NULL) {
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
ret = -ENOMEM;
|
||||
@ -945,51 +970,28 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data,
|
||||
}
|
||||
|
||||
/* Look up object handles */
|
||||
INIT_LIST_HEAD(&objects);
|
||||
for (i = 0; i < args->buffer_count; i++) {
|
||||
struct drm_i915_gem_object *obj;
|
||||
|
||||
obj = to_intel_bo(drm_gem_object_lookup(dev, file,
|
||||
exec[i].handle));
|
||||
if (&obj->base == NULL) {
|
||||
DRM_DEBUG("Invalid object handle %d at index %d\n",
|
||||
exec[i].handle, i);
|
||||
/* prevent error path from reading uninitialized data */
|
||||
ret = -ENOENT;
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (!list_empty(&obj->exec_list)) {
|
||||
DRM_DEBUG("Object %p [handle %d, index %d] appears more than once in object list\n",
|
||||
obj, exec[i].handle, i);
|
||||
ret = -EINVAL;
|
||||
goto err;
|
||||
}
|
||||
|
||||
list_add_tail(&obj->exec_list, &objects);
|
||||
obj->exec_handle = exec[i].handle;
|
||||
obj->exec_entry = &exec[i];
|
||||
eb_add_object(eb, obj);
|
||||
}
|
||||
ret = eb_lookup_objects(eb, exec, args, file);
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
/* take note of the batch buffer before we might reorder the lists */
|
||||
batch_obj = list_entry(objects.prev,
|
||||
batch_obj = list_entry(eb->objects.prev,
|
||||
struct drm_i915_gem_object,
|
||||
exec_list);
|
||||
|
||||
/* Move the objects en-masse into the GTT, evicting if necessary. */
|
||||
ret = i915_gem_execbuffer_reserve(ring, file, &objects);
|
||||
need_relocs = (args->flags & I915_EXEC_NO_RELOC) == 0;
|
||||
ret = i915_gem_execbuffer_reserve(ring, file, &eb->objects, &need_relocs);
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
/* The objects are in their final locations, apply the relocations. */
|
||||
ret = i915_gem_execbuffer_relocate(dev, eb, &objects);
|
||||
if (need_relocs)
|
||||
ret = i915_gem_execbuffer_relocate(dev, eb);
|
||||
if (ret) {
|
||||
if (ret == -EFAULT) {
|
||||
ret = i915_gem_execbuffer_relocate_slow(dev, file, ring,
|
||||
&objects, eb,
|
||||
exec,
|
||||
args->buffer_count);
|
||||
ret = i915_gem_execbuffer_relocate_slow(dev, args, file, ring,
|
||||
eb, exec);
|
||||
BUG_ON(!mutex_is_locked(&dev->struct_mutex));
|
||||
}
|
||||
if (ret)
|
||||
@ -1011,7 +1013,7 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data,
|
||||
if (flags & I915_DISPATCH_SECURE && !batch_obj->has_global_gtt_mapping)
|
||||
i915_gem_gtt_bind_object(batch_obj, batch_obj->cache_level);
|
||||
|
||||
ret = i915_gem_execbuffer_move_to_gpu(ring, &objects);
|
||||
ret = i915_gem_execbuffer_move_to_gpu(ring, &eb->objects);
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
@ -1065,20 +1067,11 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data,
|
||||
|
||||
trace_i915_gem_ring_dispatch(ring, intel_ring_get_seqno(ring), flags);
|
||||
|
||||
i915_gem_execbuffer_move_to_active(&objects, ring);
|
||||
i915_gem_execbuffer_move_to_active(&eb->objects, ring);
|
||||
i915_gem_execbuffer_retire_commands(dev, file, ring);
|
||||
|
||||
err:
|
||||
eb_destroy(eb);
|
||||
while (!list_empty(&objects)) {
|
||||
struct drm_i915_gem_object *obj;
|
||||
|
||||
obj = list_first_entry(&objects,
|
||||
struct drm_i915_gem_object,
|
||||
exec_list);
|
||||
list_del_init(&obj->exec_list);
|
||||
drm_gem_object_unreference(&obj->base);
|
||||
}
|
||||
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
|
||||
@ -1187,7 +1180,7 @@ i915_gem_execbuffer2(struct drm_device *dev, void *data,
|
||||
}
|
||||
|
||||
exec2_list = kmalloc(sizeof(*exec2_list)*args->buffer_count,
|
||||
GFP_KERNEL | __GFP_NOWARN | __GFP_NORETRY);
|
||||
GFP_TEMPORARY | __GFP_NOWARN | __GFP_NORETRY);
|
||||
if (exec2_list == NULL)
|
||||
exec2_list = drm_malloc_ab(sizeof(*exec2_list),
|
||||
args->buffer_count);
|
||||
|
@ -44,9 +44,9 @@ typedef uint32_t gtt_pte_t;
|
||||
#define GEN6_PTE_CACHE_LLC_MLC (3 << 1)
|
||||
#define GEN6_PTE_ADDR_ENCODE(addr) GEN6_GTT_ADDR_ENCODE(addr)
|
||||
|
||||
static inline gtt_pte_t pte_encode(struct drm_device *dev,
|
||||
dma_addr_t addr,
|
||||
enum i915_cache_level level)
|
||||
static inline gtt_pte_t gen6_pte_encode(struct drm_device *dev,
|
||||
dma_addr_t addr,
|
||||
enum i915_cache_level level)
|
||||
{
|
||||
gtt_pte_t pte = GEN6_PTE_VALID;
|
||||
pte |= GEN6_PTE_ADDR_ENCODE(addr);
|
||||
@ -77,7 +77,7 @@ static inline gtt_pte_t pte_encode(struct drm_device *dev,
|
||||
}
|
||||
|
||||
/* PPGTT support for Sandybdrige/Gen6 and later */
|
||||
static void i915_ppgtt_clear_range(struct i915_hw_ppgtt *ppgtt,
|
||||
static void gen6_ppgtt_clear_range(struct i915_hw_ppgtt *ppgtt,
|
||||
unsigned first_entry,
|
||||
unsigned num_entries)
|
||||
{
|
||||
@ -87,8 +87,9 @@ static void i915_ppgtt_clear_range(struct i915_hw_ppgtt *ppgtt,
|
||||
unsigned first_pte = first_entry % I915_PPGTT_PT_ENTRIES;
|
||||
unsigned last_pte, i;
|
||||
|
||||
scratch_pte = pte_encode(ppgtt->dev, ppgtt->scratch_page_dma_addr,
|
||||
I915_CACHE_LLC);
|
||||
scratch_pte = gen6_pte_encode(ppgtt->dev,
|
||||
ppgtt->scratch_page_dma_addr,
|
||||
I915_CACHE_LLC);
|
||||
|
||||
while (num_entries) {
|
||||
last_pte = first_pte + num_entries;
|
||||
@ -108,116 +109,10 @@ static void i915_ppgtt_clear_range(struct i915_hw_ppgtt *ppgtt,
|
||||
}
|
||||
}
|
||||
|
||||
int i915_gem_init_aliasing_ppgtt(struct drm_device *dev)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
struct i915_hw_ppgtt *ppgtt;
|
||||
unsigned first_pd_entry_in_global_pt;
|
||||
int i;
|
||||
int ret = -ENOMEM;
|
||||
|
||||
/* ppgtt PDEs reside in the global gtt pagetable, which has 512*1024
|
||||
* entries. For aliasing ppgtt support we just steal them at the end for
|
||||
* now. */
|
||||
first_pd_entry_in_global_pt = dev_priv->mm.gtt->gtt_total_entries - I915_PPGTT_PD_ENTRIES;
|
||||
|
||||
ppgtt = kzalloc(sizeof(*ppgtt), GFP_KERNEL);
|
||||
if (!ppgtt)
|
||||
return ret;
|
||||
|
||||
ppgtt->dev = dev;
|
||||
ppgtt->num_pd_entries = I915_PPGTT_PD_ENTRIES;
|
||||
ppgtt->pt_pages = kzalloc(sizeof(struct page *)*ppgtt->num_pd_entries,
|
||||
GFP_KERNEL);
|
||||
if (!ppgtt->pt_pages)
|
||||
goto err_ppgtt;
|
||||
|
||||
for (i = 0; i < ppgtt->num_pd_entries; i++) {
|
||||
ppgtt->pt_pages[i] = alloc_page(GFP_KERNEL);
|
||||
if (!ppgtt->pt_pages[i])
|
||||
goto err_pt_alloc;
|
||||
}
|
||||
|
||||
if (dev_priv->mm.gtt->needs_dmar) {
|
||||
ppgtt->pt_dma_addr = kzalloc(sizeof(dma_addr_t)
|
||||
*ppgtt->num_pd_entries,
|
||||
GFP_KERNEL);
|
||||
if (!ppgtt->pt_dma_addr)
|
||||
goto err_pt_alloc;
|
||||
|
||||
for (i = 0; i < ppgtt->num_pd_entries; i++) {
|
||||
dma_addr_t pt_addr;
|
||||
|
||||
pt_addr = pci_map_page(dev->pdev, ppgtt->pt_pages[i],
|
||||
0, 4096,
|
||||
PCI_DMA_BIDIRECTIONAL);
|
||||
|
||||
if (pci_dma_mapping_error(dev->pdev,
|
||||
pt_addr)) {
|
||||
ret = -EIO;
|
||||
goto err_pd_pin;
|
||||
|
||||
}
|
||||
ppgtt->pt_dma_addr[i] = pt_addr;
|
||||
}
|
||||
}
|
||||
|
||||
ppgtt->scratch_page_dma_addr = dev_priv->mm.gtt->scratch_page_dma;
|
||||
|
||||
i915_ppgtt_clear_range(ppgtt, 0,
|
||||
ppgtt->num_pd_entries*I915_PPGTT_PT_ENTRIES);
|
||||
|
||||
ppgtt->pd_offset = (first_pd_entry_in_global_pt)*sizeof(gtt_pte_t);
|
||||
|
||||
dev_priv->mm.aliasing_ppgtt = ppgtt;
|
||||
|
||||
return 0;
|
||||
|
||||
err_pd_pin:
|
||||
if (ppgtt->pt_dma_addr) {
|
||||
for (i--; i >= 0; i--)
|
||||
pci_unmap_page(dev->pdev, ppgtt->pt_dma_addr[i],
|
||||
4096, PCI_DMA_BIDIRECTIONAL);
|
||||
}
|
||||
err_pt_alloc:
|
||||
kfree(ppgtt->pt_dma_addr);
|
||||
for (i = 0; i < ppgtt->num_pd_entries; i++) {
|
||||
if (ppgtt->pt_pages[i])
|
||||
__free_page(ppgtt->pt_pages[i]);
|
||||
}
|
||||
kfree(ppgtt->pt_pages);
|
||||
err_ppgtt:
|
||||
kfree(ppgtt);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void i915_gem_cleanup_aliasing_ppgtt(struct drm_device *dev)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
struct i915_hw_ppgtt *ppgtt = dev_priv->mm.aliasing_ppgtt;
|
||||
int i;
|
||||
|
||||
if (!ppgtt)
|
||||
return;
|
||||
|
||||
if (ppgtt->pt_dma_addr) {
|
||||
for (i = 0; i < ppgtt->num_pd_entries; i++)
|
||||
pci_unmap_page(dev->pdev, ppgtt->pt_dma_addr[i],
|
||||
4096, PCI_DMA_BIDIRECTIONAL);
|
||||
}
|
||||
|
||||
kfree(ppgtt->pt_dma_addr);
|
||||
for (i = 0; i < ppgtt->num_pd_entries; i++)
|
||||
__free_page(ppgtt->pt_pages[i]);
|
||||
kfree(ppgtt->pt_pages);
|
||||
kfree(ppgtt);
|
||||
}
|
||||
|
||||
static void i915_ppgtt_insert_sg_entries(struct i915_hw_ppgtt *ppgtt,
|
||||
const struct sg_table *pages,
|
||||
unsigned first_entry,
|
||||
enum i915_cache_level cache_level)
|
||||
static void gen6_ppgtt_insert_entries(struct i915_hw_ppgtt *ppgtt,
|
||||
struct sg_table *pages,
|
||||
unsigned first_entry,
|
||||
enum i915_cache_level cache_level)
|
||||
{
|
||||
gtt_pte_t *pt_vaddr;
|
||||
unsigned act_pd = first_entry / I915_PPGTT_PT_ENTRIES;
|
||||
@ -237,8 +132,8 @@ static void i915_ppgtt_insert_sg_entries(struct i915_hw_ppgtt *ppgtt,
|
||||
|
||||
for (j = first_pte; j < I915_PPGTT_PT_ENTRIES; j++) {
|
||||
page_addr = sg_dma_address(sg) + (m << PAGE_SHIFT);
|
||||
pt_vaddr[j] = pte_encode(ppgtt->dev, page_addr,
|
||||
cache_level);
|
||||
pt_vaddr[j] = gen6_pte_encode(ppgtt->dev, page_addr,
|
||||
cache_level);
|
||||
|
||||
/* grab the next page */
|
||||
if (++m == segment_len) {
|
||||
@ -258,22 +153,145 @@ static void i915_ppgtt_insert_sg_entries(struct i915_hw_ppgtt *ppgtt,
|
||||
}
|
||||
}
|
||||
|
||||
static void gen6_ppgtt_cleanup(struct i915_hw_ppgtt *ppgtt)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (ppgtt->pt_dma_addr) {
|
||||
for (i = 0; i < ppgtt->num_pd_entries; i++)
|
||||
pci_unmap_page(ppgtt->dev->pdev,
|
||||
ppgtt->pt_dma_addr[i],
|
||||
4096, PCI_DMA_BIDIRECTIONAL);
|
||||
}
|
||||
|
||||
kfree(ppgtt->pt_dma_addr);
|
||||
for (i = 0; i < ppgtt->num_pd_entries; i++)
|
||||
__free_page(ppgtt->pt_pages[i]);
|
||||
kfree(ppgtt->pt_pages);
|
||||
kfree(ppgtt);
|
||||
}
|
||||
|
||||
static int gen6_ppgtt_init(struct i915_hw_ppgtt *ppgtt)
|
||||
{
|
||||
struct drm_device *dev = ppgtt->dev;
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
unsigned first_pd_entry_in_global_pt;
|
||||
int i;
|
||||
int ret = -ENOMEM;
|
||||
|
||||
/* ppgtt PDEs reside in the global gtt pagetable, which has 512*1024
|
||||
* entries. For aliasing ppgtt support we just steal them at the end for
|
||||
* now. */
|
||||
first_pd_entry_in_global_pt =
|
||||
gtt_total_entries(dev_priv->gtt) - I915_PPGTT_PD_ENTRIES;
|
||||
|
||||
ppgtt->num_pd_entries = I915_PPGTT_PD_ENTRIES;
|
||||
ppgtt->clear_range = gen6_ppgtt_clear_range;
|
||||
ppgtt->insert_entries = gen6_ppgtt_insert_entries;
|
||||
ppgtt->cleanup = gen6_ppgtt_cleanup;
|
||||
ppgtt->pt_pages = kzalloc(sizeof(struct page *)*ppgtt->num_pd_entries,
|
||||
GFP_KERNEL);
|
||||
if (!ppgtt->pt_pages)
|
||||
return -ENOMEM;
|
||||
|
||||
for (i = 0; i < ppgtt->num_pd_entries; i++) {
|
||||
ppgtt->pt_pages[i] = alloc_page(GFP_KERNEL);
|
||||
if (!ppgtt->pt_pages[i])
|
||||
goto err_pt_alloc;
|
||||
}
|
||||
|
||||
ppgtt->pt_dma_addr = kzalloc(sizeof(dma_addr_t) *ppgtt->num_pd_entries,
|
||||
GFP_KERNEL);
|
||||
if (!ppgtt->pt_dma_addr)
|
||||
goto err_pt_alloc;
|
||||
|
||||
for (i = 0; i < ppgtt->num_pd_entries; i++) {
|
||||
dma_addr_t pt_addr;
|
||||
|
||||
pt_addr = pci_map_page(dev->pdev, ppgtt->pt_pages[i], 0, 4096,
|
||||
PCI_DMA_BIDIRECTIONAL);
|
||||
|
||||
if (pci_dma_mapping_error(dev->pdev, pt_addr)) {
|
||||
ret = -EIO;
|
||||
goto err_pd_pin;
|
||||
|
||||
}
|
||||
ppgtt->pt_dma_addr[i] = pt_addr;
|
||||
}
|
||||
|
||||
ppgtt->scratch_page_dma_addr = dev_priv->gtt.scratch_page_dma;
|
||||
|
||||
ppgtt->clear_range(ppgtt, 0,
|
||||
ppgtt->num_pd_entries*I915_PPGTT_PT_ENTRIES);
|
||||
|
||||
ppgtt->pd_offset = (first_pd_entry_in_global_pt)*sizeof(gtt_pte_t);
|
||||
|
||||
return 0;
|
||||
|
||||
err_pd_pin:
|
||||
if (ppgtt->pt_dma_addr) {
|
||||
for (i--; i >= 0; i--)
|
||||
pci_unmap_page(dev->pdev, ppgtt->pt_dma_addr[i],
|
||||
4096, PCI_DMA_BIDIRECTIONAL);
|
||||
}
|
||||
err_pt_alloc:
|
||||
kfree(ppgtt->pt_dma_addr);
|
||||
for (i = 0; i < ppgtt->num_pd_entries; i++) {
|
||||
if (ppgtt->pt_pages[i])
|
||||
__free_page(ppgtt->pt_pages[i]);
|
||||
}
|
||||
kfree(ppgtt->pt_pages);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int i915_gem_init_aliasing_ppgtt(struct drm_device *dev)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
struct i915_hw_ppgtt *ppgtt;
|
||||
int ret;
|
||||
|
||||
ppgtt = kzalloc(sizeof(*ppgtt), GFP_KERNEL);
|
||||
if (!ppgtt)
|
||||
return -ENOMEM;
|
||||
|
||||
ppgtt->dev = dev;
|
||||
|
||||
ret = gen6_ppgtt_init(ppgtt);
|
||||
if (ret)
|
||||
kfree(ppgtt);
|
||||
else
|
||||
dev_priv->mm.aliasing_ppgtt = ppgtt;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void i915_gem_cleanup_aliasing_ppgtt(struct drm_device *dev)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
struct i915_hw_ppgtt *ppgtt = dev_priv->mm.aliasing_ppgtt;
|
||||
|
||||
if (!ppgtt)
|
||||
return;
|
||||
|
||||
ppgtt->cleanup(ppgtt);
|
||||
}
|
||||
|
||||
void i915_ppgtt_bind_object(struct i915_hw_ppgtt *ppgtt,
|
||||
struct drm_i915_gem_object *obj,
|
||||
enum i915_cache_level cache_level)
|
||||
{
|
||||
i915_ppgtt_insert_sg_entries(ppgtt,
|
||||
obj->pages,
|
||||
obj->gtt_space->start >> PAGE_SHIFT,
|
||||
cache_level);
|
||||
ppgtt->insert_entries(ppgtt, obj->pages,
|
||||
obj->gtt_space->start >> PAGE_SHIFT,
|
||||
cache_level);
|
||||
}
|
||||
|
||||
void i915_ppgtt_unbind_object(struct i915_hw_ppgtt *ppgtt,
|
||||
struct drm_i915_gem_object *obj)
|
||||
{
|
||||
i915_ppgtt_clear_range(ppgtt,
|
||||
obj->gtt_space->start >> PAGE_SHIFT,
|
||||
obj->base.size >> PAGE_SHIFT);
|
||||
ppgtt->clear_range(ppgtt,
|
||||
obj->gtt_space->start >> PAGE_SHIFT,
|
||||
obj->base.size >> PAGE_SHIFT);
|
||||
}
|
||||
|
||||
void i915_gem_init_ppgtt(struct drm_device *dev)
|
||||
@ -282,7 +300,7 @@ void i915_gem_init_ppgtt(struct drm_device *dev)
|
||||
uint32_t pd_offset;
|
||||
struct intel_ring_buffer *ring;
|
||||
struct i915_hw_ppgtt *ppgtt = dev_priv->mm.aliasing_ppgtt;
|
||||
uint32_t __iomem *pd_addr;
|
||||
gtt_pte_t __iomem *pd_addr;
|
||||
uint32_t pd_entry;
|
||||
int i;
|
||||
|
||||
@ -290,15 +308,11 @@ void i915_gem_init_ppgtt(struct drm_device *dev)
|
||||
return;
|
||||
|
||||
|
||||
pd_addr = dev_priv->mm.gtt->gtt + ppgtt->pd_offset/sizeof(uint32_t);
|
||||
pd_addr = (gtt_pte_t __iomem*)dev_priv->gtt.gsm + ppgtt->pd_offset/sizeof(gtt_pte_t);
|
||||
for (i = 0; i < ppgtt->num_pd_entries; i++) {
|
||||
dma_addr_t pt_addr;
|
||||
|
||||
if (dev_priv->mm.gtt->needs_dmar)
|
||||
pt_addr = ppgtt->pt_dma_addr[i];
|
||||
else
|
||||
pt_addr = page_to_phys(ppgtt->pt_pages[i]);
|
||||
|
||||
pt_addr = ppgtt->pt_dma_addr[i];
|
||||
pd_entry = GEN6_PDE_ADDR_ENCODE(pt_addr);
|
||||
pd_entry |= GEN6_PDE_VALID;
|
||||
|
||||
@ -338,11 +352,27 @@ void i915_gem_init_ppgtt(struct drm_device *dev)
|
||||
}
|
||||
}
|
||||
|
||||
extern int intel_iommu_gfx_mapped;
|
||||
/* Certain Gen5 chipsets require require idling the GPU before
|
||||
* unmapping anything from the GTT when VT-d is enabled.
|
||||
*/
|
||||
static inline bool needs_idle_maps(struct drm_device *dev)
|
||||
{
|
||||
#ifdef CONFIG_INTEL_IOMMU
|
||||
/* Query intel_iommu to see if we need the workaround. Presumably that
|
||||
* was loaded first.
|
||||
*/
|
||||
if (IS_GEN5(dev) && IS_MOBILE(dev) && intel_iommu_gfx_mapped)
|
||||
return true;
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool do_idling(struct drm_i915_private *dev_priv)
|
||||
{
|
||||
bool ret = dev_priv->mm.interruptible;
|
||||
|
||||
if (unlikely(dev_priv->mm.gtt->do_idle_maps)) {
|
||||
if (unlikely(dev_priv->gtt.do_idle_maps)) {
|
||||
dev_priv->mm.interruptible = false;
|
||||
if (i915_gpu_idle(dev_priv->dev)) {
|
||||
DRM_ERROR("Couldn't idle GPU\n");
|
||||
@ -356,45 +386,18 @@ static bool do_idling(struct drm_i915_private *dev_priv)
|
||||
|
||||
static void undo_idling(struct drm_i915_private *dev_priv, bool interruptible)
|
||||
{
|
||||
if (unlikely(dev_priv->mm.gtt->do_idle_maps))
|
||||
if (unlikely(dev_priv->gtt.do_idle_maps))
|
||||
dev_priv->mm.interruptible = interruptible;
|
||||
}
|
||||
|
||||
|
||||
static void i915_ggtt_clear_range(struct drm_device *dev,
|
||||
unsigned first_entry,
|
||||
unsigned num_entries)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
gtt_pte_t scratch_pte;
|
||||
gtt_pte_t __iomem *gtt_base = dev_priv->mm.gtt->gtt + first_entry;
|
||||
const int max_entries = dev_priv->mm.gtt->gtt_total_entries - first_entry;
|
||||
int i;
|
||||
|
||||
if (INTEL_INFO(dev)->gen < 6) {
|
||||
intel_gtt_clear_range(first_entry, num_entries);
|
||||
return;
|
||||
}
|
||||
|
||||
if (WARN(num_entries > max_entries,
|
||||
"First entry = %d; Num entries = %d (max=%d)\n",
|
||||
first_entry, num_entries, max_entries))
|
||||
num_entries = max_entries;
|
||||
|
||||
scratch_pte = pte_encode(dev, dev_priv->mm.gtt->scratch_page_dma, I915_CACHE_LLC);
|
||||
for (i = 0; i < num_entries; i++)
|
||||
iowrite32(scratch_pte, >t_base[i]);
|
||||
readl(gtt_base);
|
||||
}
|
||||
|
||||
void i915_gem_restore_gtt_mappings(struct drm_device *dev)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
struct drm_i915_gem_object *obj;
|
||||
|
||||
/* First fill our portion of the GTT with scratch pages */
|
||||
i915_ggtt_clear_range(dev, dev_priv->mm.gtt_start / PAGE_SIZE,
|
||||
(dev_priv->mm.gtt_end - dev_priv->mm.gtt_start) / PAGE_SIZE);
|
||||
dev_priv->gtt.gtt_clear_range(dev, dev_priv->gtt.start / PAGE_SIZE,
|
||||
dev_priv->gtt.total / PAGE_SIZE);
|
||||
|
||||
list_for_each_entry(obj, &dev_priv->mm.bound_list, gtt_list) {
|
||||
i915_gem_clflush_object(obj);
|
||||
@ -423,16 +426,15 @@ int i915_gem_gtt_prepare_object(struct drm_i915_gem_object *obj)
|
||||
* within the global GTT as well as accessible by the GPU through the GMADR
|
||||
* mapped BAR (dev_priv->mm.gtt->gtt).
|
||||
*/
|
||||
static void gen6_ggtt_bind_object(struct drm_i915_gem_object *obj,
|
||||
enum i915_cache_level level)
|
||||
static void gen6_ggtt_insert_entries(struct drm_device *dev,
|
||||
struct sg_table *st,
|
||||
unsigned int first_entry,
|
||||
enum i915_cache_level level)
|
||||
{
|
||||
struct drm_device *dev = obj->base.dev;
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
struct sg_table *st = obj->pages;
|
||||
struct scatterlist *sg = st->sgl;
|
||||
const int first_entry = obj->gtt_space->start >> PAGE_SHIFT;
|
||||
const int max_entries = dev_priv->mm.gtt->gtt_total_entries - first_entry;
|
||||
gtt_pte_t __iomem *gtt_entries = dev_priv->mm.gtt->gtt + first_entry;
|
||||
gtt_pte_t __iomem *gtt_entries =
|
||||
(gtt_pte_t __iomem *)dev_priv->gtt.gsm + first_entry;
|
||||
int unused, i = 0;
|
||||
unsigned int len, m = 0;
|
||||
dma_addr_t addr;
|
||||
@ -441,14 +443,12 @@ static void gen6_ggtt_bind_object(struct drm_i915_gem_object *obj,
|
||||
len = sg_dma_len(sg) >> PAGE_SHIFT;
|
||||
for (m = 0; m < len; m++) {
|
||||
addr = sg_dma_address(sg) + (m << PAGE_SHIFT);
|
||||
iowrite32(pte_encode(dev, addr, level), >t_entries[i]);
|
||||
iowrite32(gen6_pte_encode(dev, addr, level),
|
||||
>t_entries[i]);
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
BUG_ON(i > max_entries);
|
||||
BUG_ON(i != obj->base.size / PAGE_SIZE);
|
||||
|
||||
/* XXX: This serves as a posting read to make sure that the PTE has
|
||||
* actually been updated. There is some concern that even though
|
||||
* registers and PTEs are within the same BAR that they are potentially
|
||||
@ -456,7 +456,8 @@ static void gen6_ggtt_bind_object(struct drm_i915_gem_object *obj,
|
||||
* hardware should work, we must keep this posting read for paranoia.
|
||||
*/
|
||||
if (i != 0)
|
||||
WARN_ON(readl(>t_entries[i-1]) != pte_encode(dev, addr, level));
|
||||
WARN_ON(readl(>t_entries[i-1])
|
||||
!= gen6_pte_encode(dev, addr, level));
|
||||
|
||||
/* This next bit makes the above posting read even more important. We
|
||||
* want to flush the TLBs only after we're certain all the PTE updates
|
||||
@ -466,28 +467,70 @@ static void gen6_ggtt_bind_object(struct drm_i915_gem_object *obj,
|
||||
POSTING_READ(GFX_FLSH_CNTL_GEN6);
|
||||
}
|
||||
|
||||
static void gen6_ggtt_clear_range(struct drm_device *dev,
|
||||
unsigned int first_entry,
|
||||
unsigned int num_entries)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
gtt_pte_t scratch_pte;
|
||||
gtt_pte_t __iomem *gtt_base = (gtt_pte_t __iomem *) dev_priv->gtt.gsm + first_entry;
|
||||
const int max_entries = gtt_total_entries(dev_priv->gtt) - first_entry;
|
||||
int i;
|
||||
|
||||
if (WARN(num_entries > max_entries,
|
||||
"First entry = %d; Num entries = %d (max=%d)\n",
|
||||
first_entry, num_entries, max_entries))
|
||||
num_entries = max_entries;
|
||||
|
||||
scratch_pte = gen6_pte_encode(dev, dev_priv->gtt.scratch_page_dma,
|
||||
I915_CACHE_LLC);
|
||||
for (i = 0; i < num_entries; i++)
|
||||
iowrite32(scratch_pte, >t_base[i]);
|
||||
readl(gtt_base);
|
||||
}
|
||||
|
||||
|
||||
static void i915_ggtt_insert_entries(struct drm_device *dev,
|
||||
struct sg_table *st,
|
||||
unsigned int pg_start,
|
||||
enum i915_cache_level cache_level)
|
||||
{
|
||||
unsigned int flags = (cache_level == I915_CACHE_NONE) ?
|
||||
AGP_USER_MEMORY : AGP_USER_CACHED_MEMORY;
|
||||
|
||||
intel_gtt_insert_sg_entries(st, pg_start, flags);
|
||||
|
||||
}
|
||||
|
||||
static void i915_ggtt_clear_range(struct drm_device *dev,
|
||||
unsigned int first_entry,
|
||||
unsigned int num_entries)
|
||||
{
|
||||
intel_gtt_clear_range(first_entry, num_entries);
|
||||
}
|
||||
|
||||
|
||||
void i915_gem_gtt_bind_object(struct drm_i915_gem_object *obj,
|
||||
enum i915_cache_level cache_level)
|
||||
{
|
||||
struct drm_device *dev = obj->base.dev;
|
||||
if (INTEL_INFO(dev)->gen < 6) {
|
||||
unsigned int flags = (cache_level == I915_CACHE_NONE) ?
|
||||
AGP_USER_MEMORY : AGP_USER_CACHED_MEMORY;
|
||||
intel_gtt_insert_sg_entries(obj->pages,
|
||||
obj->gtt_space->start >> PAGE_SHIFT,
|
||||
flags);
|
||||
} else {
|
||||
gen6_ggtt_bind_object(obj, cache_level);
|
||||
}
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
|
||||
dev_priv->gtt.gtt_insert_entries(dev, obj->pages,
|
||||
obj->gtt_space->start >> PAGE_SHIFT,
|
||||
cache_level);
|
||||
|
||||
obj->has_global_gtt_mapping = 1;
|
||||
}
|
||||
|
||||
void i915_gem_gtt_unbind_object(struct drm_i915_gem_object *obj)
|
||||
{
|
||||
i915_ggtt_clear_range(obj->base.dev,
|
||||
obj->gtt_space->start >> PAGE_SHIFT,
|
||||
obj->base.size >> PAGE_SHIFT);
|
||||
struct drm_device *dev = obj->base.dev;
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
|
||||
dev_priv->gtt.gtt_clear_range(obj->base.dev,
|
||||
obj->gtt_space->start >> PAGE_SHIFT,
|
||||
obj->base.size >> PAGE_SHIFT);
|
||||
|
||||
obj->has_global_gtt_mapping = 0;
|
||||
}
|
||||
@ -524,27 +567,101 @@ static void i915_gtt_color_adjust(struct drm_mm_node *node,
|
||||
*end -= 4096;
|
||||
}
|
||||
}
|
||||
|
||||
void i915_gem_init_global_gtt(struct drm_device *dev,
|
||||
unsigned long start,
|
||||
unsigned long mappable_end,
|
||||
unsigned long end)
|
||||
void i915_gem_setup_global_gtt(struct drm_device *dev,
|
||||
unsigned long start,
|
||||
unsigned long mappable_end,
|
||||
unsigned long end)
|
||||
{
|
||||
/* Let GEM Manage all of the aperture.
|
||||
*
|
||||
* However, leave one page at the end still bound to the scratch page.
|
||||
* There are a number of places where the hardware apparently prefetches
|
||||
* past the end of the object, and we've seen multiple hangs with the
|
||||
* GPU head pointer stuck in a batchbuffer bound at the last page of the
|
||||
* aperture. One page should be enough to keep any prefetching inside
|
||||
* of the aperture.
|
||||
*/
|
||||
drm_i915_private_t *dev_priv = dev->dev_private;
|
||||
struct drm_mm_node *entry;
|
||||
struct drm_i915_gem_object *obj;
|
||||
unsigned long hole_start, hole_end;
|
||||
|
||||
/* Substract the guard page ... */
|
||||
BUG_ON(mappable_end > end);
|
||||
|
||||
/* Subtract the guard page ... */
|
||||
drm_mm_init(&dev_priv->mm.gtt_space, start, end - start - PAGE_SIZE);
|
||||
if (!HAS_LLC(dev))
|
||||
dev_priv->mm.gtt_space.color_adjust = i915_gtt_color_adjust;
|
||||
|
||||
dev_priv->mm.gtt_start = start;
|
||||
dev_priv->mm.gtt_mappable_end = mappable_end;
|
||||
dev_priv->mm.gtt_end = end;
|
||||
dev_priv->mm.gtt_total = end - start;
|
||||
dev_priv->mm.mappable_gtt_total = min(end, mappable_end) - start;
|
||||
/* Mark any preallocated objects as occupied */
|
||||
list_for_each_entry(obj, &dev_priv->mm.bound_list, gtt_list) {
|
||||
DRM_DEBUG_KMS("reserving preallocated space: %x + %zx\n",
|
||||
obj->gtt_offset, obj->base.size);
|
||||
|
||||
/* ... but ensure that we clear the entire range. */
|
||||
i915_ggtt_clear_range(dev, start / PAGE_SIZE, (end-start) / PAGE_SIZE);
|
||||
BUG_ON(obj->gtt_space != I915_GTT_RESERVED);
|
||||
obj->gtt_space = drm_mm_create_block(&dev_priv->mm.gtt_space,
|
||||
obj->gtt_offset,
|
||||
obj->base.size,
|
||||
false);
|
||||
obj->has_global_gtt_mapping = 1;
|
||||
}
|
||||
|
||||
dev_priv->gtt.start = start;
|
||||
dev_priv->gtt.total = end - start;
|
||||
|
||||
/* Clear any non-preallocated blocks */
|
||||
drm_mm_for_each_hole(entry, &dev_priv->mm.gtt_space,
|
||||
hole_start, hole_end) {
|
||||
DRM_DEBUG_KMS("clearing unused GTT space: [%lx, %lx]\n",
|
||||
hole_start, hole_end);
|
||||
dev_priv->gtt.gtt_clear_range(dev, hole_start / PAGE_SIZE,
|
||||
(hole_end-hole_start) / PAGE_SIZE);
|
||||
}
|
||||
|
||||
/* And finally clear the reserved guard page */
|
||||
dev_priv->gtt.gtt_clear_range(dev, end / PAGE_SIZE - 1, 1);
|
||||
}
|
||||
|
||||
static bool
|
||||
intel_enable_ppgtt(struct drm_device *dev)
|
||||
{
|
||||
if (i915_enable_ppgtt >= 0)
|
||||
return i915_enable_ppgtt;
|
||||
|
||||
#ifdef CONFIG_INTEL_IOMMU
|
||||
/* Disable ppgtt on SNB if VT-d is on. */
|
||||
if (INTEL_INFO(dev)->gen == 6 && intel_iommu_gfx_mapped)
|
||||
return false;
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void i915_gem_init_global_gtt(struct drm_device *dev)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
unsigned long gtt_size, mappable_size;
|
||||
|
||||
gtt_size = dev_priv->gtt.total;
|
||||
mappable_size = dev_priv->gtt.mappable_end;
|
||||
|
||||
if (intel_enable_ppgtt(dev) && HAS_ALIASING_PPGTT(dev)) {
|
||||
int ret;
|
||||
/* PPGTT pdes are stolen from global gtt ptes, so shrink the
|
||||
* aperture accordingly when using aliasing ppgtt. */
|
||||
gtt_size -= I915_PPGTT_PD_ENTRIES*PAGE_SIZE;
|
||||
|
||||
i915_gem_setup_global_gtt(dev, 0, mappable_size, gtt_size);
|
||||
|
||||
ret = i915_gem_init_aliasing_ppgtt(dev);
|
||||
if (!ret)
|
||||
return;
|
||||
|
||||
DRM_ERROR("Aliased PPGTT setup failed %d\n", ret);
|
||||
drm_mm_takedown(&dev_priv->mm.gtt_space);
|
||||
gtt_size += I915_PPGTT_PD_ENTRIES*PAGE_SIZE;
|
||||
}
|
||||
i915_gem_setup_global_gtt(dev, 0, mappable_size, gtt_size);
|
||||
}
|
||||
|
||||
static int setup_scratch_page(struct drm_device *dev)
|
||||
@ -567,8 +684,8 @@ static int setup_scratch_page(struct drm_device *dev)
|
||||
#else
|
||||
dma_addr = page_to_phys(page);
|
||||
#endif
|
||||
dev_priv->mm.gtt->scratch_page = page;
|
||||
dev_priv->mm.gtt->scratch_page_dma = dma_addr;
|
||||
dev_priv->gtt.scratch_page = page;
|
||||
dev_priv->gtt.scratch_page_dma = dma_addr;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -576,11 +693,11 @@ static int setup_scratch_page(struct drm_device *dev)
|
||||
static void teardown_scratch_page(struct drm_device *dev)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
set_pages_wb(dev_priv->mm.gtt->scratch_page, 1);
|
||||
pci_unmap_page(dev->pdev, dev_priv->mm.gtt->scratch_page_dma,
|
||||
set_pages_wb(dev_priv->gtt.scratch_page, 1);
|
||||
pci_unmap_page(dev->pdev, dev_priv->gtt.scratch_page_dma,
|
||||
PAGE_SIZE, PCI_DMA_BIDIRECTIONAL);
|
||||
put_page(dev_priv->mm.gtt->scratch_page);
|
||||
__free_page(dev_priv->mm.gtt->scratch_page);
|
||||
put_page(dev_priv->gtt.scratch_page);
|
||||
__free_page(dev_priv->gtt.scratch_page);
|
||||
}
|
||||
|
||||
static inline unsigned int gen6_get_total_gtt_size(u16 snb_gmch_ctl)
|
||||
@ -590,14 +707,14 @@ static inline unsigned int gen6_get_total_gtt_size(u16 snb_gmch_ctl)
|
||||
return snb_gmch_ctl << 20;
|
||||
}
|
||||
|
||||
static inline unsigned int gen6_get_stolen_size(u16 snb_gmch_ctl)
|
||||
static inline size_t gen6_get_stolen_size(u16 snb_gmch_ctl)
|
||||
{
|
||||
snb_gmch_ctl >>= SNB_GMCH_GMS_SHIFT;
|
||||
snb_gmch_ctl &= SNB_GMCH_GMS_MASK;
|
||||
return snb_gmch_ctl << 25; /* 32 MB units */
|
||||
}
|
||||
|
||||
static inline unsigned int gen7_get_stolen_size(u16 snb_gmch_ctl)
|
||||
static inline size_t gen7_get_stolen_size(u16 snb_gmch_ctl)
|
||||
{
|
||||
static const int stolen_decoder[] = {
|
||||
0, 0, 0, 0, 0, 32, 48, 64, 128, 256, 96, 160, 224, 352};
|
||||
@ -606,103 +723,127 @@ static inline unsigned int gen7_get_stolen_size(u16 snb_gmch_ctl)
|
||||
return stolen_decoder[snb_gmch_ctl] << 20;
|
||||
}
|
||||
|
||||
int i915_gem_gtt_init(struct drm_device *dev)
|
||||
static int gen6_gmch_probe(struct drm_device *dev,
|
||||
size_t *gtt_total,
|
||||
size_t *stolen,
|
||||
phys_addr_t *mappable_base,
|
||||
unsigned long *mappable_end)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
phys_addr_t gtt_bus_addr;
|
||||
unsigned int gtt_size;
|
||||
u16 snb_gmch_ctl;
|
||||
int ret;
|
||||
|
||||
/* On modern platforms we need not worry ourself with the legacy
|
||||
* hostbridge query stuff. Skip it entirely
|
||||
*mappable_base = pci_resource_start(dev->pdev, 2);
|
||||
*mappable_end = pci_resource_len(dev->pdev, 2);
|
||||
|
||||
/* 64/512MB is the current min/max we actually know of, but this is just
|
||||
* a coarse sanity check.
|
||||
*/
|
||||
if (INTEL_INFO(dev)->gen < 6) {
|
||||
ret = intel_gmch_probe(dev_priv->bridge_dev, dev->pdev, NULL);
|
||||
if (!ret) {
|
||||
DRM_ERROR("failed to set up gmch\n");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
dev_priv->mm.gtt = intel_gtt_get();
|
||||
if (!dev_priv->mm.gtt) {
|
||||
DRM_ERROR("Failed to initialize GTT\n");
|
||||
intel_gmch_remove();
|
||||
return -ENODEV;
|
||||
}
|
||||
return 0;
|
||||
if ((*mappable_end < (64<<20) || (*mappable_end > (512<<20)))) {
|
||||
DRM_ERROR("Unknown GMADR size (%lx)\n",
|
||||
dev_priv->gtt.mappable_end);
|
||||
return -ENXIO;
|
||||
}
|
||||
|
||||
dev_priv->mm.gtt = kzalloc(sizeof(*dev_priv->mm.gtt), GFP_KERNEL);
|
||||
if (!dev_priv->mm.gtt)
|
||||
return -ENOMEM;
|
||||
|
||||
if (!pci_set_dma_mask(dev->pdev, DMA_BIT_MASK(40)))
|
||||
pci_set_consistent_dma_mask(dev->pdev, DMA_BIT_MASK(40));
|
||||
pci_read_config_word(dev->pdev, SNB_GMCH_CTRL, &snb_gmch_ctl);
|
||||
gtt_size = gen6_get_total_gtt_size(snb_gmch_ctl);
|
||||
|
||||
#ifdef CONFIG_INTEL_IOMMU
|
||||
dev_priv->mm.gtt->needs_dmar = 1;
|
||||
#endif
|
||||
if (IS_GEN7(dev))
|
||||
*stolen = gen7_get_stolen_size(snb_gmch_ctl);
|
||||
else
|
||||
*stolen = gen6_get_stolen_size(snb_gmch_ctl);
|
||||
|
||||
*gtt_total = (gtt_size / sizeof(gtt_pte_t)) << PAGE_SHIFT;
|
||||
|
||||
/* For GEN6+ the PTEs for the ggtt live at 2MB + BAR0 */
|
||||
gtt_bus_addr = pci_resource_start(dev->pdev, 0) + (2<<20);
|
||||
dev_priv->mm.gtt->gma_bus_addr = pci_resource_start(dev->pdev, 2);
|
||||
|
||||
/* i9xx_setup */
|
||||
pci_read_config_word(dev->pdev, SNB_GMCH_CTRL, &snb_gmch_ctl);
|
||||
dev_priv->mm.gtt->gtt_total_entries =
|
||||
gen6_get_total_gtt_size(snb_gmch_ctl) / sizeof(gtt_pte_t);
|
||||
if (INTEL_INFO(dev)->gen < 7)
|
||||
dev_priv->mm.gtt->stolen_size = gen6_get_stolen_size(snb_gmch_ctl);
|
||||
else
|
||||
dev_priv->mm.gtt->stolen_size = gen7_get_stolen_size(snb_gmch_ctl);
|
||||
|
||||
dev_priv->mm.gtt->gtt_mappable_entries = pci_resource_len(dev->pdev, 2) >> PAGE_SHIFT;
|
||||
/* 64/512MB is the current min/max we actually know of, but this is just a
|
||||
* coarse sanity check.
|
||||
*/
|
||||
if ((dev_priv->mm.gtt->gtt_mappable_entries >> 8) < 64 ||
|
||||
dev_priv->mm.gtt->gtt_mappable_entries > dev_priv->mm.gtt->gtt_total_entries) {
|
||||
DRM_ERROR("Unknown GMADR entries (%d)\n",
|
||||
dev_priv->mm.gtt->gtt_mappable_entries);
|
||||
ret = -ENXIO;
|
||||
goto err_out;
|
||||
dev_priv->gtt.gsm = ioremap_wc(gtt_bus_addr, gtt_size);
|
||||
if (!dev_priv->gtt.gsm) {
|
||||
DRM_ERROR("Failed to map the gtt page table\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
ret = setup_scratch_page(dev);
|
||||
if (ret) {
|
||||
if (ret)
|
||||
DRM_ERROR("Scratch setup failed\n");
|
||||
goto err_out;
|
||||
}
|
||||
|
||||
dev_priv->mm.gtt->gtt = ioremap_wc(gtt_bus_addr,
|
||||
dev_priv->mm.gtt->gtt_total_entries * sizeof(gtt_pte_t));
|
||||
if (!dev_priv->mm.gtt->gtt) {
|
||||
DRM_ERROR("Failed to map the gtt page table\n");
|
||||
teardown_scratch_page(dev);
|
||||
ret = -ENOMEM;
|
||||
goto err_out;
|
||||
}
|
||||
dev_priv->gtt.gtt_clear_range = gen6_ggtt_clear_range;
|
||||
dev_priv->gtt.gtt_insert_entries = gen6_ggtt_insert_entries;
|
||||
|
||||
/* GMADR is the PCI aperture used by SW to access tiled GFX surfaces in a linear fashion. */
|
||||
DRM_INFO("Memory usable by graphics device = %dM\n", dev_priv->mm.gtt->gtt_total_entries >> 8);
|
||||
DRM_DEBUG_DRIVER("GMADR size = %dM\n", dev_priv->mm.gtt->gtt_mappable_entries >> 8);
|
||||
DRM_DEBUG_DRIVER("GTT stolen size = %dM\n", dev_priv->mm.gtt->stolen_size >> 20);
|
||||
|
||||
return 0;
|
||||
|
||||
err_out:
|
||||
kfree(dev_priv->mm.gtt);
|
||||
if (INTEL_INFO(dev)->gen < 6)
|
||||
intel_gmch_remove();
|
||||
return ret;
|
||||
}
|
||||
|
||||
void i915_gem_gtt_fini(struct drm_device *dev)
|
||||
static void gen6_gmch_remove(struct drm_device *dev)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
iounmap(dev_priv->mm.gtt->gtt);
|
||||
teardown_scratch_page(dev);
|
||||
if (INTEL_INFO(dev)->gen < 6)
|
||||
intel_gmch_remove();
|
||||
kfree(dev_priv->mm.gtt);
|
||||
iounmap(dev_priv->gtt.gsm);
|
||||
teardown_scratch_page(dev_priv->dev);
|
||||
}
|
||||
|
||||
static int i915_gmch_probe(struct drm_device *dev,
|
||||
size_t *gtt_total,
|
||||
size_t *stolen,
|
||||
phys_addr_t *mappable_base,
|
||||
unsigned long *mappable_end)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
int ret;
|
||||
|
||||
ret = intel_gmch_probe(dev_priv->bridge_dev, dev_priv->dev->pdev, NULL);
|
||||
if (!ret) {
|
||||
DRM_ERROR("failed to set up gmch\n");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
intel_gtt_get(gtt_total, stolen, mappable_base, mappable_end);
|
||||
|
||||
dev_priv->gtt.do_idle_maps = needs_idle_maps(dev_priv->dev);
|
||||
dev_priv->gtt.gtt_clear_range = i915_ggtt_clear_range;
|
||||
dev_priv->gtt.gtt_insert_entries = i915_ggtt_insert_entries;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void i915_gmch_remove(struct drm_device *dev)
|
||||
{
|
||||
intel_gmch_remove();
|
||||
}
|
||||
|
||||
int i915_gem_gtt_init(struct drm_device *dev)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
struct i915_gtt *gtt = &dev_priv->gtt;
|
||||
unsigned long gtt_size;
|
||||
int ret;
|
||||
|
||||
if (INTEL_INFO(dev)->gen <= 5) {
|
||||
dev_priv->gtt.gtt_probe = i915_gmch_probe;
|
||||
dev_priv->gtt.gtt_remove = i915_gmch_remove;
|
||||
} else {
|
||||
dev_priv->gtt.gtt_probe = gen6_gmch_probe;
|
||||
dev_priv->gtt.gtt_remove = gen6_gmch_remove;
|
||||
}
|
||||
|
||||
ret = dev_priv->gtt.gtt_probe(dev, &dev_priv->gtt.total,
|
||||
&dev_priv->gtt.stolen_size,
|
||||
>t->mappable_base,
|
||||
>t->mappable_end);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
gtt_size = (dev_priv->gtt.total >> PAGE_SHIFT) * sizeof(gtt_pte_t);
|
||||
|
||||
/* GMADR is the PCI mmio aperture into the global GTT. */
|
||||
DRM_INFO("Memory usable by graphics device = %zdM\n",
|
||||
dev_priv->gtt.total >> 20);
|
||||
DRM_DEBUG_DRIVER("GMADR size = %ldM\n",
|
||||
dev_priv->gtt.mappable_end >> 20);
|
||||
DRM_DEBUG_DRIVER("GTT stolen size = %zdM\n",
|
||||
dev_priv->gtt.stolen_size >> 20);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -42,85 +42,73 @@
|
||||
* for is a boon.
|
||||
*/
|
||||
|
||||
#define PTE_ADDRESS_MASK 0xfffff000
|
||||
#define PTE_ADDRESS_MASK_HIGH 0x000000f0 /* i915+ */
|
||||
#define PTE_MAPPING_TYPE_UNCACHED (0 << 1)
|
||||
#define PTE_MAPPING_TYPE_DCACHE (1 << 1) /* i830 only */
|
||||
#define PTE_MAPPING_TYPE_CACHED (3 << 1)
|
||||
#define PTE_MAPPING_TYPE_MASK (3 << 1)
|
||||
#define PTE_VALID (1 << 0)
|
||||
|
||||
/**
|
||||
* i915_stolen_to_phys - take an offset into stolen memory and turn it into
|
||||
* a physical one
|
||||
* @dev: drm device
|
||||
* @offset: address to translate
|
||||
*
|
||||
* Some chip functions require allocations from stolen space and need the
|
||||
* physical address of the memory in question.
|
||||
*/
|
||||
static unsigned long i915_stolen_to_phys(struct drm_device *dev, u32 offset)
|
||||
static unsigned long i915_stolen_to_physical(struct drm_device *dev)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
struct pci_dev *pdev = dev_priv->bridge_dev;
|
||||
u32 base;
|
||||
|
||||
#if 0
|
||||
/* On the machines I have tested the Graphics Base of Stolen Memory
|
||||
* is unreliable, so compute the base by subtracting the stolen memory
|
||||
* from the Top of Low Usable DRAM which is where the BIOS places
|
||||
* the graphics stolen memory.
|
||||
* is unreliable, so on those compute the base by subtracting the
|
||||
* stolen memory from the Top of Low Usable DRAM which is where the
|
||||
* BIOS places the graphics stolen memory.
|
||||
*
|
||||
* On gen2, the layout is slightly different with the Graphics Segment
|
||||
* immediately following Top of Memory (or Top of Usable DRAM). Note
|
||||
* it appears that TOUD is only reported by 865g, so we just use the
|
||||
* top of memory as determined by the e820 probe.
|
||||
*
|
||||
* XXX gen2 requires an unavailable symbol and 945gm fails with
|
||||
* its value of TOLUD.
|
||||
*/
|
||||
if (INTEL_INFO(dev)->gen > 3 || IS_G33(dev)) {
|
||||
/* top 32bits are reserved = 0 */
|
||||
base = 0;
|
||||
if (INTEL_INFO(dev)->gen >= 6) {
|
||||
/* Read Base Data of Stolen Memory Register (BDSM) directly.
|
||||
* Note that there is also a MCHBAR miror at 0x1080c0 or
|
||||
* we could use device 2:0x5c instead.
|
||||
*/
|
||||
pci_read_config_dword(pdev, 0xB0, &base);
|
||||
base &= ~4095; /* lower bits used for locking register */
|
||||
} else if (INTEL_INFO(dev)->gen > 3 || IS_G33(dev)) {
|
||||
/* Read Graphics Base of Stolen Memory directly */
|
||||
pci_read_config_dword(pdev, 0xA4, &base);
|
||||
} else {
|
||||
/* XXX presume 8xx is the same as i915 */
|
||||
pci_bus_read_config_dword(pdev->bus, 2, 0x5C, &base);
|
||||
}
|
||||
#else
|
||||
if (INTEL_INFO(dev)->gen > 3 || IS_G33(dev)) {
|
||||
u16 val;
|
||||
pci_read_config_word(pdev, 0xb0, &val);
|
||||
base = val >> 4 << 20;
|
||||
} else {
|
||||
#if 0
|
||||
} else if (IS_GEN3(dev)) {
|
||||
u8 val;
|
||||
/* Stolen is immediately below Top of Low Usable DRAM */
|
||||
pci_read_config_byte(pdev, 0x9c, &val);
|
||||
base = val >> 3 << 27;
|
||||
}
|
||||
base -= dev_priv->mm.gtt->stolen_size;
|
||||
base -= dev_priv->mm.gtt->stolen_size;
|
||||
} else {
|
||||
/* Stolen is immediately above Top of Memory */
|
||||
base = max_low_pfn_mapped << PAGE_SHIFT;
|
||||
#endif
|
||||
}
|
||||
|
||||
return base + offset;
|
||||
return base;
|
||||
}
|
||||
|
||||
static void i915_warn_stolen(struct drm_device *dev)
|
||||
{
|
||||
DRM_INFO("not enough stolen space for compressed buffer, disabling\n");
|
||||
DRM_INFO("hint: you may be able to increase stolen memory size in the BIOS to avoid this\n");
|
||||
}
|
||||
|
||||
static void i915_setup_compression(struct drm_device *dev, int size)
|
||||
static int i915_setup_compression(struct drm_device *dev, int size)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
struct drm_mm_node *compressed_fb, *uninitialized_var(compressed_llb);
|
||||
unsigned long cfb_base;
|
||||
unsigned long ll_base = 0;
|
||||
|
||||
/* Just in case the BIOS is doing something questionable. */
|
||||
intel_disable_fbc(dev);
|
||||
|
||||
compressed_fb = drm_mm_search_free(&dev_priv->mm.stolen, size, 4096, 0);
|
||||
/* Try to over-allocate to reduce reallocations and fragmentation */
|
||||
compressed_fb = drm_mm_search_free(&dev_priv->mm.stolen,
|
||||
size <<= 1, 4096, 0);
|
||||
if (!compressed_fb)
|
||||
compressed_fb = drm_mm_search_free(&dev_priv->mm.stolen,
|
||||
size >>= 1, 4096, 0);
|
||||
if (compressed_fb)
|
||||
compressed_fb = drm_mm_get_block(compressed_fb, size, 4096);
|
||||
if (!compressed_fb)
|
||||
goto err;
|
||||
|
||||
cfb_base = i915_stolen_to_phys(dev, compressed_fb->start);
|
||||
if (!cfb_base)
|
||||
goto err_fb;
|
||||
|
||||
if (!(IS_GM45(dev) || HAS_PCH_SPLIT(dev))) {
|
||||
if (HAS_PCH_SPLIT(dev))
|
||||
I915_WRITE(ILK_DPFC_CB_BASE, compressed_fb->start);
|
||||
else if (IS_GM45(dev)) {
|
||||
I915_WRITE(DPFC_CB_BASE, compressed_fb->start);
|
||||
} else {
|
||||
compressed_llb = drm_mm_search_free(&dev_priv->mm.stolen,
|
||||
4096, 4096, 0);
|
||||
if (compressed_llb)
|
||||
@ -129,73 +117,206 @@ static void i915_setup_compression(struct drm_device *dev, int size)
|
||||
if (!compressed_llb)
|
||||
goto err_fb;
|
||||
|
||||
ll_base = i915_stolen_to_phys(dev, compressed_llb->start);
|
||||
if (!ll_base)
|
||||
goto err_llb;
|
||||
}
|
||||
dev_priv->compressed_llb = compressed_llb;
|
||||
|
||||
dev_priv->cfb_size = size;
|
||||
I915_WRITE(FBC_CFB_BASE,
|
||||
dev_priv->mm.stolen_base + compressed_fb->start);
|
||||
I915_WRITE(FBC_LL_BASE,
|
||||
dev_priv->mm.stolen_base + compressed_llb->start);
|
||||
}
|
||||
|
||||
dev_priv->compressed_fb = compressed_fb;
|
||||
if (HAS_PCH_SPLIT(dev))
|
||||
I915_WRITE(ILK_DPFC_CB_BASE, compressed_fb->start);
|
||||
else if (IS_GM45(dev)) {
|
||||
I915_WRITE(DPFC_CB_BASE, compressed_fb->start);
|
||||
} else {
|
||||
I915_WRITE(FBC_CFB_BASE, cfb_base);
|
||||
I915_WRITE(FBC_LL_BASE, ll_base);
|
||||
dev_priv->compressed_llb = compressed_llb;
|
||||
}
|
||||
dev_priv->cfb_size = size;
|
||||
|
||||
DRM_DEBUG_KMS("FBC base 0x%08lx, ll base 0x%08lx, size %dM\n",
|
||||
cfb_base, ll_base, size >> 20);
|
||||
return;
|
||||
DRM_DEBUG_KMS("reserved %d bytes of contiguous stolen space for FBC\n",
|
||||
size);
|
||||
|
||||
return 0;
|
||||
|
||||
err_llb:
|
||||
drm_mm_put_block(compressed_llb);
|
||||
err_fb:
|
||||
drm_mm_put_block(compressed_fb);
|
||||
err:
|
||||
dev_priv->no_fbc_reason = FBC_STOLEN_TOO_SMALL;
|
||||
i915_warn_stolen(dev);
|
||||
return -ENOSPC;
|
||||
}
|
||||
|
||||
static void i915_cleanup_compression(struct drm_device *dev)
|
||||
int i915_gem_stolen_setup_compression(struct drm_device *dev, int size)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
|
||||
drm_mm_put_block(dev_priv->compressed_fb);
|
||||
if (dev_priv->mm.stolen_base == 0)
|
||||
return -ENODEV;
|
||||
|
||||
if (size < dev_priv->cfb_size)
|
||||
return 0;
|
||||
|
||||
/* Release any current block */
|
||||
i915_gem_stolen_cleanup_compression(dev);
|
||||
|
||||
return i915_setup_compression(dev, size);
|
||||
}
|
||||
|
||||
void i915_gem_stolen_cleanup_compression(struct drm_device *dev)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
|
||||
if (dev_priv->cfb_size == 0)
|
||||
return;
|
||||
|
||||
if (dev_priv->compressed_fb)
|
||||
drm_mm_put_block(dev_priv->compressed_fb);
|
||||
|
||||
if (dev_priv->compressed_llb)
|
||||
drm_mm_put_block(dev_priv->compressed_llb);
|
||||
|
||||
dev_priv->cfb_size = 0;
|
||||
}
|
||||
|
||||
void i915_gem_cleanup_stolen(struct drm_device *dev)
|
||||
{
|
||||
if (I915_HAS_FBC(dev) && i915_powersave)
|
||||
i915_cleanup_compression(dev);
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
|
||||
i915_gem_stolen_cleanup_compression(dev);
|
||||
drm_mm_takedown(&dev_priv->mm.stolen);
|
||||
}
|
||||
|
||||
int i915_gem_init_stolen(struct drm_device *dev)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
unsigned long prealloc_size = dev_priv->mm.gtt->stolen_size;
|
||||
|
||||
dev_priv->mm.stolen_base = i915_stolen_to_physical(dev);
|
||||
if (dev_priv->mm.stolen_base == 0)
|
||||
return 0;
|
||||
|
||||
DRM_DEBUG_KMS("found %zd bytes of stolen memory at %08lx\n",
|
||||
dev_priv->gtt.stolen_size, dev_priv->mm.stolen_base);
|
||||
|
||||
/* Basic memrange allocator for stolen space */
|
||||
drm_mm_init(&dev_priv->mm.stolen, 0, prealloc_size);
|
||||
|
||||
/* Try to set up FBC with a reasonable compressed buffer size */
|
||||
if (I915_HAS_FBC(dev) && i915_powersave) {
|
||||
int cfb_size;
|
||||
|
||||
/* Leave 1M for line length buffer & misc. */
|
||||
|
||||
/* Try to get a 32M buffer... */
|
||||
if (prealloc_size > (36*1024*1024))
|
||||
cfb_size = 32*1024*1024;
|
||||
else /* fall back to 7/8 of the stolen space */
|
||||
cfb_size = prealloc_size * 7 / 8;
|
||||
i915_setup_compression(dev, cfb_size);
|
||||
}
|
||||
drm_mm_init(&dev_priv->mm.stolen, 0, dev_priv->gtt.stolen_size);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct sg_table *
|
||||
i915_pages_create_for_stolen(struct drm_device *dev,
|
||||
u32 offset, u32 size)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
struct sg_table *st;
|
||||
struct scatterlist *sg;
|
||||
|
||||
DRM_DEBUG_DRIVER("offset=0x%x, size=%d\n", offset, size);
|
||||
BUG_ON(offset > dev_priv->gtt.stolen_size - size);
|
||||
|
||||
/* We hide that we have no struct page backing our stolen object
|
||||
* by wrapping the contiguous physical allocation with a fake
|
||||
* dma mapping in a single scatterlist.
|
||||
*/
|
||||
|
||||
st = kmalloc(sizeof(*st), GFP_KERNEL);
|
||||
if (st == NULL)
|
||||
return NULL;
|
||||
|
||||
if (sg_alloc_table(st, 1, GFP_KERNEL)) {
|
||||
kfree(st);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
sg = st->sgl;
|
||||
sg->offset = offset;
|
||||
sg->length = size;
|
||||
|
||||
sg_dma_address(sg) = (dma_addr_t)dev_priv->mm.stolen_base + offset;
|
||||
sg_dma_len(sg) = size;
|
||||
|
||||
return st;
|
||||
}
|
||||
|
||||
static int i915_gem_object_get_pages_stolen(struct drm_i915_gem_object *obj)
|
||||
{
|
||||
BUG();
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static void i915_gem_object_put_pages_stolen(struct drm_i915_gem_object *obj)
|
||||
{
|
||||
/* Should only be called during free */
|
||||
sg_free_table(obj->pages);
|
||||
kfree(obj->pages);
|
||||
}
|
||||
|
||||
static const struct drm_i915_gem_object_ops i915_gem_object_stolen_ops = {
|
||||
.get_pages = i915_gem_object_get_pages_stolen,
|
||||
.put_pages = i915_gem_object_put_pages_stolen,
|
||||
};
|
||||
|
||||
static struct drm_i915_gem_object *
|
||||
_i915_gem_object_create_stolen(struct drm_device *dev,
|
||||
struct drm_mm_node *stolen)
|
||||
{
|
||||
struct drm_i915_gem_object *obj;
|
||||
|
||||
obj = i915_gem_object_alloc(dev);
|
||||
if (obj == NULL)
|
||||
return NULL;
|
||||
|
||||
if (drm_gem_private_object_init(dev, &obj->base, stolen->size))
|
||||
goto cleanup;
|
||||
|
||||
i915_gem_object_init(obj, &i915_gem_object_stolen_ops);
|
||||
|
||||
obj->pages = i915_pages_create_for_stolen(dev,
|
||||
stolen->start, stolen->size);
|
||||
if (obj->pages == NULL)
|
||||
goto cleanup;
|
||||
|
||||
obj->has_dma_mapping = true;
|
||||
obj->pages_pin_count = 1;
|
||||
obj->stolen = stolen;
|
||||
|
||||
obj->base.write_domain = I915_GEM_DOMAIN_GTT;
|
||||
obj->base.read_domains = I915_GEM_DOMAIN_GTT;
|
||||
obj->cache_level = I915_CACHE_NONE;
|
||||
|
||||
return obj;
|
||||
|
||||
cleanup:
|
||||
i915_gem_object_free(obj);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct drm_i915_gem_object *
|
||||
i915_gem_object_create_stolen(struct drm_device *dev, u32 size)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
struct drm_i915_gem_object *obj;
|
||||
struct drm_mm_node *stolen;
|
||||
|
||||
if (dev_priv->mm.stolen_base == 0)
|
||||
return NULL;
|
||||
|
||||
DRM_DEBUG_KMS("creating stolen object: size=%x\n", size);
|
||||
if (size == 0)
|
||||
return NULL;
|
||||
|
||||
stolen = drm_mm_search_free(&dev_priv->mm.stolen, size, 4096, 0);
|
||||
if (stolen)
|
||||
stolen = drm_mm_get_block(stolen, size, 4096);
|
||||
if (stolen == NULL)
|
||||
return NULL;
|
||||
|
||||
obj = _i915_gem_object_create_stolen(dev, stolen);
|
||||
if (obj)
|
||||
return obj;
|
||||
|
||||
drm_mm_put_block(stolen);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void
|
||||
i915_gem_object_release_stolen(struct drm_i915_gem_object *obj)
|
||||
{
|
||||
if (obj->stolen) {
|
||||
drm_mm_put_block(obj->stolen);
|
||||
obj->stolen = NULL;
|
||||
}
|
||||
}
|
||||
|
@ -272,18 +272,7 @@ i915_gem_object_fence_ok(struct drm_i915_gem_object *obj, int tiling_mode)
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* Previous chips need to be aligned to the size of the smallest
|
||||
* fence register that can contain the object.
|
||||
*/
|
||||
if (INTEL_INFO(obj->base.dev)->gen == 3)
|
||||
size = 1024*1024;
|
||||
else
|
||||
size = 512*1024;
|
||||
|
||||
while (size < obj->base.size)
|
||||
size <<= 1;
|
||||
|
||||
size = i915_gem_get_gtt_size(obj->base.dev, obj->base.size, tiling_mode);
|
||||
if (obj->gtt_space->size != size)
|
||||
return false;
|
||||
|
||||
@ -368,15 +357,15 @@ i915_gem_set_tiling(struct drm_device *dev, void *data,
|
||||
|
||||
obj->map_and_fenceable =
|
||||
obj->gtt_space == NULL ||
|
||||
(obj->gtt_offset + obj->base.size <= dev_priv->mm.gtt_mappable_end &&
|
||||
(obj->gtt_offset + obj->base.size <= dev_priv->gtt.mappable_end &&
|
||||
i915_gem_object_fence_ok(obj, args->tiling_mode));
|
||||
|
||||
/* Rebind if we need a change of alignment */
|
||||
if (!obj->map_and_fenceable) {
|
||||
u32 unfenced_alignment =
|
||||
i915_gem_get_unfenced_gtt_alignment(dev,
|
||||
obj->base.size,
|
||||
args->tiling_mode);
|
||||
i915_gem_get_gtt_alignment(dev, obj->base.size,
|
||||
args->tiling_mode,
|
||||
false);
|
||||
if (obj->gtt_offset & (unfenced_alignment - 1))
|
||||
ret = i915_gem_object_unbind(obj);
|
||||
}
|
||||
@ -396,6 +385,18 @@ i915_gem_set_tiling(struct drm_device *dev, void *data,
|
||||
/* we have to maintain this existing ABI... */
|
||||
args->stride = obj->stride;
|
||||
args->tiling_mode = obj->tiling_mode;
|
||||
|
||||
/* Try to preallocate memory required to save swizzling on put-pages */
|
||||
if (i915_gem_object_needs_bit17_swizzle(obj)) {
|
||||
if (obj->bit_17 == NULL) {
|
||||
obj->bit_17 = kmalloc(BITS_TO_LONGS(obj->base.size >> PAGE_SHIFT) *
|
||||
sizeof(long), GFP_KERNEL);
|
||||
}
|
||||
} else {
|
||||
kfree(obj->bit_17);
|
||||
obj->bit_17 = NULL;
|
||||
}
|
||||
|
||||
drm_gem_object_unreference(&obj->base);
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
|
||||
|
@ -287,6 +287,10 @@ static void i915_hotplug_work_func(struct work_struct *work)
|
||||
struct drm_mode_config *mode_config = &dev->mode_config;
|
||||
struct intel_encoder *encoder;
|
||||
|
||||
/* HPD irq before everything is fully set up. */
|
||||
if (!dev_priv->enable_hotplug_processing)
|
||||
return;
|
||||
|
||||
mutex_lock(&mode_config->mutex);
|
||||
DRM_DEBUG_KMS("running encoder hotplug functions\n");
|
||||
|
||||
@ -300,9 +304,6 @@ static void i915_hotplug_work_func(struct work_struct *work)
|
||||
drm_helper_hpd_irq_event(dev);
|
||||
}
|
||||
|
||||
/* defined intel_pm.c */
|
||||
extern spinlock_t mchdev_lock;
|
||||
|
||||
static void ironlake_handle_rps_change(struct drm_device *dev)
|
||||
{
|
||||
drm_i915_private_t *dev_priv = dev->dev_private;
|
||||
@ -355,8 +356,8 @@ static void notify_ring(struct drm_device *dev,
|
||||
|
||||
wake_up_all(&ring->irq_queue);
|
||||
if (i915_enable_hangcheck) {
|
||||
dev_priv->hangcheck_count = 0;
|
||||
mod_timer(&dev_priv->hangcheck_timer,
|
||||
dev_priv->gpu_error.hangcheck_count = 0;
|
||||
mod_timer(&dev_priv->gpu_error.hangcheck_timer,
|
||||
round_jiffies_up(jiffies + DRM_I915_HANGCHECK_JIFFIES));
|
||||
}
|
||||
}
|
||||
@ -524,6 +525,20 @@ static void gen6_queue_rps_work(struct drm_i915_private *dev_priv,
|
||||
queue_work(dev_priv->wq, &dev_priv->rps.work);
|
||||
}
|
||||
|
||||
static void gmbus_irq_handler(struct drm_device *dev)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = (drm_i915_private_t *) dev->dev_private;
|
||||
|
||||
wake_up_all(&dev_priv->gmbus_wait_queue);
|
||||
}
|
||||
|
||||
static void dp_aux_irq_handler(struct drm_device *dev)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = (drm_i915_private_t *) dev->dev_private;
|
||||
|
||||
wake_up_all(&dev_priv->gmbus_wait_queue);
|
||||
}
|
||||
|
||||
static irqreturn_t valleyview_irq_handler(int irq, void *arg)
|
||||
{
|
||||
struct drm_device *dev = (struct drm_device *) arg;
|
||||
@ -533,7 +548,6 @@ static irqreturn_t valleyview_irq_handler(int irq, void *arg)
|
||||
unsigned long irqflags;
|
||||
int pipe;
|
||||
u32 pipe_stats[I915_MAX_PIPES];
|
||||
bool blc_event;
|
||||
|
||||
atomic_inc(&dev_priv->irq_received);
|
||||
|
||||
@ -590,8 +604,8 @@ static irqreturn_t valleyview_irq_handler(int irq, void *arg)
|
||||
I915_READ(PORT_HOTPLUG_STAT);
|
||||
}
|
||||
|
||||
if (pipe_stats[pipe] & PIPE_LEGACY_BLC_EVENT_STATUS)
|
||||
blc_event = true;
|
||||
if (pipe_stats[0] & PIPE_GMBUS_INTERRUPT_STATUS)
|
||||
gmbus_irq_handler(dev);
|
||||
|
||||
if (pm_iir & GEN6_PM_DEFERRED_EVENTS)
|
||||
gen6_queue_rps_work(dev_priv, pm_iir);
|
||||
@ -618,8 +632,11 @@ static void ibx_irq_handler(struct drm_device *dev, u32 pch_iir)
|
||||
(pch_iir & SDE_AUDIO_POWER_MASK) >>
|
||||
SDE_AUDIO_POWER_SHIFT);
|
||||
|
||||
if (pch_iir & SDE_AUX_MASK)
|
||||
dp_aux_irq_handler(dev);
|
||||
|
||||
if (pch_iir & SDE_GMBUS)
|
||||
DRM_DEBUG_DRIVER("PCH GMBUS interrupt\n");
|
||||
gmbus_irq_handler(dev);
|
||||
|
||||
if (pch_iir & SDE_AUDIO_HDCP_MASK)
|
||||
DRM_DEBUG_DRIVER("PCH HDCP audio interrupt\n");
|
||||
@ -662,10 +679,10 @@ static void cpt_irq_handler(struct drm_device *dev, u32 pch_iir)
|
||||
SDE_AUDIO_POWER_SHIFT_CPT);
|
||||
|
||||
if (pch_iir & SDE_AUX_MASK_CPT)
|
||||
DRM_DEBUG_DRIVER("AUX channel interrupt\n");
|
||||
dp_aux_irq_handler(dev);
|
||||
|
||||
if (pch_iir & SDE_GMBUS_CPT)
|
||||
DRM_DEBUG_DRIVER("PCH GMBUS interrupt\n");
|
||||
gmbus_irq_handler(dev);
|
||||
|
||||
if (pch_iir & SDE_AUDIO_CP_REQ_CPT)
|
||||
DRM_DEBUG_DRIVER("Audio CP request interrupt\n");
|
||||
@ -703,6 +720,9 @@ static irqreturn_t ivybridge_irq_handler(int irq, void *arg)
|
||||
|
||||
de_iir = I915_READ(DEIIR);
|
||||
if (de_iir) {
|
||||
if (de_iir & DE_AUX_CHANNEL_A_IVB)
|
||||
dp_aux_irq_handler(dev);
|
||||
|
||||
if (de_iir & DE_GSE_IVB)
|
||||
intel_opregion_gse_intr(dev);
|
||||
|
||||
@ -758,7 +778,7 @@ static irqreturn_t ironlake_irq_handler(int irq, void *arg)
|
||||
struct drm_device *dev = (struct drm_device *) arg;
|
||||
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
|
||||
int ret = IRQ_NONE;
|
||||
u32 de_iir, gt_iir, de_ier, pch_iir, pm_iir;
|
||||
u32 de_iir, gt_iir, de_ier, pm_iir;
|
||||
|
||||
atomic_inc(&dev_priv->irq_received);
|
||||
|
||||
@ -769,11 +789,9 @@ static irqreturn_t ironlake_irq_handler(int irq, void *arg)
|
||||
|
||||
de_iir = I915_READ(DEIIR);
|
||||
gt_iir = I915_READ(GTIIR);
|
||||
pch_iir = I915_READ(SDEIIR);
|
||||
pm_iir = I915_READ(GEN6_PMIIR);
|
||||
|
||||
if (de_iir == 0 && gt_iir == 0 && pch_iir == 0 &&
|
||||
(!IS_GEN6(dev) || pm_iir == 0))
|
||||
if (de_iir == 0 && gt_iir == 0 && (!IS_GEN6(dev) || pm_iir == 0))
|
||||
goto done;
|
||||
|
||||
ret = IRQ_HANDLED;
|
||||
@ -783,6 +801,9 @@ static irqreturn_t ironlake_irq_handler(int irq, void *arg)
|
||||
else
|
||||
snb_gt_irq_handler(dev, dev_priv, gt_iir);
|
||||
|
||||
if (de_iir & DE_AUX_CHANNEL_A)
|
||||
dp_aux_irq_handler(dev);
|
||||
|
||||
if (de_iir & DE_GSE)
|
||||
intel_opregion_gse_intr(dev);
|
||||
|
||||
@ -804,10 +825,15 @@ static irqreturn_t ironlake_irq_handler(int irq, void *arg)
|
||||
|
||||
/* check event from PCH */
|
||||
if (de_iir & DE_PCH_EVENT) {
|
||||
u32 pch_iir = I915_READ(SDEIIR);
|
||||
|
||||
if (HAS_PCH_CPT(dev))
|
||||
cpt_irq_handler(dev, pch_iir);
|
||||
else
|
||||
ibx_irq_handler(dev, pch_iir);
|
||||
|
||||
/* should clear PCH hotplug event before clear CPU irq */
|
||||
I915_WRITE(SDEIIR, pch_iir);
|
||||
}
|
||||
|
||||
if (IS_GEN5(dev) && de_iir & DE_PCU_EVENT)
|
||||
@ -816,8 +842,6 @@ static irqreturn_t ironlake_irq_handler(int irq, void *arg)
|
||||
if (IS_GEN6(dev) && pm_iir & GEN6_PM_DEFERRED_EVENTS)
|
||||
gen6_queue_rps_work(dev_priv, pm_iir);
|
||||
|
||||
/* should clear PCH hotplug event before clear CPU irq */
|
||||
I915_WRITE(SDEIIR, pch_iir);
|
||||
I915_WRITE(GTIIR, gt_iir);
|
||||
I915_WRITE(DEIIR, de_iir);
|
||||
I915_WRITE(GEN6_PMIIR, pm_iir);
|
||||
@ -838,23 +862,60 @@ done:
|
||||
*/
|
||||
static void i915_error_work_func(struct work_struct *work)
|
||||
{
|
||||
drm_i915_private_t *dev_priv = container_of(work, drm_i915_private_t,
|
||||
error_work);
|
||||
struct i915_gpu_error *error = container_of(work, struct i915_gpu_error,
|
||||
work);
|
||||
drm_i915_private_t *dev_priv = container_of(error, drm_i915_private_t,
|
||||
gpu_error);
|
||||
struct drm_device *dev = dev_priv->dev;
|
||||
struct intel_ring_buffer *ring;
|
||||
char *error_event[] = { "ERROR=1", NULL };
|
||||
char *reset_event[] = { "RESET=1", NULL };
|
||||
char *reset_done_event[] = { "ERROR=0", NULL };
|
||||
int i, ret;
|
||||
|
||||
kobject_uevent_env(&dev->primary->kdev.kobj, KOBJ_CHANGE, error_event);
|
||||
|
||||
if (atomic_read(&dev_priv->mm.wedged)) {
|
||||
/*
|
||||
* Note that there's only one work item which does gpu resets, so we
|
||||
* need not worry about concurrent gpu resets potentially incrementing
|
||||
* error->reset_counter twice. We only need to take care of another
|
||||
* racing irq/hangcheck declaring the gpu dead for a second time. A
|
||||
* quick check for that is good enough: schedule_work ensures the
|
||||
* correct ordering between hang detection and this work item, and since
|
||||
* the reset in-progress bit is only ever set by code outside of this
|
||||
* work we don't need to worry about any other races.
|
||||
*/
|
||||
if (i915_reset_in_progress(error) && !i915_terminally_wedged(error)) {
|
||||
DRM_DEBUG_DRIVER("resetting chip\n");
|
||||
kobject_uevent_env(&dev->primary->kdev.kobj, KOBJ_CHANGE, reset_event);
|
||||
if (!i915_reset(dev)) {
|
||||
atomic_set(&dev_priv->mm.wedged, 0);
|
||||
kobject_uevent_env(&dev->primary->kdev.kobj, KOBJ_CHANGE, reset_done_event);
|
||||
kobject_uevent_env(&dev->primary->kdev.kobj, KOBJ_CHANGE,
|
||||
reset_event);
|
||||
|
||||
ret = i915_reset(dev);
|
||||
|
||||
if (ret == 0) {
|
||||
/*
|
||||
* After all the gem state is reset, increment the reset
|
||||
* counter and wake up everyone waiting for the reset to
|
||||
* complete.
|
||||
*
|
||||
* Since unlock operations are a one-sided barrier only,
|
||||
* we need to insert a barrier here to order any seqno
|
||||
* updates before
|
||||
* the counter increment.
|
||||
*/
|
||||
smp_mb__before_atomic_inc();
|
||||
atomic_inc(&dev_priv->gpu_error.reset_counter);
|
||||
|
||||
kobject_uevent_env(&dev->primary->kdev.kobj,
|
||||
KOBJ_CHANGE, reset_done_event);
|
||||
} else {
|
||||
atomic_set(&error->reset_counter, I915_WEDGED);
|
||||
}
|
||||
complete_all(&dev_priv->error_completion);
|
||||
|
||||
for_each_ring(ring, dev_priv, i)
|
||||
wake_up_all(&ring->irq_queue);
|
||||
|
||||
wake_up_all(&dev_priv->gpu_error.reset_queue);
|
||||
}
|
||||
}
|
||||
|
||||
@ -915,7 +976,7 @@ i915_error_object_create(struct drm_i915_private *dev_priv,
|
||||
goto unwind;
|
||||
|
||||
local_irq_save(flags);
|
||||
if (reloc_offset < dev_priv->mm.gtt_mappable_end &&
|
||||
if (reloc_offset < dev_priv->gtt.mappable_end &&
|
||||
src->has_global_gtt_mapping) {
|
||||
void __iomem *s;
|
||||
|
||||
@ -924,10 +985,18 @@ i915_error_object_create(struct drm_i915_private *dev_priv,
|
||||
* captures what the GPU read.
|
||||
*/
|
||||
|
||||
s = io_mapping_map_atomic_wc(dev_priv->mm.gtt_mapping,
|
||||
s = io_mapping_map_atomic_wc(dev_priv->gtt.mappable,
|
||||
reloc_offset);
|
||||
memcpy_fromio(d, s, PAGE_SIZE);
|
||||
io_mapping_unmap_atomic(s);
|
||||
} else if (src->stolen) {
|
||||
unsigned long offset;
|
||||
|
||||
offset = dev_priv->mm.stolen_base;
|
||||
offset += src->stolen->start;
|
||||
offset += i << PAGE_SHIFT;
|
||||
|
||||
memcpy_fromio(d, (void __iomem *) offset, PAGE_SIZE);
|
||||
} else {
|
||||
struct page *page;
|
||||
void *s;
|
||||
@ -1074,6 +1143,8 @@ static void i915_gem_record_fences(struct drm_device *dev,
|
||||
error->fence[i] = I915_READ(FENCE_REG_830_0 + (i * 4));
|
||||
break;
|
||||
|
||||
default:
|
||||
BUG();
|
||||
}
|
||||
}
|
||||
|
||||
@ -1222,9 +1293,9 @@ static void i915_capture_error_state(struct drm_device *dev)
|
||||
unsigned long flags;
|
||||
int i, pipe;
|
||||
|
||||
spin_lock_irqsave(&dev_priv->error_lock, flags);
|
||||
error = dev_priv->first_error;
|
||||
spin_unlock_irqrestore(&dev_priv->error_lock, flags);
|
||||
spin_lock_irqsave(&dev_priv->gpu_error.lock, flags);
|
||||
error = dev_priv->gpu_error.first_error;
|
||||
spin_unlock_irqrestore(&dev_priv->gpu_error.lock, flags);
|
||||
if (error)
|
||||
return;
|
||||
|
||||
@ -1235,7 +1306,8 @@ static void i915_capture_error_state(struct drm_device *dev)
|
||||
return;
|
||||
}
|
||||
|
||||
DRM_INFO("capturing error event; look for more information in /debug/dri/%d/i915_error_state\n",
|
||||
DRM_INFO("capturing error event; look for more information in"
|
||||
"/sys/kernel/debug/dri/%d/i915_error_state\n",
|
||||
dev->primary->index);
|
||||
|
||||
kref_init(&error->ref);
|
||||
@ -1318,12 +1390,12 @@ static void i915_capture_error_state(struct drm_device *dev)
|
||||
error->overlay = intel_overlay_capture_error_state(dev);
|
||||
error->display = intel_display_capture_error_state(dev);
|
||||
|
||||
spin_lock_irqsave(&dev_priv->error_lock, flags);
|
||||
if (dev_priv->first_error == NULL) {
|
||||
dev_priv->first_error = error;
|
||||
spin_lock_irqsave(&dev_priv->gpu_error.lock, flags);
|
||||
if (dev_priv->gpu_error.first_error == NULL) {
|
||||
dev_priv->gpu_error.first_error = error;
|
||||
error = NULL;
|
||||
}
|
||||
spin_unlock_irqrestore(&dev_priv->error_lock, flags);
|
||||
spin_unlock_irqrestore(&dev_priv->gpu_error.lock, flags);
|
||||
|
||||
if (error)
|
||||
i915_error_state_free(&error->ref);
|
||||
@ -1335,10 +1407,10 @@ void i915_destroy_error_state(struct drm_device *dev)
|
||||
struct drm_i915_error_state *error;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&dev_priv->error_lock, flags);
|
||||
error = dev_priv->first_error;
|
||||
dev_priv->first_error = NULL;
|
||||
spin_unlock_irqrestore(&dev_priv->error_lock, flags);
|
||||
spin_lock_irqsave(&dev_priv->gpu_error.lock, flags);
|
||||
error = dev_priv->gpu_error.first_error;
|
||||
dev_priv->gpu_error.first_error = NULL;
|
||||
spin_unlock_irqrestore(&dev_priv->gpu_error.lock, flags);
|
||||
|
||||
if (error)
|
||||
kref_put(&error->ref, i915_error_state_free);
|
||||
@ -1459,17 +1531,18 @@ void i915_handle_error(struct drm_device *dev, bool wedged)
|
||||
i915_report_and_clear_eir(dev);
|
||||
|
||||
if (wedged) {
|
||||
INIT_COMPLETION(dev_priv->error_completion);
|
||||
atomic_set(&dev_priv->mm.wedged, 1);
|
||||
atomic_set_mask(I915_RESET_IN_PROGRESS_FLAG,
|
||||
&dev_priv->gpu_error.reset_counter);
|
||||
|
||||
/*
|
||||
* Wakeup waiting processes so they don't hang
|
||||
* Wakeup waiting processes so that the reset work item
|
||||
* doesn't deadlock trying to grab various locks.
|
||||
*/
|
||||
for_each_ring(ring, dev_priv, i)
|
||||
wake_up_all(&ring->irq_queue);
|
||||
}
|
||||
|
||||
queue_work(dev_priv->wq, &dev_priv->error_work);
|
||||
queue_work(dev_priv->wq, &dev_priv->gpu_error.work);
|
||||
}
|
||||
|
||||
static void i915_pageflip_stall_check(struct drm_device *dev, int pipe)
|
||||
@ -1700,7 +1773,7 @@ static bool i915_hangcheck_hung(struct drm_device *dev)
|
||||
{
|
||||
drm_i915_private_t *dev_priv = dev->dev_private;
|
||||
|
||||
if (dev_priv->hangcheck_count++ > 1) {
|
||||
if (dev_priv->gpu_error.hangcheck_count++ > 1) {
|
||||
bool hung = true;
|
||||
|
||||
DRM_ERROR("Hangcheck timer elapsed... GPU hung\n");
|
||||
@ -1759,25 +1832,29 @@ void i915_hangcheck_elapsed(unsigned long data)
|
||||
goto repeat;
|
||||
}
|
||||
|
||||
dev_priv->hangcheck_count = 0;
|
||||
dev_priv->gpu_error.hangcheck_count = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
i915_get_extra_instdone(dev, instdone);
|
||||
if (memcmp(dev_priv->last_acthd, acthd, sizeof(acthd)) == 0 &&
|
||||
memcmp(dev_priv->prev_instdone, instdone, sizeof(instdone)) == 0) {
|
||||
if (memcmp(dev_priv->gpu_error.last_acthd, acthd,
|
||||
sizeof(acthd)) == 0 &&
|
||||
memcmp(dev_priv->gpu_error.prev_instdone, instdone,
|
||||
sizeof(instdone)) == 0) {
|
||||
if (i915_hangcheck_hung(dev))
|
||||
return;
|
||||
} else {
|
||||
dev_priv->hangcheck_count = 0;
|
||||
dev_priv->gpu_error.hangcheck_count = 0;
|
||||
|
||||
memcpy(dev_priv->last_acthd, acthd, sizeof(acthd));
|
||||
memcpy(dev_priv->prev_instdone, instdone, sizeof(instdone));
|
||||
memcpy(dev_priv->gpu_error.last_acthd, acthd,
|
||||
sizeof(acthd));
|
||||
memcpy(dev_priv->gpu_error.prev_instdone, instdone,
|
||||
sizeof(instdone));
|
||||
}
|
||||
|
||||
repeat:
|
||||
/* Reset timer case chip hangs without another request being added */
|
||||
mod_timer(&dev_priv->hangcheck_timer,
|
||||
mod_timer(&dev_priv->gpu_error.hangcheck_timer,
|
||||
round_jiffies_up(jiffies + DRM_I915_HANGCHECK_JIFFIES));
|
||||
}
|
||||
|
||||
@ -1847,7 +1924,7 @@ static void valleyview_irq_preinstall(struct drm_device *dev)
|
||||
* This register is the same on all known PCH chips.
|
||||
*/
|
||||
|
||||
static void ironlake_enable_pch_hotplug(struct drm_device *dev)
|
||||
static void ibx_enable_hotplug(struct drm_device *dev)
|
||||
{
|
||||
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
|
||||
u32 hotplug;
|
||||
@ -1860,14 +1937,36 @@ static void ironlake_enable_pch_hotplug(struct drm_device *dev)
|
||||
I915_WRITE(PCH_PORT_HOTPLUG, hotplug);
|
||||
}
|
||||
|
||||
static void ibx_irq_postinstall(struct drm_device *dev)
|
||||
{
|
||||
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
|
||||
u32 mask;
|
||||
|
||||
if (HAS_PCH_IBX(dev))
|
||||
mask = SDE_HOTPLUG_MASK |
|
||||
SDE_GMBUS |
|
||||
SDE_AUX_MASK;
|
||||
else
|
||||
mask = SDE_HOTPLUG_MASK_CPT |
|
||||
SDE_GMBUS_CPT |
|
||||
SDE_AUX_MASK_CPT;
|
||||
|
||||
I915_WRITE(SDEIIR, I915_READ(SDEIIR));
|
||||
I915_WRITE(SDEIMR, ~mask);
|
||||
I915_WRITE(SDEIER, mask);
|
||||
POSTING_READ(SDEIER);
|
||||
|
||||
ibx_enable_hotplug(dev);
|
||||
}
|
||||
|
||||
static int ironlake_irq_postinstall(struct drm_device *dev)
|
||||
{
|
||||
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
|
||||
/* enable kind of interrupts always enabled */
|
||||
u32 display_mask = DE_MASTER_IRQ_CONTROL | DE_GSE | DE_PCH_EVENT |
|
||||
DE_PLANEA_FLIP_DONE | DE_PLANEB_FLIP_DONE;
|
||||
DE_PLANEA_FLIP_DONE | DE_PLANEB_FLIP_DONE |
|
||||
DE_AUX_CHANNEL_A;
|
||||
u32 render_irqs;
|
||||
u32 hotplug_mask;
|
||||
|
||||
dev_priv->irq_mask = ~display_mask;
|
||||
|
||||
@ -1895,27 +1994,7 @@ static int ironlake_irq_postinstall(struct drm_device *dev)
|
||||
I915_WRITE(GTIER, render_irqs);
|
||||
POSTING_READ(GTIER);
|
||||
|
||||
if (HAS_PCH_CPT(dev)) {
|
||||
hotplug_mask = (SDE_CRT_HOTPLUG_CPT |
|
||||
SDE_PORTB_HOTPLUG_CPT |
|
||||
SDE_PORTC_HOTPLUG_CPT |
|
||||
SDE_PORTD_HOTPLUG_CPT);
|
||||
} else {
|
||||
hotplug_mask = (SDE_CRT_HOTPLUG |
|
||||
SDE_PORTB_HOTPLUG |
|
||||
SDE_PORTC_HOTPLUG |
|
||||
SDE_PORTD_HOTPLUG |
|
||||
SDE_AUX_MASK);
|
||||
}
|
||||
|
||||
dev_priv->pch_irq_mask = ~hotplug_mask;
|
||||
|
||||
I915_WRITE(SDEIIR, I915_READ(SDEIIR));
|
||||
I915_WRITE(SDEIMR, dev_priv->pch_irq_mask);
|
||||
I915_WRITE(SDEIER, hotplug_mask);
|
||||
POSTING_READ(SDEIER);
|
||||
|
||||
ironlake_enable_pch_hotplug(dev);
|
||||
ibx_irq_postinstall(dev);
|
||||
|
||||
if (IS_IRONLAKE_M(dev)) {
|
||||
/* Clear & enable PCU event interrupts */
|
||||
@ -1935,9 +2014,9 @@ static int ivybridge_irq_postinstall(struct drm_device *dev)
|
||||
DE_MASTER_IRQ_CONTROL | DE_GSE_IVB | DE_PCH_EVENT_IVB |
|
||||
DE_PLANEC_FLIP_DONE_IVB |
|
||||
DE_PLANEB_FLIP_DONE_IVB |
|
||||
DE_PLANEA_FLIP_DONE_IVB;
|
||||
DE_PLANEA_FLIP_DONE_IVB |
|
||||
DE_AUX_CHANNEL_A_IVB;
|
||||
u32 render_irqs;
|
||||
u32 hotplug_mask;
|
||||
|
||||
dev_priv->irq_mask = ~display_mask;
|
||||
|
||||
@ -1961,18 +2040,7 @@ static int ivybridge_irq_postinstall(struct drm_device *dev)
|
||||
I915_WRITE(GTIER, render_irqs);
|
||||
POSTING_READ(GTIER);
|
||||
|
||||
hotplug_mask = (SDE_CRT_HOTPLUG_CPT |
|
||||
SDE_PORTB_HOTPLUG_CPT |
|
||||
SDE_PORTC_HOTPLUG_CPT |
|
||||
SDE_PORTD_HOTPLUG_CPT);
|
||||
dev_priv->pch_irq_mask = ~hotplug_mask;
|
||||
|
||||
I915_WRITE(SDEIIR, I915_READ(SDEIIR));
|
||||
I915_WRITE(SDEIMR, dev_priv->pch_irq_mask);
|
||||
I915_WRITE(SDEIER, hotplug_mask);
|
||||
POSTING_READ(SDEIER);
|
||||
|
||||
ironlake_enable_pch_hotplug(dev);
|
||||
ibx_irq_postinstall(dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -1981,7 +2049,6 @@ static int valleyview_irq_postinstall(struct drm_device *dev)
|
||||
{
|
||||
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
|
||||
u32 enable_mask;
|
||||
u32 hotplug_en = I915_READ(PORT_HOTPLUG_EN);
|
||||
u32 pipestat_enable = PLANE_FLIP_DONE_INT_EN_VLV;
|
||||
u32 render_irqs;
|
||||
u16 msid;
|
||||
@ -2010,6 +2077,9 @@ static int valleyview_irq_postinstall(struct drm_device *dev)
|
||||
msid |= (1<<14);
|
||||
pci_write_config_word(dev_priv->dev->pdev, 0x98, msid);
|
||||
|
||||
I915_WRITE(PORT_HOTPLUG_EN, 0);
|
||||
POSTING_READ(PORT_HOTPLUG_EN);
|
||||
|
||||
I915_WRITE(VLV_IMR, dev_priv->irq_mask);
|
||||
I915_WRITE(VLV_IER, enable_mask);
|
||||
I915_WRITE(VLV_IIR, 0xffffffff);
|
||||
@ -2018,6 +2088,7 @@ static int valleyview_irq_postinstall(struct drm_device *dev)
|
||||
POSTING_READ(VLV_IER);
|
||||
|
||||
i915_enable_pipestat(dev_priv, 0, pipestat_enable);
|
||||
i915_enable_pipestat(dev_priv, 0, PIPE_GMBUS_EVENT_ENABLE);
|
||||
i915_enable_pipestat(dev_priv, 1, pipestat_enable);
|
||||
|
||||
I915_WRITE(VLV_IIR, 0xffffffff);
|
||||
@ -2038,13 +2109,22 @@ static int valleyview_irq_postinstall(struct drm_device *dev)
|
||||
#endif
|
||||
|
||||
I915_WRITE(VLV_MASTER_IER, MASTER_INTERRUPT_ENABLE);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void valleyview_hpd_irq_setup(struct drm_device *dev)
|
||||
{
|
||||
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
|
||||
u32 hotplug_en = I915_READ(PORT_HOTPLUG_EN);
|
||||
|
||||
/* Note HDMI and DP share bits */
|
||||
if (dev_priv->hotplug_supported_mask & HDMIB_HOTPLUG_INT_STATUS)
|
||||
hotplug_en |= HDMIB_HOTPLUG_INT_EN;
|
||||
if (dev_priv->hotplug_supported_mask & HDMIC_HOTPLUG_INT_STATUS)
|
||||
hotplug_en |= HDMIC_HOTPLUG_INT_EN;
|
||||
if (dev_priv->hotplug_supported_mask & HDMID_HOTPLUG_INT_STATUS)
|
||||
hotplug_en |= HDMID_HOTPLUG_INT_EN;
|
||||
if (dev_priv->hotplug_supported_mask & PORTB_HOTPLUG_INT_STATUS)
|
||||
hotplug_en |= PORTB_HOTPLUG_INT_EN;
|
||||
if (dev_priv->hotplug_supported_mask & PORTC_HOTPLUG_INT_STATUS)
|
||||
hotplug_en |= PORTC_HOTPLUG_INT_EN;
|
||||
if (dev_priv->hotplug_supported_mask & PORTD_HOTPLUG_INT_STATUS)
|
||||
hotplug_en |= PORTD_HOTPLUG_INT_EN;
|
||||
if (dev_priv->hotplug_supported_mask & SDVOC_HOTPLUG_INT_STATUS_I915)
|
||||
hotplug_en |= SDVOC_HOTPLUG_INT_EN;
|
||||
if (dev_priv->hotplug_supported_mask & SDVOB_HOTPLUG_INT_STATUS_I915)
|
||||
@ -2055,8 +2135,6 @@ static int valleyview_irq_postinstall(struct drm_device *dev)
|
||||
}
|
||||
|
||||
I915_WRITE(PORT_HOTPLUG_EN, hotplug_en);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void valleyview_irq_uninstall(struct drm_device *dev)
|
||||
@ -2286,6 +2364,9 @@ static int i915_irq_postinstall(struct drm_device *dev)
|
||||
I915_USER_INTERRUPT;
|
||||
|
||||
if (I915_HAS_HOTPLUG(dev)) {
|
||||
I915_WRITE(PORT_HOTPLUG_EN, 0);
|
||||
POSTING_READ(PORT_HOTPLUG_EN);
|
||||
|
||||
/* Enable in IER... */
|
||||
enable_mask |= I915_DISPLAY_PORT_INTERRUPT;
|
||||
/* and unmask in IMR */
|
||||
@ -2296,15 +2377,25 @@ static int i915_irq_postinstall(struct drm_device *dev)
|
||||
I915_WRITE(IER, enable_mask);
|
||||
POSTING_READ(IER);
|
||||
|
||||
if (I915_HAS_HOTPLUG(dev)) {
|
||||
u32 hotplug_en = I915_READ(PORT_HOTPLUG_EN);
|
||||
intel_opregion_enable_asle(dev);
|
||||
|
||||
if (dev_priv->hotplug_supported_mask & HDMIB_HOTPLUG_INT_STATUS)
|
||||
hotplug_en |= HDMIB_HOTPLUG_INT_EN;
|
||||
if (dev_priv->hotplug_supported_mask & HDMIC_HOTPLUG_INT_STATUS)
|
||||
hotplug_en |= HDMIC_HOTPLUG_INT_EN;
|
||||
if (dev_priv->hotplug_supported_mask & HDMID_HOTPLUG_INT_STATUS)
|
||||
hotplug_en |= HDMID_HOTPLUG_INT_EN;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void i915_hpd_irq_setup(struct drm_device *dev)
|
||||
{
|
||||
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
|
||||
u32 hotplug_en;
|
||||
|
||||
if (I915_HAS_HOTPLUG(dev)) {
|
||||
hotplug_en = I915_READ(PORT_HOTPLUG_EN);
|
||||
|
||||
if (dev_priv->hotplug_supported_mask & PORTB_HOTPLUG_INT_STATUS)
|
||||
hotplug_en |= PORTB_HOTPLUG_INT_EN;
|
||||
if (dev_priv->hotplug_supported_mask & PORTC_HOTPLUG_INT_STATUS)
|
||||
hotplug_en |= PORTC_HOTPLUG_INT_EN;
|
||||
if (dev_priv->hotplug_supported_mask & PORTD_HOTPLUG_INT_STATUS)
|
||||
hotplug_en |= PORTD_HOTPLUG_INT_EN;
|
||||
if (dev_priv->hotplug_supported_mask & SDVOC_HOTPLUG_INT_STATUS_I915)
|
||||
hotplug_en |= SDVOC_HOTPLUG_INT_EN;
|
||||
if (dev_priv->hotplug_supported_mask & SDVOB_HOTPLUG_INT_STATUS_I915)
|
||||
@ -2318,10 +2409,6 @@ static int i915_irq_postinstall(struct drm_device *dev)
|
||||
|
||||
I915_WRITE(PORT_HOTPLUG_EN, hotplug_en);
|
||||
}
|
||||
|
||||
intel_opregion_enable_asle(dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static irqreturn_t i915_irq_handler(int irq, void *arg)
|
||||
@ -2481,7 +2568,6 @@ static void i965_irq_preinstall(struct drm_device * dev)
|
||||
static int i965_irq_postinstall(struct drm_device *dev)
|
||||
{
|
||||
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
|
||||
u32 hotplug_en;
|
||||
u32 enable_mask;
|
||||
u32 error_mask;
|
||||
|
||||
@ -2502,6 +2588,7 @@ static int i965_irq_postinstall(struct drm_device *dev)
|
||||
|
||||
dev_priv->pipestat[0] = 0;
|
||||
dev_priv->pipestat[1] = 0;
|
||||
i915_enable_pipestat(dev_priv, 0, PIPE_GMBUS_EVENT_ENABLE);
|
||||
|
||||
/*
|
||||
* Enable some error detection, note the instruction error mask
|
||||
@ -2522,14 +2609,27 @@ static int i965_irq_postinstall(struct drm_device *dev)
|
||||
I915_WRITE(IER, enable_mask);
|
||||
POSTING_READ(IER);
|
||||
|
||||
I915_WRITE(PORT_HOTPLUG_EN, 0);
|
||||
POSTING_READ(PORT_HOTPLUG_EN);
|
||||
|
||||
intel_opregion_enable_asle(dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void i965_hpd_irq_setup(struct drm_device *dev)
|
||||
{
|
||||
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
|
||||
u32 hotplug_en;
|
||||
|
||||
/* Note HDMI and DP share hotplug bits */
|
||||
hotplug_en = 0;
|
||||
if (dev_priv->hotplug_supported_mask & HDMIB_HOTPLUG_INT_STATUS)
|
||||
hotplug_en |= HDMIB_HOTPLUG_INT_EN;
|
||||
if (dev_priv->hotplug_supported_mask & HDMIC_HOTPLUG_INT_STATUS)
|
||||
hotplug_en |= HDMIC_HOTPLUG_INT_EN;
|
||||
if (dev_priv->hotplug_supported_mask & HDMID_HOTPLUG_INT_STATUS)
|
||||
hotplug_en |= HDMID_HOTPLUG_INT_EN;
|
||||
if (dev_priv->hotplug_supported_mask & PORTB_HOTPLUG_INT_STATUS)
|
||||
hotplug_en |= PORTB_HOTPLUG_INT_EN;
|
||||
if (dev_priv->hotplug_supported_mask & PORTC_HOTPLUG_INT_STATUS)
|
||||
hotplug_en |= PORTC_HOTPLUG_INT_EN;
|
||||
if (dev_priv->hotplug_supported_mask & PORTD_HOTPLUG_INT_STATUS)
|
||||
hotplug_en |= PORTD_HOTPLUG_INT_EN;
|
||||
if (IS_G4X(dev)) {
|
||||
if (dev_priv->hotplug_supported_mask & SDVOC_HOTPLUG_INT_STATUS_G4X)
|
||||
hotplug_en |= SDVOC_HOTPLUG_INT_EN;
|
||||
@ -2556,10 +2656,6 @@ static int i965_irq_postinstall(struct drm_device *dev)
|
||||
/* Ignore TV since it's buggy */
|
||||
|
||||
I915_WRITE(PORT_HOTPLUG_EN, hotplug_en);
|
||||
|
||||
intel_opregion_enable_asle(dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static irqreturn_t i965_irq_handler(int irq, void *arg)
|
||||
@ -2655,6 +2751,9 @@ static irqreturn_t i965_irq_handler(int irq, void *arg)
|
||||
if (blc_event || (iir & I915_ASLE_INTERRUPT))
|
||||
intel_opregion_asle_intr(dev);
|
||||
|
||||
if (pipe_stats[0] & PIPE_GMBUS_INTERRUPT_STATUS)
|
||||
gmbus_irq_handler(dev);
|
||||
|
||||
/* With MSI, interrupts are only generated when iir
|
||||
* transitions from zero to nonzero. If another bit got
|
||||
* set while we were handling the existing iir bits, then
|
||||
@ -2706,10 +2805,16 @@ void intel_irq_init(struct drm_device *dev)
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
|
||||
INIT_WORK(&dev_priv->hotplug_work, i915_hotplug_work_func);
|
||||
INIT_WORK(&dev_priv->error_work, i915_error_work_func);
|
||||
INIT_WORK(&dev_priv->gpu_error.work, i915_error_work_func);
|
||||
INIT_WORK(&dev_priv->rps.work, gen6_pm_rps_work);
|
||||
INIT_WORK(&dev_priv->l3_parity.error_work, ivybridge_parity_work);
|
||||
|
||||
setup_timer(&dev_priv->gpu_error.hangcheck_timer,
|
||||
i915_hangcheck_elapsed,
|
||||
(unsigned long) dev);
|
||||
|
||||
pm_qos_add_request(&dev_priv->pm_qos, PM_QOS_CPU_DMA_LATENCY, PM_QOS_DEFAULT_VALUE);
|
||||
|
||||
dev->driver->get_vblank_counter = i915_get_vblank_counter;
|
||||
dev->max_vblank_count = 0xffffff; /* only 24 bits of frame count */
|
||||
if (IS_G4X(dev) || INTEL_INFO(dev)->gen >= 5) {
|
||||
@ -2730,7 +2835,8 @@ void intel_irq_init(struct drm_device *dev)
|
||||
dev->driver->irq_uninstall = valleyview_irq_uninstall;
|
||||
dev->driver->enable_vblank = valleyview_enable_vblank;
|
||||
dev->driver->disable_vblank = valleyview_disable_vblank;
|
||||
} else if (IS_IVYBRIDGE(dev)) {
|
||||
dev_priv->display.hpd_irq_setup = valleyview_hpd_irq_setup;
|
||||
} else if (IS_IVYBRIDGE(dev) || IS_HASWELL(dev)) {
|
||||
/* Share pre & uninstall handlers with ILK/SNB */
|
||||
dev->driver->irq_handler = ivybridge_irq_handler;
|
||||
dev->driver->irq_preinstall = ironlake_irq_preinstall;
|
||||
@ -2738,14 +2844,6 @@ void intel_irq_init(struct drm_device *dev)
|
||||
dev->driver->irq_uninstall = ironlake_irq_uninstall;
|
||||
dev->driver->enable_vblank = ivybridge_enable_vblank;
|
||||
dev->driver->disable_vblank = ivybridge_disable_vblank;
|
||||
} else if (IS_HASWELL(dev)) {
|
||||
/* Share interrupts handling with IVB */
|
||||
dev->driver->irq_handler = ivybridge_irq_handler;
|
||||
dev->driver->irq_preinstall = ironlake_irq_preinstall;
|
||||
dev->driver->irq_postinstall = ivybridge_irq_postinstall;
|
||||
dev->driver->irq_uninstall = ironlake_irq_uninstall;
|
||||
dev->driver->enable_vblank = ivybridge_enable_vblank;
|
||||
dev->driver->disable_vblank = ivybridge_disable_vblank;
|
||||
} else if (HAS_PCH_SPLIT(dev)) {
|
||||
dev->driver->irq_handler = ironlake_irq_handler;
|
||||
dev->driver->irq_preinstall = ironlake_irq_preinstall;
|
||||
@ -2764,13 +2862,23 @@ void intel_irq_init(struct drm_device *dev)
|
||||
dev->driver->irq_postinstall = i915_irq_postinstall;
|
||||
dev->driver->irq_uninstall = i915_irq_uninstall;
|
||||
dev->driver->irq_handler = i915_irq_handler;
|
||||
dev_priv->display.hpd_irq_setup = i915_hpd_irq_setup;
|
||||
} else {
|
||||
dev->driver->irq_preinstall = i965_irq_preinstall;
|
||||
dev->driver->irq_postinstall = i965_irq_postinstall;
|
||||
dev->driver->irq_uninstall = i965_irq_uninstall;
|
||||
dev->driver->irq_handler = i965_irq_handler;
|
||||
dev_priv->display.hpd_irq_setup = i965_hpd_irq_setup;
|
||||
}
|
||||
dev->driver->enable_vblank = i915_enable_vblank;
|
||||
dev->driver->disable_vblank = i915_disable_vblank;
|
||||
}
|
||||
}
|
||||
|
||||
void intel_hpd_init(struct drm_device *dev)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
|
||||
if (dev_priv->display.hpd_irq_setup)
|
||||
dev_priv->display.hpd_irq_setup(dev);
|
||||
}
|
||||
|
@ -141,8 +141,15 @@
|
||||
#define VGA_MSR_MEM_EN (1<<1)
|
||||
#define VGA_MSR_CGA_MODE (1<<0)
|
||||
|
||||
#define VGA_SR_INDEX 0x3c4
|
||||
#define VGA_SR_DATA 0x3c5
|
||||
/*
|
||||
* SR01 is the only VGA register touched on non-UMS setups.
|
||||
* VLV doesn't do UMS, so the sequencer index/data registers
|
||||
* are the only VGA registers which need to include
|
||||
* display_mmio_offset.
|
||||
*/
|
||||
#define VGA_SR_INDEX (dev_priv->info->display_mmio_offset + 0x3c4)
|
||||
#define SR01 1
|
||||
#define VGA_SR_DATA (dev_priv->info->display_mmio_offset + 0x3c5)
|
||||
|
||||
#define VGA_AR_INDEX 0x3c0
|
||||
#define VGA_AR_VID_EN (1<<5)
|
||||
@ -301,6 +308,7 @@
|
||||
#define DISPLAY_PLANE_A (0<<20)
|
||||
#define DISPLAY_PLANE_B (1<<20)
|
||||
#define GFX_OP_PIPE_CONTROL(len) ((0x3<<29)|(0x3<<27)|(0x2<<24)|(len-2))
|
||||
#define PIPE_CONTROL_GLOBAL_GTT_IVB (1<<24) /* gen7+ */
|
||||
#define PIPE_CONTROL_CS_STALL (1<<20)
|
||||
#define PIPE_CONTROL_TLB_INVALIDATE (1<<18)
|
||||
#define PIPE_CONTROL_QW_WRITE (1<<14)
|
||||
@ -335,17 +343,19 @@
|
||||
* 0x801c/3c: core clock bits
|
||||
* 0x8048/68: low pass filter coefficients
|
||||
* 0x8100: fast clock controls
|
||||
*
|
||||
* DPIO is VLV only.
|
||||
*/
|
||||
#define DPIO_PKT 0x2100
|
||||
#define DPIO_PKT (VLV_DISPLAY_BASE + 0x2100)
|
||||
#define DPIO_RID (0<<24)
|
||||
#define DPIO_OP_WRITE (1<<16)
|
||||
#define DPIO_OP_READ (0<<16)
|
||||
#define DPIO_PORTID (0x12<<8)
|
||||
#define DPIO_BYTE (0xf<<4)
|
||||
#define DPIO_BUSY (1<<0) /* status only */
|
||||
#define DPIO_DATA 0x2104
|
||||
#define DPIO_REG 0x2108
|
||||
#define DPIO_CTL 0x2110
|
||||
#define DPIO_DATA (VLV_DISPLAY_BASE + 0x2104)
|
||||
#define DPIO_REG (VLV_DISPLAY_BASE + 0x2108)
|
||||
#define DPIO_CTL (VLV_DISPLAY_BASE + 0x2110)
|
||||
#define DPIO_MODSEL1 (1<<3) /* if ref clk b == 27 */
|
||||
#define DPIO_MODSEL0 (1<<2) /* if ref clk a == 27 */
|
||||
#define DPIO_SFR_BYPASS (1<<1)
|
||||
@ -556,13 +566,13 @@
|
||||
#define IIR 0x020a4
|
||||
#define IMR 0x020a8
|
||||
#define ISR 0x020ac
|
||||
#define VLV_GUNIT_CLOCK_GATE 0x182060
|
||||
#define VLV_GUNIT_CLOCK_GATE (VLV_DISPLAY_BASE + 0x2060)
|
||||
#define GCFG_DIS (1<<8)
|
||||
#define VLV_IIR_RW 0x182084
|
||||
#define VLV_IER 0x1820a0
|
||||
#define VLV_IIR 0x1820a4
|
||||
#define VLV_IMR 0x1820a8
|
||||
#define VLV_ISR 0x1820ac
|
||||
#define VLV_IIR_RW (VLV_DISPLAY_BASE + 0x2084)
|
||||
#define VLV_IER (VLV_DISPLAY_BASE + 0x20a0)
|
||||
#define VLV_IIR (VLV_DISPLAY_BASE + 0x20a4)
|
||||
#define VLV_IMR (VLV_DISPLAY_BASE + 0x20a8)
|
||||
#define VLV_ISR (VLV_DISPLAY_BASE + 0x20ac)
|
||||
#define I915_PIPE_CONTROL_NOTIFY_INTERRUPT (1<<18)
|
||||
#define I915_DISPLAY_PORT_INTERRUPT (1<<17)
|
||||
#define I915_RENDER_COMMAND_PARSER_ERROR_INTERRUPT (1<<15)
|
||||
@ -735,6 +745,7 @@
|
||||
#define GEN7_FF_TS_SCHED_HS0 (0x3<<16)
|
||||
#define GEN7_FF_TS_SCHED_LOAD_BALANCE (0x1<<16)
|
||||
#define GEN7_FF_TS_SCHED_HW (0x0<<16) /* Default */
|
||||
#define GEN7_FF_VS_REF_CNT_FFME (1 << 15)
|
||||
#define GEN7_FF_VS_SCHED_HS1 (0x5<<12)
|
||||
#define GEN7_FF_VS_SCHED_HS0 (0x3<<12)
|
||||
#define GEN7_FF_VS_SCHED_LOAD_BALANCE (0x1<<12) /* Default */
|
||||
@ -921,8 +932,8 @@
|
||||
#define VGA1_PD_P1_DIV_2 (1 << 13)
|
||||
#define VGA1_PD_P1_SHIFT 8
|
||||
#define VGA1_PD_P1_MASK (0x1f << 8)
|
||||
#define _DPLL_A 0x06014
|
||||
#define _DPLL_B 0x06018
|
||||
#define _DPLL_A (dev_priv->info->display_mmio_offset + 0x6014)
|
||||
#define _DPLL_B (dev_priv->info->display_mmio_offset + 0x6018)
|
||||
#define DPLL(pipe) _PIPE(pipe, _DPLL_A, _DPLL_B)
|
||||
#define DPLL_VCO_ENABLE (1 << 31)
|
||||
#define DPLL_DVO_HIGH_SPEED (1 << 30)
|
||||
@ -943,23 +954,6 @@
|
||||
#define DPLL_LOCK_VLV (1<<15)
|
||||
#define DPLL_INTEGRATED_CLOCK_VLV (1<<13)
|
||||
|
||||
#define SRX_INDEX 0x3c4
|
||||
#define SRX_DATA 0x3c5
|
||||
#define SR01 1
|
||||
#define SR01_SCREEN_OFF (1<<5)
|
||||
|
||||
#define PPCR 0x61204
|
||||
#define PPCR_ON (1<<0)
|
||||
|
||||
#define DVOB 0x61140
|
||||
#define DVOB_ON (1<<31)
|
||||
#define DVOC 0x61160
|
||||
#define DVOC_ON (1<<31)
|
||||
#define LVDS 0x61180
|
||||
#define LVDS_ON (1<<31)
|
||||
|
||||
/* Scratch pad debug 0 reg:
|
||||
*/
|
||||
#define DPLL_FPA01_P1_POST_DIV_MASK_I830 0x001f0000
|
||||
/*
|
||||
* The i830 generation, in LVDS mode, defines P1 as the bit number set within
|
||||
@ -998,7 +992,7 @@
|
||||
#define SDVO_MULTIPLIER_MASK 0x000000ff
|
||||
#define SDVO_MULTIPLIER_SHIFT_HIRES 4
|
||||
#define SDVO_MULTIPLIER_SHIFT_VGA 0
|
||||
#define _DPLL_A_MD 0x0601c /* 965+ only */
|
||||
#define _DPLL_A_MD (dev_priv->info->display_mmio_offset + 0x601c) /* 965+ only */
|
||||
/*
|
||||
* UDI pixel divider, controlling how many pixels are stuffed into a packet.
|
||||
*
|
||||
@ -1035,7 +1029,7 @@
|
||||
*/
|
||||
#define DPLL_MD_VGA_UDI_MULTIPLIER_MASK 0x0000003f
|
||||
#define DPLL_MD_VGA_UDI_MULTIPLIER_SHIFT 0
|
||||
#define _DPLL_B_MD 0x06020 /* 965+ only */
|
||||
#define _DPLL_B_MD (dev_priv->info->display_mmio_offset + 0x6020) /* 965+ only */
|
||||
#define DPLL_MD(pipe) _PIPE(pipe, _DPLL_A_MD, _DPLL_B_MD)
|
||||
|
||||
#define _FPA0 0x06040
|
||||
@ -1178,15 +1172,15 @@
|
||||
#define RAMCLK_GATE_D 0x6210 /* CRL only */
|
||||
#define DEUC 0x6214 /* CRL only */
|
||||
|
||||
#define FW_BLC_SELF_VLV 0x6500
|
||||
#define FW_BLC_SELF_VLV (VLV_DISPLAY_BASE + 0x6500)
|
||||
#define FW_CSPWRDWNEN (1<<15)
|
||||
|
||||
/*
|
||||
* Palette regs
|
||||
*/
|
||||
|
||||
#define _PALETTE_A 0x0a000
|
||||
#define _PALETTE_B 0x0a800
|
||||
#define _PALETTE_A (dev_priv->info->display_mmio_offset + 0xa000)
|
||||
#define _PALETTE_B (dev_priv->info->display_mmio_offset + 0xa800)
|
||||
#define PALETTE(pipe) _PIPE(pipe, _PALETTE_A, _PALETTE_B)
|
||||
|
||||
/* MCH MMIO space */
|
||||
@ -1242,6 +1236,10 @@
|
||||
#define MAD_DIMM_A_SIZE_SHIFT 0
|
||||
#define MAD_DIMM_A_SIZE_MASK (0xff << MAD_DIMM_A_SIZE_SHIFT)
|
||||
|
||||
/** snb MCH registers for priority tuning */
|
||||
#define MCH_SSKPD (MCHBAR_MIRROR_BASE_SNB + 0x5d10)
|
||||
#define MCH_SSKPD_WM0_MASK 0x3f
|
||||
#define MCH_SSKPD_WM0_VAL 0xc
|
||||
|
||||
/* Clocking configuration register */
|
||||
#define CLKCFG 0x10c00
|
||||
@ -1551,26 +1549,26 @@
|
||||
*/
|
||||
|
||||
/* Pipe A timing regs */
|
||||
#define _HTOTAL_A 0x60000
|
||||
#define _HBLANK_A 0x60004
|
||||
#define _HSYNC_A 0x60008
|
||||
#define _VTOTAL_A 0x6000c
|
||||
#define _VBLANK_A 0x60010
|
||||
#define _VSYNC_A 0x60014
|
||||
#define _PIPEASRC 0x6001c
|
||||
#define _BCLRPAT_A 0x60020
|
||||
#define _VSYNCSHIFT_A 0x60028
|
||||
#define _HTOTAL_A (dev_priv->info->display_mmio_offset + 0x60000)
|
||||
#define _HBLANK_A (dev_priv->info->display_mmio_offset + 0x60004)
|
||||
#define _HSYNC_A (dev_priv->info->display_mmio_offset + 0x60008)
|
||||
#define _VTOTAL_A (dev_priv->info->display_mmio_offset + 0x6000c)
|
||||
#define _VBLANK_A (dev_priv->info->display_mmio_offset + 0x60010)
|
||||
#define _VSYNC_A (dev_priv->info->display_mmio_offset + 0x60014)
|
||||
#define _PIPEASRC (dev_priv->info->display_mmio_offset + 0x6001c)
|
||||
#define _BCLRPAT_A (dev_priv->info->display_mmio_offset + 0x60020)
|
||||
#define _VSYNCSHIFT_A (dev_priv->info->display_mmio_offset + 0x60028)
|
||||
|
||||
/* Pipe B timing regs */
|
||||
#define _HTOTAL_B 0x61000
|
||||
#define _HBLANK_B 0x61004
|
||||
#define _HSYNC_B 0x61008
|
||||
#define _VTOTAL_B 0x6100c
|
||||
#define _VBLANK_B 0x61010
|
||||
#define _VSYNC_B 0x61014
|
||||
#define _PIPEBSRC 0x6101c
|
||||
#define _BCLRPAT_B 0x61020
|
||||
#define _VSYNCSHIFT_B 0x61028
|
||||
#define _HTOTAL_B (dev_priv->info->display_mmio_offset + 0x61000)
|
||||
#define _HBLANK_B (dev_priv->info->display_mmio_offset + 0x61004)
|
||||
#define _HSYNC_B (dev_priv->info->display_mmio_offset + 0x61008)
|
||||
#define _VTOTAL_B (dev_priv->info->display_mmio_offset + 0x6100c)
|
||||
#define _VBLANK_B (dev_priv->info->display_mmio_offset + 0x61010)
|
||||
#define _VSYNC_B (dev_priv->info->display_mmio_offset + 0x61014)
|
||||
#define _PIPEBSRC (dev_priv->info->display_mmio_offset + 0x6101c)
|
||||
#define _BCLRPAT_B (dev_priv->info->display_mmio_offset + 0x61020)
|
||||
#define _VSYNCSHIFT_B (dev_priv->info->display_mmio_offset + 0x61028)
|
||||
|
||||
|
||||
#define HTOTAL(trans) _TRANSCODER(trans, _HTOTAL_A, _HTOTAL_B)
|
||||
@ -1631,13 +1629,10 @@
|
||||
|
||||
|
||||
/* Hotplug control (945+ only) */
|
||||
#define PORT_HOTPLUG_EN 0x61110
|
||||
#define HDMIB_HOTPLUG_INT_EN (1 << 29)
|
||||
#define DPB_HOTPLUG_INT_EN (1 << 29)
|
||||
#define HDMIC_HOTPLUG_INT_EN (1 << 28)
|
||||
#define DPC_HOTPLUG_INT_EN (1 << 28)
|
||||
#define HDMID_HOTPLUG_INT_EN (1 << 27)
|
||||
#define DPD_HOTPLUG_INT_EN (1 << 27)
|
||||
#define PORT_HOTPLUG_EN (dev_priv->info->display_mmio_offset + 0x61110)
|
||||
#define PORTB_HOTPLUG_INT_EN (1 << 29)
|
||||
#define PORTC_HOTPLUG_INT_EN (1 << 28)
|
||||
#define PORTD_HOTPLUG_INT_EN (1 << 27)
|
||||
#define SDVOB_HOTPLUG_INT_EN (1 << 26)
|
||||
#define SDVOC_HOTPLUG_INT_EN (1 << 25)
|
||||
#define TV_HOTPLUG_INT_EN (1 << 18)
|
||||
@ -1658,21 +1653,14 @@
|
||||
#define CRT_HOTPLUG_DETECT_VOLTAGE_325MV (0 << 2)
|
||||
#define CRT_HOTPLUG_DETECT_VOLTAGE_475MV (1 << 2)
|
||||
|
||||
#define PORT_HOTPLUG_STAT 0x61114
|
||||
#define PORT_HOTPLUG_STAT (dev_priv->info->display_mmio_offset + 0x61114)
|
||||
/* HDMI/DP bits are gen4+ */
|
||||
#define DPB_HOTPLUG_LIVE_STATUS (1 << 29)
|
||||
#define DPC_HOTPLUG_LIVE_STATUS (1 << 28)
|
||||
#define DPD_HOTPLUG_LIVE_STATUS (1 << 27)
|
||||
#define DPD_HOTPLUG_INT_STATUS (3 << 21)
|
||||
#define DPC_HOTPLUG_INT_STATUS (3 << 19)
|
||||
#define DPB_HOTPLUG_INT_STATUS (3 << 17)
|
||||
/* HDMI bits are shared with the DP bits */
|
||||
#define HDMIB_HOTPLUG_LIVE_STATUS (1 << 29)
|
||||
#define HDMIC_HOTPLUG_LIVE_STATUS (1 << 28)
|
||||
#define HDMID_HOTPLUG_LIVE_STATUS (1 << 27)
|
||||
#define HDMID_HOTPLUG_INT_STATUS (3 << 21)
|
||||
#define HDMIC_HOTPLUG_INT_STATUS (3 << 19)
|
||||
#define HDMIB_HOTPLUG_INT_STATUS (3 << 17)
|
||||
#define PORTB_HOTPLUG_LIVE_STATUS (1 << 29)
|
||||
#define PORTC_HOTPLUG_LIVE_STATUS (1 << 28)
|
||||
#define PORTD_HOTPLUG_LIVE_STATUS (1 << 27)
|
||||
#define PORTD_HOTPLUG_INT_STATUS (3 << 21)
|
||||
#define PORTC_HOTPLUG_INT_STATUS (3 << 19)
|
||||
#define PORTB_HOTPLUG_INT_STATUS (3 << 17)
|
||||
/* CRT/TV common between gen3+ */
|
||||
#define CRT_HOTPLUG_INT_STATUS (1 << 11)
|
||||
#define TV_HOTPLUG_INT_STATUS (1 << 10)
|
||||
@ -1877,7 +1865,7 @@
|
||||
#define PP_DIVISOR 0x61210
|
||||
|
||||
/* Panel fitting */
|
||||
#define PFIT_CONTROL 0x61230
|
||||
#define PFIT_CONTROL (dev_priv->info->display_mmio_offset + 0x61230)
|
||||
#define PFIT_ENABLE (1 << 31)
|
||||
#define PFIT_PIPE_MASK (3 << 29)
|
||||
#define PFIT_PIPE_SHIFT 29
|
||||
@ -1895,9 +1883,7 @@
|
||||
#define PFIT_SCALING_PROGRAMMED (1 << 26)
|
||||
#define PFIT_SCALING_PILLAR (2 << 26)
|
||||
#define PFIT_SCALING_LETTER (3 << 26)
|
||||
#define PFIT_PGM_RATIOS 0x61234
|
||||
#define PFIT_VERT_SCALE_MASK 0xfff00000
|
||||
#define PFIT_HORIZ_SCALE_MASK 0x0000fff0
|
||||
#define PFIT_PGM_RATIOS (dev_priv->info->display_mmio_offset + 0x61234)
|
||||
/* Pre-965 */
|
||||
#define PFIT_VERT_SCALE_SHIFT 20
|
||||
#define PFIT_VERT_SCALE_MASK 0xfff00000
|
||||
@ -1909,7 +1895,7 @@
|
||||
#define PFIT_HORIZ_SCALE_SHIFT_965 0
|
||||
#define PFIT_HORIZ_SCALE_MASK_965 0x00001fff
|
||||
|
||||
#define PFIT_AUTO_RATIOS 0x61238
|
||||
#define PFIT_AUTO_RATIOS (dev_priv->info->display_mmio_offset + 0x61238)
|
||||
|
||||
/* Backlight control */
|
||||
#define BLC_PWM_CTL2 0x61250 /* 965+ only */
|
||||
@ -2639,10 +2625,10 @@
|
||||
/* Display & cursor control */
|
||||
|
||||
/* Pipe A */
|
||||
#define _PIPEADSL 0x70000
|
||||
#define _PIPEADSL (dev_priv->info->display_mmio_offset + 0x70000)
|
||||
#define DSL_LINEMASK_GEN2 0x00000fff
|
||||
#define DSL_LINEMASK_GEN3 0x00001fff
|
||||
#define _PIPEACONF 0x70008
|
||||
#define _PIPEACONF (dev_priv->info->display_mmio_offset + 0x70008)
|
||||
#define PIPECONF_ENABLE (1<<31)
|
||||
#define PIPECONF_DISABLE 0
|
||||
#define PIPECONF_DOUBLE_WIDE (1<<30)
|
||||
@ -2671,18 +2657,19 @@
|
||||
#define PIPECONF_INTERLACED_DBL_ILK (4 << 21) /* ilk/snb only */
|
||||
#define PIPECONF_PFIT_PF_INTERLACED_DBL_ILK (5 << 21) /* ilk/snb only */
|
||||
#define PIPECONF_CXSR_DOWNCLOCK (1<<16)
|
||||
#define PIPECONF_BPP_MASK (0x000000e0)
|
||||
#define PIPECONF_BPP_8 (0<<5)
|
||||
#define PIPECONF_BPP_10 (1<<5)
|
||||
#define PIPECONF_BPP_6 (2<<5)
|
||||
#define PIPECONF_BPP_12 (3<<5)
|
||||
#define PIPECONF_COLOR_RANGE_SELECT (1 << 13)
|
||||
#define PIPECONF_BPC_MASK (0x7 << 5)
|
||||
#define PIPECONF_8BPC (0<<5)
|
||||
#define PIPECONF_10BPC (1<<5)
|
||||
#define PIPECONF_6BPC (2<<5)
|
||||
#define PIPECONF_12BPC (3<<5)
|
||||
#define PIPECONF_DITHER_EN (1<<4)
|
||||
#define PIPECONF_DITHER_TYPE_MASK (0x0000000c)
|
||||
#define PIPECONF_DITHER_TYPE_SP (0<<2)
|
||||
#define PIPECONF_DITHER_TYPE_ST1 (1<<2)
|
||||
#define PIPECONF_DITHER_TYPE_ST2 (2<<2)
|
||||
#define PIPECONF_DITHER_TYPE_TEMP (3<<2)
|
||||
#define _PIPEASTAT 0x70024
|
||||
#define _PIPEASTAT (dev_priv->info->display_mmio_offset + 0x70024)
|
||||
#define PIPE_FIFO_UNDERRUN_STATUS (1UL<<31)
|
||||
#define SPRITE1_FLIPDONE_INT_EN_VLV (1UL<<30)
|
||||
#define PIPE_CRC_ERROR_ENABLE (1UL<<29)
|
||||
@ -2693,7 +2680,7 @@
|
||||
#define PIPE_VSYNC_INTERRUPT_ENABLE (1UL<<25)
|
||||
#define PIPE_DISPLAY_LINE_COMPARE_ENABLE (1UL<<24)
|
||||
#define PIPE_DPST_EVENT_ENABLE (1UL<<23)
|
||||
#define SPRITE0_FLIP_DONE_INT_EN_VLV (1UL<<26)
|
||||
#define SPRITE0_FLIP_DONE_INT_EN_VLV (1UL<<22)
|
||||
#define PIPE_LEGACY_BLC_EVENT_ENABLE (1UL<<22)
|
||||
#define PIPE_ODD_FIELD_INTERRUPT_ENABLE (1UL<<21)
|
||||
#define PIPE_EVEN_FIELD_INTERRUPT_ENABLE (1UL<<20)
|
||||
@ -2703,7 +2690,7 @@
|
||||
#define PIPEA_HBLANK_INT_EN_VLV (1UL<<16)
|
||||
#define PIPE_OVERLAY_UPDATED_ENABLE (1UL<<16)
|
||||
#define SPRITE1_FLIPDONE_INT_STATUS_VLV (1UL<<15)
|
||||
#define SPRITE0_FLIPDONE_INT_STATUS_VLV (1UL<<15)
|
||||
#define SPRITE0_FLIPDONE_INT_STATUS_VLV (1UL<<14)
|
||||
#define PIPE_CRC_ERROR_INTERRUPT_STATUS (1UL<<13)
|
||||
#define PIPE_CRC_DONE_INTERRUPT_STATUS (1UL<<12)
|
||||
#define PIPE_GMBUS_INTERRUPT_STATUS (1UL<<11)
|
||||
@ -2719,11 +2706,6 @@
|
||||
#define PIPE_START_VBLANK_INTERRUPT_STATUS (1UL<<2) /* 965 or later */
|
||||
#define PIPE_VBLANK_INTERRUPT_STATUS (1UL<<1)
|
||||
#define PIPE_OVERLAY_UPDATED_STATUS (1UL<<0)
|
||||
#define PIPE_BPC_MASK (7 << 5) /* Ironlake */
|
||||
#define PIPE_8BPC (0 << 5)
|
||||
#define PIPE_10BPC (1 << 5)
|
||||
#define PIPE_6BPC (2 << 5)
|
||||
#define PIPE_12BPC (3 << 5)
|
||||
|
||||
#define PIPESRC(pipe) _PIPE(pipe, _PIPEASRC, _PIPEBSRC)
|
||||
#define PIPECONF(tran) _TRANSCODER(tran, _PIPEACONF, _PIPEBCONF)
|
||||
@ -2732,7 +2714,7 @@
|
||||
#define PIPEFRAMEPIXEL(pipe) _PIPE(pipe, _PIPEAFRAMEPIXEL, _PIPEBFRAMEPIXEL)
|
||||
#define PIPESTAT(pipe) _PIPE(pipe, _PIPEASTAT, _PIPEBSTAT)
|
||||
|
||||
#define VLV_DPFLIPSTAT 0x70028
|
||||
#define VLV_DPFLIPSTAT (VLV_DISPLAY_BASE + 0x70028)
|
||||
#define PIPEB_LINE_COMPARE_INT_EN (1<<29)
|
||||
#define PIPEB_HLINE_INT_EN (1<<28)
|
||||
#define PIPEB_VBLANK_INT_EN (1<<27)
|
||||
@ -2746,7 +2728,7 @@
|
||||
#define SPRITEA_FLIPDONE_INT_EN (1<<17)
|
||||
#define PLANEA_FLIPDONE_INT_EN (1<<16)
|
||||
|
||||
#define DPINVGTT 0x7002c /* VLV only */
|
||||
#define DPINVGTT (VLV_DISPLAY_BASE + 0x7002c) /* VLV only */
|
||||
#define CURSORB_INVALID_GTT_INT_EN (1<<23)
|
||||
#define CURSORA_INVALID_GTT_INT_EN (1<<22)
|
||||
#define SPRITED_INVALID_GTT_INT_EN (1<<21)
|
||||
@ -2774,7 +2756,7 @@
|
||||
#define DSPARB_BEND_SHIFT 9 /* on 855 */
|
||||
#define DSPARB_AEND_SHIFT 0
|
||||
|
||||
#define DSPFW1 0x70034
|
||||
#define DSPFW1 (dev_priv->info->display_mmio_offset + 0x70034)
|
||||
#define DSPFW_SR_SHIFT 23
|
||||
#define DSPFW_SR_MASK (0x1ff<<23)
|
||||
#define DSPFW_CURSORB_SHIFT 16
|
||||
@ -2782,11 +2764,11 @@
|
||||
#define DSPFW_PLANEB_SHIFT 8
|
||||
#define DSPFW_PLANEB_MASK (0x7f<<8)
|
||||
#define DSPFW_PLANEA_MASK (0x7f)
|
||||
#define DSPFW2 0x70038
|
||||
#define DSPFW2 (dev_priv->info->display_mmio_offset + 0x70038)
|
||||
#define DSPFW_CURSORA_MASK 0x00003f00
|
||||
#define DSPFW_CURSORA_SHIFT 8
|
||||
#define DSPFW_PLANEC_MASK (0x7f)
|
||||
#define DSPFW3 0x7003c
|
||||
#define DSPFW3 (dev_priv->info->display_mmio_offset + 0x7003c)
|
||||
#define DSPFW_HPLL_SR_EN (1<<31)
|
||||
#define DSPFW_CURSOR_SR_SHIFT 24
|
||||
#define PINEVIEW_SELF_REFRESH_EN (1<<30)
|
||||
@ -2798,13 +2780,13 @@
|
||||
/* drain latency register values*/
|
||||
#define DRAIN_LATENCY_PRECISION_32 32
|
||||
#define DRAIN_LATENCY_PRECISION_16 16
|
||||
#define VLV_DDL1 0x70050
|
||||
#define VLV_DDL1 (VLV_DISPLAY_BASE + 0x70050)
|
||||
#define DDL_CURSORA_PRECISION_32 (1<<31)
|
||||
#define DDL_CURSORA_PRECISION_16 (0<<31)
|
||||
#define DDL_CURSORA_SHIFT 24
|
||||
#define DDL_PLANEA_PRECISION_32 (1<<7)
|
||||
#define DDL_PLANEA_PRECISION_16 (0<<7)
|
||||
#define VLV_DDL2 0x70054
|
||||
#define VLV_DDL2 (VLV_DISPLAY_BASE + 0x70054)
|
||||
#define DDL_CURSORB_PRECISION_32 (1<<31)
|
||||
#define DDL_CURSORB_PRECISION_16 (0<<31)
|
||||
#define DDL_CURSORB_SHIFT 24
|
||||
@ -2948,10 +2930,10 @@
|
||||
* } while (high1 != high2);
|
||||
* frame = (high1 << 8) | low1;
|
||||
*/
|
||||
#define _PIPEAFRAMEHIGH 0x70040
|
||||
#define _PIPEAFRAMEHIGH (dev_priv->info->display_mmio_offset + 0x70040)
|
||||
#define PIPE_FRAME_HIGH_MASK 0x0000ffff
|
||||
#define PIPE_FRAME_HIGH_SHIFT 0
|
||||
#define _PIPEAFRAMEPIXEL 0x70044
|
||||
#define _PIPEAFRAMEPIXEL (dev_priv->info->display_mmio_offset + 0x70044)
|
||||
#define PIPE_FRAME_LOW_MASK 0xff000000
|
||||
#define PIPE_FRAME_LOW_SHIFT 24
|
||||
#define PIPE_PIXEL_MASK 0x00ffffff
|
||||
@ -2962,11 +2944,12 @@
|
||||
#define PIPE_FRMCOUNT_GM45(pipe) _PIPE(pipe, _PIPEA_FRMCOUNT_GM45, _PIPEB_FRMCOUNT_GM45)
|
||||
|
||||
/* Cursor A & B regs */
|
||||
#define _CURACNTR 0x70080
|
||||
#define _CURACNTR (dev_priv->info->display_mmio_offset + 0x70080)
|
||||
/* Old style CUR*CNTR flags (desktop 8xx) */
|
||||
#define CURSOR_ENABLE 0x80000000
|
||||
#define CURSOR_GAMMA_ENABLE 0x40000000
|
||||
#define CURSOR_STRIDE_MASK 0x30000000
|
||||
#define CURSOR_PIPE_CSC_ENABLE (1<<24)
|
||||
#define CURSOR_FORMAT_SHIFT 24
|
||||
#define CURSOR_FORMAT_MASK (0x07 << CURSOR_FORMAT_SHIFT)
|
||||
#define CURSOR_FORMAT_2C (0x00 << CURSOR_FORMAT_SHIFT)
|
||||
@ -2983,16 +2966,16 @@
|
||||
#define MCURSOR_PIPE_A 0x00
|
||||
#define MCURSOR_PIPE_B (1 << 28)
|
||||
#define MCURSOR_GAMMA_ENABLE (1 << 26)
|
||||
#define _CURABASE 0x70084
|
||||
#define _CURAPOS 0x70088
|
||||
#define _CURABASE (dev_priv->info->display_mmio_offset + 0x70084)
|
||||
#define _CURAPOS (dev_priv->info->display_mmio_offset + 0x70088)
|
||||
#define CURSOR_POS_MASK 0x007FF
|
||||
#define CURSOR_POS_SIGN 0x8000
|
||||
#define CURSOR_X_SHIFT 0
|
||||
#define CURSOR_Y_SHIFT 16
|
||||
#define CURSIZE 0x700a0
|
||||
#define _CURBCNTR 0x700c0
|
||||
#define _CURBBASE 0x700c4
|
||||
#define _CURBPOS 0x700c8
|
||||
#define _CURBCNTR (dev_priv->info->display_mmio_offset + 0x700c0)
|
||||
#define _CURBBASE (dev_priv->info->display_mmio_offset + 0x700c4)
|
||||
#define _CURBPOS (dev_priv->info->display_mmio_offset + 0x700c8)
|
||||
|
||||
#define _CURBCNTR_IVB 0x71080
|
||||
#define _CURBBASE_IVB 0x71084
|
||||
@ -3007,7 +2990,7 @@
|
||||
#define CURPOS_IVB(pipe) _PIPE(pipe, _CURAPOS, _CURBPOS_IVB)
|
||||
|
||||
/* Display A control */
|
||||
#define _DSPACNTR 0x70180
|
||||
#define _DSPACNTR (dev_priv->info->display_mmio_offset + 0x70180)
|
||||
#define DISPLAY_PLANE_ENABLE (1<<31)
|
||||
#define DISPLAY_PLANE_DISABLE 0
|
||||
#define DISPPLANE_GAMMA_ENABLE (1<<30)
|
||||
@ -3028,6 +3011,7 @@
|
||||
#define DISPPLANE_RGBA888 (0xf<<26)
|
||||
#define DISPPLANE_STEREO_ENABLE (1<<25)
|
||||
#define DISPPLANE_STEREO_DISABLE 0
|
||||
#define DISPPLANE_PIPE_CSC_ENABLE (1<<24)
|
||||
#define DISPPLANE_SEL_PIPE_SHIFT 24
|
||||
#define DISPPLANE_SEL_PIPE_MASK (3<<DISPPLANE_SEL_PIPE_SHIFT)
|
||||
#define DISPPLANE_SEL_PIPE_A 0
|
||||
@ -3040,14 +3024,14 @@
|
||||
#define DISPPLANE_STEREO_POLARITY_SECOND (1<<18)
|
||||
#define DISPPLANE_TRICKLE_FEED_DISABLE (1<<14) /* Ironlake */
|
||||
#define DISPPLANE_TILED (1<<10)
|
||||
#define _DSPAADDR 0x70184
|
||||
#define _DSPASTRIDE 0x70188
|
||||
#define _DSPAPOS 0x7018C /* reserved */
|
||||
#define _DSPASIZE 0x70190
|
||||
#define _DSPASURF 0x7019C /* 965+ only */
|
||||
#define _DSPATILEOFF 0x701A4 /* 965+ only */
|
||||
#define _DSPAOFFSET 0x701A4 /* HSW */
|
||||
#define _DSPASURFLIVE 0x701AC
|
||||
#define _DSPAADDR (dev_priv->info->display_mmio_offset + 0x70184)
|
||||
#define _DSPASTRIDE (dev_priv->info->display_mmio_offset + 0x70188)
|
||||
#define _DSPAPOS (dev_priv->info->display_mmio_offset + 0x7018C) /* reserved */
|
||||
#define _DSPASIZE (dev_priv->info->display_mmio_offset + 0x70190)
|
||||
#define _DSPASURF (dev_priv->info->display_mmio_offset + 0x7019C) /* 965+ only */
|
||||
#define _DSPATILEOFF (dev_priv->info->display_mmio_offset + 0x701A4) /* 965+ only */
|
||||
#define _DSPAOFFSET (dev_priv->info->display_mmio_offset + 0x701A4) /* HSW */
|
||||
#define _DSPASURFLIVE (dev_priv->info->display_mmio_offset + 0x701AC)
|
||||
|
||||
#define DSPCNTR(plane) _PIPE(plane, _DSPACNTR, _DSPBCNTR)
|
||||
#define DSPADDR(plane) _PIPE(plane, _DSPAADDR, _DSPBADDR)
|
||||
@ -3068,44 +3052,44 @@
|
||||
(I915_WRITE((reg), (gfx_addr) | I915_LO_DISPBASE(I915_READ(reg))))
|
||||
|
||||
/* VBIOS flags */
|
||||
#define SWF00 0x71410
|
||||
#define SWF01 0x71414
|
||||
#define SWF02 0x71418
|
||||
#define SWF03 0x7141c
|
||||
#define SWF04 0x71420
|
||||
#define SWF05 0x71424
|
||||
#define SWF06 0x71428
|
||||
#define SWF10 0x70410
|
||||
#define SWF11 0x70414
|
||||
#define SWF14 0x71420
|
||||
#define SWF30 0x72414
|
||||
#define SWF31 0x72418
|
||||
#define SWF32 0x7241c
|
||||
#define SWF00 (dev_priv->info->display_mmio_offset + 0x71410)
|
||||
#define SWF01 (dev_priv->info->display_mmio_offset + 0x71414)
|
||||
#define SWF02 (dev_priv->info->display_mmio_offset + 0x71418)
|
||||
#define SWF03 (dev_priv->info->display_mmio_offset + 0x7141c)
|
||||
#define SWF04 (dev_priv->info->display_mmio_offset + 0x71420)
|
||||
#define SWF05 (dev_priv->info->display_mmio_offset + 0x71424)
|
||||
#define SWF06 (dev_priv->info->display_mmio_offset + 0x71428)
|
||||
#define SWF10 (dev_priv->info->display_mmio_offset + 0x70410)
|
||||
#define SWF11 (dev_priv->info->display_mmio_offset + 0x70414)
|
||||
#define SWF14 (dev_priv->info->display_mmio_offset + 0x71420)
|
||||
#define SWF30 (dev_priv->info->display_mmio_offset + 0x72414)
|
||||
#define SWF31 (dev_priv->info->display_mmio_offset + 0x72418)
|
||||
#define SWF32 (dev_priv->info->display_mmio_offset + 0x7241c)
|
||||
|
||||
/* Pipe B */
|
||||
#define _PIPEBDSL 0x71000
|
||||
#define _PIPEBCONF 0x71008
|
||||
#define _PIPEBSTAT 0x71024
|
||||
#define _PIPEBFRAMEHIGH 0x71040
|
||||
#define _PIPEBFRAMEPIXEL 0x71044
|
||||
#define _PIPEBDSL (dev_priv->info->display_mmio_offset + 0x71000)
|
||||
#define _PIPEBCONF (dev_priv->info->display_mmio_offset + 0x71008)
|
||||
#define _PIPEBSTAT (dev_priv->info->display_mmio_offset + 0x71024)
|
||||
#define _PIPEBFRAMEHIGH (dev_priv->info->display_mmio_offset + 0x71040)
|
||||
#define _PIPEBFRAMEPIXEL (dev_priv->info->display_mmio_offset + 0x71044)
|
||||
#define _PIPEB_FRMCOUNT_GM45 0x71040
|
||||
#define _PIPEB_FLIPCOUNT_GM45 0x71044
|
||||
|
||||
|
||||
/* Display B control */
|
||||
#define _DSPBCNTR 0x71180
|
||||
#define _DSPBCNTR (dev_priv->info->display_mmio_offset + 0x71180)
|
||||
#define DISPPLANE_ALPHA_TRANS_ENABLE (1<<15)
|
||||
#define DISPPLANE_ALPHA_TRANS_DISABLE 0
|
||||
#define DISPPLANE_SPRITE_ABOVE_DISPLAY 0
|
||||
#define DISPPLANE_SPRITE_ABOVE_OVERLAY (1)
|
||||
#define _DSPBADDR 0x71184
|
||||
#define _DSPBSTRIDE 0x71188
|
||||
#define _DSPBPOS 0x7118C
|
||||
#define _DSPBSIZE 0x71190
|
||||
#define _DSPBSURF 0x7119C
|
||||
#define _DSPBTILEOFF 0x711A4
|
||||
#define _DSPBOFFSET 0x711A4
|
||||
#define _DSPBSURFLIVE 0x711AC
|
||||
#define _DSPBADDR (dev_priv->info->display_mmio_offset + 0x71184)
|
||||
#define _DSPBSTRIDE (dev_priv->info->display_mmio_offset + 0x71188)
|
||||
#define _DSPBPOS (dev_priv->info->display_mmio_offset + 0x7118C)
|
||||
#define _DSPBSIZE (dev_priv->info->display_mmio_offset + 0x71190)
|
||||
#define _DSPBSURF (dev_priv->info->display_mmio_offset + 0x7119C)
|
||||
#define _DSPBTILEOFF (dev_priv->info->display_mmio_offset + 0x711A4)
|
||||
#define _DSPBOFFSET (dev_priv->info->display_mmio_offset + 0x711A4)
|
||||
#define _DSPBSURFLIVE (dev_priv->info->display_mmio_offset + 0x711AC)
|
||||
|
||||
/* Sprite A control */
|
||||
#define _DVSACNTR 0x72180
|
||||
@ -3116,6 +3100,7 @@
|
||||
#define DVS_FORMAT_RGBX101010 (1<<25)
|
||||
#define DVS_FORMAT_RGBX888 (2<<25)
|
||||
#define DVS_FORMAT_RGBX161616 (3<<25)
|
||||
#define DVS_PIPE_CSC_ENABLE (1<<24)
|
||||
#define DVS_SOURCE_KEY (1<<22)
|
||||
#define DVS_RGB_ORDER_XBGR (1<<20)
|
||||
#define DVS_YUV_BYTE_ORDER_MASK (3<<16)
|
||||
@ -3183,7 +3168,7 @@
|
||||
#define SPRITE_FORMAT_RGBX161616 (3<<25)
|
||||
#define SPRITE_FORMAT_YUV444 (4<<25)
|
||||
#define SPRITE_FORMAT_XR_BGR101010 (5<<25) /* Extended range */
|
||||
#define SPRITE_CSC_ENABLE (1<<24)
|
||||
#define SPRITE_PIPE_CSC_ENABLE (1<<24)
|
||||
#define SPRITE_SOURCE_KEY (1<<22)
|
||||
#define SPRITE_RGB_ORDER_RGBX (1<<20) /* only for 888 and 161616 */
|
||||
#define SPRITE_YUV_TO_RGB_CSC_DISABLE (1<<19)
|
||||
@ -3254,6 +3239,8 @@
|
||||
# define VGA_2X_MODE (1 << 30)
|
||||
# define VGA_PIPE_B_SELECT (1 << 29)
|
||||
|
||||
#define VLV_VGACNTRL (VLV_DISPLAY_BASE + 0x71400)
|
||||
|
||||
/* Ironlake */
|
||||
|
||||
#define CPU_VGACNTRL 0x41000
|
||||
@ -3294,41 +3281,41 @@
|
||||
#define FDI_PLL_FREQ_DISABLE_COUNT_LIMIT_MASK 0xff
|
||||
|
||||
|
||||
#define _PIPEA_DATA_M1 0x60030
|
||||
#define _PIPEA_DATA_M1 (dev_priv->info->display_mmio_offset + 0x60030)
|
||||
#define TU_SIZE(x) (((x)-1) << 25) /* default size 64 */
|
||||
#define TU_SIZE_MASK 0x7e000000
|
||||
#define PIPE_DATA_M1_OFFSET 0
|
||||
#define _PIPEA_DATA_N1 0x60034
|
||||
#define _PIPEA_DATA_N1 (dev_priv->info->display_mmio_offset + 0x60034)
|
||||
#define PIPE_DATA_N1_OFFSET 0
|
||||
|
||||
#define _PIPEA_DATA_M2 0x60038
|
||||
#define _PIPEA_DATA_M2 (dev_priv->info->display_mmio_offset + 0x60038)
|
||||
#define PIPE_DATA_M2_OFFSET 0
|
||||
#define _PIPEA_DATA_N2 0x6003c
|
||||
#define _PIPEA_DATA_N2 (dev_priv->info->display_mmio_offset + 0x6003c)
|
||||
#define PIPE_DATA_N2_OFFSET 0
|
||||
|
||||
#define _PIPEA_LINK_M1 0x60040
|
||||
#define _PIPEA_LINK_M1 (dev_priv->info->display_mmio_offset + 0x60040)
|
||||
#define PIPE_LINK_M1_OFFSET 0
|
||||
#define _PIPEA_LINK_N1 0x60044
|
||||
#define _PIPEA_LINK_N1 (dev_priv->info->display_mmio_offset + 0x60044)
|
||||
#define PIPE_LINK_N1_OFFSET 0
|
||||
|
||||
#define _PIPEA_LINK_M2 0x60048
|
||||
#define _PIPEA_LINK_M2 (dev_priv->info->display_mmio_offset + 0x60048)
|
||||
#define PIPE_LINK_M2_OFFSET 0
|
||||
#define _PIPEA_LINK_N2 0x6004c
|
||||
#define _PIPEA_LINK_N2 (dev_priv->info->display_mmio_offset + 0x6004c)
|
||||
#define PIPE_LINK_N2_OFFSET 0
|
||||
|
||||
/* PIPEB timing regs are same start from 0x61000 */
|
||||
|
||||
#define _PIPEB_DATA_M1 0x61030
|
||||
#define _PIPEB_DATA_N1 0x61034
|
||||
#define _PIPEB_DATA_M1 (dev_priv->info->display_mmio_offset + 0x61030)
|
||||
#define _PIPEB_DATA_N1 (dev_priv->info->display_mmio_offset + 0x61034)
|
||||
|
||||
#define _PIPEB_DATA_M2 0x61038
|
||||
#define _PIPEB_DATA_N2 0x6103c
|
||||
#define _PIPEB_DATA_M2 (dev_priv->info->display_mmio_offset + 0x61038)
|
||||
#define _PIPEB_DATA_N2 (dev_priv->info->display_mmio_offset + 0x6103c)
|
||||
|
||||
#define _PIPEB_LINK_M1 0x61040
|
||||
#define _PIPEB_LINK_N1 0x61044
|
||||
#define _PIPEB_LINK_M1 (dev_priv->info->display_mmio_offset + 0x61040)
|
||||
#define _PIPEB_LINK_N1 (dev_priv->info->display_mmio_offset + 0x61044)
|
||||
|
||||
#define _PIPEB_LINK_M2 0x61048
|
||||
#define _PIPEB_LINK_N2 0x6104c
|
||||
#define _PIPEB_LINK_M2 (dev_priv->info->display_mmio_offset + 0x61048)
|
||||
#define _PIPEB_LINK_N2 (dev_priv->info->display_mmio_offset + 0x6104c)
|
||||
|
||||
#define PIPE_DATA_M1(tran) _TRANSCODER(tran, _PIPEA_DATA_M1, _PIPEB_DATA_M1)
|
||||
#define PIPE_DATA_N1(tran) _TRANSCODER(tran, _PIPEA_DATA_N1, _PIPEB_DATA_N1)
|
||||
@ -3581,27 +3568,30 @@
|
||||
#define PORTD_PULSE_DURATION_6ms (2 << 18)
|
||||
#define PORTD_PULSE_DURATION_100ms (3 << 18)
|
||||
#define PORTD_PULSE_DURATION_MASK (3 << 18)
|
||||
#define PORTD_HOTPLUG_NO_DETECT (0)
|
||||
#define PORTD_HOTPLUG_SHORT_DETECT (1 << 16)
|
||||
#define PORTD_HOTPLUG_LONG_DETECT (1 << 17)
|
||||
#define PORTD_HOTPLUG_STATUS_MASK (0x3 << 16)
|
||||
#define PORTD_HOTPLUG_NO_DETECT (0 << 16)
|
||||
#define PORTD_HOTPLUG_SHORT_DETECT (1 << 16)
|
||||
#define PORTD_HOTPLUG_LONG_DETECT (2 << 16)
|
||||
#define PORTC_HOTPLUG_ENABLE (1 << 12)
|
||||
#define PORTC_PULSE_DURATION_2ms (0)
|
||||
#define PORTC_PULSE_DURATION_4_5ms (1 << 10)
|
||||
#define PORTC_PULSE_DURATION_6ms (2 << 10)
|
||||
#define PORTC_PULSE_DURATION_100ms (3 << 10)
|
||||
#define PORTC_PULSE_DURATION_MASK (3 << 10)
|
||||
#define PORTC_HOTPLUG_NO_DETECT (0)
|
||||
#define PORTC_HOTPLUG_SHORT_DETECT (1 << 8)
|
||||
#define PORTC_HOTPLUG_LONG_DETECT (1 << 9)
|
||||
#define PORTC_HOTPLUG_STATUS_MASK (0x3 << 8)
|
||||
#define PORTC_HOTPLUG_NO_DETECT (0 << 8)
|
||||
#define PORTC_HOTPLUG_SHORT_DETECT (1 << 8)
|
||||
#define PORTC_HOTPLUG_LONG_DETECT (2 << 8)
|
||||
#define PORTB_HOTPLUG_ENABLE (1 << 4)
|
||||
#define PORTB_PULSE_DURATION_2ms (0)
|
||||
#define PORTB_PULSE_DURATION_4_5ms (1 << 2)
|
||||
#define PORTB_PULSE_DURATION_6ms (2 << 2)
|
||||
#define PORTB_PULSE_DURATION_100ms (3 << 2)
|
||||
#define PORTB_PULSE_DURATION_MASK (3 << 2)
|
||||
#define PORTB_HOTPLUG_NO_DETECT (0)
|
||||
#define PORTB_HOTPLUG_SHORT_DETECT (1 << 0)
|
||||
#define PORTB_HOTPLUG_LONG_DETECT (1 << 1)
|
||||
#define PORTB_HOTPLUG_STATUS_MASK (0x3 << 0)
|
||||
#define PORTB_HOTPLUG_NO_DETECT (0 << 0)
|
||||
#define PORTB_HOTPLUG_SHORT_DETECT (1 << 0)
|
||||
#define PORTB_HOTPLUG_LONG_DETECT (2 << 0)
|
||||
|
||||
#define PCH_GPIOA 0xc5010
|
||||
#define PCH_GPIOB 0xc5014
|
||||
@ -3722,13 +3712,13 @@
|
||||
#define TVIDEO_DIP_DATA(pipe) _PIPE(pipe, _VIDEO_DIP_DATA_A, _VIDEO_DIP_DATA_B)
|
||||
#define TVIDEO_DIP_GCP(pipe) _PIPE(pipe, _VIDEO_DIP_GCP_A, _VIDEO_DIP_GCP_B)
|
||||
|
||||
#define VLV_VIDEO_DIP_CTL_A 0x60200
|
||||
#define VLV_VIDEO_DIP_DATA_A 0x60208
|
||||
#define VLV_VIDEO_DIP_GDCP_PAYLOAD_A 0x60210
|
||||
#define VLV_VIDEO_DIP_CTL_A (VLV_DISPLAY_BASE + 0x60200)
|
||||
#define VLV_VIDEO_DIP_DATA_A (VLV_DISPLAY_BASE + 0x60208)
|
||||
#define VLV_VIDEO_DIP_GDCP_PAYLOAD_A (VLV_DISPLAY_BASE + 0x60210)
|
||||
|
||||
#define VLV_VIDEO_DIP_CTL_B 0x61170
|
||||
#define VLV_VIDEO_DIP_DATA_B 0x61174
|
||||
#define VLV_VIDEO_DIP_GDCP_PAYLOAD_B 0x61178
|
||||
#define VLV_VIDEO_DIP_CTL_B (VLV_DISPLAY_BASE + 0x61170)
|
||||
#define VLV_VIDEO_DIP_DATA_B (VLV_DISPLAY_BASE + 0x61174)
|
||||
#define VLV_VIDEO_DIP_GDCP_PAYLOAD_B (VLV_DISPLAY_BASE + 0x61178)
|
||||
|
||||
#define VLV_TVIDEO_DIP_CTL(pipe) \
|
||||
_PIPE(pipe, VLV_VIDEO_DIP_CTL_A, VLV_VIDEO_DIP_CTL_B)
|
||||
@ -3820,8 +3810,6 @@
|
||||
#define TRANS_FSYNC_DELAY_HB2 (1<<27)
|
||||
#define TRANS_FSYNC_DELAY_HB3 (2<<27)
|
||||
#define TRANS_FSYNC_DELAY_HB4 (3<<27)
|
||||
#define TRANS_DP_AUDIO_ONLY (1<<26)
|
||||
#define TRANS_DP_VIDEO_AUDIO (0<<26)
|
||||
#define TRANS_INTERLACE_MASK (7<<21)
|
||||
#define TRANS_PROGRESSIVE (0<<21)
|
||||
#define TRANS_INTERLACED (3<<21)
|
||||
@ -3927,7 +3915,7 @@
|
||||
#define FDI_10BPC (1<<16)
|
||||
#define FDI_6BPC (2<<16)
|
||||
#define FDI_12BPC (3<<16)
|
||||
#define FDI_LINK_REVERSE_OVERWRITE (1<<15)
|
||||
#define FDI_RX_LINK_REVERSAL_OVERRIDE (1<<15)
|
||||
#define FDI_DMI_LINK_REVERSE_MASK (1<<14)
|
||||
#define FDI_RX_PLL_ENABLE (1<<13)
|
||||
#define FDI_FS_ERR_CORRECT_ENABLE (1<<11)
|
||||
@ -4020,17 +4008,17 @@
|
||||
#define LVDS_DETECTED (1 << 1)
|
||||
|
||||
/* vlv has 2 sets of panel control regs. */
|
||||
#define PIPEA_PP_STATUS 0x61200
|
||||
#define PIPEA_PP_CONTROL 0x61204
|
||||
#define PIPEA_PP_ON_DELAYS 0x61208
|
||||
#define PIPEA_PP_OFF_DELAYS 0x6120c
|
||||
#define PIPEA_PP_DIVISOR 0x61210
|
||||
#define PIPEA_PP_STATUS (VLV_DISPLAY_BASE + 0x61200)
|
||||
#define PIPEA_PP_CONTROL (VLV_DISPLAY_BASE + 0x61204)
|
||||
#define PIPEA_PP_ON_DELAYS (VLV_DISPLAY_BASE + 0x61208)
|
||||
#define PIPEA_PP_OFF_DELAYS (VLV_DISPLAY_BASE + 0x6120c)
|
||||
#define PIPEA_PP_DIVISOR (VLV_DISPLAY_BASE + 0x61210)
|
||||
|
||||
#define PIPEB_PP_STATUS 0x61300
|
||||
#define PIPEB_PP_CONTROL 0x61304
|
||||
#define PIPEB_PP_ON_DELAYS 0x61308
|
||||
#define PIPEB_PP_OFF_DELAYS 0x6130c
|
||||
#define PIPEB_PP_DIVISOR 0x61310
|
||||
#define PIPEB_PP_STATUS (VLV_DISPLAY_BASE + 0x61300)
|
||||
#define PIPEB_PP_CONTROL (VLV_DISPLAY_BASE + 0x61304)
|
||||
#define PIPEB_PP_ON_DELAYS (VLV_DISPLAY_BASE + 0x61308)
|
||||
#define PIPEB_PP_OFF_DELAYS (VLV_DISPLAY_BASE + 0x6130c)
|
||||
#define PIPEB_PP_DIVISOR (VLV_DISPLAY_BASE + 0x61310)
|
||||
|
||||
#define PCH_PP_STATUS 0xc7200
|
||||
#define PCH_PP_CONTROL 0xc7204
|
||||
@ -4211,7 +4199,9 @@
|
||||
#define GEN6_RP_INTERRUPT_LIMITS 0xA014
|
||||
#define GEN6_RPSTAT1 0xA01C
|
||||
#define GEN6_CAGF_SHIFT 8
|
||||
#define HSW_CAGF_SHIFT 7
|
||||
#define GEN6_CAGF_MASK (0x7f << GEN6_CAGF_SHIFT)
|
||||
#define HSW_CAGF_MASK (0x7f << HSW_CAGF_SHIFT)
|
||||
#define GEN6_RP_CONTROL 0xA024
|
||||
#define GEN6_RP_MEDIA_TURBO (1<<11)
|
||||
#define GEN6_RP_MEDIA_MODE_MASK (3<<9)
|
||||
@ -4280,8 +4270,8 @@
|
||||
#define GEN6_PCODE_READ_MIN_FREQ_TABLE 0x9
|
||||
#define GEN6_PCODE_WRITE_RC6VIDS 0x4
|
||||
#define GEN6_PCODE_READ_RC6VIDS 0x5
|
||||
#define GEN6_ENCODE_RC6_VID(mv) (((mv) / 5) - 245) < 0 ?: 0
|
||||
#define GEN6_DECODE_RC6_VID(vids) (((vids) * 5) > 0 ? ((vids) * 5) + 245 : 0)
|
||||
#define GEN6_ENCODE_RC6_VID(mv) (((mv) - 245) / 5)
|
||||
#define GEN6_DECODE_RC6_VID(vids) (((vids) * 5) + 245)
|
||||
#define GEN6_PCODE_DATA 0x138128
|
||||
#define GEN6_PCODE_FREQ_IA_RATIO_SHIFT 8
|
||||
|
||||
@ -4322,7 +4312,7 @@
|
||||
#define GEN7_ROW_CHICKEN2_GT2 0xf4f4
|
||||
#define DOP_CLOCK_GATING_DISABLE (1<<0)
|
||||
|
||||
#define G4X_AUD_VID_DID 0x62020
|
||||
#define G4X_AUD_VID_DID (dev_priv->info->display_mmio_offset + 0x62020)
|
||||
#define INTEL_AUDIO_DEVCL 0x808629FB
|
||||
#define INTEL_AUDIO_DEVBLC 0x80862801
|
||||
#define INTEL_AUDIO_DEVCTG 0x80862802
|
||||
@ -4438,10 +4428,10 @@
|
||||
#define AUDIO_CP_READY_C (1<<9)
|
||||
|
||||
/* HSW Power Wells */
|
||||
#define HSW_PWR_WELL_CTL1 0x45400 /* BIOS */
|
||||
#define HSW_PWR_WELL_CTL2 0x45404 /* Driver */
|
||||
#define HSW_PWR_WELL_CTL3 0x45408 /* KVMR */
|
||||
#define HSW_PWR_WELL_CTL4 0x4540C /* Debug */
|
||||
#define HSW_PWR_WELL_BIOS 0x45400 /* CTL1 */
|
||||
#define HSW_PWR_WELL_DRIVER 0x45404 /* CTL2 */
|
||||
#define HSW_PWR_WELL_KVMR 0x45408 /* CTL3 */
|
||||
#define HSW_PWR_WELL_DEBUG 0x4540C /* CTL4 */
|
||||
#define HSW_PWR_WELL_ENABLE (1<<31)
|
||||
#define HSW_PWR_WELL_STATE (1<<30)
|
||||
#define HSW_PWR_WELL_CTL5 0x45410
|
||||
@ -4524,6 +4514,7 @@
|
||||
#define DDI_BUF_EMP_800MV_0DB_HSW (7<<24) /* Sel7 */
|
||||
#define DDI_BUF_EMP_800MV_3_5DB_HSW (8<<24) /* Sel8 */
|
||||
#define DDI_BUF_EMP_MASK (0xf<<24)
|
||||
#define DDI_BUF_PORT_REVERSAL (1<<16)
|
||||
#define DDI_BUF_IS_IDLE (1<<7)
|
||||
#define DDI_A_4_LANES (1<<4)
|
||||
#define DDI_PORT_WIDTH_X1 (0<<1)
|
||||
@ -4657,4 +4648,51 @@
|
||||
#define WM_DBG_DISALLOW_MAXFIFO (1<<1)
|
||||
#define WM_DBG_DISALLOW_SPRITE (1<<2)
|
||||
|
||||
/* pipe CSC */
|
||||
#define _PIPE_A_CSC_COEFF_RY_GY 0x49010
|
||||
#define _PIPE_A_CSC_COEFF_BY 0x49014
|
||||
#define _PIPE_A_CSC_COEFF_RU_GU 0x49018
|
||||
#define _PIPE_A_CSC_COEFF_BU 0x4901c
|
||||
#define _PIPE_A_CSC_COEFF_RV_GV 0x49020
|
||||
#define _PIPE_A_CSC_COEFF_BV 0x49024
|
||||
#define _PIPE_A_CSC_MODE 0x49028
|
||||
#define _PIPE_A_CSC_PREOFF_HI 0x49030
|
||||
#define _PIPE_A_CSC_PREOFF_ME 0x49034
|
||||
#define _PIPE_A_CSC_PREOFF_LO 0x49038
|
||||
#define _PIPE_A_CSC_POSTOFF_HI 0x49040
|
||||
#define _PIPE_A_CSC_POSTOFF_ME 0x49044
|
||||
#define _PIPE_A_CSC_POSTOFF_LO 0x49048
|
||||
|
||||
#define _PIPE_B_CSC_COEFF_RY_GY 0x49110
|
||||
#define _PIPE_B_CSC_COEFF_BY 0x49114
|
||||
#define _PIPE_B_CSC_COEFF_RU_GU 0x49118
|
||||
#define _PIPE_B_CSC_COEFF_BU 0x4911c
|
||||
#define _PIPE_B_CSC_COEFF_RV_GV 0x49120
|
||||
#define _PIPE_B_CSC_COEFF_BV 0x49124
|
||||
#define _PIPE_B_CSC_MODE 0x49128
|
||||
#define _PIPE_B_CSC_PREOFF_HI 0x49130
|
||||
#define _PIPE_B_CSC_PREOFF_ME 0x49134
|
||||
#define _PIPE_B_CSC_PREOFF_LO 0x49138
|
||||
#define _PIPE_B_CSC_POSTOFF_HI 0x49140
|
||||
#define _PIPE_B_CSC_POSTOFF_ME 0x49144
|
||||
#define _PIPE_B_CSC_POSTOFF_LO 0x49148
|
||||
|
||||
#define CSC_BLACK_SCREEN_OFFSET (1 << 2)
|
||||
#define CSC_POSITION_BEFORE_GAMMA (1 << 1)
|
||||
#define CSC_MODE_YUV_TO_RGB (1 << 0)
|
||||
|
||||
#define PIPE_CSC_COEFF_RY_GY(pipe) _PIPE(pipe, _PIPE_A_CSC_COEFF_RY_GY, _PIPE_B_CSC_COEFF_RY_GY)
|
||||
#define PIPE_CSC_COEFF_BY(pipe) _PIPE(pipe, _PIPE_A_CSC_COEFF_BY, _PIPE_B_CSC_COEFF_BY)
|
||||
#define PIPE_CSC_COEFF_RU_GU(pipe) _PIPE(pipe, _PIPE_A_CSC_COEFF_RU_GU, _PIPE_B_CSC_COEFF_RU_GU)
|
||||
#define PIPE_CSC_COEFF_BU(pipe) _PIPE(pipe, _PIPE_A_CSC_COEFF_BU, _PIPE_B_CSC_COEFF_BU)
|
||||
#define PIPE_CSC_COEFF_RV_GV(pipe) _PIPE(pipe, _PIPE_A_CSC_COEFF_RV_GV, _PIPE_B_CSC_COEFF_RV_GV)
|
||||
#define PIPE_CSC_COEFF_BV(pipe) _PIPE(pipe, _PIPE_A_CSC_COEFF_BV, _PIPE_B_CSC_COEFF_BV)
|
||||
#define PIPE_CSC_MODE(pipe) _PIPE(pipe, _PIPE_A_CSC_MODE, _PIPE_B_CSC_MODE)
|
||||
#define PIPE_CSC_PREOFF_HI(pipe) _PIPE(pipe, _PIPE_A_CSC_PREOFF_HI, _PIPE_B_CSC_PREOFF_HI)
|
||||
#define PIPE_CSC_PREOFF_ME(pipe) _PIPE(pipe, _PIPE_A_CSC_PREOFF_ME, _PIPE_B_CSC_PREOFF_ME)
|
||||
#define PIPE_CSC_PREOFF_LO(pipe) _PIPE(pipe, _PIPE_A_CSC_PREOFF_LO, _PIPE_B_CSC_PREOFF_LO)
|
||||
#define PIPE_CSC_POSTOFF_HI(pipe) _PIPE(pipe, _PIPE_A_CSC_POSTOFF_HI, _PIPE_B_CSC_POSTOFF_HI)
|
||||
#define PIPE_CSC_POSTOFF_ME(pipe) _PIPE(pipe, _PIPE_A_CSC_POSTOFF_ME, _PIPE_B_CSC_POSTOFF_ME)
|
||||
#define PIPE_CSC_POSTOFF_LO(pipe) _PIPE(pipe, _PIPE_A_CSC_POSTOFF_LO, _PIPE_B_CSC_POSTOFF_LO)
|
||||
|
||||
#endif /* _I915_REG_H_ */
|
||||
|
@ -29,67 +29,6 @@
|
||||
#include "intel_drv.h"
|
||||
#include "i915_reg.h"
|
||||
|
||||
static bool i915_pipe_enabled(struct drm_device *dev, enum pipe pipe)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
u32 dpll_reg;
|
||||
|
||||
/* On IVB, 3rd pipe shares PLL with another one */
|
||||
if (pipe > 1)
|
||||
return false;
|
||||
|
||||
if (HAS_PCH_SPLIT(dev))
|
||||
dpll_reg = _PCH_DPLL(pipe);
|
||||
else
|
||||
dpll_reg = (pipe == PIPE_A) ? _DPLL_A : _DPLL_B;
|
||||
|
||||
return (I915_READ(dpll_reg) & DPLL_VCO_ENABLE);
|
||||
}
|
||||
|
||||
static void i915_save_palette(struct drm_device *dev, enum pipe pipe)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
unsigned long reg = (pipe == PIPE_A ? _PALETTE_A : _PALETTE_B);
|
||||
u32 *array;
|
||||
int i;
|
||||
|
||||
if (!i915_pipe_enabled(dev, pipe))
|
||||
return;
|
||||
|
||||
if (HAS_PCH_SPLIT(dev))
|
||||
reg = (pipe == PIPE_A) ? _LGC_PALETTE_A : _LGC_PALETTE_B;
|
||||
|
||||
if (pipe == PIPE_A)
|
||||
array = dev_priv->regfile.save_palette_a;
|
||||
else
|
||||
array = dev_priv->regfile.save_palette_b;
|
||||
|
||||
for (i = 0; i < 256; i++)
|
||||
array[i] = I915_READ(reg + (i << 2));
|
||||
}
|
||||
|
||||
static void i915_restore_palette(struct drm_device *dev, enum pipe pipe)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
unsigned long reg = (pipe == PIPE_A ? _PALETTE_A : _PALETTE_B);
|
||||
u32 *array;
|
||||
int i;
|
||||
|
||||
if (!i915_pipe_enabled(dev, pipe))
|
||||
return;
|
||||
|
||||
if (HAS_PCH_SPLIT(dev))
|
||||
reg = (pipe == PIPE_A) ? _LGC_PALETTE_A : _LGC_PALETTE_B;
|
||||
|
||||
if (pipe == PIPE_A)
|
||||
array = dev_priv->regfile.save_palette_a;
|
||||
else
|
||||
array = dev_priv->regfile.save_palette_b;
|
||||
|
||||
for (i = 0; i < 256; i++)
|
||||
I915_WRITE(reg + (i << 2), array[i]);
|
||||
}
|
||||
|
||||
static u8 i915_read_indexed(struct drm_device *dev, u16 index_port, u16 data_port, u8 reg)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
@ -130,6 +69,12 @@ static void i915_save_vga(struct drm_device *dev)
|
||||
int i;
|
||||
u16 cr_index, cr_data, st01;
|
||||
|
||||
/* VGA state */
|
||||
dev_priv->regfile.saveVGA0 = I915_READ(VGA0);
|
||||
dev_priv->regfile.saveVGA1 = I915_READ(VGA1);
|
||||
dev_priv->regfile.saveVGA_PD = I915_READ(VGA_PD);
|
||||
dev_priv->regfile.saveVGACNTRL = I915_READ(i915_vgacntrl_reg(dev));
|
||||
|
||||
/* VGA color palette registers */
|
||||
dev_priv->regfile.saveDACMASK = I915_READ8(VGA_DACMASK);
|
||||
|
||||
@ -188,6 +133,15 @@ static void i915_restore_vga(struct drm_device *dev)
|
||||
int i;
|
||||
u16 cr_index, cr_data, st01;
|
||||
|
||||
/* VGA state */
|
||||
I915_WRITE(i915_vgacntrl_reg(dev), dev_priv->regfile.saveVGACNTRL);
|
||||
|
||||
I915_WRITE(VGA0, dev_priv->regfile.saveVGA0);
|
||||
I915_WRITE(VGA1, dev_priv->regfile.saveVGA1);
|
||||
I915_WRITE(VGA_PD, dev_priv->regfile.saveVGA_PD);
|
||||
POSTING_READ(VGA_PD);
|
||||
udelay(150);
|
||||
|
||||
/* MSR bits */
|
||||
I915_WRITE8(VGA_MSR_WRITE, dev_priv->regfile.saveMSR);
|
||||
if (dev_priv->regfile.saveMSR & VGA_MSR_CGA_MODE) {
|
||||
@ -235,396 +189,18 @@ static void i915_restore_vga(struct drm_device *dev)
|
||||
I915_WRITE8(VGA_DACMASK, dev_priv->regfile.saveDACMASK);
|
||||
}
|
||||
|
||||
static void i915_save_modeset_reg(struct drm_device *dev)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
int i;
|
||||
|
||||
if (drm_core_check_feature(dev, DRIVER_MODESET))
|
||||
return;
|
||||
|
||||
/* Cursor state */
|
||||
dev_priv->regfile.saveCURACNTR = I915_READ(_CURACNTR);
|
||||
dev_priv->regfile.saveCURAPOS = I915_READ(_CURAPOS);
|
||||
dev_priv->regfile.saveCURABASE = I915_READ(_CURABASE);
|
||||
dev_priv->regfile.saveCURBCNTR = I915_READ(_CURBCNTR);
|
||||
dev_priv->regfile.saveCURBPOS = I915_READ(_CURBPOS);
|
||||
dev_priv->regfile.saveCURBBASE = I915_READ(_CURBBASE);
|
||||
if (IS_GEN2(dev))
|
||||
dev_priv->regfile.saveCURSIZE = I915_READ(CURSIZE);
|
||||
|
||||
if (HAS_PCH_SPLIT(dev)) {
|
||||
dev_priv->regfile.savePCH_DREF_CONTROL = I915_READ(PCH_DREF_CONTROL);
|
||||
dev_priv->regfile.saveDISP_ARB_CTL = I915_READ(DISP_ARB_CTL);
|
||||
}
|
||||
|
||||
/* Pipe & plane A info */
|
||||
dev_priv->regfile.savePIPEACONF = I915_READ(_PIPEACONF);
|
||||
dev_priv->regfile.savePIPEASRC = I915_READ(_PIPEASRC);
|
||||
if (HAS_PCH_SPLIT(dev)) {
|
||||
dev_priv->regfile.saveFPA0 = I915_READ(_PCH_FPA0);
|
||||
dev_priv->regfile.saveFPA1 = I915_READ(_PCH_FPA1);
|
||||
dev_priv->regfile.saveDPLL_A = I915_READ(_PCH_DPLL_A);
|
||||
} else {
|
||||
dev_priv->regfile.saveFPA0 = I915_READ(_FPA0);
|
||||
dev_priv->regfile.saveFPA1 = I915_READ(_FPA1);
|
||||
dev_priv->regfile.saveDPLL_A = I915_READ(_DPLL_A);
|
||||
}
|
||||
if (INTEL_INFO(dev)->gen >= 4 && !HAS_PCH_SPLIT(dev))
|
||||
dev_priv->regfile.saveDPLL_A_MD = I915_READ(_DPLL_A_MD);
|
||||
dev_priv->regfile.saveHTOTAL_A = I915_READ(_HTOTAL_A);
|
||||
dev_priv->regfile.saveHBLANK_A = I915_READ(_HBLANK_A);
|
||||
dev_priv->regfile.saveHSYNC_A = I915_READ(_HSYNC_A);
|
||||
dev_priv->regfile.saveVTOTAL_A = I915_READ(_VTOTAL_A);
|
||||
dev_priv->regfile.saveVBLANK_A = I915_READ(_VBLANK_A);
|
||||
dev_priv->regfile.saveVSYNC_A = I915_READ(_VSYNC_A);
|
||||
if (!HAS_PCH_SPLIT(dev))
|
||||
dev_priv->regfile.saveBCLRPAT_A = I915_READ(_BCLRPAT_A);
|
||||
|
||||
if (HAS_PCH_SPLIT(dev)) {
|
||||
dev_priv->regfile.savePIPEA_DATA_M1 = I915_READ(_PIPEA_DATA_M1);
|
||||
dev_priv->regfile.savePIPEA_DATA_N1 = I915_READ(_PIPEA_DATA_N1);
|
||||
dev_priv->regfile.savePIPEA_LINK_M1 = I915_READ(_PIPEA_LINK_M1);
|
||||
dev_priv->regfile.savePIPEA_LINK_N1 = I915_READ(_PIPEA_LINK_N1);
|
||||
|
||||
dev_priv->regfile.saveFDI_TXA_CTL = I915_READ(_FDI_TXA_CTL);
|
||||
dev_priv->regfile.saveFDI_RXA_CTL = I915_READ(_FDI_RXA_CTL);
|
||||
|
||||
dev_priv->regfile.savePFA_CTL_1 = I915_READ(_PFA_CTL_1);
|
||||
dev_priv->regfile.savePFA_WIN_SZ = I915_READ(_PFA_WIN_SZ);
|
||||
dev_priv->regfile.savePFA_WIN_POS = I915_READ(_PFA_WIN_POS);
|
||||
|
||||
dev_priv->regfile.saveTRANSACONF = I915_READ(_TRANSACONF);
|
||||
dev_priv->regfile.saveTRANS_HTOTAL_A = I915_READ(_TRANS_HTOTAL_A);
|
||||
dev_priv->regfile.saveTRANS_HBLANK_A = I915_READ(_TRANS_HBLANK_A);
|
||||
dev_priv->regfile.saveTRANS_HSYNC_A = I915_READ(_TRANS_HSYNC_A);
|
||||
dev_priv->regfile.saveTRANS_VTOTAL_A = I915_READ(_TRANS_VTOTAL_A);
|
||||
dev_priv->regfile.saveTRANS_VBLANK_A = I915_READ(_TRANS_VBLANK_A);
|
||||
dev_priv->regfile.saveTRANS_VSYNC_A = I915_READ(_TRANS_VSYNC_A);
|
||||
}
|
||||
|
||||
dev_priv->regfile.saveDSPACNTR = I915_READ(_DSPACNTR);
|
||||
dev_priv->regfile.saveDSPASTRIDE = I915_READ(_DSPASTRIDE);
|
||||
dev_priv->regfile.saveDSPASIZE = I915_READ(_DSPASIZE);
|
||||
dev_priv->regfile.saveDSPAPOS = I915_READ(_DSPAPOS);
|
||||
dev_priv->regfile.saveDSPAADDR = I915_READ(_DSPAADDR);
|
||||
if (INTEL_INFO(dev)->gen >= 4) {
|
||||
dev_priv->regfile.saveDSPASURF = I915_READ(_DSPASURF);
|
||||
dev_priv->regfile.saveDSPATILEOFF = I915_READ(_DSPATILEOFF);
|
||||
}
|
||||
i915_save_palette(dev, PIPE_A);
|
||||
dev_priv->regfile.savePIPEASTAT = I915_READ(_PIPEASTAT);
|
||||
|
||||
/* Pipe & plane B info */
|
||||
dev_priv->regfile.savePIPEBCONF = I915_READ(_PIPEBCONF);
|
||||
dev_priv->regfile.savePIPEBSRC = I915_READ(_PIPEBSRC);
|
||||
if (HAS_PCH_SPLIT(dev)) {
|
||||
dev_priv->regfile.saveFPB0 = I915_READ(_PCH_FPB0);
|
||||
dev_priv->regfile.saveFPB1 = I915_READ(_PCH_FPB1);
|
||||
dev_priv->regfile.saveDPLL_B = I915_READ(_PCH_DPLL_B);
|
||||
} else {
|
||||
dev_priv->regfile.saveFPB0 = I915_READ(_FPB0);
|
||||
dev_priv->regfile.saveFPB1 = I915_READ(_FPB1);
|
||||
dev_priv->regfile.saveDPLL_B = I915_READ(_DPLL_B);
|
||||
}
|
||||
if (INTEL_INFO(dev)->gen >= 4 && !HAS_PCH_SPLIT(dev))
|
||||
dev_priv->regfile.saveDPLL_B_MD = I915_READ(_DPLL_B_MD);
|
||||
dev_priv->regfile.saveHTOTAL_B = I915_READ(_HTOTAL_B);
|
||||
dev_priv->regfile.saveHBLANK_B = I915_READ(_HBLANK_B);
|
||||
dev_priv->regfile.saveHSYNC_B = I915_READ(_HSYNC_B);
|
||||
dev_priv->regfile.saveVTOTAL_B = I915_READ(_VTOTAL_B);
|
||||
dev_priv->regfile.saveVBLANK_B = I915_READ(_VBLANK_B);
|
||||
dev_priv->regfile.saveVSYNC_B = I915_READ(_VSYNC_B);
|
||||
if (!HAS_PCH_SPLIT(dev))
|
||||
dev_priv->regfile.saveBCLRPAT_B = I915_READ(_BCLRPAT_B);
|
||||
|
||||
if (HAS_PCH_SPLIT(dev)) {
|
||||
dev_priv->regfile.savePIPEB_DATA_M1 = I915_READ(_PIPEB_DATA_M1);
|
||||
dev_priv->regfile.savePIPEB_DATA_N1 = I915_READ(_PIPEB_DATA_N1);
|
||||
dev_priv->regfile.savePIPEB_LINK_M1 = I915_READ(_PIPEB_LINK_M1);
|
||||
dev_priv->regfile.savePIPEB_LINK_N1 = I915_READ(_PIPEB_LINK_N1);
|
||||
|
||||
dev_priv->regfile.saveFDI_TXB_CTL = I915_READ(_FDI_TXB_CTL);
|
||||
dev_priv->regfile.saveFDI_RXB_CTL = I915_READ(_FDI_RXB_CTL);
|
||||
|
||||
dev_priv->regfile.savePFB_CTL_1 = I915_READ(_PFB_CTL_1);
|
||||
dev_priv->regfile.savePFB_WIN_SZ = I915_READ(_PFB_WIN_SZ);
|
||||
dev_priv->regfile.savePFB_WIN_POS = I915_READ(_PFB_WIN_POS);
|
||||
|
||||
dev_priv->regfile.saveTRANSBCONF = I915_READ(_TRANSBCONF);
|
||||
dev_priv->regfile.saveTRANS_HTOTAL_B = I915_READ(_TRANS_HTOTAL_B);
|
||||
dev_priv->regfile.saveTRANS_HBLANK_B = I915_READ(_TRANS_HBLANK_B);
|
||||
dev_priv->regfile.saveTRANS_HSYNC_B = I915_READ(_TRANS_HSYNC_B);
|
||||
dev_priv->regfile.saveTRANS_VTOTAL_B = I915_READ(_TRANS_VTOTAL_B);
|
||||
dev_priv->regfile.saveTRANS_VBLANK_B = I915_READ(_TRANS_VBLANK_B);
|
||||
dev_priv->regfile.saveTRANS_VSYNC_B = I915_READ(_TRANS_VSYNC_B);
|
||||
}
|
||||
|
||||
dev_priv->regfile.saveDSPBCNTR = I915_READ(_DSPBCNTR);
|
||||
dev_priv->regfile.saveDSPBSTRIDE = I915_READ(_DSPBSTRIDE);
|
||||
dev_priv->regfile.saveDSPBSIZE = I915_READ(_DSPBSIZE);
|
||||
dev_priv->regfile.saveDSPBPOS = I915_READ(_DSPBPOS);
|
||||
dev_priv->regfile.saveDSPBADDR = I915_READ(_DSPBADDR);
|
||||
if (INTEL_INFO(dev)->gen >= 4) {
|
||||
dev_priv->regfile.saveDSPBSURF = I915_READ(_DSPBSURF);
|
||||
dev_priv->regfile.saveDSPBTILEOFF = I915_READ(_DSPBTILEOFF);
|
||||
}
|
||||
i915_save_palette(dev, PIPE_B);
|
||||
dev_priv->regfile.savePIPEBSTAT = I915_READ(_PIPEBSTAT);
|
||||
|
||||
/* Fences */
|
||||
switch (INTEL_INFO(dev)->gen) {
|
||||
case 7:
|
||||
case 6:
|
||||
for (i = 0; i < 16; i++)
|
||||
dev_priv->regfile.saveFENCE[i] = I915_READ64(FENCE_REG_SANDYBRIDGE_0 + (i * 8));
|
||||
break;
|
||||
case 5:
|
||||
case 4:
|
||||
for (i = 0; i < 16; i++)
|
||||
dev_priv->regfile.saveFENCE[i] = I915_READ64(FENCE_REG_965_0 + (i * 8));
|
||||
break;
|
||||
case 3:
|
||||
if (IS_I945G(dev) || IS_I945GM(dev) || IS_G33(dev))
|
||||
for (i = 0; i < 8; i++)
|
||||
dev_priv->regfile.saveFENCE[i+8] = I915_READ(FENCE_REG_945_8 + (i * 4));
|
||||
case 2:
|
||||
for (i = 0; i < 8; i++)
|
||||
dev_priv->regfile.saveFENCE[i] = I915_READ(FENCE_REG_830_0 + (i * 4));
|
||||
break;
|
||||
}
|
||||
|
||||
/* CRT state */
|
||||
if (HAS_PCH_SPLIT(dev))
|
||||
dev_priv->regfile.saveADPA = I915_READ(PCH_ADPA);
|
||||
else
|
||||
dev_priv->regfile.saveADPA = I915_READ(ADPA);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static void i915_restore_modeset_reg(struct drm_device *dev)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
int dpll_a_reg, fpa0_reg, fpa1_reg;
|
||||
int dpll_b_reg, fpb0_reg, fpb1_reg;
|
||||
int i;
|
||||
|
||||
if (drm_core_check_feature(dev, DRIVER_MODESET))
|
||||
return;
|
||||
|
||||
/* Fences */
|
||||
switch (INTEL_INFO(dev)->gen) {
|
||||
case 7:
|
||||
case 6:
|
||||
for (i = 0; i < 16; i++)
|
||||
I915_WRITE64(FENCE_REG_SANDYBRIDGE_0 + (i * 8), dev_priv->regfile.saveFENCE[i]);
|
||||
break;
|
||||
case 5:
|
||||
case 4:
|
||||
for (i = 0; i < 16; i++)
|
||||
I915_WRITE64(FENCE_REG_965_0 + (i * 8), dev_priv->regfile.saveFENCE[i]);
|
||||
break;
|
||||
case 3:
|
||||
case 2:
|
||||
if (IS_I945G(dev) || IS_I945GM(dev) || IS_G33(dev))
|
||||
for (i = 0; i < 8; i++)
|
||||
I915_WRITE(FENCE_REG_945_8 + (i * 4), dev_priv->regfile.saveFENCE[i+8]);
|
||||
for (i = 0; i < 8; i++)
|
||||
I915_WRITE(FENCE_REG_830_0 + (i * 4), dev_priv->regfile.saveFENCE[i]);
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
if (HAS_PCH_SPLIT(dev)) {
|
||||
dpll_a_reg = _PCH_DPLL_A;
|
||||
dpll_b_reg = _PCH_DPLL_B;
|
||||
fpa0_reg = _PCH_FPA0;
|
||||
fpb0_reg = _PCH_FPB0;
|
||||
fpa1_reg = _PCH_FPA1;
|
||||
fpb1_reg = _PCH_FPB1;
|
||||
} else {
|
||||
dpll_a_reg = _DPLL_A;
|
||||
dpll_b_reg = _DPLL_B;
|
||||
fpa0_reg = _FPA0;
|
||||
fpb0_reg = _FPB0;
|
||||
fpa1_reg = _FPA1;
|
||||
fpb1_reg = _FPB1;
|
||||
}
|
||||
|
||||
if (HAS_PCH_SPLIT(dev)) {
|
||||
I915_WRITE(PCH_DREF_CONTROL, dev_priv->regfile.savePCH_DREF_CONTROL);
|
||||
I915_WRITE(DISP_ARB_CTL, dev_priv->regfile.saveDISP_ARB_CTL);
|
||||
}
|
||||
|
||||
/* Pipe & plane A info */
|
||||
/* Prime the clock */
|
||||
if (dev_priv->regfile.saveDPLL_A & DPLL_VCO_ENABLE) {
|
||||
I915_WRITE(dpll_a_reg, dev_priv->regfile.saveDPLL_A &
|
||||
~DPLL_VCO_ENABLE);
|
||||
POSTING_READ(dpll_a_reg);
|
||||
udelay(150);
|
||||
}
|
||||
I915_WRITE(fpa0_reg, dev_priv->regfile.saveFPA0);
|
||||
I915_WRITE(fpa1_reg, dev_priv->regfile.saveFPA1);
|
||||
/* Actually enable it */
|
||||
I915_WRITE(dpll_a_reg, dev_priv->regfile.saveDPLL_A);
|
||||
POSTING_READ(dpll_a_reg);
|
||||
udelay(150);
|
||||
if (INTEL_INFO(dev)->gen >= 4 && !HAS_PCH_SPLIT(dev)) {
|
||||
I915_WRITE(_DPLL_A_MD, dev_priv->regfile.saveDPLL_A_MD);
|
||||
POSTING_READ(_DPLL_A_MD);
|
||||
}
|
||||
udelay(150);
|
||||
|
||||
/* Restore mode */
|
||||
I915_WRITE(_HTOTAL_A, dev_priv->regfile.saveHTOTAL_A);
|
||||
I915_WRITE(_HBLANK_A, dev_priv->regfile.saveHBLANK_A);
|
||||
I915_WRITE(_HSYNC_A, dev_priv->regfile.saveHSYNC_A);
|
||||
I915_WRITE(_VTOTAL_A, dev_priv->regfile.saveVTOTAL_A);
|
||||
I915_WRITE(_VBLANK_A, dev_priv->regfile.saveVBLANK_A);
|
||||
I915_WRITE(_VSYNC_A, dev_priv->regfile.saveVSYNC_A);
|
||||
if (!HAS_PCH_SPLIT(dev))
|
||||
I915_WRITE(_BCLRPAT_A, dev_priv->regfile.saveBCLRPAT_A);
|
||||
|
||||
if (HAS_PCH_SPLIT(dev)) {
|
||||
I915_WRITE(_PIPEA_DATA_M1, dev_priv->regfile.savePIPEA_DATA_M1);
|
||||
I915_WRITE(_PIPEA_DATA_N1, dev_priv->regfile.savePIPEA_DATA_N1);
|
||||
I915_WRITE(_PIPEA_LINK_M1, dev_priv->regfile.savePIPEA_LINK_M1);
|
||||
I915_WRITE(_PIPEA_LINK_N1, dev_priv->regfile.savePIPEA_LINK_N1);
|
||||
|
||||
I915_WRITE(_FDI_RXA_CTL, dev_priv->regfile.saveFDI_RXA_CTL);
|
||||
I915_WRITE(_FDI_TXA_CTL, dev_priv->regfile.saveFDI_TXA_CTL);
|
||||
|
||||
I915_WRITE(_PFA_CTL_1, dev_priv->regfile.savePFA_CTL_1);
|
||||
I915_WRITE(_PFA_WIN_SZ, dev_priv->regfile.savePFA_WIN_SZ);
|
||||
I915_WRITE(_PFA_WIN_POS, dev_priv->regfile.savePFA_WIN_POS);
|
||||
|
||||
I915_WRITE(_TRANSACONF, dev_priv->regfile.saveTRANSACONF);
|
||||
I915_WRITE(_TRANS_HTOTAL_A, dev_priv->regfile.saveTRANS_HTOTAL_A);
|
||||
I915_WRITE(_TRANS_HBLANK_A, dev_priv->regfile.saveTRANS_HBLANK_A);
|
||||
I915_WRITE(_TRANS_HSYNC_A, dev_priv->regfile.saveTRANS_HSYNC_A);
|
||||
I915_WRITE(_TRANS_VTOTAL_A, dev_priv->regfile.saveTRANS_VTOTAL_A);
|
||||
I915_WRITE(_TRANS_VBLANK_A, dev_priv->regfile.saveTRANS_VBLANK_A);
|
||||
I915_WRITE(_TRANS_VSYNC_A, dev_priv->regfile.saveTRANS_VSYNC_A);
|
||||
}
|
||||
|
||||
/* Restore plane info */
|
||||
I915_WRITE(_DSPASIZE, dev_priv->regfile.saveDSPASIZE);
|
||||
I915_WRITE(_DSPAPOS, dev_priv->regfile.saveDSPAPOS);
|
||||
I915_WRITE(_PIPEASRC, dev_priv->regfile.savePIPEASRC);
|
||||
I915_WRITE(_DSPAADDR, dev_priv->regfile.saveDSPAADDR);
|
||||
I915_WRITE(_DSPASTRIDE, dev_priv->regfile.saveDSPASTRIDE);
|
||||
if (INTEL_INFO(dev)->gen >= 4) {
|
||||
I915_WRITE(_DSPASURF, dev_priv->regfile.saveDSPASURF);
|
||||
I915_WRITE(_DSPATILEOFF, dev_priv->regfile.saveDSPATILEOFF);
|
||||
}
|
||||
|
||||
I915_WRITE(_PIPEACONF, dev_priv->regfile.savePIPEACONF);
|
||||
|
||||
i915_restore_palette(dev, PIPE_A);
|
||||
/* Enable the plane */
|
||||
I915_WRITE(_DSPACNTR, dev_priv->regfile.saveDSPACNTR);
|
||||
I915_WRITE(_DSPAADDR, I915_READ(_DSPAADDR));
|
||||
|
||||
/* Pipe & plane B info */
|
||||
if (dev_priv->regfile.saveDPLL_B & DPLL_VCO_ENABLE) {
|
||||
I915_WRITE(dpll_b_reg, dev_priv->regfile.saveDPLL_B &
|
||||
~DPLL_VCO_ENABLE);
|
||||
POSTING_READ(dpll_b_reg);
|
||||
udelay(150);
|
||||
}
|
||||
I915_WRITE(fpb0_reg, dev_priv->regfile.saveFPB0);
|
||||
I915_WRITE(fpb1_reg, dev_priv->regfile.saveFPB1);
|
||||
/* Actually enable it */
|
||||
I915_WRITE(dpll_b_reg, dev_priv->regfile.saveDPLL_B);
|
||||
POSTING_READ(dpll_b_reg);
|
||||
udelay(150);
|
||||
if (INTEL_INFO(dev)->gen >= 4 && !HAS_PCH_SPLIT(dev)) {
|
||||
I915_WRITE(_DPLL_B_MD, dev_priv->regfile.saveDPLL_B_MD);
|
||||
POSTING_READ(_DPLL_B_MD);
|
||||
}
|
||||
udelay(150);
|
||||
|
||||
/* Restore mode */
|
||||
I915_WRITE(_HTOTAL_B, dev_priv->regfile.saveHTOTAL_B);
|
||||
I915_WRITE(_HBLANK_B, dev_priv->regfile.saveHBLANK_B);
|
||||
I915_WRITE(_HSYNC_B, dev_priv->regfile.saveHSYNC_B);
|
||||
I915_WRITE(_VTOTAL_B, dev_priv->regfile.saveVTOTAL_B);
|
||||
I915_WRITE(_VBLANK_B, dev_priv->regfile.saveVBLANK_B);
|
||||
I915_WRITE(_VSYNC_B, dev_priv->regfile.saveVSYNC_B);
|
||||
if (!HAS_PCH_SPLIT(dev))
|
||||
I915_WRITE(_BCLRPAT_B, dev_priv->regfile.saveBCLRPAT_B);
|
||||
|
||||
if (HAS_PCH_SPLIT(dev)) {
|
||||
I915_WRITE(_PIPEB_DATA_M1, dev_priv->regfile.savePIPEB_DATA_M1);
|
||||
I915_WRITE(_PIPEB_DATA_N1, dev_priv->regfile.savePIPEB_DATA_N1);
|
||||
I915_WRITE(_PIPEB_LINK_M1, dev_priv->regfile.savePIPEB_LINK_M1);
|
||||
I915_WRITE(_PIPEB_LINK_N1, dev_priv->regfile.savePIPEB_LINK_N1);
|
||||
|
||||
I915_WRITE(_FDI_RXB_CTL, dev_priv->regfile.saveFDI_RXB_CTL);
|
||||
I915_WRITE(_FDI_TXB_CTL, dev_priv->regfile.saveFDI_TXB_CTL);
|
||||
|
||||
I915_WRITE(_PFB_CTL_1, dev_priv->regfile.savePFB_CTL_1);
|
||||
I915_WRITE(_PFB_WIN_SZ, dev_priv->regfile.savePFB_WIN_SZ);
|
||||
I915_WRITE(_PFB_WIN_POS, dev_priv->regfile.savePFB_WIN_POS);
|
||||
|
||||
I915_WRITE(_TRANSBCONF, dev_priv->regfile.saveTRANSBCONF);
|
||||
I915_WRITE(_TRANS_HTOTAL_B, dev_priv->regfile.saveTRANS_HTOTAL_B);
|
||||
I915_WRITE(_TRANS_HBLANK_B, dev_priv->regfile.saveTRANS_HBLANK_B);
|
||||
I915_WRITE(_TRANS_HSYNC_B, dev_priv->regfile.saveTRANS_HSYNC_B);
|
||||
I915_WRITE(_TRANS_VTOTAL_B, dev_priv->regfile.saveTRANS_VTOTAL_B);
|
||||
I915_WRITE(_TRANS_VBLANK_B, dev_priv->regfile.saveTRANS_VBLANK_B);
|
||||
I915_WRITE(_TRANS_VSYNC_B, dev_priv->regfile.saveTRANS_VSYNC_B);
|
||||
}
|
||||
|
||||
/* Restore plane info */
|
||||
I915_WRITE(_DSPBSIZE, dev_priv->regfile.saveDSPBSIZE);
|
||||
I915_WRITE(_DSPBPOS, dev_priv->regfile.saveDSPBPOS);
|
||||
I915_WRITE(_PIPEBSRC, dev_priv->regfile.savePIPEBSRC);
|
||||
I915_WRITE(_DSPBADDR, dev_priv->regfile.saveDSPBADDR);
|
||||
I915_WRITE(_DSPBSTRIDE, dev_priv->regfile.saveDSPBSTRIDE);
|
||||
if (INTEL_INFO(dev)->gen >= 4) {
|
||||
I915_WRITE(_DSPBSURF, dev_priv->regfile.saveDSPBSURF);
|
||||
I915_WRITE(_DSPBTILEOFF, dev_priv->regfile.saveDSPBTILEOFF);
|
||||
}
|
||||
|
||||
I915_WRITE(_PIPEBCONF, dev_priv->regfile.savePIPEBCONF);
|
||||
|
||||
i915_restore_palette(dev, PIPE_B);
|
||||
/* Enable the plane */
|
||||
I915_WRITE(_DSPBCNTR, dev_priv->regfile.saveDSPBCNTR);
|
||||
I915_WRITE(_DSPBADDR, I915_READ(_DSPBADDR));
|
||||
|
||||
/* Cursor state */
|
||||
I915_WRITE(_CURAPOS, dev_priv->regfile.saveCURAPOS);
|
||||
I915_WRITE(_CURACNTR, dev_priv->regfile.saveCURACNTR);
|
||||
I915_WRITE(_CURABASE, dev_priv->regfile.saveCURABASE);
|
||||
I915_WRITE(_CURBPOS, dev_priv->regfile.saveCURBPOS);
|
||||
I915_WRITE(_CURBCNTR, dev_priv->regfile.saveCURBCNTR);
|
||||
I915_WRITE(_CURBBASE, dev_priv->regfile.saveCURBBASE);
|
||||
if (IS_GEN2(dev))
|
||||
I915_WRITE(CURSIZE, dev_priv->regfile.saveCURSIZE);
|
||||
|
||||
/* CRT state */
|
||||
if (HAS_PCH_SPLIT(dev))
|
||||
I915_WRITE(PCH_ADPA, dev_priv->regfile.saveADPA);
|
||||
else
|
||||
I915_WRITE(ADPA, dev_priv->regfile.saveADPA);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static void i915_save_display(struct drm_device *dev)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
|
||||
/* Display arbitration control */
|
||||
dev_priv->regfile.saveDSPARB = I915_READ(DSPARB);
|
||||
if (INTEL_INFO(dev)->gen <= 4)
|
||||
dev_priv->regfile.saveDSPARB = I915_READ(DSPARB);
|
||||
|
||||
/* This is only meaningful in non-KMS mode */
|
||||
/* Don't regfile.save them in KMS mode */
|
||||
i915_save_modeset_reg(dev);
|
||||
if (!drm_core_check_feature(dev, DRIVER_MODESET))
|
||||
i915_save_display_reg(dev);
|
||||
|
||||
/* LVDS state */
|
||||
if (HAS_PCH_SPLIT(dev)) {
|
||||
@ -658,24 +234,6 @@ static void i915_save_display(struct drm_device *dev)
|
||||
dev_priv->regfile.savePP_DIVISOR = I915_READ(PP_DIVISOR);
|
||||
}
|
||||
|
||||
if (!drm_core_check_feature(dev, DRIVER_MODESET)) {
|
||||
/* Display Port state */
|
||||
if (SUPPORTS_INTEGRATED_DP(dev)) {
|
||||
dev_priv->regfile.saveDP_B = I915_READ(DP_B);
|
||||
dev_priv->regfile.saveDP_C = I915_READ(DP_C);
|
||||
dev_priv->regfile.saveDP_D = I915_READ(DP_D);
|
||||
dev_priv->regfile.savePIPEA_GMCH_DATA_M = I915_READ(_PIPEA_GMCH_DATA_M);
|
||||
dev_priv->regfile.savePIPEB_GMCH_DATA_M = I915_READ(_PIPEB_GMCH_DATA_M);
|
||||
dev_priv->regfile.savePIPEA_GMCH_DATA_N = I915_READ(_PIPEA_GMCH_DATA_N);
|
||||
dev_priv->regfile.savePIPEB_GMCH_DATA_N = I915_READ(_PIPEB_GMCH_DATA_N);
|
||||
dev_priv->regfile.savePIPEA_DP_LINK_M = I915_READ(_PIPEA_DP_LINK_M);
|
||||
dev_priv->regfile.savePIPEB_DP_LINK_M = I915_READ(_PIPEB_DP_LINK_M);
|
||||
dev_priv->regfile.savePIPEA_DP_LINK_N = I915_READ(_PIPEA_DP_LINK_N);
|
||||
dev_priv->regfile.savePIPEB_DP_LINK_N = I915_READ(_PIPEB_DP_LINK_N);
|
||||
}
|
||||
/* FIXME: regfile.save TV & SDVO state */
|
||||
}
|
||||
|
||||
/* Only regfile.save FBC state on the platform that supports FBC */
|
||||
if (I915_HAS_FBC(dev)) {
|
||||
if (HAS_PCH_SPLIT(dev)) {
|
||||
@ -690,16 +248,8 @@ static void i915_save_display(struct drm_device *dev)
|
||||
}
|
||||
}
|
||||
|
||||
/* VGA state */
|
||||
dev_priv->regfile.saveVGA0 = I915_READ(VGA0);
|
||||
dev_priv->regfile.saveVGA1 = I915_READ(VGA1);
|
||||
dev_priv->regfile.saveVGA_PD = I915_READ(VGA_PD);
|
||||
if (HAS_PCH_SPLIT(dev))
|
||||
dev_priv->regfile.saveVGACNTRL = I915_READ(CPU_VGACNTRL);
|
||||
else
|
||||
dev_priv->regfile.saveVGACNTRL = I915_READ(VGACNTRL);
|
||||
|
||||
i915_save_vga(dev);
|
||||
if (!drm_core_check_feature(dev, DRIVER_MODESET))
|
||||
i915_save_vga(dev);
|
||||
}
|
||||
|
||||
static void i915_restore_display(struct drm_device *dev)
|
||||
@ -707,25 +257,11 @@ static void i915_restore_display(struct drm_device *dev)
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
|
||||
/* Display arbitration */
|
||||
I915_WRITE(DSPARB, dev_priv->regfile.saveDSPARB);
|
||||
if (INTEL_INFO(dev)->gen <= 4)
|
||||
I915_WRITE(DSPARB, dev_priv->regfile.saveDSPARB);
|
||||
|
||||
if (!drm_core_check_feature(dev, DRIVER_MODESET)) {
|
||||
/* Display port ratios (must be done before clock is set) */
|
||||
if (SUPPORTS_INTEGRATED_DP(dev)) {
|
||||
I915_WRITE(_PIPEA_GMCH_DATA_M, dev_priv->regfile.savePIPEA_GMCH_DATA_M);
|
||||
I915_WRITE(_PIPEB_GMCH_DATA_M, dev_priv->regfile.savePIPEB_GMCH_DATA_M);
|
||||
I915_WRITE(_PIPEA_GMCH_DATA_N, dev_priv->regfile.savePIPEA_GMCH_DATA_N);
|
||||
I915_WRITE(_PIPEB_GMCH_DATA_N, dev_priv->regfile.savePIPEB_GMCH_DATA_N);
|
||||
I915_WRITE(_PIPEA_DP_LINK_M, dev_priv->regfile.savePIPEA_DP_LINK_M);
|
||||
I915_WRITE(_PIPEB_DP_LINK_M, dev_priv->regfile.savePIPEB_DP_LINK_M);
|
||||
I915_WRITE(_PIPEA_DP_LINK_N, dev_priv->regfile.savePIPEA_DP_LINK_N);
|
||||
I915_WRITE(_PIPEB_DP_LINK_N, dev_priv->regfile.savePIPEB_DP_LINK_N);
|
||||
}
|
||||
}
|
||||
|
||||
/* This is only meaningful in non-KMS mode */
|
||||
/* Don't restore them in KMS mode */
|
||||
i915_restore_modeset_reg(dev);
|
||||
if (!drm_core_check_feature(dev, DRIVER_MODESET))
|
||||
i915_restore_display_reg(dev);
|
||||
|
||||
/* LVDS state */
|
||||
if (INTEL_INFO(dev)->gen >= 4 && !HAS_PCH_SPLIT(dev))
|
||||
@ -763,16 +299,6 @@ static void i915_restore_display(struct drm_device *dev)
|
||||
I915_WRITE(PP_CONTROL, dev_priv->regfile.savePP_CONTROL);
|
||||
}
|
||||
|
||||
if (!drm_core_check_feature(dev, DRIVER_MODESET)) {
|
||||
/* Display Port state */
|
||||
if (SUPPORTS_INTEGRATED_DP(dev)) {
|
||||
I915_WRITE(DP_B, dev_priv->regfile.saveDP_B);
|
||||
I915_WRITE(DP_C, dev_priv->regfile.saveDP_C);
|
||||
I915_WRITE(DP_D, dev_priv->regfile.saveDP_D);
|
||||
}
|
||||
/* FIXME: restore TV & SDVO state */
|
||||
}
|
||||
|
||||
/* only restore FBC info on the platform that supports FBC*/
|
||||
intel_disable_fbc(dev);
|
||||
if (I915_HAS_FBC(dev)) {
|
||||
@ -787,19 +313,11 @@ static void i915_restore_display(struct drm_device *dev)
|
||||
I915_WRITE(FBC_CONTROL, dev_priv->regfile.saveFBC_CONTROL);
|
||||
}
|
||||
}
|
||||
/* VGA state */
|
||||
if (HAS_PCH_SPLIT(dev))
|
||||
I915_WRITE(CPU_VGACNTRL, dev_priv->regfile.saveVGACNTRL);
|
||||
|
||||
if (!drm_core_check_feature(dev, DRIVER_MODESET))
|
||||
i915_restore_vga(dev);
|
||||
else
|
||||
I915_WRITE(VGACNTRL, dev_priv->regfile.saveVGACNTRL);
|
||||
|
||||
I915_WRITE(VGA0, dev_priv->regfile.saveVGA0);
|
||||
I915_WRITE(VGA1, dev_priv->regfile.saveVGA1);
|
||||
I915_WRITE(VGA_PD, dev_priv->regfile.saveVGA_PD);
|
||||
POSTING_READ(VGA_PD);
|
||||
udelay(150);
|
||||
|
||||
i915_restore_vga(dev);
|
||||
i915_redisable_vga(dev);
|
||||
}
|
||||
|
||||
int i915_save_state(struct drm_device *dev)
|
||||
|
503
drivers/gpu/drm/i915/i915_ums.c
Normal file
503
drivers/gpu/drm/i915/i915_ums.c
Normal file
@ -0,0 +1,503 @@
|
||||
/*
|
||||
*
|
||||
* Copyright 2008 (c) Intel Corporation
|
||||
* Jesse Barnes <jbarnes@virtuousgeek.org>
|
||||
* Copyright 2013 (c) Intel Corporation
|
||||
* Daniel Vetter <daniel.vetter@ffwll.ch>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sub license, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice (including the
|
||||
* next paragraph) shall be included in all copies or substantial portions
|
||||
* of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
|
||||
* IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
|
||||
* ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <drm/drmP.h>
|
||||
#include <drm/i915_drm.h>
|
||||
#include "intel_drv.h"
|
||||
#include "i915_reg.h"
|
||||
|
||||
static bool i915_pipe_enabled(struct drm_device *dev, enum pipe pipe)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
u32 dpll_reg;
|
||||
|
||||
/* On IVB, 3rd pipe shares PLL with another one */
|
||||
if (pipe > 1)
|
||||
return false;
|
||||
|
||||
if (HAS_PCH_SPLIT(dev))
|
||||
dpll_reg = _PCH_DPLL(pipe);
|
||||
else
|
||||
dpll_reg = (pipe == PIPE_A) ? _DPLL_A : _DPLL_B;
|
||||
|
||||
return (I915_READ(dpll_reg) & DPLL_VCO_ENABLE);
|
||||
}
|
||||
|
||||
static void i915_save_palette(struct drm_device *dev, enum pipe pipe)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
unsigned long reg = (pipe == PIPE_A ? _PALETTE_A : _PALETTE_B);
|
||||
u32 *array;
|
||||
int i;
|
||||
|
||||
if (!i915_pipe_enabled(dev, pipe))
|
||||
return;
|
||||
|
||||
if (HAS_PCH_SPLIT(dev))
|
||||
reg = (pipe == PIPE_A) ? _LGC_PALETTE_A : _LGC_PALETTE_B;
|
||||
|
||||
if (pipe == PIPE_A)
|
||||
array = dev_priv->regfile.save_palette_a;
|
||||
else
|
||||
array = dev_priv->regfile.save_palette_b;
|
||||
|
||||
for (i = 0; i < 256; i++)
|
||||
array[i] = I915_READ(reg + (i << 2));
|
||||
}
|
||||
|
||||
static void i915_restore_palette(struct drm_device *dev, enum pipe pipe)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
unsigned long reg = (pipe == PIPE_A ? _PALETTE_A : _PALETTE_B);
|
||||
u32 *array;
|
||||
int i;
|
||||
|
||||
if (!i915_pipe_enabled(dev, pipe))
|
||||
return;
|
||||
|
||||
if (HAS_PCH_SPLIT(dev))
|
||||
reg = (pipe == PIPE_A) ? _LGC_PALETTE_A : _LGC_PALETTE_B;
|
||||
|
||||
if (pipe == PIPE_A)
|
||||
array = dev_priv->regfile.save_palette_a;
|
||||
else
|
||||
array = dev_priv->regfile.save_palette_b;
|
||||
|
||||
for (i = 0; i < 256; i++)
|
||||
I915_WRITE(reg + (i << 2), array[i]);
|
||||
}
|
||||
|
||||
void i915_save_display_reg(struct drm_device *dev)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
int i;
|
||||
|
||||
/* Cursor state */
|
||||
dev_priv->regfile.saveCURACNTR = I915_READ(_CURACNTR);
|
||||
dev_priv->regfile.saveCURAPOS = I915_READ(_CURAPOS);
|
||||
dev_priv->regfile.saveCURABASE = I915_READ(_CURABASE);
|
||||
dev_priv->regfile.saveCURBCNTR = I915_READ(_CURBCNTR);
|
||||
dev_priv->regfile.saveCURBPOS = I915_READ(_CURBPOS);
|
||||
dev_priv->regfile.saveCURBBASE = I915_READ(_CURBBASE);
|
||||
if (IS_GEN2(dev))
|
||||
dev_priv->regfile.saveCURSIZE = I915_READ(CURSIZE);
|
||||
|
||||
if (HAS_PCH_SPLIT(dev)) {
|
||||
dev_priv->regfile.savePCH_DREF_CONTROL = I915_READ(PCH_DREF_CONTROL);
|
||||
dev_priv->regfile.saveDISP_ARB_CTL = I915_READ(DISP_ARB_CTL);
|
||||
}
|
||||
|
||||
/* Pipe & plane A info */
|
||||
dev_priv->regfile.savePIPEACONF = I915_READ(_PIPEACONF);
|
||||
dev_priv->regfile.savePIPEASRC = I915_READ(_PIPEASRC);
|
||||
if (HAS_PCH_SPLIT(dev)) {
|
||||
dev_priv->regfile.saveFPA0 = I915_READ(_PCH_FPA0);
|
||||
dev_priv->regfile.saveFPA1 = I915_READ(_PCH_FPA1);
|
||||
dev_priv->regfile.saveDPLL_A = I915_READ(_PCH_DPLL_A);
|
||||
} else {
|
||||
dev_priv->regfile.saveFPA0 = I915_READ(_FPA0);
|
||||
dev_priv->regfile.saveFPA1 = I915_READ(_FPA1);
|
||||
dev_priv->regfile.saveDPLL_A = I915_READ(_DPLL_A);
|
||||
}
|
||||
if (INTEL_INFO(dev)->gen >= 4 && !HAS_PCH_SPLIT(dev))
|
||||
dev_priv->regfile.saveDPLL_A_MD = I915_READ(_DPLL_A_MD);
|
||||
dev_priv->regfile.saveHTOTAL_A = I915_READ(_HTOTAL_A);
|
||||
dev_priv->regfile.saveHBLANK_A = I915_READ(_HBLANK_A);
|
||||
dev_priv->regfile.saveHSYNC_A = I915_READ(_HSYNC_A);
|
||||
dev_priv->regfile.saveVTOTAL_A = I915_READ(_VTOTAL_A);
|
||||
dev_priv->regfile.saveVBLANK_A = I915_READ(_VBLANK_A);
|
||||
dev_priv->regfile.saveVSYNC_A = I915_READ(_VSYNC_A);
|
||||
if (!HAS_PCH_SPLIT(dev))
|
||||
dev_priv->regfile.saveBCLRPAT_A = I915_READ(_BCLRPAT_A);
|
||||
|
||||
if (HAS_PCH_SPLIT(dev)) {
|
||||
dev_priv->regfile.savePIPEA_DATA_M1 = I915_READ(_PIPEA_DATA_M1);
|
||||
dev_priv->regfile.savePIPEA_DATA_N1 = I915_READ(_PIPEA_DATA_N1);
|
||||
dev_priv->regfile.savePIPEA_LINK_M1 = I915_READ(_PIPEA_LINK_M1);
|
||||
dev_priv->regfile.savePIPEA_LINK_N1 = I915_READ(_PIPEA_LINK_N1);
|
||||
|
||||
dev_priv->regfile.saveFDI_TXA_CTL = I915_READ(_FDI_TXA_CTL);
|
||||
dev_priv->regfile.saveFDI_RXA_CTL = I915_READ(_FDI_RXA_CTL);
|
||||
|
||||
dev_priv->regfile.savePFA_CTL_1 = I915_READ(_PFA_CTL_1);
|
||||
dev_priv->regfile.savePFA_WIN_SZ = I915_READ(_PFA_WIN_SZ);
|
||||
dev_priv->regfile.savePFA_WIN_POS = I915_READ(_PFA_WIN_POS);
|
||||
|
||||
dev_priv->regfile.saveTRANSACONF = I915_READ(_TRANSACONF);
|
||||
dev_priv->regfile.saveTRANS_HTOTAL_A = I915_READ(_TRANS_HTOTAL_A);
|
||||
dev_priv->regfile.saveTRANS_HBLANK_A = I915_READ(_TRANS_HBLANK_A);
|
||||
dev_priv->regfile.saveTRANS_HSYNC_A = I915_READ(_TRANS_HSYNC_A);
|
||||
dev_priv->regfile.saveTRANS_VTOTAL_A = I915_READ(_TRANS_VTOTAL_A);
|
||||
dev_priv->regfile.saveTRANS_VBLANK_A = I915_READ(_TRANS_VBLANK_A);
|
||||
dev_priv->regfile.saveTRANS_VSYNC_A = I915_READ(_TRANS_VSYNC_A);
|
||||
}
|
||||
|
||||
dev_priv->regfile.saveDSPACNTR = I915_READ(_DSPACNTR);
|
||||
dev_priv->regfile.saveDSPASTRIDE = I915_READ(_DSPASTRIDE);
|
||||
dev_priv->regfile.saveDSPASIZE = I915_READ(_DSPASIZE);
|
||||
dev_priv->regfile.saveDSPAPOS = I915_READ(_DSPAPOS);
|
||||
dev_priv->regfile.saveDSPAADDR = I915_READ(_DSPAADDR);
|
||||
if (INTEL_INFO(dev)->gen >= 4) {
|
||||
dev_priv->regfile.saveDSPASURF = I915_READ(_DSPASURF);
|
||||
dev_priv->regfile.saveDSPATILEOFF = I915_READ(_DSPATILEOFF);
|
||||
}
|
||||
i915_save_palette(dev, PIPE_A);
|
||||
dev_priv->regfile.savePIPEASTAT = I915_READ(_PIPEASTAT);
|
||||
|
||||
/* Pipe & plane B info */
|
||||
dev_priv->regfile.savePIPEBCONF = I915_READ(_PIPEBCONF);
|
||||
dev_priv->regfile.savePIPEBSRC = I915_READ(_PIPEBSRC);
|
||||
if (HAS_PCH_SPLIT(dev)) {
|
||||
dev_priv->regfile.saveFPB0 = I915_READ(_PCH_FPB0);
|
||||
dev_priv->regfile.saveFPB1 = I915_READ(_PCH_FPB1);
|
||||
dev_priv->regfile.saveDPLL_B = I915_READ(_PCH_DPLL_B);
|
||||
} else {
|
||||
dev_priv->regfile.saveFPB0 = I915_READ(_FPB0);
|
||||
dev_priv->regfile.saveFPB1 = I915_READ(_FPB1);
|
||||
dev_priv->regfile.saveDPLL_B = I915_READ(_DPLL_B);
|
||||
}
|
||||
if (INTEL_INFO(dev)->gen >= 4 && !HAS_PCH_SPLIT(dev))
|
||||
dev_priv->regfile.saveDPLL_B_MD = I915_READ(_DPLL_B_MD);
|
||||
dev_priv->regfile.saveHTOTAL_B = I915_READ(_HTOTAL_B);
|
||||
dev_priv->regfile.saveHBLANK_B = I915_READ(_HBLANK_B);
|
||||
dev_priv->regfile.saveHSYNC_B = I915_READ(_HSYNC_B);
|
||||
dev_priv->regfile.saveVTOTAL_B = I915_READ(_VTOTAL_B);
|
||||
dev_priv->regfile.saveVBLANK_B = I915_READ(_VBLANK_B);
|
||||
dev_priv->regfile.saveVSYNC_B = I915_READ(_VSYNC_B);
|
||||
if (!HAS_PCH_SPLIT(dev))
|
||||
dev_priv->regfile.saveBCLRPAT_B = I915_READ(_BCLRPAT_B);
|
||||
|
||||
if (HAS_PCH_SPLIT(dev)) {
|
||||
dev_priv->regfile.savePIPEB_DATA_M1 = I915_READ(_PIPEB_DATA_M1);
|
||||
dev_priv->regfile.savePIPEB_DATA_N1 = I915_READ(_PIPEB_DATA_N1);
|
||||
dev_priv->regfile.savePIPEB_LINK_M1 = I915_READ(_PIPEB_LINK_M1);
|
||||
dev_priv->regfile.savePIPEB_LINK_N1 = I915_READ(_PIPEB_LINK_N1);
|
||||
|
||||
dev_priv->regfile.saveFDI_TXB_CTL = I915_READ(_FDI_TXB_CTL);
|
||||
dev_priv->regfile.saveFDI_RXB_CTL = I915_READ(_FDI_RXB_CTL);
|
||||
|
||||
dev_priv->regfile.savePFB_CTL_1 = I915_READ(_PFB_CTL_1);
|
||||
dev_priv->regfile.savePFB_WIN_SZ = I915_READ(_PFB_WIN_SZ);
|
||||
dev_priv->regfile.savePFB_WIN_POS = I915_READ(_PFB_WIN_POS);
|
||||
|
||||
dev_priv->regfile.saveTRANSBCONF = I915_READ(_TRANSBCONF);
|
||||
dev_priv->regfile.saveTRANS_HTOTAL_B = I915_READ(_TRANS_HTOTAL_B);
|
||||
dev_priv->regfile.saveTRANS_HBLANK_B = I915_READ(_TRANS_HBLANK_B);
|
||||
dev_priv->regfile.saveTRANS_HSYNC_B = I915_READ(_TRANS_HSYNC_B);
|
||||
dev_priv->regfile.saveTRANS_VTOTAL_B = I915_READ(_TRANS_VTOTAL_B);
|
||||
dev_priv->regfile.saveTRANS_VBLANK_B = I915_READ(_TRANS_VBLANK_B);
|
||||
dev_priv->regfile.saveTRANS_VSYNC_B = I915_READ(_TRANS_VSYNC_B);
|
||||
}
|
||||
|
||||
dev_priv->regfile.saveDSPBCNTR = I915_READ(_DSPBCNTR);
|
||||
dev_priv->regfile.saveDSPBSTRIDE = I915_READ(_DSPBSTRIDE);
|
||||
dev_priv->regfile.saveDSPBSIZE = I915_READ(_DSPBSIZE);
|
||||
dev_priv->regfile.saveDSPBPOS = I915_READ(_DSPBPOS);
|
||||
dev_priv->regfile.saveDSPBADDR = I915_READ(_DSPBADDR);
|
||||
if (INTEL_INFO(dev)->gen >= 4) {
|
||||
dev_priv->regfile.saveDSPBSURF = I915_READ(_DSPBSURF);
|
||||
dev_priv->regfile.saveDSPBTILEOFF = I915_READ(_DSPBTILEOFF);
|
||||
}
|
||||
i915_save_palette(dev, PIPE_B);
|
||||
dev_priv->regfile.savePIPEBSTAT = I915_READ(_PIPEBSTAT);
|
||||
|
||||
/* Fences */
|
||||
switch (INTEL_INFO(dev)->gen) {
|
||||
case 7:
|
||||
case 6:
|
||||
for (i = 0; i < 16; i++)
|
||||
dev_priv->regfile.saveFENCE[i] = I915_READ64(FENCE_REG_SANDYBRIDGE_0 + (i * 8));
|
||||
break;
|
||||
case 5:
|
||||
case 4:
|
||||
for (i = 0; i < 16; i++)
|
||||
dev_priv->regfile.saveFENCE[i] = I915_READ64(FENCE_REG_965_0 + (i * 8));
|
||||
break;
|
||||
case 3:
|
||||
if (IS_I945G(dev) || IS_I945GM(dev) || IS_G33(dev))
|
||||
for (i = 0; i < 8; i++)
|
||||
dev_priv->regfile.saveFENCE[i+8] = I915_READ(FENCE_REG_945_8 + (i * 4));
|
||||
case 2:
|
||||
for (i = 0; i < 8; i++)
|
||||
dev_priv->regfile.saveFENCE[i] = I915_READ(FENCE_REG_830_0 + (i * 4));
|
||||
break;
|
||||
}
|
||||
|
||||
/* CRT state */
|
||||
if (HAS_PCH_SPLIT(dev))
|
||||
dev_priv->regfile.saveADPA = I915_READ(PCH_ADPA);
|
||||
else
|
||||
dev_priv->regfile.saveADPA = I915_READ(ADPA);
|
||||
|
||||
/* Display Port state */
|
||||
if (SUPPORTS_INTEGRATED_DP(dev)) {
|
||||
dev_priv->regfile.saveDP_B = I915_READ(DP_B);
|
||||
dev_priv->regfile.saveDP_C = I915_READ(DP_C);
|
||||
dev_priv->regfile.saveDP_D = I915_READ(DP_D);
|
||||
dev_priv->regfile.savePIPEA_GMCH_DATA_M = I915_READ(_PIPEA_GMCH_DATA_M);
|
||||
dev_priv->regfile.savePIPEB_GMCH_DATA_M = I915_READ(_PIPEB_GMCH_DATA_M);
|
||||
dev_priv->regfile.savePIPEA_GMCH_DATA_N = I915_READ(_PIPEA_GMCH_DATA_N);
|
||||
dev_priv->regfile.savePIPEB_GMCH_DATA_N = I915_READ(_PIPEB_GMCH_DATA_N);
|
||||
dev_priv->regfile.savePIPEA_DP_LINK_M = I915_READ(_PIPEA_DP_LINK_M);
|
||||
dev_priv->regfile.savePIPEB_DP_LINK_M = I915_READ(_PIPEB_DP_LINK_M);
|
||||
dev_priv->regfile.savePIPEA_DP_LINK_N = I915_READ(_PIPEA_DP_LINK_N);
|
||||
dev_priv->regfile.savePIPEB_DP_LINK_N = I915_READ(_PIPEB_DP_LINK_N);
|
||||
}
|
||||
/* FIXME: regfile.save TV & SDVO state */
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void i915_restore_display_reg(struct drm_device *dev)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
int dpll_a_reg, fpa0_reg, fpa1_reg;
|
||||
int dpll_b_reg, fpb0_reg, fpb1_reg;
|
||||
int i;
|
||||
|
||||
/* Display port ratios (must be done before clock is set) */
|
||||
if (SUPPORTS_INTEGRATED_DP(dev)) {
|
||||
I915_WRITE(_PIPEA_GMCH_DATA_M, dev_priv->regfile.savePIPEA_GMCH_DATA_M);
|
||||
I915_WRITE(_PIPEB_GMCH_DATA_M, dev_priv->regfile.savePIPEB_GMCH_DATA_M);
|
||||
I915_WRITE(_PIPEA_GMCH_DATA_N, dev_priv->regfile.savePIPEA_GMCH_DATA_N);
|
||||
I915_WRITE(_PIPEB_GMCH_DATA_N, dev_priv->regfile.savePIPEB_GMCH_DATA_N);
|
||||
I915_WRITE(_PIPEA_DP_LINK_M, dev_priv->regfile.savePIPEA_DP_LINK_M);
|
||||
I915_WRITE(_PIPEB_DP_LINK_M, dev_priv->regfile.savePIPEB_DP_LINK_M);
|
||||
I915_WRITE(_PIPEA_DP_LINK_N, dev_priv->regfile.savePIPEA_DP_LINK_N);
|
||||
I915_WRITE(_PIPEB_DP_LINK_N, dev_priv->regfile.savePIPEB_DP_LINK_N);
|
||||
}
|
||||
|
||||
/* Fences */
|
||||
switch (INTEL_INFO(dev)->gen) {
|
||||
case 7:
|
||||
case 6:
|
||||
for (i = 0; i < 16; i++)
|
||||
I915_WRITE64(FENCE_REG_SANDYBRIDGE_0 + (i * 8), dev_priv->regfile.saveFENCE[i]);
|
||||
break;
|
||||
case 5:
|
||||
case 4:
|
||||
for (i = 0; i < 16; i++)
|
||||
I915_WRITE64(FENCE_REG_965_0 + (i * 8), dev_priv->regfile.saveFENCE[i]);
|
||||
break;
|
||||
case 3:
|
||||
case 2:
|
||||
if (IS_I945G(dev) || IS_I945GM(dev) || IS_G33(dev))
|
||||
for (i = 0; i < 8; i++)
|
||||
I915_WRITE(FENCE_REG_945_8 + (i * 4), dev_priv->regfile.saveFENCE[i+8]);
|
||||
for (i = 0; i < 8; i++)
|
||||
I915_WRITE(FENCE_REG_830_0 + (i * 4), dev_priv->regfile.saveFENCE[i]);
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
if (HAS_PCH_SPLIT(dev)) {
|
||||
dpll_a_reg = _PCH_DPLL_A;
|
||||
dpll_b_reg = _PCH_DPLL_B;
|
||||
fpa0_reg = _PCH_FPA0;
|
||||
fpb0_reg = _PCH_FPB0;
|
||||
fpa1_reg = _PCH_FPA1;
|
||||
fpb1_reg = _PCH_FPB1;
|
||||
} else {
|
||||
dpll_a_reg = _DPLL_A;
|
||||
dpll_b_reg = _DPLL_B;
|
||||
fpa0_reg = _FPA0;
|
||||
fpb0_reg = _FPB0;
|
||||
fpa1_reg = _FPA1;
|
||||
fpb1_reg = _FPB1;
|
||||
}
|
||||
|
||||
if (HAS_PCH_SPLIT(dev)) {
|
||||
I915_WRITE(PCH_DREF_CONTROL, dev_priv->regfile.savePCH_DREF_CONTROL);
|
||||
I915_WRITE(DISP_ARB_CTL, dev_priv->regfile.saveDISP_ARB_CTL);
|
||||
}
|
||||
|
||||
/* Pipe & plane A info */
|
||||
/* Prime the clock */
|
||||
if (dev_priv->regfile.saveDPLL_A & DPLL_VCO_ENABLE) {
|
||||
I915_WRITE(dpll_a_reg, dev_priv->regfile.saveDPLL_A &
|
||||
~DPLL_VCO_ENABLE);
|
||||
POSTING_READ(dpll_a_reg);
|
||||
udelay(150);
|
||||
}
|
||||
I915_WRITE(fpa0_reg, dev_priv->regfile.saveFPA0);
|
||||
I915_WRITE(fpa1_reg, dev_priv->regfile.saveFPA1);
|
||||
/* Actually enable it */
|
||||
I915_WRITE(dpll_a_reg, dev_priv->regfile.saveDPLL_A);
|
||||
POSTING_READ(dpll_a_reg);
|
||||
udelay(150);
|
||||
if (INTEL_INFO(dev)->gen >= 4 && !HAS_PCH_SPLIT(dev)) {
|
||||
I915_WRITE(_DPLL_A_MD, dev_priv->regfile.saveDPLL_A_MD);
|
||||
POSTING_READ(_DPLL_A_MD);
|
||||
}
|
||||
udelay(150);
|
||||
|
||||
/* Restore mode */
|
||||
I915_WRITE(_HTOTAL_A, dev_priv->regfile.saveHTOTAL_A);
|
||||
I915_WRITE(_HBLANK_A, dev_priv->regfile.saveHBLANK_A);
|
||||
I915_WRITE(_HSYNC_A, dev_priv->regfile.saveHSYNC_A);
|
||||
I915_WRITE(_VTOTAL_A, dev_priv->regfile.saveVTOTAL_A);
|
||||
I915_WRITE(_VBLANK_A, dev_priv->regfile.saveVBLANK_A);
|
||||
I915_WRITE(_VSYNC_A, dev_priv->regfile.saveVSYNC_A);
|
||||
if (!HAS_PCH_SPLIT(dev))
|
||||
I915_WRITE(_BCLRPAT_A, dev_priv->regfile.saveBCLRPAT_A);
|
||||
|
||||
if (HAS_PCH_SPLIT(dev)) {
|
||||
I915_WRITE(_PIPEA_DATA_M1, dev_priv->regfile.savePIPEA_DATA_M1);
|
||||
I915_WRITE(_PIPEA_DATA_N1, dev_priv->regfile.savePIPEA_DATA_N1);
|
||||
I915_WRITE(_PIPEA_LINK_M1, dev_priv->regfile.savePIPEA_LINK_M1);
|
||||
I915_WRITE(_PIPEA_LINK_N1, dev_priv->regfile.savePIPEA_LINK_N1);
|
||||
|
||||
I915_WRITE(_FDI_RXA_CTL, dev_priv->regfile.saveFDI_RXA_CTL);
|
||||
I915_WRITE(_FDI_TXA_CTL, dev_priv->regfile.saveFDI_TXA_CTL);
|
||||
|
||||
I915_WRITE(_PFA_CTL_1, dev_priv->regfile.savePFA_CTL_1);
|
||||
I915_WRITE(_PFA_WIN_SZ, dev_priv->regfile.savePFA_WIN_SZ);
|
||||
I915_WRITE(_PFA_WIN_POS, dev_priv->regfile.savePFA_WIN_POS);
|
||||
|
||||
I915_WRITE(_TRANSACONF, dev_priv->regfile.saveTRANSACONF);
|
||||
I915_WRITE(_TRANS_HTOTAL_A, dev_priv->regfile.saveTRANS_HTOTAL_A);
|
||||
I915_WRITE(_TRANS_HBLANK_A, dev_priv->regfile.saveTRANS_HBLANK_A);
|
||||
I915_WRITE(_TRANS_HSYNC_A, dev_priv->regfile.saveTRANS_HSYNC_A);
|
||||
I915_WRITE(_TRANS_VTOTAL_A, dev_priv->regfile.saveTRANS_VTOTAL_A);
|
||||
I915_WRITE(_TRANS_VBLANK_A, dev_priv->regfile.saveTRANS_VBLANK_A);
|
||||
I915_WRITE(_TRANS_VSYNC_A, dev_priv->regfile.saveTRANS_VSYNC_A);
|
||||
}
|
||||
|
||||
/* Restore plane info */
|
||||
I915_WRITE(_DSPASIZE, dev_priv->regfile.saveDSPASIZE);
|
||||
I915_WRITE(_DSPAPOS, dev_priv->regfile.saveDSPAPOS);
|
||||
I915_WRITE(_PIPEASRC, dev_priv->regfile.savePIPEASRC);
|
||||
I915_WRITE(_DSPAADDR, dev_priv->regfile.saveDSPAADDR);
|
||||
I915_WRITE(_DSPASTRIDE, dev_priv->regfile.saveDSPASTRIDE);
|
||||
if (INTEL_INFO(dev)->gen >= 4) {
|
||||
I915_WRITE(_DSPASURF, dev_priv->regfile.saveDSPASURF);
|
||||
I915_WRITE(_DSPATILEOFF, dev_priv->regfile.saveDSPATILEOFF);
|
||||
}
|
||||
|
||||
I915_WRITE(_PIPEACONF, dev_priv->regfile.savePIPEACONF);
|
||||
|
||||
i915_restore_palette(dev, PIPE_A);
|
||||
/* Enable the plane */
|
||||
I915_WRITE(_DSPACNTR, dev_priv->regfile.saveDSPACNTR);
|
||||
I915_WRITE(_DSPAADDR, I915_READ(_DSPAADDR));
|
||||
|
||||
/* Pipe & plane B info */
|
||||
if (dev_priv->regfile.saveDPLL_B & DPLL_VCO_ENABLE) {
|
||||
I915_WRITE(dpll_b_reg, dev_priv->regfile.saveDPLL_B &
|
||||
~DPLL_VCO_ENABLE);
|
||||
POSTING_READ(dpll_b_reg);
|
||||
udelay(150);
|
||||
}
|
||||
I915_WRITE(fpb0_reg, dev_priv->regfile.saveFPB0);
|
||||
I915_WRITE(fpb1_reg, dev_priv->regfile.saveFPB1);
|
||||
/* Actually enable it */
|
||||
I915_WRITE(dpll_b_reg, dev_priv->regfile.saveDPLL_B);
|
||||
POSTING_READ(dpll_b_reg);
|
||||
udelay(150);
|
||||
if (INTEL_INFO(dev)->gen >= 4 && !HAS_PCH_SPLIT(dev)) {
|
||||
I915_WRITE(_DPLL_B_MD, dev_priv->regfile.saveDPLL_B_MD);
|
||||
POSTING_READ(_DPLL_B_MD);
|
||||
}
|
||||
udelay(150);
|
||||
|
||||
/* Restore mode */
|
||||
I915_WRITE(_HTOTAL_B, dev_priv->regfile.saveHTOTAL_B);
|
||||
I915_WRITE(_HBLANK_B, dev_priv->regfile.saveHBLANK_B);
|
||||
I915_WRITE(_HSYNC_B, dev_priv->regfile.saveHSYNC_B);
|
||||
I915_WRITE(_VTOTAL_B, dev_priv->regfile.saveVTOTAL_B);
|
||||
I915_WRITE(_VBLANK_B, dev_priv->regfile.saveVBLANK_B);
|
||||
I915_WRITE(_VSYNC_B, dev_priv->regfile.saveVSYNC_B);
|
||||
if (!HAS_PCH_SPLIT(dev))
|
||||
I915_WRITE(_BCLRPAT_B, dev_priv->regfile.saveBCLRPAT_B);
|
||||
|
||||
if (HAS_PCH_SPLIT(dev)) {
|
||||
I915_WRITE(_PIPEB_DATA_M1, dev_priv->regfile.savePIPEB_DATA_M1);
|
||||
I915_WRITE(_PIPEB_DATA_N1, dev_priv->regfile.savePIPEB_DATA_N1);
|
||||
I915_WRITE(_PIPEB_LINK_M1, dev_priv->regfile.savePIPEB_LINK_M1);
|
||||
I915_WRITE(_PIPEB_LINK_N1, dev_priv->regfile.savePIPEB_LINK_N1);
|
||||
|
||||
I915_WRITE(_FDI_RXB_CTL, dev_priv->regfile.saveFDI_RXB_CTL);
|
||||
I915_WRITE(_FDI_TXB_CTL, dev_priv->regfile.saveFDI_TXB_CTL);
|
||||
|
||||
I915_WRITE(_PFB_CTL_1, dev_priv->regfile.savePFB_CTL_1);
|
||||
I915_WRITE(_PFB_WIN_SZ, dev_priv->regfile.savePFB_WIN_SZ);
|
||||
I915_WRITE(_PFB_WIN_POS, dev_priv->regfile.savePFB_WIN_POS);
|
||||
|
||||
I915_WRITE(_TRANSBCONF, dev_priv->regfile.saveTRANSBCONF);
|
||||
I915_WRITE(_TRANS_HTOTAL_B, dev_priv->regfile.saveTRANS_HTOTAL_B);
|
||||
I915_WRITE(_TRANS_HBLANK_B, dev_priv->regfile.saveTRANS_HBLANK_B);
|
||||
I915_WRITE(_TRANS_HSYNC_B, dev_priv->regfile.saveTRANS_HSYNC_B);
|
||||
I915_WRITE(_TRANS_VTOTAL_B, dev_priv->regfile.saveTRANS_VTOTAL_B);
|
||||
I915_WRITE(_TRANS_VBLANK_B, dev_priv->regfile.saveTRANS_VBLANK_B);
|
||||
I915_WRITE(_TRANS_VSYNC_B, dev_priv->regfile.saveTRANS_VSYNC_B);
|
||||
}
|
||||
|
||||
/* Restore plane info */
|
||||
I915_WRITE(_DSPBSIZE, dev_priv->regfile.saveDSPBSIZE);
|
||||
I915_WRITE(_DSPBPOS, dev_priv->regfile.saveDSPBPOS);
|
||||
I915_WRITE(_PIPEBSRC, dev_priv->regfile.savePIPEBSRC);
|
||||
I915_WRITE(_DSPBADDR, dev_priv->regfile.saveDSPBADDR);
|
||||
I915_WRITE(_DSPBSTRIDE, dev_priv->regfile.saveDSPBSTRIDE);
|
||||
if (INTEL_INFO(dev)->gen >= 4) {
|
||||
I915_WRITE(_DSPBSURF, dev_priv->regfile.saveDSPBSURF);
|
||||
I915_WRITE(_DSPBTILEOFF, dev_priv->regfile.saveDSPBTILEOFF);
|
||||
}
|
||||
|
||||
I915_WRITE(_PIPEBCONF, dev_priv->regfile.savePIPEBCONF);
|
||||
|
||||
i915_restore_palette(dev, PIPE_B);
|
||||
/* Enable the plane */
|
||||
I915_WRITE(_DSPBCNTR, dev_priv->regfile.saveDSPBCNTR);
|
||||
I915_WRITE(_DSPBADDR, I915_READ(_DSPBADDR));
|
||||
|
||||
/* Cursor state */
|
||||
I915_WRITE(_CURAPOS, dev_priv->regfile.saveCURAPOS);
|
||||
I915_WRITE(_CURACNTR, dev_priv->regfile.saveCURACNTR);
|
||||
I915_WRITE(_CURABASE, dev_priv->regfile.saveCURABASE);
|
||||
I915_WRITE(_CURBPOS, dev_priv->regfile.saveCURBPOS);
|
||||
I915_WRITE(_CURBCNTR, dev_priv->regfile.saveCURBCNTR);
|
||||
I915_WRITE(_CURBBASE, dev_priv->regfile.saveCURBBASE);
|
||||
if (IS_GEN2(dev))
|
||||
I915_WRITE(CURSIZE, dev_priv->regfile.saveCURSIZE);
|
||||
|
||||
/* CRT state */
|
||||
if (HAS_PCH_SPLIT(dev))
|
||||
I915_WRITE(PCH_ADPA, dev_priv->regfile.saveADPA);
|
||||
else
|
||||
I915_WRITE(ADPA, dev_priv->regfile.saveADPA);
|
||||
|
||||
/* Display Port state */
|
||||
if (SUPPORTS_INTEGRATED_DP(dev)) {
|
||||
I915_WRITE(DP_B, dev_priv->regfile.saveDP_B);
|
||||
I915_WRITE(DP_C, dev_priv->regfile.saveDP_C);
|
||||
I915_WRITE(DP_D, dev_priv->regfile.saveDP_D);
|
||||
}
|
||||
/* FIXME: restore TV & SDVO state */
|
||||
|
||||
return;
|
||||
}
|
@ -267,27 +267,27 @@ static bool intel_ironlake_crt_detect_hotplug(struct drm_connector *connector)
|
||||
|
||||
crt->force_hotplug_required = 0;
|
||||
|
||||
save_adpa = adpa = I915_READ(PCH_ADPA);
|
||||
save_adpa = adpa = I915_READ(crt->adpa_reg);
|
||||
DRM_DEBUG_KMS("trigger hotplug detect cycle: adpa=0x%x\n", adpa);
|
||||
|
||||
adpa |= ADPA_CRT_HOTPLUG_FORCE_TRIGGER;
|
||||
if (turn_off_dac)
|
||||
adpa &= ~ADPA_DAC_ENABLE;
|
||||
|
||||
I915_WRITE(PCH_ADPA, adpa);
|
||||
I915_WRITE(crt->adpa_reg, adpa);
|
||||
|
||||
if (wait_for((I915_READ(PCH_ADPA) & ADPA_CRT_HOTPLUG_FORCE_TRIGGER) == 0,
|
||||
if (wait_for((I915_READ(crt->adpa_reg) & ADPA_CRT_HOTPLUG_FORCE_TRIGGER) == 0,
|
||||
1000))
|
||||
DRM_DEBUG_KMS("timed out waiting for FORCE_TRIGGER");
|
||||
|
||||
if (turn_off_dac) {
|
||||
I915_WRITE(PCH_ADPA, save_adpa);
|
||||
POSTING_READ(PCH_ADPA);
|
||||
I915_WRITE(crt->adpa_reg, save_adpa);
|
||||
POSTING_READ(crt->adpa_reg);
|
||||
}
|
||||
}
|
||||
|
||||
/* Check the status to see if both blue and green are on now */
|
||||
adpa = I915_READ(PCH_ADPA);
|
||||
adpa = I915_READ(crt->adpa_reg);
|
||||
if ((adpa & ADPA_CRT_HOTPLUG_MONITOR_MASK) != 0)
|
||||
ret = true;
|
||||
else
|
||||
@ -300,26 +300,27 @@ static bool intel_ironlake_crt_detect_hotplug(struct drm_connector *connector)
|
||||
static bool valleyview_crt_detect_hotplug(struct drm_connector *connector)
|
||||
{
|
||||
struct drm_device *dev = connector->dev;
|
||||
struct intel_crt *crt = intel_attached_crt(connector);
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
u32 adpa;
|
||||
bool ret;
|
||||
u32 save_adpa;
|
||||
|
||||
save_adpa = adpa = I915_READ(ADPA);
|
||||
save_adpa = adpa = I915_READ(crt->adpa_reg);
|
||||
DRM_DEBUG_KMS("trigger hotplug detect cycle: adpa=0x%x\n", adpa);
|
||||
|
||||
adpa |= ADPA_CRT_HOTPLUG_FORCE_TRIGGER;
|
||||
|
||||
I915_WRITE(ADPA, adpa);
|
||||
I915_WRITE(crt->adpa_reg, adpa);
|
||||
|
||||
if (wait_for((I915_READ(ADPA) & ADPA_CRT_HOTPLUG_FORCE_TRIGGER) == 0,
|
||||
if (wait_for((I915_READ(crt->adpa_reg) & ADPA_CRT_HOTPLUG_FORCE_TRIGGER) == 0,
|
||||
1000)) {
|
||||
DRM_DEBUG_KMS("timed out waiting for FORCE_TRIGGER");
|
||||
I915_WRITE(ADPA, save_adpa);
|
||||
I915_WRITE(crt->adpa_reg, save_adpa);
|
||||
}
|
||||
|
||||
/* Check the status to see if both blue and green are on now */
|
||||
adpa = I915_READ(ADPA);
|
||||
adpa = I915_READ(crt->adpa_reg);
|
||||
if ((adpa & ADPA_CRT_HOTPLUG_MONITOR_MASK) != 0)
|
||||
ret = true;
|
||||
else
|
||||
@ -665,11 +666,11 @@ static void intel_crt_reset(struct drm_connector *connector)
|
||||
if (HAS_PCH_SPLIT(dev)) {
|
||||
u32 adpa;
|
||||
|
||||
adpa = I915_READ(PCH_ADPA);
|
||||
adpa = I915_READ(crt->adpa_reg);
|
||||
adpa &= ~ADPA_CRT_HOTPLUG_MASK;
|
||||
adpa |= ADPA_HOTPLUG_BITS;
|
||||
I915_WRITE(PCH_ADPA, adpa);
|
||||
POSTING_READ(PCH_ADPA);
|
||||
I915_WRITE(crt->adpa_reg, adpa);
|
||||
POSTING_READ(crt->adpa_reg);
|
||||
|
||||
DRM_DEBUG_KMS("pch crt adpa set to 0x%x\n", adpa);
|
||||
crt->force_hotplug_required = 1;
|
||||
@ -684,7 +685,6 @@ static void intel_crt_reset(struct drm_connector *connector)
|
||||
static const struct drm_encoder_helper_funcs crt_encoder_funcs = {
|
||||
.mode_fixup = intel_crt_mode_fixup,
|
||||
.mode_set = intel_crt_mode_set,
|
||||
.disable = intel_encoder_noop,
|
||||
};
|
||||
|
||||
static const struct drm_connector_funcs intel_crt_connector_funcs = {
|
||||
@ -776,7 +776,7 @@ void intel_crt_init(struct drm_device *dev)
|
||||
|
||||
crt->base.disable = intel_disable_crt;
|
||||
crt->base.enable = intel_enable_crt;
|
||||
if (IS_HASWELL(dev))
|
||||
if (HAS_DDI(dev))
|
||||
crt->base.get_hw_state = intel_ddi_get_hw_state;
|
||||
else
|
||||
crt->base.get_hw_state = intel_crt_get_hw_state;
|
||||
@ -800,10 +800,14 @@ void intel_crt_init(struct drm_device *dev)
|
||||
dev_priv->hotplug_supported_mask |= CRT_HOTPLUG_INT_STATUS;
|
||||
|
||||
/*
|
||||
* TODO: find a proper way to discover whether we need to set the
|
||||
* polarity reversal bit or not, instead of relying on the BIOS.
|
||||
* TODO: find a proper way to discover whether we need to set the the
|
||||
* polarity and link reversal bits or not, instead of relying on the
|
||||
* BIOS.
|
||||
*/
|
||||
if (HAS_PCH_LPT(dev))
|
||||
dev_priv->fdi_rx_polarity_reversed =
|
||||
!!(I915_READ(_FDI_RXA_CTL) & FDI_RX_POLARITY_REVERSED_LPT);
|
||||
if (HAS_PCH_LPT(dev)) {
|
||||
u32 fdi_config = FDI_RX_POLARITY_REVERSED_LPT |
|
||||
FDI_RX_LINK_REVERSAL_OVERRIDE;
|
||||
|
||||
dev_priv->fdi_rx_config = I915_READ(_FDI_RXA_CTL) & fdi_config;
|
||||
}
|
||||
}
|
||||
|
@ -84,7 +84,8 @@ static enum port intel_ddi_get_encoder_port(struct intel_encoder *intel_encoder)
|
||||
* in either FDI or DP modes only, as HDMI connections will work with both
|
||||
* of those
|
||||
*/
|
||||
void intel_prepare_ddi_buffers(struct drm_device *dev, enum port port, bool use_fdi_mode)
|
||||
static void intel_prepare_ddi_buffers(struct drm_device *dev, enum port port,
|
||||
bool use_fdi_mode)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
u32 reg;
|
||||
@ -114,16 +115,17 @@ void intel_prepare_ddi(struct drm_device *dev)
|
||||
{
|
||||
int port;
|
||||
|
||||
if (IS_HASWELL(dev)) {
|
||||
for (port = PORT_A; port < PORT_E; port++)
|
||||
intel_prepare_ddi_buffers(dev, port, false);
|
||||
if (!HAS_DDI(dev))
|
||||
return;
|
||||
|
||||
/* DDI E is the suggested one to work in FDI mode, so program is as such by
|
||||
* default. It will have to be re-programmed in case a digital DP output
|
||||
* will be detected on it
|
||||
*/
|
||||
intel_prepare_ddi_buffers(dev, PORT_E, true);
|
||||
}
|
||||
for (port = PORT_A; port < PORT_E; port++)
|
||||
intel_prepare_ddi_buffers(dev, port, false);
|
||||
|
||||
/* DDI E is the suggested one to work in FDI mode, so program is as such
|
||||
* by default. It will have to be re-programmed in case a digital DP
|
||||
* output will be detected on it
|
||||
*/
|
||||
intel_prepare_ddi_buffers(dev, PORT_E, true);
|
||||
}
|
||||
|
||||
static const long hsw_ddi_buf_ctl_values[] = {
|
||||
@ -178,10 +180,8 @@ void hsw_fdi_link_train(struct drm_crtc *crtc)
|
||||
FDI_RX_TP1_TO_TP2_48 | FDI_RX_FDI_DELAY_90);
|
||||
|
||||
/* Enable the PCH Receiver FDI PLL */
|
||||
rx_ctl_val = FDI_RX_PLL_ENABLE | FDI_RX_ENHANCE_FRAME_ENABLE |
|
||||
((intel_crtc->fdi_lanes - 1) << 19);
|
||||
if (dev_priv->fdi_rx_polarity_reversed)
|
||||
rx_ctl_val |= FDI_RX_POLARITY_REVERSED_LPT;
|
||||
rx_ctl_val = dev_priv->fdi_rx_config | FDI_RX_ENHANCE_FRAME_ENABLE |
|
||||
FDI_RX_PLL_ENABLE | ((intel_crtc->fdi_lanes - 1) << 19);
|
||||
I915_WRITE(_FDI_RXA_CTL, rx_ctl_val);
|
||||
POSTING_READ(_FDI_RXA_CTL);
|
||||
udelay(220);
|
||||
@ -203,7 +203,10 @@ void hsw_fdi_link_train(struct drm_crtc *crtc)
|
||||
DP_TP_CTL_LINK_TRAIN_PAT1 |
|
||||
DP_TP_CTL_ENABLE);
|
||||
|
||||
/* Configure and enable DDI_BUF_CTL for DDI E with next voltage */
|
||||
/* Configure and enable DDI_BUF_CTL for DDI E with next voltage.
|
||||
* DDI E does not support port reversal, the functionality is
|
||||
* achieved on the PCH side in FDI_RX_CTL, so no need to set the
|
||||
* port reversal bit */
|
||||
I915_WRITE(DDI_BUF_CTL(PORT_E),
|
||||
DDI_BUF_CTL_ENABLE |
|
||||
((intel_crtc->fdi_lanes - 1) << 1) |
|
||||
@ -675,10 +678,14 @@ static void intel_ddi_mode_set(struct drm_encoder *encoder,
|
||||
DRM_DEBUG_KMS("Preparing DDI mode for Haswell on port %c, pipe %c\n",
|
||||
port_name(port), pipe_name(pipe));
|
||||
|
||||
intel_crtc->eld_vld = false;
|
||||
if (type == INTEL_OUTPUT_DISPLAYPORT || type == INTEL_OUTPUT_EDP) {
|
||||
struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
|
||||
struct intel_digital_port *intel_dig_port =
|
||||
enc_to_dig_port(encoder);
|
||||
|
||||
intel_dp->DP = DDI_BUF_CTL_ENABLE | DDI_BUF_EMP_400MV_0DB_HSW;
|
||||
intel_dp->DP = intel_dig_port->port_reversal |
|
||||
DDI_BUF_CTL_ENABLE | DDI_BUF_EMP_400MV_0DB_HSW;
|
||||
switch (intel_dp->lane_count) {
|
||||
case 1:
|
||||
intel_dp->DP |= DDI_PORT_WIDTH_X1;
|
||||
@ -985,7 +992,13 @@ void intel_ddi_enable_pipe_func(struct drm_crtc *crtc)
|
||||
if (cpu_transcoder == TRANSCODER_EDP) {
|
||||
switch (pipe) {
|
||||
case PIPE_A:
|
||||
temp |= TRANS_DDI_EDP_INPUT_A_ONOFF;
|
||||
/* Can only use the always-on power well for eDP when
|
||||
* not using the panel fitter, and when not using motion
|
||||
* blur mitigation (which we don't support). */
|
||||
if (dev_priv->pch_pf_size)
|
||||
temp |= TRANS_DDI_EDP_INPUT_A_ONOFF;
|
||||
else
|
||||
temp |= TRANS_DDI_EDP_INPUT_A_ON;
|
||||
break;
|
||||
case PIPE_B:
|
||||
temp |= TRANS_DDI_EDP_INPUT_B_ONOFF;
|
||||
@ -1069,7 +1082,7 @@ bool intel_ddi_connector_get_hw_state(struct intel_connector *intel_connector)
|
||||
if (port == PORT_A)
|
||||
cpu_transcoder = TRANSCODER_EDP;
|
||||
else
|
||||
cpu_transcoder = pipe;
|
||||
cpu_transcoder = (enum transcoder) pipe;
|
||||
|
||||
tmp = I915_READ(TRANS_DDI_FUNC_CTL(cpu_transcoder));
|
||||
|
||||
@ -1285,34 +1298,58 @@ static void intel_ddi_post_disable(struct intel_encoder *intel_encoder)
|
||||
static void intel_enable_ddi(struct intel_encoder *intel_encoder)
|
||||
{
|
||||
struct drm_encoder *encoder = &intel_encoder->base;
|
||||
struct drm_crtc *crtc = encoder->crtc;
|
||||
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
|
||||
int pipe = intel_crtc->pipe;
|
||||
struct drm_device *dev = encoder->dev;
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
enum port port = intel_ddi_get_encoder_port(intel_encoder);
|
||||
int type = intel_encoder->type;
|
||||
uint32_t tmp;
|
||||
|
||||
if (type == INTEL_OUTPUT_HDMI) {
|
||||
struct intel_digital_port *intel_dig_port =
|
||||
enc_to_dig_port(encoder);
|
||||
|
||||
/* In HDMI/DVI mode, the port width, and swing/emphasis values
|
||||
* are ignored so nothing special needs to be done besides
|
||||
* enabling the port.
|
||||
*/
|
||||
I915_WRITE(DDI_BUF_CTL(port), DDI_BUF_CTL_ENABLE);
|
||||
I915_WRITE(DDI_BUF_CTL(port),
|
||||
intel_dig_port->port_reversal | DDI_BUF_CTL_ENABLE);
|
||||
} else if (type == INTEL_OUTPUT_EDP) {
|
||||
struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
|
||||
|
||||
ironlake_edp_backlight_on(intel_dp);
|
||||
}
|
||||
|
||||
if (intel_crtc->eld_vld) {
|
||||
tmp = I915_READ(HSW_AUD_PIN_ELD_CP_VLD);
|
||||
tmp |= ((AUDIO_OUTPUT_ENABLE_A | AUDIO_ELD_VALID_A) << (pipe * 4));
|
||||
I915_WRITE(HSW_AUD_PIN_ELD_CP_VLD, tmp);
|
||||
}
|
||||
}
|
||||
|
||||
static void intel_disable_ddi(struct intel_encoder *intel_encoder)
|
||||
{
|
||||
struct drm_encoder *encoder = &intel_encoder->base;
|
||||
struct drm_crtc *crtc = encoder->crtc;
|
||||
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
|
||||
int pipe = intel_crtc->pipe;
|
||||
int type = intel_encoder->type;
|
||||
struct drm_device *dev = encoder->dev;
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
uint32_t tmp;
|
||||
|
||||
if (type == INTEL_OUTPUT_EDP) {
|
||||
struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
|
||||
|
||||
ironlake_edp_backlight_off(intel_dp);
|
||||
}
|
||||
|
||||
tmp = I915_READ(HSW_AUD_PIN_ELD_CP_VLD);
|
||||
tmp &= ~((AUDIO_OUTPUT_ENABLE_A | AUDIO_ELD_VALID_A) << (pipe * 4));
|
||||
I915_WRITE(HSW_AUD_PIN_ELD_CP_VLD, tmp);
|
||||
}
|
||||
|
||||
int intel_ddi_get_cdclk_freq(struct drm_i915_private *dev_priv)
|
||||
@ -1452,11 +1489,11 @@ static const struct drm_encoder_funcs intel_ddi_funcs = {
|
||||
static const struct drm_encoder_helper_funcs intel_ddi_helper_funcs = {
|
||||
.mode_fixup = intel_ddi_mode_fixup,
|
||||
.mode_set = intel_ddi_mode_set,
|
||||
.disable = intel_encoder_noop,
|
||||
};
|
||||
|
||||
void intel_ddi_init(struct drm_device *dev, enum port port)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
struct intel_digital_port *intel_dig_port;
|
||||
struct intel_encoder *intel_encoder;
|
||||
struct drm_encoder *encoder;
|
||||
@ -1497,6 +1534,8 @@ void intel_ddi_init(struct drm_device *dev, enum port port)
|
||||
intel_encoder->get_hw_state = intel_ddi_get_hw_state;
|
||||
|
||||
intel_dig_port->port = port;
|
||||
intel_dig_port->port_reversal = I915_READ(DDI_BUF_CTL(port)) &
|
||||
DDI_BUF_PORT_REVERSAL;
|
||||
if (hdmi_connector)
|
||||
intel_dig_port->hdmi.sdvox_reg = DDI_BUF_CTL(port);
|
||||
else
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -148,15 +148,6 @@ intel_dp_max_link_bw(struct intel_dp *intel_dp)
|
||||
return max_link_bw;
|
||||
}
|
||||
|
||||
static int
|
||||
intel_dp_link_clock(uint8_t link_bw)
|
||||
{
|
||||
if (link_bw == DP_LINK_BW_2_7)
|
||||
return 270000;
|
||||
else
|
||||
return 162000;
|
||||
}
|
||||
|
||||
/*
|
||||
* The units on the numbers in the next two are... bizarre. Examples will
|
||||
* make it clearer; this one parallels an example in the eDP spec.
|
||||
@ -191,7 +182,8 @@ intel_dp_adjust_dithering(struct intel_dp *intel_dp,
|
||||
struct drm_display_mode *mode,
|
||||
bool adjust_mode)
|
||||
{
|
||||
int max_link_clock = intel_dp_link_clock(intel_dp_max_link_bw(intel_dp));
|
||||
int max_link_clock =
|
||||
drm_dp_bw_code_to_link_rate(intel_dp_max_link_bw(intel_dp));
|
||||
int max_lanes = drm_dp_max_lane_count(intel_dp->dpcd);
|
||||
int max_rate, mode_rate;
|
||||
|
||||
@ -330,6 +322,48 @@ intel_dp_check_edp(struct intel_dp *intel_dp)
|
||||
}
|
||||
}
|
||||
|
||||
static uint32_t
|
||||
intel_dp_aux_wait_done(struct intel_dp *intel_dp, bool has_aux_irq)
|
||||
{
|
||||
struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
|
||||
struct drm_device *dev = intel_dig_port->base.base.dev;
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
uint32_t ch_ctl = intel_dp->output_reg + 0x10;
|
||||
uint32_t status;
|
||||
bool done;
|
||||
|
||||
if (IS_HASWELL(dev)) {
|
||||
switch (intel_dig_port->port) {
|
||||
case PORT_A:
|
||||
ch_ctl = DPA_AUX_CH_CTL;
|
||||
break;
|
||||
case PORT_B:
|
||||
ch_ctl = PCH_DPB_AUX_CH_CTL;
|
||||
break;
|
||||
case PORT_C:
|
||||
ch_ctl = PCH_DPC_AUX_CH_CTL;
|
||||
break;
|
||||
case PORT_D:
|
||||
ch_ctl = PCH_DPD_AUX_CH_CTL;
|
||||
break;
|
||||
default:
|
||||
BUG();
|
||||
}
|
||||
}
|
||||
|
||||
#define C (((status = I915_READ_NOTRACE(ch_ctl)) & DP_AUX_CH_CTL_SEND_BUSY) == 0)
|
||||
if (has_aux_irq)
|
||||
done = wait_event_timeout(dev_priv->gmbus_wait_queue, C, 10);
|
||||
else
|
||||
done = wait_for_atomic(C, 10) == 0;
|
||||
if (!done)
|
||||
DRM_ERROR("dp aux hw did not signal timeout (has irq: %i)!\n",
|
||||
has_aux_irq);
|
||||
#undef C
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static int
|
||||
intel_dp_aux_ch(struct intel_dp *intel_dp,
|
||||
uint8_t *send, int send_bytes,
|
||||
@ -341,11 +375,17 @@ intel_dp_aux_ch(struct intel_dp *intel_dp,
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
uint32_t ch_ctl = output_reg + 0x10;
|
||||
uint32_t ch_data = ch_ctl + 4;
|
||||
int i;
|
||||
int recv_bytes;
|
||||
int i, ret, recv_bytes;
|
||||
uint32_t status;
|
||||
uint32_t aux_clock_divider;
|
||||
int try, precharge;
|
||||
bool has_aux_irq = INTEL_INFO(dev)->gen >= 5 && !IS_VALLEYVIEW(dev);
|
||||
|
||||
/* dp aux is extremely sensitive to irq latency, hence request the
|
||||
* lowest possible wakeup latency and so prevent the cpu from going into
|
||||
* deep sleep states.
|
||||
*/
|
||||
pm_qos_update_request(&dev_priv->pm_qos, 0);
|
||||
|
||||
if (IS_HASWELL(dev)) {
|
||||
switch (intel_dig_port->port) {
|
||||
@ -379,7 +419,7 @@ intel_dp_aux_ch(struct intel_dp *intel_dp,
|
||||
* clock divider.
|
||||
*/
|
||||
if (is_cpu_edp(intel_dp)) {
|
||||
if (IS_HASWELL(dev))
|
||||
if (HAS_DDI(dev))
|
||||
aux_clock_divider = intel_ddi_get_cdclk_freq(dev_priv) >> 1;
|
||||
else if (IS_VALLEYVIEW(dev))
|
||||
aux_clock_divider = 100;
|
||||
@ -399,7 +439,7 @@ intel_dp_aux_ch(struct intel_dp *intel_dp,
|
||||
|
||||
/* Try to wait for any previous AUX channel activity */
|
||||
for (try = 0; try < 3; try++) {
|
||||
status = I915_READ(ch_ctl);
|
||||
status = I915_READ_NOTRACE(ch_ctl);
|
||||
if ((status & DP_AUX_CH_CTL_SEND_BUSY) == 0)
|
||||
break;
|
||||
msleep(1);
|
||||
@ -408,7 +448,8 @@ intel_dp_aux_ch(struct intel_dp *intel_dp,
|
||||
if (try == 3) {
|
||||
WARN(1, "dp_aux_ch not started status 0x%08x\n",
|
||||
I915_READ(ch_ctl));
|
||||
return -EBUSY;
|
||||
ret = -EBUSY;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Must try at least 3 times according to DP spec */
|
||||
@ -421,6 +462,7 @@ intel_dp_aux_ch(struct intel_dp *intel_dp,
|
||||
/* Send the command and wait for it to complete */
|
||||
I915_WRITE(ch_ctl,
|
||||
DP_AUX_CH_CTL_SEND_BUSY |
|
||||
(has_aux_irq ? DP_AUX_CH_CTL_INTERRUPT : 0) |
|
||||
DP_AUX_CH_CTL_TIME_OUT_400us |
|
||||
(send_bytes << DP_AUX_CH_CTL_MESSAGE_SIZE_SHIFT) |
|
||||
(precharge << DP_AUX_CH_CTL_PRECHARGE_2US_SHIFT) |
|
||||
@ -428,12 +470,8 @@ intel_dp_aux_ch(struct intel_dp *intel_dp,
|
||||
DP_AUX_CH_CTL_DONE |
|
||||
DP_AUX_CH_CTL_TIME_OUT_ERROR |
|
||||
DP_AUX_CH_CTL_RECEIVE_ERROR);
|
||||
for (;;) {
|
||||
status = I915_READ(ch_ctl);
|
||||
if ((status & DP_AUX_CH_CTL_SEND_BUSY) == 0)
|
||||
break;
|
||||
udelay(100);
|
||||
}
|
||||
|
||||
status = intel_dp_aux_wait_done(intel_dp, has_aux_irq);
|
||||
|
||||
/* Clear done status and any errors */
|
||||
I915_WRITE(ch_ctl,
|
||||
@ -451,7 +489,8 @@ intel_dp_aux_ch(struct intel_dp *intel_dp,
|
||||
|
||||
if ((status & DP_AUX_CH_CTL_DONE) == 0) {
|
||||
DRM_ERROR("dp_aux_ch not done status 0x%08x\n", status);
|
||||
return -EBUSY;
|
||||
ret = -EBUSY;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Check for timeout or receive error.
|
||||
@ -459,14 +498,16 @@ intel_dp_aux_ch(struct intel_dp *intel_dp,
|
||||
*/
|
||||
if (status & DP_AUX_CH_CTL_RECEIVE_ERROR) {
|
||||
DRM_ERROR("dp_aux_ch receive error status 0x%08x\n", status);
|
||||
return -EIO;
|
||||
ret = -EIO;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Timeouts occur when the device isn't connected, so they're
|
||||
* "normal" -- don't fill the kernel log with these */
|
||||
if (status & DP_AUX_CH_CTL_TIME_OUT_ERROR) {
|
||||
DRM_DEBUG_KMS("dp_aux_ch timeout status 0x%08x\n", status);
|
||||
return -ETIMEDOUT;
|
||||
ret = -ETIMEDOUT;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Unload any bytes sent back from the other side */
|
||||
@ -479,7 +520,11 @@ intel_dp_aux_ch(struct intel_dp *intel_dp,
|
||||
unpack_aux(I915_READ(ch_data + i),
|
||||
recv + i, recv_bytes - i);
|
||||
|
||||
return recv_bytes;
|
||||
ret = recv_bytes;
|
||||
out:
|
||||
pm_qos_update_request(&dev_priv->pm_qos, PM_QOS_DEFAULT_VALUE);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Write data to the aux channel in native mode */
|
||||
@ -718,16 +763,35 @@ intel_dp_mode_fixup(struct drm_encoder *encoder,
|
||||
return false;
|
||||
|
||||
bpp = adjusted_mode->private_flags & INTEL_MODE_DP_FORCE_6BPC ? 18 : 24;
|
||||
|
||||
if (intel_dp->color_range_auto) {
|
||||
/*
|
||||
* See:
|
||||
* CEA-861-E - 5.1 Default Encoding Parameters
|
||||
* VESA DisplayPort Ver.1.2a - 5.1.1.1 Video Colorimetry
|
||||
*/
|
||||
if (bpp != 18 && drm_match_cea_mode(adjusted_mode) > 1)
|
||||
intel_dp->color_range = DP_COLOR_RANGE_16_235;
|
||||
else
|
||||
intel_dp->color_range = 0;
|
||||
}
|
||||
|
||||
if (intel_dp->color_range)
|
||||
adjusted_mode->private_flags |= INTEL_MODE_LIMITED_COLOR_RANGE;
|
||||
|
||||
mode_rate = intel_dp_link_required(adjusted_mode->clock, bpp);
|
||||
|
||||
for (clock = 0; clock <= max_clock; clock++) {
|
||||
for (lane_count = 1; lane_count <= max_lane_count; lane_count <<= 1) {
|
||||
int link_avail = intel_dp_max_data_rate(intel_dp_link_clock(bws[clock]), lane_count);
|
||||
int link_bw_clock =
|
||||
drm_dp_bw_code_to_link_rate(bws[clock]);
|
||||
int link_avail = intel_dp_max_data_rate(link_bw_clock,
|
||||
lane_count);
|
||||
|
||||
if (mode_rate <= link_avail) {
|
||||
intel_dp->link_bw = bws[clock];
|
||||
intel_dp->lane_count = lane_count;
|
||||
adjusted_mode->clock = intel_dp_link_clock(intel_dp->link_bw);
|
||||
adjusted_mode->clock = link_bw_clock;
|
||||
DRM_DEBUG_KMS("DP link bw %02x lane "
|
||||
"count %d clock %d bpp %d\n",
|
||||
intel_dp->link_bw, intel_dp->lane_count,
|
||||
@ -742,39 +806,6 @@ intel_dp_mode_fixup(struct drm_encoder *encoder,
|
||||
return false;
|
||||
}
|
||||
|
||||
struct intel_dp_m_n {
|
||||
uint32_t tu;
|
||||
uint32_t gmch_m;
|
||||
uint32_t gmch_n;
|
||||
uint32_t link_m;
|
||||
uint32_t link_n;
|
||||
};
|
||||
|
||||
static void
|
||||
intel_reduce_ratio(uint32_t *num, uint32_t *den)
|
||||
{
|
||||
while (*num > 0xffffff || *den > 0xffffff) {
|
||||
*num >>= 1;
|
||||
*den >>= 1;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
intel_dp_compute_m_n(int bpp,
|
||||
int nlanes,
|
||||
int pixel_clock,
|
||||
int link_clock,
|
||||
struct intel_dp_m_n *m_n)
|
||||
{
|
||||
m_n->tu = 64;
|
||||
m_n->gmch_m = (pixel_clock * bpp) >> 3;
|
||||
m_n->gmch_n = link_clock * nlanes;
|
||||
intel_reduce_ratio(&m_n->gmch_m, &m_n->gmch_n);
|
||||
m_n->link_m = pixel_clock;
|
||||
m_n->link_n = link_clock;
|
||||
intel_reduce_ratio(&m_n->link_m, &m_n->link_n);
|
||||
}
|
||||
|
||||
void
|
||||
intel_dp_set_m_n(struct drm_crtc *crtc, struct drm_display_mode *mode,
|
||||
struct drm_display_mode *adjusted_mode)
|
||||
@ -785,7 +816,7 @@ intel_dp_set_m_n(struct drm_crtc *crtc, struct drm_display_mode *mode,
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
|
||||
int lane_count = 4;
|
||||
struct intel_dp_m_n m_n;
|
||||
struct intel_link_m_n m_n;
|
||||
int pipe = intel_crtc->pipe;
|
||||
enum transcoder cpu_transcoder = intel_crtc->cpu_transcoder;
|
||||
|
||||
@ -808,8 +839,8 @@ intel_dp_set_m_n(struct drm_crtc *crtc, struct drm_display_mode *mode,
|
||||
* the number of bytes_per_pixel post-LUT, which we always
|
||||
* set up for 8-bits of R/G/B, or 3 bytes total.
|
||||
*/
|
||||
intel_dp_compute_m_n(intel_crtc->bpp, lane_count,
|
||||
mode->clock, adjusted_mode->clock, &m_n);
|
||||
intel_link_compute_m_n(intel_crtc->bpp, lane_count,
|
||||
mode->clock, adjusted_mode->clock, &m_n);
|
||||
|
||||
if (IS_HASWELL(dev)) {
|
||||
I915_WRITE(PIPE_DATA_M1(cpu_transcoder),
|
||||
@ -851,6 +882,32 @@ void intel_dp_init_link_config(struct intel_dp *intel_dp)
|
||||
}
|
||||
}
|
||||
|
||||
static void ironlake_set_pll_edp(struct drm_crtc *crtc, int clock)
|
||||
{
|
||||
struct drm_device *dev = crtc->dev;
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
u32 dpa_ctl;
|
||||
|
||||
DRM_DEBUG_KMS("eDP PLL enable for clock %d\n", clock);
|
||||
dpa_ctl = I915_READ(DP_A);
|
||||
dpa_ctl &= ~DP_PLL_FREQ_MASK;
|
||||
|
||||
if (clock < 200000) {
|
||||
/* For a long time we've carried around a ILK-DevA w/a for the
|
||||
* 160MHz clock. If we're really unlucky, it's still required.
|
||||
*/
|
||||
DRM_DEBUG_KMS("160MHz cpu eDP clock, might need ilk devA w/a\n");
|
||||
dpa_ctl |= DP_PLL_FREQ_160MHZ;
|
||||
} else {
|
||||
dpa_ctl |= DP_PLL_FREQ_270MHZ;
|
||||
}
|
||||
|
||||
I915_WRITE(DP_A, dpa_ctl);
|
||||
|
||||
POSTING_READ(DP_A);
|
||||
udelay(500);
|
||||
}
|
||||
|
||||
static void
|
||||
intel_dp_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode,
|
||||
struct drm_display_mode *adjusted_mode)
|
||||
@ -926,7 +983,8 @@ intel_dp_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode,
|
||||
else
|
||||
intel_dp->DP |= DP_PLL_FREQ_270MHZ;
|
||||
} else if (!HAS_PCH_CPT(dev) || is_cpu_edp(intel_dp)) {
|
||||
intel_dp->DP |= intel_dp->color_range;
|
||||
if (!HAS_PCH_SPLIT(dev))
|
||||
intel_dp->DP |= intel_dp->color_range;
|
||||
|
||||
if (adjusted_mode->flags & DRM_MODE_FLAG_PHSYNC)
|
||||
intel_dp->DP |= DP_SYNC_HS_HIGH;
|
||||
@ -950,6 +1008,9 @@ intel_dp_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode,
|
||||
} else {
|
||||
intel_dp->DP |= DP_LINK_TRAIN_OFF_CPT;
|
||||
}
|
||||
|
||||
if (is_cpu_edp(intel_dp))
|
||||
ironlake_set_pll_edp(crtc, adjusted_mode->clock);
|
||||
}
|
||||
|
||||
#define IDLE_ON_MASK (PP_ON | 0 | PP_SEQUENCE_MASK | 0 | PP_SEQUENCE_STATE_MASK)
|
||||
@ -1057,6 +1118,8 @@ static void ironlake_panel_vdd_off_sync(struct intel_dp *intel_dp)
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
u32 pp;
|
||||
|
||||
WARN_ON(!mutex_is_locked(&dev->mode_config.mutex));
|
||||
|
||||
if (!intel_dp->want_panel_vdd && ironlake_edp_have_panel_vdd(intel_dp)) {
|
||||
pp = ironlake_get_pp_control(dev_priv);
|
||||
pp &= ~EDP_FORCE_VDD;
|
||||
@ -1543,7 +1606,7 @@ intel_get_adjust_train(struct intel_dp *intel_dp, uint8_t link_status[DP_LINK_ST
|
||||
}
|
||||
|
||||
static uint32_t
|
||||
intel_dp_signal_levels(uint8_t train_set)
|
||||
intel_gen4_signal_levels(uint8_t train_set)
|
||||
{
|
||||
uint32_t signal_levels = 0;
|
||||
|
||||
@ -1641,7 +1704,7 @@ intel_gen7_edp_signal_levels(uint8_t train_set)
|
||||
|
||||
/* Gen7.5's (HSW) DP voltage swing and pre-emphasis control */
|
||||
static uint32_t
|
||||
intel_dp_signal_levels_hsw(uint8_t train_set)
|
||||
intel_hsw_signal_levels(uint8_t train_set)
|
||||
{
|
||||
int signal_levels = train_set & (DP_TRAIN_VOLTAGE_SWING_MASK |
|
||||
DP_TRAIN_PRE_EMPHASIS_MASK);
|
||||
@ -1673,6 +1736,34 @@ intel_dp_signal_levels_hsw(uint8_t train_set)
|
||||
}
|
||||
}
|
||||
|
||||
/* Properly updates "DP" with the correct signal levels. */
|
||||
static void
|
||||
intel_dp_set_signal_levels(struct intel_dp *intel_dp, uint32_t *DP)
|
||||
{
|
||||
struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
|
||||
struct drm_device *dev = intel_dig_port->base.base.dev;
|
||||
uint32_t signal_levels, mask;
|
||||
uint8_t train_set = intel_dp->train_set[0];
|
||||
|
||||
if (IS_HASWELL(dev)) {
|
||||
signal_levels = intel_hsw_signal_levels(train_set);
|
||||
mask = DDI_BUF_EMP_MASK;
|
||||
} else if (IS_GEN7(dev) && is_cpu_edp(intel_dp) && !IS_VALLEYVIEW(dev)) {
|
||||
signal_levels = intel_gen7_edp_signal_levels(train_set);
|
||||
mask = EDP_LINK_TRAIN_VOL_EMP_MASK_IVB;
|
||||
} else if (IS_GEN6(dev) && is_cpu_edp(intel_dp)) {
|
||||
signal_levels = intel_gen6_edp_signal_levels(train_set);
|
||||
mask = EDP_LINK_TRAIN_VOL_EMP_MASK_SNB;
|
||||
} else {
|
||||
signal_levels = intel_gen4_signal_levels(train_set);
|
||||
mask = DP_VOLTAGE_MASK | DP_PRE_EMPHASIS_MASK;
|
||||
}
|
||||
|
||||
DRM_DEBUG_KMS("Using signal levels %08x\n", signal_levels);
|
||||
|
||||
*DP = (*DP & ~mask) | signal_levels;
|
||||
}
|
||||
|
||||
static bool
|
||||
intel_dp_set_link_train(struct intel_dp *intel_dp,
|
||||
uint32_t dp_reg_value,
|
||||
@ -1696,14 +1787,18 @@ intel_dp_set_link_train(struct intel_dp *intel_dp,
|
||||
temp &= ~DP_TP_CTL_LINK_TRAIN_MASK;
|
||||
switch (dp_train_pat & DP_TRAINING_PATTERN_MASK) {
|
||||
case DP_TRAINING_PATTERN_DISABLE:
|
||||
temp |= DP_TP_CTL_LINK_TRAIN_IDLE;
|
||||
I915_WRITE(DP_TP_CTL(port), temp);
|
||||
|
||||
if (wait_for((I915_READ(DP_TP_STATUS(port)) &
|
||||
DP_TP_STATUS_IDLE_DONE), 1))
|
||||
DRM_ERROR("Timed out waiting for DP idle patterns\n");
|
||||
if (port != PORT_A) {
|
||||
temp |= DP_TP_CTL_LINK_TRAIN_IDLE;
|
||||
I915_WRITE(DP_TP_CTL(port), temp);
|
||||
|
||||
if (wait_for((I915_READ(DP_TP_STATUS(port)) &
|
||||
DP_TP_STATUS_IDLE_DONE), 1))
|
||||
DRM_ERROR("Timed out waiting for DP idle patterns\n");
|
||||
|
||||
temp &= ~DP_TP_CTL_LINK_TRAIN_MASK;
|
||||
}
|
||||
|
||||
temp &= ~DP_TP_CTL_LINK_TRAIN_MASK;
|
||||
temp |= DP_TP_CTL_LINK_TRAIN_NORMAL;
|
||||
|
||||
break;
|
||||
@ -1791,7 +1886,7 @@ intel_dp_start_link_train(struct intel_dp *intel_dp)
|
||||
int voltage_tries, loop_tries;
|
||||
uint32_t DP = intel_dp->DP;
|
||||
|
||||
if (IS_HASWELL(dev))
|
||||
if (HAS_DDI(dev))
|
||||
intel_ddi_prepare_link_retrain(encoder);
|
||||
|
||||
/* Write the link configuration data */
|
||||
@ -1809,24 +1904,8 @@ intel_dp_start_link_train(struct intel_dp *intel_dp)
|
||||
for (;;) {
|
||||
/* Use intel_dp->train_set[0] to set the voltage and pre emphasis values */
|
||||
uint8_t link_status[DP_LINK_STATUS_SIZE];
|
||||
uint32_t signal_levels;
|
||||
|
||||
if (IS_HASWELL(dev)) {
|
||||
signal_levels = intel_dp_signal_levels_hsw(
|
||||
intel_dp->train_set[0]);
|
||||
DP = (DP & ~DDI_BUF_EMP_MASK) | signal_levels;
|
||||
} else if (IS_GEN7(dev) && is_cpu_edp(intel_dp) && !IS_VALLEYVIEW(dev)) {
|
||||
signal_levels = intel_gen7_edp_signal_levels(intel_dp->train_set[0]);
|
||||
DP = (DP & ~EDP_LINK_TRAIN_VOL_EMP_MASK_IVB) | signal_levels;
|
||||
} else if (IS_GEN6(dev) && is_cpu_edp(intel_dp)) {
|
||||
signal_levels = intel_gen6_edp_signal_levels(intel_dp->train_set[0]);
|
||||
DP = (DP & ~EDP_LINK_TRAIN_VOL_EMP_MASK_SNB) | signal_levels;
|
||||
} else {
|
||||
signal_levels = intel_dp_signal_levels(intel_dp->train_set[0]);
|
||||
DP = (DP & ~(DP_VOLTAGE_MASK|DP_PRE_EMPHASIS_MASK)) | signal_levels;
|
||||
}
|
||||
DRM_DEBUG_KMS("training pattern 1 signal levels %08x\n",
|
||||
signal_levels);
|
||||
intel_dp_set_signal_levels(intel_dp, &DP);
|
||||
|
||||
/* Set training pattern 1 */
|
||||
if (!intel_dp_set_link_train(intel_dp, DP,
|
||||
@ -1882,7 +1961,6 @@ intel_dp_start_link_train(struct intel_dp *intel_dp)
|
||||
void
|
||||
intel_dp_complete_link_train(struct intel_dp *intel_dp)
|
||||
{
|
||||
struct drm_device *dev = intel_dp_to_dev(intel_dp);
|
||||
bool channel_eq = false;
|
||||
int tries, cr_tries;
|
||||
uint32_t DP = intel_dp->DP;
|
||||
@ -1892,8 +1970,6 @@ intel_dp_complete_link_train(struct intel_dp *intel_dp)
|
||||
cr_tries = 0;
|
||||
channel_eq = false;
|
||||
for (;;) {
|
||||
/* Use intel_dp->train_set[0] to set the voltage and pre emphasis values */
|
||||
uint32_t signal_levels;
|
||||
uint8_t link_status[DP_LINK_STATUS_SIZE];
|
||||
|
||||
if (cr_tries > 5) {
|
||||
@ -1902,19 +1978,7 @@ intel_dp_complete_link_train(struct intel_dp *intel_dp)
|
||||
break;
|
||||
}
|
||||
|
||||
if (IS_HASWELL(dev)) {
|
||||
signal_levels = intel_dp_signal_levels_hsw(intel_dp->train_set[0]);
|
||||
DP = (DP & ~DDI_BUF_EMP_MASK) | signal_levels;
|
||||
} else if (IS_GEN7(dev) && is_cpu_edp(intel_dp) && !IS_VALLEYVIEW(dev)) {
|
||||
signal_levels = intel_gen7_edp_signal_levels(intel_dp->train_set[0]);
|
||||
DP = (DP & ~EDP_LINK_TRAIN_VOL_EMP_MASK_IVB) | signal_levels;
|
||||
} else if (IS_GEN6(dev) && is_cpu_edp(intel_dp)) {
|
||||
signal_levels = intel_gen6_edp_signal_levels(intel_dp->train_set[0]);
|
||||
DP = (DP & ~EDP_LINK_TRAIN_VOL_EMP_MASK_SNB) | signal_levels;
|
||||
} else {
|
||||
signal_levels = intel_dp_signal_levels(intel_dp->train_set[0]);
|
||||
DP = (DP & ~(DP_VOLTAGE_MASK|DP_PRE_EMPHASIS_MASK)) | signal_levels;
|
||||
}
|
||||
intel_dp_set_signal_levels(intel_dp, &DP);
|
||||
|
||||
/* channel eq pattern */
|
||||
if (!intel_dp_set_link_train(intel_dp, DP,
|
||||
@ -1964,6 +2028,8 @@ intel_dp_link_down(struct intel_dp *intel_dp)
|
||||
struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
|
||||
struct drm_device *dev = intel_dig_port->base.base.dev;
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
struct intel_crtc *intel_crtc =
|
||||
to_intel_crtc(intel_dig_port->base.base.crtc);
|
||||
uint32_t DP = intel_dp->DP;
|
||||
|
||||
/*
|
||||
@ -1981,7 +2047,7 @@ intel_dp_link_down(struct intel_dp *intel_dp)
|
||||
* intel_ddi_prepare_link_retrain will take care of redoing the link
|
||||
* train.
|
||||
*/
|
||||
if (IS_HASWELL(dev))
|
||||
if (HAS_DDI(dev))
|
||||
return;
|
||||
|
||||
if (WARN_ON((I915_READ(intel_dp->output_reg) & DP_PORT_EN) == 0))
|
||||
@ -1998,7 +2064,8 @@ intel_dp_link_down(struct intel_dp *intel_dp)
|
||||
}
|
||||
POSTING_READ(intel_dp->output_reg);
|
||||
|
||||
msleep(17);
|
||||
/* We don't really know why we're doing this */
|
||||
intel_wait_for_vblank(dev, intel_crtc->pipe);
|
||||
|
||||
if (HAS_PCH_IBX(dev) &&
|
||||
I915_READ(intel_dp->output_reg) & DP_PIPEB_SELECT) {
|
||||
@ -2018,19 +2085,14 @@ intel_dp_link_down(struct intel_dp *intel_dp)
|
||||
/* Changes to enable or select take place the vblank
|
||||
* after being written.
|
||||
*/
|
||||
if (crtc == NULL) {
|
||||
/* We can arrive here never having been attached
|
||||
* to a CRTC, for instance, due to inheriting
|
||||
* random state from the BIOS.
|
||||
*
|
||||
* If the pipe is not running, play safe and
|
||||
* wait for the clocks to stabilise before
|
||||
* continuing.
|
||||
*/
|
||||
if (WARN_ON(crtc == NULL)) {
|
||||
/* We should never try to disable a port without a crtc
|
||||
* attached. For paranoia keep the code around for a
|
||||
* bit. */
|
||||
POSTING_READ(intel_dp->output_reg);
|
||||
msleep(50);
|
||||
} else
|
||||
intel_wait_for_vblank(dev, to_intel_crtc(crtc)->pipe);
|
||||
intel_wait_for_vblank(dev, intel_crtc->pipe);
|
||||
}
|
||||
|
||||
DP &= ~DP_AUDIO_OUTPUT_ENABLE;
|
||||
@ -2042,10 +2104,16 @@ intel_dp_link_down(struct intel_dp *intel_dp)
|
||||
static bool
|
||||
intel_dp_get_dpcd(struct intel_dp *intel_dp)
|
||||
{
|
||||
char dpcd_hex_dump[sizeof(intel_dp->dpcd) * 3];
|
||||
|
||||
if (intel_dp_aux_native_read_retry(intel_dp, 0x000, intel_dp->dpcd,
|
||||
sizeof(intel_dp->dpcd)) == 0)
|
||||
return false; /* aux transfer failed */
|
||||
|
||||
hex_dump_to_buffer(intel_dp->dpcd, sizeof(intel_dp->dpcd),
|
||||
32, 1, dpcd_hex_dump, sizeof(dpcd_hex_dump), false);
|
||||
DRM_DEBUG_KMS("DPCD: %s\n", dpcd_hex_dump);
|
||||
|
||||
if (intel_dp->dpcd[DP_DPCD_REV] == 0)
|
||||
return false; /* DPCD not present */
|
||||
|
||||
@ -2206,6 +2274,8 @@ static enum drm_connector_status
|
||||
ironlake_dp_detect(struct intel_dp *intel_dp)
|
||||
{
|
||||
struct drm_device *dev = intel_dp_to_dev(intel_dp);
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
|
||||
enum drm_connector_status status;
|
||||
|
||||
/* Can't disconnect eDP, but you can close the lid... */
|
||||
@ -2216,6 +2286,9 @@ ironlake_dp_detect(struct intel_dp *intel_dp)
|
||||
return status;
|
||||
}
|
||||
|
||||
if (!ibx_digital_port_connected(dev_priv, intel_dig_port))
|
||||
return connector_status_disconnected;
|
||||
|
||||
return intel_dp_detect_dpcd(intel_dp);
|
||||
}
|
||||
|
||||
@ -2224,17 +2297,18 @@ g4x_dp_detect(struct intel_dp *intel_dp)
|
||||
{
|
||||
struct drm_device *dev = intel_dp_to_dev(intel_dp);
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
|
||||
uint32_t bit;
|
||||
|
||||
switch (intel_dp->output_reg) {
|
||||
case DP_B:
|
||||
bit = DPB_HOTPLUG_LIVE_STATUS;
|
||||
switch (intel_dig_port->port) {
|
||||
case PORT_B:
|
||||
bit = PORTB_HOTPLUG_LIVE_STATUS;
|
||||
break;
|
||||
case DP_C:
|
||||
bit = DPC_HOTPLUG_LIVE_STATUS;
|
||||
case PORT_C:
|
||||
bit = PORTC_HOTPLUG_LIVE_STATUS;
|
||||
break;
|
||||
case DP_D:
|
||||
bit = DPD_HOTPLUG_LIVE_STATUS;
|
||||
case PORT_D:
|
||||
bit = PORTD_HOTPLUG_LIVE_STATUS;
|
||||
break;
|
||||
default:
|
||||
return connector_status_unknown;
|
||||
@ -2290,13 +2364,6 @@ intel_dp_get_edid_modes(struct drm_connector *connector, struct i2c_adapter *ada
|
||||
return intel_ddc_get_modes(connector, adapter);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Uses CRT_HOTPLUG_EN and CRT_HOTPLUG_STAT to detect DP connection.
|
||||
*
|
||||
* \return true if DP port is connected.
|
||||
* \return false if DP port is disconnected.
|
||||
*/
|
||||
static enum drm_connector_status
|
||||
intel_dp_detect(struct drm_connector *connector, bool force)
|
||||
{
|
||||
@ -2306,7 +2373,6 @@ intel_dp_detect(struct drm_connector *connector, bool force)
|
||||
struct drm_device *dev = connector->dev;
|
||||
enum drm_connector_status status;
|
||||
struct edid *edid = NULL;
|
||||
char dpcd_hex_dump[sizeof(intel_dp->dpcd) * 3];
|
||||
|
||||
intel_dp->has_audio = false;
|
||||
|
||||
@ -2315,10 +2381,6 @@ intel_dp_detect(struct drm_connector *connector, bool force)
|
||||
else
|
||||
status = g4x_dp_detect(intel_dp);
|
||||
|
||||
hex_dump_to_buffer(intel_dp->dpcd, sizeof(intel_dp->dpcd),
|
||||
32, 1, dpcd_hex_dump, sizeof(dpcd_hex_dump), false);
|
||||
DRM_DEBUG_KMS("DPCD: %s\n", dpcd_hex_dump);
|
||||
|
||||
if (status != connector_status_connected)
|
||||
return status;
|
||||
|
||||
@ -2419,10 +2481,21 @@ intel_dp_set_property(struct drm_connector *connector,
|
||||
}
|
||||
|
||||
if (property == dev_priv->broadcast_rgb_property) {
|
||||
if (val == !!intel_dp->color_range)
|
||||
return 0;
|
||||
|
||||
intel_dp->color_range = val ? DP_COLOR_RANGE_16_235 : 0;
|
||||
switch (val) {
|
||||
case INTEL_BROADCAST_RGB_AUTO:
|
||||
intel_dp->color_range_auto = true;
|
||||
break;
|
||||
case INTEL_BROADCAST_RGB_FULL:
|
||||
intel_dp->color_range_auto = false;
|
||||
intel_dp->color_range = 0;
|
||||
break;
|
||||
case INTEL_BROADCAST_RGB_LIMITED:
|
||||
intel_dp->color_range_auto = false;
|
||||
intel_dp->color_range = DP_COLOR_RANGE_16_235;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
goto done;
|
||||
}
|
||||
|
||||
@ -2445,11 +2518,8 @@ intel_dp_set_property(struct drm_connector *connector,
|
||||
return -EINVAL;
|
||||
|
||||
done:
|
||||
if (intel_encoder->base.crtc) {
|
||||
struct drm_crtc *crtc = intel_encoder->base.crtc;
|
||||
intel_set_mode(crtc, &crtc->mode,
|
||||
crtc->x, crtc->y, crtc->fb);
|
||||
}
|
||||
if (intel_encoder->base.crtc)
|
||||
intel_crtc_restore_mode(intel_encoder->base.crtc);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -2491,7 +2561,6 @@ void intel_dp_encoder_destroy(struct drm_encoder *encoder)
|
||||
static const struct drm_encoder_helper_funcs intel_dp_helper_funcs = {
|
||||
.mode_fixup = intel_dp_mode_fixup,
|
||||
.mode_set = intel_dp_mode_set,
|
||||
.disable = intel_encoder_noop,
|
||||
};
|
||||
|
||||
static const struct drm_connector_funcs intel_dp_connector_funcs = {
|
||||
@ -2566,6 +2635,7 @@ intel_dp_add_properties(struct intel_dp *intel_dp, struct drm_connector *connect
|
||||
|
||||
intel_attach_force_audio_property(connector);
|
||||
intel_attach_broadcast_rgb_property(connector);
|
||||
intel_dp->color_range_auto = true;
|
||||
|
||||
if (is_edp(intel_dp)) {
|
||||
drm_mode_create_scaling_mode_property(connector->dev);
|
||||
@ -2755,7 +2825,7 @@ intel_dp_init_connector(struct intel_digital_port *intel_dig_port,
|
||||
intel_connector_attach_encoder(intel_connector, intel_encoder);
|
||||
drm_sysfs_connector_add(connector);
|
||||
|
||||
if (IS_HASWELL(dev))
|
||||
if (HAS_DDI(dev))
|
||||
intel_connector->get_hw_state = intel_ddi_connector_get_hw_state;
|
||||
else
|
||||
intel_connector->get_hw_state = intel_connector_get_hw_state;
|
||||
@ -2767,15 +2837,15 @@ intel_dp_init_connector(struct intel_digital_port *intel_dig_port,
|
||||
name = "DPDDC-A";
|
||||
break;
|
||||
case PORT_B:
|
||||
dev_priv->hotplug_supported_mask |= DPB_HOTPLUG_INT_STATUS;
|
||||
dev_priv->hotplug_supported_mask |= PORTB_HOTPLUG_INT_STATUS;
|
||||
name = "DPDDC-B";
|
||||
break;
|
||||
case PORT_C:
|
||||
dev_priv->hotplug_supported_mask |= DPC_HOTPLUG_INT_STATUS;
|
||||
dev_priv->hotplug_supported_mask |= PORTC_HOTPLUG_INT_STATUS;
|
||||
name = "DPDDC-C";
|
||||
break;
|
||||
case PORT_D:
|
||||
dev_priv->hotplug_supported_mask |= DPD_HOTPLUG_INT_STATUS;
|
||||
dev_priv->hotplug_supported_mask |= PORTD_HOTPLUG_INT_STATUS;
|
||||
name = "DPDDC-D";
|
||||
break;
|
||||
default:
|
||||
|
@ -109,6 +109,11 @@
|
||||
* timings in the mode to prevent the crtc fixup from overwriting them.
|
||||
* Currently only lvds needs that. */
|
||||
#define INTEL_MODE_CRTC_TIMINGS_SET (0x20)
|
||||
/*
|
||||
* Set when limited 16-235 (as opposed to full 0-255) RGB color range is
|
||||
* to be used.
|
||||
*/
|
||||
#define INTEL_MODE_LIMITED_COLOR_RANGE (0x40)
|
||||
|
||||
static inline void
|
||||
intel_mode_set_pixel_multiplier(struct drm_display_mode *mode,
|
||||
@ -153,6 +158,7 @@ struct intel_encoder {
|
||||
bool cloneable;
|
||||
bool connectors_active;
|
||||
void (*hot_plug)(struct intel_encoder *);
|
||||
void (*pre_pll_enable)(struct intel_encoder *);
|
||||
void (*pre_enable)(struct intel_encoder *);
|
||||
void (*enable)(struct intel_encoder *);
|
||||
void (*disable)(struct intel_encoder *);
|
||||
@ -205,6 +211,7 @@ struct intel_crtc {
|
||||
* some outputs connected to this crtc.
|
||||
*/
|
||||
bool active;
|
||||
bool eld_vld;
|
||||
bool primary_disabled; /* is the crtc obscured by a plane? */
|
||||
bool lowfreq_avail;
|
||||
struct intel_overlay *overlay;
|
||||
@ -228,6 +235,9 @@ struct intel_crtc {
|
||||
/* We can share PLLs across outputs if the timings match */
|
||||
struct intel_pch_pll *pch_pll;
|
||||
uint32_t ddi_pll_sel;
|
||||
|
||||
/* reset counter value when the last flip was submitted */
|
||||
unsigned int reset_counter;
|
||||
};
|
||||
|
||||
struct intel_plane {
|
||||
@ -283,6 +293,9 @@ struct cxsr_latency {
|
||||
#define DIP_LEN_AVI 13
|
||||
#define DIP_AVI_PR_1 0
|
||||
#define DIP_AVI_PR_2 1
|
||||
#define DIP_AVI_RGB_QUANT_RANGE_DEFAULT (0 << 2)
|
||||
#define DIP_AVI_RGB_QUANT_RANGE_LIMITED (1 << 2)
|
||||
#define DIP_AVI_RGB_QUANT_RANGE_FULL (2 << 2)
|
||||
|
||||
#define DIP_TYPE_SPD 0x83
|
||||
#define DIP_VERSION_SPD 0x1
|
||||
@ -337,9 +350,11 @@ struct intel_hdmi {
|
||||
u32 sdvox_reg;
|
||||
int ddc_bus;
|
||||
uint32_t color_range;
|
||||
bool color_range_auto;
|
||||
bool has_hdmi_sink;
|
||||
bool has_audio;
|
||||
enum hdmi_force_audio force_audio;
|
||||
bool rgb_quant_range_selectable;
|
||||
void (*write_infoframe)(struct drm_encoder *encoder,
|
||||
struct dip_infoframe *frame);
|
||||
void (*set_infoframes)(struct drm_encoder *encoder,
|
||||
@ -356,6 +371,7 @@ struct intel_dp {
|
||||
bool has_audio;
|
||||
enum hdmi_force_audio force_audio;
|
||||
uint32_t color_range;
|
||||
bool color_range_auto;
|
||||
uint8_t link_bw;
|
||||
uint8_t lane_count;
|
||||
uint8_t dpcd[DP_RECEIVER_CAP_SIZE];
|
||||
@ -377,6 +393,7 @@ struct intel_dp {
|
||||
struct intel_digital_port {
|
||||
struct intel_encoder base;
|
||||
enum port port;
|
||||
u32 port_reversal;
|
||||
struct intel_dp dp;
|
||||
struct intel_hdmi hdmi;
|
||||
};
|
||||
@ -439,10 +456,10 @@ extern bool intel_sdvo_init(struct drm_device *dev, uint32_t sdvo_reg,
|
||||
extern void intel_dvo_init(struct drm_device *dev);
|
||||
extern void intel_tv_init(struct drm_device *dev);
|
||||
extern void intel_mark_busy(struct drm_device *dev);
|
||||
extern void intel_mark_idle(struct drm_device *dev);
|
||||
extern void intel_mark_fb_busy(struct drm_i915_gem_object *obj);
|
||||
extern void intel_mark_fb_idle(struct drm_i915_gem_object *obj);
|
||||
extern void intel_mark_idle(struct drm_device *dev);
|
||||
extern bool intel_lvds_init(struct drm_device *dev);
|
||||
extern bool intel_is_dual_link_lvds(struct drm_device *dev);
|
||||
extern void intel_dp_init(struct drm_device *dev, int output_reg,
|
||||
enum port port);
|
||||
extern void intel_dp_init_connector(struct intel_digital_port *intel_dig_port,
|
||||
@ -502,12 +519,12 @@ struct intel_set_config {
|
||||
bool mode_changed;
|
||||
};
|
||||
|
||||
extern bool intel_set_mode(struct drm_crtc *crtc, struct drm_display_mode *mode,
|
||||
int x, int y, struct drm_framebuffer *old_fb);
|
||||
extern int intel_set_mode(struct drm_crtc *crtc, struct drm_display_mode *mode,
|
||||
int x, int y, struct drm_framebuffer *old_fb);
|
||||
extern void intel_modeset_disable(struct drm_device *dev);
|
||||
extern void intel_crtc_restore_mode(struct drm_crtc *crtc);
|
||||
extern void intel_crtc_load_lut(struct drm_crtc *crtc);
|
||||
extern void intel_crtc_update_dpms(struct drm_crtc *crtc);
|
||||
extern void intel_encoder_noop(struct drm_encoder *encoder);
|
||||
extern void intel_encoder_destroy(struct drm_encoder *encoder);
|
||||
extern void intel_encoder_dpms(struct intel_encoder *encoder, int mode);
|
||||
extern bool intel_encoder_check_is_cloned(struct intel_encoder *encoder);
|
||||
@ -546,6 +563,9 @@ hdmi_to_dig_port(struct intel_hdmi *intel_hdmi)
|
||||
return container_of(intel_hdmi, struct intel_digital_port, hdmi);
|
||||
}
|
||||
|
||||
bool ibx_digital_port_connected(struct drm_i915_private *dev_priv,
|
||||
struct intel_digital_port *port);
|
||||
|
||||
extern void intel_connector_attach_encoder(struct intel_connector *connector,
|
||||
struct intel_encoder *encoder);
|
||||
extern struct drm_encoder *intel_best_encoder(struct drm_connector *connector);
|
||||
@ -589,6 +609,7 @@ extern int intel_framebuffer_init(struct drm_device *dev,
|
||||
struct drm_mode_fb_cmd2 *mode_cmd,
|
||||
struct drm_i915_gem_object *obj);
|
||||
extern int intel_fbdev_init(struct drm_device *dev);
|
||||
extern void intel_fbdev_initial_config(struct drm_device *dev);
|
||||
extern void intel_fbdev_fini(struct drm_device *dev);
|
||||
extern void intel_fbdev_set_suspend(struct drm_device *dev, int state);
|
||||
extern void intel_prepare_page_flip(struct drm_device *dev, int plane);
|
||||
@ -627,9 +648,10 @@ extern void intel_update_sprite_watermarks(struct drm_device *dev, int pipe,
|
||||
extern void intel_update_linetime_watermarks(struct drm_device *dev, int pipe,
|
||||
struct drm_display_mode *mode);
|
||||
|
||||
extern unsigned long intel_gen4_compute_offset_xtiled(int *x, int *y,
|
||||
unsigned int bpp,
|
||||
unsigned int pitch);
|
||||
extern unsigned long intel_gen4_compute_page_offset(int *x, int *y,
|
||||
unsigned int tiling_mode,
|
||||
unsigned int bpp,
|
||||
unsigned int pitch);
|
||||
|
||||
extern int intel_sprite_set_colorkey(struct drm_device *dev, void *data,
|
||||
struct drm_file *file_priv);
|
||||
@ -648,7 +670,8 @@ extern void intel_update_fbc(struct drm_device *dev);
|
||||
extern void intel_gpu_ips_init(struct drm_i915_private *dev_priv);
|
||||
extern void intel_gpu_ips_teardown(void);
|
||||
|
||||
extern void intel_init_power_wells(struct drm_device *dev);
|
||||
extern void intel_init_power_well(struct drm_device *dev);
|
||||
extern void intel_set_power_well(struct drm_device *dev, bool enable);
|
||||
extern void intel_enable_gt_powersave(struct drm_device *dev);
|
||||
extern void intel_disable_gt_powersave(struct drm_device *dev);
|
||||
extern void gen6_gt_check_fifodbg(struct drm_i915_private *dev_priv);
|
||||
|
@ -345,7 +345,6 @@ static void intel_dvo_destroy(struct drm_connector *connector)
|
||||
static const struct drm_encoder_helper_funcs intel_dvo_helper_funcs = {
|
||||
.mode_fixup = intel_dvo_mode_fixup,
|
||||
.mode_set = intel_dvo_mode_set,
|
||||
.disable = intel_encoder_noop,
|
||||
};
|
||||
|
||||
static const struct drm_connector_funcs intel_dvo_connector_funcs = {
|
||||
|
@ -57,9 +57,10 @@ static struct fb_ops intelfb_ops = {
|
||||
.fb_debug_leave = drm_fb_helper_debug_leave,
|
||||
};
|
||||
|
||||
static int intelfb_create(struct intel_fbdev *ifbdev,
|
||||
static int intelfb_create(struct drm_fb_helper *helper,
|
||||
struct drm_fb_helper_surface_size *sizes)
|
||||
{
|
||||
struct intel_fbdev *ifbdev = (struct intel_fbdev *)helper;
|
||||
struct drm_device *dev = ifbdev->helper.dev;
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
struct fb_info *info;
|
||||
@ -83,7 +84,9 @@ static int intelfb_create(struct intel_fbdev *ifbdev,
|
||||
|
||||
size = mode_cmd.pitches[0] * mode_cmd.height;
|
||||
size = ALIGN(size, PAGE_SIZE);
|
||||
obj = i915_gem_alloc_object(dev, size);
|
||||
obj = i915_gem_object_create_stolen(dev, size);
|
||||
if (obj == NULL)
|
||||
obj = i915_gem_alloc_object(dev, size);
|
||||
if (!obj) {
|
||||
DRM_ERROR("failed to allocate framebuffer\n");
|
||||
ret = -ENOMEM;
|
||||
@ -133,14 +136,13 @@ static int intelfb_create(struct intel_fbdev *ifbdev,
|
||||
goto out_unpin;
|
||||
}
|
||||
info->apertures->ranges[0].base = dev->mode_config.fb_base;
|
||||
info->apertures->ranges[0].size =
|
||||
dev_priv->mm.gtt->gtt_mappable_entries << PAGE_SHIFT;
|
||||
info->apertures->ranges[0].size = dev_priv->gtt.mappable_end;
|
||||
|
||||
info->fix.smem_start = dev->mode_config.fb_base + obj->gtt_offset;
|
||||
info->fix.smem_len = size;
|
||||
|
||||
info->screen_base =
|
||||
ioremap_wc(dev_priv->mm.gtt_base_addr + obj->gtt_offset,
|
||||
ioremap_wc(dev_priv->gtt.mappable_base + obj->gtt_offset,
|
||||
size);
|
||||
if (!info->screen_base) {
|
||||
ret = -ENOSPC;
|
||||
@ -153,6 +155,13 @@ static int intelfb_create(struct intel_fbdev *ifbdev,
|
||||
drm_fb_helper_fill_fix(info, fb->pitches[0], fb->depth);
|
||||
drm_fb_helper_fill_var(info, &ifbdev->helper, sizes->fb_width, sizes->fb_height);
|
||||
|
||||
/* If the object is shmemfs backed, it will have given us zeroed pages.
|
||||
* If the object is stolen however, it will be full of whatever
|
||||
* garbage was left in there.
|
||||
*/
|
||||
if (ifbdev->ifb.obj->stolen)
|
||||
memset_io(info->screen_base, 0, info->screen_size);
|
||||
|
||||
/* Use default scratch pixmap (info->pixmap.flags = FB_PIXMAP_SYSTEM) */
|
||||
|
||||
DRM_DEBUG_KMS("allocated %dx%d fb: 0x%08x, bo %p\n",
|
||||
@ -173,26 +182,10 @@ out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int intel_fb_find_or_create_single(struct drm_fb_helper *helper,
|
||||
struct drm_fb_helper_surface_size *sizes)
|
||||
{
|
||||
struct intel_fbdev *ifbdev = (struct intel_fbdev *)helper;
|
||||
int new_fb = 0;
|
||||
int ret;
|
||||
|
||||
if (!helper->fb) {
|
||||
ret = intelfb_create(ifbdev, sizes);
|
||||
if (ret)
|
||||
return ret;
|
||||
new_fb = 1;
|
||||
}
|
||||
return new_fb;
|
||||
}
|
||||
|
||||
static struct drm_fb_helper_funcs intel_fb_helper_funcs = {
|
||||
.gamma_set = intel_crtc_fb_gamma_set,
|
||||
.gamma_get = intel_crtc_fb_gamma_get,
|
||||
.fb_probe = intel_fb_find_or_create_single,
|
||||
.fb_probe = intelfb_create,
|
||||
};
|
||||
|
||||
static void intel_fbdev_destroy(struct drm_device *dev,
|
||||
@ -212,6 +205,7 @@ static void intel_fbdev_destroy(struct drm_device *dev,
|
||||
|
||||
drm_fb_helper_fini(&ifbdev->helper);
|
||||
|
||||
drm_framebuffer_unregister_private(&ifb->base);
|
||||
drm_framebuffer_cleanup(&ifb->base);
|
||||
if (ifb->obj) {
|
||||
drm_gem_object_unreference_unlocked(&ifb->obj->base);
|
||||
@ -241,10 +235,18 @@ int intel_fbdev_init(struct drm_device *dev)
|
||||
}
|
||||
|
||||
drm_fb_helper_single_add_all_connectors(&ifbdev->helper);
|
||||
drm_fb_helper_initial_config(&ifbdev->helper, 32);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void intel_fbdev_initial_config(struct drm_device *dev)
|
||||
{
|
||||
drm_i915_private_t *dev_priv = dev->dev_private;
|
||||
|
||||
/* Due to peculiar init order wrt to hpd handling this is separate. */
|
||||
drm_fb_helper_initial_config(&dev_priv->fbdev->helper, 32);
|
||||
}
|
||||
|
||||
void intel_fbdev_fini(struct drm_device *dev)
|
||||
{
|
||||
drm_i915_private_t *dev_priv = dev->dev_private;
|
||||
@ -280,7 +282,7 @@ void intel_fb_restore_mode(struct drm_device *dev)
|
||||
struct drm_mode_config *config = &dev->mode_config;
|
||||
struct drm_plane *plane;
|
||||
|
||||
mutex_lock(&dev->mode_config.mutex);
|
||||
drm_modeset_lock_all(dev);
|
||||
|
||||
ret = drm_fb_helper_restore_fbdev_mode(&dev_priv->fbdev->helper);
|
||||
if (ret)
|
||||
@ -288,7 +290,8 @@ void intel_fb_restore_mode(struct drm_device *dev)
|
||||
|
||||
/* Be sure to shut off any planes that may be active */
|
||||
list_for_each_entry(plane, &config->plane_list, head)
|
||||
plane->funcs->disable_plane(plane);
|
||||
if (plane->enabled)
|
||||
plane->funcs->disable_plane(plane);
|
||||
|
||||
mutex_unlock(&dev->mode_config.mutex);
|
||||
drm_modeset_unlock_all(dev);
|
||||
}
|
||||
|
@ -48,7 +48,7 @@ assert_hdmi_port_disabled(struct intel_hdmi *intel_hdmi)
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
uint32_t enabled_bits;
|
||||
|
||||
enabled_bits = IS_HASWELL(dev) ? DDI_BUF_CTL_ENABLE : SDVO_ENABLE;
|
||||
enabled_bits = HAS_DDI(dev) ? DDI_BUF_CTL_ENABLE : SDVO_ENABLE;
|
||||
|
||||
WARN(I915_READ(intel_hdmi->sdvox_reg) & enabled_bits,
|
||||
"HDMI port enabled, expecting disabled\n");
|
||||
@ -331,6 +331,7 @@ static void intel_set_infoframe(struct drm_encoder *encoder,
|
||||
static void intel_hdmi_set_avi_infoframe(struct drm_encoder *encoder,
|
||||
struct drm_display_mode *adjusted_mode)
|
||||
{
|
||||
struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder);
|
||||
struct dip_infoframe avi_if = {
|
||||
.type = DIP_TYPE_AVI,
|
||||
.ver = DIP_VERSION_AVI,
|
||||
@ -340,7 +341,14 @@ static void intel_hdmi_set_avi_infoframe(struct drm_encoder *encoder,
|
||||
if (adjusted_mode->flags & DRM_MODE_FLAG_DBLCLK)
|
||||
avi_if.body.avi.YQ_CN_PR |= DIP_AVI_PR_2;
|
||||
|
||||
avi_if.body.avi.VIC = drm_mode_cea_vic(adjusted_mode);
|
||||
if (intel_hdmi->rgb_quant_range_selectable) {
|
||||
if (adjusted_mode->private_flags & INTEL_MODE_LIMITED_COLOR_RANGE)
|
||||
avi_if.body.avi.ITC_EC_Q_SC |= DIP_AVI_RGB_QUANT_RANGE_LIMITED;
|
||||
else
|
||||
avi_if.body.avi.ITC_EC_Q_SC |= DIP_AVI_RGB_QUANT_RANGE_FULL;
|
||||
}
|
||||
|
||||
avi_if.body.avi.VIC = drm_match_cea_mode(adjusted_mode);
|
||||
|
||||
intel_set_infoframe(encoder, &avi_if);
|
||||
}
|
||||
@ -364,7 +372,8 @@ static void g4x_set_infoframes(struct drm_encoder *encoder,
|
||||
struct drm_display_mode *adjusted_mode)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = encoder->dev->dev_private;
|
||||
struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder);
|
||||
struct intel_digital_port *intel_dig_port = enc_to_dig_port(encoder);
|
||||
struct intel_hdmi *intel_hdmi = &intel_dig_port->hdmi;
|
||||
u32 reg = VIDEO_DIP_CTL;
|
||||
u32 val = I915_READ(reg);
|
||||
u32 port;
|
||||
@ -391,11 +400,11 @@ static void g4x_set_infoframes(struct drm_encoder *encoder,
|
||||
return;
|
||||
}
|
||||
|
||||
switch (intel_hdmi->sdvox_reg) {
|
||||
case SDVOB:
|
||||
switch (intel_dig_port->port) {
|
||||
case PORT_B:
|
||||
port = VIDEO_DIP_PORT_B;
|
||||
break;
|
||||
case SDVOC:
|
||||
case PORT_C:
|
||||
port = VIDEO_DIP_PORT_C;
|
||||
break;
|
||||
default:
|
||||
@ -428,7 +437,8 @@ static void ibx_set_infoframes(struct drm_encoder *encoder,
|
||||
{
|
||||
struct drm_i915_private *dev_priv = encoder->dev->dev_private;
|
||||
struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc);
|
||||
struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder);
|
||||
struct intel_digital_port *intel_dig_port = enc_to_dig_port(encoder);
|
||||
struct intel_hdmi *intel_hdmi = &intel_dig_port->hdmi;
|
||||
u32 reg = TVIDEO_DIP_CTL(intel_crtc->pipe);
|
||||
u32 val = I915_READ(reg);
|
||||
u32 port;
|
||||
@ -447,14 +457,14 @@ static void ibx_set_infoframes(struct drm_encoder *encoder,
|
||||
return;
|
||||
}
|
||||
|
||||
switch (intel_hdmi->sdvox_reg) {
|
||||
case HDMIB:
|
||||
switch (intel_dig_port->port) {
|
||||
case PORT_B:
|
||||
port = VIDEO_DIP_PORT_B;
|
||||
break;
|
||||
case HDMIC:
|
||||
case PORT_C:
|
||||
port = VIDEO_DIP_PORT_C;
|
||||
break;
|
||||
case HDMID:
|
||||
case PORT_D:
|
||||
port = VIDEO_DIP_PORT_D;
|
||||
break;
|
||||
default:
|
||||
@ -766,46 +776,38 @@ bool intel_hdmi_mode_fixup(struct drm_encoder *encoder,
|
||||
const struct drm_display_mode *mode,
|
||||
struct drm_display_mode *adjusted_mode)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder);
|
||||
|
||||
static bool g4x_hdmi_connected(struct intel_hdmi *intel_hdmi)
|
||||
{
|
||||
struct drm_device *dev = intel_hdmi_to_dev(intel_hdmi);
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
uint32_t bit;
|
||||
|
||||
switch (intel_hdmi->sdvox_reg) {
|
||||
case SDVOB:
|
||||
bit = HDMIB_HOTPLUG_LIVE_STATUS;
|
||||
break;
|
||||
case SDVOC:
|
||||
bit = HDMIC_HOTPLUG_LIVE_STATUS;
|
||||
break;
|
||||
default:
|
||||
bit = 0;
|
||||
break;
|
||||
if (intel_hdmi->color_range_auto) {
|
||||
/* See CEA-861-E - 5.1 Default Encoding Parameters */
|
||||
if (intel_hdmi->has_hdmi_sink &&
|
||||
drm_match_cea_mode(adjusted_mode) > 1)
|
||||
intel_hdmi->color_range = SDVO_COLOR_RANGE_16_235;
|
||||
else
|
||||
intel_hdmi->color_range = 0;
|
||||
}
|
||||
|
||||
return I915_READ(PORT_HOTPLUG_STAT) & bit;
|
||||
if (intel_hdmi->color_range)
|
||||
adjusted_mode->private_flags |= INTEL_MODE_LIMITED_COLOR_RANGE;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static enum drm_connector_status
|
||||
intel_hdmi_detect(struct drm_connector *connector, bool force)
|
||||
{
|
||||
struct drm_device *dev = connector->dev;
|
||||
struct intel_hdmi *intel_hdmi = intel_attached_hdmi(connector);
|
||||
struct intel_digital_port *intel_dig_port =
|
||||
hdmi_to_dig_port(intel_hdmi);
|
||||
struct intel_encoder *intel_encoder = &intel_dig_port->base;
|
||||
struct drm_i915_private *dev_priv = connector->dev->dev_private;
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
struct edid *edid;
|
||||
enum drm_connector_status status = connector_status_disconnected;
|
||||
|
||||
if (IS_G4X(connector->dev) && !g4x_hdmi_connected(intel_hdmi))
|
||||
return status;
|
||||
|
||||
intel_hdmi->has_hdmi_sink = false;
|
||||
intel_hdmi->has_audio = false;
|
||||
intel_hdmi->rgb_quant_range_selectable = false;
|
||||
edid = drm_get_edid(connector,
|
||||
intel_gmbus_get_adapter(dev_priv,
|
||||
intel_hdmi->ddc_bus));
|
||||
@ -817,6 +819,8 @@ intel_hdmi_detect(struct drm_connector *connector, bool force)
|
||||
intel_hdmi->has_hdmi_sink =
|
||||
drm_detect_hdmi_monitor(edid);
|
||||
intel_hdmi->has_audio = drm_detect_monitor_audio(edid);
|
||||
intel_hdmi->rgb_quant_range_selectable =
|
||||
drm_rgb_quant_range_selectable(edid);
|
||||
}
|
||||
kfree(edid);
|
||||
}
|
||||
@ -902,21 +906,29 @@ intel_hdmi_set_property(struct drm_connector *connector,
|
||||
}
|
||||
|
||||
if (property == dev_priv->broadcast_rgb_property) {
|
||||
if (val == !!intel_hdmi->color_range)
|
||||
return 0;
|
||||
|
||||
intel_hdmi->color_range = val ? SDVO_COLOR_RANGE_16_235 : 0;
|
||||
switch (val) {
|
||||
case INTEL_BROADCAST_RGB_AUTO:
|
||||
intel_hdmi->color_range_auto = true;
|
||||
break;
|
||||
case INTEL_BROADCAST_RGB_FULL:
|
||||
intel_hdmi->color_range_auto = false;
|
||||
intel_hdmi->color_range = 0;
|
||||
break;
|
||||
case INTEL_BROADCAST_RGB_LIMITED:
|
||||
intel_hdmi->color_range_auto = false;
|
||||
intel_hdmi->color_range = SDVO_COLOR_RANGE_16_235;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
goto done;
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
|
||||
done:
|
||||
if (intel_dig_port->base.base.crtc) {
|
||||
struct drm_crtc *crtc = intel_dig_port->base.base.crtc;
|
||||
intel_set_mode(crtc, &crtc->mode,
|
||||
crtc->x, crtc->y, crtc->fb);
|
||||
}
|
||||
if (intel_dig_port->base.base.crtc)
|
||||
intel_crtc_restore_mode(intel_dig_port->base.base.crtc);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -931,7 +943,6 @@ static void intel_hdmi_destroy(struct drm_connector *connector)
|
||||
static const struct drm_encoder_helper_funcs intel_hdmi_helper_funcs = {
|
||||
.mode_fixup = intel_hdmi_mode_fixup,
|
||||
.mode_set = intel_hdmi_mode_set,
|
||||
.disable = intel_encoder_noop,
|
||||
};
|
||||
|
||||
static const struct drm_connector_funcs intel_hdmi_connector_funcs = {
|
||||
@ -957,6 +968,7 @@ intel_hdmi_add_properties(struct intel_hdmi *intel_hdmi, struct drm_connector *c
|
||||
{
|
||||
intel_attach_force_audio_property(connector);
|
||||
intel_attach_broadcast_rgb_property(connector);
|
||||
intel_hdmi->color_range_auto = true;
|
||||
}
|
||||
|
||||
void intel_hdmi_init_connector(struct intel_digital_port *intel_dig_port,
|
||||
@ -980,15 +992,15 @@ void intel_hdmi_init_connector(struct intel_digital_port *intel_dig_port,
|
||||
switch (port) {
|
||||
case PORT_B:
|
||||
intel_hdmi->ddc_bus = GMBUS_PORT_DPB;
|
||||
dev_priv->hotplug_supported_mask |= HDMIB_HOTPLUG_INT_STATUS;
|
||||
dev_priv->hotplug_supported_mask |= PORTB_HOTPLUG_INT_STATUS;
|
||||
break;
|
||||
case PORT_C:
|
||||
intel_hdmi->ddc_bus = GMBUS_PORT_DPC;
|
||||
dev_priv->hotplug_supported_mask |= HDMIC_HOTPLUG_INT_STATUS;
|
||||
dev_priv->hotplug_supported_mask |= PORTC_HOTPLUG_INT_STATUS;
|
||||
break;
|
||||
case PORT_D:
|
||||
intel_hdmi->ddc_bus = GMBUS_PORT_DPD;
|
||||
dev_priv->hotplug_supported_mask |= HDMID_HOTPLUG_INT_STATUS;
|
||||
dev_priv->hotplug_supported_mask |= PORTD_HOTPLUG_INT_STATUS;
|
||||
break;
|
||||
case PORT_A:
|
||||
/* Internal port only for eDP. */
|
||||
@ -1013,7 +1025,7 @@ void intel_hdmi_init_connector(struct intel_digital_port *intel_dig_port,
|
||||
intel_hdmi->set_infoframes = cpt_set_infoframes;
|
||||
}
|
||||
|
||||
if (IS_HASWELL(dev))
|
||||
if (HAS_DDI(dev))
|
||||
intel_connector->get_hw_state = intel_ddi_connector_get_hw_state;
|
||||
else
|
||||
intel_connector->get_hw_state = intel_connector_get_hw_state;
|
||||
|
@ -63,6 +63,7 @@ intel_i2c_reset(struct drm_device *dev)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
I915_WRITE(dev_priv->gpio_mmio_base + GMBUS0, 0);
|
||||
I915_WRITE(dev_priv->gpio_mmio_base + GMBUS4, 0);
|
||||
}
|
||||
|
||||
static void intel_i2c_quirk_set(struct drm_i915_private *dev_priv, bool enable)
|
||||
@ -202,6 +203,68 @@ intel_gpio_setup(struct intel_gmbus *bus, u32 pin)
|
||||
algo->data = bus;
|
||||
}
|
||||
|
||||
#define HAS_GMBUS_IRQ(dev) (INTEL_INFO(dev)->gen >= 4)
|
||||
static int
|
||||
gmbus_wait_hw_status(struct drm_i915_private *dev_priv,
|
||||
u32 gmbus2_status,
|
||||
u32 gmbus4_irq_en)
|
||||
{
|
||||
int i;
|
||||
int reg_offset = dev_priv->gpio_mmio_base;
|
||||
u32 gmbus2 = 0;
|
||||
DEFINE_WAIT(wait);
|
||||
|
||||
/* Important: The hw handles only the first bit, so set only one! Since
|
||||
* we also need to check for NAKs besides the hw ready/idle signal, we
|
||||
* need to wake up periodically and check that ourselves. */
|
||||
I915_WRITE(GMBUS4 + reg_offset, gmbus4_irq_en);
|
||||
|
||||
for (i = 0; i < msecs_to_jiffies(50) + 1; i++) {
|
||||
prepare_to_wait(&dev_priv->gmbus_wait_queue, &wait,
|
||||
TASK_UNINTERRUPTIBLE);
|
||||
|
||||
gmbus2 = I915_READ_NOTRACE(GMBUS2 + reg_offset);
|
||||
if (gmbus2 & (GMBUS_SATOER | gmbus2_status))
|
||||
break;
|
||||
|
||||
schedule_timeout(1);
|
||||
}
|
||||
finish_wait(&dev_priv->gmbus_wait_queue, &wait);
|
||||
|
||||
I915_WRITE(GMBUS4 + reg_offset, 0);
|
||||
|
||||
if (gmbus2 & GMBUS_SATOER)
|
||||
return -ENXIO;
|
||||
if (gmbus2 & gmbus2_status)
|
||||
return 0;
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
static int
|
||||
gmbus_wait_idle(struct drm_i915_private *dev_priv)
|
||||
{
|
||||
int ret;
|
||||
int reg_offset = dev_priv->gpio_mmio_base;
|
||||
|
||||
#define C ((I915_READ_NOTRACE(GMBUS2 + reg_offset) & GMBUS_ACTIVE) == 0)
|
||||
|
||||
if (!HAS_GMBUS_IRQ(dev_priv->dev))
|
||||
return wait_for(C, 10);
|
||||
|
||||
/* Important: The hw handles only the first bit, so set only one! */
|
||||
I915_WRITE(GMBUS4 + reg_offset, GMBUS_IDLE_EN);
|
||||
|
||||
ret = wait_event_timeout(dev_priv->gmbus_wait_queue, C, 10);
|
||||
|
||||
I915_WRITE(GMBUS4 + reg_offset, 0);
|
||||
|
||||
if (ret)
|
||||
return 0;
|
||||
else
|
||||
return -ETIMEDOUT;
|
||||
#undef C
|
||||
}
|
||||
|
||||
static int
|
||||
gmbus_xfer_read(struct drm_i915_private *dev_priv, struct i2c_msg *msg,
|
||||
u32 gmbus1_index)
|
||||
@ -219,15 +282,11 @@ gmbus_xfer_read(struct drm_i915_private *dev_priv, struct i2c_msg *msg,
|
||||
while (len) {
|
||||
int ret;
|
||||
u32 val, loop = 0;
|
||||
u32 gmbus2;
|
||||
|
||||
ret = wait_for((gmbus2 = I915_READ(GMBUS2 + reg_offset)) &
|
||||
(GMBUS_SATOER | GMBUS_HW_RDY),
|
||||
50);
|
||||
ret = gmbus_wait_hw_status(dev_priv, GMBUS_HW_RDY,
|
||||
GMBUS_HW_RDY_EN);
|
||||
if (ret)
|
||||
return -ETIMEDOUT;
|
||||
if (gmbus2 & GMBUS_SATOER)
|
||||
return -ENXIO;
|
||||
return ret;
|
||||
|
||||
val = I915_READ(GMBUS3 + reg_offset);
|
||||
do {
|
||||
@ -261,7 +320,6 @@ gmbus_xfer_write(struct drm_i915_private *dev_priv, struct i2c_msg *msg)
|
||||
GMBUS_SLAVE_WRITE | GMBUS_SW_RDY);
|
||||
while (len) {
|
||||
int ret;
|
||||
u32 gmbus2;
|
||||
|
||||
val = loop = 0;
|
||||
do {
|
||||
@ -270,13 +328,10 @@ gmbus_xfer_write(struct drm_i915_private *dev_priv, struct i2c_msg *msg)
|
||||
|
||||
I915_WRITE(GMBUS3 + reg_offset, val);
|
||||
|
||||
ret = wait_for((gmbus2 = I915_READ(GMBUS2 + reg_offset)) &
|
||||
(GMBUS_SATOER | GMBUS_HW_RDY),
|
||||
50);
|
||||
ret = gmbus_wait_hw_status(dev_priv, GMBUS_HW_RDY,
|
||||
GMBUS_HW_RDY_EN);
|
||||
if (ret)
|
||||
return -ETIMEDOUT;
|
||||
if (gmbus2 & GMBUS_SATOER)
|
||||
return -ENXIO;
|
||||
return ret;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@ -345,8 +400,6 @@ gmbus_xfer(struct i2c_adapter *adapter,
|
||||
I915_WRITE(GMBUS0 + reg_offset, bus->reg0);
|
||||
|
||||
for (i = 0; i < num; i++) {
|
||||
u32 gmbus2;
|
||||
|
||||
if (gmbus_is_index_read(msgs, i, num)) {
|
||||
ret = gmbus_xfer_index_read(dev_priv, &msgs[i]);
|
||||
i += 1; /* set i to the index of the read xfer */
|
||||
@ -361,13 +414,12 @@ gmbus_xfer(struct i2c_adapter *adapter,
|
||||
if (ret == -ENXIO)
|
||||
goto clear_err;
|
||||
|
||||
ret = wait_for((gmbus2 = I915_READ(GMBUS2 + reg_offset)) &
|
||||
(GMBUS_SATOER | GMBUS_HW_WAIT_PHASE),
|
||||
50);
|
||||
ret = gmbus_wait_hw_status(dev_priv, GMBUS_HW_WAIT_PHASE,
|
||||
GMBUS_HW_WAIT_EN);
|
||||
if (ret == -ENXIO)
|
||||
goto clear_err;
|
||||
if (ret)
|
||||
goto timeout;
|
||||
if (gmbus2 & GMBUS_SATOER)
|
||||
goto clear_err;
|
||||
}
|
||||
|
||||
/* Generate a STOP condition on the bus. Note that gmbus can't generata
|
||||
@ -380,8 +432,7 @@ gmbus_xfer(struct i2c_adapter *adapter,
|
||||
* We will re-enable it at the start of the next xfer,
|
||||
* till then let it sleep.
|
||||
*/
|
||||
if (wait_for((I915_READ(GMBUS2 + reg_offset) & GMBUS_ACTIVE) == 0,
|
||||
10)) {
|
||||
if (gmbus_wait_idle(dev_priv)) {
|
||||
DRM_DEBUG_KMS("GMBUS [%s] timed out waiting for idle\n",
|
||||
adapter->name);
|
||||
ret = -ETIMEDOUT;
|
||||
@ -405,8 +456,7 @@ clear_err:
|
||||
* it's slow responding and only answers on the 2nd retry.
|
||||
*/
|
||||
ret = -ENXIO;
|
||||
if (wait_for((I915_READ(GMBUS2 + reg_offset) & GMBUS_ACTIVE) == 0,
|
||||
10)) {
|
||||
if (gmbus_wait_idle(dev_priv)) {
|
||||
DRM_DEBUG_KMS("GMBUS [%s] timed out after NAK\n",
|
||||
adapter->name);
|
||||
ret = -ETIMEDOUT;
|
||||
@ -465,10 +515,13 @@ int intel_setup_gmbus(struct drm_device *dev)
|
||||
|
||||
if (HAS_PCH_SPLIT(dev))
|
||||
dev_priv->gpio_mmio_base = PCH_GPIOA - GPIOA;
|
||||
else if (IS_VALLEYVIEW(dev))
|
||||
dev_priv->gpio_mmio_base = VLV_DISPLAY_BASE;
|
||||
else
|
||||
dev_priv->gpio_mmio_base = 0;
|
||||
|
||||
mutex_init(&dev_priv->gmbus_mutex);
|
||||
init_waitqueue_head(&dev_priv->gmbus_wait_queue);
|
||||
|
||||
for (i = 0; i < GMBUS_NUM_PORTS; i++) {
|
||||
struct intel_gmbus *bus = &dev_priv->gmbus[i];
|
||||
|
@ -51,7 +51,8 @@ struct intel_lvds_encoder {
|
||||
|
||||
u32 pfit_control;
|
||||
u32 pfit_pgm_ratios;
|
||||
bool pfit_dirty;
|
||||
bool is_dual_link;
|
||||
u32 reg;
|
||||
|
||||
struct intel_lvds_connector *attached_connector;
|
||||
};
|
||||
@ -71,15 +72,10 @@ static bool intel_lvds_get_hw_state(struct intel_encoder *encoder,
|
||||
{
|
||||
struct drm_device *dev = encoder->base.dev;
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
u32 lvds_reg, tmp;
|
||||
struct intel_lvds_encoder *lvds_encoder = to_lvds_encoder(&encoder->base);
|
||||
u32 tmp;
|
||||
|
||||
if (HAS_PCH_SPLIT(dev)) {
|
||||
lvds_reg = PCH_LVDS;
|
||||
} else {
|
||||
lvds_reg = LVDS;
|
||||
}
|
||||
|
||||
tmp = I915_READ(lvds_reg);
|
||||
tmp = I915_READ(lvds_encoder->reg);
|
||||
|
||||
if (!(tmp & LVDS_PORT_EN))
|
||||
return false;
|
||||
@ -92,6 +88,91 @@ static bool intel_lvds_get_hw_state(struct intel_encoder *encoder,
|
||||
return true;
|
||||
}
|
||||
|
||||
/* The LVDS pin pair needs to be on before the DPLLs are enabled.
|
||||
* This is an exception to the general rule that mode_set doesn't turn
|
||||
* things on.
|
||||
*/
|
||||
static void intel_pre_pll_enable_lvds(struct intel_encoder *encoder)
|
||||
{
|
||||
struct intel_lvds_encoder *lvds_encoder = to_lvds_encoder(&encoder->base);
|
||||
struct drm_device *dev = encoder->base.dev;
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
struct intel_crtc *intel_crtc = to_intel_crtc(encoder->base.crtc);
|
||||
struct drm_display_mode *fixed_mode =
|
||||
lvds_encoder->attached_connector->base.panel.fixed_mode;
|
||||
int pipe = intel_crtc->pipe;
|
||||
u32 temp;
|
||||
|
||||
temp = I915_READ(lvds_encoder->reg);
|
||||
temp |= LVDS_PORT_EN | LVDS_A0A2_CLKA_POWER_UP;
|
||||
|
||||
if (HAS_PCH_CPT(dev)) {
|
||||
temp &= ~PORT_TRANS_SEL_MASK;
|
||||
temp |= PORT_TRANS_SEL_CPT(pipe);
|
||||
} else {
|
||||
if (pipe == 1) {
|
||||
temp |= LVDS_PIPEB_SELECT;
|
||||
} else {
|
||||
temp &= ~LVDS_PIPEB_SELECT;
|
||||
}
|
||||
}
|
||||
|
||||
/* set the corresponsding LVDS_BORDER bit */
|
||||
temp |= dev_priv->lvds_border_bits;
|
||||
/* Set the B0-B3 data pairs corresponding to whether we're going to
|
||||
* set the DPLLs for dual-channel mode or not.
|
||||
*/
|
||||
if (lvds_encoder->is_dual_link)
|
||||
temp |= LVDS_B0B3_POWER_UP | LVDS_CLKB_POWER_UP;
|
||||
else
|
||||
temp &= ~(LVDS_B0B3_POWER_UP | LVDS_CLKB_POWER_UP);
|
||||
|
||||
/* It would be nice to set 24 vs 18-bit mode (LVDS_A3_POWER_UP)
|
||||
* appropriately here, but we need to look more thoroughly into how
|
||||
* panels behave in the two modes.
|
||||
*/
|
||||
|
||||
/* Set the dithering flag on LVDS as needed, note that there is no
|
||||
* special lvds dither control bit on pch-split platforms, dithering is
|
||||
* only controlled through the PIPECONF reg. */
|
||||
if (INTEL_INFO(dev)->gen == 4) {
|
||||
if (dev_priv->lvds_dither)
|
||||
temp |= LVDS_ENABLE_DITHER;
|
||||
else
|
||||
temp &= ~LVDS_ENABLE_DITHER;
|
||||
}
|
||||
temp &= ~(LVDS_HSYNC_POLARITY | LVDS_VSYNC_POLARITY);
|
||||
if (fixed_mode->flags & DRM_MODE_FLAG_NHSYNC)
|
||||
temp |= LVDS_HSYNC_POLARITY;
|
||||
if (fixed_mode->flags & DRM_MODE_FLAG_NVSYNC)
|
||||
temp |= LVDS_VSYNC_POLARITY;
|
||||
|
||||
I915_WRITE(lvds_encoder->reg, temp);
|
||||
}
|
||||
|
||||
static void intel_pre_enable_lvds(struct intel_encoder *encoder)
|
||||
{
|
||||
struct drm_device *dev = encoder->base.dev;
|
||||
struct intel_lvds_encoder *enc = to_lvds_encoder(&encoder->base);
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
|
||||
if (HAS_PCH_SPLIT(dev) || !enc->pfit_control)
|
||||
return;
|
||||
|
||||
/*
|
||||
* Enable automatic panel scaling so that non-native modes
|
||||
* fill the screen. The panel fitter should only be
|
||||
* adjusted whilst the pipe is disabled, according to
|
||||
* register description and PRM.
|
||||
*/
|
||||
DRM_DEBUG_KMS("applying panel-fitter: %x, %x\n",
|
||||
enc->pfit_control,
|
||||
enc->pfit_pgm_ratios);
|
||||
|
||||
I915_WRITE(PFIT_PGM_RATIOS, enc->pfit_pgm_ratios);
|
||||
I915_WRITE(PFIT_CONTROL, enc->pfit_control);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the power state for the panel.
|
||||
*/
|
||||
@ -101,38 +182,20 @@ static void intel_enable_lvds(struct intel_encoder *encoder)
|
||||
struct intel_lvds_encoder *lvds_encoder = to_lvds_encoder(&encoder->base);
|
||||
struct intel_crtc *intel_crtc = to_intel_crtc(encoder->base.crtc);
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
u32 ctl_reg, lvds_reg, stat_reg;
|
||||
u32 ctl_reg, stat_reg;
|
||||
|
||||
if (HAS_PCH_SPLIT(dev)) {
|
||||
ctl_reg = PCH_PP_CONTROL;
|
||||
lvds_reg = PCH_LVDS;
|
||||
stat_reg = PCH_PP_STATUS;
|
||||
} else {
|
||||
ctl_reg = PP_CONTROL;
|
||||
lvds_reg = LVDS;
|
||||
stat_reg = PP_STATUS;
|
||||
}
|
||||
|
||||
I915_WRITE(lvds_reg, I915_READ(lvds_reg) | LVDS_PORT_EN);
|
||||
|
||||
if (lvds_encoder->pfit_dirty) {
|
||||
/*
|
||||
* Enable automatic panel scaling so that non-native modes
|
||||
* fill the screen. The panel fitter should only be
|
||||
* adjusted whilst the pipe is disabled, according to
|
||||
* register description and PRM.
|
||||
*/
|
||||
DRM_DEBUG_KMS("applying panel-fitter: %x, %x\n",
|
||||
lvds_encoder->pfit_control,
|
||||
lvds_encoder->pfit_pgm_ratios);
|
||||
|
||||
I915_WRITE(PFIT_PGM_RATIOS, lvds_encoder->pfit_pgm_ratios);
|
||||
I915_WRITE(PFIT_CONTROL, lvds_encoder->pfit_control);
|
||||
lvds_encoder->pfit_dirty = false;
|
||||
}
|
||||
I915_WRITE(lvds_encoder->reg, I915_READ(lvds_encoder->reg) | LVDS_PORT_EN);
|
||||
|
||||
I915_WRITE(ctl_reg, I915_READ(ctl_reg) | POWER_TARGET_ON);
|
||||
POSTING_READ(lvds_reg);
|
||||
POSTING_READ(lvds_encoder->reg);
|
||||
if (wait_for((I915_READ(stat_reg) & PP_ON) != 0, 1000))
|
||||
DRM_ERROR("timed out waiting for panel to power on\n");
|
||||
|
||||
@ -144,15 +207,13 @@ static void intel_disable_lvds(struct intel_encoder *encoder)
|
||||
struct drm_device *dev = encoder->base.dev;
|
||||
struct intel_lvds_encoder *lvds_encoder = to_lvds_encoder(&encoder->base);
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
u32 ctl_reg, lvds_reg, stat_reg;
|
||||
u32 ctl_reg, stat_reg;
|
||||
|
||||
if (HAS_PCH_SPLIT(dev)) {
|
||||
ctl_reg = PCH_PP_CONTROL;
|
||||
lvds_reg = PCH_LVDS;
|
||||
stat_reg = PCH_PP_STATUS;
|
||||
} else {
|
||||
ctl_reg = PP_CONTROL;
|
||||
lvds_reg = LVDS;
|
||||
stat_reg = PP_STATUS;
|
||||
}
|
||||
|
||||
@ -162,13 +223,8 @@ static void intel_disable_lvds(struct intel_encoder *encoder)
|
||||
if (wait_for((I915_READ(stat_reg) & PP_ON) == 0, 1000))
|
||||
DRM_ERROR("timed out waiting for panel to power off\n");
|
||||
|
||||
if (lvds_encoder->pfit_control) {
|
||||
I915_WRITE(PFIT_CONTROL, 0);
|
||||
lvds_encoder->pfit_dirty = true;
|
||||
}
|
||||
|
||||
I915_WRITE(lvds_reg, I915_READ(lvds_reg) & ~LVDS_PORT_EN);
|
||||
POSTING_READ(lvds_reg);
|
||||
I915_WRITE(lvds_encoder->reg, I915_READ(lvds_encoder->reg) & ~LVDS_PORT_EN);
|
||||
POSTING_READ(lvds_encoder->reg);
|
||||
}
|
||||
|
||||
static int intel_lvds_mode_valid(struct drm_connector *connector,
|
||||
@ -406,7 +462,6 @@ out:
|
||||
pfit_pgm_ratios != lvds_encoder->pfit_pgm_ratios) {
|
||||
lvds_encoder->pfit_control = pfit_control;
|
||||
lvds_encoder->pfit_pgm_ratios = pfit_pgm_ratios;
|
||||
lvds_encoder->pfit_dirty = true;
|
||||
}
|
||||
dev_priv->lvds_border_bits = border;
|
||||
|
||||
@ -492,13 +547,14 @@ static const struct dmi_system_id intel_no_modeset_on_lid[] = {
|
||||
};
|
||||
|
||||
/*
|
||||
* Lid events. Note the use of 'modeset_on_lid':
|
||||
* - we set it on lid close, and reset it on open
|
||||
* Lid events. Note the use of 'modeset':
|
||||
* - we set it to MODESET_ON_LID_OPEN on lid close,
|
||||
* and set it to MODESET_DONE on open
|
||||
* - we use it as a "only once" bit (ie we ignore
|
||||
* duplicate events where it was already properly
|
||||
* set/reset)
|
||||
* - the suspend/resume paths will also set it to
|
||||
* zero, since they restore the mode ("lid open").
|
||||
* duplicate events where it was already properly set)
|
||||
* - the suspend/resume paths will set it to
|
||||
* MODESET_SUSPENDED and ignore the lid open event,
|
||||
* because they restore the mode ("lid open").
|
||||
*/
|
||||
static int intel_lid_notify(struct notifier_block *nb, unsigned long val,
|
||||
void *unused)
|
||||
@ -512,6 +568,9 @@ static int intel_lid_notify(struct notifier_block *nb, unsigned long val,
|
||||
if (dev->switch_power_state != DRM_SWITCH_POWER_ON)
|
||||
return NOTIFY_OK;
|
||||
|
||||
mutex_lock(&dev_priv->modeset_restore_lock);
|
||||
if (dev_priv->modeset_restore == MODESET_SUSPENDED)
|
||||
goto exit;
|
||||
/*
|
||||
* check and update the status of LVDS connector after receiving
|
||||
* the LID nofication event.
|
||||
@ -520,21 +579,24 @@ static int intel_lid_notify(struct notifier_block *nb, unsigned long val,
|
||||
|
||||
/* Don't force modeset on machines where it causes a GPU lockup */
|
||||
if (dmi_check_system(intel_no_modeset_on_lid))
|
||||
return NOTIFY_OK;
|
||||
goto exit;
|
||||
if (!acpi_lid_open()) {
|
||||
dev_priv->modeset_on_lid = 1;
|
||||
return NOTIFY_OK;
|
||||
/* do modeset on next lid open event */
|
||||
dev_priv->modeset_restore = MODESET_ON_LID_OPEN;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if (!dev_priv->modeset_on_lid)
|
||||
return NOTIFY_OK;
|
||||
if (dev_priv->modeset_restore == MODESET_DONE)
|
||||
goto exit;
|
||||
|
||||
dev_priv->modeset_on_lid = 0;
|
||||
|
||||
mutex_lock(&dev->mode_config.mutex);
|
||||
drm_modeset_lock_all(dev);
|
||||
intel_modeset_setup_hw_state(dev, true);
|
||||
mutex_unlock(&dev->mode_config.mutex);
|
||||
drm_modeset_unlock_all(dev);
|
||||
|
||||
dev_priv->modeset_restore = MODESET_DONE;
|
||||
|
||||
exit:
|
||||
mutex_unlock(&dev_priv->modeset_restore_lock);
|
||||
return NOTIFY_OK;
|
||||
}
|
||||
|
||||
@ -591,8 +653,7 @@ static int intel_lvds_set_property(struct drm_connector *connector,
|
||||
* If the CRTC is enabled, the display will be changed
|
||||
* according to the new panel fitting mode.
|
||||
*/
|
||||
intel_set_mode(crtc, &crtc->mode,
|
||||
crtc->x, crtc->y, crtc->fb);
|
||||
intel_crtc_restore_mode(crtc);
|
||||
}
|
||||
}
|
||||
|
||||
@ -602,7 +663,6 @@ static int intel_lvds_set_property(struct drm_connector *connector,
|
||||
static const struct drm_encoder_helper_funcs intel_lvds_helper_funcs = {
|
||||
.mode_fixup = intel_lvds_mode_fixup,
|
||||
.mode_set = intel_lvds_mode_set,
|
||||
.disable = intel_encoder_noop,
|
||||
};
|
||||
|
||||
static const struct drm_connector_helper_funcs intel_lvds_connector_helper_funcs = {
|
||||
@ -895,6 +955,66 @@ static bool lvds_is_present_in_vbt(struct drm_device *dev,
|
||||
return false;
|
||||
}
|
||||
|
||||
static int intel_dual_link_lvds_callback(const struct dmi_system_id *id)
|
||||
{
|
||||
DRM_INFO("Forcing lvds to dual link mode on %s\n", id->ident);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static const struct dmi_system_id intel_dual_link_lvds[] = {
|
||||
{
|
||||
.callback = intel_dual_link_lvds_callback,
|
||||
.ident = "Apple MacBook Pro (Core i5/i7 Series)",
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
|
||||
DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro8,2"),
|
||||
},
|
||||
},
|
||||
{ } /* terminating entry */
|
||||
};
|
||||
|
||||
bool intel_is_dual_link_lvds(struct drm_device *dev)
|
||||
{
|
||||
struct intel_encoder *encoder;
|
||||
struct intel_lvds_encoder *lvds_encoder;
|
||||
|
||||
list_for_each_entry(encoder, &dev->mode_config.encoder_list,
|
||||
base.head) {
|
||||
if (encoder->type == INTEL_OUTPUT_LVDS) {
|
||||
lvds_encoder = to_lvds_encoder(&encoder->base);
|
||||
|
||||
return lvds_encoder->is_dual_link;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool compute_is_dual_link_lvds(struct intel_lvds_encoder *lvds_encoder)
|
||||
{
|
||||
struct drm_device *dev = lvds_encoder->base.base.dev;
|
||||
unsigned int val;
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
|
||||
/* use the module option value if specified */
|
||||
if (i915_lvds_channel_mode > 0)
|
||||
return i915_lvds_channel_mode == 2;
|
||||
|
||||
if (dmi_check_system(intel_dual_link_lvds))
|
||||
return true;
|
||||
|
||||
/* BIOS should set the proper LVDS register value at boot, but
|
||||
* in reality, it doesn't set the value when the lid is closed;
|
||||
* we need to check "the value to be set" in VBT when LVDS
|
||||
* register is uninitialized.
|
||||
*/
|
||||
val = I915_READ(lvds_encoder->reg);
|
||||
if (!(val & ~(LVDS_PIPE_MASK | LVDS_DETECTED)))
|
||||
val = dev_priv->bios_lvds_val;
|
||||
|
||||
return (val & LVDS_CLKB_POWER_MASK) == LVDS_CLKB_POWER_UP;
|
||||
}
|
||||
|
||||
static bool intel_lvds_supported(struct drm_device *dev)
|
||||
{
|
||||
/* With the introduction of the PCH we gained a dedicated
|
||||
@ -980,6 +1100,8 @@ bool intel_lvds_init(struct drm_device *dev)
|
||||
DRM_MODE_ENCODER_LVDS);
|
||||
|
||||
intel_encoder->enable = intel_enable_lvds;
|
||||
intel_encoder->pre_enable = intel_pre_enable_lvds;
|
||||
intel_encoder->pre_pll_enable = intel_pre_pll_enable_lvds;
|
||||
intel_encoder->disable = intel_disable_lvds;
|
||||
intel_encoder->get_hw_state = intel_lvds_get_hw_state;
|
||||
intel_connector->get_hw_state = intel_connector_get_hw_state;
|
||||
@ -1001,6 +1123,12 @@ bool intel_lvds_init(struct drm_device *dev)
|
||||
connector->interlace_allowed = false;
|
||||
connector->doublescan_allowed = false;
|
||||
|
||||
if (HAS_PCH_SPLIT(dev)) {
|
||||
lvds_encoder->reg = PCH_LVDS;
|
||||
} else {
|
||||
lvds_encoder->reg = LVDS;
|
||||
}
|
||||
|
||||
/* create the scaling mode property */
|
||||
drm_mode_create_scaling_mode_property(dev);
|
||||
drm_object_attach_property(&connector->base,
|
||||
@ -1101,6 +1229,10 @@ bool intel_lvds_init(struct drm_device *dev)
|
||||
goto failed;
|
||||
|
||||
out:
|
||||
lvds_encoder->is_dual_link = compute_is_dual_link_lvds(lvds_encoder);
|
||||
DRM_DEBUG_KMS("detected %s-link lvds configuration\n",
|
||||
lvds_encoder->is_dual_link ? "dual" : "single");
|
||||
|
||||
/*
|
||||
* Unlock registers and just
|
||||
* leave them unlocked
|
||||
|
@ -28,7 +28,6 @@
|
||||
#include <linux/fb.h>
|
||||
#include <drm/drm_edid.h>
|
||||
#include <drm/drmP.h>
|
||||
#include <drm/drm_edid.h>
|
||||
#include "intel_drv.h"
|
||||
#include "i915_drv.h"
|
||||
|
||||
@ -101,8 +100,9 @@ intel_attach_force_audio_property(struct drm_connector *connector)
|
||||
}
|
||||
|
||||
static const struct drm_prop_enum_list broadcast_rgb_names[] = {
|
||||
{ 0, "Full" },
|
||||
{ 1, "Limited 16:235" },
|
||||
{ INTEL_BROADCAST_RGB_AUTO, "Automatic" },
|
||||
{ INTEL_BROADCAST_RGB_FULL, "Full" },
|
||||
{ INTEL_BROADCAST_RGB_LIMITED, "Limited 16:235" },
|
||||
};
|
||||
|
||||
void
|
||||
|
@ -347,7 +347,7 @@ static void intel_didl_outputs(struct drm_device *dev)
|
||||
int i = 0;
|
||||
|
||||
handle = DEVICE_ACPI_HANDLE(&dev->pdev->dev);
|
||||
if (!handle || ACPI_FAILURE(acpi_bus_get_device(handle, &acpi_dev)))
|
||||
if (!handle || acpi_bus_get_device(handle, &acpi_dev))
|
||||
return;
|
||||
|
||||
if (acpi_is_video_device(acpi_dev))
|
||||
|
@ -195,7 +195,7 @@ intel_overlay_map_regs(struct intel_overlay *overlay)
|
||||
if (OVERLAY_NEEDS_PHYSICAL(overlay->dev))
|
||||
regs = (struct overlay_registers __iomem *)overlay->reg_bo->phys_obj->handle->vaddr;
|
||||
else
|
||||
regs = io_mapping_map_wc(dev_priv->mm.gtt_mapping,
|
||||
regs = io_mapping_map_wc(dev_priv->gtt.mappable,
|
||||
overlay->reg_bo->gtt_offset);
|
||||
|
||||
return regs;
|
||||
@ -1045,13 +1045,13 @@ int intel_overlay_put_image(struct drm_device *dev, void *data,
|
||||
}
|
||||
|
||||
if (!(put_image_rec->flags & I915_OVERLAY_ENABLE)) {
|
||||
mutex_lock(&dev->mode_config.mutex);
|
||||
drm_modeset_lock_all(dev);
|
||||
mutex_lock(&dev->struct_mutex);
|
||||
|
||||
ret = intel_overlay_switch_off(overlay);
|
||||
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
mutex_unlock(&dev->mode_config.mutex);
|
||||
drm_modeset_unlock_all(dev);
|
||||
|
||||
return ret;
|
||||
}
|
||||
@ -1075,7 +1075,7 @@ int intel_overlay_put_image(struct drm_device *dev, void *data,
|
||||
goto out_free;
|
||||
}
|
||||
|
||||
mutex_lock(&dev->mode_config.mutex);
|
||||
drm_modeset_lock_all(dev);
|
||||
mutex_lock(&dev->struct_mutex);
|
||||
|
||||
if (new_bo->tiling_mode) {
|
||||
@ -1157,7 +1157,7 @@ int intel_overlay_put_image(struct drm_device *dev, void *data,
|
||||
goto out_unlock;
|
||||
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
mutex_unlock(&dev->mode_config.mutex);
|
||||
drm_modeset_unlock_all(dev);
|
||||
|
||||
kfree(params);
|
||||
|
||||
@ -1165,7 +1165,7 @@ int intel_overlay_put_image(struct drm_device *dev, void *data,
|
||||
|
||||
out_unlock:
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
mutex_unlock(&dev->mode_config.mutex);
|
||||
drm_modeset_unlock_all(dev);
|
||||
drm_gem_object_unreference_unlocked(&new_bo->base);
|
||||
out_free:
|
||||
kfree(params);
|
||||
@ -1241,7 +1241,7 @@ int intel_overlay_attrs(struct drm_device *dev, void *data,
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
mutex_lock(&dev->mode_config.mutex);
|
||||
drm_modeset_lock_all(dev);
|
||||
mutex_lock(&dev->struct_mutex);
|
||||
|
||||
ret = -EINVAL;
|
||||
@ -1307,7 +1307,7 @@ int intel_overlay_attrs(struct drm_device *dev, void *data,
|
||||
ret = 0;
|
||||
out_unlock:
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
mutex_unlock(&dev->mode_config.mutex);
|
||||
drm_modeset_unlock_all(dev);
|
||||
|
||||
return ret;
|
||||
}
|
||||
@ -1333,8 +1333,10 @@ void intel_setup_overlay(struct drm_device *dev)
|
||||
|
||||
overlay->dev = dev;
|
||||
|
||||
reg_bo = i915_gem_alloc_object(dev, PAGE_SIZE);
|
||||
if (!reg_bo)
|
||||
reg_bo = i915_gem_object_create_stolen(dev, PAGE_SIZE);
|
||||
if (reg_bo == NULL)
|
||||
reg_bo = i915_gem_alloc_object(dev, PAGE_SIZE);
|
||||
if (reg_bo == NULL)
|
||||
goto out_free;
|
||||
overlay->reg_bo = reg_bo;
|
||||
|
||||
@ -1432,7 +1434,7 @@ intel_overlay_map_regs_atomic(struct intel_overlay *overlay)
|
||||
regs = (struct overlay_registers __iomem *)
|
||||
overlay->reg_bo->phys_obj->handle->vaddr;
|
||||
else
|
||||
regs = io_mapping_map_atomic_wc(dev_priv->mm.gtt_mapping,
|
||||
regs = io_mapping_map_atomic_wc(dev_priv->gtt.mappable,
|
||||
overlay->reg_bo->gtt_offset);
|
||||
|
||||
return regs;
|
||||
|
@ -321,6 +321,9 @@ void intel_panel_enable_backlight(struct drm_device *dev,
|
||||
if (dev_priv->backlight_level == 0)
|
||||
dev_priv->backlight_level = intel_panel_get_max_backlight(dev);
|
||||
|
||||
dev_priv->backlight_enabled = true;
|
||||
intel_panel_actually_set_backlight(dev, dev_priv->backlight_level);
|
||||
|
||||
if (INTEL_INFO(dev)->gen >= 4) {
|
||||
uint32_t reg, tmp;
|
||||
|
||||
@ -356,12 +359,12 @@ void intel_panel_enable_backlight(struct drm_device *dev,
|
||||
}
|
||||
|
||||
set_level:
|
||||
/* Call below after setting BLC_PWM_CPU_CTL2 and BLC_PWM_PCH_CTL1.
|
||||
* BLC_PWM_CPU_CTL may be cleared to zero automatically when these
|
||||
* registers are set.
|
||||
/* Check the current backlight level and try to set again if it's zero.
|
||||
* On some machines, BLC_PWM_CPU_CTL is cleared to zero automatically
|
||||
* when BLC_PWM_CPU_CTL2 and BLC_PWM_PCH_CTL1 are written.
|
||||
*/
|
||||
dev_priv->backlight_enabled = true;
|
||||
intel_panel_actually_set_backlight(dev, dev_priv->backlight_level);
|
||||
if (!intel_panel_get_backlight(dev))
|
||||
intel_panel_actually_set_backlight(dev, dev_priv->backlight_level);
|
||||
}
|
||||
|
||||
static void intel_panel_init_backlight(struct drm_device *dev)
|
||||
|
@ -447,12 +447,6 @@ void intel_update_fbc(struct drm_device *dev)
|
||||
dev_priv->no_fbc_reason = FBC_MODULE_PARAM;
|
||||
goto out_disable;
|
||||
}
|
||||
if (intel_fb->obj->base.size > dev_priv->cfb_size) {
|
||||
DRM_DEBUG_KMS("framebuffer too large, disabling "
|
||||
"compression\n");
|
||||
dev_priv->no_fbc_reason = FBC_STOLEN_TOO_SMALL;
|
||||
goto out_disable;
|
||||
}
|
||||
if ((crtc->mode.flags & DRM_MODE_FLAG_INTERLACE) ||
|
||||
(crtc->mode.flags & DRM_MODE_FLAG_DBLSCAN)) {
|
||||
DRM_DEBUG_KMS("mode incompatible with compression, "
|
||||
@ -486,6 +480,14 @@ void intel_update_fbc(struct drm_device *dev)
|
||||
if (in_dbg_master())
|
||||
goto out_disable;
|
||||
|
||||
if (i915_gem_stolen_setup_compression(dev, intel_fb->obj->base.size)) {
|
||||
DRM_INFO("not enough stolen space for compressed buffer (need %zd bytes), disabling\n", intel_fb->obj->base.size);
|
||||
DRM_INFO("hint: you may be able to increase stolen memory size in the BIOS to avoid this\n");
|
||||
DRM_DEBUG_KMS("framebuffer too large, disabling compression\n");
|
||||
dev_priv->no_fbc_reason = FBC_STOLEN_TOO_SMALL;
|
||||
goto out_disable;
|
||||
}
|
||||
|
||||
/* If the scanout has not changed, don't modify the FBC settings.
|
||||
* Note that we make the fundamental assumption that the fb->obj
|
||||
* cannot be unpinned (and have its GTT offset and fence revoked)
|
||||
@ -533,6 +535,7 @@ out_disable:
|
||||
DRM_DEBUG_KMS("unsupported config, disabling FBC\n");
|
||||
intel_disable_fbc(dev);
|
||||
}
|
||||
i915_gem_stolen_cleanup_compression(dev);
|
||||
}
|
||||
|
||||
static void i915_pineview_get_mem_freq(struct drm_device *dev)
|
||||
@ -2286,7 +2289,6 @@ err_unpin:
|
||||
i915_gem_object_unpin(ctx);
|
||||
err_unref:
|
||||
drm_gem_object_unreference(&ctx->base);
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@ -3581,6 +3583,19 @@ static void cpt_init_clock_gating(struct drm_device *dev)
|
||||
}
|
||||
}
|
||||
|
||||
static void gen6_check_mch_setup(struct drm_device *dev)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
uint32_t tmp;
|
||||
|
||||
tmp = I915_READ(MCH_SSKPD);
|
||||
if ((tmp & MCH_SSKPD_WM0_MASK) != MCH_SSKPD_WM0_VAL) {
|
||||
DRM_INFO("Wrong MCH_SSKPD value: 0x%08x\n", tmp);
|
||||
DRM_INFO("This can cause pipe underruns and display issues.\n");
|
||||
DRM_INFO("Please upgrade your BIOS to fix this.\n");
|
||||
}
|
||||
}
|
||||
|
||||
static void gen6_init_clock_gating(struct drm_device *dev)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
@ -3673,6 +3688,8 @@ static void gen6_init_clock_gating(struct drm_device *dev)
|
||||
I915_WRITE(GEN6_GT_MODE, _MASKED_BIT_ENABLE(GEN6_GT_MODE_HI));
|
||||
|
||||
cpt_init_clock_gating(dev);
|
||||
|
||||
gen6_check_mch_setup(dev);
|
||||
}
|
||||
|
||||
static void gen7_setup_fixed_func_scheduler(struct drm_i915_private *dev_priv)
|
||||
@ -3684,6 +3701,10 @@ static void gen7_setup_fixed_func_scheduler(struct drm_i915_private *dev_priv)
|
||||
reg |= GEN7_FF_VS_SCHED_HW;
|
||||
reg |= GEN7_FF_DS_SCHED_HW;
|
||||
|
||||
/* WaVSRefCountFullforceMissDisable */
|
||||
if (IS_HASWELL(dev_priv->dev))
|
||||
reg &= ~GEN7_FF_VS_REF_CNT_FFME;
|
||||
|
||||
I915_WRITE(GEN7_FF_THREAD_MODE, reg);
|
||||
}
|
||||
|
||||
@ -3854,6 +3875,8 @@ static void ivybridge_init_clock_gating(struct drm_device *dev)
|
||||
I915_WRITE(GEN6_MBCUNIT_SNPCR, snpcr);
|
||||
|
||||
cpt_init_clock_gating(dev);
|
||||
|
||||
gen6_check_mch_setup(dev);
|
||||
}
|
||||
|
||||
static void valleyview_init_clock_gating(struct drm_device *dev)
|
||||
@ -4047,35 +4070,57 @@ void intel_init_clock_gating(struct drm_device *dev)
|
||||
dev_priv->display.init_clock_gating(dev);
|
||||
}
|
||||
|
||||
/* Starting with Haswell, we have different power wells for
|
||||
* different parts of the GPU. This attempts to enable them all.
|
||||
*/
|
||||
void intel_init_power_wells(struct drm_device *dev)
|
||||
void intel_set_power_well(struct drm_device *dev, bool enable)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
unsigned long power_wells[] = {
|
||||
HSW_PWR_WELL_CTL1,
|
||||
HSW_PWR_WELL_CTL2,
|
||||
HSW_PWR_WELL_CTL4
|
||||
};
|
||||
int i;
|
||||
bool is_enabled, enable_requested;
|
||||
uint32_t tmp;
|
||||
|
||||
if (!IS_HASWELL(dev))
|
||||
return;
|
||||
|
||||
mutex_lock(&dev->struct_mutex);
|
||||
tmp = I915_READ(HSW_PWR_WELL_DRIVER);
|
||||
is_enabled = tmp & HSW_PWR_WELL_STATE;
|
||||
enable_requested = tmp & HSW_PWR_WELL_ENABLE;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(power_wells); i++) {
|
||||
int well = I915_READ(power_wells[i]);
|
||||
if (enable) {
|
||||
if (!enable_requested)
|
||||
I915_WRITE(HSW_PWR_WELL_DRIVER, HSW_PWR_WELL_ENABLE);
|
||||
|
||||
if ((well & HSW_PWR_WELL_STATE) == 0) {
|
||||
I915_WRITE(power_wells[i], well & HSW_PWR_WELL_ENABLE);
|
||||
if (wait_for((I915_READ(power_wells[i]) & HSW_PWR_WELL_STATE), 20))
|
||||
DRM_ERROR("Error enabling power well %lx\n", power_wells[i]);
|
||||
if (!is_enabled) {
|
||||
DRM_DEBUG_KMS("Enabling power well\n");
|
||||
if (wait_for((I915_READ(HSW_PWR_WELL_DRIVER) &
|
||||
HSW_PWR_WELL_STATE), 20))
|
||||
DRM_ERROR("Timeout enabling power well\n");
|
||||
}
|
||||
} else {
|
||||
if (enable_requested) {
|
||||
I915_WRITE(HSW_PWR_WELL_DRIVER, 0);
|
||||
DRM_DEBUG_KMS("Requesting to disable the power well\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
/*
|
||||
* Starting with Haswell, we have a "Power Down Well" that can be turned off
|
||||
* when not needed anymore. We have 4 registers that can request the power well
|
||||
* to be enabled, and it will only be disabled if none of the registers is
|
||||
* requesting it to be enabled.
|
||||
*/
|
||||
void intel_init_power_well(struct drm_device *dev)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
|
||||
if (!IS_HASWELL(dev))
|
||||
return;
|
||||
|
||||
/* For now, we need the power well to be always enabled. */
|
||||
intel_set_power_well(dev, true);
|
||||
|
||||
/* We're taking over the BIOS, so clear any requests made by it since
|
||||
* the driver is in charge now. */
|
||||
if (I915_READ(HSW_PWR_WELL_BIOS) & HSW_PWR_WELL_ENABLE)
|
||||
I915_WRITE(HSW_PWR_WELL_BIOS, 0);
|
||||
}
|
||||
|
||||
/* Set up chip specific power management-related functions */
|
||||
|
@ -318,6 +318,7 @@ gen7_render_ring_flush(struct intel_ring_buffer *ring,
|
||||
* TLB invalidate requires a post-sync write.
|
||||
*/
|
||||
flags |= PIPE_CONTROL_QW_WRITE;
|
||||
flags |= PIPE_CONTROL_GLOBAL_GTT_IVB;
|
||||
|
||||
/* Workaround: we must issue a pipe_control with CS-stall bit
|
||||
* set before a pipe_control command that has the state cache
|
||||
@ -331,7 +332,7 @@ gen7_render_ring_flush(struct intel_ring_buffer *ring,
|
||||
|
||||
intel_ring_emit(ring, GFX_OP_PIPE_CONTROL(4));
|
||||
intel_ring_emit(ring, flags);
|
||||
intel_ring_emit(ring, scratch_addr | PIPE_CONTROL_GLOBAL_GTT);
|
||||
intel_ring_emit(ring, scratch_addr);
|
||||
intel_ring_emit(ring, 0);
|
||||
intel_ring_advance(ring);
|
||||
|
||||
@ -467,6 +468,9 @@ init_pipe_control(struct intel_ring_buffer *ring)
|
||||
if (pc->cpu_page == NULL)
|
||||
goto err_unpin;
|
||||
|
||||
DRM_DEBUG_DRIVER("%s pipe control offset: 0x%08x\n",
|
||||
ring->name, pc->gtt_offset);
|
||||
|
||||
pc->obj = obj;
|
||||
ring->private = pc;
|
||||
return 0;
|
||||
@ -613,6 +617,13 @@ gen6_add_request(struct intel_ring_buffer *ring)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline bool i915_gem_has_seqno_wrapped(struct drm_device *dev,
|
||||
u32 seqno)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
return dev_priv->last_seqno < seqno;
|
||||
}
|
||||
|
||||
/**
|
||||
* intel_ring_sync - sync the waiter to the signaller on seqno
|
||||
*
|
||||
@ -643,11 +654,20 @@ gen6_ring_sync(struct intel_ring_buffer *waiter,
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
intel_ring_emit(waiter,
|
||||
dw1 | signaller->semaphore_register[waiter->id]);
|
||||
intel_ring_emit(waiter, seqno);
|
||||
intel_ring_emit(waiter, 0);
|
||||
intel_ring_emit(waiter, MI_NOOP);
|
||||
/* If seqno wrap happened, omit the wait with no-ops */
|
||||
if (likely(!i915_gem_has_seqno_wrapped(waiter->dev, seqno))) {
|
||||
intel_ring_emit(waiter,
|
||||
dw1 |
|
||||
signaller->semaphore_register[waiter->id]);
|
||||
intel_ring_emit(waiter, seqno);
|
||||
intel_ring_emit(waiter, 0);
|
||||
intel_ring_emit(waiter, MI_NOOP);
|
||||
} else {
|
||||
intel_ring_emit(waiter, MI_NOOP);
|
||||
intel_ring_emit(waiter, MI_NOOP);
|
||||
intel_ring_emit(waiter, MI_NOOP);
|
||||
intel_ring_emit(waiter, MI_NOOP);
|
||||
}
|
||||
intel_ring_advance(waiter);
|
||||
|
||||
return 0;
|
||||
@ -728,6 +748,12 @@ ring_get_seqno(struct intel_ring_buffer *ring, bool lazy_coherency)
|
||||
return intel_read_status_page(ring, I915_GEM_HWS_INDEX);
|
||||
}
|
||||
|
||||
static void
|
||||
ring_set_seqno(struct intel_ring_buffer *ring, u32 seqno)
|
||||
{
|
||||
intel_write_status_page(ring, I915_GEM_HWS_INDEX, seqno);
|
||||
}
|
||||
|
||||
static u32
|
||||
pc_render_get_seqno(struct intel_ring_buffer *ring, bool lazy_coherency)
|
||||
{
|
||||
@ -735,6 +761,13 @@ pc_render_get_seqno(struct intel_ring_buffer *ring, bool lazy_coherency)
|
||||
return pc->cpu_page[0];
|
||||
}
|
||||
|
||||
static void
|
||||
pc_render_set_seqno(struct intel_ring_buffer *ring, u32 seqno)
|
||||
{
|
||||
struct pipe_control *pc = ring->private;
|
||||
pc->cpu_page[0] = seqno;
|
||||
}
|
||||
|
||||
static bool
|
||||
gen5_ring_get_irq(struct intel_ring_buffer *ring)
|
||||
{
|
||||
@ -1164,7 +1197,11 @@ static int intel_init_ring_buffer(struct drm_device *dev,
|
||||
return ret;
|
||||
}
|
||||
|
||||
obj = i915_gem_alloc_object(dev, ring->size);
|
||||
obj = NULL;
|
||||
if (!HAS_LLC(dev))
|
||||
obj = i915_gem_object_create_stolen(dev, ring->size);
|
||||
if (obj == NULL)
|
||||
obj = i915_gem_alloc_object(dev, ring->size);
|
||||
if (obj == NULL) {
|
||||
DRM_ERROR("Failed to allocate ringbuffer\n");
|
||||
ret = -ENOMEM;
|
||||
@ -1182,7 +1219,7 @@ static int intel_init_ring_buffer(struct drm_device *dev,
|
||||
goto err_unpin;
|
||||
|
||||
ring->virtual_start =
|
||||
ioremap_wc(dev_priv->mm.gtt->gma_bus_addr + obj->gtt_offset,
|
||||
ioremap_wc(dev_priv->gtt.mappable_base + obj->gtt_offset,
|
||||
ring->size);
|
||||
if (ring->virtual_start == NULL) {
|
||||
DRM_ERROR("Failed to map ringbuffer.\n");
|
||||
@ -1348,7 +1385,8 @@ static int ring_wait_for_space(struct intel_ring_buffer *ring, int n)
|
||||
|
||||
msleep(1);
|
||||
|
||||
ret = i915_gem_check_wedge(dev_priv, dev_priv->mm.interruptible);
|
||||
ret = i915_gem_check_wedge(&dev_priv->gpu_error,
|
||||
dev_priv->mm.interruptible);
|
||||
if (ret)
|
||||
return ret;
|
||||
} while (!time_after(jiffies, end));
|
||||
@ -1410,14 +1448,35 @@ intel_ring_alloc_seqno(struct intel_ring_buffer *ring)
|
||||
return i915_gem_get_seqno(ring->dev, &ring->outstanding_lazy_request);
|
||||
}
|
||||
|
||||
static int __intel_ring_begin(struct intel_ring_buffer *ring,
|
||||
int bytes)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (unlikely(ring->tail + bytes > ring->effective_size)) {
|
||||
ret = intel_wrap_ring_buffer(ring);
|
||||
if (unlikely(ret))
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (unlikely(ring->space < bytes)) {
|
||||
ret = ring_wait_for_space(ring, bytes);
|
||||
if (unlikely(ret))
|
||||
return ret;
|
||||
}
|
||||
|
||||
ring->space -= bytes;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int intel_ring_begin(struct intel_ring_buffer *ring,
|
||||
int num_dwords)
|
||||
{
|
||||
drm_i915_private_t *dev_priv = ring->dev->dev_private;
|
||||
int n = 4*num_dwords;
|
||||
int ret;
|
||||
|
||||
ret = i915_gem_check_wedge(dev_priv, dev_priv->mm.interruptible);
|
||||
ret = i915_gem_check_wedge(&dev_priv->gpu_error,
|
||||
dev_priv->mm.interruptible);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
@ -1426,20 +1485,21 @@ int intel_ring_begin(struct intel_ring_buffer *ring,
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (unlikely(ring->tail + n > ring->effective_size)) {
|
||||
ret = intel_wrap_ring_buffer(ring);
|
||||
if (unlikely(ret))
|
||||
return ret;
|
||||
return __intel_ring_begin(ring, num_dwords * sizeof(uint32_t));
|
||||
}
|
||||
|
||||
void intel_ring_init_seqno(struct intel_ring_buffer *ring, u32 seqno)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = ring->dev->dev_private;
|
||||
|
||||
BUG_ON(ring->outstanding_lazy_request);
|
||||
|
||||
if (INTEL_INFO(ring->dev)->gen >= 6) {
|
||||
I915_WRITE(RING_SYNC_0(ring->mmio_base), 0);
|
||||
I915_WRITE(RING_SYNC_1(ring->mmio_base), 0);
|
||||
}
|
||||
|
||||
if (unlikely(ring->space < n)) {
|
||||
ret = ring_wait_for_space(ring, n);
|
||||
if (unlikely(ret))
|
||||
return ret;
|
||||
}
|
||||
|
||||
ring->space -= n;
|
||||
return 0;
|
||||
ring->set_seqno(ring, seqno);
|
||||
}
|
||||
|
||||
void intel_ring_advance(struct intel_ring_buffer *ring)
|
||||
@ -1447,7 +1507,7 @@ void intel_ring_advance(struct intel_ring_buffer *ring)
|
||||
struct drm_i915_private *dev_priv = ring->dev->dev_private;
|
||||
|
||||
ring->tail &= ring->size - 1;
|
||||
if (dev_priv->stop_rings & intel_ring_flag(ring))
|
||||
if (dev_priv->gpu_error.stop_rings & intel_ring_flag(ring))
|
||||
return;
|
||||
ring->write_tail(ring, ring->tail);
|
||||
}
|
||||
@ -1604,6 +1664,7 @@ int intel_init_render_ring_buffer(struct drm_device *dev)
|
||||
ring->irq_put = gen6_ring_put_irq;
|
||||
ring->irq_enable_mask = GT_USER_INTERRUPT;
|
||||
ring->get_seqno = gen6_ring_get_seqno;
|
||||
ring->set_seqno = ring_set_seqno;
|
||||
ring->sync_to = gen6_ring_sync;
|
||||
ring->semaphore_register[0] = MI_SEMAPHORE_SYNC_INVALID;
|
||||
ring->semaphore_register[1] = MI_SEMAPHORE_SYNC_RV;
|
||||
@ -1614,6 +1675,7 @@ int intel_init_render_ring_buffer(struct drm_device *dev)
|
||||
ring->add_request = pc_render_add_request;
|
||||
ring->flush = gen4_render_ring_flush;
|
||||
ring->get_seqno = pc_render_get_seqno;
|
||||
ring->set_seqno = pc_render_set_seqno;
|
||||
ring->irq_get = gen5_ring_get_irq;
|
||||
ring->irq_put = gen5_ring_put_irq;
|
||||
ring->irq_enable_mask = GT_USER_INTERRUPT | GT_PIPE_NOTIFY;
|
||||
@ -1624,6 +1686,7 @@ int intel_init_render_ring_buffer(struct drm_device *dev)
|
||||
else
|
||||
ring->flush = gen4_render_ring_flush;
|
||||
ring->get_seqno = ring_get_seqno;
|
||||
ring->set_seqno = ring_set_seqno;
|
||||
if (IS_GEN2(dev)) {
|
||||
ring->irq_get = i8xx_ring_get_irq;
|
||||
ring->irq_put = i8xx_ring_put_irq;
|
||||
@ -1695,6 +1758,7 @@ int intel_render_ring_init_dri(struct drm_device *dev, u64 start, u32 size)
|
||||
else
|
||||
ring->flush = gen4_render_ring_flush;
|
||||
ring->get_seqno = ring_get_seqno;
|
||||
ring->set_seqno = ring_set_seqno;
|
||||
if (IS_GEN2(dev)) {
|
||||
ring->irq_get = i8xx_ring_get_irq;
|
||||
ring->irq_put = i8xx_ring_put_irq;
|
||||
@ -1755,6 +1819,7 @@ int intel_init_bsd_ring_buffer(struct drm_device *dev)
|
||||
ring->flush = gen6_ring_flush;
|
||||
ring->add_request = gen6_add_request;
|
||||
ring->get_seqno = gen6_ring_get_seqno;
|
||||
ring->set_seqno = ring_set_seqno;
|
||||
ring->irq_enable_mask = GEN6_BSD_USER_INTERRUPT;
|
||||
ring->irq_get = gen6_ring_get_irq;
|
||||
ring->irq_put = gen6_ring_put_irq;
|
||||
@ -1770,6 +1835,7 @@ int intel_init_bsd_ring_buffer(struct drm_device *dev)
|
||||
ring->flush = bsd_ring_flush;
|
||||
ring->add_request = i9xx_add_request;
|
||||
ring->get_seqno = ring_get_seqno;
|
||||
ring->set_seqno = ring_set_seqno;
|
||||
if (IS_GEN5(dev)) {
|
||||
ring->irq_enable_mask = GT_BSD_USER_INTERRUPT;
|
||||
ring->irq_get = gen5_ring_get_irq;
|
||||
@ -1799,6 +1865,7 @@ int intel_init_blt_ring_buffer(struct drm_device *dev)
|
||||
ring->flush = blt_ring_flush;
|
||||
ring->add_request = gen6_add_request;
|
||||
ring->get_seqno = gen6_ring_get_seqno;
|
||||
ring->set_seqno = ring_set_seqno;
|
||||
ring->irq_enable_mask = GEN6_BLITTER_USER_INTERRUPT;
|
||||
ring->irq_get = gen6_ring_get_irq;
|
||||
ring->irq_put = gen6_ring_put_irq;
|
||||
|
@ -90,6 +90,8 @@ struct intel_ring_buffer {
|
||||
*/
|
||||
u32 (*get_seqno)(struct intel_ring_buffer *ring,
|
||||
bool lazy_coherency);
|
||||
void (*set_seqno)(struct intel_ring_buffer *ring,
|
||||
u32 seqno);
|
||||
int (*dispatch_execbuffer)(struct intel_ring_buffer *ring,
|
||||
u32 offset, u32 length,
|
||||
unsigned flags);
|
||||
@ -178,6 +180,13 @@ intel_read_status_page(struct intel_ring_buffer *ring,
|
||||
return ring->status_page.page_addr[reg];
|
||||
}
|
||||
|
||||
static inline void
|
||||
intel_write_status_page(struct intel_ring_buffer *ring,
|
||||
int reg, u32 value)
|
||||
{
|
||||
ring->status_page.page_addr[reg] = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads a dword out of the status page, which is written to from the command
|
||||
* queue by automatic updates, MI_REPORT_HEAD, MI_STORE_DATA_INDEX, or
|
||||
@ -208,7 +217,7 @@ static inline void intel_ring_emit(struct intel_ring_buffer *ring,
|
||||
}
|
||||
void intel_ring_advance(struct intel_ring_buffer *ring);
|
||||
int __must_check intel_ring_idle(struct intel_ring_buffer *ring);
|
||||
|
||||
void intel_ring_init_seqno(struct intel_ring_buffer *ring, u32 seqno);
|
||||
int intel_ring_flush_all_caches(struct intel_ring_buffer *ring);
|
||||
int intel_ring_invalidate_all_caches(struct intel_ring_buffer *ring);
|
||||
|
||||
|
@ -103,6 +103,7 @@ struct intel_sdvo {
|
||||
* It is only valid when using TMDS encoding and 8 bit per color mode.
|
||||
*/
|
||||
uint32_t color_range;
|
||||
bool color_range_auto;
|
||||
|
||||
/**
|
||||
* This is set if we're going to treat the device as TV-out.
|
||||
@ -125,6 +126,7 @@ struct intel_sdvo {
|
||||
bool is_hdmi;
|
||||
bool has_hdmi_monitor;
|
||||
bool has_hdmi_audio;
|
||||
bool rgb_quant_range_selectable;
|
||||
|
||||
/**
|
||||
* This is set if we detect output of sdvo device as LVDS and
|
||||
@ -946,7 +948,8 @@ static bool intel_sdvo_write_infoframe(struct intel_sdvo *intel_sdvo,
|
||||
&tx_rate, 1);
|
||||
}
|
||||
|
||||
static bool intel_sdvo_set_avi_infoframe(struct intel_sdvo *intel_sdvo)
|
||||
static bool intel_sdvo_set_avi_infoframe(struct intel_sdvo *intel_sdvo,
|
||||
const struct drm_display_mode *adjusted_mode)
|
||||
{
|
||||
struct dip_infoframe avi_if = {
|
||||
.type = DIP_TYPE_AVI,
|
||||
@ -955,6 +958,13 @@ static bool intel_sdvo_set_avi_infoframe(struct intel_sdvo *intel_sdvo)
|
||||
};
|
||||
uint8_t sdvo_data[4 + sizeof(avi_if.body.avi)];
|
||||
|
||||
if (intel_sdvo->rgb_quant_range_selectable) {
|
||||
if (adjusted_mode->private_flags & INTEL_MODE_LIMITED_COLOR_RANGE)
|
||||
avi_if.body.avi.ITC_EC_Q_SC |= DIP_AVI_RGB_QUANT_RANGE_LIMITED;
|
||||
else
|
||||
avi_if.body.avi.ITC_EC_Q_SC |= DIP_AVI_RGB_QUANT_RANGE_FULL;
|
||||
}
|
||||
|
||||
intel_dip_infoframe_csum(&avi_if);
|
||||
|
||||
/* sdvo spec says that the ecc is handled by the hw, and it looks like
|
||||
@ -1064,6 +1074,18 @@ static bool intel_sdvo_mode_fixup(struct drm_encoder *encoder,
|
||||
multiplier = intel_sdvo_get_pixel_multiplier(adjusted_mode);
|
||||
intel_mode_set_pixel_multiplier(adjusted_mode, multiplier);
|
||||
|
||||
if (intel_sdvo->color_range_auto) {
|
||||
/* See CEA-861-E - 5.1 Default Encoding Parameters */
|
||||
if (intel_sdvo->has_hdmi_monitor &&
|
||||
drm_match_cea_mode(adjusted_mode) > 1)
|
||||
intel_sdvo->color_range = SDVO_COLOR_RANGE_16_235;
|
||||
else
|
||||
intel_sdvo->color_range = 0;
|
||||
}
|
||||
|
||||
if (intel_sdvo->color_range)
|
||||
adjusted_mode->private_flags |= INTEL_MODE_LIMITED_COLOR_RANGE;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -1121,7 +1143,7 @@ static void intel_sdvo_mode_set(struct drm_encoder *encoder,
|
||||
intel_sdvo_set_encode(intel_sdvo, SDVO_ENCODE_HDMI);
|
||||
intel_sdvo_set_colorimetry(intel_sdvo,
|
||||
SDVO_COLORIMETRY_RGB256);
|
||||
intel_sdvo_set_avi_infoframe(intel_sdvo);
|
||||
intel_sdvo_set_avi_infoframe(intel_sdvo, adjusted_mode);
|
||||
} else
|
||||
intel_sdvo_set_encode(intel_sdvo, SDVO_ENCODE_DVI);
|
||||
|
||||
@ -1153,7 +1175,7 @@ static void intel_sdvo_mode_set(struct drm_encoder *encoder,
|
||||
/* The real mode polarity is set by the SDVO commands, using
|
||||
* struct intel_sdvo_dtd. */
|
||||
sdvox = SDVO_VSYNC_ACTIVE_HIGH | SDVO_HSYNC_ACTIVE_HIGH;
|
||||
if (intel_sdvo->is_hdmi)
|
||||
if (!HAS_PCH_SPLIT(dev) && intel_sdvo->is_hdmi)
|
||||
sdvox |= intel_sdvo->color_range;
|
||||
if (INTEL_INFO(dev)->gen < 5)
|
||||
sdvox |= SDVO_BORDER_ENABLE;
|
||||
@ -1513,6 +1535,8 @@ intel_sdvo_tmds_sink_detect(struct drm_connector *connector)
|
||||
if (intel_sdvo->is_hdmi) {
|
||||
intel_sdvo->has_hdmi_monitor = drm_detect_hdmi_monitor(edid);
|
||||
intel_sdvo->has_hdmi_audio = drm_detect_monitor_audio(edid);
|
||||
intel_sdvo->rgb_quant_range_selectable =
|
||||
drm_rgb_quant_range_selectable(edid);
|
||||
}
|
||||
} else
|
||||
status = connector_status_disconnected;
|
||||
@ -1564,6 +1588,7 @@ intel_sdvo_detect(struct drm_connector *connector, bool force)
|
||||
|
||||
intel_sdvo->has_hdmi_monitor = false;
|
||||
intel_sdvo->has_hdmi_audio = false;
|
||||
intel_sdvo->rgb_quant_range_selectable = false;
|
||||
|
||||
if ((intel_sdvo_connector->output_flag & response) == 0)
|
||||
ret = connector_status_disconnected;
|
||||
@ -1897,10 +1922,21 @@ intel_sdvo_set_property(struct drm_connector *connector,
|
||||
}
|
||||
|
||||
if (property == dev_priv->broadcast_rgb_property) {
|
||||
if (val == !!intel_sdvo->color_range)
|
||||
return 0;
|
||||
|
||||
intel_sdvo->color_range = val ? SDVO_COLOR_RANGE_16_235 : 0;
|
||||
switch (val) {
|
||||
case INTEL_BROADCAST_RGB_AUTO:
|
||||
intel_sdvo->color_range_auto = true;
|
||||
break;
|
||||
case INTEL_BROADCAST_RGB_FULL:
|
||||
intel_sdvo->color_range_auto = false;
|
||||
intel_sdvo->color_range = 0;
|
||||
break;
|
||||
case INTEL_BROADCAST_RGB_LIMITED:
|
||||
intel_sdvo->color_range_auto = false;
|
||||
intel_sdvo->color_range = SDVO_COLOR_RANGE_16_235;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
goto done;
|
||||
}
|
||||
|
||||
@ -1997,11 +2033,8 @@ set_value:
|
||||
|
||||
|
||||
done:
|
||||
if (intel_sdvo->base.base.crtc) {
|
||||
struct drm_crtc *crtc = intel_sdvo->base.base.crtc;
|
||||
intel_set_mode(crtc, &crtc->mode,
|
||||
crtc->x, crtc->y, crtc->fb);
|
||||
}
|
||||
if (intel_sdvo->base.base.crtc)
|
||||
intel_crtc_restore_mode(intel_sdvo->base.base.crtc);
|
||||
|
||||
return 0;
|
||||
#undef CHECK_PROPERTY
|
||||
@ -2010,7 +2043,6 @@ done:
|
||||
static const struct drm_encoder_helper_funcs intel_sdvo_helper_funcs = {
|
||||
.mode_fixup = intel_sdvo_mode_fixup,
|
||||
.mode_set = intel_sdvo_mode_set,
|
||||
.disable = intel_encoder_noop,
|
||||
};
|
||||
|
||||
static const struct drm_connector_funcs intel_sdvo_connector_funcs = {
|
||||
@ -2200,13 +2232,16 @@ intel_sdvo_connector_init(struct intel_sdvo_connector *connector,
|
||||
}
|
||||
|
||||
static void
|
||||
intel_sdvo_add_hdmi_properties(struct intel_sdvo_connector *connector)
|
||||
intel_sdvo_add_hdmi_properties(struct intel_sdvo *intel_sdvo,
|
||||
struct intel_sdvo_connector *connector)
|
||||
{
|
||||
struct drm_device *dev = connector->base.base.dev;
|
||||
|
||||
intel_attach_force_audio_property(&connector->base.base);
|
||||
if (INTEL_INFO(dev)->gen >= 4 && IS_MOBILE(dev))
|
||||
if (INTEL_INFO(dev)->gen >= 4 && IS_MOBILE(dev)) {
|
||||
intel_attach_broadcast_rgb_property(&connector->base.base);
|
||||
intel_sdvo->color_range_auto = true;
|
||||
}
|
||||
}
|
||||
|
||||
static bool
|
||||
@ -2254,7 +2289,7 @@ intel_sdvo_dvi_init(struct intel_sdvo *intel_sdvo, int device)
|
||||
|
||||
intel_sdvo_connector_init(intel_sdvo_connector, intel_sdvo);
|
||||
if (intel_sdvo->is_hdmi)
|
||||
intel_sdvo_add_hdmi_properties(intel_sdvo_connector);
|
||||
intel_sdvo_add_hdmi_properties(intel_sdvo, intel_sdvo_connector);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -50,6 +50,7 @@ ivb_update_plane(struct drm_plane *plane, struct drm_framebuffer *fb,
|
||||
u32 sprctl, sprscale = 0;
|
||||
unsigned long sprsurf_offset, linear_offset;
|
||||
int pixel_size = drm_format_plane_cpp(fb->pixel_format, 0);
|
||||
bool scaling_was_enabled = dev_priv->sprite_scaling_enabled;
|
||||
|
||||
sprctl = I915_READ(SPRCTL(pipe));
|
||||
|
||||
@ -89,6 +90,9 @@ ivb_update_plane(struct drm_plane *plane, struct drm_framebuffer *fb,
|
||||
sprctl |= SPRITE_TRICKLE_FEED_DISABLE;
|
||||
sprctl |= SPRITE_ENABLE;
|
||||
|
||||
if (IS_HASWELL(dev))
|
||||
sprctl |= SPRITE_PIPE_CSC_ENABLE;
|
||||
|
||||
/* Sizes are 0 based */
|
||||
src_w--;
|
||||
src_h--;
|
||||
@ -103,27 +107,23 @@ ivb_update_plane(struct drm_plane *plane, struct drm_framebuffer *fb,
|
||||
* when scaling is disabled.
|
||||
*/
|
||||
if (crtc_w != src_w || crtc_h != src_h) {
|
||||
if (!dev_priv->sprite_scaling_enabled) {
|
||||
dev_priv->sprite_scaling_enabled = true;
|
||||
dev_priv->sprite_scaling_enabled |= 1 << pipe;
|
||||
|
||||
if (!scaling_was_enabled) {
|
||||
intel_update_watermarks(dev);
|
||||
intel_wait_for_vblank(dev, pipe);
|
||||
}
|
||||
sprscale = SPRITE_SCALE_ENABLE | (src_w << 16) | src_h;
|
||||
} else {
|
||||
if (dev_priv->sprite_scaling_enabled) {
|
||||
dev_priv->sprite_scaling_enabled = false;
|
||||
/* potentially re-enable LP watermarks */
|
||||
intel_update_watermarks(dev);
|
||||
}
|
||||
}
|
||||
} else
|
||||
dev_priv->sprite_scaling_enabled &= ~(1 << pipe);
|
||||
|
||||
I915_WRITE(SPRSTRIDE(pipe), fb->pitches[0]);
|
||||
I915_WRITE(SPRPOS(pipe), (crtc_y << 16) | crtc_x);
|
||||
|
||||
linear_offset = y * fb->pitches[0] + x * pixel_size;
|
||||
sprsurf_offset =
|
||||
intel_gen4_compute_offset_xtiled(&x, &y,
|
||||
pixel_size, fb->pitches[0]);
|
||||
intel_gen4_compute_page_offset(&x, &y, obj->tiling_mode,
|
||||
pixel_size, fb->pitches[0]);
|
||||
linear_offset -= sprsurf_offset;
|
||||
|
||||
/* HSW consolidates SPRTILEOFF and SPRLINOFF into a single SPROFFSET
|
||||
@ -141,6 +141,10 @@ ivb_update_plane(struct drm_plane *plane, struct drm_framebuffer *fb,
|
||||
I915_WRITE(SPRCTL(pipe), sprctl);
|
||||
I915_MODIFY_DISPBASE(SPRSURF(pipe), obj->gtt_offset + sprsurf_offset);
|
||||
POSTING_READ(SPRSURF(pipe));
|
||||
|
||||
/* potentially re-enable LP watermarks */
|
||||
if (scaling_was_enabled && !dev_priv->sprite_scaling_enabled)
|
||||
intel_update_watermarks(dev);
|
||||
}
|
||||
|
||||
static void
|
||||
@ -150,6 +154,7 @@ ivb_disable_plane(struct drm_plane *plane)
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
struct intel_plane *intel_plane = to_intel_plane(plane);
|
||||
int pipe = intel_plane->pipe;
|
||||
bool scaling_was_enabled = dev_priv->sprite_scaling_enabled;
|
||||
|
||||
I915_WRITE(SPRCTL(pipe), I915_READ(SPRCTL(pipe)) & ~SPRITE_ENABLE);
|
||||
/* Can't leave the scaler enabled... */
|
||||
@ -159,8 +164,11 @@ ivb_disable_plane(struct drm_plane *plane)
|
||||
I915_MODIFY_DISPBASE(SPRSURF(pipe), 0);
|
||||
POSTING_READ(SPRSURF(pipe));
|
||||
|
||||
dev_priv->sprite_scaling_enabled = false;
|
||||
intel_update_watermarks(dev);
|
||||
dev_priv->sprite_scaling_enabled &= ~(1 << pipe);
|
||||
|
||||
/* potentially re-enable LP watermarks */
|
||||
if (scaling_was_enabled && !dev_priv->sprite_scaling_enabled)
|
||||
intel_update_watermarks(dev);
|
||||
}
|
||||
|
||||
static int
|
||||
@ -287,8 +295,8 @@ ilk_update_plane(struct drm_plane *plane, struct drm_framebuffer *fb,
|
||||
|
||||
linear_offset = y * fb->pitches[0] + x * pixel_size;
|
||||
dvssurf_offset =
|
||||
intel_gen4_compute_offset_xtiled(&x, &y,
|
||||
pixel_size, fb->pitches[0]);
|
||||
intel_gen4_compute_page_offset(&x, &y, obj->tiling_mode,
|
||||
pixel_size, fb->pitches[0]);
|
||||
linear_offset -= dvssurf_offset;
|
||||
|
||||
if (obj->tiling_mode != I915_TILING_NONE)
|
||||
@ -593,7 +601,7 @@ int intel_sprite_set_colorkey(struct drm_device *dev, void *data,
|
||||
if ((set->flags & (I915_SET_COLORKEY_DESTINATION | I915_SET_COLORKEY_SOURCE)) == (I915_SET_COLORKEY_DESTINATION | I915_SET_COLORKEY_SOURCE))
|
||||
return -EINVAL;
|
||||
|
||||
mutex_lock(&dev->mode_config.mutex);
|
||||
drm_modeset_lock_all(dev);
|
||||
|
||||
obj = drm_mode_object_find(dev, set->plane_id, DRM_MODE_OBJECT_PLANE);
|
||||
if (!obj) {
|
||||
@ -606,7 +614,7 @@ int intel_sprite_set_colorkey(struct drm_device *dev, void *data,
|
||||
ret = intel_plane->update_colorkey(plane, set);
|
||||
|
||||
out_unlock:
|
||||
mutex_unlock(&dev->mode_config.mutex);
|
||||
drm_modeset_unlock_all(dev);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -622,7 +630,7 @@ int intel_sprite_get_colorkey(struct drm_device *dev, void *data,
|
||||
if (!drm_core_check_feature(dev, DRIVER_MODESET))
|
||||
return -ENODEV;
|
||||
|
||||
mutex_lock(&dev->mode_config.mutex);
|
||||
drm_modeset_lock_all(dev);
|
||||
|
||||
obj = drm_mode_object_find(dev, get->plane_id, DRM_MODE_OBJECT_PLANE);
|
||||
if (!obj) {
|
||||
@ -635,7 +643,7 @@ int intel_sprite_get_colorkey(struct drm_device *dev, void *data,
|
||||
intel_plane->get_colorkey(plane, get);
|
||||
|
||||
out_unlock:
|
||||
mutex_unlock(&dev->mode_config.mutex);
|
||||
drm_modeset_unlock_all(dev);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -1479,8 +1479,7 @@ intel_tv_set_property(struct drm_connector *connector, struct drm_property *prop
|
||||
}
|
||||
|
||||
if (changed && crtc)
|
||||
intel_set_mode(crtc, &crtc->mode,
|
||||
crtc->x, crtc->y, crtc->fb);
|
||||
intel_crtc_restore_mode(crtc);
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
@ -1488,7 +1487,6 @@ out:
|
||||
static const struct drm_encoder_helper_funcs intel_tv_helper_funcs = {
|
||||
.mode_fixup = intel_tv_mode_fixup,
|
||||
.mode_set = intel_tv_mode_set,
|
||||
.disable = intel_encoder_noop,
|
||||
};
|
||||
|
||||
static const struct drm_connector_funcs intel_tv_connector_funcs = {
|
||||
|
@ -13,6 +13,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 mgag200fb_create_object(struct mga_fbdev *afbdev,
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int mgag200fb_create(struct mga_fbdev *mfbdev,
|
||||
static int mgag200fb_create(struct drm_fb_helper *helper,
|
||||
struct drm_fb_helper_surface_size *sizes)
|
||||
{
|
||||
struct mga_fbdev *mfbdev = (struct mga_fbdev *)helper;
|
||||
struct drm_device *dev = mfbdev->helper.dev;
|
||||
struct drm_mode_fb_cmd2 mode_cmd;
|
||||
struct mga_device *mdev = dev->dev_private;
|
||||
@ -209,23 +211,6 @@ out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int mga_fb_find_or_create_single(struct drm_fb_helper *helper,
|
||||
struct drm_fb_helper_surface_size
|
||||
*sizes)
|
||||
{
|
||||
struct mga_fbdev *mfbdev = (struct mga_fbdev *)helper;
|
||||
int new_fb = 0;
|
||||
int ret;
|
||||
|
||||
if (!helper->fb) {
|
||||
ret = mgag200fb_create(mfbdev, sizes);
|
||||
if (ret)
|
||||
return ret;
|
||||
new_fb = 1;
|
||||
}
|
||||
return new_fb;
|
||||
}
|
||||
|
||||
static int mga_fbdev_destroy(struct drm_device *dev,
|
||||
struct mga_fbdev *mfbdev)
|
||||
{
|
||||
@ -247,6 +232,7 @@ static int mga_fbdev_destroy(struct drm_device *dev,
|
||||
}
|
||||
drm_fb_helper_fini(&mfbdev->helper);
|
||||
vfree(mfbdev->sysram);
|
||||
drm_framebuffer_unregister_private(&mfb->base);
|
||||
drm_framebuffer_cleanup(&mfb->base);
|
||||
|
||||
return 0;
|
||||
@ -255,7 +241,7 @@ static int mga_fbdev_destroy(struct drm_device *dev,
|
||||
static struct drm_fb_helper_funcs mga_fb_helper_funcs = {
|
||||
.gamma_set = mga_crtc_fb_gamma_set,
|
||||
.gamma_get = mga_crtc_fb_gamma_get,
|
||||
.fb_probe = mga_fb_find_or_create_single,
|
||||
.fb_probe = mgag200fb_create,
|
||||
};
|
||||
|
||||
int mgag200_fbdev_init(struct mga_device *mdev)
|
||||
@ -277,6 +263,10 @@ int mgag200_fbdev_init(struct mga_device *mdev)
|
||||
return ret;
|
||||
}
|
||||
drm_fb_helper_single_add_all_connectors(&mfbdev->helper);
|
||||
|
||||
/* disable all the possible outputs/crtcs before entering KMS mode */
|
||||
drm_helper_disable_unused_functions(mdev->dev);
|
||||
|
||||
drm_fb_helper_initial_config(&mfbdev->helper, 32);
|
||||
|
||||
return 0;
|
||||
|
@ -23,16 +23,8 @@ static void mga_user_framebuffer_destroy(struct drm_framebuffer *fb)
|
||||
kfree(fb);
|
||||
}
|
||||
|
||||
static int mga_user_framebuffer_create_handle(struct drm_framebuffer *fb,
|
||||
struct drm_file *file_priv,
|
||||
unsigned int *handle)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct drm_framebuffer_funcs mga_fb_funcs = {
|
||||
.destroy = mga_user_framebuffer_destroy,
|
||||
.create_handle = mga_user_framebuffer_create_handle,
|
||||
};
|
||||
|
||||
int mgag200_framebuffer_init(struct drm_device *dev,
|
||||
@ -40,13 +32,15 @@ int mgag200_framebuffer_init(struct drm_device *dev,
|
||||
struct drm_mode_fb_cmd2 *mode_cmd,
|
||||
struct drm_gem_object *obj)
|
||||
{
|
||||
int ret = drm_framebuffer_init(dev, &gfb->base, &mga_fb_funcs);
|
||||
int ret;
|
||||
|
||||
drm_helper_mode_fill_fb_struct(&gfb->base, mode_cmd);
|
||||
gfb->obj = obj;
|
||||
ret = drm_framebuffer_init(dev, &gfb->base, &mga_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;
|
||||
}
|
||||
|
||||
|
@ -11,8 +11,9 @@ config DRM_NOUVEAU
|
||||
select FRAMEBUFFER_CONSOLE if !EXPERT
|
||||
select FB_BACKLIGHT if DRM_NOUVEAU_BACKLIGHT
|
||||
select ACPI_VIDEO if ACPI && X86 && BACKLIGHT_CLASS_DEVICE && VIDEO_OUTPUT_CONTROL && INPUT
|
||||
select ACPI_WMI if ACPI
|
||||
select MXM_WMI if ACPI
|
||||
select X86_PLATFORM_DEVICES if ACPI && X86
|
||||
select ACPI_WMI if ACPI && X86
|
||||
select MXM_WMI if ACPI && X86
|
||||
select POWER_SUPPLY
|
||||
help
|
||||
Choose this option for open-source nVidia support.
|
||||
@ -52,26 +53,3 @@ config DRM_NOUVEAU_BACKLIGHT
|
||||
help
|
||||
Say Y here if you want to control the backlight of your display
|
||||
(e.g. a laptop panel).
|
||||
|
||||
menu "I2C encoder or helper chips"
|
||||
depends on DRM && DRM_KMS_HELPER && I2C
|
||||
|
||||
config DRM_I2C_CH7006
|
||||
tristate "Chrontel ch7006 TV encoder"
|
||||
default m if DRM_NOUVEAU
|
||||
help
|
||||
Support for Chrontel ch7006 and similar TV encoders, found
|
||||
on some nVidia video cards.
|
||||
|
||||
This driver is currently only useful if you're also using
|
||||
the nouveau driver.
|
||||
|
||||
config DRM_I2C_SIL164
|
||||
tristate "Silicon Image sil164 TMDS transmitter"
|
||||
default m if DRM_NOUVEAU
|
||||
help
|
||||
Support for sil164 and similar single-link (or dual-link
|
||||
when used in pairs) TMDS transmitters, used in some nVidia
|
||||
video cards.
|
||||
|
||||
endmenu
|
||||
|
@ -11,6 +11,7 @@ nouveau-y := core/core/client.o
|
||||
nouveau-y += core/core/engctx.o
|
||||
nouveau-y += core/core/engine.o
|
||||
nouveau-y += core/core/enum.o
|
||||
nouveau-y += core/core/event.o
|
||||
nouveau-y += core/core/falcon.o
|
||||
nouveau-y += core/core/gpuobj.o
|
||||
nouveau-y += core/core/handle.o
|
||||
@ -40,6 +41,11 @@ nouveau-y += core/subdev/bios/mxm.o
|
||||
nouveau-y += core/subdev/bios/perf.o
|
||||
nouveau-y += core/subdev/bios/pll.o
|
||||
nouveau-y += core/subdev/bios/therm.o
|
||||
nouveau-y += core/subdev/bios/xpio.o
|
||||
nouveau-y += core/subdev/bus/nv04.o
|
||||
nouveau-y += core/subdev/bus/nv31.o
|
||||
nouveau-y += core/subdev/bus/nv50.o
|
||||
nouveau-y += core/subdev/bus/nvc0.o
|
||||
nouveau-y += core/subdev/clock/nv04.o
|
||||
nouveau-y += core/subdev/clock/nv40.o
|
||||
nouveau-y += core/subdev/clock/nv50.o
|
||||
@ -85,9 +91,16 @@ nouveau-y += core/subdev/gpio/base.o
|
||||
nouveau-y += core/subdev/gpio/nv10.o
|
||||
nouveau-y += core/subdev/gpio/nv50.o
|
||||
nouveau-y += core/subdev/gpio/nvd0.o
|
||||
nouveau-y += core/subdev/gpio/nve0.o
|
||||
nouveau-y += core/subdev/i2c/base.o
|
||||
nouveau-y += core/subdev/i2c/anx9805.o
|
||||
nouveau-y += core/subdev/i2c/aux.o
|
||||
nouveau-y += core/subdev/i2c/bit.o
|
||||
nouveau-y += core/subdev/i2c/nv04.o
|
||||
nouveau-y += core/subdev/i2c/nv4e.o
|
||||
nouveau-y += core/subdev/i2c/nv50.o
|
||||
nouveau-y += core/subdev/i2c/nv94.o
|
||||
nouveau-y += core/subdev/i2c/nvd0.o
|
||||
nouveau-y += core/subdev/ibus/nvc0.o
|
||||
nouveau-y += core/subdev/ibus/nve0.o
|
||||
nouveau-y += core/subdev/instmem/base.o
|
||||
@ -106,10 +119,15 @@ nouveau-y += core/subdev/mxm/mxms.o
|
||||
nouveau-y += core/subdev/mxm/nv50.o
|
||||
nouveau-y += core/subdev/therm/base.o
|
||||
nouveau-y += core/subdev/therm/fan.o
|
||||
nouveau-y += core/subdev/therm/fannil.o
|
||||
nouveau-y += core/subdev/therm/fanpwm.o
|
||||
nouveau-y += core/subdev/therm/fantog.o
|
||||
nouveau-y += core/subdev/therm/ic.o
|
||||
nouveau-y += core/subdev/therm/temp.o
|
||||
nouveau-y += core/subdev/therm/nv40.o
|
||||
nouveau-y += core/subdev/therm/nv50.o
|
||||
nouveau-y += core/subdev/therm/temp.o
|
||||
nouveau-y += core/subdev/therm/nva3.o
|
||||
nouveau-y += core/subdev/therm/nvd0.o
|
||||
nouveau-y += core/subdev/timer/base.o
|
||||
nouveau-y += core/subdev/timer/nv04.o
|
||||
nouveau-y += core/subdev/vm/base.o
|
||||
@ -132,6 +150,7 @@ nouveau-y += core/engine/copy/nvc0.o
|
||||
nouveau-y += core/engine/copy/nve0.o
|
||||
nouveau-y += core/engine/crypt/nv84.o
|
||||
nouveau-y += core/engine/crypt/nv98.o
|
||||
nouveau-y += core/engine/disp/base.o
|
||||
nouveau-y += core/engine/disp/nv04.o
|
||||
nouveau-y += core/engine/disp/nv50.o
|
||||
nouveau-y += core/engine/disp/nv84.o
|
||||
@ -141,11 +160,13 @@ nouveau-y += core/engine/disp/nva3.o
|
||||
nouveau-y += core/engine/disp/nvd0.o
|
||||
nouveau-y += core/engine/disp/nve0.o
|
||||
nouveau-y += core/engine/disp/dacnv50.o
|
||||
nouveau-y += core/engine/disp/dport.o
|
||||
nouveau-y += core/engine/disp/hdanva3.o
|
||||
nouveau-y += core/engine/disp/hdanvd0.o
|
||||
nouveau-y += core/engine/disp/hdminv84.o
|
||||
nouveau-y += core/engine/disp/hdminva3.o
|
||||
nouveau-y += core/engine/disp/hdminvd0.o
|
||||
nouveau-y += core/engine/disp/piornv50.o
|
||||
nouveau-y += core/engine/disp/sornv50.o
|
||||
nouveau-y += core/engine/disp/sornv94.o
|
||||
nouveau-y += core/engine/disp/sornvd0.o
|
||||
@ -194,7 +215,8 @@ nouveau-y += nouveau_drm.o nouveau_chan.o nouveau_dma.o nouveau_fence.o
|
||||
nouveau-y += nouveau_irq.o nouveau_vga.o nouveau_agp.o
|
||||
nouveau-y += nouveau_ttm.o nouveau_sgdma.o nouveau_bo.o nouveau_gem.o
|
||||
nouveau-y += nouveau_prime.o nouveau_abi16.o
|
||||
nouveau-y += nv04_fence.o nv10_fence.o nv50_fence.o nv84_fence.o nvc0_fence.o
|
||||
nouveau-y += nv04_fence.o nv10_fence.o nv17_fence.o
|
||||
nouveau-y += nv50_fence.o nv84_fence.o nvc0_fence.o
|
||||
|
||||
# drm/kms
|
||||
nouveau-y += nouveau_bios.o nouveau_fbcon.o nouveau_display.o
|
||||
@ -216,7 +238,10 @@ nouveau-y += nouveau_mem.o
|
||||
|
||||
# other random bits
|
||||
nouveau-$(CONFIG_COMPAT) += nouveau_ioc32.o
|
||||
ifdef CONFIG_X86
|
||||
nouveau-$(CONFIG_ACPI) += nouveau_acpi.o
|
||||
endif
|
||||
nouveau-$(CONFIG_DRM_NOUVEAU_BACKLIGHT) += nouveau_backlight.o
|
||||
nouveau-$(CONFIG_DEBUG_FS) += nouveau_debugfs.o
|
||||
|
||||
obj-$(CONFIG_DRM_NOUVEAU)+= nouveau.o
|
||||
|
@ -99,3 +99,13 @@ nouveau_client_fini(struct nouveau_client *client, bool suspend)
|
||||
nv_debug(client, "%s completed with %d\n", name[suspend], ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
const char *
|
||||
nouveau_client_name(void *obj)
|
||||
{
|
||||
const char *client_name = "unknown";
|
||||
struct nouveau_client *client = nouveau_client(obj);
|
||||
if (client)
|
||||
client_name = client->name;
|
||||
return client_name;
|
||||
}
|
||||
|
@ -40,14 +40,15 @@ nouveau_enum_find(const struct nouveau_enum *en, u32 value)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void
|
||||
const struct nouveau_enum *
|
||||
nouveau_enum_print(const struct nouveau_enum *en, u32 value)
|
||||
{
|
||||
en = nouveau_enum_find(en, value);
|
||||
if (en)
|
||||
printk("%s", en->name);
|
||||
pr_cont("%s", en->name);
|
||||
else
|
||||
printk("(unknown enum 0x%08x)", value);
|
||||
pr_cont("(unknown enum 0x%08x)", value);
|
||||
return en;
|
||||
}
|
||||
|
||||
void
|
||||
@ -55,7 +56,7 @@ nouveau_bitfield_print(const struct nouveau_bitfield *bf, u32 value)
|
||||
{
|
||||
while (bf->name) {
|
||||
if (value & bf->mask) {
|
||||
printk(" %s", bf->name);
|
||||
pr_cont(" %s", bf->name);
|
||||
value &= ~bf->mask;
|
||||
}
|
||||
|
||||
@ -63,5 +64,5 @@ nouveau_bitfield_print(const struct nouveau_bitfield *bf, u32 value)
|
||||
}
|
||||
|
||||
if (value)
|
||||
printk(" (unknown bits 0x%08x)", value);
|
||||
pr_cont(" (unknown bits 0x%08x)", value);
|
||||
}
|
||||
|
106
drivers/gpu/drm/nouveau/core/core/event.c
Normal file
106
drivers/gpu/drm/nouveau/core/core/event.c
Normal file
@ -0,0 +1,106 @@
|
||||
/*
|
||||
* Copyright 2013 Red Hat Inc.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <core/os.h>
|
||||
#include <core/event.h>
|
||||
|
||||
static void
|
||||
nouveau_event_put_locked(struct nouveau_event *event, int index,
|
||||
struct nouveau_eventh *handler)
|
||||
{
|
||||
if (!--event->index[index].refs)
|
||||
event->disable(event, index);
|
||||
list_del(&handler->head);
|
||||
}
|
||||
|
||||
void
|
||||
nouveau_event_put(struct nouveau_event *event, int index,
|
||||
struct nouveau_eventh *handler)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&event->lock, flags);
|
||||
if (index < event->index_nr)
|
||||
nouveau_event_put_locked(event, index, handler);
|
||||
spin_unlock_irqrestore(&event->lock, flags);
|
||||
}
|
||||
|
||||
void
|
||||
nouveau_event_get(struct nouveau_event *event, int index,
|
||||
struct nouveau_eventh *handler)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&event->lock, flags);
|
||||
if (index < event->index_nr) {
|
||||
list_add(&handler->head, &event->index[index].list);
|
||||
if (!event->index[index].refs++)
|
||||
event->enable(event, index);
|
||||
}
|
||||
spin_unlock_irqrestore(&event->lock, flags);
|
||||
}
|
||||
|
||||
void
|
||||
nouveau_event_trigger(struct nouveau_event *event, int index)
|
||||
{
|
||||
struct nouveau_eventh *handler, *temp;
|
||||
unsigned long flags;
|
||||
|
||||
if (index >= event->index_nr)
|
||||
return;
|
||||
|
||||
spin_lock_irqsave(&event->lock, flags);
|
||||
list_for_each_entry_safe(handler, temp, &event->index[index].list, head) {
|
||||
if (handler->func(handler, index) == NVKM_EVENT_DROP) {
|
||||
nouveau_event_put_locked(event, index, handler);
|
||||
}
|
||||
}
|
||||
spin_unlock_irqrestore(&event->lock, flags);
|
||||
}
|
||||
|
||||
void
|
||||
nouveau_event_destroy(struct nouveau_event **pevent)
|
||||
{
|
||||
struct nouveau_event *event = *pevent;
|
||||
if (event) {
|
||||
kfree(event);
|
||||
*pevent = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
nouveau_event_create(int index_nr, struct nouveau_event **pevent)
|
||||
{
|
||||
struct nouveau_event *event;
|
||||
int i;
|
||||
|
||||
event = *pevent = kzalloc(sizeof(*event) + index_nr *
|
||||
sizeof(event->index[0]), GFP_KERNEL);
|
||||
if (!event)
|
||||
return -ENOMEM;
|
||||
|
||||
spin_lock_init(&event->lock);
|
||||
for (i = 0; i < index_nr; i++)
|
||||
INIT_LIST_HEAD(&event->index[i].list);
|
||||
event->index_nr = index_nr;
|
||||
return 0;
|
||||
}
|
@ -22,6 +22,7 @@
|
||||
* Authors: Ben Skeggs
|
||||
*/
|
||||
|
||||
#include <core/client.h>
|
||||
#include <core/falcon.h>
|
||||
#include <core/class.h>
|
||||
#include <core/enum.h>
|
||||
@ -100,8 +101,9 @@ nva3_copy_intr(struct nouveau_subdev *subdev)
|
||||
if (stat & 0x00000040) {
|
||||
nv_error(falcon, "DISPATCH_ERROR [");
|
||||
nouveau_enum_print(nva3_copy_isr_error_name, ssta);
|
||||
printk("] ch %d [0x%010llx] subc %d mthd 0x%04x data 0x%08x\n",
|
||||
chid, inst << 12, subc, mthd, data);
|
||||
pr_cont("] ch %d [0x%010llx %s] subc %d mthd 0x%04x data 0x%08x\n",
|
||||
chid, inst << 12, nouveau_client_name(engctx), subc,
|
||||
mthd, data);
|
||||
nv_wo32(falcon, 0x004, 0x00000040);
|
||||
stat &= ~0x00000040;
|
||||
}
|
||||
|
@ -22,6 +22,7 @@
|
||||
* Authors: Ben Skeggs
|
||||
*/
|
||||
|
||||
#include <core/client.h>
|
||||
#include <core/os.h>
|
||||
#include <core/enum.h>
|
||||
#include <core/class.h>
|
||||
@ -126,10 +127,11 @@ nv84_crypt_intr(struct nouveau_subdev *subdev)
|
||||
chid = pfifo->chid(pfifo, engctx);
|
||||
|
||||
if (stat) {
|
||||
nv_error(priv, "");
|
||||
nv_error(priv, "%s", "");
|
||||
nouveau_bitfield_print(nv84_crypt_intr_mask, stat);
|
||||
printk(" ch %d [0x%010llx] mthd 0x%04x data 0x%08x\n",
|
||||
chid, (u64)inst << 12, mthd, data);
|
||||
pr_cont(" ch %d [0x%010llx %s] mthd 0x%04x data 0x%08x\n",
|
||||
chid, (u64)inst << 12, nouveau_client_name(engctx),
|
||||
mthd, data);
|
||||
}
|
||||
|
||||
nv_wr32(priv, 0x102130, stat);
|
||||
|
@ -22,6 +22,7 @@
|
||||
* Authors: Ben Skeggs
|
||||
*/
|
||||
|
||||
#include <core/client.h>
|
||||
#include <core/os.h>
|
||||
#include <core/enum.h>
|
||||
#include <core/class.h>
|
||||
@ -102,8 +103,9 @@ nv98_crypt_intr(struct nouveau_subdev *subdev)
|
||||
if (stat & 0x00000040) {
|
||||
nv_error(priv, "DISPATCH_ERROR [");
|
||||
nouveau_enum_print(nv98_crypt_isr_error_name, ssta);
|
||||
printk("] ch %d [0x%010llx] subc %d mthd 0x%04x data 0x%08x\n",
|
||||
chid, (u64)inst << 12, subc, mthd, data);
|
||||
pr_cont("] ch %d [0x%010llx %s] subc %d mthd 0x%04x data 0x%08x\n",
|
||||
chid, (u64)inst << 12, nouveau_client_name(engctx),
|
||||
subc, mthd, data);
|
||||
nv_wr32(priv, 0x087004, 0x00000040);
|
||||
stat &= ~0x00000040;
|
||||
}
|
||||
|
52
drivers/gpu/drm/nouveau/core/engine/disp/base.c
Normal file
52
drivers/gpu/drm/nouveau/core/engine/disp/base.c
Normal file
@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Copyright 2013 Red Hat Inc.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* Authors: Ben Skeggs
|
||||
*/
|
||||
|
||||
#include <engine/disp.h>
|
||||
|
||||
void
|
||||
_nouveau_disp_dtor(struct nouveau_object *object)
|
||||
{
|
||||
struct nouveau_disp *disp = (void *)object;
|
||||
nouveau_event_destroy(&disp->vblank);
|
||||
nouveau_engine_destroy(&disp->base);
|
||||
}
|
||||
|
||||
int
|
||||
nouveau_disp_create_(struct nouveau_object *parent,
|
||||
struct nouveau_object *engine,
|
||||
struct nouveau_oclass *oclass, int heads,
|
||||
const char *intname, const char *extname,
|
||||
int length, void **pobject)
|
||||
{
|
||||
struct nouveau_disp *disp;
|
||||
int ret;
|
||||
|
||||
ret = nouveau_engine_create_(parent, engine, oclass, true,
|
||||
intname, extname, length, pobject);
|
||||
disp = *pobject;
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return nouveau_event_create(heads, &disp->vblank);
|
||||
}
|
346
drivers/gpu/drm/nouveau/core/engine/disp/dport.c
Normal file
346
drivers/gpu/drm/nouveau/core/engine/disp/dport.c
Normal file
@ -0,0 +1,346 @@
|
||||
/*
|
||||
* Copyright 2013 Red Hat Inc.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* Authors: Ben Skeggs
|
||||
*/
|
||||
|
||||
#include <subdev/bios.h>
|
||||
#include <subdev/bios/dcb.h>
|
||||
#include <subdev/bios/dp.h>
|
||||
#include <subdev/bios/init.h>
|
||||
#include <subdev/i2c.h>
|
||||
|
||||
#include <engine/disp.h>
|
||||
|
||||
#include "dport.h"
|
||||
|
||||
#define DBG(fmt, args...) nv_debug(dp->disp, "DP:%04x:%04x: " fmt, \
|
||||
dp->outp->hasht, dp->outp->hashm, ##args)
|
||||
#define ERR(fmt, args...) nv_error(dp->disp, "DP:%04x:%04x: " fmt, \
|
||||
dp->outp->hasht, dp->outp->hashm, ##args)
|
||||
|
||||
/******************************************************************************
|
||||
* link training
|
||||
*****************************************************************************/
|
||||
struct dp_state {
|
||||
const struct nouveau_dp_func *func;
|
||||
struct nouveau_disp *disp;
|
||||
struct dcb_output *outp;
|
||||
struct nvbios_dpout info;
|
||||
u8 version;
|
||||
struct nouveau_i2c_port *aux;
|
||||
int head;
|
||||
u8 dpcd[4];
|
||||
int link_nr;
|
||||
u32 link_bw;
|
||||
u8 stat[6];
|
||||
u8 conf[4];
|
||||
};
|
||||
|
||||
static int
|
||||
dp_set_link_config(struct dp_state *dp)
|
||||
{
|
||||
struct nouveau_disp *disp = dp->disp;
|
||||
struct nouveau_bios *bios = nouveau_bios(disp);
|
||||
struct nvbios_init init = {
|
||||
.subdev = nv_subdev(dp->disp),
|
||||
.bios = bios,
|
||||
.offset = 0x0000,
|
||||
.outp = dp->outp,
|
||||
.crtc = dp->head,
|
||||
.execute = 1,
|
||||
};
|
||||
u32 lnkcmp;
|
||||
u8 sink[2];
|
||||
|
||||
DBG("%d lanes at %d KB/s\n", dp->link_nr, dp->link_bw);
|
||||
|
||||
/* set desired link configuration on the sink */
|
||||
sink[0] = dp->link_bw / 27000;
|
||||
sink[1] = dp->link_nr;
|
||||
if (dp->dpcd[DPCD_RC02] & DPCD_RC02_ENHANCED_FRAME_CAP)
|
||||
sink[1] |= DPCD_LC01_ENHANCED_FRAME_EN;
|
||||
|
||||
nv_wraux(dp->aux, DPCD_LC00, sink, 2);
|
||||
|
||||
/* set desired link configuration on the source */
|
||||
if ((lnkcmp = dp->info.lnkcmp)) {
|
||||
if (dp->version < 0x30) {
|
||||
while ((dp->link_bw / 10) < nv_ro16(bios, lnkcmp))
|
||||
lnkcmp += 4;
|
||||
init.offset = nv_ro16(bios, lnkcmp + 2);
|
||||
} else {
|
||||
while ((dp->link_bw / 27000) < nv_ro08(bios, lnkcmp))
|
||||
lnkcmp += 3;
|
||||
init.offset = nv_ro16(bios, lnkcmp + 1);
|
||||
}
|
||||
|
||||
nvbios_exec(&init);
|
||||
}
|
||||
|
||||
return dp->func->lnk_ctl(dp->disp, dp->outp, dp->head,
|
||||
dp->link_nr, dp->link_bw / 27000,
|
||||
dp->dpcd[DPCD_RC02] &
|
||||
DPCD_RC02_ENHANCED_FRAME_CAP);
|
||||
}
|
||||
|
||||
static void
|
||||
dp_set_training_pattern(struct dp_state *dp, u8 pattern)
|
||||
{
|
||||
u8 sink_tp;
|
||||
|
||||
DBG("training pattern %d\n", pattern);
|
||||
dp->func->pattern(dp->disp, dp->outp, dp->head, pattern);
|
||||
|
||||
nv_rdaux(dp->aux, DPCD_LC02, &sink_tp, 1);
|
||||
sink_tp &= ~DPCD_LC02_TRAINING_PATTERN_SET;
|
||||
sink_tp |= pattern;
|
||||
nv_wraux(dp->aux, DPCD_LC02, &sink_tp, 1);
|
||||
}
|
||||
|
||||
static int
|
||||
dp_link_train_commit(struct dp_state *dp)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < dp->link_nr; i++) {
|
||||
u8 lane = (dp->stat[4 + (i >> 1)] >> ((i & 1) * 4)) & 0xf;
|
||||
u8 lpre = (lane & 0x0c) >> 2;
|
||||
u8 lvsw = (lane & 0x03) >> 0;
|
||||
|
||||
dp->conf[i] = (lpre << 3) | lvsw;
|
||||
if (lvsw == 3)
|
||||
dp->conf[i] |= DPCD_LC03_MAX_SWING_REACHED;
|
||||
if (lpre == 3)
|
||||
dp->conf[i] |= DPCD_LC03_MAX_PRE_EMPHASIS_REACHED;
|
||||
|
||||
DBG("config lane %d %02x\n", i, dp->conf[i]);
|
||||
dp->func->drv_ctl(dp->disp, dp->outp, dp->head, i, lvsw, lpre);
|
||||
}
|
||||
|
||||
return nv_wraux(dp->aux, DPCD_LC03(0), dp->conf, 4);
|
||||
}
|
||||
|
||||
static int
|
||||
dp_link_train_update(struct dp_state *dp, u32 delay)
|
||||
{
|
||||
int ret;
|
||||
|
||||
udelay(delay);
|
||||
|
||||
ret = nv_rdaux(dp->aux, DPCD_LS02, dp->stat, 6);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
DBG("status %*ph\n", 6, dp->stat);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
dp_link_train_cr(struct dp_state *dp)
|
||||
{
|
||||
bool cr_done = false, abort = false;
|
||||
int voltage = dp->conf[0] & DPCD_LC03_VOLTAGE_SWING_SET;
|
||||
int tries = 0, i;
|
||||
|
||||
dp_set_training_pattern(dp, 1);
|
||||
|
||||
do {
|
||||
if (dp_link_train_commit(dp) ||
|
||||
dp_link_train_update(dp, 100))
|
||||
break;
|
||||
|
||||
cr_done = true;
|
||||
for (i = 0; i < dp->link_nr; i++) {
|
||||
u8 lane = (dp->stat[i >> 1] >> ((i & 1) * 4)) & 0xf;
|
||||
if (!(lane & DPCD_LS02_LANE0_CR_DONE)) {
|
||||
cr_done = false;
|
||||
if (dp->conf[i] & DPCD_LC03_MAX_SWING_REACHED)
|
||||
abort = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ((dp->conf[0] & DPCD_LC03_VOLTAGE_SWING_SET) != voltage) {
|
||||
voltage = dp->conf[0] & DPCD_LC03_VOLTAGE_SWING_SET;
|
||||
tries = 0;
|
||||
}
|
||||
} while (!cr_done && !abort && ++tries < 5);
|
||||
|
||||
return cr_done ? 0 : -1;
|
||||
}
|
||||
|
||||
static int
|
||||
dp_link_train_eq(struct dp_state *dp)
|
||||
{
|
||||
bool eq_done, cr_done = true;
|
||||
int tries = 0, i;
|
||||
|
||||
dp_set_training_pattern(dp, 2);
|
||||
|
||||
do {
|
||||
if (dp_link_train_update(dp, 400))
|
||||
break;
|
||||
|
||||
eq_done = !!(dp->stat[2] & DPCD_LS04_INTERLANE_ALIGN_DONE);
|
||||
for (i = 0; i < dp->link_nr && eq_done; i++) {
|
||||
u8 lane = (dp->stat[i >> 1] >> ((i & 1) * 4)) & 0xf;
|
||||
if (!(lane & DPCD_LS02_LANE0_CR_DONE))
|
||||
cr_done = false;
|
||||
if (!(lane & DPCD_LS02_LANE0_CHANNEL_EQ_DONE) ||
|
||||
!(lane & DPCD_LS02_LANE0_SYMBOL_LOCKED))
|
||||
eq_done = false;
|
||||
}
|
||||
|
||||
if (dp_link_train_commit(dp))
|
||||
break;
|
||||
} while (!eq_done && cr_done && ++tries <= 5);
|
||||
|
||||
return eq_done ? 0 : -1;
|
||||
}
|
||||
|
||||
static void
|
||||
dp_link_train_init(struct dp_state *dp, bool spread)
|
||||
{
|
||||
struct nvbios_init init = {
|
||||
.subdev = nv_subdev(dp->disp),
|
||||
.bios = nouveau_bios(dp->disp),
|
||||
.outp = dp->outp,
|
||||
.crtc = dp->head,
|
||||
.execute = 1,
|
||||
};
|
||||
|
||||
/* set desired spread */
|
||||
if (spread)
|
||||
init.offset = dp->info.script[2];
|
||||
else
|
||||
init.offset = dp->info.script[3];
|
||||
nvbios_exec(&init);
|
||||
|
||||
/* pre-train script */
|
||||
init.offset = dp->info.script[0];
|
||||
nvbios_exec(&init);
|
||||
}
|
||||
|
||||
static void
|
||||
dp_link_train_fini(struct dp_state *dp)
|
||||
{
|
||||
struct nvbios_init init = {
|
||||
.subdev = nv_subdev(dp->disp),
|
||||
.bios = nouveau_bios(dp->disp),
|
||||
.outp = dp->outp,
|
||||
.crtc = dp->head,
|
||||
.execute = 1,
|
||||
};
|
||||
|
||||
/* post-train script */
|
||||
init.offset = dp->info.script[1],
|
||||
nvbios_exec(&init);
|
||||
}
|
||||
|
||||
int
|
||||
nouveau_dp_train(struct nouveau_disp *disp, const struct nouveau_dp_func *func,
|
||||
struct dcb_output *outp, int head, u32 datarate)
|
||||
{
|
||||
struct nouveau_bios *bios = nouveau_bios(disp);
|
||||
struct nouveau_i2c *i2c = nouveau_i2c(disp);
|
||||
struct dp_state _dp = {
|
||||
.disp = disp,
|
||||
.func = func,
|
||||
.outp = outp,
|
||||
.head = head,
|
||||
}, *dp = &_dp;
|
||||
const u32 bw_list[] = { 270000, 162000, 0 };
|
||||
const u32 *link_bw = bw_list;
|
||||
u8 hdr, cnt, len;
|
||||
u32 data;
|
||||
int ret;
|
||||
|
||||
/* find the bios displayport data relevant to this output */
|
||||
data = nvbios_dpout_match(bios, outp->hasht, outp->hashm, &dp->version,
|
||||
&hdr, &cnt, &len, &dp->info);
|
||||
if (!data) {
|
||||
ERR("bios data not found\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* acquire the aux channel and fetch some info about the display */
|
||||
if (outp->location)
|
||||
dp->aux = i2c->find_type(i2c, NV_I2C_TYPE_EXTAUX(outp->extdev));
|
||||
else
|
||||
dp->aux = i2c->find(i2c, NV_I2C_TYPE_DCBI2C(outp->i2c_index));
|
||||
if (!dp->aux) {
|
||||
ERR("no aux channel?!\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
ret = nv_rdaux(dp->aux, 0x00000, dp->dpcd, sizeof(dp->dpcd));
|
||||
if (ret) {
|
||||
ERR("failed to read DPCD\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* adjust required bandwidth for 8B/10B coding overhead */
|
||||
datarate = (datarate / 8) * 10;
|
||||
|
||||
/* enable down-spreading and execute pre-train script from vbios */
|
||||
dp_link_train_init(dp, dp->dpcd[3] & 0x01);
|
||||
|
||||
/* start off at highest link rate supported by encoder and display */
|
||||
while (*link_bw > (dp->dpcd[1] * 27000))
|
||||
link_bw++;
|
||||
|
||||
while (link_bw[0]) {
|
||||
/* find minimum required lane count at this link rate */
|
||||
dp->link_nr = dp->dpcd[2] & DPCD_RC02_MAX_LANE_COUNT;
|
||||
while ((dp->link_nr >> 1) * link_bw[0] > datarate)
|
||||
dp->link_nr >>= 1;
|
||||
|
||||
/* drop link rate to minimum with this lane count */
|
||||
while ((link_bw[1] * dp->link_nr) > datarate)
|
||||
link_bw++;
|
||||
dp->link_bw = link_bw[0];
|
||||
|
||||
/* program selected link configuration */
|
||||
ret = dp_set_link_config(dp);
|
||||
if (ret == 0) {
|
||||
/* attempt to train the link at this configuration */
|
||||
memset(dp->stat, 0x00, sizeof(dp->stat));
|
||||
if (!dp_link_train_cr(dp) &&
|
||||
!dp_link_train_eq(dp))
|
||||
break;
|
||||
} else
|
||||
if (ret >= 1) {
|
||||
/* dp_set_link_config() handled training */
|
||||
break;
|
||||
}
|
||||
|
||||
/* retry at lower rate */
|
||||
link_bw++;
|
||||
}
|
||||
|
||||
/* finish link training */
|
||||
dp_set_training_pattern(dp, 0);
|
||||
|
||||
/* execute post-train script from vbios */
|
||||
dp_link_train_fini(dp);
|
||||
return true;
|
||||
}
|
78
drivers/gpu/drm/nouveau/core/engine/disp/dport.h
Normal file
78
drivers/gpu/drm/nouveau/core/engine/disp/dport.h
Normal file
@ -0,0 +1,78 @@
|
||||
#ifndef __NVKM_DISP_DPORT_H__
|
||||
#define __NVKM_DISP_DPORT_H__
|
||||
|
||||
/* DPCD Receiver Capabilities */
|
||||
#define DPCD_RC00 0x00000
|
||||
#define DPCD_RC00_DPCD_REV 0xff
|
||||
#define DPCD_RC01 0x00001
|
||||
#define DPCD_RC01_MAX_LINK_RATE 0xff
|
||||
#define DPCD_RC02 0x00002
|
||||
#define DPCD_RC02_ENHANCED_FRAME_CAP 0x80
|
||||
#define DPCD_RC02_MAX_LANE_COUNT 0x1f
|
||||
#define DPCD_RC03 0x00003
|
||||
#define DPCD_RC03_MAX_DOWNSPREAD 0x01
|
||||
|
||||
/* DPCD Link Configuration */
|
||||
#define DPCD_LC00 0x00100
|
||||
#define DPCD_LC00_LINK_BW_SET 0xff
|
||||
#define DPCD_LC01 0x00101
|
||||
#define DPCD_LC01_ENHANCED_FRAME_EN 0x80
|
||||
#define DPCD_LC01_LANE_COUNT_SET 0x1f
|
||||
#define DPCD_LC02 0x00102
|
||||
#define DPCD_LC02_TRAINING_PATTERN_SET 0x03
|
||||
#define DPCD_LC03(l) ((l) + 0x00103)
|
||||
#define DPCD_LC03_MAX_PRE_EMPHASIS_REACHED 0x20
|
||||
#define DPCD_LC03_PRE_EMPHASIS_SET 0x18
|
||||
#define DPCD_LC03_MAX_SWING_REACHED 0x04
|
||||
#define DPCD_LC03_VOLTAGE_SWING_SET 0x03
|
||||
|
||||
/* DPCD Link/Sink Status */
|
||||
#define DPCD_LS02 0x00202
|
||||
#define DPCD_LS02_LANE1_SYMBOL_LOCKED 0x40
|
||||
#define DPCD_LS02_LANE1_CHANNEL_EQ_DONE 0x20
|
||||
#define DPCD_LS02_LANE1_CR_DONE 0x10
|
||||
#define DPCD_LS02_LANE0_SYMBOL_LOCKED 0x04
|
||||
#define DPCD_LS02_LANE0_CHANNEL_EQ_DONE 0x02
|
||||
#define DPCD_LS02_LANE0_CR_DONE 0x01
|
||||
#define DPCD_LS03 0x00203
|
||||
#define DPCD_LS03_LANE3_SYMBOL_LOCKED 0x40
|
||||
#define DPCD_LS03_LANE3_CHANNEL_EQ_DONE 0x20
|
||||
#define DPCD_LS03_LANE3_CR_DONE 0x10
|
||||
#define DPCD_LS03_LANE2_SYMBOL_LOCKED 0x04
|
||||
#define DPCD_LS03_LANE2_CHANNEL_EQ_DONE 0x02
|
||||
#define DPCD_LS03_LANE2_CR_DONE 0x01
|
||||
#define DPCD_LS04 0x00204
|
||||
#define DPCD_LS04_LINK_STATUS_UPDATED 0x80
|
||||
#define DPCD_LS04_DOWNSTREAM_PORT_STATUS_CHANGED 0x40
|
||||
#define DPCD_LS04_INTERLANE_ALIGN_DONE 0x01
|
||||
#define DPCD_LS06 0x00206
|
||||
#define DPCD_LS06_LANE1_PRE_EMPHASIS 0xc0
|
||||
#define DPCD_LS06_LANE1_VOLTAGE_SWING 0x30
|
||||
#define DPCD_LS06_LANE0_PRE_EMPHASIS 0x0c
|
||||
#define DPCD_LS06_LANE0_VOLTAGE_SWING 0x03
|
||||
#define DPCD_LS07 0x00207
|
||||
#define DPCD_LS07_LANE3_PRE_EMPHASIS 0xc0
|
||||
#define DPCD_LS07_LANE3_VOLTAGE_SWING 0x30
|
||||
#define DPCD_LS07_LANE2_PRE_EMPHASIS 0x0c
|
||||
#define DPCD_LS07_LANE2_VOLTAGE_SWING 0x03
|
||||
|
||||
struct nouveau_disp;
|
||||
struct dcb_output;
|
||||
|
||||
struct nouveau_dp_func {
|
||||
int (*pattern)(struct nouveau_disp *, struct dcb_output *,
|
||||
int head, int pattern);
|
||||
int (*lnk_ctl)(struct nouveau_disp *, struct dcb_output *, int head,
|
||||
int link_nr, int link_bw, bool enh_frame);
|
||||
int (*drv_ctl)(struct nouveau_disp *, struct dcb_output *, int head,
|
||||
int lane, int swing, int preem);
|
||||
};
|
||||
|
||||
extern const struct nouveau_dp_func nv94_sor_dp_func;
|
||||
extern const struct nouveau_dp_func nvd0_sor_dp_func;
|
||||
extern const struct nouveau_dp_func nv50_pior_dp_func;
|
||||
|
||||
int nouveau_dp_train(struct nouveau_disp *, const struct nouveau_dp_func *,
|
||||
struct dcb_output *, int, u32);
|
||||
|
||||
#endif
|
@ -24,21 +24,33 @@
|
||||
|
||||
#include <engine/disp.h>
|
||||
|
||||
#include <core/event.h>
|
||||
#include <core/class.h>
|
||||
|
||||
struct nv04_disp_priv {
|
||||
struct nouveau_disp base;
|
||||
};
|
||||
|
||||
static struct nouveau_oclass
|
||||
nv04_disp_sclass[] = {
|
||||
{ NV04_DISP_CLASS, &nouveau_object_ofuncs },
|
||||
{},
|
||||
};
|
||||
|
||||
/*******************************************************************************
|
||||
* Display engine implementation
|
||||
******************************************************************************/
|
||||
|
||||
static void
|
||||
nv04_disp_intr_vblank(struct nv04_disp_priv *priv, int crtc)
|
||||
nv04_disp_vblank_enable(struct nouveau_event *event, int head)
|
||||
{
|
||||
struct nouveau_disp *disp = &priv->base;
|
||||
if (disp->vblank.notify)
|
||||
disp->vblank.notify(disp->vblank.data, crtc);
|
||||
nv_wr32(event->priv, 0x600140 + (head * 0x2000) , 0x00000001);
|
||||
}
|
||||
|
||||
static void
|
||||
nv04_disp_vblank_disable(struct nouveau_event *event, int head)
|
||||
{
|
||||
nv_wr32(event->priv, 0x600140 + (head * 0x2000) , 0x00000000);
|
||||
}
|
||||
|
||||
static void
|
||||
@ -49,25 +61,25 @@ nv04_disp_intr(struct nouveau_subdev *subdev)
|
||||
u32 crtc1 = nv_rd32(priv, 0x602100);
|
||||
|
||||
if (crtc0 & 0x00000001) {
|
||||
nv04_disp_intr_vblank(priv, 0);
|
||||
nouveau_event_trigger(priv->base.vblank, 0);
|
||||
nv_wr32(priv, 0x600100, 0x00000001);
|
||||
}
|
||||
|
||||
if (crtc1 & 0x00000001) {
|
||||
nv04_disp_intr_vblank(priv, 1);
|
||||
nouveau_event_trigger(priv->base.vblank, 1);
|
||||
nv_wr32(priv, 0x602100, 0x00000001);
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
nv04_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
|
||||
struct nouveau_oclass *oclass, void *data, u32 size,
|
||||
struct nouveau_object **pobject)
|
||||
struct nouveau_oclass *oclass, void *data, u32 size,
|
||||
struct nouveau_object **pobject)
|
||||
{
|
||||
struct nv04_disp_priv *priv;
|
||||
int ret;
|
||||
|
||||
ret = nouveau_disp_create(parent, engine, oclass, "DISPLAY",
|
||||
ret = nouveau_disp_create(parent, engine, oclass, 2, "DISPLAY",
|
||||
"display", &priv);
|
||||
*pobject = nv_object(priv);
|
||||
if (ret)
|
||||
@ -75,6 +87,9 @@ nv04_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
|
||||
|
||||
nv_engine(priv)->sclass = nv04_disp_sclass;
|
||||
nv_subdev(priv)->intr = nv04_disp_intr;
|
||||
priv->base.vblank->priv = priv;
|
||||
priv->base.vblank->enable = nv04_disp_vblank_enable;
|
||||
priv->base.vblank->disable = nv04_disp_vblank_disable;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user