Commit e9f37d3a authored by Linus Torvalds's avatar Linus Torvalds

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

Pull drm updates from Dave Airlie:
 "Highlights:

   - drm:

     Generic display port aux features, primary plane support, drm
     master management fixes, logging cleanups, enforced locking checks
     (instead of docs), documentation improvements, minor number
     handling cleanup, pseudofs for shared inodes.

   - ttm:

     add ability to allocate from both ends

   - i915:

     broadwell features, power domain and runtime pm, per-process
     address space infrastructure (not enabled)

   - msm:

     power management, hdmi audio support

   - nouveau:

     ongoing GPU fault recovery, initial maxwell support, random fixes

   - exynos:

     refactored driver to clean up a lot of abstraction, DP support
     moved into drm, LVDS bridge support added, parallel panel support

   - gma500:

     SGX MMU support, SGX irq handling, asle irq work fixes

   - radeon:

     video engine bringup, ring handling fixes, use dp aux helpers

   - vmwgfx:

     add rendernode support"

* 'drm-next' of git://people.freedesktop.org/~airlied/linux: (849 commits)
  DRM: armada: fix corruption while loading cursors
  drm/dp_helper: don't return EPROTO for defers (v2)
  drm/bridge: export ptn3460_init function
  drm/exynos: remove MODULE_DEVICE_TABLE definitions
  ARM: dts: exynos4412-trats2: enable exynos/fimd node
  ARM: dts: exynos4210-trats: enable exynos/fimd node
  ARM: dts: exynos4412-trats2: add panel node
  ARM: dts: exynos4210-trats: add panel node
  ARM: dts: exynos4: add MIPI DSI Master node
  drm/panel: add S6E8AA0 driver
  ARM: dts: exynos4210-universal_c210: add proper panel node
  drm/panel: add ld9040 driver
  panel/ld9040: add DT bindings
  panel/s6e8aa0: add DT bindings
  drm/exynos: add DSIM driver
  exynos/dsim: add DT bindings
  drm/exynos: disallow fbdev initialization if no device is connected
  drm/mipi_dsi: create dsi devices only for nodes with reg property
  drm/mipi_dsi: add flags to DSI messages
  Skip intel_crt_init for Dell XPS 8700
  ...
