aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDave Airlie <airlied@redhat.com>2018-09-06 19:34:04 -0400
committerDave Airlie <airlied@redhat.com>2018-09-06 20:44:35 -0400
commitf5169a17af4ee5170587fd76d76aaa72ae4b864a (patch)
tree923164e6b95de08874c2d87c8b1af5767042d53c
parent57361846b52bc686112da6ca5368d11210796804 (diff)
parent3ee22b769fd761c98eeaceab49153c3eb7612821 (diff)
Merge tag 'drm-misc-next-2018-09-05' of git://anongit.freedesktop.org/drm/drm-misc into drm-next
drm-misc-next for 4.20: UAPI Changes: - Add userspace dma-buf device to turn memfd regions into dma-bufs (Gerd) - Add per-plane blend mode property (Lowry) - Change in drm_fourcc.h is documentation only (Brian) Cross-subsystem Changes: - None Core Changes: - Remove user logspam and useless lock in vma_offset_mgr destroy (Chris) - Add get/verify_crc_source for improved crc source selection (Mahesh) - Add __drm_atomic_helper_plane_reset to reduce copypasta (Alexandru) Driver Changes: - various: Replance ref/unref calls with drm_dev_get/put (Thomas) - bridge: Add driver for TI SN65DSI86 chip (Sandeep) - rockchip: Add PX30 support (Sandy) - sun4i: Add support for R40 TCON (Jernej) - vkms: Continued building out vkms, added gem support (Haneen)Driver Changes: - various: fbdev: Wrap remove_conflicting_framebuffers with resource_len accessors to remove a bunch of cargo-cult (Michał) - rockchip: Add rgb output iface support + fixes (Sandy/Heiko) - nouveau/amdgpu: Add cec-over-aux support (Hans) - sun4i: Add support for Allwinner A64 (Jagan) Cc: Gerd Hoffmann <kraxel@redhat.com> Cc: Chris Wilson <chris@chris-wilson.co.uk> Cc: Michał Mirosław <mirq-linux@rere.qmqm.pl> Cc: Heiko Stuebner <heiko@sntech.de> Cc: Sandy Huang <hjc@rock-chips.com> Cc: Hans Verkuil <hans.verkuil@cisco.com> Cc: Jagan Teki <jagan@amarulasolutions.com> Signed-off-by: Dave Airlie <airlied@redhat.com> From: Sean Paul <sean@poorly.run> Link: https://patchwork.freedesktop.org/patch/msgid/20180905202210.GA95199@art_vandelay
-rw-r--r--Documentation/devicetree/bindings/display/atmel/hlcdc-dc.txt23
-rw-r--r--Documentation/devicetree/bindings/display/bridge/lvds-transmitter.txt8
-rw-r--r--Documentation/devicetree/bindings/display/bridge/ti,sn65dsi86.txt87
-rw-r--r--Documentation/devicetree/bindings/display/bridge/toshiba,tc358764.txt35
-rw-r--r--Documentation/devicetree/bindings/display/mipi-dsi-bus.txt153
-rw-r--r--Documentation/devicetree/bindings/display/rockchip/rockchip-vop.txt3
-rw-r--r--Documentation/devicetree/bindings/display/sunxi/sun4i-drm.txt9
-rw-r--r--Documentation/gpu/drm-kms.rst6
-rw-r--r--Documentation/gpu/drm-mm.rst2
-rw-r--r--Documentation/ioctl/ioctl-number.txt1
-rw-r--r--MAINTAINERS8
-rw-r--r--drivers/dma-buf/Kconfig8
-rw-r--r--drivers/dma-buf/Makefile1
-rw-r--r--drivers/dma-buf/dma-buf.c1
-rw-r--r--drivers/dma-buf/udmabuf.c288
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c24
-rw-r--r--drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c10
-rw-r--r--drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h7
-rw-r--r--drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crc.c20
-rw-r--r--drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c2
-rw-r--r--drivers/gpu/drm/arm/malidp_planes.c7
-rw-r--r--drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c100
-rw-r--r--drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.h1
-rw-r--r--drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_output.c92
-rw-r--r--drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c5
-rw-r--r--drivers/gpu/drm/bochs/bochs_drv.c18
-rw-r--r--drivers/gpu/drm/bochs/bochs_mm.c2
-rw-r--r--drivers/gpu/drm/bridge/Kconfig18
-rw-r--r--drivers/gpu/drm/bridge/Makefile2
-rw-r--r--drivers/gpu/drm/bridge/synopsys/Makefile2
-rw-r--r--drivers/gpu/drm/bridge/tc358764.c499
-rw-r--r--drivers/gpu/drm/bridge/ti-sn65dsi86.c779
-rw-r--r--drivers/gpu/drm/cirrus/cirrus_drv.c27
-rw-r--r--drivers/gpu/drm/cirrus/cirrus_drv.h2
-rw-r--r--drivers/gpu/drm/cirrus/cirrus_fbdev.c51
-rw-r--r--drivers/gpu/drm/cirrus/cirrus_main.c2
-rw-r--r--drivers/gpu/drm/cirrus/cirrus_mode.c4
-rw-r--r--drivers/gpu/drm/drm_atomic.c4
-rw-r--r--drivers/gpu/drm/drm_atomic_helper.c34
-rw-r--r--drivers/gpu/drm/drm_blend.c123
-rw-r--r--drivers/gpu/drm/drm_debugfs_crc.c92
-rw-r--r--drivers/gpu/drm/drm_dp_cec.c18
-rw-r--r--drivers/gpu/drm/drm_dp_helper.c3
-rw-r--r--drivers/gpu/drm/drm_dp_mst_topology.c1
-rw-r--r--drivers/gpu/drm/drm_fb_cma_helper.c26
-rw-r--r--drivers/gpu/drm/drm_gem_cma_helper.c4
-rw-r--r--drivers/gpu/drm/drm_panel.c2
-rw-r--r--drivers/gpu/drm/drm_syncobj.c15
-rw-r--r--drivers/gpu/drm/drm_vblank.c6
-rw-r--r--drivers/gpu/drm/drm_vma_manager.c3
-rw-r--r--drivers/gpu/drm/gma500/psb_drv.h1
-rw-r--r--drivers/gpu/drm/i915/i915_gem_clflush.c7
-rw-r--r--drivers/gpu/drm/i915/intel_display.c2
-rw-r--r--drivers/gpu/drm/i915/intel_drv.h9
-rw-r--r--drivers/gpu/drm/i915/intel_pipe_crc.c119
-rw-r--r--drivers/gpu/drm/i915/selftests/i915_sw_fence.c8
-rw-r--r--drivers/gpu/drm/imx/ipuv3-plane.c9
-rw-r--r--drivers/gpu/drm/mgag200/mgag200_drv.c21
-rw-r--r--drivers/gpu/drm/mgag200/mgag200_main.c9
-rw-r--r--drivers/gpu/drm/msm/msm_fence.c8
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_connector.c17
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_fence.c1
-rw-r--r--drivers/gpu/drm/qxl/qxl_display.c16
-rw-r--r--drivers/gpu/drm/qxl/qxl_drv.c28
-rw-r--r--drivers/gpu/drm/qxl/qxl_gem.c2
-rw-r--r--drivers/gpu/drm/qxl/qxl_kms.c80
-rw-r--r--drivers/gpu/drm/radeon/radeon_drv.c23
-rw-r--r--drivers/gpu/drm/rcar-du/rcar_du_crtc.c149
-rw-r--r--drivers/gpu/drm/rcar-du/rcar_du_crtc.h3
-rw-r--r--drivers/gpu/drm/rcar-du/rcar_du_plane.c6
-rw-r--r--drivers/gpu/drm/rcar-du/rcar_du_vsp.c5
-rw-r--r--drivers/gpu/drm/rockchip/Kconfig25
-rw-r--r--drivers/gpu/drm/rockchip/Makefile1
-rw-r--r--drivers/gpu/drm/rockchip/rockchip_drm_drv.c98
-rw-r--r--drivers/gpu/drm/rockchip/rockchip_drm_drv.h2
-rw-r--r--drivers/gpu/drm/rockchip/rockchip_drm_vop.c48
-rw-r--r--drivers/gpu/drm/rockchip/rockchip_drm_vop.h1
-rw-r--r--drivers/gpu/drm/rockchip/rockchip_rgb.c173
-rw-r--r--drivers/gpu/drm/rockchip/rockchip_rgb.h33
-rw-r--r--drivers/gpu/drm/rockchip/rockchip_vop_reg.c215
-rw-r--r--drivers/gpu/drm/rockchip/rockchip_vop_reg.h99
-rw-r--r--drivers/gpu/drm/sti/sti_hda.c1
-rw-r--r--drivers/gpu/drm/sti/sti_hdmi.c1
-rw-r--r--drivers/gpu/drm/sun4i/sun4i_backend.c81
-rw-r--r--drivers/gpu/drm/sun4i/sun4i_backend.h3
-rw-r--r--drivers/gpu/drm/sun4i/sun4i_drv.c19
-rw-r--r--drivers/gpu/drm/sun4i/sun4i_layer.c4
-rw-r--r--drivers/gpu/drm/sun4i/sun4i_tcon.c119
-rw-r--r--drivers/gpu/drm/sun4i/sun8i_dw_hdmi.c17
-rw-r--r--drivers/gpu/drm/sun4i/sun8i_dw_hdmi.h2
-rw-r--r--drivers/gpu/drm/sun4i/sun8i_mixer.c24
-rw-r--r--drivers/gpu/drm/sun4i/sun8i_tcon_top.c3
-rw-r--r--drivers/gpu/drm/tegra/drm.c4
-rw-r--r--drivers/gpu/drm/tinydrm/core/tinydrm-core.c6
-rw-r--r--drivers/gpu/drm/vc4/vc4_drv.c20
-rw-r--r--drivers/gpu/drm/vc4/vc4_plane.c4
-rw-r--r--drivers/gpu/drm/vgem/vgem_drv.c2
-rw-r--r--drivers/gpu/drm/vgem/vgem_fence.c13
-rw-r--r--drivers/gpu/drm/virtio/virtgpu_display.c4
-rw-r--r--drivers/gpu/drm/virtio/virtgpu_drm_bus.c26
-rw-r--r--drivers/gpu/drm/virtio/virtgpu_drv.h13
-rw-r--r--drivers/gpu/drm/virtio/virtgpu_fb.c2
-rw-r--r--drivers/gpu/drm/virtio/virtgpu_plane.c2
-rw-r--r--drivers/gpu/drm/virtio/virtgpu_ttm.c39
-rw-r--r--drivers/gpu/drm/virtio/virtgpu_vq.c57
-rw-r--r--drivers/gpu/drm/vkms/Makefile2
-rw-r--r--drivers/gpu/drm/vkms/vkms_crc.c153
-rw-r--r--drivers/gpu/drm/vkms/vkms_crtc.c114
-rw-r--r--drivers/gpu/drm/vkms/vkms_drv.c1
-rw-r--r--drivers/gpu/drm/vkms/vkms_drv.h59
-rw-r--r--drivers/gpu/drm/vkms/vkms_gem.c83
-rw-r--r--drivers/gpu/drm/vkms/vkms_plane.c140
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_kms.c4
-rw-r--r--drivers/gpu/drm/xen/xen_drm_front_gem.c2
-rw-r--r--drivers/video/fbdev/core/fbmem.c63
-rw-r--r--include/drm/drm_atomic_helper.h2
-rw-r--r--include/drm/drm_blend.h6
-rw-r--r--include/drm/drm_crtc.h41
-rw-r--r--include/drm/drm_dp_helper.h5
-rw-r--r--include/drm/drm_fb_cma_helper.h1
-rw-r--r--include/drm/drm_fb_helper.h12
-rw-r--r--include/drm/drm_panel.h1
-rw-r--r--include/drm/drm_plane.h16
-rw-r--r--include/drm/drm_print.h2
-rw-r--r--include/drm/drm_syncobj.h5
-rw-r--r--include/linux/fb.h2
-rw-r--r--include/uapi/drm/drm_fourcc.h36
-rw-r--r--include/uapi/linux/udmabuf.h33
-rw-r--r--tools/testing/selftests/drivers/dma-buf/Makefile5
-rw-r--r--tools/testing/selftests/drivers/dma-buf/udmabuf.c96
130 files changed, 4522 insertions, 684 deletions
diff --git a/Documentation/devicetree/bindings/display/atmel/hlcdc-dc.txt b/Documentation/devicetree/bindings/display/atmel/hlcdc-dc.txt
index 82f2acb3d374..0398aec488ac 100644
--- a/Documentation/devicetree/bindings/display/atmel/hlcdc-dc.txt
+++ b/Documentation/devicetree/bindings/display/atmel/hlcdc-dc.txt
@@ -15,6 +15,13 @@ Required children nodes:
15 to external devices using the OF graph reprensentation (see ../graph.txt). 15 to external devices using the OF graph reprensentation (see ../graph.txt).
16 At least one port node is required. 16 At least one port node is required.
17 17
18Optional properties in grandchild nodes:
19 Any endpoint grandchild node may specify a desired video interface
20 according to ../../media/video-interfaces.txt, specifically
21 - bus-width: recognized values are <12>, <16>, <18> and <24>, and
22 override any output mode selection heuristic, forcing "rgb444",
23 "rgb565", "rgb666" and "rgb888" respectively.
24
18Example: 25Example:
19 26
20 hlcdc: hlcdc@f0030000 { 27 hlcdc: hlcdc@f0030000 {
@@ -50,3 +57,19 @@ Example:
50 #pwm-cells = <3>; 57 #pwm-cells = <3>;
51 }; 58 };
52 }; 59 };
60
61Example 2: With a video interface override to force rgb565; as above
62but with these changes/additions:
63
64 &hlcdc {
65 hlcdc-display-controller {
66 pinctrl-names = "default";
67 pinctrl-0 = <&pinctrl_lcd_base &pinctrl_lcd_rgb565>;
68
69 port@0 {
70 hlcdc_panel_output: endpoint@0 {
71 bus-width = <16>;
72 };
73 };
74 };
75 };
diff --git a/Documentation/devicetree/bindings/display/bridge/lvds-transmitter.txt b/Documentation/devicetree/bindings/display/bridge/lvds-transmitter.txt
index fd39ad34c383..50220190c203 100644
--- a/Documentation/devicetree/bindings/display/bridge/lvds-transmitter.txt
+++ b/Documentation/devicetree/bindings/display/bridge/lvds-transmitter.txt
@@ -22,7 +22,13 @@ among others.
22 22
23Required properties: 23Required properties:
24 24
25- compatible: Must be "lvds-encoder" 25- compatible: Must be one or more of the following
26 - "ti,ds90c185" for the TI DS90C185 FPD-Link Serializer
27 - "lvds-encoder" for a generic LVDS encoder device
28
29 When compatible with the generic version, nodes must list the
30 device-specific version corresponding to the device first
31 followed by the generic version.
26 32
27Required nodes: 33Required nodes:
28 34
diff --git a/Documentation/devicetree/bindings/display/bridge/ti,sn65dsi86.txt b/Documentation/devicetree/bindings/display/bridge/ti,sn65dsi86.txt
new file mode 100644
index 000000000000..0a3fbb53a16e
--- /dev/null
+++ b/Documentation/devicetree/bindings/display/bridge/ti,sn65dsi86.txt
@@ -0,0 +1,87 @@
1SN65DSI86 DSI to eDP bridge chip
2--------------------------------
3
4This is the binding for Texas Instruments SN65DSI86 bridge.
5http://www.ti.com/general/docs/lit/getliterature.tsp?genericPartNumber=sn65dsi86&fileType=pdf
6
7Required properties:
8- compatible: Must be "ti,sn65dsi86"
9- reg: i2c address of the chip, 0x2d as per datasheet
10- enable-gpios: gpio specification for bridge_en pin (active high)
11
12- vccio-supply: A 1.8V supply that powers up the digital IOs.
13- vpll-supply: A 1.8V supply that powers up the displayport PLL.
14- vcca-supply: A 1.2V supply that powers up the analog circuits.
15- vcc-supply: A 1.2V supply that powers up the digital core.
16
17Optional properties:
18- interrupts-extended: Specifier for the SN65DSI86 interrupt line.
19
20- gpio-controller: Marks the device has a GPIO controller.
21- #gpio-cells : Should be two. The first cell is the pin number and
22 the second cell is used to specify flags.
23 See ../../gpio/gpio.txt for more information.
24- #pwm-cells : Should be one. See ../../pwm/pwm.txt for description of
25 the cell formats.
26
27- clock-names: should be "refclk"
28- clocks: Specification for input reference clock. The reference
29 clock rate must be 12 MHz, 19.2 MHz, 26 MHz, 27 MHz or 38.4 MHz.
30
31- data-lanes: See ../../media/video-interface.txt
32- lane-polarities: See ../../media/video-interface.txt
33
34- suspend-gpios: specification for GPIO1 pin on bridge (active low)
35
36Required nodes:
37This device has two video ports. Their connections are modelled using the
38OF graph bindings specified in Documentation/devicetree/bindings/graph.txt.
39
40- Video port 0 for DSI input
41- Video port 1 for eDP output
42
43Example
44-------
45
46edp-bridge@2d {
47 compatible = "ti,sn65dsi86";
48 #address-cells = <1>;
49 #size-cells = <0>;
50 reg = <0x2d>;
51
52 enable-gpios = <&msmgpio 33 GPIO_ACTIVE_HIGH>;
53 suspend-gpios = <&msmgpio 34 GPIO_ACTIVE_LOW>;
54
55 interrupts-extended = <&gpio3 4 IRQ_TYPE_EDGE_FALLING>;
56
57 vccio-supply = <&pm8916_l17>;
58 vcca-supply = <&pm8916_l6>;
59 vpll-supply = <&pm8916_l17>;
60 vcc-supply = <&pm8916_l6>;
61
62 clock-names = "refclk";
63 clocks = <&input_refclk>;
64
65 ports {
66 #address-cells = <1>;
67 #size-cells = <0>;
68
69 port@0 {
70 reg = <0>;
71
72 edp_bridge_in: endpoint {
73 remote-endpoint = <&dsi_out>;
74 };
75 };
76
77 port@1 {
78 reg = <1>;
79
80 edp_bridge_out: endpoint {
81 data-lanes = <2 1 3 0>;
82 lane-polarities = <0 1 0 1>;
83 remote-endpoint = <&edp_panel_in>;
84 };
85 };
86 };
87}
diff --git a/Documentation/devicetree/bindings/display/bridge/toshiba,tc358764.txt b/Documentation/devicetree/bindings/display/bridge/toshiba,tc358764.txt
new file mode 100644
index 000000000000..8f9abf28a8fa
--- /dev/null
+++ b/Documentation/devicetree/bindings/display/bridge/toshiba,tc358764.txt
@@ -0,0 +1,35 @@
1TC358764 MIPI-DSI to LVDS panel bridge
2
3Required properties:
4 - compatible: "toshiba,tc358764"
5 - reg: the virtual channel number of a DSI peripheral
6 - vddc-supply: core voltage supply, 1.2V
7 - vddio-supply: I/O voltage supply, 1.8V or 3.3V
8 - vddlvds-supply: LVDS1/2 voltage supply, 3.3V
9 - reset-gpios: a GPIO spec for the reset pin
10
11The device node can contain following 'port' child nodes,
12according to the OF graph bindings defined in [1]:
13 0: DSI Input, not required, if the bridge is DSI controlled
14 1: LVDS Output, mandatory
15
16[1]: Documentation/devicetree/bindings/media/video-interfaces.txt
17
18Example:
19
20 bridge@0 {
21 reg = <0>;
22 compatible = "toshiba,tc358764";
23 vddc-supply = <&vcc_1v2_reg>;
24 vddio-supply = <&vcc_1v8_reg>;
25 vddlvds-supply = <&vcc_3v3_reg>;
26 reset-gpios = <&gpd1 6 GPIO_ACTIVE_LOW>;
27 #address-cells = <1>;
28 #size-cells = <0>;
29 port@1 {
30 reg = <1>;
31 lvds_ep: endpoint {
32 remote-endpoint = <&panel_ep>;
33 };
34 };
35 };
diff --git a/Documentation/devicetree/bindings/display/mipi-dsi-bus.txt b/Documentation/devicetree/bindings/display/mipi-dsi-bus.txt
index 973c27273772..a336599f6c03 100644
--- a/Documentation/devicetree/bindings/display/mipi-dsi-bus.txt
+++ b/Documentation/devicetree/bindings/display/mipi-dsi-bus.txt
@@ -16,7 +16,7 @@ The following assumes that only a single peripheral is connected to a DSI
16host. Experience shows that this is true for the large majority of setups. 16host. Experience shows that this is true for the large majority of setups.
17 17
18DSI host 18DSI host
19-------- 19========
20 20
21In addition to the standard properties and those defined by the parent bus of 21In addition to the standard properties and those defined by the parent bus of
22a DSI host, the following properties apply to a node representing a DSI host. 22a DSI host, the following properties apply to a node representing a DSI host.
@@ -29,12 +29,24 @@ Required properties:
29- #size-cells: Should be 0. There are cases where it makes sense to use a 29- #size-cells: Should be 0. There are cases where it makes sense to use a
30 different value here. See below. 30 different value here. See below.
31 31
32Optional properties:
33- clock-master: boolean. Should be enabled if the host is being used in
34 conjunction with another DSI host to drive the same peripheral. Hardware
35 supporting such a configuration generally requires the data on both the busses
36 to be driven by the same clock. Only the DSI host instance controlling this
37 clock should contain this property.
38
32DSI peripheral 39DSI peripheral
33-------------- 40==============
41
42Peripherals with DSI as control bus, or no control bus
43------------------------------------------------------
34 44
35Peripherals are represented as child nodes of the DSI host's node. Properties 45Peripherals with the DSI bus as the primary control bus, or peripherals with
36described here apply to all DSI peripherals, but individual bindings may want 46no control bus but use the DSI bus to transmit pixel data are represented
37to define additional, device-specific properties. 47as child nodes of the DSI host's node. Properties described here apply to all
48DSI peripherals, but individual bindings may want to define additional,
49device-specific properties.
38 50
39Required properties: 51Required properties:
40- reg: The virtual channel number of a DSI peripheral. Must be in the range 52- reg: The virtual channel number of a DSI peripheral. Must be in the range
@@ -49,9 +61,37 @@ case two alternative representations can be chosen:
49 property is the number of the first virtual channel and the second cell is 61 property is the number of the first virtual channel and the second cell is
50 the number of consecutive virtual channels. 62 the number of consecutive virtual channels.
51 63
52Example 64Peripherals with a different control bus
53------- 65----------------------------------------
54 66
67There are peripherals that have I2C/SPI (or some other non-DSI bus) as the
68primary control bus, but are also connected to a DSI bus (mostly for the data
69path). Connections between such peripherals and a DSI host can be represented
70using the graph bindings [1], [2].
71
72Peripherals that support dual channel DSI
73-----------------------------------------
74
75Peripherals with higher bandwidth requirements can be connected to 2 DSI
76busses. Each DSI bus/channel drives some portion of the pixel data (generally
77left/right half of each line of the display, or even/odd lines of the display).
78The graph bindings should be used to represent the multiple DSI busses that are
79connected to this peripheral. Each DSI host's output endpoint can be linked to
80an input endpoint of the DSI peripheral.
81
82[1] Documentation/devicetree/bindings/graph.txt
83[2] Documentation/devicetree/bindings/media/video-interfaces.txt
84
85Examples
86========
87- (1), (2) and (3) are examples of a DSI host and peripheral on the DSI bus
88 with different virtual channel configurations.
89- (4) is an example of a peripheral on a I2C control bus connected to a
90 DSI host using of-graph bindings.
91- (5) is an example of 2 DSI hosts driving a dual-channel DSI peripheral,
92 which uses I2C as its primary control bus.
93
941)
55 dsi-host { 95 dsi-host {
56 ... 96 ...
57 97
@@ -67,6 +107,7 @@ Example
67 ... 107 ...
68 }; 108 };
69 109
1102)
70 dsi-host { 111 dsi-host {
71 ... 112 ...
72 113
@@ -82,6 +123,7 @@ Example
82 ... 123 ...
83 }; 124 };
84 125
1263)
85 dsi-host { 127 dsi-host {
86 ... 128 ...
87 129
@@ -96,3 +138,98 @@ Example
96 138
97 ... 139 ...
98 }; 140 };
141
1424)
143 i2c-host {
144 ...
145
146 dsi-bridge@35 {
147 compatible = "...";
148 reg = <0x35>;
149
150 ports {
151 ...
152
153 port {
154 bridge_mipi_in: endpoint {
155 remote-endpoint = <&host_mipi_out>;
156 };
157 };
158 };
159 };
160 };
161
162 dsi-host {
163 ...
164
165 ports {
166 ...
167
168 port {
169 host_mipi_out: endpoint {
170 remote-endpoint = <&bridge_mipi_in>;
171 };
172 };
173 };
174 };
175
1765)
177 i2c-host {
178 dsi-bridge@35 {
179 compatible = "...";
180 reg = <0x35>;
181
182 ports {
183 #address-cells = <1>;
184 #size-cells = <0>;
185
186 port@0 {
187 reg = <0>;
188 dsi0_in: endpoint {
189 remote-endpoint = <&dsi0_out>;
190 };
191 };
192
193 port@1 {
194 reg = <1>;
195 dsi1_in: endpoint {
196 remote-endpoint = <&dsi1_out>;
197 };
198 };
199 };
200 };
201 };
202
203 dsi0-host {
204 ...
205
206 /*
207 * this DSI instance drives the clock for both the host
208 * controllers
209 */
210 clock-master;
211
212 ports {
213 ...
214
215 port {
216 dsi0_out: endpoint {
217 remote-endpoint = <&dsi0_in>;
218 };
219 };
220 };
221 };
222
223 dsi1-host {
224 ...
225
226 ports {
227 ...
228
229 port {
230 dsi1_out: endpoint {
231 remote-endpoint = <&dsi1_in>;
232 };
233 };
234 };
235 };
diff --git a/Documentation/devicetree/bindings/display/rockchip/rockchip-vop.txt b/Documentation/devicetree/bindings/display/rockchip/rockchip-vop.txt
index eeda3597011e..b79e5769f0ae 100644
--- a/Documentation/devicetree/bindings/display/rockchip/rockchip-vop.txt
+++ b/Documentation/devicetree/bindings/display/rockchip/rockchip-vop.txt
@@ -8,6 +8,9 @@ Required properties:
8- compatible: value should be one of the following 8- compatible: value should be one of the following
9 "rockchip,rk3036-vop"; 9 "rockchip,rk3036-vop";
10 "rockchip,rk3126-vop"; 10 "rockchip,rk3126-vop";
11 "rockchip,px30-vop-lit";
12 "rockchip,px30-vop-big";
13 "rockchip,rk3188-vop";
11 "rockchip,rk3288-vop"; 14 "rockchip,rk3288-vop";
12 "rockchip,rk3368-vop"; 15 "rockchip,rk3368-vop";
13 "rockchip,rk3366-vop"; 16 "rockchip,rk3366-vop";
diff --git a/Documentation/devicetree/bindings/display/sunxi/sun4i-drm.txt b/Documentation/devicetree/bindings/display/sunxi/sun4i-drm.txt
index f8773ecb7525..0bbb5d47f228 100644
--- a/Documentation/devicetree/bindings/display/sunxi/sun4i-drm.txt
+++ b/Documentation/devicetree/bindings/display/sunxi/sun4i-drm.txt
@@ -78,6 +78,7 @@ Required properties:
78 78
79 - compatible: value must be one of: 79 - compatible: value must be one of:
80 * "allwinner,sun8i-a83t-dw-hdmi" 80 * "allwinner,sun8i-a83t-dw-hdmi"
81 * "allwinner,sun50i-a64-dw-hdmi", "allwinner,sun8i-a83t-dw-hdmi"
81 - reg: base address and size of memory-mapped region 82 - reg: base address and size of memory-mapped region
82 - reg-io-width: See dw_hdmi.txt. Shall be 1. 83 - reg-io-width: See dw_hdmi.txt. Shall be 1.
83 - interrupts: HDMI interrupt number 84 - interrupts: HDMI interrupt number
@@ -96,6 +97,9 @@ Required properties:
96 first port should be the input endpoint. The second should be the 97 first port should be the input endpoint. The second should be the
97 output, usually to an HDMI connector. 98 output, usually to an HDMI connector.
98 99
100Optional properties:
101 - hvcc-supply: the VCC power supply of the controller
102
99DWC HDMI PHY 103DWC HDMI PHY
100------------ 104------------
101 105
@@ -151,6 +155,8 @@ Required properties:
151 * allwinner,sun8i-v3s-tcon 155 * allwinner,sun8i-v3s-tcon
152 * allwinner,sun9i-a80-tcon-lcd 156 * allwinner,sun9i-a80-tcon-lcd
153 * allwinner,sun9i-a80-tcon-tv 157 * allwinner,sun9i-a80-tcon-tv
158 * "allwinner,sun50i-a64-tcon-lcd", "allwinner,sun8i-a83t-tcon-lcd"
159 * "allwinner,sun50i-a64-tcon-tv", "allwinner,sun8i-a83t-tcon-tv"
154 - reg: base address and size of memory-mapped region 160 - reg: base address and size of memory-mapped region
155 - interrupts: interrupt associated to this IP 161 - interrupts: interrupt associated to this IP
156 - clocks: phandles to the clocks feeding the TCON. 162 - clocks: phandles to the clocks feeding the TCON.
@@ -370,6 +376,8 @@ Required properties:
370 * allwinner,sun8i-a83t-de2-mixer-1 376 * allwinner,sun8i-a83t-de2-mixer-1
371 * allwinner,sun8i-h3-de2-mixer-0 377 * allwinner,sun8i-h3-de2-mixer-0
372 * allwinner,sun8i-v3s-de2-mixer 378 * allwinner,sun8i-v3s-de2-mixer
379 * allwinner,sun50i-a64-de2-mixer-0
380 * allwinner,sun50i-a64-de2-mixer-1
373 - reg: base address and size of the memory-mapped region. 381 - reg: base address and size of the memory-mapped region.
374 - clocks: phandles to the clocks feeding the mixer 382 - clocks: phandles to the clocks feeding the mixer
375 * bus: the mixer interface clock 383 * bus: the mixer interface clock
@@ -403,6 +411,7 @@ Required properties:
403 * allwinner,sun8i-r40-display-engine 411 * allwinner,sun8i-r40-display-engine
404 * allwinner,sun8i-v3s-display-engine 412 * allwinner,sun8i-v3s-display-engine
405 * allwinner,sun9i-a80-display-engine 413 * allwinner,sun9i-a80-display-engine
414 * allwinner,sun50i-a64-display-engine
406 415
407 - allwinner,pipelines: list of phandle to the display engine 416 - allwinner,pipelines: list of phandle to the display engine
408 frontends (DE 1.0) or mixers (DE 2.0) available. 417 frontends (DE 1.0) or mixers (DE 2.0) available.
diff --git a/Documentation/gpu/drm-kms.rst b/Documentation/gpu/drm-kms.rst
index 5dee6b8a4c12..f8f5bf11a6ca 100644
--- a/Documentation/gpu/drm-kms.rst
+++ b/Documentation/gpu/drm-kms.rst
@@ -323,6 +323,12 @@ Frame Buffer Functions Reference
323DRM Format Handling 323DRM Format Handling
324=================== 324===================
325 325
326.. kernel-doc:: include/uapi/drm/drm_fourcc.h
327 :doc: overview
328
329Format Functions Reference
330--------------------------
331
326.. kernel-doc:: include/drm/drm_fourcc.h 332.. kernel-doc:: include/drm/drm_fourcc.h
327 :internal: 333 :internal:
328 334
diff --git a/Documentation/gpu/drm-mm.rst b/Documentation/gpu/drm-mm.rst
index 21b6b72a9ba8..c3ae888b92ef 100644
--- a/Documentation/gpu/drm-mm.rst
+++ b/Documentation/gpu/drm-mm.rst
@@ -297,7 +297,7 @@ made up of several fields, the more interesting ones being:
297 struct vm_operations_struct { 297 struct vm_operations_struct {
298 void (*open)(struct vm_area_struct * area); 298 void (*open)(struct vm_area_struct * area);
299 void (*close)(struct vm_area_struct * area); 299 void (*close)(struct vm_area_struct * area);
300 int (*fault)(struct vm_fault *vmf); 300 vm_fault_t (*fault)(struct vm_fault *vmf);
301 }; 301 };
302 302
303 303
diff --git a/Documentation/ioctl/ioctl-number.txt b/Documentation/ioctl/ioctl-number.txt
index 13a7c999c04a..f2ac672eb766 100644
--- a/Documentation/ioctl/ioctl-number.txt
+++ b/Documentation/ioctl/ioctl-number.txt
@@ -272,6 +272,7 @@ Code Seq#(hex) Include File Comments
272't' 90-91 linux/toshiba.h toshiba and toshiba_acpi SMM 272't' 90-91 linux/toshiba.h toshiba and toshiba_acpi SMM
273'u' 00-1F linux/smb_fs.h gone 273'u' 00-1F linux/smb_fs.h gone
274'u' 20-3F linux/uvcvideo.h USB video class host driver 274'u' 20-3F linux/uvcvideo.h USB video class host driver
275'u' 40-4f linux/udmabuf.h userspace dma-buf misc device
275'v' 00-1F linux/ext2_fs.h conflict! 276'v' 00-1F linux/ext2_fs.h conflict!
276'v' 00-1F linux/fs.h conflict! 277'v' 00-1F linux/fs.h conflict!
277'v' 00-0F linux/sonypi.h conflict! 278'v' 00-0F linux/sonypi.h conflict!
diff --git a/MAINTAINERS b/MAINTAINERS
index 9ad052aeac39..029baa270a11 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -15343,6 +15343,14 @@ F: arch/x86/um/
15343F: fs/hostfs/ 15343F: fs/hostfs/
15344F: fs/hppfs/ 15344F: fs/hppfs/
15345 15345
15346USERSPACE DMA BUFFER DRIVER
15347M: Gerd Hoffmann <kraxel@redhat.com>
15348S: Maintained
15349L: dri-devel@lists.freedesktop.org
15350F: drivers/dma-buf/udmabuf.c
15351F: include/uapi/linux/udmabuf.h
15352T: git git://anongit.freedesktop.org/drm/drm-misc
15353
15346USERSPACE I/O (UIO) 15354USERSPACE I/O (UIO)
15347M: Greg Kroah-Hartman <gregkh@linuxfoundation.org> 15355M: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
15348S: Maintained 15356S: Maintained
diff --git a/drivers/dma-buf/Kconfig b/drivers/dma-buf/Kconfig
index ed3b785bae37..338129eb126f 100644
--- a/drivers/dma-buf/Kconfig
+++ b/drivers/dma-buf/Kconfig
@@ -30,4 +30,12 @@ config SW_SYNC
30 WARNING: improper use of this can result in deadlocking kernel 30 WARNING: improper use of this can result in deadlocking kernel
31 drivers from userspace. Intended for test and debug only. 31 drivers from userspace. Intended for test and debug only.
32 32
33config UDMABUF
34 bool "userspace dmabuf misc driver"
35 default n
36 depends on DMA_SHARED_BUFFER
37 help
38 A driver to let userspace turn memfd regions into dma-bufs.
39 Qemu can use this to create host dmabufs for guest framebuffers.
40
33endmenu 41endmenu
diff --git a/drivers/dma-buf/Makefile b/drivers/dma-buf/Makefile
index c33bf8863147..0913a6ccab5a 100644
--- a/drivers/dma-buf/Makefile
+++ b/drivers/dma-buf/Makefile
@@ -1,3 +1,4 @@
1obj-y := dma-buf.o dma-fence.o dma-fence-array.o reservation.o seqno-fence.o 1obj-y := dma-buf.o dma-fence.o dma-fence-array.o reservation.o seqno-fence.o
2obj-$(CONFIG_SYNC_FILE) += sync_file.o 2obj-$(CONFIG_SYNC_FILE) += sync_file.o
3obj-$(CONFIG_SW_SYNC) += sw_sync.o sync_debug.o 3obj-$(CONFIG_SW_SYNC) += sw_sync.o sync_debug.o
4obj-$(CONFIG_UDMABUF) += udmabuf.o
diff --git a/drivers/dma-buf/dma-buf.c b/drivers/dma-buf/dma-buf.c
index 13884474d158..02f7f9a89979 100644
--- a/drivers/dma-buf/dma-buf.c
+++ b/drivers/dma-buf/dma-buf.c
@@ -405,7 +405,6 @@ struct dma_buf *dma_buf_export(const struct dma_buf_export_info *exp_info)
405 || !exp_info->ops->map_dma_buf 405 || !exp_info->ops->map_dma_buf
406 || !exp_info->ops->unmap_dma_buf 406 || !exp_info->ops->unmap_dma_buf
407 || !exp_info->ops->release 407 || !exp_info->ops->release
408 || !exp_info->ops->map
409 || !exp_info->ops->mmap)) { 408 || !exp_info->ops->mmap)) {
410 return ERR_PTR(-EINVAL); 409 return ERR_PTR(-EINVAL);
411 } 410 }
diff --git a/drivers/dma-buf/udmabuf.c b/drivers/dma-buf/udmabuf.c
new file mode 100644
index 000000000000..2e8502250afe
--- /dev/null
+++ b/drivers/dma-buf/udmabuf.c
@@ -0,0 +1,288 @@
1// SPDX-License-Identifier: GPL-2.0
2#include <linux/init.h>
3#include <linux/module.h>
4#include <linux/device.h>
5#include <linux/kernel.h>
6#include <linux/slab.h>
7#include <linux/miscdevice.h>
8#include <linux/dma-buf.h>
9#include <linux/highmem.h>
10#include <linux/cred.h>
11#include <linux/shmem_fs.h>
12#include <linux/memfd.h>
13
14#include <uapi/linux/udmabuf.h>
15
16struct udmabuf {
17 u32 pagecount;
18 struct page **pages;
19};
20
21static int udmabuf_vm_fault(struct vm_fault *vmf)
22{
23 struct vm_area_struct *vma = vmf->vma;
24 struct udmabuf *ubuf = vma->vm_private_data;
25
26 if (WARN_ON(vmf->pgoff >= ubuf->pagecount))
27 return VM_FAULT_SIGBUS;
28
29 vmf->page = ubuf->pages[vmf->pgoff];
30 get_page(vmf->page);
31 return 0;
32}
33
34static const struct vm_operations_struct udmabuf_vm_ops = {
35 .fault = udmabuf_vm_fault,
36};
37
38static int mmap_udmabuf(struct dma_buf *buf, struct vm_area_struct *vma)
39{
40 struct udmabuf *ubuf = buf->priv;
41
42 if ((vma->vm_flags & (VM_SHARED | VM_MAYSHARE)) == 0)
43 return -EINVAL;
44
45 vma->vm_ops = &udmabuf_vm_ops;
46 vma->vm_private_data = ubuf;
47 return 0;
48}
49
50static struct sg_table *map_udmabuf(struct dma_buf_attachment *at,
51 enum dma_data_direction direction)
52{
53 struct udmabuf *ubuf = at->dmabuf->priv;
54 struct sg_table *sg;
55
56 sg = kzalloc(sizeof(*sg), GFP_KERNEL);
57 if (!sg)
58 goto err1;
59 if (sg_alloc_table_from_pages(sg, ubuf->pages, ubuf->pagecount,
60 0, ubuf->pagecount << PAGE_SHIFT,
61 GFP_KERNEL) < 0)
62 goto err2;
63 if (!dma_map_sg(at->dev, sg->sgl, sg->nents, direction))
64 goto err3;
65
66 return sg;
67
68err3:
69 sg_free_table(sg);
70err2:
71 kfree(sg);
72err1:
73 return ERR_PTR(-ENOMEM);
74}
75
76static void unmap_udmabuf(struct dma_buf_attachment *at,
77 struct sg_table *sg,
78 enum dma_data_direction direction)
79{
80 sg_free_table(sg);
81 kfree(sg);
82}
83
84static void release_udmabuf(struct dma_buf *buf)
85{
86 struct udmabuf *ubuf = buf->priv;
87 pgoff_t pg;
88
89 for (pg = 0; pg < ubuf->pagecount; pg++)
90 put_page(ubuf->pages[pg]);
91 kfree(ubuf->pages);
92 kfree(ubuf);
93}
94
95static void *kmap_udmabuf(struct dma_buf *buf, unsigned long page_num)
96{
97 struct udmabuf *ubuf = buf->priv;
98 struct page *page = ubuf->pages[page_num];
99
100 return kmap(page);
101}
102
103static void kunmap_udmabuf(struct dma_buf *buf, unsigned long page_num,
104 void *vaddr)
105{
106 kunmap(vaddr);
107}
108
109static struct dma_buf_ops udmabuf_ops = {
110 .map_dma_buf = map_udmabuf,
111 .unmap_dma_buf = unmap_udmabuf,
112 .release = release_udmabuf,
113 .map = kmap_udmabuf,
114 .unmap = kunmap_udmabuf,
115 .mmap = mmap_udmabuf,
116};
117
118#define SEALS_WANTED (F_SEAL_SHRINK)
119#define SEALS_DENIED (F_SEAL_WRITE)
120
121static long udmabuf_create(struct udmabuf_create_list *head,
122 struct udmabuf_create_item *list)
123{
124 DEFINE_DMA_BUF_EXPORT_INFO(exp_info);
125 struct file *memfd = NULL;
126 struct udmabuf *ubuf;
127 struct dma_buf *buf;
128 pgoff_t pgoff, pgcnt, pgidx, pgbuf;
129 struct page *page;
130 int seals, ret = -EINVAL;
131 u32 i, flags;
132
133 ubuf = kzalloc(sizeof(struct udmabuf), GFP_KERNEL);
134 if (!ubuf)
135 return -ENOMEM;
136
137 for (i = 0; i < head->count; i++) {
138 if (!IS_ALIGNED(list[i].offset, PAGE_SIZE))
139 goto err_free_ubuf;
140 if (!IS_ALIGNED(list[i].size, PAGE_SIZE))
141 goto err_free_ubuf;
142 ubuf->pagecount += list[i].size >> PAGE_SHIFT;
143 }
144 ubuf->pages = kmalloc_array(ubuf->pagecount, sizeof(struct page *),
145 GFP_KERNEL);
146 if (!ubuf->pages) {
147 ret = -ENOMEM;
148 goto err_free_ubuf;
149 }
150
151 pgbuf = 0;
152 for (i = 0; i < head->count; i++) {
153 memfd = fget(list[i].memfd);
154 if (!memfd)
155 goto err_put_pages;
156 if (!shmem_mapping(file_inode(memfd)->i_mapping))
157 goto err_put_pages;
158 seals = memfd_fcntl(memfd, F_GET_SEALS, 0);
159 if (seals == -EINVAL ||
160 (seals & SEALS_WANTED) != SEALS_WANTED ||
161 (seals & SEALS_DENIED) != 0)
162 goto err_put_pages;
163 pgoff = list[i].offset >> PAGE_SHIFT;
164 pgcnt = list[i].size >> PAGE_SHIFT;
165 for (pgidx = 0; pgidx < pgcnt; pgidx++) {
166 page = shmem_read_mapping_page(
167 file_inode(memfd)->i_mapping, pgoff + pgidx);
168 if (IS_ERR(page)) {
169 ret = PTR_ERR(page);
170 goto err_put_pages;
171 }
172 ubuf->pages[pgbuf++] = page;
173 }
174 fput(memfd);
175 }
176 memfd = NULL;
177
178 exp_info.ops = &udmabuf_ops;
179 exp_info.size = ubuf->pagecount << PAGE_SHIFT;
180 exp_info.priv = ubuf;
181
182 buf = dma_buf_export(&exp_info);
183 if (IS_ERR(buf)) {
184 ret = PTR_ERR(buf);
185 goto err_put_pages;
186 }
187
188 flags = 0;
189 if (head->flags & UDMABUF_FLAGS_CLOEXEC)
190 flags |= O_CLOEXEC;
191 return dma_buf_fd(buf, flags);
192
193err_put_pages:
194 while (pgbuf > 0)
195 put_page(ubuf->pages[--pgbuf]);
196err_free_ubuf:
197 if (memfd)
198 fput(memfd);
199 kfree(ubuf->pages);
200 kfree(ubuf);
201 return ret;
202}
203
204static long udmabuf_ioctl_create(struct file *filp, unsigned long arg)
205{
206 struct udmabuf_create create;
207 struct udmabuf_create_list head;
208 struct udmabuf_create_item list;
209
210 if (copy_from_user(&create, (void __user *)arg,
211 sizeof(struct udmabuf_create)))
212 return -EFAULT;
213
214 head.flags = create.flags;
215 head.count = 1;
216 list.memfd = create.memfd;
217 list.offset = create.offset;
218 list.size = create.size;
219
220 return udmabuf_create(&head, &list);
221}
222
223static long udmabuf_ioctl_create_list(struct file *filp, unsigned long arg)
224{
225 struct udmabuf_create_list head;
226 struct udmabuf_create_item *list;
227 int ret = -EINVAL;
228 u32 lsize;
229
230 if (copy_from_user(&head, (void __user *)arg, sizeof(head)))
231 return -EFAULT;
232 if (head.count > 1024)
233 return -EINVAL;
234 lsize = sizeof(struct udmabuf_create_item) * head.count;
235 list = memdup_user((void __user *)(arg + sizeof(head)), lsize);
236 if (IS_ERR(list))
237 return PTR_ERR(list);
238
239 ret = udmabuf_create(&head, list);
240 kfree(list);
241 return ret;
242}
243
244static long udmabuf_ioctl(struct file *filp, unsigned int ioctl,
245 unsigned long arg)
246{
247 long ret;
248
249 switch (ioctl) {
250 case UDMABUF_CREATE:
251 ret = udmabuf_ioctl_create(filp, arg);
252 break;
253 case UDMABUF_CREATE_LIST:
254 ret = udmabuf_ioctl_create_list(filp, arg);
255 break;
256 default:
257 ret = -EINVAL;
258 break;
259 }
260 return ret;
261}
262
263static const struct file_operations udmabuf_fops = {
264 .owner = THIS_MODULE,
265 .unlocked_ioctl = udmabuf_ioctl,
266};
267
268static struct miscdevice udmabuf_misc = {
269 .minor = MISC_DYNAMIC_MINOR,
270 .name = "udmabuf",
271 .fops = &udmabuf_fops,
272};
273
274static int __init udmabuf_dev_init(void)
275{
276 return misc_register(&udmabuf_misc);
277}
278
279static void __exit udmabuf_dev_exit(void)
280{
281 misc_deregister(&udmabuf_misc);
282}
283
284module_init(udmabuf_dev_init)
285module_exit(udmabuf_dev_exit)
286
287MODULE_AUTHOR("Gerd Hoffmann <kraxel@redhat.com>");
288MODULE_LICENSE("GPL v2");
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
index 8843a06360fa..6870909da926 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
@@ -785,28 +785,6 @@ MODULE_DEVICE_TABLE(pci, pciidlist);
785 785
786static struct drm_driver kms_driver; 786static struct drm_driver kms_driver;
787 787
788static int amdgpu_kick_out_firmware_fb(struct pci_dev *pdev)
789{
790 struct apertures_struct *ap;
791 bool primary = false;
792
793 ap = alloc_apertures(1);
794 if (!ap)
795 return -ENOMEM;
796
797 ap->ranges[0].base = pci_resource_start(pdev, 0);
798 ap->ranges[0].size = pci_resource_len(pdev, 0);
799
800#ifdef CONFIG_X86
801 primary = pdev->resource[PCI_ROM_RESOURCE].flags & IORESOURCE_ROM_SHADOW;
802#endif
803 drm_fb_helper_remove_conflicting_framebuffers(ap, "amdgpudrmfb", primary);
804 kfree(ap);
805
806 return 0;
807}
808
809
810static int amdgpu_pci_probe(struct pci_dev *pdev, 788static int amdgpu_pci_probe(struct pci_dev *pdev,
811 const struct pci_device_id *ent) 789 const struct pci_device_id *ent)
812{ 790{
@@ -834,7 +812,7 @@ static int amdgpu_pci_probe(struct pci_dev *pdev,
834 return ret; 812 return ret;
835 813
836 /* Get rid of things like offb */ 814 /* Get rid of things like offb */
837 ret = amdgpu_kick_out_firmware_fb(pdev); 815 ret = drm_fb_helper_remove_conflicting_pci_framebuffers(pdev, 0, "amdgpudrmfb");
838 if (ret) 816 if (ret)
839 return ret; 817 return ret;
840 818
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
index 800f481a6995..af6adffba788 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@ -896,6 +896,7 @@ amdgpu_dm_update_connector_after_detect(struct amdgpu_dm_connector *aconnector)
896 aconnector->dc_sink = sink; 896 aconnector->dc_sink = sink;
897 if (sink->dc_edid.length == 0) { 897 if (sink->dc_edid.length == 0) {
898 aconnector->edid = NULL; 898 aconnector->edid = NULL;
899 drm_dp_cec_unset_edid(&aconnector->dm_dp_aux.aux);
899 } else { 900 } else {
900 aconnector->edid = 901 aconnector->edid =
901 (struct edid *) sink->dc_edid.raw_edid; 902 (struct edid *) sink->dc_edid.raw_edid;
@@ -903,10 +904,13 @@ amdgpu_dm_update_connector_after_detect(struct amdgpu_dm_connector *aconnector)
903 904
904 drm_connector_update_edid_property(connector, 905 drm_connector_update_edid_property(connector,
905 aconnector->edid); 906 aconnector->edid);
907 drm_dp_cec_set_edid(&aconnector->dm_dp_aux.aux,
908 aconnector->edid);
906 } 909 }
907 amdgpu_dm_add_sink_to_freesync_module(connector, aconnector->edid); 910 amdgpu_dm_add_sink_to_freesync_module(connector, aconnector->edid);
908 911
909 } else { 912 } else {
913 drm_dp_cec_unset_edid(&aconnector->dm_dp_aux.aux);
910 amdgpu_dm_remove_sink_from_freesync_module(connector); 914 amdgpu_dm_remove_sink_from_freesync_module(connector);
911 drm_connector_update_edid_property(connector, NULL); 915 drm_connector_update_edid_property(connector, NULL);
912 aconnector->num_modes = 0; 916 aconnector->num_modes = 0;
@@ -1061,8 +1065,10 @@ static void handle_hpd_rx_irq(void *param)
1061 (dc_link->type == dc_connection_mst_branch)) 1065 (dc_link->type == dc_connection_mst_branch))
1062 dm_handle_hpd_rx_irq(aconnector); 1066 dm_handle_hpd_rx_irq(aconnector);
1063 1067
1064 if (dc_link->type != dc_connection_mst_branch) 1068 if (dc_link->type != dc_connection_mst_branch) {
1069 drm_dp_cec_irq(&aconnector->dm_dp_aux.aux);
1065 mutex_unlock(&aconnector->hpd_lock); 1070 mutex_unlock(&aconnector->hpd_lock);
1071 }
1066} 1072}
1067 1073
1068static void register_hpd_handlers(struct amdgpu_device *adev) 1074static void register_hpd_handlers(struct amdgpu_device *adev)
@@ -2595,6 +2601,7 @@ static const struct drm_crtc_funcs amdgpu_dm_crtc_funcs = {
2595 .atomic_duplicate_state = dm_crtc_duplicate_state, 2601 .atomic_duplicate_state = dm_crtc_duplicate_state,
2596 .atomic_destroy_state = dm_crtc_destroy_state, 2602 .atomic_destroy_state = dm_crtc_destroy_state,
2597 .set_crc_source = amdgpu_dm_crtc_set_crc_source, 2603 .set_crc_source = amdgpu_dm_crtc_set_crc_source,
2604 .verify_crc_source = amdgpu_dm_crtc_verify_crc_source,
2598 .enable_vblank = dm_enable_vblank, 2605 .enable_vblank = dm_enable_vblank,
2599 .disable_vblank = dm_disable_vblank, 2606 .disable_vblank = dm_disable_vblank,
2600}; 2607};
@@ -2730,6 +2737,7 @@ static void amdgpu_dm_connector_destroy(struct drm_connector *connector)
2730 dm->backlight_dev = NULL; 2737 dm->backlight_dev = NULL;
2731 } 2738 }
2732#endif 2739#endif
2740 drm_dp_cec_unregister_connector(&aconnector->dm_dp_aux.aux);
2733 drm_connector_unregister(connector); 2741 drm_connector_unregister(connector);
2734 drm_connector_cleanup(connector); 2742 drm_connector_cleanup(connector);
2735 kfree(connector); 2743 kfree(connector);
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
index a29dc35954c9..54056d180003 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
@@ -258,11 +258,14 @@ amdgpu_dm_remove_sink_from_freesync_module(struct drm_connector *connector);
258 258
259/* amdgpu_dm_crc.c */ 259/* amdgpu_dm_crc.c */
260#ifdef CONFIG_DEBUG_FS 260#ifdef CONFIG_DEBUG_FS
261int amdgpu_dm_crtc_set_crc_source(struct drm_crtc *crtc, const char *src_name, 261int amdgpu_dm_crtc_set_crc_source(struct drm_crtc *crtc, const char *src_name);
262 size_t *values_cnt); 262int amdgpu_dm_crtc_verify_crc_source(struct drm_crtc *crtc,
263 const char *src_name,
264 size_t *values_cnt);
263void amdgpu_dm_crtc_handle_crc_irq(struct drm_crtc *crtc); 265void amdgpu_dm_crtc_handle_crc_irq(struct drm_crtc *crtc);
264#else 266#else
265#define amdgpu_dm_crtc_set_crc_source NULL 267#define amdgpu_dm_crtc_set_crc_source NULL
268#define amdgpu_dm_crtc_verify_crc_source NULL
266#define amdgpu_dm_crtc_handle_crc_irq(x) 269#define amdgpu_dm_crtc_handle_crc_irq(x)
267#endif 270#endif
268 271
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crc.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crc.c
index 9bfb040352e9..01fc5717b657 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crc.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crc.c
@@ -46,8 +46,23 @@ static enum amdgpu_dm_pipe_crc_source dm_parse_crc_source(const char *source)
46 return AMDGPU_DM_PIPE_CRC_SOURCE_INVALID; 46 return AMDGPU_DM_PIPE_CRC_SOURCE_INVALID;
47} 47}
48 48
49int amdgpu_dm_crtc_set_crc_source(struct drm_crtc *crtc, const char *src_name, 49int
50 size_t *values_cnt) 50amdgpu_dm_crtc_verify_crc_source(struct drm_crtc *crtc, const char *src_name,
51 size_t *values_cnt)
52{
53 enum amdgpu_dm_pipe_crc_source source = dm_parse_crc_source(src_name);
54
55 if (source < 0) {
56 DRM_DEBUG_DRIVER("Unknown CRC source %s for CRTC%d\n",
57 src_name, crtc->index);
58 return -EINVAL;
59 }
60
61 *values_cnt = 3;
62 return 0;
63}
64
65int amdgpu_dm_crtc_set_crc_source(struct drm_crtc *crtc, const char *src_name)
51{ 66{
52 struct dm_crtc_state *crtc_state = to_dm_crtc_state(crtc->state); 67 struct dm_crtc_state *crtc_state = to_dm_crtc_state(crtc->state);
53 struct dc_stream_state *stream_state = crtc_state->stream; 68 struct dc_stream_state *stream_state = crtc_state->stream;
@@ -83,7 +98,6 @@ int amdgpu_dm_crtc_set_crc_source(struct drm_crtc *crtc, const char *src_name,
83 return -EINVAL; 98 return -EINVAL;
84 } 99 }
85 100
86 *values_cnt = 3;
87 /* Reset crc_skipped on dm state */ 101 /* Reset crc_skipped on dm state */
88 crtc_state->crc_skip_count = 0; 102 crtc_state->crc_skip_count = 0;
89 return 0; 103 return 0;
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c
index 9a300732ba37..18a3a6e5ffa0 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c
@@ -496,6 +496,8 @@ void amdgpu_dm_initialize_dp_connector(struct amdgpu_display_manager *dm,
496 aconnector->dm_dp_aux.ddc_service = aconnector->dc_link->ddc; 496 aconnector->dm_dp_aux.ddc_service = aconnector->dc_link->ddc;
497 497
498 drm_dp_aux_register(&aconnector->dm_dp_aux.aux); 498 drm_dp_aux_register(&aconnector->dm_dp_aux.aux);
499 drm_dp_cec_register_connector(&aconnector->dm_dp_aux.aux,
500 aconnector->base.name, dm->adev->dev);
499 aconnector->mst_mgr.cbs = &dm_mst_cbs; 501 aconnector->mst_mgr.cbs = &dm_mst_cbs;
500 drm_dp_mst_topology_mgr_init( 502 drm_dp_mst_topology_mgr_init(
501 &aconnector->mst_mgr, 503 &aconnector->mst_mgr,
diff --git a/drivers/gpu/drm/arm/malidp_planes.c b/drivers/gpu/drm/arm/malidp_planes.c
index 29409a65d864..49c37f6dd63e 100644
--- a/drivers/gpu/drm/arm/malidp_planes.c
+++ b/drivers/gpu/drm/arm/malidp_planes.c
@@ -78,11 +78,8 @@ static void malidp_plane_reset(struct drm_plane *plane)
78 kfree(state); 78 kfree(state);
79 plane->state = NULL; 79 plane->state = NULL;
80 state = kzalloc(sizeof(*state), GFP_KERNEL); 80 state = kzalloc(sizeof(*state), GFP_KERNEL);
81 if (state) { 81 if (state)
82 state->base.plane = plane; 82 __drm_atomic_helper_plane_reset(plane, &state->base);
83 state->base.rotation = DRM_MODE_ROTATE_0;
84 plane->state = &state->base;
85 }
86} 83}
87 84
88static struct 85static struct
diff --git a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c
index d73281095fac..9e34bce089d0 100644
--- a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c
+++ b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c
@@ -101,18 +101,34 @@ static void atmel_hlcdc_crtc_mode_set_nofb(struct drm_crtc *c)
101 (adj->crtc_hdisplay - 1) | 101 (adj->crtc_hdisplay - 1) |
102 ((adj->crtc_vdisplay - 1) << 16)); 102 ((adj->crtc_vdisplay - 1) << 16));
103 103
104 cfg = 0; 104 cfg = ATMEL_HLCDC_CLKSEL;
105 105
106 prate = clk_get_rate(crtc->dc->hlcdc->sys_clk); 106 prate = 2 * clk_get_rate(crtc->dc->hlcdc->sys_clk);
107 mode_rate = adj->crtc_clock * 1000; 107 mode_rate = adj->crtc_clock * 1000;
108 if ((prate / 2) < mode_rate) {
109 prate *= 2;
110 cfg |= ATMEL_HLCDC_CLKSEL;
111 }
112 108
113 div = DIV_ROUND_UP(prate, mode_rate); 109 div = DIV_ROUND_UP(prate, mode_rate);
114 if (div < 2) 110 if (div < 2) {
115 div = 2; 111 div = 2;
112 } else if (ATMEL_HLCDC_CLKDIV(div) & ~ATMEL_HLCDC_CLKDIV_MASK) {
113 /* The divider ended up too big, try a lower base rate. */
114 cfg &= ~ATMEL_HLCDC_CLKSEL;
115 prate /= 2;
116 div = DIV_ROUND_UP(prate, mode_rate);
117 if (ATMEL_HLCDC_CLKDIV(div) & ~ATMEL_HLCDC_CLKDIV_MASK)
118 div = ATMEL_HLCDC_CLKDIV_MASK;
119 } else {
120 int div_low = prate / mode_rate;
121
122 if (div_low >= 2 &&
123 ((prate / div_low - mode_rate) <
124 10 * (mode_rate - prate / div)))
125 /*
126 * At least 10 times better when using a higher
127 * frequency than requested, instead of a lower.
128 * So, go with that.
129 */
130 div = div_low;
131 }
116 132
117 cfg |= ATMEL_HLCDC_CLKDIV(div); 133 cfg |= ATMEL_HLCDC_CLKDIV(div);
118 134
@@ -226,6 +242,55 @@ static void atmel_hlcdc_crtc_atomic_enable(struct drm_crtc *c,
226#define ATMEL_HLCDC_RGB888_OUTPUT BIT(3) 242#define ATMEL_HLCDC_RGB888_OUTPUT BIT(3)
227#define ATMEL_HLCDC_OUTPUT_MODE_MASK GENMASK(3, 0) 243#define ATMEL_HLCDC_OUTPUT_MODE_MASK GENMASK(3, 0)
228 244
245static int atmel_hlcdc_connector_output_mode(struct drm_connector_state *state)
246{
247 struct drm_connector *connector = state->connector;
248 struct drm_display_info *info = &connector->display_info;
249 struct drm_encoder *encoder;
250 unsigned int supported_fmts = 0;
251 int j;
252
253 encoder = state->best_encoder;
254 if (!encoder)
255 encoder = connector->encoder;
256
257 switch (atmel_hlcdc_encoder_get_bus_fmt(encoder)) {
258 case 0:
259 break;
260 case MEDIA_BUS_FMT_RGB444_1X12:
261 return ATMEL_HLCDC_RGB444_OUTPUT;
262 case MEDIA_BUS_FMT_RGB565_1X16:
263 return ATMEL_HLCDC_RGB565_OUTPUT;
264 case MEDIA_BUS_FMT_RGB666_1X18:
265 return ATMEL_HLCDC_RGB666_OUTPUT;
266 case MEDIA_BUS_FMT_RGB888_1X24:
267 return ATMEL_HLCDC_RGB888_OUTPUT;
268 default:
269 return -EINVAL;
270 }
271
272 for (j = 0; j < info->num_bus_formats; j++) {
273 switch (info->bus_formats[j]) {
274 case MEDIA_BUS_FMT_RGB444_1X12:
275 supported_fmts |= ATMEL_HLCDC_RGB444_OUTPUT;
276 break;
277 case MEDIA_BUS_FMT_RGB565_1X16:
278 supported_fmts |= ATMEL_HLCDC_RGB565_OUTPUT;
279 break;
280 case MEDIA_BUS_FMT_RGB666_1X18:
281 supported_fmts |= ATMEL_HLCDC_RGB666_OUTPUT;
282 break;
283 case MEDIA_BUS_FMT_RGB888_1X24:
284 supported_fmts |= ATMEL_HLCDC_RGB888_OUTPUT;
285 break;
286 default:
287 break;
288 }
289 }
290
291 return supported_fmts;
292}
293
229static int atmel_hlcdc_crtc_select_output_mode(struct drm_crtc_state *state) 294static int atmel_hlcdc_crtc_select_output_mode(struct drm_crtc_state *state)
230{ 295{
231 unsigned int output_fmts = ATMEL_HLCDC_OUTPUT_MODE_MASK; 296 unsigned int output_fmts = ATMEL_HLCDC_OUTPUT_MODE_MASK;
@@ -238,31 +303,12 @@ static int atmel_hlcdc_crtc_select_output_mode(struct drm_crtc_state *state)
238 crtc = drm_crtc_to_atmel_hlcdc_crtc(state->crtc); 303 crtc = drm_crtc_to_atmel_hlcdc_crtc(state->crtc);
239 304
240 for_each_new_connector_in_state(state->state, connector, cstate, i) { 305 for_each_new_connector_in_state(state->state, connector, cstate, i) {
241 struct drm_display_info *info = &connector->display_info;
242 unsigned int supported_fmts = 0; 306 unsigned int supported_fmts = 0;
243 int j;
244 307
245 if (!cstate->crtc) 308 if (!cstate->crtc)
246 continue; 309 continue;
247 310
248 for (j = 0; j < info->num_bus_formats; j++) { 311 supported_fmts = atmel_hlcdc_connector_output_mode(cstate);
249 switch (info->bus_formats[j]) {
250 case MEDIA_BUS_FMT_RGB444_1X12:
251 supported_fmts |= ATMEL_HLCDC_RGB444_OUTPUT;
252 break;
253 case MEDIA_BUS_FMT_RGB565_1X16:
254 supported_fmts |= ATMEL_HLCDC_RGB565_OUTPUT;
255 break;
256 case MEDIA_BUS_FMT_RGB666_1X18:
257 supported_fmts |= ATMEL_HLCDC_RGB666_OUTPUT;
258 break;
259 case MEDIA_BUS_FMT_RGB888_1X24:
260 supported_fmts |= ATMEL_HLCDC_RGB888_OUTPUT;
261 break;
262 default:
263 break;
264 }
265 }
266 312
267 if (crtc->dc->desc->conflicting_output_formats) 313 if (crtc->dc->desc->conflicting_output_formats)
268 output_fmts &= supported_fmts; 314 output_fmts &= supported_fmts;
diff --git a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.h b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.h
index 60c937f42114..4cc1e03f0aee 100644
--- a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.h
+++ b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.h
@@ -441,5 +441,6 @@ void atmel_hlcdc_crtc_irq(struct drm_crtc *c);
441int atmel_hlcdc_crtc_create(struct drm_device *dev); 441int atmel_hlcdc_crtc_create(struct drm_device *dev);
442 442
443int atmel_hlcdc_create_outputs(struct drm_device *dev); 443int atmel_hlcdc_create_outputs(struct drm_device *dev);
444int atmel_hlcdc_encoder_get_bus_fmt(struct drm_encoder *encoder);
444 445
445#endif /* DRM_ATMEL_HLCDC_H */ 446#endif /* DRM_ATMEL_HLCDC_H */
diff --git a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_output.c b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_output.c
index 8db51fb131db..f73d8a92274e 100644
--- a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_output.c
+++ b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_output.c
@@ -27,33 +27,94 @@
27 27
28#include "atmel_hlcdc_dc.h" 28#include "atmel_hlcdc_dc.h"
29 29
30struct atmel_hlcdc_rgb_output {
31 struct drm_encoder encoder;
32 int bus_fmt;
33};
34
30static const struct drm_encoder_funcs atmel_hlcdc_panel_encoder_funcs = { 35static const struct drm_encoder_funcs atmel_hlcdc_panel_encoder_funcs = {
31 .destroy = drm_encoder_cleanup, 36 .destroy = drm_encoder_cleanup,
32}; 37};
33 38
39static struct atmel_hlcdc_rgb_output *
40atmel_hlcdc_encoder_to_rgb_output(struct drm_encoder *encoder)
41{
42 return container_of(encoder, struct atmel_hlcdc_rgb_output, encoder);
43}
44
45int atmel_hlcdc_encoder_get_bus_fmt(struct drm_encoder *encoder)
46{
47 struct atmel_hlcdc_rgb_output *output;
48
49 output = atmel_hlcdc_encoder_to_rgb_output(encoder);
50
51 return output->bus_fmt;
52}
53
54static int atmel_hlcdc_of_bus_fmt(const struct device_node *ep)
55{
56 u32 bus_width;
57 int ret;
58
59 ret = of_property_read_u32(ep, "bus-width", &bus_width);
60 if (ret == -EINVAL)
61 return 0;
62 if (ret)
63 return ret;
64
65 switch (bus_width) {
66 case 12:
67 return MEDIA_BUS_FMT_RGB444_1X12;
68 case 16:
69 return MEDIA_BUS_FMT_RGB565_1X16;
70 case 18:
71 return MEDIA_BUS_FMT_RGB666_1X18;
72 case 24:
73 return MEDIA_BUS_FMT_RGB888_1X24;
74 default:
75 return -EINVAL;
76 }
77}
78
34static int atmel_hlcdc_attach_endpoint(struct drm_device *dev, int endpoint) 79static int atmel_hlcdc_attach_endpoint(struct drm_device *dev, int endpoint)
35{ 80{
36 struct drm_encoder *encoder; 81 struct atmel_hlcdc_rgb_output *output;
82 struct device_node *ep;
37 struct drm_panel *panel; 83 struct drm_panel *panel;
38 struct drm_bridge *bridge; 84 struct drm_bridge *bridge;
39 int ret; 85 int ret;
40 86
87 ep = of_graph_get_endpoint_by_regs(dev->dev->of_node, 0, endpoint);
88 if (!ep)
89 return -ENODEV;
90
41 ret = drm_of_find_panel_or_bridge(dev->dev->of_node, 0, endpoint, 91 ret = drm_of_find_panel_or_bridge(dev->dev->of_node, 0, endpoint,
42 &panel, &bridge); 92 &panel, &bridge);
43 if (ret) 93 if (ret) {
94 of_node_put(ep);
44 return ret; 95 return ret;
96 }
45 97
46 encoder = devm_kzalloc(dev->dev, sizeof(*encoder), GFP_KERNEL); 98 output = devm_kzalloc(dev->dev, sizeof(*output), GFP_KERNEL);
47 if (!encoder) 99 if (!output) {
100 of_node_put(ep);
101 return -ENOMEM;
102 }
103
104 output->bus_fmt = atmel_hlcdc_of_bus_fmt(ep);
105 of_node_put(ep);
106 if (output->bus_fmt < 0) {
107 dev_err(dev->dev, "endpoint %d: invalid bus width\n", endpoint);
48 return -EINVAL; 108 return -EINVAL;
109 }
49 110
50 ret = drm_encoder_init(dev, encoder, 111 ret = drm_encoder_init(dev, &output->encoder,
51 &atmel_hlcdc_panel_encoder_funcs, 112 &atmel_hlcdc_panel_encoder_funcs,
52 DRM_MODE_ENCODER_NONE, NULL); 113 DRM_MODE_ENCODER_NONE, NULL);
53 if (ret) 114 if (ret)
54 return ret; 115 return ret;
55 116
56 encoder->possible_crtcs = 0x1; 117 output->encoder.possible_crtcs = 0x1;
57 118
58 if (panel) { 119 if (panel) {
59 bridge = drm_panel_bridge_add(panel, DRM_MODE_CONNECTOR_Unknown); 120 bridge = drm_panel_bridge_add(panel, DRM_MODE_CONNECTOR_Unknown);
@@ -62,7 +123,7 @@ static int atmel_hlcdc_attach_endpoint(struct drm_device *dev, int endpoint)
62 } 123 }
63 124
64 if (bridge) { 125 if (bridge) {
65 ret = drm_bridge_attach(encoder, bridge, NULL); 126 ret = drm_bridge_attach(&output->encoder, bridge, NULL);
66 if (!ret) 127 if (!ret)
67 return 0; 128 return 0;
68 129
@@ -70,7 +131,7 @@ static int atmel_hlcdc_attach_endpoint(struct drm_device *dev, int endpoint)
70 drm_panel_bridge_remove(bridge); 131 drm_panel_bridge_remove(bridge);
71 } 132 }
72 133
73 drm_encoder_cleanup(encoder); 134 drm_encoder_cleanup(&output->encoder);
74 135
75 return ret; 136 return ret;
76} 137}
@@ -78,12 +139,23 @@ static int atmel_hlcdc_attach_endpoint(struct drm_device *dev, int endpoint)
78int atmel_hlcdc_create_outputs(struct drm_device *dev) 139int atmel_hlcdc_create_outputs(struct drm_device *dev)
79{ 140{
80 int endpoint, ret = 0; 141 int endpoint, ret = 0;
142 int attached = 0;
81 143
82 for (endpoint = 0; !ret; endpoint++) 144 /*
145 * Always scan the first few endpoints even if we get -ENODEV,
146 * but keep going after that as long as we keep getting hits.
147 */
148 for (endpoint = 0; !ret || endpoint < 4; endpoint++) {
83 ret = atmel_hlcdc_attach_endpoint(dev, endpoint); 149 ret = atmel_hlcdc_attach_endpoint(dev, endpoint);
150 if (ret == -ENODEV)
151 continue;
152 if (ret)
153 break;
154 attached++;
155 }
84 156
85 /* At least one device was successfully attached.*/ 157 /* At least one device was successfully attached.*/
86 if (ret == -ENODEV && endpoint) 158 if (ret == -ENODEV && attached)
87 return 0; 159 return 0;
88 160
89 return ret; 161 return ret;
diff --git a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c
index 04440064b9b7..9330a076e15a 100644
--- a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c
+++ b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c
@@ -942,10 +942,7 @@ static void atmel_hlcdc_plane_reset(struct drm_plane *p)
942 "Failed to allocate initial plane state\n"); 942 "Failed to allocate initial plane state\n");
943 return; 943 return;
944 } 944 }
945 945 __drm_atomic_helper_plane_reset(p, &state->base);
946 p->state = &state->base;
947 p->state->alpha = DRM_BLEND_ALPHA_OPAQUE;
948 p->state->plane = p;
949 } 946 }
950} 947}
951 948
diff --git a/drivers/gpu/drm/bochs/bochs_drv.c b/drivers/gpu/drm/bochs/bochs_drv.c
index 7b20318483e4..c61b40c72b62 100644
--- a/drivers/gpu/drm/bochs/bochs_drv.c
+++ b/drivers/gpu/drm/bochs/bochs_drv.c
@@ -143,22 +143,6 @@ static const struct dev_pm_ops bochs_pm_ops = {
143/* ---------------------------------------------------------------------- */ 143/* ---------------------------------------------------------------------- */
144/* pci interface */ 144/* pci interface */
145 145
146static int bochs_kick_out_firmware_fb(struct pci_dev *pdev)
147{
148 struct apertures_struct *ap;
149
150 ap = alloc_apertures(1);
151 if (!ap)
152 return -ENOMEM;
153
154 ap->ranges[0].base = pci_resource_start(pdev, 0);
155 ap->ranges[0].size = pci_resource_len(pdev, 0);
156 drm_fb_helper_remove_conflicting_framebuffers(ap, "bochsdrmfb", false);
157 kfree(ap);
158
159 return 0;
160}
161
162static int bochs_pci_probe(struct pci_dev *pdev, 146static int bochs_pci_probe(struct pci_dev *pdev,
163 const struct pci_device_id *ent) 147 const struct pci_device_id *ent)
164{ 148{
@@ -171,7 +155,7 @@ static int bochs_pci_probe(struct pci_dev *pdev,
171 return -ENOMEM; 155 return -ENOMEM;
172 } 156 }
173 157
174 ret = bochs_kick_out_firmware_fb(pdev); 158 ret = drm_fb_helper_remove_conflicting_pci_framebuffers(pdev, 0, "bochsdrmfb");
175 if (ret) 159 if (ret)
176 return ret; 160 return ret;
177 161
diff --git a/drivers/gpu/drm/bochs/bochs_mm.c b/drivers/gpu/drm/bochs/bochs_mm.c
index 39cd08416773..c9c7097030ca 100644
--- a/drivers/gpu/drm/bochs/bochs_mm.c
+++ b/drivers/gpu/drm/bochs/bochs_mm.c
@@ -430,7 +430,7 @@ static void bochs_bo_unref(struct bochs_bo **bo)
430 return; 430 return;
431 431
432 tbo = &((*bo)->bo); 432 tbo = &((*bo)->bo);
433 ttm_bo_unref(&tbo); 433 ttm_bo_put(tbo);
434 *bo = NULL; 434 *bo = NULL;
435} 435}
436 436
diff --git a/drivers/gpu/drm/bridge/Kconfig b/drivers/gpu/drm/bridge/Kconfig
index bf6cad6c9178..9eeb8ef0b174 100644
--- a/drivers/gpu/drm/bridge/Kconfig
+++ b/drivers/gpu/drm/bridge/Kconfig
@@ -112,6 +112,14 @@ config DRM_THINE_THC63LVD1024
112 ---help--- 112 ---help---
113 Thine THC63LVD1024 LVDS/parallel converter driver. 113 Thine THC63LVD1024 LVDS/parallel converter driver.
114 114
115config DRM_TOSHIBA_TC358764
116 tristate "TC358764 DSI/LVDS bridge"
117 depends on DRM && DRM_PANEL
118 depends on OF
119 select DRM_MIPI_DSI
120 help
121 Toshiba TC358764 DSI/LVDS bridge driver.
122
115config DRM_TOSHIBA_TC358767 123config DRM_TOSHIBA_TC358767
116 tristate "Toshiba TC358767 eDP bridge" 124 tristate "Toshiba TC358767 eDP bridge"
117 depends on OF 125 depends on OF
@@ -128,6 +136,16 @@ config DRM_TI_TFP410
128 ---help--- 136 ---help---
129 Texas Instruments TFP410 DVI/HDMI Transmitter driver 137 Texas Instruments TFP410 DVI/HDMI Transmitter driver
130 138
139config DRM_TI_SN65DSI86
140 tristate "TI SN65DSI86 DSI to eDP bridge"
141 depends on OF
142 select DRM_KMS_HELPER
143 select REGMAP_I2C
144 select DRM_PANEL
145 select DRM_MIPI_DSI
146 help
147 Texas Instruments SN65DSI86 DSI to eDP Bridge driver
148
131source "drivers/gpu/drm/bridge/analogix/Kconfig" 149source "drivers/gpu/drm/bridge/analogix/Kconfig"
132 150
133source "drivers/gpu/drm/bridge/adv7511/Kconfig" 151source "drivers/gpu/drm/bridge/adv7511/Kconfig"
diff --git a/drivers/gpu/drm/bridge/Makefile b/drivers/gpu/drm/bridge/Makefile
index 35f88d48ec20..4934fcf5a6f8 100644
--- a/drivers/gpu/drm/bridge/Makefile
+++ b/drivers/gpu/drm/bridge/Makefile
@@ -10,8 +10,10 @@ obj-$(CONFIG_DRM_SIL_SII8620) += sil-sii8620.o
10obj-$(CONFIG_DRM_SII902X) += sii902x.o 10obj-$(CONFIG_DRM_SII902X) += sii902x.o
11obj-$(CONFIG_DRM_SII9234) += sii9234.o 11obj-$(CONFIG_DRM_SII9234) += sii9234.o
12obj-$(CONFIG_DRM_THINE_THC63LVD1024) += thc63lvd1024.o 12obj-$(CONFIG_DRM_THINE_THC63LVD1024) += thc63lvd1024.o
13obj-$(CONFIG_DRM_TOSHIBA_TC358764) += tc358764.o
13obj-$(CONFIG_DRM_TOSHIBA_TC358767) += tc358767.o 14obj-$(CONFIG_DRM_TOSHIBA_TC358767) += tc358767.o
14obj-$(CONFIG_DRM_ANALOGIX_DP) += analogix/ 15obj-$(CONFIG_DRM_ANALOGIX_DP) += analogix/
15obj-$(CONFIG_DRM_I2C_ADV7511) += adv7511/ 16obj-$(CONFIG_DRM_I2C_ADV7511) += adv7511/
17obj-$(CONFIG_DRM_TI_SN65DSI86) += ti-sn65dsi86.o
16obj-$(CONFIG_DRM_TI_TFP410) += ti-tfp410.o 18obj-$(CONFIG_DRM_TI_TFP410) += ti-tfp410.o
17obj-y += synopsys/ 19obj-y += synopsys/
diff --git a/drivers/gpu/drm/bridge/synopsys/Makefile b/drivers/gpu/drm/bridge/synopsys/Makefile
index 5dad97d920be..3e1b1e3d9533 100644
--- a/drivers/gpu/drm/bridge/synopsys/Makefile
+++ b/drivers/gpu/drm/bridge/synopsys/Makefile
@@ -1,5 +1,3 @@
1#ccflags-y := -Iinclude/drm
2
3obj-$(CONFIG_DRM_DW_HDMI) += dw-hdmi.o 1obj-$(CONFIG_DRM_DW_HDMI) += dw-hdmi.o
4obj-$(CONFIG_DRM_DW_HDMI_AHB_AUDIO) += dw-hdmi-ahb-audio.o 2obj-$(CONFIG_DRM_DW_HDMI_AHB_AUDIO) += dw-hdmi-ahb-audio.o
5obj-$(CONFIG_DRM_DW_HDMI_I2S_AUDIO) += dw-hdmi-i2s-audio.o 3obj-$(CONFIG_DRM_DW_HDMI_I2S_AUDIO) += dw-hdmi-i2s-audio.o
diff --git a/drivers/gpu/drm/bridge/tc358764.c b/drivers/gpu/drm/bridge/tc358764.c
new file mode 100644
index 000000000000..ee6b98efa9c2
--- /dev/null
+++ b/drivers/gpu/drm/bridge/tc358764.c
@@ -0,0 +1,499 @@
1// SPDX-License-Identifier: GPL-2.0
2/*
3 * Copyright (C) 2018 Samsung Electronics Co., Ltd
4 *
5 * Authors:
6 * Andrzej Hajda <a.hajda@samsung.com>
7 * Maciej Purski <m.purski@samsung.com>
8 */
9
10#include <drm/drm_atomic_helper.h>
11#include <drm/drm_crtc.h>
12#include <drm/drm_crtc_helper.h>
13#include <drm/drm_fb_helper.h>
14#include <drm/drm_mipi_dsi.h>
15#include <drm/drm_of.h>
16#include <drm/drm_panel.h>
17#include <drm/drmP.h>
18#include <linux/gpio/consumer.h>
19#include <linux/of_graph.h>
20#include <linux/regulator/consumer.h>
21#include <video/mipi_display.h>
22
23#define FLD_MASK(start, end) (((1 << ((start) - (end) + 1)) - 1) << (end))
24#define FLD_VAL(val, start, end) (((val) << (end)) & FLD_MASK(start, end))
25
26/* PPI layer registers */
27#define PPI_STARTPPI 0x0104 /* START control bit */
28#define PPI_LPTXTIMECNT 0x0114 /* LPTX timing signal */
29#define PPI_LANEENABLE 0x0134 /* Enables each lane */
30#define PPI_TX_RX_TA 0x013C /* BTA timing parameters */
31#define PPI_D0S_CLRSIPOCOUNT 0x0164 /* Assertion timer for Lane 0 */
32#define PPI_D1S_CLRSIPOCOUNT 0x0168 /* Assertion timer for Lane 1 */
33#define PPI_D2S_CLRSIPOCOUNT 0x016C /* Assertion timer for Lane 2 */
34#define PPI_D3S_CLRSIPOCOUNT 0x0170 /* Assertion timer for Lane 3 */
35#define PPI_START_FUNCTION 1
36
37/* DSI layer registers */
38#define DSI_STARTDSI 0x0204 /* START control bit of DSI-TX */
39#define DSI_LANEENABLE 0x0210 /* Enables each lane */
40#define DSI_RX_START 1
41
42/* Video path registers */
43#define VP_CTRL 0x0450 /* Video Path Control */
44#define VP_CTRL_MSF(v) FLD_VAL(v, 0, 0) /* Magic square in RGB666 */
45#define VP_CTRL_VTGEN(v) FLD_VAL(v, 4, 4) /* Use chip clock for timing */
46#define VP_CTRL_EVTMODE(v) FLD_VAL(v, 5, 5) /* Event mode */
47#define VP_CTRL_RGB888(v) FLD_VAL(v, 8, 8) /* RGB888 mode */
48#define VP_CTRL_VSDELAY(v) FLD_VAL(v, 31, 20) /* VSYNC delay */
49#define VP_CTRL_HSPOL BIT(17) /* Polarity of HSYNC signal */
50#define VP_CTRL_DEPOL BIT(18) /* Polarity of DE signal */
51#define VP_CTRL_VSPOL BIT(19) /* Polarity of VSYNC signal */
52#define VP_HTIM1 0x0454 /* Horizontal Timing Control 1 */
53#define VP_HTIM1_HBP(v) FLD_VAL(v, 24, 16)
54#define VP_HTIM1_HSYNC(v) FLD_VAL(v, 8, 0)
55#define VP_HTIM2 0x0458 /* Horizontal Timing Control 2 */
56#define VP_HTIM2_HFP(v) FLD_VAL(v, 24, 16)
57#define VP_HTIM2_HACT(v) FLD_VAL(v, 10, 0)
58#define VP_VTIM1 0x045C /* Vertical Timing Control 1 */
59#define VP_VTIM1_VBP(v) FLD_VAL(v, 23, 16)
60#define VP_VTIM1_VSYNC(v) FLD_VAL(v, 7, 0)
61#define VP_VTIM2 0x0460 /* Vertical Timing Control 2 */
62#define VP_VTIM2_VFP(v) FLD_VAL(v, 23, 16)
63#define VP_VTIM2_VACT(v) FLD_VAL(v, 10, 0)
64#define VP_VFUEN 0x0464 /* Video Frame Timing Update Enable */
65
66/* LVDS registers */
67#define LV_MX0003 0x0480 /* Mux input bit 0 to 3 */
68#define LV_MX0407 0x0484 /* Mux input bit 4 to 7 */
69#define LV_MX0811 0x0488 /* Mux input bit 8 to 11 */
70#define LV_MX1215 0x048C /* Mux input bit 12 to 15 */
71#define LV_MX1619 0x0490 /* Mux input bit 16 to 19 */
72#define LV_MX2023 0x0494 /* Mux input bit 20 to 23 */
73#define LV_MX2427 0x0498 /* Mux input bit 24 to 27 */
74#define LV_MX(b0, b1, b2, b3) (FLD_VAL(b0, 4, 0) | FLD_VAL(b1, 12, 8) | \
75 FLD_VAL(b2, 20, 16) | FLD_VAL(b3, 28, 24))
76
77/* Input bit numbers used in mux registers */
78enum {
79 LVI_R0,
80 LVI_R1,
81 LVI_R2,
82 LVI_R3,
83 LVI_R4,
84 LVI_R5,
85 LVI_R6,
86 LVI_R7,
87 LVI_G0,
88 LVI_G1,
89 LVI_G2,
90 LVI_G3,
91 LVI_G4,
92 LVI_G5,
93 LVI_G6,
94 LVI_G7,
95 LVI_B0,
96 LVI_B1,
97 LVI_B2,
98 LVI_B3,
99 LVI_B4,
100 LVI_B5,
101 LVI_B6,
102 LVI_B7,
103 LVI_HS,
104 LVI_VS,
105 LVI_DE,
106 LVI_L0
107};
108
109#define LV_CFG 0x049C /* LVDS Configuration */
110#define LV_PHY0 0x04A0 /* LVDS PHY 0 */
111#define LV_PHY0_RST(v) FLD_VAL(v, 22, 22) /* PHY reset */
112#define LV_PHY0_IS(v) FLD_VAL(v, 15, 14)
113#define LV_PHY0_ND(v) FLD_VAL(v, 4, 0) /* Frequency range select */
114#define LV_PHY0_PRBS_ON(v) FLD_VAL(v, 20, 16) /* Clock/Data Flag pins */
115
116/* System registers */
117#define SYS_RST 0x0504 /* System Reset */
118#define SYS_ID 0x0580 /* System ID */
119
120#define SYS_RST_I2CS BIT(0) /* Reset I2C-Slave controller */
121#define SYS_RST_I2CM BIT(1) /* Reset I2C-Master controller */
122#define SYS_RST_LCD BIT(2) /* Reset LCD controller */
123#define SYS_RST_BM BIT(3) /* Reset Bus Management controller */
124#define SYS_RST_DSIRX BIT(4) /* Reset DSI-RX and App controller */
125#define SYS_RST_REG BIT(5) /* Reset Register module */
126
127#define LPX_PERIOD 2
128#define TTA_SURE 3
129#define TTA_GET 0x20000
130
131/* Lane enable PPI and DSI register bits */
132#define LANEENABLE_CLEN BIT(0)
133#define LANEENABLE_L0EN BIT(1)
134#define LANEENABLE_L1EN BIT(2)
135#define LANEENABLE_L2EN BIT(3)
136#define LANEENABLE_L3EN BIT(4)
137
138/* LVCFG fields */
139#define LV_CFG_LVEN BIT(0)
140#define LV_CFG_LVDLINK BIT(1)
141#define LV_CFG_CLKPOL1 BIT(2)
142#define LV_CFG_CLKPOL2 BIT(3)
143
144static const char * const tc358764_supplies[] = {
145 "vddc", "vddio", "vddlvds"
146};
147
148struct tc358764 {
149 struct device *dev;
150 struct drm_bridge bridge;
151 struct drm_connector connector;
152 struct regulator_bulk_data supplies[ARRAY_SIZE(tc358764_supplies)];
153 struct gpio_desc *gpio_reset;
154 struct drm_panel *panel;
155 int error;
156};
157
158static int tc358764_clear_error(struct tc358764 *ctx)
159{
160 int ret = ctx->error;
161
162 ctx->error = 0;
163 return ret;
164}
165
166static void tc358764_read(struct tc358764 *ctx, u16 addr, u32 *val)
167{
168 struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
169 ssize_t ret;
170
171 if (ctx->error)
172 return;
173
174 cpu_to_le16s(&addr);
175 ret = mipi_dsi_generic_read(dsi, &addr, sizeof(addr), val, sizeof(*val));
176 if (ret >= 0)
177 le32_to_cpus(val);
178
179 dev_dbg(ctx->dev, "read: %d, addr: %d\n", addr, *val);
180}
181
182static void tc358764_write(struct tc358764 *ctx, u16 addr, u32 val)
183{
184 struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
185 ssize_t ret;
186 u8 data[6];
187
188 if (ctx->error)
189 return;
190
191 data[0] = addr;
192 data[1] = addr >> 8;
193 data[2] = val;
194 data[3] = val >> 8;
195 data[4] = val >> 16;
196 data[5] = val >> 24;
197
198 ret = mipi_dsi_generic_write(dsi, data, sizeof(data));
199 if (ret < 0)
200 ctx->error = ret;
201}
202
203static inline struct tc358764 *bridge_to_tc358764(struct drm_bridge *bridge)
204{
205 return container_of(bridge, struct tc358764, bridge);
206}
207
208static inline
209struct tc358764 *connector_to_tc358764(struct drm_connector *connector)
210{
211 return container_of(connector, struct tc358764, connector);
212}
213
214static int tc358764_init(struct tc358764 *ctx)
215{
216 u32 v = 0;
217
218 tc358764_read(ctx, SYS_ID, &v);
219 if (ctx->error)
220 return tc358764_clear_error(ctx);
221 dev_info(ctx->dev, "ID: %#x\n", v);
222
223 /* configure PPI counters */
224 tc358764_write(ctx, PPI_TX_RX_TA, TTA_GET | TTA_SURE);
225 tc358764_write(ctx, PPI_LPTXTIMECNT, LPX_PERIOD);
226 tc358764_write(ctx, PPI_D0S_CLRSIPOCOUNT, 5);
227 tc358764_write(ctx, PPI_D1S_CLRSIPOCOUNT, 5);
228 tc358764_write(ctx, PPI_D2S_CLRSIPOCOUNT, 5);
229 tc358764_write(ctx, PPI_D3S_CLRSIPOCOUNT, 5);
230
231 /* enable four data lanes and clock lane */
232 tc358764_write(ctx, PPI_LANEENABLE, LANEENABLE_L3EN | LANEENABLE_L2EN |
233 LANEENABLE_L1EN | LANEENABLE_L0EN | LANEENABLE_CLEN);
234 tc358764_write(ctx, DSI_LANEENABLE, LANEENABLE_L3EN | LANEENABLE_L2EN |
235 LANEENABLE_L1EN | LANEENABLE_L0EN | LANEENABLE_CLEN);
236
237 /* start */
238 tc358764_write(ctx, PPI_STARTPPI, PPI_START_FUNCTION);
239 tc358764_write(ctx, DSI_STARTDSI, DSI_RX_START);
240
241 /* configure video path */
242 tc358764_write(ctx, VP_CTRL, VP_CTRL_VSDELAY(15) | VP_CTRL_RGB888(1) |
243 VP_CTRL_EVTMODE(1) | VP_CTRL_HSPOL | VP_CTRL_VSPOL);
244
245 /* reset PHY */
246 tc358764_write(ctx, LV_PHY0, LV_PHY0_RST(1) |
247 LV_PHY0_PRBS_ON(4) | LV_PHY0_IS(2) | LV_PHY0_ND(6));
248 tc358764_write(ctx, LV_PHY0, LV_PHY0_PRBS_ON(4) | LV_PHY0_IS(2) |
249 LV_PHY0_ND(6));
250
251 /* reset bridge */
252 tc358764_write(ctx, SYS_RST, SYS_RST_LCD);
253
254 /* set bit order */
255 tc358764_write(ctx, LV_MX0003, LV_MX(LVI_R0, LVI_R1, LVI_R2, LVI_R3));
256 tc358764_write(ctx, LV_MX0407, LV_MX(LVI_R4, LVI_R7, LVI_R5, LVI_G0));
257 tc358764_write(ctx, LV_MX0811, LV_MX(LVI_G1, LVI_G2, LVI_G6, LVI_G7));
258 tc358764_write(ctx, LV_MX1215, LV_MX(LVI_G3, LVI_G4, LVI_G5, LVI_B0));
259 tc358764_write(ctx, LV_MX1619, LV_MX(LVI_B6, LVI_B7, LVI_B1, LVI_B2));
260 tc358764_write(ctx, LV_MX2023, LV_MX(LVI_B3, LVI_B4, LVI_B5, LVI_L0));
261 tc358764_write(ctx, LV_MX2427, LV_MX(LVI_HS, LVI_VS, LVI_DE, LVI_R6));
262 tc358764_write(ctx, LV_CFG, LV_CFG_CLKPOL2 | LV_CFG_CLKPOL1 |
263 LV_CFG_LVEN);
264
265 return tc358764_clear_error(ctx);
266}
267
268static void tc358764_reset(struct tc358764 *ctx)
269{
270 gpiod_set_value(ctx->gpio_reset, 1);
271 usleep_range(1000, 2000);
272 gpiod_set_value(ctx->gpio_reset, 0);
273 usleep_range(1000, 2000);
274}
275
276static int tc358764_get_modes(struct drm_connector *connector)
277{
278 struct tc358764 *ctx = connector_to_tc358764(connector);
279
280 return drm_panel_get_modes(ctx->panel);
281}
282
283static const
284struct drm_connector_helper_funcs tc358764_connector_helper_funcs = {
285 .get_modes = tc358764_get_modes,
286};
287
288static const struct drm_connector_funcs tc358764_connector_funcs = {
289 .fill_modes = drm_helper_probe_single_connector_modes,
290 .destroy = drm_connector_cleanup,
291 .reset = drm_atomic_helper_connector_reset,
292 .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
293 .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
294};
295
296static void tc358764_disable(struct drm_bridge *bridge)
297{
298 struct tc358764 *ctx = bridge_to_tc358764(bridge);
299 int ret = drm_panel_disable(bridge_to_tc358764(bridge)->panel);
300
301 if (ret < 0)
302 dev_err(ctx->dev, "error disabling panel (%d)\n", ret);
303}
304
305static void tc358764_post_disable(struct drm_bridge *bridge)
306{
307 struct tc358764 *ctx = bridge_to_tc358764(bridge);
308 int ret;
309
310 ret = drm_panel_unprepare(ctx->panel);
311 if (ret < 0)
312 dev_err(ctx->dev, "error unpreparing panel (%d)\n", ret);
313 tc358764_reset(ctx);
314 usleep_range(10000, 15000);
315 ret = regulator_bulk_disable(ARRAY_SIZE(ctx->supplies), ctx->supplies);
316 if (ret < 0)
317 dev_err(ctx->dev, "error disabling regulators (%d)\n", ret);
318}
319
320static void tc358764_pre_enable(struct drm_bridge *bridge)
321{
322 struct tc358764 *ctx = bridge_to_tc358764(bridge);
323 int ret;
324
325 ret = regulator_bulk_enable(ARRAY_SIZE(ctx->supplies), ctx->supplies);
326 if (ret < 0)
327 dev_err(ctx->dev, "error enabling regulators (%d)\n", ret);
328 usleep_range(10000, 15000);
329 tc358764_reset(ctx);
330 ret = tc358764_init(ctx);
331 if (ret < 0)
332 dev_err(ctx->dev, "error initializing bridge (%d)\n", ret);
333 ret = drm_panel_prepare(ctx->panel);
334 if (ret < 0)
335 dev_err(ctx->dev, "error preparing panel (%d)\n", ret);
336}
337
338static void tc358764_enable(struct drm_bridge *bridge)
339{
340 struct tc358764 *ctx = bridge_to_tc358764(bridge);
341 int ret = drm_panel_enable(ctx->panel);
342
343 if (ret < 0)
344 dev_err(ctx->dev, "error enabling panel (%d)\n", ret);
345}
346
347static int tc358764_attach(struct drm_bridge *bridge)
348{
349 struct tc358764 *ctx = bridge_to_tc358764(bridge);
350 struct drm_device *drm = bridge->dev;
351 int ret;
352
353 ctx->connector.polled = DRM_CONNECTOR_POLL_HPD;
354 ret = drm_connector_init(drm, &ctx->connector,
355 &tc358764_connector_funcs,
356 DRM_MODE_CONNECTOR_LVDS);
357 if (ret) {
358 DRM_ERROR("Failed to initialize connector\n");
359 return ret;
360 }
361
362 drm_connector_helper_add(&ctx->connector,
363 &tc358764_connector_helper_funcs);
364 drm_connector_attach_encoder(&ctx->connector, bridge->encoder);
365 drm_panel_attach(ctx->panel, &ctx->connector);
366 ctx->connector.funcs->reset(&ctx->connector);
367 drm_fb_helper_add_one_connector(drm->fb_helper, &ctx->connector);
368 drm_connector_register(&ctx->connector);
369
370 return 0;
371}
372
373static void tc358764_detach(struct drm_bridge *bridge)
374{
375 struct tc358764 *ctx = bridge_to_tc358764(bridge);
376 struct drm_device *drm = bridge->dev;
377
378 drm_connector_unregister(&ctx->connector);
379 drm_fb_helper_remove_one_connector(drm->fb_helper, &ctx->connector);
380 drm_panel_detach(ctx->panel);
381 ctx->panel = NULL;
382 drm_connector_unreference(&ctx->connector);
383}
384
385static const struct drm_bridge_funcs tc358764_bridge_funcs = {
386 .disable = tc358764_disable,
387 .post_disable = tc358764_post_disable,
388 .enable = tc358764_enable,
389 .pre_enable = tc358764_pre_enable,
390 .attach = tc358764_attach,
391 .detach = tc358764_detach,
392};
393
394static int tc358764_parse_dt(struct tc358764 *ctx)
395{
396 struct device *dev = ctx->dev;
397 int ret;
398
399 ctx->gpio_reset = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW);
400 if (IS_ERR(ctx->gpio_reset)) {
401 dev_err(dev, "no reset GPIO pin provided\n");
402 return PTR_ERR(ctx->gpio_reset);
403 }
404
405 ret = drm_of_find_panel_or_bridge(ctx->dev->of_node, 1, 0, &ctx->panel,
406 NULL);
407 if (ret && ret != -EPROBE_DEFER)
408 dev_err(dev, "cannot find panel (%d)\n", ret);
409
410 return ret;
411}
412
413static int tc358764_configure_regulators(struct tc358764 *ctx)
414{
415 int i, ret;
416
417 for (i = 0; i < ARRAY_SIZE(ctx->supplies); ++i)
418 ctx->supplies[i].supply = tc358764_supplies[i];
419
420 ret = devm_regulator_bulk_get(ctx->dev, ARRAY_SIZE(ctx->supplies),
421 ctx->supplies);
422 if (ret < 0)
423 dev_err(ctx->dev, "failed to get regulators: %d\n", ret);
424
425 return ret;
426}
427
428static int tc358764_probe(struct mipi_dsi_device *dsi)
429{
430 struct device *dev = &dsi->dev;
431 struct tc358764 *ctx;
432 int ret;
433
434 ctx = devm_kzalloc(dev, sizeof(struct tc358764), GFP_KERNEL);
435 if (!ctx)
436 return -ENOMEM;
437
438 mipi_dsi_set_drvdata(dsi, ctx);
439
440 ctx->dev = dev;
441
442 dsi->lanes = 4;
443 dsi->format = MIPI_DSI_FMT_RGB888;
444 dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST
445 | MIPI_DSI_MODE_VIDEO_AUTO_VERT | MIPI_DSI_MODE_LPM;
446
447 ret = tc358764_parse_dt(ctx);
448 if (ret < 0)
449 return ret;
450
451 ret = tc358764_configure_regulators(ctx);
452 if (ret < 0)
453 return ret;
454
455 ctx->bridge.funcs = &tc358764_bridge_funcs;
456 ctx->bridge.of_node = dev->of_node;
457
458 drm_bridge_add(&ctx->bridge);
459
460 ret = mipi_dsi_attach(dsi);
461 if (ret < 0) {
462 drm_bridge_remove(&ctx->bridge);
463 dev_err(dev, "failed to attach dsi\n");
464 }
465
466 return ret;
467}
468
469static int tc358764_remove(struct mipi_dsi_device *dsi)
470{
471 struct tc358764 *ctx = mipi_dsi_get_drvdata(dsi);
472
473 mipi_dsi_detach(dsi);
474 drm_bridge_remove(&ctx->bridge);
475
476 return 0;
477}
478
479static const struct of_device_id tc358764_of_match[] = {
480 { .compatible = "toshiba,tc358764" },
481 { }
482};
483MODULE_DEVICE_TABLE(of, tc358764_of_match);
484
485static struct mipi_dsi_driver tc358764_driver = {
486 .probe = tc358764_probe,
487 .remove = tc358764_remove,
488 .driver = {
489 .name = "tc358764",
490 .owner = THIS_MODULE,
491 .of_match_table = tc358764_of_match,
492 },
493};
494module_mipi_dsi_driver(tc358764_driver);
495
496MODULE_AUTHOR("Andrzej Hajda <a.hajda@samsung.com>");
497MODULE_AUTHOR("Maciej Purski <m.purski@samsung.com>");
498MODULE_DESCRIPTION("MIPI-DSI based Driver for TC358764 DSI/LVDS Bridge");
499MODULE_LICENSE("GPL v2");
diff --git a/drivers/gpu/drm/bridge/ti-sn65dsi86.c b/drivers/gpu/drm/bridge/ti-sn65dsi86.c
new file mode 100644
index 000000000000..f8a931cf3665
--- /dev/null
+++ b/drivers/gpu/drm/bridge/ti-sn65dsi86.c
@@ -0,0 +1,779 @@
1// SPDX-License-Identifier: GPL-2.0
2/*
3 * Copyright (c) 2018, The Linux Foundation. All rights reserved.
4 */
5
6#include <drm/drmP.h>
7#include <drm/drm_atomic.h>
8#include <drm/drm_atomic_helper.h>
9#include <drm/drm_crtc_helper.h>
10#include <drm/drm_dp_helper.h>
11#include <drm/drm_mipi_dsi.h>
12#include <drm/drm_of.h>
13#include <drm/drm_panel.h>
14#include <linux/clk.h>
15#include <linux/gpio/consumer.h>
16#include <linux/i2c.h>
17#include <linux/iopoll.h>
18#include <linux/of_graph.h>
19#include <linux/pm_runtime.h>
20#include <linux/regmap.h>
21#include <linux/regulator/consumer.h>
22
23#define SN_DEVICE_REV_REG 0x08
24#define SN_DPPLL_SRC_REG 0x0A
25#define DPPLL_CLK_SRC_DSICLK BIT(0)
26#define REFCLK_FREQ_MASK GENMASK(3, 1)
27#define REFCLK_FREQ(x) ((x) << 1)
28#define DPPLL_SRC_DP_PLL_LOCK BIT(7)
29#define SN_PLL_ENABLE_REG 0x0D
30#define SN_DSI_LANES_REG 0x10
31#define CHA_DSI_LANES_MASK GENMASK(4, 3)
32#define CHA_DSI_LANES(x) ((x) << 3)
33#define SN_DSIA_CLK_FREQ_REG 0x12
34#define SN_CHA_ACTIVE_LINE_LENGTH_LOW_REG 0x20
35#define SN_CHA_VERTICAL_DISPLAY_SIZE_LOW_REG 0x24
36#define SN_CHA_HSYNC_PULSE_WIDTH_LOW_REG 0x2C
37#define SN_CHA_HSYNC_PULSE_WIDTH_HIGH_REG 0x2D
38#define CHA_HSYNC_POLARITY BIT(7)
39#define SN_CHA_VSYNC_PULSE_WIDTH_LOW_REG 0x30
40#define SN_CHA_VSYNC_PULSE_WIDTH_HIGH_REG 0x31
41#define CHA_VSYNC_POLARITY BIT(7)
42#define SN_CHA_HORIZONTAL_BACK_PORCH_REG 0x34
43#define SN_CHA_VERTICAL_BACK_PORCH_REG 0x36
44#define SN_CHA_HORIZONTAL_FRONT_PORCH_REG 0x38
45#define SN_CHA_VERTICAL_FRONT_PORCH_REG 0x3A
46#define SN_ENH_FRAME_REG 0x5A
47#define VSTREAM_ENABLE BIT(3)
48#define SN_DATA_FORMAT_REG 0x5B
49#define SN_HPD_DISABLE_REG 0x5C
50#define HPD_DISABLE BIT(0)
51#define SN_AUX_WDATA_REG(x) (0x64 + (x))
52#define SN_AUX_ADDR_19_16_REG 0x74
53#define SN_AUX_ADDR_15_8_REG 0x75
54#define SN_AUX_ADDR_7_0_REG 0x76
55#define SN_AUX_LENGTH_REG 0x77
56#define SN_AUX_CMD_REG 0x78
57#define AUX_CMD_SEND BIT(1)
58#define AUX_CMD_REQ(x) ((x) << 4)
59#define SN_AUX_RDATA_REG(x) (0x79 + (x))
60#define SN_SSC_CONFIG_REG 0x93
61#define DP_NUM_LANES_MASK GENMASK(5, 4)
62#define DP_NUM_LANES(x) ((x) << 4)
63#define SN_DATARATE_CONFIG_REG 0x94
64#define DP_DATARATE_MASK GENMASK(7, 5)
65#define DP_DATARATE(x) ((x) << 5)
66#define SN_ML_TX_MODE_REG 0x96
67#define ML_TX_MAIN_LINK_OFF 0
68#define ML_TX_NORMAL_MODE BIT(0)
69#define SN_AUX_CMD_STATUS_REG 0xF4
70#define AUX_IRQ_STATUS_AUX_RPLY_TOUT BIT(3)
71#define AUX_IRQ_STATUS_AUX_SHORT BIT(5)
72#define AUX_IRQ_STATUS_NAT_I2C_FAIL BIT(6)
73
74#define MIN_DSI_CLK_FREQ_MHZ 40
75
76/* fudge factor required to account for 8b/10b encoding */
77#define DP_CLK_FUDGE_NUM 10
78#define DP_CLK_FUDGE_DEN 8
79
80/* Matches DP_AUX_MAX_PAYLOAD_BYTES (for now) */
81#define SN_AUX_MAX_PAYLOAD_BYTES 16
82
83#define SN_REGULATOR_SUPPLY_NUM 4
84
85struct ti_sn_bridge {
86 struct device *dev;
87 struct regmap *regmap;
88 struct drm_dp_aux aux;
89 struct drm_bridge bridge;
90 struct drm_connector connector;
91 struct device_node *host_node;
92 struct mipi_dsi_device *dsi;
93 struct clk *refclk;
94 struct drm_panel *panel;
95 struct gpio_desc *enable_gpio;
96 struct regulator_bulk_data supplies[SN_REGULATOR_SUPPLY_NUM];
97};
98
99static const struct regmap_range ti_sn_bridge_volatile_ranges[] = {
100 { .range_min = 0, .range_max = 0xFF },
101};
102
103static const struct regmap_access_table ti_sn_bridge_volatile_table = {
104 .yes_ranges = ti_sn_bridge_volatile_ranges,
105 .n_yes_ranges = ARRAY_SIZE(ti_sn_bridge_volatile_ranges),
106};
107
108static const struct regmap_config ti_sn_bridge_regmap_config = {
109 .reg_bits = 8,
110 .val_bits = 8,
111 .volatile_table = &ti_sn_bridge_volatile_table,
112 .cache_type = REGCACHE_NONE,
113};
114
115static void ti_sn_bridge_write_u16(struct ti_sn_bridge *pdata,
116 unsigned int reg, u16 val)
117{
118 regmap_write(pdata->regmap, reg, val & 0xFF);
119 regmap_write(pdata->regmap, reg + 1, val >> 8);
120}
121
122static int __maybe_unused ti_sn_bridge_resume(struct device *dev)
123{
124 struct ti_sn_bridge *pdata = dev_get_drvdata(dev);
125 int ret;
126
127 ret = regulator_bulk_enable(SN_REGULATOR_SUPPLY_NUM, pdata->supplies);
128 if (ret) {
129 DRM_ERROR("failed to enable supplies %d\n", ret);
130 return ret;
131 }
132
133 gpiod_set_value(pdata->enable_gpio, 1);
134
135 return ret;
136}
137
138static int __maybe_unused ti_sn_bridge_suspend(struct device *dev)
139{
140 struct ti_sn_bridge *pdata = dev_get_drvdata(dev);
141 int ret;
142
143 gpiod_set_value(pdata->enable_gpio, 0);
144
145 ret = regulator_bulk_disable(SN_REGULATOR_SUPPLY_NUM, pdata->supplies);
146 if (ret)
147 DRM_ERROR("failed to disable supplies %d\n", ret);
148
149 return ret;
150}
151
152static const struct dev_pm_ops ti_sn_bridge_pm_ops = {
153 SET_RUNTIME_PM_OPS(ti_sn_bridge_suspend, ti_sn_bridge_resume, NULL)
154};
155
156/* Connector funcs */
157static struct ti_sn_bridge *
158connector_to_ti_sn_bridge(struct drm_connector *connector)
159{
160 return container_of(connector, struct ti_sn_bridge, connector);
161}
162
163static int ti_sn_bridge_connector_get_modes(struct drm_connector *connector)
164{
165 struct ti_sn_bridge *pdata = connector_to_ti_sn_bridge(connector);
166
167 return drm_panel_get_modes(pdata->panel);
168}
169
170static enum drm_mode_status
171ti_sn_bridge_connector_mode_valid(struct drm_connector *connector,
172 struct drm_display_mode *mode)
173{
174 /* maximum supported resolution is 4K at 60 fps */
175 if (mode->clock > 594000)
176 return MODE_CLOCK_HIGH;
177
178 return MODE_OK;
179}
180
181static struct drm_connector_helper_funcs ti_sn_bridge_connector_helper_funcs = {
182 .get_modes = ti_sn_bridge_connector_get_modes,
183 .mode_valid = ti_sn_bridge_connector_mode_valid,
184};
185
186static enum drm_connector_status
187ti_sn_bridge_connector_detect(struct drm_connector *connector, bool force)
188{
189 /**
190 * TODO: Currently if drm_panel is present, then always
191 * return the status as connected. Need to add support to detect
192 * device state for hot pluggable scenarios.
193 */
194 return connector_status_connected;
195}
196
197static const struct drm_connector_funcs ti_sn_bridge_connector_funcs = {
198 .fill_modes = drm_helper_probe_single_connector_modes,
199 .detect = ti_sn_bridge_connector_detect,
200 .destroy = drm_connector_cleanup,
201 .reset = drm_atomic_helper_connector_reset,
202 .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
203 .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
204};
205
206static struct ti_sn_bridge *bridge_to_ti_sn_bridge(struct drm_bridge *bridge)
207{
208 return container_of(bridge, struct ti_sn_bridge, bridge);
209}
210
211static int ti_sn_bridge_parse_regulators(struct ti_sn_bridge *pdata)
212{
213 unsigned int i;
214 const char * const ti_sn_bridge_supply_names[] = {
215 "vcca", "vcc", "vccio", "vpll",
216 };
217
218 for (i = 0; i < SN_REGULATOR_SUPPLY_NUM; i++)
219 pdata->supplies[i].supply = ti_sn_bridge_supply_names[i];
220
221 return devm_regulator_bulk_get(pdata->dev, SN_REGULATOR_SUPPLY_NUM,
222 pdata->supplies);
223}
224
225static int ti_sn_bridge_attach(struct drm_bridge *bridge)
226{
227 int ret, val;
228 struct ti_sn_bridge *pdata = bridge_to_ti_sn_bridge(bridge);
229 struct mipi_dsi_host *host;
230 struct mipi_dsi_device *dsi;
231 const struct mipi_dsi_device_info info = { .type = "ti_sn_bridge",
232 .channel = 0,
233 .node = NULL,
234 };
235
236 ret = drm_connector_init(bridge->dev, &pdata->connector,
237 &ti_sn_bridge_connector_funcs,
238 DRM_MODE_CONNECTOR_eDP);
239 if (ret) {
240 DRM_ERROR("Failed to initialize connector with drm\n");
241 return ret;
242 }
243
244 drm_connector_helper_add(&pdata->connector,
245 &ti_sn_bridge_connector_helper_funcs);
246 drm_connector_attach_encoder(&pdata->connector, bridge->encoder);
247
248 /*
249 * TODO: ideally finding host resource and dsi dev registration needs
250 * to be done in bridge probe. But some existing DSI host drivers will
251 * wait for any of the drm_bridge/drm_panel to get added to the global
252 * bridge/panel list, before completing their probe. So if we do the
253 * dsi dev registration part in bridge probe, before populating in
254 * the global bridge list, then it will cause deadlock as dsi host probe
255 * will never complete, neither our bridge probe. So keeping it here
256 * will satisfy most of the existing host drivers. Once the host driver
257 * is fixed we can move the below code to bridge probe safely.
258 */
259 host = of_find_mipi_dsi_host_by_node(pdata->host_node);
260 if (!host) {
261 DRM_ERROR("failed to find dsi host\n");
262 ret = -ENODEV;
263 goto err_dsi_host;
264 }
265
266 dsi = mipi_dsi_device_register_full(host, &info);
267 if (IS_ERR(dsi)) {
268 DRM_ERROR("failed to create dsi device\n");
269 ret = PTR_ERR(dsi);
270 goto err_dsi_host;
271 }
272
273 /* TODO: setting to 4 lanes always for now */
274 dsi->lanes = 4;
275 dsi->format = MIPI_DSI_FMT_RGB888;
276 dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_SYNC_PULSE |
277 MIPI_DSI_MODE_EOT_PACKET | MIPI_DSI_MODE_VIDEO_HSE;
278
279 /* check if continuous dsi clock is required or not */
280 pm_runtime_get_sync(pdata->dev);
281 regmap_read(pdata->regmap, SN_DPPLL_SRC_REG, &val);
282 pm_runtime_put(pdata->dev);
283 if (!(val & DPPLL_CLK_SRC_DSICLK))
284 dsi->mode_flags |= MIPI_DSI_CLOCK_NON_CONTINUOUS;
285
286 ret = mipi_dsi_attach(dsi);
287 if (ret < 0) {
288 DRM_ERROR("failed to attach dsi to host\n");
289 goto err_dsi_attach;
290 }
291 pdata->dsi = dsi;
292
293 /* attach panel to bridge */
294 drm_panel_attach(pdata->panel, &pdata->connector);
295
296 return 0;
297
298err_dsi_attach:
299 mipi_dsi_device_unregister(dsi);
300err_dsi_host:
301 drm_connector_cleanup(&pdata->connector);
302 return ret;
303}
304
305static void ti_sn_bridge_disable(struct drm_bridge *bridge)
306{
307 struct ti_sn_bridge *pdata = bridge_to_ti_sn_bridge(bridge);
308
309 drm_panel_disable(pdata->panel);
310
311 /* disable video stream */
312 regmap_update_bits(pdata->regmap, SN_ENH_FRAME_REG, VSTREAM_ENABLE, 0);
313 /* semi auto link training mode OFF */
314 regmap_write(pdata->regmap, SN_ML_TX_MODE_REG, 0);
315 /* disable DP PLL */
316 regmap_write(pdata->regmap, SN_PLL_ENABLE_REG, 0);
317
318 drm_panel_unprepare(pdata->panel);
319}
320
321static u32 ti_sn_bridge_get_dsi_freq(struct ti_sn_bridge *pdata)
322{
323 u32 bit_rate_khz, clk_freq_khz;
324 struct drm_display_mode *mode =
325 &pdata->bridge.encoder->crtc->state->adjusted_mode;
326
327 bit_rate_khz = mode->clock *
328 mipi_dsi_pixel_format_to_bpp(pdata->dsi->format);
329 clk_freq_khz = bit_rate_khz / (pdata->dsi->lanes * 2);
330
331 return clk_freq_khz;
332}
333
334/* clk frequencies supported by bridge in Hz in case derived from REFCLK pin */
335static const u32 ti_sn_bridge_refclk_lut[] = {
336 12000000,
337 19200000,
338 26000000,
339 27000000,
340 38400000,
341};
342
343/* clk frequencies supported by bridge in Hz in case derived from DACP/N pin */
344static const u32 ti_sn_bridge_dsiclk_lut[] = {
345 468000000,
346 384000000,
347 416000000,
348 486000000,
349 460800000,
350};
351
352static void ti_sn_bridge_set_refclk_freq(struct ti_sn_bridge *pdata)
353{
354 int i;
355 u32 refclk_rate;
356 const u32 *refclk_lut;
357 size_t refclk_lut_size;
358
359 if (pdata->refclk) {
360 refclk_rate = clk_get_rate(pdata->refclk);
361 refclk_lut = ti_sn_bridge_refclk_lut;
362 refclk_lut_size = ARRAY_SIZE(ti_sn_bridge_refclk_lut);
363 clk_prepare_enable(pdata->refclk);
364 } else {
365 refclk_rate = ti_sn_bridge_get_dsi_freq(pdata) * 1000;
366 refclk_lut = ti_sn_bridge_dsiclk_lut;
367 refclk_lut_size = ARRAY_SIZE(ti_sn_bridge_dsiclk_lut);
368 }
369
370 /* for i equals to refclk_lut_size means default frequency */
371 for (i = 0; i < refclk_lut_size; i++)
372 if (refclk_lut[i] == refclk_rate)
373 break;
374
375 regmap_update_bits(pdata->regmap, SN_DPPLL_SRC_REG, REFCLK_FREQ_MASK,
376 REFCLK_FREQ(i));
377}
378
379/**
380 * LUT index corresponds to register value and
381 * LUT values corresponds to dp data rate supported
382 * by the bridge in Mbps unit.
383 */
384static const unsigned int ti_sn_bridge_dp_rate_lut[] = {
385 0, 1620, 2160, 2430, 2700, 3240, 4320, 5400
386};
387
388static void ti_sn_bridge_set_dsi_dp_rate(struct ti_sn_bridge *pdata)
389{
390 unsigned int bit_rate_mhz, clk_freq_mhz, dp_rate_mhz;
391 unsigned int val, i;
392 struct drm_display_mode *mode =
393 &pdata->bridge.encoder->crtc->state->adjusted_mode;
394
395 /* set DSIA clk frequency */
396 bit_rate_mhz = (mode->clock / 1000) *
397 mipi_dsi_pixel_format_to_bpp(pdata->dsi->format);
398 clk_freq_mhz = bit_rate_mhz / (pdata->dsi->lanes * 2);
399
400 /* for each increment in val, frequency increases by 5MHz */
401 val = (MIN_DSI_CLK_FREQ_MHZ / 5) +
402 (((clk_freq_mhz - MIN_DSI_CLK_FREQ_MHZ) / 5) & 0xFF);
403 regmap_write(pdata->regmap, SN_DSIA_CLK_FREQ_REG, val);
404
405 /* set DP data rate */
406 dp_rate_mhz = ((bit_rate_mhz / pdata->dsi->lanes) * DP_CLK_FUDGE_NUM) /
407 DP_CLK_FUDGE_DEN;
408 for (i = 0; i < ARRAY_SIZE(ti_sn_bridge_dp_rate_lut) - 1; i++)
409 if (ti_sn_bridge_dp_rate_lut[i] > dp_rate_mhz)
410 break;
411
412 regmap_update_bits(pdata->regmap, SN_DATARATE_CONFIG_REG,
413 DP_DATARATE_MASK, DP_DATARATE(i));
414}
415
416static void ti_sn_bridge_set_video_timings(struct ti_sn_bridge *pdata)
417{
418 struct drm_display_mode *mode =
419 &pdata->bridge.encoder->crtc->state->adjusted_mode;
420 u8 hsync_polarity = 0, vsync_polarity = 0;
421
422 if (mode->flags & DRM_MODE_FLAG_PHSYNC)
423 hsync_polarity = CHA_HSYNC_POLARITY;
424 if (mode->flags & DRM_MODE_FLAG_PVSYNC)
425 vsync_polarity = CHA_VSYNC_POLARITY;
426
427 ti_sn_bridge_write_u16(pdata, SN_CHA_ACTIVE_LINE_LENGTH_LOW_REG,
428 mode->hdisplay);
429 ti_sn_bridge_write_u16(pdata, SN_CHA_VERTICAL_DISPLAY_SIZE_LOW_REG,
430 mode->vdisplay);
431 regmap_write(pdata->regmap, SN_CHA_HSYNC_PULSE_WIDTH_LOW_REG,
432 (mode->hsync_end - mode->hsync_start) & 0xFF);
433 regmap_write(pdata->regmap, SN_CHA_HSYNC_PULSE_WIDTH_HIGH_REG,
434 (((mode->hsync_end - mode->hsync_start) >> 8) & 0x7F) |
435 hsync_polarity);
436 regmap_write(pdata->regmap, SN_CHA_VSYNC_PULSE_WIDTH_LOW_REG,
437 (mode->vsync_end - mode->vsync_start) & 0xFF);
438 regmap_write(pdata->regmap, SN_CHA_VSYNC_PULSE_WIDTH_HIGH_REG,
439 (((mode->vsync_end - mode->vsync_start) >> 8) & 0x7F) |
440 vsync_polarity);
441
442 regmap_write(pdata->regmap, SN_CHA_HORIZONTAL_BACK_PORCH_REG,
443 (mode->htotal - mode->hsync_end) & 0xFF);
444 regmap_write(pdata->regmap, SN_CHA_VERTICAL_BACK_PORCH_REG,
445 (mode->vtotal - mode->vsync_end) & 0xFF);
446
447 regmap_write(pdata->regmap, SN_CHA_HORIZONTAL_FRONT_PORCH_REG,
448 (mode->hsync_start - mode->hdisplay) & 0xFF);
449 regmap_write(pdata->regmap, SN_CHA_VERTICAL_FRONT_PORCH_REG,
450 (mode->vsync_start - mode->vdisplay) & 0xFF);
451
452 usleep_range(10000, 10500); /* 10ms delay recommended by spec */
453}
454
455static void ti_sn_bridge_enable(struct drm_bridge *bridge)
456{
457 struct ti_sn_bridge *pdata = bridge_to_ti_sn_bridge(bridge);
458 unsigned int val;
459 int ret;
460
461 /*
462 * FIXME:
463 * This 70ms was found necessary by experimentation. If it's not
464 * present, link training fails. It seems like it can go anywhere from
465 * pre_enable() up to semi-auto link training initiation below.
466 *
467 * Neither the datasheet for the bridge nor the panel tested mention a
468 * delay of this magnitude in the timing requirements. So for now, add
469 * the mystery delay until someone figures out a better fix.
470 */
471 msleep(70);
472
473 /* DSI_A lane config */
474 val = CHA_DSI_LANES(4 - pdata->dsi->lanes);
475 regmap_update_bits(pdata->regmap, SN_DSI_LANES_REG,
476 CHA_DSI_LANES_MASK, val);
477
478 /* DP lane config */
479 val = DP_NUM_LANES(pdata->dsi->lanes - 1);
480 regmap_update_bits(pdata->regmap, SN_SSC_CONFIG_REG, DP_NUM_LANES_MASK,
481 val);
482
483 /* set dsi/dp clk frequency value */
484 ti_sn_bridge_set_dsi_dp_rate(pdata);
485
486 /* enable DP PLL */
487 regmap_write(pdata->regmap, SN_PLL_ENABLE_REG, 1);
488
489 ret = regmap_read_poll_timeout(pdata->regmap, SN_DPPLL_SRC_REG, val,
490 val & DPPLL_SRC_DP_PLL_LOCK, 1000,
491 50 * 1000);
492 if (ret) {
493 DRM_ERROR("DP_PLL_LOCK polling failed (%d)\n", ret);
494 return;
495 }
496
497 /**
498 * The SN65DSI86 only supports ASSR Display Authentication method and
499 * this method is enabled by default. An eDP panel must support this
500 * authentication method. We need to enable this method in the eDP panel
501 * at DisplayPort address 0x0010A prior to link training.
502 */
503 drm_dp_dpcd_writeb(&pdata->aux, DP_EDP_CONFIGURATION_SET,
504 DP_ALTERNATE_SCRAMBLER_RESET_ENABLE);
505
506 /* Semi auto link training mode */
507 regmap_write(pdata->regmap, SN_ML_TX_MODE_REG, 0x0A);
508 ret = regmap_read_poll_timeout(pdata->regmap, SN_ML_TX_MODE_REG, val,
509 val == ML_TX_MAIN_LINK_OFF ||
510 val == ML_TX_NORMAL_MODE, 1000,
511 500 * 1000);
512 if (ret) {
513 DRM_ERROR("Training complete polling failed (%d)\n", ret);
514 return;
515 } else if (val == ML_TX_MAIN_LINK_OFF) {
516 DRM_ERROR("Link training failed, link is off\n");
517 return;
518 }
519
520 /* config video parameters */
521 ti_sn_bridge_set_video_timings(pdata);
522
523 /* enable video stream */
524 regmap_update_bits(pdata->regmap, SN_ENH_FRAME_REG, VSTREAM_ENABLE,
525 VSTREAM_ENABLE);
526
527 drm_panel_enable(pdata->panel);
528}
529
530static void ti_sn_bridge_pre_enable(struct drm_bridge *bridge)
531{
532 struct ti_sn_bridge *pdata = bridge_to_ti_sn_bridge(bridge);
533
534 pm_runtime_get_sync(pdata->dev);
535
536 /* configure bridge ref_clk */
537 ti_sn_bridge_set_refclk_freq(pdata);
538
539 /* in case drm_panel is connected then HPD is not supported */
540 regmap_update_bits(pdata->regmap, SN_HPD_DISABLE_REG, HPD_DISABLE,
541 HPD_DISABLE);
542
543 drm_panel_prepare(pdata->panel);
544}
545
546static void ti_sn_bridge_post_disable(struct drm_bridge *bridge)
547{
548 struct ti_sn_bridge *pdata = bridge_to_ti_sn_bridge(bridge);
549
550 if (pdata->refclk)
551 clk_disable_unprepare(pdata->refclk);
552
553 pm_runtime_put_sync(pdata->dev);
554}
555
556static const struct drm_bridge_funcs ti_sn_bridge_funcs = {
557 .attach = ti_sn_bridge_attach,
558 .pre_enable = ti_sn_bridge_pre_enable,
559 .enable = ti_sn_bridge_enable,
560 .disable = ti_sn_bridge_disable,
561 .post_disable = ti_sn_bridge_post_disable,
562};
563
564static struct ti_sn_bridge *aux_to_ti_sn_bridge(struct drm_dp_aux *aux)
565{
566 return container_of(aux, struct ti_sn_bridge, aux);
567}
568
569static ssize_t ti_sn_aux_transfer(struct drm_dp_aux *aux,
570 struct drm_dp_aux_msg *msg)
571{
572 struct ti_sn_bridge *pdata = aux_to_ti_sn_bridge(aux);
573 u32 request = msg->request & ~DP_AUX_I2C_MOT;
574 u32 request_val = AUX_CMD_REQ(msg->request);
575 u8 *buf = (u8 *)msg->buffer;
576 unsigned int val;
577 int ret, i;
578
579 if (msg->size > SN_AUX_MAX_PAYLOAD_BYTES)
580 return -EINVAL;
581
582 switch (request) {
583 case DP_AUX_NATIVE_WRITE:
584 case DP_AUX_I2C_WRITE:
585 case DP_AUX_NATIVE_READ:
586 case DP_AUX_I2C_READ:
587 regmap_write(pdata->regmap, SN_AUX_CMD_REG, request_val);
588 break;
589 default:
590 return -EINVAL;
591 }
592
593 regmap_write(pdata->regmap, SN_AUX_ADDR_19_16_REG,
594 (msg->address >> 16) & 0xF);
595 regmap_write(pdata->regmap, SN_AUX_ADDR_15_8_REG,
596 (msg->address >> 8) & 0xFF);
597 regmap_write(pdata->regmap, SN_AUX_ADDR_7_0_REG, msg->address & 0xFF);
598
599 regmap_write(pdata->regmap, SN_AUX_LENGTH_REG, msg->size);
600
601 if (request == DP_AUX_NATIVE_WRITE || request == DP_AUX_I2C_WRITE) {
602 for (i = 0; i < msg->size; i++)
603 regmap_write(pdata->regmap, SN_AUX_WDATA_REG(i),
604 buf[i]);
605 }
606
607 regmap_write(pdata->regmap, SN_AUX_CMD_REG, request_val | AUX_CMD_SEND);
608
609 ret = regmap_read_poll_timeout(pdata->regmap, SN_AUX_CMD_REG, val,
610 !(val & AUX_CMD_SEND), 200,
611 50 * 1000);
612 if (ret)
613 return ret;
614
615 ret = regmap_read(pdata->regmap, SN_AUX_CMD_STATUS_REG, &val);
616 if (ret)
617 return ret;
618 else if ((val & AUX_IRQ_STATUS_NAT_I2C_FAIL)
619 || (val & AUX_IRQ_STATUS_AUX_RPLY_TOUT)
620 || (val & AUX_IRQ_STATUS_AUX_SHORT))
621 return -ENXIO;
622
623 if (request == DP_AUX_NATIVE_WRITE || request == DP_AUX_I2C_WRITE)
624 return msg->size;
625
626 for (i = 0; i < msg->size; i++) {
627 unsigned int val;
628 ret = regmap_read(pdata->regmap, SN_AUX_RDATA_REG(i),
629 &val);
630 if (ret)
631 return ret;
632
633 WARN_ON(val & ~0xFF);
634 buf[i] = (u8)(val & 0xFF);
635 }
636
637 return msg->size;
638}
639
640static int ti_sn_bridge_parse_dsi_host(struct ti_sn_bridge *pdata)
641{
642 struct device_node *np = pdata->dev->of_node;
643
644 pdata->host_node = of_graph_get_remote_node(np, 0, 0);
645
646 if (!pdata->host_node) {
647 DRM_ERROR("remote dsi host node not found\n");
648 return -ENODEV;
649 }
650
651 return 0;
652}
653
654static int ti_sn_bridge_probe(struct i2c_client *client,
655 const struct i2c_device_id *id)
656{
657 struct ti_sn_bridge *pdata;
658 int ret;
659
660 if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
661 DRM_ERROR("device doesn't support I2C\n");
662 return -ENODEV;
663 }
664
665 pdata = devm_kzalloc(&client->dev, sizeof(struct ti_sn_bridge),
666 GFP_KERNEL);
667 if (!pdata)
668 return -ENOMEM;
669
670 pdata->regmap = devm_regmap_init_i2c(client,
671 &ti_sn_bridge_regmap_config);
672 if (IS_ERR(pdata->regmap)) {
673 DRM_ERROR("regmap i2c init failed\n");
674 return PTR_ERR(pdata->regmap);
675 }
676
677 pdata->dev = &client->dev;
678
679 ret = drm_of_find_panel_or_bridge(pdata->dev->of_node, 1, 0,
680 &pdata->panel, NULL);
681 if (ret) {
682 DRM_ERROR("could not find any panel node\n");
683 return ret;
684 }
685
686 dev_set_drvdata(&client->dev, pdata);
687
688 pdata->enable_gpio = devm_gpiod_get(pdata->dev, "enable",
689 GPIOD_OUT_LOW);
690 if (IS_ERR(pdata->enable_gpio)) {
691 DRM_ERROR("failed to get enable gpio from DT\n");
692 ret = PTR_ERR(pdata->enable_gpio);
693 return ret;
694 }
695
696 ret = ti_sn_bridge_parse_regulators(pdata);
697 if (ret) {
698 DRM_ERROR("failed to parse regulators\n");
699 return ret;
700 }
701
702 pdata->refclk = devm_clk_get(pdata->dev, "refclk");
703 if (IS_ERR(pdata->refclk)) {
704 ret = PTR_ERR(pdata->refclk);
705 if (ret == -EPROBE_DEFER)
706 return ret;
707 DRM_DEBUG_KMS("refclk not found\n");
708 pdata->refclk = NULL;
709 }
710
711 ret = ti_sn_bridge_parse_dsi_host(pdata);
712 if (ret)
713 return ret;
714
715 pm_runtime_enable(pdata->dev);
716
717 i2c_set_clientdata(client, pdata);
718
719 pdata->aux.name = "ti-sn65dsi86-aux";
720 pdata->aux.dev = pdata->dev;
721 pdata->aux.transfer = ti_sn_aux_transfer;
722 drm_dp_aux_register(&pdata->aux);
723
724 pdata->bridge.funcs = &ti_sn_bridge_funcs;
725 pdata->bridge.of_node = client->dev.of_node;
726
727 drm_bridge_add(&pdata->bridge);
728
729 return 0;
730}
731
732static int ti_sn_bridge_remove(struct i2c_client *client)
733{
734 struct ti_sn_bridge *pdata = i2c_get_clientdata(client);
735
736 if (!pdata)
737 return -EINVAL;
738
739 of_node_put(pdata->host_node);
740
741 pm_runtime_disable(pdata->dev);
742
743 if (pdata->dsi) {
744 mipi_dsi_detach(pdata->dsi);
745 mipi_dsi_device_unregister(pdata->dsi);
746 }
747
748 drm_bridge_remove(&pdata->bridge);
749
750 return 0;
751}
752
753static struct i2c_device_id ti_sn_bridge_id[] = {
754 { "ti,sn65dsi86", 0},
755 {},
756};
757MODULE_DEVICE_TABLE(i2c, ti_sn_bridge_id);
758
759static const struct of_device_id ti_sn_bridge_match_table[] = {
760 {.compatible = "ti,sn65dsi86"},
761 {},
762};
763MODULE_DEVICE_TABLE(of, ti_sn_bridge_match_table);
764
765static struct i2c_driver ti_sn_bridge_driver = {
766 .driver = {
767 .name = "ti_sn65dsi86",
768 .of_match_table = ti_sn_bridge_match_table,
769 .pm = &ti_sn_bridge_pm_ops,
770 },
771 .probe = ti_sn_bridge_probe,
772 .remove = ti_sn_bridge_remove,
773 .id_table = ti_sn_bridge_id,
774};
775module_i2c_driver(ti_sn_bridge_driver);
776
777MODULE_AUTHOR("Sandeep Panda <spanda@codeaurora.org>");
778MODULE_DESCRIPTION("sn65dsi86 DSI to eDP bridge driver");
779MODULE_LICENSE("GPL v2");
diff --git a/drivers/gpu/drm/cirrus/cirrus_drv.c b/drivers/gpu/drm/cirrus/cirrus_drv.c
index 69c4e352dd78..db40b77c7f7c 100644
--- a/drivers/gpu/drm/cirrus/cirrus_drv.c
+++ b/drivers/gpu/drm/cirrus/cirrus_drv.c
@@ -16,11 +16,11 @@
16#include "cirrus_drv.h" 16#include "cirrus_drv.h"
17 17
18int cirrus_modeset = -1; 18int cirrus_modeset = -1;
19int cirrus_bpp = 24; 19int cirrus_bpp = 16;
20 20
21MODULE_PARM_DESC(modeset, "Disable/Enable modesetting"); 21MODULE_PARM_DESC(modeset, "Disable/Enable modesetting");
22module_param_named(modeset, cirrus_modeset, int, 0400); 22module_param_named(modeset, cirrus_modeset, int, 0400);
23MODULE_PARM_DESC(bpp, "Max bits-per-pixel (default:24)"); 23MODULE_PARM_DESC(bpp, "Max bits-per-pixel (default:16)");
24module_param_named(bpp, cirrus_bpp, int, 0400); 24module_param_named(bpp, cirrus_bpp, int, 0400);
25 25
26/* 26/*
@@ -42,33 +42,12 @@ static const struct pci_device_id pciidlist[] = {
42}; 42};
43 43
44 44
45static int cirrus_kick_out_firmware_fb(struct pci_dev *pdev)
46{
47 struct apertures_struct *ap;
48 bool primary = false;
49
50 ap = alloc_apertures(1);
51 if (!ap)
52 return -ENOMEM;
53
54 ap->ranges[0].base = pci_resource_start(pdev, 0);
55 ap->ranges[0].size = pci_resource_len(pdev, 0);
56
57#ifdef CONFIG_X86
58 primary = pdev->resource[PCI_ROM_RESOURCE].flags & IORESOURCE_ROM_SHADOW;
59#endif
60 drm_fb_helper_remove_conflicting_framebuffers(ap, "cirrusdrmfb", primary);
61 kfree(ap);
62
63 return 0;
64}
65
66static int cirrus_pci_probe(struct pci_dev *pdev, 45static int cirrus_pci_probe(struct pci_dev *pdev,
67 const struct pci_device_id *ent) 46 const struct pci_device_id *ent)
68{ 47{
69 int ret; 48 int ret;
70 49
71 ret = cirrus_kick_out_firmware_fb(pdev); 50 ret = drm_fb_helper_remove_conflicting_pci_framebuffers(pdev, 0, "cirrusdrmfb");
72 if (ret) 51 if (ret)
73 return ret; 52 return ret;
74 53
diff --git a/drivers/gpu/drm/cirrus/cirrus_drv.h b/drivers/gpu/drm/cirrus/cirrus_drv.h
index ce9db7aab225..a29f87e98d9d 100644
--- a/drivers/gpu/drm/cirrus/cirrus_drv.h
+++ b/drivers/gpu/drm/cirrus/cirrus_drv.h
@@ -146,7 +146,7 @@ struct cirrus_device {
146 146
147struct cirrus_fbdev { 147struct cirrus_fbdev {
148 struct drm_fb_helper helper; 148 struct drm_fb_helper helper;
149 struct drm_framebuffer gfb; 149 struct drm_framebuffer *gfb;
150 void *sysram; 150 void *sysram;
151 int size; 151 int size;
152 int x1, y1, x2, y2; /* dirty rect */ 152 int x1, y1, x2, y2; /* dirty rect */
diff --git a/drivers/gpu/drm/cirrus/cirrus_fbdev.c b/drivers/gpu/drm/cirrus/cirrus_fbdev.c
index b643ac92801c..68ab1821e15b 100644
--- a/drivers/gpu/drm/cirrus/cirrus_fbdev.c
+++ b/drivers/gpu/drm/cirrus/cirrus_fbdev.c
@@ -22,14 +22,14 @@ static void cirrus_dirty_update(struct cirrus_fbdev *afbdev,
22 struct drm_gem_object *obj; 22 struct drm_gem_object *obj;
23 struct cirrus_bo *bo; 23 struct cirrus_bo *bo;
24 int src_offset, dst_offset; 24 int src_offset, dst_offset;
25 int bpp = afbdev->gfb.format->cpp[0]; 25 int bpp = afbdev->gfb->format->cpp[0];
26 int ret = -EBUSY; 26 int ret = -EBUSY;
27 bool unmap = false; 27 bool unmap = false;
28 bool store_for_later = false; 28 bool store_for_later = false;
29 int x2, y2; 29 int x2, y2;
30 unsigned long flags; 30 unsigned long flags;
31 31
32 obj = afbdev->gfb.obj[0]; 32 obj = afbdev->gfb->obj[0];
33 bo = gem_to_cirrus_bo(obj); 33 bo = gem_to_cirrus_bo(obj);
34 34
35 /* 35 /*
@@ -82,7 +82,7 @@ static void cirrus_dirty_update(struct cirrus_fbdev *afbdev,
82 } 82 }
83 for (i = y; i < y + height; i++) { 83 for (i = y; i < y + height; i++) {
84 /* assume equal stride for now */ 84 /* assume equal stride for now */
85 src_offset = dst_offset = i * afbdev->gfb.pitches[0] + (x * bpp); 85 src_offset = dst_offset = i * afbdev->gfb->pitches[0] + (x * bpp);
86 memcpy_toio(bo->kmap.virtual + src_offset, afbdev->sysram + src_offset, width * bpp); 86 memcpy_toio(bo->kmap.virtual + src_offset, afbdev->sysram + src_offset, width * bpp);
87 87
88 } 88 }
@@ -192,23 +192,26 @@ static int cirrusfb_create(struct drm_fb_helper *helper,
192 return -ENOMEM; 192 return -ENOMEM;
193 193
194 info = drm_fb_helper_alloc_fbi(helper); 194 info = drm_fb_helper_alloc_fbi(helper);
195 if (IS_ERR(info)) 195 if (IS_ERR(info)) {
196 return PTR_ERR(info); 196 ret = PTR_ERR(info);
197 goto err_vfree;
198 }
197 199
198 info->par = gfbdev; 200 info->par = gfbdev;
199 201
200 ret = cirrus_framebuffer_init(cdev->dev, &gfbdev->gfb, &mode_cmd, gobj); 202 fb = kzalloc(sizeof(*fb), GFP_KERNEL);
203 if (!fb) {
204 ret = -ENOMEM;
205 goto err_drm_gem_object_put_unlocked;
206 }
207
208 ret = cirrus_framebuffer_init(cdev->dev, fb, &mode_cmd, gobj);
201 if (ret) 209 if (ret)
202 return ret; 210 goto err_kfree;
203 211
204 gfbdev->sysram = sysram; 212 gfbdev->sysram = sysram;
205 gfbdev->size = size; 213 gfbdev->size = size;
206 214 gfbdev->gfb = fb;
207 fb = &gfbdev->gfb;
208 if (!fb) {
209 DRM_INFO("fb is NULL\n");
210 return -EINVAL;
211 }
212 215
213 /* setup helper */ 216 /* setup helper */
214 gfbdev->helper.fb = fb; 217 gfbdev->helper.fb = fb;
@@ -241,24 +244,27 @@ static int cirrusfb_create(struct drm_fb_helper *helper,
241 DRM_INFO(" pitch is %d\n", fb->pitches[0]); 244 DRM_INFO(" pitch is %d\n", fb->pitches[0]);
242 245
243 return 0; 246 return 0;
247
248err_kfree:
249 kfree(fb);
250err_drm_gem_object_put_unlocked:
251 drm_gem_object_put_unlocked(gobj);
252err_vfree:
253 vfree(sysram);
254 return ret;
244} 255}
245 256
246static int cirrus_fbdev_destroy(struct drm_device *dev, 257static int cirrus_fbdev_destroy(struct drm_device *dev,
247 struct cirrus_fbdev *gfbdev) 258 struct cirrus_fbdev *gfbdev)
248{ 259{
249 struct drm_framebuffer *gfb = &gfbdev->gfb; 260 struct drm_framebuffer *gfb = gfbdev->gfb;
250 261
251 drm_fb_helper_unregister_fbi(&gfbdev->helper); 262 drm_fb_helper_unregister_fbi(&gfbdev->helper);
252 263
253 if (gfb->obj[0]) {
254 drm_gem_object_put_unlocked(gfb->obj[0]);
255 gfb->obj[0] = NULL;
256 }
257
258 vfree(gfbdev->sysram); 264 vfree(gfbdev->sysram);
259 drm_fb_helper_fini(&gfbdev->helper); 265 drm_fb_helper_fini(&gfbdev->helper);
260 drm_framebuffer_unregister_private(gfb); 266 if (gfb)
261 drm_framebuffer_cleanup(gfb); 267 drm_framebuffer_put(gfb);
262 268
263 return 0; 269 return 0;
264} 270}
@@ -271,7 +277,6 @@ int cirrus_fbdev_init(struct cirrus_device *cdev)
271{ 277{
272 struct cirrus_fbdev *gfbdev; 278 struct cirrus_fbdev *gfbdev;
273 int ret; 279 int ret;
274 int bpp_sel = 24;
275 280
276 /*bpp_sel = 8;*/ 281 /*bpp_sel = 8;*/
277 gfbdev = kzalloc(sizeof(struct cirrus_fbdev), GFP_KERNEL); 282 gfbdev = kzalloc(sizeof(struct cirrus_fbdev), GFP_KERNEL);
@@ -296,7 +301,7 @@ int cirrus_fbdev_init(struct cirrus_device *cdev)
296 /* disable all the possible outputs/crtcs before entering KMS mode */ 301 /* disable all the possible outputs/crtcs before entering KMS mode */
297 drm_helper_disable_unused_functions(cdev->dev); 302 drm_helper_disable_unused_functions(cdev->dev);
298 303
299 return drm_fb_helper_initial_config(&gfbdev->helper, bpp_sel); 304 return drm_fb_helper_initial_config(&gfbdev->helper, cirrus_bpp);
300} 305}
301 306
302void cirrus_fbdev_fini(struct cirrus_device *cdev) 307void cirrus_fbdev_fini(struct cirrus_device *cdev)
diff --git a/drivers/gpu/drm/cirrus/cirrus_main.c b/drivers/gpu/drm/cirrus/cirrus_main.c
index 60d54e10a34d..57f8fe6d020b 100644
--- a/drivers/gpu/drm/cirrus/cirrus_main.c
+++ b/drivers/gpu/drm/cirrus/cirrus_main.c
@@ -269,7 +269,7 @@ static void cirrus_bo_unref(struct cirrus_bo **bo)
269 return; 269 return;
270 270
271 tbo = &((*bo)->bo); 271 tbo = &((*bo)->bo);
272 ttm_bo_unref(&tbo); 272 ttm_bo_put(tbo);
273 *bo = NULL; 273 *bo = NULL;
274} 274}
275 275
diff --git a/drivers/gpu/drm/cirrus/cirrus_mode.c b/drivers/gpu/drm/cirrus/cirrus_mode.c
index 336bfda40125..ed7dcf212a34 100644
--- a/drivers/gpu/drm/cirrus/cirrus_mode.c
+++ b/drivers/gpu/drm/cirrus/cirrus_mode.c
@@ -127,7 +127,7 @@ static int cirrus_crtc_do_set_base(struct drm_crtc *crtc,
127 return ret; 127 return ret;
128 } 128 }
129 129
130 if (&cdev->mode_info.gfbdev->gfb == crtc->primary->fb) { 130 if (cdev->mode_info.gfbdev->gfb == crtc->primary->fb) {
131 /* if pushing console in kmap it */ 131 /* if pushing console in kmap it */
132 ret = ttm_bo_kmap(&bo->bo, 0, bo->bo.num_pages, &bo->kmap); 132 ret = ttm_bo_kmap(&bo->bo, 0, bo->bo.num_pages, &bo->kmap);
133 if (ret) 133 if (ret)
@@ -512,7 +512,7 @@ int cirrus_modeset_init(struct cirrus_device *cdev)
512 cdev->dev->mode_config.max_height = CIRRUS_MAX_FB_HEIGHT; 512 cdev->dev->mode_config.max_height = CIRRUS_MAX_FB_HEIGHT;
513 513
514 cdev->dev->mode_config.fb_base = cdev->mc.vram_base; 514 cdev->dev->mode_config.fb_base = cdev->mc.vram_base;
515 cdev->dev->mode_config.preferred_depth = 24; 515 cdev->dev->mode_config.preferred_depth = cirrus_bpp;
516 /* don't prefer a shadow on virt GPU */ 516 /* don't prefer a shadow on virt GPU */
517 cdev->dev->mode_config.prefer_shadow = 0; 517 cdev->dev->mode_config.prefer_shadow = 0;
518 518
diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c
index 3eb061e11e2e..d0478abc01bd 100644
--- a/drivers/gpu/drm/drm_atomic.c
+++ b/drivers/gpu/drm/drm_atomic.c
@@ -895,6 +895,8 @@ static int drm_atomic_plane_set_property(struct drm_plane *plane,
895 state->src_h = val; 895 state->src_h = val;
896 } else if (property == plane->alpha_property) { 896 } else if (property == plane->alpha_property) {
897 state->alpha = val; 897 state->alpha = val;
898 } else if (property == plane->blend_mode_property) {
899 state->pixel_blend_mode = val;
898 } else if (property == plane->rotation_property) { 900 } else if (property == plane->rotation_property) {
899 if (!is_power_of_2(val & DRM_MODE_ROTATE_MASK)) { 901 if (!is_power_of_2(val & DRM_MODE_ROTATE_MASK)) {
900 DRM_DEBUG_ATOMIC("[PLANE:%d:%s] bad rotation bitmask: 0x%llx\n", 902 DRM_DEBUG_ATOMIC("[PLANE:%d:%s] bad rotation bitmask: 0x%llx\n",
@@ -968,6 +970,8 @@ drm_atomic_plane_get_property(struct drm_plane *plane,
968 *val = state->src_h; 970 *val = state->src_h;
969 } else if (property == plane->alpha_property) { 971 } else if (property == plane->alpha_property) {
970 *val = state->alpha; 972 *val = state->alpha;
973 } else if (property == plane->blend_mode_property) {
974 *val = state->pixel_blend_mode;
971 } else if (property == plane->rotation_property) { 975 } else if (property == plane->rotation_property) {
972 *val = state->rotation; 976 *val = state->rotation;
973 } else if (property == plane->zpos_property) { 977 } else if (property == plane->zpos_property) {
diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c
index 80be74df7ba6..2c23a48482da 100644
--- a/drivers/gpu/drm/drm_atomic_helper.c
+++ b/drivers/gpu/drm/drm_atomic_helper.c
@@ -3555,6 +3555,29 @@ void drm_atomic_helper_crtc_destroy_state(struct drm_crtc *crtc,
3555EXPORT_SYMBOL(drm_atomic_helper_crtc_destroy_state); 3555EXPORT_SYMBOL(drm_atomic_helper_crtc_destroy_state);
3556 3556
3557/** 3557/**
3558 * __drm_atomic_helper_plane_reset - resets planes state to default values
3559 * @plane: plane object, must not be NULL
3560 * @state: atomic plane state, must not be NULL
3561 *
3562 * Initializes plane state to default. This is useful for drivers that subclass
3563 * the plane state.
3564 */
3565void __drm_atomic_helper_plane_reset(struct drm_plane *plane,
3566 struct drm_plane_state *state)
3567{
3568 state->plane = plane;
3569 state->rotation = DRM_MODE_ROTATE_0;
3570
3571 /* Reset the alpha value to fully opaque if it matters */
3572 if (plane->alpha_property)
3573 state->alpha = plane->alpha_property->values[1];
3574 state->pixel_blend_mode = DRM_MODE_BLEND_PREMULTI;
3575
3576 plane->state = state;
3577}
3578EXPORT_SYMBOL(__drm_atomic_helper_plane_reset);
3579
3580/**
3558 * drm_atomic_helper_plane_reset - default &drm_plane_funcs.reset hook for planes 3581 * drm_atomic_helper_plane_reset - default &drm_plane_funcs.reset hook for planes
3559 * @plane: drm plane 3582 * @plane: drm plane
3560 * 3583 *
@@ -3568,15 +3591,8 @@ void drm_atomic_helper_plane_reset(struct drm_plane *plane)
3568 3591
3569 kfree(plane->state); 3592 kfree(plane->state);
3570 plane->state = kzalloc(sizeof(*plane->state), GFP_KERNEL); 3593 plane->state = kzalloc(sizeof(*plane->state), GFP_KERNEL);
3571 3594 if (plane->state)
3572 if (plane->state) { 3595 __drm_atomic_helper_plane_reset(plane, plane->state);
3573 plane->state->plane = plane;
3574 plane->state->rotation = DRM_MODE_ROTATE_0;
3575
3576 /* Reset the alpha value to fully opaque if it matters */
3577 if (plane->alpha_property)
3578 plane->state->alpha = plane->alpha_property->values[1];
3579 }
3580} 3596}
3581EXPORT_SYMBOL(drm_atomic_helper_plane_reset); 3597EXPORT_SYMBOL(drm_atomic_helper_plane_reset);
3582 3598
diff --git a/drivers/gpu/drm/drm_blend.c b/drivers/gpu/drm/drm_blend.c
index a16a74d7e15e..402b62d3f072 100644
--- a/drivers/gpu/drm/drm_blend.c
+++ b/drivers/gpu/drm/drm_blend.c
@@ -107,6 +107,52 @@
107 * planes. Without this property the primary plane is always below the cursor 107 * planes. Without this property the primary plane is always below the cursor
108 * plane, and ordering between all other planes is undefined. 108 * plane, and ordering between all other planes is undefined.
109 * 109 *
110 * pixel blend mode:
111 * Pixel blend mode is set up with drm_plane_create_blend_mode_property().
112 * It adds a blend mode for alpha blending equation selection, describing
113 * how the pixels from the current plane are composited with the
114 * background.
115 *
116 * Three alpha blending equations are defined:
117 *
118 * "None":
119 * Blend formula that ignores the pixel alpha::
120 *
121 * out.rgb = plane_alpha * fg.rgb +
122 * (1 - plane_alpha) * bg.rgb
123 *
124 * "Pre-multiplied":
125 * Blend formula that assumes the pixel color values
126 * have been already pre-multiplied with the alpha
127 * channel values::
128 *
129 * out.rgb = plane_alpha * fg.rgb +
130 * (1 - (plane_alpha * fg.alpha)) * bg.rgb
131 *
132 * "Coverage":
133 * Blend formula that assumes the pixel color values have not
134 * been pre-multiplied and will do so when blending them to the
135 * background color values::
136 *
137 * out.rgb = plane_alpha * fg.alpha * fg.rgb +
138 * (1 - (plane_alpha * fg.alpha)) * bg.rgb
139 *
140 * Using the following symbols:
141 *
142 * "fg.rgb":
143 * Each of the RGB component values from the plane's pixel
144 * "fg.alpha":
145 * Alpha component value from the plane's pixel. If the plane's
146 * pixel format has no alpha component, then this is assumed to be
147 * 1.0. In these cases, this property has no effect, as all three
148 * equations become equivalent.
149 * "bg.rgb":
150 * Each of the RGB component values from the background
151 * "plane_alpha":
152 * Plane alpha value set by the plane "alpha" property. If the
153 * plane does not expose the "alpha" property, then this is
154 * assumed to be 1.0
155 *
110 * Note that all the property extensions described here apply either to the 156 * Note that all the property extensions described here apply either to the
111 * plane or the CRTC (e.g. for the background color, which currently is not 157 * plane or the CRTC (e.g. for the background color, which currently is not
112 * exposed and assumed to be black). 158 * exposed and assumed to be black).
@@ -448,3 +494,80 @@ int drm_atomic_normalize_zpos(struct drm_device *dev,
448 return 0; 494 return 0;
449} 495}
450EXPORT_SYMBOL(drm_atomic_normalize_zpos); 496EXPORT_SYMBOL(drm_atomic_normalize_zpos);
497
498/**
499 * drm_plane_create_blend_mode_property - create a new blend mode property
500 * @plane: drm plane
501 * @supported_modes: bitmask of supported modes, must include
502 * BIT(DRM_MODE_BLEND_PREMULTI). Current DRM assumption is
503 * that alpha is premultiplied, and old userspace can break if
504 * the property defaults to anything else.
505 *
506 * This creates a new property describing the blend mode.
507 *
508 * The property exposed to userspace is an enumeration property (see
509 * drm_property_create_enum()) called "pixel blend mode" and has the
510 * following enumeration values:
511 *
512 * "None":
513 * Blend formula that ignores the pixel alpha.
514 *
515 * "Pre-multiplied":
516 * Blend formula that assumes the pixel color values have been already
517 * pre-multiplied with the alpha channel values.
518 *
519 * "Coverage":
520 * Blend formula that assumes the pixel color values have not been
521 * pre-multiplied and will do so when blending them to the background color
522 * values.
523 *
524 * RETURNS:
525 * Zero for success or -errno
526 */
527int drm_plane_create_blend_mode_property(struct drm_plane *plane,
528 unsigned int supported_modes)
529{
530 struct drm_device *dev = plane->dev;
531 struct drm_property *prop;
532 static const struct drm_prop_enum_list props[] = {
533 { DRM_MODE_BLEND_PIXEL_NONE, "None" },
534 { DRM_MODE_BLEND_PREMULTI, "Pre-multiplied" },
535 { DRM_MODE_BLEND_COVERAGE, "Coverage" },
536 };
537 unsigned int valid_mode_mask = BIT(DRM_MODE_BLEND_PIXEL_NONE) |
538 BIT(DRM_MODE_BLEND_PREMULTI) |
539 BIT(DRM_MODE_BLEND_COVERAGE);
540 int i;
541
542 if (WARN_ON((supported_modes & ~valid_mode_mask) ||
543 ((supported_modes & BIT(DRM_MODE_BLEND_PREMULTI)) == 0)))
544 return -EINVAL;
545
546 prop = drm_property_create(dev, DRM_MODE_PROP_ENUM,
547 "pixel blend mode",
548 hweight32(supported_modes));
549 if (!prop)
550 return -ENOMEM;
551
552 for (i = 0; i < ARRAY_SIZE(props); i++) {
553 int ret;
554
555 if (!(BIT(props[i].type) & supported_modes))
556 continue;
557
558 ret = drm_property_add_enum(prop, props[i].type,
559 props[i].name);
560
561 if (ret) {
562 drm_property_destroy(dev, prop);
563
564 return ret;
565 }
566 }
567
568 drm_object_attach_property(&plane->base, prop, DRM_MODE_BLEND_PREMULTI);
569 plane->blend_mode_property = prop;
570
571 return 0;
572}
573EXPORT_SYMBOL(drm_plane_create_blend_mode_property);
diff --git a/drivers/gpu/drm/drm_debugfs_crc.c b/drivers/gpu/drm/drm_debugfs_crc.c
index 99961192bf03..00e743153e94 100644
--- a/drivers/gpu/drm/drm_debugfs_crc.c
+++ b/drivers/gpu/drm/drm_debugfs_crc.c
@@ -68,8 +68,29 @@ static int crc_control_show(struct seq_file *m, void *data)
68{ 68{
69 struct drm_crtc *crtc = m->private; 69 struct drm_crtc *crtc = m->private;
70 70
71 seq_printf(m, "%s\n", crtc->crc.source); 71 if (crtc->funcs->get_crc_sources) {
72 size_t count;
73 const char *const *sources = crtc->funcs->get_crc_sources(crtc,
74 &count);
75 size_t values_cnt;
76 int i;
77
78 if (count == 0 || !sources)
79 goto out;
80
81 for (i = 0; i < count; i++)
82 if (!crtc->funcs->verify_crc_source(crtc, sources[i],
83 &values_cnt)) {
84 if (strcmp(sources[i], crtc->crc.source))
85 seq_printf(m, "%s\n", sources[i]);
86 else
87 seq_printf(m, "%s*\n", sources[i]);
88 }
89 }
90 return 0;
72 91
92out:
93 seq_printf(m, "%s*\n", crtc->crc.source);
73 return 0; 94 return 0;
74} 95}
75 96
@@ -87,6 +108,8 @@ static ssize_t crc_control_write(struct file *file, const char __user *ubuf,
87 struct drm_crtc *crtc = m->private; 108 struct drm_crtc *crtc = m->private;
88 struct drm_crtc_crc *crc = &crtc->crc; 109 struct drm_crtc_crc *crc = &crtc->crc;
89 char *source; 110 char *source;
111 size_t values_cnt;
112 int ret;
90 113
91 if (len == 0) 114 if (len == 0)
92 return 0; 115 return 0;
@@ -104,6 +127,10 @@ static ssize_t crc_control_write(struct file *file, const char __user *ubuf,
104 if (source[len] == '\n') 127 if (source[len] == '\n')
105 source[len] = '\0'; 128 source[len] = '\0';
106 129
130 ret = crtc->funcs->verify_crc_source(crtc, source, &values_cnt);
131 if (ret)
132 return ret;
133
107 spin_lock_irq(&crc->lock); 134 spin_lock_irq(&crc->lock);
108 135
109 if (crc->opened) { 136 if (crc->opened) {
@@ -168,57 +195,41 @@ static int crtc_crc_open(struct inode *inode, struct file *filep)
168 return ret; 195 return ret;
169 } 196 }
170 197
171 spin_lock_irq(&crc->lock); 198 ret = crtc->funcs->verify_crc_source(crtc, crc->source, &values_cnt);
172 if (!crc->opened)
173 crc->opened = true;
174 else
175 ret = -EBUSY;
176 spin_unlock_irq(&crc->lock);
177
178 if (ret) 199 if (ret)
179 return ret; 200 return ret;
180 201
181 ret = crtc->funcs->set_crc_source(crtc, crc->source, &values_cnt); 202 if (WARN_ON(values_cnt > DRM_MAX_CRC_NR))
182 if (ret) 203 return -EINVAL;
183 goto err;
184
185 if (WARN_ON(values_cnt > DRM_MAX_CRC_NR)) {
186 ret = -EINVAL;
187 goto err_disable;
188 }
189 204
190 if (WARN_ON(values_cnt == 0)) { 205 if (WARN_ON(values_cnt == 0))
191 ret = -EINVAL; 206 return -EINVAL;
192 goto err_disable;
193 }
194 207
195 entries = kcalloc(DRM_CRC_ENTRIES_NR, sizeof(*entries), GFP_KERNEL); 208 entries = kcalloc(DRM_CRC_ENTRIES_NR, sizeof(*entries), GFP_KERNEL);
196 if (!entries) { 209 if (!entries)
197 ret = -ENOMEM; 210 return -ENOMEM;
198 goto err_disable;
199 }
200 211
201 spin_lock_irq(&crc->lock); 212 spin_lock_irq(&crc->lock);
202 crc->entries = entries; 213 if (!crc->opened) {
203 crc->values_cnt = values_cnt; 214 crc->opened = true;
204 215 crc->entries = entries;
205 /* 216 crc->values_cnt = values_cnt;
206 * Only return once we got a first frame, so userspace doesn't have to 217 } else {
207 * guess when this particular piece of HW will be ready to start 218 ret = -EBUSY;
208 * generating CRCs. 219 }
209 */
210 ret = wait_event_interruptible_lock_irq(crc->wq,
211 crtc_crc_data_count(crc),
212 crc->lock);
213 spin_unlock_irq(&crc->lock); 220 spin_unlock_irq(&crc->lock);
214 221
222 if (ret) {
223 kfree(entries);
224 return ret;
225 }
226
227 ret = crtc->funcs->set_crc_source(crtc, crc->source);
215 if (ret) 228 if (ret)
216 goto err_disable; 229 goto err;
217 230
218 return 0; 231 return 0;
219 232
220err_disable:
221 crtc->funcs->set_crc_source(crtc, NULL, &values_cnt);
222err: 233err:
223 spin_lock_irq(&crc->lock); 234 spin_lock_irq(&crc->lock);
224 crtc_crc_cleanup(crc); 235 crtc_crc_cleanup(crc);
@@ -230,9 +241,8 @@ static int crtc_crc_release(struct inode *inode, struct file *filep)
230{ 241{
231 struct drm_crtc *crtc = filep->f_inode->i_private; 242 struct drm_crtc *crtc = filep->f_inode->i_private;
232 struct drm_crtc_crc *crc = &crtc->crc; 243 struct drm_crtc_crc *crc = &crtc->crc;
233 size_t values_cnt;
234 244
235 crtc->funcs->set_crc_source(crtc, NULL, &values_cnt); 245 crtc->funcs->set_crc_source(crtc, NULL);
236 246
237 spin_lock_irq(&crc->lock); 247 spin_lock_irq(&crc->lock);
238 crtc_crc_cleanup(crc); 248 crtc_crc_cleanup(crc);
@@ -338,7 +348,7 @@ int drm_debugfs_crtc_crc_add(struct drm_crtc *crtc)
338{ 348{
339 struct dentry *crc_ent, *ent; 349 struct dentry *crc_ent, *ent;
340 350
341 if (!crtc->funcs->set_crc_source) 351 if (!crtc->funcs->set_crc_source || !crtc->funcs->verify_crc_source)
342 return 0; 352 return 0;
343 353
344 crc_ent = debugfs_create_dir("crc", crtc->debugfs_entry); 354 crc_ent = debugfs_create_dir("crc", crtc->debugfs_entry);
diff --git a/drivers/gpu/drm/drm_dp_cec.c b/drivers/gpu/drm/drm_dp_cec.c
index 988513346e9c..8a718f85079a 100644
--- a/drivers/gpu/drm/drm_dp_cec.c
+++ b/drivers/gpu/drm/drm_dp_cec.c
@@ -16,7 +16,9 @@
16 * here. Quite a few active (mini-)DP-to-HDMI or USB-C-to-HDMI adapters 16 * here. Quite a few active (mini-)DP-to-HDMI or USB-C-to-HDMI adapters
17 * have a converter chip that supports CEC-Tunneling-over-AUX (usually the 17 * have a converter chip that supports CEC-Tunneling-over-AUX (usually the
18 * Parade PS176), but they do not wire up the CEC pin, thus making CEC 18 * Parade PS176), but they do not wire up the CEC pin, thus making CEC
19 * useless. 19 * useless. Note that MegaChips 2900-based adapters appear to have good
20 * support for CEC tunneling. Those adapters that I have tested using
21 * this chipset all have the CEC line connected.
20 * 22 *
21 * Sadly there is no way for this driver to know this. What happens is 23 * Sadly there is no way for this driver to know this. What happens is
22 * that a /dev/cecX device is created that is isolated and unable to see 24 * that a /dev/cecX device is created that is isolated and unable to see
@@ -238,6 +240,10 @@ void drm_dp_cec_irq(struct drm_dp_aux *aux)
238 u8 cec_irq; 240 u8 cec_irq;
239 int ret; 241 int ret;
240 242
243 /* No transfer function was set, so not a DP connector */
244 if (!aux->transfer)
245 return;
246
241 mutex_lock(&aux->cec.lock); 247 mutex_lock(&aux->cec.lock);
242 if (!aux->cec.adap) 248 if (!aux->cec.adap)
243 goto unlock; 249 goto unlock;
@@ -293,6 +299,10 @@ void drm_dp_cec_set_edid(struct drm_dp_aux *aux, const struct edid *edid)
293 unsigned int num_las = 1; 299 unsigned int num_las = 1;
294 u8 cap; 300 u8 cap;
295 301
302 /* No transfer function was set, so not a DP connector */
303 if (!aux->transfer)
304 return;
305
296#ifndef CONFIG_MEDIA_CEC_RC 306#ifndef CONFIG_MEDIA_CEC_RC
297 /* 307 /*
298 * CEC_CAP_RC is part of CEC_CAP_DEFAULTS, but it is stripped by 308 * CEC_CAP_RC is part of CEC_CAP_DEFAULTS, but it is stripped by
@@ -361,6 +371,10 @@ EXPORT_SYMBOL(drm_dp_cec_set_edid);
361 */ 371 */
362void drm_dp_cec_unset_edid(struct drm_dp_aux *aux) 372void drm_dp_cec_unset_edid(struct drm_dp_aux *aux)
363{ 373{
374 /* No transfer function was set, so not a DP connector */
375 if (!aux->transfer)
376 return;
377
364 cancel_delayed_work_sync(&aux->cec.unregister_work); 378 cancel_delayed_work_sync(&aux->cec.unregister_work);
365 379
366 mutex_lock(&aux->cec.lock); 380 mutex_lock(&aux->cec.lock);
@@ -404,6 +418,8 @@ void drm_dp_cec_register_connector(struct drm_dp_aux *aux, const char *name,
404 struct device *parent) 418 struct device *parent)
405{ 419{
406 WARN_ON(aux->cec.adap); 420 WARN_ON(aux->cec.adap);
421 if (WARN_ON(!aux->transfer))
422 return;
407 aux->cec.name = name; 423 aux->cec.name = name;
408 aux->cec.parent = parent; 424 aux->cec.parent = parent;
409 INIT_DELAYED_WORK(&aux->cec.unregister_work, 425 INIT_DELAYED_WORK(&aux->cec.unregister_work,
diff --git a/drivers/gpu/drm/drm_dp_helper.c b/drivers/gpu/drm/drm_dp_helper.c
index 0cccbcb2d03e..8c6b9fd89f8a 100644
--- a/drivers/gpu/drm/drm_dp_helper.c
+++ b/drivers/gpu/drm/drm_dp_helper.c
@@ -850,7 +850,8 @@ static int drm_dp_i2c_do_msg(struct drm_dp_aux *aux, struct drm_dp_aux_msg *msg)
850 return ret; 850 return ret;
851 851
852 case DP_AUX_I2C_REPLY_NACK: 852 case DP_AUX_I2C_REPLY_NACK:
853 DRM_DEBUG_KMS("I2C nack (result=%d, size=%zu\n", ret, msg->size); 853 DRM_DEBUG_KMS("I2C nack (result=%d, size=%zu)\n",
854 ret, msg->size);
854 aux->i2c_nack_count++; 855 aux->i2c_nack_count++;
855 return -EREMOTEIO; 856 return -EREMOTEIO;
856 857
diff --git a/drivers/gpu/drm/drm_dp_mst_topology.c b/drivers/gpu/drm/drm_dp_mst_topology.c
index 7780567aa669..5ff1d79b86c4 100644
--- a/drivers/gpu/drm/drm_dp_mst_topology.c
+++ b/drivers/gpu/drm/drm_dp_mst_topology.c
@@ -439,6 +439,7 @@ static bool drm_dp_sideband_parse_remote_dpcd_read(struct drm_dp_sideband_msg_rx
439 if (idx > raw->curlen) 439 if (idx > raw->curlen)
440 goto fail_len; 440 goto fail_len;
441 repmsg->u.remote_dpcd_read_ack.num_bytes = raw->msg[idx]; 441 repmsg->u.remote_dpcd_read_ack.num_bytes = raw->msg[idx];
442 idx++;
442 if (idx > raw->curlen) 443 if (idx > raw->curlen)
443 goto fail_len; 444 goto fail_len;
444 445
diff --git a/drivers/gpu/drm/drm_fb_cma_helper.c b/drivers/gpu/drm/drm_fb_cma_helper.c
index 9da36a6271d3..47e0e2f6642d 100644
--- a/drivers/gpu/drm/drm_fb_cma_helper.c
+++ b/drivers/gpu/drm/drm_fb_cma_helper.c
@@ -86,14 +86,21 @@ dma_addr_t drm_fb_cma_get_gem_addr(struct drm_framebuffer *fb,
86{ 86{
87 struct drm_gem_cma_object *obj; 87 struct drm_gem_cma_object *obj;
88 dma_addr_t paddr; 88 dma_addr_t paddr;
89 u8 h_div = 1, v_div = 1;
89 90
90 obj = drm_fb_cma_get_gem_obj(fb, plane); 91 obj = drm_fb_cma_get_gem_obj(fb, plane);
91 if (!obj) 92 if (!obj)
92 return 0; 93 return 0;
93 94
94 paddr = obj->paddr + fb->offsets[plane]; 95 paddr = obj->paddr + fb->offsets[plane];
95 paddr += fb->format->cpp[plane] * (state->src_x >> 16); 96
96 paddr += fb->pitches[plane] * (state->src_y >> 16); 97 if (plane > 0) {
98 h_div = fb->format->hsub;
99 v_div = fb->format->vsub;
100 }
101
102 paddr += (fb->format->cpp[plane] * (state->src_x >> 16)) / h_div;
103 paddr += (fb->pitches[plane] * (state->src_y >> 16)) / v_div;
97 104
98 return paddr; 105 return paddr;
99} 106}
@@ -219,21 +226,6 @@ void drm_fbdev_cma_hotplug_event(struct drm_fbdev_cma *fbdev_cma)
219EXPORT_SYMBOL_GPL(drm_fbdev_cma_hotplug_event); 226EXPORT_SYMBOL_GPL(drm_fbdev_cma_hotplug_event);
220 227
221/** 228/**
222 * drm_fbdev_cma_set_suspend - wrapper around drm_fb_helper_set_suspend
223 * @fbdev_cma: The drm_fbdev_cma struct, may be NULL
224 * @state: desired state, zero to resume, non-zero to suspend
225 *
226 * Calls drm_fb_helper_set_suspend, which is a wrapper around
227 * fb_set_suspend implemented by fbdev core.
228 */
229void drm_fbdev_cma_set_suspend(struct drm_fbdev_cma *fbdev_cma, bool state)
230{
231 if (fbdev_cma)
232 drm_fb_helper_set_suspend(&fbdev_cma->fb_helper, state);
233}
234EXPORT_SYMBOL(drm_fbdev_cma_set_suspend);
235
236/**
237 * drm_fbdev_cma_set_suspend_unlocked - wrapper around 229 * drm_fbdev_cma_set_suspend_unlocked - wrapper around
238 * drm_fb_helper_set_suspend_unlocked 230 * drm_fb_helper_set_suspend_unlocked
239 * @fbdev_cma: The drm_fbdev_cma struct, may be NULL 231 * @fbdev_cma: The drm_fbdev_cma struct, may be NULL
diff --git a/drivers/gpu/drm/drm_gem_cma_helper.c b/drivers/gpu/drm/drm_gem_cma_helper.c
index 80a5115c3846..1d2ced882b66 100644
--- a/drivers/gpu/drm/drm_gem_cma_helper.c
+++ b/drivers/gpu/drm/drm_gem_cma_helper.c
@@ -436,7 +436,7 @@ struct sg_table *drm_gem_cma_prime_get_sg_table(struct drm_gem_object *obj)
436 436
437 sgt = kzalloc(sizeof(*sgt), GFP_KERNEL); 437 sgt = kzalloc(sizeof(*sgt), GFP_KERNEL);
438 if (!sgt) 438 if (!sgt)
439 return NULL; 439 return ERR_PTR(-ENOMEM);
440 440
441 ret = dma_get_sgtable(obj->dev->dev, sgt, cma_obj->vaddr, 441 ret = dma_get_sgtable(obj->dev->dev, sgt, cma_obj->vaddr,
442 cma_obj->paddr, obj->size); 442 cma_obj->paddr, obj->size);
@@ -447,7 +447,7 @@ struct sg_table *drm_gem_cma_prime_get_sg_table(struct drm_gem_object *obj)
447 447
448out: 448out:
449 kfree(sgt); 449 kfree(sgt);
450 return NULL; 450 return ERR_PTR(ret);
451} 451}
452EXPORT_SYMBOL_GPL(drm_gem_cma_prime_get_sg_table); 452EXPORT_SYMBOL_GPL(drm_gem_cma_prime_get_sg_table);
453 453
diff --git a/drivers/gpu/drm/drm_panel.c b/drivers/gpu/drm/drm_panel.c
index b902361dee6e..0db486d10d1c 100644
--- a/drivers/gpu/drm/drm_panel.c
+++ b/drivers/gpu/drm/drm_panel.c
@@ -152,7 +152,9 @@ EXPORT_SYMBOL(drm_panel_detach);
152 * 152 *
153 * Return: A pointer to the panel registered for the specified device tree 153 * Return: A pointer to the panel registered for the specified device tree
154 * node or an ERR_PTR() if no panel matching the device tree node can be found. 154 * node or an ERR_PTR() if no panel matching the device tree node can be found.
155 *
155 * Possible error codes returned by this function: 156 * Possible error codes returned by this function:
157 *
156 * - EPROBE_DEFER: the panel device has not been probed yet, and the caller 158 * - EPROBE_DEFER: the panel device has not been probed yet, and the caller
157 * should retry later 159 * should retry later
158 * - ENODEV: the device is not available (status != "okay" or "ok") 160 * - ENODEV: the device is not available (status != "okay" or "ok")
diff --git a/drivers/gpu/drm/drm_syncobj.c b/drivers/gpu/drm/drm_syncobj.c
index adb3cb27d31e..3a8837c49639 100644
--- a/drivers/gpu/drm/drm_syncobj.c
+++ b/drivers/gpu/drm/drm_syncobj.c
@@ -120,14 +120,6 @@ static int drm_syncobj_fence_get_or_add_callback(struct drm_syncobj *syncobj,
120 return ret; 120 return ret;
121} 121}
122 122
123/**
124 * drm_syncobj_add_callback - adds a callback to syncobj::cb_list
125 * @syncobj: Sync object to which to add the callback
126 * @cb: Callback to add
127 * @func: Func to use when initializing the drm_syncobj_cb struct
128 *
129 * This adds a callback to be called next time the fence is replaced
130 */
131void drm_syncobj_add_callback(struct drm_syncobj *syncobj, 123void drm_syncobj_add_callback(struct drm_syncobj *syncobj,
132 struct drm_syncobj_cb *cb, 124 struct drm_syncobj_cb *cb,
133 drm_syncobj_func_t func) 125 drm_syncobj_func_t func)
@@ -136,13 +128,7 @@ void drm_syncobj_add_callback(struct drm_syncobj *syncobj,
136 drm_syncobj_add_callback_locked(syncobj, cb, func); 128 drm_syncobj_add_callback_locked(syncobj, cb, func);
137 spin_unlock(&syncobj->lock); 129 spin_unlock(&syncobj->lock);
138} 130}
139EXPORT_SYMBOL(drm_syncobj_add_callback);
140 131
141/**
142 * drm_syncobj_add_callback - removes a callback to syncobj::cb_list
143 * @syncobj: Sync object from which to remove the callback
144 * @cb: Callback to remove
145 */
146void drm_syncobj_remove_callback(struct drm_syncobj *syncobj, 132void drm_syncobj_remove_callback(struct drm_syncobj *syncobj,
147 struct drm_syncobj_cb *cb) 133 struct drm_syncobj_cb *cb)
148{ 134{
@@ -150,7 +136,6 @@ void drm_syncobj_remove_callback(struct drm_syncobj *syncobj,
150 list_del_init(&cb->node); 136 list_del_init(&cb->node);
151 spin_unlock(&syncobj->lock); 137 spin_unlock(&syncobj->lock);
152} 138}
153EXPORT_SYMBOL(drm_syncobj_remove_callback);
154 139
155/** 140/**
156 * drm_syncobj_replace_fence - replace fence in a sync object. 141 * drm_syncobj_replace_fence - replace fence in a sync object.
diff --git a/drivers/gpu/drm/drm_vblank.c b/drivers/gpu/drm/drm_vblank.c
index 28cdcf76b6f9..ec2dcfdac8ef 100644
--- a/drivers/gpu/drm/drm_vblank.c
+++ b/drivers/gpu/drm/drm_vblank.c
@@ -873,8 +873,8 @@ static void send_vblank_event(struct drm_device *dev,
873 * handler by calling drm_crtc_send_vblank_event() and make sure that there's no 873 * handler by calling drm_crtc_send_vblank_event() and make sure that there's no
874 * possible race with the hardware committing the atomic update. 874 * possible race with the hardware committing the atomic update.
875 * 875 *
876 * Caller must hold a vblank reference for the event @e, which will be dropped 876 * Caller must hold a vblank reference for the event @e acquired by a
877 * when the next vblank arrives. 877 * drm_crtc_vblank_get(), which will be dropped when the next vblank arrives.
878 */ 878 */
879void drm_crtc_arm_vblank_event(struct drm_crtc *crtc, 879void drm_crtc_arm_vblank_event(struct drm_crtc *crtc,
880 struct drm_pending_vblank_event *e) 880 struct drm_pending_vblank_event *e)
@@ -1541,7 +1541,7 @@ int drm_wait_vblank_ioctl(struct drm_device *dev, void *data,
1541 if (vblwait->request.type & 1541 if (vblwait->request.type &
1542 ~(_DRM_VBLANK_TYPES_MASK | _DRM_VBLANK_FLAGS_MASK | 1542 ~(_DRM_VBLANK_TYPES_MASK | _DRM_VBLANK_FLAGS_MASK |
1543 _DRM_VBLANK_HIGH_CRTC_MASK)) { 1543 _DRM_VBLANK_HIGH_CRTC_MASK)) {
1544 DRM_ERROR("Unsupported type value 0x%x, supported mask 0x%x\n", 1544 DRM_DEBUG("Unsupported type value 0x%x, supported mask 0x%x\n",
1545 vblwait->request.type, 1545 vblwait->request.type,
1546 (_DRM_VBLANK_TYPES_MASK | _DRM_VBLANK_FLAGS_MASK | 1546 (_DRM_VBLANK_TYPES_MASK | _DRM_VBLANK_FLAGS_MASK |
1547 _DRM_VBLANK_HIGH_CRTC_MASK)); 1547 _DRM_VBLANK_HIGH_CRTC_MASK));
diff --git a/drivers/gpu/drm/drm_vma_manager.c b/drivers/gpu/drm/drm_vma_manager.c
index a6b2fe36b025..c5d0d2358301 100644
--- a/drivers/gpu/drm/drm_vma_manager.c
+++ b/drivers/gpu/drm/drm_vma_manager.c
@@ -103,10 +103,7 @@ EXPORT_SYMBOL(drm_vma_offset_manager_init);
103 */ 103 */
104void drm_vma_offset_manager_destroy(struct drm_vma_offset_manager *mgr) 104void drm_vma_offset_manager_destroy(struct drm_vma_offset_manager *mgr)
105{ 105{
106 /* take the lock to protect against buggy drivers */
107 write_lock(&mgr->vm_lock);
108 drm_mm_takedown(&mgr->vm_addr_space_mm); 106 drm_mm_takedown(&mgr->vm_addr_space_mm);
109 write_unlock(&mgr->vm_lock);
110} 107}
111EXPORT_SYMBOL(drm_vma_offset_manager_destroy); 108EXPORT_SYMBOL(drm_vma_offset_manager_destroy);
112 109
diff --git a/drivers/gpu/drm/gma500/psb_drv.h b/drivers/gpu/drm/gma500/psb_drv.h
index 93d2f4000d2f..941b238bdcc9 100644
--- a/drivers/gpu/drm/gma500/psb_drv.h
+++ b/drivers/gpu/drm/gma500/psb_drv.h
@@ -24,7 +24,6 @@
24#include <linux/mm_types.h> 24#include <linux/mm_types.h>
25 25
26#include <drm/drmP.h> 26#include <drm/drmP.h>
27#include <drm/drm_global.h>
28#include <drm/gma_drm.h> 27#include <drm/gma_drm.h>
29#include "psb_reg.h" 28#include "psb_reg.h"
30#include "psb_intel_drv.h" 29#include "psb_intel_drv.h"
diff --git a/drivers/gpu/drm/i915/i915_gem_clflush.c b/drivers/gpu/drm/i915/i915_gem_clflush.c
index f5c570d35b2a..8e74c23cbd91 100644
--- a/drivers/gpu/drm/i915/i915_gem_clflush.c
+++ b/drivers/gpu/drm/i915/i915_gem_clflush.c
@@ -45,11 +45,6 @@ static const char *i915_clflush_get_timeline_name(struct dma_fence *fence)
45 return "clflush"; 45 return "clflush";
46} 46}
47 47
48static bool i915_clflush_enable_signaling(struct dma_fence *fence)
49{
50 return true;
51}
52
53static void i915_clflush_release(struct dma_fence *fence) 48static void i915_clflush_release(struct dma_fence *fence)
54{ 49{
55 struct clflush *clflush = container_of(fence, typeof(*clflush), dma); 50 struct clflush *clflush = container_of(fence, typeof(*clflush), dma);
@@ -63,8 +58,6 @@ static void i915_clflush_release(struct dma_fence *fence)
63static const struct dma_fence_ops i915_clflush_ops = { 58static const struct dma_fence_ops i915_clflush_ops = {
64 .get_driver_name = i915_clflush_get_driver_name, 59 .get_driver_name = i915_clflush_get_driver_name,
65 .get_timeline_name = i915_clflush_get_timeline_name, 60 .get_timeline_name = i915_clflush_get_timeline_name,
66 .enable_signaling = i915_clflush_enable_signaling,
67 .wait = dma_fence_default_wait,
68 .release = i915_clflush_release, 61 .release = i915_clflush_release,
69}; 62};
70 63
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index 4a3c8ee9a973..775968fa2049 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -12896,6 +12896,8 @@ static const struct drm_crtc_funcs intel_crtc_funcs = {
12896 .atomic_duplicate_state = intel_crtc_duplicate_state, 12896 .atomic_duplicate_state = intel_crtc_duplicate_state,
12897 .atomic_destroy_state = intel_crtc_destroy_state, 12897 .atomic_destroy_state = intel_crtc_destroy_state,
12898 .set_crc_source = intel_crtc_set_crc_source, 12898 .set_crc_source = intel_crtc_set_crc_source,
12899 .verify_crc_source = intel_crtc_verify_crc_source,
12900 .get_crc_sources = intel_crtc_get_crc_sources,
12899}; 12901};
12900 12902
12901struct wait_rps_boost { 12903struct wait_rps_boost {
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index 8fc61e96754f..5f63e1a9c25b 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -2172,12 +2172,17 @@ void lspcon_wait_pcon_mode(struct intel_lspcon *lspcon);
2172 2172
2173/* intel_pipe_crc.c */ 2173/* intel_pipe_crc.c */
2174#ifdef CONFIG_DEBUG_FS 2174#ifdef CONFIG_DEBUG_FS
2175int intel_crtc_set_crc_source(struct drm_crtc *crtc, const char *source_name, 2175int intel_crtc_set_crc_source(struct drm_crtc *crtc, const char *source_name);
2176 size_t *values_cnt); 2176int intel_crtc_verify_crc_source(struct drm_crtc *crtc,
2177 const char *source_name, size_t *values_cnt);
2178const char *const *intel_crtc_get_crc_sources(struct drm_crtc *crtc,
2179 size_t *count);
2177void intel_crtc_disable_pipe_crc(struct intel_crtc *crtc); 2180void intel_crtc_disable_pipe_crc(struct intel_crtc *crtc);
2178void intel_crtc_enable_pipe_crc(struct intel_crtc *crtc); 2181void intel_crtc_enable_pipe_crc(struct intel_crtc *crtc);
2179#else 2182#else
2180#define intel_crtc_set_crc_source NULL 2183#define intel_crtc_set_crc_source NULL
2184#define intel_crtc_verify_crc_source NULL
2185#define intel_crtc_get_crc_sources NULL
2181static inline void intel_crtc_disable_pipe_crc(struct intel_crtc *crtc) 2186static inline void intel_crtc_disable_pipe_crc(struct intel_crtc *crtc)
2182{ 2187{
2183} 2188}
diff --git a/drivers/gpu/drm/i915/intel_pipe_crc.c b/drivers/gpu/drm/i915/intel_pipe_crc.c
index 849e1b69ba73..f3c9010e332a 100644
--- a/drivers/gpu/drm/i915/intel_pipe_crc.c
+++ b/drivers/gpu/drm/i915/intel_pipe_crc.c
@@ -468,8 +468,122 @@ void intel_display_crc_init(struct drm_i915_private *dev_priv)
468 } 468 }
469} 469}
470 470
471int intel_crtc_set_crc_source(struct drm_crtc *crtc, const char *source_name, 471static int i8xx_crc_source_valid(struct drm_i915_private *dev_priv,
472 size_t *values_cnt) 472 const enum intel_pipe_crc_source source)
473{
474 switch (source) {
475 case INTEL_PIPE_CRC_SOURCE_PIPE:
476 case INTEL_PIPE_CRC_SOURCE_NONE:
477 return 0;
478 default:
479 return -EINVAL;
480 }
481}
482
483static int i9xx_crc_source_valid(struct drm_i915_private *dev_priv,
484 const enum intel_pipe_crc_source source)
485{
486 switch (source) {
487 case INTEL_PIPE_CRC_SOURCE_PIPE:
488 case INTEL_PIPE_CRC_SOURCE_TV:
489 case INTEL_PIPE_CRC_SOURCE_DP_B:
490 case INTEL_PIPE_CRC_SOURCE_DP_C:
491 case INTEL_PIPE_CRC_SOURCE_DP_D:
492 case INTEL_PIPE_CRC_SOURCE_NONE:
493 return 0;
494 default:
495 return -EINVAL;
496 }
497}
498
499static int vlv_crc_source_valid(struct drm_i915_private *dev_priv,
500 const enum intel_pipe_crc_source source)
501{
502 switch (source) {
503 case INTEL_PIPE_CRC_SOURCE_PIPE:
504 case INTEL_PIPE_CRC_SOURCE_DP_B:
505 case INTEL_PIPE_CRC_SOURCE_DP_C:
506 case INTEL_PIPE_CRC_SOURCE_DP_D:
507 case INTEL_PIPE_CRC_SOURCE_NONE:
508 return 0;
509 default:
510 return -EINVAL;
511 }
512}
513
514static int ilk_crc_source_valid(struct drm_i915_private *dev_priv,
515 const enum intel_pipe_crc_source source)
516{
517 switch (source) {
518 case INTEL_PIPE_CRC_SOURCE_PIPE:
519 case INTEL_PIPE_CRC_SOURCE_PLANE1:
520 case INTEL_PIPE_CRC_SOURCE_PLANE2:
521 case INTEL_PIPE_CRC_SOURCE_NONE:
522 return 0;
523 default:
524 return -EINVAL;
525 }
526}
527
528static int ivb_crc_source_valid(struct drm_i915_private *dev_priv,
529 const enum intel_pipe_crc_source source)
530{
531 switch (source) {
532 case INTEL_PIPE_CRC_SOURCE_PIPE:
533 case INTEL_PIPE_CRC_SOURCE_PLANE1:
534 case INTEL_PIPE_CRC_SOURCE_PLANE2:
535 case INTEL_PIPE_CRC_SOURCE_PF:
536 case INTEL_PIPE_CRC_SOURCE_NONE:
537 return 0;
538 default:
539 return -EINVAL;
540 }
541}
542
543static int
544intel_is_valid_crc_source(struct drm_i915_private *dev_priv,
545 const enum intel_pipe_crc_source source)
546{
547 if (IS_GEN2(dev_priv))
548 return i8xx_crc_source_valid(dev_priv, source);
549 else if (INTEL_GEN(dev_priv) < 5)
550 return i9xx_crc_source_valid(dev_priv, source);
551 else if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv))
552 return vlv_crc_source_valid(dev_priv, source);
553 else if (IS_GEN5(dev_priv) || IS_GEN6(dev_priv))
554 return ilk_crc_source_valid(dev_priv, source);
555 else
556 return ivb_crc_source_valid(dev_priv, source);
557}
558
559const char *const *intel_crtc_get_crc_sources(struct drm_crtc *crtc,
560 size_t *count)
561{
562 *count = ARRAY_SIZE(pipe_crc_sources);
563 return pipe_crc_sources;
564}
565
566int intel_crtc_verify_crc_source(struct drm_crtc *crtc, const char *source_name,
567 size_t *values_cnt)
568{
569 struct drm_i915_private *dev_priv = to_i915(crtc->dev);
570 enum intel_pipe_crc_source source;
571
572 if (display_crc_ctl_parse_source(source_name, &source) < 0) {
573 DRM_DEBUG_DRIVER("unknown source %s\n", source_name);
574 return -EINVAL;
575 }
576
577 if (source == INTEL_PIPE_CRC_SOURCE_AUTO ||
578 intel_is_valid_crc_source(dev_priv, source) == 0) {
579 *values_cnt = 5;
580 return 0;
581 }
582
583 return -EINVAL;
584}
585
586int intel_crtc_set_crc_source(struct drm_crtc *crtc, const char *source_name)
473{ 587{
474 struct drm_i915_private *dev_priv = to_i915(crtc->dev); 588 struct drm_i915_private *dev_priv = to_i915(crtc->dev);
475 struct intel_pipe_crc *pipe_crc = &dev_priv->pipe_crc[crtc->index]; 589 struct intel_pipe_crc *pipe_crc = &dev_priv->pipe_crc[crtc->index];
@@ -508,7 +622,6 @@ int intel_crtc_set_crc_source(struct drm_crtc *crtc, const char *source_name,
508 } 622 }
509 623
510 pipe_crc->skipped = 0; 624 pipe_crc->skipped = 0;
511 *values_cnt = 5;
512 625
513out: 626out:
514 intel_display_power_put(dev_priv, power_domain); 627 intel_display_power_put(dev_priv, power_domain);
diff --git a/drivers/gpu/drm/i915/selftests/i915_sw_fence.c b/drivers/gpu/drm/i915/selftests/i915_sw_fence.c
index 570e325af93e..cdbc8f134e5e 100644
--- a/drivers/gpu/drm/i915/selftests/i915_sw_fence.c
+++ b/drivers/gpu/drm/i915/selftests/i915_sw_fence.c
@@ -611,17 +611,9 @@ static const char *mock_name(struct dma_fence *fence)
611 return "mock"; 611 return "mock";
612} 612}
613 613
614static bool mock_enable_signaling(struct dma_fence *fence)
615{
616 return true;
617}
618
619static const struct dma_fence_ops mock_fence_ops = { 614static const struct dma_fence_ops mock_fence_ops = {
620 .get_driver_name = mock_name, 615 .get_driver_name = mock_name,
621 .get_timeline_name = mock_name, 616 .get_timeline_name = mock_name,
622 .enable_signaling = mock_enable_signaling,
623 .wait = dma_fence_default_wait,
624 .release = dma_fence_free,
625}; 617};
626 618
627static DEFINE_SPINLOCK(mock_fence_lock); 619static DEFINE_SPINLOCK(mock_fence_lock);
diff --git a/drivers/gpu/drm/imx/ipuv3-plane.c b/drivers/gpu/drm/imx/ipuv3-plane.c
index 203f247d4854..40605fdf0e33 100644
--- a/drivers/gpu/drm/imx/ipuv3-plane.c
+++ b/drivers/gpu/drm/imx/ipuv3-plane.c
@@ -281,16 +281,13 @@ static void ipu_plane_state_reset(struct drm_plane *plane)
281 ipu_state = to_ipu_plane_state(plane->state); 281 ipu_state = to_ipu_plane_state(plane->state);
282 __drm_atomic_helper_plane_destroy_state(plane->state); 282 __drm_atomic_helper_plane_destroy_state(plane->state);
283 kfree(ipu_state); 283 kfree(ipu_state);
284 plane->state = NULL;
284 } 285 }
285 286
286 ipu_state = kzalloc(sizeof(*ipu_state), GFP_KERNEL); 287 ipu_state = kzalloc(sizeof(*ipu_state), GFP_KERNEL);
287 288
288 if (ipu_state) { 289 if (ipu_state)
289 ipu_state->base.plane = plane; 290 __drm_atomic_helper_plane_reset(plane, &ipu_state->base);
290 ipu_state->base.rotation = DRM_MODE_ROTATE_0;
291 }
292
293 plane->state = &ipu_state->base;
294} 291}
295 292
296static struct drm_plane_state * 293static struct drm_plane_state *
diff --git a/drivers/gpu/drm/mgag200/mgag200_drv.c b/drivers/gpu/drm/mgag200/mgag200_drv.c
index 74cdde2ee474..ac6af4bd9df6 100644
--- a/drivers/gpu/drm/mgag200/mgag200_drv.c
+++ b/drivers/gpu/drm/mgag200/mgag200_drv.c
@@ -42,29 +42,10 @@ static const struct pci_device_id pciidlist[] = {
42 42
43MODULE_DEVICE_TABLE(pci, pciidlist); 43MODULE_DEVICE_TABLE(pci, pciidlist);
44 44
45static void mgag200_kick_out_firmware_fb(struct pci_dev *pdev)
46{
47 struct apertures_struct *ap;
48 bool primary = false;
49
50 ap = alloc_apertures(1);
51 if (!ap)
52 return;
53
54 ap->ranges[0].base = pci_resource_start(pdev, 0);
55 ap->ranges[0].size = pci_resource_len(pdev, 0);
56
57#ifdef CONFIG_X86
58 primary = pdev->resource[PCI_ROM_RESOURCE].flags & IORESOURCE_ROM_SHADOW;
59#endif
60 drm_fb_helper_remove_conflicting_framebuffers(ap, "mgag200drmfb", primary);
61 kfree(ap);
62}
63
64 45
65static int mga_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) 46static int mga_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
66{ 47{
67 mgag200_kick_out_firmware_fb(pdev); 48 drm_fb_helper_remove_conflicting_pci_framebuffers(pdev, 0, "mgag200drmfb");
68 49
69 return drm_get_pci_dev(pdev, ent, &driver); 50 return drm_get_pci_dev(pdev, ent, &driver);
70} 51}
diff --git a/drivers/gpu/drm/mgag200/mgag200_main.c b/drivers/gpu/drm/mgag200/mgag200_main.c
index 780f983b0294..79d54103d470 100644
--- a/drivers/gpu/drm/mgag200/mgag200_main.c
+++ b/drivers/gpu/drm/mgag200/mgag200_main.c
@@ -124,20 +124,11 @@ static int mga_probe_vram(struct mga_device *mdev, void __iomem *mem)
124static int mga_vram_init(struct mga_device *mdev) 124static int mga_vram_init(struct mga_device *mdev)
125{ 125{
126 void __iomem *mem; 126 void __iomem *mem;
127 struct apertures_struct *aper = alloc_apertures(1);
128 if (!aper)
129 return -ENOMEM;
130 127
131 /* BAR 0 is VRAM */ 128 /* BAR 0 is VRAM */
132 mdev->mc.vram_base = pci_resource_start(mdev->dev->pdev, 0); 129 mdev->mc.vram_base = pci_resource_start(mdev->dev->pdev, 0);
133 mdev->mc.vram_window = pci_resource_len(mdev->dev->pdev, 0); 130 mdev->mc.vram_window = pci_resource_len(mdev->dev->pdev, 0);
134 131
135 aper->ranges[0].base = mdev->mc.vram_base;
136 aper->ranges[0].size = mdev->mc.vram_window;
137
138 drm_fb_helper_remove_conflicting_framebuffers(aper, "mgafb", true);
139 kfree(aper);
140
141 if (!devm_request_mem_region(mdev->dev->dev, mdev->mc.vram_base, mdev->mc.vram_window, 132 if (!devm_request_mem_region(mdev->dev->dev, mdev->mc.vram_base, mdev->mc.vram_window,
142 "mgadrmfb_vram")) { 133 "mgadrmfb_vram")) {
143 DRM_ERROR("can't reserve VRAM\n"); 134 DRM_ERROR("can't reserve VRAM\n");
diff --git a/drivers/gpu/drm/msm/msm_fence.c b/drivers/gpu/drm/msm/msm_fence.c
index 349c12f670eb..77263cf97b20 100644
--- a/drivers/gpu/drm/msm/msm_fence.c
+++ b/drivers/gpu/drm/msm/msm_fence.c
@@ -119,11 +119,6 @@ static const char *msm_fence_get_timeline_name(struct dma_fence *fence)
119 return f->fctx->name; 119 return f->fctx->name;
120} 120}
121 121
122static bool msm_fence_enable_signaling(struct dma_fence *fence)
123{
124 return true;
125}
126
127static bool msm_fence_signaled(struct dma_fence *fence) 122static bool msm_fence_signaled(struct dma_fence *fence)
128{ 123{
129 struct msm_fence *f = to_msm_fence(fence); 124 struct msm_fence *f = to_msm_fence(fence);
@@ -133,10 +128,7 @@ static bool msm_fence_signaled(struct dma_fence *fence)
133static const struct dma_fence_ops msm_fence_ops = { 128static const struct dma_fence_ops msm_fence_ops = {
134 .get_driver_name = msm_fence_get_driver_name, 129 .get_driver_name = msm_fence_get_driver_name,
135 .get_timeline_name = msm_fence_get_timeline_name, 130 .get_timeline_name = msm_fence_get_timeline_name,
136 .enable_signaling = msm_fence_enable_signaling,
137 .signaled = msm_fence_signaled, 131 .signaled = msm_fence_signaled,
138 .wait = dma_fence_default_wait,
139 .release = dma_fence_free,
140}; 132};
141 133
142struct dma_fence * 134struct dma_fence *
diff --git a/drivers/gpu/drm/nouveau/nouveau_connector.c b/drivers/gpu/drm/nouveau/nouveau_connector.c
index 51932c72334e..eb4f766b5958 100644
--- a/drivers/gpu/drm/nouveau/nouveau_connector.c
+++ b/drivers/gpu/drm/nouveau/nouveau_connector.c
@@ -400,8 +400,10 @@ nouveau_connector_destroy(struct drm_connector *connector)
400 kfree(nv_connector->edid); 400 kfree(nv_connector->edid);
401 drm_connector_unregister(connector); 401 drm_connector_unregister(connector);
402 drm_connector_cleanup(connector); 402 drm_connector_cleanup(connector);
403 if (nv_connector->aux.transfer) 403 if (nv_connector->aux.transfer) {
404 drm_dp_cec_unregister_connector(&nv_connector->aux);
404 drm_dp_aux_unregister(&nv_connector->aux); 405 drm_dp_aux_unregister(&nv_connector->aux);
406 }
405 kfree(connector); 407 kfree(connector);
406} 408}
407 409
@@ -608,6 +610,7 @@ nouveau_connector_detect(struct drm_connector *connector, bool force)
608 610
609 nouveau_connector_set_encoder(connector, nv_encoder); 611 nouveau_connector_set_encoder(connector, nv_encoder);
610 conn_status = connector_status_connected; 612 conn_status = connector_status_connected;
613 drm_dp_cec_set_edid(&nv_connector->aux, nv_connector->edid);
611 goto out; 614 goto out;
612 } 615 }
613 616
@@ -1108,11 +1111,14 @@ nouveau_connector_hotplug(struct nvif_notify *notify)
1108 1111
1109 if (rep->mask & NVIF_NOTIFY_CONN_V0_IRQ) { 1112 if (rep->mask & NVIF_NOTIFY_CONN_V0_IRQ) {
1110 NV_DEBUG(drm, "service %s\n", name); 1113 NV_DEBUG(drm, "service %s\n", name);
1114 drm_dp_cec_irq(&nv_connector->aux);
1111 if ((nv_encoder = find_encoder(connector, DCB_OUTPUT_DP))) 1115 if ((nv_encoder = find_encoder(connector, DCB_OUTPUT_DP)))
1112 nv50_mstm_service(nv_encoder->dp.mstm); 1116 nv50_mstm_service(nv_encoder->dp.mstm);
1113 } else { 1117 } else {
1114 bool plugged = (rep->mask != NVIF_NOTIFY_CONN_V0_UNPLUG); 1118 bool plugged = (rep->mask != NVIF_NOTIFY_CONN_V0_UNPLUG);
1115 1119
1120 if (!plugged)
1121 drm_dp_cec_unset_edid(&nv_connector->aux);
1116 NV_DEBUG(drm, "%splugged %s\n", plugged ? "" : "un", name); 1122 NV_DEBUG(drm, "%splugged %s\n", plugged ? "" : "un", name);
1117 if ((nv_encoder = find_encoder(connector, DCB_OUTPUT_DP))) { 1123 if ((nv_encoder = find_encoder(connector, DCB_OUTPUT_DP))) {
1118 if (!plugged) 1124 if (!plugged)
@@ -1302,7 +1308,6 @@ nouveau_connector_create(struct drm_device *dev, int index)
1302 kfree(nv_connector); 1308 kfree(nv_connector);
1303 return ERR_PTR(ret); 1309 return ERR_PTR(ret);
1304 } 1310 }
1305
1306 funcs = &nouveau_connector_funcs; 1311 funcs = &nouveau_connector_funcs;
1307 break; 1312 break;
1308 default: 1313 default:
@@ -1356,6 +1361,14 @@ nouveau_connector_create(struct drm_device *dev, int index)
1356 break; 1361 break;
1357 } 1362 }
1358 1363
1364 switch (type) {
1365 case DRM_MODE_CONNECTOR_DisplayPort:
1366 case DRM_MODE_CONNECTOR_eDP:
1367 drm_dp_cec_register_connector(&nv_connector->aux,
1368 connector->name, dev->dev);
1369 break;
1370 }
1371
1359 ret = nvif_notify_init(&disp->disp.object, nouveau_connector_hotplug, 1372 ret = nvif_notify_init(&disp->disp.object, nouveau_connector_hotplug,
1360 true, NV04_DISP_NTFY_CONN, 1373 true, NV04_DISP_NTFY_CONN,
1361 &(struct nvif_notify_conn_req_v0) { 1374 &(struct nvif_notify_conn_req_v0) {
diff --git a/drivers/gpu/drm/nouveau/nouveau_fence.c b/drivers/gpu/drm/nouveau/nouveau_fence.c
index 412d49bc6e56..99be61ddeb75 100644
--- a/drivers/gpu/drm/nouveau/nouveau_fence.c
+++ b/drivers/gpu/drm/nouveau/nouveau_fence.c
@@ -526,6 +526,5 @@ static const struct dma_fence_ops nouveau_fence_ops_uevent = {
526 .get_timeline_name = nouveau_fence_get_timeline_name, 526 .get_timeline_name = nouveau_fence_get_timeline_name,
527 .enable_signaling = nouveau_fence_enable_signaling, 527 .enable_signaling = nouveau_fence_enable_signaling,
528 .signaled = nouveau_fence_is_signaled, 528 .signaled = nouveau_fence_is_signaled,
529 .wait = dma_fence_default_wait,
530 .release = nouveau_fence_release 529 .release = nouveau_fence_release
531}; 530};
diff --git a/drivers/gpu/drm/qxl/qxl_display.c b/drivers/gpu/drm/qxl/qxl_display.c
index 0570c6826bff..01704a7f07cb 100644
--- a/drivers/gpu/drm/qxl/qxl_display.c
+++ b/drivers/gpu/drm/qxl/qxl_display.c
@@ -37,7 +37,8 @@ static bool qxl_head_enabled(struct qxl_head *head)
37 return head->width && head->height; 37 return head->width && head->height;
38} 38}
39 39
40static void qxl_alloc_client_monitors_config(struct qxl_device *qdev, unsigned count) 40static int qxl_alloc_client_monitors_config(struct qxl_device *qdev,
41 unsigned int count)
41{ 42{
42 if (qdev->client_monitors_config && 43 if (qdev->client_monitors_config &&
43 count > qdev->client_monitors_config->count) { 44 count > qdev->client_monitors_config->count) {
@@ -49,15 +50,17 @@ static void qxl_alloc_client_monitors_config(struct qxl_device *qdev, unsigned c
49 sizeof(struct qxl_monitors_config) + 50 sizeof(struct qxl_monitors_config) +
50 sizeof(struct qxl_head) * count, GFP_KERNEL); 51 sizeof(struct qxl_head) * count, GFP_KERNEL);
51 if (!qdev->client_monitors_config) 52 if (!qdev->client_monitors_config)
52 return; 53 return -ENOMEM;
53 } 54 }
54 qdev->client_monitors_config->count = count; 55 qdev->client_monitors_config->count = count;
56 return 0;
55} 57}
56 58
57enum { 59enum {
58 MONITORS_CONFIG_MODIFIED, 60 MONITORS_CONFIG_MODIFIED,
59 MONITORS_CONFIG_UNCHANGED, 61 MONITORS_CONFIG_UNCHANGED,
60 MONITORS_CONFIG_BAD_CRC, 62 MONITORS_CONFIG_BAD_CRC,
63 MONITORS_CONFIG_ERROR,
61}; 64};
62 65
63static int qxl_display_copy_rom_client_monitors_config(struct qxl_device *qdev) 66static int qxl_display_copy_rom_client_monitors_config(struct qxl_device *qdev)
@@ -87,7 +90,10 @@ static int qxl_display_copy_rom_client_monitors_config(struct qxl_device *qdev)
87 && (num_monitors != qdev->client_monitors_config->count)) { 90 && (num_monitors != qdev->client_monitors_config->count)) {
88 status = MONITORS_CONFIG_MODIFIED; 91 status = MONITORS_CONFIG_MODIFIED;
89 } 92 }
90 qxl_alloc_client_monitors_config(qdev, num_monitors); 93 if (qxl_alloc_client_monitors_config(qdev, num_monitors)) {
94 status = MONITORS_CONFIG_ERROR;
95 return status;
96 }
91 /* we copy max from the client but it isn't used */ 97 /* we copy max from the client but it isn't used */
92 qdev->client_monitors_config->max_allowed = 98 qdev->client_monitors_config->max_allowed =
93 qdev->monitors_config->max_allowed; 99 qdev->monitors_config->max_allowed;
@@ -161,6 +167,10 @@ void qxl_display_read_client_monitors_config(struct qxl_device *qdev)
161 break; 167 break;
162 udelay(5); 168 udelay(5);
163 } 169 }
170 if (status == MONITORS_CONFIG_ERROR) {
171 DRM_DEBUG_KMS("ignoring client monitors config: error");
172 return;
173 }
164 if (status == MONITORS_CONFIG_BAD_CRC) { 174 if (status == MONITORS_CONFIG_BAD_CRC) {
165 DRM_DEBUG_KMS("ignoring client monitors config: bad crc"); 175 DRM_DEBUG_KMS("ignoring client monitors config: bad crc");
166 return; 176 return;
diff --git a/drivers/gpu/drm/qxl/qxl_drv.c b/drivers/gpu/drm/qxl/qxl_drv.c
index 2445e75cf7ea..13c8a662f9b4 100644
--- a/drivers/gpu/drm/qxl/qxl_drv.c
+++ b/drivers/gpu/drm/qxl/qxl_drv.c
@@ -119,7 +119,7 @@ qxl_pci_remove(struct pci_dev *pdev)
119 119
120 dev->dev_private = NULL; 120 dev->dev_private = NULL;
121 kfree(qdev); 121 kfree(qdev);
122 drm_dev_unref(dev); 122 drm_dev_put(dev);
123} 123}
124 124
125static const struct file_operations qxl_fops = { 125static const struct file_operations qxl_fops = {
@@ -136,20 +136,11 @@ static int qxl_drm_freeze(struct drm_device *dev)
136{ 136{
137 struct pci_dev *pdev = dev->pdev; 137 struct pci_dev *pdev = dev->pdev;
138 struct qxl_device *qdev = dev->dev_private; 138 struct qxl_device *qdev = dev->dev_private;
139 struct drm_crtc *crtc; 139 int ret;
140
141 drm_kms_helper_poll_disable(dev);
142
143 console_lock();
144 qxl_fbdev_set_suspend(qdev, 1);
145 console_unlock();
146 140
147 /* unpin the front buffers */ 141 ret = drm_mode_config_helper_suspend(dev);
148 list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { 142 if (ret)
149 const struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private; 143 return ret;
150 if (crtc->enabled)
151 (*crtc_funcs->disable)(crtc);
152 }
153 144
154 qxl_destroy_monitors_object(qdev); 145 qxl_destroy_monitors_object(qdev);
155 qxl_surf_evict(qdev); 146 qxl_surf_evict(qdev);
@@ -175,14 +166,7 @@ static int qxl_drm_resume(struct drm_device *dev, bool thaw)
175 } 166 }
176 167
177 qxl_create_monitors_object(qdev); 168 qxl_create_monitors_object(qdev);
178 drm_helper_resume_force_mode(dev); 169 return drm_mode_config_helper_resume(dev);
179
180 console_lock();
181 qxl_fbdev_set_suspend(qdev, 0);
182 console_unlock();
183
184 drm_kms_helper_poll_enable(dev);
185 return 0;
186} 170}
187 171
188static int qxl_pm_suspend(struct device *dev) 172static int qxl_pm_suspend(struct device *dev)
diff --git a/drivers/gpu/drm/qxl/qxl_gem.c b/drivers/gpu/drm/qxl/qxl_gem.c
index f5c1e7872e92..89606c819d82 100644
--- a/drivers/gpu/drm/qxl/qxl_gem.c
+++ b/drivers/gpu/drm/qxl/qxl_gem.c
@@ -40,7 +40,7 @@ void qxl_gem_object_free(struct drm_gem_object *gobj)
40 qxl_surface_evict(qdev, qobj, false); 40 qxl_surface_evict(qdev, qobj, false);
41 41
42 tbo = &qobj->tbo; 42 tbo = &qobj->tbo;
43 ttm_bo_unref(&tbo); 43 ttm_bo_put(tbo);
44} 44}
45 45
46int qxl_gem_object_create(struct qxl_device *qdev, int size, 46int qxl_gem_object_create(struct qxl_device *qdev, int size,
diff --git a/drivers/gpu/drm/qxl/qxl_kms.c b/drivers/gpu/drm/qxl/qxl_kms.c
index 771250aed78d..e25c589d5f50 100644
--- a/drivers/gpu/drm/qxl/qxl_kms.c
+++ b/drivers/gpu/drm/qxl/qxl_kms.c
@@ -102,8 +102,10 @@ int qxl_device_init(struct qxl_device *qdev,
102 int r, sb; 102 int r, sb;
103 103
104 r = drm_dev_init(&qdev->ddev, drv, &pdev->dev); 104 r = drm_dev_init(&qdev->ddev, drv, &pdev->dev);
105 if (r) 105 if (r) {
106 return r; 106 pr_err("Unable to init drm dev");
107 goto error;
108 }
107 109
108 qdev->ddev.pdev = pdev; 110 qdev->ddev.pdev = pdev;
109 pci_set_drvdata(pdev, &qdev->ddev); 111 pci_set_drvdata(pdev, &qdev->ddev);
@@ -121,6 +123,11 @@ int qxl_device_init(struct qxl_device *qdev,
121 qdev->io_base = pci_resource_start(pdev, 3); 123 qdev->io_base = pci_resource_start(pdev, 3);
122 124
123 qdev->vram_mapping = io_mapping_create_wc(qdev->vram_base, pci_resource_len(pdev, 0)); 125 qdev->vram_mapping = io_mapping_create_wc(qdev->vram_base, pci_resource_len(pdev, 0));
126 if (!qdev->vram_mapping) {
127 pr_err("Unable to create vram_mapping");
128 r = -ENOMEM;
129 goto error;
130 }
124 131
125 if (pci_resource_len(pdev, 4) > 0) { 132 if (pci_resource_len(pdev, 4) > 0) {
126 /* 64bit surface bar present */ 133 /* 64bit surface bar present */
@@ -139,6 +146,11 @@ int qxl_device_init(struct qxl_device *qdev,
139 qdev->surface_mapping = 146 qdev->surface_mapping =
140 io_mapping_create_wc(qdev->surfaceram_base, 147 io_mapping_create_wc(qdev->surfaceram_base,
141 qdev->surfaceram_size); 148 qdev->surfaceram_size);
149 if (!qdev->surface_mapping) {
150 pr_err("Unable to create surface_mapping");
151 r = -ENOMEM;
152 goto vram_mapping_free;
153 }
142 } 154 }
143 155
144 DRM_DEBUG_KMS("qxl: vram %llx-%llx(%dM %dk), surface %llx-%llx(%dM %dk, %s)\n", 156 DRM_DEBUG_KMS("qxl: vram %llx-%llx(%dM %dk), surface %llx-%llx(%dM %dk, %s)\n",
@@ -155,20 +167,29 @@ int qxl_device_init(struct qxl_device *qdev,
155 qdev->rom = ioremap(qdev->rom_base, qdev->rom_size); 167 qdev->rom = ioremap(qdev->rom_base, qdev->rom_size);
156 if (!qdev->rom) { 168 if (!qdev->rom) {
157 pr_err("Unable to ioremap ROM\n"); 169 pr_err("Unable to ioremap ROM\n");
158 return -ENOMEM; 170 r = -ENOMEM;
171 goto surface_mapping_free;
159 } 172 }
160 173
161 qxl_check_device(qdev); 174 if (!qxl_check_device(qdev)) {
175 r = -ENODEV;
176 goto surface_mapping_free;
177 }
162 178
163 r = qxl_bo_init(qdev); 179 r = qxl_bo_init(qdev);
164 if (r) { 180 if (r) {
165 DRM_ERROR("bo init failed %d\n", r); 181 DRM_ERROR("bo init failed %d\n", r);
166 return r; 182 goto rom_unmap;
167 } 183 }
168 184
169 qdev->ram_header = ioremap(qdev->vram_base + 185 qdev->ram_header = ioremap(qdev->vram_base +
170 qdev->rom->ram_header_offset, 186 qdev->rom->ram_header_offset,
171 sizeof(*qdev->ram_header)); 187 sizeof(*qdev->ram_header));
188 if (!qdev->ram_header) {
189 DRM_ERROR("Unable to ioremap RAM header\n");
190 r = -ENOMEM;
191 goto bo_fini;
192 }
172 193
173 qdev->command_ring = qxl_ring_create(&(qdev->ram_header->cmd_ring_hdr), 194 qdev->command_ring = qxl_ring_create(&(qdev->ram_header->cmd_ring_hdr),
174 sizeof(struct qxl_command), 195 sizeof(struct qxl_command),
@@ -176,6 +197,11 @@ int qxl_device_init(struct qxl_device *qdev,
176 qdev->io_base + QXL_IO_NOTIFY_CMD, 197 qdev->io_base + QXL_IO_NOTIFY_CMD,
177 false, 198 false,
178 &qdev->display_event); 199 &qdev->display_event);
200 if (!qdev->command_ring) {
201 DRM_ERROR("Unable to create command ring\n");
202 r = -ENOMEM;
203 goto ram_header_unmap;
204 }
179 205
180 qdev->cursor_ring = qxl_ring_create( 206 qdev->cursor_ring = qxl_ring_create(
181 &(qdev->ram_header->cursor_ring_hdr), 207 &(qdev->ram_header->cursor_ring_hdr),
@@ -185,12 +211,23 @@ int qxl_device_init(struct qxl_device *qdev,
185 false, 211 false,
186 &qdev->cursor_event); 212 &qdev->cursor_event);
187 213
214 if (!qdev->cursor_ring) {
215 DRM_ERROR("Unable to create cursor ring\n");
216 r = -ENOMEM;
217 goto command_ring_free;
218 }
219
188 qdev->release_ring = qxl_ring_create( 220 qdev->release_ring = qxl_ring_create(
189 &(qdev->ram_header->release_ring_hdr), 221 &(qdev->ram_header->release_ring_hdr),
190 sizeof(uint64_t), 222 sizeof(uint64_t),
191 QXL_RELEASE_RING_SIZE, 0, true, 223 QXL_RELEASE_RING_SIZE, 0, true,
192 NULL); 224 NULL);
193 225
226 if (!qdev->release_ring) {
227 DRM_ERROR("Unable to create release ring\n");
228 r = -ENOMEM;
229 goto cursor_ring_free;
230 }
194 /* TODO - slot initialization should happen on reset. where is our 231 /* TODO - slot initialization should happen on reset. where is our
195 * reset handler? */ 232 * reset handler? */
196 qdev->n_mem_slots = qdev->rom->slots_end; 233 qdev->n_mem_slots = qdev->rom->slots_end;
@@ -203,6 +240,12 @@ int qxl_device_init(struct qxl_device *qdev,
203 kmalloc_array(qdev->n_mem_slots, sizeof(struct qxl_memslot), 240 kmalloc_array(qdev->n_mem_slots, sizeof(struct qxl_memslot),
204 GFP_KERNEL); 241 GFP_KERNEL);
205 242
243 if (!qdev->mem_slots) {
244 DRM_ERROR("Unable to alloc mem slots\n");
245 r = -ENOMEM;
246 goto release_ring_free;
247 }
248
206 idr_init(&qdev->release_idr); 249 idr_init(&qdev->release_idr);
207 spin_lock_init(&qdev->release_idr_lock); 250 spin_lock_init(&qdev->release_idr_lock);
208 spin_lock_init(&qdev->release_lock); 251 spin_lock_init(&qdev->release_lock);
@@ -218,8 +261,10 @@ int qxl_device_init(struct qxl_device *qdev,
218 261
219 /* must initialize irq before first async io - slot creation */ 262 /* must initialize irq before first async io - slot creation */
220 r = qxl_irq_init(qdev); 263 r = qxl_irq_init(qdev);
221 if (r) 264 if (r) {
222 return r; 265 DRM_ERROR("Unable to init qxl irq\n");
266 goto mem_slots_free;
267 }
223 268
224 /* 269 /*
225 * Note that virtual is surface0. We rely on the single ioremap done 270 * Note that virtual is surface0. We rely on the single ioremap done
@@ -243,6 +288,27 @@ int qxl_device_init(struct qxl_device *qdev,
243 INIT_WORK(&qdev->gc_work, qxl_gc_work); 288 INIT_WORK(&qdev->gc_work, qxl_gc_work);
244 289
245 return 0; 290 return 0;
291
292mem_slots_free:
293 kfree(qdev->mem_slots);
294release_ring_free:
295 qxl_ring_free(qdev->release_ring);
296cursor_ring_free:
297 qxl_ring_free(qdev->cursor_ring);
298command_ring_free:
299 qxl_ring_free(qdev->command_ring);
300ram_header_unmap:
301 iounmap(qdev->ram_header);
302bo_fini:
303 qxl_bo_fini(qdev);
304rom_unmap:
305 iounmap(qdev->rom);
306surface_mapping_free:
307 io_mapping_free(qdev->surface_mapping);
308vram_mapping_free:
309 io_mapping_free(qdev->vram_mapping);
310error:
311 return r;
246} 312}
247 313
248void qxl_device_fini(struct qxl_device *qdev) 314void qxl_device_fini(struct qxl_device *qdev)
diff --git a/drivers/gpu/drm/radeon/radeon_drv.c b/drivers/gpu/drm/radeon/radeon_drv.c
index 2a7977a23b31..99c63eeb2866 100644
--- a/drivers/gpu/drm/radeon/radeon_drv.c
+++ b/drivers/gpu/drm/radeon/radeon_drv.c
@@ -316,27 +316,6 @@ static struct drm_driver kms_driver;
316 316
317bool radeon_device_is_virtual(void); 317bool radeon_device_is_virtual(void);
318 318
319static int radeon_kick_out_firmware_fb(struct pci_dev *pdev)
320{
321 struct apertures_struct *ap;
322 bool primary = false;
323
324 ap = alloc_apertures(1);
325 if (!ap)
326 return -ENOMEM;
327
328 ap->ranges[0].base = pci_resource_start(pdev, 0);
329 ap->ranges[0].size = pci_resource_len(pdev, 0);
330
331#ifdef CONFIG_X86
332 primary = pdev->resource[PCI_ROM_RESOURCE].flags & IORESOURCE_ROM_SHADOW;
333#endif
334 drm_fb_helper_remove_conflicting_framebuffers(ap, "radeondrmfb", primary);
335 kfree(ap);
336
337 return 0;
338}
339
340static int radeon_pci_probe(struct pci_dev *pdev, 319static int radeon_pci_probe(struct pci_dev *pdev,
341 const struct pci_device_id *ent) 320 const struct pci_device_id *ent)
342{ 321{
@@ -346,7 +325,7 @@ static int radeon_pci_probe(struct pci_dev *pdev,
346 return -EPROBE_DEFER; 325 return -EPROBE_DEFER;
347 326
348 /* Get rid of things like offb */ 327 /* Get rid of things like offb */
349 ret = radeon_kick_out_firmware_fb(pdev); 328 ret = drm_fb_helper_remove_conflicting_pci_framebuffers(pdev, 0, "radeondrmfb");
350 if (ret) 329 if (ret)
351 return ret; 330 return ret;
352 331
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c
index 15dc9caa128b..8a9e5e6f16b4 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c
+++ b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c
@@ -691,6 +691,65 @@ static const struct drm_crtc_helper_funcs crtc_helper_funcs = {
691 .atomic_disable = rcar_du_crtc_atomic_disable, 691 .atomic_disable = rcar_du_crtc_atomic_disable,
692}; 692};
693 693
694static void rcar_du_crtc_crc_init(struct rcar_du_crtc *rcrtc)
695{
696 struct rcar_du_device *rcdu = rcrtc->group->dev;
697 const char **sources;
698 unsigned int count;
699 int i = -1;
700
701 /* CRC available only on Gen3 HW. */
702 if (rcdu->info->gen < 3)
703 return;
704
705 /* Reserve 1 for "auto" source. */
706 count = rcrtc->vsp->num_planes + 1;
707
708 sources = kmalloc_array(count, sizeof(*sources), GFP_KERNEL);
709 if (!sources)
710 return;
711
712 sources[0] = kstrdup("auto", GFP_KERNEL);
713 if (!sources[0])
714 goto error;
715
716 for (i = 0; i < rcrtc->vsp->num_planes; ++i) {
717 struct drm_plane *plane = &rcrtc->vsp->planes[i].plane;
718 char name[16];
719
720 sprintf(name, "plane%u", plane->base.id);
721 sources[i + 1] = kstrdup(name, GFP_KERNEL);
722 if (!sources[i + 1])
723 goto error;
724 }
725
726 rcrtc->sources = sources;
727 rcrtc->sources_count = count;
728 return;
729
730error:
731 while (i >= 0) {
732 kfree(sources[i]);
733 i--;
734 }
735 kfree(sources);
736}
737
738static void rcar_du_crtc_crc_cleanup(struct rcar_du_crtc *rcrtc)
739{
740 unsigned int i;
741
742 if (!rcrtc->sources)
743 return;
744
745 for (i = 0; i < rcrtc->sources_count; i++)
746 kfree(rcrtc->sources[i]);
747 kfree(rcrtc->sources);
748
749 rcrtc->sources = NULL;
750 rcrtc->sources_count = 0;
751}
752
694static struct drm_crtc_state * 753static struct drm_crtc_state *
695rcar_du_crtc_atomic_duplicate_state(struct drm_crtc *crtc) 754rcar_du_crtc_atomic_duplicate_state(struct drm_crtc *crtc)
696{ 755{
@@ -717,6 +776,15 @@ static void rcar_du_crtc_atomic_destroy_state(struct drm_crtc *crtc,
717 kfree(to_rcar_crtc_state(state)); 776 kfree(to_rcar_crtc_state(state));
718} 777}
719 778
779static void rcar_du_crtc_cleanup(struct drm_crtc *crtc)
780{
781 struct rcar_du_crtc *rcrtc = to_rcar_crtc(crtc);
782
783 rcar_du_crtc_crc_cleanup(rcrtc);
784
785 return drm_crtc_cleanup(crtc);
786}
787
720static void rcar_du_crtc_reset(struct drm_crtc *crtc) 788static void rcar_du_crtc_reset(struct drm_crtc *crtc)
721{ 789{
722 struct rcar_du_crtc_state *state; 790 struct rcar_du_crtc_state *state;
@@ -756,17 +824,11 @@ static void rcar_du_crtc_disable_vblank(struct drm_crtc *crtc)
756 rcrtc->vblank_enable = false; 824 rcrtc->vblank_enable = false;
757} 825}
758 826
759static int rcar_du_crtc_set_crc_source(struct drm_crtc *crtc, 827static int rcar_du_crtc_parse_crc_source(struct rcar_du_crtc *rcrtc,
760 const char *source_name, 828 const char *source_name,
761 size_t *values_cnt) 829 enum vsp1_du_crc_source *source)
762{ 830{
763 struct rcar_du_crtc *rcrtc = to_rcar_crtc(crtc); 831 unsigned int index;
764 struct drm_modeset_acquire_ctx ctx;
765 struct drm_crtc_state *crtc_state;
766 struct drm_atomic_state *state;
767 enum vsp1_du_crc_source source;
768 unsigned int index = 0;
769 unsigned int i;
770 int ret; 832 int ret;
771 833
772 /* 834 /*
@@ -774,31 +836,72 @@ static int rcar_du_crtc_set_crc_source(struct drm_crtc *crtc,
774 * CRC on an input plane (%u is the plane ID), and "auto" to compute the 836 * CRC on an input plane (%u is the plane ID), and "auto" to compute the
775 * CRC on the composer (VSP) output. 837 * CRC on the composer (VSP) output.
776 */ 838 */
839
777 if (!source_name) { 840 if (!source_name) {
778 source = VSP1_DU_CRC_NONE; 841 *source = VSP1_DU_CRC_NONE;
842 return 0;
779 } else if (!strcmp(source_name, "auto")) { 843 } else if (!strcmp(source_name, "auto")) {
780 source = VSP1_DU_CRC_OUTPUT; 844 *source = VSP1_DU_CRC_OUTPUT;
845 return 0;
781 } else if (strstarts(source_name, "plane")) { 846 } else if (strstarts(source_name, "plane")) {
782 source = VSP1_DU_CRC_PLANE; 847 unsigned int i;
848
849 *source = VSP1_DU_CRC_PLANE;
783 850
784 ret = kstrtouint(source_name + strlen("plane"), 10, &index); 851 ret = kstrtouint(source_name + strlen("plane"), 10, &index);
785 if (ret < 0) 852 if (ret < 0)
786 return ret; 853 return ret;
787 854
788 for (i = 0; i < rcrtc->vsp->num_planes; ++i) { 855 for (i = 0; i < rcrtc->vsp->num_planes; ++i) {
789 if (index == rcrtc->vsp->planes[i].plane.base.id) { 856 if (index == rcrtc->vsp->planes[i].plane.base.id)
790 index = i; 857 return i;
791 break;
792 }
793 } 858 }
859 }
794 860
795 if (i >= rcrtc->vsp->num_planes) 861 return -EINVAL;
796 return -EINVAL; 862}
797 } else { 863
864static int rcar_du_crtc_verify_crc_source(struct drm_crtc *crtc,
865 const char *source_name,
866 size_t *values_cnt)
867{
868 struct rcar_du_crtc *rcrtc = to_rcar_crtc(crtc);
869 enum vsp1_du_crc_source source;
870
871 if (rcar_du_crtc_parse_crc_source(rcrtc, source_name, &source) < 0) {
872 DRM_DEBUG_DRIVER("unknown source %s\n", source_name);
798 return -EINVAL; 873 return -EINVAL;
799 } 874 }
800 875
801 *values_cnt = 1; 876 *values_cnt = 1;
877 return 0;
878}
879
880const char *const *rcar_du_crtc_get_crc_sources(struct drm_crtc *crtc,
881 size_t *count)
882{
883 struct rcar_du_crtc *rcrtc = to_rcar_crtc(crtc);
884
885 *count = rcrtc->sources_count;
886 return rcrtc->sources;
887}
888
889static int rcar_du_crtc_set_crc_source(struct drm_crtc *crtc,
890 const char *source_name)
891{
892 struct rcar_du_crtc *rcrtc = to_rcar_crtc(crtc);
893 struct drm_modeset_acquire_ctx ctx;
894 struct drm_crtc_state *crtc_state;
895 struct drm_atomic_state *state;
896 enum vsp1_du_crc_source source;
897 unsigned int index;
898 int ret;
899
900 ret = rcar_du_crtc_parse_crc_source(rcrtc, source_name, &source);
901 if (ret < 0)
902 return ret;
903
904 index = ret;
802 905
803 /* Perform an atomic commit to set the CRC source. */ 906 /* Perform an atomic commit to set the CRC source. */
804 drm_modeset_acquire_init(&ctx, 0); 907 drm_modeset_acquire_init(&ctx, 0);
@@ -853,7 +956,7 @@ static const struct drm_crtc_funcs crtc_funcs_gen2 = {
853 956
854static const struct drm_crtc_funcs crtc_funcs_gen3 = { 957static const struct drm_crtc_funcs crtc_funcs_gen3 = {
855 .reset = rcar_du_crtc_reset, 958 .reset = rcar_du_crtc_reset,
856 .destroy = drm_crtc_cleanup, 959 .destroy = rcar_du_crtc_cleanup,
857 .set_config = drm_atomic_helper_set_config, 960 .set_config = drm_atomic_helper_set_config,
858 .page_flip = drm_atomic_helper_page_flip, 961 .page_flip = drm_atomic_helper_page_flip,
859 .atomic_duplicate_state = rcar_du_crtc_atomic_duplicate_state, 962 .atomic_duplicate_state = rcar_du_crtc_atomic_duplicate_state,
@@ -861,6 +964,8 @@ static const struct drm_crtc_funcs crtc_funcs_gen3 = {
861 .enable_vblank = rcar_du_crtc_enable_vblank, 964 .enable_vblank = rcar_du_crtc_enable_vblank,
862 .disable_vblank = rcar_du_crtc_disable_vblank, 965 .disable_vblank = rcar_du_crtc_disable_vblank,
863 .set_crc_source = rcar_du_crtc_set_crc_source, 966 .set_crc_source = rcar_du_crtc_set_crc_source,
967 .verify_crc_source = rcar_du_crtc_verify_crc_source,
968 .get_crc_sources = rcar_du_crtc_get_crc_sources,
864}; 969};
865 970
866/* ----------------------------------------------------------------------------- 971/* -----------------------------------------------------------------------------
@@ -999,5 +1104,7 @@ int rcar_du_crtc_create(struct rcar_du_group *rgrp, unsigned int swindex,
999 return ret; 1104 return ret;
1000 } 1105 }
1001 1106
1107 rcar_du_crtc_crc_init(rcrtc);
1108
1002 return 0; 1109 return 0;
1003} 1110}
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_crtc.h b/drivers/gpu/drm/rcar-du/rcar_du_crtc.h
index 7680cb2636c8..592c79993e08 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_crtc.h
+++ b/drivers/gpu/drm/rcar-du/rcar_du_crtc.h
@@ -67,6 +67,9 @@ struct rcar_du_crtc {
67 struct rcar_du_group *group; 67 struct rcar_du_group *group;
68 struct rcar_du_vsp *vsp; 68 struct rcar_du_vsp *vsp;
69 unsigned int vsp_pipe; 69 unsigned int vsp_pipe;
70
71 const char *const *sources;
72 unsigned int sources_count;
70}; 73};
71 74
72#define to_rcar_crtc(c) container_of(c, struct rcar_du_crtc, crtc) 75#define to_rcar_crtc(c) container_of(c, struct rcar_du_crtc, crtc)
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_plane.c b/drivers/gpu/drm/rcar-du/rcar_du_plane.c
index c20f7ed48c8d..8861e715c248 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_plane.c
+++ b/drivers/gpu/drm/rcar-du/rcar_du_plane.c
@@ -690,14 +690,12 @@ static void rcar_du_plane_reset(struct drm_plane *plane)
690 if (state == NULL) 690 if (state == NULL)
691 return; 691 return;
692 692
693 __drm_atomic_helper_plane_reset(plane, &state->state);
694
693 state->hwindex = -1; 695 state->hwindex = -1;
694 state->source = RCAR_DU_PLANE_MEMORY; 696 state->source = RCAR_DU_PLANE_MEMORY;
695 state->colorkey = RCAR_DU_COLORKEY_NONE; 697 state->colorkey = RCAR_DU_COLORKEY_NONE;
696 state->state.zpos = plane->type == DRM_PLANE_TYPE_PRIMARY ? 0 : 1; 698 state->state.zpos = plane->type == DRM_PLANE_TYPE_PRIMARY ? 0 : 1;
697
698 plane->state = &state->state;
699 plane->state->alpha = DRM_BLEND_ALPHA_OPAQUE;
700 plane->state->plane = plane;
701} 699}
702 700
703static int rcar_du_plane_atomic_set_property(struct drm_plane *plane, 701static int rcar_du_plane_atomic_set_property(struct drm_plane *plane,
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_vsp.c b/drivers/gpu/drm/rcar-du/rcar_du_vsp.c
index 72eebeda518e..45eb777a16a4 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_vsp.c
+++ b/drivers/gpu/drm/rcar-du/rcar_du_vsp.c
@@ -346,11 +346,8 @@ static void rcar_du_vsp_plane_reset(struct drm_plane *plane)
346 if (state == NULL) 346 if (state == NULL)
347 return; 347 return;
348 348
349 state->state.alpha = DRM_BLEND_ALPHA_OPAQUE; 349 __drm_atomic_helper_plane_reset(plane, &state->state);
350 state->state.zpos = plane->type == DRM_PLANE_TYPE_PRIMARY ? 0 : 1; 350 state->state.zpos = plane->type == DRM_PLANE_TYPE_PRIMARY ? 0 : 1;
351
352 plane->state = &state->state;
353 plane->state->plane = plane;
354} 351}
355 352
356static const struct drm_plane_funcs rcar_du_vsp_plane_funcs = { 353static const struct drm_plane_funcs rcar_du_vsp_plane_funcs = {
diff --git a/drivers/gpu/drm/rockchip/Kconfig b/drivers/gpu/drm/rockchip/Kconfig
index 0ccc76217ee4..26438d45732b 100644
--- a/drivers/gpu/drm/rockchip/Kconfig
+++ b/drivers/gpu/drm/rockchip/Kconfig
@@ -8,6 +8,7 @@ config DRM_ROCKCHIP
8 select DRM_ANALOGIX_DP if ROCKCHIP_ANALOGIX_DP 8 select DRM_ANALOGIX_DP if ROCKCHIP_ANALOGIX_DP
9 select DRM_DW_HDMI if ROCKCHIP_DW_HDMI 9 select DRM_DW_HDMI if ROCKCHIP_DW_HDMI
10 select DRM_MIPI_DSI if ROCKCHIP_DW_MIPI_DSI 10 select DRM_MIPI_DSI if ROCKCHIP_DW_MIPI_DSI
11 select DRM_RGB if ROCKCHIP_RGB
11 select SND_SOC_HDMI_CODEC if ROCKCHIP_CDN_DP && SND_SOC 12 select SND_SOC_HDMI_CODEC if ROCKCHIP_CDN_DP && SND_SOC
12 help 13 help
13 Choose this option if you have a Rockchip soc chipset. 14 Choose this option if you have a Rockchip soc chipset.
@@ -23,7 +24,7 @@ config ROCKCHIP_ANALOGIX_DP
23 help 24 help
24 This selects support for Rockchip SoC specific extensions 25 This selects support for Rockchip SoC specific extensions
25 for the Analogix Core DP driver. If you want to enable DP 26 for the Analogix Core DP driver. If you want to enable DP
26 on RK3288 based SoC, you should selet this option. 27 on RK3288 or RK3399 based SoC, you should select this option.
27 28
28config ROCKCHIP_CDN_DP 29config ROCKCHIP_CDN_DP
29 bool "Rockchip cdn DP" 30 bool "Rockchip cdn DP"
@@ -39,16 +40,16 @@ config ROCKCHIP_DW_HDMI
39 help 40 help
40 This selects support for Rockchip SoC specific extensions 41 This selects support for Rockchip SoC specific extensions
41 for the Synopsys DesignWare HDMI driver. If you want to 42 for the Synopsys DesignWare HDMI driver. If you want to
42 enable HDMI on RK3288 based SoC, you should selet this 43 enable HDMI on RK3288 or RK3399 based SoC, you should select
43 option. 44 this option.
44 45
45config ROCKCHIP_DW_MIPI_DSI 46config ROCKCHIP_DW_MIPI_DSI
46 bool "Rockchip specific extensions for Synopsys DW MIPI DSI" 47 bool "Rockchip specific extensions for Synopsys DW MIPI DSI"
47 help 48 help
48 This selects support for Rockchip SoC specific extensions 49 This selects support for Rockchip SoC specific extensions
49 for the Synopsys DesignWare HDMI driver. If you want to 50 for the Synopsys DesignWare HDMI driver. If you want to
50 enable MIPI DSI on RK3288 based SoC, you should selet this 51 enable MIPI DSI on RK3288 or RK3399 based SoC, you should
51 option. 52 select this option.
52 53
53config ROCKCHIP_INNO_HDMI 54config ROCKCHIP_INNO_HDMI
54 bool "Rockchip specific extensions for Innosilicon HDMI" 55 bool "Rockchip specific extensions for Innosilicon HDMI"
@@ -66,4 +67,14 @@ config ROCKCHIP_LVDS
66 Rockchip rk3288 SoC has LVDS TX Controller can be used, and it 67 Rockchip rk3288 SoC has LVDS TX Controller can be used, and it
67 support LVDS, rgb, dual LVDS output mode. say Y to enable its 68 support LVDS, rgb, dual LVDS output mode. say Y to enable its
68 driver. 69 driver.
70
71config ROCKCHIP_RGB
72 bool "Rockchip RGB support"
73 depends on DRM_ROCKCHIP
74 depends on PINCTRL
75 help
76 Choose this option to enable support for Rockchip RGB output.
77 Some Rockchip CRTCs, like rv1108, can directly output parallel
78 and serial RGB format to panel or connect to a conversion chip.
79 say Y to enable its driver.
69endif 80endif
diff --git a/drivers/gpu/drm/rockchip/Makefile b/drivers/gpu/drm/rockchip/Makefile
index a314e2109e76..868263ff0302 100644
--- a/drivers/gpu/drm/rockchip/Makefile
+++ b/drivers/gpu/drm/rockchip/Makefile
@@ -14,5 +14,6 @@ rockchipdrm-$(CONFIG_ROCKCHIP_DW_HDMI) += dw_hdmi-rockchip.o
14rockchipdrm-$(CONFIG_ROCKCHIP_DW_MIPI_DSI) += dw-mipi-dsi.o 14rockchipdrm-$(CONFIG_ROCKCHIP_DW_MIPI_DSI) += dw-mipi-dsi.o
15rockchipdrm-$(CONFIG_ROCKCHIP_INNO_HDMI) += inno_hdmi.o 15rockchipdrm-$(CONFIG_ROCKCHIP_INNO_HDMI) += inno_hdmi.o
16rockchipdrm-$(CONFIG_ROCKCHIP_LVDS) += rockchip_lvds.o 16rockchipdrm-$(CONFIG_ROCKCHIP_LVDS) += rockchip_lvds.o
17rockchipdrm-$(CONFIG_ROCKCHIP_RGB) += rockchip_rgb.o
17 18
18obj-$(CONFIG_DRM_ROCKCHIP) += rockchipdrm.o 19obj-$(CONFIG_DRM_ROCKCHIP) += rockchipdrm.o
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_drv.c b/drivers/gpu/drm/rockchip/rockchip_drm_drv.c
index f814d37b1db2..5864cb452c5c 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_drv.c
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.c
@@ -24,6 +24,7 @@
24#include <linux/pm_runtime.h> 24#include <linux/pm_runtime.h>
25#include <linux/module.h> 25#include <linux/module.h>
26#include <linux/of_graph.h> 26#include <linux/of_graph.h>
27#include <linux/of_platform.h>
27#include <linux/component.h> 28#include <linux/component.h>
28#include <linux/console.h> 29#include <linux/console.h>
29#include <linux/iommu.h> 30#include <linux/iommu.h>
@@ -184,7 +185,7 @@ err_mode_config_cleanup:
184err_free: 185err_free:
185 drm_dev->dev_private = NULL; 186 drm_dev->dev_private = NULL;
186 dev_set_drvdata(dev, NULL); 187 dev_set_drvdata(dev, NULL);
187 drm_dev_unref(drm_dev); 188 drm_dev_put(drm_dev);
188 return ret; 189 return ret;
189} 190}
190 191
@@ -204,7 +205,7 @@ static void rockchip_drm_unbind(struct device *dev)
204 205
205 drm_dev->dev_private = NULL; 206 drm_dev->dev_private = NULL;
206 dev_set_drvdata(dev, NULL); 207 dev_set_drvdata(dev, NULL);
207 drm_dev_unref(drm_dev); 208 drm_dev_put(drm_dev);
208} 209}
209 210
210static const struct file_operations rockchip_drm_driver_fops = { 211static const struct file_operations rockchip_drm_driver_fops = {
@@ -243,60 +244,18 @@ static struct drm_driver rockchip_drm_driver = {
243}; 244};
244 245
245#ifdef CONFIG_PM_SLEEP 246#ifdef CONFIG_PM_SLEEP
246static void rockchip_drm_fb_suspend(struct drm_device *drm)
247{
248 struct rockchip_drm_private *priv = drm->dev_private;
249
250 console_lock();
251 drm_fb_helper_set_suspend(&priv->fbdev_helper, 1);
252 console_unlock();
253}
254
255static void rockchip_drm_fb_resume(struct drm_device *drm)
256{
257 struct rockchip_drm_private *priv = drm->dev_private;
258
259 console_lock();
260 drm_fb_helper_set_suspend(&priv->fbdev_helper, 0);
261 console_unlock();
262}
263
264static int rockchip_drm_sys_suspend(struct device *dev) 247static int rockchip_drm_sys_suspend(struct device *dev)
265{ 248{
266 struct drm_device *drm = dev_get_drvdata(dev); 249 struct drm_device *drm = dev_get_drvdata(dev);
267 struct rockchip_drm_private *priv;
268
269 if (!drm)
270 return 0;
271 250
272 drm_kms_helper_poll_disable(drm); 251 return drm_mode_config_helper_suspend(drm);
273 rockchip_drm_fb_suspend(drm);
274
275 priv = drm->dev_private;
276 priv->state = drm_atomic_helper_suspend(drm);
277 if (IS_ERR(priv->state)) {
278 rockchip_drm_fb_resume(drm);
279 drm_kms_helper_poll_enable(drm);
280 return PTR_ERR(priv->state);
281 }
282
283 return 0;
284} 252}
285 253
286static int rockchip_drm_sys_resume(struct device *dev) 254static int rockchip_drm_sys_resume(struct device *dev)
287{ 255{
288 struct drm_device *drm = dev_get_drvdata(dev); 256 struct drm_device *drm = dev_get_drvdata(dev);
289 struct rockchip_drm_private *priv;
290
291 if (!drm)
292 return 0;
293
294 priv = drm->dev_private;
295 drm_atomic_helper_resume(drm, priv->state);
296 rockchip_drm_fb_resume(drm);
297 drm_kms_helper_poll_enable(drm);
298 257
299 return 0; 258 return drm_mode_config_helper_resume(drm);
300} 259}
301#endif 260#endif
302 261
@@ -309,6 +268,53 @@ static const struct dev_pm_ops rockchip_drm_pm_ops = {
309static struct platform_driver *rockchip_sub_drivers[MAX_ROCKCHIP_SUB_DRIVERS]; 268static struct platform_driver *rockchip_sub_drivers[MAX_ROCKCHIP_SUB_DRIVERS];
310static int num_rockchip_sub_drivers; 269static int num_rockchip_sub_drivers;
311 270
271/*
272 * Check if a vop endpoint is leading to a rockchip subdriver or bridge.
273 * Should be called from the component bind stage of the drivers
274 * to ensure that all subdrivers are probed.
275 *
276 * @ep: endpoint of a rockchip vop
277 *
278 * returns true if subdriver, false if external bridge and -ENODEV
279 * if remote port does not contain a device.
280 */
281int rockchip_drm_endpoint_is_subdriver(struct device_node *ep)
282{
283 struct device_node *node = of_graph_get_remote_port_parent(ep);
284 struct platform_device *pdev;
285 struct device_driver *drv;
286 int i;
287
288 if (!node)
289 return -ENODEV;
290
291 /* status disabled will prevent creation of platform-devices */
292 pdev = of_find_device_by_node(node);
293 of_node_put(node);
294 if (!pdev)
295 return -ENODEV;
296
297 /*
298 * All rockchip subdrivers have probed at this point, so
299 * any device not having a driver now is an external bridge.
300 */
301 drv = pdev->dev.driver;
302 if (!drv) {
303 platform_device_put(pdev);
304 return false;
305 }
306
307 for (i = 0; i < num_rockchip_sub_drivers; i++) {
308 if (rockchip_sub_drivers[i] == to_platform_driver(drv)) {
309 platform_device_put(pdev);
310 return true;
311 }
312 }
313
314 platform_device_put(pdev);
315 return false;
316}
317
312static int compare_dev(struct device *dev, void *data) 318static int compare_dev(struct device *dev, void *data)
313{ 319{
314 return dev == (struct device *)data; 320 return dev == (struct device *)data;
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_drv.h b/drivers/gpu/drm/rockchip/rockchip_drm_drv.h
index 3a6ebfc26036..21a023a97bb8 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_drv.h
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.h
@@ -51,7 +51,6 @@ struct rockchip_crtc_state {
51struct rockchip_drm_private { 51struct rockchip_drm_private {
52 struct drm_fb_helper fbdev_helper; 52 struct drm_fb_helper fbdev_helper;
53 struct drm_gem_object *fbdev_bo; 53 struct drm_gem_object *fbdev_bo;
54 struct drm_atomic_state *state;
55 struct iommu_domain *domain; 54 struct iommu_domain *domain;
56 struct mutex mm_lock; 55 struct mutex mm_lock;
57 struct drm_mm mm; 56 struct drm_mm mm;
@@ -65,6 +64,7 @@ void rockchip_drm_dma_detach_device(struct drm_device *drm_dev,
65 struct device *dev); 64 struct device *dev);
66int rockchip_drm_wait_vact_end(struct drm_crtc *crtc, unsigned int mstimeout); 65int rockchip_drm_wait_vact_end(struct drm_crtc *crtc, unsigned int mstimeout);
67 66
67int rockchip_drm_endpoint_is_subdriver(struct device_node *ep);
68extern struct platform_driver cdn_dp_driver; 68extern struct platform_driver cdn_dp_driver;
69extern struct platform_driver dw_hdmi_rockchip_pltfm_driver; 69extern struct platform_driver dw_hdmi_rockchip_pltfm_driver;
70extern struct platform_driver dw_mipi_dsi_driver; 70extern struct platform_driver dw_mipi_dsi_driver;
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
index 1359e5c773e4..0c35a88e33dd 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
@@ -32,6 +32,7 @@
32#include <linux/of_device.h> 32#include <linux/of_device.h>
33#include <linux/pm_runtime.h> 33#include <linux/pm_runtime.h>
34#include <linux/component.h> 34#include <linux/component.h>
35#include <linux/overflow.h>
35 36
36#include <linux/reset.h> 37#include <linux/reset.h>
37#include <linux/delay.h> 38#include <linux/delay.h>
@@ -41,6 +42,7 @@
41#include "rockchip_drm_fb.h" 42#include "rockchip_drm_fb.h"
42#include "rockchip_drm_psr.h" 43#include "rockchip_drm_psr.h"
43#include "rockchip_drm_vop.h" 44#include "rockchip_drm_vop.h"
45#include "rockchip_rgb.h"
44 46
45#define VOP_WIN_SET(x, win, name, v) \ 47#define VOP_WIN_SET(x, win, name, v) \
46 vop_reg_set(vop, &win->phy->name, win->base, ~0, v, #name) 48 vop_reg_set(vop, &win->phy->name, win->base, ~0, v, #name)
@@ -92,6 +94,7 @@ struct vop_win {
92 struct vop *vop; 94 struct vop *vop;
93}; 95};
94 96
97struct rockchip_rgb;
95struct vop { 98struct vop {
96 struct drm_crtc crtc; 99 struct drm_crtc crtc;
97 struct device *dev; 100 struct device *dev;
@@ -135,6 +138,9 @@ struct vop {
135 /* vop dclk reset */ 138 /* vop dclk reset */
136 struct reset_control *dclk_rst; 139 struct reset_control *dclk_rst;
137 140
141 /* optional internal rgb encoder */
142 struct rockchip_rgb *rgb;
143
138 struct vop_win win[]; 144 struct vop_win win[];
139}; 145};
140 146
@@ -1111,7 +1117,7 @@ static struct drm_connector *vop_get_edp_connector(struct vop *vop)
1111} 1117}
1112 1118
1113static int vop_crtc_set_crc_source(struct drm_crtc *crtc, 1119static int vop_crtc_set_crc_source(struct drm_crtc *crtc,
1114 const char *source_name, size_t *values_cnt) 1120 const char *source_name)
1115{ 1121{
1116 struct vop *vop = to_vop(crtc); 1122 struct vop *vop = to_vop(crtc);
1117 struct drm_connector *connector; 1123 struct drm_connector *connector;
@@ -1121,8 +1127,6 @@ static int vop_crtc_set_crc_source(struct drm_crtc *crtc,
1121 if (!connector) 1127 if (!connector)
1122 return -EINVAL; 1128 return -EINVAL;
1123 1129
1124 *values_cnt = 3;
1125
1126 if (source_name && strcmp(source_name, "auto") == 0) 1130 if (source_name && strcmp(source_name, "auto") == 0)
1127 ret = analogix_dp_start_crc(connector); 1131 ret = analogix_dp_start_crc(connector);
1128 else if (!source_name) 1132 else if (!source_name)
@@ -1132,9 +1136,28 @@ static int vop_crtc_set_crc_source(struct drm_crtc *crtc,
1132 1136
1133 return ret; 1137 return ret;
1134} 1138}
1139
1140static int
1141vop_crtc_verify_crc_source(struct drm_crtc *crtc, const char *source_name,
1142 size_t *values_cnt)
1143{
1144 if (source_name && strcmp(source_name, "auto") != 0)
1145 return -EINVAL;
1146
1147 *values_cnt = 3;
1148 return 0;
1149}
1150
1135#else 1151#else
1136static int vop_crtc_set_crc_source(struct drm_crtc *crtc, 1152static int vop_crtc_set_crc_source(struct drm_crtc *crtc,
1137 const char *source_name, size_t *values_cnt) 1153 const char *source_name)
1154{
1155 return -ENODEV;
1156}
1157
1158static int
1159vop_crtc_verify_crc_source(struct drm_crtc *crtc, const char *source_name,
1160 size_t *values_cnt)
1138{ 1161{
1139 return -ENODEV; 1162 return -ENODEV;
1140} 1163}
@@ -1150,6 +1173,7 @@ static const struct drm_crtc_funcs vop_crtc_funcs = {
1150 .enable_vblank = vop_crtc_enable_vblank, 1173 .enable_vblank = vop_crtc_enable_vblank,
1151 .disable_vblank = vop_crtc_disable_vblank, 1174 .disable_vblank = vop_crtc_disable_vblank,
1152 .set_crc_source = vop_crtc_set_crc_source, 1175 .set_crc_source = vop_crtc_set_crc_source,
1176 .verify_crc_source = vop_crtc_verify_crc_source,
1153}; 1177};
1154 1178
1155static void vop_fb_unref_worker(struct drm_flip_work *work, void *val) 1179static void vop_fb_unref_worker(struct drm_flip_work *work, void *val)
@@ -1561,7 +1585,6 @@ static int vop_bind(struct device *dev, struct device *master, void *data)
1561 struct drm_device *drm_dev = data; 1585 struct drm_device *drm_dev = data;
1562 struct vop *vop; 1586 struct vop *vop;
1563 struct resource *res; 1587 struct resource *res;
1564 size_t alloc_size;
1565 int ret, irq; 1588 int ret, irq;
1566 1589
1567 vop_data = of_device_get_match_data(dev); 1590 vop_data = of_device_get_match_data(dev);
@@ -1569,8 +1592,8 @@ static int vop_bind(struct device *dev, struct device *master, void *data)
1569 return -ENODEV; 1592 return -ENODEV;
1570 1593
1571 /* Allocate vop struct and its vop_win array */ 1594 /* Allocate vop struct and its vop_win array */
1572 alloc_size = sizeof(*vop) + sizeof(*vop->win) * vop_data->win_size; 1595 vop = devm_kzalloc(dev, struct_size(vop, win, vop_data->win_size),
1573 vop = devm_kzalloc(dev, alloc_size, GFP_KERNEL); 1596 GFP_KERNEL);
1574 if (!vop) 1597 if (!vop)
1575 return -ENOMEM; 1598 return -ENOMEM;
1576 1599
@@ -1620,6 +1643,14 @@ static int vop_bind(struct device *dev, struct device *master, void *data)
1620 if (ret) 1643 if (ret)
1621 goto err_disable_pm_runtime; 1644 goto err_disable_pm_runtime;
1622 1645
1646 if (vop->data->feature & VOP_FEATURE_INTERNAL_RGB) {
1647 vop->rgb = rockchip_rgb_init(dev, &vop->crtc, vop->drm_dev);
1648 if (IS_ERR(vop->rgb)) {
1649 ret = PTR_ERR(vop->rgb);
1650 goto err_disable_pm_runtime;
1651 }
1652 }
1653
1623 return 0; 1654 return 0;
1624 1655
1625err_disable_pm_runtime: 1656err_disable_pm_runtime:
@@ -1632,6 +1663,9 @@ static void vop_unbind(struct device *dev, struct device *master, void *data)
1632{ 1663{
1633 struct vop *vop = dev_get_drvdata(dev); 1664 struct vop *vop = dev_get_drvdata(dev);
1634 1665
1666 if (vop->rgb)
1667 rockchip_rgb_fini(vop->rgb);
1668
1635 pm_runtime_disable(dev); 1669 pm_runtime_disable(dev);
1636 vop_destroy_crtc(vop); 1670 vop_destroy_crtc(vop);
1637 1671
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.h b/drivers/gpu/drm/rockchip/rockchip_drm_vop.h
index fcb91041a666..fd5765dfd637 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.h
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.h
@@ -162,6 +162,7 @@ struct vop_data {
162 unsigned int win_size; 162 unsigned int win_size;
163 163
164#define VOP_FEATURE_OUTPUT_RGB10 BIT(0) 164#define VOP_FEATURE_OUTPUT_RGB10 BIT(0)
165#define VOP_FEATURE_INTERNAL_RGB BIT(1)
165 u64 feature; 166 u64 feature;
166}; 167};
167 168
diff --git a/drivers/gpu/drm/rockchip/rockchip_rgb.c b/drivers/gpu/drm/rockchip/rockchip_rgb.c
new file mode 100644
index 000000000000..96ac1458a59c
--- /dev/null
+++ b/drivers/gpu/drm/rockchip/rockchip_rgb.c
@@ -0,0 +1,173 @@
1//SPDX-License-Identifier: GPL-2.0+
2/*
3 * Copyright (C) Fuzhou Rockchip Electronics Co.Ltd
4 * Author:
5 * Sandy Huang <hjc@rock-chips.com>
6 *
7 * This software is licensed under the terms of the GNU General Public
8 * License version 2, as published by the Free Software Foundation, and
9 * may be copied, distributed, and modified under those terms.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 */
16
17#include <drm/drmP.h>
18#include <drm/drm_atomic_helper.h>
19#include <drm/drm_crtc_helper.h>
20#include <drm/drm_dp_helper.h>
21#include <drm/drm_panel.h>
22#include <drm/drm_of.h>
23
24#include <linux/component.h>
25#include <linux/of_graph.h>
26
27#include "rockchip_drm_drv.h"
28#include "rockchip_drm_vop.h"
29
30#define encoder_to_rgb(c) container_of(c, struct rockchip_rgb, encoder)
31
32struct rockchip_rgb {
33 struct device *dev;
34 struct drm_device *drm_dev;
35 struct drm_bridge *bridge;
36 struct drm_encoder encoder;
37 int output_mode;
38};
39
40static int
41rockchip_rgb_encoder_atomic_check(struct drm_encoder *encoder,
42 struct drm_crtc_state *crtc_state,
43 struct drm_connector_state *conn_state)
44{
45 struct rockchip_crtc_state *s = to_rockchip_crtc_state(crtc_state);
46 struct drm_connector *connector = conn_state->connector;
47 struct drm_display_info *info = &connector->display_info;
48 u32 bus_format;
49
50 if (info->num_bus_formats)
51 bus_format = info->bus_formats[0];
52 else
53 bus_format = MEDIA_BUS_FMT_RGB888_1X24;
54
55 switch (bus_format) {
56 case MEDIA_BUS_FMT_RGB666_1X18:
57 s->output_mode = ROCKCHIP_OUT_MODE_P666;
58 break;
59 case MEDIA_BUS_FMT_RGB565_1X16:
60 s->output_mode = ROCKCHIP_OUT_MODE_P565;
61 break;
62 case MEDIA_BUS_FMT_RGB888_1X24:
63 case MEDIA_BUS_FMT_RGB666_1X24_CPADHI:
64 default:
65 s->output_mode = ROCKCHIP_OUT_MODE_P888;
66 break;
67 }
68
69 s->output_type = DRM_MODE_CONNECTOR_LVDS;
70
71 return 0;
72}
73
74static const
75struct drm_encoder_helper_funcs rockchip_rgb_encoder_helper_funcs = {
76 .atomic_check = rockchip_rgb_encoder_atomic_check,
77};
78
79static const struct drm_encoder_funcs rockchip_rgb_encoder_funcs = {
80 .destroy = drm_encoder_cleanup,
81};
82
83struct rockchip_rgb *rockchip_rgb_init(struct device *dev,
84 struct drm_crtc *crtc,
85 struct drm_device *drm_dev)
86{
87 struct rockchip_rgb *rgb;
88 struct drm_encoder *encoder;
89 struct device_node *port, *endpoint;
90 u32 endpoint_id;
91 int ret = 0, child_count = 0;
92 struct drm_panel *panel;
93 struct drm_bridge *bridge;
94
95 rgb = devm_kzalloc(dev, sizeof(*rgb), GFP_KERNEL);
96 if (!rgb)
97 return ERR_PTR(-ENOMEM);
98
99 rgb->dev = dev;
100 rgb->drm_dev = drm_dev;
101
102 port = of_graph_get_port_by_id(dev->of_node, 0);
103 if (!port)
104 return ERR_PTR(-EINVAL);
105
106 for_each_child_of_node(port, endpoint) {
107 if (of_property_read_u32(endpoint, "reg", &endpoint_id))
108 endpoint_id = 0;
109
110 if (rockchip_drm_endpoint_is_subdriver(endpoint) > 0)
111 continue;
112
113 child_count++;
114 ret = drm_of_find_panel_or_bridge(dev->of_node, 0, endpoint_id,
115 &panel, &bridge);
116 if (!ret)
117 break;
118 }
119
120 of_node_put(port);
121
122 /* if the rgb output is not connected to anything, just return */
123 if (!child_count)
124 return NULL;
125
126 if (ret < 0) {
127 if (ret != -EPROBE_DEFER)
128 DRM_DEV_ERROR(dev, "failed to find panel or bridge %d\n", ret);
129 return ERR_PTR(ret);
130 }
131
132 encoder = &rgb->encoder;
133 encoder->possible_crtcs = drm_crtc_mask(crtc);
134
135 ret = drm_encoder_init(drm_dev, encoder, &rockchip_rgb_encoder_funcs,
136 DRM_MODE_ENCODER_NONE, NULL);
137 if (ret < 0) {
138 DRM_DEV_ERROR(drm_dev->dev,
139 "failed to initialize encoder: %d\n", ret);
140 return ERR_PTR(ret);
141 }
142
143 drm_encoder_helper_add(encoder, &rockchip_rgb_encoder_helper_funcs);
144
145 if (panel) {
146 bridge = drm_panel_bridge_add(panel, DRM_MODE_CONNECTOR_LVDS);
147 if (IS_ERR(bridge))
148 return ERR_CAST(bridge);
149 }
150
151 rgb->bridge = bridge;
152
153 ret = drm_bridge_attach(encoder, rgb->bridge, NULL);
154 if (ret) {
155 DRM_DEV_ERROR(drm_dev->dev,
156 "failed to attach bridge: %d\n", ret);
157 goto err_free_encoder;
158 }
159
160 return rgb;
161
162err_free_encoder:
163 drm_encoder_cleanup(encoder);
164 return ERR_PTR(ret);
165}
166EXPORT_SYMBOL_GPL(rockchip_rgb_init);
167
168void rockchip_rgb_fini(struct rockchip_rgb *rgb)
169{
170 drm_panel_bridge_remove(rgb->bridge);
171 drm_encoder_cleanup(&rgb->encoder);
172}
173EXPORT_SYMBOL_GPL(rockchip_rgb_fini);
diff --git a/drivers/gpu/drm/rockchip/rockchip_rgb.h b/drivers/gpu/drm/rockchip/rockchip_rgb.h
new file mode 100644
index 000000000000..38b52e63b2b0
--- /dev/null
+++ b/drivers/gpu/drm/rockchip/rockchip_rgb.h
@@ -0,0 +1,33 @@
1//SPDX-License-Identifier: GPL-2.0+
2/*
3 * Copyright (C) Fuzhou Rockchip Electronics Co.Ltd
4 * Author:
5 * Sandy Huang <hjc@rock-chips.com>
6 *
7 * This software is licensed under the terms of the GNU General Public
8 * License version 2, as published by the Free Software Foundation, and
9 * may be copied, distributed, and modified under those terms.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 */
16
17#ifdef CONFIG_ROCKCHIP_RGB
18struct rockchip_rgb *rockchip_rgb_init(struct device *dev,
19 struct drm_crtc *crtc,
20 struct drm_device *drm_dev);
21void rockchip_rgb_fini(struct rockchip_rgb *rgb);
22#else
23static inline struct rockchip_rgb *rockchip_rgb_init(struct device *dev,
24 struct drm_crtc *crtc,
25 struct drm_device *drm_dev)
26{
27 return NULL;
28}
29
30static inline void rockchip_rgb_fini(struct rockchip_rgb *rgb)
31{
32}
33#endif
diff --git a/drivers/gpu/drm/rockchip/rockchip_vop_reg.c b/drivers/gpu/drm/rockchip/rockchip_vop_reg.c
index 08023d3ecb76..a6db3cd5544b 100644
--- a/drivers/gpu/drm/rockchip/rockchip_vop_reg.c
+++ b/drivers/gpu/drm/rockchip/rockchip_vop_reg.c
@@ -177,6 +177,215 @@ static const struct vop_data rk3126_vop = {
177 .win_size = ARRAY_SIZE(rk3126_vop_win_data), 177 .win_size = ARRAY_SIZE(rk3126_vop_win_data),
178}; 178};
179 179
180static const int px30_vop_intrs[] = {
181 FS_INTR,
182 0, 0,
183 LINE_FLAG_INTR,
184 0,
185 BUS_ERROR_INTR,
186 0, 0,
187 DSP_HOLD_VALID_INTR,
188};
189
190static const struct vop_intr px30_intr = {
191 .intrs = px30_vop_intrs,
192 .nintrs = ARRAY_SIZE(px30_vop_intrs),
193 .line_flag_num[0] = VOP_REG(PX30_LINE_FLAG, 0xfff, 0),
194 .status = VOP_REG_MASK_SYNC(PX30_INTR_STATUS, 0xffff, 0),
195 .enable = VOP_REG_MASK_SYNC(PX30_INTR_EN, 0xffff, 0),
196 .clear = VOP_REG_MASK_SYNC(PX30_INTR_CLEAR, 0xffff, 0),
197};
198
199static const struct vop_common px30_common = {
200 .standby = VOP_REG_SYNC(PX30_SYS_CTRL2, 0x1, 1),
201 .out_mode = VOP_REG(PX30_DSP_CTRL2, 0xf, 16),
202 .dsp_blank = VOP_REG(PX30_DSP_CTRL2, 0x1, 14),
203 .cfg_done = VOP_REG_SYNC(PX30_REG_CFG_DONE, 0x1, 0),
204};
205
206static const struct vop_modeset px30_modeset = {
207 .htotal_pw = VOP_REG(PX30_DSP_HTOTAL_HS_END, 0x0fff0fff, 0),
208 .hact_st_end = VOP_REG(PX30_DSP_HACT_ST_END, 0x0fff0fff, 0),
209 .vtotal_pw = VOP_REG(PX30_DSP_VTOTAL_VS_END, 0x0fff0fff, 0),
210 .vact_st_end = VOP_REG(PX30_DSP_VACT_ST_END, 0x0fff0fff, 0),
211};
212
213static const struct vop_output px30_output = {
214 .rgb_pin_pol = VOP_REG(PX30_DSP_CTRL0, 0xf, 1),
215 .mipi_pin_pol = VOP_REG(PX30_DSP_CTRL0, 0xf, 25),
216 .rgb_en = VOP_REG(PX30_DSP_CTRL0, 0x1, 0),
217 .mipi_en = VOP_REG(PX30_DSP_CTRL0, 0x1, 24),
218};
219
220static const struct vop_scl_regs px30_win_scl = {
221 .scale_yrgb_x = VOP_REG(PX30_WIN0_SCL_FACTOR_YRGB, 0xffff, 0x0),
222 .scale_yrgb_y = VOP_REG(PX30_WIN0_SCL_FACTOR_YRGB, 0xffff, 16),
223 .scale_cbcr_x = VOP_REG(PX30_WIN0_SCL_FACTOR_CBR, 0xffff, 0x0),
224 .scale_cbcr_y = VOP_REG(PX30_WIN0_SCL_FACTOR_CBR, 0xffff, 16),
225};
226
227static const struct vop_win_phy px30_win0_data = {
228 .scl = &px30_win_scl,
229 .data_formats = formats_win_full,
230 .nformats = ARRAY_SIZE(formats_win_full),
231 .enable = VOP_REG(PX30_WIN0_CTRL0, 0x1, 0),
232 .format = VOP_REG(PX30_WIN0_CTRL0, 0x7, 1),
233 .rb_swap = VOP_REG(PX30_WIN0_CTRL0, 0x1, 12),
234 .act_info = VOP_REG(PX30_WIN0_ACT_INFO, 0xffffffff, 0),
235 .dsp_info = VOP_REG(PX30_WIN0_DSP_INFO, 0xffffffff, 0),
236 .dsp_st = VOP_REG(PX30_WIN0_DSP_ST, 0xffffffff, 0),
237 .yrgb_mst = VOP_REG(PX30_WIN0_YRGB_MST0, 0xffffffff, 0),
238 .uv_mst = VOP_REG(PX30_WIN0_CBR_MST0, 0xffffffff, 0),
239 .yrgb_vir = VOP_REG(PX30_WIN0_VIR, 0x1fff, 0),
240 .uv_vir = VOP_REG(PX30_WIN0_VIR, 0x1fff, 16),
241};
242
243static const struct vop_win_phy px30_win1_data = {
244 .data_formats = formats_win_lite,
245 .nformats = ARRAY_SIZE(formats_win_lite),
246 .enable = VOP_REG(PX30_WIN1_CTRL0, 0x1, 0),
247 .format = VOP_REG(PX30_WIN1_CTRL0, 0x7, 4),
248 .rb_swap = VOP_REG(PX30_WIN1_CTRL0, 0x1, 12),
249 .dsp_info = VOP_REG(PX30_WIN1_DSP_INFO, 0xffffffff, 0),
250 .dsp_st = VOP_REG(PX30_WIN1_DSP_ST, 0xffffffff, 0),
251 .yrgb_mst = VOP_REG(PX30_WIN1_MST, 0xffffffff, 0),
252 .yrgb_vir = VOP_REG(PX30_WIN1_VIR, 0x1fff, 0),
253};
254
255static const struct vop_win_phy px30_win2_data = {
256 .data_formats = formats_win_lite,
257 .nformats = ARRAY_SIZE(formats_win_lite),
258 .gate = VOP_REG(PX30_WIN2_CTRL0, 0x1, 4),
259 .enable = VOP_REG(PX30_WIN2_CTRL0, 0x1, 0),
260 .format = VOP_REG(PX30_WIN2_CTRL0, 0x3, 5),
261 .rb_swap = VOP_REG(PX30_WIN2_CTRL0, 0x1, 20),
262 .dsp_info = VOP_REG(PX30_WIN2_DSP_INFO0, 0x0fff0fff, 0),
263 .dsp_st = VOP_REG(PX30_WIN2_DSP_ST0, 0x1fff1fff, 0),
264 .yrgb_mst = VOP_REG(PX30_WIN2_MST0, 0xffffffff, 0),
265 .yrgb_vir = VOP_REG(PX30_WIN2_VIR0_1, 0x1fff, 0),
266};
267
268static const struct vop_win_data px30_vop_big_win_data[] = {
269 { .base = 0x00, .phy = &px30_win0_data,
270 .type = DRM_PLANE_TYPE_PRIMARY },
271 { .base = 0x00, .phy = &px30_win1_data,
272 .type = DRM_PLANE_TYPE_OVERLAY },
273 { .base = 0x00, .phy = &px30_win2_data,
274 .type = DRM_PLANE_TYPE_CURSOR },
275};
276
277static const struct vop_data px30_vop_big = {
278 .intr = &px30_intr,
279 .feature = VOP_FEATURE_INTERNAL_RGB,
280 .common = &px30_common,
281 .modeset = &px30_modeset,
282 .output = &px30_output,
283 .win = px30_vop_big_win_data,
284 .win_size = ARRAY_SIZE(px30_vop_big_win_data),
285};
286
287static const struct vop_win_data px30_vop_lit_win_data[] = {
288 { .base = 0x00, .phy = &px30_win1_data,
289 .type = DRM_PLANE_TYPE_PRIMARY },
290};
291
292static const struct vop_data px30_vop_lit = {
293 .intr = &px30_intr,
294 .feature = VOP_FEATURE_INTERNAL_RGB,
295 .common = &px30_common,
296 .modeset = &px30_modeset,
297 .output = &px30_output,
298 .win = px30_vop_lit_win_data,
299 .win_size = ARRAY_SIZE(px30_vop_lit_win_data),
300};
301
302static const struct vop_scl_regs rk3188_win_scl = {
303 .scale_yrgb_x = VOP_REG(RK3188_WIN0_SCL_FACTOR_YRGB, 0xffff, 0x0),
304 .scale_yrgb_y = VOP_REG(RK3188_WIN0_SCL_FACTOR_YRGB, 0xffff, 16),
305 .scale_cbcr_x = VOP_REG(RK3188_WIN0_SCL_FACTOR_CBR, 0xffff, 0x0),
306 .scale_cbcr_y = VOP_REG(RK3188_WIN0_SCL_FACTOR_CBR, 0xffff, 16),
307};
308
309static const struct vop_win_phy rk3188_win0_data = {
310 .scl = &rk3188_win_scl,
311 .data_formats = formats_win_full,
312 .nformats = ARRAY_SIZE(formats_win_full),
313 .enable = VOP_REG(RK3188_SYS_CTRL, 0x1, 0),
314 .format = VOP_REG(RK3188_SYS_CTRL, 0x7, 3),
315 .rb_swap = VOP_REG(RK3188_SYS_CTRL, 0x1, 15),
316 .act_info = VOP_REG(RK3188_WIN0_ACT_INFO, 0x1fff1fff, 0),
317 .dsp_info = VOP_REG(RK3188_WIN0_DSP_INFO, 0x0fff0fff, 0),
318 .dsp_st = VOP_REG(RK3188_WIN0_DSP_ST, 0x1fff1fff, 0),
319 .yrgb_mst = VOP_REG(RK3188_WIN0_YRGB_MST0, 0xffffffff, 0),
320 .uv_mst = VOP_REG(RK3188_WIN0_CBR_MST0, 0xffffffff, 0),
321 .yrgb_vir = VOP_REG(RK3188_WIN_VIR, 0x1fff, 0),
322};
323
324static const struct vop_win_phy rk3188_win1_data = {
325 .data_formats = formats_win_lite,
326 .nformats = ARRAY_SIZE(formats_win_lite),
327 .enable = VOP_REG(RK3188_SYS_CTRL, 0x1, 1),
328 .format = VOP_REG(RK3188_SYS_CTRL, 0x7, 6),
329 .rb_swap = VOP_REG(RK3188_SYS_CTRL, 0x1, 19),
330 /* no act_info on window1 */
331 .dsp_info = VOP_REG(RK3188_WIN1_DSP_INFO, 0x07ff07ff, 0),
332 .dsp_st = VOP_REG(RK3188_WIN1_DSP_ST, 0x0fff0fff, 0),
333 .yrgb_mst = VOP_REG(RK3188_WIN1_MST, 0xffffffff, 0),
334 .yrgb_vir = VOP_REG(RK3188_WIN_VIR, 0x1fff, 16),
335};
336
337static const struct vop_modeset rk3188_modeset = {
338 .htotal_pw = VOP_REG(RK3188_DSP_HTOTAL_HS_END, 0x0fff0fff, 0),
339 .hact_st_end = VOP_REG(RK3188_DSP_HACT_ST_END, 0x0fff0fff, 0),
340 .vtotal_pw = VOP_REG(RK3188_DSP_VTOTAL_VS_END, 0x0fff0fff, 0),
341 .vact_st_end = VOP_REG(RK3188_DSP_VACT_ST_END, 0x0fff0fff, 0),
342};
343
344static const struct vop_output rk3188_output = {
345 .pin_pol = VOP_REG(RK3188_DSP_CTRL0, 0xf, 4),
346};
347
348static const struct vop_common rk3188_common = {
349 .gate_en = VOP_REG(RK3188_SYS_CTRL, 0x1, 31),
350 .standby = VOP_REG(RK3188_SYS_CTRL, 0x1, 30),
351 .out_mode = VOP_REG(RK3188_DSP_CTRL0, 0xf, 0),
352 .cfg_done = VOP_REG(RK3188_REG_CFG_DONE, 0x1, 0),
353 .dsp_blank = VOP_REG(RK3188_DSP_CTRL1, 0x3, 24),
354};
355
356static const struct vop_win_data rk3188_vop_win_data[] = {
357 { .base = 0x00, .phy = &rk3188_win0_data,
358 .type = DRM_PLANE_TYPE_PRIMARY },
359 { .base = 0x00, .phy = &rk3188_win1_data,
360 .type = DRM_PLANE_TYPE_CURSOR },
361};
362
363static const int rk3188_vop_intrs[] = {
364 0,
365 FS_INTR,
366 LINE_FLAG_INTR,
367 BUS_ERROR_INTR,
368};
369
370static const struct vop_intr rk3188_vop_intr = {
371 .intrs = rk3188_vop_intrs,
372 .nintrs = ARRAY_SIZE(rk3188_vop_intrs),
373 .line_flag_num[0] = VOP_REG(RK3188_INT_STATUS, 0xfff, 12),
374 .status = VOP_REG(RK3188_INT_STATUS, 0xf, 0),
375 .enable = VOP_REG(RK3188_INT_STATUS, 0xf, 4),
376 .clear = VOP_REG(RK3188_INT_STATUS, 0xf, 8),
377};
378
379static const struct vop_data rk3188_vop = {
380 .intr = &rk3188_vop_intr,
381 .common = &rk3188_common,
382 .modeset = &rk3188_modeset,
383 .output = &rk3188_output,
384 .win = rk3188_vop_win_data,
385 .win_size = ARRAY_SIZE(rk3188_vop_win_data),
386 .feature = VOP_FEATURE_INTERNAL_RGB,
387};
388
180static const struct vop_scl_extension rk3288_win_full_scl_ext = { 389static const struct vop_scl_extension rk3288_win_full_scl_ext = {
181 .cbcr_vsd_mode = VOP_REG(RK3288_WIN0_CTRL1, 0x1, 31), 390 .cbcr_vsd_mode = VOP_REG(RK3288_WIN0_CTRL1, 0x1, 31),
182 .cbcr_vsu_mode = VOP_REG(RK3288_WIN0_CTRL1, 0x1, 30), 391 .cbcr_vsu_mode = VOP_REG(RK3288_WIN0_CTRL1, 0x1, 30),
@@ -541,6 +750,12 @@ static const struct of_device_id vop_driver_dt_match[] = {
541 .data = &rk3036_vop }, 750 .data = &rk3036_vop },
542 { .compatible = "rockchip,rk3126-vop", 751 { .compatible = "rockchip,rk3126-vop",
543 .data = &rk3126_vop }, 752 .data = &rk3126_vop },
753 { .compatible = "rockchip,px30-vop-big",
754 .data = &px30_vop_big },
755 { .compatible = "rockchip,px30-vop-lit",
756 .data = &px30_vop_lit },
757 { .compatible = "rockchip,rk3188-vop",
758 .data = &rk3188_vop },
544 { .compatible = "rockchip,rk3288-vop", 759 { .compatible = "rockchip,rk3288-vop",
545 .data = &rk3288_vop }, 760 .data = &rk3288_vop },
546 { .compatible = "rockchip,rk3368-vop", 761 { .compatible = "rockchip,rk3368-vop",
diff --git a/drivers/gpu/drm/rockchip/rockchip_vop_reg.h b/drivers/gpu/drm/rockchip/rockchip_vop_reg.h
index f81b510ea99c..7348c68352ed 100644
--- a/drivers/gpu/drm/rockchip/rockchip_vop_reg.h
+++ b/drivers/gpu/drm/rockchip/rockchip_vop_reg.h
@@ -884,4 +884,103 @@
884#define RK3126_WIN1_DSP_ST 0x54 884#define RK3126_WIN1_DSP_ST 0x54
885/* rk3126 register definition end */ 885/* rk3126 register definition end */
886 886
887/* px30 register definition */
888#define PX30_REG_CFG_DONE 0x00000
889#define PX30_VERSION 0x00004
890#define PX30_DSP_BG 0x00008
891#define PX30_MCU_CTRL 0x0000c
892#define PX30_SYS_CTRL0 0x00010
893#define PX30_SYS_CTRL1 0x00014
894#define PX30_SYS_CTRL2 0x00018
895#define PX30_DSP_CTRL0 0x00020
896#define PX30_DSP_CTRL2 0x00028
897#define PX30_VOP_STATUS 0x0002c
898#define PX30_LINE_FLAG 0x00030
899#define PX30_INTR_EN 0x00034
900#define PX30_INTR_CLEAR 0x00038
901#define PX30_INTR_STATUS 0x0003c
902#define PX30_WIN0_CTRL0 0x00050
903#define PX30_WIN0_CTRL1 0x00054
904#define PX30_WIN0_COLOR_KEY 0x00058
905#define PX30_WIN0_VIR 0x0005c
906#define PX30_WIN0_YRGB_MST0 0x00060
907#define PX30_WIN0_CBR_MST0 0x00064
908#define PX30_WIN0_ACT_INFO 0x00068
909#define PX30_WIN0_DSP_INFO 0x0006c
910#define PX30_WIN0_DSP_ST 0x00070
911#define PX30_WIN0_SCL_FACTOR_YRGB 0x00074
912#define PX30_WIN0_SCL_FACTOR_CBR 0x00078
913#define PX30_WIN0_SCL_OFFSET 0x0007c
914#define PX30_WIN0_ALPHA_CTRL 0x00080
915#define PX30_WIN1_CTRL0 0x00090
916#define PX30_WIN1_CTRL1 0x00094
917#define PX30_WIN1_VIR 0x00098
918#define PX30_WIN1_MST 0x000a0
919#define PX30_WIN1_DSP_INFO 0x000a4
920#define PX30_WIN1_DSP_ST 0x000a8
921#define PX30_WIN1_COLOR_KEY 0x000ac
922#define PX30_WIN1_ALPHA_CTRL 0x000bc
923#define PX30_HWC_CTRL0 0x000e0
924#define PX30_HWC_CTRL1 0x000e4
925#define PX30_HWC_MST 0x000e8
926#define PX30_HWC_DSP_ST 0x000ec
927#define PX30_HWC_ALPHA_CTRL 0x000f0
928#define PX30_DSP_HTOTAL_HS_END 0x00100
929#define PX30_DSP_HACT_ST_END 0x00104
930#define PX30_DSP_VTOTAL_VS_END 0x00108
931#define PX30_DSP_VACT_ST_END 0x0010c
932#define PX30_DSP_VS_ST_END_F1 0x00110
933#define PX30_DSP_VACT_ST_END_F1 0x00114
934#define PX30_BCSH_CTRL 0x00160
935#define PX30_BCSH_COL_BAR 0x00164
936#define PX30_BCSH_BCS 0x00168
937#define PX30_BCSH_H 0x0016c
938#define PX30_FRC_LOWER01_0 0x00170
939#define PX30_FRC_LOWER01_1 0x00174
940#define PX30_FRC_LOWER10_0 0x00178
941#define PX30_FRC_LOWER10_1 0x0017c
942#define PX30_FRC_LOWER11_0 0x00180
943#define PX30_FRC_LOWER11_1 0x00184
944#define PX30_MCU_RW_BYPASS_PORT 0x0018c
945#define PX30_WIN2_CTRL0 0x00190
946#define PX30_WIN2_CTRL1 0x00194
947#define PX30_WIN2_VIR0_1 0x00198
948#define PX30_WIN2_VIR2_3 0x0019c
949#define PX30_WIN2_MST0 0x001a0
950#define PX30_WIN2_DSP_INFO0 0x001a4
951#define PX30_WIN2_DSP_ST0 0x001a8
952#define PX30_WIN2_COLOR_KEY 0x001ac
953#define PX30_WIN2_ALPHA_CTRL 0x001bc
954#define PX30_BLANKING_VALUE 0x001f4
955#define PX30_FLAG_REG_FRM_VALID 0x001f8
956#define PX30_FLAG_REG 0x001fc
957#define PX30_HWC_LUT_ADDR 0x00600
958#define PX30_GAMMA_LUT_ADDR 0x00a00
959/* px30 register definition end */
960
961/* rk3188 register definition */
962#define RK3188_SYS_CTRL 0x00
963#define RK3188_DSP_CTRL0 0x04
964#define RK3188_DSP_CTRL1 0x08
965#define RK3188_INT_STATUS 0x10
966#define RK3188_WIN0_YRGB_MST0 0x20
967#define RK3188_WIN0_CBR_MST0 0x24
968#define RK3188_WIN0_YRGB_MST1 0x28
969#define RK3188_WIN0_CBR_MST1 0x2c
970#define RK3188_WIN_VIR 0x30
971#define RK3188_WIN0_ACT_INFO 0x34
972#define RK3188_WIN0_DSP_INFO 0x38
973#define RK3188_WIN0_DSP_ST 0x3c
974#define RK3188_WIN0_SCL_FACTOR_YRGB 0x40
975#define RK3188_WIN0_SCL_FACTOR_CBR 0x44
976#define RK3188_WIN1_MST 0x4c
977#define RK3188_WIN1_DSP_INFO 0x50
978#define RK3188_WIN1_DSP_ST 0x54
979#define RK3188_DSP_HTOTAL_HS_END 0x6c
980#define RK3188_DSP_HACT_ST_END 0x70
981#define RK3188_DSP_VTOTAL_VS_END 0x74
982#define RK3188_DSP_VACT_ST_END 0x78
983#define RK3188_REG_CFG_DONE 0x90
984/* rk3188 register definition end */
985
887#endif /* _ROCKCHIP_VOP_REG_H */ 986#endif /* _ROCKCHIP_VOP_REG_H */
diff --git a/drivers/gpu/drm/sti/sti_hda.c b/drivers/gpu/drm/sti/sti_hda.c
index 49438337f70d..19b9b5ed1297 100644
--- a/drivers/gpu/drm/sti/sti_hda.c
+++ b/drivers/gpu/drm/sti/sti_hda.c
@@ -721,7 +721,6 @@ static int sti_hda_bind(struct device *dev, struct device *master, void *data)
721 return 0; 721 return 0;
722 722
723err_sysfs: 723err_sysfs:
724 drm_bridge_remove(bridge);
725 return -EINVAL; 724 return -EINVAL;
726} 725}
727 726
diff --git a/drivers/gpu/drm/sti/sti_hdmi.c b/drivers/gpu/drm/sti/sti_hdmi.c
index 34cdc4644435..ccf718404a1c 100644
--- a/drivers/gpu/drm/sti/sti_hdmi.c
+++ b/drivers/gpu/drm/sti/sti_hdmi.c
@@ -1315,7 +1315,6 @@ static int sti_hdmi_bind(struct device *dev, struct device *master, void *data)
1315 return 0; 1315 return 0;
1316 1316
1317err_sysfs: 1317err_sysfs:
1318 drm_bridge_remove(bridge);
1319 hdmi->drm_connector = NULL; 1318 hdmi->drm_connector = NULL;
1320 return -EINVAL; 1319 return -EINVAL;
1321} 1320}
diff --git a/drivers/gpu/drm/sun4i/sun4i_backend.c b/drivers/gpu/drm/sun4i/sun4i_backend.c
index d7950b52a1fd..bf49c55b0f2c 100644
--- a/drivers/gpu/drm/sun4i/sun4i_backend.c
+++ b/drivers/gpu/drm/sun4i/sun4i_backend.c
@@ -34,6 +34,9 @@
34struct sun4i_backend_quirks { 34struct sun4i_backend_quirks {
35 /* backend <-> TCON muxing selection done in backend */ 35 /* backend <-> TCON muxing selection done in backend */
36 bool needs_output_muxing; 36 bool needs_output_muxing;
37
38 /* alpha at the lowest z position is not always supported */
39 bool supports_lowest_plane_alpha;
37}; 40};
38 41
39static const u32 sunxi_rgb2yuv_coef[12] = { 42static const u32 sunxi_rgb2yuv_coef[12] = {
@@ -60,32 +63,6 @@ static const u32 sunxi_bt601_yuv2rgb_coef[12] = {
60 0x000004a7, 0x00000812, 0x00000000, 0x00002eb1, 63 0x000004a7, 0x00000812, 0x00000000, 0x00002eb1,
61}; 64};
62 65
63static inline bool sun4i_backend_format_is_planar_yuv(uint32_t format)
64{
65 switch (format) {
66 case DRM_FORMAT_YUV411:
67 case DRM_FORMAT_YUV422:
68 case DRM_FORMAT_YUV444:
69 return true;
70 default:
71 return false;
72 }
73}
74
75static inline bool sun4i_backend_format_is_packed_yuv422(uint32_t format)
76{
77 switch (format) {
78 case DRM_FORMAT_YUYV:
79 case DRM_FORMAT_YVYU:
80 case DRM_FORMAT_UYVY:
81 case DRM_FORMAT_VYUY:
82 return true;
83
84 default:
85 return false;
86 }
87}
88
89static void sun4i_backend_apply_color_correction(struct sunxi_engine *engine) 66static void sun4i_backend_apply_color_correction(struct sunxi_engine *engine)
90{ 67{
91 int i; 68 int i;
@@ -215,7 +192,8 @@ static int sun4i_backend_update_yuv_format(struct sun4i_backend *backend,
215{ 192{
216 struct drm_plane_state *state = plane->state; 193 struct drm_plane_state *state = plane->state;
217 struct drm_framebuffer *fb = state->fb; 194 struct drm_framebuffer *fb = state->fb;
218 uint32_t format = fb->format->format; 195 const struct drm_format_info *format = fb->format;
196 const uint32_t fmt = format->format;
219 u32 val = SUN4I_BACKEND_IYUVCTL_EN; 197 u32 val = SUN4I_BACKEND_IYUVCTL_EN;
220 int i; 198 int i;
221 199
@@ -233,16 +211,16 @@ static int sun4i_backend_update_yuv_format(struct sun4i_backend *backend,
233 SUN4I_BACKEND_ATTCTL_REG0_LAY_YUVEN); 211 SUN4I_BACKEND_ATTCTL_REG0_LAY_YUVEN);
234 212
235 /* TODO: Add support for the multi-planar YUV formats */ 213 /* TODO: Add support for the multi-planar YUV formats */
236 if (sun4i_backend_format_is_packed_yuv422(format)) 214 if (format->num_planes == 1)
237 val |= SUN4I_BACKEND_IYUVCTL_FBFMT_PACKED_YUV422; 215 val |= SUN4I_BACKEND_IYUVCTL_FBFMT_PACKED_YUV422;
238 else 216 else
239 DRM_DEBUG_DRIVER("Unsupported YUV format (0x%x)\n", format); 217 DRM_DEBUG_DRIVER("Unsupported YUV format (0x%x)\n", fmt);
240 218
241 /* 219 /*
242 * Allwinner seems to list the pixel sequence from right to left, while 220 * Allwinner seems to list the pixel sequence from right to left, while
243 * DRM lists it from left to right. 221 * DRM lists it from left to right.
244 */ 222 */
245 switch (format) { 223 switch (fmt) {
246 case DRM_FORMAT_YUYV: 224 case DRM_FORMAT_YUYV:
247 val |= SUN4I_BACKEND_IYUVCTL_FBPS_VYUY; 225 val |= SUN4I_BACKEND_IYUVCTL_FBPS_VYUY;
248 break; 226 break;
@@ -257,7 +235,7 @@ static int sun4i_backend_update_yuv_format(struct sun4i_backend *backend,
257 break; 235 break;
258 default: 236 default:
259 DRM_DEBUG_DRIVER("Unsupported YUV pixel sequence (0x%x)\n", 237 DRM_DEBUG_DRIVER("Unsupported YUV pixel sequence (0x%x)\n",
260 format); 238 fmt);
261 } 239 }
262 240
263 regmap_write(backend->engine.regs, SUN4I_BACKEND_IYUVCTL_REG, val); 241 regmap_write(backend->engine.regs, SUN4I_BACKEND_IYUVCTL_REG, val);
@@ -457,12 +435,14 @@ static int sun4i_backend_atomic_check(struct sunxi_engine *engine,
457 struct drm_crtc_state *crtc_state) 435 struct drm_crtc_state *crtc_state)
458{ 436{
459 struct drm_plane_state *plane_states[SUN4I_BACKEND_NUM_LAYERS] = { 0 }; 437 struct drm_plane_state *plane_states[SUN4I_BACKEND_NUM_LAYERS] = { 0 };
438 struct sun4i_backend *backend = engine_to_sun4i_backend(engine);
460 struct drm_atomic_state *state = crtc_state->state; 439 struct drm_atomic_state *state = crtc_state->state;
461 struct drm_device *drm = state->dev; 440 struct drm_device *drm = state->dev;
462 struct drm_plane *plane; 441 struct drm_plane *plane;
463 unsigned int num_planes = 0; 442 unsigned int num_planes = 0;
464 unsigned int num_alpha_planes = 0; 443 unsigned int num_alpha_planes = 0;
465 unsigned int num_frontend_planes = 0; 444 unsigned int num_frontend_planes = 0;
445 unsigned int num_alpha_planes_max = 1;
466 unsigned int num_yuv_planes = 0; 446 unsigned int num_yuv_planes = 0;
467 unsigned int current_pipe = 0; 447 unsigned int current_pipe = 0;
468 unsigned int i; 448 unsigned int i;
@@ -526,33 +506,40 @@ static int sun4i_backend_atomic_check(struct sunxi_engine *engine,
526 * the layer with the highest priority. 506 * the layer with the highest priority.
527 * 507 *
528 * The second step is the actual alpha blending, that takes 508 * The second step is the actual alpha blending, that takes
529 * the two pipes as input, and uses the eventual alpha 509 * the two pipes as input, and uses the potential alpha
530 * component to do the transparency between the two. 510 * component to do the transparency between the two.
531 * 511 *
532 * This two steps scenario makes us unable to guarantee a 512 * This two-step scenario makes us unable to guarantee a
533 * robust alpha blending between the 4 layers in all 513 * robust alpha blending between the 4 layers in all
534 * situations, since this means that we need to have one layer 514 * situations, since this means that we need to have one layer
535 * with alpha at the lowest position of our two pipes. 515 * with alpha at the lowest position of our two pipes.
536 * 516 *
537 * However, we cannot even do that, since the hardware has a 517 * However, we cannot even do that on every platform, since
538 * bug where the lowest plane of the lowest pipe (pipe 0, 518 * the hardware has a bug where the lowest plane of the lowest
539 * priority 0), if it has any alpha, will discard the pixel 519 * pipe (pipe 0, priority 0), if it has any alpha, will
540 * entirely and just display the pixels in the background 520 * discard the pixel data entirely and just display the pixels
541 * color (black by default). 521 * in the background color (black by default).
542 * 522 *
543 * This means that we effectively have only three valid 523 * This means that on the affected platforms, we effectively
544 * configurations with alpha, all of them with the alpha being 524 * have only three valid configurations with alpha, all of
545 * on pipe1 with the lowest position, which can be 1, 2 or 3 525 * them with the alpha being on pipe1 with the lowest
546 * depending on the number of planes and their zpos. 526 * position, which can be 1, 2 or 3 depending on the number of
527 * planes and their zpos.
547 */ 528 */
548 if (num_alpha_planes > SUN4I_BACKEND_NUM_ALPHA_LAYERS) { 529
530 /* For platforms that are not affected by the issue described above. */
531 if (backend->quirks->supports_lowest_plane_alpha)
532 num_alpha_planes_max++;
533
534 if (num_alpha_planes > num_alpha_planes_max) {
549 DRM_DEBUG_DRIVER("Too many planes with alpha, rejecting...\n"); 535 DRM_DEBUG_DRIVER("Too many planes with alpha, rejecting...\n");
550 return -EINVAL; 536 return -EINVAL;
551 } 537 }
552 538
553 /* We can't have an alpha plane at the lowest position */ 539 /* We can't have an alpha plane at the lowest position */
554 if (plane_states[0]->fb->format->has_alpha || 540 if (!backend->quirks->supports_lowest_plane_alpha &&
555 (plane_states[0]->alpha != DRM_BLEND_ALPHA_OPAQUE)) 541 (plane_states[0]->fb->format->has_alpha ||
542 (plane_states[0]->alpha != DRM_BLEND_ALPHA_OPAQUE)))
556 return -EINVAL; 543 return -EINVAL;
557 544
558 for (i = 1; i < num_planes; i++) { 545 for (i = 1; i < num_planes; i++) {
@@ -876,6 +863,8 @@ static int sun4i_backend_bind(struct device *dev, struct device *master,
876 : SUN4I_BACKEND_MODCTL_OUT_LCD0)); 863 : SUN4I_BACKEND_MODCTL_OUT_LCD0));
877 } 864 }
878 865
866 backend->quirks = quirks;
867
879 return 0; 868 return 0;
880 869
881err_disable_ram_clk: 870err_disable_ram_clk:
@@ -935,9 +924,11 @@ static const struct sun4i_backend_quirks sun6i_backend_quirks = {
935 924
936static const struct sun4i_backend_quirks sun7i_backend_quirks = { 925static const struct sun4i_backend_quirks sun7i_backend_quirks = {
937 .needs_output_muxing = true, 926 .needs_output_muxing = true,
927 .supports_lowest_plane_alpha = true,
938}; 928};
939 929
940static const struct sun4i_backend_quirks sun8i_a33_backend_quirks = { 930static const struct sun4i_backend_quirks sun8i_a33_backend_quirks = {
931 .supports_lowest_plane_alpha = true,
941}; 932};
942 933
943static const struct sun4i_backend_quirks sun9i_backend_quirks = { 934static const struct sun4i_backend_quirks sun9i_backend_quirks = {
diff --git a/drivers/gpu/drm/sun4i/sun4i_backend.h b/drivers/gpu/drm/sun4i/sun4i_backend.h
index 4caee0392fa4..e3d4c6035eb2 100644
--- a/drivers/gpu/drm/sun4i/sun4i_backend.h
+++ b/drivers/gpu/drm/sun4i/sun4i_backend.h
@@ -167,7 +167,6 @@
167#define SUN4I_BACKEND_PIPE_OFF(p) (0x5000 + (0x400 * (p))) 167#define SUN4I_BACKEND_PIPE_OFF(p) (0x5000 + (0x400 * (p)))
168 168
169#define SUN4I_BACKEND_NUM_LAYERS 4 169#define SUN4I_BACKEND_NUM_LAYERS 4
170#define SUN4I_BACKEND_NUM_ALPHA_LAYERS 1
171#define SUN4I_BACKEND_NUM_FRONTEND_LAYERS 1 170#define SUN4I_BACKEND_NUM_FRONTEND_LAYERS 1
172#define SUN4I_BACKEND_NUM_YUV_PLANES 1 171#define SUN4I_BACKEND_NUM_YUV_PLANES 1
173 172
@@ -187,6 +186,8 @@ struct sun4i_backend {
187 /* Protects against races in the frontend teardown */ 186 /* Protects against races in the frontend teardown */
188 spinlock_t frontend_lock; 187 spinlock_t frontend_lock;
189 bool frontend_teardown; 188 bool frontend_teardown;
189
190 const struct sun4i_backend_quirks *quirks;
190}; 191};
191 192
192static inline struct sun4i_backend * 193static inline struct sun4i_backend *
diff --git a/drivers/gpu/drm/sun4i/sun4i_drv.c b/drivers/gpu/drm/sun4i/sun4i_drv.c
index dd19d674055c..1e41c3f5fd6d 100644
--- a/drivers/gpu/drm/sun4i/sun4i_drv.c
+++ b/drivers/gpu/drm/sun4i/sun4i_drv.c
@@ -61,22 +61,6 @@ static struct drm_driver sun4i_drv_driver = {
61 /* Frame Buffer Operations */ 61 /* Frame Buffer Operations */
62}; 62};
63 63
64static void sun4i_remove_framebuffers(void)
65{
66 struct apertures_struct *ap;
67
68 ap = alloc_apertures(1);
69 if (!ap)
70 return;
71
72 /* The framebuffer can be located anywhere in RAM */
73 ap->ranges[0].base = 0;
74 ap->ranges[0].size = ~0;
75
76 drm_fb_helper_remove_conflicting_framebuffers(ap, "sun4i-drm-fb", false);
77 kfree(ap);
78}
79
80static int sun4i_drv_bind(struct device *dev) 64static int sun4i_drv_bind(struct device *dev)
81{ 65{
82 struct drm_device *drm; 66 struct drm_device *drm;
@@ -119,7 +103,7 @@ static int sun4i_drv_bind(struct device *dev)
119 drm->irq_enabled = true; 103 drm->irq_enabled = true;
120 104
121 /* Remove early framebuffers (ie. simplefb) */ 105 /* Remove early framebuffers (ie. simplefb) */
122 sun4i_remove_framebuffers(); 106 drm_fb_helper_remove_conflicting_framebuffers(NULL, "sun4i-drm-fb", false);
123 107
124 /* Create our framebuffer */ 108 /* Create our framebuffer */
125 ret = sun4i_framebuffer_init(drm); 109 ret = sun4i_framebuffer_init(drm);
@@ -421,6 +405,7 @@ static const struct of_device_id sun4i_drv_of_table[] = {
421 { .compatible = "allwinner,sun8i-r40-display-engine" }, 405 { .compatible = "allwinner,sun8i-r40-display-engine" },
422 { .compatible = "allwinner,sun8i-v3s-display-engine" }, 406 { .compatible = "allwinner,sun8i-v3s-display-engine" },
423 { .compatible = "allwinner,sun9i-a80-display-engine" }, 407 { .compatible = "allwinner,sun9i-a80-display-engine" },
408 { .compatible = "allwinner,sun50i-a64-display-engine" },
424 { } 409 { }
425}; 410};
426MODULE_DEVICE_TABLE(of, sun4i_drv_of_table); 411MODULE_DEVICE_TABLE(of, sun4i_drv_of_table);
diff --git a/drivers/gpu/drm/sun4i/sun4i_layer.c b/drivers/gpu/drm/sun4i/sun4i_layer.c
index 750ad24de1d7..78f77af8805a 100644
--- a/drivers/gpu/drm/sun4i/sun4i_layer.c
+++ b/drivers/gpu/drm/sun4i/sun4i_layer.c
@@ -35,9 +35,7 @@ static void sun4i_backend_layer_reset(struct drm_plane *plane)
35 35
36 state = kzalloc(sizeof(*state), GFP_KERNEL); 36 state = kzalloc(sizeof(*state), GFP_KERNEL);
37 if (state) { 37 if (state) {
38 plane->state = &state->state; 38 __drm_atomic_helper_plane_reset(plane, &state->state);
39 plane->state->plane = plane;
40 plane->state->alpha = DRM_BLEND_ALPHA_OPAQUE;
41 plane->state->zpos = layer->id; 39 plane->state->zpos = layer->id;
42 } 40 }
43} 41}
diff --git a/drivers/gpu/drm/sun4i/sun4i_tcon.c b/drivers/gpu/drm/sun4i/sun4i_tcon.c
index 3fb084f802e2..0cebb2db5b99 100644
--- a/drivers/gpu/drm/sun4i/sun4i_tcon.c
+++ b/drivers/gpu/drm/sun4i/sun4i_tcon.c
@@ -17,6 +17,7 @@
17#include <drm/drm_encoder.h> 17#include <drm/drm_encoder.h>
18#include <drm/drm_modes.h> 18#include <drm/drm_modes.h>
19#include <drm/drm_of.h> 19#include <drm/drm_of.h>
20#include <drm/drm_panel.h>
20 21
21#include <uapi/drm/drm_mode.h> 22#include <uapi/drm/drm_mode.h>
22 23
@@ -35,6 +36,7 @@
35#include "sun4i_rgb.h" 36#include "sun4i_rgb.h"
36#include "sun4i_tcon.h" 37#include "sun4i_tcon.h"
37#include "sun6i_mipi_dsi.h" 38#include "sun6i_mipi_dsi.h"
39#include "sun8i_tcon_top.h"
38#include "sunxi_engine.h" 40#include "sunxi_engine.h"
39 41
40static struct drm_connector *sun4i_tcon_get_connector(const struct drm_encoder *encoder) 42static struct drm_connector *sun4i_tcon_get_connector(const struct drm_encoder *encoder)
@@ -474,6 +476,33 @@ static void sun4i_tcon0_mode_set_rgb(struct sun4i_tcon *tcon,
474 if (mode->flags & DRM_MODE_FLAG_PVSYNC) 476 if (mode->flags & DRM_MODE_FLAG_PVSYNC)
475 val |= SUN4I_TCON0_IO_POL_VSYNC_POSITIVE; 477 val |= SUN4I_TCON0_IO_POL_VSYNC_POSITIVE;
476 478
479 /*
480 * On A20 and similar SoCs, the only way to achieve Positive Edge
481 * (Rising Edge), is setting dclk clock phase to 2/3(240°).
482 * By default TCON works in Negative Edge(Falling Edge),
483 * this is why phase is set to 0 in that case.
484 * Unfortunately there's no way to logically invert dclk through
485 * IO_POL register.
486 * The only acceptable way to work, triple checked with scope,
487 * is using clock phase set to 0° for Negative Edge and set to 240°
488 * for Positive Edge.
489 * On A33 and similar SoCs there would be a 90° phase option,
490 * but it divides also dclk by 2.
491 * Following code is a way to avoid quirks all around TCON
492 * and DOTCLOCK drivers.
493 */
494 if (!IS_ERR(tcon->panel)) {
495 struct drm_panel *panel = tcon->panel;
496 struct drm_connector *connector = panel->connector;
497 struct drm_display_info display_info = connector->display_info;
498
499 if (display_info.bus_flags & DRM_BUS_FLAG_PIXDATA_POSEDGE)
500 clk_set_phase(tcon->dclk, 240);
501
502 if (display_info.bus_flags & DRM_BUS_FLAG_PIXDATA_NEGEDGE)
503 clk_set_phase(tcon->dclk, 0);
504 }
505
477 regmap_update_bits(tcon->regs, SUN4I_TCON0_IO_POL_REG, 506 regmap_update_bits(tcon->regs, SUN4I_TCON0_IO_POL_REG,
478 SUN4I_TCON0_IO_POL_HSYNC_POSITIVE | SUN4I_TCON0_IO_POL_VSYNC_POSITIVE, 507 SUN4I_TCON0_IO_POL_HSYNC_POSITIVE | SUN4I_TCON0_IO_POL_VSYNC_POSITIVE,
479 val); 508 val);
@@ -880,6 +909,36 @@ static struct sunxi_engine *sun4i_tcon_get_engine_by_id(struct sun4i_drv *drv,
880 return ERR_PTR(-EINVAL); 909 return ERR_PTR(-EINVAL);
881} 910}
882 911
912static bool sun4i_tcon_connected_to_tcon_top(struct device_node *node)
913{
914 struct device_node *remote;
915 bool ret = false;
916
917 remote = of_graph_get_remote_node(node, 0, -1);
918 if (remote) {
919 ret = !!of_match_node(sun8i_tcon_top_of_table, remote);
920 of_node_put(remote);
921 }
922
923 return ret;
924}
925
926static int sun4i_tcon_get_index(struct sun4i_drv *drv)
927{
928 struct list_head *pos;
929 int size = 0;
930
931 /*
932 * Because TCON is added to the list at the end of the probe
933 * (after this function is called), index of the current TCON
934 * will be same as current TCON list size.
935 */
936 list_for_each(pos, &drv->tcon_list)
937 ++size;
938
939 return size;
940}
941
883/* 942/*
884 * On SoCs with the old display pipeline design (Display Engine 1.0), 943 * On SoCs with the old display pipeline design (Display Engine 1.0),
885 * we assumed the TCON was always tied to just one backend. However 944 * we assumed the TCON was always tied to just one backend. However
@@ -928,8 +987,24 @@ static struct sunxi_engine *sun4i_tcon_find_engine(struct sun4i_drv *drv,
928 * connections between the backend and TCON? 987 * connections between the backend and TCON?
929 */ 988 */
930 if (of_get_child_count(port) > 1) { 989 if (of_get_child_count(port) > 1) {
931 /* Get our ID directly from an upstream endpoint */ 990 int id;
932 int id = sun4i_tcon_of_get_id_from_port(port); 991
992 /*
993 * When pipeline has the same number of TCONs and engines which
994 * are represented by frontends/backends (DE1) or mixers (DE2),
995 * we match them by their respective IDs. However, if pipeline
996 * contains TCON TOP, chances are that there are either more
997 * TCONs than engines (R40) or TCONs with non-consecutive ids.
998 * (H6). In that case it's easier just use TCON index in list
999 * as an id. That means that on R40, any 2 TCONs can be enabled
1000 * in DT out of 4 (there are 2 mixers). Due to the design of
1001 * TCON TOP, remaining 2 TCONs can't be connected to anything
1002 * anyway.
1003 */
1004 if (sun4i_tcon_connected_to_tcon_top(node))
1005 id = sun4i_tcon_get_index(drv);
1006 else
1007 id = sun4i_tcon_of_get_id_from_port(port);
933 1008
934 /* Get our engine by matching our ID */ 1009 /* Get our engine by matching our ID */
935 engine = sun4i_tcon_get_engine_by_id(drv, id); 1010 engine = sun4i_tcon_get_engine_by_id(drv, id);
@@ -1244,6 +1319,40 @@ static int sun6i_tcon_set_mux(struct sun4i_tcon *tcon,
1244 return 0; 1319 return 0;
1245} 1320}
1246 1321
1322static int sun8i_r40_tcon_tv_set_mux(struct sun4i_tcon *tcon,
1323 const struct drm_encoder *encoder)
1324{
1325 struct device_node *port, *remote;
1326 struct platform_device *pdev;
1327 int id, ret;
1328
1329 /* find TCON TOP platform device and TCON id */
1330
1331 port = of_graph_get_port_by_id(tcon->dev->of_node, 0);
1332 if (!port)
1333 return -EINVAL;
1334
1335 id = sun4i_tcon_of_get_id_from_port(port);
1336 of_node_put(port);
1337
1338 remote = of_graph_get_remote_node(tcon->dev->of_node, 0, -1);
1339 if (!remote)
1340 return -EINVAL;
1341
1342 pdev = of_find_device_by_node(remote);
1343 of_node_put(remote);
1344 if (!pdev)
1345 return -EINVAL;
1346
1347 if (encoder->encoder_type == DRM_MODE_ENCODER_TMDS) {
1348 ret = sun8i_tcon_top_set_hdmi_src(&pdev->dev, id);
1349 if (ret)
1350 return ret;
1351 }
1352
1353 return sun8i_tcon_top_de_config(&pdev->dev, tcon->id, id);
1354}
1355
1247static const struct sun4i_tcon_quirks sun4i_a10_quirks = { 1356static const struct sun4i_tcon_quirks sun4i_a10_quirks = {
1248 .has_channel_0 = true, 1357 .has_channel_0 = true,
1249 .has_channel_1 = true, 1358 .has_channel_1 = true,
@@ -1291,6 +1400,11 @@ static const struct sun4i_tcon_quirks sun8i_a83t_tv_quirks = {
1291 .has_channel_1 = true, 1400 .has_channel_1 = true,
1292}; 1401};
1293 1402
1403static const struct sun4i_tcon_quirks sun8i_r40_tv_quirks = {
1404 .has_channel_1 = true,
1405 .set_mux = sun8i_r40_tcon_tv_set_mux,
1406};
1407
1294static const struct sun4i_tcon_quirks sun8i_v3s_quirks = { 1408static const struct sun4i_tcon_quirks sun8i_v3s_quirks = {
1295 .has_channel_0 = true, 1409 .has_channel_0 = true,
1296}; 1410};
@@ -1315,6 +1429,7 @@ const struct of_device_id sun4i_tcon_of_table[] = {
1315 { .compatible = "allwinner,sun8i-a33-tcon", .data = &sun8i_a33_quirks }, 1429 { .compatible = "allwinner,sun8i-a33-tcon", .data = &sun8i_a33_quirks },
1316 { .compatible = "allwinner,sun8i-a83t-tcon-lcd", .data = &sun8i_a83t_lcd_quirks }, 1430 { .compatible = "allwinner,sun8i-a83t-tcon-lcd", .data = &sun8i_a83t_lcd_quirks },
1317 { .compatible = "allwinner,sun8i-a83t-tcon-tv", .data = &sun8i_a83t_tv_quirks }, 1431 { .compatible = "allwinner,sun8i-a83t-tcon-tv", .data = &sun8i_a83t_tv_quirks },
1432 { .compatible = "allwinner,sun8i-r40-tcon-tv", .data = &sun8i_r40_tv_quirks },
1318 { .compatible = "allwinner,sun8i-v3s-tcon", .data = &sun8i_v3s_quirks }, 1433 { .compatible = "allwinner,sun8i-v3s-tcon", .data = &sun8i_v3s_quirks },
1319 { .compatible = "allwinner,sun9i-a80-tcon-lcd", .data = &sun9i_a80_tcon_lcd_quirks }, 1434 { .compatible = "allwinner,sun9i-a80-tcon-lcd", .data = &sun9i_a80_tcon_lcd_quirks },
1320 { .compatible = "allwinner,sun9i-a80-tcon-tv", .data = &sun9i_a80_tcon_tv_quirks }, 1435 { .compatible = "allwinner,sun9i-a80-tcon-tv", .data = &sun9i_a80_tcon_tv_quirks },
diff --git a/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.c b/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.c
index 31875b636434..ed2983770e9c 100644
--- a/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.c
+++ b/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.c
@@ -125,10 +125,22 @@ static int sun8i_dw_hdmi_bind(struct device *dev, struct device *master,
125 return PTR_ERR(hdmi->clk_tmds); 125 return PTR_ERR(hdmi->clk_tmds);
126 } 126 }
127 127
128 hdmi->regulator = devm_regulator_get(dev, "hvcc");
129 if (IS_ERR(hdmi->regulator)) {
130 dev_err(dev, "Couldn't get regulator\n");
131 return PTR_ERR(hdmi->regulator);
132 }
133
134 ret = regulator_enable(hdmi->regulator);
135 if (ret) {
136 dev_err(dev, "Failed to enable regulator\n");
137 return ret;
138 }
139
128 ret = reset_control_deassert(hdmi->rst_ctrl); 140 ret = reset_control_deassert(hdmi->rst_ctrl);
129 if (ret) { 141 if (ret) {
130 dev_err(dev, "Could not deassert ctrl reset control\n"); 142 dev_err(dev, "Could not deassert ctrl reset control\n");
131 return ret; 143 goto err_disable_regulator;
132 } 144 }
133 145
134 ret = clk_prepare_enable(hdmi->clk_tmds); 146 ret = clk_prepare_enable(hdmi->clk_tmds);
@@ -183,6 +195,8 @@ err_disable_clk_tmds:
183 clk_disable_unprepare(hdmi->clk_tmds); 195 clk_disable_unprepare(hdmi->clk_tmds);
184err_assert_ctrl_reset: 196err_assert_ctrl_reset:
185 reset_control_assert(hdmi->rst_ctrl); 197 reset_control_assert(hdmi->rst_ctrl);
198err_disable_regulator:
199 regulator_disable(hdmi->regulator);
186 200
187 return ret; 201 return ret;
188} 202}
@@ -196,6 +210,7 @@ static void sun8i_dw_hdmi_unbind(struct device *dev, struct device *master,
196 sun8i_hdmi_phy_remove(hdmi); 210 sun8i_hdmi_phy_remove(hdmi);
197 clk_disable_unprepare(hdmi->clk_tmds); 211 clk_disable_unprepare(hdmi->clk_tmds);
198 reset_control_assert(hdmi->rst_ctrl); 212 reset_control_assert(hdmi->rst_ctrl);
213 regulator_disable(hdmi->regulator);
199} 214}
200 215
201static const struct component_ops sun8i_dw_hdmi_ops = { 216static const struct component_ops sun8i_dw_hdmi_ops = {
diff --git a/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.h b/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.h
index aadbe0a10b0c..7fdc1ecd2892 100644
--- a/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.h
+++ b/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.h
@@ -10,6 +10,7 @@
10#include <drm/drm_encoder.h> 10#include <drm/drm_encoder.h>
11#include <linux/clk.h> 11#include <linux/clk.h>
12#include <linux/regmap.h> 12#include <linux/regmap.h>
13#include <linux/regulator/consumer.h>
13#include <linux/reset.h> 14#include <linux/reset.h>
14 15
15#define SUN8I_HDMI_PHY_DBG_CTRL_REG 0x0000 16#define SUN8I_HDMI_PHY_DBG_CTRL_REG 0x0000
@@ -176,6 +177,7 @@ struct sun8i_dw_hdmi {
176 struct drm_encoder encoder; 177 struct drm_encoder encoder;
177 struct sun8i_hdmi_phy *phy; 178 struct sun8i_hdmi_phy *phy;
178 struct dw_hdmi_plat_data plat_data; 179 struct dw_hdmi_plat_data plat_data;
180 struct regulator *regulator;
179 struct reset_control *rst_ctrl; 181 struct reset_control *rst_ctrl;
180}; 182};
181 183
diff --git a/drivers/gpu/drm/sun4i/sun8i_mixer.c b/drivers/gpu/drm/sun4i/sun8i_mixer.c
index fc3713608f78..8b3d02b146b7 100644
--- a/drivers/gpu/drm/sun4i/sun8i_mixer.c
+++ b/drivers/gpu/drm/sun4i/sun8i_mixer.c
@@ -569,6 +569,22 @@ static const struct sun8i_mixer_cfg sun8i_v3s_mixer_cfg = {
569 .mod_rate = 150000000, 569 .mod_rate = 150000000,
570}; 570};
571 571
572static const struct sun8i_mixer_cfg sun50i_a64_mixer0_cfg = {
573 .ccsc = 0,
574 .mod_rate = 297000000,
575 .scaler_mask = 0xf,
576 .ui_num = 3,
577 .vi_num = 1,
578};
579
580static const struct sun8i_mixer_cfg sun50i_a64_mixer1_cfg = {
581 .ccsc = 1,
582 .mod_rate = 297000000,
583 .scaler_mask = 0x3,
584 .ui_num = 1,
585 .vi_num = 1,
586};
587
572static const struct of_device_id sun8i_mixer_of_table[] = { 588static const struct of_device_id sun8i_mixer_of_table[] = {
573 { 589 {
574 .compatible = "allwinner,sun8i-a83t-de2-mixer-0", 590 .compatible = "allwinner,sun8i-a83t-de2-mixer-0",
@@ -594,6 +610,14 @@ static const struct of_device_id sun8i_mixer_of_table[] = {
594 .compatible = "allwinner,sun8i-v3s-de2-mixer", 610 .compatible = "allwinner,sun8i-v3s-de2-mixer",
595 .data = &sun8i_v3s_mixer_cfg, 611 .data = &sun8i_v3s_mixer_cfg,
596 }, 612 },
613 {
614 .compatible = "allwinner,sun50i-a64-de2-mixer-0",
615 .data = &sun50i_a64_mixer0_cfg,
616 },
617 {
618 .compatible = "allwinner,sun50i-a64-de2-mixer-1",
619 .data = &sun50i_a64_mixer1_cfg,
620 },
597 { } 621 { }
598}; 622};
599MODULE_DEVICE_TABLE(of, sun8i_mixer_of_table); 623MODULE_DEVICE_TABLE(of, sun8i_mixer_of_table);
diff --git a/drivers/gpu/drm/sun4i/sun8i_tcon_top.c b/drivers/gpu/drm/sun4i/sun8i_tcon_top.c
index 55fe398d8290..3040a79f298f 100644
--- a/drivers/gpu/drm/sun4i/sun8i_tcon_top.c
+++ b/drivers/gpu/drm/sun4i/sun8i_tcon_top.c
@@ -129,8 +129,7 @@ static int sun8i_tcon_top_bind(struct device *dev, struct device *master,
129 if (!tcon_top) 129 if (!tcon_top)
130 return -ENOMEM; 130 return -ENOMEM;
131 131
132 clk_data = devm_kzalloc(dev, sizeof(*clk_data) + 132 clk_data = devm_kzalloc(dev, struct_size(clk_data, hws, CLK_NUM),
133 sizeof(*clk_data->hws) * CLK_NUM,
134 GFP_KERNEL); 133 GFP_KERNEL);
135 if (!clk_data) 134 if (!clk_data)
136 return -ENOMEM; 135 return -ENOMEM;
diff --git a/drivers/gpu/drm/tegra/drm.c b/drivers/gpu/drm/tegra/drm.c
index a2bd5876c633..b424bc911b95 100644
--- a/drivers/gpu/drm/tegra/drm.c
+++ b/drivers/gpu/drm/tegra/drm.c
@@ -1187,6 +1187,10 @@ static int host1x_drm_probe(struct host1x_device *dev)
1187 1187
1188 dev_set_drvdata(&dev->dev, drm); 1188 dev_set_drvdata(&dev->dev, drm);
1189 1189
1190 err = drm_fb_helper_remove_conflicting_framebuffers(NULL, "tegradrmfb", false);
1191 if (err < 0)
1192 goto unref;
1193
1190 err = drm_dev_register(drm, 0); 1194 err = drm_dev_register(drm, 0);
1191 if (err < 0) 1195 if (err < 0)
1192 goto unref; 1196 goto unref;
diff --git a/drivers/gpu/drm/tinydrm/core/tinydrm-core.c b/drivers/gpu/drm/tinydrm/core/tinydrm-core.c
index 19c7f70adfa5..255341ee4eb9 100644
--- a/drivers/gpu/drm/tinydrm/core/tinydrm-core.c
+++ b/drivers/gpu/drm/tinydrm/core/tinydrm-core.c
@@ -135,7 +135,7 @@ static int tinydrm_init(struct device *parent, struct tinydrm_device *tdev,
135 /* 135 /*
136 * We don't embed drm_device, because that prevent us from using 136 * We don't embed drm_device, because that prevent us from using
137 * devm_kzalloc() to allocate tinydrm_device in the driver since 137 * devm_kzalloc() to allocate tinydrm_device in the driver since
138 * drm_dev_unref() frees the structure. The devm_ functions provide 138 * drm_dev_put() frees the structure. The devm_ functions provide
139 * for easy error handling. 139 * for easy error handling.
140 */ 140 */
141 drm = drm_dev_alloc(driver, parent); 141 drm = drm_dev_alloc(driver, parent);
@@ -155,7 +155,7 @@ static void tinydrm_fini(struct tinydrm_device *tdev)
155 drm_mode_config_cleanup(tdev->drm); 155 drm_mode_config_cleanup(tdev->drm);
156 mutex_destroy(&tdev->dirty_lock); 156 mutex_destroy(&tdev->dirty_lock);
157 tdev->drm->dev_private = NULL; 157 tdev->drm->dev_private = NULL;
158 drm_dev_unref(tdev->drm); 158 drm_dev_put(tdev->drm);
159} 159}
160 160
161static void devm_tinydrm_release(void *data) 161static void devm_tinydrm_release(void *data)
@@ -172,7 +172,7 @@ static void devm_tinydrm_release(void *data)
172 * 172 *
173 * This function initializes @tdev, the underlying DRM device and it's 173 * This function initializes @tdev, the underlying DRM device and it's
174 * mode_config. Resources will be automatically freed on driver detach (devres) 174 * mode_config. Resources will be automatically freed on driver detach (devres)
175 * using drm_mode_config_cleanup() and drm_dev_unref(). 175 * using drm_mode_config_cleanup() and drm_dev_put().
176 * 176 *
177 * Returns: 177 * Returns:
178 * Zero on success, negative error code on failure. 178 * Zero on success, negative error code on failure.
diff --git a/drivers/gpu/drm/vc4/vc4_drv.c b/drivers/gpu/drm/vc4/vc4_drv.c
index 04270a14fcaa..e2a15c63a81f 100644
--- a/drivers/gpu/drm/vc4/vc4_drv.c
+++ b/drivers/gpu/drm/vc4/vc4_drv.c
@@ -248,24 +248,6 @@ static void vc4_match_add_drivers(struct device *dev,
248 } 248 }
249} 249}
250 250
251static void vc4_kick_out_firmware_fb(void)
252{
253 struct apertures_struct *ap;
254
255 ap = alloc_apertures(1);
256 if (!ap)
257 return;
258
259 /* Since VC4 is a UMA device, the simplefb node may have been
260 * located anywhere in memory.
261 */
262 ap->ranges[0].base = 0;
263 ap->ranges[0].size = ~0;
264
265 drm_fb_helper_remove_conflicting_framebuffers(ap, "vc4drmfb", false);
266 kfree(ap);
267}
268
269static int vc4_drm_bind(struct device *dev) 251static int vc4_drm_bind(struct device *dev)
270{ 252{
271 struct platform_device *pdev = to_platform_device(dev); 253 struct platform_device *pdev = to_platform_device(dev);
@@ -298,7 +280,7 @@ static int vc4_drm_bind(struct device *dev)
298 if (ret) 280 if (ret)
299 goto gem_destroy; 281 goto gem_destroy;
300 282
301 vc4_kick_out_firmware_fb(); 283 drm_fb_helper_remove_conflicting_framebuffers(NULL, "vc4drmfb", false);
302 284
303 ret = drm_dev_register(drm, 0); 285 ret = drm_dev_register(drm, 0);
304 if (ret < 0) 286 if (ret < 0)
diff --git a/drivers/gpu/drm/vc4/vc4_plane.c b/drivers/gpu/drm/vc4/vc4_plane.c
index cfb50fedfa2b..cf78f74bb87f 100644
--- a/drivers/gpu/drm/vc4/vc4_plane.c
+++ b/drivers/gpu/drm/vc4/vc4_plane.c
@@ -200,9 +200,7 @@ static void vc4_plane_reset(struct drm_plane *plane)
200 if (!vc4_state) 200 if (!vc4_state)
201 return; 201 return;
202 202
203 plane->state = &vc4_state->base; 203 __drm_atomic_helper_plane_reset(plane, &vc4_state->base);
204 plane->state->alpha = DRM_BLEND_ALPHA_OPAQUE;
205 vc4_state->base.plane = plane;
206} 204}
207 205
208static void vc4_dlist_write(struct vc4_plane_state *vc4_state, u32 val) 206static void vc4_dlist_write(struct vc4_plane_state *vc4_state, u32 val)
diff --git a/drivers/gpu/drm/vgem/vgem_drv.c b/drivers/gpu/drm/vgem/vgem_drv.c
index 0e5620f76ee0..ec6af8b920da 100644
--- a/drivers/gpu/drm/vgem/vgem_drv.c
+++ b/drivers/gpu/drm/vgem/vgem_drv.c
@@ -504,7 +504,7 @@ out_free:
504static void __exit vgem_exit(void) 504static void __exit vgem_exit(void)
505{ 505{
506 drm_dev_unregister(&vgem_device->drm); 506 drm_dev_unregister(&vgem_device->drm);
507 drm_dev_unref(&vgem_device->drm); 507 drm_dev_put(&vgem_device->drm);
508} 508}
509 509
510module_init(vgem_init); 510module_init(vgem_init);
diff --git a/drivers/gpu/drm/vgem/vgem_fence.c b/drivers/gpu/drm/vgem/vgem_fence.c
index b28876c222b4..e6ee71323a66 100644
--- a/drivers/gpu/drm/vgem/vgem_fence.c
+++ b/drivers/gpu/drm/vgem/vgem_fence.c
@@ -43,16 +43,6 @@ static const char *vgem_fence_get_timeline_name(struct dma_fence *fence)
43 return "unbound"; 43 return "unbound";
44} 44}
45 45
46static bool vgem_fence_signaled(struct dma_fence *fence)
47{
48 return false;
49}
50
51static bool vgem_fence_enable_signaling(struct dma_fence *fence)
52{
53 return true;
54}
55
56static void vgem_fence_release(struct dma_fence *base) 46static void vgem_fence_release(struct dma_fence *base)
57{ 47{
58 struct vgem_fence *fence = container_of(base, typeof(*fence), base); 48 struct vgem_fence *fence = container_of(base, typeof(*fence), base);
@@ -76,9 +66,6 @@ static void vgem_fence_timeline_value_str(struct dma_fence *fence, char *str,
76static const struct dma_fence_ops vgem_fence_ops = { 66static const struct dma_fence_ops vgem_fence_ops = {
77 .get_driver_name = vgem_fence_get_driver_name, 67 .get_driver_name = vgem_fence_get_driver_name,
78 .get_timeline_name = vgem_fence_get_timeline_name, 68 .get_timeline_name = vgem_fence_get_timeline_name,
79 .enable_signaling = vgem_fence_enable_signaling,
80 .signaled = vgem_fence_signaled,
81 .wait = dma_fence_default_wait,
82 .release = vgem_fence_release, 69 .release = vgem_fence_release,
83 70
84 .fence_value_str = vgem_fence_value_str, 71 .fence_value_str = vgem_fence_value_str,
diff --git a/drivers/gpu/drm/virtio/virtgpu_display.c b/drivers/gpu/drm/virtio/virtgpu_display.c
index 25503b933599..9f1e0a669d4c 100644
--- a/drivers/gpu/drm/virtio/virtgpu_display.c
+++ b/drivers/gpu/drm/virtio/virtgpu_display.c
@@ -109,6 +109,9 @@ static void virtio_gpu_crtc_mode_set_nofb(struct drm_crtc *crtc)
109static void virtio_gpu_crtc_atomic_enable(struct drm_crtc *crtc, 109static void virtio_gpu_crtc_atomic_enable(struct drm_crtc *crtc,
110 struct drm_crtc_state *old_state) 110 struct drm_crtc_state *old_state)
111{ 111{
112 struct virtio_gpu_output *output = drm_crtc_to_virtio_gpu_output(crtc);
113
114 output->enabled = true;
112} 115}
113 116
114static void virtio_gpu_crtc_atomic_disable(struct drm_crtc *crtc, 117static void virtio_gpu_crtc_atomic_disable(struct drm_crtc *crtc,
@@ -119,6 +122,7 @@ static void virtio_gpu_crtc_atomic_disable(struct drm_crtc *crtc,
119 struct virtio_gpu_output *output = drm_crtc_to_virtio_gpu_output(crtc); 122 struct virtio_gpu_output *output = drm_crtc_to_virtio_gpu_output(crtc);
120 123
121 virtio_gpu_cmd_set_scanout(vgdev, output->index, 0, 0, 0, 0, 0); 124 virtio_gpu_cmd_set_scanout(vgdev, output->index, 0, 0, 0, 0, 0);
125 output->enabled = false;
122} 126}
123 127
124static int virtio_gpu_crtc_atomic_check(struct drm_crtc *crtc, 128static int virtio_gpu_crtc_atomic_check(struct drm_crtc *crtc,
diff --git a/drivers/gpu/drm/virtio/virtgpu_drm_bus.c b/drivers/gpu/drm/virtio/virtgpu_drm_bus.c
index 7df8d0c9026a..757ca28ab93e 100644
--- a/drivers/gpu/drm/virtio/virtgpu_drm_bus.c
+++ b/drivers/gpu/drm/virtio/virtgpu_drm_bus.c
@@ -28,26 +28,6 @@
28 28
29#include "virtgpu_drv.h" 29#include "virtgpu_drv.h"
30 30
31static void virtio_pci_kick_out_firmware_fb(struct pci_dev *pci_dev)
32{
33 struct apertures_struct *ap;
34 bool primary;
35
36 ap = alloc_apertures(1);
37 if (!ap)
38 return;
39
40 ap->ranges[0].base = pci_resource_start(pci_dev, 0);
41 ap->ranges[0].size = pci_resource_len(pci_dev, 0);
42
43 primary = pci_dev->resource[PCI_ROM_RESOURCE].flags
44 & IORESOURCE_ROM_SHADOW;
45
46 drm_fb_helper_remove_conflicting_framebuffers(ap, "virtiodrmfb", primary);
47
48 kfree(ap);
49}
50
51int drm_virtio_init(struct drm_driver *driver, struct virtio_device *vdev) 31int drm_virtio_init(struct drm_driver *driver, struct virtio_device *vdev)
52{ 32{
53 struct drm_device *dev; 33 struct drm_device *dev;
@@ -69,7 +49,9 @@ int drm_virtio_init(struct drm_driver *driver, struct virtio_device *vdev)
69 pname); 49 pname);
70 dev->pdev = pdev; 50 dev->pdev = pdev;
71 if (vga) 51 if (vga)
72 virtio_pci_kick_out_firmware_fb(pdev); 52 drm_fb_helper_remove_conflicting_pci_framebuffers(pdev,
53 0,
54 "virtiodrmfb");
73 55
74 snprintf(unique, sizeof(unique), "pci:%s", pname); 56 snprintf(unique, sizeof(unique), "pci:%s", pname);
75 ret = drm_dev_set_unique(dev, unique); 57 ret = drm_dev_set_unique(dev, unique);
@@ -85,6 +67,6 @@ int drm_virtio_init(struct drm_driver *driver, struct virtio_device *vdev)
85 return 0; 67 return 0;
86 68
87err_free: 69err_free:
88 drm_dev_unref(dev); 70 drm_dev_put(dev);
89 return ret; 71 return ret;
90} 72}
diff --git a/drivers/gpu/drm/virtio/virtgpu_drv.h b/drivers/gpu/drm/virtio/virtgpu_drv.h
index 65605e207bbe..f8f4a40dd1b8 100644
--- a/drivers/gpu/drm/virtio/virtgpu_drv.h
+++ b/drivers/gpu/drm/virtio/virtgpu_drv.h
@@ -57,6 +57,7 @@ struct virtio_gpu_object {
57 uint32_t hw_res_handle; 57 uint32_t hw_res_handle;
58 58
59 struct sg_table *pages; 59 struct sg_table *pages;
60 uint32_t mapped;
60 void *vmap; 61 void *vmap;
61 bool dumb; 62 bool dumb;
62 struct ttm_place placement_code; 63 struct ttm_place placement_code;
@@ -114,6 +115,7 @@ struct virtio_gpu_output {
114 struct virtio_gpu_update_cursor cursor; 115 struct virtio_gpu_update_cursor cursor;
115 int cur_x; 116 int cur_x;
116 int cur_y; 117 int cur_y;
118 bool enabled;
117}; 119};
118#define drm_crtc_to_virtio_gpu_output(x) \ 120#define drm_crtc_to_virtio_gpu_output(x) \
119 container_of(x, struct virtio_gpu_output, crtc) 121 container_of(x, struct virtio_gpu_output, crtc)
@@ -276,13 +278,13 @@ int virtio_gpu_object_attach(struct virtio_gpu_device *vgdev,
276 struct virtio_gpu_object *obj, 278 struct virtio_gpu_object *obj,
277 uint32_t resource_id, 279 uint32_t resource_id,
278 struct virtio_gpu_fence **fence); 280 struct virtio_gpu_fence **fence);
281void virtio_gpu_object_detach(struct virtio_gpu_device *vgdev,
282 struct virtio_gpu_object *obj);
279int virtio_gpu_attach_status_page(struct virtio_gpu_device *vgdev); 283int virtio_gpu_attach_status_page(struct virtio_gpu_device *vgdev);
280int virtio_gpu_detach_status_page(struct virtio_gpu_device *vgdev); 284int virtio_gpu_detach_status_page(struct virtio_gpu_device *vgdev);
281void virtio_gpu_cursor_ping(struct virtio_gpu_device *vgdev, 285void virtio_gpu_cursor_ping(struct virtio_gpu_device *vgdev,
282 struct virtio_gpu_output *output); 286 struct virtio_gpu_output *output);
283int virtio_gpu_cmd_get_display_info(struct virtio_gpu_device *vgdev); 287int virtio_gpu_cmd_get_display_info(struct virtio_gpu_device *vgdev);
284void virtio_gpu_cmd_resource_inval_backing(struct virtio_gpu_device *vgdev,
285 uint32_t resource_id);
286int virtio_gpu_cmd_get_capset_info(struct virtio_gpu_device *vgdev, int idx); 288int virtio_gpu_cmd_get_capset_info(struct virtio_gpu_device *vgdev, int idx);
287int virtio_gpu_cmd_get_capset(struct virtio_gpu_device *vgdev, 289int virtio_gpu_cmd_get_capset(struct virtio_gpu_device *vgdev,
288 int idx, int version, 290 int idx, int version,
@@ -372,7 +374,7 @@ int virtgpu_gem_prime_mmap(struct drm_gem_object *obj,
372static inline struct virtio_gpu_object* 374static inline struct virtio_gpu_object*
373virtio_gpu_object_ref(struct virtio_gpu_object *bo) 375virtio_gpu_object_ref(struct virtio_gpu_object *bo)
374{ 376{
375 ttm_bo_reference(&bo->tbo); 377 ttm_bo_get(&bo->tbo);
376 return bo; 378 return bo;
377} 379}
378 380
@@ -383,9 +385,8 @@ static inline void virtio_gpu_object_unref(struct virtio_gpu_object **bo)
383 if ((*bo) == NULL) 385 if ((*bo) == NULL)
384 return; 386 return;
385 tbo = &((*bo)->tbo); 387 tbo = &((*bo)->tbo);
386 ttm_bo_unref(&tbo); 388 ttm_bo_put(tbo);
387 if (tbo == NULL) 389 *bo = NULL;
388 *bo = NULL;
389} 390}
390 391
391static inline u64 virtio_gpu_object_mmap_offset(struct virtio_gpu_object *bo) 392static inline u64 virtio_gpu_object_mmap_offset(struct virtio_gpu_object *bo)
diff --git a/drivers/gpu/drm/virtio/virtgpu_fb.c b/drivers/gpu/drm/virtio/virtgpu_fb.c
index a121b1c79522..b5cebc9a179a 100644
--- a/drivers/gpu/drm/virtio/virtgpu_fb.c
+++ b/drivers/gpu/drm/virtio/virtgpu_fb.c
@@ -291,7 +291,7 @@ static int virtio_gpufb_create(struct drm_fb_helper *helper,
291 return 0; 291 return 0;
292 292
293err_fb_alloc: 293err_fb_alloc:
294 virtio_gpu_cmd_resource_inval_backing(vgdev, resid); 294 virtio_gpu_object_detach(vgdev, obj);
295err_obj_attach: 295err_obj_attach:
296err_obj_vmap: 296err_obj_vmap:
297 virtio_gpu_gem_free_object(&obj->gem_base); 297 virtio_gpu_gem_free_object(&obj->gem_base);
diff --git a/drivers/gpu/drm/virtio/virtgpu_plane.c b/drivers/gpu/drm/virtio/virtgpu_plane.c
index dc5b5b2b7aab..88f2fb8c61c4 100644
--- a/drivers/gpu/drm/virtio/virtgpu_plane.c
+++ b/drivers/gpu/drm/virtio/virtgpu_plane.c
@@ -152,7 +152,7 @@ static void virtio_gpu_primary_plane_update(struct drm_plane *plane,
152 if (WARN_ON(!output)) 152 if (WARN_ON(!output))
153 return; 153 return;
154 154
155 if (plane->state->fb) { 155 if (plane->state->fb && output->enabled) {
156 vgfb = to_virtio_gpu_framebuffer(plane->state->fb); 156 vgfb = to_virtio_gpu_framebuffer(plane->state->fb);
157 bo = gem_to_virtio_gpu_obj(vgfb->base.obj[0]); 157 bo = gem_to_virtio_gpu_obj(vgfb->base.obj[0]);
158 handle = bo->hw_res_handle; 158 handle = bo->hw_res_handle;
diff --git a/drivers/gpu/drm/virtio/virtgpu_ttm.c b/drivers/gpu/drm/virtio/virtgpu_ttm.c
index 11f8ae5b5332..e3152d45c5f1 100644
--- a/drivers/gpu/drm/virtio/virtgpu_ttm.c
+++ b/drivers/gpu/drm/virtio/virtgpu_ttm.c
@@ -106,29 +106,6 @@ static void virtio_gpu_ttm_global_fini(struct virtio_gpu_device *vgdev)
106 } 106 }
107} 107}
108 108
109#if 0
110/*
111 * Hmm, seems to not do anything useful. Leftover debug hack?
112 * Something like printing pagefaults to kernel log?
113 */
114static struct vm_operations_struct virtio_gpu_ttm_vm_ops;
115static const struct vm_operations_struct *ttm_vm_ops;
116
117static int virtio_gpu_ttm_fault(struct vm_fault *vmf)
118{
119 struct ttm_buffer_object *bo;
120 struct virtio_gpu_device *vgdev;
121 int r;
122
123 bo = (struct ttm_buffer_object *)vmf->vma->vm_private_data;
124 if (bo == NULL)
125 return VM_FAULT_NOPAGE;
126 vgdev = virtio_gpu_get_vgdev(bo->bdev);
127 r = ttm_vm_ops->fault(vmf);
128 return r;
129}
130#endif
131
132int virtio_gpu_mmap(struct file *filp, struct vm_area_struct *vma) 109int virtio_gpu_mmap(struct file *filp, struct vm_area_struct *vma)
133{ 110{
134 struct drm_file *file_priv; 111 struct drm_file *file_priv;
@@ -143,19 +120,8 @@ int virtio_gpu_mmap(struct file *filp, struct vm_area_struct *vma)
143 return -EINVAL; 120 return -EINVAL;
144 } 121 }
145 r = ttm_bo_mmap(filp, vma, &vgdev->mman.bdev); 122 r = ttm_bo_mmap(filp, vma, &vgdev->mman.bdev);
146#if 0 123
147 if (unlikely(r != 0))
148 return r;
149 if (unlikely(ttm_vm_ops == NULL)) {
150 ttm_vm_ops = vma->vm_ops;
151 virtio_gpu_ttm_vm_ops = *ttm_vm_ops;
152 virtio_gpu_ttm_vm_ops.fault = &virtio_gpu_ttm_fault;
153 }
154 vma->vm_ops = &virtio_gpu_ttm_vm_ops;
155 return 0;
156#else
157 return r; 124 return r;
158#endif
159} 125}
160 126
161static int virtio_gpu_invalidate_caches(struct ttm_bo_device *bdev, 127static int virtio_gpu_invalidate_caches(struct ttm_bo_device *bdev,
@@ -377,8 +343,7 @@ static void virtio_gpu_bo_move_notify(struct ttm_buffer_object *tbo,
377 343
378 if (!new_mem || (new_mem->placement & TTM_PL_FLAG_SYSTEM)) { 344 if (!new_mem || (new_mem->placement & TTM_PL_FLAG_SYSTEM)) {
379 if (bo->hw_res_handle) 345 if (bo->hw_res_handle)
380 virtio_gpu_cmd_resource_inval_backing(vgdev, 346 virtio_gpu_object_detach(vgdev, bo);
381 bo->hw_res_handle);
382 347
383 } else if (new_mem->placement & TTM_PL_FLAG_TT) { 348 } else if (new_mem->placement & TTM_PL_FLAG_TT) {
384 if (bo->hw_res_handle) { 349 if (bo->hw_res_handle) {
diff --git a/drivers/gpu/drm/virtio/virtgpu_vq.c b/drivers/gpu/drm/virtio/virtgpu_vq.c
index 020070d483d3..5784c3ea8767 100644
--- a/drivers/gpu/drm/virtio/virtgpu_vq.c
+++ b/drivers/gpu/drm/virtio/virtgpu_vq.c
@@ -423,8 +423,9 @@ void virtio_gpu_cmd_unref_resource(struct virtio_gpu_device *vgdev,
423 virtio_gpu_queue_ctrl_buffer(vgdev, vbuf); 423 virtio_gpu_queue_ctrl_buffer(vgdev, vbuf);
424} 424}
425 425
426void virtio_gpu_cmd_resource_inval_backing(struct virtio_gpu_device *vgdev, 426static void virtio_gpu_cmd_resource_inval_backing(struct virtio_gpu_device *vgdev,
427 uint32_t resource_id) 427 uint32_t resource_id,
428 struct virtio_gpu_fence **fence)
428{ 429{
429 struct virtio_gpu_resource_detach_backing *cmd_p; 430 struct virtio_gpu_resource_detach_backing *cmd_p;
430 struct virtio_gpu_vbuffer *vbuf; 431 struct virtio_gpu_vbuffer *vbuf;
@@ -435,7 +436,7 @@ void virtio_gpu_cmd_resource_inval_backing(struct virtio_gpu_device *vgdev,
435 cmd_p->hdr.type = cpu_to_le32(VIRTIO_GPU_CMD_RESOURCE_DETACH_BACKING); 436 cmd_p->hdr.type = cpu_to_le32(VIRTIO_GPU_CMD_RESOURCE_DETACH_BACKING);
436 cmd_p->resource_id = cpu_to_le32(resource_id); 437 cmd_p->resource_id = cpu_to_le32(resource_id);
437 438
438 virtio_gpu_queue_ctrl_buffer(vgdev, vbuf); 439 virtio_gpu_queue_fenced_ctrl_buffer(vgdev, vbuf, &cmd_p->hdr, fence);
439} 440}
440 441
441void virtio_gpu_cmd_set_scanout(struct virtio_gpu_device *vgdev, 442void virtio_gpu_cmd_set_scanout(struct virtio_gpu_device *vgdev,
@@ -648,11 +649,11 @@ int virtio_gpu_cmd_get_capset(struct virtio_gpu_device *vgdev,
648{ 649{
649 struct virtio_gpu_get_capset *cmd_p; 650 struct virtio_gpu_get_capset *cmd_p;
650 struct virtio_gpu_vbuffer *vbuf; 651 struct virtio_gpu_vbuffer *vbuf;
651 int max_size = vgdev->capsets[idx].max_size; 652 int max_size;
652 struct virtio_gpu_drv_cap_cache *cache_ent; 653 struct virtio_gpu_drv_cap_cache *cache_ent;
653 void *resp_buf; 654 void *resp_buf;
654 655
655 if (idx > vgdev->num_capsets) 656 if (idx >= vgdev->num_capsets)
656 return -EINVAL; 657 return -EINVAL;
657 658
658 if (version > vgdev->capsets[idx].max_version) 659 if (version > vgdev->capsets[idx].max_version)
@@ -662,6 +663,7 @@ int virtio_gpu_cmd_get_capset(struct virtio_gpu_device *vgdev,
662 if (!cache_ent) 663 if (!cache_ent)
663 return -ENOMEM; 664 return -ENOMEM;
664 665
666 max_size = vgdev->capsets[idx].max_size;
665 cache_ent->caps_cache = kmalloc(max_size, GFP_KERNEL); 667 cache_ent->caps_cache = kmalloc(max_size, GFP_KERNEL);
666 if (!cache_ent->caps_cache) { 668 if (!cache_ent->caps_cache) {
667 kfree(cache_ent); 669 kfree(cache_ent);
@@ -848,9 +850,10 @@ int virtio_gpu_object_attach(struct virtio_gpu_device *vgdev,
848 uint32_t resource_id, 850 uint32_t resource_id,
849 struct virtio_gpu_fence **fence) 851 struct virtio_gpu_fence **fence)
850{ 852{
853 bool use_dma_api = !virtio_has_iommu_quirk(vgdev->vdev);
851 struct virtio_gpu_mem_entry *ents; 854 struct virtio_gpu_mem_entry *ents;
852 struct scatterlist *sg; 855 struct scatterlist *sg;
853 int si; 856 int si, nents;
854 857
855 if (!obj->pages) { 858 if (!obj->pages) {
856 int ret; 859 int ret;
@@ -860,28 +863,60 @@ int virtio_gpu_object_attach(struct virtio_gpu_device *vgdev,
860 return ret; 863 return ret;
861 } 864 }
862 865
866 if (use_dma_api) {
867 obj->mapped = dma_map_sg(vgdev->vdev->dev.parent,
868 obj->pages->sgl, obj->pages->nents,
869 DMA_TO_DEVICE);
870 nents = obj->mapped;
871 } else {
872 nents = obj->pages->nents;
873 }
874
863 /* gets freed when the ring has consumed it */ 875 /* gets freed when the ring has consumed it */
864 ents = kmalloc_array(obj->pages->nents, 876 ents = kmalloc_array(nents, sizeof(struct virtio_gpu_mem_entry),
865 sizeof(struct virtio_gpu_mem_entry),
866 GFP_KERNEL); 877 GFP_KERNEL);
867 if (!ents) { 878 if (!ents) {
868 DRM_ERROR("failed to allocate ent list\n"); 879 DRM_ERROR("failed to allocate ent list\n");
869 return -ENOMEM; 880 return -ENOMEM;
870 } 881 }
871 882
872 for_each_sg(obj->pages->sgl, sg, obj->pages->nents, si) { 883 for_each_sg(obj->pages->sgl, sg, nents, si) {
873 ents[si].addr = cpu_to_le64(sg_phys(sg)); 884 ents[si].addr = cpu_to_le64(use_dma_api
885 ? sg_dma_address(sg)
886 : sg_phys(sg));
874 ents[si].length = cpu_to_le32(sg->length); 887 ents[si].length = cpu_to_le32(sg->length);
875 ents[si].padding = 0; 888 ents[si].padding = 0;
876 } 889 }
877 890
878 virtio_gpu_cmd_resource_attach_backing(vgdev, resource_id, 891 virtio_gpu_cmd_resource_attach_backing(vgdev, resource_id,
879 ents, obj->pages->nents, 892 ents, nents,
880 fence); 893 fence);
881 obj->hw_res_handle = resource_id; 894 obj->hw_res_handle = resource_id;
882 return 0; 895 return 0;
883} 896}
884 897
898void virtio_gpu_object_detach(struct virtio_gpu_device *vgdev,
899 struct virtio_gpu_object *obj)
900{
901 bool use_dma_api = !virtio_has_iommu_quirk(vgdev->vdev);
902 struct virtio_gpu_fence *fence;
903
904 if (use_dma_api && obj->mapped) {
905 /* detach backing and wait for the host process it ... */
906 virtio_gpu_cmd_resource_inval_backing(vgdev, obj->hw_res_handle, &fence);
907 dma_fence_wait(&fence->f, true);
908 dma_fence_put(&fence->f);
909
910 /* ... then tear down iommu mappings */
911 dma_unmap_sg(vgdev->vdev->dev.parent,
912 obj->pages->sgl, obj->mapped,
913 DMA_TO_DEVICE);
914 obj->mapped = 0;
915 } else {
916 virtio_gpu_cmd_resource_inval_backing(vgdev, obj->hw_res_handle, NULL);
917 }
918}
919
885void virtio_gpu_cursor_ping(struct virtio_gpu_device *vgdev, 920void virtio_gpu_cursor_ping(struct virtio_gpu_device *vgdev,
886 struct virtio_gpu_output *output) 921 struct virtio_gpu_output *output)
887{ 922{
diff --git a/drivers/gpu/drm/vkms/Makefile b/drivers/gpu/drm/vkms/Makefile
index 986297da51bf..37966914f70b 100644
--- a/drivers/gpu/drm/vkms/Makefile
+++ b/drivers/gpu/drm/vkms/Makefile
@@ -1,3 +1,3 @@
1vkms-y := vkms_drv.o vkms_plane.o vkms_output.o vkms_crtc.o vkms_gem.o 1vkms-y := vkms_drv.o vkms_plane.o vkms_output.o vkms_crtc.o vkms_gem.o vkms_crc.o
2 2
3obj-$(CONFIG_DRM_VKMS) += vkms.o 3obj-$(CONFIG_DRM_VKMS) += vkms.o
diff --git a/drivers/gpu/drm/vkms/vkms_crc.c b/drivers/gpu/drm/vkms/vkms_crc.c
new file mode 100644
index 000000000000..68db42f15086
--- /dev/null
+++ b/drivers/gpu/drm/vkms/vkms_crc.c
@@ -0,0 +1,153 @@
1// SPDX-License-Identifier: GPL-2.0
2#include "vkms_drv.h"
3#include <linux/crc32.h>
4#include <drm/drm_gem_framebuffer_helper.h>
5
6static uint32_t _vkms_get_crc(struct vkms_crc_data *crc_data)
7{
8 struct drm_framebuffer *fb = &crc_data->fb;
9 struct drm_gem_object *gem_obj = drm_gem_fb_get_obj(fb, 0);
10 struct vkms_gem_object *vkms_obj = drm_gem_to_vkms_gem(gem_obj);
11 u32 crc = 0;
12 int i = 0;
13 unsigned int x = crc_data->src.x1 >> 16;
14 unsigned int y = crc_data->src.y1 >> 16;
15 unsigned int height = drm_rect_height(&crc_data->src) >> 16;
16 unsigned int width = drm_rect_width(&crc_data->src) >> 16;
17 unsigned int cpp = fb->format->cpp[0];
18 unsigned int src_offset;
19 unsigned int size_byte = width * cpp;
20 void *vaddr;
21
22 mutex_lock(&vkms_obj->pages_lock);
23 vaddr = vkms_obj->vaddr;
24 if (WARN_ON(!vaddr))
25 goto out;
26
27 for (i = y; i < y + height; i++) {
28 src_offset = fb->offsets[0] + (i * fb->pitches[0]) + (x * cpp);
29 crc = crc32_le(crc, vaddr + src_offset, size_byte);
30 }
31
32out:
33 mutex_unlock(&vkms_obj->pages_lock);
34 return crc;
35}
36
37/**
38 * vkms_crc_work_handle - ordered work_struct to compute CRC
39 *
40 * @work: work_struct
41 *
42 * Work handler for computing CRCs. work_struct scheduled in
43 * an ordered workqueue that's periodically scheduled to run by
44 * _vblank_handle() and flushed at vkms_atomic_crtc_destroy_state().
45 */
46void vkms_crc_work_handle(struct work_struct *work)
47{
48 struct vkms_crtc_state *crtc_state = container_of(work,
49 struct vkms_crtc_state,
50 crc_work);
51 struct drm_crtc *crtc = crtc_state->base.crtc;
52 struct vkms_output *out = drm_crtc_to_vkms_output(crtc);
53 struct vkms_device *vdev = container_of(out, struct vkms_device,
54 output);
55 struct vkms_crc_data *primary_crc = NULL;
56 struct drm_plane *plane;
57 u32 crc32 = 0;
58 u64 frame_start, frame_end;
59 unsigned long flags;
60
61 spin_lock_irqsave(&out->state_lock, flags);
62 frame_start = crtc_state->frame_start;
63 frame_end = crtc_state->frame_end;
64 spin_unlock_irqrestore(&out->state_lock, flags);
65
66 /* _vblank_handle() hasn't updated frame_start yet */
67 if (!frame_start || frame_start == frame_end)
68 goto out;
69
70 drm_for_each_plane(plane, &vdev->drm) {
71 struct vkms_plane_state *vplane_state;
72 struct vkms_crc_data *crc_data;
73
74 vplane_state = to_vkms_plane_state(plane->state);
75 crc_data = vplane_state->crc_data;
76
77 if (drm_framebuffer_read_refcount(&crc_data->fb) == 0)
78 continue;
79
80 if (plane->type == DRM_PLANE_TYPE_PRIMARY) {
81 primary_crc = crc_data;
82 break;
83 }
84 }
85
86 if (primary_crc)
87 crc32 = _vkms_get_crc(primary_crc);
88
89 frame_end = drm_crtc_accurate_vblank_count(crtc);
90
91 /* queue_work can fail to schedule crc_work; add crc for
92 * missing frames
93 */
94 while (frame_start <= frame_end)
95 drm_crtc_add_crc_entry(crtc, true, frame_start++, &crc32);
96
97out:
98 /* to avoid using the same value for frame number again */
99 spin_lock_irqsave(&out->state_lock, flags);
100 crtc_state->frame_end = frame_end;
101 crtc_state->frame_start = 0;
102 spin_unlock_irqrestore(&out->state_lock, flags);
103}
104
105static int vkms_crc_parse_source(const char *src_name, bool *enabled)
106{
107 int ret = 0;
108
109 if (!src_name) {
110 *enabled = false;
111 } else if (strcmp(src_name, "auto") == 0) {
112 *enabled = true;
113 } else {
114 *enabled = false;
115 ret = -EINVAL;
116 }
117
118 return ret;
119}
120
121int vkms_verify_crc_source(struct drm_crtc *crtc, const char *src_name,
122 size_t *values_cnt)
123{
124 bool enabled;
125
126 if (vkms_crc_parse_source(src_name, &enabled) < 0) {
127 DRM_DEBUG_DRIVER("unknown source %s\n", src_name);
128 return -EINVAL;
129 }
130
131 *values_cnt = 1;
132
133 return 0;
134}
135
136int vkms_set_crc_source(struct drm_crtc *crtc, const char *src_name)
137{
138 struct vkms_output *out = drm_crtc_to_vkms_output(crtc);
139 bool enabled = false;
140 unsigned long flags;
141 int ret = 0;
142
143 ret = vkms_crc_parse_source(src_name, &enabled);
144
145 /* make sure nothing is scheduled on crtc workq */
146 flush_workqueue(out->crc_workq);
147
148 spin_lock_irqsave(&out->lock, flags);
149 out->crc_enabled = enabled;
150 spin_unlock_irqrestore(&out->lock, flags);
151
152 return ret;
153}
diff --git a/drivers/gpu/drm/vkms/vkms_crtc.c b/drivers/gpu/drm/vkms/vkms_crtc.c
index 875fca662ac0..177bbcb38306 100644
--- a/drivers/gpu/drm/vkms/vkms_crtc.c
+++ b/drivers/gpu/drm/vkms/vkms_crtc.c
@@ -10,18 +10,44 @@
10#include <drm/drm_atomic_helper.h> 10#include <drm/drm_atomic_helper.h>
11#include <drm/drm_crtc_helper.h> 11#include <drm/drm_crtc_helper.h>
12 12
13static enum hrtimer_restart vkms_vblank_simulate(struct hrtimer *timer) 13static void _vblank_handle(struct vkms_output *output)
14{ 14{
15 struct vkms_output *output = container_of(timer, struct vkms_output,
16 vblank_hrtimer);
17 struct drm_crtc *crtc = &output->crtc; 15 struct drm_crtc *crtc = &output->crtc;
18 int ret_overrun; 16 struct vkms_crtc_state *state = to_vkms_crtc_state(crtc->state);
19 bool ret; 17 bool ret;
20 18
19 spin_lock(&output->lock);
21 ret = drm_crtc_handle_vblank(crtc); 20 ret = drm_crtc_handle_vblank(crtc);
22 if (!ret) 21 if (!ret)
23 DRM_ERROR("vkms failure on handling vblank"); 22 DRM_ERROR("vkms failure on handling vblank");
24 23
24 if (state && output->crc_enabled) {
25 u64 frame = drm_crtc_accurate_vblank_count(crtc);
26
27 /* update frame_start only if a queued vkms_crc_work_handle()
28 * has read the data
29 */
30 spin_lock(&output->state_lock);
31 if (!state->frame_start)
32 state->frame_start = frame;
33 spin_unlock(&output->state_lock);
34
35 ret = queue_work(output->crc_workq, &state->crc_work);
36 if (!ret)
37 DRM_WARN("failed to queue vkms_crc_work_handle");
38 }
39
40 spin_unlock(&output->lock);
41}
42
43static enum hrtimer_restart vkms_vblank_simulate(struct hrtimer *timer)
44{
45 struct vkms_output *output = container_of(timer, struct vkms_output,
46 vblank_hrtimer);
47 int ret_overrun;
48
49 _vblank_handle(output);
50
25 ret_overrun = hrtimer_forward_now(&output->vblank_hrtimer, 51 ret_overrun = hrtimer_forward_now(&output->vblank_hrtimer,
26 output->period_ns); 52 output->period_ns);
27 53
@@ -64,15 +90,68 @@ bool vkms_get_vblank_timestamp(struct drm_device *dev, unsigned int pipe,
64 return true; 90 return true;
65} 91}
66 92
93static void vkms_atomic_crtc_reset(struct drm_crtc *crtc)
94{
95 struct vkms_crtc_state *vkms_state = NULL;
96
97 if (crtc->state) {
98 vkms_state = to_vkms_crtc_state(crtc->state);
99 __drm_atomic_helper_crtc_destroy_state(crtc->state);
100 kfree(vkms_state);
101 crtc->state = NULL;
102 }
103
104 vkms_state = kzalloc(sizeof(*vkms_state), GFP_KERNEL);
105 if (!vkms_state)
106 return;
107
108 crtc->state = &vkms_state->base;
109 crtc->state->crtc = crtc;
110}
111
112static struct drm_crtc_state *
113vkms_atomic_crtc_duplicate_state(struct drm_crtc *crtc)
114{
115 struct vkms_crtc_state *vkms_state;
116
117 if (WARN_ON(!crtc->state))
118 return NULL;
119
120 vkms_state = kzalloc(sizeof(*vkms_state), GFP_KERNEL);
121 if (!vkms_state)
122 return NULL;
123
124 __drm_atomic_helper_crtc_duplicate_state(crtc, &vkms_state->base);
125
126 INIT_WORK(&vkms_state->crc_work, vkms_crc_work_handle);
127
128 return &vkms_state->base;
129}
130
131static void vkms_atomic_crtc_destroy_state(struct drm_crtc *crtc,
132 struct drm_crtc_state *state)
133{
134 struct vkms_crtc_state *vkms_state = to_vkms_crtc_state(state);
135
136 __drm_atomic_helper_crtc_destroy_state(state);
137
138 if (vkms_state) {
139 flush_work(&vkms_state->crc_work);
140 kfree(vkms_state);
141 }
142}
143
67static const struct drm_crtc_funcs vkms_crtc_funcs = { 144static const struct drm_crtc_funcs vkms_crtc_funcs = {
68 .set_config = drm_atomic_helper_set_config, 145 .set_config = drm_atomic_helper_set_config,
69 .destroy = drm_crtc_cleanup, 146 .destroy = drm_crtc_cleanup,
70 .page_flip = drm_atomic_helper_page_flip, 147 .page_flip = drm_atomic_helper_page_flip,
71 .reset = drm_atomic_helper_crtc_reset, 148 .reset = vkms_atomic_crtc_reset,
72 .atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state, 149 .atomic_duplicate_state = vkms_atomic_crtc_duplicate_state,
73 .atomic_destroy_state = drm_atomic_helper_crtc_destroy_state, 150 .atomic_destroy_state = vkms_atomic_crtc_destroy_state,
74 .enable_vblank = vkms_enable_vblank, 151 .enable_vblank = vkms_enable_vblank,
75 .disable_vblank = vkms_disable_vblank, 152 .disable_vblank = vkms_disable_vblank,
153 .set_crc_source = vkms_set_crc_source,
154 .verify_crc_source = vkms_verify_crc_source,
76}; 155};
77 156
78static void vkms_crtc_atomic_enable(struct drm_crtc *crtc, 157static void vkms_crtc_atomic_enable(struct drm_crtc *crtc,
@@ -87,9 +166,21 @@ static void vkms_crtc_atomic_disable(struct drm_crtc *crtc,
87 drm_crtc_vblank_off(crtc); 166 drm_crtc_vblank_off(crtc);
88} 167}
89 168
169static void vkms_crtc_atomic_begin(struct drm_crtc *crtc,
170 struct drm_crtc_state *old_crtc_state)
171{
172 struct vkms_output *vkms_output = drm_crtc_to_vkms_output(crtc);
173
174 /* This lock is held across the atomic commit to block vblank timer
175 * from scheduling vkms_crc_work_handle until the crc_data is updated
176 */
177 spin_lock_irq(&vkms_output->lock);
178}
179
90static void vkms_crtc_atomic_flush(struct drm_crtc *crtc, 180static void vkms_crtc_atomic_flush(struct drm_crtc *crtc,
91 struct drm_crtc_state *old_crtc_state) 181 struct drm_crtc_state *old_crtc_state)
92{ 182{
183 struct vkms_output *vkms_output = drm_crtc_to_vkms_output(crtc);
93 unsigned long flags; 184 unsigned long flags;
94 185
95 if (crtc->state->event) { 186 if (crtc->state->event) {
@@ -104,9 +195,12 @@ static void vkms_crtc_atomic_flush(struct drm_crtc *crtc,
104 195
105 crtc->state->event = NULL; 196 crtc->state->event = NULL;
106 } 197 }
198
199 spin_unlock_irq(&vkms_output->lock);
107} 200}
108 201
109static const struct drm_crtc_helper_funcs vkms_crtc_helper_funcs = { 202static const struct drm_crtc_helper_funcs vkms_crtc_helper_funcs = {
203 .atomic_begin = vkms_crtc_atomic_begin,
110 .atomic_flush = vkms_crtc_atomic_flush, 204 .atomic_flush = vkms_crtc_atomic_flush,
111 .atomic_enable = vkms_crtc_atomic_enable, 205 .atomic_enable = vkms_crtc_atomic_enable,
112 .atomic_disable = vkms_crtc_atomic_disable, 206 .atomic_disable = vkms_crtc_atomic_disable,
@@ -115,6 +209,7 @@ static const struct drm_crtc_helper_funcs vkms_crtc_helper_funcs = {
115int vkms_crtc_init(struct drm_device *dev, struct drm_crtc *crtc, 209int vkms_crtc_init(struct drm_device *dev, struct drm_crtc *crtc,
116 struct drm_plane *primary, struct drm_plane *cursor) 210 struct drm_plane *primary, struct drm_plane *cursor)
117{ 211{
212 struct vkms_output *vkms_out = drm_crtc_to_vkms_output(crtc);
118 int ret; 213 int ret;
119 214
120 ret = drm_crtc_init_with_planes(dev, crtc, primary, cursor, 215 ret = drm_crtc_init_with_planes(dev, crtc, primary, cursor,
@@ -126,5 +221,10 @@ int vkms_crtc_init(struct drm_device *dev, struct drm_crtc *crtc,
126 221
127 drm_crtc_helper_add(crtc, &vkms_crtc_helper_funcs); 222 drm_crtc_helper_add(crtc, &vkms_crtc_helper_funcs);
128 223
224 spin_lock_init(&vkms_out->lock);
225 spin_lock_init(&vkms_out->state_lock);
226
227 vkms_out->crc_workq = alloc_ordered_workqueue("vkms_crc_workq", 0);
228
129 return ret; 229 return ret;
130} 230}
diff --git a/drivers/gpu/drm/vkms/vkms_drv.c b/drivers/gpu/drm/vkms/vkms_drv.c
index 6e728b825259..bd9d4b2389bd 100644
--- a/drivers/gpu/drm/vkms/vkms_drv.c
+++ b/drivers/gpu/drm/vkms/vkms_drv.c
@@ -47,6 +47,7 @@ static void vkms_release(struct drm_device *dev)
47 drm_atomic_helper_shutdown(&vkms->drm); 47 drm_atomic_helper_shutdown(&vkms->drm);
48 drm_mode_config_cleanup(&vkms->drm); 48 drm_mode_config_cleanup(&vkms->drm);
49 drm_dev_fini(&vkms->drm); 49 drm_dev_fini(&vkms->drm);
50 destroy_workqueue(vkms->output.crc_workq);
50} 51}
51 52
52static struct drm_driver vkms_driver = { 53static struct drm_driver vkms_driver = {
diff --git a/drivers/gpu/drm/vkms/vkms_drv.h b/drivers/gpu/drm/vkms/vkms_drv.h
index 07be29f2dc44..80af6d3a65e7 100644
--- a/drivers/gpu/drm/vkms/vkms_drv.h
+++ b/drivers/gpu/drm/vkms/vkms_drv.h
@@ -20,6 +20,35 @@ static const u32 vkms_formats[] = {
20 DRM_FORMAT_XRGB8888, 20 DRM_FORMAT_XRGB8888,
21}; 21};
22 22
23struct vkms_crc_data {
24 struct drm_rect src;
25 struct drm_framebuffer fb;
26};
27
28/**
29 * vkms_plane_state - Driver specific plane state
30 * @base: base plane state
31 * @crc_data: data required for CRC computation
32 */
33struct vkms_plane_state {
34 struct drm_plane_state base;
35 struct vkms_crc_data *crc_data;
36};
37
38/**
39 * vkms_crtc_state - Driver specific CRTC state
40 * @base: base CRTC state
41 * @crc_work: work struct to compute and add CRC entries
42 * @n_frame_start: start frame number for computed CRC
43 * @n_frame_end: end frame number for computed CRC
44 */
45struct vkms_crtc_state {
46 struct drm_crtc_state base;
47 struct work_struct crc_work;
48 u64 frame_start;
49 u64 frame_end;
50};
51
23struct vkms_output { 52struct vkms_output {
24 struct drm_crtc crtc; 53 struct drm_crtc crtc;
25 struct drm_encoder encoder; 54 struct drm_encoder encoder;
@@ -27,6 +56,13 @@ struct vkms_output {
27 struct hrtimer vblank_hrtimer; 56 struct hrtimer vblank_hrtimer;
28 ktime_t period_ns; 57 ktime_t period_ns;
29 struct drm_pending_vblank_event *event; 58 struct drm_pending_vblank_event *event;
59 bool crc_enabled;
60 /* ordered wq for crc_work */
61 struct workqueue_struct *crc_workq;
62 /* protects concurrent access to crc_data */
63 spinlock_t lock;
64 /* protects concurrent access to crtc_state */
65 spinlock_t state_lock;
30}; 66};
31 67
32struct vkms_device { 68struct vkms_device {
@@ -39,6 +75,8 @@ struct vkms_gem_object {
39 struct drm_gem_object gem; 75 struct drm_gem_object gem;
40 struct mutex pages_lock; /* Page lock used in page fault handler */ 76 struct mutex pages_lock; /* Page lock used in page fault handler */
41 struct page **pages; 77 struct page **pages;
78 unsigned int vmap_count;
79 void *vaddr;
42}; 80};
43 81
44#define drm_crtc_to_vkms_output(target) \ 82#define drm_crtc_to_vkms_output(target) \
@@ -47,6 +85,15 @@ struct vkms_gem_object {
47#define drm_device_to_vkms_device(target) \ 85#define drm_device_to_vkms_device(target) \
48 container_of(target, struct vkms_device, drm) 86 container_of(target, struct vkms_device, drm)
49 87
88#define drm_gem_to_vkms_gem(target)\
89 container_of(target, struct vkms_gem_object, gem)
90
91#define to_vkms_crtc_state(target)\
92 container_of(target, struct vkms_crtc_state, base)
93
94#define to_vkms_plane_state(target)\
95 container_of(target, struct vkms_plane_state, base)
96
50/* CRTC */ 97/* CRTC */
51int vkms_crtc_init(struct drm_device *dev, struct drm_crtc *crtc, 98int vkms_crtc_init(struct drm_device *dev, struct drm_crtc *crtc,
52 struct drm_plane *primary, struct drm_plane *cursor); 99 struct drm_plane *primary, struct drm_plane *cursor);
@@ -65,7 +112,7 @@ struct drm_gem_object *vkms_gem_create(struct drm_device *dev,
65 u32 *handle, 112 u32 *handle,
66 u64 size); 113 u64 size);
67 114
68int vkms_gem_fault(struct vm_fault *vmf); 115vm_fault_t vkms_gem_fault(struct vm_fault *vmf);
69 116
70int vkms_dumb_create(struct drm_file *file, struct drm_device *dev, 117int vkms_dumb_create(struct drm_file *file, struct drm_device *dev,
71 struct drm_mode_create_dumb *args); 118 struct drm_mode_create_dumb *args);
@@ -75,4 +122,14 @@ int vkms_dumb_map(struct drm_file *file, struct drm_device *dev,
75 122
76void vkms_gem_free_object(struct drm_gem_object *obj); 123void vkms_gem_free_object(struct drm_gem_object *obj);
77 124
125int vkms_gem_vmap(struct drm_gem_object *obj);
126
127void vkms_gem_vunmap(struct drm_gem_object *obj);
128
129/* CRC Support */
130int vkms_set_crc_source(struct drm_crtc *crtc, const char *src_name);
131int vkms_verify_crc_source(struct drm_crtc *crtc, const char *source_name,
132 size_t *values_cnt);
133void vkms_crc_work_handle(struct work_struct *work);
134
78#endif /* _VKMS_DRV_H_ */ 135#endif /* _VKMS_DRV_H_ */
diff --git a/drivers/gpu/drm/vkms/vkms_gem.c b/drivers/gpu/drm/vkms/vkms_gem.c
index c7e38368602b..d04e988b4cbe 100644
--- a/drivers/gpu/drm/vkms/vkms_gem.c
+++ b/drivers/gpu/drm/vkms/vkms_gem.c
@@ -37,20 +37,22 @@ void vkms_gem_free_object(struct drm_gem_object *obj)
37 struct vkms_gem_object *gem = container_of(obj, struct vkms_gem_object, 37 struct vkms_gem_object *gem = container_of(obj, struct vkms_gem_object,
38 gem); 38 gem);
39 39
40 kvfree(gem->pages); 40 WARN_ON(gem->pages);
41 WARN_ON(gem->vaddr);
42
41 mutex_destroy(&gem->pages_lock); 43 mutex_destroy(&gem->pages_lock);
42 drm_gem_object_release(obj); 44 drm_gem_object_release(obj);
43 kfree(gem); 45 kfree(gem);
44} 46}
45 47
46int vkms_gem_fault(struct vm_fault *vmf) 48vm_fault_t vkms_gem_fault(struct vm_fault *vmf)
47{ 49{
48 struct vm_area_struct *vma = vmf->vma; 50 struct vm_area_struct *vma = vmf->vma;
49 struct vkms_gem_object *obj = vma->vm_private_data; 51 struct vkms_gem_object *obj = vma->vm_private_data;
50 unsigned long vaddr = vmf->address; 52 unsigned long vaddr = vmf->address;
51 pgoff_t page_offset; 53 pgoff_t page_offset;
52 loff_t num_pages; 54 loff_t num_pages;
53 int ret; 55 vm_fault_t ret = VM_FAULT_SIGBUS;
54 56
55 page_offset = (vaddr - vma->vm_start) >> PAGE_SHIFT; 57 page_offset = (vaddr - vma->vm_start) >> PAGE_SHIFT;
56 num_pages = DIV_ROUND_UP(obj->gem.size, PAGE_SIZE); 58 num_pages = DIV_ROUND_UP(obj->gem.size, PAGE_SIZE);
@@ -58,7 +60,6 @@ int vkms_gem_fault(struct vm_fault *vmf)
58 if (page_offset > num_pages) 60 if (page_offset > num_pages)
59 return VM_FAULT_SIGBUS; 61 return VM_FAULT_SIGBUS;
60 62
61 ret = -ENOENT;
62 mutex_lock(&obj->pages_lock); 63 mutex_lock(&obj->pages_lock);
63 if (obj->pages) { 64 if (obj->pages) {
64 get_page(obj->pages[page_offset]); 65 get_page(obj->pages[page_offset]);
@@ -177,3 +178,77 @@ unref:
177 178
178 return ret; 179 return ret;
179} 180}
181
182static struct page **_get_pages(struct vkms_gem_object *vkms_obj)
183{
184 struct drm_gem_object *gem_obj = &vkms_obj->gem;
185
186 if (!vkms_obj->pages) {
187 struct page **pages = drm_gem_get_pages(gem_obj);
188
189 if (IS_ERR(pages))
190 return pages;
191
192 if (cmpxchg(&vkms_obj->pages, NULL, pages))
193 drm_gem_put_pages(gem_obj, pages, false, true);
194 }
195
196 return vkms_obj->pages;
197}
198
199void vkms_gem_vunmap(struct drm_gem_object *obj)
200{
201 struct vkms_gem_object *vkms_obj = drm_gem_to_vkms_gem(obj);
202
203 mutex_lock(&vkms_obj->pages_lock);
204 if (vkms_obj->vmap_count < 1) {
205 WARN_ON(vkms_obj->vaddr);
206 WARN_ON(vkms_obj->pages);
207 mutex_unlock(&vkms_obj->pages_lock);
208 return;
209 }
210
211 vkms_obj->vmap_count--;
212
213 if (vkms_obj->vmap_count == 0) {
214 vunmap(vkms_obj->vaddr);
215 vkms_obj->vaddr = NULL;
216 drm_gem_put_pages(obj, vkms_obj->pages, false, true);
217 vkms_obj->pages = NULL;
218 }
219
220 mutex_unlock(&vkms_obj->pages_lock);
221}
222
223int vkms_gem_vmap(struct drm_gem_object *obj)
224{
225 struct vkms_gem_object *vkms_obj = drm_gem_to_vkms_gem(obj);
226 int ret = 0;
227
228 mutex_lock(&vkms_obj->pages_lock);
229
230 if (!vkms_obj->vaddr) {
231 unsigned int n_pages = obj->size >> PAGE_SHIFT;
232 struct page **pages = _get_pages(vkms_obj);
233
234 if (IS_ERR(pages)) {
235 ret = PTR_ERR(pages);
236 goto out;
237 }
238
239 vkms_obj->vaddr = vmap(pages, n_pages, VM_MAP, PAGE_KERNEL);
240 if (!vkms_obj->vaddr)
241 goto err_vmap;
242 }
243
244 vkms_obj->vmap_count++;
245 goto out;
246
247err_vmap:
248 ret = -ENOMEM;
249 drm_gem_put_pages(obj, vkms_obj->pages, false, true);
250 vkms_obj->pages = NULL;
251out:
252 mutex_unlock(&vkms_obj->pages_lock);
253 return ret;
254}
diff --git a/drivers/gpu/drm/vkms/vkms_plane.c b/drivers/gpu/drm/vkms/vkms_plane.c
index 9f75b1e2c1c4..c91661631c76 100644
--- a/drivers/gpu/drm/vkms/vkms_plane.c
+++ b/drivers/gpu/drm/vkms/vkms_plane.c
@@ -8,24 +8,158 @@
8 8
9#include "vkms_drv.h" 9#include "vkms_drv.h"
10#include <drm/drm_plane_helper.h> 10#include <drm/drm_plane_helper.h>
11#include <drm/drm_atomic.h>
11#include <drm/drm_atomic_helper.h> 12#include <drm/drm_atomic_helper.h>
13#include <drm/drm_gem_framebuffer_helper.h>
14
15static struct drm_plane_state *
16vkms_plane_duplicate_state(struct drm_plane *plane)
17{
18 struct vkms_plane_state *vkms_state;
19 struct vkms_crc_data *crc_data;
20
21 vkms_state = kzalloc(sizeof(*vkms_state), GFP_KERNEL);
22 if (!vkms_state)
23 return NULL;
24
25 crc_data = kzalloc(sizeof(*crc_data), GFP_KERNEL);
26 if (WARN_ON(!crc_data))
27 DRM_INFO("Couldn't allocate crc_data");
28
29 vkms_state->crc_data = crc_data;
30
31 __drm_atomic_helper_plane_duplicate_state(plane,
32 &vkms_state->base);
33
34 return &vkms_state->base;
35}
36
37static void vkms_plane_destroy_state(struct drm_plane *plane,
38 struct drm_plane_state *old_state)
39{
40 struct vkms_plane_state *vkms_state = to_vkms_plane_state(old_state);
41 struct drm_crtc *crtc = vkms_state->base.crtc;
42
43 if (crtc) {
44 /* dropping the reference we acquired in
45 * vkms_primary_plane_update()
46 */
47 if (drm_framebuffer_read_refcount(&vkms_state->crc_data->fb))
48 drm_framebuffer_put(&vkms_state->crc_data->fb);
49 }
50
51 kfree(vkms_state->crc_data);
52 vkms_state->crc_data = NULL;
53
54 __drm_atomic_helper_plane_destroy_state(old_state);
55 kfree(vkms_state);
56}
57
58static void vkms_plane_reset(struct drm_plane *plane)
59{
60 struct vkms_plane_state *vkms_state;
61
62 if (plane->state)
63 vkms_plane_destroy_state(plane, plane->state);
64
65 vkms_state = kzalloc(sizeof(*vkms_state), GFP_KERNEL);
66 if (!vkms_state) {
67 DRM_ERROR("Cannot allocate vkms_plane_state\n");
68 return;
69 }
70
71 plane->state = &vkms_state->base;
72 plane->state->plane = plane;
73}
12 74
13static const struct drm_plane_funcs vkms_plane_funcs = { 75static const struct drm_plane_funcs vkms_plane_funcs = {
14 .update_plane = drm_atomic_helper_update_plane, 76 .update_plane = drm_atomic_helper_update_plane,
15 .disable_plane = drm_atomic_helper_disable_plane, 77 .disable_plane = drm_atomic_helper_disable_plane,
16 .destroy = drm_plane_cleanup, 78 .destroy = drm_plane_cleanup,
17 .reset = drm_atomic_helper_plane_reset, 79 .reset = vkms_plane_reset,
18 .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state, 80 .atomic_duplicate_state = vkms_plane_duplicate_state,
19 .atomic_destroy_state = drm_atomic_helper_plane_destroy_state, 81 .atomic_destroy_state = vkms_plane_destroy_state,
20}; 82};
21 83
22static void vkms_primary_plane_update(struct drm_plane *plane, 84static void vkms_primary_plane_update(struct drm_plane *plane,
23 struct drm_plane_state *old_state) 85 struct drm_plane_state *old_state)
24{ 86{
87 struct vkms_plane_state *vkms_plane_state;
88 struct vkms_crc_data *crc_data;
89
90 if (!plane->state->crtc || !plane->state->fb)
91 return;
92
93 vkms_plane_state = to_vkms_plane_state(plane->state);
94 crc_data = vkms_plane_state->crc_data;
95 memcpy(&crc_data->src, &plane->state->src, sizeof(struct drm_rect));
96 memcpy(&crc_data->fb, plane->state->fb, sizeof(struct drm_framebuffer));
97 drm_framebuffer_get(&crc_data->fb);
98}
99
100static int vkms_plane_atomic_check(struct drm_plane *plane,
101 struct drm_plane_state *state)
102{
103 struct drm_crtc_state *crtc_state;
104 int ret;
105
106 if (!state->fb | !state->crtc)
107 return 0;
108
109 crtc_state = drm_atomic_get_crtc_state(state->state, state->crtc);
110 if (IS_ERR(crtc_state))
111 return PTR_ERR(crtc_state);
112
113 ret = drm_atomic_helper_check_plane_state(state, crtc_state,
114 DRM_PLANE_HELPER_NO_SCALING,
115 DRM_PLANE_HELPER_NO_SCALING,
116 false, true);
117 if (ret != 0)
118 return ret;
119
120 /* for now primary plane must be visible and full screen */
121 if (!state->visible)
122 return -EINVAL;
123
124 return 0;
125}
126
127static int vkms_prepare_fb(struct drm_plane *plane,
128 struct drm_plane_state *state)
129{
130 struct drm_gem_object *gem_obj;
131 struct vkms_gem_object *vkms_obj;
132 int ret;
133
134 if (!state->fb)
135 return 0;
136
137 gem_obj = drm_gem_fb_get_obj(state->fb, 0);
138 vkms_obj = drm_gem_to_vkms_gem(gem_obj);
139 ret = vkms_gem_vmap(gem_obj);
140 if (ret)
141 DRM_ERROR("vmap failed: %d\n", ret);
142
143 return drm_gem_fb_prepare_fb(plane, state);
144}
145
146static void vkms_cleanup_fb(struct drm_plane *plane,
147 struct drm_plane_state *old_state)
148{
149 struct drm_gem_object *gem_obj;
150
151 if (!old_state->fb)
152 return;
153
154 gem_obj = drm_gem_fb_get_obj(old_state->fb, 0);
155 vkms_gem_vunmap(gem_obj);
25} 156}
26 157
27static const struct drm_plane_helper_funcs vkms_primary_helper_funcs = { 158static const struct drm_plane_helper_funcs vkms_primary_helper_funcs = {
28 .atomic_update = vkms_primary_plane_update, 159 .atomic_update = vkms_primary_plane_update,
160 .atomic_check = vkms_plane_atomic_check,
161 .prepare_fb = vkms_prepare_fb,
162 .cleanup_fb = vkms_cleanup_fb,
29}; 163};
30 164
31struct drm_plane *vkms_plane_init(struct vkms_device *vkmsdev) 165struct drm_plane *vkms_plane_init(struct vkms_device *vkmsdev)
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
index 23beff5d8e3c..0c25bb8faf80 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
@@ -720,9 +720,7 @@ void vmw_du_plane_reset(struct drm_plane *plane)
720 return; 720 return;
721 } 721 }
722 722
723 plane->state = &vps->base; 723 __drm_atomic_helper_plane_reset(plane, &vps->base);
724 plane->state->plane = plane;
725 plane->state->rotation = DRM_MODE_ROTATE_0;
726} 724}
727 725
728 726
diff --git a/drivers/gpu/drm/xen/xen_drm_front_gem.c b/drivers/gpu/drm/xen/xen_drm_front_gem.c
index c85bfe7571cb..47ff019d3aef 100644
--- a/drivers/gpu/drm/xen/xen_drm_front_gem.c
+++ b/drivers/gpu/drm/xen/xen_drm_front_gem.c
@@ -179,7 +179,7 @@ struct sg_table *xen_drm_front_gem_get_sg_table(struct drm_gem_object *gem_obj)
179 struct xen_gem_object *xen_obj = to_xen_gem_obj(gem_obj); 179 struct xen_gem_object *xen_obj = to_xen_gem_obj(gem_obj);
180 180
181 if (!xen_obj->pages) 181 if (!xen_obj->pages)
182 return NULL; 182 return ERR_PTR(-ENOMEM);
183 183
184 return drm_prime_pages_to_sg(xen_obj->pages, xen_obj->num_pages); 184 return drm_prime_pages_to_sg(xen_obj->pages, xen_obj->num_pages);
185} 185}
diff --git a/drivers/video/fbdev/core/fbmem.c b/drivers/video/fbdev/core/fbmem.c
index 20405421a5ed..5ffadc8e681d 100644
--- a/drivers/video/fbdev/core/fbmem.c
+++ b/drivers/video/fbdev/core/fbmem.c
@@ -34,6 +34,7 @@
34#include <linux/fb.h> 34#include <linux/fb.h>
35#include <linux/fbcon.h> 35#include <linux/fbcon.h>
36#include <linux/mem_encrypt.h> 36#include <linux/mem_encrypt.h>
37#include <linux/pci.h>
37 38
38#include <asm/fb.h> 39#include <asm/fb.h>
39 40
@@ -1605,8 +1606,8 @@ static int do_remove_conflicting_framebuffers(struct apertures_struct *a,
1605 (primary && gen_aper && gen_aper->count && 1606 (primary && gen_aper && gen_aper->count &&
1606 gen_aper->ranges[0].base == VGA_FB_PHYS)) { 1607 gen_aper->ranges[0].base == VGA_FB_PHYS)) {
1607 1608
1608 printk(KERN_INFO "fb: switching to %s from %s\n", 1609 printk(KERN_INFO "fb%d: switching to %s from %s\n",
1609 name, registered_fb[i]->fix.id); 1610 i, name, registered_fb[i]->fix.id);
1610 ret = do_unregister_framebuffer(registered_fb[i]); 1611 ret = do_unregister_framebuffer(registered_fb[i]);
1611 if (ret) 1612 if (ret)
1612 return ret; 1613 return ret;
@@ -1793,20 +1794,78 @@ int unlink_framebuffer(struct fb_info *fb_info)
1793} 1794}
1794EXPORT_SYMBOL(unlink_framebuffer); 1795EXPORT_SYMBOL(unlink_framebuffer);
1795 1796
1797/**
1798 * remove_conflicting_framebuffers - remove firmware-configured framebuffers
1799 * @a: memory range, users of which are to be removed
1800 * @name: requesting driver name
1801 * @primary: also kick vga16fb if present
1802 *
1803 * This function removes framebuffer devices (initialized by firmware/bootloader)
1804 * which use memory range described by @a. If @a is NULL all such devices are
1805 * removed.
1806 */
1796int remove_conflicting_framebuffers(struct apertures_struct *a, 1807int remove_conflicting_framebuffers(struct apertures_struct *a,
1797 const char *name, bool primary) 1808 const char *name, bool primary)
1798{ 1809{
1799 int ret; 1810 int ret;
1811 bool do_free = false;
1812
1813 if (!a) {
1814 a = alloc_apertures(1);
1815 if (!a)
1816 return -ENOMEM;
1817
1818 a->ranges[0].base = 0;
1819 a->ranges[0].size = ~0;
1820 do_free = true;
1821 }
1800 1822
1801 mutex_lock(&registration_lock); 1823 mutex_lock(&registration_lock);
1802 ret = do_remove_conflicting_framebuffers(a, name, primary); 1824 ret = do_remove_conflicting_framebuffers(a, name, primary);
1803 mutex_unlock(&registration_lock); 1825 mutex_unlock(&registration_lock);
1804 1826
1827 if (do_free)
1828 kfree(a);
1829
1805 return ret; 1830 return ret;
1806} 1831}
1807EXPORT_SYMBOL(remove_conflicting_framebuffers); 1832EXPORT_SYMBOL(remove_conflicting_framebuffers);
1808 1833
1809/** 1834/**
1835 * remove_conflicting_pci_framebuffers - remove firmware-configured framebuffers for PCI devices
1836 * @pdev: PCI device
1837 * @resource_id: index of PCI BAR configuring framebuffer memory
1838 * @name: requesting driver name
1839 *
1840 * This function removes framebuffer devices (eg. initialized by firmware)
1841 * using memory range configured for @pdev's BAR @resource_id.
1842 *
1843 * The function assumes that PCI device with shadowed ROM drives a primary
1844 * display and so kicks out vga16fb.
1845 */
1846int remove_conflicting_pci_framebuffers(struct pci_dev *pdev, int res_id, const char *name)
1847{
1848 struct apertures_struct *ap;
1849 bool primary = false;
1850 int err;
1851
1852 ap = alloc_apertures(1);
1853 if (!ap)
1854 return -ENOMEM;
1855
1856 ap->ranges[0].base = pci_resource_start(pdev, res_id);
1857 ap->ranges[0].size = pci_resource_len(pdev, res_id);
1858#ifdef CONFIG_X86
1859 primary = pdev->resource[PCI_ROM_RESOURCE].flags &
1860 IORESOURCE_ROM_SHADOW;
1861#endif
1862 err = remove_conflicting_framebuffers(ap, name, primary);
1863 kfree(ap);
1864 return err;
1865}
1866EXPORT_SYMBOL(remove_conflicting_pci_framebuffers);
1867
1868/**
1810 * register_framebuffer - registers a frame buffer device 1869 * register_framebuffer - registers a frame buffer device
1811 * @fb_info: frame buffer info structure 1870 * @fb_info: frame buffer info structure
1812 * 1871 *
diff --git a/include/drm/drm_atomic_helper.h b/include/drm/drm_atomic_helper.h
index 99e2a5297c69..f4c7ed876c97 100644
--- a/include/drm/drm_atomic_helper.h
+++ b/include/drm/drm_atomic_helper.h
@@ -156,6 +156,8 @@ void __drm_atomic_helper_crtc_destroy_state(struct drm_crtc_state *state);
156void drm_atomic_helper_crtc_destroy_state(struct drm_crtc *crtc, 156void drm_atomic_helper_crtc_destroy_state(struct drm_crtc *crtc,
157 struct drm_crtc_state *state); 157 struct drm_crtc_state *state);
158 158
159void __drm_atomic_helper_plane_reset(struct drm_plane *plane,
160 struct drm_plane_state *state);
159void drm_atomic_helper_plane_reset(struct drm_plane *plane); 161void drm_atomic_helper_plane_reset(struct drm_plane *plane);
160void __drm_atomic_helper_plane_duplicate_state(struct drm_plane *plane, 162void __drm_atomic_helper_plane_duplicate_state(struct drm_plane *plane,
161 struct drm_plane_state *state); 163 struct drm_plane_state *state);
diff --git a/include/drm/drm_blend.h b/include/drm/drm_blend.h
index 330c561c4c11..88bdfec3bd88 100644
--- a/include/drm/drm_blend.h
+++ b/include/drm/drm_blend.h
@@ -27,6 +27,10 @@
27#include <linux/ctype.h> 27#include <linux/ctype.h>
28#include <drm/drm_mode.h> 28#include <drm/drm_mode.h>
29 29
30#define DRM_MODE_BLEND_PREMULTI 0
31#define DRM_MODE_BLEND_COVERAGE 1
32#define DRM_MODE_BLEND_PIXEL_NONE 2
33
30struct drm_device; 34struct drm_device;
31struct drm_atomic_state; 35struct drm_atomic_state;
32struct drm_plane; 36struct drm_plane;
@@ -52,4 +56,6 @@ int drm_plane_create_zpos_immutable_property(struct drm_plane *plane,
52 unsigned int zpos); 56 unsigned int zpos);
53int drm_atomic_normalize_zpos(struct drm_device *dev, 57int drm_atomic_normalize_zpos(struct drm_device *dev,
54 struct drm_atomic_state *state); 58 struct drm_atomic_state *state);
59int drm_plane_create_blend_mode_property(struct drm_plane *plane,
60 unsigned int supported_modes);
55#endif 61#endif
diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h
index 92e7fc7f05a4..b21437bc95bf 100644
--- a/include/drm/drm_crtc.h
+++ b/include/drm/drm_crtc.h
@@ -744,8 +744,45 @@ struct drm_crtc_funcs {
744 * 744 *
745 * 0 on success or a negative error code on failure. 745 * 0 on success or a negative error code on failure.
746 */ 746 */
747 int (*set_crc_source)(struct drm_crtc *crtc, const char *source, 747 int (*set_crc_source)(struct drm_crtc *crtc, const char *source);
748 size_t *values_cnt); 748 /**
749 * @verify_crc_source:
750 *
751 * verifies the source of CRC checksums of frames before setting the
752 * source for CRC and during crc open. Source parameter can be NULL
753 * while disabling crc source.
754 *
755 * This callback is optional if the driver does not support any CRC
756 * generation functionality.
757 *
758 * RETURNS:
759 *
760 * 0 on success or a negative error code on failure.
761 */
762 int (*verify_crc_source)(struct drm_crtc *crtc, const char *source,
763 size_t *values_cnt);
764 /**
765 * @get_crc_sources:
766 *
767 * Driver callback for getting a list of all the available sources for
768 * CRC generation. This callback depends upon verify_crc_source, So
769 * verify_crc_source callback should be implemented before implementing
770 * this. Driver can pass full list of available crc sources, this
771 * callback does the verification on each crc-source before passing it
772 * to userspace.
773 *
774 * This callback is optional if the driver does not support exporting of
775 * possible CRC sources list.
776 *
777 * RETURNS:
778 *
779 * a constant character pointer to the list of all the available CRC
780 * sources. On failure driver should return NULL. count should be
781 * updated with number of sources in list. if zero we don't process any
782 * source from the list.
783 */
784 const char *const *(*get_crc_sources)(struct drm_crtc *crtc,
785 size_t *count);
749 786
750 /** 787 /**
751 * @atomic_print_state: 788 * @atomic_print_state:
diff --git a/include/drm/drm_dp_helper.h b/include/drm/drm_dp_helper.h
index 05cc31b5db16..698082a02b97 100644
--- a/include/drm/drm_dp_helper.h
+++ b/include/drm/drm_dp_helper.h
@@ -123,8 +123,9 @@
123# define DP_FRAMING_CHANGE_CAP (1 << 1) 123# define DP_FRAMING_CHANGE_CAP (1 << 1)
124# define DP_DPCD_DISPLAY_CONTROL_CAPABLE (1 << 3) /* edp v1.2 or higher */ 124# define DP_DPCD_DISPLAY_CONTROL_CAPABLE (1 << 3) /* edp v1.2 or higher */
125 125
126#define DP_TRAINING_AUX_RD_INTERVAL 0x00e /* XXX 1.2? */ 126#define DP_TRAINING_AUX_RD_INTERVAL 0x00e /* XXX 1.2? */
127# define DP_TRAINING_AUX_RD_MASK 0x7F /* XXX 1.2? */ 127# define DP_TRAINING_AUX_RD_MASK 0x7F /* DP 1.3 */
128# define DP_EXTENDED_RECEIVER_CAP_FIELD_PRESENT (1 << 7) /* DP 1.3 */
128 129
129#define DP_ADAPTER_CAP 0x00f /* 1.2 */ 130#define DP_ADAPTER_CAP 0x00f /* 1.2 */
130# define DP_FORCE_LOAD_SENSE_CAP (1 << 0) 131# define DP_FORCE_LOAD_SENSE_CAP (1 << 0)
diff --git a/include/drm/drm_fb_cma_helper.h b/include/drm/drm_fb_cma_helper.h
index 96e26e3b9a0c..4a65f0d155b0 100644
--- a/include/drm/drm_fb_cma_helper.h
+++ b/include/drm/drm_fb_cma_helper.h
@@ -26,7 +26,6 @@ void drm_fbdev_cma_fini(struct drm_fbdev_cma *fbdev_cma);
26 26
27void drm_fbdev_cma_restore_mode(struct drm_fbdev_cma *fbdev_cma); 27void drm_fbdev_cma_restore_mode(struct drm_fbdev_cma *fbdev_cma);
28void drm_fbdev_cma_hotplug_event(struct drm_fbdev_cma *fbdev_cma); 28void drm_fbdev_cma_hotplug_event(struct drm_fbdev_cma *fbdev_cma);
29void drm_fbdev_cma_set_suspend(struct drm_fbdev_cma *fbdev_cma, bool state);
30void drm_fbdev_cma_set_suspend_unlocked(struct drm_fbdev_cma *fbdev_cma, 29void drm_fbdev_cma_set_suspend_unlocked(struct drm_fbdev_cma *fbdev_cma,
31 bool state); 30 bool state);
32 31
diff --git a/include/drm/drm_fb_helper.h b/include/drm/drm_fb_helper.h
index 5db08c8f1d25..8b6ab3200a2c 100644
--- a/include/drm/drm_fb_helper.h
+++ b/include/drm/drm_fb_helper.h
@@ -615,4 +615,16 @@ drm_fb_helper_remove_conflicting_framebuffers(struct apertures_struct *a,
615#endif 615#endif
616} 616}
617 617
618static inline int
619drm_fb_helper_remove_conflicting_pci_framebuffers(struct pci_dev *pdev,
620 int resource_id,
621 const char *name)
622{
623#if IS_REACHABLE(CONFIG_FB)
624 return remove_conflicting_pci_framebuffers(pdev, resource_id, name);
625#else
626 return 0;
627#endif
628}
629
618#endif 630#endif
diff --git a/include/drm/drm_panel.h b/include/drm/drm_panel.h
index 582a0ec0aa70..a82c292af6c5 100644
--- a/include/drm/drm_panel.h
+++ b/include/drm/drm_panel.h
@@ -82,6 +82,7 @@ struct drm_panel_funcs {
82 * @drm: DRM device owning the panel 82 * @drm: DRM device owning the panel
83 * @connector: DRM connector that the panel is attached to 83 * @connector: DRM connector that the panel is attached to
84 * @dev: parent device of the panel 84 * @dev: parent device of the panel
85 * @link: link from panel device (supplier) to DRM device (consumer)
85 * @funcs: operations that can be performed on the panel 86 * @funcs: operations that can be performed on the panel
86 * @list: panel entry in registry 87 * @list: panel entry in registry
87 */ 88 */
diff --git a/include/drm/drm_plane.h b/include/drm/drm_plane.h
index 8a152dc16ea5..16f5b66684ca 100644
--- a/include/drm/drm_plane.h
+++ b/include/drm/drm_plane.h
@@ -119,6 +119,14 @@ struct drm_plane_state {
119 u16 alpha; 119 u16 alpha;
120 120
121 /** 121 /**
122 * @pixel_blend_mode:
123 * The alpha blending equation selection, describing how the pixels from
124 * the current plane are composited with the background. Value can be
125 * one of DRM_MODE_BLEND_*
126 */
127 uint16_t pixel_blend_mode;
128
129 /**
122 * @rotation: 130 * @rotation:
123 * Rotation of the plane. See drm_plane_create_rotation_property() for 131 * Rotation of the plane. See drm_plane_create_rotation_property() for
124 * more details. 132 * more details.
@@ -659,6 +667,14 @@ struct drm_plane {
659 * drm_plane_create_rotation_property(). 667 * drm_plane_create_rotation_property().
660 */ 668 */
661 struct drm_property *rotation_property; 669 struct drm_property *rotation_property;
670 /**
671 * @blend_mode_property:
672 * Optional "pixel blend mode" enum property for this plane.
673 * Blend mode property represents the alpha blending equation selection,
674 * describing how the pixels from the current plane are composited with
675 * the background.
676 */
677 struct drm_property *blend_mode_property;
662 678
663 /** 679 /**
664 * @color_encoding_property: 680 * @color_encoding_property:
diff --git a/include/drm/drm_print.h b/include/drm/drm_print.h
index f3e6eed3e79c..afbc3beef089 100644
--- a/include/drm/drm_print.h
+++ b/include/drm/drm_print.h
@@ -381,7 +381,7 @@ void drm_err(const char *format, ...);
381 381
382#define DRM_DEV_DEBUG_DP(dev, fmt, ...) \ 382#define DRM_DEV_DEBUG_DP(dev, fmt, ...) \
383 drm_dev_dbg(dev, DRM_UT_DP, fmt, ## __VA_ARGS__) 383 drm_dev_dbg(dev, DRM_UT_DP, fmt, ## __VA_ARGS__)
384#define DRM_DEBUG_DP(dev, fmt, ...) \ 384#define DRM_DEBUG_DP(fmt, ...) \
385 drm_dbg(DRM_UT_DP, fmt, ## __VA_ARGS__) 385 drm_dbg(DRM_UT_DP, fmt, ## __VA_ARGS__)
386 386
387#define _DRM_DEV_DEFINE_DEBUG_RATELIMITED(dev, category, fmt, ...) \ 387#define _DRM_DEV_DEFINE_DEBUG_RATELIMITED(dev, category, fmt, ...) \
diff --git a/include/drm/drm_syncobj.h b/include/drm/drm_syncobj.h
index 3980602472c0..e419c79ba94d 100644
--- a/include/drm/drm_syncobj.h
+++ b/include/drm/drm_syncobj.h
@@ -131,11 +131,6 @@ drm_syncobj_fence_get(struct drm_syncobj *syncobj)
131 131
132struct drm_syncobj *drm_syncobj_find(struct drm_file *file_private, 132struct drm_syncobj *drm_syncobj_find(struct drm_file *file_private,
133 u32 handle); 133 u32 handle);
134void drm_syncobj_add_callback(struct drm_syncobj *syncobj,
135 struct drm_syncobj_cb *cb,
136 drm_syncobj_func_t func);
137void drm_syncobj_remove_callback(struct drm_syncobj *syncobj,
138 struct drm_syncobj_cb *cb);
139void drm_syncobj_replace_fence(struct drm_syncobj *syncobj, 134void drm_syncobj_replace_fence(struct drm_syncobj *syncobj,
140 struct dma_fence *fence); 135 struct dma_fence *fence);
141int drm_syncobj_find_fence(struct drm_file *file_private, 136int drm_syncobj_find_fence(struct drm_file *file_private,
diff --git a/include/linux/fb.h b/include/linux/fb.h
index 3e7e75383d32..3cd375dafd0e 100644
--- a/include/linux/fb.h
+++ b/include/linux/fb.h
@@ -632,6 +632,8 @@ extern ssize_t fb_sys_write(struct fb_info *info, const char __user *buf,
632extern int register_framebuffer(struct fb_info *fb_info); 632extern int register_framebuffer(struct fb_info *fb_info);
633extern int unregister_framebuffer(struct fb_info *fb_info); 633extern int unregister_framebuffer(struct fb_info *fb_info);
634extern int unlink_framebuffer(struct fb_info *fb_info); 634extern int unlink_framebuffer(struct fb_info *fb_info);
635extern int remove_conflicting_pci_framebuffers(struct pci_dev *pdev, int res_id,
636 const char *name);
635extern int remove_conflicting_framebuffers(struct apertures_struct *a, 637extern int remove_conflicting_framebuffers(struct apertures_struct *a,
636 const char *name, bool primary); 638 const char *name, bool primary);
637extern int fb_prepare_logo(struct fb_info *fb_info, int rotate); 639extern int fb_prepare_logo(struct fb_info *fb_info, int rotate);
diff --git a/include/uapi/drm/drm_fourcc.h b/include/uapi/drm/drm_fourcc.h
index 721ab7e54d96..2ed46e9ae16a 100644
--- a/include/uapi/drm/drm_fourcc.h
+++ b/include/uapi/drm/drm_fourcc.h
@@ -30,6 +30,42 @@
30extern "C" { 30extern "C" {
31#endif 31#endif
32 32
33/**
34 * DOC: overview
35 *
36 * In the DRM subsystem, framebuffer pixel formats are described using the
37 * fourcc codes defined in `include/uapi/drm/drm_fourcc.h`. In addition to the
38 * fourcc code, a Format Modifier may optionally be provided, in order to
39 * further describe the buffer's format - for example tiling or compression.
40 *
41 * Format Modifiers
42 * ----------------
43 *
44 * Format modifiers are used in conjunction with a fourcc code, forming a
45 * unique fourcc:modifier pair. This format:modifier pair must fully define the
46 * format and data layout of the buffer, and should be the only way to describe
47 * that particular buffer.
48 *
49 * Having multiple fourcc:modifier pairs which describe the same layout should
50 * be avoided, as such aliases run the risk of different drivers exposing
51 * different names for the same data format, forcing userspace to understand
52 * that they are aliases.
53 *
54 * Format modifiers may change any property of the buffer, including the number
55 * of planes and/or the required allocation size. Format modifiers are
56 * vendor-namespaced, and as such the relationship between a fourcc code and a
57 * modifier is specific to the modifer being used. For example, some modifiers
58 * may preserve meaning - such as number of planes - from the fourcc code,
59 * whereas others may not.
60 *
61 * Vendors should document their modifier usage in as much detail as
62 * possible, to ensure maximum compatibility across devices, drivers and
63 * applications.
64 *
65 * The authoritative list of format modifier codes is found in
66 * `include/uapi/drm/drm_fourcc.h`
67 */
68
33#define fourcc_code(a, b, c, d) ((__u32)(a) | ((__u32)(b) << 8) | \ 69#define fourcc_code(a, b, c, d) ((__u32)(a) | ((__u32)(b) << 8) | \
34 ((__u32)(c) << 16) | ((__u32)(d) << 24)) 70 ((__u32)(c) << 16) | ((__u32)(d) << 24))
35 71
diff --git a/include/uapi/linux/udmabuf.h b/include/uapi/linux/udmabuf.h
new file mode 100644
index 000000000000..46b6532ed855
--- /dev/null
+++ b/include/uapi/linux/udmabuf.h
@@ -0,0 +1,33 @@
1/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
2#ifndef _UAPI_LINUX_UDMABUF_H
3#define _UAPI_LINUX_UDMABUF_H
4
5#include <linux/types.h>
6#include <linux/ioctl.h>
7
8#define UDMABUF_FLAGS_CLOEXEC 0x01
9
10struct udmabuf_create {
11 __u32 memfd;
12 __u32 flags;
13 __u64 offset;
14 __u64 size;
15};
16
17struct udmabuf_create_item {
18 __u32 memfd;
19 __u32 __pad;
20 __u64 offset;
21 __u64 size;
22};
23
24struct udmabuf_create_list {
25 __u32 flags;
26 __u32 count;
27 struct udmabuf_create_item list[];
28};
29
30#define UDMABUF_CREATE _IOW('u', 0x42, struct udmabuf_create)
31#define UDMABUF_CREATE_LIST _IOW('u', 0x43, struct udmabuf_create_list)
32
33#endif /* _UAPI_LINUX_UDMABUF_H */
diff --git a/tools/testing/selftests/drivers/dma-buf/Makefile b/tools/testing/selftests/drivers/dma-buf/Makefile
new file mode 100644
index 000000000000..4154c3d7aa58
--- /dev/null
+++ b/tools/testing/selftests/drivers/dma-buf/Makefile
@@ -0,0 +1,5 @@
1CFLAGS += -I../../../../../usr/include/
2
3TEST_GEN_PROGS := udmabuf
4
5include ../../lib.mk
diff --git a/tools/testing/selftests/drivers/dma-buf/udmabuf.c b/tools/testing/selftests/drivers/dma-buf/udmabuf.c
new file mode 100644
index 000000000000..376b1d6730bd
--- /dev/null
+++ b/tools/testing/selftests/drivers/dma-buf/udmabuf.c
@@ -0,0 +1,96 @@
1// SPDX-License-Identifier: GPL-2.0
2#include <stdio.h>
3#include <stdlib.h>
4#include <unistd.h>
5#include <string.h>
6#include <errno.h>
7#include <fcntl.h>
8#include <malloc.h>
9
10#include <sys/ioctl.h>
11#include <sys/syscall.h>
12#include <linux/memfd.h>
13#include <linux/udmabuf.h>
14
15#define TEST_PREFIX "drivers/dma-buf/udmabuf"
16#define NUM_PAGES 4
17
18static int memfd_create(const char *name, unsigned int flags)
19{
20 return syscall(__NR_memfd_create, name, flags);
21}
22
23int main(int argc, char *argv[])
24{
25 struct udmabuf_create create;
26 int devfd, memfd, buf, ret;
27 off_t size;
28 void *mem;
29
30 devfd = open("/dev/udmabuf", O_RDWR);
31 if (devfd < 0) {
32 printf("%s: [skip,no-udmabuf]\n", TEST_PREFIX);
33 exit(77);
34 }
35
36 memfd = memfd_create("udmabuf-test", MFD_CLOEXEC);
37 if (memfd < 0) {
38 printf("%s: [skip,no-memfd]\n", TEST_PREFIX);
39 exit(77);
40 }
41
42 size = getpagesize() * NUM_PAGES;
43 ret = ftruncate(memfd, size);
44 if (ret == -1) {
45 printf("%s: [FAIL,memfd-truncate]\n", TEST_PREFIX);
46 exit(1);
47 }
48
49 memset(&create, 0, sizeof(create));
50
51 /* should fail (offset not page aligned) */
52 create.memfd = memfd;
53 create.offset = getpagesize()/2;
54 create.size = getpagesize();
55 buf = ioctl(devfd, UDMABUF_CREATE, &create);
56 if (buf >= 0) {
57 printf("%s: [FAIL,test-1]\n", TEST_PREFIX);
58 exit(1);
59 }
60
61 /* should fail (size not multiple of page) */
62 create.memfd = memfd;
63 create.offset = 0;
64 create.size = getpagesize()/2;
65 buf = ioctl(devfd, UDMABUF_CREATE, &create);
66 if (buf >= 0) {
67 printf("%s: [FAIL,test-2]\n", TEST_PREFIX);
68 exit(1);
69 }
70
71 /* should fail (not memfd) */
72 create.memfd = 0; /* stdin */
73 create.offset = 0;
74 create.size = size;
75 buf = ioctl(devfd, UDMABUF_CREATE, &create);
76 if (buf >= 0) {
77 printf("%s: [FAIL,test-3]\n", TEST_PREFIX);
78 exit(1);
79 }
80
81 /* should work */
82 create.memfd = memfd;
83 create.offset = 0;
84 create.size = size;
85 buf = ioctl(devfd, UDMABUF_CREATE, &create);
86 if (buf < 0) {
87 printf("%s: [FAIL,test-4]\n", TEST_PREFIX);
88 exit(1);
89 }
90
91 fprintf(stderr, "%s: ok\n", TEST_PREFIX);
92 close(buf);
93 close(memfd);
94 close(devfd);
95 return 0;
96}