parents 5fb6b953 c39b0695
This diff is collapsed.
ptn3460 bridge bindings
Required properties:
- compatible: "nxp,ptn3460"
- reg: i2c address of the bridge
- powerdown-gpio: OF device-tree gpio specification
- reset-gpio: OF device-tree gpio specification
- edid-emulation: The EDID emulation entry to use
+-------+------------+------------------+
| Value | Resolution | Description |
| 0 | 1024x768 | NXP Generic |
| 1 | 1920x1080 | NXP Generic |
| 2 | 1920x1080 | NXP Generic |
| 3 | 1600x900 | Samsung LTM200KT |
| 4 | 1920x1080 | Samsung LTM230HT |
| 5 | 1366x768 | NXP Generic |
| 6 | 1600x900 | ChiMei M215HGE |
+-------+------------+------------------+
Example:
lvds-bridge@20 {
compatible = "nxp,ptn3460";
reg = <0x20>;
powerdown-gpio = <&gpy2 5 1 0 0>;
reset-gpio = <&gpx1 5 1 0 0>;
edid-emulation = <5>;
};
Device-Tree bindings for the NXP TDA998x HDMI transmitter
Required properties;
- compatible: must be "nxp,tda998x"
Optional properties:
- interrupts: interrupt number and trigger type
default: polling
- pinctrl-0: pin control group to be used for
screen plug/unplug interrupt.
- pinctrl-names: must contain a "default" entry.
- video-ports: 24 bits value which defines how the video controller
output is wired to the TDA998x input - default: <0x230145>
Example:
tda998x: hdmi-encoder {
compatible = "nxp,tda998x";
reg = <0x70>;
interrupt-parent = <&gpio0>;
interrupts = <27 2>; /* falling edge */
pinctrl-0 = <&pmx_camera>;
pinctrl-names = "default";
};
......@@ -190,6 +190,48 @@ of the following host1x client modules:
- nvidia,edid: supplies a binary EDID blob
- nvidia,panel: phandle of a display panel
- sor: serial output resource
Required properties:
- compatible: "nvidia,tegra124-sor"
- reg: Physical base address and length of the controller's registers.
- interrupts: The interrupt outputs from the controller.
- clocks: Must contain an entry for each entry in clock-names.
See ../clocks/clock-bindings.txt for details.
- clock-names: Must include the following entries:
- sor: clock input for the SOR hardware
- parent: input for the pixel clock
- dp: reference clock for the SOR clock
- safe: safe reference for the SOR clock during power up
- resets: Must contain an entry for each entry in reset-names.
See ../reset/reset.txt for details.
- reset-names: Must include the following entries:
- sor
Optional properties:
- nvidia,ddc-i2c-bus: phandle of an I2C controller used for DDC EDID probing
- nvidia,hpd-gpio: specifies a GPIO used for hotplug detection
- nvidia,edid: supplies a binary EDID blob
- nvidia,panel: phandle of a display panel
Optional properties when driving an eDP output:
- nvidia,dpaux: phandle to a DispayPort AUX interface
- dpaux: DisplayPort AUX interface
- compatible: "nvidia,tegra124-dpaux"
- reg: Physical base address and length of the controller's registers.
- interrupts: The interrupt outputs from the controller.
- clocks: Must contain an entry for each entry in clock-names.
See ../clocks/clock-bindings.txt for details.
- clock-names: Must include the following entries:
- dpaux: clock input for the DPAUX hardware
- parent: reference clock
- resets: Must contain an entry for each entry in reset-names.
See ../reset/reset.txt for details.
- reset-names: Must include the following entries:
- dpaux
- vdd-supply: phandle of a supply that powers the DisplayPort link
Example:
/ {
......
LG Corporation 7" WXGA TFT LCD panel
Required properties:
- compatible: should be "lg,ld070wx3-sl01"
This binding is compatible with the simple-panel binding, which is specified
in simple-panel.txt in this directory.
LG Corporation 5" HD TFT LCD panel
Required properties:
- compatible: should be "lg,lh500wx1-sd03"
This binding is compatible with the simple-panel binding, which is specified
in simple-panel.txt in this directory.
LG 12.9" (2560x1700 pixels) TFT LCD panel
Required properties:
- compatible: should be "lg,lp129qe"
This binding is compatible with the simple-panel binding, which is specified
in simple-panel.txt in this directory.
Samsung LD9040 AMOLED LCD parallel RGB panel with SPI control bus
Required properties:
- compatible: "samsung,ld9040"
- reg: address of the panel on SPI bus
- vdd3-supply: core voltage supply
- vci-supply: voltage supply for analog circuits
- reset-gpios: a GPIO spec for the reset pin
- display-timings: timings for the connected panel according to [1]
The panel must obey rules for SPI slave device specified in document [2].
Optional properties:
- power-on-delay: delay after turning regulators on [ms]
- reset-delay: delay after reset sequence [ms]
- panel-width-mm: physical panel width [mm]
- panel-height-mm: physical panel height [mm]
The device node can contain one 'port' child node with one child
'endpoint' node, according to the bindings defined in [3]. This
node should describe panel's video bus.
[1]: Documentation/devicetree/bindings/video/display-timing.txt
[2]: Documentation/devicetree/bindings/spi/spi-bus.txt
[3]: Documentation/devicetree/bindings/media/video-interfaces.txt
Example:
lcd@0 {
compatible = "samsung,ld9040";
reg = <0>;
vdd3-supply = <&ldo7_reg>;
vci-supply = <&ldo17_reg>;
reset-gpios = <&gpy4 5 0>;
spi-max-frequency = <1200000>;
spi-cpol;
spi-cpha;
power-on-delay = <10>;
reset-delay = <10>;
panel-width-mm = <90>;
panel-height-mm = <154>;
display-timings {
timing {
clock-frequency = <23492370>;
hactive = <480>;
vactive = <800>;
hback-porch = <16>;
hfront-porch = <16>;
vback-porch = <2>;
vfront-porch = <28>;
hsync-len = <2>;
vsync-len = <1>;
hsync-active = <0>;
vsync-active = <0>;
de-active = <0>;
pixelclk-active = <0>;
};
};
port {
lcd_ep: endpoint {
remote-endpoint = <&fimd_dpi_ep>;
};
};
};
Samsung S6E8AA0 AMOLED LCD 5.3 inch panel
Required properties:
- compatible: "samsung,s6e8aa0"
- reg: the virtual channel number of a DSI peripheral
- vdd3-supply: core voltage supply
- vci-supply: voltage supply for analog circuits
- reset-gpios: a GPIO spec for the reset pin
- display-timings: timings for the connected panel as described by [1]
Optional properties:
- power-on-delay: delay after turning regulators on [ms]
- reset-delay: delay after reset sequence [ms]
- init-delay: delay after initialization sequence [ms]
- panel-width-mm: physical panel width [mm]
- panel-height-mm: physical panel height [mm]
- flip-horizontal: boolean to flip image horizontally
- flip-vertical: boolean to flip image vertically
The device node can contain one 'port' child node with one child
'endpoint' node, according to the bindings defined in [2]. This
node should describe panel's video bus.
[1]: Documentation/devicetree/bindings/video/display-timing.txt
[2]: Documentation/devicetree/bindings/media/video-interfaces.txt
Example:
panel {
compatible = "samsung,s6e8aa0";
reg = <0>;
vdd3-supply = <&vcclcd_reg>;
vci-supply = <&vlcd_reg>;
reset-gpios = <&gpy4 5 0>;
power-on-delay= <50>;
reset-delay = <100>;
init-delay = <100>;
panel-width-mm = <58>;
panel-height-mm = <103>;
flip-horizontal;
flip-vertical;
display-timings {
timing0: timing-0 {
clock-frequency = <57153600>;
hactive = <720>;
vactive = <1280>;
hfront-porch = <5>;
hback-porch = <5>;
hsync-len = <5>;
vfront-porch = <13>;
vback-porch = <1>;
vsync-len = <2>;
};
};
};
......@@ -49,6 +49,8 @@ Required properties for dp-controller:
-samsung,lane-count:
number of lanes supported by the panel.
LANE_COUNT1 = 1, LANE_COUNT2 = 2, LANE_COUNT4 = 4
- display-timings: timings for the connected panel as described by
Documentation/devicetree/bindings/video/display-timing.txt
Optional properties for dp-controller:
-interlaced:
......@@ -84,4 +86,19 @@ Board Specific portion:
samsung,color-depth = <1>;
samsung,link-rate = <0x0a>;
samsung,lane-count = <4>;
display-timings {
native-mode = <&lcd_timing>;
lcd_timing: 1366x768 {
clock-frequency = <70589280>;
hactive = <1366>;
vactive = <768>;
hfront-porch = <40>;
hback-porch = <40>;
hsync-len = <32>;
vback-porch = <10>;
vfront-porch = <12>;
vsync-len = <6>;
};
};
};
Exynos MIPI DSI Master
Required properties:
- compatible: "samsung,exynos4210-mipi-dsi"
- reg: physical base address and length of the registers set for the device
- interrupts: should contain DSI interrupt
- clocks: list of clock specifiers, must contain an entry for each required
entry in clock-names
- clock-names: should include "bus_clk"and "pll_clk" entries
- phys: list of phy specifiers, must contain an entry for each required
entry in phy-names
- phy-names: should include "dsim" entry
- vddcore-supply: MIPI DSIM Core voltage supply (e.g. 1.1V)
- vddio-supply: MIPI DSIM I/O and PLL voltage supply (e.g. 1.8V)
- samsung,pll-clock-frequency: specifies frequency of the "pll_clk" clock
- #address-cells, #size-cells: should be set respectively to <1> and <0>
according to DSI host bindings (see MIPI DSI bindings [1])
Optional properties:
- samsung,power-domain: a phandle to DSIM power domain node
Child nodes:
Should contain DSI peripheral nodes (see MIPI DSI bindings [1]).
Video interfaces:
Device node can contain video interface port nodes according to [2].
The following are properties specific to those nodes:
port node:
- reg: (required) can be 0 for input RGB/I80 port or 1 for DSI port;
endpoint node of DSI port (reg = 1):
- samsung,burst-clock-frequency: specifies DSI frequency in high-speed burst
mode
- samsung,esc-clock-frequency: specifies DSI frequency in escape mode
[1]: Documentation/devicetree/bindings/mipi/dsi/mipi-dsi-bus.txt
[2]: Documentation/devicetree/bindings/media/video-interfaces.txt
Example:
dsi@11C80000 {
compatible = "samsung,exynos4210-mipi-dsi";
reg = <0x11C80000 0x10000>;
interrupts = <0 79 0>;
clocks = <&clock 286>, <&clock 143>;
clock-names = "bus_clk", "pll_clk";
phys = <&mipi_phy 1>;
phy-names = "dsim";
vddcore-supply = <&vusb_reg>;
vddio-supply = <&vmipi_reg>;
samsung,power-domain = <&pd_lcd0>;
#address-cells = <1>;
#size-cells = <0>;
samsung,pll-clock-frequency = <24000000>;
panel@1 {
reg = <0>;
...
port {
panel_ep: endpoint {
remote-endpoint = <&dsi_ep>;
};
};
};
ports {
#address-cells = <1>;
#size-cells = <0>;
port@1 {
dsi_ep: endpoint {
reg = <0>;
samsung,burst-clock-frequency = <500000000>;
samsung,esc-clock-frequency = <20000000>;
remote-endpoint = <&panel_ep>;
};
};
};
};
......@@ -25,6 +25,9 @@ Required properties:
sclk_pixel.
- clock-names: aliases as per driver requirements for above clock IDs:
"hdmi", "sclk_hdmi", "sclk_pixel", "sclk_hdmiphy" and "mout_hdmi".
- ddc: phandle to the hdmi ddc node
- phy: phandle to the hdmi phy node
Example:
hdmi {
......@@ -32,4 +35,6 @@ Example:
reg = <0x14530000 0x100000>;
interrupts = <0 95 0>;
hpd-gpio = <&gpx3 7 1>;
ddc = <&hdmi_ddc_node>;
phy = <&hdmi_phy_node>;
};
......@@ -39,6 +39,23 @@ Required properties:
Optional Properties:
- samsung,power-domain: a phandle to FIMD power domain node.
- samsung,invert-vden: video enable signal is inverted
- samsung,invert-vclk: video clock signal is inverted
- display-timings: timing settings for FIMD, as described in document [1].
Can be used in case timings cannot be provided otherwise
or to override timings provided by the panel.
The device node can contain 'port' child nodes according to the bindings defined
in [2]. The following are properties specific to those nodes:
- reg: (required) port index, can be:
0 - for CAMIF0 input,
1 - for CAMIF1 input,
2 - for CAMIF2 input,
3 - for parallel output,
4 - for write-back interface
[1]: Documentation/devicetree/bindings/video/display-timing.txt
[2]: Documentation/devicetree/bindings/media/video-interfaces.txt
Example:
......
......@@ -2945,6 +2945,16 @@ F: drivers/gpu/drm/radeon/
F: include/drm/radeon*
F: include/uapi/drm/radeon*
DRM PANEL DRIVERS
M: Thierry Reding <thierry.reding@gmail.com>
L: dri-devel@lists.freedesktop.org
T: git git://anongit.freedesktop.org/tegra/linux.git
S: Maintained
F: drivers/gpu/drm/drm_panel.c
F: drivers/gpu/drm/panel/
F: include/drm/drm_panel.h
F: Documentation/devicetree/bindings/panel/
INTEL DRM DRIVERS (excluding Poulsbo, Moorestown and derivative chipsets)
M: Daniel Vetter <daniel.vetter@ffwll.ch>
M: Jani Nikula <jani.nikula@linux.intel.com>
......@@ -3474,12 +3484,6 @@ S: Maintained
F: drivers/extcon/
F: Documentation/extcon/
EXYNOS DP DRIVER
M: Jingoo Han <jg1.han@samsung.com>
L: linux-fbdev@vger.kernel.org
S: Maintained
F: drivers/video/exynos/exynos_dp*
EXYNOS MIPI DISPLAY DRIVERS
M: Inki Dae <inki.dae@samsung.com>
M: Donghwa Lee <dh09.lee@samsung.com>
......
......@@ -110,6 +110,20 @@ sys_reg: syscon@10010000 {
reg = <0x10010000 0x400>;
};
dsi_0: dsi@11C80000 {
compatible = "samsung,exynos4210-mipi-dsi";
reg = <0x11C80000 0x10000>;
interrupts = <0 79 0>;
samsung,power-domain = <&pd_lcd0>;
phys = <&mipi_phy 1>;
phy-names = "dsim";
clocks = <&clock 286>, <&clock 143>;
clock-names = "bus_clk", "pll_clk";
status = "disabled";
#address-cells = <1>;
#size-cells = <0>;
};
camera {
compatible = "samsung,fimc", "simple-bus";
status = "disabled";
......
......@@ -353,6 +353,67 @@ xusbxti {
};
};
dsi_0: dsi@11C80000 {
vddcore-supply = <&vusb_reg>;
vddio-supply = <&vmipi_reg>;
samsung,pll-clock-frequency = <24000000>;
status = "okay";
ports {
#address-cells = <1>;
#size-cells = <0>;
port@1 {
reg = <1>;
dsi_out: endpoint {
remote-endpoint = <&dsi_in>;
samsung,burst-clock-frequency = <500000000>;
samsung,esc-clock-frequency = <20000000>;
};
};
};
panel@0 {
reg = <0>;
compatible = "samsung,s6e8aa0";
vdd3-supply = <&vcclcd_reg>;
vci-supply = <&vlcd_reg>;
reset-gpios = <&gpy4 5 0>;
power-on-delay= <50>;
reset-delay = <100>;
init-delay = <100>;
flip-horizontal;
flip-vertical;
panel-width-mm = <58>;
panel-height-mm = <103>;
display-timings {
timing-0 {
clock-frequency = <57153600>;
hactive = <720>;
vactive = <1280>;
hfront-porch = <5>;
hback-porch = <5>;
hsync-len = <5>;
vfront-porch = <13>;
vback-porch = <1>;
vsync-len = <2>;
};
};
port {
dsi_in: endpoint {
remote-endpoint = <&dsi_out>;
};
};
};
};
fimd@11c00000 {
status = "okay";
};
camera {
pinctrl-names = "default";
pinctrl-0 = <>;
......
......@@ -345,6 +345,70 @@ safeout2_reg: ESAFEOUT2 {
};
};
spi-lcd {
compatible = "spi-gpio";
#address-cells = <1>;
#size-cells = <0>;
gpio-sck = <&gpy3 1 0>;
gpio-mosi = <&gpy3 3 0>;
num-chipselects = <1>;
cs-gpios = <&gpy4 3 0>;
lcd@0 {
compatible = "samsung,ld9040";
reg = <0>;
vdd3-supply = <&ldo7_reg>;
vci-supply = <&ldo17_reg>;
reset-gpios = <&gpy4 5 0>;
spi-max-frequency = <1200000>;
spi-cpol;
spi-cpha;
power-on-delay = <10>;
reset-delay = <10>;
panel-width-mm = <90>;
panel-height-mm = <154>;
display-timings {
timing {
clock-frequency = <23492370>;
hactive = <480>;
vactive = <800>;
hback-porch = <16>;
hfront-porch = <16>;
vback-porch = <2>;
vfront-porch = <28>;
hsync-len = <2>;
vsync-len = <1>;
hsync-active = <0>;
vsync-active = <0>;
de-active = <0>;
pixelclk-active = <0>;
};
};
port {
lcd_ep: endpoint {
remote-endpoint = <&fimd_dpi_ep>;
};
};
};
};
fimd: fimd@11c00000 {
pinctrl-0 = <&lcd_clk>, <&lcd_data24>;
pinctrl-names = "default";
status = "okay";
samsung,invert-vden;
samsung,invert-vclk;
#address-cells = <1>;
#size-cells = <0>;
port@3 {
reg = <3>;
fimd_dpi_ep: endpoint {
remote-endpoint = <&lcd_ep>;
};
};
};
pwm@139D0000 {
compatible = "samsung,s5p6440-pwm";
status = "okay";
......
......@@ -71,6 +71,15 @@ cam_io_reg: voltage-regulator-1 {
enable-active-high;
};
lcd_vdd3_reg: voltage-regulator-2 {
compatible = "regulator-fixed";
regulator-name = "LCD_VDD_2.2V";
regulator-min-microvolt = <2200000>;
regulator-max-microvolt = <2200000>;
gpio = <&gpc0 1 0>;
enable-active-high;
};
/* More to come */
};
......@@ -516,6 +525,67 @@ controller-data {
};
};
dsi_0: dsi@11C80000 {
vddcore-supply = <&ldo8_reg>;
vddio-supply = <&ldo10_reg>;
samsung,pll-clock-frequency = <24000000>;
status = "okay";
ports {
#address-cells = <1>;
#size-cells = <0>;
port@1 {
reg = <1>;
dsi_out: endpoint {
remote-endpoint = <&dsi_in>;
samsung,burst-clock-frequency = <500000000>;
samsung,esc-clock-frequency = <20000000>;
};
};
};
panel@0 {
compatible = "samsung,s6e8aa0";
reg = <0>;
vdd3-supply = <&lcd_vdd3_reg>;
vci-supply = <&ldo25_reg>;
reset-gpios = <&gpy4 5 0>;
power-on-delay= <50>;
reset-delay = <100>;
init-delay = <100>;
flip-horizontal;
flip-vertical;
panel-width-mm = <58>;
panel-height-mm = <103>;
display-timings {
timing-0 {
clock-frequency = <0>;
hactive = <720>;
vactive = <1280>;
hfront-porch = <5>;
hback-porch = <5>;
hsync-len = <5>;
vfront-porch = <13>;
vback-porch = <1>;
vsync-len = <2>;
};
};
port {
dsi_in: endpoint {
remote-endpoint = <&dsi_out>;
};
};
};
};
fimd@11c00000 {
status = "okay";
};
camera {
pinctrl-0 = <&cam_port_b_clk_active>;
pinctrl-names = "default";
......
......@@ -199,3 +199,5 @@ source "drivers/gpu/drm/msm/Kconfig"
source "drivers/gpu/drm/tegra/Kconfig"
source "drivers/gpu/drm/panel/Kconfig"
source "drivers/gpu/drm/bridge/Kconfig"
......@@ -13,7 +13,8 @@ drm-y := drm_auth.o drm_buffer.o drm_bufs.o drm_cache.o \
drm_crtc.o drm_modes.o drm_edid.o \
drm_info.o drm_debugfs.o drm_encoder_slave.o \
drm_trace_points.o drm_global.o drm_prime.o \
drm_rect.o drm_vma_manager.o drm_flip_work.o
drm_rect.o drm_vma_manager.o drm_flip_work.o \
drm_plane_helper.o
drm-$(CONFIG_COMPAT) += drm_ioc32.o
drm-$(CONFIG_DRM_GEM_CMA_HELPER) += drm_gem_cma_helper.o
......@@ -63,3 +64,4 @@ obj-$(CONFIG_DRM_MSM) += msm/
obj-$(CONFIG_DRM_TEGRA) += tegra/
obj-y += i2c/
obj-y += panel/
obj-y += bridge/
......@@ -478,11 +478,12 @@ static int armada_drm_crtc_mode_set(struct drm_crtc *crtc,
unsigned i;
bool interlaced;
drm_framebuffer_reference(crtc->fb);
drm_framebuffer_reference(crtc->primary->fb);
interlaced = !!(adj->flags & DRM_MODE_FLAG_INTERLACE);
i = armada_drm_crtc_calc_fb(dcrtc->crtc.fb, x, y, regs, interlaced);
i = armada_drm_crtc_calc_fb(dcrtc->crtc.primary->fb,
x, y, regs, interlaced);
rm = adj->crtc_hsync_start - adj->crtc_hdisplay;
lm = adj->crtc_htotal - adj->crtc_hsync_end;
......@@ -567,10 +568,10 @@ static int armada_drm_crtc_mode_set(struct drm_crtc *crtc,
}
val = CFG_GRA_ENA | CFG_GRA_HSMOOTH;
val |= CFG_GRA_FMT(drm_fb_to_armada_fb(dcrtc->crtc.fb)->fmt);
val |= CFG_GRA_MOD(drm_fb_to_armada_fb(dcrtc->crtc.fb)->mod);
val |= CFG_GRA_FMT(drm_fb_to_armada_fb(dcrtc->crtc.primary->fb)->fmt);
val |= CFG_GRA_MOD(drm_fb_to_armada_fb(dcrtc->crtc.primary->fb)->mod);
if (drm_fb_to_armada_fb(dcrtc->crtc.fb)->fmt > CFG_420)
if (drm_fb_to_armada_fb(dcrtc->crtc.primary->fb)->fmt > CFG_420)
val |= CFG_PALETTE_ENA;
if (interlaced)
......@@ -608,7 +609,7 @@ static int armada_drm_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y,
struct armada_regs regs[4];
unsigned i;
i = armada_drm_crtc_calc_fb(crtc->fb, crtc->x, crtc->y, regs,
i = armada_drm_crtc_calc_fb(crtc->primary->fb, crtc->x, crtc->y, regs,
dcrtc->interlaced);
armada_reg_queue_end(regs, i);
......@@ -616,7 +617,7 @@ static int armada_drm_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y,
wait_event(dcrtc->frame_wait, !dcrtc->frame_work);
/* Take a reference to the new fb as we're using it */
drm_framebuffer_reference(crtc->fb);
drm_framebuffer_reference(crtc->primary->fb);
/* Update the base in the CRTC */
armada_drm_crtc_update_regs(dcrtc, regs);
......@@ -637,7 +638,7 @@ static void armada_drm_crtc_disable(struct drm_crtc *crtc)
struct armada_crtc *dcrtc = drm_to_armada_crtc(crtc);
armada_drm_crtc_dpms(crtc, DRM_MODE_DPMS_OFF);
armada_drm_crtc_finish_fb(dcrtc, crtc->fb, true);
armada_drm_crtc_finish_fb(dcrtc, crtc->primary->fb, true);
/* Power down most RAMs and FIFOs */
writel_relaxed(CFG_PDWN256x32 | CFG_PDWN256x24 | CFG_PDWN256x8 |
......@@ -678,6 +679,7 @@ static void armada_load_cursor_argb(void __iomem *base, uint32_t *pix,
base + LCD_SPU_SRAM_WRDAT);
writel_relaxed(addr | SRAM_WRITE,
base + LCD_SPU_SRAM_CTRL);
readl_relaxed(base + LCD_SPU_HWC_OVSA_HPXL_VLN);
addr += 1;
if ((addr & 0x00ff) == 0)
addr += 0xf00;
......@@ -904,7 +906,7 @@ static int armada_drm_crtc_page_flip(struct drm_crtc *crtc,
int ret;
/* We don't support changing the pixel format */
if (fb->pixel_format != crtc->fb->pixel_format)
if (fb->pixel_format != crtc->primary->fb->pixel_format)
return -EINVAL;
work = kmalloc(sizeof(*work), GFP_KERNEL);
......@@ -912,7 +914,7 @@ static int armada_drm_crtc_page_flip(struct drm_crtc *crtc,
return -ENOMEM;
work->event = event;
work->old_fb = dcrtc->crtc.fb;
work->old_fb = dcrtc->crtc.primary->fb;
i = armada_drm_crtc_calc_fb(fb, crtc->x, crtc->y, work->regs,
dcrtc->interlaced);
......@@ -941,7 +943,7 @@ static int armada_drm_crtc_page_flip(struct drm_crtc *crtc,
* will _not_ drop that reference on successful return from this
* function. Simply mark this new framebuffer as the current one.
*/
dcrtc->crtc.fb = fb;
dcrtc->crtc.primary->fb = fb;
/*
* Finally, if the display is blanked, we won't receive an
......
......@@ -81,7 +81,7 @@ static bool ast_get_vbios_mode_info(struct drm_crtc *crtc, struct drm_display_mo
u32 refresh_rate_index = 0, mode_id, color_index, refresh_rate;
u32 hborder, vborder;
switch (crtc->fb->bits_per_pixel) {
switch (crtc->primary->fb->bits_per_pixel) {
case 8:
vbios_mode->std_table = &vbios_stdtable[VGAModeIndex];
color_index = VGAModeIndex - 1;
......@@ -176,7 +176,7 @@ static bool ast_get_vbios_mode_info(struct drm_crtc *crtc, struct drm_display_mo
ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0x8e, mode_id & 0xff);
ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0x91, 0xa8);
ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0x92, crtc->fb->bits_per_pixel);
ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0x92, crtc->primary->fb->bits_per_pixel);
ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0x93, adjusted_mode->clock / 1000);
ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0x94, adjusted_mode->crtc_hdisplay);
ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0x95, adjusted_mode->crtc_hdisplay >> 8);
......@@ -340,7 +340,7 @@ static void ast_set_offset_reg(struct drm_crtc *crtc)
u16 offset;
offset = crtc->fb->pitches[0] >> 3;
offset = crtc->primary->fb->pitches[0] >> 3;
ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0x13, (offset & 0xff));
ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0xb0, (offset >> 8) & 0x3f);
}
......@@ -365,7 +365,7 @@ static void ast_set_ext_reg(struct drm_crtc *crtc, struct drm_display_mode *mode
struct ast_private *ast = crtc->dev->dev_private;
u8 jregA0 = 0, jregA3 = 0, jregA8 = 0;
switch (crtc->fb->bits_per_pixel) {
switch (crtc->primary->fb->bits_per_pixel) {
case 8:
jregA0 = 0x70;
jregA3 = 0x01;
......@@ -418,7 +418,7 @@ static void ast_set_sync_reg(struct drm_device *dev, struct drm_display_mode *mo
static bool ast_set_dac_reg(struct drm_crtc *crtc, struct drm_display_mode *mode,
struct ast_vbios_mode_info *vbios_mode)
{
switch (crtc->fb->bits_per_pixel) {
switch (crtc->primary->fb->bits_per_pixel) {
case 8:
break;
default:
......@@ -490,7 +490,7 @@ static int ast_crtc_do_set_base(struct drm_crtc *crtc,
ast_bo_unreserve(bo);
}
ast_fb = to_ast_framebuffer(crtc->fb);
ast_fb = to_ast_framebuffer(crtc->primary->fb);
obj = ast_fb->obj;
bo = gem_to_ast_bo(obj);
......
......@@ -259,7 +259,9 @@ int ast_mm_init(struct ast_private *ast)
ret = ttm_bo_device_init(&ast->ttm.bdev,
ast->ttm.bo_global_ref.ref.object,
&ast_bo_driver, DRM_FILE_PAGE_OFFSET,
&ast_bo_driver,
dev->anon_inode->i_mapping,
DRM_FILE_PAGE_OFFSET,
true);
if (ret) {
DRM_ERROR("Error initialising bo driver; %d\n", ret);
......@@ -324,7 +326,6 @@ int ast_bo_create(struct drm_device *dev, int size, int align,
}
astbo->bo.bdev = &ast->ttm.bdev;
astbo->bo.bdev->dev_mapping = dev->dev_mapping;
ast_ttm_placement(astbo, TTM_PL_FLAG_VRAM | TTM_PL_FLAG_SYSTEM);
......
......@@ -62,10 +62,10 @@ static int bochs_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y,
}
}
if (WARN_ON(crtc->fb == NULL))
if (WARN_ON(crtc->primary->fb == NULL))
return -EINVAL;
bochs_fb = to_bochs_framebuffer(crtc->fb);
bochs_fb = to_bochs_framebuffer(crtc->primary->fb);
bo = gem_to_bochs_bo(bochs_fb->obj);
ret = ttm_bo_reserve(&bo->bo, true, false, false, 0);
if (ret)
......
......@@ -225,7 +225,9 @@ int bochs_mm_init(struct bochs_device *bochs)
ret = ttm_bo_device_init(&bochs->ttm.bdev,
bochs->ttm.bo_global_ref.ref.object,
&bochs_bo_driver, DRM_FILE_PAGE_OFFSET,
&bochs_bo_driver,
bochs->dev->anon_inode->i_mapping,
DRM_FILE_PAGE_OFFSET,
true);
if (ret) {
DRM_ERROR("Error initialising bo driver; %d\n", ret);
......@@ -359,7 +361,7 @@ static int bochs_bo_create(struct drm_device *dev, int size, int align,
}
bochsbo->bo.bdev = &bochs->ttm.bdev;
bochsbo->bo.bdev->dev_mapping = dev->dev_mapping;
bochsbo->bo.bdev->dev_mapping = dev->anon_inode->i_mapping;
bochs_ttm_placement(bochsbo, TTM_PL_FLAG_VRAM | TTM_PL_FLAG_SYSTEM);
......
config DRM_PTN3460
tristate "PTN3460 DP/LVDS bridge"
depends on DRM
select DRM_KMS_HELPER
---help---
ccflags-y := -Iinclude/drm
obj-$(CONFIG_DRM_PTN3460) += ptn3460.o
/*
* NXP PTN3460 DP/LVDS bridge driver
*
* Copyright (C) 2013 Google, Inc.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
#include <linux/i2c.h>
#include <linux/gpio.h>
#include <linux/delay.h>
#include "drmP.h"
#include "drm_edid.h"
#include "drm_crtc.h"
#include "drm_crtc_helper.h"
#include "bridge/ptn3460.h"
#define PTN3460_EDID_ADDR 0x0
#define PTN3460_EDID_EMULATION_ADDR 0x84
#define PTN3460_EDID_ENABLE_EMULATION 0
#define PTN3460_EDID_EMULATION_SELECTION 1
#define PTN3460_EDID_SRAM_LOAD_ADDR 0x85
struct ptn3460_bridge {
struct drm_connector connector;
struct i2c_client *client;
struct drm_encoder *encoder;
struct drm_bridge *bridge;
struct edid *edid;
int gpio_pd_n;
int gpio_rst_n;
u32 edid_emulation;
bool enabled;
};
static int ptn3460_read_bytes(struct ptn3460_bridge *ptn_bridge, char addr,
u8 *buf, int len)
{
int ret;
ret = i2c_master_send(ptn_bridge->client, &addr, 1);
if (ret <= 0) {
DRM_ERROR("Failed to send i2c command, ret=%d\n", ret);
return ret;
}
ret = i2c_master_recv(ptn_bridge->client, buf, len);
if (ret <= 0) {
DRM_ERROR("Failed to recv i2c data, ret=%d\n", ret);
return ret;
}
return 0;
}
static int ptn3460_write_byte(struct ptn3460_bridge *ptn_bridge, char addr,
char val)
{
int ret;
char buf[2];
buf[0] = addr;
buf[1] = val;
ret = i2c_master_send(ptn_bridge->client, buf, ARRAY_SIZE(buf));
if (ret <= 0) {
DRM_ERROR("Failed to send i2c command, ret=%d\n", ret);
return ret;
}
return 0;
}
static int ptn3460_select_edid(struct ptn3460_bridge *ptn_bridge)
{
int ret;
char val;
/* Load the selected edid into SRAM (accessed at PTN3460_EDID_ADDR) */
ret = ptn3460_write_byte(ptn_bridge, PTN3460_EDID_SRAM_LOAD_ADDR,
ptn_bridge->edid_emulation);
if (ret) {
DRM_ERROR("Failed to transfer edid to sram, ret=%d\n", ret);
return ret;
}
/* Enable EDID emulation and select the desired EDID */
val = 1 << PTN3460_EDID_ENABLE_EMULATION |
ptn_bridge->edid_emulation << PTN3460_EDID_EMULATION_SELECTION;
ret = ptn3460_write_byte(ptn_bridge, PTN3460_EDID_EMULATION_ADDR, val);
if (ret) {
DRM_ERROR("Failed to write edid value, ret=%d\n", ret);
return ret;
}
return 0;
}
static void ptn3460_pre_enable(struct drm_bridge *bridge)
{
struct ptn3460_bridge *ptn_bridge = bridge->driver_private;
int ret;
if (ptn_bridge->enabled)
return;
if (gpio_is_valid(ptn_bridge->gpio_pd_n))
gpio_set_value(ptn_bridge->gpio_pd_n, 1);
if (gpio_is_valid(ptn_bridge->gpio_rst_n)) {
gpio_set_value(ptn_bridge->gpio_rst_n, 0);
udelay(10);
gpio_set_value(ptn_bridge->gpio_rst_n, 1);
}
/*
* There's a bug in the PTN chip where it falsely asserts hotplug before
* it is fully functional. We're forced to wait for the maximum start up
* time specified in the chip's datasheet to make sure we're really up.
*/
msleep(90);
ret = ptn3460_select_edid(ptn_bridge);
if (ret)
DRM_ERROR("Select edid failed ret=%d\n", ret);
ptn_bridge->enabled = true;
}
static void ptn3460_enable(struct drm_bridge *bridge)
{
}
static void ptn3460_disable(struct drm_bridge *bridge)
{
struct ptn3460_bridge *ptn_bridge = bridge->driver_private;
if (!ptn_bridge->enabled)
return;
ptn_bridge->enabled = false;
if (gpio_is_valid(ptn_bridge->gpio_rst_n))
gpio_set_value(ptn_bridge->gpio_rst_n, 1);
if (gpio_is_valid(ptn_bridge->gpio_pd_n))
gpio_set_value(ptn_bridge->gpio_pd_n, 0);
}
static void ptn3460_post_disable(struct drm_bridge *bridge)
{
}
void ptn3460_bridge_destroy(struct drm_bridge *bridge)
{
struct ptn3460_bridge *ptn_bridge = bridge->driver_private;
drm_bridge_cleanup(bridge);
if (gpio_is_valid(ptn_bridge->gpio_pd_n))
gpio_free(ptn_bridge->gpio_pd_n);
if (gpio_is_valid(ptn_bridge->gpio_rst_n))
gpio_free(ptn_bridge->gpio_rst_n);
/* Nothing else to free, we've got devm allocated memory */
}
struct drm_bridge_funcs ptn3460_bridge_funcs = {
.pre_enable = ptn3460_pre_enable,
.enable = ptn3460_enable,
.disable = ptn3460_disable,
.post_disable = ptn3460_post_disable,
.destroy = ptn3460_bridge_destroy,
};
int ptn3460_get_modes(struct drm_connector *connector)
{
struct ptn3460_bridge *ptn_bridge;
u8 *edid;
int ret, num_modes;
bool power_off;
ptn_bridge = container_of(connector, struct ptn3460_bridge, connector);
if (ptn_bridge->edid)
return drm_add_edid_modes(connector, ptn_bridge->edid);
power_off = !ptn_bridge->enabled;
ptn3460_pre_enable(ptn_bridge->bridge);
edid = kmalloc(EDID_LENGTH, GFP_KERNEL);
if (!edid) {
DRM_ERROR("Failed to allocate edid\n");
return 0;
}
ret = ptn3460_read_bytes(ptn_bridge, PTN3460_EDID_ADDR, edid,
EDID_LENGTH);
if (ret) {
kfree(edid);
num_modes = 0;
goto out;
}
ptn_bridge->edid = (struct edid *)edid;
drm_mode_connector_update_edid_property(connector, ptn_bridge->edid);
num_modes = drm_add_edid_modes(connector, ptn_bridge->edid);
out:
if (power_off)
ptn3460_disable(ptn_bridge->bridge);
return num_modes;
}
static int ptn3460_mode_valid(struct drm_connector *connector,
struct drm_display_mode *mode)
{
return MODE_OK;
}
struct drm_encoder *ptn3460_best_encoder(struct drm_connector *connector)
{
struct ptn3460_bridge *ptn_bridge;
ptn_bridge = container_of(connector, struct ptn3460_bridge, connector);
return ptn_bridge->encoder;
}
struct drm_connector_helper_funcs ptn3460_connector_helper_funcs = {
.get_modes = ptn3460_get_modes,
.mode_valid = ptn3460_mode_valid,
.best_encoder = ptn3460_best_encoder,
};
enum drm_connector_status ptn3460_detect(struct drm_connector *connector,
bool force)
{
return connector_status_connected;
}
void ptn3460_connector_destroy(struct drm_connector *connector)
{
drm_connector_cleanup(connector);
}
struct drm_connector_funcs ptn3460_connector_funcs = {
.dpms = drm_helper_connector_dpms,
.fill_modes = drm_helper_probe_single_connector_modes,
.detect = ptn3460_detect,
.destroy = ptn3460_connector_destroy,
};
int ptn3460_init(struct drm_device *dev, struct drm_encoder *encoder,
struct i2c_client *client, struct device_node *node)
{
int ret;
struct drm_bridge *bridge;
struct ptn3460_bridge *ptn_bridge;
bridge = devm_kzalloc(dev->dev, sizeof(*bridge), GFP_KERNEL);
if (!bridge) {
DRM_ERROR("Failed to allocate drm bridge\n");
return -ENOMEM;
}
ptn_bridge = devm_kzalloc(dev->dev, sizeof(*ptn_bridge), GFP_KERNEL);
if (!ptn_bridge) {
DRM_ERROR("Failed to allocate ptn bridge\n");
return -ENOMEM;
}
ptn_bridge->client = client;
ptn_bridge->encoder = encoder;
ptn_bridge->bridge = bridge;
ptn_bridge->gpio_pd_n = of_get_named_gpio(node, "powerdown-gpio", 0);
if (gpio_is_valid(ptn_bridge->gpio_pd_n)) {
ret = gpio_request_one(ptn_bridge->gpio_pd_n,
GPIOF_OUT_INIT_HIGH, "PTN3460_PD_N");
if (ret) {
DRM_ERROR("Request powerdown-gpio failed (%d)\n", ret);
return ret;
}
}
ptn_bridge->gpio_rst_n = of_get_named_gpio(node, "reset-gpio", 0);
if (gpio_is_valid(ptn_bridge->gpio_rst_n)) {
/*
* Request the reset pin low to avoid the bridge being
* initialized prematurely
*/
ret = gpio_request_one(ptn_bridge->gpio_rst_n,
GPIOF_OUT_INIT_LOW, "PTN3460_RST_N");
if (ret) {
DRM_ERROR("Request reset-gpio failed (%d)\n", ret);
gpio_free(ptn_bridge->gpio_pd_n);
return ret;
}
}
ret = of_property_read_u32(node, "edid-emulation",
&ptn_bridge->edid_emulation);
if (ret) {
DRM_ERROR("Can't read edid emulation value\n");
goto err;
}
ret = drm_bridge_init(dev, bridge, &ptn3460_bridge_funcs);
if (ret) {
DRM_ERROR("Failed to initialize bridge with drm\n");
goto err;
}
bridge->driver_private = ptn_bridge;
encoder->bridge = bridge;
ret = drm_connector_init(dev, &ptn_bridge->connector,
&ptn3460_connector_funcs, DRM_MODE_CONNECTOR_LVDS);
if (ret) {
DRM_ERROR("Failed to initialize connector with drm\n");
goto err;
}
drm_connector_helper_add(&ptn_bridge->connector,
&ptn3460_connector_helper_funcs);
drm_sysfs_connector_add(&ptn_bridge->connector);
drm_mode_connector_attach_encoder(&ptn_bridge->connector, encoder);
return 0;
err:
if (gpio_is_valid(ptn_bridge->gpio_pd_n))
gpio_free(ptn_bridge->gpio_pd_n);
if (gpio_is_valid(ptn_bridge->gpio_rst_n))
gpio_free(ptn_bridge->gpio_rst_n);
return ret;
}
EXPORT_SYMBOL(ptn3460_init);
......@@ -149,7 +149,7 @@ static int cirrus_crtc_do_set_base(struct drm_crtc *crtc,
cirrus_bo_unreserve(bo);
}
cirrus_fb = to_cirrus_framebuffer(crtc->fb);
cirrus_fb = to_cirrus_framebuffer(crtc->primary->fb);
obj = cirrus_fb->obj;
bo = gem_to_cirrus_bo(obj);
......@@ -268,7 +268,7 @@ static int cirrus_crtc_mode_set(struct drm_crtc *crtc,
sr07 = RREG8(SEQ_DATA);
sr07 &= 0xe0;
hdr = 0;
switch (crtc->fb->bits_per_pixel) {
switch (crtc->primary->fb->bits_per_pixel) {
case 8:
sr07 |= 0x11;
break;
......@@ -291,13 +291,13 @@ static int cirrus_crtc_mode_set(struct drm_crtc *crtc,
WREG_SEQ(0x7, sr07);
/* Program the pitch */
tmp = crtc->fb->pitches[0] / 8;
tmp = crtc->primary->fb->pitches[0] / 8;
WREG_CRT(VGA_CRTC_OFFSET, tmp);
/* Enable extended blanking and pitch bits, and enable full memory */
tmp = 0x22;
tmp |= (crtc->fb->pitches[0] >> 7) & 0x10;
tmp |= (crtc->fb->pitches[0] >> 6) & 0x40;
tmp |= (crtc->primary->fb->pitches[0] >> 7) & 0x10;
tmp |= (crtc->primary->fb->pitches[0] >> 6) & 0x40;
WREG_CRT(0x1b, tmp);
/* Enable high-colour modes */
......
......@@ -259,7 +259,9 @@ int cirrus_mm_init(struct cirrus_device *cirrus)
ret = ttm_bo_device_init(&cirrus->ttm.bdev,
cirrus->ttm.bo_global_ref.ref.object,
&cirrus_bo_driver, DRM_FILE_PAGE_OFFSET,
&cirrus_bo_driver,
dev->anon_inode->i_mapping,
DRM_FILE_PAGE_OFFSET,
true);
if (ret) {
DRM_ERROR("Error initialising bo driver; %d\n", ret);
......@@ -329,7 +331,6 @@ int cirrus_bo_create(struct drm_device *dev, int size, int align,
}
cirrusbo->bo.bdev = &cirrus->ttm.bdev;
cirrusbo->bo.bdev->dev_mapping = dev->dev_mapping;
cirrus_ttm_placement(cirrusbo, TTM_PL_FLAG_VRAM | TTM_PL_FLAG_SYSTEM);
......
This diff is collapsed.
This diff is collapsed.
/*
* Copyright © 2006 Keith Packard
* Copyright © 2007-2008 Dave Airlie
* Copyright © 2007-2008 Intel Corporation
* Jesse Barnes <jesse.barnes@intel.com>
* Copyright © 2014 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, 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.
*/
/*
* This header file contains mode setting related functions and definitions
* which are only used within the drm module as internal implementation details
* and are not exported to drivers.
*/
int drm_mode_object_get(struct drm_device *dev,
struct drm_mode_object *obj, uint32_t obj_type);
void drm_mode_object_put(struct drm_device *dev,
struct drm_mode_object *object);
This diff is collapsed.
......@@ -285,6 +285,45 @@ static int drm_version(struct drm_device *dev, void *data,
return err;
}
/**
* drm_ioctl_permit - Check ioctl permissions against caller
*
* @flags: ioctl permission flags.
* @file_priv: Pointer to struct drm_file identifying the caller.
*
* Checks whether the caller is allowed to run an ioctl with the
* indicated permissions. If so, returns zero. Otherwise returns an
* error code suitable for ioctl return.
*/
static int drm_ioctl_permit(u32 flags, struct drm_file *file_priv)
{
/* ROOT_ONLY is only for CAP_SYS_ADMIN */
if (unlikely((flags & DRM_ROOT_ONLY) && !capable(CAP_SYS_ADMIN)))
return -EACCES;
/* AUTH is only for authenticated or render client */
if (unlikely((flags & DRM_AUTH) && !drm_is_render_client(file_priv) &&
!file_priv->authenticated))
return -EACCES;
/* MASTER is only for master or control clients */
if (unlikely((flags & DRM_MASTER) && !file_priv->is_master &&
!drm_is_control_client(file_priv)))
return -EACCES;
/* Control clients must be explicitly allowed */
if (unlikely(!(flags & DRM_CONTROL_ALLOW) &&
drm_is_control_client(file_priv)))
return -EACCES;
/* Render clients must be explicitly allowed */
if (unlikely(!(flags & DRM_RENDER_ALLOW) &&
drm_is_render_client(file_priv)))
return -EACCES;
return 0;
}
/**
* Called whenever a process performs an ioctl on /dev/drm.
*
......@@ -344,22 +383,22 @@ long drm_ioctl(struct file *filp,
DRM_DEBUG("pid=%d, dev=0x%lx, auth=%d, %s\n",
task_pid_nr(current),
(long)old_encode_dev(file_priv->minor->device),
(long)old_encode_dev(file_priv->minor->kdev->devt),
file_priv->authenticated, ioctl->name);
/* Do not trust userspace, use our own definition */
func = ioctl->func;
if (!func) {
if (unlikely(!func)) {
DRM_DEBUG("no function\n");
retcode = -EINVAL;
} else if (((ioctl->flags & DRM_ROOT_ONLY) && !capable(CAP_SYS_ADMIN)) ||
((ioctl->flags & DRM_AUTH) && !drm_is_render_client(file_priv) && !file_priv->authenticated) ||
((ioctl->flags & DRM_MASTER) && !file_priv->is_master) ||
(!(ioctl->flags & DRM_CONTROL_ALLOW) && (file_priv->minor->type == DRM_MINOR_CONTROL)) ||
(!(ioctl->flags & DRM_RENDER_ALLOW) && drm_is_render_client(file_priv))) {
retcode = -EACCES;
} else {
goto err_i1;
}
retcode = drm_ioctl_permit(ioctl->flags, file_priv);
if (unlikely(retcode))
goto err_i1;
if (cmd & (IOC_IN | IOC_OUT)) {
if (asize <= sizeof(stack_kdata)) {
kdata = stack_kdata;
......@@ -396,13 +435,12 @@ long drm_ioctl(struct file *filp,
usize) != 0)
retcode = -EFAULT;
}
}
err_i1:
if (!ioctl)
DRM_DEBUG("invalid ioctl: pid=%d, dev=0x%lx, auth=%d, cmd=0x%02x, nr=0x%02x\n",
task_pid_nr(current),
(long)old_encode_dev(file_priv->minor->device),
(long)old_encode_dev(file_priv->minor->kdev->devt),
file_priv->authenticated, cmd, nr);
if (kdata != stack_kdata)
......@@ -412,3 +450,21 @@ long drm_ioctl(struct file *filp,
return retcode;
}
EXPORT_SYMBOL(drm_ioctl);
/**
* drm_ioctl_flags - Check for core ioctl and return ioctl permission flags
*
* @nr: Ioctl number.
* @flags: Where to return the ioctl permission flags
*/
bool drm_ioctl_flags(unsigned int nr, unsigned int *flags)
{
if ((nr >= DRM_COMMAND_END && nr < DRM_CORE_IOCTL_COUNT) ||
(nr < DRM_COMMAND_BASE)) {
*flags = drm_ioctls[nr].flags;
return true;
}
return false;
}
EXPORT_SYMBOL(drm_ioctl_flags);
......@@ -1098,10 +1098,14 @@ EXPORT_SYMBOL(drm_edid_is_valid);
/**
* Get EDID information via I2C.
*
* \param adapter : i2c device adaptor
* \param buf : EDID data buffer to be filled
* \param len : EDID data buffer length
* \return 0 on success or -1 on failure.
* @adapter : i2c device adaptor
* @buf: EDID data buffer to be filled
* @block: 128 byte EDID block to start fetching from
* @len: EDID data buffer length to fetch
*
* Returns:
*
* 0 on success or -1 on failure.
*
* Try to fetch EDID information by calling i2c driver function.
*/
......@@ -1243,9 +1247,11 @@ drm_do_get_edid(struct drm_connector *connector, struct i2c_adapter *adapter)
/**
* Probe DDC presence.
* @adapter: i2c adapter to probe
*
* Returns:
*
* \param adapter : i2c device adaptor
* \return 1 on success
* 1 on success
*/
bool
drm_probe_ddc(struct i2c_adapter *adapter)
......@@ -1586,8 +1592,10 @@ bad_std_timing(u8 a, u8 b)
/**
* drm_mode_std - convert standard mode info (width, height, refresh) into mode
* @connector: connector of for the EDID block
* @edid: EDID block to scan
* @t: standard timing params
* @timing_level: standard timing level
* @revision: standard timing level
*
* Take the standard timing params (in this case width, aspect, and refresh)
* and convert them into a real mode using CVT/GTF/DMT.
......@@ -2132,6 +2140,7 @@ do_established_modes(struct detailed_timing *timing, void *c)
/**
* add_established_modes - get est. modes from EDID and add them
* @connector: connector of for the EDID block
* @edid: EDID block to scan
*
* Each EDID block contains a bitmap of the supported "established modes" list
......@@ -2194,6 +2203,7 @@ do_standard_modes(struct detailed_timing *timing, void *c)
/**
* add_standard_modes - get std. modes from EDID and add them
* @connector: connector of for the EDID block
* @edid: EDID block to scan
*
* Standard modes can be calculated using the appropriate standard (DMT,
......@@ -2580,6 +2590,9 @@ drm_display_mode_from_vic_index(struct drm_connector *connector,
return NULL;
newmode = drm_mode_duplicate(dev, &edid_cea_modes[cea_mode]);
if (!newmode)
return NULL;
newmode->vrefresh = 0;
return newmode;
......@@ -3300,6 +3313,7 @@ EXPORT_SYMBOL(drm_detect_hdmi_monitor);
/**
* drm_detect_monitor_audio - check monitor audio capability
* @edid: EDID block to scan
*
* Monitor should have CEA extension block.
* If monitor has 'basic audio', but no CEA audio blocks, it's 'basic
......@@ -3345,6 +3359,7 @@ EXPORT_SYMBOL(drm_detect_monitor_audio);
/**
* drm_rgb_quant_range_selectable - is RGB quantization range selectable?
* @edid: EDID block to scan
*
* Check whether the monitor reports the RGB quantization range selection
* as supported. The AVI infoframe can then be used to inform the monitor
......@@ -3564,8 +3579,8 @@ void drm_set_preferred_mode(struct drm_connector *connector,
struct drm_display_mode *mode;
list_for_each_entry(mode, &connector->probed_modes, head) {
if (drm_mode_width(mode) == hpref &&
drm_mode_height(mode) == vpref)
if (mode->hdisplay == hpref &&
mode->vdisplay == vpref)
mode->type |= DRM_MODE_TYPE_PREFERRED;
}
}
......@@ -3599,6 +3614,7 @@ drm_hdmi_avi_infoframe_from_display_mode(struct hdmi_avi_infoframe *frame,
frame->picture_aspect = HDMI_PICTURE_ASPECT_NONE;
frame->active_aspect = HDMI_ACTIVE_ASPECT_PICTURE;
frame->scan_mode = HDMI_SCAN_MODE_UNDERSCAN;
return 0;
}
......
......@@ -232,7 +232,7 @@ static struct drm_framebuffer *drm_mode_config_fb(struct drm_crtc *crtc)
list_for_each_entry(c, &dev->mode_config.crtc_list, head) {
if (crtc->base.id == c->base.id)
return c->fb;
return c->primary->fb;
}
return NULL;
......@@ -291,6 +291,7 @@ bool drm_fb_helper_restore_fbdev_mode(struct drm_fb_helper *fb_helper)
drm_warn_on_modeset_not_all_locked(dev);
list_for_each_entry(plane, &dev->mode_config.plane_list, head)
if (plane->type != DRM_PLANE_TYPE_PRIMARY)
drm_plane_force_disable(plane);
for (i = 0; i < fb_helper->crtc_count; i++) {
......@@ -365,9 +366,9 @@ static bool drm_fb_helper_is_bound(struct drm_fb_helper *fb_helper)
return false;
list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
if (crtc->fb)
if (crtc->primary->fb)
crtcs_bound++;
if (crtc->fb == fb_helper->fb)
if (crtc->primary->fb == fb_helper->fb)
bound++;
}
......@@ -516,6 +517,9 @@ int drm_fb_helper_init(struct drm_device *dev,
struct drm_crtc *crtc;
int i;
if (!max_conn_count)
return -EINVAL;
fb_helper->dev = dev;
INIT_LIST_HEAD(&fb_helper->kernel_fb_list);
......@@ -809,8 +813,6 @@ 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;
int ret;
int i;
if (var->pixclock != 0) {
DRM_ERROR("PIXEL CLOCK SET\n");
......@@ -818,13 +820,7 @@ int drm_fb_helper_set_par(struct fb_info *info)
}
drm_modeset_lock_all(dev);
for (i = 0; i < fb_helper->crtc_count; i++) {
ret = drm_mode_set_config_internal(&fb_helper->crtc_info[i].mode_set);
if (ret) {
drm_modeset_unlock_all(dev);
return ret;
}
}
drm_fb_helper_restore_fbdev_mode(fb_helper);
drm_modeset_unlock_all(dev);
if (fb_helper->delayed_hotplug) {
......@@ -1136,19 +1132,20 @@ static int drm_fb_helper_probe_connector_modes(struct drm_fb_helper *fb_helper,
return count;
}
static struct drm_display_mode *drm_has_preferred_mode(struct drm_fb_helper_connector *fb_connector, int width, int height)
struct drm_display_mode *drm_has_preferred_mode(struct drm_fb_helper_connector *fb_connector, int width, int height)
{
struct drm_display_mode *mode;
list_for_each_entry(mode, &fb_connector->connector->modes, head) {
if (drm_mode_width(mode) > width ||
drm_mode_height(mode) > height)
if (mode->hdisplay > width ||
mode->vdisplay > height)
continue;
if (mode->type & DRM_MODE_TYPE_PREFERRED)
return mode;
}
return NULL;
}
EXPORT_SYMBOL(drm_has_preferred_mode);
static bool drm_has_cmdline_mode(struct drm_fb_helper_connector *fb_connector)
{
......@@ -1157,11 +1154,12 @@ static bool drm_has_cmdline_mode(struct drm_fb_helper_connector *fb_connector)
return cmdline_mode->specified;
}
static struct drm_display_mode *drm_pick_cmdline_mode(struct drm_fb_helper_connector *fb_helper_conn,
struct drm_display_mode *drm_pick_cmdline_mode(struct drm_fb_helper_connector *fb_helper_conn,
int width, int height)
{
struct drm_cmdline_mode *cmdline_mode;
struct drm_display_mode *mode = NULL;
bool prefer_non_interlace;
cmdline_mode = &fb_helper_conn->cmdline_mode;
if (cmdline_mode->specified == false)
......@@ -1173,6 +1171,8 @@ static struct drm_display_mode *drm_pick_cmdline_mode(struct drm_fb_helper_conne
if (cmdline_mode->rb || cmdline_mode->margins)
goto create_mode;
prefer_non_interlace = !cmdline_mode->interlace;
again:
list_for_each_entry(mode, &fb_helper_conn->connector->modes, head) {
/* check width/height */
if (mode->hdisplay != cmdline_mode->xres ||
......@@ -1187,16 +1187,25 @@ static struct drm_display_mode *drm_pick_cmdline_mode(struct drm_fb_helper_conne
if (cmdline_mode->interlace) {
if (!(mode->flags & DRM_MODE_FLAG_INTERLACE))
continue;
} else if (prefer_non_interlace) {
if (mode->flags & DRM_MODE_FLAG_INTERLACE)
continue;
}
return mode;
}
if (prefer_non_interlace) {
prefer_non_interlace = false;
goto again;
}
create_mode:
mode = drm_mode_create_from_cmdline_mode(fb_helper_conn->connector->dev,
cmdline_mode);
list_add(&mode->head, &fb_helper_conn->connector->modes);
return mode;
}
EXPORT_SYMBOL(drm_pick_cmdline_mode);
static bool drm_connector_enabled(struct drm_connector *connector, bool strict)
{
......@@ -1539,9 +1548,11 @@ bool drm_fb_helper_initial_config(struct drm_fb_helper *fb_helper, int bpp_sel)
drm_fb_helper_parse_command_line(fb_helper);
mutex_lock(&dev->mode_config.mutex);
count = drm_fb_helper_probe_connector_modes(fb_helper,
dev->mode_config.max_width,
dev->mode_config.max_height);
mutex_unlock(&dev->mode_config.mutex);
/*
* we shouldn't end up with no modes here.
*/
......
This diff is collapsed.
......@@ -85,9 +85,9 @@
#endif
/**
* Initialize the GEM device fields
* drm_gem_init - Initialize the GEM device fields
* @dev: drm_devic structure to initialize
*/
int
drm_gem_init(struct drm_device *dev)
{
......@@ -120,6 +120,11 @@ drm_gem_destroy(struct drm_device *dev)
}
/**
* drm_gem_object_init - initialize an allocated shmem-backed GEM object
* @dev: drm_device the object should be initialized for
* @obj: drm_gem_object to initialize
* @size: object size
*
* Initialize an already allocated GEM object of the specified size with
* shmfs backing store.
*/
......@@ -141,6 +146,11 @@ int drm_gem_object_init(struct drm_device *dev,
EXPORT_SYMBOL(drm_gem_object_init);
/**
* drm_gem_object_init - initialize an allocated private GEM object
* @dev: drm_device the object should be initialized for
* @obj: drm_gem_object to initialize
* @size: object size
*
* Initialize an already allocated GEM object of the specified size with
* no GEM provided backing store. Instead the caller is responsible for
* backing the object and handling it.
......@@ -176,6 +186,9 @@ drm_gem_remove_prime_handles(struct drm_gem_object *obj, struct drm_file *filp)
}
/**
* drm_gem_object_free - release resources bound to userspace handles
* @obj: GEM object to clean up.
*
* Called after the last handle to the object has been closed
*
* Removes any name for the object. Note that this must be
......@@ -225,7 +238,12 @@ drm_gem_object_handle_unreference_unlocked(struct drm_gem_object *obj)
}
/**
* Removes the mapping from handle to filp for this object.
* drm_gem_handle_delete - deletes the given file-private handle
* @filp: drm file-private structure to use for the handle look up
* @handle: userspace handle to delete
*
* Removes the GEM handle from the @filp lookup table and if this is the last
* handle also cleans up linked resources like GEM names.
*/
int
drm_gem_handle_delete(struct drm_file *filp, u32 handle)
......@@ -270,6 +288,9 @@ EXPORT_SYMBOL(drm_gem_handle_delete);
/**
* drm_gem_dumb_destroy - dumb fb callback helper for gem based drivers
* @file: drm file-private structure to remove the dumb handle from
* @dev: corresponding drm_device
* @handle: the dumb handle to remove
*
* This implements the ->dumb_destroy kms driver callback for drivers which use
* gem to manage their backing storage.
......@@ -284,6 +305,9 @@ EXPORT_SYMBOL(drm_gem_dumb_destroy);
/**
* drm_gem_handle_create_tail - internal functions to create a handle
* @file_priv: drm file-private structure to register the handle for
* @obj: object to register
* @handlep: pionter to return the created handle to the caller
*
* This expects the dev->object_name_lock to be held already and will drop it
* before returning. Used to avoid races in establishing new handles when
......@@ -336,6 +360,11 @@ drm_gem_handle_create_tail(struct drm_file *file_priv,
}
/**
* gem_handle_create - create a gem handle for an object
* @file_priv: drm file-private structure to register the handle for
* @obj: object to register
* @handlep: pionter to return the created handle to the caller
*
* Create a handle for this object. This adds a handle reference
* to the object, which includes a regular reference count. Callers
* will likely want to dereference the object afterwards.
......@@ -536,6 +565,11 @@ drm_gem_object_lookup(struct drm_device *dev, struct drm_file *filp,
EXPORT_SYMBOL(drm_gem_object_lookup);
/**
* drm_gem_close_ioctl - implementation of the GEM_CLOSE ioctl
* @dev: drm_device
* @data: ioctl data
* @file_priv: drm file-private structure
*
* Releases the handle to an mm object.
*/
int
......@@ -554,6 +588,11 @@ drm_gem_close_ioctl(struct drm_device *dev, void *data,
}
/**
* drm_gem_flink_ioctl - implementation of the GEM_FLINK ioctl
* @dev: drm_device
* @data: ioctl data
* @file_priv: drm file-private structure
*
* Create a global name for an object, returning the name.
*
* Note that the name does not hold a reference; when the object
......@@ -601,6 +640,11 @@ drm_gem_flink_ioctl(struct drm_device *dev, void *data,
}
/**
* drm_gem_open - implementation of the GEM_OPEN ioctl
* @dev: drm_device
* @data: ioctl data
* @file_priv: drm file-private structure
*
* Open an object using the global name, returning a handle and the size.
*
* This handle (of course) holds a reference to the object, so the object
......@@ -640,6 +684,10 @@ drm_gem_open_ioctl(struct drm_device *dev, void *data,
}
/**
* gem_gem_open - initalizes GEM file-private structures at devnode open time
* @dev: drm_device which is being opened by userspace
* @file_private: drm file-private structure to set up
*
* Called at device open time, sets up the structure for handling refcounting
* of mm objects.
*/
......@@ -650,7 +698,7 @@ drm_gem_open(struct drm_device *dev, struct drm_file *file_private)
spin_lock_init(&file_private->table_lock);
}
/**
/*
* Called at device close to release the file's
* handle references on objects.
*/
......@@ -674,6 +722,10 @@ drm_gem_object_release_handle(int id, void *ptr, void *data)
}
/**
* drm_gem_release - release file-private GEM resources
* @dev: drm_device which is being closed by userspace
* @file_private: drm file-private structure to clean up
*
* Called at close time when the filp is going away.
*
* Releases any remaining references on objects by this filp.
......@@ -693,10 +745,15 @@ drm_gem_object_release(struct drm_gem_object *obj)
if (obj->filp)
fput(obj->filp);
drm_gem_free_mmap_offset(obj);
}
EXPORT_SYMBOL(drm_gem_object_release);
/**
* drm_gem_object_free - free a GEM object
* @kref: kref of the object to free
*
* Called after the last reference to the object has been lost.
* Must be called holding struct_ mutex
*
......@@ -818,7 +875,7 @@ int drm_gem_mmap(struct file *filp, struct vm_area_struct *vma)
struct drm_device *dev = priv->minor->dev;
struct drm_gem_object *obj;
struct drm_vma_offset_node *node;
int ret = 0;
int ret;
if (drm_device_is_unplugged(dev))
return -ENODEV;
......
This diff is collapsed.
......@@ -328,6 +328,13 @@ drm_setclientcap(struct drm_device *dev, void *data, struct drm_file *file_priv)
return -EINVAL;
file_priv->stereo_allowed = req->value;
break;
case DRM_CLIENT_CAP_UNIVERSAL_PLANES:
if (!drm_universal_planes)
return -EINVAL;
if (req->value > 1)
return -EINVAL;
file_priv->universal_planes = req->value;
break;
default:
return -EINVAL;
}
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
......@@ -351,7 +351,7 @@ int drm_get_pci_dev(struct pci_dev *pdev, const struct pci_device_id *ent,
drm_pci_agp_destroy(dev);
pci_disable_device(pdev);
err_free:
drm_dev_free(dev);
drm_dev_unref(dev);
return ret;
}
EXPORT_SYMBOL(drm_get_pci_dev);
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment