diff options
author | Dave Airlie <airlied@redhat.com> | 2019-01-17 18:20:10 -0500 |
---|---|---|
committer | Dave Airlie <airlied@redhat.com> | 2019-01-17 18:31:28 -0500 |
commit | f164a94c2c87752caeb1a3cbe068c440e7f7921f (patch) | |
tree | e914296ef0ce1df83e506a12bf4306d5aa468b24 | |
parent | b122153c7198e35fcb981ca9efd63b0df8ef3eab (diff) | |
parent | 94520db52fc0e931327bb77fe79a952a0e9dd2b0 (diff) |
Merge tag 'drm-misc-next-2019-01-16' of git://anongit.freedesktop.org/drm/drm-misc into drm-next
drm-misc-next for 5.1:
UAPI Changes:
- New fourcc identifier for ARM Framebuffer Compression v1.3
Cross-subsystem Changes:
Core Changes:
- Reorganisation of drm_device and drm_framebuffer headers
- Cleanup of the drmP inclusion
- Fix leaks in the fb-helpers
- Allow for depth different from bpp in fb-helper fbdev emulation
- Remove drm_mode_object from drm_display_mode
Driver Changes:
- Add reflection properties to rockchip
- a bunch of fixes for virtio
- a bunch of fixes for dp_mst and drivers using it, and introduction of a
new refcounting scheme
- Convertion of bochs to atomic and generic fbdev emulation
- Allow meson to remove the firmware framebuffers
[airlied: patch rcar-du to add drm_modes.h]
Signed-off-by: Dave Airlie <airlied@redhat.com>
From: Maxime Ripard <maxime.ripard@bootlin.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20190116200428.u2n4jbk4mzza7n6e@flea
160 files changed, 3490 insertions, 1507 deletions
diff --git a/Documentation/devicetree/bindings/display/panel/auo,g101evn010 b/Documentation/devicetree/bindings/display/panel/auo,g101evn010.txt index bc6a0c858e23..bc6a0c858e23 100644 --- a/Documentation/devicetree/bindings/display/panel/auo,g101evn010 +++ b/Documentation/devicetree/bindings/display/panel/auo,g101evn010.txt | |||
diff --git a/Documentation/devicetree/bindings/display/rockchip/rockchip-vop.txt b/Documentation/devicetree/bindings/display/rockchip/rockchip-vop.txt index b79e5769f0ae..4f58c5a2d195 100644 --- a/Documentation/devicetree/bindings/display/rockchip/rockchip-vop.txt +++ b/Documentation/devicetree/bindings/display/rockchip/rockchip-vop.txt | |||
@@ -10,6 +10,7 @@ Required properties: | |||
10 | "rockchip,rk3126-vop"; | 10 | "rockchip,rk3126-vop"; |
11 | "rockchip,px30-vop-lit"; | 11 | "rockchip,px30-vop-lit"; |
12 | "rockchip,px30-vop-big"; | 12 | "rockchip,px30-vop-big"; |
13 | "rockchip,rk3066-vop"; | ||
13 | "rockchip,rk3188-vop"; | 14 | "rockchip,rk3188-vop"; |
14 | "rockchip,rk3288-vop"; | 15 | "rockchip,rk3288-vop"; |
15 | "rockchip,rk3368-vop"; | 16 | "rockchip,rk3368-vop"; |
diff --git a/Documentation/gpu/dp-mst/topology-figure-1.dot b/Documentation/gpu/dp-mst/topology-figure-1.dot new file mode 100644 index 000000000000..157e17c7e0b0 --- /dev/null +++ b/Documentation/gpu/dp-mst/topology-figure-1.dot | |||
@@ -0,0 +1,52 @@ | |||
1 | digraph T { | ||
2 | /* Make sure our payloads are always drawn below the driver node */ | ||
3 | subgraph cluster_driver { | ||
4 | fillcolor = grey; | ||
5 | style = filled; | ||
6 | driver -> {payload1, payload2} [dir=none]; | ||
7 | } | ||
8 | |||
9 | /* Driver malloc references */ | ||
10 | edge [style=dashed]; | ||
11 | driver -> port1; | ||
12 | driver -> port2; | ||
13 | driver -> port3:e; | ||
14 | driver -> port4; | ||
15 | |||
16 | payload1:s -> port1:e; | ||
17 | payload2:s -> port3:e; | ||
18 | edge [style=""]; | ||
19 | |||
20 | subgraph cluster_topology { | ||
21 | label="Topology Manager"; | ||
22 | labelloc=bottom; | ||
23 | |||
24 | /* Topology references */ | ||
25 | mstb1 -> {port1, port2}; | ||
26 | port1 -> mstb2; | ||
27 | port2 -> mstb3 -> {port3, port4}; | ||
28 | port3 -> mstb4; | ||
29 | |||
30 | /* Malloc references */ | ||
31 | edge [style=dashed;dir=back]; | ||
32 | mstb1 -> {port1, port2}; | ||
33 | port1 -> mstb2; | ||
34 | port2 -> mstb3 -> {port3, port4}; | ||
35 | port3 -> mstb4; | ||
36 | } | ||
37 | |||
38 | driver [label="DRM driver";style=filled;shape=box;fillcolor=lightblue]; | ||
39 | |||
40 | payload1 [label="Payload #1";style=filled;shape=box;fillcolor=lightblue]; | ||
41 | payload2 [label="Payload #2";style=filled;shape=box;fillcolor=lightblue]; | ||
42 | |||
43 | mstb1 [label="MSTB #1";style=filled;fillcolor=palegreen;shape=oval]; | ||
44 | mstb2 [label="MSTB #2";style=filled;fillcolor=palegreen;shape=oval]; | ||
45 | mstb3 [label="MSTB #3";style=filled;fillcolor=palegreen;shape=oval]; | ||
46 | mstb4 [label="MSTB #4";style=filled;fillcolor=palegreen;shape=oval]; | ||
47 | |||
48 | port1 [label="Port #1";shape=oval]; | ||
49 | port2 [label="Port #2";shape=oval]; | ||
50 | port3 [label="Port #3";shape=oval]; | ||
51 | port4 [label="Port #4";shape=oval]; | ||
52 | } | ||
diff --git a/Documentation/gpu/dp-mst/topology-figure-2.dot b/Documentation/gpu/dp-mst/topology-figure-2.dot new file mode 100644 index 000000000000..4243dd1737cb --- /dev/null +++ b/Documentation/gpu/dp-mst/topology-figure-2.dot | |||
@@ -0,0 +1,56 @@ | |||
1 | digraph T { | ||
2 | /* Make sure our payloads are always drawn below the driver node */ | ||
3 | subgraph cluster_driver { | ||
4 | fillcolor = grey; | ||
5 | style = filled; | ||
6 | driver -> {payload1, payload2} [dir=none]; | ||
7 | } | ||
8 | |||
9 | /* Driver malloc references */ | ||
10 | edge [style=dashed]; | ||
11 | driver -> port1; | ||
12 | driver -> port2; | ||
13 | driver -> port3:e; | ||
14 | driver -> port4 [color=red]; | ||
15 | |||
16 | payload1:s -> port1:e; | ||
17 | payload2:s -> port3:e; | ||
18 | edge [style=""]; | ||
19 | |||
20 | subgraph cluster_topology { | ||
21 | label="Topology Manager"; | ||
22 | labelloc=bottom; | ||
23 | |||
24 | /* Topology references */ | ||
25 | mstb1 -> {port1, port2}; | ||
26 | port1 -> mstb2; | ||
27 | edge [color=red]; | ||
28 | port2 -> mstb3 -> {port3, port4}; | ||
29 | port3 -> mstb4; | ||
30 | edge [color=""]; | ||
31 | |||
32 | /* Malloc references */ | ||
33 | edge [style=dashed;dir=back]; | ||
34 | mstb1 -> {port1, port2}; | ||
35 | port1 -> mstb2; | ||
36 | port2 -> mstb3 -> port3; | ||
37 | edge [color=red]; | ||
38 | mstb3 -> port4; | ||
39 | port3 -> mstb4; | ||
40 | } | ||
41 | |||
42 | mstb1 [label="MSTB #1";style=filled;fillcolor=palegreen]; | ||
43 | mstb2 [label="MSTB #2";style=filled;fillcolor=palegreen]; | ||
44 | mstb3 [label="MSTB #3";style=filled;fillcolor=palegreen]; | ||
45 | mstb4 [label="MSTB #4";style=filled;fillcolor=grey]; | ||
46 | |||
47 | port1 [label="Port #1"]; | ||
48 | port2 [label="Port #2"]; | ||
49 | port3 [label="Port #3"]; | ||
50 | port4 [label="Port #4";style=filled;fillcolor=grey]; | ||
51 | |||
52 | driver [label="DRM driver";style=filled;shape=box;fillcolor=lightblue]; | ||
53 | |||
54 | payload1 [label="Payload #1";style=filled;shape=box;fillcolor=lightblue]; | ||
55 | payload2 [label="Payload #2";style=filled;shape=box;fillcolor=lightblue]; | ||
56 | } | ||
diff --git a/Documentation/gpu/dp-mst/topology-figure-3.dot b/Documentation/gpu/dp-mst/topology-figure-3.dot new file mode 100644 index 000000000000..6cd78d06778b --- /dev/null +++ b/Documentation/gpu/dp-mst/topology-figure-3.dot | |||
@@ -0,0 +1,59 @@ | |||
1 | digraph T { | ||
2 | /* Make sure our payloads are always drawn below the driver node */ | ||
3 | subgraph cluster_driver { | ||
4 | fillcolor = grey; | ||
5 | style = filled; | ||
6 | edge [dir=none]; | ||
7 | driver -> payload1; | ||
8 | driver -> payload2 [penwidth=3]; | ||
9 | edge [dir=""]; | ||
10 | } | ||
11 | |||
12 | /* Driver malloc references */ | ||
13 | edge [style=dashed]; | ||
14 | driver -> port1; | ||
15 | driver -> port2; | ||
16 | driver -> port3:e; | ||
17 | driver -> port4 [color=grey]; | ||
18 | payload1:s -> port1:e; | ||
19 | payload2:s -> port3:e [penwidth=3]; | ||
20 | edge [style=""]; | ||
21 | |||
22 | subgraph cluster_topology { | ||
23 | label="Topology Manager"; | ||
24 | labelloc=bottom; | ||
25 | |||
26 | /* Topology references */ | ||
27 | mstb1 -> {port1, port2}; | ||
28 | port1 -> mstb2; | ||
29 | edge [color=grey]; | ||
30 | port2 -> mstb3 -> {port3, port4}; | ||
31 | port3 -> mstb4; | ||
32 | edge [color=""]; | ||
33 | |||
34 | /* Malloc references */ | ||
35 | edge [style=dashed;dir=back]; | ||
36 | mstb1 -> {port1, port2}; | ||
37 | port1 -> mstb2; | ||
38 | port2 -> mstb3 [penwidth=3]; | ||
39 | mstb3 -> port3 [penwidth=3]; | ||
40 | edge [color=grey]; | ||
41 | mstb3 -> port4; | ||
42 | port3 -> mstb4; | ||
43 | } | ||
44 | |||
45 | mstb1 [label="MSTB #1";style=filled;fillcolor=palegreen]; | ||
46 | mstb2 [label="MSTB #2";style=filled;fillcolor=palegreen]; | ||
47 | mstb3 [label="MSTB #3";style=filled;fillcolor=palegreen;penwidth=3]; | ||
48 | mstb4 [label="MSTB #4";style=filled;fillcolor=grey]; | ||
49 | |||
50 | port1 [label="Port #1"]; | ||
51 | port2 [label="Port #2";penwidth=5]; | ||
52 | port3 [label="Port #3";penwidth=3]; | ||
53 | port4 [label="Port #4";style=filled;fillcolor=grey]; | ||
54 | |||
55 | driver [label="DRM driver";style=filled;shape=box;fillcolor=lightblue]; | ||
56 | |||
57 | payload1 [label="Payload #1";style=filled;shape=box;fillcolor=lightblue]; | ||
58 | payload2 [label="Payload #2";style=filled;shape=box;fillcolor=lightblue;penwidth=3]; | ||
59 | } | ||
diff --git a/Documentation/gpu/drm-internals.rst b/Documentation/gpu/drm-internals.rst index 5ee9674fb9e9..2caf21effd28 100644 --- a/Documentation/gpu/drm-internals.rst +++ b/Documentation/gpu/drm-internals.rst | |||
@@ -143,6 +143,9 @@ Device Instance and Driver Handling | |||
143 | .. kernel-doc:: drivers/gpu/drm/drm_drv.c | 143 | .. kernel-doc:: drivers/gpu/drm/drm_drv.c |
144 | :doc: driver instance overview | 144 | :doc: driver instance overview |
145 | 145 | ||
146 | .. kernel-doc:: include/drm/drm_device.h | ||
147 | :internal: | ||
148 | |||
146 | .. kernel-doc:: include/drm/drm_drv.h | 149 | .. kernel-doc:: include/drm/drm_drv.h |
147 | :internal: | 150 | :internal: |
148 | 151 | ||
@@ -230,6 +233,15 @@ Printer | |||
230 | .. kernel-doc:: drivers/gpu/drm/drm_print.c | 233 | .. kernel-doc:: drivers/gpu/drm/drm_print.c |
231 | :export: | 234 | :export: |
232 | 235 | ||
236 | Utilities | ||
237 | --------- | ||
238 | |||
239 | .. kernel-doc:: include/drm/drm_util.h | ||
240 | :doc: drm utils | ||
241 | |||
242 | .. kernel-doc:: include/drm/drm_util.h | ||
243 | :internal: | ||
244 | |||
233 | 245 | ||
234 | Legacy Support Code | 246 | Legacy Support Code |
235 | =================== | 247 | =================== |
diff --git a/Documentation/gpu/drm-kms-helpers.rst b/Documentation/gpu/drm-kms-helpers.rst index b422eb8edf16..fbd11b2fe5b5 100644 --- a/Documentation/gpu/drm-kms-helpers.rst +++ b/Documentation/gpu/drm-kms-helpers.rst | |||
@@ -116,8 +116,6 @@ Framebuffer CMA Helper Functions Reference | |||
116 | .. kernel-doc:: drivers/gpu/drm/drm_fb_cma_helper.c | 116 | .. kernel-doc:: drivers/gpu/drm/drm_fb_cma_helper.c |
117 | :export: | 117 | :export: |
118 | 118 | ||
119 | .. _drm_bridges: | ||
120 | |||
121 | Framebuffer GEM Helper Reference | 119 | Framebuffer GEM Helper Reference |
122 | ================================ | 120 | ================================ |
123 | 121 | ||
@@ -127,6 +125,8 @@ Framebuffer GEM Helper Reference | |||
127 | .. kernel-doc:: drivers/gpu/drm/drm_gem_framebuffer_helper.c | 125 | .. kernel-doc:: drivers/gpu/drm/drm_gem_framebuffer_helper.c |
128 | :export: | 126 | :export: |
129 | 127 | ||
128 | .. _drm_bridges: | ||
129 | |||
130 | Bridges | 130 | Bridges |
131 | ======= | 131 | ======= |
132 | 132 | ||
@@ -208,18 +208,40 @@ Display Port Dual Mode Adaptor Helper Functions Reference | |||
208 | .. kernel-doc:: drivers/gpu/drm/drm_dp_dual_mode_helper.c | 208 | .. kernel-doc:: drivers/gpu/drm/drm_dp_dual_mode_helper.c |
209 | :export: | 209 | :export: |
210 | 210 | ||
211 | Display Port MST Helper Functions Reference | 211 | Display Port MST Helpers |
212 | =========================================== | 212 | ======================== |
213 | |||
214 | Overview | ||
215 | -------- | ||
213 | 216 | ||
214 | .. kernel-doc:: drivers/gpu/drm/drm_dp_mst_topology.c | 217 | .. kernel-doc:: drivers/gpu/drm/drm_dp_mst_topology.c |
215 | :doc: dp mst helper | 218 | :doc: dp mst helper |
216 | 219 | ||
220 | .. kernel-doc:: drivers/gpu/drm/drm_dp_mst_topology.c | ||
221 | :doc: Branch device and port refcounting | ||
222 | |||
223 | Functions Reference | ||
224 | ------------------- | ||
225 | |||
217 | .. kernel-doc:: include/drm/drm_dp_mst_helper.h | 226 | .. kernel-doc:: include/drm/drm_dp_mst_helper.h |
218 | :internal: | 227 | :internal: |
219 | 228 | ||
220 | .. kernel-doc:: drivers/gpu/drm/drm_dp_mst_topology.c | 229 | .. kernel-doc:: drivers/gpu/drm/drm_dp_mst_topology.c |
221 | :export: | 230 | :export: |
222 | 231 | ||
232 | Topology Lifetime Internals | ||
233 | --------------------------- | ||
234 | |||
235 | These functions aren't exported to drivers, but are documented here to help make | ||
236 | the MST topology helpers easier to understand | ||
237 | |||
238 | .. kernel-doc:: drivers/gpu/drm/drm_dp_mst_topology.c | ||
239 | :functions: drm_dp_mst_topology_try_get_mstb drm_dp_mst_topology_get_mstb | ||
240 | drm_dp_mst_topology_put_mstb | ||
241 | drm_dp_mst_topology_try_get_port drm_dp_mst_topology_get_port | ||
242 | drm_dp_mst_topology_put_port | ||
243 | drm_dp_mst_get_mstb_malloc drm_dp_mst_put_mstb_malloc | ||
244 | |||
223 | MIPI DSI Helper Functions Reference | 245 | MIPI DSI Helper Functions Reference |
224 | =================================== | 246 | =================================== |
225 | 247 | ||
diff --git a/Documentation/gpu/todo.rst b/Documentation/gpu/todo.rst index 41da7b06195c..0a85dad876ae 100644 --- a/Documentation/gpu/todo.rst +++ b/Documentation/gpu/todo.rst | |||
@@ -209,6 +209,36 @@ Would be great to refactor this all into a set of small common helpers. | |||
209 | 209 | ||
210 | Contact: Daniel Vetter | 210 | Contact: Daniel Vetter |
211 | 211 | ||
212 | Generic fbdev defio support | ||
213 | --------------------------- | ||
214 | |||
215 | The defio support code in the fbdev core has some very specific requirements, | ||
216 | which means drivers need to have a special framebuffer for fbdev. Which prevents | ||
217 | us from using the generic fbdev emulation code everywhere. The main issue is | ||
218 | that it uses some fields in struct page itself, which breaks shmem gem objects | ||
219 | (and other things). | ||
220 | |||
221 | Possible solution would be to write our own defio mmap code in the drm fbdev | ||
222 | emulation. It would need to fully wrap the existing mmap ops, forwarding | ||
223 | everything after it has done the write-protect/mkwrite trickery: | ||
224 | |||
225 | - In the drm_fbdev_fb_mmap helper, if we need defio, change the | ||
226 | default page prots to write-protected with something like this:: | ||
227 | |||
228 | vma->vm_page_prot = pgprot_wrprotect(vma->vm_page_prot); | ||
229 | |||
230 | - Set the mkwrite and fsync callbacks with similar implementions to the core | ||
231 | fbdev defio stuff. These should all work on plain ptes, they don't actually | ||
232 | require a struct page. uff. These should all work on plain ptes, they don't | ||
233 | actually require a struct page. | ||
234 | |||
235 | - Track the dirty pages in a separate structure (bitfield with one bit per page | ||
236 | should work) to avoid clobbering struct page. | ||
237 | |||
238 | Might be good to also have some igt testcases for this. | ||
239 | |||
240 | Contact: Daniel Vetter, Noralf Tronnes | ||
241 | |||
212 | Put a reservation_object into drm_gem_object | 242 | Put a reservation_object into drm_gem_object |
213 | -------------------------------------------- | 243 | -------------------------------------------- |
214 | 244 | ||
diff --git a/MAINTAINERS b/MAINTAINERS index 6b510ef800f6..6e1cef2f21d9 100644 --- a/MAINTAINERS +++ b/MAINTAINERS | |||
@@ -4910,6 +4910,13 @@ DRM DRIVER FOR TDFX VIDEO CARDS | |||
4910 | S: Orphan / Obsolete | 4910 | S: Orphan / Obsolete |
4911 | F: drivers/gpu/drm/tdfx/ | 4911 | F: drivers/gpu/drm/tdfx/ |
4912 | 4912 | ||
4913 | DRM DRIVER FOR TPO TPG110 PANELS | ||
4914 | M: Linus Walleij <linus.walleij@linaro.org> | ||
4915 | T: git git://anongit.freedesktop.org/drm/drm-misc | ||
4916 | S: Maintained | ||
4917 | F: drivers/gpu/drm/panel/panel-tpo-tpg110.c | ||
4918 | F: Documentation/devicetree/bindings/display/panel/tpo,tpg110.txt | ||
4919 | |||
4913 | DRM DRIVER FOR USB DISPLAYLINK VIDEO ADAPTERS | 4920 | DRM DRIVER FOR USB DISPLAYLINK VIDEO ADAPTERS |
4914 | M: Dave Airlie <airlied@redhat.com> | 4921 | M: Dave Airlie <airlied@redhat.com> |
4915 | R: Sean Paul <sean@poorly.run> | 4922 | R: Sean Paul <sean@poorly.run> |
@@ -4918,6 +4925,16 @@ S: Odd Fixes | |||
4918 | F: drivers/gpu/drm/udl/ | 4925 | F: drivers/gpu/drm/udl/ |
4919 | T: git git://anongit.freedesktop.org/drm/drm-misc | 4926 | T: git git://anongit.freedesktop.org/drm/drm-misc |
4920 | 4927 | ||
4928 | DRM DRIVER FOR VIRTUAL KERNEL MODESETTING (VKMS) | ||
4929 | M: Rodrigo Siqueira <rodrigosiqueiramelo@gmail.com> | ||
4930 | R: Haneen Mohammed <hamohammed.sa@gmail.com> | ||
4931 | R: Daniel Vetter <daniel@ffwll.ch> | ||
4932 | T: git git://anongit.freedesktop.org/drm/drm-misc | ||
4933 | S: Maintained | ||
4934 | L: dri-devel@lists.freedesktop.org | ||
4935 | F: drivers/gpu/drm/vkms/ | ||
4936 | F: Documentation/gpu/vkms.rst | ||
4937 | |||
4921 | DRM DRIVER FOR VMWARE VIRTUAL GPU | 4938 | DRM DRIVER FOR VMWARE VIRTUAL GPU |
4922 | M: "VMware Graphics" <linux-graphics-maintainer@vmware.com> | 4939 | M: "VMware Graphics" <linux-graphics-maintainer@vmware.com> |
4923 | M: Thomas Hellstrom <thellstrom@vmware.com> | 4940 | M: Thomas Hellstrom <thellstrom@vmware.com> |
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c index 8a078f4ae73d..28bccceaa363 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c | |||
@@ -2708,7 +2708,7 @@ void amdgpu_device_fini(struct amdgpu_device *adev) | |||
2708 | amdgpu_irq_disable_all(adev); | 2708 | amdgpu_irq_disable_all(adev); |
2709 | if (adev->mode_info.mode_config_initialized){ | 2709 | if (adev->mode_info.mode_config_initialized){ |
2710 | if (!amdgpu_device_has_dc_support(adev)) | 2710 | if (!amdgpu_device_has_dc_support(adev)) |
2711 | drm_crtc_force_disable_all(adev->ddev); | 2711 | drm_helper_force_disable_all(adev->ddev); |
2712 | else | 2712 | else |
2713 | drm_atomic_helper_shutdown(adev->ddev); | 2713 | drm_atomic_helper_shutdown(adev->ddev); |
2714 | } | 2714 | } |
diff --git a/drivers/gpu/drm/amd/amdgpu/atom.c b/drivers/gpu/drm/amd/amdgpu/atom.c index e9934de1b9cf..dd30f4e61a8c 100644 --- a/drivers/gpu/drm/amd/amdgpu/atom.c +++ b/drivers/gpu/drm/amd/amdgpu/atom.c | |||
@@ -27,6 +27,8 @@ | |||
27 | #include <linux/slab.h> | 27 | #include <linux/slab.h> |
28 | #include <asm/unaligned.h> | 28 | #include <asm/unaligned.h> |
29 | 29 | ||
30 | #include <drm/drm_util.h> | ||
31 | |||
30 | #define ATOM_DEBUG | 32 | #define ATOM_DEBUG |
31 | 33 | ||
32 | #include "atom.h" | 34 | #include "atom.h" |
diff --git a/drivers/gpu/drm/amd/amdgpu/dce_v10_0.c b/drivers/gpu/drm/amd/amdgpu/dce_v10_0.c index 4cfecdce29a3..1f0426d2fc2a 100644 --- a/drivers/gpu/drm/amd/amdgpu/dce_v10_0.c +++ b/drivers/gpu/drm/amd/amdgpu/dce_v10_0.c | |||
@@ -1682,7 +1682,7 @@ static void dce_v10_0_afmt_setmode(struct drm_encoder *encoder, | |||
1682 | dce_v10_0_audio_write_sad_regs(encoder); | 1682 | dce_v10_0_audio_write_sad_regs(encoder); |
1683 | dce_v10_0_audio_write_latency_fields(encoder, mode); | 1683 | dce_v10_0_audio_write_latency_fields(encoder, mode); |
1684 | 1684 | ||
1685 | err = drm_hdmi_avi_infoframe_from_display_mode(&frame, mode, false); | 1685 | err = drm_hdmi_avi_infoframe_from_display_mode(&frame, connector, mode); |
1686 | if (err < 0) { | 1686 | if (err < 0) { |
1687 | DRM_ERROR("failed to setup AVI infoframe: %zd\n", err); | 1687 | DRM_ERROR("failed to setup AVI infoframe: %zd\n", err); |
1688 | return; | 1688 | return; |
diff --git a/drivers/gpu/drm/amd/amdgpu/dce_v11_0.c b/drivers/gpu/drm/amd/amdgpu/dce_v11_0.c index 7c868916d90f..2280b971d758 100644 --- a/drivers/gpu/drm/amd/amdgpu/dce_v11_0.c +++ b/drivers/gpu/drm/amd/amdgpu/dce_v11_0.c | |||
@@ -1724,7 +1724,7 @@ static void dce_v11_0_afmt_setmode(struct drm_encoder *encoder, | |||
1724 | dce_v11_0_audio_write_sad_regs(encoder); | 1724 | dce_v11_0_audio_write_sad_regs(encoder); |
1725 | dce_v11_0_audio_write_latency_fields(encoder, mode); | 1725 | dce_v11_0_audio_write_latency_fields(encoder, mode); |
1726 | 1726 | ||
1727 | err = drm_hdmi_avi_infoframe_from_display_mode(&frame, mode, false); | 1727 | err = drm_hdmi_avi_infoframe_from_display_mode(&frame, connector, mode); |
1728 | if (err < 0) { | 1728 | if (err < 0) { |
1729 | DRM_ERROR("failed to setup AVI infoframe: %zd\n", err); | 1729 | DRM_ERROR("failed to setup AVI infoframe: %zd\n", err); |
1730 | return; | 1730 | return; |
diff --git a/drivers/gpu/drm/amd/amdgpu/dce_v6_0.c b/drivers/gpu/drm/amd/amdgpu/dce_v6_0.c index 17eaaba36017..db443ec53d3a 100644 --- a/drivers/gpu/drm/amd/amdgpu/dce_v6_0.c +++ b/drivers/gpu/drm/amd/amdgpu/dce_v6_0.c | |||
@@ -1423,6 +1423,7 @@ static void dce_v6_0_audio_set_avi_infoframe(struct drm_encoder *encoder, | |||
1423 | struct amdgpu_device *adev = dev->dev_private; | 1423 | struct amdgpu_device *adev = dev->dev_private; |
1424 | struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder); | 1424 | struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder); |
1425 | struct amdgpu_encoder_atom_dig *dig = amdgpu_encoder->enc_priv; | 1425 | struct amdgpu_encoder_atom_dig *dig = amdgpu_encoder->enc_priv; |
1426 | struct drm_connector *connector = amdgpu_get_connector_for_encoder(encoder); | ||
1426 | struct hdmi_avi_infoframe frame; | 1427 | struct hdmi_avi_infoframe frame; |
1427 | u8 buffer[HDMI_INFOFRAME_HEADER_SIZE + HDMI_AVI_INFOFRAME_SIZE]; | 1428 | u8 buffer[HDMI_INFOFRAME_HEADER_SIZE + HDMI_AVI_INFOFRAME_SIZE]; |
1428 | uint8_t *payload = buffer + 3; | 1429 | uint8_t *payload = buffer + 3; |
@@ -1430,7 +1431,7 @@ static void dce_v6_0_audio_set_avi_infoframe(struct drm_encoder *encoder, | |||
1430 | ssize_t err; | 1431 | ssize_t err; |
1431 | u32 tmp; | 1432 | u32 tmp; |
1432 | 1433 | ||
1433 | err = drm_hdmi_avi_infoframe_from_display_mode(&frame, mode, false); | 1434 | err = drm_hdmi_avi_infoframe_from_display_mode(&frame, connector, mode); |
1434 | if (err < 0) { | 1435 | if (err < 0) { |
1435 | DRM_ERROR("failed to setup AVI infoframe: %zd\n", err); | 1436 | DRM_ERROR("failed to setup AVI infoframe: %zd\n", err); |
1436 | return; | 1437 | return; |
diff --git a/drivers/gpu/drm/amd/amdgpu/dce_v8_0.c b/drivers/gpu/drm/amd/amdgpu/dce_v8_0.c index 8c0576978d36..13da915991dd 100644 --- a/drivers/gpu/drm/amd/amdgpu/dce_v8_0.c +++ b/drivers/gpu/drm/amd/amdgpu/dce_v8_0.c | |||
@@ -1616,7 +1616,7 @@ static void dce_v8_0_afmt_setmode(struct drm_encoder *encoder, | |||
1616 | dce_v8_0_audio_write_sad_regs(encoder); | 1616 | dce_v8_0_audio_write_sad_regs(encoder); |
1617 | dce_v8_0_audio_write_latency_fields(encoder, mode); | 1617 | dce_v8_0_audio_write_latency_fields(encoder, mode); |
1618 | 1618 | ||
1619 | err = drm_hdmi_avi_infoframe_from_display_mode(&frame, mode, false); | 1619 | err = drm_hdmi_avi_infoframe_from_display_mode(&frame, connector, mode); |
1620 | if (err < 0) { | 1620 | if (err < 0) { |
1621 | DRM_ERROR("failed to setup AVI infoframe: %zd\n", err); | 1621 | DRM_ERROR("failed to setup AVI infoframe: %zd\n", err); |
1622 | return; | 1622 | return; |
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 5e7ca1f3a8d1..24632727e127 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 | |||
@@ -191,6 +191,7 @@ dm_dp_mst_connector_destroy(struct drm_connector *connector) | |||
191 | drm_encoder_cleanup(&amdgpu_encoder->base); | 191 | drm_encoder_cleanup(&amdgpu_encoder->base); |
192 | kfree(amdgpu_encoder); | 192 | kfree(amdgpu_encoder); |
193 | drm_connector_cleanup(connector); | 193 | drm_connector_cleanup(connector); |
194 | drm_dp_mst_put_port_malloc(amdgpu_dm_connector->port); | ||
194 | kfree(amdgpu_dm_connector); | 195 | kfree(amdgpu_dm_connector); |
195 | } | 196 | } |
196 | 197 | ||
@@ -363,7 +364,9 @@ dm_dp_add_mst_connector(struct drm_dp_mst_topology_mgr *mgr, | |||
363 | amdgpu_dm_connector_funcs_reset(connector); | 364 | amdgpu_dm_connector_funcs_reset(connector); |
364 | 365 | ||
365 | DRM_INFO("DM_MST: added connector: %p [id: %d] [master: %p]\n", | 366 | DRM_INFO("DM_MST: added connector: %p [id: %d] [master: %p]\n", |
366 | aconnector, connector->base.id, aconnector->mst_port); | 367 | aconnector, connector->base.id, aconnector->mst_port); |
368 | |||
369 | drm_dp_mst_get_port_malloc(port); | ||
367 | 370 | ||
368 | DRM_DEBUG_KMS(":%d\n", connector->base.id); | 371 | DRM_DEBUG_KMS(":%d\n", connector->base.id); |
369 | 372 | ||
@@ -379,12 +382,12 @@ static void dm_dp_destroy_mst_connector(struct drm_dp_mst_topology_mgr *mgr, | |||
379 | struct amdgpu_dm_connector *aconnector = to_amdgpu_dm_connector(connector); | 382 | struct amdgpu_dm_connector *aconnector = to_amdgpu_dm_connector(connector); |
380 | 383 | ||
381 | DRM_INFO("DM_MST: Disabling connector: %p [id: %d] [master: %p]\n", | 384 | DRM_INFO("DM_MST: Disabling connector: %p [id: %d] [master: %p]\n", |
382 | aconnector, connector->base.id, aconnector->mst_port); | 385 | aconnector, connector->base.id, aconnector->mst_port); |
383 | 386 | ||
384 | aconnector->port = NULL; | ||
385 | if (aconnector->dc_sink) { | 387 | if (aconnector->dc_sink) { |
386 | amdgpu_dm_update_freesync_caps(connector, NULL); | 388 | amdgpu_dm_update_freesync_caps(connector, NULL); |
387 | dc_link_remove_remote_sink(aconnector->dc_link, aconnector->dc_sink); | 389 | dc_link_remove_remote_sink(aconnector->dc_link, |
390 | aconnector->dc_sink); | ||
388 | dc_sink_release(aconnector->dc_sink); | 391 | dc_sink_release(aconnector->dc_sink); |
389 | aconnector->dc_sink = NULL; | 392 | aconnector->dc_sink = NULL; |
390 | } | 393 | } |
diff --git a/drivers/gpu/drm/arc/arcpgu_crtc.c b/drivers/gpu/drm/arc/arcpgu_crtc.c index 62f51f70606d..155ab177ce0b 100644 --- a/drivers/gpu/drm/arc/arcpgu_crtc.c +++ b/drivers/gpu/drm/arc/arcpgu_crtc.c | |||
@@ -16,8 +16,10 @@ | |||
16 | 16 | ||
17 | #include <drm/drm_atomic_helper.h> | 17 | #include <drm/drm_atomic_helper.h> |
18 | #include <drm/drm_crtc_helper.h> | 18 | #include <drm/drm_crtc_helper.h> |
19 | #include <drm/drm_device.h> | ||
19 | #include <drm/drm_fb_cma_helper.h> | 20 | #include <drm/drm_fb_cma_helper.h> |
20 | #include <drm/drm_gem_cma_helper.h> | 21 | #include <drm/drm_gem_cma_helper.h> |
22 | #include <drm/drm_vblank.h> | ||
21 | #include <drm/drm_plane_helper.h> | 23 | #include <drm/drm_plane_helper.h> |
22 | #include <linux/clk.h> | 24 | #include <linux/clk.h> |
23 | #include <linux/platform_data/simplefb.h> | 25 | #include <linux/platform_data/simplefb.h> |
diff --git a/drivers/gpu/drm/arc/arcpgu_drv.c b/drivers/gpu/drm/arc/arcpgu_drv.c index 206a76abf771..39a79f5718c4 100644 --- a/drivers/gpu/drm/arc/arcpgu_drv.c +++ b/drivers/gpu/drm/arc/arcpgu_drv.c | |||
@@ -16,12 +16,18 @@ | |||
16 | 16 | ||
17 | #include <linux/clk.h> | 17 | #include <linux/clk.h> |
18 | #include <drm/drm_crtc_helper.h> | 18 | #include <drm/drm_crtc_helper.h> |
19 | #include <drm/drm_device.h> | ||
20 | #include <drm/drm_debugfs.h> | ||
21 | #include <drm/drm_drv.h> | ||
19 | #include <drm/drm_fb_cma_helper.h> | 22 | #include <drm/drm_fb_cma_helper.h> |
20 | #include <drm/drm_fb_helper.h> | 23 | #include <drm/drm_fb_helper.h> |
21 | #include <drm/drm_gem_cma_helper.h> | 24 | #include <drm/drm_gem_cma_helper.h> |
22 | #include <drm/drm_gem_framebuffer_helper.h> | 25 | #include <drm/drm_gem_framebuffer_helper.h> |
23 | #include <drm/drm_atomic_helper.h> | 26 | #include <drm/drm_atomic_helper.h> |
27 | #include <linux/dma-mapping.h> | ||
28 | #include <linux/module.h> | ||
24 | #include <linux/of_reserved_mem.h> | 29 | #include <linux/of_reserved_mem.h> |
30 | #include <linux/platform_device.h> | ||
25 | 31 | ||
26 | #include "arcpgu.h" | 32 | #include "arcpgu.h" |
27 | #include "arcpgu_regs.h" | 33 | #include "arcpgu_regs.h" |
diff --git a/drivers/gpu/drm/arc/arcpgu_sim.c b/drivers/gpu/drm/arc/arcpgu_sim.c index 68629e614990..6530d88f7293 100644 --- a/drivers/gpu/drm/arc/arcpgu_sim.c +++ b/drivers/gpu/drm/arc/arcpgu_sim.c | |||
@@ -51,7 +51,6 @@ arcpgu_drm_connector_helper_funcs = { | |||
51 | }; | 51 | }; |
52 | 52 | ||
53 | static const struct drm_connector_funcs arcpgu_drm_connector_funcs = { | 53 | static const struct drm_connector_funcs arcpgu_drm_connector_funcs = { |
54 | .dpms = drm_helper_connector_dpms, | ||
55 | .reset = drm_atomic_helper_connector_reset, | 54 | .reset = drm_atomic_helper_connector_reset, |
56 | .fill_modes = drm_helper_probe_single_connector_modes, | 55 | .fill_modes = drm_helper_probe_single_connector_modes, |
57 | .destroy = arcpgu_drm_connector_destroy, | 56 | .destroy = arcpgu_drm_connector_destroy, |
diff --git a/drivers/gpu/drm/armada/armada_crtc.c b/drivers/gpu/drm/armada/armada_crtc.c index da9360688b55..20dfb29561c2 100644 --- a/drivers/gpu/drm/armada/armada_crtc.c +++ b/drivers/gpu/drm/armada/armada_crtc.c | |||
@@ -270,13 +270,7 @@ static void armada_drm_crtc_mode_set_nofb(struct drm_crtc *crtc) | |||
270 | tm = adj->crtc_vtotal - adj->crtc_vsync_end; | 270 | tm = adj->crtc_vtotal - adj->crtc_vsync_end; |
271 | 271 | ||
272 | DRM_DEBUG_KMS("[CRTC:%d:%s] mode " DRM_MODE_FMT "\n", | 272 | DRM_DEBUG_KMS("[CRTC:%d:%s] mode " DRM_MODE_FMT "\n", |
273 | crtc->base.id, crtc->name, | 273 | crtc->base.id, crtc->name, DRM_MODE_ARG(adj)); |
274 | adj->base.id, adj->name, adj->vrefresh, adj->clock, | ||
275 | adj->crtc_hdisplay, adj->crtc_hsync_start, | ||
276 | adj->crtc_hsync_end, adj->crtc_htotal, | ||
277 | adj->crtc_vdisplay, adj->crtc_vsync_start, | ||
278 | adj->crtc_vsync_end, adj->crtc_vtotal, | ||
279 | adj->type, adj->flags); | ||
280 | DRM_DEBUG_KMS("lm %d rm %d tm %d bm %d\n", lm, rm, tm, bm); | 274 | DRM_DEBUG_KMS("lm %d rm %d tm %d bm %d\n", lm, rm, tm, bm); |
281 | 275 | ||
282 | /* Now compute the divider for real */ | 276 | /* Now compute the divider for real */ |
diff --git a/drivers/gpu/drm/ast/ast_fb.c b/drivers/gpu/drm/ast/ast_fb.c index c2e41369adcf..2c9f8dd9733a 100644 --- a/drivers/gpu/drm/ast/ast_fb.c +++ b/drivers/gpu/drm/ast/ast_fb.c | |||
@@ -39,7 +39,9 @@ | |||
39 | #include <drm/drmP.h> | 39 | #include <drm/drmP.h> |
40 | #include <drm/drm_crtc.h> | 40 | #include <drm/drm_crtc.h> |
41 | #include <drm/drm_fb_helper.h> | 41 | #include <drm/drm_fb_helper.h> |
42 | #include <drm/drm_util.h> | ||
42 | #include <drm/drm_crtc_helper.h> | 43 | #include <drm/drm_crtc_helper.h> |
44 | |||
43 | #include "ast_drv.h" | 45 | #include "ast_drv.h" |
44 | 46 | ||
45 | static void ast_dirty_update(struct ast_fbdev *afbdev, | 47 | static void ast_dirty_update(struct ast_fbdev *afbdev, |
@@ -261,7 +263,7 @@ static void ast_fbdev_destroy(struct drm_device *dev, | |||
261 | { | 263 | { |
262 | struct ast_framebuffer *afb = &afbdev->afb; | 264 | struct ast_framebuffer *afb = &afbdev->afb; |
263 | 265 | ||
264 | drm_crtc_force_disable_all(dev); | 266 | drm_helper_force_disable_all(dev); |
265 | drm_fb_helper_unregister_fbi(&afbdev->helper); | 267 | drm_fb_helper_unregister_fbi(&afbdev->helper); |
266 | 268 | ||
267 | if (afb->obj) { | 269 | if (afb->obj) { |
diff --git a/drivers/gpu/drm/bochs/Makefile b/drivers/gpu/drm/bochs/Makefile index 98ef60a19e8f..e9e0f8f5eb5b 100644 --- a/drivers/gpu/drm/bochs/Makefile +++ b/drivers/gpu/drm/bochs/Makefile | |||
@@ -1,3 +1,3 @@ | |||
1 | bochs-drm-y := bochs_drv.o bochs_mm.o bochs_kms.o bochs_fbdev.o bochs_hw.o | 1 | bochs-drm-y := bochs_drv.o bochs_mm.o bochs_kms.o bochs_hw.o |
2 | 2 | ||
3 | obj-$(CONFIG_DRM_BOCHS) += bochs-drm.o | 3 | obj-$(CONFIG_DRM_BOCHS) += bochs-drm.o |
diff --git a/drivers/gpu/drm/bochs/bochs.h b/drivers/gpu/drm/bochs/bochs.h index fb38c8b857b5..03711394f1ed 100644 --- a/drivers/gpu/drm/bochs/bochs.h +++ b/drivers/gpu/drm/bochs/bochs.h | |||
@@ -80,12 +80,6 @@ struct bochs_device { | |||
80 | struct ttm_bo_device bdev; | 80 | struct ttm_bo_device bdev; |
81 | bool initialized; | 81 | bool initialized; |
82 | } ttm; | 82 | } ttm; |
83 | |||
84 | /* fbdev */ | ||
85 | struct { | ||
86 | struct drm_framebuffer *fb; | ||
87 | struct drm_fb_helper helper; | ||
88 | } fb; | ||
89 | }; | 83 | }; |
90 | 84 | ||
91 | struct bochs_bo { | 85 | struct bochs_bo { |
@@ -121,8 +115,9 @@ int bochs_hw_init(struct drm_device *dev); | |||
121 | void bochs_hw_fini(struct drm_device *dev); | 115 | void bochs_hw_fini(struct drm_device *dev); |
122 | 116 | ||
123 | void bochs_hw_setmode(struct bochs_device *bochs, | 117 | void bochs_hw_setmode(struct bochs_device *bochs, |
124 | struct drm_display_mode *mode, | 118 | struct drm_display_mode *mode); |
125 | const struct drm_format_info *format); | 119 | void bochs_hw_setformat(struct bochs_device *bochs, |
120 | const struct drm_format_info *format); | ||
126 | void bochs_hw_setbase(struct bochs_device *bochs, | 121 | void bochs_hw_setbase(struct bochs_device *bochs, |
127 | int x, int y, u64 addr); | 122 | int x, int y, u64 addr); |
128 | int bochs_hw_load_edid(struct bochs_device *bochs); | 123 | int bochs_hw_load_edid(struct bochs_device *bochs); |
@@ -141,15 +136,19 @@ int bochs_dumb_create(struct drm_file *file, struct drm_device *dev, | |||
141 | int bochs_dumb_mmap_offset(struct drm_file *file, struct drm_device *dev, | 136 | int bochs_dumb_mmap_offset(struct drm_file *file, struct drm_device *dev, |
142 | uint32_t handle, uint64_t *offset); | 137 | uint32_t handle, uint64_t *offset); |
143 | 138 | ||
144 | int bochs_bo_pin(struct bochs_bo *bo, u32 pl_flag, u64 *gpu_addr); | 139 | int bochs_bo_pin(struct bochs_bo *bo, u32 pl_flag); |
145 | int bochs_bo_unpin(struct bochs_bo *bo); | 140 | int bochs_bo_unpin(struct bochs_bo *bo); |
146 | 141 | ||
142 | int bochs_gem_prime_pin(struct drm_gem_object *obj); | ||
143 | void bochs_gem_prime_unpin(struct drm_gem_object *obj); | ||
144 | void *bochs_gem_prime_vmap(struct drm_gem_object *obj); | ||
145 | void bochs_gem_prime_vunmap(struct drm_gem_object *obj, void *vaddr); | ||
146 | int bochs_gem_prime_mmap(struct drm_gem_object *obj, | ||
147 | struct vm_area_struct *vma); | ||
148 | |||
147 | /* bochs_kms.c */ | 149 | /* bochs_kms.c */ |
148 | int bochs_kms_init(struct bochs_device *bochs); | 150 | int bochs_kms_init(struct bochs_device *bochs); |
149 | void bochs_kms_fini(struct bochs_device *bochs); | 151 | void bochs_kms_fini(struct bochs_device *bochs); |
150 | 152 | ||
151 | /* bochs_fbdev.c */ | 153 | /* bochs_fbdev.c */ |
152 | int bochs_fbdev_init(struct bochs_device *bochs); | ||
153 | void bochs_fbdev_fini(struct bochs_device *bochs); | ||
154 | |||
155 | extern const struct drm_mode_config_funcs bochs_mode_funcs; | 154 | extern const struct drm_mode_config_funcs bochs_mode_funcs; |
diff --git a/drivers/gpu/drm/bochs/bochs_drv.c b/drivers/gpu/drm/bochs/bochs_drv.c index f3dd66ae990a..cea42ac64d7e 100644 --- a/drivers/gpu/drm/bochs/bochs_drv.c +++ b/drivers/gpu/drm/bochs/bochs_drv.c | |||
@@ -16,10 +16,6 @@ static int bochs_modeset = -1; | |||
16 | module_param_named(modeset, bochs_modeset, int, 0444); | 16 | module_param_named(modeset, bochs_modeset, int, 0444); |
17 | MODULE_PARM_DESC(modeset, "enable/disable kernel modesetting"); | 17 | MODULE_PARM_DESC(modeset, "enable/disable kernel modesetting"); |
18 | 18 | ||
19 | static bool enable_fbdev = true; | ||
20 | module_param_named(fbdev, enable_fbdev, bool, 0444); | ||
21 | MODULE_PARM_DESC(fbdev, "register fbdev device"); | ||
22 | |||
23 | /* ---------------------------------------------------------------------- */ | 19 | /* ---------------------------------------------------------------------- */ |
24 | /* drm interface */ | 20 | /* drm interface */ |
25 | 21 | ||
@@ -27,7 +23,6 @@ static void bochs_unload(struct drm_device *dev) | |||
27 | { | 23 | { |
28 | struct bochs_device *bochs = dev->dev_private; | 24 | struct bochs_device *bochs = dev->dev_private; |
29 | 25 | ||
30 | bochs_fbdev_fini(bochs); | ||
31 | bochs_kms_fini(bochs); | 26 | bochs_kms_fini(bochs); |
32 | bochs_mm_fini(bochs); | 27 | bochs_mm_fini(bochs); |
33 | bochs_hw_fini(dev); | 28 | bochs_hw_fini(dev); |
@@ -58,9 +53,6 @@ static int bochs_load(struct drm_device *dev) | |||
58 | if (ret) | 53 | if (ret) |
59 | goto err; | 54 | goto err; |
60 | 55 | ||
61 | if (enable_fbdev) | ||
62 | bochs_fbdev_init(bochs); | ||
63 | |||
64 | return 0; | 56 | return 0; |
65 | 57 | ||
66 | err: | 58 | err: |
@@ -81,7 +73,8 @@ static const struct file_operations bochs_fops = { | |||
81 | }; | 73 | }; |
82 | 74 | ||
83 | static struct drm_driver bochs_driver = { | 75 | static struct drm_driver bochs_driver = { |
84 | .driver_features = DRIVER_GEM | DRIVER_MODESET, | 76 | .driver_features = DRIVER_GEM | DRIVER_MODESET | DRIVER_ATOMIC | |
77 | DRIVER_PRIME, | ||
85 | .fops = &bochs_fops, | 78 | .fops = &bochs_fops, |
86 | .name = "bochs-drm", | 79 | .name = "bochs-drm", |
87 | .desc = "bochs dispi vga interface (qemu stdvga)", | 80 | .desc = "bochs dispi vga interface (qemu stdvga)", |
@@ -91,6 +84,14 @@ static struct drm_driver bochs_driver = { | |||
91 | .gem_free_object_unlocked = bochs_gem_free_object, | 84 | .gem_free_object_unlocked = bochs_gem_free_object, |
92 | .dumb_create = bochs_dumb_create, | 85 | .dumb_create = bochs_dumb_create, |
93 | .dumb_map_offset = bochs_dumb_mmap_offset, | 86 | .dumb_map_offset = bochs_dumb_mmap_offset, |
87 | |||
88 | .gem_prime_export = drm_gem_prime_export, | ||
89 | .gem_prime_import = drm_gem_prime_import, | ||
90 | .gem_prime_pin = bochs_gem_prime_pin, | ||
91 | .gem_prime_unpin = bochs_gem_prime_unpin, | ||
92 | .gem_prime_vmap = bochs_gem_prime_vmap, | ||
93 | .gem_prime_vunmap = bochs_gem_prime_vunmap, | ||
94 | .gem_prime_mmap = bochs_gem_prime_mmap, | ||
94 | }; | 95 | }; |
95 | 96 | ||
96 | /* ---------------------------------------------------------------------- */ | 97 | /* ---------------------------------------------------------------------- */ |
@@ -101,27 +102,16 @@ static int bochs_pm_suspend(struct device *dev) | |||
101 | { | 102 | { |
102 | struct pci_dev *pdev = to_pci_dev(dev); | 103 | struct pci_dev *pdev = to_pci_dev(dev); |
103 | struct drm_device *drm_dev = pci_get_drvdata(pdev); | 104 | struct drm_device *drm_dev = pci_get_drvdata(pdev); |
104 | struct bochs_device *bochs = drm_dev->dev_private; | ||
105 | |||
106 | drm_kms_helper_poll_disable(drm_dev); | ||
107 | |||
108 | drm_fb_helper_set_suspend_unlocked(&bochs->fb.helper, 1); | ||
109 | 105 | ||
110 | return 0; | 106 | return drm_mode_config_helper_suspend(drm_dev); |
111 | } | 107 | } |
112 | 108 | ||
113 | static int bochs_pm_resume(struct device *dev) | 109 | static int bochs_pm_resume(struct device *dev) |
114 | { | 110 | { |
115 | struct pci_dev *pdev = to_pci_dev(dev); | 111 | struct pci_dev *pdev = to_pci_dev(dev); |
116 | struct drm_device *drm_dev = pci_get_drvdata(pdev); | 112 | struct drm_device *drm_dev = pci_get_drvdata(pdev); |
117 | struct bochs_device *bochs = drm_dev->dev_private; | ||
118 | |||
119 | drm_helper_resume_force_mode(drm_dev); | ||
120 | 113 | ||
121 | drm_fb_helper_set_suspend_unlocked(&bochs->fb.helper, 0); | 114 | return drm_mode_config_helper_resume(drm_dev); |
122 | |||
123 | drm_kms_helper_poll_enable(drm_dev); | ||
124 | return 0; | ||
125 | } | 115 | } |
126 | #endif | 116 | #endif |
127 | 117 | ||
@@ -165,6 +155,7 @@ static int bochs_pci_probe(struct pci_dev *pdev, | |||
165 | if (ret) | 155 | if (ret) |
166 | goto err_unload; | 156 | goto err_unload; |
167 | 157 | ||
158 | drm_fbdev_generic_setup(dev, 32); | ||
168 | return ret; | 159 | return ret; |
169 | 160 | ||
170 | err_unload: | 161 | err_unload: |
diff --git a/drivers/gpu/drm/bochs/bochs_fbdev.c b/drivers/gpu/drm/bochs/bochs_fbdev.c deleted file mode 100644 index dd3c7df267da..000000000000 --- a/drivers/gpu/drm/bochs/bochs_fbdev.c +++ /dev/null | |||
@@ -1,163 +0,0 @@ | |||
1 | /* | ||
2 | * This program is free software; you can redistribute it and/or modify | ||
3 | * it under the terms of the GNU General Public License as published by | ||
4 | * the Free Software Foundation; either version 2 of the License, or | ||
5 | * (at your option) any later version. | ||
6 | */ | ||
7 | |||
8 | #include "bochs.h" | ||
9 | #include <drm/drm_gem_framebuffer_helper.h> | ||
10 | |||
11 | /* ---------------------------------------------------------------------- */ | ||
12 | |||
13 | static int bochsfb_mmap(struct fb_info *info, | ||
14 | struct vm_area_struct *vma) | ||
15 | { | ||
16 | struct drm_fb_helper *fb_helper = info->par; | ||
17 | struct bochs_bo *bo = gem_to_bochs_bo(fb_helper->fb->obj[0]); | ||
18 | |||
19 | return ttm_fbdev_mmap(vma, &bo->bo); | ||
20 | } | ||
21 | |||
22 | static struct fb_ops bochsfb_ops = { | ||
23 | .owner = THIS_MODULE, | ||
24 | DRM_FB_HELPER_DEFAULT_OPS, | ||
25 | .fb_fillrect = drm_fb_helper_cfb_fillrect, | ||
26 | .fb_copyarea = drm_fb_helper_cfb_copyarea, | ||
27 | .fb_imageblit = drm_fb_helper_cfb_imageblit, | ||
28 | .fb_mmap = bochsfb_mmap, | ||
29 | }; | ||
30 | |||
31 | static int bochsfb_create_object(struct bochs_device *bochs, | ||
32 | const struct drm_mode_fb_cmd2 *mode_cmd, | ||
33 | struct drm_gem_object **gobj_p) | ||
34 | { | ||
35 | struct drm_device *dev = bochs->dev; | ||
36 | struct drm_gem_object *gobj; | ||
37 | u32 size; | ||
38 | int ret = 0; | ||
39 | |||
40 | size = mode_cmd->pitches[0] * mode_cmd->height; | ||
41 | ret = bochs_gem_create(dev, size, true, &gobj); | ||
42 | if (ret) | ||
43 | return ret; | ||
44 | |||
45 | *gobj_p = gobj; | ||
46 | return ret; | ||
47 | } | ||
48 | |||
49 | static int bochsfb_create(struct drm_fb_helper *helper, | ||
50 | struct drm_fb_helper_surface_size *sizes) | ||
51 | { | ||
52 | struct bochs_device *bochs = | ||
53 | container_of(helper, struct bochs_device, fb.helper); | ||
54 | struct fb_info *info; | ||
55 | struct drm_framebuffer *fb; | ||
56 | struct drm_mode_fb_cmd2 mode_cmd; | ||
57 | struct drm_gem_object *gobj = NULL; | ||
58 | struct bochs_bo *bo = NULL; | ||
59 | int size, ret; | ||
60 | |||
61 | if (sizes->surface_bpp != 32) | ||
62 | return -EINVAL; | ||
63 | |||
64 | mode_cmd.width = sizes->surface_width; | ||
65 | mode_cmd.height = sizes->surface_height; | ||
66 | mode_cmd.pitches[0] = sizes->surface_width * 4; | ||
67 | mode_cmd.pixel_format = DRM_FORMAT_HOST_XRGB8888; | ||
68 | size = mode_cmd.pitches[0] * mode_cmd.height; | ||
69 | |||
70 | /* alloc, pin & map bo */ | ||
71 | ret = bochsfb_create_object(bochs, &mode_cmd, &gobj); | ||
72 | if (ret) { | ||
73 | DRM_ERROR("failed to create fbcon backing object %d\n", ret); | ||
74 | return ret; | ||
75 | } | ||
76 | |||
77 | bo = gem_to_bochs_bo(gobj); | ||
78 | |||
79 | ret = ttm_bo_reserve(&bo->bo, true, false, NULL); | ||
80 | if (ret) | ||
81 | return ret; | ||
82 | |||
83 | ret = bochs_bo_pin(bo, TTM_PL_FLAG_VRAM, NULL); | ||
84 | if (ret) { | ||
85 | DRM_ERROR("failed to pin fbcon\n"); | ||
86 | ttm_bo_unreserve(&bo->bo); | ||
87 | return ret; | ||
88 | } | ||
89 | |||
90 | ret = ttm_bo_kmap(&bo->bo, 0, bo->bo.num_pages, | ||
91 | &bo->kmap); | ||
92 | if (ret) { | ||
93 | DRM_ERROR("failed to kmap fbcon\n"); | ||
94 | ttm_bo_unreserve(&bo->bo); | ||
95 | return ret; | ||
96 | } | ||
97 | |||
98 | ttm_bo_unreserve(&bo->bo); | ||
99 | |||
100 | /* init fb device */ | ||
101 | info = drm_fb_helper_alloc_fbi(helper); | ||
102 | if (IS_ERR(info)) { | ||
103 | DRM_ERROR("Failed to allocate fbi: %ld\n", PTR_ERR(info)); | ||
104 | return PTR_ERR(info); | ||
105 | } | ||
106 | |||
107 | info->par = &bochs->fb.helper; | ||
108 | |||
109 | fb = drm_gem_fbdev_fb_create(bochs->dev, sizes, 0, gobj, NULL); | ||
110 | if (IS_ERR(fb)) { | ||
111 | DRM_ERROR("Failed to create framebuffer: %ld\n", PTR_ERR(fb)); | ||
112 | return PTR_ERR(fb); | ||
113 | } | ||
114 | |||
115 | /* setup helper */ | ||
116 | bochs->fb.helper.fb = fb; | ||
117 | |||
118 | strcpy(info->fix.id, "bochsdrmfb"); | ||
119 | |||
120 | info->fbops = &bochsfb_ops; | ||
121 | |||
122 | drm_fb_helper_fill_fix(info, fb->pitches[0], fb->format->depth); | ||
123 | drm_fb_helper_fill_var(info, &bochs->fb.helper, sizes->fb_width, | ||
124 | sizes->fb_height); | ||
125 | |||
126 | info->screen_base = bo->kmap.virtual; | ||
127 | info->screen_size = size; | ||
128 | |||
129 | drm_vma_offset_remove(&bo->bo.bdev->vma_manager, &bo->bo.vma_node); | ||
130 | info->fix.smem_start = 0; | ||
131 | info->fix.smem_len = size; | ||
132 | return 0; | ||
133 | } | ||
134 | |||
135 | static const struct drm_fb_helper_funcs bochs_fb_helper_funcs = { | ||
136 | .fb_probe = bochsfb_create, | ||
137 | }; | ||
138 | |||
139 | static struct drm_framebuffer * | ||
140 | bochs_gem_fb_create(struct drm_device *dev, struct drm_file *file, | ||
141 | const struct drm_mode_fb_cmd2 *mode_cmd) | ||
142 | { | ||
143 | if (mode_cmd->pixel_format != DRM_FORMAT_XRGB8888 && | ||
144 | mode_cmd->pixel_format != DRM_FORMAT_BGRX8888) | ||
145 | return ERR_PTR(-EINVAL); | ||
146 | |||
147 | return drm_gem_fb_create(dev, file, mode_cmd); | ||
148 | } | ||
149 | |||
150 | const struct drm_mode_config_funcs bochs_mode_funcs = { | ||
151 | .fb_create = bochs_gem_fb_create, | ||
152 | }; | ||
153 | |||
154 | int bochs_fbdev_init(struct bochs_device *bochs) | ||
155 | { | ||
156 | return drm_fb_helper_fbdev_setup(bochs->dev, &bochs->fb.helper, | ||
157 | &bochs_fb_helper_funcs, 32, 1); | ||
158 | } | ||
159 | |||
160 | void bochs_fbdev_fini(struct bochs_device *bochs) | ||
161 | { | ||
162 | drm_fb_helper_fbdev_teardown(bochs->dev); | ||
163 | } | ||
diff --git a/drivers/gpu/drm/bochs/bochs_hw.c b/drivers/gpu/drm/bochs/bochs_hw.c index d0b4e1cee83e..3e04b2f0ec08 100644 --- a/drivers/gpu/drm/bochs/bochs_hw.c +++ b/drivers/gpu/drm/bochs/bochs_hw.c | |||
@@ -204,8 +204,7 @@ void bochs_hw_fini(struct drm_device *dev) | |||
204 | } | 204 | } |
205 | 205 | ||
206 | void bochs_hw_setmode(struct bochs_device *bochs, | 206 | void bochs_hw_setmode(struct bochs_device *bochs, |
207 | struct drm_display_mode *mode, | 207 | struct drm_display_mode *mode) |
208 | const struct drm_format_info *format) | ||
209 | { | 208 | { |
210 | bochs->xres = mode->hdisplay; | 209 | bochs->xres = mode->hdisplay; |
211 | bochs->yres = mode->vdisplay; | 210 | bochs->yres = mode->vdisplay; |
@@ -213,12 +212,8 @@ void bochs_hw_setmode(struct bochs_device *bochs, | |||
213 | bochs->stride = mode->hdisplay * (bochs->bpp / 8); | 212 | bochs->stride = mode->hdisplay * (bochs->bpp / 8); |
214 | bochs->yres_virtual = bochs->fb_size / bochs->stride; | 213 | bochs->yres_virtual = bochs->fb_size / bochs->stride; |
215 | 214 | ||
216 | DRM_DEBUG_DRIVER("%dx%d @ %d bpp, format %c%c%c%c, vy %d\n", | 215 | DRM_DEBUG_DRIVER("%dx%d @ %d bpp, vy %d\n", |
217 | bochs->xres, bochs->yres, bochs->bpp, | 216 | bochs->xres, bochs->yres, bochs->bpp, |
218 | (format->format >> 0) & 0xff, | ||
219 | (format->format >> 8) & 0xff, | ||
220 | (format->format >> 16) & 0xff, | ||
221 | (format->format >> 24) & 0xff, | ||
222 | bochs->yres_virtual); | 217 | bochs->yres_virtual); |
223 | 218 | ||
224 | bochs_vga_writeb(bochs, 0x3c0, 0x20); /* unblank */ | 219 | bochs_vga_writeb(bochs, 0x3c0, 0x20); /* unblank */ |
@@ -236,6 +231,16 @@ void bochs_hw_setmode(struct bochs_device *bochs, | |||
236 | 231 | ||
237 | bochs_dispi_write(bochs, VBE_DISPI_INDEX_ENABLE, | 232 | bochs_dispi_write(bochs, VBE_DISPI_INDEX_ENABLE, |
238 | VBE_DISPI_ENABLED | VBE_DISPI_LFB_ENABLED); | 233 | VBE_DISPI_ENABLED | VBE_DISPI_LFB_ENABLED); |
234 | } | ||
235 | |||
236 | void bochs_hw_setformat(struct bochs_device *bochs, | ||
237 | const struct drm_format_info *format) | ||
238 | { | ||
239 | DRM_DEBUG_DRIVER("format %c%c%c%c\n", | ||
240 | (format->format >> 0) & 0xff, | ||
241 | (format->format >> 8) & 0xff, | ||
242 | (format->format >> 16) & 0xff, | ||
243 | (format->format >> 24) & 0xff); | ||
239 | 244 | ||
240 | switch (format->format) { | 245 | switch (format->format) { |
241 | case DRM_FORMAT_XRGB8888: | 246 | case DRM_FORMAT_XRGB8888: |
diff --git a/drivers/gpu/drm/bochs/bochs_kms.c b/drivers/gpu/drm/bochs/bochs_kms.c index f87c284dd93d..e9d5dbc34676 100644 --- a/drivers/gpu/drm/bochs/bochs_kms.c +++ b/drivers/gpu/drm/bochs/bochs_kms.c | |||
@@ -6,7 +6,10 @@ | |||
6 | */ | 6 | */ |
7 | 7 | ||
8 | #include "bochs.h" | 8 | #include "bochs.h" |
9 | #include <drm/drm_atomic_helper.h> | ||
9 | #include <drm/drm_plane_helper.h> | 10 | #include <drm/drm_plane_helper.h> |
11 | #include <drm/drm_atomic_uapi.h> | ||
12 | #include <drm/drm_gem_framebuffer_helper.h> | ||
10 | 13 | ||
11 | static int defx = 1024; | 14 | static int defx = 1024; |
12 | static int defy = 768; | 15 | static int defy = 768; |
@@ -18,115 +21,51 @@ MODULE_PARM_DESC(defy, "default y resolution"); | |||
18 | 21 | ||
19 | /* ---------------------------------------------------------------------- */ | 22 | /* ---------------------------------------------------------------------- */ |
20 | 23 | ||
21 | static void bochs_crtc_dpms(struct drm_crtc *crtc, int mode) | 24 | static void bochs_crtc_mode_set_nofb(struct drm_crtc *crtc) |
22 | { | ||
23 | switch (mode) { | ||
24 | case DRM_MODE_DPMS_ON: | ||
25 | case DRM_MODE_DPMS_STANDBY: | ||
26 | case DRM_MODE_DPMS_SUSPEND: | ||
27 | case DRM_MODE_DPMS_OFF: | ||
28 | default: | ||
29 | return; | ||
30 | } | ||
31 | } | ||
32 | |||
33 | static int bochs_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y, | ||
34 | struct drm_framebuffer *old_fb) | ||
35 | { | ||
36 | struct bochs_device *bochs = | ||
37 | container_of(crtc, struct bochs_device, crtc); | ||
38 | struct bochs_bo *bo; | ||
39 | u64 gpu_addr = 0; | ||
40 | int ret; | ||
41 | |||
42 | if (old_fb) { | ||
43 | bo = gem_to_bochs_bo(old_fb->obj[0]); | ||
44 | ret = ttm_bo_reserve(&bo->bo, true, false, NULL); | ||
45 | if (ret) { | ||
46 | DRM_ERROR("failed to reserve old_fb bo\n"); | ||
47 | } else { | ||
48 | bochs_bo_unpin(bo); | ||
49 | ttm_bo_unreserve(&bo->bo); | ||
50 | } | ||
51 | } | ||
52 | |||
53 | if (WARN_ON(crtc->primary->fb == NULL)) | ||
54 | return -EINVAL; | ||
55 | |||
56 | bo = gem_to_bochs_bo(crtc->primary->fb->obj[0]); | ||
57 | ret = ttm_bo_reserve(&bo->bo, true, false, NULL); | ||
58 | if (ret) | ||
59 | return ret; | ||
60 | |||
61 | ret = bochs_bo_pin(bo, TTM_PL_FLAG_VRAM, &gpu_addr); | ||
62 | if (ret) { | ||
63 | ttm_bo_unreserve(&bo->bo); | ||
64 | return ret; | ||
65 | } | ||
66 | |||
67 | ttm_bo_unreserve(&bo->bo); | ||
68 | bochs_hw_setbase(bochs, x, y, gpu_addr); | ||
69 | return 0; | ||
70 | } | ||
71 | |||
72 | static int bochs_crtc_mode_set(struct drm_crtc *crtc, | ||
73 | struct drm_display_mode *mode, | ||
74 | struct drm_display_mode *adjusted_mode, | ||
75 | int x, int y, struct drm_framebuffer *old_fb) | ||
76 | { | 25 | { |
77 | struct bochs_device *bochs = | 26 | struct bochs_device *bochs = |
78 | container_of(crtc, struct bochs_device, crtc); | 27 | container_of(crtc, struct bochs_device, crtc); |
79 | 28 | ||
80 | if (WARN_ON(crtc->primary->fb == NULL)) | 29 | bochs_hw_setmode(bochs, &crtc->mode); |
81 | return -EINVAL; | ||
82 | |||
83 | bochs_hw_setmode(bochs, mode, crtc->primary->fb->format); | ||
84 | bochs_crtc_mode_set_base(crtc, x, y, old_fb); | ||
85 | return 0; | ||
86 | } | 30 | } |
87 | 31 | ||
88 | static void bochs_crtc_prepare(struct drm_crtc *crtc) | 32 | static void bochs_crtc_atomic_enable(struct drm_crtc *crtc, |
33 | struct drm_crtc_state *old_crtc_state) | ||
89 | { | 34 | { |
90 | } | 35 | } |
91 | 36 | ||
92 | static void bochs_crtc_commit(struct drm_crtc *crtc) | 37 | static void bochs_crtc_atomic_flush(struct drm_crtc *crtc, |
38 | struct drm_crtc_state *old_crtc_state) | ||
93 | { | 39 | { |
94 | } | 40 | struct drm_device *dev = crtc->dev; |
41 | struct drm_pending_vblank_event *event; | ||
95 | 42 | ||
96 | static int bochs_crtc_page_flip(struct drm_crtc *crtc, | 43 | if (crtc->state && crtc->state->event) { |
97 | struct drm_framebuffer *fb, | 44 | unsigned long irqflags; |
98 | struct drm_pending_vblank_event *event, | ||
99 | uint32_t page_flip_flags, | ||
100 | struct drm_modeset_acquire_ctx *ctx) | ||
101 | { | ||
102 | struct bochs_device *bochs = | ||
103 | container_of(crtc, struct bochs_device, crtc); | ||
104 | struct drm_framebuffer *old_fb = crtc->primary->fb; | ||
105 | unsigned long irqflags; | ||
106 | 45 | ||
107 | crtc->primary->fb = fb; | 46 | spin_lock_irqsave(&dev->event_lock, irqflags); |
108 | bochs_crtc_mode_set_base(crtc, 0, 0, old_fb); | 47 | event = crtc->state->event; |
109 | if (event) { | 48 | crtc->state->event = NULL; |
110 | spin_lock_irqsave(&bochs->dev->event_lock, irqflags); | ||
111 | drm_crtc_send_vblank_event(crtc, event); | 49 | drm_crtc_send_vblank_event(crtc, event); |
112 | spin_unlock_irqrestore(&bochs->dev->event_lock, irqflags); | 50 | spin_unlock_irqrestore(&dev->event_lock, irqflags); |
113 | } | 51 | } |
114 | return 0; | ||
115 | } | 52 | } |
116 | 53 | ||
54 | |||
117 | /* These provide the minimum set of functions required to handle a CRTC */ | 55 | /* These provide the minimum set of functions required to handle a CRTC */ |
118 | static const struct drm_crtc_funcs bochs_crtc_funcs = { | 56 | static const struct drm_crtc_funcs bochs_crtc_funcs = { |
119 | .set_config = drm_crtc_helper_set_config, | 57 | .set_config = drm_atomic_helper_set_config, |
120 | .destroy = drm_crtc_cleanup, | 58 | .destroy = drm_crtc_cleanup, |
121 | .page_flip = bochs_crtc_page_flip, | 59 | .page_flip = drm_atomic_helper_page_flip, |
60 | .reset = drm_atomic_helper_crtc_reset, | ||
61 | .atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state, | ||
62 | .atomic_destroy_state = drm_atomic_helper_crtc_destroy_state, | ||
122 | }; | 63 | }; |
123 | 64 | ||
124 | static const struct drm_crtc_helper_funcs bochs_helper_funcs = { | 65 | static const struct drm_crtc_helper_funcs bochs_helper_funcs = { |
125 | .dpms = bochs_crtc_dpms, | 66 | .mode_set_nofb = bochs_crtc_mode_set_nofb, |
126 | .mode_set = bochs_crtc_mode_set, | 67 | .atomic_enable = bochs_crtc_atomic_enable, |
127 | .mode_set_base = bochs_crtc_mode_set_base, | 68 | .atomic_flush = bochs_crtc_atomic_flush, |
128 | .prepare = bochs_crtc_prepare, | ||
129 | .commit = bochs_crtc_commit, | ||
130 | }; | 69 | }; |
131 | 70 | ||
132 | static const uint32_t bochs_formats[] = { | 71 | static const uint32_t bochs_formats[] = { |
@@ -134,6 +73,59 @@ static const uint32_t bochs_formats[] = { | |||
134 | DRM_FORMAT_BGRX8888, | 73 | DRM_FORMAT_BGRX8888, |
135 | }; | 74 | }; |
136 | 75 | ||
76 | static void bochs_plane_atomic_update(struct drm_plane *plane, | ||
77 | struct drm_plane_state *old_state) | ||
78 | { | ||
79 | struct bochs_device *bochs = plane->dev->dev_private; | ||
80 | struct bochs_bo *bo; | ||
81 | |||
82 | if (!plane->state->fb) | ||
83 | return; | ||
84 | bo = gem_to_bochs_bo(plane->state->fb->obj[0]); | ||
85 | bochs_hw_setbase(bochs, | ||
86 | plane->state->crtc_x, | ||
87 | plane->state->crtc_y, | ||
88 | bo->bo.offset); | ||
89 | bochs_hw_setformat(bochs, plane->state->fb->format); | ||
90 | } | ||
91 | |||
92 | static int bochs_plane_prepare_fb(struct drm_plane *plane, | ||
93 | struct drm_plane_state *new_state) | ||
94 | { | ||
95 | struct bochs_bo *bo; | ||
96 | |||
97 | if (!new_state->fb) | ||
98 | return 0; | ||
99 | bo = gem_to_bochs_bo(new_state->fb->obj[0]); | ||
100 | return bochs_bo_pin(bo, TTM_PL_FLAG_VRAM); | ||
101 | } | ||
102 | |||
103 | static void bochs_plane_cleanup_fb(struct drm_plane *plane, | ||
104 | struct drm_plane_state *old_state) | ||
105 | { | ||
106 | struct bochs_bo *bo; | ||
107 | |||
108 | if (!old_state->fb) | ||
109 | return; | ||
110 | bo = gem_to_bochs_bo(old_state->fb->obj[0]); | ||
111 | bochs_bo_unpin(bo); | ||
112 | } | ||
113 | |||
114 | static const struct drm_plane_helper_funcs bochs_plane_helper_funcs = { | ||
115 | .atomic_update = bochs_plane_atomic_update, | ||
116 | .prepare_fb = bochs_plane_prepare_fb, | ||
117 | .cleanup_fb = bochs_plane_cleanup_fb, | ||
118 | }; | ||
119 | |||
120 | static const struct drm_plane_funcs bochs_plane_funcs = { | ||
121 | .update_plane = drm_atomic_helper_update_plane, | ||
122 | .disable_plane = drm_atomic_helper_disable_plane, | ||
123 | .destroy = drm_primary_helper_destroy, | ||
124 | .reset = drm_atomic_helper_plane_reset, | ||
125 | .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state, | ||
126 | .atomic_destroy_state = drm_atomic_helper_plane_destroy_state, | ||
127 | }; | ||
128 | |||
137 | static struct drm_plane *bochs_primary_plane(struct drm_device *dev) | 129 | static struct drm_plane *bochs_primary_plane(struct drm_device *dev) |
138 | { | 130 | { |
139 | struct drm_plane *primary; | 131 | struct drm_plane *primary; |
@@ -146,16 +138,17 @@ static struct drm_plane *bochs_primary_plane(struct drm_device *dev) | |||
146 | } | 138 | } |
147 | 139 | ||
148 | ret = drm_universal_plane_init(dev, primary, 0, | 140 | ret = drm_universal_plane_init(dev, primary, 0, |
149 | &drm_primary_helper_funcs, | 141 | &bochs_plane_funcs, |
150 | bochs_formats, | 142 | bochs_formats, |
151 | ARRAY_SIZE(bochs_formats), | 143 | ARRAY_SIZE(bochs_formats), |
152 | NULL, | 144 | NULL, |
153 | DRM_PLANE_TYPE_PRIMARY, NULL); | 145 | DRM_PLANE_TYPE_PRIMARY, NULL); |
154 | if (ret) { | 146 | if (ret) { |
155 | kfree(primary); | 147 | kfree(primary); |
156 | primary = NULL; | 148 | return NULL; |
157 | } | 149 | } |
158 | 150 | ||
151 | drm_plane_helper_add(primary, &bochs_plane_helper_funcs); | ||
159 | return primary; | 152 | return primary; |
160 | } | 153 | } |
161 | 154 | ||
@@ -170,31 +163,6 @@ static void bochs_crtc_init(struct drm_device *dev) | |||
170 | drm_crtc_helper_add(crtc, &bochs_helper_funcs); | 163 | drm_crtc_helper_add(crtc, &bochs_helper_funcs); |
171 | } | 164 | } |
172 | 165 | ||
173 | static void bochs_encoder_mode_set(struct drm_encoder *encoder, | ||
174 | struct drm_display_mode *mode, | ||
175 | struct drm_display_mode *adjusted_mode) | ||
176 | { | ||
177 | } | ||
178 | |||
179 | static void bochs_encoder_dpms(struct drm_encoder *encoder, int state) | ||
180 | { | ||
181 | } | ||
182 | |||
183 | static void bochs_encoder_prepare(struct drm_encoder *encoder) | ||
184 | { | ||
185 | } | ||
186 | |||
187 | static void bochs_encoder_commit(struct drm_encoder *encoder) | ||
188 | { | ||
189 | } | ||
190 | |||
191 | static const struct drm_encoder_helper_funcs bochs_encoder_helper_funcs = { | ||
192 | .dpms = bochs_encoder_dpms, | ||
193 | .mode_set = bochs_encoder_mode_set, | ||
194 | .prepare = bochs_encoder_prepare, | ||
195 | .commit = bochs_encoder_commit, | ||
196 | }; | ||
197 | |||
198 | static const struct drm_encoder_funcs bochs_encoder_encoder_funcs = { | 166 | static const struct drm_encoder_funcs bochs_encoder_encoder_funcs = { |
199 | .destroy = drm_encoder_cleanup, | 167 | .destroy = drm_encoder_cleanup, |
200 | }; | 168 | }; |
@@ -207,7 +175,6 @@ static void bochs_encoder_init(struct drm_device *dev) | |||
207 | encoder->possible_crtcs = 0x1; | 175 | encoder->possible_crtcs = 0x1; |
208 | drm_encoder_init(dev, encoder, &bochs_encoder_encoder_funcs, | 176 | drm_encoder_init(dev, encoder, &bochs_encoder_encoder_funcs, |
209 | DRM_MODE_ENCODER_DAC, NULL); | 177 | DRM_MODE_ENCODER_DAC, NULL); |
210 | drm_encoder_helper_add(encoder, &bochs_encoder_helper_funcs); | ||
211 | } | 178 | } |
212 | 179 | ||
213 | 180 | ||
@@ -266,6 +233,9 @@ static const struct drm_connector_funcs bochs_connector_connector_funcs = { | |||
266 | .dpms = drm_helper_connector_dpms, | 233 | .dpms = drm_helper_connector_dpms, |
267 | .fill_modes = drm_helper_probe_single_connector_modes, | 234 | .fill_modes = drm_helper_probe_single_connector_modes, |
268 | .destroy = drm_connector_cleanup, | 235 | .destroy = drm_connector_cleanup, |
236 | .reset = drm_atomic_helper_connector_reset, | ||
237 | .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, | ||
238 | .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, | ||
269 | }; | 239 | }; |
270 | 240 | ||
271 | static void bochs_connector_init(struct drm_device *dev) | 241 | static void bochs_connector_init(struct drm_device *dev) |
@@ -287,6 +257,22 @@ static void bochs_connector_init(struct drm_device *dev) | |||
287 | } | 257 | } |
288 | } | 258 | } |
289 | 259 | ||
260 | static struct drm_framebuffer * | ||
261 | bochs_gem_fb_create(struct drm_device *dev, struct drm_file *file, | ||
262 | const struct drm_mode_fb_cmd2 *mode_cmd) | ||
263 | { | ||
264 | if (mode_cmd->pixel_format != DRM_FORMAT_XRGB8888 && | ||
265 | mode_cmd->pixel_format != DRM_FORMAT_BGRX8888) | ||
266 | return ERR_PTR(-EINVAL); | ||
267 | |||
268 | return drm_gem_fb_create(dev, file, mode_cmd); | ||
269 | } | ||
270 | |||
271 | const struct drm_mode_config_funcs bochs_mode_funcs = { | ||
272 | .fb_create = bochs_gem_fb_create, | ||
273 | .atomic_check = drm_atomic_helper_check, | ||
274 | .atomic_commit = drm_atomic_helper_commit, | ||
275 | }; | ||
290 | 276 | ||
291 | int bochs_kms_init(struct bochs_device *bochs) | 277 | int bochs_kms_init(struct bochs_device *bochs) |
292 | { | 278 | { |
@@ -309,6 +295,8 @@ int bochs_kms_init(struct bochs_device *bochs) | |||
309 | drm_connector_attach_encoder(&bochs->connector, | 295 | drm_connector_attach_encoder(&bochs->connector, |
310 | &bochs->encoder); | 296 | &bochs->encoder); |
311 | 297 | ||
298 | drm_mode_config_reset(bochs->dev); | ||
299 | |||
312 | return 0; | 300 | return 0; |
313 | } | 301 | } |
314 | 302 | ||
diff --git a/drivers/gpu/drm/bochs/bochs_mm.c b/drivers/gpu/drm/bochs/bochs_mm.c index 0980411e41bf..641a33f134ee 100644 --- a/drivers/gpu/drm/bochs/bochs_mm.c +++ b/drivers/gpu/drm/bochs/bochs_mm.c | |||
@@ -210,33 +210,28 @@ static void bochs_ttm_placement(struct bochs_bo *bo, int domain) | |||
210 | bo->placement.num_busy_placement = c; | 210 | bo->placement.num_busy_placement = c; |
211 | } | 211 | } |
212 | 212 | ||
213 | static inline u64 bochs_bo_gpu_offset(struct bochs_bo *bo) | 213 | int bochs_bo_pin(struct bochs_bo *bo, u32 pl_flag) |
214 | { | ||
215 | return bo->bo.offset; | ||
216 | } | ||
217 | |||
218 | int bochs_bo_pin(struct bochs_bo *bo, u32 pl_flag, u64 *gpu_addr) | ||
219 | { | 214 | { |
220 | struct ttm_operation_ctx ctx = { false, false }; | 215 | struct ttm_operation_ctx ctx = { false, false }; |
221 | int i, ret; | 216 | int i, ret; |
222 | 217 | ||
223 | if (bo->pin_count) { | 218 | if (bo->pin_count) { |
224 | bo->pin_count++; | 219 | bo->pin_count++; |
225 | if (gpu_addr) | ||
226 | *gpu_addr = bochs_bo_gpu_offset(bo); | ||
227 | return 0; | 220 | return 0; |
228 | } | 221 | } |
229 | 222 | ||
230 | bochs_ttm_placement(bo, pl_flag); | 223 | bochs_ttm_placement(bo, pl_flag); |
231 | for (i = 0; i < bo->placement.num_placement; i++) | 224 | for (i = 0; i < bo->placement.num_placement; i++) |
232 | bo->placements[i].flags |= TTM_PL_FLAG_NO_EVICT; | 225 | bo->placements[i].flags |= TTM_PL_FLAG_NO_EVICT; |
226 | ret = ttm_bo_reserve(&bo->bo, true, false, NULL); | ||
227 | if (ret) | ||
228 | return ret; | ||
233 | ret = ttm_bo_validate(&bo->bo, &bo->placement, &ctx); | 229 | ret = ttm_bo_validate(&bo->bo, &bo->placement, &ctx); |
230 | ttm_bo_unreserve(&bo->bo); | ||
234 | if (ret) | 231 | if (ret) |
235 | return ret; | 232 | return ret; |
236 | 233 | ||
237 | bo->pin_count = 1; | 234 | bo->pin_count = 1; |
238 | if (gpu_addr) | ||
239 | *gpu_addr = bochs_bo_gpu_offset(bo); | ||
240 | return 0; | 235 | return 0; |
241 | } | 236 | } |
242 | 237 | ||
@@ -256,7 +251,11 @@ int bochs_bo_unpin(struct bochs_bo *bo) | |||
256 | 251 | ||
257 | for (i = 0; i < bo->placement.num_placement; i++) | 252 | for (i = 0; i < bo->placement.num_placement; i++) |
258 | bo->placements[i].flags &= ~TTM_PL_FLAG_NO_EVICT; | 253 | bo->placements[i].flags &= ~TTM_PL_FLAG_NO_EVICT; |
254 | ret = ttm_bo_reserve(&bo->bo, true, false, NULL); | ||
255 | if (ret) | ||
256 | return ret; | ||
259 | ret = ttm_bo_validate(&bo->bo, &bo->placement, &ctx); | 257 | ret = ttm_bo_validate(&bo->bo, &bo->placement, &ctx); |
258 | ttm_bo_unreserve(&bo->bo); | ||
260 | if (ret) | 259 | if (ret) |
261 | return ret; | 260 | return ret; |
262 | 261 | ||
@@ -396,3 +395,52 @@ int bochs_dumb_mmap_offset(struct drm_file *file, struct drm_device *dev, | |||
396 | drm_gem_object_put_unlocked(obj); | 395 | drm_gem_object_put_unlocked(obj); |
397 | return 0; | 396 | return 0; |
398 | } | 397 | } |
398 | |||
399 | /* ---------------------------------------------------------------------- */ | ||
400 | |||
401 | int bochs_gem_prime_pin(struct drm_gem_object *obj) | ||
402 | { | ||
403 | struct bochs_bo *bo = gem_to_bochs_bo(obj); | ||
404 | |||
405 | return bochs_bo_pin(bo, TTM_PL_FLAG_VRAM); | ||
406 | } | ||
407 | |||
408 | void bochs_gem_prime_unpin(struct drm_gem_object *obj) | ||
409 | { | ||
410 | struct bochs_bo *bo = gem_to_bochs_bo(obj); | ||
411 | |||
412 | bochs_bo_unpin(bo); | ||
413 | } | ||
414 | |||
415 | void *bochs_gem_prime_vmap(struct drm_gem_object *obj) | ||
416 | { | ||
417 | struct bochs_bo *bo = gem_to_bochs_bo(obj); | ||
418 | bool is_iomem; | ||
419 | int ret; | ||
420 | |||
421 | ret = bochs_bo_pin(bo, TTM_PL_FLAG_VRAM); | ||
422 | if (ret) | ||
423 | return NULL; | ||
424 | ret = ttm_bo_kmap(&bo->bo, 0, bo->bo.num_pages, &bo->kmap); | ||
425 | if (ret) { | ||
426 | bochs_bo_unpin(bo); | ||
427 | return NULL; | ||
428 | } | ||
429 | return ttm_kmap_obj_virtual(&bo->kmap, &is_iomem); | ||
430 | } | ||
431 | |||
432 | void bochs_gem_prime_vunmap(struct drm_gem_object *obj, void *vaddr) | ||
433 | { | ||
434 | struct bochs_bo *bo = gem_to_bochs_bo(obj); | ||
435 | |||
436 | ttm_bo_kunmap(&bo->kmap); | ||
437 | bochs_bo_unpin(bo); | ||
438 | } | ||
439 | |||
440 | int bochs_gem_prime_mmap(struct drm_gem_object *obj, | ||
441 | struct vm_area_struct *vma) | ||
442 | { | ||
443 | struct bochs_bo *bo = gem_to_bochs_bo(obj); | ||
444 | |||
445 | return ttm_fbdev_mmap(vma, &bo->bo); | ||
446 | } | ||
diff --git a/drivers/gpu/drm/bridge/analogix-anx78xx.c b/drivers/gpu/drm/bridge/analogix-anx78xx.c index 705620e9f505..4cf7bc17ae14 100644 --- a/drivers/gpu/drm/bridge/analogix-anx78xx.c +++ b/drivers/gpu/drm/bridge/analogix-anx78xx.c | |||
@@ -1094,8 +1094,9 @@ static void anx78xx_bridge_mode_set(struct drm_bridge *bridge, | |||
1094 | 1094 | ||
1095 | mutex_lock(&anx78xx->lock); | 1095 | mutex_lock(&anx78xx->lock); |
1096 | 1096 | ||
1097 | err = drm_hdmi_avi_infoframe_from_display_mode(&frame, adjusted_mode, | 1097 | err = drm_hdmi_avi_infoframe_from_display_mode(&frame, |
1098 | false); | 1098 | &anx78xx->connector, |
1099 | adjusted_mode); | ||
1099 | if (err) { | 1100 | if (err) { |
1100 | DRM_ERROR("Failed to setup AVI infoframe: %d\n", err); | 1101 | DRM_ERROR("Failed to setup AVI infoframe: %d\n", err); |
1101 | goto unlock; | 1102 | goto unlock; |
diff --git a/drivers/gpu/drm/bridge/panel.c b/drivers/gpu/drm/bridge/panel.c index 7cbaba213ef6..37baa79e95c3 100644 --- a/drivers/gpu/drm/bridge/panel.c +++ b/drivers/gpu/drm/bridge/panel.c | |||
@@ -134,8 +134,8 @@ static const struct drm_bridge_funcs panel_bridge_bridge_funcs = { | |||
134 | }; | 134 | }; |
135 | 135 | ||
136 | /** | 136 | /** |
137 | * drm_panel_bridge_add - Creates a drm_bridge and drm_connector that | 137 | * drm_panel_bridge_add - Creates a &drm_bridge and &drm_connector that |
138 | * just calls the appropriate functions from drm_panel. | 138 | * just calls the appropriate functions from &drm_panel. |
139 | * | 139 | * |
140 | * @panel: The drm_panel being wrapped. Must be non-NULL. | 140 | * @panel: The drm_panel being wrapped. Must be non-NULL. |
141 | * @connector_type: The DRM_MODE_CONNECTOR_* for the connector to be | 141 | * @connector_type: The DRM_MODE_CONNECTOR_* for the connector to be |
@@ -149,9 +149,12 @@ static const struct drm_bridge_funcs panel_bridge_bridge_funcs = { | |||
149 | * passed to drm_bridge_attach(). The drm_panel_prepare() and related | 149 | * passed to drm_bridge_attach(). The drm_panel_prepare() and related |
150 | * functions can be dropped from the encoder driver (they're now | 150 | * functions can be dropped from the encoder driver (they're now |
151 | * called by the KMS helpers before calling into the encoder), along | 151 | * called by the KMS helpers before calling into the encoder), along |
152 | * with connector creation. When done with the bridge, | 152 | * with connector creation. When done with the bridge (after |
153 | * drm_bridge_detach() should be called as normal, then | 153 | * drm_mode_config_cleanup() if the bridge has already been attached), then |
154 | * drm_panel_bridge_remove() to free it. | 154 | * drm_panel_bridge_remove() to free it. |
155 | * | ||
156 | * See devm_drm_panel_bridge_add() for an automatically manged version of this | ||
157 | * function. | ||
155 | */ | 158 | */ |
156 | struct drm_bridge *drm_panel_bridge_add(struct drm_panel *panel, | 159 | struct drm_bridge *drm_panel_bridge_add(struct drm_panel *panel, |
157 | u32 connector_type) | 160 | u32 connector_type) |
@@ -210,6 +213,17 @@ static void devm_drm_panel_bridge_release(struct device *dev, void *res) | |||
210 | drm_panel_bridge_remove(*bridge); | 213 | drm_panel_bridge_remove(*bridge); |
211 | } | 214 | } |
212 | 215 | ||
216 | /** | ||
217 | * devm_drm_panel_bridge_add - Creates a managed &drm_bridge and &drm_connector | ||
218 | * that just calls the appropriate functions from &drm_panel. | ||
219 | * @dev: device to tie the bridge lifetime to | ||
220 | * @panel: The drm_panel being wrapped. Must be non-NULL. | ||
221 | * @connector_type: The DRM_MODE_CONNECTOR_* for the connector to be | ||
222 | * created. | ||
223 | * | ||
224 | * This is the managed version of drm_panel_bridge_add() which automatically | ||
225 | * calls drm_panel_bridge_remove() when @dev is unbound. | ||
226 | */ | ||
213 | struct drm_bridge *devm_drm_panel_bridge_add(struct device *dev, | 227 | struct drm_bridge *devm_drm_panel_bridge_add(struct device *dev, |
214 | struct drm_panel *panel, | 228 | struct drm_panel *panel, |
215 | u32 connector_type) | 229 | u32 connector_type) |
diff --git a/drivers/gpu/drm/bridge/sii902x.c b/drivers/gpu/drm/bridge/sii902x.c index a0b3a568dd9c..a5d58f7035c1 100644 --- a/drivers/gpu/drm/bridge/sii902x.c +++ b/drivers/gpu/drm/bridge/sii902x.c | |||
@@ -258,7 +258,8 @@ static void sii902x_bridge_mode_set(struct drm_bridge *bridge, | |||
258 | if (ret) | 258 | if (ret) |
259 | return; | 259 | return; |
260 | 260 | ||
261 | ret = drm_hdmi_avi_infoframe_from_display_mode(&frame, adj, false); | 261 | ret = drm_hdmi_avi_infoframe_from_display_mode(&frame, |
262 | &sii902x->connector, adj); | ||
262 | if (ret < 0) { | 263 | if (ret < 0) { |
263 | DRM_ERROR("couldn't fill AVI infoframe\n"); | 264 | DRM_ERROR("couldn't fill AVI infoframe\n"); |
264 | return; | 265 | return; |
diff --git a/drivers/gpu/drm/bridge/sil-sii8620.c b/drivers/gpu/drm/bridge/sil-sii8620.c index a6e8f4591e63..0cc293a6ac24 100644 --- a/drivers/gpu/drm/bridge/sil-sii8620.c +++ b/drivers/gpu/drm/bridge/sil-sii8620.c | |||
@@ -1104,8 +1104,7 @@ static void sii8620_set_infoframes(struct sii8620 *ctx, | |||
1104 | int ret; | 1104 | int ret; |
1105 | 1105 | ||
1106 | ret = drm_hdmi_avi_infoframe_from_display_mode(&frm.avi, | 1106 | ret = drm_hdmi_avi_infoframe_from_display_mode(&frm.avi, |
1107 | mode, | 1107 | NULL, mode); |
1108 | true); | ||
1109 | if (ctx->use_packed_pixel) | 1108 | if (ctx->use_packed_pixel) |
1110 | frm.avi.colorspace = HDMI_COLORSPACE_YUV422; | 1109 | frm.avi.colorspace = HDMI_COLORSPACE_YUV422; |
1111 | 1110 | ||
diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-i2s-audio.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-i2s-audio.c index 2228689d9a5e..5cbb71a866d5 100644 --- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-i2s-audio.c +++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-i2s-audio.c | |||
@@ -5,6 +5,10 @@ | |||
5 | * Copyright (c) 2017 Renesas Solutions Corp. | 5 | * Copyright (c) 2017 Renesas Solutions Corp. |
6 | * Kuninori Morimoto <kuninori.morimoto.gx@renesas.com> | 6 | * Kuninori Morimoto <kuninori.morimoto.gx@renesas.com> |
7 | */ | 7 | */ |
8 | |||
9 | #include <linux/dma-mapping.h> | ||
10 | #include <linux/module.h> | ||
11 | |||
8 | #include <drm/bridge/dw_hdmi.h> | 12 | #include <drm/bridge/dw_hdmi.h> |
9 | 13 | ||
10 | #include <sound/hdmi-codec.h> | 14 | #include <sound/hdmi-codec.h> |
diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c index 4fed3eda6ded..129f464cbeb1 100644 --- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c +++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | |||
@@ -1344,7 +1344,8 @@ static void hdmi_config_AVI(struct dw_hdmi *hdmi, struct drm_display_mode *mode) | |||
1344 | u8 val; | 1344 | u8 val; |
1345 | 1345 | ||
1346 | /* Initialise info frame from DRM mode */ | 1346 | /* Initialise info frame from DRM mode */ |
1347 | drm_hdmi_avi_infoframe_from_display_mode(&frame, mode, false); | 1347 | drm_hdmi_avi_infoframe_from_display_mode(&frame, |
1348 | &hdmi->connector, mode); | ||
1348 | 1349 | ||
1349 | if (hdmi_bus_fmt_is_yuv444(hdmi->hdmi_data.enc_out_bus_format)) | 1350 | if (hdmi_bus_fmt_is_yuv444(hdmi->hdmi_data.enc_out_bus_format)) |
1350 | frame.colorspace = HDMI_COLORSPACE_YUV444; | 1351 | frame.colorspace = HDMI_COLORSPACE_YUV444; |
diff --git a/drivers/gpu/drm/cirrus/cirrus_fbdev.c b/drivers/gpu/drm/cirrus/cirrus_fbdev.c index 4dd499c7d1ba..39df62acac69 100644 --- a/drivers/gpu/drm/cirrus/cirrus_fbdev.c +++ b/drivers/gpu/drm/cirrus/cirrus_fbdev.c | |||
@@ -10,6 +10,7 @@ | |||
10 | */ | 10 | */ |
11 | #include <linux/module.h> | 11 | #include <linux/module.h> |
12 | #include <drm/drmP.h> | 12 | #include <drm/drmP.h> |
13 | #include <drm/drm_util.h> | ||
13 | #include <drm/drm_fb_helper.h> | 14 | #include <drm/drm_fb_helper.h> |
14 | #include <drm/drm_crtc_helper.h> | 15 | #include <drm/drm_crtc_helper.h> |
15 | 16 | ||
@@ -256,6 +257,8 @@ static int cirrus_fbdev_destroy(struct drm_device *dev, | |||
256 | { | 257 | { |
257 | struct drm_framebuffer *gfb = gfbdev->gfb; | 258 | struct drm_framebuffer *gfb = gfbdev->gfb; |
258 | 259 | ||
260 | drm_helper_force_disable_all(dev); | ||
261 | |||
259 | drm_fb_helper_unregister_fbi(&gfbdev->helper); | 262 | drm_fb_helper_unregister_fbi(&gfbdev->helper); |
260 | 263 | ||
261 | vfree(gfbdev->sysram); | 264 | vfree(gfbdev->sysram); |
diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index 1593dd6cdfb7..7dabbaf033a1 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c | |||
@@ -93,15 +93,6 @@ struct drm_crtc *drm_crtc_from_index(struct drm_device *dev, int idx) | |||
93 | } | 93 | } |
94 | EXPORT_SYMBOL(drm_crtc_from_index); | 94 | EXPORT_SYMBOL(drm_crtc_from_index); |
95 | 95 | ||
96 | /** | ||
97 | * drm_crtc_force_disable - Forcibly turn off a CRTC | ||
98 | * @crtc: CRTC to turn off | ||
99 | * | ||
100 | * Note: This should only be used by non-atomic legacy drivers. | ||
101 | * | ||
102 | * Returns: | ||
103 | * Zero on success, error code on failure. | ||
104 | */ | ||
105 | int drm_crtc_force_disable(struct drm_crtc *crtc) | 96 | int drm_crtc_force_disable(struct drm_crtc *crtc) |
106 | { | 97 | { |
107 | struct drm_mode_set set = { | 98 | struct drm_mode_set set = { |
@@ -112,38 +103,6 @@ int drm_crtc_force_disable(struct drm_crtc *crtc) | |||
112 | 103 | ||
113 | return drm_mode_set_config_internal(&set); | 104 | return drm_mode_set_config_internal(&set); |
114 | } | 105 | } |
115 | EXPORT_SYMBOL(drm_crtc_force_disable); | ||
116 | |||
117 | /** | ||
118 | * drm_crtc_force_disable_all - Forcibly turn off all enabled CRTCs | ||
119 | * @dev: DRM device whose CRTCs to turn off | ||
120 | * | ||
121 | * Drivers may want to call this on unload to ensure that all displays are | ||
122 | * unlit and the GPU is in a consistent, low power state. Takes modeset locks. | ||
123 | * | ||
124 | * Note: This should only be used by non-atomic legacy drivers. For an atomic | ||
125 | * version look at drm_atomic_helper_shutdown(). | ||
126 | * | ||
127 | * Returns: | ||
128 | * Zero on success, error code on failure. | ||
129 | */ | ||
130 | int drm_crtc_force_disable_all(struct drm_device *dev) | ||
131 | { | ||
132 | struct drm_crtc *crtc; | ||
133 | int ret = 0; | ||
134 | |||
135 | drm_modeset_lock_all(dev); | ||
136 | drm_for_each_crtc(crtc, dev) | ||
137 | if (crtc->enabled) { | ||
138 | ret = drm_crtc_force_disable(crtc); | ||
139 | if (ret) | ||
140 | goto out; | ||
141 | } | ||
142 | out: | ||
143 | drm_modeset_unlock_all(dev); | ||
144 | return ret; | ||
145 | } | ||
146 | EXPORT_SYMBOL(drm_crtc_force_disable_all); | ||
147 | 106 | ||
148 | static unsigned int drm_num_crtcs(struct drm_device *dev) | 107 | static unsigned int drm_num_crtcs(struct drm_device *dev) |
149 | { | 108 | { |
diff --git a/drivers/gpu/drm/drm_crtc_helper.c b/drivers/gpu/drm/drm_crtc_helper.c index a3c81850e755..747661f63fbb 100644 --- a/drivers/gpu/drm/drm_crtc_helper.c +++ b/drivers/gpu/drm/drm_crtc_helper.c | |||
@@ -93,6 +93,8 @@ bool drm_helper_encoder_in_use(struct drm_encoder *encoder) | |||
93 | struct drm_connector_list_iter conn_iter; | 93 | struct drm_connector_list_iter conn_iter; |
94 | struct drm_device *dev = encoder->dev; | 94 | struct drm_device *dev = encoder->dev; |
95 | 95 | ||
96 | WARN_ON(drm_drv_uses_atomic_modeset(dev)); | ||
97 | |||
96 | /* | 98 | /* |
97 | * We can expect this mutex to be locked if we are not panicking. | 99 | * We can expect this mutex to be locked if we are not panicking. |
98 | * Locking is currently fubar in the panic handler. | 100 | * Locking is currently fubar in the panic handler. |
@@ -131,6 +133,8 @@ bool drm_helper_crtc_in_use(struct drm_crtc *crtc) | |||
131 | struct drm_encoder *encoder; | 133 | struct drm_encoder *encoder; |
132 | struct drm_device *dev = crtc->dev; | 134 | struct drm_device *dev = crtc->dev; |
133 | 135 | ||
136 | WARN_ON(drm_drv_uses_atomic_modeset(dev)); | ||
137 | |||
134 | /* | 138 | /* |
135 | * We can expect this mutex to be locked if we are not panicking. | 139 | * We can expect this mutex to be locked if we are not panicking. |
136 | * Locking is currently fubar in the panic handler. | 140 | * Locking is currently fubar in the panic handler. |
@@ -212,8 +216,7 @@ static void __drm_helper_disable_unused_functions(struct drm_device *dev) | |||
212 | */ | 216 | */ |
213 | void drm_helper_disable_unused_functions(struct drm_device *dev) | 217 | void drm_helper_disable_unused_functions(struct drm_device *dev) |
214 | { | 218 | { |
215 | if (drm_core_check_feature(dev, DRIVER_ATOMIC)) | 219 | WARN_ON(drm_drv_uses_atomic_modeset(dev)); |
216 | DRM_ERROR("Called for atomic driver, this is not what you want.\n"); | ||
217 | 220 | ||
218 | drm_modeset_lock_all(dev); | 221 | drm_modeset_lock_all(dev); |
219 | __drm_helper_disable_unused_functions(dev); | 222 | __drm_helper_disable_unused_functions(dev); |
@@ -281,6 +284,8 @@ bool drm_crtc_helper_set_mode(struct drm_crtc *crtc, | |||
281 | struct drm_encoder *encoder; | 284 | struct drm_encoder *encoder; |
282 | bool ret = true; | 285 | bool ret = true; |
283 | 286 | ||
287 | WARN_ON(drm_drv_uses_atomic_modeset(dev)); | ||
288 | |||
284 | drm_warn_on_modeset_not_all_locked(dev); | 289 | drm_warn_on_modeset_not_all_locked(dev); |
285 | 290 | ||
286 | saved_enabled = crtc->enabled; | 291 | saved_enabled = crtc->enabled; |
@@ -386,9 +391,8 @@ bool drm_crtc_helper_set_mode(struct drm_crtc *crtc, | |||
386 | if (!encoder_funcs) | 391 | if (!encoder_funcs) |
387 | continue; | 392 | continue; |
388 | 393 | ||
389 | DRM_DEBUG_KMS("[ENCODER:%d:%s] set [MODE:%d:%s]\n", | 394 | DRM_DEBUG_KMS("[ENCODER:%d:%s] set [MODE:%s]\n", |
390 | encoder->base.id, encoder->name, | 395 | encoder->base.id, encoder->name, mode->name); |
391 | mode->base.id, mode->name); | ||
392 | if (encoder_funcs->mode_set) | 396 | if (encoder_funcs->mode_set) |
393 | encoder_funcs->mode_set(encoder, mode, adjusted_mode); | 397 | encoder_funcs->mode_set(encoder, mode, adjusted_mode); |
394 | 398 | ||
@@ -540,6 +544,9 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set, | |||
540 | 544 | ||
541 | crtc_funcs = set->crtc->helper_private; | 545 | crtc_funcs = set->crtc->helper_private; |
542 | 546 | ||
547 | dev = set->crtc->dev; | ||
548 | WARN_ON(drm_drv_uses_atomic_modeset(dev)); | ||
549 | |||
543 | if (!set->mode) | 550 | if (!set->mode) |
544 | set->fb = NULL; | 551 | set->fb = NULL; |
545 | 552 | ||
@@ -555,8 +562,6 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set, | |||
555 | return 0; | 562 | return 0; |
556 | } | 563 | } |
557 | 564 | ||
558 | dev = set->crtc->dev; | ||
559 | |||
560 | drm_warn_on_modeset_not_all_locked(dev); | 565 | drm_warn_on_modeset_not_all_locked(dev); |
561 | 566 | ||
562 | /* | 567 | /* |
@@ -875,6 +880,8 @@ int drm_helper_connector_dpms(struct drm_connector *connector, int mode) | |||
875 | struct drm_crtc *crtc = encoder ? encoder->crtc : NULL; | 880 | struct drm_crtc *crtc = encoder ? encoder->crtc : NULL; |
876 | int old_dpms, encoder_dpms = DRM_MODE_DPMS_OFF; | 881 | int old_dpms, encoder_dpms = DRM_MODE_DPMS_OFF; |
877 | 882 | ||
883 | WARN_ON(drm_drv_uses_atomic_modeset(connector->dev)); | ||
884 | |||
878 | if (mode == connector->dpms) | 885 | if (mode == connector->dpms) |
879 | return 0; | 886 | return 0; |
880 | 887 | ||
@@ -946,6 +953,8 @@ void drm_helper_resume_force_mode(struct drm_device *dev) | |||
946 | int encoder_dpms; | 953 | int encoder_dpms; |
947 | bool ret; | 954 | bool ret; |
948 | 955 | ||
956 | WARN_ON(drm_drv_uses_atomic_modeset(dev)); | ||
957 | |||
949 | drm_modeset_lock_all(dev); | 958 | drm_modeset_lock_all(dev); |
950 | drm_for_each_crtc(crtc, dev) { | 959 | drm_for_each_crtc(crtc, dev) { |
951 | 960 | ||
@@ -984,3 +993,38 @@ void drm_helper_resume_force_mode(struct drm_device *dev) | |||
984 | drm_modeset_unlock_all(dev); | 993 | drm_modeset_unlock_all(dev); |
985 | } | 994 | } |
986 | EXPORT_SYMBOL(drm_helper_resume_force_mode); | 995 | EXPORT_SYMBOL(drm_helper_resume_force_mode); |
996 | |||
997 | /** | ||
998 | * drm_helper_force_disable_all - Forcibly turn off all enabled CRTCs | ||
999 | * @dev: DRM device whose CRTCs to turn off | ||
1000 | * | ||
1001 | * Drivers may want to call this on unload to ensure that all displays are | ||
1002 | * unlit and the GPU is in a consistent, low power state. Takes modeset locks. | ||
1003 | * | ||
1004 | * Note: This should only be used by non-atomic legacy drivers. For an atomic | ||
1005 | * version look at drm_atomic_helper_shutdown(). | ||
1006 | * | ||
1007 | * Returns: | ||
1008 | * Zero on success, error code on failure. | ||
1009 | */ | ||
1010 | int drm_helper_force_disable_all(struct drm_device *dev) | ||
1011 | { | ||
1012 | struct drm_crtc *crtc; | ||
1013 | int ret = 0; | ||
1014 | |||
1015 | drm_modeset_lock_all(dev); | ||
1016 | drm_for_each_crtc(crtc, dev) | ||
1017 | if (crtc->enabled) { | ||
1018 | struct drm_mode_set set = { | ||
1019 | .crtc = crtc, | ||
1020 | }; | ||
1021 | |||
1022 | ret = drm_mode_set_config_internal(&set); | ||
1023 | if (ret) | ||
1024 | goto out; | ||
1025 | } | ||
1026 | out: | ||
1027 | drm_modeset_unlock_all(dev); | ||
1028 | return ret; | ||
1029 | } | ||
1030 | EXPORT_SYMBOL(drm_helper_force_disable_all); | ||
diff --git a/drivers/gpu/drm/drm_crtc_internal.h b/drivers/gpu/drm/drm_crtc_internal.h index 86893448f486..216f2a9ee3d4 100644 --- a/drivers/gpu/drm/drm_crtc_internal.h +++ b/drivers/gpu/drm/drm_crtc_internal.h | |||
@@ -50,6 +50,7 @@ int drm_crtc_check_viewport(const struct drm_crtc *crtc, | |||
50 | const struct drm_framebuffer *fb); | 50 | const struct drm_framebuffer *fb); |
51 | int drm_crtc_register_all(struct drm_device *dev); | 51 | int drm_crtc_register_all(struct drm_device *dev); |
52 | void drm_crtc_unregister_all(struct drm_device *dev); | 52 | void drm_crtc_unregister_all(struct drm_device *dev); |
53 | int drm_crtc_force_disable(struct drm_crtc *crtc); | ||
53 | 54 | ||
54 | struct dma_fence *drm_crtc_create_fence(struct drm_crtc *crtc); | 55 | struct dma_fence *drm_crtc_create_fence(struct drm_crtc *crtc); |
55 | 56 | ||
diff --git a/drivers/gpu/drm/drm_dp_helper.c b/drivers/gpu/drm/drm_dp_helper.c index 2d6c491a0542..f51a116543f7 100644 --- a/drivers/gpu/drm/drm_dp_helper.c +++ b/drivers/gpu/drm/drm_dp_helper.c | |||
@@ -154,6 +154,7 @@ u8 drm_dp_link_rate_to_bw_code(int link_rate) | |||
154 | default: | 154 | default: |
155 | WARN(1, "unknown DP link rate %d, using %x\n", link_rate, | 155 | WARN(1, "unknown DP link rate %d, using %x\n", link_rate, |
156 | DP_LINK_BW_1_62); | 156 | DP_LINK_BW_1_62); |
157 | /* fall through */ | ||
157 | case 162000: | 158 | case 162000: |
158 | return DP_LINK_BW_1_62; | 159 | return DP_LINK_BW_1_62; |
159 | case 270000: | 160 | case 270000: |
@@ -171,6 +172,7 @@ int drm_dp_bw_code_to_link_rate(u8 link_bw) | |||
171 | switch (link_bw) { | 172 | switch (link_bw) { |
172 | default: | 173 | default: |
173 | WARN(1, "unknown DP link BW code %x, using 162000\n", link_bw); | 174 | WARN(1, "unknown DP link BW code %x, using 162000\n", link_bw); |
175 | /* fall through */ | ||
174 | case DP_LINK_BW_1_62: | 176 | case DP_LINK_BW_1_62: |
175 | return 162000; | 177 | return 162000; |
176 | case DP_LINK_BW_2_7: | 178 | case DP_LINK_BW_2_7: |
@@ -552,6 +554,7 @@ int drm_dp_downstream_max_bpc(const u8 dpcd[DP_RECEIVER_CAP_SIZE], | |||
552 | case DP_DS_16BPC: | 554 | case DP_DS_16BPC: |
553 | return 16; | 555 | return 16; |
554 | } | 556 | } |
557 | /* fall through */ | ||
555 | default: | 558 | default: |
556 | return 0; | 559 | return 0; |
557 | } | 560 | } |
diff --git a/drivers/gpu/drm/drm_dp_mst_topology.c b/drivers/gpu/drm/drm_dp_mst_topology.c index 2ab16c9e6243..196ebba8af5f 100644 --- a/drivers/gpu/drm/drm_dp_mst_topology.c +++ b/drivers/gpu/drm/drm_dp_mst_topology.c | |||
@@ -46,7 +46,7 @@ static bool dump_dp_payload_table(struct drm_dp_mst_topology_mgr *mgr, | |||
46 | char *buf); | 46 | char *buf); |
47 | static int test_calc_pbn_mode(void); | 47 | static int test_calc_pbn_mode(void); |
48 | 48 | ||
49 | static void drm_dp_put_port(struct drm_dp_mst_port *port); | 49 | static void drm_dp_mst_topology_put_port(struct drm_dp_mst_port *port); |
50 | 50 | ||
51 | static int drm_dp_dpcd_write_payload(struct drm_dp_mst_topology_mgr *mgr, | 51 | static int drm_dp_dpcd_write_payload(struct drm_dp_mst_topology_mgr *mgr, |
52 | int id, | 52 | int id, |
@@ -850,46 +850,212 @@ static struct drm_dp_mst_branch *drm_dp_add_mst_branch_device(u8 lct, u8 *rad) | |||
850 | if (lct > 1) | 850 | if (lct > 1) |
851 | memcpy(mstb->rad, rad, lct / 2); | 851 | memcpy(mstb->rad, rad, lct / 2); |
852 | INIT_LIST_HEAD(&mstb->ports); | 852 | INIT_LIST_HEAD(&mstb->ports); |
853 | kref_init(&mstb->kref); | 853 | kref_init(&mstb->topology_kref); |
854 | kref_init(&mstb->malloc_kref); | ||
854 | return mstb; | 855 | return mstb; |
855 | } | 856 | } |
856 | 857 | ||
857 | static void drm_dp_free_mst_port(struct kref *kref); | ||
858 | |||
859 | static void drm_dp_free_mst_branch_device(struct kref *kref) | 858 | static void drm_dp_free_mst_branch_device(struct kref *kref) |
860 | { | 859 | { |
861 | struct drm_dp_mst_branch *mstb = container_of(kref, struct drm_dp_mst_branch, kref); | 860 | struct drm_dp_mst_branch *mstb = |
862 | if (mstb->port_parent) { | 861 | container_of(kref, struct drm_dp_mst_branch, malloc_kref); |
863 | if (list_empty(&mstb->port_parent->next)) | 862 | |
864 | kref_put(&mstb->port_parent->kref, drm_dp_free_mst_port); | 863 | if (mstb->port_parent) |
865 | } | 864 | drm_dp_mst_put_port_malloc(mstb->port_parent); |
865 | |||
866 | kfree(mstb); | 866 | kfree(mstb); |
867 | } | 867 | } |
868 | 868 | ||
869 | /** | ||
870 | * DOC: Branch device and port refcounting | ||
871 | * | ||
872 | * Topology refcount overview | ||
873 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
874 | * | ||
875 | * The refcounting schemes for &struct drm_dp_mst_branch and &struct | ||
876 | * drm_dp_mst_port are somewhat unusual. Both ports and branch devices have | ||
877 | * two different kinds of refcounts: topology refcounts, and malloc refcounts. | ||
878 | * | ||
879 | * Topology refcounts are not exposed to drivers, and are handled internally | ||
880 | * by the DP MST helpers. The helpers use them in order to prevent the | ||
881 | * in-memory topology state from being changed in the middle of critical | ||
882 | * operations like changing the internal state of payload allocations. This | ||
883 | * means each branch and port will be considered to be connected to the rest | ||
884 | * of the topology until it's topology refcount reaches zero. Additionally, | ||
885 | * for ports this means that their associated &struct drm_connector will stay | ||
886 | * registered with userspace until the port's refcount reaches 0. | ||
887 | * | ||
888 | * Malloc refcount overview | ||
889 | * ~~~~~~~~~~~~~~~~~~~~~~~~ | ||
890 | * | ||
891 | * Malloc references are used to keep a &struct drm_dp_mst_port or &struct | ||
892 | * drm_dp_mst_branch allocated even after all of its topology references have | ||
893 | * been dropped, so that the driver or MST helpers can safely access each | ||
894 | * branch's last known state before it was disconnected from the topology. | ||
895 | * When the malloc refcount of a port or branch reaches 0, the memory | ||
896 | * allocation containing the &struct drm_dp_mst_branch or &struct | ||
897 | * drm_dp_mst_port respectively will be freed. | ||
898 | * | ||
899 | * For &struct drm_dp_mst_branch, malloc refcounts are not currently exposed | ||
900 | * to drivers. As of writing this documentation, there are no drivers that | ||
901 | * have a usecase for accessing &struct drm_dp_mst_branch outside of the MST | ||
902 | * helpers. Exposing this API to drivers in a race-free manner would take more | ||
903 | * tweaking of the refcounting scheme, however patches are welcome provided | ||
904 | * there is a legitimate driver usecase for this. | ||
905 | * | ||
906 | * Refcount relationships in a topology | ||
907 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
908 | * | ||
909 | * Let's take a look at why the relationship between topology and malloc | ||
910 | * refcounts is designed the way it is. | ||
911 | * | ||
912 | * .. kernel-figure:: dp-mst/topology-figure-1.dot | ||
913 | * | ||
914 | * An example of topology and malloc refs in a DP MST topology with two | ||
915 | * active payloads. Topology refcount increments are indicated by solid | ||
916 | * lines, and malloc refcount increments are indicated by dashed lines. | ||
917 | * Each starts from the branch which incremented the refcount, and ends at | ||
918 | * the branch to which the refcount belongs to, i.e. the arrow points the | ||
919 | * same way as the C pointers used to reference a structure. | ||
920 | * | ||
921 | * As you can see in the above figure, every branch increments the topology | ||
922 | * refcount of it's children, and increments the malloc refcount of it's | ||
923 | * parent. Additionally, every payload increments the malloc refcount of it's | ||
924 | * assigned port by 1. | ||
925 | * | ||
926 | * So, what would happen if MSTB #3 from the above figure was unplugged from | ||
927 | * the system, but the driver hadn't yet removed payload #2 from port #3? The | ||
928 | * topology would start to look like the figure below. | ||
929 | * | ||
930 | * .. kernel-figure:: dp-mst/topology-figure-2.dot | ||
931 | * | ||
932 | * Ports and branch devices which have been released from memory are | ||
933 | * colored grey, and references which have been removed are colored red. | ||
934 | * | ||
935 | * Whenever a port or branch device's topology refcount reaches zero, it will | ||
936 | * decrement the topology refcounts of all its children, the malloc refcount | ||
937 | * of its parent, and finally its own malloc refcount. For MSTB #4 and port | ||
938 | * #4, this means they both have been disconnected from the topology and freed | ||
939 | * from memory. But, because payload #2 is still holding a reference to port | ||
940 | * #3, port #3 is removed from the topology but it's &struct drm_dp_mst_port | ||
941 | * is still accessible from memory. This also means port #3 has not yet | ||
942 | * decremented the malloc refcount of MSTB #3, so it's &struct | ||
943 | * drm_dp_mst_branch will also stay allocated in memory until port #3's | ||
944 | * malloc refcount reaches 0. | ||
945 | * | ||
946 | * This relationship is necessary because in order to release payload #2, we | ||
947 | * need to be able to figure out the last relative of port #3 that's still | ||
948 | * connected to the topology. In this case, we would travel up the topology as | ||
949 | * shown below. | ||
950 | * | ||
951 | * .. kernel-figure:: dp-mst/topology-figure-3.dot | ||
952 | * | ||
953 | * And finally, remove payload #2 by communicating with port #2 through | ||
954 | * sideband transactions. | ||
955 | */ | ||
956 | |||
957 | /** | ||
958 | * drm_dp_mst_get_mstb_malloc() - Increment the malloc refcount of a branch | ||
959 | * device | ||
960 | * @mstb: The &struct drm_dp_mst_branch to increment the malloc refcount of | ||
961 | * | ||
962 | * Increments &drm_dp_mst_branch.malloc_kref. When | ||
963 | * &drm_dp_mst_branch.malloc_kref reaches 0, the memory allocation for @mstb | ||
964 | * will be released and @mstb may no longer be used. | ||
965 | * | ||
966 | * See also: drm_dp_mst_put_mstb_malloc() | ||
967 | */ | ||
968 | static void | ||
969 | drm_dp_mst_get_mstb_malloc(struct drm_dp_mst_branch *mstb) | ||
970 | { | ||
971 | kref_get(&mstb->malloc_kref); | ||
972 | DRM_DEBUG("mstb %p (%d)\n", mstb, kref_read(&mstb->malloc_kref)); | ||
973 | } | ||
974 | |||
975 | /** | ||
976 | * drm_dp_mst_put_mstb_malloc() - Decrement the malloc refcount of a branch | ||
977 | * device | ||
978 | * @mstb: The &struct drm_dp_mst_branch to decrement the malloc refcount of | ||
979 | * | ||
980 | * Decrements &drm_dp_mst_branch.malloc_kref. When | ||
981 | * &drm_dp_mst_branch.malloc_kref reaches 0, the memory allocation for @mstb | ||
982 | * will be released and @mstb may no longer be used. | ||
983 | * | ||
984 | * See also: drm_dp_mst_get_mstb_malloc() | ||
985 | */ | ||
986 | static void | ||
987 | drm_dp_mst_put_mstb_malloc(struct drm_dp_mst_branch *mstb) | ||
988 | { | ||
989 | DRM_DEBUG("mstb %p (%d)\n", mstb, kref_read(&mstb->malloc_kref) - 1); | ||
990 | kref_put(&mstb->malloc_kref, drm_dp_free_mst_branch_device); | ||
991 | } | ||
992 | |||
993 | static void drm_dp_free_mst_port(struct kref *kref) | ||
994 | { | ||
995 | struct drm_dp_mst_port *port = | ||
996 | container_of(kref, struct drm_dp_mst_port, malloc_kref); | ||
997 | |||
998 | drm_dp_mst_put_mstb_malloc(port->parent); | ||
999 | kfree(port); | ||
1000 | } | ||
1001 | |||
1002 | /** | ||
1003 | * drm_dp_mst_get_port_malloc() - Increment the malloc refcount of an MST port | ||
1004 | * @port: The &struct drm_dp_mst_port to increment the malloc refcount of | ||
1005 | * | ||
1006 | * Increments &drm_dp_mst_port.malloc_kref. When &drm_dp_mst_port.malloc_kref | ||
1007 | * reaches 0, the memory allocation for @port will be released and @port may | ||
1008 | * no longer be used. | ||
1009 | * | ||
1010 | * Because @port could potentially be freed at any time by the DP MST helpers | ||
1011 | * if &drm_dp_mst_port.malloc_kref reaches 0, including during a call to this | ||
1012 | * function, drivers that which to make use of &struct drm_dp_mst_port should | ||
1013 | * ensure that they grab at least one main malloc reference to their MST ports | ||
1014 | * in &drm_dp_mst_topology_cbs.add_connector. This callback is called before | ||
1015 | * there is any chance for &drm_dp_mst_port.malloc_kref to reach 0. | ||
1016 | * | ||
1017 | * See also: drm_dp_mst_put_port_malloc() | ||
1018 | */ | ||
1019 | void | ||
1020 | drm_dp_mst_get_port_malloc(struct drm_dp_mst_port *port) | ||
1021 | { | ||
1022 | kref_get(&port->malloc_kref); | ||
1023 | DRM_DEBUG("port %p (%d)\n", port, kref_read(&port->malloc_kref)); | ||
1024 | } | ||
1025 | EXPORT_SYMBOL(drm_dp_mst_get_port_malloc); | ||
1026 | |||
1027 | /** | ||
1028 | * drm_dp_mst_put_port_malloc() - Decrement the malloc refcount of an MST port | ||
1029 | * @port: The &struct drm_dp_mst_port to decrement the malloc refcount of | ||
1030 | * | ||
1031 | * Decrements &drm_dp_mst_port.malloc_kref. When &drm_dp_mst_port.malloc_kref | ||
1032 | * reaches 0, the memory allocation for @port will be released and @port may | ||
1033 | * no longer be used. | ||
1034 | * | ||
1035 | * See also: drm_dp_mst_get_port_malloc() | ||
1036 | */ | ||
1037 | void | ||
1038 | drm_dp_mst_put_port_malloc(struct drm_dp_mst_port *port) | ||
1039 | { | ||
1040 | DRM_DEBUG("port %p (%d)\n", port, kref_read(&port->malloc_kref) - 1); | ||
1041 | kref_put(&port->malloc_kref, drm_dp_free_mst_port); | ||
1042 | } | ||
1043 | EXPORT_SYMBOL(drm_dp_mst_put_port_malloc); | ||
1044 | |||
869 | static void drm_dp_destroy_mst_branch_device(struct kref *kref) | 1045 | static void drm_dp_destroy_mst_branch_device(struct kref *kref) |
870 | { | 1046 | { |
871 | struct drm_dp_mst_branch *mstb = container_of(kref, struct drm_dp_mst_branch, kref); | 1047 | struct drm_dp_mst_branch *mstb = |
1048 | container_of(kref, struct drm_dp_mst_branch, topology_kref); | ||
1049 | struct drm_dp_mst_topology_mgr *mgr = mstb->mgr; | ||
872 | struct drm_dp_mst_port *port, *tmp; | 1050 | struct drm_dp_mst_port *port, *tmp; |
873 | bool wake_tx = false; | 1051 | bool wake_tx = false; |
874 | 1052 | ||
875 | /* | 1053 | mutex_lock(&mgr->lock); |
876 | * init kref again to be used by ports to remove mst branch when it is | ||
877 | * not needed anymore | ||
878 | */ | ||
879 | kref_init(kref); | ||
880 | |||
881 | if (mstb->port_parent && list_empty(&mstb->port_parent->next)) | ||
882 | kref_get(&mstb->port_parent->kref); | ||
883 | |||
884 | /* | ||
885 | * destroy all ports - don't need lock | ||
886 | * as there are no more references to the mst branch | ||
887 | * device at this point. | ||
888 | */ | ||
889 | list_for_each_entry_safe(port, tmp, &mstb->ports, next) { | 1054 | list_for_each_entry_safe(port, tmp, &mstb->ports, next) { |
890 | list_del(&port->next); | 1055 | list_del(&port->next); |
891 | drm_dp_put_port(port); | 1056 | drm_dp_mst_topology_put_port(port); |
892 | } | 1057 | } |
1058 | mutex_unlock(&mgr->lock); | ||
893 | 1059 | ||
894 | /* drop any tx slots msg */ | 1060 | /* drop any tx slots msg */ |
895 | mutex_lock(&mstb->mgr->qlock); | 1061 | mutex_lock(&mstb->mgr->qlock); |
@@ -908,14 +1074,83 @@ static void drm_dp_destroy_mst_branch_device(struct kref *kref) | |||
908 | if (wake_tx) | 1074 | if (wake_tx) |
909 | wake_up_all(&mstb->mgr->tx_waitq); | 1075 | wake_up_all(&mstb->mgr->tx_waitq); |
910 | 1076 | ||
911 | kref_put(kref, drm_dp_free_mst_branch_device); | 1077 | drm_dp_mst_put_mstb_malloc(mstb); |
912 | } | 1078 | } |
913 | 1079 | ||
914 | static void drm_dp_put_mst_branch_device(struct drm_dp_mst_branch *mstb) | 1080 | /** |
1081 | * drm_dp_mst_topology_try_get_mstb() - Increment the topology refcount of a | ||
1082 | * branch device unless its zero | ||
1083 | * @mstb: &struct drm_dp_mst_branch to increment the topology refcount of | ||
1084 | * | ||
1085 | * Attempts to grab a topology reference to @mstb, if it hasn't yet been | ||
1086 | * removed from the topology (e.g. &drm_dp_mst_branch.topology_kref has | ||
1087 | * reached 0). Holding a topology reference implies that a malloc reference | ||
1088 | * will be held to @mstb as long as the user holds the topology reference. | ||
1089 | * | ||
1090 | * Care should be taken to ensure that the user has at least one malloc | ||
1091 | * reference to @mstb. If you already have a topology reference to @mstb, you | ||
1092 | * should use drm_dp_mst_topology_get_mstb() instead. | ||
1093 | * | ||
1094 | * See also: | ||
1095 | * drm_dp_mst_topology_get_mstb() | ||
1096 | * drm_dp_mst_topology_put_mstb() | ||
1097 | * | ||
1098 | * Returns: | ||
1099 | * * 1: A topology reference was grabbed successfully | ||
1100 | * * 0: @port is no longer in the topology, no reference was grabbed | ||
1101 | */ | ||
1102 | static int __must_check | ||
1103 | drm_dp_mst_topology_try_get_mstb(struct drm_dp_mst_branch *mstb) | ||
915 | { | 1104 | { |
916 | kref_put(&mstb->kref, drm_dp_destroy_mst_branch_device); | 1105 | int ret = kref_get_unless_zero(&mstb->topology_kref); |
1106 | |||
1107 | if (ret) | ||
1108 | DRM_DEBUG("mstb %p (%d)\n", mstb, | ||
1109 | kref_read(&mstb->topology_kref)); | ||
1110 | |||
1111 | return ret; | ||
917 | } | 1112 | } |
918 | 1113 | ||
1114 | /** | ||
1115 | * drm_dp_mst_topology_get_mstb() - Increment the topology refcount of a | ||
1116 | * branch device | ||
1117 | * @mstb: The &struct drm_dp_mst_branch to increment the topology refcount of | ||
1118 | * | ||
1119 | * Increments &drm_dp_mst_branch.topology_refcount without checking whether or | ||
1120 | * not it's already reached 0. This is only valid to use in scenarios where | ||
1121 | * you are already guaranteed to have at least one active topology reference | ||
1122 | * to @mstb. Otherwise, drm_dp_mst_topology_try_get_mstb() must be used. | ||
1123 | * | ||
1124 | * See also: | ||
1125 | * drm_dp_mst_topology_try_get_mstb() | ||
1126 | * drm_dp_mst_topology_put_mstb() | ||
1127 | */ | ||
1128 | static void drm_dp_mst_topology_get_mstb(struct drm_dp_mst_branch *mstb) | ||
1129 | { | ||
1130 | WARN_ON(kref_read(&mstb->topology_kref) == 0); | ||
1131 | kref_get(&mstb->topology_kref); | ||
1132 | DRM_DEBUG("mstb %p (%d)\n", mstb, kref_read(&mstb->topology_kref)); | ||
1133 | } | ||
1134 | |||
1135 | /** | ||
1136 | * drm_dp_mst_topology_put_mstb() - release a topology reference to a branch | ||
1137 | * device | ||
1138 | * @mstb: The &struct drm_dp_mst_branch to release the topology reference from | ||
1139 | * | ||
1140 | * Releases a topology reference from @mstb by decrementing | ||
1141 | * &drm_dp_mst_branch.topology_kref. | ||
1142 | * | ||
1143 | * See also: | ||
1144 | * drm_dp_mst_topology_try_get_mstb() | ||
1145 | * drm_dp_mst_topology_get_mstb() | ||
1146 | */ | ||
1147 | static void | ||
1148 | drm_dp_mst_topology_put_mstb(struct drm_dp_mst_branch *mstb) | ||
1149 | { | ||
1150 | DRM_DEBUG("mstb %p (%d)\n", | ||
1151 | mstb, kref_read(&mstb->topology_kref) - 1); | ||
1152 | kref_put(&mstb->topology_kref, drm_dp_destroy_mst_branch_device); | ||
1153 | } | ||
919 | 1154 | ||
920 | static void drm_dp_port_teardown_pdt(struct drm_dp_mst_port *port, int old_pdt) | 1155 | static void drm_dp_port_teardown_pdt(struct drm_dp_mst_port *port, int old_pdt) |
921 | { | 1156 | { |
@@ -930,19 +1165,18 @@ static void drm_dp_port_teardown_pdt(struct drm_dp_mst_port *port, int old_pdt) | |||
930 | case DP_PEER_DEVICE_MST_BRANCHING: | 1165 | case DP_PEER_DEVICE_MST_BRANCHING: |
931 | mstb = port->mstb; | 1166 | mstb = port->mstb; |
932 | port->mstb = NULL; | 1167 | port->mstb = NULL; |
933 | drm_dp_put_mst_branch_device(mstb); | 1168 | drm_dp_mst_topology_put_mstb(mstb); |
934 | break; | 1169 | break; |
935 | } | 1170 | } |
936 | } | 1171 | } |
937 | 1172 | ||
938 | static void drm_dp_destroy_port(struct kref *kref) | 1173 | static void drm_dp_destroy_port(struct kref *kref) |
939 | { | 1174 | { |
940 | struct drm_dp_mst_port *port = container_of(kref, struct drm_dp_mst_port, kref); | 1175 | struct drm_dp_mst_port *port = |
1176 | container_of(kref, struct drm_dp_mst_port, topology_kref); | ||
941 | struct drm_dp_mst_topology_mgr *mgr = port->mgr; | 1177 | struct drm_dp_mst_topology_mgr *mgr = port->mgr; |
942 | 1178 | ||
943 | if (!port->input) { | 1179 | if (!port->input) { |
944 | port->vcpi.num_slots = 0; | ||
945 | |||
946 | kfree(port->cached_edid); | 1180 | kfree(port->cached_edid); |
947 | 1181 | ||
948 | /* | 1182 | /* |
@@ -956,7 +1190,6 @@ static void drm_dp_destroy_port(struct kref *kref) | |||
956 | * from an EDID retrieval */ | 1190 | * from an EDID retrieval */ |
957 | 1191 | ||
958 | mutex_lock(&mgr->destroy_connector_lock); | 1192 | mutex_lock(&mgr->destroy_connector_lock); |
959 | kref_get(&port->parent->kref); | ||
960 | list_add(&port->next, &mgr->destroy_connector_list); | 1193 | list_add(&port->next, &mgr->destroy_connector_list); |
961 | mutex_unlock(&mgr->destroy_connector_lock); | 1194 | mutex_unlock(&mgr->destroy_connector_lock); |
962 | schedule_work(&mgr->destroy_connector_work); | 1195 | schedule_work(&mgr->destroy_connector_work); |
@@ -967,25 +1200,95 @@ static void drm_dp_destroy_port(struct kref *kref) | |||
967 | drm_dp_port_teardown_pdt(port, port->pdt); | 1200 | drm_dp_port_teardown_pdt(port, port->pdt); |
968 | port->pdt = DP_PEER_DEVICE_NONE; | 1201 | port->pdt = DP_PEER_DEVICE_NONE; |
969 | } | 1202 | } |
970 | kfree(port); | 1203 | drm_dp_mst_put_port_malloc(port); |
971 | } | 1204 | } |
972 | 1205 | ||
973 | static void drm_dp_put_port(struct drm_dp_mst_port *port) | 1206 | /** |
1207 | * drm_dp_mst_topology_try_get_port() - Increment the topology refcount of a | ||
1208 | * port unless its zero | ||
1209 | * @port: &struct drm_dp_mst_port to increment the topology refcount of | ||
1210 | * | ||
1211 | * Attempts to grab a topology reference to @port, if it hasn't yet been | ||
1212 | * removed from the topology (e.g. &drm_dp_mst_port.topology_kref has reached | ||
1213 | * 0). Holding a topology reference implies that a malloc reference will be | ||
1214 | * held to @port as long as the user holds the topology reference. | ||
1215 | * | ||
1216 | * Care should be taken to ensure that the user has at least one malloc | ||
1217 | * reference to @port. If you already have a topology reference to @port, you | ||
1218 | * should use drm_dp_mst_topology_get_port() instead. | ||
1219 | * | ||
1220 | * See also: | ||
1221 | * drm_dp_mst_topology_get_port() | ||
1222 | * drm_dp_mst_topology_put_port() | ||
1223 | * | ||
1224 | * Returns: | ||
1225 | * * 1: A topology reference was grabbed successfully | ||
1226 | * * 0: @port is no longer in the topology, no reference was grabbed | ||
1227 | */ | ||
1228 | static int __must_check | ||
1229 | drm_dp_mst_topology_try_get_port(struct drm_dp_mst_port *port) | ||
974 | { | 1230 | { |
975 | kref_put(&port->kref, drm_dp_destroy_port); | 1231 | int ret = kref_get_unless_zero(&port->topology_kref); |
1232 | |||
1233 | if (ret) | ||
1234 | DRM_DEBUG("port %p (%d)\n", port, | ||
1235 | kref_read(&port->topology_kref)); | ||
1236 | |||
1237 | return ret; | ||
976 | } | 1238 | } |
977 | 1239 | ||
978 | static struct drm_dp_mst_branch *drm_dp_mst_get_validated_mstb_ref_locked(struct drm_dp_mst_branch *mstb, struct drm_dp_mst_branch *to_find) | 1240 | /** |
1241 | * drm_dp_mst_topology_get_port() - Increment the topology refcount of a port | ||
1242 | * @port: The &struct drm_dp_mst_port to increment the topology refcount of | ||
1243 | * | ||
1244 | * Increments &drm_dp_mst_port.topology_refcount without checking whether or | ||
1245 | * not it's already reached 0. This is only valid to use in scenarios where | ||
1246 | * you are already guaranteed to have at least one active topology reference | ||
1247 | * to @port. Otherwise, drm_dp_mst_topology_try_get_port() must be used. | ||
1248 | * | ||
1249 | * See also: | ||
1250 | * drm_dp_mst_topology_try_get_port() | ||
1251 | * drm_dp_mst_topology_put_port() | ||
1252 | */ | ||
1253 | static void drm_dp_mst_topology_get_port(struct drm_dp_mst_port *port) | ||
1254 | { | ||
1255 | WARN_ON(kref_read(&port->topology_kref) == 0); | ||
1256 | kref_get(&port->topology_kref); | ||
1257 | DRM_DEBUG("port %p (%d)\n", port, kref_read(&port->topology_kref)); | ||
1258 | } | ||
1259 | |||
1260 | /** | ||
1261 | * drm_dp_mst_topology_put_port() - release a topology reference to a port | ||
1262 | * @port: The &struct drm_dp_mst_port to release the topology reference from | ||
1263 | * | ||
1264 | * Releases a topology reference from @port by decrementing | ||
1265 | * &drm_dp_mst_port.topology_kref. | ||
1266 | * | ||
1267 | * See also: | ||
1268 | * drm_dp_mst_topology_try_get_port() | ||
1269 | * drm_dp_mst_topology_get_port() | ||
1270 | */ | ||
1271 | static void drm_dp_mst_topology_put_port(struct drm_dp_mst_port *port) | ||
1272 | { | ||
1273 | DRM_DEBUG("port %p (%d)\n", | ||
1274 | port, kref_read(&port->topology_kref) - 1); | ||
1275 | kref_put(&port->topology_kref, drm_dp_destroy_port); | ||
1276 | } | ||
1277 | |||
1278 | static struct drm_dp_mst_branch * | ||
1279 | drm_dp_mst_topology_get_mstb_validated_locked(struct drm_dp_mst_branch *mstb, | ||
1280 | struct drm_dp_mst_branch *to_find) | ||
979 | { | 1281 | { |
980 | struct drm_dp_mst_port *port; | 1282 | struct drm_dp_mst_port *port; |
981 | struct drm_dp_mst_branch *rmstb; | 1283 | struct drm_dp_mst_branch *rmstb; |
982 | if (to_find == mstb) { | 1284 | |
983 | kref_get(&mstb->kref); | 1285 | if (to_find == mstb) |
984 | return mstb; | 1286 | return mstb; |
985 | } | 1287 | |
986 | list_for_each_entry(port, &mstb->ports, next) { | 1288 | list_for_each_entry(port, &mstb->ports, next) { |
987 | if (port->mstb) { | 1289 | if (port->mstb) { |
988 | rmstb = drm_dp_mst_get_validated_mstb_ref_locked(port->mstb, to_find); | 1290 | rmstb = drm_dp_mst_topology_get_mstb_validated_locked( |
1291 | port->mstb, to_find); | ||
989 | if (rmstb) | 1292 | if (rmstb) |
990 | return rmstb; | 1293 | return rmstb; |
991 | } | 1294 | } |
@@ -993,27 +1296,37 @@ static struct drm_dp_mst_branch *drm_dp_mst_get_validated_mstb_ref_locked(struct | |||
993 | return NULL; | 1296 | return NULL; |
994 | } | 1297 | } |
995 | 1298 | ||
996 | static struct drm_dp_mst_branch *drm_dp_get_validated_mstb_ref(struct drm_dp_mst_topology_mgr *mgr, struct drm_dp_mst_branch *mstb) | 1299 | static struct drm_dp_mst_branch * |
1300 | drm_dp_mst_topology_get_mstb_validated(struct drm_dp_mst_topology_mgr *mgr, | ||
1301 | struct drm_dp_mst_branch *mstb) | ||
997 | { | 1302 | { |
998 | struct drm_dp_mst_branch *rmstb = NULL; | 1303 | struct drm_dp_mst_branch *rmstb = NULL; |
1304 | |||
999 | mutex_lock(&mgr->lock); | 1305 | mutex_lock(&mgr->lock); |
1000 | if (mgr->mst_primary) | 1306 | if (mgr->mst_primary) { |
1001 | rmstb = drm_dp_mst_get_validated_mstb_ref_locked(mgr->mst_primary, mstb); | 1307 | rmstb = drm_dp_mst_topology_get_mstb_validated_locked( |
1308 | mgr->mst_primary, mstb); | ||
1309 | |||
1310 | if (rmstb && !drm_dp_mst_topology_try_get_mstb(rmstb)) | ||
1311 | rmstb = NULL; | ||
1312 | } | ||
1002 | mutex_unlock(&mgr->lock); | 1313 | mutex_unlock(&mgr->lock); |
1003 | return rmstb; | 1314 | return rmstb; |
1004 | } | 1315 | } |
1005 | 1316 | ||
1006 | static struct drm_dp_mst_port *drm_dp_mst_get_port_ref_locked(struct drm_dp_mst_branch *mstb, struct drm_dp_mst_port *to_find) | 1317 | static struct drm_dp_mst_port * |
1318 | drm_dp_mst_topology_get_port_validated_locked(struct drm_dp_mst_branch *mstb, | ||
1319 | struct drm_dp_mst_port *to_find) | ||
1007 | { | 1320 | { |
1008 | struct drm_dp_mst_port *port, *mport; | 1321 | struct drm_dp_mst_port *port, *mport; |
1009 | 1322 | ||
1010 | list_for_each_entry(port, &mstb->ports, next) { | 1323 | list_for_each_entry(port, &mstb->ports, next) { |
1011 | if (port == to_find) { | 1324 | if (port == to_find) |
1012 | kref_get(&port->kref); | ||
1013 | return port; | 1325 | return port; |
1014 | } | 1326 | |
1015 | if (port->mstb) { | 1327 | if (port->mstb) { |
1016 | mport = drm_dp_mst_get_port_ref_locked(port->mstb, to_find); | 1328 | mport = drm_dp_mst_topology_get_port_validated_locked( |
1329 | port->mstb, to_find); | ||
1017 | if (mport) | 1330 | if (mport) |
1018 | return mport; | 1331 | return mport; |
1019 | } | 1332 | } |
@@ -1021,12 +1334,20 @@ static struct drm_dp_mst_port *drm_dp_mst_get_port_ref_locked(struct drm_dp_mst_ | |||
1021 | return NULL; | 1334 | return NULL; |
1022 | } | 1335 | } |
1023 | 1336 | ||
1024 | static struct drm_dp_mst_port *drm_dp_get_validated_port_ref(struct drm_dp_mst_topology_mgr *mgr, struct drm_dp_mst_port *port) | 1337 | static struct drm_dp_mst_port * |
1338 | drm_dp_mst_topology_get_port_validated(struct drm_dp_mst_topology_mgr *mgr, | ||
1339 | struct drm_dp_mst_port *port) | ||
1025 | { | 1340 | { |
1026 | struct drm_dp_mst_port *rport = NULL; | 1341 | struct drm_dp_mst_port *rport = NULL; |
1342 | |||
1027 | mutex_lock(&mgr->lock); | 1343 | mutex_lock(&mgr->lock); |
1028 | if (mgr->mst_primary) | 1344 | if (mgr->mst_primary) { |
1029 | rport = drm_dp_mst_get_port_ref_locked(mgr->mst_primary, port); | 1345 | rport = drm_dp_mst_topology_get_port_validated_locked( |
1346 | mgr->mst_primary, port); | ||
1347 | |||
1348 | if (rport && !drm_dp_mst_topology_try_get_port(rport)) | ||
1349 | rport = NULL; | ||
1350 | } | ||
1030 | mutex_unlock(&mgr->lock); | 1351 | mutex_unlock(&mgr->lock); |
1031 | return rport; | 1352 | return rport; |
1032 | } | 1353 | } |
@@ -1034,11 +1355,12 @@ static struct drm_dp_mst_port *drm_dp_get_validated_port_ref(struct drm_dp_mst_t | |||
1034 | static struct drm_dp_mst_port *drm_dp_get_port(struct drm_dp_mst_branch *mstb, u8 port_num) | 1355 | static struct drm_dp_mst_port *drm_dp_get_port(struct drm_dp_mst_branch *mstb, u8 port_num) |
1035 | { | 1356 | { |
1036 | struct drm_dp_mst_port *port; | 1357 | struct drm_dp_mst_port *port; |
1358 | int ret; | ||
1037 | 1359 | ||
1038 | list_for_each_entry(port, &mstb->ports, next) { | 1360 | list_for_each_entry(port, &mstb->ports, next) { |
1039 | if (port->port_num == port_num) { | 1361 | if (port->port_num == port_num) { |
1040 | kref_get(&port->kref); | 1362 | ret = drm_dp_mst_topology_try_get_port(port); |
1041 | return port; | 1363 | return ret ? port : NULL; |
1042 | } | 1364 | } |
1043 | } | 1365 | } |
1044 | 1366 | ||
@@ -1087,6 +1409,11 @@ static bool drm_dp_port_setup_pdt(struct drm_dp_mst_port *port) | |||
1087 | if (port->mstb) { | 1409 | if (port->mstb) { |
1088 | port->mstb->mgr = port->mgr; | 1410 | port->mstb->mgr = port->mgr; |
1089 | port->mstb->port_parent = port; | 1411 | port->mstb->port_parent = port; |
1412 | /* | ||
1413 | * Make sure this port's memory allocation stays | ||
1414 | * around until it's child MSTB releases it | ||
1415 | */ | ||
1416 | drm_dp_mst_get_port_malloc(port); | ||
1090 | 1417 | ||
1091 | send_link = true; | 1418 | send_link = true; |
1092 | } | 1419 | } |
@@ -1147,17 +1474,26 @@ static void drm_dp_add_port(struct drm_dp_mst_branch *mstb, | |||
1147 | bool created = false; | 1474 | bool created = false; |
1148 | int old_pdt = 0; | 1475 | int old_pdt = 0; |
1149 | int old_ddps = 0; | 1476 | int old_ddps = 0; |
1477 | |||
1150 | port = drm_dp_get_port(mstb, port_msg->port_number); | 1478 | port = drm_dp_get_port(mstb, port_msg->port_number); |
1151 | if (!port) { | 1479 | if (!port) { |
1152 | port = kzalloc(sizeof(*port), GFP_KERNEL); | 1480 | port = kzalloc(sizeof(*port), GFP_KERNEL); |
1153 | if (!port) | 1481 | if (!port) |
1154 | return; | 1482 | return; |
1155 | kref_init(&port->kref); | 1483 | kref_init(&port->topology_kref); |
1484 | kref_init(&port->malloc_kref); | ||
1156 | port->parent = mstb; | 1485 | port->parent = mstb; |
1157 | port->port_num = port_msg->port_number; | 1486 | port->port_num = port_msg->port_number; |
1158 | port->mgr = mstb->mgr; | 1487 | port->mgr = mstb->mgr; |
1159 | port->aux.name = "DPMST"; | 1488 | port->aux.name = "DPMST"; |
1160 | port->aux.dev = dev->dev; | 1489 | port->aux.dev = dev->dev; |
1490 | |||
1491 | /* | ||
1492 | * Make sure the memory allocation for our parent branch stays | ||
1493 | * around until our own memory allocation is released | ||
1494 | */ | ||
1495 | drm_dp_mst_get_mstb_malloc(mstb); | ||
1496 | |||
1161 | created = true; | 1497 | created = true; |
1162 | } else { | 1498 | } else { |
1163 | old_pdt = port->pdt; | 1499 | old_pdt = port->pdt; |
@@ -1177,18 +1513,20 @@ static void drm_dp_add_port(struct drm_dp_mst_branch *mstb, | |||
1177 | for this list */ | 1513 | for this list */ |
1178 | if (created) { | 1514 | if (created) { |
1179 | mutex_lock(&mstb->mgr->lock); | 1515 | mutex_lock(&mstb->mgr->lock); |
1180 | kref_get(&port->kref); | 1516 | drm_dp_mst_topology_get_port(port); |
1181 | list_add(&port->next, &mstb->ports); | 1517 | list_add(&port->next, &mstb->ports); |
1182 | mutex_unlock(&mstb->mgr->lock); | 1518 | mutex_unlock(&mstb->mgr->lock); |
1183 | } | 1519 | } |
1184 | 1520 | ||
1185 | if (old_ddps != port->ddps) { | 1521 | if (old_ddps != port->ddps) { |
1186 | if (port->ddps) { | 1522 | if (port->ddps) { |
1187 | if (!port->input) | 1523 | if (!port->input) { |
1188 | drm_dp_send_enum_path_resources(mstb->mgr, mstb, port); | 1524 | drm_dp_send_enum_path_resources(mstb->mgr, |
1525 | mstb, port); | ||
1526 | } | ||
1189 | } else { | 1527 | } else { |
1190 | port->available_pbn = 0; | 1528 | port->available_pbn = 0; |
1191 | } | 1529 | } |
1192 | } | 1530 | } |
1193 | 1531 | ||
1194 | if (old_pdt != port->pdt && !port->input) { | 1532 | if (old_pdt != port->pdt && !port->input) { |
@@ -1202,21 +1540,25 @@ static void drm_dp_add_port(struct drm_dp_mst_branch *mstb, | |||
1202 | if (created && !port->input) { | 1540 | if (created && !port->input) { |
1203 | char proppath[255]; | 1541 | char proppath[255]; |
1204 | 1542 | ||
1205 | build_mst_prop_path(mstb, port->port_num, proppath, sizeof(proppath)); | 1543 | build_mst_prop_path(mstb, port->port_num, proppath, |
1206 | port->connector = (*mstb->mgr->cbs->add_connector)(mstb->mgr, port, proppath); | 1544 | sizeof(proppath)); |
1545 | port->connector = (*mstb->mgr->cbs->add_connector)(mstb->mgr, | ||
1546 | port, | ||
1547 | proppath); | ||
1207 | if (!port->connector) { | 1548 | if (!port->connector) { |
1208 | /* remove it from the port list */ | 1549 | /* remove it from the port list */ |
1209 | mutex_lock(&mstb->mgr->lock); | 1550 | mutex_lock(&mstb->mgr->lock); |
1210 | list_del(&port->next); | 1551 | list_del(&port->next); |
1211 | mutex_unlock(&mstb->mgr->lock); | 1552 | mutex_unlock(&mstb->mgr->lock); |
1212 | /* drop port list reference */ | 1553 | /* drop port list reference */ |
1213 | drm_dp_put_port(port); | 1554 | drm_dp_mst_topology_put_port(port); |
1214 | goto out; | 1555 | goto out; |
1215 | } | 1556 | } |
1216 | if ((port->pdt == DP_PEER_DEVICE_DP_LEGACY_CONV || | 1557 | if ((port->pdt == DP_PEER_DEVICE_DP_LEGACY_CONV || |
1217 | port->pdt == DP_PEER_DEVICE_SST_SINK) && | 1558 | port->pdt == DP_PEER_DEVICE_SST_SINK) && |
1218 | port->port_num >= DP_MST_LOGICAL_PORT_0) { | 1559 | port->port_num >= DP_MST_LOGICAL_PORT_0) { |
1219 | port->cached_edid = drm_get_edid(port->connector, &port->aux.ddc); | 1560 | port->cached_edid = drm_get_edid(port->connector, |
1561 | &port->aux.ddc); | ||
1220 | drm_connector_set_tile_property(port->connector); | 1562 | drm_connector_set_tile_property(port->connector); |
1221 | } | 1563 | } |
1222 | (*mstb->mgr->cbs->register_connector)(port->connector); | 1564 | (*mstb->mgr->cbs->register_connector)(port->connector); |
@@ -1224,7 +1566,7 @@ static void drm_dp_add_port(struct drm_dp_mst_branch *mstb, | |||
1224 | 1566 | ||
1225 | out: | 1567 | out: |
1226 | /* put reference to this port */ | 1568 | /* put reference to this port */ |
1227 | drm_dp_put_port(port); | 1569 | drm_dp_mst_topology_put_port(port); |
1228 | } | 1570 | } |
1229 | 1571 | ||
1230 | static void drm_dp_update_port(struct drm_dp_mst_branch *mstb, | 1572 | static void drm_dp_update_port(struct drm_dp_mst_branch *mstb, |
@@ -1259,7 +1601,7 @@ static void drm_dp_update_port(struct drm_dp_mst_branch *mstb, | |||
1259 | dowork = true; | 1601 | dowork = true; |
1260 | } | 1602 | } |
1261 | 1603 | ||
1262 | drm_dp_put_port(port); | 1604 | drm_dp_mst_topology_put_port(port); |
1263 | if (dowork) | 1605 | if (dowork) |
1264 | queue_work(system_long_wq, &mstb->mgr->work); | 1606 | queue_work(system_long_wq, &mstb->mgr->work); |
1265 | 1607 | ||
@@ -1270,7 +1612,7 @@ static struct drm_dp_mst_branch *drm_dp_get_mst_branch_device(struct drm_dp_mst_ | |||
1270 | { | 1612 | { |
1271 | struct drm_dp_mst_branch *mstb; | 1613 | struct drm_dp_mst_branch *mstb; |
1272 | struct drm_dp_mst_port *port; | 1614 | struct drm_dp_mst_port *port; |
1273 | int i; | 1615 | int i, ret; |
1274 | /* find the port by iterating down */ | 1616 | /* find the port by iterating down */ |
1275 | 1617 | ||
1276 | mutex_lock(&mgr->lock); | 1618 | mutex_lock(&mgr->lock); |
@@ -1295,7 +1637,9 @@ static struct drm_dp_mst_branch *drm_dp_get_mst_branch_device(struct drm_dp_mst_ | |||
1295 | } | 1637 | } |
1296 | } | 1638 | } |
1297 | } | 1639 | } |
1298 | kref_get(&mstb->kref); | 1640 | ret = drm_dp_mst_topology_try_get_mstb(mstb); |
1641 | if (!ret) | ||
1642 | mstb = NULL; | ||
1299 | out: | 1643 | out: |
1300 | mutex_unlock(&mgr->lock); | 1644 | mutex_unlock(&mgr->lock); |
1301 | return mstb; | 1645 | return mstb; |
@@ -1325,19 +1669,22 @@ static struct drm_dp_mst_branch *get_mst_branch_device_by_guid_helper( | |||
1325 | return NULL; | 1669 | return NULL; |
1326 | } | 1670 | } |
1327 | 1671 | ||
1328 | static struct drm_dp_mst_branch *drm_dp_get_mst_branch_device_by_guid( | 1672 | static struct drm_dp_mst_branch * |
1329 | struct drm_dp_mst_topology_mgr *mgr, | 1673 | drm_dp_get_mst_branch_device_by_guid(struct drm_dp_mst_topology_mgr *mgr, |
1330 | uint8_t *guid) | 1674 | uint8_t *guid) |
1331 | { | 1675 | { |
1332 | struct drm_dp_mst_branch *mstb; | 1676 | struct drm_dp_mst_branch *mstb; |
1677 | int ret; | ||
1333 | 1678 | ||
1334 | /* find the port by iterating down */ | 1679 | /* find the port by iterating down */ |
1335 | mutex_lock(&mgr->lock); | 1680 | mutex_lock(&mgr->lock); |
1336 | 1681 | ||
1337 | mstb = get_mst_branch_device_by_guid_helper(mgr->mst_primary, guid); | 1682 | mstb = get_mst_branch_device_by_guid_helper(mgr->mst_primary, guid); |
1338 | 1683 | if (mstb) { | |
1339 | if (mstb) | 1684 | ret = drm_dp_mst_topology_try_get_mstb(mstb); |
1340 | kref_get(&mstb->kref); | 1685 | if (!ret) |
1686 | mstb = NULL; | ||
1687 | } | ||
1341 | 1688 | ||
1342 | mutex_unlock(&mgr->lock); | 1689 | mutex_unlock(&mgr->lock); |
1343 | return mstb; | 1690 | return mstb; |
@@ -1362,10 +1709,11 @@ static void drm_dp_check_and_send_link_address(struct drm_dp_mst_topology_mgr *m | |||
1362 | drm_dp_send_enum_path_resources(mgr, mstb, port); | 1709 | drm_dp_send_enum_path_resources(mgr, mstb, port); |
1363 | 1710 | ||
1364 | if (port->mstb) { | 1711 | if (port->mstb) { |
1365 | mstb_child = drm_dp_get_validated_mstb_ref(mgr, port->mstb); | 1712 | mstb_child = drm_dp_mst_topology_get_mstb_validated( |
1713 | mgr, port->mstb); | ||
1366 | if (mstb_child) { | 1714 | if (mstb_child) { |
1367 | drm_dp_check_and_send_link_address(mgr, mstb_child); | 1715 | drm_dp_check_and_send_link_address(mgr, mstb_child); |
1368 | drm_dp_put_mst_branch_device(mstb_child); | 1716 | drm_dp_mst_topology_put_mstb(mstb_child); |
1369 | } | 1717 | } |
1370 | } | 1718 | } |
1371 | } | 1719 | } |
@@ -1375,16 +1723,19 @@ static void drm_dp_mst_link_probe_work(struct work_struct *work) | |||
1375 | { | 1723 | { |
1376 | struct drm_dp_mst_topology_mgr *mgr = container_of(work, struct drm_dp_mst_topology_mgr, work); | 1724 | struct drm_dp_mst_topology_mgr *mgr = container_of(work, struct drm_dp_mst_topology_mgr, work); |
1377 | struct drm_dp_mst_branch *mstb; | 1725 | struct drm_dp_mst_branch *mstb; |
1726 | int ret; | ||
1378 | 1727 | ||
1379 | mutex_lock(&mgr->lock); | 1728 | mutex_lock(&mgr->lock); |
1380 | mstb = mgr->mst_primary; | 1729 | mstb = mgr->mst_primary; |
1381 | if (mstb) { | 1730 | if (mstb) { |
1382 | kref_get(&mstb->kref); | 1731 | ret = drm_dp_mst_topology_try_get_mstb(mstb); |
1732 | if (!ret) | ||
1733 | mstb = NULL; | ||
1383 | } | 1734 | } |
1384 | mutex_unlock(&mgr->lock); | 1735 | mutex_unlock(&mgr->lock); |
1385 | if (mstb) { | 1736 | if (mstb) { |
1386 | drm_dp_check_and_send_link_address(mgr, mstb); | 1737 | drm_dp_check_and_send_link_address(mgr, mstb); |
1387 | drm_dp_put_mst_branch_device(mstb); | 1738 | drm_dp_mst_topology_put_mstb(mstb); |
1388 | } | 1739 | } |
1389 | } | 1740 | } |
1390 | 1741 | ||
@@ -1695,22 +2046,40 @@ static struct drm_dp_mst_port *drm_dp_get_last_connected_port_to_mstb(struct drm | |||
1695 | return drm_dp_get_last_connected_port_to_mstb(mstb->port_parent->parent); | 2046 | return drm_dp_get_last_connected_port_to_mstb(mstb->port_parent->parent); |
1696 | } | 2047 | } |
1697 | 2048 | ||
1698 | static struct drm_dp_mst_branch *drm_dp_get_last_connected_port_and_mstb(struct drm_dp_mst_topology_mgr *mgr, | 2049 | /* |
1699 | struct drm_dp_mst_branch *mstb, | 2050 | * Searches upwards in the topology starting from mstb to try to find the |
1700 | int *port_num) | 2051 | * closest available parent of mstb that's still connected to the rest of the |
2052 | * topology. This can be used in order to perform operations like releasing | ||
2053 | * payloads, where the branch device which owned the payload may no longer be | ||
2054 | * around and thus would require that the payload on the last living relative | ||
2055 | * be freed instead. | ||
2056 | */ | ||
2057 | static struct drm_dp_mst_branch * | ||
2058 | drm_dp_get_last_connected_port_and_mstb(struct drm_dp_mst_topology_mgr *mgr, | ||
2059 | struct drm_dp_mst_branch *mstb, | ||
2060 | int *port_num) | ||
1701 | { | 2061 | { |
1702 | struct drm_dp_mst_branch *rmstb = NULL; | 2062 | struct drm_dp_mst_branch *rmstb = NULL; |
1703 | struct drm_dp_mst_port *found_port; | 2063 | struct drm_dp_mst_port *found_port; |
2064 | |||
1704 | mutex_lock(&mgr->lock); | 2065 | mutex_lock(&mgr->lock); |
1705 | if (mgr->mst_primary) { | 2066 | if (!mgr->mst_primary) |
2067 | goto out; | ||
2068 | |||
2069 | do { | ||
1706 | found_port = drm_dp_get_last_connected_port_to_mstb(mstb); | 2070 | found_port = drm_dp_get_last_connected_port_to_mstb(mstb); |
2071 | if (!found_port) | ||
2072 | break; | ||
1707 | 2073 | ||
1708 | if (found_port) { | 2074 | if (drm_dp_mst_topology_try_get_mstb(found_port->parent)) { |
1709 | rmstb = found_port->parent; | 2075 | rmstb = found_port->parent; |
1710 | kref_get(&rmstb->kref); | ||
1711 | *port_num = found_port->port_num; | 2076 | *port_num = found_port->port_num; |
2077 | } else { | ||
2078 | /* Search again, starting from this parent */ | ||
2079 | mstb = found_port->parent; | ||
1712 | } | 2080 | } |
1713 | } | 2081 | } while (!rmstb); |
2082 | out: | ||
1714 | mutex_unlock(&mgr->lock); | 2083 | mutex_unlock(&mgr->lock); |
1715 | return rmstb; | 2084 | return rmstb; |
1716 | } | 2085 | } |
@@ -1726,19 +2095,15 @@ static int drm_dp_payload_send_msg(struct drm_dp_mst_topology_mgr *mgr, | |||
1726 | u8 sinks[DRM_DP_MAX_SDP_STREAMS]; | 2095 | u8 sinks[DRM_DP_MAX_SDP_STREAMS]; |
1727 | int i; | 2096 | int i; |
1728 | 2097 | ||
1729 | port = drm_dp_get_validated_port_ref(mgr, port); | ||
1730 | if (!port) | ||
1731 | return -EINVAL; | ||
1732 | |||
1733 | port_num = port->port_num; | 2098 | port_num = port->port_num; |
1734 | mstb = drm_dp_get_validated_mstb_ref(mgr, port->parent); | 2099 | mstb = drm_dp_mst_topology_get_mstb_validated(mgr, port->parent); |
1735 | if (!mstb) { | 2100 | if (!mstb) { |
1736 | mstb = drm_dp_get_last_connected_port_and_mstb(mgr, port->parent, &port_num); | 2101 | mstb = drm_dp_get_last_connected_port_and_mstb(mgr, |
2102 | port->parent, | ||
2103 | &port_num); | ||
1737 | 2104 | ||
1738 | if (!mstb) { | 2105 | if (!mstb) |
1739 | drm_dp_put_port(port); | ||
1740 | return -EINVAL; | 2106 | return -EINVAL; |
1741 | } | ||
1742 | } | 2107 | } |
1743 | 2108 | ||
1744 | txmsg = kzalloc(sizeof(*txmsg), GFP_KERNEL); | 2109 | txmsg = kzalloc(sizeof(*txmsg), GFP_KERNEL); |
@@ -1757,17 +2122,24 @@ static int drm_dp_payload_send_msg(struct drm_dp_mst_topology_mgr *mgr, | |||
1757 | 2122 | ||
1758 | drm_dp_queue_down_tx(mgr, txmsg); | 2123 | drm_dp_queue_down_tx(mgr, txmsg); |
1759 | 2124 | ||
2125 | /* | ||
2126 | * FIXME: there is a small chance that between getting the last | ||
2127 | * connected mstb and sending the payload message, the last connected | ||
2128 | * mstb could also be removed from the topology. In the future, this | ||
2129 | * needs to be fixed by restarting the | ||
2130 | * drm_dp_get_last_connected_port_and_mstb() search in the event of a | ||
2131 | * timeout if the topology is still connected to the system. | ||
2132 | */ | ||
1760 | ret = drm_dp_mst_wait_tx_reply(mstb, txmsg); | 2133 | ret = drm_dp_mst_wait_tx_reply(mstb, txmsg); |
1761 | if (ret > 0) { | 2134 | if (ret > 0) { |
1762 | if (txmsg->reply.reply_type == 1) { | 2135 | if (txmsg->reply.reply_type == 1) |
1763 | ret = -EINVAL; | 2136 | ret = -EINVAL; |
1764 | } else | 2137 | else |
1765 | ret = 0; | 2138 | ret = 0; |
1766 | } | 2139 | } |
1767 | kfree(txmsg); | 2140 | kfree(txmsg); |
1768 | fail_put: | 2141 | fail_put: |
1769 | drm_dp_put_mst_branch_device(mstb); | 2142 | drm_dp_mst_topology_put_mstb(mstb); |
1770 | drm_dp_put_port(port); | ||
1771 | return ret; | 2143 | return ret; |
1772 | } | 2144 | } |
1773 | 2145 | ||
@@ -1777,13 +2149,13 @@ int drm_dp_send_power_updown_phy(struct drm_dp_mst_topology_mgr *mgr, | |||
1777 | struct drm_dp_sideband_msg_tx *txmsg; | 2149 | struct drm_dp_sideband_msg_tx *txmsg; |
1778 | int len, ret; | 2150 | int len, ret; |
1779 | 2151 | ||
1780 | port = drm_dp_get_validated_port_ref(mgr, port); | 2152 | port = drm_dp_mst_topology_get_port_validated(mgr, port); |
1781 | if (!port) | 2153 | if (!port) |
1782 | return -EINVAL; | 2154 | return -EINVAL; |
1783 | 2155 | ||
1784 | txmsg = kzalloc(sizeof(*txmsg), GFP_KERNEL); | 2156 | txmsg = kzalloc(sizeof(*txmsg), GFP_KERNEL); |
1785 | if (!txmsg) { | 2157 | if (!txmsg) { |
1786 | drm_dp_put_port(port); | 2158 | drm_dp_mst_topology_put_port(port); |
1787 | return -ENOMEM; | 2159 | return -ENOMEM; |
1788 | } | 2160 | } |
1789 | 2161 | ||
@@ -1799,7 +2171,7 @@ int drm_dp_send_power_updown_phy(struct drm_dp_mst_topology_mgr *mgr, | |||
1799 | ret = 0; | 2171 | ret = 0; |
1800 | } | 2172 | } |
1801 | kfree(txmsg); | 2173 | kfree(txmsg); |
1802 | drm_dp_put_port(port); | 2174 | drm_dp_mst_topology_put_port(port); |
1803 | 2175 | ||
1804 | return ret; | 2176 | return ret; |
1805 | } | 2177 | } |
@@ -1872,15 +2244,16 @@ static int drm_dp_destroy_payload_step2(struct drm_dp_mst_topology_mgr *mgr, | |||
1872 | */ | 2244 | */ |
1873 | int drm_dp_update_payload_part1(struct drm_dp_mst_topology_mgr *mgr) | 2245 | int drm_dp_update_payload_part1(struct drm_dp_mst_topology_mgr *mgr) |
1874 | { | 2246 | { |
1875 | int i, j; | ||
1876 | int cur_slots = 1; | ||
1877 | struct drm_dp_payload req_payload; | 2247 | struct drm_dp_payload req_payload; |
1878 | struct drm_dp_mst_port *port; | 2248 | struct drm_dp_mst_port *port; |
2249 | int i, j; | ||
2250 | int cur_slots = 1; | ||
1879 | 2251 | ||
1880 | mutex_lock(&mgr->payload_lock); | 2252 | mutex_lock(&mgr->payload_lock); |
1881 | for (i = 0; i < mgr->max_payloads; i++) { | 2253 | for (i = 0; i < mgr->max_payloads; i++) { |
1882 | struct drm_dp_vcpi *vcpi = mgr->proposed_vcpis[i]; | 2254 | struct drm_dp_vcpi *vcpi = mgr->proposed_vcpis[i]; |
1883 | struct drm_dp_payload *payload = &mgr->payloads[i]; | 2255 | struct drm_dp_payload *payload = &mgr->payloads[i]; |
2256 | bool put_port = false; | ||
1884 | 2257 | ||
1885 | /* solve the current payloads - compare to the hw ones | 2258 | /* solve the current payloads - compare to the hw ones |
1886 | - update the hw view */ | 2259 | - update the hw view */ |
@@ -1888,11 +2261,20 @@ int drm_dp_update_payload_part1(struct drm_dp_mst_topology_mgr *mgr) | |||
1888 | if (vcpi) { | 2261 | if (vcpi) { |
1889 | port = container_of(vcpi, struct drm_dp_mst_port, | 2262 | port = container_of(vcpi, struct drm_dp_mst_port, |
1890 | vcpi); | 2263 | vcpi); |
1891 | port = drm_dp_get_validated_port_ref(mgr, port); | 2264 | |
1892 | if (!port) { | 2265 | /* Validated ports don't matter if we're releasing |
1893 | mutex_unlock(&mgr->payload_lock); | 2266 | * VCPI |
1894 | return -EINVAL; | 2267 | */ |
2268 | if (vcpi->num_slots) { | ||
2269 | port = drm_dp_mst_topology_get_port_validated( | ||
2270 | mgr, port); | ||
2271 | if (!port) { | ||
2272 | mutex_unlock(&mgr->payload_lock); | ||
2273 | return -EINVAL; | ||
2274 | } | ||
2275 | put_port = true; | ||
1895 | } | 2276 | } |
2277 | |||
1896 | req_payload.num_slots = vcpi->num_slots; | 2278 | req_payload.num_slots = vcpi->num_slots; |
1897 | req_payload.vcpi = vcpi->vcpi; | 2279 | req_payload.vcpi = vcpi->vcpi; |
1898 | } else { | 2280 | } else { |
@@ -1924,8 +2306,8 @@ int drm_dp_update_payload_part1(struct drm_dp_mst_topology_mgr *mgr) | |||
1924 | } | 2306 | } |
1925 | cur_slots += req_payload.num_slots; | 2307 | cur_slots += req_payload.num_slots; |
1926 | 2308 | ||
1927 | if (port) | 2309 | if (put_port) |
1928 | drm_dp_put_port(port); | 2310 | drm_dp_mst_topology_put_port(port); |
1929 | } | 2311 | } |
1930 | 2312 | ||
1931 | for (i = 0; i < mgr->max_payloads; i++) { | 2313 | for (i = 0; i < mgr->max_payloads; i++) { |
@@ -2024,7 +2406,7 @@ static int drm_dp_send_dpcd_write(struct drm_dp_mst_topology_mgr *mgr, | |||
2024 | struct drm_dp_sideband_msg_tx *txmsg; | 2406 | struct drm_dp_sideband_msg_tx *txmsg; |
2025 | struct drm_dp_mst_branch *mstb; | 2407 | struct drm_dp_mst_branch *mstb; |
2026 | 2408 | ||
2027 | mstb = drm_dp_get_validated_mstb_ref(mgr, port->parent); | 2409 | mstb = drm_dp_mst_topology_get_mstb_validated(mgr, port->parent); |
2028 | if (!mstb) | 2410 | if (!mstb) |
2029 | return -EINVAL; | 2411 | return -EINVAL; |
2030 | 2412 | ||
@@ -2048,7 +2430,7 @@ static int drm_dp_send_dpcd_write(struct drm_dp_mst_topology_mgr *mgr, | |||
2048 | } | 2430 | } |
2049 | kfree(txmsg); | 2431 | kfree(txmsg); |
2050 | fail_put: | 2432 | fail_put: |
2051 | drm_dp_put_mst_branch_device(mstb); | 2433 | drm_dp_mst_topology_put_mstb(mstb); |
2052 | return ret; | 2434 | return ret; |
2053 | } | 2435 | } |
2054 | 2436 | ||
@@ -2158,7 +2540,7 @@ int drm_dp_mst_topology_mgr_set_mst(struct drm_dp_mst_topology_mgr *mgr, bool ms | |||
2158 | 2540 | ||
2159 | /* give this the main reference */ | 2541 | /* give this the main reference */ |
2160 | mgr->mst_primary = mstb; | 2542 | mgr->mst_primary = mstb; |
2161 | kref_get(&mgr->mst_primary->kref); | 2543 | drm_dp_mst_topology_get_mstb(mgr->mst_primary); |
2162 | 2544 | ||
2163 | ret = drm_dp_dpcd_writeb(mgr->aux, DP_MSTM_CTRL, | 2545 | ret = drm_dp_dpcd_writeb(mgr->aux, DP_MSTM_CTRL, |
2164 | DP_MST_EN | DP_UP_REQ_EN | DP_UPSTREAM_IS_SRC); | 2546 | DP_MST_EN | DP_UP_REQ_EN | DP_UPSTREAM_IS_SRC); |
@@ -2192,7 +2574,7 @@ int drm_dp_mst_topology_mgr_set_mst(struct drm_dp_mst_topology_mgr *mgr, bool ms | |||
2192 | out_unlock: | 2574 | out_unlock: |
2193 | mutex_unlock(&mgr->lock); | 2575 | mutex_unlock(&mgr->lock); |
2194 | if (mstb) | 2576 | if (mstb) |
2195 | drm_dp_put_mst_branch_device(mstb); | 2577 | drm_dp_mst_topology_put_mstb(mstb); |
2196 | return ret; | 2578 | return ret; |
2197 | 2579 | ||
2198 | } | 2580 | } |
@@ -2357,7 +2739,7 @@ static int drm_dp_mst_handle_down_rep(struct drm_dp_mst_topology_mgr *mgr) | |||
2357 | mgr->down_rep_recv.initial_hdr.lct, | 2739 | mgr->down_rep_recv.initial_hdr.lct, |
2358 | mgr->down_rep_recv.initial_hdr.rad[0], | 2740 | mgr->down_rep_recv.initial_hdr.rad[0], |
2359 | mgr->down_rep_recv.msg[0]); | 2741 | mgr->down_rep_recv.msg[0]); |
2360 | drm_dp_put_mst_branch_device(mstb); | 2742 | drm_dp_mst_topology_put_mstb(mstb); |
2361 | memset(&mgr->down_rep_recv, 0, sizeof(struct drm_dp_sideband_msg_rx)); | 2743 | memset(&mgr->down_rep_recv, 0, sizeof(struct drm_dp_sideband_msg_rx)); |
2362 | return 0; | 2744 | return 0; |
2363 | } | 2745 | } |
@@ -2368,7 +2750,7 @@ static int drm_dp_mst_handle_down_rep(struct drm_dp_mst_topology_mgr *mgr) | |||
2368 | } | 2750 | } |
2369 | 2751 | ||
2370 | memset(&mgr->down_rep_recv, 0, sizeof(struct drm_dp_sideband_msg_rx)); | 2752 | memset(&mgr->down_rep_recv, 0, sizeof(struct drm_dp_sideband_msg_rx)); |
2371 | drm_dp_put_mst_branch_device(mstb); | 2753 | drm_dp_mst_topology_put_mstb(mstb); |
2372 | 2754 | ||
2373 | mutex_lock(&mgr->qlock); | 2755 | mutex_lock(&mgr->qlock); |
2374 | txmsg->state = DRM_DP_SIDEBAND_TX_RX; | 2756 | txmsg->state = DRM_DP_SIDEBAND_TX_RX; |
@@ -2441,7 +2823,7 @@ static int drm_dp_mst_handle_up_req(struct drm_dp_mst_topology_mgr *mgr) | |||
2441 | } | 2823 | } |
2442 | 2824 | ||
2443 | if (mstb) | 2825 | if (mstb) |
2444 | drm_dp_put_mst_branch_device(mstb); | 2826 | drm_dp_mst_topology_put_mstb(mstb); |
2445 | 2827 | ||
2446 | memset(&mgr->up_req_recv, 0, sizeof(struct drm_dp_sideband_msg_rx)); | 2828 | memset(&mgr->up_req_recv, 0, sizeof(struct drm_dp_sideband_msg_rx)); |
2447 | } | 2829 | } |
@@ -2501,7 +2883,7 @@ enum drm_connector_status drm_dp_mst_detect_port(struct drm_connector *connector | |||
2501 | enum drm_connector_status status = connector_status_disconnected; | 2883 | enum drm_connector_status status = connector_status_disconnected; |
2502 | 2884 | ||
2503 | /* we need to search for the port in the mgr in case its gone */ | 2885 | /* we need to search for the port in the mgr in case its gone */ |
2504 | port = drm_dp_get_validated_port_ref(mgr, port); | 2886 | port = drm_dp_mst_topology_get_port_validated(mgr, port); |
2505 | if (!port) | 2887 | if (!port) |
2506 | return connector_status_disconnected; | 2888 | return connector_status_disconnected; |
2507 | 2889 | ||
@@ -2526,7 +2908,7 @@ enum drm_connector_status drm_dp_mst_detect_port(struct drm_connector *connector | |||
2526 | break; | 2908 | break; |
2527 | } | 2909 | } |
2528 | out: | 2910 | out: |
2529 | drm_dp_put_port(port); | 2911 | drm_dp_mst_topology_put_port(port); |
2530 | return status; | 2912 | return status; |
2531 | } | 2913 | } |
2532 | EXPORT_SYMBOL(drm_dp_mst_detect_port); | 2914 | EXPORT_SYMBOL(drm_dp_mst_detect_port); |
@@ -2543,11 +2925,11 @@ bool drm_dp_mst_port_has_audio(struct drm_dp_mst_topology_mgr *mgr, | |||
2543 | { | 2925 | { |
2544 | bool ret = false; | 2926 | bool ret = false; |
2545 | 2927 | ||
2546 | port = drm_dp_get_validated_port_ref(mgr, port); | 2928 | port = drm_dp_mst_topology_get_port_validated(mgr, port); |
2547 | if (!port) | 2929 | if (!port) |
2548 | return ret; | 2930 | return ret; |
2549 | ret = port->has_audio; | 2931 | ret = port->has_audio; |
2550 | drm_dp_put_port(port); | 2932 | drm_dp_mst_topology_put_port(port); |
2551 | return ret; | 2933 | return ret; |
2552 | } | 2934 | } |
2553 | EXPORT_SYMBOL(drm_dp_mst_port_has_audio); | 2935 | EXPORT_SYMBOL(drm_dp_mst_port_has_audio); |
@@ -2567,7 +2949,7 @@ struct edid *drm_dp_mst_get_edid(struct drm_connector *connector, struct drm_dp_ | |||
2567 | struct edid *edid = NULL; | 2949 | struct edid *edid = NULL; |
2568 | 2950 | ||
2569 | /* we need to search for the port in the mgr in case its gone */ | 2951 | /* we need to search for the port in the mgr in case its gone */ |
2570 | port = drm_dp_get_validated_port_ref(mgr, port); | 2952 | port = drm_dp_mst_topology_get_port_validated(mgr, port); |
2571 | if (!port) | 2953 | if (!port) |
2572 | return NULL; | 2954 | return NULL; |
2573 | 2955 | ||
@@ -2578,7 +2960,7 @@ struct edid *drm_dp_mst_get_edid(struct drm_connector *connector, struct drm_dp_ | |||
2578 | drm_connector_set_tile_property(connector); | 2960 | drm_connector_set_tile_property(connector); |
2579 | } | 2961 | } |
2580 | port->has_audio = drm_detect_monitor_audio(edid); | 2962 | port->has_audio = drm_detect_monitor_audio(edid); |
2581 | drm_dp_put_port(port); | 2963 | drm_dp_mst_topology_put_port(port); |
2582 | return edid; | 2964 | return edid; |
2583 | } | 2965 | } |
2584 | EXPORT_SYMBOL(drm_dp_mst_get_edid); | 2966 | EXPORT_SYMBOL(drm_dp_mst_get_edid); |
@@ -2629,43 +3011,98 @@ static int drm_dp_init_vcpi(struct drm_dp_mst_topology_mgr *mgr, | |||
2629 | } | 3011 | } |
2630 | 3012 | ||
2631 | /** | 3013 | /** |
2632 | * drm_dp_atomic_find_vcpi_slots() - Find and add vcpi slots to the state | 3014 | * drm_dp_atomic_find_vcpi_slots() - Find and add VCPI slots to the state |
2633 | * @state: global atomic state | 3015 | * @state: global atomic state |
2634 | * @mgr: MST topology manager for the port | 3016 | * @mgr: MST topology manager for the port |
2635 | * @port: port to find vcpi slots for | 3017 | * @port: port to find vcpi slots for |
2636 | * @pbn: bandwidth required for the mode in PBN | 3018 | * @pbn: bandwidth required for the mode in PBN |
2637 | * | 3019 | * |
2638 | * RETURNS: | 3020 | * Allocates VCPI slots to @port, replacing any previous VCPI allocations it |
2639 | * Total slots in the atomic state assigned for this port or error | 3021 | * may have had. Any atomic drivers which support MST must call this function |
3022 | * in their &drm_encoder_helper_funcs.atomic_check() callback to change the | ||
3023 | * current VCPI allocation for the new state, but only when | ||
3024 | * &drm_crtc_state.mode_changed or &drm_crtc_state.connectors_changed is set | ||
3025 | * to ensure compatibility with userspace applications that still use the | ||
3026 | * legacy modesetting UAPI. | ||
3027 | * | ||
3028 | * Allocations set by this function are not checked against the bandwidth | ||
3029 | * restraints of @mgr until the driver calls drm_dp_mst_atomic_check(). | ||
3030 | * | ||
3031 | * Additionally, it is OK to call this function multiple times on the same | ||
3032 | * @port as needed. It is not OK however, to call this function and | ||
3033 | * drm_dp_atomic_release_vcpi_slots() in the same atomic check phase. | ||
3034 | * | ||
3035 | * See also: | ||
3036 | * drm_dp_atomic_release_vcpi_slots() | ||
3037 | * drm_dp_mst_atomic_check() | ||
3038 | * | ||
3039 | * Returns: | ||
3040 | * Total slots in the atomic state assigned for this port, or a negative error | ||
3041 | * code if the port no longer exists | ||
2640 | */ | 3042 | */ |
2641 | int drm_dp_atomic_find_vcpi_slots(struct drm_atomic_state *state, | 3043 | int drm_dp_atomic_find_vcpi_slots(struct drm_atomic_state *state, |
2642 | struct drm_dp_mst_topology_mgr *mgr, | 3044 | struct drm_dp_mst_topology_mgr *mgr, |
2643 | struct drm_dp_mst_port *port, int pbn) | 3045 | struct drm_dp_mst_port *port, int pbn) |
2644 | { | 3046 | { |
2645 | struct drm_dp_mst_topology_state *topology_state; | 3047 | struct drm_dp_mst_topology_state *topology_state; |
2646 | int req_slots; | 3048 | struct drm_dp_vcpi_allocation *pos, *vcpi = NULL; |
3049 | int prev_slots, req_slots, ret; | ||
2647 | 3050 | ||
2648 | topology_state = drm_atomic_get_mst_topology_state(state, mgr); | 3051 | topology_state = drm_atomic_get_mst_topology_state(state, mgr); |
2649 | if (IS_ERR(topology_state)) | 3052 | if (IS_ERR(topology_state)) |
2650 | return PTR_ERR(topology_state); | 3053 | return PTR_ERR(topology_state); |
2651 | 3054 | ||
2652 | port = drm_dp_get_validated_port_ref(mgr, port); | 3055 | port = drm_dp_mst_topology_get_port_validated(mgr, port); |
2653 | if (port == NULL) | 3056 | if (port == NULL) |
2654 | return -EINVAL; | 3057 | return -EINVAL; |
2655 | req_slots = DIV_ROUND_UP(pbn, mgr->pbn_div); | ||
2656 | DRM_DEBUG_KMS("vcpi slots req=%d, avail=%d\n", | ||
2657 | req_slots, topology_state->avail_slots); | ||
2658 | 3058 | ||
2659 | if (req_slots > topology_state->avail_slots) { | 3059 | /* Find the current allocation for this port, if any */ |
2660 | drm_dp_put_port(port); | 3060 | list_for_each_entry(pos, &topology_state->vcpis, next) { |
2661 | return -ENOSPC; | 3061 | if (pos->port == port) { |
3062 | vcpi = pos; | ||
3063 | prev_slots = vcpi->vcpi; | ||
3064 | |||
3065 | /* | ||
3066 | * This should never happen, unless the driver tries | ||
3067 | * releasing and allocating the same VCPI allocation, | ||
3068 | * which is an error | ||
3069 | */ | ||
3070 | if (WARN_ON(!prev_slots)) { | ||
3071 | DRM_ERROR("cannot allocate and release VCPI on [MST PORT:%p] in the same state\n", | ||
3072 | port); | ||
3073 | return -EINVAL; | ||
3074 | } | ||
3075 | |||
3076 | break; | ||
3077 | } | ||
2662 | } | 3078 | } |
3079 | if (!vcpi) | ||
3080 | prev_slots = 0; | ||
3081 | |||
3082 | req_slots = DIV_ROUND_UP(pbn, mgr->pbn_div); | ||
2663 | 3083 | ||
2664 | topology_state->avail_slots -= req_slots; | 3084 | DRM_DEBUG_ATOMIC("[CONNECTOR:%d:%s] [MST PORT:%p] VCPI %d -> %d\n", |
2665 | DRM_DEBUG_KMS("vcpi slots avail=%d", topology_state->avail_slots); | 3085 | port->connector->base.id, port->connector->name, |
3086 | port, prev_slots, req_slots); | ||
3087 | |||
3088 | /* Add the new allocation to the state */ | ||
3089 | if (!vcpi) { | ||
3090 | vcpi = kzalloc(sizeof(*vcpi), GFP_KERNEL); | ||
3091 | if (!vcpi) { | ||
3092 | ret = -ENOMEM; | ||
3093 | goto out; | ||
3094 | } | ||
3095 | |||
3096 | drm_dp_mst_get_port_malloc(port); | ||
3097 | vcpi->port = port; | ||
3098 | list_add(&vcpi->next, &topology_state->vcpis); | ||
3099 | } | ||
3100 | vcpi->vcpi = req_slots; | ||
2666 | 3101 | ||
2667 | drm_dp_put_port(port); | 3102 | ret = req_slots; |
2668 | return req_slots; | 3103 | out: |
3104 | drm_dp_mst_topology_put_port(port); | ||
3105 | return ret; | ||
2669 | } | 3106 | } |
2670 | EXPORT_SYMBOL(drm_dp_atomic_find_vcpi_slots); | 3107 | EXPORT_SYMBOL(drm_dp_atomic_find_vcpi_slots); |
2671 | 3108 | ||
@@ -2673,31 +3110,57 @@ EXPORT_SYMBOL(drm_dp_atomic_find_vcpi_slots); | |||
2673 | * drm_dp_atomic_release_vcpi_slots() - Release allocated vcpi slots | 3110 | * drm_dp_atomic_release_vcpi_slots() - Release allocated vcpi slots |
2674 | * @state: global atomic state | 3111 | * @state: global atomic state |
2675 | * @mgr: MST topology manager for the port | 3112 | * @mgr: MST topology manager for the port |
2676 | * @slots: number of vcpi slots to release | 3113 | * @port: The port to release the VCPI slots from |
2677 | * | 3114 | * |
2678 | * RETURNS: | 3115 | * Releases any VCPI slots that have been allocated to a port in the atomic |
2679 | * 0 if @slots were added back to &drm_dp_mst_topology_state->avail_slots or | 3116 | * state. Any atomic drivers which support MST must call this function in |
2680 | * negative error code | 3117 | * their &drm_connector_helper_funcs.atomic_check() callback when the |
3118 | * connector will no longer have VCPI allocated (e.g. because it's CRTC was | ||
3119 | * removed) when it had VCPI allocated in the previous atomic state. | ||
3120 | * | ||
3121 | * It is OK to call this even if @port has been removed from the system. | ||
3122 | * Additionally, it is OK to call this function multiple times on the same | ||
3123 | * @port as needed. It is not OK however, to call this function and | ||
3124 | * drm_dp_atomic_find_vcpi_slots() on the same @port in a single atomic check | ||
3125 | * phase. | ||
3126 | * | ||
3127 | * See also: | ||
3128 | * drm_dp_atomic_find_vcpi_slots() | ||
3129 | * drm_dp_mst_atomic_check() | ||
3130 | * | ||
3131 | * Returns: | ||
3132 | * 0 if all slots for this port were added back to | ||
3133 | * &drm_dp_mst_topology_state.avail_slots or negative error code | ||
2681 | */ | 3134 | */ |
2682 | int drm_dp_atomic_release_vcpi_slots(struct drm_atomic_state *state, | 3135 | int drm_dp_atomic_release_vcpi_slots(struct drm_atomic_state *state, |
2683 | struct drm_dp_mst_topology_mgr *mgr, | 3136 | struct drm_dp_mst_topology_mgr *mgr, |
2684 | int slots) | 3137 | struct drm_dp_mst_port *port) |
2685 | { | 3138 | { |
2686 | struct drm_dp_mst_topology_state *topology_state; | 3139 | struct drm_dp_mst_topology_state *topology_state; |
3140 | struct drm_dp_vcpi_allocation *pos; | ||
3141 | bool found = false; | ||
2687 | 3142 | ||
2688 | topology_state = drm_atomic_get_mst_topology_state(state, mgr); | 3143 | topology_state = drm_atomic_get_mst_topology_state(state, mgr); |
2689 | if (IS_ERR(topology_state)) | 3144 | if (IS_ERR(topology_state)) |
2690 | return PTR_ERR(topology_state); | 3145 | return PTR_ERR(topology_state); |
2691 | 3146 | ||
2692 | /* We cannot rely on port->vcpi.num_slots to update | 3147 | list_for_each_entry(pos, &topology_state->vcpis, next) { |
2693 | * topology_state->avail_slots as the port may not exist if the parent | 3148 | if (pos->port == port) { |
2694 | * branch device was unplugged. This should be fixed by tracking | 3149 | found = true; |
2695 | * per-port slot allocation in drm_dp_mst_topology_state instead of | 3150 | break; |
2696 | * depending on the caller to tell us how many slots to release. | 3151 | } |
2697 | */ | 3152 | } |
2698 | topology_state->avail_slots += slots; | 3153 | if (WARN_ON(!found)) { |
2699 | DRM_DEBUG_KMS("vcpi slots released=%d, avail=%d\n", | 3154 | DRM_ERROR("no VCPI for [MST PORT:%p] found in mst state %p\n", |
2700 | slots, topology_state->avail_slots); | 3155 | port, &topology_state->base); |
3156 | return -EINVAL; | ||
3157 | } | ||
3158 | |||
3159 | DRM_DEBUG_ATOMIC("[MST PORT:%p] VCPI %d -> 0\n", port, pos->vcpi); | ||
3160 | if (pos->vcpi) { | ||
3161 | drm_dp_mst_put_port_malloc(port); | ||
3162 | pos->vcpi = 0; | ||
3163 | } | ||
2701 | 3164 | ||
2702 | return 0; | 3165 | return 0; |
2703 | } | 3166 | } |
@@ -2715,7 +3178,7 @@ bool drm_dp_mst_allocate_vcpi(struct drm_dp_mst_topology_mgr *mgr, | |||
2715 | { | 3178 | { |
2716 | int ret; | 3179 | int ret; |
2717 | 3180 | ||
2718 | port = drm_dp_get_validated_port_ref(mgr, port); | 3181 | port = drm_dp_mst_topology_get_port_validated(mgr, port); |
2719 | if (!port) | 3182 | if (!port) |
2720 | return false; | 3183 | return false; |
2721 | 3184 | ||
@@ -2723,9 +3186,10 @@ bool drm_dp_mst_allocate_vcpi(struct drm_dp_mst_topology_mgr *mgr, | |||
2723 | return false; | 3186 | return false; |
2724 | 3187 | ||
2725 | if (port->vcpi.vcpi > 0) { | 3188 | if (port->vcpi.vcpi > 0) { |
2726 | DRM_DEBUG_KMS("payload: vcpi %d already allocated for pbn %d - requested pbn %d\n", port->vcpi.vcpi, port->vcpi.pbn, pbn); | 3189 | DRM_DEBUG_KMS("payload: vcpi %d already allocated for pbn %d - requested pbn %d\n", |
3190 | port->vcpi.vcpi, port->vcpi.pbn, pbn); | ||
2727 | if (pbn == port->vcpi.pbn) { | 3191 | if (pbn == port->vcpi.pbn) { |
2728 | drm_dp_put_port(port); | 3192 | drm_dp_mst_topology_put_port(port); |
2729 | return true; | 3193 | return true; |
2730 | } | 3194 | } |
2731 | } | 3195 | } |
@@ -2733,13 +3197,15 @@ bool drm_dp_mst_allocate_vcpi(struct drm_dp_mst_topology_mgr *mgr, | |||
2733 | ret = drm_dp_init_vcpi(mgr, &port->vcpi, pbn, slots); | 3197 | ret = drm_dp_init_vcpi(mgr, &port->vcpi, pbn, slots); |
2734 | if (ret) { | 3198 | if (ret) { |
2735 | DRM_DEBUG_KMS("failed to init vcpi slots=%d max=63 ret=%d\n", | 3199 | DRM_DEBUG_KMS("failed to init vcpi slots=%d max=63 ret=%d\n", |
2736 | DIV_ROUND_UP(pbn, mgr->pbn_div), ret); | 3200 | DIV_ROUND_UP(pbn, mgr->pbn_div), ret); |
2737 | goto out; | 3201 | goto out; |
2738 | } | 3202 | } |
2739 | DRM_DEBUG_KMS("initing vcpi for pbn=%d slots=%d\n", | 3203 | DRM_DEBUG_KMS("initing vcpi for pbn=%d slots=%d\n", |
2740 | pbn, port->vcpi.num_slots); | 3204 | pbn, port->vcpi.num_slots); |
2741 | 3205 | ||
2742 | drm_dp_put_port(port); | 3206 | /* Keep port allocated until it's payload has been removed */ |
3207 | drm_dp_mst_get_port_malloc(port); | ||
3208 | drm_dp_mst_topology_put_port(port); | ||
2743 | return true; | 3209 | return true; |
2744 | out: | 3210 | out: |
2745 | return false; | 3211 | return false; |
@@ -2749,12 +3215,12 @@ EXPORT_SYMBOL(drm_dp_mst_allocate_vcpi); | |||
2749 | int drm_dp_mst_get_vcpi_slots(struct drm_dp_mst_topology_mgr *mgr, struct drm_dp_mst_port *port) | 3215 | int drm_dp_mst_get_vcpi_slots(struct drm_dp_mst_topology_mgr *mgr, struct drm_dp_mst_port *port) |
2750 | { | 3216 | { |
2751 | int slots = 0; | 3217 | int slots = 0; |
2752 | port = drm_dp_get_validated_port_ref(mgr, port); | 3218 | port = drm_dp_mst_topology_get_port_validated(mgr, port); |
2753 | if (!port) | 3219 | if (!port) |
2754 | return slots; | 3220 | return slots; |
2755 | 3221 | ||
2756 | slots = port->vcpi.num_slots; | 3222 | slots = port->vcpi.num_slots; |
2757 | drm_dp_put_port(port); | 3223 | drm_dp_mst_topology_put_port(port); |
2758 | return slots; | 3224 | return slots; |
2759 | } | 3225 | } |
2760 | EXPORT_SYMBOL(drm_dp_mst_get_vcpi_slots); | 3226 | EXPORT_SYMBOL(drm_dp_mst_get_vcpi_slots); |
@@ -2768,11 +3234,12 @@ EXPORT_SYMBOL(drm_dp_mst_get_vcpi_slots); | |||
2768 | */ | 3234 | */ |
2769 | void drm_dp_mst_reset_vcpi_slots(struct drm_dp_mst_topology_mgr *mgr, struct drm_dp_mst_port *port) | 3235 | void drm_dp_mst_reset_vcpi_slots(struct drm_dp_mst_topology_mgr *mgr, struct drm_dp_mst_port *port) |
2770 | { | 3236 | { |
2771 | port = drm_dp_get_validated_port_ref(mgr, port); | 3237 | /* |
2772 | if (!port) | 3238 | * A port with VCPI will remain allocated until it's VCPI is |
2773 | return; | 3239 | * released, no verified ref needed |
3240 | */ | ||
3241 | |||
2774 | port->vcpi.num_slots = 0; | 3242 | port->vcpi.num_slots = 0; |
2775 | drm_dp_put_port(port); | ||
2776 | } | 3243 | } |
2777 | EXPORT_SYMBOL(drm_dp_mst_reset_vcpi_slots); | 3244 | EXPORT_SYMBOL(drm_dp_mst_reset_vcpi_slots); |
2778 | 3245 | ||
@@ -2781,18 +3248,20 @@ EXPORT_SYMBOL(drm_dp_mst_reset_vcpi_slots); | |||
2781 | * @mgr: manager for this port | 3248 | * @mgr: manager for this port |
2782 | * @port: unverified port to deallocate vcpi for | 3249 | * @port: unverified port to deallocate vcpi for |
2783 | */ | 3250 | */ |
2784 | void drm_dp_mst_deallocate_vcpi(struct drm_dp_mst_topology_mgr *mgr, struct drm_dp_mst_port *port) | 3251 | void drm_dp_mst_deallocate_vcpi(struct drm_dp_mst_topology_mgr *mgr, |
3252 | struct drm_dp_mst_port *port) | ||
2785 | { | 3253 | { |
2786 | port = drm_dp_get_validated_port_ref(mgr, port); | 3254 | /* |
2787 | if (!port) | 3255 | * A port with VCPI will remain allocated until it's VCPI is |
2788 | return; | 3256 | * released, no verified ref needed |
3257 | */ | ||
2789 | 3258 | ||
2790 | drm_dp_mst_put_payload_id(mgr, port->vcpi.vcpi); | 3259 | drm_dp_mst_put_payload_id(mgr, port->vcpi.vcpi); |
2791 | port->vcpi.num_slots = 0; | 3260 | port->vcpi.num_slots = 0; |
2792 | port->vcpi.pbn = 0; | 3261 | port->vcpi.pbn = 0; |
2793 | port->vcpi.aligned_pbn = 0; | 3262 | port->vcpi.aligned_pbn = 0; |
2794 | port->vcpi.vcpi = 0; | 3263 | port->vcpi.vcpi = 0; |
2795 | drm_dp_put_port(port); | 3264 | drm_dp_mst_put_port_malloc(port); |
2796 | } | 3265 | } |
2797 | EXPORT_SYMBOL(drm_dp_mst_deallocate_vcpi); | 3266 | EXPORT_SYMBOL(drm_dp_mst_deallocate_vcpi); |
2798 | 3267 | ||
@@ -3076,13 +3545,6 @@ static void drm_dp_tx_work(struct work_struct *work) | |||
3076 | mutex_unlock(&mgr->qlock); | 3545 | mutex_unlock(&mgr->qlock); |
3077 | } | 3546 | } |
3078 | 3547 | ||
3079 | static void drm_dp_free_mst_port(struct kref *kref) | ||
3080 | { | ||
3081 | struct drm_dp_mst_port *port = container_of(kref, struct drm_dp_mst_port, kref); | ||
3082 | kref_put(&port->parent->kref, drm_dp_free_mst_branch_device); | ||
3083 | kfree(port); | ||
3084 | } | ||
3085 | |||
3086 | static void drm_dp_destroy_connector_work(struct work_struct *work) | 3548 | static void drm_dp_destroy_connector_work(struct work_struct *work) |
3087 | { | 3549 | { |
3088 | struct drm_dp_mst_topology_mgr *mgr = container_of(work, struct drm_dp_mst_topology_mgr, destroy_connector_work); | 3550 | struct drm_dp_mst_topology_mgr *mgr = container_of(work, struct drm_dp_mst_topology_mgr, destroy_connector_work); |
@@ -3103,7 +3565,6 @@ static void drm_dp_destroy_connector_work(struct work_struct *work) | |||
3103 | list_del(&port->next); | 3565 | list_del(&port->next); |
3104 | mutex_unlock(&mgr->destroy_connector_lock); | 3566 | mutex_unlock(&mgr->destroy_connector_lock); |
3105 | 3567 | ||
3106 | kref_init(&port->kref); | ||
3107 | INIT_LIST_HEAD(&port->next); | 3568 | INIT_LIST_HEAD(&port->next); |
3108 | 3569 | ||
3109 | mgr->cbs->destroy_connector(mgr, port->connector); | 3570 | mgr->cbs->destroy_connector(mgr, port->connector); |
@@ -3111,13 +3572,7 @@ static void drm_dp_destroy_connector_work(struct work_struct *work) | |||
3111 | drm_dp_port_teardown_pdt(port, port->pdt); | 3572 | drm_dp_port_teardown_pdt(port, port->pdt); |
3112 | port->pdt = DP_PEER_DEVICE_NONE; | 3573 | port->pdt = DP_PEER_DEVICE_NONE; |
3113 | 3574 | ||
3114 | if (!port->input && port->vcpi.vcpi > 0) { | 3575 | drm_dp_mst_put_port_malloc(port); |
3115 | drm_dp_mst_reset_vcpi_slots(mgr, port); | ||
3116 | drm_dp_update_payload_part1(mgr); | ||
3117 | drm_dp_mst_put_payload_id(mgr, port->vcpi.vcpi); | ||
3118 | } | ||
3119 | |||
3120 | kref_put(&port->kref, drm_dp_free_mst_port); | ||
3121 | send_hotplug = true; | 3576 | send_hotplug = true; |
3122 | } | 3577 | } |
3123 | if (send_hotplug) | 3578 | if (send_hotplug) |
@@ -3127,15 +3582,41 @@ static void drm_dp_destroy_connector_work(struct work_struct *work) | |||
3127 | static struct drm_private_state * | 3582 | static struct drm_private_state * |
3128 | drm_dp_mst_duplicate_state(struct drm_private_obj *obj) | 3583 | drm_dp_mst_duplicate_state(struct drm_private_obj *obj) |
3129 | { | 3584 | { |
3130 | struct drm_dp_mst_topology_state *state; | 3585 | struct drm_dp_mst_topology_state *state, *old_state = |
3586 | to_dp_mst_topology_state(obj->state); | ||
3587 | struct drm_dp_vcpi_allocation *pos, *vcpi; | ||
3131 | 3588 | ||
3132 | state = kmemdup(obj->state, sizeof(*state), GFP_KERNEL); | 3589 | state = kmemdup(old_state, sizeof(*state), GFP_KERNEL); |
3133 | if (!state) | 3590 | if (!state) |
3134 | return NULL; | 3591 | return NULL; |
3135 | 3592 | ||
3136 | __drm_atomic_helper_private_obj_duplicate_state(obj, &state->base); | 3593 | __drm_atomic_helper_private_obj_duplicate_state(obj, &state->base); |
3137 | 3594 | ||
3595 | INIT_LIST_HEAD(&state->vcpis); | ||
3596 | |||
3597 | list_for_each_entry(pos, &old_state->vcpis, next) { | ||
3598 | /* Prune leftover freed VCPI allocations */ | ||
3599 | if (!pos->vcpi) | ||
3600 | continue; | ||
3601 | |||
3602 | vcpi = kmemdup(pos, sizeof(*vcpi), GFP_KERNEL); | ||
3603 | if (!vcpi) | ||
3604 | goto fail; | ||
3605 | |||
3606 | drm_dp_mst_get_port_malloc(vcpi->port); | ||
3607 | list_add(&vcpi->next, &state->vcpis); | ||
3608 | } | ||
3609 | |||
3138 | return &state->base; | 3610 | return &state->base; |
3611 | |||
3612 | fail: | ||
3613 | list_for_each_entry_safe(pos, vcpi, &state->vcpis, next) { | ||
3614 | drm_dp_mst_put_port_malloc(pos->port); | ||
3615 | kfree(pos); | ||
3616 | } | ||
3617 | kfree(state); | ||
3618 | |||
3619 | return NULL; | ||
3139 | } | 3620 | } |
3140 | 3621 | ||
3141 | static void drm_dp_mst_destroy_state(struct drm_private_obj *obj, | 3622 | static void drm_dp_mst_destroy_state(struct drm_private_obj *obj, |
@@ -3143,14 +3624,99 @@ static void drm_dp_mst_destroy_state(struct drm_private_obj *obj, | |||
3143 | { | 3624 | { |
3144 | struct drm_dp_mst_topology_state *mst_state = | 3625 | struct drm_dp_mst_topology_state *mst_state = |
3145 | to_dp_mst_topology_state(state); | 3626 | to_dp_mst_topology_state(state); |
3627 | struct drm_dp_vcpi_allocation *pos, *tmp; | ||
3628 | |||
3629 | list_for_each_entry_safe(pos, tmp, &mst_state->vcpis, next) { | ||
3630 | /* We only keep references to ports with non-zero VCPIs */ | ||
3631 | if (pos->vcpi) | ||
3632 | drm_dp_mst_put_port_malloc(pos->port); | ||
3633 | kfree(pos); | ||
3634 | } | ||
3146 | 3635 | ||
3147 | kfree(mst_state); | 3636 | kfree(mst_state); |
3148 | } | 3637 | } |
3149 | 3638 | ||
3150 | static const struct drm_private_state_funcs mst_state_funcs = { | 3639 | static inline int |
3640 | drm_dp_mst_atomic_check_topology_state(struct drm_dp_mst_topology_mgr *mgr, | ||
3641 | struct drm_dp_mst_topology_state *mst_state) | ||
3642 | { | ||
3643 | struct drm_dp_vcpi_allocation *vcpi; | ||
3644 | int avail_slots = 63, payload_count = 0; | ||
3645 | |||
3646 | list_for_each_entry(vcpi, &mst_state->vcpis, next) { | ||
3647 | /* Releasing VCPI is always OK-even if the port is gone */ | ||
3648 | if (!vcpi->vcpi) { | ||
3649 | DRM_DEBUG_ATOMIC("[MST PORT:%p] releases all VCPI slots\n", | ||
3650 | vcpi->port); | ||
3651 | continue; | ||
3652 | } | ||
3653 | |||
3654 | DRM_DEBUG_ATOMIC("[MST PORT:%p] requires %d vcpi slots\n", | ||
3655 | vcpi->port, vcpi->vcpi); | ||
3656 | |||
3657 | avail_slots -= vcpi->vcpi; | ||
3658 | if (avail_slots < 0) { | ||
3659 | DRM_DEBUG_ATOMIC("[MST PORT:%p] not enough VCPI slots in mst state %p (avail=%d)\n", | ||
3660 | vcpi->port, mst_state, | ||
3661 | avail_slots + vcpi->vcpi); | ||
3662 | return -ENOSPC; | ||
3663 | } | ||
3664 | |||
3665 | if (++payload_count > mgr->max_payloads) { | ||
3666 | DRM_DEBUG_ATOMIC("[MST MGR:%p] state %p has too many payloads (max=%d)\n", | ||
3667 | mgr, mst_state, mgr->max_payloads); | ||
3668 | return -EINVAL; | ||
3669 | } | ||
3670 | } | ||
3671 | DRM_DEBUG_ATOMIC("[MST MGR:%p] mst state %p VCPI avail=%d used=%d\n", | ||
3672 | mgr, mst_state, avail_slots, | ||
3673 | 63 - avail_slots); | ||
3674 | |||
3675 | return 0; | ||
3676 | } | ||
3677 | |||
3678 | /** | ||
3679 | * drm_dp_mst_atomic_check - Check that the new state of an MST topology in an | ||
3680 | * atomic update is valid | ||
3681 | * @state: Pointer to the new &struct drm_dp_mst_topology_state | ||
3682 | * | ||
3683 | * Checks the given topology state for an atomic update to ensure that it's | ||
3684 | * valid. This includes checking whether there's enough bandwidth to support | ||
3685 | * the new VCPI allocations in the atomic update. | ||
3686 | * | ||
3687 | * Any atomic drivers supporting DP MST must make sure to call this after | ||
3688 | * checking the rest of their state in their | ||
3689 | * &drm_mode_config_funcs.atomic_check() callback. | ||
3690 | * | ||
3691 | * See also: | ||
3692 | * drm_dp_atomic_find_vcpi_slots() | ||
3693 | * drm_dp_atomic_release_vcpi_slots() | ||
3694 | * | ||
3695 | * Returns: | ||
3696 | * | ||
3697 | * 0 if the new state is valid, negative error code otherwise. | ||
3698 | */ | ||
3699 | int drm_dp_mst_atomic_check(struct drm_atomic_state *state) | ||
3700 | { | ||
3701 | struct drm_dp_mst_topology_mgr *mgr; | ||
3702 | struct drm_dp_mst_topology_state *mst_state; | ||
3703 | int i, ret = 0; | ||
3704 | |||
3705 | for_each_new_mst_mgr_in_state(state, mgr, mst_state, i) { | ||
3706 | ret = drm_dp_mst_atomic_check_topology_state(mgr, mst_state); | ||
3707 | if (ret) | ||
3708 | break; | ||
3709 | } | ||
3710 | |||
3711 | return ret; | ||
3712 | } | ||
3713 | EXPORT_SYMBOL(drm_dp_mst_atomic_check); | ||
3714 | |||
3715 | const struct drm_private_state_funcs drm_dp_mst_topology_state_funcs = { | ||
3151 | .atomic_duplicate_state = drm_dp_mst_duplicate_state, | 3716 | .atomic_duplicate_state = drm_dp_mst_duplicate_state, |
3152 | .atomic_destroy_state = drm_dp_mst_destroy_state, | 3717 | .atomic_destroy_state = drm_dp_mst_destroy_state, |
3153 | }; | 3718 | }; |
3719 | EXPORT_SYMBOL(drm_dp_mst_topology_state_funcs); | ||
3154 | 3720 | ||
3155 | /** | 3721 | /** |
3156 | * drm_atomic_get_mst_topology_state: get MST topology state | 3722 | * drm_atomic_get_mst_topology_state: get MST topology state |
@@ -3228,13 +3794,11 @@ int drm_dp_mst_topology_mgr_init(struct drm_dp_mst_topology_mgr *mgr, | |||
3228 | return -ENOMEM; | 3794 | return -ENOMEM; |
3229 | 3795 | ||
3230 | mst_state->mgr = mgr; | 3796 | mst_state->mgr = mgr; |
3231 | 3797 | INIT_LIST_HEAD(&mst_state->vcpis); | |
3232 | /* max. time slots - one slot for MTP header */ | ||
3233 | mst_state->avail_slots = 63; | ||
3234 | 3798 | ||
3235 | drm_atomic_private_obj_init(dev, &mgr->base, | 3799 | drm_atomic_private_obj_init(dev, &mgr->base, |
3236 | &mst_state->base, | 3800 | &mst_state->base, |
3237 | &mst_state_funcs); | 3801 | &drm_dp_mst_topology_state_funcs); |
3238 | 3802 | ||
3239 | return 0; | 3803 | return 0; |
3240 | } | 3804 | } |
@@ -3292,7 +3856,7 @@ static int drm_dp_mst_i2c_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs | |||
3292 | struct drm_dp_sideband_msg_tx *txmsg = NULL; | 3856 | struct drm_dp_sideband_msg_tx *txmsg = NULL; |
3293 | int ret; | 3857 | int ret; |
3294 | 3858 | ||
3295 | mstb = drm_dp_get_validated_mstb_ref(mgr, port->parent); | 3859 | mstb = drm_dp_mst_topology_get_mstb_validated(mgr, port->parent); |
3296 | if (!mstb) | 3860 | if (!mstb) |
3297 | return -EREMOTEIO; | 3861 | return -EREMOTEIO; |
3298 | 3862 | ||
@@ -3342,7 +3906,7 @@ static int drm_dp_mst_i2c_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs | |||
3342 | } | 3906 | } |
3343 | out: | 3907 | out: |
3344 | kfree(txmsg); | 3908 | kfree(txmsg); |
3345 | drm_dp_put_mst_branch_device(mstb); | 3909 | drm_dp_mst_topology_put_mstb(mstb); |
3346 | return ret; | 3910 | return ret; |
3347 | } | 3911 | } |
3348 | 3912 | ||
diff --git a/drivers/gpu/drm/drm_drv.c b/drivers/gpu/drm/drm_drv.c index a5fe91b8c3c9..381581b01d48 100644 --- a/drivers/gpu/drm/drm_drv.c +++ b/drivers/gpu/drm/drm_drv.c | |||
@@ -264,14 +264,13 @@ void drm_minor_release(struct drm_minor *minor) | |||
264 | * DOC: driver instance overview | 264 | * DOC: driver instance overview |
265 | * | 265 | * |
266 | * A device instance for a drm driver is represented by &struct drm_device. This | 266 | * A device instance for a drm driver is represented by &struct drm_device. This |
267 | * is allocated with drm_dev_alloc(), usually from bus-specific ->probe() | 267 | * is initialized with drm_dev_init(), usually from bus-specific ->probe() |
268 | * callbacks implemented by the driver. The driver then needs to initialize all | 268 | * callbacks implemented by the driver. The driver then needs to initialize all |
269 | * the various subsystems for the drm device like memory management, vblank | 269 | * the various subsystems for the drm device like memory management, vblank |
270 | * handling, modesetting support and intial output configuration plus obviously | 270 | * handling, modesetting support and intial output configuration plus obviously |
271 | * initialize all the corresponding hardware bits. An important part of this is | 271 | * initialize all the corresponding hardware bits. Finally when everything is up |
272 | * also calling drm_dev_set_unique() to set the userspace-visible unique name of | 272 | * and running and ready for userspace the device instance can be published |
273 | * this device instance. Finally when everything is up and running and ready for | 273 | * using drm_dev_register(). |
274 | * userspace the device instance can be published using drm_dev_register(). | ||
275 | * | 274 | * |
276 | * There is also deprecated support for initalizing device instances using | 275 | * There is also deprecated support for initalizing device instances using |
277 | * bus-specific helpers and the &drm_driver.load callback. But due to | 276 | * bus-specific helpers and the &drm_driver.load callback. But due to |
@@ -287,9 +286,6 @@ void drm_minor_release(struct drm_minor *minor) | |||
287 | * Note that the lifetime rules for &drm_device instance has still a lot of | 286 | * Note that the lifetime rules for &drm_device instance has still a lot of |
288 | * historical baggage. Hence use the reference counting provided by | 287 | * historical baggage. Hence use the reference counting provided by |
289 | * drm_dev_get() and drm_dev_put() only carefully. | 288 | * drm_dev_get() and drm_dev_put() only carefully. |
290 | * | ||
291 | * It is recommended that drivers embed &struct drm_device into their own device | ||
292 | * structure, which is supported through drm_dev_init(). | ||
293 | */ | 289 | */ |
294 | 290 | ||
295 | /** | 291 | /** |
@@ -475,6 +471,9 @@ static void drm_fs_inode_free(struct inode *inode) | |||
475 | * The initial ref-count of the object is 1. Use drm_dev_get() and | 471 | * The initial ref-count of the object is 1. Use drm_dev_get() and |
476 | * drm_dev_put() to take and drop further ref-counts. | 472 | * drm_dev_put() to take and drop further ref-counts. |
477 | * | 473 | * |
474 | * It is recommended that drivers embed &struct drm_device into their own device | ||
475 | * structure. | ||
476 | * | ||
478 | * Drivers that do not want to allocate their own device struct | 477 | * Drivers that do not want to allocate their own device struct |
479 | * embedding &struct drm_device can call drm_dev_alloc() instead. For drivers | 478 | * embedding &struct drm_device can call drm_dev_alloc() instead. For drivers |
480 | * that do embed &struct drm_device it must be placed first in the overall | 479 | * that do embed &struct drm_device it must be placed first in the overall |
@@ -765,7 +764,7 @@ static void remove_compat_control_link(struct drm_device *dev) | |||
765 | * @flags: Flags passed to the driver's .load() function | 764 | * @flags: Flags passed to the driver's .load() function |
766 | * | 765 | * |
767 | * Register the DRM device @dev with the system, advertise device to user-space | 766 | * Register the DRM device @dev with the system, advertise device to user-space |
768 | * and start normal device operation. @dev must be allocated via drm_dev_alloc() | 767 | * and start normal device operation. @dev must be initialized via drm_dev_init() |
769 | * previously. | 768 | * previously. |
770 | * | 769 | * |
771 | * Never call this twice on any device! | 770 | * Never call this twice on any device! |
@@ -877,9 +876,9 @@ EXPORT_SYMBOL(drm_dev_unregister); | |||
877 | * @dev: device of which to set the unique name | 876 | * @dev: device of which to set the unique name |
878 | * @name: unique name | 877 | * @name: unique name |
879 | * | 878 | * |
880 | * Sets the unique name of a DRM device using the specified string. Drivers | 879 | * Sets the unique name of a DRM device using the specified string. This is |
881 | * can use this at driver probe time if the unique name of the devices they | 880 | * already done by drm_dev_init(), drivers should only override the default |
882 | * drive is static. | 881 | * unique name for backwards compatibility reasons. |
883 | * | 882 | * |
884 | * Return: 0 on success or a negative error code on failure. | 883 | * Return: 0 on success or a negative error code on failure. |
885 | */ | 884 | */ |
diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index b506e3622b08..990b1909f9d7 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c | |||
@@ -3641,6 +3641,20 @@ static bool cea_db_is_hdmi_forum_vsdb(const u8 *db) | |||
3641 | return oui == HDMI_FORUM_IEEE_OUI; | 3641 | return oui == HDMI_FORUM_IEEE_OUI; |
3642 | } | 3642 | } |
3643 | 3643 | ||
3644 | static bool cea_db_is_vcdb(const u8 *db) | ||
3645 | { | ||
3646 | if (cea_db_tag(db) != USE_EXTENDED_TAG) | ||
3647 | return false; | ||
3648 | |||
3649 | if (cea_db_payload_len(db) != 2) | ||
3650 | return false; | ||
3651 | |||
3652 | if (cea_db_extended_tag(db) != EXT_VIDEO_CAPABILITY_BLOCK) | ||
3653 | return false; | ||
3654 | |||
3655 | return true; | ||
3656 | } | ||
3657 | |||
3644 | static bool cea_db_is_y420cmdb(const u8 *db) | 3658 | static bool cea_db_is_y420cmdb(const u8 *db) |
3645 | { | 3659 | { |
3646 | if (cea_db_tag(db) != USE_EXTENDED_TAG) | 3660 | if (cea_db_tag(db) != USE_EXTENDED_TAG) |
@@ -4223,41 +4237,6 @@ end: | |||
4223 | } | 4237 | } |
4224 | EXPORT_SYMBOL(drm_detect_monitor_audio); | 4238 | EXPORT_SYMBOL(drm_detect_monitor_audio); |
4225 | 4239 | ||
4226 | /** | ||
4227 | * drm_rgb_quant_range_selectable - is RGB quantization range selectable? | ||
4228 | * @edid: EDID block to scan | ||
4229 | * | ||
4230 | * Check whether the monitor reports the RGB quantization range selection | ||
4231 | * as supported. The AVI infoframe can then be used to inform the monitor | ||
4232 | * which quantization range (full or limited) is used. | ||
4233 | * | ||
4234 | * Return: True if the RGB quantization range is selectable, false otherwise. | ||
4235 | */ | ||
4236 | bool drm_rgb_quant_range_selectable(struct edid *edid) | ||
4237 | { | ||
4238 | u8 *edid_ext; | ||
4239 | int i, start, end; | ||
4240 | |||
4241 | edid_ext = drm_find_cea_extension(edid); | ||
4242 | if (!edid_ext) | ||
4243 | return false; | ||
4244 | |||
4245 | if (cea_db_offsets(edid_ext, &start, &end)) | ||
4246 | return false; | ||
4247 | |||
4248 | for_each_cea_db(edid_ext, i, start, end) { | ||
4249 | if (cea_db_tag(&edid_ext[i]) == USE_EXTENDED_TAG && | ||
4250 | cea_db_payload_len(&edid_ext[i]) == 2 && | ||
4251 | cea_db_extended_tag(&edid_ext[i]) == | ||
4252 | EXT_VIDEO_CAPABILITY_BLOCK) { | ||
4253 | DRM_DEBUG_KMS("CEA VCDB 0x%02x\n", edid_ext[i + 2]); | ||
4254 | return edid_ext[i + 2] & EDID_CEA_VCDB_QS; | ||
4255 | } | ||
4256 | } | ||
4257 | |||
4258 | return false; | ||
4259 | } | ||
4260 | EXPORT_SYMBOL(drm_rgb_quant_range_selectable); | ||
4261 | 4240 | ||
4262 | /** | 4241 | /** |
4263 | * drm_default_rgb_quant_range - default RGB quantization range | 4242 | * drm_default_rgb_quant_range - default RGB quantization range |
@@ -4278,6 +4257,16 @@ drm_default_rgb_quant_range(const struct drm_display_mode *mode) | |||
4278 | } | 4257 | } |
4279 | EXPORT_SYMBOL(drm_default_rgb_quant_range); | 4258 | EXPORT_SYMBOL(drm_default_rgb_quant_range); |
4280 | 4259 | ||
4260 | static void drm_parse_vcdb(struct drm_connector *connector, const u8 *db) | ||
4261 | { | ||
4262 | struct drm_display_info *info = &connector->display_info; | ||
4263 | |||
4264 | DRM_DEBUG_KMS("CEA VCDB 0x%02x\n", db[2]); | ||
4265 | |||
4266 | if (db[2] & EDID_CEA_VCDB_QS) | ||
4267 | info->rgb_quant_range_selectable = true; | ||
4268 | } | ||
4269 | |||
4281 | static void drm_parse_ycbcr420_deep_color_info(struct drm_connector *connector, | 4270 | static void drm_parse_ycbcr420_deep_color_info(struct drm_connector *connector, |
4282 | const u8 *db) | 4271 | const u8 *db) |
4283 | { | 4272 | { |
@@ -4452,6 +4441,8 @@ static void drm_parse_cea_ext(struct drm_connector *connector, | |||
4452 | drm_parse_hdmi_forum_vsdb(connector, db); | 4441 | drm_parse_hdmi_forum_vsdb(connector, db); |
4453 | if (cea_db_is_y420cmdb(db)) | 4442 | if (cea_db_is_y420cmdb(db)) |
4454 | drm_parse_y420cmdb_bitmap(connector, db); | 4443 | drm_parse_y420cmdb_bitmap(connector, db); |
4444 | if (cea_db_is_vcdb(db)) | ||
4445 | drm_parse_vcdb(connector, db); | ||
4455 | } | 4446 | } |
4456 | } | 4447 | } |
4457 | 4448 | ||
@@ -4472,6 +4463,7 @@ drm_reset_display_info(struct drm_connector *connector) | |||
4472 | info->max_tmds_clock = 0; | 4463 | info->max_tmds_clock = 0; |
4473 | info->dvi_dual = false; | 4464 | info->dvi_dual = false; |
4474 | info->has_hdmi_infoframe = false; | 4465 | info->has_hdmi_infoframe = false; |
4466 | info->rgb_quant_range_selectable = false; | ||
4475 | memset(&info->hdmi, 0, sizeof(info->hdmi)); | 4467 | memset(&info->hdmi, 0, sizeof(info->hdmi)); |
4476 | 4468 | ||
4477 | info->non_desktop = 0; | 4469 | info->non_desktop = 0; |
@@ -4830,19 +4822,32 @@ void drm_set_preferred_mode(struct drm_connector *connector, | |||
4830 | } | 4822 | } |
4831 | EXPORT_SYMBOL(drm_set_preferred_mode); | 4823 | EXPORT_SYMBOL(drm_set_preferred_mode); |
4832 | 4824 | ||
4825 | static bool is_hdmi2_sink(struct drm_connector *connector) | ||
4826 | { | ||
4827 | /* | ||
4828 | * FIXME: sil-sii8620 doesn't have a connector around when | ||
4829 | * we need one, so we have to be prepared for a NULL connector. | ||
4830 | */ | ||
4831 | if (!connector) | ||
4832 | return true; | ||
4833 | |||
4834 | return connector->display_info.hdmi.scdc.supported || | ||
4835 | connector->display_info.color_formats & DRM_COLOR_FORMAT_YCRCB420; | ||
4836 | } | ||
4837 | |||
4833 | /** | 4838 | /** |
4834 | * drm_hdmi_avi_infoframe_from_display_mode() - fill an HDMI AVI infoframe with | 4839 | * drm_hdmi_avi_infoframe_from_display_mode() - fill an HDMI AVI infoframe with |
4835 | * data from a DRM display mode | 4840 | * data from a DRM display mode |
4836 | * @frame: HDMI AVI infoframe | 4841 | * @frame: HDMI AVI infoframe |
4842 | * @connector: the connector | ||
4837 | * @mode: DRM display mode | 4843 | * @mode: DRM display mode |
4838 | * @is_hdmi2_sink: Sink is HDMI 2.0 compliant | ||
4839 | * | 4844 | * |
4840 | * Return: 0 on success or a negative error code on failure. | 4845 | * Return: 0 on success or a negative error code on failure. |
4841 | */ | 4846 | */ |
4842 | int | 4847 | int |
4843 | drm_hdmi_avi_infoframe_from_display_mode(struct hdmi_avi_infoframe *frame, | 4848 | drm_hdmi_avi_infoframe_from_display_mode(struct hdmi_avi_infoframe *frame, |
4844 | const struct drm_display_mode *mode, | 4849 | struct drm_connector *connector, |
4845 | bool is_hdmi2_sink) | 4850 | const struct drm_display_mode *mode) |
4846 | { | 4851 | { |
4847 | enum hdmi_picture_aspect picture_aspect; | 4852 | enum hdmi_picture_aspect picture_aspect; |
4848 | int err; | 4853 | int err; |
@@ -4864,7 +4869,7 @@ drm_hdmi_avi_infoframe_from_display_mode(struct hdmi_avi_infoframe *frame, | |||
4864 | * HDMI 2.0 VIC range: 1 <= VIC <= 107 (CEA-861-F). So we | 4869 | * HDMI 2.0 VIC range: 1 <= VIC <= 107 (CEA-861-F). So we |
4865 | * have to make sure we dont break HDMI 1.4 sinks. | 4870 | * have to make sure we dont break HDMI 1.4 sinks. |
4866 | */ | 4871 | */ |
4867 | if (!is_hdmi2_sink && frame->video_code > 64) | 4872 | if (!is_hdmi2_sink(connector) && frame->video_code > 64) |
4868 | frame->video_code = 0; | 4873 | frame->video_code = 0; |
4869 | 4874 | ||
4870 | /* | 4875 | /* |
@@ -4923,22 +4928,18 @@ EXPORT_SYMBOL(drm_hdmi_avi_infoframe_from_display_mode); | |||
4923 | * drm_hdmi_avi_infoframe_quant_range() - fill the HDMI AVI infoframe | 4928 | * drm_hdmi_avi_infoframe_quant_range() - fill the HDMI AVI infoframe |
4924 | * quantization range information | 4929 | * quantization range information |
4925 | * @frame: HDMI AVI infoframe | 4930 | * @frame: HDMI AVI infoframe |
4931 | * @connector: the connector | ||
4926 | * @mode: DRM display mode | 4932 | * @mode: DRM display mode |
4927 | * @rgb_quant_range: RGB quantization range (Q) | 4933 | * @rgb_quant_range: RGB quantization range (Q) |
4928 | * @rgb_quant_range_selectable: Sink support selectable RGB quantization range (QS) | ||
4929 | * @is_hdmi2_sink: HDMI 2.0 sink, which has different default recommendations | ||
4930 | * | ||
4931 | * Note that @is_hdmi2_sink can be derived by looking at the | ||
4932 | * &drm_scdc.supported flag stored in &drm_hdmi_info.scdc, | ||
4933 | * &drm_display_info.hdmi, which can be found in &drm_connector.display_info. | ||
4934 | */ | 4934 | */ |
4935 | void | 4935 | void |
4936 | drm_hdmi_avi_infoframe_quant_range(struct hdmi_avi_infoframe *frame, | 4936 | drm_hdmi_avi_infoframe_quant_range(struct hdmi_avi_infoframe *frame, |
4937 | struct drm_connector *connector, | ||
4937 | const struct drm_display_mode *mode, | 4938 | const struct drm_display_mode *mode, |
4938 | enum hdmi_quantization_range rgb_quant_range, | 4939 | enum hdmi_quantization_range rgb_quant_range) |
4939 | bool rgb_quant_range_selectable, | ||
4940 | bool is_hdmi2_sink) | ||
4941 | { | 4940 | { |
4941 | const struct drm_display_info *info = &connector->display_info; | ||
4942 | |||
4942 | /* | 4943 | /* |
4943 | * CEA-861: | 4944 | * CEA-861: |
4944 | * "A Source shall not send a non-zero Q value that does not correspond | 4945 | * "A Source shall not send a non-zero Q value that does not correspond |
@@ -4949,7 +4950,7 @@ drm_hdmi_avi_infoframe_quant_range(struct hdmi_avi_infoframe *frame, | |||
4949 | * HDMI 2.0 recommends sending non-zero Q when it does match the | 4950 | * HDMI 2.0 recommends sending non-zero Q when it does match the |
4950 | * default RGB quantization range for the mode, even when QS=0. | 4951 | * default RGB quantization range for the mode, even when QS=0. |
4951 | */ | 4952 | */ |
4952 | if (rgb_quant_range_selectable || | 4953 | if (info->rgb_quant_range_selectable || |
4953 | rgb_quant_range == drm_default_rgb_quant_range(mode)) | 4954 | rgb_quant_range == drm_default_rgb_quant_range(mode)) |
4954 | frame->quantization_range = rgb_quant_range; | 4955 | frame->quantization_range = rgb_quant_range; |
4955 | else | 4956 | else |
@@ -4968,7 +4969,7 @@ drm_hdmi_avi_infoframe_quant_range(struct hdmi_avi_infoframe *frame, | |||
4968 | * we limit non-zero YQ to HDMI 2.0 sinks only as HDMI 2.0 is based | 4969 | * we limit non-zero YQ to HDMI 2.0 sinks only as HDMI 2.0 is based |
4969 | * on on CEA-861-F. | 4970 | * on on CEA-861-F. |
4970 | */ | 4971 | */ |
4971 | if (!is_hdmi2_sink || | 4972 | if (!is_hdmi2_sink(connector) || |
4972 | rgb_quant_range == HDMI_QUANTIZATION_RANGE_LIMITED) | 4973 | rgb_quant_range == HDMI_QUANTIZATION_RANGE_LIMITED) |
4973 | frame->ycc_quantization_range = | 4974 | frame->ycc_quantization_range = |
4974 | HDMI_YCC_QUANTIZATION_RANGE_LIMITED; | 4975 | HDMI_YCC_QUANTIZATION_RANGE_LIMITED; |
diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c index d3af098b0922..ca706fb1d975 100644 --- a/drivers/gpu/drm/drm_fb_helper.c +++ b/drivers/gpu/drm/drm_fb_helper.c | |||
@@ -1797,6 +1797,7 @@ static int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper, | |||
1797 | int i; | 1797 | int i; |
1798 | struct drm_fb_helper_surface_size sizes; | 1798 | struct drm_fb_helper_surface_size sizes; |
1799 | int gamma_size = 0; | 1799 | int gamma_size = 0; |
1800 | int best_depth = 0; | ||
1800 | 1801 | ||
1801 | memset(&sizes, 0, sizeof(struct drm_fb_helper_surface_size)); | 1802 | memset(&sizes, 0, sizeof(struct drm_fb_helper_surface_size)); |
1802 | sizes.surface_depth = 24; | 1803 | sizes.surface_depth = 24; |
@@ -1804,7 +1805,10 @@ static int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper, | |||
1804 | sizes.fb_width = (u32)-1; | 1805 | sizes.fb_width = (u32)-1; |
1805 | sizes.fb_height = (u32)-1; | 1806 | sizes.fb_height = (u32)-1; |
1806 | 1807 | ||
1807 | /* if driver picks 8 or 16 by default use that for both depth/bpp */ | 1808 | /* |
1809 | * If driver picks 8 or 16 by default use that for both depth/bpp | ||
1810 | * to begin with | ||
1811 | */ | ||
1808 | if (preferred_bpp != sizes.surface_bpp) | 1812 | if (preferred_bpp != sizes.surface_bpp) |
1809 | sizes.surface_depth = sizes.surface_bpp = preferred_bpp; | 1813 | sizes.surface_depth = sizes.surface_bpp = preferred_bpp; |
1810 | 1814 | ||
@@ -1839,6 +1843,55 @@ static int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper, | |||
1839 | } | 1843 | } |
1840 | } | 1844 | } |
1841 | 1845 | ||
1846 | /* | ||
1847 | * If we run into a situation where, for example, the primary plane | ||
1848 | * supports RGBA5551 (16 bpp, depth 15) but not RGB565 (16 bpp, depth | ||
1849 | * 16) we need to scale down the depth of the sizes we request. | ||
1850 | */ | ||
1851 | for (i = 0; i < fb_helper->crtc_count; i++) { | ||
1852 | struct drm_mode_set *mode_set = &fb_helper->crtc_info[i].mode_set; | ||
1853 | struct drm_crtc *crtc = mode_set->crtc; | ||
1854 | struct drm_plane *plane = crtc->primary; | ||
1855 | int j; | ||
1856 | |||
1857 | DRM_DEBUG("test CRTC %d primary plane\n", i); | ||
1858 | |||
1859 | for (j = 0; j < plane->format_count; j++) { | ||
1860 | const struct drm_format_info *fmt; | ||
1861 | |||
1862 | fmt = drm_format_info(plane->format_types[j]); | ||
1863 | |||
1864 | /* | ||
1865 | * Do not consider YUV or other complicated formats | ||
1866 | * for framebuffers. This means only legacy formats | ||
1867 | * are supported (fmt->depth is a legacy field) but | ||
1868 | * the framebuffer emulation can only deal with such | ||
1869 | * formats, specifically RGB/BGA formats. | ||
1870 | */ | ||
1871 | if (fmt->depth == 0) | ||
1872 | continue; | ||
1873 | |||
1874 | /* We found a perfect fit, great */ | ||
1875 | if (fmt->depth == sizes.surface_depth) { | ||
1876 | best_depth = fmt->depth; | ||
1877 | break; | ||
1878 | } | ||
1879 | |||
1880 | /* Skip depths above what we're looking for */ | ||
1881 | if (fmt->depth > sizes.surface_depth) | ||
1882 | continue; | ||
1883 | |||
1884 | /* Best depth found so far */ | ||
1885 | if (fmt->depth > best_depth) | ||
1886 | best_depth = fmt->depth; | ||
1887 | } | ||
1888 | } | ||
1889 | if (sizes.surface_depth != best_depth) { | ||
1890 | DRM_INFO("requested bpp %d, scaled depth down to %d", | ||
1891 | sizes.surface_bpp, best_depth); | ||
1892 | sizes.surface_depth = best_depth; | ||
1893 | } | ||
1894 | |||
1842 | crtc_count = 0; | 1895 | crtc_count = 0; |
1843 | for (i = 0; i < fb_helper->crtc_count; i++) { | 1896 | for (i = 0; i < fb_helper->crtc_count; i++) { |
1844 | struct drm_display_mode *desired_mode; | 1897 | struct drm_display_mode *desired_mode; |
@@ -2866,7 +2919,7 @@ int drm_fb_helper_fbdev_setup(struct drm_device *dev, | |||
2866 | return 0; | 2919 | return 0; |
2867 | 2920 | ||
2868 | err_drm_fb_helper_fini: | 2921 | err_drm_fb_helper_fini: |
2869 | drm_fb_helper_fini(fb_helper); | 2922 | drm_fb_helper_fbdev_teardown(dev); |
2870 | 2923 | ||
2871 | return ret; | 2924 | return ret; |
2872 | } | 2925 | } |
@@ -2961,18 +3014,16 @@ static int drm_fbdev_fb_release(struct fb_info *info, int user) | |||
2961 | return 0; | 3014 | return 0; |
2962 | } | 3015 | } |
2963 | 3016 | ||
2964 | /* | 3017 | static void drm_fbdev_cleanup(struct drm_fb_helper *fb_helper) |
2965 | * fb_ops.fb_destroy is called by the last put_fb_info() call at the end of | ||
2966 | * unregister_framebuffer() or fb_release(). | ||
2967 | */ | ||
2968 | static void drm_fbdev_fb_destroy(struct fb_info *info) | ||
2969 | { | 3018 | { |
2970 | struct drm_fb_helper *fb_helper = info->par; | ||
2971 | struct fb_info *fbi = fb_helper->fbdev; | 3019 | struct fb_info *fbi = fb_helper->fbdev; |
2972 | struct fb_ops *fbops = NULL; | 3020 | struct fb_ops *fbops = NULL; |
2973 | void *shadow = NULL; | 3021 | void *shadow = NULL; |
2974 | 3022 | ||
2975 | if (fbi->fbdefio) { | 3023 | if (!fb_helper->dev) |
3024 | return; | ||
3025 | |||
3026 | if (fbi && fbi->fbdefio) { | ||
2976 | fb_deferred_io_cleanup(fbi); | 3027 | fb_deferred_io_cleanup(fbi); |
2977 | shadow = fbi->screen_buffer; | 3028 | shadow = fbi->screen_buffer; |
2978 | fbops = fbi->fbops; | 3029 | fbops = fbi->fbops; |
@@ -2986,6 +3037,12 @@ static void drm_fbdev_fb_destroy(struct fb_info *info) | |||
2986 | } | 3037 | } |
2987 | 3038 | ||
2988 | drm_client_framebuffer_delete(fb_helper->buffer); | 3039 | drm_client_framebuffer_delete(fb_helper->buffer); |
3040 | } | ||
3041 | |||
3042 | static void drm_fbdev_release(struct drm_fb_helper *fb_helper) | ||
3043 | { | ||
3044 | drm_fbdev_cleanup(fb_helper); | ||
3045 | |||
2989 | /* | 3046 | /* |
2990 | * FIXME: | 3047 | * FIXME: |
2991 | * Remove conditional when all CMA drivers have been moved over to using | 3048 | * Remove conditional when all CMA drivers have been moved over to using |
@@ -2997,6 +3054,15 @@ static void drm_fbdev_fb_destroy(struct fb_info *info) | |||
2997 | } | 3054 | } |
2998 | } | 3055 | } |
2999 | 3056 | ||
3057 | /* | ||
3058 | * fb_ops.fb_destroy is called by the last put_fb_info() call at the end of | ||
3059 | * unregister_framebuffer() or fb_release(). | ||
3060 | */ | ||
3061 | static void drm_fbdev_fb_destroy(struct fb_info *info) | ||
3062 | { | ||
3063 | drm_fbdev_release(info->par); | ||
3064 | } | ||
3065 | |||
3000 | static int drm_fbdev_fb_mmap(struct fb_info *info, struct vm_area_struct *vma) | 3066 | static int drm_fbdev_fb_mmap(struct fb_info *info, struct vm_area_struct *vma) |
3001 | { | 3067 | { |
3002 | struct drm_fb_helper *fb_helper = info->par; | 3068 | struct drm_fb_helper *fb_helper = info->par; |
@@ -3047,7 +3113,6 @@ int drm_fb_helper_generic_probe(struct drm_fb_helper *fb_helper, | |||
3047 | struct drm_framebuffer *fb; | 3113 | struct drm_framebuffer *fb; |
3048 | struct fb_info *fbi; | 3114 | struct fb_info *fbi; |
3049 | u32 format; | 3115 | u32 format; |
3050 | int ret; | ||
3051 | 3116 | ||
3052 | DRM_DEBUG_KMS("surface width(%d), height(%d) and bpp(%d)\n", | 3117 | DRM_DEBUG_KMS("surface width(%d), height(%d) and bpp(%d)\n", |
3053 | sizes->surface_width, sizes->surface_height, | 3118 | sizes->surface_width, sizes->surface_height, |
@@ -3064,10 +3129,8 @@ int drm_fb_helper_generic_probe(struct drm_fb_helper *fb_helper, | |||
3064 | fb = buffer->fb; | 3129 | fb = buffer->fb; |
3065 | 3130 | ||
3066 | fbi = drm_fb_helper_alloc_fbi(fb_helper); | 3131 | fbi = drm_fb_helper_alloc_fbi(fb_helper); |
3067 | if (IS_ERR(fbi)) { | 3132 | if (IS_ERR(fbi)) |
3068 | ret = PTR_ERR(fbi); | 3133 | return PTR_ERR(fbi); |
3069 | goto err_free_buffer; | ||
3070 | } | ||
3071 | 3134 | ||
3072 | fbi->par = fb_helper; | 3135 | fbi->par = fb_helper; |
3073 | fbi->fbops = &drm_fbdev_fb_ops; | 3136 | fbi->fbops = &drm_fbdev_fb_ops; |
@@ -3098,8 +3161,7 @@ int drm_fb_helper_generic_probe(struct drm_fb_helper *fb_helper, | |||
3098 | if (!fbops || !shadow) { | 3161 | if (!fbops || !shadow) { |
3099 | kfree(fbops); | 3162 | kfree(fbops); |
3100 | vfree(shadow); | 3163 | vfree(shadow); |
3101 | ret = -ENOMEM; | 3164 | return -ENOMEM; |
3102 | goto err_fb_info_destroy; | ||
3103 | } | 3165 | } |
3104 | 3166 | ||
3105 | *fbops = *fbi->fbops; | 3167 | *fbops = *fbi->fbops; |
@@ -3111,13 +3173,6 @@ int drm_fb_helper_generic_probe(struct drm_fb_helper *fb_helper, | |||
3111 | } | 3173 | } |
3112 | 3174 | ||
3113 | return 0; | 3175 | return 0; |
3114 | |||
3115 | err_fb_info_destroy: | ||
3116 | drm_fb_helper_fini(fb_helper); | ||
3117 | err_free_buffer: | ||
3118 | drm_client_framebuffer_delete(buffer); | ||
3119 | |||
3120 | return ret; | ||
3121 | } | 3176 | } |
3122 | EXPORT_SYMBOL(drm_fb_helper_generic_probe); | 3177 | EXPORT_SYMBOL(drm_fb_helper_generic_probe); |
3123 | 3178 | ||
@@ -3129,18 +3184,11 @@ static void drm_fbdev_client_unregister(struct drm_client_dev *client) | |||
3129 | { | 3184 | { |
3130 | struct drm_fb_helper *fb_helper = drm_fb_helper_from_client(client); | 3185 | struct drm_fb_helper *fb_helper = drm_fb_helper_from_client(client); |
3131 | 3186 | ||
3132 | if (fb_helper->fbdev) { | 3187 | if (fb_helper->fbdev) |
3133 | drm_fb_helper_unregister_fbi(fb_helper); | ||
3134 | /* drm_fbdev_fb_destroy() takes care of cleanup */ | 3188 | /* drm_fbdev_fb_destroy() takes care of cleanup */ |
3135 | return; | 3189 | drm_fb_helper_unregister_fbi(fb_helper); |
3136 | } | 3190 | else |
3137 | 3191 | drm_fbdev_release(fb_helper); | |
3138 | /* Did drm_fb_helper_fbdev_setup() run? */ | ||
3139 | if (fb_helper->dev) | ||
3140 | drm_fb_helper_fini(fb_helper); | ||
3141 | |||
3142 | drm_client_release(client); | ||
3143 | kfree(fb_helper); | ||
3144 | } | 3192 | } |
3145 | 3193 | ||
3146 | static int drm_fbdev_client_restore(struct drm_client_dev *client) | 3194 | static int drm_fbdev_client_restore(struct drm_client_dev *client) |
@@ -3158,7 +3206,7 @@ static int drm_fbdev_client_hotplug(struct drm_client_dev *client) | |||
3158 | struct drm_device *dev = client->dev; | 3206 | struct drm_device *dev = client->dev; |
3159 | int ret; | 3207 | int ret; |
3160 | 3208 | ||
3161 | /* If drm_fb_helper_fbdev_setup() failed, we only try once */ | 3209 | /* Setup is not retried if it has failed */ |
3162 | if (!fb_helper->dev && fb_helper->funcs) | 3210 | if (!fb_helper->dev && fb_helper->funcs) |
3163 | return 0; | 3211 | return 0; |
3164 | 3212 | ||
@@ -3170,15 +3218,34 @@ static int drm_fbdev_client_hotplug(struct drm_client_dev *client) | |||
3170 | return 0; | 3218 | return 0; |
3171 | } | 3219 | } |
3172 | 3220 | ||
3173 | ret = drm_fb_helper_fbdev_setup(dev, fb_helper, &drm_fb_helper_generic_funcs, | 3221 | drm_fb_helper_prepare(dev, fb_helper, &drm_fb_helper_generic_funcs); |
3174 | fb_helper->preferred_bpp, 0); | 3222 | |
3175 | if (ret) { | 3223 | ret = drm_fb_helper_init(dev, fb_helper, dev->mode_config.num_connector); |
3176 | fb_helper->dev = NULL; | 3224 | if (ret) |
3177 | fb_helper->fbdev = NULL; | 3225 | goto err; |
3178 | return ret; | 3226 | |
3179 | } | 3227 | ret = drm_fb_helper_single_add_all_connectors(fb_helper); |
3228 | if (ret) | ||
3229 | goto err_cleanup; | ||
3230 | |||
3231 | if (!drm_drv_uses_atomic_modeset(dev)) | ||
3232 | drm_helper_disable_unused_functions(dev); | ||
3233 | |||
3234 | ret = drm_fb_helper_initial_config(fb_helper, fb_helper->preferred_bpp); | ||
3235 | if (ret) | ||
3236 | goto err_cleanup; | ||
3180 | 3237 | ||
3181 | return 0; | 3238 | return 0; |
3239 | |||
3240 | err_cleanup: | ||
3241 | drm_fbdev_cleanup(fb_helper); | ||
3242 | err: | ||
3243 | fb_helper->dev = NULL; | ||
3244 | fb_helper->fbdev = NULL; | ||
3245 | |||
3246 | DRM_DEV_ERROR(dev->dev, "fbdev: Failed to setup generic emulation (ret=%d)\n", ret); | ||
3247 | |||
3248 | return ret; | ||
3182 | } | 3249 | } |
3183 | 3250 | ||
3184 | static const struct drm_client_funcs drm_fbdev_client_funcs = { | 3251 | static const struct drm_client_funcs drm_fbdev_client_funcs = { |
@@ -3237,6 +3304,10 @@ int drm_fbdev_generic_setup(struct drm_device *dev, unsigned int preferred_bpp) | |||
3237 | 3304 | ||
3238 | drm_client_add(&fb_helper->client); | 3305 | drm_client_add(&fb_helper->client); |
3239 | 3306 | ||
3307 | if (!preferred_bpp) | ||
3308 | preferred_bpp = dev->mode_config.preferred_depth; | ||
3309 | if (!preferred_bpp) | ||
3310 | preferred_bpp = 32; | ||
3240 | fb_helper->preferred_bpp = preferred_bpp; | 3311 | fb_helper->preferred_bpp = preferred_bpp; |
3241 | 3312 | ||
3242 | ret = drm_fbdev_client_hotplug(&fb_helper->client); | 3313 | ret = drm_fbdev_client_hotplug(&fb_helper->client); |
diff --git a/drivers/gpu/drm/drm_flip_work.c b/drivers/gpu/drm/drm_flip_work.c index 12dea16f22a8..3da3bf5af405 100644 --- a/drivers/gpu/drm/drm_flip_work.c +++ b/drivers/gpu/drm/drm_flip_work.c | |||
@@ -22,6 +22,7 @@ | |||
22 | */ | 22 | */ |
23 | 23 | ||
24 | #include <drm/drmP.h> | 24 | #include <drm/drmP.h> |
25 | #include <drm/drm_util.h> | ||
25 | #include <drm/drm_flip_work.h> | 26 | #include <drm/drm_flip_work.h> |
26 | 27 | ||
27 | /** | 28 | /** |
diff --git a/drivers/gpu/drm/drm_framebuffer.c b/drivers/gpu/drm/drm_framebuffer.c index fcaea8f50513..7abcb265a108 100644 --- a/drivers/gpu/drm/drm_framebuffer.c +++ b/drivers/gpu/drm/drm_framebuffer.c | |||
@@ -27,6 +27,7 @@ | |||
27 | #include <drm/drm_atomic.h> | 27 | #include <drm/drm_atomic.h> |
28 | #include <drm/drm_atomic_uapi.h> | 28 | #include <drm/drm_atomic_uapi.h> |
29 | #include <drm/drm_print.h> | 29 | #include <drm/drm_print.h> |
30 | #include <drm/drm_util.h> | ||
30 | 31 | ||
31 | #include "drm_internal.h" | 32 | #include "drm_internal.h" |
32 | #include "drm_crtc_internal.h" | 33 | #include "drm_crtc_internal.h" |
diff --git a/drivers/gpu/drm/drm_gem.c b/drivers/gpu/drm/drm_gem.c index 8b55ece97967..2896ff60552f 100644 --- a/drivers/gpu/drm/drm_gem.c +++ b/drivers/gpu/drm/drm_gem.c | |||
@@ -37,6 +37,7 @@ | |||
37 | #include <linux/shmem_fs.h> | 37 | #include <linux/shmem_fs.h> |
38 | #include <linux/dma-buf.h> | 38 | #include <linux/dma-buf.h> |
39 | #include <linux/mem_encrypt.h> | 39 | #include <linux/mem_encrypt.h> |
40 | #include <linux/pagevec.h> | ||
40 | #include <drm/drmP.h> | 41 | #include <drm/drmP.h> |
41 | #include <drm/drm_vma_manager.h> | 42 | #include <drm/drm_vma_manager.h> |
42 | #include <drm/drm_gem.h> | 43 | #include <drm/drm_gem.h> |
@@ -526,6 +527,17 @@ int drm_gem_create_mmap_offset(struct drm_gem_object *obj) | |||
526 | } | 527 | } |
527 | EXPORT_SYMBOL(drm_gem_create_mmap_offset); | 528 | EXPORT_SYMBOL(drm_gem_create_mmap_offset); |
528 | 529 | ||
530 | /* | ||
531 | * Move pages to appropriate lru and release the pagevec, decrementing the | ||
532 | * ref count of those pages. | ||
533 | */ | ||
534 | static void drm_gem_check_release_pagevec(struct pagevec *pvec) | ||
535 | { | ||
536 | check_move_unevictable_pages(pvec); | ||
537 | __pagevec_release(pvec); | ||
538 | cond_resched(); | ||
539 | } | ||
540 | |||
529 | /** | 541 | /** |
530 | * drm_gem_get_pages - helper to allocate backing pages for a GEM object | 542 | * drm_gem_get_pages - helper to allocate backing pages for a GEM object |
531 | * from shmem | 543 | * from shmem |
@@ -551,6 +563,7 @@ struct page **drm_gem_get_pages(struct drm_gem_object *obj) | |||
551 | { | 563 | { |
552 | struct address_space *mapping; | 564 | struct address_space *mapping; |
553 | struct page *p, **pages; | 565 | struct page *p, **pages; |
566 | struct pagevec pvec; | ||
554 | int i, npages; | 567 | int i, npages; |
555 | 568 | ||
556 | /* This is the shared memory object that backs the GEM resource */ | 569 | /* This is the shared memory object that backs the GEM resource */ |
@@ -568,6 +581,8 @@ struct page **drm_gem_get_pages(struct drm_gem_object *obj) | |||
568 | if (pages == NULL) | 581 | if (pages == NULL) |
569 | return ERR_PTR(-ENOMEM); | 582 | return ERR_PTR(-ENOMEM); |
570 | 583 | ||
584 | mapping_set_unevictable(mapping); | ||
585 | |||
571 | for (i = 0; i < npages; i++) { | 586 | for (i = 0; i < npages; i++) { |
572 | p = shmem_read_mapping_page(mapping, i); | 587 | p = shmem_read_mapping_page(mapping, i); |
573 | if (IS_ERR(p)) | 588 | if (IS_ERR(p)) |
@@ -586,8 +601,14 @@ struct page **drm_gem_get_pages(struct drm_gem_object *obj) | |||
586 | return pages; | 601 | return pages; |
587 | 602 | ||
588 | fail: | 603 | fail: |
589 | while (i--) | 604 | mapping_clear_unevictable(mapping); |
590 | put_page(pages[i]); | 605 | pagevec_init(&pvec); |
606 | while (i--) { | ||
607 | if (!pagevec_add(&pvec, pages[i])) | ||
608 | drm_gem_check_release_pagevec(&pvec); | ||
609 | } | ||
610 | if (pagevec_count(&pvec)) | ||
611 | drm_gem_check_release_pagevec(&pvec); | ||
591 | 612 | ||
592 | kvfree(pages); | 613 | kvfree(pages); |
593 | return ERR_CAST(p); | 614 | return ERR_CAST(p); |
@@ -605,6 +626,11 @@ void drm_gem_put_pages(struct drm_gem_object *obj, struct page **pages, | |||
605 | bool dirty, bool accessed) | 626 | bool dirty, bool accessed) |
606 | { | 627 | { |
607 | int i, npages; | 628 | int i, npages; |
629 | struct address_space *mapping; | ||
630 | struct pagevec pvec; | ||
631 | |||
632 | mapping = file_inode(obj->filp)->i_mapping; | ||
633 | mapping_clear_unevictable(mapping); | ||
608 | 634 | ||
609 | /* We already BUG_ON() for non-page-aligned sizes in | 635 | /* We already BUG_ON() for non-page-aligned sizes in |
610 | * drm_gem_object_init(), so we should never hit this unless | 636 | * drm_gem_object_init(), so we should never hit this unless |
@@ -614,6 +640,7 @@ void drm_gem_put_pages(struct drm_gem_object *obj, struct page **pages, | |||
614 | 640 | ||
615 | npages = obj->size >> PAGE_SHIFT; | 641 | npages = obj->size >> PAGE_SHIFT; |
616 | 642 | ||
643 | pagevec_init(&pvec); | ||
617 | for (i = 0; i < npages; i++) { | 644 | for (i = 0; i < npages; i++) { |
618 | if (dirty) | 645 | if (dirty) |
619 | set_page_dirty(pages[i]); | 646 | set_page_dirty(pages[i]); |
@@ -622,8 +649,11 @@ void drm_gem_put_pages(struct drm_gem_object *obj, struct page **pages, | |||
622 | mark_page_accessed(pages[i]); | 649 | mark_page_accessed(pages[i]); |
623 | 650 | ||
624 | /* Undo the reference we took when populating the table */ | 651 | /* Undo the reference we took when populating the table */ |
625 | put_page(pages[i]); | 652 | if (!pagevec_add(&pvec, pages[i])) |
653 | drm_gem_check_release_pagevec(&pvec); | ||
626 | } | 654 | } |
655 | if (pagevec_count(&pvec)) | ||
656 | drm_gem_check_release_pagevec(&pvec); | ||
627 | 657 | ||
628 | kvfree(pages); | 658 | kvfree(pages); |
629 | } | 659 | } |
diff --git a/drivers/gpu/drm/drm_modes.c b/drivers/gpu/drm/drm_modes.c index 24a750436559..adce9a26bac9 100644 --- a/drivers/gpu/drm/drm_modes.c +++ b/drivers/gpu/drm/drm_modes.c | |||
@@ -71,11 +71,6 @@ struct drm_display_mode *drm_mode_create(struct drm_device *dev) | |||
71 | if (!nmode) | 71 | if (!nmode) |
72 | return NULL; | 72 | return NULL; |
73 | 73 | ||
74 | if (drm_mode_object_add(dev, &nmode->base, DRM_MODE_OBJECT_MODE)) { | ||
75 | kfree(nmode); | ||
76 | return NULL; | ||
77 | } | ||
78 | |||
79 | return nmode; | 74 | return nmode; |
80 | } | 75 | } |
81 | EXPORT_SYMBOL(drm_mode_create); | 76 | EXPORT_SYMBOL(drm_mode_create); |
@@ -92,8 +87,6 @@ void drm_mode_destroy(struct drm_device *dev, struct drm_display_mode *mode) | |||
92 | if (!mode) | 87 | if (!mode) |
93 | return; | 88 | return; |
94 | 89 | ||
95 | drm_mode_object_unregister(dev, &mode->base); | ||
96 | |||
97 | kfree(mode); | 90 | kfree(mode); |
98 | } | 91 | } |
99 | EXPORT_SYMBOL(drm_mode_destroy); | 92 | EXPORT_SYMBOL(drm_mode_destroy); |
@@ -911,11 +904,9 @@ EXPORT_SYMBOL(drm_mode_set_crtcinfo); | |||
911 | */ | 904 | */ |
912 | void drm_mode_copy(struct drm_display_mode *dst, const struct drm_display_mode *src) | 905 | void drm_mode_copy(struct drm_display_mode *dst, const struct drm_display_mode *src) |
913 | { | 906 | { |
914 | int id = dst->base.id; | ||
915 | struct list_head head = dst->head; | 907 | struct list_head head = dst->head; |
916 | 908 | ||
917 | *dst = *src; | 909 | *dst = *src; |
918 | dst->base.id = id; | ||
919 | dst->head = head; | 910 | dst->head = head; |
920 | } | 911 | } |
921 | EXPORT_SYMBOL(drm_mode_copy); | 912 | EXPORT_SYMBOL(drm_mode_copy); |
diff --git a/drivers/gpu/drm/drm_of.c b/drivers/gpu/drm/drm_of.c index 2763a5ec845b..f2f71d71494a 100644 --- a/drivers/gpu/drm/drm_of.c +++ b/drivers/gpu/drm/drm_of.c | |||
@@ -217,9 +217,11 @@ int drm_of_encoder_active_endpoint(struct device_node *node, | |||
217 | } | 217 | } |
218 | EXPORT_SYMBOL_GPL(drm_of_encoder_active_endpoint); | 218 | EXPORT_SYMBOL_GPL(drm_of_encoder_active_endpoint); |
219 | 219 | ||
220 | /* | 220 | /** |
221 | * drm_of_find_panel_or_bridge - return connected panel or bridge device | 221 | * drm_of_find_panel_or_bridge - return connected panel or bridge device |
222 | * @np: device tree node containing encoder output ports | 222 | * @np: device tree node containing encoder output ports |
223 | * @port: port in the device tree node | ||
224 | * @endpoint: endpoint in the device tree node | ||
223 | * @panel: pointer to hold returned drm_panel | 225 | * @panel: pointer to hold returned drm_panel |
224 | * @bridge: pointer to hold returned drm_bridge | 226 | * @bridge: pointer to hold returned drm_bridge |
225 | * | 227 | * |
diff --git a/drivers/gpu/drm/drm_panel.c b/drivers/gpu/drm/drm_panel.c index c33f95e08e1b..dbd5b873e8f2 100644 --- a/drivers/gpu/drm/drm_panel.c +++ b/drivers/gpu/drm/drm_panel.c | |||
@@ -36,6 +36,9 @@ static LIST_HEAD(panel_list); | |||
36 | * The DRM panel helpers allow drivers to register panel objects with a | 36 | * The DRM panel helpers allow drivers to register panel objects with a |
37 | * central registry and provide functions to retrieve those panels in display | 37 | * central registry and provide functions to retrieve those panels in display |
38 | * drivers. | 38 | * drivers. |
39 | * | ||
40 | * For easy integration into drivers using the &drm_bridge infrastructure please | ||
41 | * take look at drm_panel_bridge_add() and devm_drm_panel_bridge_add(). | ||
39 | */ | 42 | */ |
40 | 43 | ||
41 | /** | 44 | /** |
diff --git a/drivers/gpu/drm/drm_plane.c b/drivers/gpu/drm/drm_plane.c index 5f650d8fc66b..4cfb56893b7f 100644 --- a/drivers/gpu/drm/drm_plane.c +++ b/drivers/gpu/drm/drm_plane.c | |||
@@ -220,6 +220,9 @@ int drm_universal_plane_init(struct drm_device *dev, struct drm_plane *plane, | |||
220 | format_modifier_count++; | 220 | format_modifier_count++; |
221 | } | 221 | } |
222 | 222 | ||
223 | if (format_modifier_count) | ||
224 | config->allow_fb_modifiers = true; | ||
225 | |||
223 | plane->modifier_count = format_modifier_count; | 226 | plane->modifier_count = format_modifier_count; |
224 | plane->modifiers = kmalloc_array(format_modifier_count, | 227 | plane->modifiers = kmalloc_array(format_modifier_count, |
225 | sizeof(format_modifiers[0]), | 228 | sizeof(format_modifiers[0]), |
diff --git a/drivers/gpu/drm/drm_vblank.c b/drivers/gpu/drm/drm_vblank.c index 98e091175921..cde71ee95a8f 100644 --- a/drivers/gpu/drm/drm_vblank.c +++ b/drivers/gpu/drm/drm_vblank.c | |||
@@ -105,13 +105,20 @@ static void store_vblank(struct drm_device *dev, unsigned int pipe, | |||
105 | write_sequnlock(&vblank->seqlock); | 105 | write_sequnlock(&vblank->seqlock); |
106 | } | 106 | } |
107 | 107 | ||
108 | static u32 drm_max_vblank_count(struct drm_device *dev, unsigned int pipe) | ||
109 | { | ||
110 | struct drm_vblank_crtc *vblank = &dev->vblank[pipe]; | ||
111 | |||
112 | return vblank->max_vblank_count ?: dev->max_vblank_count; | ||
113 | } | ||
114 | |||
108 | /* | 115 | /* |
109 | * "No hw counter" fallback implementation of .get_vblank_counter() hook, | 116 | * "No hw counter" fallback implementation of .get_vblank_counter() hook, |
110 | * if there is no useable hardware frame counter available. | 117 | * if there is no useable hardware frame counter available. |
111 | */ | 118 | */ |
112 | static u32 drm_vblank_no_hw_counter(struct drm_device *dev, unsigned int pipe) | 119 | static u32 drm_vblank_no_hw_counter(struct drm_device *dev, unsigned int pipe) |
113 | { | 120 | { |
114 | WARN_ON_ONCE(dev->max_vblank_count != 0); | 121 | WARN_ON_ONCE(drm_max_vblank_count(dev, pipe) != 0); |
115 | return 0; | 122 | return 0; |
116 | } | 123 | } |
117 | 124 | ||
@@ -198,6 +205,7 @@ static void drm_update_vblank_count(struct drm_device *dev, unsigned int pipe, | |||
198 | ktime_t t_vblank; | 205 | ktime_t t_vblank; |
199 | int count = DRM_TIMESTAMP_MAXRETRIES; | 206 | int count = DRM_TIMESTAMP_MAXRETRIES; |
200 | int framedur_ns = vblank->framedur_ns; | 207 | int framedur_ns = vblank->framedur_ns; |
208 | u32 max_vblank_count = drm_max_vblank_count(dev, pipe); | ||
201 | 209 | ||
202 | /* | 210 | /* |
203 | * Interrupts were disabled prior to this call, so deal with counter | 211 | * Interrupts were disabled prior to this call, so deal with counter |
@@ -216,9 +224,9 @@ static void drm_update_vblank_count(struct drm_device *dev, unsigned int pipe, | |||
216 | rc = drm_get_last_vbltimestamp(dev, pipe, &t_vblank, in_vblank_irq); | 224 | rc = drm_get_last_vbltimestamp(dev, pipe, &t_vblank, in_vblank_irq); |
217 | } while (cur_vblank != __get_vblank_counter(dev, pipe) && --count > 0); | 225 | } while (cur_vblank != __get_vblank_counter(dev, pipe) && --count > 0); |
218 | 226 | ||
219 | if (dev->max_vblank_count != 0) { | 227 | if (max_vblank_count) { |
220 | /* trust the hw counter when it's around */ | 228 | /* trust the hw counter when it's around */ |
221 | diff = (cur_vblank - vblank->last) & dev->max_vblank_count; | 229 | diff = (cur_vblank - vblank->last) & max_vblank_count; |
222 | } else if (rc && framedur_ns) { | 230 | } else if (rc && framedur_ns) { |
223 | u64 diff_ns = ktime_to_ns(ktime_sub(t_vblank, vblank->time)); | 231 | u64 diff_ns = ktime_to_ns(ktime_sub(t_vblank, vblank->time)); |
224 | 232 | ||
@@ -1205,6 +1213,37 @@ void drm_crtc_vblank_reset(struct drm_crtc *crtc) | |||
1205 | EXPORT_SYMBOL(drm_crtc_vblank_reset); | 1213 | EXPORT_SYMBOL(drm_crtc_vblank_reset); |
1206 | 1214 | ||
1207 | /** | 1215 | /** |
1216 | * drm_crtc_set_max_vblank_count - configure the hw max vblank counter value | ||
1217 | * @crtc: CRTC in question | ||
1218 | * @max_vblank_count: max hardware vblank counter value | ||
1219 | * | ||
1220 | * Update the maximum hardware vblank counter value for @crtc | ||
1221 | * at runtime. Useful for hardware where the operation of the | ||
1222 | * hardware vblank counter depends on the currently active | ||
1223 | * display configuration. | ||
1224 | * | ||
1225 | * For example, if the hardware vblank counter does not work | ||
1226 | * when a specific connector is active the maximum can be set | ||
1227 | * to zero. And when that specific connector isn't active the | ||
1228 | * maximum can again be set to the appropriate non-zero value. | ||
1229 | * | ||
1230 | * If used, must be called before drm_vblank_on(). | ||
1231 | */ | ||
1232 | void drm_crtc_set_max_vblank_count(struct drm_crtc *crtc, | ||
1233 | u32 max_vblank_count) | ||
1234 | { | ||
1235 | struct drm_device *dev = crtc->dev; | ||
1236 | unsigned int pipe = drm_crtc_index(crtc); | ||
1237 | struct drm_vblank_crtc *vblank = &dev->vblank[pipe]; | ||
1238 | |||
1239 | WARN_ON(dev->max_vblank_count); | ||
1240 | WARN_ON(!READ_ONCE(vblank->inmodeset)); | ||
1241 | |||
1242 | vblank->max_vblank_count = max_vblank_count; | ||
1243 | } | ||
1244 | EXPORT_SYMBOL(drm_crtc_set_max_vblank_count); | ||
1245 | |||
1246 | /** | ||
1208 | * drm_crtc_vblank_on - enable vblank events on a CRTC | 1247 | * drm_crtc_vblank_on - enable vblank events on a CRTC |
1209 | * @crtc: CRTC in question | 1248 | * @crtc: CRTC in question |
1210 | * | 1249 | * |
diff --git a/drivers/gpu/drm/exynos/exynos_hdmi.c b/drivers/gpu/drm/exynos/exynos_hdmi.c index 2092a650df7d..b857df67aff0 100644 --- a/drivers/gpu/drm/exynos/exynos_hdmi.c +++ b/drivers/gpu/drm/exynos/exynos_hdmi.c | |||
@@ -819,7 +819,8 @@ static void hdmi_reg_infoframes(struct hdmi_context *hdata) | |||
819 | return; | 819 | return; |
820 | } | 820 | } |
821 | 821 | ||
822 | ret = drm_hdmi_avi_infoframe_from_display_mode(&frm.avi, m, false); | 822 | ret = drm_hdmi_avi_infoframe_from_display_mode(&frm.avi, |
823 | &hdata->connector, m); | ||
823 | if (!ret) | 824 | if (!ret) |
824 | ret = hdmi_avi_infoframe_pack(&frm.avi, buf, sizeof(buf)); | 825 | ret = hdmi_avi_infoframe_pack(&frm.avi, buf, sizeof(buf)); |
825 | if (ret > 0) { | 826 | if (ret > 0) { |
diff --git a/drivers/gpu/drm/hisilicon/kirin/kirin_drm_drv.c b/drivers/gpu/drm/hisilicon/kirin/kirin_drm_drv.c index e6a62d5a00a3..15e32e5d9101 100644 --- a/drivers/gpu/drm/hisilicon/kirin/kirin_drm_drv.c +++ b/drivers/gpu/drm/hisilicon/kirin/kirin_drm_drv.c | |||
@@ -22,6 +22,7 @@ | |||
22 | #include <drm/drmP.h> | 22 | #include <drm/drmP.h> |
23 | #include <drm/drm_gem_cma_helper.h> | 23 | #include <drm/drm_gem_cma_helper.h> |
24 | #include <drm/drm_fb_cma_helper.h> | 24 | #include <drm/drm_fb_cma_helper.h> |
25 | #include <drm/drm_fb_helper.h> | ||
25 | #include <drm/drm_gem_framebuffer_helper.h> | 26 | #include <drm/drm_gem_framebuffer_helper.h> |
26 | #include <drm/drm_atomic_helper.h> | 27 | #include <drm/drm_atomic_helper.h> |
27 | #include <drm/drm_crtc_helper.h> | 28 | #include <drm/drm_crtc_helper.h> |
@@ -33,32 +34,15 @@ static struct kirin_dc_ops *dc_ops; | |||
33 | 34 | ||
34 | static int kirin_drm_kms_cleanup(struct drm_device *dev) | 35 | static int kirin_drm_kms_cleanup(struct drm_device *dev) |
35 | { | 36 | { |
36 | struct kirin_drm_private *priv = dev->dev_private; | ||
37 | |||
38 | if (priv->fbdev) { | ||
39 | drm_fbdev_cma_fini(priv->fbdev); | ||
40 | priv->fbdev = NULL; | ||
41 | } | ||
42 | |||
43 | drm_kms_helper_poll_fini(dev); | 37 | drm_kms_helper_poll_fini(dev); |
44 | dc_ops->cleanup(to_platform_device(dev->dev)); | 38 | dc_ops->cleanup(to_platform_device(dev->dev)); |
45 | drm_mode_config_cleanup(dev); | 39 | drm_mode_config_cleanup(dev); |
46 | devm_kfree(dev->dev, priv); | ||
47 | dev->dev_private = NULL; | ||
48 | 40 | ||
49 | return 0; | 41 | return 0; |
50 | } | 42 | } |
51 | 43 | ||
52 | static void kirin_fbdev_output_poll_changed(struct drm_device *dev) | ||
53 | { | ||
54 | struct kirin_drm_private *priv = dev->dev_private; | ||
55 | |||
56 | drm_fbdev_cma_hotplug_event(priv->fbdev); | ||
57 | } | ||
58 | |||
59 | static const struct drm_mode_config_funcs kirin_drm_mode_config_funcs = { | 44 | static const struct drm_mode_config_funcs kirin_drm_mode_config_funcs = { |
60 | .fb_create = drm_gem_fb_create, | 45 | .fb_create = drm_gem_fb_create, |
61 | .output_poll_changed = kirin_fbdev_output_poll_changed, | ||
62 | .atomic_check = drm_atomic_helper_check, | 46 | .atomic_check = drm_atomic_helper_check, |
63 | .atomic_commit = drm_atomic_helper_commit, | 47 | .atomic_commit = drm_atomic_helper_commit, |
64 | }; | 48 | }; |
@@ -76,14 +60,8 @@ static void kirin_drm_mode_config_init(struct drm_device *dev) | |||
76 | 60 | ||
77 | static int kirin_drm_kms_init(struct drm_device *dev) | 61 | static int kirin_drm_kms_init(struct drm_device *dev) |
78 | { | 62 | { |
79 | struct kirin_drm_private *priv; | ||
80 | int ret; | 63 | int ret; |
81 | 64 | ||
82 | priv = devm_kzalloc(dev->dev, sizeof(*priv), GFP_KERNEL); | ||
83 | if (!priv) | ||
84 | return -ENOMEM; | ||
85 | |||
86 | dev->dev_private = priv; | ||
87 | dev_set_drvdata(dev->dev, dev); | 65 | dev_set_drvdata(dev->dev, dev); |
88 | 66 | ||
89 | /* dev->mode_config initialization */ | 67 | /* dev->mode_config initialization */ |
@@ -117,26 +95,14 @@ static int kirin_drm_kms_init(struct drm_device *dev) | |||
117 | /* init kms poll for handling hpd */ | 95 | /* init kms poll for handling hpd */ |
118 | drm_kms_helper_poll_init(dev); | 96 | drm_kms_helper_poll_init(dev); |
119 | 97 | ||
120 | priv->fbdev = drm_fbdev_cma_init(dev, 32, | ||
121 | dev->mode_config.num_connector); | ||
122 | |||
123 | if (IS_ERR(priv->fbdev)) { | ||
124 | DRM_ERROR("failed to initialize fbdev.\n"); | ||
125 | ret = PTR_ERR(priv->fbdev); | ||
126 | goto err_cleanup_poll; | ||
127 | } | ||
128 | return 0; | 98 | return 0; |
129 | 99 | ||
130 | err_cleanup_poll: | ||
131 | drm_kms_helper_poll_fini(dev); | ||
132 | err_unbind_all: | 100 | err_unbind_all: |
133 | component_unbind_all(dev->dev, dev); | 101 | component_unbind_all(dev->dev, dev); |
134 | err_dc_cleanup: | 102 | err_dc_cleanup: |
135 | dc_ops->cleanup(to_platform_device(dev->dev)); | 103 | dc_ops->cleanup(to_platform_device(dev->dev)); |
136 | err_mode_config_cleanup: | 104 | err_mode_config_cleanup: |
137 | drm_mode_config_cleanup(dev); | 105 | drm_mode_config_cleanup(dev); |
138 | devm_kfree(dev->dev, priv); | ||
139 | dev->dev_private = NULL; | ||
140 | 106 | ||
141 | return ret; | 107 | return ret; |
142 | } | 108 | } |
@@ -199,6 +165,8 @@ static int kirin_drm_bind(struct device *dev) | |||
199 | if (ret) | 165 | if (ret) |
200 | goto err_kms_cleanup; | 166 | goto err_kms_cleanup; |
201 | 167 | ||
168 | drm_fbdev_generic_setup(drm_dev, 32); | ||
169 | |||
202 | return 0; | 170 | return 0; |
203 | 171 | ||
204 | err_kms_cleanup: | 172 | err_kms_cleanup: |
diff --git a/drivers/gpu/drm/hisilicon/kirin/kirin_drm_drv.h b/drivers/gpu/drm/hisilicon/kirin/kirin_drm_drv.h index 56cb62df065c..ad027d1cc826 100644 --- a/drivers/gpu/drm/hisilicon/kirin/kirin_drm_drv.h +++ b/drivers/gpu/drm/hisilicon/kirin/kirin_drm_drv.h | |||
@@ -19,10 +19,6 @@ struct kirin_dc_ops { | |||
19 | void (*cleanup)(struct platform_device *pdev); | 19 | void (*cleanup)(struct platform_device *pdev); |
20 | }; | 20 | }; |
21 | 21 | ||
22 | struct kirin_drm_private { | ||
23 | struct drm_fbdev_cma *fbdev; | ||
24 | }; | ||
25 | |||
26 | extern const struct kirin_dc_ops ade_dc_ops; | 22 | extern const struct kirin_dc_ops ade_dc_ops; |
27 | 23 | ||
28 | #endif /* __KIRIN_DRM_DRV_H__ */ | 24 | #endif /* __KIRIN_DRM_DRV_H__ */ |
diff --git a/drivers/gpu/drm/i2c/ch7006_drv.c b/drivers/gpu/drm/i2c/ch7006_drv.c index 544a8a2d3562..b91e48d2190d 100644 --- a/drivers/gpu/drm/i2c/ch7006_drv.c +++ b/drivers/gpu/drm/i2c/ch7006_drv.c | |||
@@ -359,10 +359,10 @@ static int ch7006_encoder_set_property(struct drm_encoder *encoder, | |||
359 | if (modes_changed) { | 359 | if (modes_changed) { |
360 | drm_helper_probe_single_connector_modes(connector, 0, 0); | 360 | drm_helper_probe_single_connector_modes(connector, 0, 0); |
361 | 361 | ||
362 | /* Disable the crtc to ensure a full modeset is | ||
363 | * performed whenever it's turned on again. */ | ||
364 | if (crtc) | 362 | if (crtc) |
365 | drm_crtc_force_disable(crtc); | 363 | drm_crtc_helper_set_mode(crtc, &crtc->mode, |
364 | crtc->x, crtc->y, | ||
365 | crtc->primary->fb); | ||
366 | } | 366 | } |
367 | 367 | ||
368 | return 0; | 368 | return 0; |
diff --git a/drivers/gpu/drm/i2c/tda998x_drv.c b/drivers/gpu/drm/i2c/tda998x_drv.c index a6ba461749b2..ecdb8070ed35 100644 --- a/drivers/gpu/drm/i2c/tda998x_drv.c +++ b/drivers/gpu/drm/i2c/tda998x_drv.c | |||
@@ -849,7 +849,8 @@ tda998x_write_avi(struct tda998x_priv *priv, const struct drm_display_mode *mode | |||
849 | { | 849 | { |
850 | union hdmi_infoframe frame; | 850 | union hdmi_infoframe frame; |
851 | 851 | ||
852 | drm_hdmi_avi_infoframe_from_display_mode(&frame.avi, mode, false); | 852 | drm_hdmi_avi_infoframe_from_display_mode(&frame.avi, |
853 | &priv->connector, mode); | ||
853 | frame.avi.quantization_range = HDMI_QUANTIZATION_RANGE_FULL; | 854 | frame.avi.quantization_range = HDMI_QUANTIZATION_RANGE_FULL; |
854 | 855 | ||
855 | tda998x_write_if(priv, DIP_IF_FLAGS_IF2, REG_IF2_HB0, &frame); | 856 | tda998x_write_if(priv, DIP_IF_FLAGS_IF2, REG_IF2_HB0, &frame); |
@@ -1122,7 +1123,6 @@ static void tda998x_connector_destroy(struct drm_connector *connector) | |||
1122 | } | 1123 | } |
1123 | 1124 | ||
1124 | static const struct drm_connector_funcs tda998x_connector_funcs = { | 1125 | static const struct drm_connector_funcs tda998x_connector_funcs = { |
1125 | .dpms = drm_helper_connector_dpms, | ||
1126 | .reset = drm_atomic_helper_connector_reset, | 1126 | .reset = drm_atomic_helper_connector_reset, |
1127 | .fill_modes = drm_helper_probe_single_connector_modes, | 1127 | .fill_modes = drm_helper_probe_single_connector_modes, |
1128 | .detect = tda998x_connector_detect, | 1128 | .detect = tda998x_connector_detect, |
diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index 38dcee1ca062..9bad6a32adae 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c | |||
@@ -2948,14 +2948,7 @@ static void intel_seq_print_mode(struct seq_file *m, int tabs, | |||
2948 | for (i = 0; i < tabs; i++) | 2948 | for (i = 0; i < tabs; i++) |
2949 | seq_putc(m, '\t'); | 2949 | seq_putc(m, '\t'); |
2950 | 2950 | ||
2951 | seq_printf(m, "id %d:\"%s\" freq %d clock %d hdisp %d hss %d hse %d htot %d vdisp %d vss %d vse %d vtot %d type 0x%x flags 0x%x\n", | 2951 | seq_printf(m, DRM_MODE_FMT "\n", DRM_MODE_ARG(mode)); |
2952 | mode->base.id, mode->name, | ||
2953 | mode->vrefresh, mode->clock, | ||
2954 | mode->hdisplay, mode->hsync_start, | ||
2955 | mode->hsync_end, mode->htotal, | ||
2956 | mode->vdisplay, mode->vsync_start, | ||
2957 | mode->vsync_end, mode->vtotal, | ||
2958 | mode->type, mode->flags); | ||
2959 | } | 2952 | } |
2960 | 2953 | ||
2961 | static void intel_encoder_info(struct seq_file *m, | 2954 | static void intel_encoder_info(struct seq_file *m, |
diff --git a/drivers/gpu/drm/i915/icl_dsi.c b/drivers/gpu/drm/i915/icl_dsi.c index 4dd793b78996..d9dcee4ec51f 100644 --- a/drivers/gpu/drm/i915/icl_dsi.c +++ b/drivers/gpu/drm/i915/icl_dsi.c | |||
@@ -1178,9 +1178,9 @@ static void gen11_dsi_get_config(struct intel_encoder *encoder, | |||
1178 | pipe_config->output_types |= BIT(INTEL_OUTPUT_DSI); | 1178 | pipe_config->output_types |= BIT(INTEL_OUTPUT_DSI); |
1179 | } | 1179 | } |
1180 | 1180 | ||
1181 | static bool gen11_dsi_compute_config(struct intel_encoder *encoder, | 1181 | static int gen11_dsi_compute_config(struct intel_encoder *encoder, |
1182 | struct intel_crtc_state *pipe_config, | 1182 | struct intel_crtc_state *pipe_config, |
1183 | struct drm_connector_state *conn_state) | 1183 | struct drm_connector_state *conn_state) |
1184 | { | 1184 | { |
1185 | struct intel_dsi *intel_dsi = container_of(encoder, struct intel_dsi, | 1185 | struct intel_dsi *intel_dsi = container_of(encoder, struct intel_dsi, |
1186 | base); | 1186 | base); |
@@ -1205,7 +1205,7 @@ static bool gen11_dsi_compute_config(struct intel_encoder *encoder, | |||
1205 | pipe_config->clock_set = true; | 1205 | pipe_config->clock_set = true; |
1206 | pipe_config->port_clock = intel_dsi_bitrate(intel_dsi) / 5; | 1206 | pipe_config->port_clock = intel_dsi_bitrate(intel_dsi) / 5; |
1207 | 1207 | ||
1208 | return true; | 1208 | return 0; |
1209 | } | 1209 | } |
1210 | 1210 | ||
1211 | static u64 gen11_dsi_get_power_domains(struct intel_encoder *encoder, | 1211 | static u64 gen11_dsi_get_power_domains(struct intel_encoder *encoder, |
diff --git a/drivers/gpu/drm/i915/intel_connector.c b/drivers/gpu/drm/i915/intel_connector.c index 18e370f607bc..37d2c644f4b8 100644 --- a/drivers/gpu/drm/i915/intel_connector.c +++ b/drivers/gpu/drm/i915/intel_connector.c | |||
@@ -95,6 +95,10 @@ void intel_connector_destroy(struct drm_connector *connector) | |||
95 | intel_panel_fini(&intel_connector->panel); | 95 | intel_panel_fini(&intel_connector->panel); |
96 | 96 | ||
97 | drm_connector_cleanup(connector); | 97 | drm_connector_cleanup(connector); |
98 | |||
99 | if (intel_connector->port) | ||
100 | drm_dp_mst_put_port_malloc(intel_connector->port); | ||
101 | |||
98 | kfree(connector); | 102 | kfree(connector); |
99 | } | 103 | } |
100 | 104 | ||
diff --git a/drivers/gpu/drm/i915/intel_crt.c b/drivers/gpu/drm/i915/intel_crt.c index 68f2fb89ece3..2e0fd9927db2 100644 --- a/drivers/gpu/drm/i915/intel_crt.c +++ b/drivers/gpu/drm/i915/intel_crt.c | |||
@@ -344,51 +344,52 @@ intel_crt_mode_valid(struct drm_connector *connector, | |||
344 | return MODE_OK; | 344 | return MODE_OK; |
345 | } | 345 | } |
346 | 346 | ||
347 | static bool intel_crt_compute_config(struct intel_encoder *encoder, | 347 | static int intel_crt_compute_config(struct intel_encoder *encoder, |
348 | struct intel_crtc_state *pipe_config, | 348 | struct intel_crtc_state *pipe_config, |
349 | struct drm_connector_state *conn_state) | 349 | struct drm_connector_state *conn_state) |
350 | { | 350 | { |
351 | struct drm_display_mode *adjusted_mode = | 351 | struct drm_display_mode *adjusted_mode = |
352 | &pipe_config->base.adjusted_mode; | 352 | &pipe_config->base.adjusted_mode; |
353 | 353 | ||
354 | if (adjusted_mode->flags & DRM_MODE_FLAG_DBLSCAN) | 354 | if (adjusted_mode->flags & DRM_MODE_FLAG_DBLSCAN) |
355 | return false; | 355 | return -EINVAL; |
356 | 356 | ||
357 | pipe_config->output_format = INTEL_OUTPUT_FORMAT_RGB; | 357 | pipe_config->output_format = INTEL_OUTPUT_FORMAT_RGB; |
358 | return true; | 358 | |
359 | return 0; | ||
359 | } | 360 | } |
360 | 361 | ||
361 | static bool pch_crt_compute_config(struct intel_encoder *encoder, | 362 | static int pch_crt_compute_config(struct intel_encoder *encoder, |
362 | struct intel_crtc_state *pipe_config, | 363 | struct intel_crtc_state *pipe_config, |
363 | struct drm_connector_state *conn_state) | 364 | struct drm_connector_state *conn_state) |
364 | { | 365 | { |
365 | struct drm_display_mode *adjusted_mode = | 366 | struct drm_display_mode *adjusted_mode = |
366 | &pipe_config->base.adjusted_mode; | 367 | &pipe_config->base.adjusted_mode; |
367 | 368 | ||
368 | if (adjusted_mode->flags & DRM_MODE_FLAG_DBLSCAN) | 369 | if (adjusted_mode->flags & DRM_MODE_FLAG_DBLSCAN) |
369 | return false; | 370 | return -EINVAL; |
370 | 371 | ||
371 | pipe_config->has_pch_encoder = true; | 372 | pipe_config->has_pch_encoder = true; |
372 | pipe_config->output_format = INTEL_OUTPUT_FORMAT_RGB; | 373 | pipe_config->output_format = INTEL_OUTPUT_FORMAT_RGB; |
373 | 374 | ||
374 | return true; | 375 | return 0; |
375 | } | 376 | } |
376 | 377 | ||
377 | static bool hsw_crt_compute_config(struct intel_encoder *encoder, | 378 | static int hsw_crt_compute_config(struct intel_encoder *encoder, |
378 | struct intel_crtc_state *pipe_config, | 379 | struct intel_crtc_state *pipe_config, |
379 | struct drm_connector_state *conn_state) | 380 | struct drm_connector_state *conn_state) |
380 | { | 381 | { |
381 | struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); | 382 | struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); |
382 | struct drm_display_mode *adjusted_mode = | 383 | struct drm_display_mode *adjusted_mode = |
383 | &pipe_config->base.adjusted_mode; | 384 | &pipe_config->base.adjusted_mode; |
384 | 385 | ||
385 | if (adjusted_mode->flags & DRM_MODE_FLAG_DBLSCAN) | 386 | if (adjusted_mode->flags & DRM_MODE_FLAG_DBLSCAN) |
386 | return false; | 387 | return -EINVAL; |
387 | 388 | ||
388 | /* HSW/BDW FDI limited to 4k */ | 389 | /* HSW/BDW FDI limited to 4k */ |
389 | if (adjusted_mode->crtc_hdisplay > 4096 || | 390 | if (adjusted_mode->crtc_hdisplay > 4096 || |
390 | adjusted_mode->crtc_hblank_start > 4096) | 391 | adjusted_mode->crtc_hblank_start > 4096) |
391 | return false; | 392 | return -EINVAL; |
392 | 393 | ||
393 | pipe_config->has_pch_encoder = true; | 394 | pipe_config->has_pch_encoder = true; |
394 | pipe_config->output_format = INTEL_OUTPUT_FORMAT_RGB; | 395 | pipe_config->output_format = INTEL_OUTPUT_FORMAT_RGB; |
@@ -397,7 +398,7 @@ static bool hsw_crt_compute_config(struct intel_encoder *encoder, | |||
397 | if (HAS_PCH_LPT(dev_priv)) { | 398 | if (HAS_PCH_LPT(dev_priv)) { |
398 | if (pipe_config->bw_constrained && pipe_config->pipe_bpp < 24) { | 399 | if (pipe_config->bw_constrained && pipe_config->pipe_bpp < 24) { |
399 | DRM_DEBUG_KMS("LPT only supports 24bpp\n"); | 400 | DRM_DEBUG_KMS("LPT only supports 24bpp\n"); |
400 | return false; | 401 | return -EINVAL; |
401 | } | 402 | } |
402 | 403 | ||
403 | pipe_config->pipe_bpp = 24; | 404 | pipe_config->pipe_bpp = 24; |
@@ -406,7 +407,7 @@ static bool hsw_crt_compute_config(struct intel_encoder *encoder, | |||
406 | /* FDI must always be 2.7 GHz */ | 407 | /* FDI must always be 2.7 GHz */ |
407 | pipe_config->port_clock = 135000 * 2; | 408 | pipe_config->port_clock = 135000 * 2; |
408 | 409 | ||
409 | return true; | 410 | return 0; |
410 | } | 411 | } |
411 | 412 | ||
412 | static bool intel_ironlake_crt_detect_hotplug(struct drm_connector *connector) | 413 | static bool intel_ironlake_crt_detect_hotplug(struct drm_connector *connector) |
diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c index f3e1d6a0b7dd..fd06d1fd39d3 100644 --- a/drivers/gpu/drm/i915/intel_ddi.c +++ b/drivers/gpu/drm/i915/intel_ddi.c | |||
@@ -3875,9 +3875,9 @@ intel_ddi_compute_output_type(struct intel_encoder *encoder, | |||
3875 | } | 3875 | } |
3876 | } | 3876 | } |
3877 | 3877 | ||
3878 | static bool intel_ddi_compute_config(struct intel_encoder *encoder, | 3878 | static int intel_ddi_compute_config(struct intel_encoder *encoder, |
3879 | struct intel_crtc_state *pipe_config, | 3879 | struct intel_crtc_state *pipe_config, |
3880 | struct drm_connector_state *conn_state) | 3880 | struct drm_connector_state *conn_state) |
3881 | { | 3881 | { |
3882 | struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); | 3882 | struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); |
3883 | enum port port = encoder->port; | 3883 | enum port port = encoder->port; |
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 3da9c0f9e948..52c63135bc65 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c | |||
@@ -11517,10 +11517,13 @@ encoder_retry: | |||
11517 | continue; | 11517 | continue; |
11518 | 11518 | ||
11519 | encoder = to_intel_encoder(connector_state->best_encoder); | 11519 | encoder = to_intel_encoder(connector_state->best_encoder); |
11520 | 11520 | ret = encoder->compute_config(encoder, pipe_config, | |
11521 | if (!(encoder->compute_config(encoder, pipe_config, connector_state))) { | 11521 | connector_state); |
11522 | DRM_DEBUG_KMS("Encoder config failure\n"); | 11522 | if (ret < 0) { |
11523 | return -EINVAL; | 11523 | if (ret != -EDEADLK) |
11524 | DRM_DEBUG_KMS("Encoder config failure: %d\n", | ||
11525 | ret); | ||
11526 | return ret; | ||
11524 | } | 11527 | } |
11525 | } | 11528 | } |
11526 | 11529 | ||
@@ -12695,6 +12698,10 @@ static int intel_atomic_check(struct drm_device *dev, | |||
12695 | "[modeset]" : "[fastset]"); | 12698 | "[modeset]" : "[fastset]"); |
12696 | } | 12699 | } |
12697 | 12700 | ||
12701 | ret = drm_dp_mst_atomic_check(state); | ||
12702 | if (ret) | ||
12703 | return ret; | ||
12704 | |||
12698 | if (any_ms) { | 12705 | if (any_ms) { |
12699 | ret = intel_modeset_checks(state); | 12706 | ret = intel_modeset_checks(state); |
12700 | 12707 | ||
diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index fdd2cbc56fa3..d18b72b5f0b8 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c | |||
@@ -1808,7 +1808,7 @@ intel_dp_adjust_compliance_config(struct intel_dp *intel_dp, | |||
1808 | } | 1808 | } |
1809 | 1809 | ||
1810 | /* Optimize link config in order: max bpp, min clock, min lanes */ | 1810 | /* Optimize link config in order: max bpp, min clock, min lanes */ |
1811 | static bool | 1811 | static int |
1812 | intel_dp_compute_link_config_wide(struct intel_dp *intel_dp, | 1812 | intel_dp_compute_link_config_wide(struct intel_dp *intel_dp, |
1813 | struct intel_crtc_state *pipe_config, | 1813 | struct intel_crtc_state *pipe_config, |
1814 | const struct link_config_limits *limits) | 1814 | const struct link_config_limits *limits) |
@@ -1834,17 +1834,17 @@ intel_dp_compute_link_config_wide(struct intel_dp *intel_dp, | |||
1834 | pipe_config->pipe_bpp = bpp; | 1834 | pipe_config->pipe_bpp = bpp; |
1835 | pipe_config->port_clock = link_clock; | 1835 | pipe_config->port_clock = link_clock; |
1836 | 1836 | ||
1837 | return true; | 1837 | return 0; |
1838 | } | 1838 | } |
1839 | } | 1839 | } |
1840 | } | 1840 | } |
1841 | } | 1841 | } |
1842 | 1842 | ||
1843 | return false; | 1843 | return -EINVAL; |
1844 | } | 1844 | } |
1845 | 1845 | ||
1846 | /* Optimize link config in order: max bpp, min lanes, min clock */ | 1846 | /* Optimize link config in order: max bpp, min lanes, min clock */ |
1847 | static bool | 1847 | static int |
1848 | intel_dp_compute_link_config_fast(struct intel_dp *intel_dp, | 1848 | intel_dp_compute_link_config_fast(struct intel_dp *intel_dp, |
1849 | struct intel_crtc_state *pipe_config, | 1849 | struct intel_crtc_state *pipe_config, |
1850 | const struct link_config_limits *limits) | 1850 | const struct link_config_limits *limits) |
@@ -1870,13 +1870,13 @@ intel_dp_compute_link_config_fast(struct intel_dp *intel_dp, | |||
1870 | pipe_config->pipe_bpp = bpp; | 1870 | pipe_config->pipe_bpp = bpp; |
1871 | pipe_config->port_clock = link_clock; | 1871 | pipe_config->port_clock = link_clock; |
1872 | 1872 | ||
1873 | return true; | 1873 | return 0; |
1874 | } | 1874 | } |
1875 | } | 1875 | } |
1876 | } | 1876 | } |
1877 | } | 1877 | } |
1878 | 1878 | ||
1879 | return false; | 1879 | return -EINVAL; |
1880 | } | 1880 | } |
1881 | 1881 | ||
1882 | static int intel_dp_dsc_compute_bpp(struct intel_dp *intel_dp, u8 dsc_max_bpc) | 1882 | static int intel_dp_dsc_compute_bpp(struct intel_dp *intel_dp, u8 dsc_max_bpc) |
@@ -1894,19 +1894,20 @@ static int intel_dp_dsc_compute_bpp(struct intel_dp *intel_dp, u8 dsc_max_bpc) | |||
1894 | return 0; | 1894 | return 0; |
1895 | } | 1895 | } |
1896 | 1896 | ||
1897 | static bool intel_dp_dsc_compute_config(struct intel_dp *intel_dp, | 1897 | static int intel_dp_dsc_compute_config(struct intel_dp *intel_dp, |
1898 | struct intel_crtc_state *pipe_config, | 1898 | struct intel_crtc_state *pipe_config, |
1899 | struct drm_connector_state *conn_state, | 1899 | struct drm_connector_state *conn_state, |
1900 | struct link_config_limits *limits) | 1900 | struct link_config_limits *limits) |
1901 | { | 1901 | { |
1902 | struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp); | 1902 | struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp); |
1903 | struct drm_i915_private *dev_priv = to_i915(dig_port->base.base.dev); | 1903 | struct drm_i915_private *dev_priv = to_i915(dig_port->base.base.dev); |
1904 | struct drm_display_mode *adjusted_mode = &pipe_config->base.adjusted_mode; | 1904 | struct drm_display_mode *adjusted_mode = &pipe_config->base.adjusted_mode; |
1905 | u8 dsc_max_bpc; | 1905 | u8 dsc_max_bpc; |
1906 | int pipe_bpp; | 1906 | int pipe_bpp; |
1907 | int ret; | ||
1907 | 1908 | ||
1908 | if (!intel_dp_supports_dsc(intel_dp, pipe_config)) | 1909 | if (!intel_dp_supports_dsc(intel_dp, pipe_config)) |
1909 | return false; | 1910 | return -EINVAL; |
1910 | 1911 | ||
1911 | dsc_max_bpc = min_t(u8, DP_DSC_MAX_SUPPORTED_BPC, | 1912 | dsc_max_bpc = min_t(u8, DP_DSC_MAX_SUPPORTED_BPC, |
1912 | conn_state->max_requested_bpc); | 1913 | conn_state->max_requested_bpc); |
@@ -1914,7 +1915,7 @@ static bool intel_dp_dsc_compute_config(struct intel_dp *intel_dp, | |||
1914 | pipe_bpp = intel_dp_dsc_compute_bpp(intel_dp, dsc_max_bpc); | 1915 | pipe_bpp = intel_dp_dsc_compute_bpp(intel_dp, dsc_max_bpc); |
1915 | if (pipe_bpp < DP_DSC_MIN_SUPPORTED_BPC * 3) { | 1916 | if (pipe_bpp < DP_DSC_MIN_SUPPORTED_BPC * 3) { |
1916 | DRM_DEBUG_KMS("No DSC support for less than 8bpc\n"); | 1917 | DRM_DEBUG_KMS("No DSC support for less than 8bpc\n"); |
1917 | return false; | 1918 | return -EINVAL; |
1918 | } | 1919 | } |
1919 | 1920 | ||
1920 | /* | 1921 | /* |
@@ -1948,7 +1949,7 @@ static bool intel_dp_dsc_compute_config(struct intel_dp *intel_dp, | |||
1948 | adjusted_mode->crtc_hdisplay); | 1949 | adjusted_mode->crtc_hdisplay); |
1949 | if (!dsc_max_output_bpp || !dsc_dp_slice_count) { | 1950 | if (!dsc_max_output_bpp || !dsc_dp_slice_count) { |
1950 | DRM_DEBUG_KMS("Compressed BPP/Slice Count not supported\n"); | 1951 | DRM_DEBUG_KMS("Compressed BPP/Slice Count not supported\n"); |
1951 | return false; | 1952 | return -EINVAL; |
1952 | } | 1953 | } |
1953 | pipe_config->dsc_params.compressed_bpp = min_t(u16, | 1954 | pipe_config->dsc_params.compressed_bpp = min_t(u16, |
1954 | dsc_max_output_bpp >> 4, | 1955 | dsc_max_output_bpp >> 4, |
@@ -1965,16 +1966,19 @@ static bool intel_dp_dsc_compute_config(struct intel_dp *intel_dp, | |||
1965 | pipe_config->dsc_params.dsc_split = true; | 1966 | pipe_config->dsc_params.dsc_split = true; |
1966 | } else { | 1967 | } else { |
1967 | DRM_DEBUG_KMS("Cannot split stream to use 2 VDSC instances\n"); | 1968 | DRM_DEBUG_KMS("Cannot split stream to use 2 VDSC instances\n"); |
1968 | return false; | 1969 | return -EINVAL; |
1969 | } | 1970 | } |
1970 | } | 1971 | } |
1971 | if (intel_dp_compute_dsc_params(intel_dp, pipe_config) < 0) { | 1972 | |
1973 | ret = intel_dp_compute_dsc_params(intel_dp, pipe_config); | ||
1974 | if (ret < 0) { | ||
1972 | DRM_DEBUG_KMS("Cannot compute valid DSC parameters for Input Bpp = %d " | 1975 | DRM_DEBUG_KMS("Cannot compute valid DSC parameters for Input Bpp = %d " |
1973 | "Compressed BPP = %d\n", | 1976 | "Compressed BPP = %d\n", |
1974 | pipe_config->pipe_bpp, | 1977 | pipe_config->pipe_bpp, |
1975 | pipe_config->dsc_params.compressed_bpp); | 1978 | pipe_config->dsc_params.compressed_bpp); |
1976 | return false; | 1979 | return ret; |
1977 | } | 1980 | } |
1981 | |||
1978 | pipe_config->dsc_params.compression_enable = true; | 1982 | pipe_config->dsc_params.compression_enable = true; |
1979 | DRM_DEBUG_KMS("DP DSC computed with Input Bpp = %d " | 1983 | DRM_DEBUG_KMS("DP DSC computed with Input Bpp = %d " |
1980 | "Compressed Bpp = %d Slice Count = %d\n", | 1984 | "Compressed Bpp = %d Slice Count = %d\n", |
@@ -1982,10 +1986,10 @@ static bool intel_dp_dsc_compute_config(struct intel_dp *intel_dp, | |||
1982 | pipe_config->dsc_params.compressed_bpp, | 1986 | pipe_config->dsc_params.compressed_bpp, |
1983 | pipe_config->dsc_params.slice_count); | 1987 | pipe_config->dsc_params.slice_count); |
1984 | 1988 | ||
1985 | return true; | 1989 | return 0; |
1986 | } | 1990 | } |
1987 | 1991 | ||
1988 | static bool | 1992 | static int |
1989 | intel_dp_compute_link_config(struct intel_encoder *encoder, | 1993 | intel_dp_compute_link_config(struct intel_encoder *encoder, |
1990 | struct intel_crtc_state *pipe_config, | 1994 | struct intel_crtc_state *pipe_config, |
1991 | struct drm_connector_state *conn_state) | 1995 | struct drm_connector_state *conn_state) |
@@ -1994,7 +1998,7 @@ intel_dp_compute_link_config(struct intel_encoder *encoder, | |||
1994 | struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base); | 1998 | struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base); |
1995 | struct link_config_limits limits; | 1999 | struct link_config_limits limits; |
1996 | int common_len; | 2000 | int common_len; |
1997 | bool ret; | 2001 | int ret; |
1998 | 2002 | ||
1999 | common_len = intel_dp_common_len_rate_limit(intel_dp, | 2003 | common_len = intel_dp_common_len_rate_limit(intel_dp, |
2000 | intel_dp->max_link_rate); | 2004 | intel_dp->max_link_rate); |
@@ -2051,10 +2055,11 @@ intel_dp_compute_link_config(struct intel_encoder *encoder, | |||
2051 | &limits); | 2055 | &limits); |
2052 | 2056 | ||
2053 | /* enable compression if the mode doesn't fit available BW */ | 2057 | /* enable compression if the mode doesn't fit available BW */ |
2054 | if (!ret) { | 2058 | if (ret) { |
2055 | if (!intel_dp_dsc_compute_config(intel_dp, pipe_config, | 2059 | ret = intel_dp_dsc_compute_config(intel_dp, pipe_config, |
2056 | conn_state, &limits)) | 2060 | conn_state, &limits); |
2057 | return false; | 2061 | if (ret < 0) |
2062 | return ret; | ||
2058 | } | 2063 | } |
2059 | 2064 | ||
2060 | if (pipe_config->dsc_params.compression_enable) { | 2065 | if (pipe_config->dsc_params.compression_enable) { |
@@ -2079,10 +2084,10 @@ intel_dp_compute_link_config(struct intel_encoder *encoder, | |||
2079 | intel_dp_max_data_rate(pipe_config->port_clock, | 2084 | intel_dp_max_data_rate(pipe_config->port_clock, |
2080 | pipe_config->lane_count)); | 2085 | pipe_config->lane_count)); |
2081 | } | 2086 | } |
2082 | return true; | 2087 | return 0; |
2083 | } | 2088 | } |
2084 | 2089 | ||
2085 | bool | 2090 | int |
2086 | intel_dp_compute_config(struct intel_encoder *encoder, | 2091 | intel_dp_compute_config(struct intel_encoder *encoder, |
2087 | struct intel_crtc_state *pipe_config, | 2092 | struct intel_crtc_state *pipe_config, |
2088 | struct drm_connector_state *conn_state) | 2093 | struct drm_connector_state *conn_state) |
@@ -2098,6 +2103,7 @@ intel_dp_compute_config(struct intel_encoder *encoder, | |||
2098 | to_intel_digital_connector_state(conn_state); | 2103 | to_intel_digital_connector_state(conn_state); |
2099 | bool constant_n = drm_dp_has_quirk(&intel_dp->desc, | 2104 | bool constant_n = drm_dp_has_quirk(&intel_dp->desc, |
2100 | DP_DPCD_QUIRK_CONSTANT_N); | 2105 | DP_DPCD_QUIRK_CONSTANT_N); |
2106 | int ret; | ||
2101 | 2107 | ||
2102 | if (HAS_PCH_SPLIT(dev_priv) && !HAS_DDI(dev_priv) && port != PORT_A) | 2108 | if (HAS_PCH_SPLIT(dev_priv) && !HAS_DDI(dev_priv) && port != PORT_A) |
2103 | pipe_config->has_pch_encoder = true; | 2109 | pipe_config->has_pch_encoder = true; |
@@ -2119,8 +2125,6 @@ intel_dp_compute_config(struct intel_encoder *encoder, | |||
2119 | adjusted_mode); | 2125 | adjusted_mode); |
2120 | 2126 | ||
2121 | if (INTEL_GEN(dev_priv) >= 9) { | 2127 | if (INTEL_GEN(dev_priv) >= 9) { |
2122 | int ret; | ||
2123 | |||
2124 | ret = skl_update_scaler_crtc(pipe_config); | 2128 | ret = skl_update_scaler_crtc(pipe_config); |
2125 | if (ret) | 2129 | if (ret) |
2126 | return ret; | 2130 | return ret; |
@@ -2135,20 +2139,21 @@ intel_dp_compute_config(struct intel_encoder *encoder, | |||
2135 | } | 2139 | } |
2136 | 2140 | ||
2137 | if (adjusted_mode->flags & DRM_MODE_FLAG_DBLSCAN) | 2141 | if (adjusted_mode->flags & DRM_MODE_FLAG_DBLSCAN) |
2138 | return false; | 2142 | return -EINVAL; |
2139 | 2143 | ||
2140 | if (HAS_GMCH_DISPLAY(dev_priv) && | 2144 | if (HAS_GMCH_DISPLAY(dev_priv) && |
2141 | adjusted_mode->flags & DRM_MODE_FLAG_INTERLACE) | 2145 | adjusted_mode->flags & DRM_MODE_FLAG_INTERLACE) |
2142 | return false; | 2146 | return -EINVAL; |
2143 | 2147 | ||
2144 | if (adjusted_mode->flags & DRM_MODE_FLAG_DBLCLK) | 2148 | if (adjusted_mode->flags & DRM_MODE_FLAG_DBLCLK) |
2145 | return false; | 2149 | return -EINVAL; |
2146 | 2150 | ||
2147 | pipe_config->fec_enable = !intel_dp_is_edp(intel_dp) && | 2151 | pipe_config->fec_enable = !intel_dp_is_edp(intel_dp) && |
2148 | intel_dp_supports_fec(intel_dp, pipe_config); | 2152 | intel_dp_supports_fec(intel_dp, pipe_config); |
2149 | 2153 | ||
2150 | if (!intel_dp_compute_link_config(encoder, pipe_config, conn_state)) | 2154 | ret = intel_dp_compute_link_config(encoder, pipe_config, conn_state); |
2151 | return false; | 2155 | if (ret < 0) |
2156 | return ret; | ||
2152 | 2157 | ||
2153 | if (intel_conn_state->broadcast_rgb == INTEL_BROADCAST_RGB_AUTO) { | 2158 | if (intel_conn_state->broadcast_rgb == INTEL_BROADCAST_RGB_AUTO) { |
2154 | /* | 2159 | /* |
@@ -2196,7 +2201,7 @@ intel_dp_compute_config(struct intel_encoder *encoder, | |||
2196 | 2201 | ||
2197 | intel_psr_compute_config(intel_dp, pipe_config); | 2202 | intel_psr_compute_config(intel_dp, pipe_config); |
2198 | 2203 | ||
2199 | return true; | 2204 | return 0; |
2200 | } | 2205 | } |
2201 | 2206 | ||
2202 | void intel_dp_set_link_params(struct intel_dp *intel_dp, | 2207 | void intel_dp_set_link_params(struct intel_dp *intel_dp, |
diff --git a/drivers/gpu/drm/i915/intel_dp_mst.c b/drivers/gpu/drm/i915/intel_dp_mst.c index f05427b74e34..5899debe2184 100644 --- a/drivers/gpu/drm/i915/intel_dp_mst.c +++ b/drivers/gpu/drm/i915/intel_dp_mst.c | |||
@@ -30,9 +30,9 @@ | |||
30 | #include <drm/drm_crtc_helper.h> | 30 | #include <drm/drm_crtc_helper.h> |
31 | #include <drm/drm_edid.h> | 31 | #include <drm/drm_edid.h> |
32 | 32 | ||
33 | static bool intel_dp_mst_compute_config(struct intel_encoder *encoder, | 33 | static int intel_dp_mst_compute_config(struct intel_encoder *encoder, |
34 | struct intel_crtc_state *pipe_config, | 34 | struct intel_crtc_state *pipe_config, |
35 | struct drm_connector_state *conn_state) | 35 | struct drm_connector_state *conn_state) |
36 | { | 36 | { |
37 | struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); | 37 | struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); |
38 | struct intel_dp_mst_encoder *intel_mst = enc_to_mst(&encoder->base); | 38 | struct intel_dp_mst_encoder *intel_mst = enc_to_mst(&encoder->base); |
@@ -41,15 +41,19 @@ static bool intel_dp_mst_compute_config(struct intel_encoder *encoder, | |||
41 | struct drm_connector *connector = conn_state->connector; | 41 | struct drm_connector *connector = conn_state->connector; |
42 | void *port = to_intel_connector(connector)->port; | 42 | void *port = to_intel_connector(connector)->port; |
43 | struct drm_atomic_state *state = pipe_config->base.state; | 43 | struct drm_atomic_state *state = pipe_config->base.state; |
44 | struct drm_crtc *crtc = pipe_config->base.crtc; | ||
45 | struct drm_crtc_state *old_crtc_state = | ||
46 | drm_atomic_get_old_crtc_state(state, crtc); | ||
44 | int bpp; | 47 | int bpp; |
45 | int lane_count, slots = 0; | 48 | int lane_count, slots = |
49 | to_intel_crtc_state(old_crtc_state)->dp_m_n.tu; | ||
46 | const struct drm_display_mode *adjusted_mode = &pipe_config->base.adjusted_mode; | 50 | const struct drm_display_mode *adjusted_mode = &pipe_config->base.adjusted_mode; |
47 | int mst_pbn; | 51 | int mst_pbn; |
48 | bool constant_n = drm_dp_has_quirk(&intel_dp->desc, | 52 | bool constant_n = drm_dp_has_quirk(&intel_dp->desc, |
49 | DP_DPCD_QUIRK_CONSTANT_N); | 53 | DP_DPCD_QUIRK_CONSTANT_N); |
50 | 54 | ||
51 | if (adjusted_mode->flags & DRM_MODE_FLAG_DBLSCAN) | 55 | if (adjusted_mode->flags & DRM_MODE_FLAG_DBLSCAN) |
52 | return false; | 56 | return -EINVAL; |
53 | 57 | ||
54 | pipe_config->output_format = INTEL_OUTPUT_FORMAT_RGB; | 58 | pipe_config->output_format = INTEL_OUTPUT_FORMAT_RGB; |
55 | pipe_config->has_pch_encoder = false; | 59 | pipe_config->has_pch_encoder = false; |
@@ -86,7 +90,7 @@ static bool intel_dp_mst_compute_config(struct intel_encoder *encoder, | |||
86 | if (slots < 0) { | 90 | if (slots < 0) { |
87 | DRM_DEBUG_KMS("failed finding vcpi slots:%d\n", | 91 | DRM_DEBUG_KMS("failed finding vcpi slots:%d\n", |
88 | slots); | 92 | slots); |
89 | return false; | 93 | return slots; |
90 | } | 94 | } |
91 | } | 95 | } |
92 | 96 | ||
@@ -104,38 +108,42 @@ static bool intel_dp_mst_compute_config(struct intel_encoder *encoder, | |||
104 | 108 | ||
105 | intel_ddi_compute_min_voltage_level(dev_priv, pipe_config); | 109 | intel_ddi_compute_min_voltage_level(dev_priv, pipe_config); |
106 | 110 | ||
107 | return true; | 111 | return 0; |
108 | } | 112 | } |
109 | 113 | ||
110 | static int intel_dp_mst_atomic_check(struct drm_connector *connector, | 114 | static int |
111 | struct drm_connector_state *new_conn_state) | 115 | intel_dp_mst_atomic_check(struct drm_connector *connector, |
116 | struct drm_connector_state *new_conn_state) | ||
112 | { | 117 | { |
113 | struct drm_atomic_state *state = new_conn_state->state; | 118 | struct drm_atomic_state *state = new_conn_state->state; |
114 | struct drm_connector_state *old_conn_state; | 119 | struct drm_connector_state *old_conn_state = |
115 | struct drm_crtc *old_crtc; | 120 | drm_atomic_get_old_connector_state(state, connector); |
121 | struct intel_connector *intel_connector = | ||
122 | to_intel_connector(connector); | ||
123 | struct drm_crtc *new_crtc = new_conn_state->crtc; | ||
116 | struct drm_crtc_state *crtc_state; | 124 | struct drm_crtc_state *crtc_state; |
117 | int slots, ret = 0; | 125 | struct drm_dp_mst_topology_mgr *mgr; |
118 | 126 | int ret = 0; | |
119 | old_conn_state = drm_atomic_get_old_connector_state(state, connector); | ||
120 | old_crtc = old_conn_state->crtc; | ||
121 | if (!old_crtc) | ||
122 | return ret; | ||
123 | 127 | ||
124 | crtc_state = drm_atomic_get_new_crtc_state(state, old_crtc); | 128 | if (!old_conn_state->crtc) |
125 | slots = to_intel_crtc_state(crtc_state)->dp_m_n.tu; | 129 | return 0; |
126 | if (drm_atomic_crtc_needs_modeset(crtc_state) && slots > 0) { | ||
127 | struct drm_dp_mst_topology_mgr *mgr; | ||
128 | struct drm_encoder *old_encoder; | ||
129 | 130 | ||
130 | old_encoder = old_conn_state->best_encoder; | 131 | /* We only want to free VCPI if this state disables the CRTC on this |
131 | mgr = &enc_to_mst(old_encoder)->primary->dp.mst_mgr; | 132 | * connector |
133 | */ | ||
134 | if (new_crtc) { | ||
135 | crtc_state = drm_atomic_get_new_crtc_state(state, new_crtc); | ||
132 | 136 | ||
133 | ret = drm_dp_atomic_release_vcpi_slots(state, mgr, slots); | 137 | if (!crtc_state || |
134 | if (ret) | 138 | !drm_atomic_crtc_needs_modeset(crtc_state) || |
135 | DRM_DEBUG_KMS("failed releasing %d vcpi slots:%d\n", slots, ret); | 139 | crtc_state->enable) |
136 | else | 140 | return 0; |
137 | to_intel_crtc_state(crtc_state)->dp_m_n.tu = 0; | ||
138 | } | 141 | } |
142 | |||
143 | mgr = &enc_to_mst(old_conn_state->best_encoder)->primary->dp.mst_mgr; | ||
144 | ret = drm_dp_atomic_release_vcpi_slots(state, mgr, | ||
145 | intel_connector->port); | ||
146 | |||
139 | return ret; | 147 | return ret; |
140 | } | 148 | } |
141 | 149 | ||
@@ -457,6 +465,7 @@ static struct drm_connector *intel_dp_add_mst_connector(struct drm_dp_mst_topolo | |||
457 | intel_connector->get_hw_state = intel_dp_mst_get_hw_state; | 465 | intel_connector->get_hw_state = intel_dp_mst_get_hw_state; |
458 | intel_connector->mst_port = intel_dp; | 466 | intel_connector->mst_port = intel_dp; |
459 | intel_connector->port = port; | 467 | intel_connector->port = port; |
468 | drm_dp_mst_get_port_malloc(port); | ||
460 | 469 | ||
461 | connector = &intel_connector->base; | 470 | connector = &intel_connector->base; |
462 | ret = drm_connector_init(dev, connector, &intel_dp_mst_connector_funcs, | 471 | ret = drm_connector_init(dev, connector, &intel_dp_mst_connector_funcs, |
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index f94a04b4ad87..19d9abd2666e 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h | |||
@@ -222,9 +222,9 @@ struct intel_encoder { | |||
222 | enum intel_output_type (*compute_output_type)(struct intel_encoder *, | 222 | enum intel_output_type (*compute_output_type)(struct intel_encoder *, |
223 | struct intel_crtc_state *, | 223 | struct intel_crtc_state *, |
224 | struct drm_connector_state *); | 224 | struct drm_connector_state *); |
225 | bool (*compute_config)(struct intel_encoder *, | 225 | int (*compute_config)(struct intel_encoder *, |
226 | struct intel_crtc_state *, | 226 | struct intel_crtc_state *, |
227 | struct drm_connector_state *); | 227 | struct drm_connector_state *); |
228 | void (*pre_pll_enable)(struct intel_encoder *, | 228 | void (*pre_pll_enable)(struct intel_encoder *, |
229 | const struct intel_crtc_state *, | 229 | const struct intel_crtc_state *, |
230 | const struct drm_connector_state *); | 230 | const struct drm_connector_state *); |
@@ -1074,7 +1074,6 @@ struct intel_hdmi { | |||
1074 | } dp_dual_mode; | 1074 | } dp_dual_mode; |
1075 | bool has_hdmi_sink; | 1075 | bool has_hdmi_sink; |
1076 | bool has_audio; | 1076 | bool has_audio; |
1077 | bool rgb_quant_range_selectable; | ||
1078 | struct intel_connector *attached_connector; | 1077 | struct intel_connector *attached_connector; |
1079 | struct cec_notifier *cec_notifier; | 1078 | struct cec_notifier *cec_notifier; |
1080 | }; | 1079 | }; |
@@ -1807,9 +1806,9 @@ void intel_dp_sink_set_decompression_state(struct intel_dp *intel_dp, | |||
1807 | void intel_dp_encoder_reset(struct drm_encoder *encoder); | 1806 | void intel_dp_encoder_reset(struct drm_encoder *encoder); |
1808 | void intel_dp_encoder_suspend(struct intel_encoder *intel_encoder); | 1807 | void intel_dp_encoder_suspend(struct intel_encoder *intel_encoder); |
1809 | void intel_dp_encoder_destroy(struct drm_encoder *encoder); | 1808 | void intel_dp_encoder_destroy(struct drm_encoder *encoder); |
1810 | bool intel_dp_compute_config(struct intel_encoder *encoder, | 1809 | int intel_dp_compute_config(struct intel_encoder *encoder, |
1811 | struct intel_crtc_state *pipe_config, | 1810 | struct intel_crtc_state *pipe_config, |
1812 | struct drm_connector_state *conn_state); | 1811 | struct drm_connector_state *conn_state); |
1813 | bool intel_dp_is_edp(struct intel_dp *intel_dp); | 1812 | bool intel_dp_is_edp(struct intel_dp *intel_dp); |
1814 | bool intel_dp_is_port_edp(struct drm_i915_private *dev_priv, enum port port); | 1813 | bool intel_dp_is_port_edp(struct drm_i915_private *dev_priv, enum port port); |
1815 | enum irqreturn intel_dp_hpd_pulse(struct intel_digital_port *intel_dig_port, | 1814 | enum irqreturn intel_dp_hpd_pulse(struct intel_digital_port *intel_dig_port, |
@@ -1967,9 +1966,9 @@ void intel_hdmi_init(struct drm_i915_private *dev_priv, i915_reg_t hdmi_reg, | |||
1967 | void intel_hdmi_init_connector(struct intel_digital_port *intel_dig_port, | 1966 | void intel_hdmi_init_connector(struct intel_digital_port *intel_dig_port, |
1968 | struct intel_connector *intel_connector); | 1967 | struct intel_connector *intel_connector); |
1969 | struct intel_hdmi *enc_to_intel_hdmi(struct drm_encoder *encoder); | 1968 | struct intel_hdmi *enc_to_intel_hdmi(struct drm_encoder *encoder); |
1970 | bool intel_hdmi_compute_config(struct intel_encoder *encoder, | 1969 | int intel_hdmi_compute_config(struct intel_encoder *encoder, |
1971 | struct intel_crtc_state *pipe_config, | 1970 | struct intel_crtc_state *pipe_config, |
1972 | struct drm_connector_state *conn_state); | 1971 | struct drm_connector_state *conn_state); |
1973 | bool intel_hdmi_handle_sink_scrambling(struct intel_encoder *encoder, | 1972 | bool intel_hdmi_handle_sink_scrambling(struct intel_encoder *encoder, |
1974 | struct drm_connector *connector, | 1973 | struct drm_connector *connector, |
1975 | bool high_tmds_clock_ratio, | 1974 | bool high_tmds_clock_ratio, |
diff --git a/drivers/gpu/drm/i915/intel_dvo.c b/drivers/gpu/drm/i915/intel_dvo.c index 0042a7f69387..17a16917e134 100644 --- a/drivers/gpu/drm/i915/intel_dvo.c +++ b/drivers/gpu/drm/i915/intel_dvo.c | |||
@@ -235,9 +235,9 @@ intel_dvo_mode_valid(struct drm_connector *connector, | |||
235 | return intel_dvo->dev.dev_ops->mode_valid(&intel_dvo->dev, mode); | 235 | return intel_dvo->dev.dev_ops->mode_valid(&intel_dvo->dev, mode); |
236 | } | 236 | } |
237 | 237 | ||
238 | static bool intel_dvo_compute_config(struct intel_encoder *encoder, | 238 | static int intel_dvo_compute_config(struct intel_encoder *encoder, |
239 | struct intel_crtc_state *pipe_config, | 239 | struct intel_crtc_state *pipe_config, |
240 | struct drm_connector_state *conn_state) | 240 | struct drm_connector_state *conn_state) |
241 | { | 241 | { |
242 | struct intel_dvo *intel_dvo = enc_to_dvo(encoder); | 242 | struct intel_dvo *intel_dvo = enc_to_dvo(encoder); |
243 | const struct drm_display_mode *fixed_mode = | 243 | const struct drm_display_mode *fixed_mode = |
@@ -254,10 +254,11 @@ static bool intel_dvo_compute_config(struct intel_encoder *encoder, | |||
254 | intel_fixed_panel_mode(fixed_mode, adjusted_mode); | 254 | intel_fixed_panel_mode(fixed_mode, adjusted_mode); |
255 | 255 | ||
256 | if (adjusted_mode->flags & DRM_MODE_FLAG_DBLSCAN) | 256 | if (adjusted_mode->flags & DRM_MODE_FLAG_DBLSCAN) |
257 | return false; | 257 | return -EINVAL; |
258 | 258 | ||
259 | pipe_config->output_format = INTEL_OUTPUT_FORMAT_RGB; | 259 | pipe_config->output_format = INTEL_OUTPUT_FORMAT_RGB; |
260 | return true; | 260 | |
261 | return 0; | ||
261 | } | 262 | } |
262 | 263 | ||
263 | static void intel_dvo_pre_enable(struct intel_encoder *encoder, | 264 | static void intel_dvo_pre_enable(struct intel_encoder *encoder, |
diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c index 07e803a604bd..1da7bb148fca 100644 --- a/drivers/gpu/drm/i915/intel_hdmi.c +++ b/drivers/gpu/drm/i915/intel_hdmi.c | |||
@@ -479,18 +479,14 @@ static void intel_hdmi_set_avi_infoframe(struct intel_encoder *encoder, | |||
479 | const struct intel_crtc_state *crtc_state, | 479 | const struct intel_crtc_state *crtc_state, |
480 | const struct drm_connector_state *conn_state) | 480 | const struct drm_connector_state *conn_state) |
481 | { | 481 | { |
482 | struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&encoder->base); | ||
483 | const struct drm_display_mode *adjusted_mode = | 482 | const struct drm_display_mode *adjusted_mode = |
484 | &crtc_state->base.adjusted_mode; | 483 | &crtc_state->base.adjusted_mode; |
485 | struct drm_connector *connector = &intel_hdmi->attached_connector->base; | ||
486 | bool is_hdmi2_sink = connector->display_info.hdmi.scdc.supported || | ||
487 | connector->display_info.color_formats & DRM_COLOR_FORMAT_YCRCB420; | ||
488 | union hdmi_infoframe frame; | 484 | union hdmi_infoframe frame; |
489 | int ret; | 485 | int ret; |
490 | 486 | ||
491 | ret = drm_hdmi_avi_infoframe_from_display_mode(&frame.avi, | 487 | ret = drm_hdmi_avi_infoframe_from_display_mode(&frame.avi, |
492 | adjusted_mode, | 488 | conn_state->connector, |
493 | is_hdmi2_sink); | 489 | adjusted_mode); |
494 | if (ret < 0) { | 490 | if (ret < 0) { |
495 | DRM_ERROR("couldn't fill AVI infoframe\n"); | 491 | DRM_ERROR("couldn't fill AVI infoframe\n"); |
496 | return; | 492 | return; |
@@ -503,12 +499,12 @@ static void intel_hdmi_set_avi_infoframe(struct intel_encoder *encoder, | |||
503 | else | 499 | else |
504 | frame.avi.colorspace = HDMI_COLORSPACE_RGB; | 500 | frame.avi.colorspace = HDMI_COLORSPACE_RGB; |
505 | 501 | ||
506 | drm_hdmi_avi_infoframe_quant_range(&frame.avi, adjusted_mode, | 502 | drm_hdmi_avi_infoframe_quant_range(&frame.avi, |
503 | conn_state->connector, | ||
504 | adjusted_mode, | ||
507 | crtc_state->limited_color_range ? | 505 | crtc_state->limited_color_range ? |
508 | HDMI_QUANTIZATION_RANGE_LIMITED : | 506 | HDMI_QUANTIZATION_RANGE_LIMITED : |
509 | HDMI_QUANTIZATION_RANGE_FULL, | 507 | HDMI_QUANTIZATION_RANGE_FULL); |
510 | intel_hdmi->rgb_quant_range_selectable, | ||
511 | is_hdmi2_sink); | ||
512 | 508 | ||
513 | drm_hdmi_avi_infoframe_content_type(&frame.avi, | 509 | drm_hdmi_avi_infoframe_content_type(&frame.avi, |
514 | conn_state); | 510 | conn_state); |
@@ -1707,9 +1703,9 @@ intel_hdmi_ycbcr420_config(struct drm_connector *connector, | |||
1707 | return true; | 1703 | return true; |
1708 | } | 1704 | } |
1709 | 1705 | ||
1710 | bool intel_hdmi_compute_config(struct intel_encoder *encoder, | 1706 | int intel_hdmi_compute_config(struct intel_encoder *encoder, |
1711 | struct intel_crtc_state *pipe_config, | 1707 | struct intel_crtc_state *pipe_config, |
1712 | struct drm_connector_state *conn_state) | 1708 | struct drm_connector_state *conn_state) |
1713 | { | 1709 | { |
1714 | struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&encoder->base); | 1710 | struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&encoder->base); |
1715 | struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); | 1711 | struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); |
@@ -1725,7 +1721,7 @@ bool intel_hdmi_compute_config(struct intel_encoder *encoder, | |||
1725 | bool force_dvi = intel_conn_state->force_audio == HDMI_AUDIO_OFF_DVI; | 1721 | bool force_dvi = intel_conn_state->force_audio == HDMI_AUDIO_OFF_DVI; |
1726 | 1722 | ||
1727 | if (adjusted_mode->flags & DRM_MODE_FLAG_DBLSCAN) | 1723 | if (adjusted_mode->flags & DRM_MODE_FLAG_DBLSCAN) |
1728 | return false; | 1724 | return -EINVAL; |
1729 | 1725 | ||
1730 | pipe_config->output_format = INTEL_OUTPUT_FORMAT_RGB; | 1726 | pipe_config->output_format = INTEL_OUTPUT_FORMAT_RGB; |
1731 | pipe_config->has_hdmi_sink = !force_dvi && intel_hdmi->has_hdmi_sink; | 1727 | pipe_config->has_hdmi_sink = !force_dvi && intel_hdmi->has_hdmi_sink; |
@@ -1756,7 +1752,7 @@ bool intel_hdmi_compute_config(struct intel_encoder *encoder, | |||
1756 | &clock_12bpc, &clock_10bpc, | 1752 | &clock_12bpc, &clock_10bpc, |
1757 | &clock_8bpc)) { | 1753 | &clock_8bpc)) { |
1758 | DRM_ERROR("Can't support YCBCR420 output\n"); | 1754 | DRM_ERROR("Can't support YCBCR420 output\n"); |
1759 | return false; | 1755 | return -EINVAL; |
1760 | } | 1756 | } |
1761 | } | 1757 | } |
1762 | 1758 | ||
@@ -1806,7 +1802,7 @@ bool intel_hdmi_compute_config(struct intel_encoder *encoder, | |||
1806 | if (hdmi_port_clock_valid(intel_hdmi, pipe_config->port_clock, | 1802 | if (hdmi_port_clock_valid(intel_hdmi, pipe_config->port_clock, |
1807 | false, force_dvi) != MODE_OK) { | 1803 | false, force_dvi) != MODE_OK) { |
1808 | DRM_DEBUG_KMS("unsupported HDMI clock, rejecting mode\n"); | 1804 | DRM_DEBUG_KMS("unsupported HDMI clock, rejecting mode\n"); |
1809 | return false; | 1805 | return -EINVAL; |
1810 | } | 1806 | } |
1811 | 1807 | ||
1812 | /* Set user selected PAR to incoming mode's member */ | 1808 | /* Set user selected PAR to incoming mode's member */ |
@@ -1825,7 +1821,7 @@ bool intel_hdmi_compute_config(struct intel_encoder *encoder, | |||
1825 | } | 1821 | } |
1826 | } | 1822 | } |
1827 | 1823 | ||
1828 | return true; | 1824 | return 0; |
1829 | } | 1825 | } |
1830 | 1826 | ||
1831 | static void | 1827 | static void |
@@ -1835,7 +1831,6 @@ intel_hdmi_unset_edid(struct drm_connector *connector) | |||
1835 | 1831 | ||
1836 | intel_hdmi->has_hdmi_sink = false; | 1832 | intel_hdmi->has_hdmi_sink = false; |
1837 | intel_hdmi->has_audio = false; | 1833 | intel_hdmi->has_audio = false; |
1838 | intel_hdmi->rgb_quant_range_selectable = false; | ||
1839 | 1834 | ||
1840 | intel_hdmi->dp_dual_mode.type = DRM_DP_DUAL_MODE_NONE; | 1835 | intel_hdmi->dp_dual_mode.type = DRM_DP_DUAL_MODE_NONE; |
1841 | intel_hdmi->dp_dual_mode.max_tmds_clock = 0; | 1836 | intel_hdmi->dp_dual_mode.max_tmds_clock = 0; |
@@ -1919,9 +1914,6 @@ intel_hdmi_set_edid(struct drm_connector *connector) | |||
1919 | 1914 | ||
1920 | to_intel_connector(connector)->detect_edid = edid; | 1915 | to_intel_connector(connector)->detect_edid = edid; |
1921 | if (edid && edid->input & DRM_EDID_INPUT_DIGITAL) { | 1916 | if (edid && edid->input & DRM_EDID_INPUT_DIGITAL) { |
1922 | intel_hdmi->rgb_quant_range_selectable = | ||
1923 | drm_rgb_quant_range_selectable(edid); | ||
1924 | |||
1925 | intel_hdmi->has_audio = drm_detect_monitor_audio(edid); | 1917 | intel_hdmi->has_audio = drm_detect_monitor_audio(edid); |
1926 | intel_hdmi->has_hdmi_sink = drm_detect_hdmi_monitor(edid); | 1918 | intel_hdmi->has_hdmi_sink = drm_detect_hdmi_monitor(edid); |
1927 | 1919 | ||
diff --git a/drivers/gpu/drm/i915/intel_lspcon.c b/drivers/gpu/drm/i915/intel_lspcon.c index 96a8d9524b0c..7d15be5932e0 100644 --- a/drivers/gpu/drm/i915/intel_lspcon.c +++ b/drivers/gpu/drm/i915/intel_lspcon.c | |||
@@ -462,10 +462,8 @@ void lspcon_set_infoframes(struct intel_encoder *encoder, | |||
462 | uint8_t buf[VIDEO_DIP_DATA_SIZE]; | 462 | uint8_t buf[VIDEO_DIP_DATA_SIZE]; |
463 | struct intel_digital_port *dig_port = enc_to_dig_port(&encoder->base); | 463 | struct intel_digital_port *dig_port = enc_to_dig_port(&encoder->base); |
464 | struct intel_lspcon *lspcon = &dig_port->lspcon; | 464 | struct intel_lspcon *lspcon = &dig_port->lspcon; |
465 | struct intel_dp *intel_dp = &dig_port->dp; | 465 | const struct drm_display_mode *adjusted_mode = |
466 | struct drm_connector *connector = &intel_dp->attached_connector->base; | 466 | &crtc_state->base.adjusted_mode; |
467 | const struct drm_display_mode *mode = &crtc_state->base.adjusted_mode; | ||
468 | bool is_hdmi2_sink = connector->display_info.hdmi.scdc.supported; | ||
469 | 467 | ||
470 | if (!lspcon->active) { | 468 | if (!lspcon->active) { |
471 | DRM_ERROR("Writing infoframes while LSPCON disabled ?\n"); | 469 | DRM_ERROR("Writing infoframes while LSPCON disabled ?\n"); |
@@ -473,7 +471,8 @@ void lspcon_set_infoframes(struct intel_encoder *encoder, | |||
473 | } | 471 | } |
474 | 472 | ||
475 | ret = drm_hdmi_avi_infoframe_from_display_mode(&frame.avi, | 473 | ret = drm_hdmi_avi_infoframe_from_display_mode(&frame.avi, |
476 | mode, is_hdmi2_sink); | 474 | conn_state->connector, |
475 | adjusted_mode); | ||
477 | if (ret < 0) { | 476 | if (ret < 0) { |
478 | DRM_ERROR("couldn't fill AVI infoframe\n"); | 477 | DRM_ERROR("couldn't fill AVI infoframe\n"); |
479 | return; | 478 | return; |
@@ -488,11 +487,12 @@ void lspcon_set_infoframes(struct intel_encoder *encoder, | |||
488 | frame.avi.colorspace = HDMI_COLORSPACE_RGB; | 487 | frame.avi.colorspace = HDMI_COLORSPACE_RGB; |
489 | } | 488 | } |
490 | 489 | ||
491 | drm_hdmi_avi_infoframe_quant_range(&frame.avi, mode, | 490 | drm_hdmi_avi_infoframe_quant_range(&frame.avi, |
491 | conn_state->connector, | ||
492 | adjusted_mode, | ||
492 | crtc_state->limited_color_range ? | 493 | crtc_state->limited_color_range ? |
493 | HDMI_QUANTIZATION_RANGE_LIMITED : | 494 | HDMI_QUANTIZATION_RANGE_LIMITED : |
494 | HDMI_QUANTIZATION_RANGE_FULL, | 495 | HDMI_QUANTIZATION_RANGE_FULL); |
495 | false, is_hdmi2_sink); | ||
496 | 496 | ||
497 | ret = hdmi_infoframe_pack(&frame, buf, sizeof(buf)); | 497 | ret = hdmi_infoframe_pack(&frame, buf, sizeof(buf)); |
498 | if (ret < 0) { | 498 | if (ret < 0) { |
diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c index e6c5d985ea0a..3377d813dbb3 100644 --- a/drivers/gpu/drm/i915/intel_lvds.c +++ b/drivers/gpu/drm/i915/intel_lvds.c | |||
@@ -379,9 +379,9 @@ intel_lvds_mode_valid(struct drm_connector *connector, | |||
379 | return MODE_OK; | 379 | return MODE_OK; |
380 | } | 380 | } |
381 | 381 | ||
382 | static bool intel_lvds_compute_config(struct intel_encoder *intel_encoder, | 382 | static int intel_lvds_compute_config(struct intel_encoder *intel_encoder, |
383 | struct intel_crtc_state *pipe_config, | 383 | struct intel_crtc_state *pipe_config, |
384 | struct drm_connector_state *conn_state) | 384 | struct drm_connector_state *conn_state) |
385 | { | 385 | { |
386 | struct drm_i915_private *dev_priv = to_i915(intel_encoder->base.dev); | 386 | struct drm_i915_private *dev_priv = to_i915(intel_encoder->base.dev); |
387 | struct intel_lvds_encoder *lvds_encoder = | 387 | struct intel_lvds_encoder *lvds_encoder = |
@@ -395,7 +395,7 @@ static bool intel_lvds_compute_config(struct intel_encoder *intel_encoder, | |||
395 | /* Should never happen!! */ | 395 | /* Should never happen!! */ |
396 | if (INTEL_GEN(dev_priv) < 4 && intel_crtc->pipe == 0) { | 396 | if (INTEL_GEN(dev_priv) < 4 && intel_crtc->pipe == 0) { |
397 | DRM_ERROR("Can't support LVDS on pipe A\n"); | 397 | DRM_ERROR("Can't support LVDS on pipe A\n"); |
398 | return false; | 398 | return -EINVAL; |
399 | } | 399 | } |
400 | 400 | ||
401 | if (lvds_encoder->a3_power == LVDS_A3_POWER_UP) | 401 | if (lvds_encoder->a3_power == LVDS_A3_POWER_UP) |
@@ -421,7 +421,7 @@ static bool intel_lvds_compute_config(struct intel_encoder *intel_encoder, | |||
421 | adjusted_mode); | 421 | adjusted_mode); |
422 | 422 | ||
423 | if (adjusted_mode->flags & DRM_MODE_FLAG_DBLSCAN) | 423 | if (adjusted_mode->flags & DRM_MODE_FLAG_DBLSCAN) |
424 | return false; | 424 | return -EINVAL; |
425 | 425 | ||
426 | if (HAS_PCH_SPLIT(dev_priv)) { | 426 | if (HAS_PCH_SPLIT(dev_priv)) { |
427 | pipe_config->has_pch_encoder = true; | 427 | pipe_config->has_pch_encoder = true; |
@@ -440,7 +440,7 @@ static bool intel_lvds_compute_config(struct intel_encoder *intel_encoder, | |||
440 | * user's requested refresh rate. | 440 | * user's requested refresh rate. |
441 | */ | 441 | */ |
442 | 442 | ||
443 | return true; | 443 | return 0; |
444 | } | 444 | } |
445 | 445 | ||
446 | static enum drm_connector_status | 446 | static enum drm_connector_status |
diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c index 5805ec1aba12..4a03b7f67dd5 100644 --- a/drivers/gpu/drm/i915/intel_sdvo.c +++ b/drivers/gpu/drm/i915/intel_sdvo.c | |||
@@ -103,7 +103,6 @@ struct intel_sdvo { | |||
103 | 103 | ||
104 | bool has_hdmi_monitor; | 104 | bool has_hdmi_monitor; |
105 | bool has_hdmi_audio; | 105 | bool has_hdmi_audio; |
106 | bool rgb_quant_range_selectable; | ||
107 | 106 | ||
108 | /* DDC bus used by this SDVO encoder */ | 107 | /* DDC bus used by this SDVO encoder */ |
109 | uint8_t ddc_bus; | 108 | uint8_t ddc_bus; |
@@ -981,29 +980,30 @@ static bool intel_sdvo_write_infoframe(struct intel_sdvo *intel_sdvo, | |||
981 | } | 980 | } |
982 | 981 | ||
983 | static bool intel_sdvo_set_avi_infoframe(struct intel_sdvo *intel_sdvo, | 982 | static bool intel_sdvo_set_avi_infoframe(struct intel_sdvo *intel_sdvo, |
984 | const struct intel_crtc_state *pipe_config) | 983 | const struct intel_crtc_state *pipe_config, |
984 | const struct drm_connector_state *conn_state) | ||
985 | { | 985 | { |
986 | const struct drm_display_mode *adjusted_mode = | ||
987 | &pipe_config->base.adjusted_mode; | ||
986 | uint8_t sdvo_data[HDMI_INFOFRAME_SIZE(AVI)]; | 988 | uint8_t sdvo_data[HDMI_INFOFRAME_SIZE(AVI)]; |
987 | union hdmi_infoframe frame; | 989 | union hdmi_infoframe frame; |
988 | int ret; | 990 | int ret; |
989 | ssize_t len; | 991 | ssize_t len; |
990 | 992 | ||
991 | ret = drm_hdmi_avi_infoframe_from_display_mode(&frame.avi, | 993 | ret = drm_hdmi_avi_infoframe_from_display_mode(&frame.avi, |
992 | &pipe_config->base.adjusted_mode, | 994 | conn_state->connector, |
993 | false); | 995 | adjusted_mode); |
994 | if (ret < 0) { | 996 | if (ret < 0) { |
995 | DRM_ERROR("couldn't fill AVI infoframe\n"); | 997 | DRM_ERROR("couldn't fill AVI infoframe\n"); |
996 | return false; | 998 | return false; |
997 | } | 999 | } |
998 | 1000 | ||
999 | if (intel_sdvo->rgb_quant_range_selectable) { | 1001 | drm_hdmi_avi_infoframe_quant_range(&frame.avi, |
1000 | if (pipe_config->limited_color_range) | 1002 | conn_state->connector, |
1001 | frame.avi.quantization_range = | 1003 | adjusted_mode, |
1002 | HDMI_QUANTIZATION_RANGE_LIMITED; | 1004 | pipe_config->limited_color_range ? |
1003 | else | 1005 | HDMI_QUANTIZATION_RANGE_LIMITED : |
1004 | frame.avi.quantization_range = | 1006 | HDMI_QUANTIZATION_RANGE_FULL); |
1005 | HDMI_QUANTIZATION_RANGE_FULL; | ||
1006 | } | ||
1007 | 1007 | ||
1008 | len = hdmi_infoframe_pack(&frame, sdvo_data, sizeof(sdvo_data)); | 1008 | len = hdmi_infoframe_pack(&frame, sdvo_data, sizeof(sdvo_data)); |
1009 | if (len < 0) | 1009 | if (len < 0) |
@@ -1108,9 +1108,9 @@ static void i9xx_adjust_sdvo_tv_clock(struct intel_crtc_state *pipe_config) | |||
1108 | pipe_config->clock_set = true; | 1108 | pipe_config->clock_set = true; |
1109 | } | 1109 | } |
1110 | 1110 | ||
1111 | static bool intel_sdvo_compute_config(struct intel_encoder *encoder, | 1111 | static int intel_sdvo_compute_config(struct intel_encoder *encoder, |
1112 | struct intel_crtc_state *pipe_config, | 1112 | struct intel_crtc_state *pipe_config, |
1113 | struct drm_connector_state *conn_state) | 1113 | struct drm_connector_state *conn_state) |
1114 | { | 1114 | { |
1115 | struct intel_sdvo *intel_sdvo = to_sdvo(encoder); | 1115 | struct intel_sdvo *intel_sdvo = to_sdvo(encoder); |
1116 | struct intel_sdvo_connector_state *intel_sdvo_state = | 1116 | struct intel_sdvo_connector_state *intel_sdvo_state = |
@@ -1135,7 +1135,7 @@ static bool intel_sdvo_compute_config(struct intel_encoder *encoder, | |||
1135 | */ | 1135 | */ |
1136 | if (IS_TV(intel_sdvo_connector)) { | 1136 | if (IS_TV(intel_sdvo_connector)) { |
1137 | if (!intel_sdvo_set_output_timings_from_mode(intel_sdvo, mode)) | 1137 | if (!intel_sdvo_set_output_timings_from_mode(intel_sdvo, mode)) |
1138 | return false; | 1138 | return -EINVAL; |
1139 | 1139 | ||
1140 | (void) intel_sdvo_get_preferred_input_mode(intel_sdvo, | 1140 | (void) intel_sdvo_get_preferred_input_mode(intel_sdvo, |
1141 | intel_sdvo_connector, | 1141 | intel_sdvo_connector, |
@@ -1145,7 +1145,7 @@ static bool intel_sdvo_compute_config(struct intel_encoder *encoder, | |||
1145 | } else if (IS_LVDS(intel_sdvo_connector)) { | 1145 | } else if (IS_LVDS(intel_sdvo_connector)) { |
1146 | if (!intel_sdvo_set_output_timings_from_mode(intel_sdvo, | 1146 | if (!intel_sdvo_set_output_timings_from_mode(intel_sdvo, |
1147 | intel_sdvo_connector->base.panel.fixed_mode)) | 1147 | intel_sdvo_connector->base.panel.fixed_mode)) |
1148 | return false; | 1148 | return -EINVAL; |
1149 | 1149 | ||
1150 | (void) intel_sdvo_get_preferred_input_mode(intel_sdvo, | 1150 | (void) intel_sdvo_get_preferred_input_mode(intel_sdvo, |
1151 | intel_sdvo_connector, | 1151 | intel_sdvo_connector, |
@@ -1154,7 +1154,7 @@ static bool intel_sdvo_compute_config(struct intel_encoder *encoder, | |||
1154 | } | 1154 | } |
1155 | 1155 | ||
1156 | if (adjusted_mode->flags & DRM_MODE_FLAG_DBLSCAN) | 1156 | if (adjusted_mode->flags & DRM_MODE_FLAG_DBLSCAN) |
1157 | return false; | 1157 | return -EINVAL; |
1158 | 1158 | ||
1159 | /* | 1159 | /* |
1160 | * Make the CRTC code factor in the SDVO pixel multiplier. The | 1160 | * Make the CRTC code factor in the SDVO pixel multiplier. The |
@@ -1194,7 +1194,7 @@ static bool intel_sdvo_compute_config(struct intel_encoder *encoder, | |||
1194 | if (intel_sdvo_connector->is_hdmi) | 1194 | if (intel_sdvo_connector->is_hdmi) |
1195 | adjusted_mode->picture_aspect_ratio = conn_state->picture_aspect_ratio; | 1195 | adjusted_mode->picture_aspect_ratio = conn_state->picture_aspect_ratio; |
1196 | 1196 | ||
1197 | return true; | 1197 | return 0; |
1198 | } | 1198 | } |
1199 | 1199 | ||
1200 | #define UPDATE_PROPERTY(input, NAME) \ | 1200 | #define UPDATE_PROPERTY(input, NAME) \ |
@@ -1316,7 +1316,8 @@ static void intel_sdvo_pre_enable(struct intel_encoder *intel_encoder, | |||
1316 | intel_sdvo_set_encode(intel_sdvo, SDVO_ENCODE_HDMI); | 1316 | intel_sdvo_set_encode(intel_sdvo, SDVO_ENCODE_HDMI); |
1317 | intel_sdvo_set_colorimetry(intel_sdvo, | 1317 | intel_sdvo_set_colorimetry(intel_sdvo, |
1318 | SDVO_COLORIMETRY_RGB256); | 1318 | SDVO_COLORIMETRY_RGB256); |
1319 | intel_sdvo_set_avi_infoframe(intel_sdvo, crtc_state); | 1319 | intel_sdvo_set_avi_infoframe(intel_sdvo, |
1320 | crtc_state, conn_state); | ||
1320 | } else | 1321 | } else |
1321 | intel_sdvo_set_encode(intel_sdvo, SDVO_ENCODE_DVI); | 1322 | intel_sdvo_set_encode(intel_sdvo, SDVO_ENCODE_DVI); |
1322 | 1323 | ||
@@ -1802,8 +1803,6 @@ intel_sdvo_tmds_sink_detect(struct drm_connector *connector) | |||
1802 | if (intel_sdvo_connector->is_hdmi) { | 1803 | if (intel_sdvo_connector->is_hdmi) { |
1803 | intel_sdvo->has_hdmi_monitor = drm_detect_hdmi_monitor(edid); | 1804 | intel_sdvo->has_hdmi_monitor = drm_detect_hdmi_monitor(edid); |
1804 | intel_sdvo->has_hdmi_audio = drm_detect_monitor_audio(edid); | 1805 | intel_sdvo->has_hdmi_audio = drm_detect_monitor_audio(edid); |
1805 | intel_sdvo->rgb_quant_range_selectable = | ||
1806 | drm_rgb_quant_range_selectable(edid); | ||
1807 | } | 1806 | } |
1808 | } else | 1807 | } else |
1809 | status = connector_status_disconnected; | 1808 | status = connector_status_disconnected; |
@@ -1852,7 +1851,6 @@ intel_sdvo_detect(struct drm_connector *connector, bool force) | |||
1852 | 1851 | ||
1853 | intel_sdvo->has_hdmi_monitor = false; | 1852 | intel_sdvo->has_hdmi_monitor = false; |
1854 | intel_sdvo->has_hdmi_audio = false; | 1853 | intel_sdvo->has_hdmi_audio = false; |
1855 | intel_sdvo->rgb_quant_range_selectable = false; | ||
1856 | 1854 | ||
1857 | if ((intel_sdvo_connector->output_flag & response) == 0) | 1855 | if ((intel_sdvo_connector->output_flag & response) == 0) |
1858 | ret = connector_status_disconnected; | 1856 | ret = connector_status_disconnected; |
diff --git a/drivers/gpu/drm/i915/intel_tv.c b/drivers/gpu/drm/i915/intel_tv.c index 860f306a23ba..9bbe35a0f0f2 100644 --- a/drivers/gpu/drm/i915/intel_tv.c +++ b/drivers/gpu/drm/i915/intel_tv.c | |||
@@ -870,7 +870,7 @@ intel_tv_get_config(struct intel_encoder *encoder, | |||
870 | pipe_config->base.adjusted_mode.crtc_clock = pipe_config->port_clock; | 870 | pipe_config->base.adjusted_mode.crtc_clock = pipe_config->port_clock; |
871 | } | 871 | } |
872 | 872 | ||
873 | static bool | 873 | static int |
874 | intel_tv_compute_config(struct intel_encoder *encoder, | 874 | intel_tv_compute_config(struct intel_encoder *encoder, |
875 | struct intel_crtc_state *pipe_config, | 875 | struct intel_crtc_state *pipe_config, |
876 | struct drm_connector_state *conn_state) | 876 | struct drm_connector_state *conn_state) |
@@ -880,10 +880,10 @@ intel_tv_compute_config(struct intel_encoder *encoder, | |||
880 | &pipe_config->base.adjusted_mode; | 880 | &pipe_config->base.adjusted_mode; |
881 | 881 | ||
882 | if (!tv_mode) | 882 | if (!tv_mode) |
883 | return false; | 883 | return -EINVAL; |
884 | 884 | ||
885 | if (adjusted_mode->flags & DRM_MODE_FLAG_DBLSCAN) | 885 | if (adjusted_mode->flags & DRM_MODE_FLAG_DBLSCAN) |
886 | return false; | 886 | return -EINVAL; |
887 | 887 | ||
888 | pipe_config->output_format = INTEL_OUTPUT_FORMAT_RGB; | 888 | pipe_config->output_format = INTEL_OUTPUT_FORMAT_RGB; |
889 | adjusted_mode->crtc_clock = tv_mode->clock; | 889 | adjusted_mode->crtc_clock = tv_mode->clock; |
@@ -898,7 +898,7 @@ intel_tv_compute_config(struct intel_encoder *encoder, | |||
898 | * or whether userspace is doing something stupid. | 898 | * or whether userspace is doing something stupid. |
899 | */ | 899 | */ |
900 | 900 | ||
901 | return true; | 901 | return 0; |
902 | } | 902 | } |
903 | 903 | ||
904 | static void | 904 | static void |
diff --git a/drivers/gpu/drm/i915/vlv_dsi.c b/drivers/gpu/drm/i915/vlv_dsi.c index 361e962a7969..9fc8085f76dc 100644 --- a/drivers/gpu/drm/i915/vlv_dsi.c +++ b/drivers/gpu/drm/i915/vlv_dsi.c | |||
@@ -257,9 +257,9 @@ static void band_gap_reset(struct drm_i915_private *dev_priv) | |||
257 | mutex_unlock(&dev_priv->sb_lock); | 257 | mutex_unlock(&dev_priv->sb_lock); |
258 | } | 258 | } |
259 | 259 | ||
260 | static bool intel_dsi_compute_config(struct intel_encoder *encoder, | 260 | static int intel_dsi_compute_config(struct intel_encoder *encoder, |
261 | struct intel_crtc_state *pipe_config, | 261 | struct intel_crtc_state *pipe_config, |
262 | struct drm_connector_state *conn_state) | 262 | struct drm_connector_state *conn_state) |
263 | { | 263 | { |
264 | struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); | 264 | struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); |
265 | struct intel_dsi *intel_dsi = container_of(encoder, struct intel_dsi, | 265 | struct intel_dsi *intel_dsi = container_of(encoder, struct intel_dsi, |
@@ -285,7 +285,7 @@ static bool intel_dsi_compute_config(struct intel_encoder *encoder, | |||
285 | } | 285 | } |
286 | 286 | ||
287 | if (adjusted_mode->flags & DRM_MODE_FLAG_DBLSCAN) | 287 | if (adjusted_mode->flags & DRM_MODE_FLAG_DBLSCAN) |
288 | return false; | 288 | return -EINVAL; |
289 | 289 | ||
290 | /* DSI uses short packets for sync events, so clear mode flags for DSI */ | 290 | /* DSI uses short packets for sync events, so clear mode flags for DSI */ |
291 | adjusted_mode->flags = 0; | 291 | adjusted_mode->flags = 0; |
@@ -303,16 +303,16 @@ static bool intel_dsi_compute_config(struct intel_encoder *encoder, | |||
303 | 303 | ||
304 | ret = bxt_dsi_pll_compute(encoder, pipe_config); | 304 | ret = bxt_dsi_pll_compute(encoder, pipe_config); |
305 | if (ret) | 305 | if (ret) |
306 | return false; | 306 | return -EINVAL; |
307 | } else { | 307 | } else { |
308 | ret = vlv_dsi_pll_compute(encoder, pipe_config); | 308 | ret = vlv_dsi_pll_compute(encoder, pipe_config); |
309 | if (ret) | 309 | if (ret) |
310 | return false; | 310 | return -EINVAL; |
311 | } | 311 | } |
312 | 312 | ||
313 | pipe_config->clock_set = true; | 313 | pipe_config->clock_set = true; |
314 | 314 | ||
315 | return true; | 315 | return 0; |
316 | } | 316 | } |
317 | 317 | ||
318 | static bool glk_dsi_enable_io(struct intel_encoder *encoder) | 318 | static bool glk_dsi_enable_io(struct intel_encoder *encoder) |
diff --git a/drivers/gpu/drm/mediatek/mtk_hdmi.c b/drivers/gpu/drm/mediatek/mtk_hdmi.c index 994f0d8646bf..12ad00d01063 100644 --- a/drivers/gpu/drm/mediatek/mtk_hdmi.c +++ b/drivers/gpu/drm/mediatek/mtk_hdmi.c | |||
@@ -981,7 +981,8 @@ static int mtk_hdmi_setup_avi_infoframe(struct mtk_hdmi *hdmi, | |||
981 | u8 buffer[17]; | 981 | u8 buffer[17]; |
982 | ssize_t err; | 982 | ssize_t err; |
983 | 983 | ||
984 | err = drm_hdmi_avi_infoframe_from_display_mode(&frame, mode, false); | 984 | err = drm_hdmi_avi_infoframe_from_display_mode(&frame, |
985 | &hdmi->conn, mode); | ||
985 | if (err < 0) { | 986 | if (err < 0) { |
986 | dev_err(hdmi->dev, | 987 | dev_err(hdmi->dev, |
987 | "Failed to get AVI infoframe from mode: %zd\n", err); | 988 | "Failed to get AVI infoframe from mode: %zd\n", err); |
diff --git a/drivers/gpu/drm/meson/meson_drv.c b/drivers/gpu/drm/meson/meson_drv.c index 3ee4d4a4ecba..1e360828ac38 100644 --- a/drivers/gpu/drm/meson/meson_drv.c +++ b/drivers/gpu/drm/meson/meson_drv.c | |||
@@ -152,6 +152,23 @@ static void meson_vpu_init(struct meson_drm *priv) | |||
152 | writel_relaxed(0x20000, priv->io_base + _REG(VPU_WRARB_MODE_L2C1)); | 152 | writel_relaxed(0x20000, priv->io_base + _REG(VPU_WRARB_MODE_L2C1)); |
153 | } | 153 | } |
154 | 154 | ||
155 | static void meson_remove_framebuffers(void) | ||
156 | { | ||
157 | struct apertures_struct *ap; | ||
158 | |||
159 | ap = alloc_apertures(1); | ||
160 | if (!ap) | ||
161 | return; | ||
162 | |||
163 | /* The framebuffer can be located anywhere in RAM */ | ||
164 | ap->ranges[0].base = 0; | ||
165 | ap->ranges[0].size = ~0; | ||
166 | |||
167 | drm_fb_helper_remove_conflicting_framebuffers(ap, "meson-drm-fb", | ||
168 | false); | ||
169 | kfree(ap); | ||
170 | } | ||
171 | |||
155 | static int meson_drv_bind_master(struct device *dev, bool has_components) | 172 | static int meson_drv_bind_master(struct device *dev, bool has_components) |
156 | { | 173 | { |
157 | struct platform_device *pdev = to_platform_device(dev); | 174 | struct platform_device *pdev = to_platform_device(dev); |
@@ -262,6 +279,9 @@ static int meson_drv_bind_master(struct device *dev, bool has_components) | |||
262 | if (ret) | 279 | if (ret) |
263 | goto free_drm; | 280 | goto free_drm; |
264 | 281 | ||
282 | /* Remove early framebuffers (ie. simplefb) */ | ||
283 | meson_remove_framebuffers(); | ||
284 | |||
265 | drm_mode_config_init(drm); | 285 | drm_mode_config_init(drm); |
266 | drm->mode_config.max_width = 3840; | 286 | drm->mode_config.max_width = 3840; |
267 | drm->mode_config.max_height = 2160; | 287 | drm->mode_config.max_height = 2160; |
diff --git a/drivers/gpu/drm/meson/meson_dw_hdmi.c b/drivers/gpu/drm/meson/meson_dw_hdmi.c index 807111ebfdd9..bc25001b8207 100644 --- a/drivers/gpu/drm/meson/meson_dw_hdmi.c +++ b/drivers/gpu/drm/meson/meson_dw_hdmi.c | |||
@@ -365,7 +365,7 @@ static int dw_hdmi_phy_init(struct dw_hdmi *hdmi, void *data, | |||
365 | unsigned int wr_clk = | 365 | unsigned int wr_clk = |
366 | readl_relaxed(priv->io_base + _REG(VPU_HDMI_SETTING)); | 366 | readl_relaxed(priv->io_base + _REG(VPU_HDMI_SETTING)); |
367 | 367 | ||
368 | DRM_DEBUG_DRIVER("%d:\"%s\"\n", mode->base.id, mode->name); | 368 | DRM_DEBUG_DRIVER("\"%s\"\n", mode->name); |
369 | 369 | ||
370 | /* Enable clocks */ | 370 | /* Enable clocks */ |
371 | regmap_update_bits(priv->hhi, HHI_HDMI_CLK_CNTL, 0xffff, 0x100); | 371 | regmap_update_bits(priv->hhi, HHI_HDMI_CLK_CNTL, 0xffff, 0x100); |
@@ -555,12 +555,7 @@ dw_hdmi_mode_valid(struct drm_connector *connector, | |||
555 | int vic = drm_match_cea_mode(mode); | 555 | int vic = drm_match_cea_mode(mode); |
556 | enum drm_mode_status status; | 556 | enum drm_mode_status status; |
557 | 557 | ||
558 | DRM_DEBUG_DRIVER("Modeline %d:\"%s\" %d %d %d %d %d %d %d %d %d %d 0x%x 0x%x\n", | 558 | DRM_DEBUG_DRIVER("Modeline " DRM_MODE_FMT "\n", DRM_MODE_ARG(mode)); |
559 | mode->base.id, mode->name, mode->vrefresh, mode->clock, | ||
560 | mode->hdisplay, mode->hsync_start, | ||
561 | mode->hsync_end, mode->htotal, | ||
562 | mode->vdisplay, mode->vsync_start, | ||
563 | mode->vsync_end, mode->vtotal, mode->type, mode->flags); | ||
564 | 559 | ||
565 | /* Check against non-VIC supported modes */ | 560 | /* Check against non-VIC supported modes */ |
566 | if (!vic) { | 561 | if (!vic) { |
@@ -650,8 +645,7 @@ static void meson_venc_hdmi_encoder_mode_set(struct drm_encoder *encoder, | |||
650 | struct meson_drm *priv = dw_hdmi->priv; | 645 | struct meson_drm *priv = dw_hdmi->priv; |
651 | int vic = drm_match_cea_mode(mode); | 646 | int vic = drm_match_cea_mode(mode); |
652 | 647 | ||
653 | DRM_DEBUG_DRIVER("%d:\"%s\" vic %d\n", | 648 | DRM_DEBUG_DRIVER("\"%s\" vic %d\n", mode->name, vic); |
654 | mode->base.id, mode->name, vic); | ||
655 | 649 | ||
656 | /* VENC + VENC-DVI Mode setup */ | 650 | /* VENC + VENC-DVI Mode setup */ |
657 | meson_venc_hdmi_mode_set(priv, vic, mode); | 651 | meson_venc_hdmi_mode_set(priv, vic, mode); |
diff --git a/drivers/gpu/drm/mgag200/mgag200_fb.c b/drivers/gpu/drm/mgag200/mgag200_fb.c index 30726c9fe28c..6893934b26c0 100644 --- a/drivers/gpu/drm/mgag200/mgag200_fb.c +++ b/drivers/gpu/drm/mgag200/mgag200_fb.c | |||
@@ -12,6 +12,7 @@ | |||
12 | */ | 12 | */ |
13 | #include <linux/module.h> | 13 | #include <linux/module.h> |
14 | #include <drm/drmP.h> | 14 | #include <drm/drmP.h> |
15 | #include <drm/drm_util.h> | ||
15 | #include <drm/drm_fb_helper.h> | 16 | #include <drm/drm_fb_helper.h> |
16 | #include <drm/drm_crtc_helper.h> | 17 | #include <drm/drm_crtc_helper.h> |
17 | 18 | ||
diff --git a/drivers/gpu/drm/msm/disp/mdp4/mdp4_crtc.c b/drivers/gpu/drm/msm/disp/mdp4/mdp4_crtc.c index 8f2359dc87b4..cc32ea5f4289 100644 --- a/drivers/gpu/drm/msm/disp/mdp4/mdp4_crtc.c +++ b/drivers/gpu/drm/msm/disp/mdp4/mdp4_crtc.c | |||
@@ -244,14 +244,8 @@ static void mdp4_crtc_mode_set_nofb(struct drm_crtc *crtc) | |||
244 | 244 | ||
245 | mode = &crtc->state->adjusted_mode; | 245 | mode = &crtc->state->adjusted_mode; |
246 | 246 | ||
247 | DBG("%s: set mode: %d:\"%s\" %d %d %d %d %d %d %d %d %d %d 0x%x 0x%x", | 247 | DBG("%s: set mode: " DRM_MODE_FMT, |
248 | mdp4_crtc->name, mode->base.id, mode->name, | 248 | mdp4_crtc->name, DRM_MODE_ARG(mode)); |
249 | mode->vrefresh, mode->clock, | ||
250 | mode->hdisplay, mode->hsync_start, | ||
251 | mode->hsync_end, mode->htotal, | ||
252 | mode->vdisplay, mode->vsync_start, | ||
253 | mode->vsync_end, mode->vtotal, | ||
254 | mode->type, mode->flags); | ||
255 | 249 | ||
256 | mdp4_write(mdp4_kms, REG_MDP4_DMA_SRC_SIZE(dma), | 250 | mdp4_write(mdp4_kms, REG_MDP4_DMA_SRC_SIZE(dma), |
257 | MDP4_DMA_SRC_SIZE_WIDTH(mode->hdisplay) | | 251 | MDP4_DMA_SRC_SIZE_WIDTH(mode->hdisplay) | |
diff --git a/drivers/gpu/drm/msm/disp/mdp4/mdp4_dsi_encoder.c b/drivers/gpu/drm/msm/disp/mdp4/mdp4_dsi_encoder.c index 6a1ebdace391..48ce218b8463 100644 --- a/drivers/gpu/drm/msm/disp/mdp4/mdp4_dsi_encoder.c +++ b/drivers/gpu/drm/msm/disp/mdp4/mdp4_dsi_encoder.c | |||
@@ -58,14 +58,7 @@ static void mdp4_dsi_encoder_mode_set(struct drm_encoder *encoder, | |||
58 | 58 | ||
59 | mode = adjusted_mode; | 59 | mode = adjusted_mode; |
60 | 60 | ||
61 | DBG("set mode: %d:\"%s\" %d %d %d %d %d %d %d %d %d %d 0x%x 0x%x", | 61 | DBG("set mode: " DRM_MODE_FMT, DRM_MODE_ARG(mode)); |
62 | mode->base.id, mode->name, | ||
63 | mode->vrefresh, mode->clock, | ||
64 | mode->hdisplay, mode->hsync_start, | ||
65 | mode->hsync_end, mode->htotal, | ||
66 | mode->vdisplay, mode->vsync_start, | ||
67 | mode->vsync_end, mode->vtotal, | ||
68 | mode->type, mode->flags); | ||
69 | 62 | ||
70 | ctrl_pol = 0; | 63 | ctrl_pol = 0; |
71 | if (mode->flags & DRM_MODE_FLAG_NHSYNC) | 64 | if (mode->flags & DRM_MODE_FLAG_NHSYNC) |
diff --git a/drivers/gpu/drm/msm/disp/mdp4/mdp4_dtv_encoder.c b/drivers/gpu/drm/msm/disp/mdp4/mdp4_dtv_encoder.c index a8fd14d4846b..ff8f2da160c0 100644 --- a/drivers/gpu/drm/msm/disp/mdp4/mdp4_dtv_encoder.c +++ b/drivers/gpu/drm/msm/disp/mdp4/mdp4_dtv_encoder.c | |||
@@ -104,14 +104,7 @@ static void mdp4_dtv_encoder_mode_set(struct drm_encoder *encoder, | |||
104 | 104 | ||
105 | mode = adjusted_mode; | 105 | mode = adjusted_mode; |
106 | 106 | ||
107 | DBG("set mode: %d:\"%s\" %d %d %d %d %d %d %d %d %d %d 0x%x 0x%x", | 107 | DBG("set mode: " DRM_MODE_FMT, DRM_MODE_ARG(mode)); |
108 | mode->base.id, mode->name, | ||
109 | mode->vrefresh, mode->clock, | ||
110 | mode->hdisplay, mode->hsync_start, | ||
111 | mode->hsync_end, mode->htotal, | ||
112 | mode->vdisplay, mode->vsync_start, | ||
113 | mode->vsync_end, mode->vtotal, | ||
114 | mode->type, mode->flags); | ||
115 | 108 | ||
116 | mdp4_dtv_encoder->pixclock = mode->clock * 1000; | 109 | mdp4_dtv_encoder->pixclock = mode->clock * 1000; |
117 | 110 | ||
diff --git a/drivers/gpu/drm/msm/disp/mdp4/mdp4_lcdc_encoder.c b/drivers/gpu/drm/msm/disp/mdp4/mdp4_lcdc_encoder.c index c9e34501a89e..fff77a4b12c2 100644 --- a/drivers/gpu/drm/msm/disp/mdp4/mdp4_lcdc_encoder.c +++ b/drivers/gpu/drm/msm/disp/mdp4/mdp4_lcdc_encoder.c | |||
@@ -273,14 +273,7 @@ static void mdp4_lcdc_encoder_mode_set(struct drm_encoder *encoder, | |||
273 | 273 | ||
274 | mode = adjusted_mode; | 274 | mode = adjusted_mode; |
275 | 275 | ||
276 | DBG("set mode: %d:\"%s\" %d %d %d %d %d %d %d %d %d %d 0x%x 0x%x", | 276 | DBG("set mode: " DRM_MODE_FMT, DRM_MODE_ARG(mode)); |
277 | mode->base.id, mode->name, | ||
278 | mode->vrefresh, mode->clock, | ||
279 | mode->hdisplay, mode->hsync_start, | ||
280 | mode->hsync_end, mode->htotal, | ||
281 | mode->vdisplay, mode->vsync_start, | ||
282 | mode->vsync_end, mode->vtotal, | ||
283 | mode->type, mode->flags); | ||
284 | 277 | ||
285 | mdp4_lcdc_encoder->pixclock = mode->clock * 1000; | 278 | mdp4_lcdc_encoder->pixclock = mode->clock * 1000; |
286 | 279 | ||
diff --git a/drivers/gpu/drm/msm/disp/mdp5/mdp5_cmd_encoder.c b/drivers/gpu/drm/msm/disp/mdp5/mdp5_cmd_encoder.c index c1962f29ec7d..976585d8bfd6 100644 --- a/drivers/gpu/drm/msm/disp/mdp5/mdp5_cmd_encoder.c +++ b/drivers/gpu/drm/msm/disp/mdp5/mdp5_cmd_encoder.c | |||
@@ -134,14 +134,7 @@ void mdp5_cmd_encoder_mode_set(struct drm_encoder *encoder, | |||
134 | { | 134 | { |
135 | mode = adjusted_mode; | 135 | mode = adjusted_mode; |
136 | 136 | ||
137 | DBG("set mode: %d:\"%s\" %d %d %d %d %d %d %d %d %d %d 0x%x 0x%x", | 137 | DBG("set mode: " DRM_MODE_FMT, DRM_MODE_ARG(mode)); |
138 | mode->base.id, mode->name, | ||
139 | mode->vrefresh, mode->clock, | ||
140 | mode->hdisplay, mode->hsync_start, | ||
141 | mode->hsync_end, mode->htotal, | ||
142 | mode->vdisplay, mode->vsync_start, | ||
143 | mode->vsync_end, mode->vtotal, | ||
144 | mode->type, mode->flags); | ||
145 | pingpong_tearcheck_setup(encoder, mode); | 138 | pingpong_tearcheck_setup(encoder, mode); |
146 | mdp5_crtc_set_pipeline(encoder->crtc); | 139 | mdp5_crtc_set_pipeline(encoder->crtc); |
147 | } | 140 | } |
diff --git a/drivers/gpu/drm/msm/disp/mdp5/mdp5_crtc.c b/drivers/gpu/drm/msm/disp/mdp5/mdp5_crtc.c index c5fde1a4191a..2f95e6525589 100644 --- a/drivers/gpu/drm/msm/disp/mdp5/mdp5_crtc.c +++ b/drivers/gpu/drm/msm/disp/mdp5/mdp5_crtc.c | |||
@@ -384,14 +384,7 @@ static void mdp5_crtc_mode_set_nofb(struct drm_crtc *crtc) | |||
384 | 384 | ||
385 | mode = &crtc->state->adjusted_mode; | 385 | mode = &crtc->state->adjusted_mode; |
386 | 386 | ||
387 | DBG("%s: set mode: %d:\"%s\" %d %d %d %d %d %d %d %d %d %d 0x%x 0x%x", | 387 | DBG("%s: set mode: " DRM_MODE_FMT, crtc->name, DRM_MODE_ARG(mode)); |
388 | crtc->name, mode->base.id, mode->name, | ||
389 | mode->vrefresh, mode->clock, | ||
390 | mode->hdisplay, mode->hsync_start, | ||
391 | mode->hsync_end, mode->htotal, | ||
392 | mode->vdisplay, mode->vsync_start, | ||
393 | mode->vsync_end, mode->vtotal, | ||
394 | mode->type, mode->flags); | ||
395 | 388 | ||
396 | mixer_width = mode->hdisplay; | 389 | mixer_width = mode->hdisplay; |
397 | if (r_mixer) | 390 | if (r_mixer) |
diff --git a/drivers/gpu/drm/msm/disp/mdp5/mdp5_encoder.c b/drivers/gpu/drm/msm/disp/mdp5/mdp5_encoder.c index fcd44d1d1068..d2a56e55e53d 100644 --- a/drivers/gpu/drm/msm/disp/mdp5/mdp5_encoder.c +++ b/drivers/gpu/drm/msm/disp/mdp5/mdp5_encoder.c | |||
@@ -118,14 +118,7 @@ static void mdp5_vid_encoder_mode_set(struct drm_encoder *encoder, | |||
118 | 118 | ||
119 | mode = adjusted_mode; | 119 | mode = adjusted_mode; |
120 | 120 | ||
121 | DBG("set mode: %d:\"%s\" %d %d %d %d %d %d %d %d %d %d 0x%x 0x%x", | 121 | DBG("set mode: " DRM_MODE_FMT, DRM_MODE_ARG(mode)); |
122 | mode->base.id, mode->name, | ||
123 | mode->vrefresh, mode->clock, | ||
124 | mode->hdisplay, mode->hsync_start, | ||
125 | mode->hsync_end, mode->htotal, | ||
126 | mode->vdisplay, mode->vsync_start, | ||
127 | mode->vsync_end, mode->vtotal, | ||
128 | mode->type, mode->flags); | ||
129 | 122 | ||
130 | ctrl_pol = 0; | 123 | ctrl_pol = 0; |
131 | 124 | ||
diff --git a/drivers/gpu/drm/msm/disp/mdp5/mdp5_smp.c b/drivers/gpu/drm/msm/disp/mdp5/mdp5_smp.c index 7cebcb2b3a37..6153514db04c 100644 --- a/drivers/gpu/drm/msm/disp/mdp5/mdp5_smp.c +++ b/drivers/gpu/drm/msm/disp/mdp5/mdp5_smp.c | |||
@@ -16,6 +16,7 @@ | |||
16 | * this program. If not, see <http://www.gnu.org/licenses/>. | 16 | * this program. If not, see <http://www.gnu.org/licenses/>. |
17 | */ | 17 | */ |
18 | 18 | ||
19 | #include <drm/drm_util.h> | ||
19 | 20 | ||
20 | #include "mdp5_kms.h" | 21 | #include "mdp5_kms.h" |
21 | #include "mdp5_smp.h" | 22 | #include "mdp5_smp.h" |
diff --git a/drivers/gpu/drm/msm/dsi/dsi_manager.c b/drivers/gpu/drm/msm/dsi/dsi_manager.c index bdb063b2dc4a..979a8e929341 100644 --- a/drivers/gpu/drm/msm/dsi/dsi_manager.c +++ b/drivers/gpu/drm/msm/dsi/dsi_manager.c | |||
@@ -536,14 +536,7 @@ static void dsi_mgr_bridge_mode_set(struct drm_bridge *bridge, | |||
536 | struct mipi_dsi_host *host = msm_dsi->host; | 536 | struct mipi_dsi_host *host = msm_dsi->host; |
537 | bool is_dual_dsi = IS_DUAL_DSI(); | 537 | bool is_dual_dsi = IS_DUAL_DSI(); |
538 | 538 | ||
539 | DBG("set mode: %d:\"%s\" %d %d %d %d %d %d %d %d %d %d 0x%x 0x%x", | 539 | DBG("set mode: " DRM_MODE_FMT, DRM_MODE_ARG(mode)); |
540 | mode->base.id, mode->name, | ||
541 | mode->vrefresh, mode->clock, | ||
542 | mode->hdisplay, mode->hsync_start, | ||
543 | mode->hsync_end, mode->htotal, | ||
544 | mode->vdisplay, mode->vsync_start, | ||
545 | mode->vsync_end, mode->vtotal, | ||
546 | mode->type, mode->flags); | ||
547 | 540 | ||
548 | if (is_dual_dsi && !IS_MASTER_DSI_LINK(id)) | 541 | if (is_dual_dsi && !IS_MASTER_DSI_LINK(id)) |
549 | return; | 542 | return; |
diff --git a/drivers/gpu/drm/msm/edp/edp_bridge.c b/drivers/gpu/drm/msm/edp/edp_bridge.c index 86366ba03e60..11166bf232ff 100644 --- a/drivers/gpu/drm/msm/edp/edp_bridge.c +++ b/drivers/gpu/drm/msm/edp/edp_bridge.c | |||
@@ -60,14 +60,7 @@ static void edp_bridge_mode_set(struct drm_bridge *bridge, | |||
60 | struct edp_bridge *edp_bridge = to_edp_bridge(bridge); | 60 | struct edp_bridge *edp_bridge = to_edp_bridge(bridge); |
61 | struct msm_edp *edp = edp_bridge->edp; | 61 | struct msm_edp *edp = edp_bridge->edp; |
62 | 62 | ||
63 | DBG("set mode: %d:\"%s\" %d %d %d %d %d %d %d %d %d %d 0x%x 0x%x", | 63 | DBG("set mode: " DRM_MODE_FMT, DRM_MODE_ARG(mode)); |
64 | mode->base.id, mode->name, | ||
65 | mode->vrefresh, mode->clock, | ||
66 | mode->hdisplay, mode->hsync_start, | ||
67 | mode->hsync_end, mode->htotal, | ||
68 | mode->vdisplay, mode->vsync_start, | ||
69 | mode->vsync_end, mode->vtotal, | ||
70 | mode->type, mode->flags); | ||
71 | 64 | ||
72 | list_for_each_entry(connector, &dev->mode_config.connector_list, head) { | 65 | list_for_each_entry(connector, &dev->mode_config.connector_list, head) { |
73 | if ((connector->encoder != NULL) && | 66 | if ((connector->encoder != NULL) && |
diff --git a/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c b/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c index b42feb80531b..03197b8959ba 100644 --- a/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c +++ b/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c | |||
@@ -101,7 +101,8 @@ static void msm_hdmi_config_avi_infoframe(struct hdmi *hdmi) | |||
101 | u32 val; | 101 | u32 val; |
102 | int len; | 102 | int len; |
103 | 103 | ||
104 | drm_hdmi_avi_infoframe_from_display_mode(&frame.avi, mode, false); | 104 | drm_hdmi_avi_infoframe_from_display_mode(&frame.avi, |
105 | hdmi->connector, mode); | ||
105 | 106 | ||
106 | len = hdmi_infoframe_pack(&frame, buffer, sizeof(buffer)); | 107 | len = hdmi_infoframe_pack(&frame, buffer, sizeof(buffer)); |
107 | if (len < 0) { | 108 | if (len < 0) { |
diff --git a/drivers/gpu/drm/mxsfb/mxsfb_drv.c b/drivers/gpu/drm/mxsfb/mxsfb_drv.c index 88ba003979e6..13e778825098 100644 --- a/drivers/gpu/drm/mxsfb/mxsfb_drv.c +++ b/drivers/gpu/drm/mxsfb/mxsfb_drv.c | |||
@@ -263,23 +263,12 @@ static int mxsfb_load(struct drm_device *drm, unsigned long flags) | |||
263 | 263 | ||
264 | drm_kms_helper_poll_init(drm); | 264 | drm_kms_helper_poll_init(drm); |
265 | 265 | ||
266 | mxsfb->fbdev = drm_fbdev_cma_init(drm, 32, | ||
267 | drm->mode_config.num_connector); | ||
268 | if (IS_ERR(mxsfb->fbdev)) { | ||
269 | ret = PTR_ERR(mxsfb->fbdev); | ||
270 | mxsfb->fbdev = NULL; | ||
271 | dev_err(drm->dev, "Failed to init FB CMA area\n"); | ||
272 | goto err_cma; | ||
273 | } | ||
274 | |||
275 | platform_set_drvdata(pdev, drm); | 266 | platform_set_drvdata(pdev, drm); |
276 | 267 | ||
277 | drm_helper_hpd_irq_event(drm); | 268 | drm_helper_hpd_irq_event(drm); |
278 | 269 | ||
279 | return 0; | 270 | return 0; |
280 | 271 | ||
281 | err_cma: | ||
282 | drm_irq_uninstall(drm); | ||
283 | err_irq: | 272 | err_irq: |
284 | drm_panel_detach(mxsfb->panel); | 273 | drm_panel_detach(mxsfb->panel); |
285 | err_vblank: | 274 | err_vblank: |
@@ -290,11 +279,6 @@ err_vblank: | |||
290 | 279 | ||
291 | static void mxsfb_unload(struct drm_device *drm) | 280 | static void mxsfb_unload(struct drm_device *drm) |
292 | { | 281 | { |
293 | struct mxsfb_drm_private *mxsfb = drm->dev_private; | ||
294 | |||
295 | if (mxsfb->fbdev) | ||
296 | drm_fbdev_cma_fini(mxsfb->fbdev); | ||
297 | |||
298 | drm_kms_helper_poll_fini(drm); | 282 | drm_kms_helper_poll_fini(drm); |
299 | drm_mode_config_cleanup(drm); | 283 | drm_mode_config_cleanup(drm); |
300 | 284 | ||
@@ -307,13 +291,6 @@ static void mxsfb_unload(struct drm_device *drm) | |||
307 | pm_runtime_disable(drm->dev); | 291 | pm_runtime_disable(drm->dev); |
308 | } | 292 | } |
309 | 293 | ||
310 | static void mxsfb_lastclose(struct drm_device *drm) | ||
311 | { | ||
312 | struct mxsfb_drm_private *mxsfb = drm->dev_private; | ||
313 | |||
314 | drm_fbdev_cma_restore_mode(mxsfb->fbdev); | ||
315 | } | ||
316 | |||
317 | static void mxsfb_irq_preinstall(struct drm_device *drm) | 294 | static void mxsfb_irq_preinstall(struct drm_device *drm) |
318 | { | 295 | { |
319 | struct mxsfb_drm_private *mxsfb = drm->dev_private; | 296 | struct mxsfb_drm_private *mxsfb = drm->dev_private; |
@@ -347,7 +324,6 @@ static struct drm_driver mxsfb_driver = { | |||
347 | .driver_features = DRIVER_GEM | DRIVER_MODESET | | 324 | .driver_features = DRIVER_GEM | DRIVER_MODESET | |
348 | DRIVER_PRIME | DRIVER_ATOMIC | | 325 | DRIVER_PRIME | DRIVER_ATOMIC | |
349 | DRIVER_HAVE_IRQ, | 326 | DRIVER_HAVE_IRQ, |
350 | .lastclose = mxsfb_lastclose, | ||
351 | .irq_handler = mxsfb_irq_handler, | 327 | .irq_handler = mxsfb_irq_handler, |
352 | .irq_preinstall = mxsfb_irq_preinstall, | 328 | .irq_preinstall = mxsfb_irq_preinstall, |
353 | .irq_uninstall = mxsfb_irq_preinstall, | 329 | .irq_uninstall = mxsfb_irq_preinstall, |
@@ -412,6 +388,8 @@ static int mxsfb_probe(struct platform_device *pdev) | |||
412 | if (ret) | 388 | if (ret) |
413 | goto err_unload; | 389 | goto err_unload; |
414 | 390 | ||
391 | drm_fbdev_generic_setup(drm, 32); | ||
392 | |||
415 | return 0; | 393 | return 0; |
416 | 394 | ||
417 | err_unload: | 395 | err_unload: |
diff --git a/drivers/gpu/drm/mxsfb/mxsfb_drv.h b/drivers/gpu/drm/mxsfb/mxsfb_drv.h index 5d0883fc805b..bedd6801edca 100644 --- a/drivers/gpu/drm/mxsfb/mxsfb_drv.h +++ b/drivers/gpu/drm/mxsfb/mxsfb_drv.h | |||
@@ -37,7 +37,6 @@ struct mxsfb_drm_private { | |||
37 | struct drm_simple_display_pipe pipe; | 37 | struct drm_simple_display_pipe pipe; |
38 | struct drm_connector connector; | 38 | struct drm_connector connector; |
39 | struct drm_panel *panel; | 39 | struct drm_panel *panel; |
40 | struct drm_fbdev_cma *fbdev; | ||
41 | }; | 40 | }; |
42 | 41 | ||
43 | int mxsfb_setup_crtc(struct drm_device *dev); | 42 | int mxsfb_setup_crtc(struct drm_device *dev); |
diff --git a/drivers/gpu/drm/nouveau/dispnv04/tvnv17.c b/drivers/gpu/drm/nouveau/dispnv04/tvnv17.c index 6a4ca139cf5d..8fd8124d72ba 100644 --- a/drivers/gpu/drm/nouveau/dispnv04/tvnv17.c +++ b/drivers/gpu/drm/nouveau/dispnv04/tvnv17.c | |||
@@ -750,7 +750,9 @@ static int nv17_tv_set_property(struct drm_encoder *encoder, | |||
750 | /* Disable the crtc to ensure a full modeset is | 750 | /* Disable the crtc to ensure a full modeset is |
751 | * performed whenever it's turned on again. */ | 751 | * performed whenever it's turned on again. */ |
752 | if (crtc) | 752 | if (crtc) |
753 | drm_crtc_force_disable(crtc); | 753 | drm_crtc_helper_set_mode(crtc, &crtc->mode, |
754 | crtc->x, crtc->y, | ||
755 | crtc->primary->fb); | ||
754 | } | 756 | } |
755 | 757 | ||
756 | return 0; | 758 | return 0; |
diff --git a/drivers/gpu/drm/nouveau/dispnv50/disp.c b/drivers/gpu/drm/nouveau/dispnv50/disp.c index 26af45785939..67107f0b1299 100644 --- a/drivers/gpu/drm/nouveau/dispnv50/disp.c +++ b/drivers/gpu/drm/nouveau/dispnv50/disp.c | |||
@@ -561,7 +561,7 @@ nv50_hdmi_enable(struct drm_encoder *encoder, struct drm_display_mode *mode) | |||
561 | u32 max_ac_packet; | 561 | u32 max_ac_packet; |
562 | union hdmi_infoframe avi_frame; | 562 | union hdmi_infoframe avi_frame; |
563 | union hdmi_infoframe vendor_frame; | 563 | union hdmi_infoframe vendor_frame; |
564 | bool scdc_supported, high_tmds_clock_ratio = false, scrambling = false; | 564 | bool high_tmds_clock_ratio = false, scrambling = false; |
565 | u8 config; | 565 | u8 config; |
566 | int ret; | 566 | int ret; |
567 | int size; | 567 | int size; |
@@ -571,10 +571,9 @@ nv50_hdmi_enable(struct drm_encoder *encoder, struct drm_display_mode *mode) | |||
571 | return; | 571 | return; |
572 | 572 | ||
573 | hdmi = &nv_connector->base.display_info.hdmi; | 573 | hdmi = &nv_connector->base.display_info.hdmi; |
574 | scdc_supported = hdmi->scdc.supported; | ||
575 | 574 | ||
576 | ret = drm_hdmi_avi_infoframe_from_display_mode(&avi_frame.avi, mode, | 575 | ret = drm_hdmi_avi_infoframe_from_display_mode(&avi_frame.avi, |
577 | scdc_supported); | 576 | &nv_connector->base, mode); |
578 | if (!ret) { | 577 | if (!ret) { |
579 | /* We have an AVI InfoFrame, populate it to the display */ | 578 | /* We have an AVI InfoFrame, populate it to the display */ |
580 | args.pwr.avi_infoframe_length | 579 | args.pwr.avi_infoframe_length |
@@ -680,6 +679,8 @@ nv50_msto_payload(struct nv50_msto *msto) | |||
680 | struct nv50_mstm *mstm = mstc->mstm; | 679 | struct nv50_mstm *mstm = mstc->mstm; |
681 | int vcpi = mstc->port->vcpi.vcpi, i; | 680 | int vcpi = mstc->port->vcpi.vcpi, i; |
682 | 681 | ||
682 | WARN_ON(!mutex_is_locked(&mstm->mgr.payload_lock)); | ||
683 | |||
683 | NV_ATOMIC(drm, "%s: vcpi %d\n", msto->encoder.name, vcpi); | 684 | NV_ATOMIC(drm, "%s: vcpi %d\n", msto->encoder.name, vcpi); |
684 | for (i = 0; i < mstm->mgr.max_payloads; i++) { | 685 | for (i = 0; i < mstm->mgr.max_payloads; i++) { |
685 | struct drm_dp_payload *payload = &mstm->mgr.payloads[i]; | 686 | struct drm_dp_payload *payload = &mstm->mgr.payloads[i]; |
@@ -704,14 +705,16 @@ nv50_msto_cleanup(struct nv50_msto *msto) | |||
704 | struct nv50_mstc *mstc = msto->mstc; | 705 | struct nv50_mstc *mstc = msto->mstc; |
705 | struct nv50_mstm *mstm = mstc->mstm; | 706 | struct nv50_mstm *mstm = mstc->mstm; |
706 | 707 | ||
708 | if (!msto->disabled) | ||
709 | return; | ||
710 | |||
707 | NV_ATOMIC(drm, "%s: msto cleanup\n", msto->encoder.name); | 711 | NV_ATOMIC(drm, "%s: msto cleanup\n", msto->encoder.name); |
708 | if (mstc->port && mstc->port->vcpi.vcpi > 0 && !nv50_msto_payload(msto)) | 712 | |
709 | drm_dp_mst_deallocate_vcpi(&mstm->mgr, mstc->port); | 713 | drm_dp_mst_deallocate_vcpi(&mstm->mgr, mstc->port); |
710 | if (msto->disabled) { | 714 | |
711 | msto->mstc = NULL; | 715 | msto->mstc = NULL; |
712 | msto->head = NULL; | 716 | msto->head = NULL; |
713 | msto->disabled = false; | 717 | msto->disabled = false; |
714 | } | ||
715 | } | 718 | } |
716 | 719 | ||
717 | static void | 720 | static void |
@@ -731,8 +734,10 @@ nv50_msto_prepare(struct nv50_msto *msto) | |||
731 | (0x0100 << msto->head->base.index), | 734 | (0x0100 << msto->head->base.index), |
732 | }; | 735 | }; |
733 | 736 | ||
737 | mutex_lock(&mstm->mgr.payload_lock); | ||
738 | |||
734 | NV_ATOMIC(drm, "%s: msto prepare\n", msto->encoder.name); | 739 | NV_ATOMIC(drm, "%s: msto prepare\n", msto->encoder.name); |
735 | if (mstc->port && mstc->port->vcpi.vcpi > 0) { | 740 | if (mstc->port->vcpi.vcpi > 0) { |
736 | struct drm_dp_payload *payload = nv50_msto_payload(msto); | 741 | struct drm_dp_payload *payload = nv50_msto_payload(msto); |
737 | if (payload) { | 742 | if (payload) { |
738 | args.vcpi.start_slot = payload->start_slot; | 743 | args.vcpi.start_slot = payload->start_slot; |
@@ -746,7 +751,9 @@ nv50_msto_prepare(struct nv50_msto *msto) | |||
746 | msto->encoder.name, msto->head->base.base.name, | 751 | msto->encoder.name, msto->head->base.base.name, |
747 | args.vcpi.start_slot, args.vcpi.num_slots, | 752 | args.vcpi.start_slot, args.vcpi.num_slots, |
748 | args.vcpi.pbn, args.vcpi.aligned_pbn); | 753 | args.vcpi.pbn, args.vcpi.aligned_pbn); |
754 | |||
749 | nvif_mthd(&drm->display->disp.object, 0, &args, sizeof(args)); | 755 | nvif_mthd(&drm->display->disp.object, 0, &args, sizeof(args)); |
756 | mutex_unlock(&mstm->mgr.payload_lock); | ||
750 | } | 757 | } |
751 | 758 | ||
752 | static int | 759 | static int |
@@ -754,16 +761,23 @@ nv50_msto_atomic_check(struct drm_encoder *encoder, | |||
754 | struct drm_crtc_state *crtc_state, | 761 | struct drm_crtc_state *crtc_state, |
755 | struct drm_connector_state *conn_state) | 762 | struct drm_connector_state *conn_state) |
756 | { | 763 | { |
757 | struct nv50_mstc *mstc = nv50_mstc(conn_state->connector); | 764 | struct drm_atomic_state *state = crtc_state->state; |
765 | struct drm_connector *connector = conn_state->connector; | ||
766 | struct nv50_mstc *mstc = nv50_mstc(connector); | ||
758 | struct nv50_mstm *mstm = mstc->mstm; | 767 | struct nv50_mstm *mstm = mstc->mstm; |
759 | int bpp = conn_state->connector->display_info.bpc * 3; | 768 | int bpp = connector->display_info.bpc * 3; |
760 | int slots; | 769 | int slots; |
761 | 770 | ||
762 | mstc->pbn = drm_dp_calc_pbn_mode(crtc_state->adjusted_mode.clock, bpp); | 771 | mstc->pbn = drm_dp_calc_pbn_mode(crtc_state->adjusted_mode.clock, |
772 | bpp); | ||
763 | 773 | ||
764 | slots = drm_dp_find_vcpi_slots(&mstm->mgr, mstc->pbn); | 774 | if (drm_atomic_crtc_needs_modeset(crtc_state) && |
765 | if (slots < 0) | 775 | !drm_connector_is_unregistered(connector)) { |
766 | return slots; | 776 | slots = drm_dp_atomic_find_vcpi_slots(state, &mstm->mgr, |
777 | mstc->port, mstc->pbn); | ||
778 | if (slots < 0) | ||
779 | return slots; | ||
780 | } | ||
767 | 781 | ||
768 | return nv50_outp_atomic_check_view(encoder, crtc_state, conn_state, | 782 | return nv50_outp_atomic_check_view(encoder, crtc_state, conn_state, |
769 | mstc->native); | 783 | mstc->native); |
@@ -829,8 +843,7 @@ nv50_msto_disable(struct drm_encoder *encoder) | |||
829 | struct nv50_mstc *mstc = msto->mstc; | 843 | struct nv50_mstc *mstc = msto->mstc; |
830 | struct nv50_mstm *mstm = mstc->mstm; | 844 | struct nv50_mstm *mstm = mstc->mstm; |
831 | 845 | ||
832 | if (mstc->port) | 846 | drm_dp_mst_reset_vcpi_slots(&mstm->mgr, mstc->port); |
833 | drm_dp_mst_reset_vcpi_slots(&mstm->mgr, mstc->port); | ||
834 | 847 | ||
835 | mstm->outp->update(mstm->outp, msto->head->base.index, NULL, 0, 0); | 848 | mstm->outp->update(mstm->outp, msto->head->base.index, NULL, 0, 0); |
836 | mstm->modified = true; | 849 | mstm->modified = true; |
@@ -927,12 +940,43 @@ nv50_mstc_get_modes(struct drm_connector *connector) | |||
927 | return ret; | 940 | return ret; |
928 | } | 941 | } |
929 | 942 | ||
943 | static int | ||
944 | nv50_mstc_atomic_check(struct drm_connector *connector, | ||
945 | struct drm_connector_state *new_conn_state) | ||
946 | { | ||
947 | struct drm_atomic_state *state = new_conn_state->state; | ||
948 | struct nv50_mstc *mstc = nv50_mstc(connector); | ||
949 | struct drm_dp_mst_topology_mgr *mgr = &mstc->mstm->mgr; | ||
950 | struct drm_connector_state *old_conn_state = | ||
951 | drm_atomic_get_old_connector_state(state, connector); | ||
952 | struct drm_crtc_state *crtc_state; | ||
953 | struct drm_crtc *new_crtc = new_conn_state->crtc; | ||
954 | |||
955 | if (!old_conn_state->crtc) | ||
956 | return 0; | ||
957 | |||
958 | /* We only want to free VCPI if this state disables the CRTC on this | ||
959 | * connector | ||
960 | */ | ||
961 | if (new_crtc) { | ||
962 | crtc_state = drm_atomic_get_new_crtc_state(state, new_crtc); | ||
963 | |||
964 | if (!crtc_state || | ||
965 | !drm_atomic_crtc_needs_modeset(crtc_state) || | ||
966 | crtc_state->enable) | ||
967 | return 0; | ||
968 | } | ||
969 | |||
970 | return drm_dp_atomic_release_vcpi_slots(state, mgr, mstc->port); | ||
971 | } | ||
972 | |||
930 | static const struct drm_connector_helper_funcs | 973 | static const struct drm_connector_helper_funcs |
931 | nv50_mstc_help = { | 974 | nv50_mstc_help = { |
932 | .get_modes = nv50_mstc_get_modes, | 975 | .get_modes = nv50_mstc_get_modes, |
933 | .mode_valid = nv50_mstc_mode_valid, | 976 | .mode_valid = nv50_mstc_mode_valid, |
934 | .best_encoder = nv50_mstc_best_encoder, | 977 | .best_encoder = nv50_mstc_best_encoder, |
935 | .atomic_best_encoder = nv50_mstc_atomic_best_encoder, | 978 | .atomic_best_encoder = nv50_mstc_atomic_best_encoder, |
979 | .atomic_check = nv50_mstc_atomic_check, | ||
936 | }; | 980 | }; |
937 | 981 | ||
938 | static enum drm_connector_status | 982 | static enum drm_connector_status |
@@ -942,7 +986,7 @@ nv50_mstc_detect(struct drm_connector *connector, bool force) | |||
942 | enum drm_connector_status conn_status; | 986 | enum drm_connector_status conn_status; |
943 | int ret; | 987 | int ret; |
944 | 988 | ||
945 | if (!mstc->port) | 989 | if (drm_connector_is_unregistered(connector)) |
946 | return connector_status_disconnected; | 990 | return connector_status_disconnected; |
947 | 991 | ||
948 | ret = pm_runtime_get_sync(connector->dev->dev); | 992 | ret = pm_runtime_get_sync(connector->dev->dev); |
@@ -961,7 +1005,10 @@ static void | |||
961 | nv50_mstc_destroy(struct drm_connector *connector) | 1005 | nv50_mstc_destroy(struct drm_connector *connector) |
962 | { | 1006 | { |
963 | struct nv50_mstc *mstc = nv50_mstc(connector); | 1007 | struct nv50_mstc *mstc = nv50_mstc(connector); |
1008 | |||
964 | drm_connector_cleanup(&mstc->connector); | 1009 | drm_connector_cleanup(&mstc->connector); |
1010 | drm_dp_mst_put_port_malloc(mstc->port); | ||
1011 | |||
965 | kfree(mstc); | 1012 | kfree(mstc); |
966 | } | 1013 | } |
967 | 1014 | ||
@@ -1009,6 +1056,7 @@ nv50_mstc_new(struct nv50_mstm *mstm, struct drm_dp_mst_port *port, | |||
1009 | drm_object_attach_property(&mstc->connector.base, dev->mode_config.path_property, 0); | 1056 | drm_object_attach_property(&mstc->connector.base, dev->mode_config.path_property, 0); |
1010 | drm_object_attach_property(&mstc->connector.base, dev->mode_config.tile_property, 0); | 1057 | drm_object_attach_property(&mstc->connector.base, dev->mode_config.tile_property, 0); |
1011 | drm_connector_set_path_property(&mstc->connector, path); | 1058 | drm_connector_set_path_property(&mstc->connector, path); |
1059 | drm_dp_mst_get_port_malloc(port); | ||
1012 | return 0; | 1060 | return 0; |
1013 | } | 1061 | } |
1014 | 1062 | ||
@@ -1073,10 +1121,6 @@ nv50_mstm_destroy_connector(struct drm_dp_mst_topology_mgr *mgr, | |||
1073 | 1121 | ||
1074 | drm_fb_helper_remove_one_connector(&drm->fbcon->helper, &mstc->connector); | 1122 | drm_fb_helper_remove_one_connector(&drm->fbcon->helper, &mstc->connector); |
1075 | 1123 | ||
1076 | drm_modeset_lock(&drm->dev->mode_config.connection_mutex, NULL); | ||
1077 | mstc->port = NULL; | ||
1078 | drm_modeset_unlock(&drm->dev->mode_config.connection_mutex); | ||
1079 | |||
1080 | drm_connector_put(&mstc->connector); | 1124 | drm_connector_put(&mstc->connector); |
1081 | } | 1125 | } |
1082 | 1126 | ||
@@ -1099,11 +1143,8 @@ nv50_mstm_add_connector(struct drm_dp_mst_topology_mgr *mgr, | |||
1099 | int ret; | 1143 | int ret; |
1100 | 1144 | ||
1101 | ret = nv50_mstc_new(mstm, port, path, &mstc); | 1145 | ret = nv50_mstc_new(mstm, port, path, &mstc); |
1102 | if (ret) { | 1146 | if (ret) |
1103 | if (mstc) | ||
1104 | mstc->connector.funcs->destroy(&mstc->connector); | ||
1105 | return NULL; | 1147 | return NULL; |
1106 | } | ||
1107 | 1148 | ||
1108 | return &mstc->connector; | 1149 | return &mstc->connector; |
1109 | } | 1150 | } |
@@ -2117,6 +2158,10 @@ nv50_disp_atomic_check(struct drm_device *dev, struct drm_atomic_state *state) | |||
2117 | return ret; | 2158 | return ret; |
2118 | } | 2159 | } |
2119 | 2160 | ||
2161 | ret = drm_dp_mst_atomic_check(state); | ||
2162 | if (ret) | ||
2163 | return ret; | ||
2164 | |||
2120 | return 0; | 2165 | return 0; |
2121 | } | 2166 | } |
2122 | 2167 | ||
diff --git a/drivers/gpu/drm/nouveau/nouveau_display.c b/drivers/gpu/drm/nouveau/nouveau_display.c index f326ffd86766..5d273a655479 100644 --- a/drivers/gpu/drm/nouveau/nouveau_display.c +++ b/drivers/gpu/drm/nouveau/nouveau_display.c | |||
@@ -453,7 +453,7 @@ nouveau_display_fini(struct drm_device *dev, bool suspend, bool runtime) | |||
453 | if (drm_drv_uses_atomic_modeset(dev)) | 453 | if (drm_drv_uses_atomic_modeset(dev)) |
454 | drm_atomic_helper_shutdown(dev); | 454 | drm_atomic_helper_shutdown(dev); |
455 | else | 455 | else |
456 | drm_crtc_force_disable_all(dev); | 456 | drm_helper_force_disable_all(dev); |
457 | } | 457 | } |
458 | 458 | ||
459 | /* disable flip completion events */ | 459 | /* disable flip completion events */ |
diff --git a/drivers/gpu/drm/omapdrm/omap_connector.c b/drivers/gpu/drm/omapdrm/omap_connector.c index b81302c4bf9e..874d8f3cbff6 100644 --- a/drivers/gpu/drm/omapdrm/omap_connector.c +++ b/drivers/gpu/drm/omapdrm/omap_connector.c | |||
@@ -305,14 +305,9 @@ static int omap_connector_mode_valid(struct drm_connector *connector, | |||
305 | drm_mode_destroy(dev, new_mode); | 305 | drm_mode_destroy(dev, new_mode); |
306 | 306 | ||
307 | done: | 307 | done: |
308 | DBG("connector: mode %s: " | 308 | DBG("connector: mode %s: " DRM_MODE_FMT, |
309 | "%d:\"%s\" %d %d %d %d %d %d %d %d %d %d 0x%x 0x%x", | ||
310 | (ret == MODE_OK) ? "valid" : "invalid", | 309 | (ret == MODE_OK) ? "valid" : "invalid", |
311 | mode->base.id, mode->name, mode->vrefresh, mode->clock, | 310 | DRM_MODE_ARG(mode)); |
312 | mode->hdisplay, mode->hsync_start, | ||
313 | mode->hsync_end, mode->htotal, | ||
314 | mode->vdisplay, mode->vsync_start, | ||
315 | mode->vsync_end, mode->vtotal, mode->type, mode->flags); | ||
316 | 311 | ||
317 | return ret; | 312 | return ret; |
318 | } | 313 | } |
diff --git a/drivers/gpu/drm/omapdrm/omap_crtc.c b/drivers/gpu/drm/omapdrm/omap_crtc.c index caffc547ef97..40acf4ce7c9f 100644 --- a/drivers/gpu/drm/omapdrm/omap_crtc.c +++ b/drivers/gpu/drm/omapdrm/omap_crtc.c | |||
@@ -427,12 +427,8 @@ static void omap_crtc_mode_set_nofb(struct drm_crtc *crtc) | |||
427 | struct omap_crtc *omap_crtc = to_omap_crtc(crtc); | 427 | struct omap_crtc *omap_crtc = to_omap_crtc(crtc); |
428 | struct drm_display_mode *mode = &crtc->state->adjusted_mode; | 428 | struct drm_display_mode *mode = &crtc->state->adjusted_mode; |
429 | 429 | ||
430 | DBG("%s: set mode: %d:\"%s\" %d %d %d %d %d %d %d %d %d %d 0x%x 0x%x", | 430 | DBG("%s: set mode: " DRM_MODE_FMT, |
431 | omap_crtc->name, mode->base.id, mode->name, | 431 | omap_crtc->name, DRM_MODE_ARG(mode)); |
432 | mode->vrefresh, mode->clock, | ||
433 | mode->hdisplay, mode->hsync_start, mode->hsync_end, mode->htotal, | ||
434 | mode->vdisplay, mode->vsync_start, mode->vsync_end, mode->vtotal, | ||
435 | mode->type, mode->flags); | ||
436 | 432 | ||
437 | drm_display_mode_to_videomode(mode, &omap_crtc->vm); | 433 | drm_display_mode_to_videomode(mode, &omap_crtc->vm); |
438 | } | 434 | } |
diff --git a/drivers/gpu/drm/omapdrm/omap_encoder.c b/drivers/gpu/drm/omapdrm/omap_encoder.c index 933ebc9f9faa..148b6b20274f 100644 --- a/drivers/gpu/drm/omapdrm/omap_encoder.c +++ b/drivers/gpu/drm/omapdrm/omap_encoder.c | |||
@@ -76,8 +76,8 @@ static void omap_encoder_hdmi_mode_set(struct drm_encoder *encoder, | |||
76 | struct hdmi_avi_infoframe avi; | 76 | struct hdmi_avi_infoframe avi; |
77 | int r; | 77 | int r; |
78 | 78 | ||
79 | r = drm_hdmi_avi_infoframe_from_display_mode(&avi, adjusted_mode, | 79 | r = drm_hdmi_avi_infoframe_from_display_mode(&avi, connector, |
80 | false); | 80 | adjusted_mode); |
81 | if (r == 0) | 81 | if (r == 0) |
82 | dssdev->ops->hdmi.set_infoframe(dssdev, &avi); | 82 | dssdev->ops->hdmi.set_infoframe(dssdev, &avi); |
83 | } | 83 | } |
diff --git a/drivers/gpu/drm/omapdrm/omap_fbdev.c b/drivers/gpu/drm/omapdrm/omap_fbdev.c index aee99194499f..851c59f07eb1 100644 --- a/drivers/gpu/drm/omapdrm/omap_fbdev.c +++ b/drivers/gpu/drm/omapdrm/omap_fbdev.c | |||
@@ -16,6 +16,7 @@ | |||
16 | */ | 16 | */ |
17 | 17 | ||
18 | #include <drm/drm_crtc.h> | 18 | #include <drm/drm_crtc.h> |
19 | #include <drm/drm_util.h> | ||
19 | #include <drm/drm_fb_helper.h> | 20 | #include <drm/drm_fb_helper.h> |
20 | 21 | ||
21 | #include "omap_drv.h" | 22 | #include "omap_drv.h" |
diff --git a/drivers/gpu/drm/panel/Kconfig b/drivers/gpu/drm/panel/Kconfig index 3f3537719beb..a71f44191273 100644 --- a/drivers/gpu/drm/panel/Kconfig +++ b/drivers/gpu/drm/panel/Kconfig | |||
@@ -204,6 +204,15 @@ config DRM_PANEL_SITRONIX_ST7789V | |||
204 | Say Y here if you want to enable support for the Sitronix | 204 | Say Y here if you want to enable support for the Sitronix |
205 | ST7789V controller for 240x320 LCD panels | 205 | ST7789V controller for 240x320 LCD panels |
206 | 206 | ||
207 | config DRM_PANEL_TPO_TPG110 | ||
208 | tristate "TPO TPG 800x400 panel" | ||
209 | depends on OF && SPI && GPIOLIB | ||
210 | depends on BACKLIGHT_CLASS_DEVICE | ||
211 | help | ||
212 | Say Y here if you want to enable support for TPO TPG110 | ||
213 | 400CH LTPS TFT LCD Single Chip Digital Driver for up to | ||
214 | 800x400 LCD panels. | ||
215 | |||
207 | config DRM_PANEL_TRULY_NT35597_WQXGA | 216 | config DRM_PANEL_TRULY_NT35597_WQXGA |
208 | tristate "Truly WQXGA" | 217 | tristate "Truly WQXGA" |
209 | depends on OF | 218 | depends on OF |
diff --git a/drivers/gpu/drm/panel/Makefile b/drivers/gpu/drm/panel/Makefile index 4396658a7996..cd14ca39c6e0 100644 --- a/drivers/gpu/drm/panel/Makefile +++ b/drivers/gpu/drm/panel/Makefile | |||
@@ -21,4 +21,5 @@ obj-$(CONFIG_DRM_PANEL_SEIKO_43WVF1G) += panel-seiko-43wvf1g.o | |||
21 | obj-$(CONFIG_DRM_PANEL_SHARP_LQ101R1SX01) += panel-sharp-lq101r1sx01.o | 21 | obj-$(CONFIG_DRM_PANEL_SHARP_LQ101R1SX01) += panel-sharp-lq101r1sx01.o |
22 | obj-$(CONFIG_DRM_PANEL_SHARP_LS043T1LE01) += panel-sharp-ls043t1le01.o | 22 | obj-$(CONFIG_DRM_PANEL_SHARP_LS043T1LE01) += panel-sharp-ls043t1le01.o |
23 | obj-$(CONFIG_DRM_PANEL_SITRONIX_ST7789V) += panel-sitronix-st7789v.o | 23 | obj-$(CONFIG_DRM_PANEL_SITRONIX_ST7789V) += panel-sitronix-st7789v.o |
24 | obj-$(CONFIG_DRM_PANEL_TPO_TPG110) += panel-tpo-tpg110.o | ||
24 | obj-$(CONFIG_DRM_PANEL_TRULY_NT35597_WQXGA) += panel-truly-nt35597.o | 25 | obj-$(CONFIG_DRM_PANEL_TRULY_NT35597_WQXGA) += panel-truly-nt35597.o |
diff --git a/drivers/gpu/drm/panel/panel-tpo-tpg110.c b/drivers/gpu/drm/panel/panel-tpo-tpg110.c new file mode 100644 index 000000000000..5a9f8f4d5d24 --- /dev/null +++ b/drivers/gpu/drm/panel/panel-tpo-tpg110.c | |||
@@ -0,0 +1,496 @@ | |||
1 | // SPDX-License-Identifier: GPL-2.0 | ||
2 | /* | ||
3 | * Panel driver for the TPO TPG110 400CH LTPS TFT LCD Single Chip | ||
4 | * Digital Driver. | ||
5 | * | ||
6 | * This chip drives a TFT LCD, so it does not know what kind of | ||
7 | * display is actually connected to it, so the width and height of that | ||
8 | * display needs to be supplied from the machine configuration. | ||
9 | * | ||
10 | * Author: | ||
11 | * Linus Walleij <linus.walleij@linaro.org> | ||
12 | */ | ||
13 | #include <drm/drm_modes.h> | ||
14 | #include <drm/drm_panel.h> | ||
15 | #include <drm/drm_print.h> | ||
16 | |||
17 | #include <linux/backlight.h> | ||
18 | #include <linux/bitops.h> | ||
19 | #include <linux/delay.h> | ||
20 | #include <linux/gpio/consumer.h> | ||
21 | #include <linux/init.h> | ||
22 | #include <linux/kernel.h> | ||
23 | #include <linux/module.h> | ||
24 | #include <linux/platform_device.h> | ||
25 | #include <linux/spi/spi.h> | ||
26 | |||
27 | #define TPG110_TEST 0x00 | ||
28 | #define TPG110_CHIPID 0x01 | ||
29 | #define TPG110_CTRL1 0x02 | ||
30 | #define TPG110_RES_MASK GENMASK(2, 0) | ||
31 | #define TPG110_RES_800X480 0x07 | ||
32 | #define TPG110_RES_640X480 0x06 | ||
33 | #define TPG110_RES_480X272 0x05 | ||
34 | #define TPG110_RES_480X640 0x04 | ||
35 | #define TPG110_RES_480X272_D 0x01 /* Dual scan: outputs 800x480 */ | ||
36 | #define TPG110_RES_400X240_D 0x00 /* Dual scan: outputs 800x480 */ | ||
37 | #define TPG110_CTRL2 0x03 | ||
38 | #define TPG110_CTRL2_PM BIT(0) | ||
39 | #define TPG110_CTRL2_RES_PM_CTRL BIT(7) | ||
40 | |||
41 | /** | ||
42 | * struct tpg110_panel_mode - lookup struct for the supported modes | ||
43 | */ | ||
44 | struct tpg110_panel_mode { | ||
45 | /** | ||
46 | * @name: the name of this panel | ||
47 | */ | ||
48 | const char *name; | ||
49 | /** | ||
50 | * @magic: the magic value from the detection register | ||
51 | */ | ||
52 | u32 magic; | ||
53 | /** | ||
54 | * @mode: the DRM display mode for this panel | ||
55 | */ | ||
56 | struct drm_display_mode mode; | ||
57 | /** | ||
58 | * @bus_flags: the DRM bus flags for this panel e.g. inverted clock | ||
59 | */ | ||
60 | u32 bus_flags; | ||
61 | }; | ||
62 | |||
63 | /** | ||
64 | * struct tpg110 - state container for the TPG110 panel | ||
65 | */ | ||
66 | struct tpg110 { | ||
67 | /** | ||
68 | * @dev: the container device | ||
69 | */ | ||
70 | struct device *dev; | ||
71 | /** | ||
72 | * @spi: the corresponding SPI device | ||
73 | */ | ||
74 | struct spi_device *spi; | ||
75 | /** | ||
76 | * @panel: the DRM panel instance for this device | ||
77 | */ | ||
78 | struct drm_panel panel; | ||
79 | /** | ||
80 | * @backlight: backlight for this panel | ||
81 | */ | ||
82 | struct backlight_device *backlight; | ||
83 | /** | ||
84 | * @panel_type: the panel mode as detected | ||
85 | */ | ||
86 | const struct tpg110_panel_mode *panel_mode; | ||
87 | /** | ||
88 | * @width: the width of this panel in mm | ||
89 | */ | ||
90 | u32 width; | ||
91 | /** | ||
92 | * @height: the height of this panel in mm | ||
93 | */ | ||
94 | u32 height; | ||
95 | /** | ||
96 | * @grestb: reset GPIO line | ||
97 | */ | ||
98 | struct gpio_desc *grestb; | ||
99 | }; | ||
100 | |||
101 | /* | ||
102 | * TPG110 modes, these are the simple modes, the dualscan modes that | ||
103 | * take 400x240 or 480x272 in and display as 800x480 are not listed. | ||
104 | */ | ||
105 | static const struct tpg110_panel_mode tpg110_modes[] = { | ||
106 | { | ||
107 | .name = "800x480 RGB", | ||
108 | .magic = TPG110_RES_800X480, | ||
109 | .mode = { | ||
110 | .clock = 33200, | ||
111 | .hdisplay = 800, | ||
112 | .hsync_start = 800 + 40, | ||
113 | .hsync_end = 800 + 40 + 1, | ||
114 | .htotal = 800 + 40 + 1 + 216, | ||
115 | .vdisplay = 480, | ||
116 | .vsync_start = 480 + 10, | ||
117 | .vsync_end = 480 + 10 + 1, | ||
118 | .vtotal = 480 + 10 + 1 + 35, | ||
119 | .vrefresh = 60, | ||
120 | }, | ||
121 | .bus_flags = DRM_BUS_FLAG_PIXDATA_POSEDGE, | ||
122 | }, | ||
123 | { | ||
124 | .name = "640x480 RGB", | ||
125 | .magic = TPG110_RES_640X480, | ||
126 | .mode = { | ||
127 | .clock = 25200, | ||
128 | .hdisplay = 640, | ||
129 | .hsync_start = 640 + 24, | ||
130 | .hsync_end = 640 + 24 + 1, | ||
131 | .htotal = 640 + 24 + 1 + 136, | ||
132 | .vdisplay = 480, | ||
133 | .vsync_start = 480 + 18, | ||
134 | .vsync_end = 480 + 18 + 1, | ||
135 | .vtotal = 480 + 18 + 1 + 27, | ||
136 | .vrefresh = 60, | ||
137 | }, | ||
138 | .bus_flags = DRM_BUS_FLAG_PIXDATA_POSEDGE, | ||
139 | }, | ||
140 | { | ||
141 | .name = "480x272 RGB", | ||
142 | .magic = TPG110_RES_480X272, | ||
143 | .mode = { | ||
144 | .clock = 9000, | ||
145 | .hdisplay = 480, | ||
146 | .hsync_start = 480 + 2, | ||
147 | .hsync_end = 480 + 2 + 1, | ||
148 | .htotal = 480 + 2 + 1 + 43, | ||
149 | .vdisplay = 272, | ||
150 | .vsync_start = 272 + 2, | ||
151 | .vsync_end = 272 + 2 + 1, | ||
152 | .vtotal = 272 + 2 + 1 + 12, | ||
153 | .vrefresh = 60, | ||
154 | }, | ||
155 | .bus_flags = DRM_BUS_FLAG_PIXDATA_POSEDGE, | ||
156 | }, | ||
157 | { | ||
158 | .name = "480x640 RGB", | ||
159 | .magic = TPG110_RES_480X640, | ||
160 | .mode = { | ||
161 | .clock = 20500, | ||
162 | .hdisplay = 480, | ||
163 | .hsync_start = 480 + 2, | ||
164 | .hsync_end = 480 + 2 + 1, | ||
165 | .htotal = 480 + 2 + 1 + 43, | ||
166 | .vdisplay = 640, | ||
167 | .vsync_start = 640 + 4, | ||
168 | .vsync_end = 640 + 4 + 1, | ||
169 | .vtotal = 640 + 4 + 1 + 8, | ||
170 | .vrefresh = 60, | ||
171 | }, | ||
172 | .bus_flags = DRM_BUS_FLAG_PIXDATA_POSEDGE, | ||
173 | }, | ||
174 | { | ||
175 | .name = "400x240 RGB", | ||
176 | .magic = TPG110_RES_400X240_D, | ||
177 | .mode = { | ||
178 | .clock = 8300, | ||
179 | .hdisplay = 400, | ||
180 | .hsync_start = 400 + 20, | ||
181 | .hsync_end = 400 + 20 + 1, | ||
182 | .htotal = 400 + 20 + 1 + 108, | ||
183 | .vdisplay = 240, | ||
184 | .vsync_start = 240 + 2, | ||
185 | .vsync_end = 240 + 2 + 1, | ||
186 | .vtotal = 240 + 2 + 1 + 20, | ||
187 | .vrefresh = 60, | ||
188 | }, | ||
189 | .bus_flags = DRM_BUS_FLAG_PIXDATA_POSEDGE, | ||
190 | }, | ||
191 | }; | ||
192 | |||
193 | static inline struct tpg110 * | ||
194 | to_tpg110(struct drm_panel *panel) | ||
195 | { | ||
196 | return container_of(panel, struct tpg110, panel); | ||
197 | } | ||
198 | |||
199 | static u8 tpg110_readwrite_reg(struct tpg110 *tpg, bool write, | ||
200 | u8 address, u8 outval) | ||
201 | { | ||
202 | struct spi_message m; | ||
203 | struct spi_transfer t[2]; | ||
204 | u8 buf[2]; | ||
205 | int ret; | ||
206 | |||
207 | spi_message_init(&m); | ||
208 | memset(t, 0, sizeof(t)); | ||
209 | |||
210 | if (write) { | ||
211 | /* | ||
212 | * Clear address bit 0, 1 when writing, just to be sure | ||
213 | * The actual bit indicating a write here is bit 1, bit | ||
214 | * 0 is just surplus to pad it up to 8 bits. | ||
215 | */ | ||
216 | buf[0] = address << 2; | ||
217 | buf[0] &= ~0x03; | ||
218 | buf[1] = outval; | ||
219 | |||
220 | t[0].bits_per_word = 8; | ||
221 | t[0].tx_buf = &buf[0]; | ||
222 | t[0].len = 1; | ||
223 | |||
224 | t[1].tx_buf = &buf[1]; | ||
225 | t[1].len = 1; | ||
226 | t[1].bits_per_word = 8; | ||
227 | } else { | ||
228 | /* Set address bit 0 to 1 to read */ | ||
229 | buf[0] = address << 1; | ||
230 | buf[0] |= 0x01; | ||
231 | |||
232 | /* | ||
233 | * The last bit/clock is Hi-Z turnaround cycle, so we need | ||
234 | * to send only 7 bits here. The 8th bit is the high impedance | ||
235 | * turn-around cycle. | ||
236 | */ | ||
237 | t[0].bits_per_word = 7; | ||
238 | t[0].tx_buf = &buf[0]; | ||
239 | t[0].len = 1; | ||
240 | |||
241 | t[1].rx_buf = &buf[1]; | ||
242 | t[1].len = 1; | ||
243 | t[1].bits_per_word = 8; | ||
244 | } | ||
245 | |||
246 | spi_message_add_tail(&t[0], &m); | ||
247 | spi_message_add_tail(&t[1], &m); | ||
248 | ret = spi_sync(tpg->spi, &m); | ||
249 | if (ret) { | ||
250 | DRM_DEV_ERROR(tpg->dev, "SPI message error %d\n", ret); | ||
251 | return ret; | ||
252 | } | ||
253 | if (write) | ||
254 | return 0; | ||
255 | /* Read */ | ||
256 | return buf[1]; | ||
257 | } | ||
258 | |||
259 | static u8 tpg110_read_reg(struct tpg110 *tpg, u8 address) | ||
260 | { | ||
261 | return tpg110_readwrite_reg(tpg, false, address, 0); | ||
262 | } | ||
263 | |||
264 | static void tpg110_write_reg(struct tpg110 *tpg, u8 address, u8 outval) | ||
265 | { | ||
266 | tpg110_readwrite_reg(tpg, true, address, outval); | ||
267 | } | ||
268 | |||
269 | static int tpg110_startup(struct tpg110 *tpg) | ||
270 | { | ||
271 | u8 val; | ||
272 | int i; | ||
273 | |||
274 | /* De-assert the reset signal */ | ||
275 | gpiod_set_value_cansleep(tpg->grestb, 0); | ||
276 | usleep_range(1000, 2000); | ||
277 | DRM_DEV_DEBUG(tpg->dev, "de-asserted GRESTB\n"); | ||
278 | |||
279 | /* Test display communication */ | ||
280 | tpg110_write_reg(tpg, TPG110_TEST, 0x55); | ||
281 | val = tpg110_read_reg(tpg, TPG110_TEST); | ||
282 | if (val != 0x55) { | ||
283 | DRM_DEV_ERROR(tpg->dev, "failed communication test\n"); | ||
284 | return -ENODEV; | ||
285 | } | ||
286 | |||
287 | val = tpg110_read_reg(tpg, TPG110_CHIPID); | ||
288 | DRM_DEV_INFO(tpg->dev, "TPG110 chip ID: %d version: %d\n", | ||
289 | val >> 4, val & 0x0f); | ||
290 | |||
291 | /* Show display resolution */ | ||
292 | val = tpg110_read_reg(tpg, TPG110_CTRL1); | ||
293 | val &= TPG110_RES_MASK; | ||
294 | switch (val) { | ||
295 | case TPG110_RES_400X240_D: | ||
296 | DRM_DEV_INFO(tpg->dev, | ||
297 | "IN 400x240 RGB -> OUT 800x480 RGB (dual scan)\n"); | ||
298 | break; | ||
299 | case TPG110_RES_480X272_D: | ||
300 | DRM_DEV_INFO(tpg->dev, | ||
301 | "IN 480x272 RGB -> OUT 800x480 RGB (dual scan)\n"); | ||
302 | break; | ||
303 | case TPG110_RES_480X640: | ||
304 | DRM_DEV_INFO(tpg->dev, "480x640 RGB\n"); | ||
305 | break; | ||
306 | case TPG110_RES_480X272: | ||
307 | DRM_DEV_INFO(tpg->dev, "480x272 RGB\n"); | ||
308 | break; | ||
309 | case TPG110_RES_640X480: | ||
310 | DRM_DEV_INFO(tpg->dev, "640x480 RGB\n"); | ||
311 | break; | ||
312 | case TPG110_RES_800X480: | ||
313 | DRM_DEV_INFO(tpg->dev, "800x480 RGB\n"); | ||
314 | break; | ||
315 | default: | ||
316 | DRM_DEV_ERROR(tpg->dev, "ILLEGAL RESOLUTION 0x%02x\n", val); | ||
317 | break; | ||
318 | } | ||
319 | |||
320 | /* From the producer side, this is the same resolution */ | ||
321 | if (val == TPG110_RES_480X272_D) | ||
322 | val = TPG110_RES_480X272; | ||
323 | |||
324 | for (i = 0; i < ARRAY_SIZE(tpg110_modes); i++) { | ||
325 | const struct tpg110_panel_mode *pm; | ||
326 | |||
327 | pm = &tpg110_modes[i]; | ||
328 | if (pm->magic == val) { | ||
329 | tpg->panel_mode = pm; | ||
330 | break; | ||
331 | } | ||
332 | } | ||
333 | if (i == ARRAY_SIZE(tpg110_modes)) { | ||
334 | DRM_DEV_ERROR(tpg->dev, "unsupported mode (%02x) detected\n", | ||
335 | val); | ||
336 | return -ENODEV; | ||
337 | } | ||
338 | |||
339 | val = tpg110_read_reg(tpg, TPG110_CTRL2); | ||
340 | DRM_DEV_INFO(tpg->dev, "resolution and standby is controlled by %s\n", | ||
341 | (val & TPG110_CTRL2_RES_PM_CTRL) ? "software" : "hardware"); | ||
342 | /* Take control over resolution and standby */ | ||
343 | val |= TPG110_CTRL2_RES_PM_CTRL; | ||
344 | tpg110_write_reg(tpg, TPG110_CTRL2, val); | ||
345 | |||
346 | return 0; | ||
347 | } | ||
348 | |||
349 | static int tpg110_disable(struct drm_panel *panel) | ||
350 | { | ||
351 | struct tpg110 *tpg = to_tpg110(panel); | ||
352 | u8 val; | ||
353 | |||
354 | /* Put chip into standby */ | ||
355 | val = tpg110_read_reg(tpg, TPG110_CTRL2_PM); | ||
356 | val &= ~TPG110_CTRL2_PM; | ||
357 | tpg110_write_reg(tpg, TPG110_CTRL2_PM, val); | ||
358 | |||
359 | backlight_disable(tpg->backlight); | ||
360 | |||
361 | return 0; | ||
362 | } | ||
363 | |||
364 | static int tpg110_enable(struct drm_panel *panel) | ||
365 | { | ||
366 | struct tpg110 *tpg = to_tpg110(panel); | ||
367 | u8 val; | ||
368 | |||
369 | backlight_enable(tpg->backlight); | ||
370 | |||
371 | /* Take chip out of standby */ | ||
372 | val = tpg110_read_reg(tpg, TPG110_CTRL2_PM); | ||
373 | val |= TPG110_CTRL2_PM; | ||
374 | tpg110_write_reg(tpg, TPG110_CTRL2_PM, val); | ||
375 | |||
376 | return 0; | ||
377 | } | ||
378 | |||
379 | /** | ||
380 | * tpg110_get_modes() - return the appropriate mode | ||
381 | * @panel: the panel to get the mode for | ||
382 | * | ||
383 | * This currently does not present a forest of modes, instead it | ||
384 | * presents the mode that is configured for the system under use, | ||
385 | * and which is detected by reading the registers of the display. | ||
386 | */ | ||
387 | static int tpg110_get_modes(struct drm_panel *panel) | ||
388 | { | ||
389 | struct drm_connector *connector = panel->connector; | ||
390 | struct tpg110 *tpg = to_tpg110(panel); | ||
391 | struct drm_display_mode *mode; | ||
392 | |||
393 | strncpy(connector->display_info.name, tpg->panel_mode->name, | ||
394 | DRM_DISPLAY_INFO_LEN); | ||
395 | connector->display_info.width_mm = tpg->width; | ||
396 | connector->display_info.height_mm = tpg->height; | ||
397 | connector->display_info.bus_flags = tpg->panel_mode->bus_flags; | ||
398 | |||
399 | mode = drm_mode_duplicate(panel->drm, &tpg->panel_mode->mode); | ||
400 | drm_mode_set_name(mode); | ||
401 | mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED; | ||
402 | |||
403 | mode->width_mm = tpg->width; | ||
404 | mode->height_mm = tpg->height; | ||
405 | |||
406 | drm_mode_probed_add(connector, mode); | ||
407 | |||
408 | return 1; | ||
409 | } | ||
410 | |||
411 | static const struct drm_panel_funcs tpg110_drm_funcs = { | ||
412 | .disable = tpg110_disable, | ||
413 | .enable = tpg110_enable, | ||
414 | .get_modes = tpg110_get_modes, | ||
415 | }; | ||
416 | |||
417 | static int tpg110_probe(struct spi_device *spi) | ||
418 | { | ||
419 | struct device *dev = &spi->dev; | ||
420 | struct device_node *np = dev->of_node; | ||
421 | struct tpg110 *tpg; | ||
422 | int ret; | ||
423 | |||
424 | tpg = devm_kzalloc(dev, sizeof(*tpg), GFP_KERNEL); | ||
425 | if (!tpg) | ||
426 | return -ENOMEM; | ||
427 | tpg->dev = dev; | ||
428 | |||
429 | /* We get the physical display dimensions from the DT */ | ||
430 | ret = of_property_read_u32(np, "width-mm", &tpg->width); | ||
431 | if (ret) | ||
432 | DRM_DEV_ERROR(dev, "no panel width specified\n"); | ||
433 | ret = of_property_read_u32(np, "height-mm", &tpg->height); | ||
434 | if (ret) | ||
435 | DRM_DEV_ERROR(dev, "no panel height specified\n"); | ||
436 | |||
437 | /* Look for some optional backlight */ | ||
438 | tpg->backlight = devm_of_find_backlight(dev); | ||
439 | if (IS_ERR(tpg->backlight)) | ||
440 | return PTR_ERR(tpg->backlight); | ||
441 | |||
442 | /* This asserts the GRESTB signal, putting the display into reset */ | ||
443 | tpg->grestb = devm_gpiod_get(dev, "grestb", GPIOD_OUT_HIGH); | ||
444 | if (IS_ERR(tpg->grestb)) { | ||
445 | DRM_DEV_ERROR(dev, "no GRESTB GPIO\n"); | ||
446 | return -ENODEV; | ||
447 | } | ||
448 | |||
449 | spi->bits_per_word = 8; | ||
450 | spi->mode |= SPI_3WIRE_HIZ; | ||
451 | ret = spi_setup(spi); | ||
452 | if (ret < 0) { | ||
453 | DRM_DEV_ERROR(dev, "spi setup failed.\n"); | ||
454 | return ret; | ||
455 | } | ||
456 | tpg->spi = spi; | ||
457 | |||
458 | ret = tpg110_startup(tpg); | ||
459 | if (ret) | ||
460 | return ret; | ||
461 | |||
462 | drm_panel_init(&tpg->panel); | ||
463 | tpg->panel.dev = dev; | ||
464 | tpg->panel.funcs = &tpg110_drm_funcs; | ||
465 | spi_set_drvdata(spi, tpg); | ||
466 | |||
467 | return drm_panel_add(&tpg->panel); | ||
468 | } | ||
469 | |||
470 | static int tpg110_remove(struct spi_device *spi) | ||
471 | { | ||
472 | struct tpg110 *tpg = spi_get_drvdata(spi); | ||
473 | |||
474 | drm_panel_remove(&tpg->panel); | ||
475 | return 0; | ||
476 | } | ||
477 | |||
478 | static const struct of_device_id tpg110_match[] = { | ||
479 | { .compatible = "tpo,tpg110", }, | ||
480 | {}, | ||
481 | }; | ||
482 | MODULE_DEVICE_TABLE(of, tpg110_match); | ||
483 | |||
484 | static struct spi_driver tpg110_driver = { | ||
485 | .probe = tpg110_probe, | ||
486 | .remove = tpg110_remove, | ||
487 | .driver = { | ||
488 | .name = "tpo-tpg110-panel", | ||
489 | .of_match_table = tpg110_match, | ||
490 | }, | ||
491 | }; | ||
492 | module_spi_driver(tpg110_driver); | ||
493 | |||
494 | MODULE_AUTHOR("Linus Walleij <linus.walleij@linaro.org>"); | ||
495 | MODULE_DESCRIPTION("TPO TPG110 panel driver"); | ||
496 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/drivers/gpu/drm/qxl/qxl_cmd.c b/drivers/gpu/drm/qxl/qxl_cmd.c index dffc5093ff16..2e100f644236 100644 --- a/drivers/gpu/drm/qxl/qxl_cmd.c +++ b/drivers/gpu/drm/qxl/qxl_cmd.c | |||
@@ -25,6 +25,8 @@ | |||
25 | 25 | ||
26 | /* QXL cmd/ring handling */ | 26 | /* QXL cmd/ring handling */ |
27 | 27 | ||
28 | #include <drm/drm_util.h> | ||
29 | |||
28 | #include "qxl_drv.h" | 30 | #include "qxl_drv.h" |
29 | #include "qxl_object.h" | 31 | #include "qxl_object.h" |
30 | 32 | ||
diff --git a/drivers/gpu/drm/qxl/qxl_display.c b/drivers/gpu/drm/qxl/qxl_display.c index 72a1784dae54..1f8fddcc34d6 100644 --- a/drivers/gpu/drm/qxl/qxl_display.c +++ b/drivers/gpu/drm/qxl/qxl_display.c | |||
@@ -48,8 +48,8 @@ static int qxl_alloc_client_monitors_config(struct qxl_device *qdev, | |||
48 | } | 48 | } |
49 | if (!qdev->client_monitors_config) { | 49 | if (!qdev->client_monitors_config) { |
50 | qdev->client_monitors_config = kzalloc( | 50 | qdev->client_monitors_config = kzalloc( |
51 | sizeof(struct qxl_monitors_config) + | 51 | struct_size(qdev->client_monitors_config, |
52 | sizeof(struct qxl_head) * count, GFP_KERNEL); | 52 | heads, count), GFP_KERNEL); |
53 | if (!qdev->client_monitors_config) | 53 | if (!qdev->client_monitors_config) |
54 | return -ENOMEM; | 54 | return -ENOMEM; |
55 | } | 55 | } |
diff --git a/drivers/gpu/drm/radeon/atom.c b/drivers/gpu/drm/radeon/atom.c index e55cbeee7a53..ac98ad561870 100644 --- a/drivers/gpu/drm/radeon/atom.c +++ b/drivers/gpu/drm/radeon/atom.c | |||
@@ -27,6 +27,8 @@ | |||
27 | #include <linux/slab.h> | 27 | #include <linux/slab.h> |
28 | #include <asm/unaligned.h> | 28 | #include <asm/unaligned.h> |
29 | 29 | ||
30 | #include <drm/drm_util.h> | ||
31 | |||
30 | #define ATOM_DEBUG | 32 | #define ATOM_DEBUG |
31 | 33 | ||
32 | #include "atom.h" | 34 | #include "atom.h" |
diff --git a/drivers/gpu/drm/radeon/radeon_audio.c b/drivers/gpu/drm/radeon/radeon_audio.c index 770e31f5fd1b..96f71114237a 100644 --- a/drivers/gpu/drm/radeon/radeon_audio.c +++ b/drivers/gpu/drm/radeon/radeon_audio.c | |||
@@ -516,21 +516,17 @@ static int radeon_audio_set_avi_packet(struct drm_encoder *encoder, | |||
516 | if (!connector) | 516 | if (!connector) |
517 | return -EINVAL; | 517 | return -EINVAL; |
518 | 518 | ||
519 | err = drm_hdmi_avi_infoframe_from_display_mode(&frame, mode, false); | 519 | err = drm_hdmi_avi_infoframe_from_display_mode(&frame, connector, mode); |
520 | if (err < 0) { | 520 | if (err < 0) { |
521 | DRM_ERROR("failed to setup AVI infoframe: %d\n", err); | 521 | DRM_ERROR("failed to setup AVI infoframe: %d\n", err); |
522 | return err; | 522 | return err; |
523 | } | 523 | } |
524 | 524 | ||
525 | if (radeon_encoder->output_csc != RADEON_OUTPUT_CSC_BYPASS) { | 525 | if (radeon_encoder->output_csc != RADEON_OUTPUT_CSC_BYPASS) { |
526 | if (drm_rgb_quant_range_selectable(radeon_connector_edid(connector))) { | 526 | drm_hdmi_avi_infoframe_quant_range(&frame, connector, mode, |
527 | if (radeon_encoder->output_csc == RADEON_OUTPUT_CSC_TVRGB) | 527 | radeon_encoder->output_csc == RADEON_OUTPUT_CSC_TVRGB ? |
528 | frame.quantization_range = HDMI_QUANTIZATION_RANGE_LIMITED; | 528 | HDMI_QUANTIZATION_RANGE_LIMITED : |
529 | else | 529 | HDMI_QUANTIZATION_RANGE_FULL); |
530 | frame.quantization_range = HDMI_QUANTIZATION_RANGE_FULL; | ||
531 | } else { | ||
532 | frame.quantization_range = HDMI_QUANTIZATION_RANGE_DEFAULT; | ||
533 | } | ||
534 | } | 530 | } |
535 | 531 | ||
536 | err = hdmi_avi_infoframe_pack(&frame, buffer, sizeof(buffer)); | 532 | err = hdmi_avi_infoframe_pack(&frame, buffer, sizeof(buffer)); |
diff --git a/drivers/gpu/drm/radeon/radeon_display.c b/drivers/gpu/drm/radeon/radeon_display.c index 9d3ac8b981da..b190478ad087 100644 --- a/drivers/gpu/drm/radeon/radeon_display.c +++ b/drivers/gpu/drm/radeon/radeon_display.c | |||
@@ -1646,7 +1646,7 @@ void radeon_modeset_fini(struct radeon_device *rdev) | |||
1646 | if (rdev->mode_info.mode_config_initialized) { | 1646 | if (rdev->mode_info.mode_config_initialized) { |
1647 | drm_kms_helper_poll_fini(rdev->ddev); | 1647 | drm_kms_helper_poll_fini(rdev->ddev); |
1648 | radeon_hpd_fini(rdev); | 1648 | radeon_hpd_fini(rdev); |
1649 | drm_crtc_force_disable_all(rdev->ddev); | 1649 | drm_helper_force_disable_all(rdev->ddev); |
1650 | radeon_fbdev_fini(rdev); | 1650 | radeon_fbdev_fini(rdev); |
1651 | radeon_afmt_fini(rdev); | 1651 | radeon_afmt_fini(rdev); |
1652 | drm_mode_config_cleanup(rdev->ddev); | 1652 | drm_mode_config_cleanup(rdev->ddev); |
diff --git a/drivers/gpu/drm/radeon/radeon_legacy_encoders.c b/drivers/gpu/drm/radeon/radeon_legacy_encoders.c index 222a1fa41d7c..7e3257e8fd56 100644 --- a/drivers/gpu/drm/radeon/radeon_legacy_encoders.c +++ b/drivers/gpu/drm/radeon/radeon_legacy_encoders.c | |||
@@ -24,6 +24,7 @@ | |||
24 | * Alex Deucher | 24 | * Alex Deucher |
25 | */ | 25 | */ |
26 | #include <drm/drmP.h> | 26 | #include <drm/drmP.h> |
27 | #include <drm/drm_util.h> | ||
27 | #include <drm/drm_crtc_helper.h> | 28 | #include <drm/drm_crtc_helper.h> |
28 | #include <drm/radeon_drm.h> | 29 | #include <drm/radeon_drm.h> |
29 | #include "radeon.h" | 30 | #include "radeon.h" |
diff --git a/drivers/gpu/drm/rcar-du/rcar_dw_hdmi.c b/drivers/gpu/drm/rcar-du/rcar_dw_hdmi.c index 603bb340e8cf..452461dc96f2 100644 --- a/drivers/gpu/drm/rcar-du/rcar_dw_hdmi.c +++ b/drivers/gpu/drm/rcar-du/rcar_dw_hdmi.c | |||
@@ -7,10 +7,12 @@ | |||
7 | * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com) | 7 | * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com) |
8 | */ | 8 | */ |
9 | 9 | ||
10 | #include <linux/mod_devicetable.h> | ||
10 | #include <linux/module.h> | 11 | #include <linux/module.h> |
11 | #include <linux/platform_device.h> | 12 | #include <linux/platform_device.h> |
12 | 13 | ||
13 | #include <drm/bridge/dw_hdmi.h> | 14 | #include <drm/bridge/dw_hdmi.h> |
15 | #include <drm/drm_modes.h> | ||
14 | 16 | ||
15 | #define RCAR_HDMI_PHY_OPMODE_PLLCFG 0x06 /* Mode of operation and PLL dividers */ | 17 | #define RCAR_HDMI_PHY_OPMODE_PLLCFG 0x06 /* Mode of operation and PLL dividers */ |
16 | #define RCAR_HDMI_PHY_PLLCURRGMPCTRL 0x10 /* PLL current and Gmp (conductance) */ | 18 | #define RCAR_HDMI_PHY_PLLCURRGMPCTRL 0x10 /* PLL current and Gmp (conductance) */ |
diff --git a/drivers/gpu/drm/rockchip/inno_hdmi.c b/drivers/gpu/drm/rockchip/inno_hdmi.c index 1c02b3e61299..27c945e030a0 100644 --- a/drivers/gpu/drm/rockchip/inno_hdmi.c +++ b/drivers/gpu/drm/rockchip/inno_hdmi.c | |||
@@ -295,7 +295,9 @@ static int inno_hdmi_config_video_avi(struct inno_hdmi *hdmi, | |||
295 | union hdmi_infoframe frame; | 295 | union hdmi_infoframe frame; |
296 | int rc; | 296 | int rc; |
297 | 297 | ||
298 | rc = drm_hdmi_avi_infoframe_from_display_mode(&frame.avi, mode, false); | 298 | rc = drm_hdmi_avi_infoframe_from_display_mode(&frame.avi, |
299 | &hdmi->connector, | ||
300 | mode); | ||
299 | 301 | ||
300 | if (hdmi->hdmi_data.enc_out_format == HDMI_COLORSPACE_YUV444) | 302 | if (hdmi->hdmi_data.enc_out_format == HDMI_COLORSPACE_YUV444) |
301 | frame.avi.colorspace = HDMI_COLORSPACE_YUV444; | 303 | frame.avi.colorspace = HDMI_COLORSPACE_YUV444; |
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_fb.c b/drivers/gpu/drm/rockchip/rockchip_drm_fb.c index ea18cb2a76c0..08bec50d9c5d 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_fb.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_fb.c | |||
@@ -128,42 +128,6 @@ err_gem_object_unreference: | |||
128 | } | 128 | } |
129 | 129 | ||
130 | static void | 130 | static void |
131 | rockchip_drm_psr_inhibit_get_state(struct drm_atomic_state *state) | ||
132 | { | ||
133 | struct drm_crtc *crtc; | ||
134 | struct drm_crtc_state *crtc_state; | ||
135 | struct drm_encoder *encoder; | ||
136 | u32 encoder_mask = 0; | ||
137 | int i; | ||
138 | |||
139 | for_each_old_crtc_in_state(state, crtc, crtc_state, i) { | ||
140 | encoder_mask |= crtc_state->encoder_mask; | ||
141 | encoder_mask |= crtc->state->encoder_mask; | ||
142 | } | ||
143 | |||
144 | drm_for_each_encoder_mask(encoder, state->dev, encoder_mask) | ||
145 | rockchip_drm_psr_inhibit_get(encoder); | ||
146 | } | ||
147 | |||
148 | static void | ||
149 | rockchip_drm_psr_inhibit_put_state(struct drm_atomic_state *state) | ||
150 | { | ||
151 | struct drm_crtc *crtc; | ||
152 | struct drm_crtc_state *crtc_state; | ||
153 | struct drm_encoder *encoder; | ||
154 | u32 encoder_mask = 0; | ||
155 | int i; | ||
156 | |||
157 | for_each_old_crtc_in_state(state, crtc, crtc_state, i) { | ||
158 | encoder_mask |= crtc_state->encoder_mask; | ||
159 | encoder_mask |= crtc->state->encoder_mask; | ||
160 | } | ||
161 | |||
162 | drm_for_each_encoder_mask(encoder, state->dev, encoder_mask) | ||
163 | rockchip_drm_psr_inhibit_put(encoder); | ||
164 | } | ||
165 | |||
166 | static void | ||
167 | rockchip_atomic_helper_commit_tail_rpm(struct drm_atomic_state *old_state) | 131 | rockchip_atomic_helper_commit_tail_rpm(struct drm_atomic_state *old_state) |
168 | { | 132 | { |
169 | struct drm_device *dev = old_state->dev; | 133 | struct drm_device *dev = old_state->dev; |
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_psr.c b/drivers/gpu/drm/rockchip/rockchip_drm_psr.c index 01ff3c858875..22a70ab6e214 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_psr.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_psr.c | |||
@@ -13,6 +13,7 @@ | |||
13 | */ | 13 | */ |
14 | 14 | ||
15 | #include <drm/drmP.h> | 15 | #include <drm/drmP.h> |
16 | #include <drm/drm_atomic.h> | ||
16 | #include <drm/drm_crtc_helper.h> | 17 | #include <drm/drm_crtc_helper.h> |
17 | 18 | ||
18 | #include "rockchip_drm_drv.h" | 19 | #include "rockchip_drm_drv.h" |
@@ -109,6 +110,42 @@ int rockchip_drm_psr_inhibit_put(struct drm_encoder *encoder) | |||
109 | } | 110 | } |
110 | EXPORT_SYMBOL(rockchip_drm_psr_inhibit_put); | 111 | EXPORT_SYMBOL(rockchip_drm_psr_inhibit_put); |
111 | 112 | ||
113 | void rockchip_drm_psr_inhibit_get_state(struct drm_atomic_state *state) | ||
114 | { | ||
115 | struct drm_crtc *crtc; | ||
116 | struct drm_crtc_state *crtc_state; | ||
117 | struct drm_encoder *encoder; | ||
118 | u32 encoder_mask = 0; | ||
119 | int i; | ||
120 | |||
121 | for_each_old_crtc_in_state(state, crtc, crtc_state, i) { | ||
122 | encoder_mask |= crtc_state->encoder_mask; | ||
123 | encoder_mask |= crtc->state->encoder_mask; | ||
124 | } | ||
125 | |||
126 | drm_for_each_encoder_mask(encoder, state->dev, encoder_mask) | ||
127 | rockchip_drm_psr_inhibit_get(encoder); | ||
128 | } | ||
129 | EXPORT_SYMBOL(rockchip_drm_psr_inhibit_get_state); | ||
130 | |||
131 | void rockchip_drm_psr_inhibit_put_state(struct drm_atomic_state *state) | ||
132 | { | ||
133 | struct drm_crtc *crtc; | ||
134 | struct drm_crtc_state *crtc_state; | ||
135 | struct drm_encoder *encoder; | ||
136 | u32 encoder_mask = 0; | ||
137 | int i; | ||
138 | |||
139 | for_each_old_crtc_in_state(state, crtc, crtc_state, i) { | ||
140 | encoder_mask |= crtc_state->encoder_mask; | ||
141 | encoder_mask |= crtc->state->encoder_mask; | ||
142 | } | ||
143 | |||
144 | drm_for_each_encoder_mask(encoder, state->dev, encoder_mask) | ||
145 | rockchip_drm_psr_inhibit_put(encoder); | ||
146 | } | ||
147 | EXPORT_SYMBOL(rockchip_drm_psr_inhibit_put_state); | ||
148 | |||
112 | /** | 149 | /** |
113 | * rockchip_drm_psr_inhibit_get - acquire PSR inhibit on given encoder | 150 | * rockchip_drm_psr_inhibit_get - acquire PSR inhibit on given encoder |
114 | * @encoder: encoder to obtain the PSR encoder | 151 | * @encoder: encoder to obtain the PSR encoder |
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_psr.h b/drivers/gpu/drm/rockchip/rockchip_drm_psr.h index 860c62494496..25350ba3237b 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_psr.h +++ b/drivers/gpu/drm/rockchip/rockchip_drm_psr.h | |||
@@ -20,6 +20,9 @@ void rockchip_drm_psr_flush_all(struct drm_device *dev); | |||
20 | int rockchip_drm_psr_inhibit_put(struct drm_encoder *encoder); | 20 | int rockchip_drm_psr_inhibit_put(struct drm_encoder *encoder); |
21 | int rockchip_drm_psr_inhibit_get(struct drm_encoder *encoder); | 21 | int rockchip_drm_psr_inhibit_get(struct drm_encoder *encoder); |
22 | 22 | ||
23 | void rockchip_drm_psr_inhibit_get_state(struct drm_atomic_state *state); | ||
24 | void rockchip_drm_psr_inhibit_put_state(struct drm_atomic_state *state); | ||
25 | |||
23 | int rockchip_drm_psr_register(struct drm_encoder *encoder, | 26 | int rockchip_drm_psr_register(struct drm_encoder *encoder, |
24 | int (*psr_set)(struct drm_encoder *, bool enable)); | 27 | int (*psr_set)(struct drm_encoder *, bool enable)); |
25 | void rockchip_drm_psr_unregister(struct drm_encoder *encoder); | 28 | void rockchip_drm_psr_unregister(struct drm_encoder *encoder); |
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c index db8358e6d230..619b6db05d58 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c | |||
@@ -15,6 +15,7 @@ | |||
15 | #include <drm/drm.h> | 15 | #include <drm/drm.h> |
16 | #include <drm/drmP.h> | 16 | #include <drm/drmP.h> |
17 | #include <drm/drm_atomic.h> | 17 | #include <drm/drm_atomic.h> |
18 | #include <drm/drm_atomic_uapi.h> | ||
18 | #include <drm/drm_crtc.h> | 19 | #include <drm/drm_crtc.h> |
19 | #include <drm/drm_crtc_helper.h> | 20 | #include <drm/drm_crtc_helper.h> |
20 | #include <drm/drm_flip_work.h> | 21 | #include <drm/drm_flip_work.h> |
@@ -45,14 +46,26 @@ | |||
45 | #include "rockchip_drm_vop.h" | 46 | #include "rockchip_drm_vop.h" |
46 | #include "rockchip_rgb.h" | 47 | #include "rockchip_rgb.h" |
47 | 48 | ||
48 | #define VOP_WIN_SET(x, win, name, v) \ | 49 | #define VOP_WIN_SET(vop, win, name, v) \ |
49 | vop_reg_set(vop, &win->phy->name, win->base, ~0, v, #name) | 50 | vop_reg_set(vop, &win->phy->name, win->base, ~0, v, #name) |
50 | #define VOP_SCL_SET(x, win, name, v) \ | 51 | #define VOP_SCL_SET(vop, win, name, v) \ |
51 | vop_reg_set(vop, &win->phy->scl->name, win->base, ~0, v, #name) | 52 | vop_reg_set(vop, &win->phy->scl->name, win->base, ~0, v, #name) |
52 | #define VOP_SCL_SET_EXT(x, win, name, v) \ | 53 | #define VOP_SCL_SET_EXT(vop, win, name, v) \ |
53 | vop_reg_set(vop, &win->phy->scl->ext->name, \ | 54 | vop_reg_set(vop, &win->phy->scl->ext->name, \ |
54 | win->base, ~0, v, #name) | 55 | win->base, ~0, v, #name) |
55 | 56 | ||
57 | #define VOP_WIN_YUV2YUV_SET(vop, win_yuv2yuv, name, v) \ | ||
58 | do { \ | ||
59 | if (win_yuv2yuv && win_yuv2yuv->name.mask) \ | ||
60 | vop_reg_set(vop, &win_yuv2yuv->name, 0, ~0, v, #name); \ | ||
61 | } while (0) | ||
62 | |||
63 | #define VOP_WIN_YUV2YUV_COEFFICIENT_SET(vop, win_yuv2yuv, name, v) \ | ||
64 | do { \ | ||
65 | if (win_yuv2yuv && win_yuv2yuv->phy->name.mask) \ | ||
66 | vop_reg_set(vop, &win_yuv2yuv->phy->name, win_yuv2yuv->base, ~0, v, #name); \ | ||
67 | } while (0) | ||
68 | |||
56 | #define VOP_INTR_SET_MASK(vop, name, mask, v) \ | 69 | #define VOP_INTR_SET_MASK(vop, name, mask, v) \ |
57 | vop_reg_set(vop, &vop->data->intr->name, 0, mask, v, #name) | 70 | vop_reg_set(vop, &vop->data->intr->name, 0, mask, v, #name) |
58 | 71 | ||
@@ -73,8 +86,11 @@ | |||
73 | #define VOP_INTR_GET_TYPE(vop, name, type) \ | 86 | #define VOP_INTR_GET_TYPE(vop, name, type) \ |
74 | vop_get_intr_type(vop, &vop->data->intr->name, type) | 87 | vop_get_intr_type(vop, &vop->data->intr->name, type) |
75 | 88 | ||
76 | #define VOP_WIN_GET(x, win, name) \ | 89 | #define VOP_WIN_GET(vop, win, name) \ |
77 | vop_read_reg(x, win->offset, win->phy->name) | 90 | vop_read_reg(vop, win->offset, win->phy->name) |
91 | |||
92 | #define VOP_WIN_HAS_REG(win, name) \ | ||
93 | (!!(win->phy->name.mask)) | ||
78 | 94 | ||
79 | #define VOP_WIN_GET_YRGBADDR(vop, win) \ | 95 | #define VOP_WIN_GET_YRGBADDR(vop, win) \ |
80 | vop_readl(vop, win->base + win->phy->yrgb_mst.offset) | 96 | vop_readl(vop, win->base + win->phy->yrgb_mst.offset) |
@@ -85,6 +101,18 @@ | |||
85 | #define to_vop(x) container_of(x, struct vop, crtc) | 101 | #define to_vop(x) container_of(x, struct vop, crtc) |
86 | #define to_vop_win(x) container_of(x, struct vop_win, base) | 102 | #define to_vop_win(x) container_of(x, struct vop_win, base) |
87 | 103 | ||
104 | /* | ||
105 | * The coefficients of the following matrix are all fixed points. | ||
106 | * The format is S2.10 for the 3x3 part of the matrix, and S9.12 for the offsets. | ||
107 | * They are all represented in two's complement. | ||
108 | */ | ||
109 | static const uint32_t bt601_yuv2rgb[] = { | ||
110 | 0x4A8, 0x0, 0x662, | ||
111 | 0x4A8, 0x1E6F, 0x1CBF, | ||
112 | 0x4A8, 0x812, 0x0, | ||
113 | 0x321168, 0x0877CF, 0x2EB127 | ||
114 | }; | ||
115 | |||
88 | enum vop_pending { | 116 | enum vop_pending { |
89 | VOP_PENDING_FB_UNREF, | 117 | VOP_PENDING_FB_UNREF, |
90 | }; | 118 | }; |
@@ -92,6 +120,7 @@ enum vop_pending { | |||
92 | struct vop_win { | 120 | struct vop_win { |
93 | struct drm_plane base; | 121 | struct drm_plane base; |
94 | const struct vop_win_data *data; | 122 | const struct vop_win_data *data; |
123 | const struct vop_win_yuv2yuv_data *yuv2yuv_data; | ||
95 | struct vop *vop; | 124 | struct vop *vop; |
96 | }; | 125 | }; |
97 | 126 | ||
@@ -686,6 +715,11 @@ static int vop_plane_atomic_check(struct drm_plane *plane, | |||
686 | return -EINVAL; | 715 | return -EINVAL; |
687 | } | 716 | } |
688 | 717 | ||
718 | if (fb->format->is_yuv && state->rotation & DRM_MODE_REFLECT_Y) { | ||
719 | DRM_ERROR("Invalid Source: Yuv format does not support this rotation\n"); | ||
720 | return -EINVAL; | ||
721 | } | ||
722 | |||
689 | return 0; | 723 | return 0; |
690 | } | 724 | } |
691 | 725 | ||
@@ -713,6 +747,7 @@ static void vop_plane_atomic_update(struct drm_plane *plane, | |||
713 | struct drm_crtc *crtc = state->crtc; | 747 | struct drm_crtc *crtc = state->crtc; |
714 | struct vop_win *vop_win = to_vop_win(plane); | 748 | struct vop_win *vop_win = to_vop_win(plane); |
715 | const struct vop_win_data *win = vop_win->data; | 749 | const struct vop_win_data *win = vop_win->data; |
750 | const struct vop_win_yuv2yuv_data *win_yuv2yuv = vop_win->yuv2yuv_data; | ||
716 | struct vop *vop = to_vop(state->crtc); | 751 | struct vop *vop = to_vop(state->crtc); |
717 | struct drm_framebuffer *fb = state->fb; | 752 | struct drm_framebuffer *fb = state->fb; |
718 | unsigned int actual_w, actual_h; | 753 | unsigned int actual_w, actual_h; |
@@ -728,6 +763,8 @@ static void vop_plane_atomic_update(struct drm_plane *plane, | |||
728 | bool rb_swap; | 763 | bool rb_swap; |
729 | int win_index = VOP_WIN_TO_INDEX(vop_win); | 764 | int win_index = VOP_WIN_TO_INDEX(vop_win); |
730 | int format; | 765 | int format; |
766 | int is_yuv = fb->format->is_yuv; | ||
767 | int i; | ||
731 | 768 | ||
732 | /* | 769 | /* |
733 | * can't update plane when vop is disabled. | 770 | * can't update plane when vop is disabled. |
@@ -761,6 +798,13 @@ static void vop_plane_atomic_update(struct drm_plane *plane, | |||
761 | offset += (src->y1 >> 16) * fb->pitches[0]; | 798 | offset += (src->y1 >> 16) * fb->pitches[0]; |
762 | dma_addr = rk_obj->dma_addr + offset + fb->offsets[0]; | 799 | dma_addr = rk_obj->dma_addr + offset + fb->offsets[0]; |
763 | 800 | ||
801 | /* | ||
802 | * For y-mirroring we need to move address | ||
803 | * to the beginning of the last line. | ||
804 | */ | ||
805 | if (state->rotation & DRM_MODE_REFLECT_Y) | ||
806 | dma_addr += (actual_h - 1) * fb->pitches[0]; | ||
807 | |||
764 | format = vop_convert_format(fb->format->format); | 808 | format = vop_convert_format(fb->format->format); |
765 | 809 | ||
766 | spin_lock(&vop->reg_lock); | 810 | spin_lock(&vop->reg_lock); |
@@ -768,7 +812,13 @@ static void vop_plane_atomic_update(struct drm_plane *plane, | |||
768 | VOP_WIN_SET(vop, win, format, format); | 812 | VOP_WIN_SET(vop, win, format, format); |
769 | VOP_WIN_SET(vop, win, yrgb_vir, DIV_ROUND_UP(fb->pitches[0], 4)); | 813 | VOP_WIN_SET(vop, win, yrgb_vir, DIV_ROUND_UP(fb->pitches[0], 4)); |
770 | VOP_WIN_SET(vop, win, yrgb_mst, dma_addr); | 814 | VOP_WIN_SET(vop, win, yrgb_mst, dma_addr); |
771 | if (fb->format->is_yuv) { | 815 | VOP_WIN_YUV2YUV_SET(vop, win_yuv2yuv, y2r_en, is_yuv); |
816 | VOP_WIN_SET(vop, win, y_mir_en, | ||
817 | (state->rotation & DRM_MODE_REFLECT_Y) ? 1 : 0); | ||
818 | VOP_WIN_SET(vop, win, x_mir_en, | ||
819 | (state->rotation & DRM_MODE_REFLECT_X) ? 1 : 0); | ||
820 | |||
821 | if (is_yuv) { | ||
772 | int hsub = drm_format_horz_chroma_subsampling(fb->format->format); | 822 | int hsub = drm_format_horz_chroma_subsampling(fb->format->format); |
773 | int vsub = drm_format_vert_chroma_subsampling(fb->format->format); | 823 | int vsub = drm_format_vert_chroma_subsampling(fb->format->format); |
774 | int bpp = fb->format->cpp[1]; | 824 | int bpp = fb->format->cpp[1]; |
@@ -782,6 +832,13 @@ static void vop_plane_atomic_update(struct drm_plane *plane, | |||
782 | dma_addr = rk_uv_obj->dma_addr + offset + fb->offsets[1]; | 832 | dma_addr = rk_uv_obj->dma_addr + offset + fb->offsets[1]; |
783 | VOP_WIN_SET(vop, win, uv_vir, DIV_ROUND_UP(fb->pitches[1], 4)); | 833 | VOP_WIN_SET(vop, win, uv_vir, DIV_ROUND_UP(fb->pitches[1], 4)); |
784 | VOP_WIN_SET(vop, win, uv_mst, dma_addr); | 834 | VOP_WIN_SET(vop, win, uv_mst, dma_addr); |
835 | |||
836 | for (i = 0; i < NUM_YUV2YUV_COEFFICIENTS; i++) { | ||
837 | VOP_WIN_YUV2YUV_COEFFICIENT_SET(vop, | ||
838 | win_yuv2yuv, | ||
839 | y2r_coefficients[i], | ||
840 | bt601_yuv2rgb[i]); | ||
841 | } | ||
785 | } | 842 | } |
786 | 843 | ||
787 | if (win->phy->scl) | 844 | if (win->phy->scl) |
@@ -820,10 +877,83 @@ static void vop_plane_atomic_update(struct drm_plane *plane, | |||
820 | spin_unlock(&vop->reg_lock); | 877 | spin_unlock(&vop->reg_lock); |
821 | } | 878 | } |
822 | 879 | ||
880 | static int vop_plane_atomic_async_check(struct drm_plane *plane, | ||
881 | struct drm_plane_state *state) | ||
882 | { | ||
883 | struct vop_win *vop_win = to_vop_win(plane); | ||
884 | const struct vop_win_data *win = vop_win->data; | ||
885 | int min_scale = win->phy->scl ? FRAC_16_16(1, 8) : | ||
886 | DRM_PLANE_HELPER_NO_SCALING; | ||
887 | int max_scale = win->phy->scl ? FRAC_16_16(8, 1) : | ||
888 | DRM_PLANE_HELPER_NO_SCALING; | ||
889 | struct drm_crtc_state *crtc_state; | ||
890 | |||
891 | if (plane != state->crtc->cursor) | ||
892 | return -EINVAL; | ||
893 | |||
894 | if (!plane->state) | ||
895 | return -EINVAL; | ||
896 | |||
897 | if (!plane->state->fb) | ||
898 | return -EINVAL; | ||
899 | |||
900 | if (state->state) | ||
901 | crtc_state = drm_atomic_get_existing_crtc_state(state->state, | ||
902 | state->crtc); | ||
903 | else /* Special case for asynchronous cursor updates. */ | ||
904 | crtc_state = plane->crtc->state; | ||
905 | |||
906 | return drm_atomic_helper_check_plane_state(plane->state, crtc_state, | ||
907 | min_scale, max_scale, | ||
908 | true, true); | ||
909 | } | ||
910 | |||
911 | static void vop_plane_atomic_async_update(struct drm_plane *plane, | ||
912 | struct drm_plane_state *new_state) | ||
913 | { | ||
914 | struct vop *vop = to_vop(plane->state->crtc); | ||
915 | struct drm_plane_state *plane_state; | ||
916 | |||
917 | plane_state = plane->funcs->atomic_duplicate_state(plane); | ||
918 | plane_state->crtc_x = new_state->crtc_x; | ||
919 | plane_state->crtc_y = new_state->crtc_y; | ||
920 | plane_state->crtc_h = new_state->crtc_h; | ||
921 | plane_state->crtc_w = new_state->crtc_w; | ||
922 | plane_state->src_x = new_state->src_x; | ||
923 | plane_state->src_y = new_state->src_y; | ||
924 | plane_state->src_h = new_state->src_h; | ||
925 | plane_state->src_w = new_state->src_w; | ||
926 | |||
927 | if (plane_state->fb != new_state->fb) | ||
928 | drm_atomic_set_fb_for_plane(plane_state, new_state->fb); | ||
929 | |||
930 | swap(plane_state, plane->state); | ||
931 | |||
932 | if (plane->state->fb && plane->state->fb != new_state->fb) { | ||
933 | drm_framebuffer_get(plane->state->fb); | ||
934 | WARN_ON(drm_crtc_vblank_get(plane->state->crtc) != 0); | ||
935 | drm_flip_work_queue(&vop->fb_unref_work, plane->state->fb); | ||
936 | set_bit(VOP_PENDING_FB_UNREF, &vop->pending); | ||
937 | } | ||
938 | |||
939 | if (vop->is_enabled) { | ||
940 | rockchip_drm_psr_inhibit_get_state(new_state->state); | ||
941 | vop_plane_atomic_update(plane, plane->state); | ||
942 | spin_lock(&vop->reg_lock); | ||
943 | vop_cfg_done(vop); | ||
944 | spin_unlock(&vop->reg_lock); | ||
945 | rockchip_drm_psr_inhibit_put_state(new_state->state); | ||
946 | } | ||
947 | |||
948 | plane->funcs->atomic_destroy_state(plane, plane_state); | ||
949 | } | ||
950 | |||
823 | static const struct drm_plane_helper_funcs plane_helper_funcs = { | 951 | static const struct drm_plane_helper_funcs plane_helper_funcs = { |
824 | .atomic_check = vop_plane_atomic_check, | 952 | .atomic_check = vop_plane_atomic_check, |
825 | .atomic_update = vop_plane_atomic_update, | 953 | .atomic_update = vop_plane_atomic_update, |
826 | .atomic_disable = vop_plane_atomic_disable, | 954 | .atomic_disable = vop_plane_atomic_disable, |
955 | .atomic_async_check = vop_plane_atomic_async_check, | ||
956 | .atomic_async_update = vop_plane_atomic_async_update, | ||
827 | .prepare_fb = drm_gem_fb_prepare_fb, | 957 | .prepare_fb = drm_gem_fb_prepare_fb, |
828 | }; | 958 | }; |
829 | 959 | ||
@@ -1274,6 +1404,18 @@ out: | |||
1274 | return ret; | 1404 | return ret; |
1275 | } | 1405 | } |
1276 | 1406 | ||
1407 | static void vop_plane_add_properties(struct drm_plane *plane, | ||
1408 | const struct vop_win_data *win_data) | ||
1409 | { | ||
1410 | unsigned int flags = 0; | ||
1411 | |||
1412 | flags |= VOP_WIN_HAS_REG(win_data, x_mir_en) ? DRM_MODE_REFLECT_X : 0; | ||
1413 | flags |= VOP_WIN_HAS_REG(win_data, y_mir_en) ? DRM_MODE_REFLECT_Y : 0; | ||
1414 | if (flags) | ||
1415 | drm_plane_create_rotation_property(plane, DRM_MODE_ROTATE_0, | ||
1416 | DRM_MODE_ROTATE_0 | flags); | ||
1417 | } | ||
1418 | |||
1277 | static int vop_create_crtc(struct vop *vop) | 1419 | static int vop_create_crtc(struct vop *vop) |
1278 | { | 1420 | { |
1279 | const struct vop_data *vop_data = vop->data; | 1421 | const struct vop_data *vop_data = vop->data; |
@@ -1311,6 +1453,7 @@ static int vop_create_crtc(struct vop *vop) | |||
1311 | 1453 | ||
1312 | plane = &vop_win->base; | 1454 | plane = &vop_win->base; |
1313 | drm_plane_helper_add(plane, &plane_helper_funcs); | 1455 | drm_plane_helper_add(plane, &plane_helper_funcs); |
1456 | vop_plane_add_properties(plane, win_data); | ||
1314 | if (plane->type == DRM_PLANE_TYPE_PRIMARY) | 1457 | if (plane->type == DRM_PLANE_TYPE_PRIMARY) |
1315 | primary = plane; | 1458 | primary = plane; |
1316 | else if (plane->type == DRM_PLANE_TYPE_CURSOR) | 1459 | else if (plane->type == DRM_PLANE_TYPE_CURSOR) |
@@ -1348,6 +1491,7 @@ static int vop_create_crtc(struct vop *vop) | |||
1348 | goto err_cleanup_crtc; | 1491 | goto err_cleanup_crtc; |
1349 | } | 1492 | } |
1350 | drm_plane_helper_add(&vop_win->base, &plane_helper_funcs); | 1493 | drm_plane_helper_add(&vop_win->base, &plane_helper_funcs); |
1494 | vop_plane_add_properties(&vop_win->base, win_data); | ||
1351 | } | 1495 | } |
1352 | 1496 | ||
1353 | port = of_get_child_by_name(dev->of_node, "port"); | 1497 | port = of_get_child_by_name(dev->of_node, "port"); |
@@ -1531,6 +1675,7 @@ static void vop_win_init(struct vop *vop) | |||
1531 | 1675 | ||
1532 | vop_win->data = win_data; | 1676 | vop_win->data = win_data; |
1533 | vop_win->vop = vop; | 1677 | vop_win->vop = vop; |
1678 | vop_win->yuv2yuv_data = &vop_data->win_yuv2yuv[i]; | ||
1534 | } | 1679 | } |
1535 | } | 1680 | } |
1536 | 1681 | ||
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.h b/drivers/gpu/drm/rockchip/rockchip_drm_vop.h index 0fe40e1983d9..04ed401d2325 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.h +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.h | |||
@@ -23,6 +23,8 @@ | |||
23 | #define VOP_MAJOR(version) ((version) >> 8) | 23 | #define VOP_MAJOR(version) ((version) >> 8) |
24 | #define VOP_MINOR(version) ((version) & 0xff) | 24 | #define VOP_MINOR(version) ((version) & 0xff) |
25 | 25 | ||
26 | #define NUM_YUV2YUV_COEFFICIENTS 12 | ||
27 | |||
26 | enum vop_data_format { | 28 | enum vop_data_format { |
27 | VOP_FMT_ARGB8888 = 0, | 29 | VOP_FMT_ARGB8888 = 0, |
28 | VOP_FMT_RGB888, | 30 | VOP_FMT_RGB888, |
@@ -124,6 +126,10 @@ struct vop_scl_regs { | |||
124 | struct vop_reg scale_cbcr_y; | 126 | struct vop_reg scale_cbcr_y; |
125 | }; | 127 | }; |
126 | 128 | ||
129 | struct vop_yuv2yuv_phy { | ||
130 | struct vop_reg y2r_coefficients[NUM_YUV2YUV_COEFFICIENTS]; | ||
131 | }; | ||
132 | |||
127 | struct vop_win_phy { | 133 | struct vop_win_phy { |
128 | const struct vop_scl_regs *scl; | 134 | const struct vop_scl_regs *scl; |
129 | const uint32_t *data_formats; | 135 | const uint32_t *data_formats; |
@@ -140,12 +146,20 @@ struct vop_win_phy { | |||
140 | struct vop_reg uv_mst; | 146 | struct vop_reg uv_mst; |
141 | struct vop_reg yrgb_vir; | 147 | struct vop_reg yrgb_vir; |
142 | struct vop_reg uv_vir; | 148 | struct vop_reg uv_vir; |
149 | struct vop_reg y_mir_en; | ||
150 | struct vop_reg x_mir_en; | ||
143 | 151 | ||
144 | struct vop_reg dst_alpha_ctl; | 152 | struct vop_reg dst_alpha_ctl; |
145 | struct vop_reg src_alpha_ctl; | 153 | struct vop_reg src_alpha_ctl; |
146 | struct vop_reg channel; | 154 | struct vop_reg channel; |
147 | }; | 155 | }; |
148 | 156 | ||
157 | struct vop_win_yuv2yuv_data { | ||
158 | uint32_t base; | ||
159 | const struct vop_yuv2yuv_phy *phy; | ||
160 | struct vop_reg y2r_en; | ||
161 | }; | ||
162 | |||
149 | struct vop_win_data { | 163 | struct vop_win_data { |
150 | uint32_t base; | 164 | uint32_t base; |
151 | const struct vop_win_phy *phy; | 165 | const struct vop_win_phy *phy; |
@@ -159,6 +173,7 @@ struct vop_data { | |||
159 | const struct vop_misc *misc; | 173 | const struct vop_misc *misc; |
160 | const struct vop_modeset *modeset; | 174 | const struct vop_modeset *modeset; |
161 | const struct vop_output *output; | 175 | const struct vop_output *output; |
176 | const struct vop_win_yuv2yuv_data *win_yuv2yuv; | ||
162 | const struct vop_win_data *win; | 177 | const struct vop_win_data *win; |
163 | unsigned int win_size; | 178 | unsigned int win_size; |
164 | 179 | ||
diff --git a/drivers/gpu/drm/rockchip/rockchip_vop_reg.c b/drivers/gpu/drm/rockchip/rockchip_vop_reg.c index 08fc40af52c8..bd76328c0fdb 100644 --- a/drivers/gpu/drm/rockchip/rockchip_vop_reg.c +++ b/drivers/gpu/drm/rockchip/rockchip_vop_reg.c | |||
@@ -299,6 +299,114 @@ static const struct vop_data px30_vop_lit = { | |||
299 | .win_size = ARRAY_SIZE(px30_vop_lit_win_data), | 299 | .win_size = ARRAY_SIZE(px30_vop_lit_win_data), |
300 | }; | 300 | }; |
301 | 301 | ||
302 | static const struct vop_scl_regs rk3066_win_scl = { | ||
303 | .scale_yrgb_x = VOP_REG(RK3066_WIN0_SCL_FACTOR_YRGB, 0xffff, 0x0), | ||
304 | .scale_yrgb_y = VOP_REG(RK3066_WIN0_SCL_FACTOR_YRGB, 0xffff, 16), | ||
305 | .scale_cbcr_x = VOP_REG(RK3066_WIN0_SCL_FACTOR_CBR, 0xffff, 0x0), | ||
306 | .scale_cbcr_y = VOP_REG(RK3066_WIN0_SCL_FACTOR_CBR, 0xffff, 16), | ||
307 | }; | ||
308 | |||
309 | static const struct vop_win_phy rk3066_win0_data = { | ||
310 | .scl = &rk3066_win_scl, | ||
311 | .data_formats = formats_win_full, | ||
312 | .nformats = ARRAY_SIZE(formats_win_full), | ||
313 | .enable = VOP_REG(RK3066_SYS_CTRL1, 0x1, 0), | ||
314 | .format = VOP_REG(RK3066_SYS_CTRL0, 0x7, 4), | ||
315 | .rb_swap = VOP_REG(RK3066_SYS_CTRL0, 0x1, 19), | ||
316 | .act_info = VOP_REG(RK3066_WIN0_ACT_INFO, 0x1fff1fff, 0), | ||
317 | .dsp_info = VOP_REG(RK3066_WIN0_DSP_INFO, 0x0fff0fff, 0), | ||
318 | .dsp_st = VOP_REG(RK3066_WIN0_DSP_ST, 0x1fff1fff, 0), | ||
319 | .yrgb_mst = VOP_REG(RK3066_WIN0_YRGB_MST0, 0xffffffff, 0), | ||
320 | .uv_mst = VOP_REG(RK3066_WIN0_CBR_MST0, 0xffffffff, 0), | ||
321 | .yrgb_vir = VOP_REG(RK3066_WIN0_VIR, 0xffff, 0), | ||
322 | .uv_vir = VOP_REG(RK3066_WIN0_VIR, 0x1fff, 16), | ||
323 | }; | ||
324 | |||
325 | static const struct vop_win_phy rk3066_win1_data = { | ||
326 | .scl = &rk3066_win_scl, | ||
327 | .data_formats = formats_win_full, | ||
328 | .nformats = ARRAY_SIZE(formats_win_full), | ||
329 | .enable = VOP_REG(RK3066_SYS_CTRL1, 0x1, 1), | ||
330 | .format = VOP_REG(RK3066_SYS_CTRL0, 0x7, 7), | ||
331 | .rb_swap = VOP_REG(RK3066_SYS_CTRL0, 0x1, 23), | ||
332 | .act_info = VOP_REG(RK3066_WIN1_ACT_INFO, 0x1fff1fff, 0), | ||
333 | .dsp_info = VOP_REG(RK3066_WIN1_DSP_INFO, 0x0fff0fff, 0), | ||
334 | .dsp_st = VOP_REG(RK3066_WIN1_DSP_ST, 0x1fff1fff, 0), | ||
335 | .yrgb_mst = VOP_REG(RK3066_WIN1_YRGB_MST, 0xffffffff, 0), | ||
336 | .uv_mst = VOP_REG(RK3066_WIN1_CBR_MST, 0xffffffff, 0), | ||
337 | .yrgb_vir = VOP_REG(RK3066_WIN1_VIR, 0xffff, 0), | ||
338 | .uv_vir = VOP_REG(RK3066_WIN1_VIR, 0x1fff, 16), | ||
339 | }; | ||
340 | |||
341 | static const struct vop_win_phy rk3066_win2_data = { | ||
342 | .data_formats = formats_win_lite, | ||
343 | .nformats = ARRAY_SIZE(formats_win_lite), | ||
344 | .enable = VOP_REG(RK3066_SYS_CTRL1, 0x1, 2), | ||
345 | .format = VOP_REG(RK3066_SYS_CTRL0, 0x7, 10), | ||
346 | .rb_swap = VOP_REG(RK3066_SYS_CTRL0, 0x1, 27), | ||
347 | .dsp_info = VOP_REG(RK3066_WIN2_DSP_INFO, 0x0fff0fff, 0), | ||
348 | .dsp_st = VOP_REG(RK3066_WIN2_DSP_ST, 0x1fff1fff, 0), | ||
349 | .yrgb_mst = VOP_REG(RK3066_WIN2_MST, 0xffffffff, 0), | ||
350 | .yrgb_vir = VOP_REG(RK3066_WIN2_VIR, 0xffff, 0), | ||
351 | }; | ||
352 | |||
353 | static const struct vop_modeset rk3066_modeset = { | ||
354 | .htotal_pw = VOP_REG(RK3066_DSP_HTOTAL_HS_END, 0x1fff1fff, 0), | ||
355 | .hact_st_end = VOP_REG(RK3066_DSP_HACT_ST_END, 0x1fff1fff, 0), | ||
356 | .vtotal_pw = VOP_REG(RK3066_DSP_VTOTAL_VS_END, 0x1fff1fff, 0), | ||
357 | .vact_st_end = VOP_REG(RK3066_DSP_VACT_ST_END, 0x1fff1fff, 0), | ||
358 | }; | ||
359 | |||
360 | static const struct vop_output rk3066_output = { | ||
361 | .pin_pol = VOP_REG(RK3066_DSP_CTRL0, 0x7, 4), | ||
362 | }; | ||
363 | |||
364 | static const struct vop_common rk3066_common = { | ||
365 | .standby = VOP_REG(RK3066_SYS_CTRL0, 0x1, 1), | ||
366 | .out_mode = VOP_REG(RK3066_DSP_CTRL0, 0xf, 0), | ||
367 | .cfg_done = VOP_REG(RK3066_REG_CFG_DONE, 0x1, 0), | ||
368 | .dsp_blank = VOP_REG(RK3066_DSP_CTRL1, 0x1, 24), | ||
369 | }; | ||
370 | |||
371 | static const struct vop_win_data rk3066_vop_win_data[] = { | ||
372 | { .base = 0x00, .phy = &rk3066_win0_data, | ||
373 | .type = DRM_PLANE_TYPE_PRIMARY }, | ||
374 | { .base = 0x00, .phy = &rk3066_win1_data, | ||
375 | .type = DRM_PLANE_TYPE_OVERLAY }, | ||
376 | { .base = 0x00, .phy = &rk3066_win2_data, | ||
377 | .type = DRM_PLANE_TYPE_CURSOR }, | ||
378 | }; | ||
379 | |||
380 | static const int rk3066_vop_intrs[] = { | ||
381 | /* | ||
382 | * hs_start interrupt fires at frame-start, so serves | ||
383 | * the same purpose as dsp_hold in the driver. | ||
384 | */ | ||
385 | DSP_HOLD_VALID_INTR, | ||
386 | FS_INTR, | ||
387 | LINE_FLAG_INTR, | ||
388 | BUS_ERROR_INTR, | ||
389 | }; | ||
390 | |||
391 | static const struct vop_intr rk3066_intr = { | ||
392 | .intrs = rk3066_vop_intrs, | ||
393 | .nintrs = ARRAY_SIZE(rk3066_vop_intrs), | ||
394 | .line_flag_num[0] = VOP_REG(RK3066_INT_STATUS, 0xfff, 12), | ||
395 | .status = VOP_REG(RK3066_INT_STATUS, 0xf, 0), | ||
396 | .enable = VOP_REG(RK3066_INT_STATUS, 0xf, 4), | ||
397 | .clear = VOP_REG(RK3066_INT_STATUS, 0xf, 8), | ||
398 | }; | ||
399 | |||
400 | static const struct vop_data rk3066_vop = { | ||
401 | .version = VOP_VERSION(2, 1), | ||
402 | .intr = &rk3066_intr, | ||
403 | .common = &rk3066_common, | ||
404 | .modeset = &rk3066_modeset, | ||
405 | .output = &rk3066_output, | ||
406 | .win = rk3066_vop_win_data, | ||
407 | .win_size = ARRAY_SIZE(rk3066_vop_win_data), | ||
408 | }; | ||
409 | |||
302 | static const struct vop_scl_regs rk3188_win_scl = { | 410 | static const struct vop_scl_regs rk3188_win_scl = { |
303 | .scale_yrgb_x = VOP_REG(RK3188_WIN0_SCL_FACTOR_YRGB, 0xffff, 0x0), | 411 | .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), | 412 | .scale_yrgb_y = VOP_REG(RK3188_WIN0_SCL_FACTOR_YRGB, 0xffff, 16), |
@@ -550,6 +658,27 @@ static const struct vop_intr rk3368_vop_intr = { | |||
550 | .clear = VOP_REG_MASK_SYNC(RK3368_INTR_CLEAR, 0x3fff, 0), | 658 | .clear = VOP_REG_MASK_SYNC(RK3368_INTR_CLEAR, 0x3fff, 0), |
551 | }; | 659 | }; |
552 | 660 | ||
661 | static const struct vop_win_phy rk3368_win01_data = { | ||
662 | .scl = &rk3288_win_full_scl, | ||
663 | .data_formats = formats_win_full, | ||
664 | .nformats = ARRAY_SIZE(formats_win_full), | ||
665 | .enable = VOP_REG(RK3368_WIN0_CTRL0, 0x1, 0), | ||
666 | .format = VOP_REG(RK3368_WIN0_CTRL0, 0x7, 1), | ||
667 | .rb_swap = VOP_REG(RK3368_WIN0_CTRL0, 0x1, 12), | ||
668 | .x_mir_en = VOP_REG(RK3368_WIN0_CTRL0, 0x1, 21), | ||
669 | .y_mir_en = VOP_REG(RK3368_WIN0_CTRL0, 0x1, 22), | ||
670 | .act_info = VOP_REG(RK3368_WIN0_ACT_INFO, 0x1fff1fff, 0), | ||
671 | .dsp_info = VOP_REG(RK3368_WIN0_DSP_INFO, 0x0fff0fff, 0), | ||
672 | .dsp_st = VOP_REG(RK3368_WIN0_DSP_ST, 0x1fff1fff, 0), | ||
673 | .yrgb_mst = VOP_REG(RK3368_WIN0_YRGB_MST, 0xffffffff, 0), | ||
674 | .uv_mst = VOP_REG(RK3368_WIN0_CBR_MST, 0xffffffff, 0), | ||
675 | .yrgb_vir = VOP_REG(RK3368_WIN0_VIR, 0x3fff, 0), | ||
676 | .uv_vir = VOP_REG(RK3368_WIN0_VIR, 0x3fff, 16), | ||
677 | .src_alpha_ctl = VOP_REG(RK3368_WIN0_SRC_ALPHA_CTRL, 0xff, 0), | ||
678 | .dst_alpha_ctl = VOP_REG(RK3368_WIN0_DST_ALPHA_CTRL, 0xff, 0), | ||
679 | .channel = VOP_REG(RK3368_WIN0_CTRL2, 0xff, 0), | ||
680 | }; | ||
681 | |||
553 | static const struct vop_win_phy rk3368_win23_data = { | 682 | static const struct vop_win_phy rk3368_win23_data = { |
554 | .data_formats = formats_win_lite, | 683 | .data_formats = formats_win_lite, |
555 | .nformats = ARRAY_SIZE(formats_win_lite), | 684 | .nformats = ARRAY_SIZE(formats_win_lite), |
@@ -557,6 +686,7 @@ static const struct vop_win_phy rk3368_win23_data = { | |||
557 | .enable = VOP_REG(RK3368_WIN2_CTRL0, 0x1, 4), | 686 | .enable = VOP_REG(RK3368_WIN2_CTRL0, 0x1, 4), |
558 | .format = VOP_REG(RK3368_WIN2_CTRL0, 0x3, 5), | 687 | .format = VOP_REG(RK3368_WIN2_CTRL0, 0x3, 5), |
559 | .rb_swap = VOP_REG(RK3368_WIN2_CTRL0, 0x1, 20), | 688 | .rb_swap = VOP_REG(RK3368_WIN2_CTRL0, 0x1, 20), |
689 | .y_mir_en = VOP_REG(RK3368_WIN2_CTRL1, 0x1, 15), | ||
560 | .dsp_info = VOP_REG(RK3368_WIN2_DSP_INFO0, 0x0fff0fff, 0), | 690 | .dsp_info = VOP_REG(RK3368_WIN2_DSP_INFO0, 0x0fff0fff, 0), |
561 | .dsp_st = VOP_REG(RK3368_WIN2_DSP_ST0, 0x1fff1fff, 0), | 691 | .dsp_st = VOP_REG(RK3368_WIN2_DSP_ST0, 0x1fff1fff, 0), |
562 | .yrgb_mst = VOP_REG(RK3368_WIN2_MST0, 0xffffffff, 0), | 692 | .yrgb_mst = VOP_REG(RK3368_WIN2_MST0, 0xffffffff, 0), |
@@ -566,9 +696,9 @@ static const struct vop_win_phy rk3368_win23_data = { | |||
566 | }; | 696 | }; |
567 | 697 | ||
568 | static const struct vop_win_data rk3368_vop_win_data[] = { | 698 | static const struct vop_win_data rk3368_vop_win_data[] = { |
569 | { .base = 0x00, .phy = &rk3288_win01_data, | 699 | { .base = 0x00, .phy = &rk3368_win01_data, |
570 | .type = DRM_PLANE_TYPE_PRIMARY }, | 700 | .type = DRM_PLANE_TYPE_PRIMARY }, |
571 | { .base = 0x40, .phy = &rk3288_win01_data, | 701 | { .base = 0x40, .phy = &rk3368_win01_data, |
572 | .type = DRM_PLANE_TYPE_OVERLAY }, | 702 | .type = DRM_PLANE_TYPE_OVERLAY }, |
573 | { .base = 0x00, .phy = &rk3368_win23_data, | 703 | { .base = 0x00, .phy = &rk3368_win23_data, |
574 | .type = DRM_PLANE_TYPE_OVERLAY }, | 704 | .type = DRM_PLANE_TYPE_OVERLAY }, |
@@ -637,6 +767,34 @@ static const struct vop_output rk3399_output = { | |||
637 | .mipi_dual_channel_en = VOP_REG(RK3288_SYS_CTRL, 0x1, 3), | 767 | .mipi_dual_channel_en = VOP_REG(RK3288_SYS_CTRL, 0x1, 3), |
638 | }; | 768 | }; |
639 | 769 | ||
770 | static const struct vop_yuv2yuv_phy rk3399_yuv2yuv_win01_data = { | ||
771 | .y2r_coefficients = { | ||
772 | VOP_REG(RK3399_WIN0_YUV2YUV_Y2R + 0, 0xffff, 0), | ||
773 | VOP_REG(RK3399_WIN0_YUV2YUV_Y2R + 0, 0xffff, 16), | ||
774 | VOP_REG(RK3399_WIN0_YUV2YUV_Y2R + 4, 0xffff, 0), | ||
775 | VOP_REG(RK3399_WIN0_YUV2YUV_Y2R + 4, 0xffff, 16), | ||
776 | VOP_REG(RK3399_WIN0_YUV2YUV_Y2R + 8, 0xffff, 0), | ||
777 | VOP_REG(RK3399_WIN0_YUV2YUV_Y2R + 8, 0xffff, 16), | ||
778 | VOP_REG(RK3399_WIN0_YUV2YUV_Y2R + 12, 0xffff, 0), | ||
779 | VOP_REG(RK3399_WIN0_YUV2YUV_Y2R + 12, 0xffff, 16), | ||
780 | VOP_REG(RK3399_WIN0_YUV2YUV_Y2R + 16, 0xffff, 0), | ||
781 | VOP_REG(RK3399_WIN0_YUV2YUV_Y2R + 20, 0xffffffff, 0), | ||
782 | VOP_REG(RK3399_WIN0_YUV2YUV_Y2R + 24, 0xffffffff, 0), | ||
783 | VOP_REG(RK3399_WIN0_YUV2YUV_Y2R + 28, 0xffffffff, 0), | ||
784 | }, | ||
785 | }; | ||
786 | |||
787 | static const struct vop_yuv2yuv_phy rk3399_yuv2yuv_win23_data = { }; | ||
788 | |||
789 | static const struct vop_win_yuv2yuv_data rk3399_vop_big_win_yuv2yuv_data[] = { | ||
790 | { .base = 0x00, .phy = &rk3399_yuv2yuv_win01_data, | ||
791 | .y2r_en = VOP_REG(RK3399_YUV2YUV_WIN, 0x1, 1) }, | ||
792 | { .base = 0x60, .phy = &rk3399_yuv2yuv_win01_data, | ||
793 | .y2r_en = VOP_REG(RK3399_YUV2YUV_WIN, 0x1, 9) }, | ||
794 | { .base = 0xC0, .phy = &rk3399_yuv2yuv_win23_data }, | ||
795 | { .base = 0x120, .phy = &rk3399_yuv2yuv_win23_data }, | ||
796 | }; | ||
797 | |||
640 | static const struct vop_data rk3399_vop_big = { | 798 | static const struct vop_data rk3399_vop_big = { |
641 | .version = VOP_VERSION(3, 5), | 799 | .version = VOP_VERSION(3, 5), |
642 | .feature = VOP_FEATURE_OUTPUT_RGB10, | 800 | .feature = VOP_FEATURE_OUTPUT_RGB10, |
@@ -647,15 +805,22 @@ static const struct vop_data rk3399_vop_big = { | |||
647 | .misc = &rk3368_misc, | 805 | .misc = &rk3368_misc, |
648 | .win = rk3368_vop_win_data, | 806 | .win = rk3368_vop_win_data, |
649 | .win_size = ARRAY_SIZE(rk3368_vop_win_data), | 807 | .win_size = ARRAY_SIZE(rk3368_vop_win_data), |
808 | .win_yuv2yuv = rk3399_vop_big_win_yuv2yuv_data, | ||
650 | }; | 809 | }; |
651 | 810 | ||
652 | static const struct vop_win_data rk3399_vop_lit_win_data[] = { | 811 | static const struct vop_win_data rk3399_vop_lit_win_data[] = { |
653 | { .base = 0x00, .phy = &rk3288_win01_data, | 812 | { .base = 0x00, .phy = &rk3368_win01_data, |
654 | .type = DRM_PLANE_TYPE_PRIMARY }, | 813 | .type = DRM_PLANE_TYPE_PRIMARY }, |
655 | { .base = 0x00, .phy = &rk3368_win23_data, | 814 | { .base = 0x00, .phy = &rk3368_win23_data, |
656 | .type = DRM_PLANE_TYPE_CURSOR}, | 815 | .type = DRM_PLANE_TYPE_CURSOR}, |
657 | }; | 816 | }; |
658 | 817 | ||
818 | static const struct vop_win_yuv2yuv_data rk3399_vop_lit_win_yuv2yuv_data[] = { | ||
819 | { .base = 0x00, .phy = &rk3399_yuv2yuv_win01_data, | ||
820 | .y2r_en = VOP_REG(RK3399_YUV2YUV_WIN, 0x1, 1)}, | ||
821 | { .base = 0x60, .phy = &rk3399_yuv2yuv_win23_data }, | ||
822 | }; | ||
823 | |||
659 | static const struct vop_data rk3399_vop_lit = { | 824 | static const struct vop_data rk3399_vop_lit = { |
660 | .version = VOP_VERSION(3, 6), | 825 | .version = VOP_VERSION(3, 6), |
661 | .intr = &rk3366_vop_intr, | 826 | .intr = &rk3366_vop_intr, |
@@ -665,6 +830,7 @@ static const struct vop_data rk3399_vop_lit = { | |||
665 | .misc = &rk3368_misc, | 830 | .misc = &rk3368_misc, |
666 | .win = rk3399_vop_lit_win_data, | 831 | .win = rk3399_vop_lit_win_data, |
667 | .win_size = ARRAY_SIZE(rk3399_vop_lit_win_data), | 832 | .win_size = ARRAY_SIZE(rk3399_vop_lit_win_data), |
833 | .win_yuv2yuv = rk3399_vop_lit_win_yuv2yuv_data, | ||
668 | }; | 834 | }; |
669 | 835 | ||
670 | static const struct vop_win_data rk3228_vop_win_data[] = { | 836 | static const struct vop_win_data rk3228_vop_win_data[] = { |
@@ -730,11 +896,11 @@ static const struct vop_intr rk3328_vop_intr = { | |||
730 | }; | 896 | }; |
731 | 897 | ||
732 | static const struct vop_win_data rk3328_vop_win_data[] = { | 898 | static const struct vop_win_data rk3328_vop_win_data[] = { |
733 | { .base = 0xd0, .phy = &rk3288_win01_data, | 899 | { .base = 0xd0, .phy = &rk3368_win01_data, |
734 | .type = DRM_PLANE_TYPE_PRIMARY }, | 900 | .type = DRM_PLANE_TYPE_PRIMARY }, |
735 | { .base = 0x1d0, .phy = &rk3288_win01_data, | 901 | { .base = 0x1d0, .phy = &rk3368_win01_data, |
736 | .type = DRM_PLANE_TYPE_OVERLAY }, | 902 | .type = DRM_PLANE_TYPE_OVERLAY }, |
737 | { .base = 0x2d0, .phy = &rk3288_win01_data, | 903 | { .base = 0x2d0, .phy = &rk3368_win01_data, |
738 | .type = DRM_PLANE_TYPE_CURSOR }, | 904 | .type = DRM_PLANE_TYPE_CURSOR }, |
739 | }; | 905 | }; |
740 | 906 | ||
@@ -759,6 +925,8 @@ static const struct of_device_id vop_driver_dt_match[] = { | |||
759 | .data = &px30_vop_big }, | 925 | .data = &px30_vop_big }, |
760 | { .compatible = "rockchip,px30-vop-lit", | 926 | { .compatible = "rockchip,px30-vop-lit", |
761 | .data = &px30_vop_lit }, | 927 | .data = &px30_vop_lit }, |
928 | { .compatible = "rockchip,rk3066-vop", | ||
929 | .data = &rk3066_vop }, | ||
762 | { .compatible = "rockchip,rk3188-vop", | 930 | { .compatible = "rockchip,rk3188-vop", |
763 | .data = &rk3188_vop }, | 931 | .data = &rk3188_vop }, |
764 | { .compatible = "rockchip,rk3288-vop", | 932 | { .compatible = "rockchip,rk3288-vop", |
diff --git a/drivers/gpu/drm/rockchip/rockchip_vop_reg.h b/drivers/gpu/drm/rockchip/rockchip_vop_reg.h index 7348c68352ed..d837d4a7df4a 100644 --- a/drivers/gpu/drm/rockchip/rockchip_vop_reg.h +++ b/drivers/gpu/drm/rockchip/rockchip_vop_reg.h | |||
@@ -983,4 +983,57 @@ | |||
983 | #define RK3188_REG_CFG_DONE 0x90 | 983 | #define RK3188_REG_CFG_DONE 0x90 |
984 | /* rk3188 register definition end */ | 984 | /* rk3188 register definition end */ |
985 | 985 | ||
986 | /* rk3066 register definition */ | ||
987 | #define RK3066_SYS_CTRL0 0x00 | ||
988 | #define RK3066_SYS_CTRL1 0x04 | ||
989 | #define RK3066_DSP_CTRL0 0x08 | ||
990 | #define RK3066_DSP_CTRL1 0x0c | ||
991 | #define RK3066_INT_STATUS 0x10 | ||
992 | #define RK3066_MCU_CTRL 0x14 | ||
993 | #define RK3066_BLEND_CTRL 0x18 | ||
994 | #define RK3066_WIN0_COLOR_KEY_CTRL 0x1c | ||
995 | #define RK3066_WIN1_COLOR_KEY_CTRL 0x20 | ||
996 | #define RK3066_WIN2_COLOR_KEY_CTRL 0x24 | ||
997 | #define RK3066_WIN0_YRGB_MST0 0x28 | ||
998 | #define RK3066_WIN0_CBR_MST0 0x2c | ||
999 | #define RK3066_WIN0_YRGB_MST1 0x30 | ||
1000 | #define RK3066_WIN0_CBR_MST1 0x34 | ||
1001 | #define RK3066_WIN0_VIR 0x38 | ||
1002 | #define RK3066_WIN0_ACT_INFO 0x3c | ||
1003 | #define RK3066_WIN0_DSP_INFO 0x40 | ||
1004 | #define RK3066_WIN0_DSP_ST 0x44 | ||
1005 | #define RK3066_WIN0_SCL_FACTOR_YRGB 0x48 | ||
1006 | #define RK3066_WIN0_SCL_FACTOR_CBR 0x4c | ||
1007 | #define RK3066_WIN0_SCL_OFFSET 0x50 | ||
1008 | #define RK3066_WIN1_YRGB_MST 0x54 | ||
1009 | #define RK3066_WIN1_CBR_MST 0x58 | ||
1010 | #define RK3066_WIN1_VIR 0x5c | ||
1011 | #define RK3066_WIN1_ACT_INFO 0x60 | ||
1012 | #define RK3066_WIN1_DSP_INFO 0x64 | ||
1013 | #define RK3066_WIN1_DSP_ST 0x68 | ||
1014 | #define RK3066_WIN1_SCL_FACTOR_YRGB 0x6c | ||
1015 | #define RK3066_WIN1_SCL_FACTOR_CBR 0x70 | ||
1016 | #define RK3066_WIN1_SCL_OFFSET 0x74 | ||
1017 | #define RK3066_WIN2_MST 0x78 | ||
1018 | #define RK3066_WIN2_VIR 0x7c | ||
1019 | #define RK3066_WIN2_DSP_INFO 0x80 | ||
1020 | #define RK3066_WIN2_DSP_ST 0x84 | ||
1021 | #define RK3066_HWC_MST 0x88 | ||
1022 | #define RK3066_HWC_DSP_ST 0x8c | ||
1023 | #define RK3066_HWC_COLOR_LUT0 0x90 | ||
1024 | #define RK3066_HWC_COLOR_LUT1 0x94 | ||
1025 | #define RK3066_HWC_COLOR_LUT2 0x98 | ||
1026 | #define RK3066_DSP_HTOTAL_HS_END 0x9c | ||
1027 | #define RK3066_DSP_HACT_ST_END 0xa0 | ||
1028 | #define RK3066_DSP_VTOTAL_VS_END 0xa4 | ||
1029 | #define RK3066_DSP_VACT_ST_END 0xa8 | ||
1030 | #define RK3066_DSP_VS_ST_END_F1 0xac | ||
1031 | #define RK3066_DSP_VACT_ST_END_F1 0xb0 | ||
1032 | #define RK3066_REG_CFG_DONE 0xc0 | ||
1033 | #define RK3066_MCU_BYPASS_WPORT 0x100 | ||
1034 | #define RK3066_MCU_BYPASS_RPORT 0x200 | ||
1035 | #define RK3066_WIN2_LUT_ADDR 0x400 | ||
1036 | #define RK3066_DSP_LUT_ADDR 0x800 | ||
1037 | /* rk3066 register definition end */ | ||
1038 | |||
986 | #endif /* _ROCKCHIP_VOP_REG_H */ | 1039 | #endif /* _ROCKCHIP_VOP_REG_H */ |
diff --git a/drivers/gpu/drm/sti/sti_crtc.c b/drivers/gpu/drm/sti/sti_crtc.c index ed76e52eb213..ec9f87483e39 100644 --- a/drivers/gpu/drm/sti/sti_crtc.c +++ b/drivers/gpu/drm/sti/sti_crtc.c | |||
@@ -53,18 +53,10 @@ sti_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *mode) | |||
53 | struct clk *compo_clk, *pix_clk; | 53 | struct clk *compo_clk, *pix_clk; |
54 | int rate = mode->clock * 1000; | 54 | int rate = mode->clock * 1000; |
55 | 55 | ||
56 | DRM_DEBUG_KMS("CRTC:%d (%s) mode:%d (%s)\n", | 56 | DRM_DEBUG_KMS("CRTC:%d (%s) mode: (%s)\n", |
57 | crtc->base.id, sti_mixer_to_str(mixer), | 57 | crtc->base.id, sti_mixer_to_str(mixer), mode->name); |
58 | mode->base.id, mode->name); | 58 | |
59 | 59 | DRM_DEBUG_KMS(DRM_MODE_FMT "\n", DRM_MODE_ARG(mode)); | |
60 | DRM_DEBUG_KMS("%d %d %d %d %d %d %d %d %d %d 0x%x 0x%x\n", | ||
61 | mode->vrefresh, mode->clock, | ||
62 | mode->hdisplay, | ||
63 | mode->hsync_start, mode->hsync_end, | ||
64 | mode->htotal, | ||
65 | mode->vdisplay, | ||
66 | mode->vsync_start, mode->vsync_end, | ||
67 | mode->vtotal, mode->type, mode->flags); | ||
68 | 60 | ||
69 | if (mixer->id == STI_MIXER_MAIN) { | 61 | if (mixer->id == STI_MIXER_MAIN) { |
70 | compo_clk = compo->clk_compo_main; | 62 | compo_clk = compo->clk_compo_main; |
diff --git a/drivers/gpu/drm/sti/sti_hdmi.c b/drivers/gpu/drm/sti/sti_hdmi.c index fbef4ad6c8ef..458fcb5a93f2 100644 --- a/drivers/gpu/drm/sti/sti_hdmi.c +++ b/drivers/gpu/drm/sti/sti_hdmi.c | |||
@@ -434,7 +434,8 @@ static int hdmi_avi_infoframe_config(struct sti_hdmi *hdmi) | |||
434 | 434 | ||
435 | DRM_DEBUG_DRIVER("\n"); | 435 | DRM_DEBUG_DRIVER("\n"); |
436 | 436 | ||
437 | ret = drm_hdmi_avi_infoframe_from_display_mode(&infoframe, mode, false); | 437 | ret = drm_hdmi_avi_infoframe_from_display_mode(&infoframe, |
438 | hdmi->drm_connector, mode); | ||
438 | if (ret < 0) { | 439 | if (ret < 0) { |
439 | DRM_ERROR("failed to setup AVI infoframe: %d\n", ret); | 440 | DRM_ERROR("failed to setup AVI infoframe: %d\n", ret); |
440 | return ret; | 441 | return ret; |
diff --git a/drivers/gpu/drm/sun4i/sun4i_hdmi_enc.c b/drivers/gpu/drm/sun4i/sun4i_hdmi_enc.c index 061d2e0d9011..554a6f4561f3 100644 --- a/drivers/gpu/drm/sun4i/sun4i_hdmi_enc.c +++ b/drivers/gpu/drm/sun4i/sun4i_hdmi_enc.c | |||
@@ -52,7 +52,8 @@ static int sun4i_hdmi_setup_avi_infoframes(struct sun4i_hdmi *hdmi, | |||
52 | u8 buffer[17]; | 52 | u8 buffer[17]; |
53 | int i, ret; | 53 | int i, ret; |
54 | 54 | ||
55 | ret = drm_hdmi_avi_infoframe_from_display_mode(&frame, mode, false); | 55 | ret = drm_hdmi_avi_infoframe_from_display_mode(&frame, |
56 | &hdmi->connector, mode); | ||
56 | if (ret < 0) { | 57 | if (ret < 0) { |
57 | DRM_ERROR("Failed to get infoframes from mode\n"); | 58 | DRM_ERROR("Failed to get infoframes from mode\n"); |
58 | return ret; | 59 | return ret; |
diff --git a/drivers/gpu/drm/tegra/hdmi.c b/drivers/gpu/drm/tegra/hdmi.c index 0082468f703c..a7566c67bfb0 100644 --- a/drivers/gpu/drm/tegra/hdmi.c +++ b/drivers/gpu/drm/tegra/hdmi.c | |||
@@ -741,7 +741,8 @@ static void tegra_hdmi_setup_avi_infoframe(struct tegra_hdmi *hdmi, | |||
741 | u8 buffer[17]; | 741 | u8 buffer[17]; |
742 | ssize_t err; | 742 | ssize_t err; |
743 | 743 | ||
744 | err = drm_hdmi_avi_infoframe_from_display_mode(&frame, mode, false); | 744 | err = drm_hdmi_avi_infoframe_from_display_mode(&frame, |
745 | &hdmi->output.connector, mode); | ||
745 | if (err < 0) { | 746 | if (err < 0) { |
746 | dev_err(hdmi->dev, "failed to setup AVI infoframe: %zd\n", err); | 747 | dev_err(hdmi->dev, "failed to setup AVI infoframe: %zd\n", err); |
747 | return; | 748 | return; |
diff --git a/drivers/gpu/drm/tegra/sor.c b/drivers/gpu/drm/tegra/sor.c index ef8692b7075a..44feac2a0359 100644 --- a/drivers/gpu/drm/tegra/sor.c +++ b/drivers/gpu/drm/tegra/sor.c | |||
@@ -2116,7 +2116,8 @@ tegra_sor_hdmi_setup_avi_infoframe(struct tegra_sor *sor, | |||
2116 | value &= ~INFOFRAME_CTRL_ENABLE; | 2116 | value &= ~INFOFRAME_CTRL_ENABLE; |
2117 | tegra_sor_writel(sor, value, SOR_HDMI_AVI_INFOFRAME_CTRL); | 2117 | tegra_sor_writel(sor, value, SOR_HDMI_AVI_INFOFRAME_CTRL); |
2118 | 2118 | ||
2119 | err = drm_hdmi_avi_infoframe_from_display_mode(&frame, mode, false); | 2119 | err = drm_hdmi_avi_infoframe_from_display_mode(&frame, |
2120 | &sor->output.connector, mode); | ||
2120 | if (err < 0) { | 2121 | if (err < 0) { |
2121 | dev_err(sor->dev, "failed to setup AVI infoframe: %d\n", err); | 2122 | dev_err(sor->dev, "failed to setup AVI infoframe: %d\n", err); |
2122 | return err; | 2123 | return err; |
diff --git a/drivers/gpu/drm/tinydrm/core/tinydrm-core.c b/drivers/gpu/drm/tinydrm/core/tinydrm-core.c index 01a6f2d42440..aeb93eadb047 100644 --- a/drivers/gpu/drm/tinydrm/core/tinydrm-core.c +++ b/drivers/gpu/drm/tinydrm/core/tinydrm-core.c | |||
@@ -10,11 +10,14 @@ | |||
10 | #include <drm/drm_atomic.h> | 10 | #include <drm/drm_atomic.h> |
11 | #include <drm/drm_atomic_helper.h> | 11 | #include <drm/drm_atomic_helper.h> |
12 | #include <drm/drm_crtc_helper.h> | 12 | #include <drm/drm_crtc_helper.h> |
13 | #include <drm/drm_drv.h> | ||
13 | #include <drm/drm_fb_helper.h> | 14 | #include <drm/drm_fb_helper.h> |
14 | #include <drm/drm_gem_framebuffer_helper.h> | 15 | #include <drm/drm_gem_framebuffer_helper.h> |
16 | #include <drm/drm_print.h> | ||
15 | #include <drm/tinydrm/tinydrm.h> | 17 | #include <drm/tinydrm/tinydrm.h> |
16 | #include <linux/device.h> | 18 | #include <linux/device.h> |
17 | #include <linux/dma-buf.h> | 19 | #include <linux/dma-buf.h> |
20 | #include <linux/module.h> | ||
18 | 21 | ||
19 | /** | 22 | /** |
20 | * DOC: overview | 23 | * DOC: overview |
diff --git a/drivers/gpu/drm/tinydrm/core/tinydrm-pipe.c b/drivers/gpu/drm/tinydrm/core/tinydrm-pipe.c index eacfc0ec8ff1..d4576d6e8ce4 100644 --- a/drivers/gpu/drm/tinydrm/core/tinydrm-pipe.c +++ b/drivers/gpu/drm/tinydrm/core/tinydrm-pipe.c | |||
@@ -9,8 +9,11 @@ | |||
9 | 9 | ||
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 | #include <drm/drm_drv.h> | ||
12 | #include <drm/drm_gem_framebuffer_helper.h> | 13 | #include <drm/drm_gem_framebuffer_helper.h> |
13 | #include <drm/drm_modes.h> | 14 | #include <drm/drm_modes.h> |
15 | #include <drm/drm_print.h> | ||
16 | #include <drm/drm_vblank.h> | ||
14 | #include <drm/tinydrm/tinydrm.h> | 17 | #include <drm/tinydrm/tinydrm.h> |
15 | 18 | ||
16 | struct tinydrm_connector { | 19 | struct tinydrm_connector { |
diff --git a/drivers/gpu/drm/tinydrm/hx8357d.c b/drivers/gpu/drm/tinydrm/hx8357d.c index 81a2bbeb25d4..3ae11aa4b73b 100644 --- a/drivers/gpu/drm/tinydrm/hx8357d.c +++ b/drivers/gpu/drm/tinydrm/hx8357d.c | |||
@@ -16,6 +16,7 @@ | |||
16 | #include <linux/property.h> | 16 | #include <linux/property.h> |
17 | #include <linux/spi/spi.h> | 17 | #include <linux/spi/spi.h> |
18 | 18 | ||
19 | #include <drm/drm_drv.h> | ||
19 | #include <drm/drm_gem_cma_helper.h> | 20 | #include <drm/drm_gem_cma_helper.h> |
20 | #include <drm/drm_gem_framebuffer_helper.h> | 21 | #include <drm/drm_gem_framebuffer_helper.h> |
21 | #include <drm/drm_modeset_helper.h> | 22 | #include <drm/drm_modeset_helper.h> |
diff --git a/drivers/gpu/drm/tinydrm/ili9225.c b/drivers/gpu/drm/tinydrm/ili9225.c index 78f7c2d1b449..b0ad58b97227 100644 --- a/drivers/gpu/drm/tinydrm/ili9225.c +++ b/drivers/gpu/drm/tinydrm/ili9225.c | |||
@@ -20,7 +20,9 @@ | |||
20 | #include <linux/spi/spi.h> | 20 | #include <linux/spi/spi.h> |
21 | #include <video/mipi_display.h> | 21 | #include <video/mipi_display.h> |
22 | 22 | ||
23 | #include <drm/drm_drv.h> | ||
23 | #include <drm/drm_fb_cma_helper.h> | 24 | #include <drm/drm_fb_cma_helper.h> |
25 | #include <drm/drm_fourcc.h> | ||
24 | #include <drm/drm_gem_cma_helper.h> | 26 | #include <drm/drm_gem_cma_helper.h> |
25 | #include <drm/drm_gem_framebuffer_helper.h> | 27 | #include <drm/drm_gem_framebuffer_helper.h> |
26 | #include <drm/tinydrm/mipi-dbi.h> | 28 | #include <drm/tinydrm/mipi-dbi.h> |
diff --git a/drivers/gpu/drm/tinydrm/ili9341.c b/drivers/gpu/drm/tinydrm/ili9341.c index 51395bdc6ca2..bcdf10906ade 100644 --- a/drivers/gpu/drm/tinydrm/ili9341.c +++ b/drivers/gpu/drm/tinydrm/ili9341.c | |||
@@ -15,6 +15,7 @@ | |||
15 | #include <linux/property.h> | 15 | #include <linux/property.h> |
16 | #include <linux/spi/spi.h> | 16 | #include <linux/spi/spi.h> |
17 | 17 | ||
18 | #include <drm/drm_drv.h> | ||
18 | #include <drm/drm_gem_cma_helper.h> | 19 | #include <drm/drm_gem_cma_helper.h> |
19 | #include <drm/drm_gem_framebuffer_helper.h> | 20 | #include <drm/drm_gem_framebuffer_helper.h> |
20 | #include <drm/drm_modeset_helper.h> | 21 | #include <drm/drm_modeset_helper.h> |
diff --git a/drivers/gpu/drm/tinydrm/mi0283qt.c b/drivers/gpu/drm/tinydrm/mi0283qt.c index 3fa62e77c30b..97805ca37a04 100644 --- a/drivers/gpu/drm/tinydrm/mi0283qt.c +++ b/drivers/gpu/drm/tinydrm/mi0283qt.c | |||
@@ -17,6 +17,7 @@ | |||
17 | #include <linux/regulator/consumer.h> | 17 | #include <linux/regulator/consumer.h> |
18 | #include <linux/spi/spi.h> | 18 | #include <linux/spi/spi.h> |
19 | 19 | ||
20 | #include <drm/drm_drv.h> | ||
20 | #include <drm/drm_gem_cma_helper.h> | 21 | #include <drm/drm_gem_cma_helper.h> |
21 | #include <drm/drm_gem_framebuffer_helper.h> | 22 | #include <drm/drm_gem_framebuffer_helper.h> |
22 | #include <drm/drm_modeset_helper.h> | 23 | #include <drm/drm_modeset_helper.h> |
diff --git a/drivers/gpu/drm/tinydrm/mipi-dbi.c b/drivers/gpu/drm/tinydrm/mipi-dbi.c index 3a05e56f9b0d..10294e1283dd 100644 --- a/drivers/gpu/drm/tinydrm/mipi-dbi.c +++ b/drivers/gpu/drm/tinydrm/mipi-dbi.c | |||
@@ -10,14 +10,17 @@ | |||
10 | */ | 10 | */ |
11 | 11 | ||
12 | #include <linux/debugfs.h> | 12 | #include <linux/debugfs.h> |
13 | #include <linux/delay.h> | ||
13 | #include <linux/dma-buf.h> | 14 | #include <linux/dma-buf.h> |
14 | #include <linux/gpio/consumer.h> | 15 | #include <linux/gpio/consumer.h> |
15 | #include <linux/module.h> | 16 | #include <linux/module.h> |
16 | #include <linux/regulator/consumer.h> | 17 | #include <linux/regulator/consumer.h> |
17 | #include <linux/spi/spi.h> | 18 | #include <linux/spi/spi.h> |
18 | 19 | ||
20 | #include <drm/drm_drv.h> | ||
19 | #include <drm/drm_fb_cma_helper.h> | 21 | #include <drm/drm_fb_cma_helper.h> |
20 | #include <drm/drm_gem_cma_helper.h> | 22 | #include <drm/drm_gem_cma_helper.h> |
23 | #include <drm/drm_fourcc.h> | ||
21 | #include <drm/drm_gem_framebuffer_helper.h> | 24 | #include <drm/drm_gem_framebuffer_helper.h> |
22 | #include <drm/tinydrm/mipi-dbi.h> | 25 | #include <drm/tinydrm/mipi-dbi.h> |
23 | #include <drm/tinydrm/tinydrm-helpers.h> | 26 | #include <drm/tinydrm/tinydrm-helpers.h> |
diff --git a/drivers/gpu/drm/tinydrm/repaper.c b/drivers/gpu/drm/tinydrm/repaper.c index 54d6fe0f37ce..b2a8f894946a 100644 --- a/drivers/gpu/drm/tinydrm/repaper.c +++ b/drivers/gpu/drm/tinydrm/repaper.c | |||
@@ -26,6 +26,7 @@ | |||
26 | #include <linux/spi/spi.h> | 26 | #include <linux/spi/spi.h> |
27 | #include <linux/thermal.h> | 27 | #include <linux/thermal.h> |
28 | 28 | ||
29 | #include <drm/drm_drv.h> | ||
29 | #include <drm/drm_fb_cma_helper.h> | 30 | #include <drm/drm_fb_cma_helper.h> |
30 | #include <drm/drm_gem_cma_helper.h> | 31 | #include <drm/drm_gem_cma_helper.h> |
31 | #include <drm/drm_gem_framebuffer_helper.h> | 32 | #include <drm/drm_gem_framebuffer_helper.h> |
diff --git a/drivers/gpu/drm/tinydrm/st7586.c b/drivers/gpu/drm/tinydrm/st7586.c index a6a8a1081b73..bf518167760a 100644 --- a/drivers/gpu/drm/tinydrm/st7586.c +++ b/drivers/gpu/drm/tinydrm/st7586.c | |||
@@ -17,6 +17,7 @@ | |||
17 | #include <linux/spi/spi.h> | 17 | #include <linux/spi/spi.h> |
18 | #include <video/mipi_display.h> | 18 | #include <video/mipi_display.h> |
19 | 19 | ||
20 | #include <drm/drm_drv.h> | ||
20 | #include <drm/drm_fb_cma_helper.h> | 21 | #include <drm/drm_fb_cma_helper.h> |
21 | #include <drm/drm_gem_cma_helper.h> | 22 | #include <drm/drm_gem_cma_helper.h> |
22 | #include <drm/drm_gem_framebuffer_helper.h> | 23 | #include <drm/drm_gem_framebuffer_helper.h> |
diff --git a/drivers/gpu/drm/tinydrm/st7735r.c b/drivers/gpu/drm/tinydrm/st7735r.c index b39779e0dcd8..9bc93d5a0401 100644 --- a/drivers/gpu/drm/tinydrm/st7735r.c +++ b/drivers/gpu/drm/tinydrm/st7735r.c | |||
@@ -14,6 +14,7 @@ | |||
14 | #include <linux/spi/spi.h> | 14 | #include <linux/spi/spi.h> |
15 | #include <video/mipi_display.h> | 15 | #include <video/mipi_display.h> |
16 | 16 | ||
17 | #include <drm/drm_drv.h> | ||
17 | #include <drm/drm_gem_cma_helper.h> | 18 | #include <drm/drm_gem_cma_helper.h> |
18 | #include <drm/drm_gem_framebuffer_helper.h> | 19 | #include <drm/drm_gem_framebuffer_helper.h> |
19 | #include <drm/tinydrm/mipi-dbi.h> | 20 | #include <drm/tinydrm/mipi-dbi.h> |
diff --git a/drivers/gpu/drm/vc4/vc4_drv.h b/drivers/gpu/drm/vc4/vc4_drv.h index c24b078f0593..2c635f001c71 100644 --- a/drivers/gpu/drm/vc4/vc4_drv.h +++ b/drivers/gpu/drm/vc4/vc4_drv.h | |||
@@ -9,6 +9,7 @@ | |||
9 | #include <linux/mm_types.h> | 9 | #include <linux/mm_types.h> |
10 | #include <linux/reservation.h> | 10 | #include <linux/reservation.h> |
11 | #include <drm/drmP.h> | 11 | #include <drm/drmP.h> |
12 | #include <drm/drm_util.h> | ||
12 | #include <drm/drm_encoder.h> | 13 | #include <drm/drm_encoder.h> |
13 | #include <drm/drm_gem_cma_helper.h> | 14 | #include <drm/drm_gem_cma_helper.h> |
14 | #include <drm/drm_atomic.h> | 15 | #include <drm/drm_atomic.h> |
diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c index 2f276222e30f..051b61b62541 100644 --- a/drivers/gpu/drm/vc4/vc4_hdmi.c +++ b/drivers/gpu/drm/vc4/vc4_hdmi.c | |||
@@ -109,7 +109,6 @@ struct vc4_hdmi_encoder { | |||
109 | struct vc4_encoder base; | 109 | struct vc4_encoder base; |
110 | bool hdmi_monitor; | 110 | bool hdmi_monitor; |
111 | bool limited_rgb_range; | 111 | bool limited_rgb_range; |
112 | bool rgb_range_selectable; | ||
113 | }; | 112 | }; |
114 | 113 | ||
115 | static inline struct vc4_hdmi_encoder * | 114 | static inline struct vc4_hdmi_encoder * |
@@ -280,11 +279,6 @@ static int vc4_hdmi_connector_get_modes(struct drm_connector *connector) | |||
280 | 279 | ||
281 | vc4_encoder->hdmi_monitor = drm_detect_hdmi_monitor(edid); | 280 | vc4_encoder->hdmi_monitor = drm_detect_hdmi_monitor(edid); |
282 | 281 | ||
283 | if (edid && edid->input & DRM_EDID_INPUT_DIGITAL) { | ||
284 | vc4_encoder->rgb_range_selectable = | ||
285 | drm_rgb_quant_range_selectable(edid); | ||
286 | } | ||
287 | |||
288 | drm_connector_update_edid_property(connector, edid); | 282 | drm_connector_update_edid_property(connector, edid); |
289 | ret = drm_add_edid_modes(connector, edid); | 283 | ret = drm_add_edid_modes(connector, edid); |
290 | kfree(edid); | 284 | kfree(edid); |
@@ -424,18 +418,18 @@ static void vc4_hdmi_set_avi_infoframe(struct drm_encoder *encoder) | |||
424 | union hdmi_infoframe frame; | 418 | union hdmi_infoframe frame; |
425 | int ret; | 419 | int ret; |
426 | 420 | ||
427 | ret = drm_hdmi_avi_infoframe_from_display_mode(&frame.avi, mode, false); | 421 | ret = drm_hdmi_avi_infoframe_from_display_mode(&frame.avi, |
422 | hdmi->connector, mode); | ||
428 | if (ret < 0) { | 423 | if (ret < 0) { |
429 | DRM_ERROR("couldn't fill AVI infoframe\n"); | 424 | DRM_ERROR("couldn't fill AVI infoframe\n"); |
430 | return; | 425 | return; |
431 | } | 426 | } |
432 | 427 | ||
433 | drm_hdmi_avi_infoframe_quant_range(&frame.avi, mode, | 428 | drm_hdmi_avi_infoframe_quant_range(&frame.avi, |
429 | hdmi->connector, mode, | ||
434 | vc4_encoder->limited_rgb_range ? | 430 | vc4_encoder->limited_rgb_range ? |
435 | HDMI_QUANTIZATION_RANGE_LIMITED : | 431 | HDMI_QUANTIZATION_RANGE_LIMITED : |
436 | HDMI_QUANTIZATION_RANGE_FULL, | 432 | HDMI_QUANTIZATION_RANGE_FULL); |
437 | vc4_encoder->rgb_range_selectable, | ||
438 | false); | ||
439 | 433 | ||
440 | frame.avi.right_bar = cstate->tv.margins.right; | 434 | frame.avi.right_bar = cstate->tv.margins.right; |
441 | frame.avi.left_bar = cstate->tv.margins.left; | 435 | frame.avi.left_bar = cstate->tv.margins.left; |
diff --git a/drivers/gpu/drm/vc4/vc4_plane.c b/drivers/gpu/drm/vc4/vc4_plane.c index 2901ed0c5223..d098337c10e9 100644 --- a/drivers/gpu/drm/vc4/vc4_plane.c +++ b/drivers/gpu/drm/vc4/vc4_plane.c | |||
@@ -675,20 +675,7 @@ static int vc4_plane_mode_set(struct drm_plane *plane, | |||
675 | uint32_t param = fourcc_mod_broadcom_param(fb->modifier); | 675 | uint32_t param = fourcc_mod_broadcom_param(fb->modifier); |
676 | u32 tile_w, tile, x_off, pix_per_tile; | 676 | u32 tile_w, tile, x_off, pix_per_tile; |
677 | 677 | ||
678 | /* Column-based NV12 or RGBA. | 678 | hvs_format = HVS_PIXEL_FORMAT_H264; |
679 | */ | ||
680 | if (fb->format->num_planes > 1) { | ||
681 | if (hvs_format != HVS_PIXEL_FORMAT_YCBCR_YUV420_2PLANE) { | ||
682 | DRM_DEBUG_KMS("SAND format only valid for NV12/21"); | ||
683 | return -EINVAL; | ||
684 | } | ||
685 | hvs_format = HVS_PIXEL_FORMAT_H264; | ||
686 | } else { | ||
687 | if (base_format_mod == DRM_FORMAT_MOD_BROADCOM_SAND256) { | ||
688 | DRM_DEBUG_KMS("SAND256 format only valid for H.264"); | ||
689 | return -EINVAL; | ||
690 | } | ||
691 | } | ||
692 | 679 | ||
693 | switch (base_format_mod) { | 680 | switch (base_format_mod) { |
694 | case DRM_FORMAT_MOD_BROADCOM_SAND64: | 681 | case DRM_FORMAT_MOD_BROADCOM_SAND64: |
@@ -1151,8 +1138,6 @@ static bool vc4_format_mod_supported(struct drm_plane *plane, | |||
1151 | switch (fourcc_mod_broadcom_mod(modifier)) { | 1138 | switch (fourcc_mod_broadcom_mod(modifier)) { |
1152 | case DRM_FORMAT_MOD_LINEAR: | 1139 | case DRM_FORMAT_MOD_LINEAR: |
1153 | case DRM_FORMAT_MOD_BROADCOM_VC4_T_TILED: | 1140 | case DRM_FORMAT_MOD_BROADCOM_VC4_T_TILED: |
1154 | case DRM_FORMAT_MOD_BROADCOM_SAND64: | ||
1155 | case DRM_FORMAT_MOD_BROADCOM_SAND128: | ||
1156 | return true; | 1141 | return true; |
1157 | default: | 1142 | default: |
1158 | return false; | 1143 | return false; |
diff --git a/drivers/gpu/drm/virtio/Makefile b/drivers/gpu/drm/virtio/Makefile index f29deec83d1f..4e90cc8fa651 100644 --- a/drivers/gpu/drm/virtio/Makefile +++ b/drivers/gpu/drm/virtio/Makefile | |||
@@ -3,7 +3,7 @@ | |||
3 | # Makefile for the drm device driver. This driver provides support for the | 3 | # Makefile for the drm device driver. This driver provides support for the |
4 | # Direct Rendering Infrastructure (DRI) in XFree86 4.1.0 and higher. | 4 | # Direct Rendering Infrastructure (DRI) in XFree86 4.1.0 and higher. |
5 | 5 | ||
6 | virtio-gpu-y := virtgpu_drv.o virtgpu_kms.o virtgpu_drm_bus.o virtgpu_gem.o \ | 6 | virtio-gpu-y := virtgpu_drv.o virtgpu_kms.o virtgpu_gem.o \ |
7 | virtgpu_fb.o virtgpu_display.o virtgpu_vq.o virtgpu_ttm.o \ | 7 | virtgpu_fb.o virtgpu_display.o virtgpu_vq.o virtgpu_ttm.o \ |
8 | virtgpu_fence.o virtgpu_object.o virtgpu_debugfs.o virtgpu_plane.o \ | 8 | virtgpu_fence.o virtgpu_object.o virtgpu_debugfs.o virtgpu_plane.o \ |
9 | virtgpu_ioctl.o virtgpu_prime.o | 9 | virtgpu_ioctl.o virtgpu_prime.o |
diff --git a/drivers/gpu/drm/virtio/virtgpu_display.c b/drivers/gpu/drm/virtio/virtgpu_display.c index e1c223e18d86..87d7c49cf057 100644 --- a/drivers/gpu/drm/virtio/virtgpu_display.c +++ b/drivers/gpu/drm/virtio/virtgpu_display.c | |||
@@ -243,12 +243,8 @@ static enum drm_connector_status virtio_gpu_conn_detect( | |||
243 | 243 | ||
244 | static void virtio_gpu_conn_destroy(struct drm_connector *connector) | 244 | static void virtio_gpu_conn_destroy(struct drm_connector *connector) |
245 | { | 245 | { |
246 | struct virtio_gpu_output *virtio_gpu_output = | ||
247 | drm_connector_to_virtio_gpu_output(connector); | ||
248 | |||
249 | drm_connector_unregister(connector); | 246 | drm_connector_unregister(connector); |
250 | drm_connector_cleanup(connector); | 247 | drm_connector_cleanup(connector); |
251 | kfree(virtio_gpu_output); | ||
252 | } | 248 | } |
253 | 249 | ||
254 | static const struct drm_connector_funcs virtio_gpu_connector_funcs = { | 250 | static const struct drm_connector_funcs virtio_gpu_connector_funcs = { |
@@ -362,7 +358,7 @@ static const struct drm_mode_config_funcs virtio_gpu_mode_funcs = { | |||
362 | .atomic_commit = drm_atomic_helper_commit, | 358 | .atomic_commit = drm_atomic_helper_commit, |
363 | }; | 359 | }; |
364 | 360 | ||
365 | int virtio_gpu_modeset_init(struct virtio_gpu_device *vgdev) | 361 | void virtio_gpu_modeset_init(struct virtio_gpu_device *vgdev) |
366 | { | 362 | { |
367 | int i; | 363 | int i; |
368 | 364 | ||
@@ -381,7 +377,6 @@ int virtio_gpu_modeset_init(struct virtio_gpu_device *vgdev) | |||
381 | vgdev_output_init(vgdev, i); | 377 | vgdev_output_init(vgdev, i); |
382 | 378 | ||
383 | drm_mode_config_reset(vgdev->ddev); | 379 | drm_mode_config_reset(vgdev->ddev); |
384 | return 0; | ||
385 | } | 380 | } |
386 | 381 | ||
387 | void virtio_gpu_modeset_fini(struct virtio_gpu_device *vgdev) | 382 | void virtio_gpu_modeset_fini(struct virtio_gpu_device *vgdev) |
diff --git a/drivers/gpu/drm/virtio/virtgpu_drm_bus.c b/drivers/gpu/drm/virtio/virtgpu_drm_bus.c deleted file mode 100644 index 0887e0b64b9c..000000000000 --- a/drivers/gpu/drm/virtio/virtgpu_drm_bus.c +++ /dev/null | |||
@@ -1,103 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2015 Red Hat, Inc. | ||
3 | * All Rights Reserved. | ||
4 | * | ||
5 | * Permission is hereby granted, free of charge, to any person obtaining | ||
6 | * a copy of this software and associated documentation files (the | ||
7 | * "Software"), to deal in the Software without restriction, including | ||
8 | * without limitation the rights to use, copy, modify, merge, publish, | ||
9 | * distribute, sublicense, and/or sell copies of the Software, and to | ||
10 | * permit persons to whom the Software is furnished to do so, subject to | ||
11 | * the following conditions: | ||
12 | * | ||
13 | * The above copyright notice and this permission notice (including the | ||
14 | * next paragraph) shall be included in all copies or substantial | ||
15 | * portions of the Software. | ||
16 | * | ||
17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | ||
18 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | ||
19 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. | ||
20 | * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE | ||
21 | * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION | ||
22 | * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION | ||
23 | * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | ||
24 | */ | ||
25 | |||
26 | #include <linux/pci.h> | ||
27 | #include <drm/drm_fb_helper.h> | ||
28 | |||
29 | #include "virtgpu_drv.h" | ||
30 | |||
31 | int drm_virtio_init(struct drm_driver *driver, struct virtio_device *vdev) | ||
32 | { | ||
33 | struct drm_device *dev; | ||
34 | int ret; | ||
35 | |||
36 | dev = drm_dev_alloc(driver, &vdev->dev); | ||
37 | if (IS_ERR(dev)) | ||
38 | return PTR_ERR(dev); | ||
39 | vdev->priv = dev; | ||
40 | |||
41 | if (strcmp(vdev->dev.parent->bus->name, "pci") == 0) { | ||
42 | struct pci_dev *pdev = to_pci_dev(vdev->dev.parent); | ||
43 | const char *pname = dev_name(&pdev->dev); | ||
44 | bool vga = (pdev->class >> 8) == PCI_CLASS_DISPLAY_VGA; | ||
45 | char unique[20]; | ||
46 | |||
47 | DRM_INFO("pci: %s detected at %s\n", | ||
48 | vga ? "virtio-vga" : "virtio-gpu-pci", | ||
49 | pname); | ||
50 | dev->pdev = pdev; | ||
51 | if (vga) | ||
52 | drm_fb_helper_remove_conflicting_pci_framebuffers(pdev, | ||
53 | 0, | ||
54 | "virtiodrmfb"); | ||
55 | |||
56 | /* | ||
57 | * Normally the drm_dev_set_unique() call is done by core DRM. | ||
58 | * The following comment covers, why virtio cannot rely on it. | ||
59 | * | ||
60 | * Unlike the other virtual GPU drivers, virtio abstracts the | ||
61 | * underlying bus type by using struct virtio_device. | ||
62 | * | ||
63 | * Hence the dev_is_pci() check, used in core DRM, will fail | ||
64 | * and the unique returned will be the virtio_device "virtio0", | ||
65 | * while a "pci:..." one is required. | ||
66 | * | ||
67 | * A few other ideas were considered: | ||
68 | * - Extend the dev_is_pci() check [in drm_set_busid] to | ||
69 | * consider virtio. | ||
70 | * Seems like a bigger hack than what we have already. | ||
71 | * | ||
72 | * - Point drm_device::dev to the parent of the virtio_device | ||
73 | * Semantic changes: | ||
74 | * * Using the wrong device for i2c, framebuffer_alloc and | ||
75 | * prime import. | ||
76 | * Visual changes: | ||
77 | * * Helpers such as DRM_DEV_ERROR, dev_info, drm_printer, | ||
78 | * will print the wrong information. | ||
79 | * | ||
80 | * We could address the latter issues, by introducing | ||
81 | * drm_device::bus_dev, ... which would be used solely for this. | ||
82 | * | ||
83 | * So for the moment keep things as-is, with a bulky comment | ||
84 | * for the next person who feels like removing this | ||
85 | * drm_dev_set_unique() quirk. | ||
86 | */ | ||
87 | snprintf(unique, sizeof(unique), "pci:%s", pname); | ||
88 | ret = drm_dev_set_unique(dev, unique); | ||
89 | if (ret) | ||
90 | goto err_free; | ||
91 | |||
92 | } | ||
93 | |||
94 | ret = drm_dev_register(dev, 0); | ||
95 | if (ret) | ||
96 | goto err_free; | ||
97 | |||
98 | return 0; | ||
99 | |||
100 | err_free: | ||
101 | drm_dev_put(dev); | ||
102 | return ret; | ||
103 | } | ||
diff --git a/drivers/gpu/drm/virtio/virtgpu_drv.c b/drivers/gpu/drm/virtio/virtgpu_drv.c index 7df50920c1e0..af92964b6889 100644 --- a/drivers/gpu/drm/virtio/virtgpu_drv.c +++ b/drivers/gpu/drm/virtio/virtgpu_drv.c | |||
@@ -40,8 +40,60 @@ static int virtio_gpu_modeset = -1; | |||
40 | MODULE_PARM_DESC(modeset, "Disable/Enable modesetting"); | 40 | MODULE_PARM_DESC(modeset, "Disable/Enable modesetting"); |
41 | module_param_named(modeset, virtio_gpu_modeset, int, 0400); | 41 | module_param_named(modeset, virtio_gpu_modeset, int, 0400); |
42 | 42 | ||
43 | static int virtio_gpu_pci_quirk(struct drm_device *dev, struct virtio_device *vdev) | ||
44 | { | ||
45 | struct pci_dev *pdev = to_pci_dev(vdev->dev.parent); | ||
46 | const char *pname = dev_name(&pdev->dev); | ||
47 | bool vga = (pdev->class >> 8) == PCI_CLASS_DISPLAY_VGA; | ||
48 | char unique[20]; | ||
49 | |||
50 | DRM_INFO("pci: %s detected at %s\n", | ||
51 | vga ? "virtio-vga" : "virtio-gpu-pci", | ||
52 | pname); | ||
53 | dev->pdev = pdev; | ||
54 | if (vga) | ||
55 | drm_fb_helper_remove_conflicting_pci_framebuffers(pdev, | ||
56 | 0, | ||
57 | "virtiodrmfb"); | ||
58 | |||
59 | /* | ||
60 | * Normally the drm_dev_set_unique() call is done by core DRM. | ||
61 | * The following comment covers, why virtio cannot rely on it. | ||
62 | * | ||
63 | * Unlike the other virtual GPU drivers, virtio abstracts the | ||
64 | * underlying bus type by using struct virtio_device. | ||
65 | * | ||
66 | * Hence the dev_is_pci() check, used in core DRM, will fail | ||
67 | * and the unique returned will be the virtio_device "virtio0", | ||
68 | * while a "pci:..." one is required. | ||
69 | * | ||
70 | * A few other ideas were considered: | ||
71 | * - Extend the dev_is_pci() check [in drm_set_busid] to | ||
72 | * consider virtio. | ||
73 | * Seems like a bigger hack than what we have already. | ||
74 | * | ||
75 | * - Point drm_device::dev to the parent of the virtio_device | ||
76 | * Semantic changes: | ||
77 | * * Using the wrong device for i2c, framebuffer_alloc and | ||
78 | * prime import. | ||
79 | * Visual changes: | ||
80 | * * Helpers such as DRM_DEV_ERROR, dev_info, drm_printer, | ||
81 | * will print the wrong information. | ||
82 | * | ||
83 | * We could address the latter issues, by introducing | ||
84 | * drm_device::bus_dev, ... which would be used solely for this. | ||
85 | * | ||
86 | * So for the moment keep things as-is, with a bulky comment | ||
87 | * for the next person who feels like removing this | ||
88 | * drm_dev_set_unique() quirk. | ||
89 | */ | ||
90 | snprintf(unique, sizeof(unique), "pci:%s", pname); | ||
91 | return drm_dev_set_unique(dev, unique); | ||
92 | } | ||
93 | |||
43 | static int virtio_gpu_probe(struct virtio_device *vdev) | 94 | static int virtio_gpu_probe(struct virtio_device *vdev) |
44 | { | 95 | { |
96 | struct drm_device *dev; | ||
45 | int ret; | 97 | int ret; |
46 | 98 | ||
47 | if (vgacon_text_force() && virtio_gpu_modeset == -1) | 99 | if (vgacon_text_force() && virtio_gpu_modeset == -1) |
@@ -50,18 +102,39 @@ static int virtio_gpu_probe(struct virtio_device *vdev) | |||
50 | if (virtio_gpu_modeset == 0) | 102 | if (virtio_gpu_modeset == 0) |
51 | return -EINVAL; | 103 | return -EINVAL; |
52 | 104 | ||
53 | ret = drm_virtio_init(&driver, vdev); | 105 | dev = drm_dev_alloc(&driver, &vdev->dev); |
106 | if (IS_ERR(dev)) | ||
107 | return PTR_ERR(dev); | ||
108 | vdev->priv = dev; | ||
109 | |||
110 | if (!strcmp(vdev->dev.parent->bus->name, "pci")) { | ||
111 | ret = virtio_gpu_pci_quirk(dev, vdev); | ||
112 | if (ret) | ||
113 | goto err_free; | ||
114 | } | ||
115 | |||
116 | ret = virtio_gpu_init(dev); | ||
54 | if (ret) | 117 | if (ret) |
55 | return ret; | 118 | goto err_free; |
119 | |||
120 | ret = drm_dev_register(dev, 0); | ||
121 | if (ret) | ||
122 | goto err_free; | ||
56 | 123 | ||
57 | drm_fbdev_generic_setup(vdev->priv, 32); | 124 | drm_fbdev_generic_setup(vdev->priv, 32); |
58 | return 0; | 125 | return 0; |
126 | |||
127 | err_free: | ||
128 | drm_dev_put(dev); | ||
129 | return ret; | ||
59 | } | 130 | } |
60 | 131 | ||
61 | static void virtio_gpu_remove(struct virtio_device *vdev) | 132 | static void virtio_gpu_remove(struct virtio_device *vdev) |
62 | { | 133 | { |
63 | struct drm_device *dev = vdev->priv; | 134 | struct drm_device *dev = vdev->priv; |
64 | 135 | ||
136 | drm_dev_unregister(dev); | ||
137 | virtio_gpu_deinit(dev); | ||
65 | drm_put_dev(dev); | 138 | drm_put_dev(dev); |
66 | } | 139 | } |
67 | 140 | ||
@@ -123,8 +196,6 @@ static const struct file_operations virtio_gpu_driver_fops = { | |||
123 | 196 | ||
124 | static struct drm_driver driver = { | 197 | static struct drm_driver driver = { |
125 | .driver_features = DRIVER_MODESET | DRIVER_GEM | DRIVER_PRIME | DRIVER_RENDER | DRIVER_ATOMIC, | 198 | .driver_features = DRIVER_MODESET | DRIVER_GEM | DRIVER_PRIME | DRIVER_RENDER | DRIVER_ATOMIC, |
126 | .load = virtio_gpu_driver_load, | ||
127 | .unload = virtio_gpu_driver_unload, | ||
128 | .open = virtio_gpu_driver_open, | 199 | .open = virtio_gpu_driver_open, |
129 | .postclose = virtio_gpu_driver_postclose, | 200 | .postclose = virtio_gpu_driver_postclose, |
130 | 201 | ||
diff --git a/drivers/gpu/drm/virtio/virtgpu_drv.h b/drivers/gpu/drm/virtio/virtgpu_drv.h index 63704915f8ce..cf896d879382 100644 --- a/drivers/gpu/drm/virtio/virtgpu_drv.h +++ b/drivers/gpu/drm/virtio/virtgpu_drv.h | |||
@@ -50,9 +50,6 @@ | |||
50 | #define DRIVER_MINOR 1 | 50 | #define DRIVER_MINOR 1 |
51 | #define DRIVER_PATCHLEVEL 0 | 51 | #define DRIVER_PATCHLEVEL 0 |
52 | 52 | ||
53 | /* virtgpu_drm_bus.c */ | ||
54 | int drm_virtio_init(struct drm_driver *driver, struct virtio_device *vdev); | ||
55 | |||
56 | struct virtio_gpu_object { | 53 | struct virtio_gpu_object { |
57 | struct drm_gem_object gem_base; | 54 | struct drm_gem_object gem_base; |
58 | uint32_t hw_res_handle; | 55 | uint32_t hw_res_handle; |
@@ -209,8 +206,8 @@ struct virtio_gpu_fpriv { | |||
209 | extern struct drm_ioctl_desc virtio_gpu_ioctls[DRM_VIRTIO_NUM_IOCTLS]; | 206 | extern struct drm_ioctl_desc virtio_gpu_ioctls[DRM_VIRTIO_NUM_IOCTLS]; |
210 | 207 | ||
211 | /* virtio_kms.c */ | 208 | /* virtio_kms.c */ |
212 | int virtio_gpu_driver_load(struct drm_device *dev, unsigned long flags); | 209 | int virtio_gpu_init(struct drm_device *dev); |
213 | void virtio_gpu_driver_unload(struct drm_device *dev); | 210 | void virtio_gpu_deinit(struct drm_device *dev); |
214 | int virtio_gpu_driver_open(struct drm_device *dev, struct drm_file *file); | 211 | int virtio_gpu_driver_open(struct drm_device *dev, struct drm_file *file); |
215 | void virtio_gpu_driver_postclose(struct drm_device *dev, struct drm_file *file); | 212 | void virtio_gpu_driver_postclose(struct drm_device *dev, struct drm_file *file); |
216 | 213 | ||
@@ -320,7 +317,7 @@ int virtio_gpu_framebuffer_init(struct drm_device *dev, | |||
320 | struct virtio_gpu_framebuffer *vgfb, | 317 | struct virtio_gpu_framebuffer *vgfb, |
321 | const struct drm_mode_fb_cmd2 *mode_cmd, | 318 | const struct drm_mode_fb_cmd2 *mode_cmd, |
322 | struct drm_gem_object *obj); | 319 | struct drm_gem_object *obj); |
323 | int virtio_gpu_modeset_init(struct virtio_gpu_device *vgdev); | 320 | void virtio_gpu_modeset_init(struct virtio_gpu_device *vgdev); |
324 | void virtio_gpu_modeset_fini(struct virtio_gpu_device *vgdev); | 321 | void virtio_gpu_modeset_fini(struct virtio_gpu_device *vgdev); |
325 | 322 | ||
326 | /* virtio_gpu_plane.c */ | 323 | /* virtio_gpu_plane.c */ |
@@ -337,7 +334,6 @@ int virtio_gpu_mmap(struct file *filp, struct vm_area_struct *vma); | |||
337 | /* virtio_gpu_fence.c */ | 334 | /* virtio_gpu_fence.c */ |
338 | struct virtio_gpu_fence *virtio_gpu_fence_alloc( | 335 | struct virtio_gpu_fence *virtio_gpu_fence_alloc( |
339 | struct virtio_gpu_device *vgdev); | 336 | struct virtio_gpu_device *vgdev); |
340 | void virtio_gpu_fence_cleanup(struct virtio_gpu_fence *fence); | ||
341 | int virtio_gpu_fence_emit(struct virtio_gpu_device *vgdev, | 337 | int virtio_gpu_fence_emit(struct virtio_gpu_device *vgdev, |
342 | struct virtio_gpu_ctrl_hdr *cmd_hdr, | 338 | struct virtio_gpu_ctrl_hdr *cmd_hdr, |
343 | struct virtio_gpu_fence *fence); | 339 | struct virtio_gpu_fence *fence); |
diff --git a/drivers/gpu/drm/virtio/virtgpu_fence.c b/drivers/gpu/drm/virtio/virtgpu_fence.c index 4d6826b27814..21bd4c4a32d1 100644 --- a/drivers/gpu/drm/virtio/virtgpu_fence.c +++ b/drivers/gpu/drm/virtio/virtgpu_fence.c | |||
@@ -81,14 +81,6 @@ struct virtio_gpu_fence *virtio_gpu_fence_alloc(struct virtio_gpu_device *vgdev) | |||
81 | return fence; | 81 | return fence; |
82 | } | 82 | } |
83 | 83 | ||
84 | void virtio_gpu_fence_cleanup(struct virtio_gpu_fence *fence) | ||
85 | { | ||
86 | if (!fence) | ||
87 | return; | ||
88 | |||
89 | dma_fence_put(&fence->f); | ||
90 | } | ||
91 | |||
92 | int virtio_gpu_fence_emit(struct virtio_gpu_device *vgdev, | 84 | int virtio_gpu_fence_emit(struct virtio_gpu_device *vgdev, |
93 | struct virtio_gpu_ctrl_hdr *cmd_hdr, | 85 | struct virtio_gpu_ctrl_hdr *cmd_hdr, |
94 | struct virtio_gpu_fence *fence) | 86 | struct virtio_gpu_fence *fence) |
diff --git a/drivers/gpu/drm/virtio/virtgpu_ioctl.c b/drivers/gpu/drm/virtio/virtgpu_ioctl.c index 161b80fee492..14ce8188c052 100644 --- a/drivers/gpu/drm/virtio/virtgpu_ioctl.c +++ b/drivers/gpu/drm/virtio/virtgpu_ioctl.c | |||
@@ -351,7 +351,7 @@ static int virtio_gpu_resource_create_ioctl(struct drm_device *dev, void *data, | |||
351 | virtio_gpu_cmd_resource_create_3d(vgdev, qobj, &rc_3d); | 351 | virtio_gpu_cmd_resource_create_3d(vgdev, qobj, &rc_3d); |
352 | ret = virtio_gpu_object_attach(vgdev, qobj, fence); | 352 | ret = virtio_gpu_object_attach(vgdev, qobj, fence); |
353 | if (ret) { | 353 | if (ret) { |
354 | virtio_gpu_fence_cleanup(fence); | 354 | dma_fence_put(&fence->f); |
355 | goto fail_backoff; | 355 | goto fail_backoff; |
356 | } | 356 | } |
357 | ttm_eu_fence_buffer_objects(&ticket, &validate_list, &fence->f); | 357 | ttm_eu_fence_buffer_objects(&ticket, &validate_list, &fence->f); |
diff --git a/drivers/gpu/drm/virtio/virtgpu_kms.c b/drivers/gpu/drm/virtio/virtgpu_kms.c index 1072064a0db2..84b6a6bf00c6 100644 --- a/drivers/gpu/drm/virtio/virtgpu_kms.c +++ b/drivers/gpu/drm/virtio/virtgpu_kms.c | |||
@@ -106,7 +106,7 @@ static void virtio_gpu_get_capsets(struct virtio_gpu_device *vgdev, | |||
106 | vgdev->num_capsets = num_capsets; | 106 | vgdev->num_capsets = num_capsets; |
107 | } | 107 | } |
108 | 108 | ||
109 | int virtio_gpu_driver_load(struct drm_device *dev, unsigned long flags) | 109 | int virtio_gpu_init(struct drm_device *dev) |
110 | { | 110 | { |
111 | static vq_callback_t *callbacks[] = { | 111 | static vq_callback_t *callbacks[] = { |
112 | virtio_gpu_ctrl_ack, virtio_gpu_cursor_ack | 112 | virtio_gpu_ctrl_ack, virtio_gpu_cursor_ack |
@@ -193,9 +193,7 @@ int virtio_gpu_driver_load(struct drm_device *dev, unsigned long flags) | |||
193 | num_capsets, &num_capsets); | 193 | num_capsets, &num_capsets); |
194 | DRM_INFO("number of cap sets: %d\n", num_capsets); | 194 | DRM_INFO("number of cap sets: %d\n", num_capsets); |
195 | 195 | ||
196 | ret = virtio_gpu_modeset_init(vgdev); | 196 | virtio_gpu_modeset_init(vgdev); |
197 | if (ret) | ||
198 | goto err_modeset; | ||
199 | 197 | ||
200 | virtio_device_ready(vgdev->vdev); | 198 | virtio_device_ready(vgdev->vdev); |
201 | vgdev->vqs_ready = true; | 199 | vgdev->vqs_ready = true; |
@@ -209,7 +207,6 @@ int virtio_gpu_driver_load(struct drm_device *dev, unsigned long flags) | |||
209 | 5 * HZ); | 207 | 5 * HZ); |
210 | return 0; | 208 | return 0; |
211 | 209 | ||
212 | err_modeset: | ||
213 | err_scanouts: | 210 | err_scanouts: |
214 | virtio_gpu_ttm_fini(vgdev); | 211 | virtio_gpu_ttm_fini(vgdev); |
215 | err_ttm: | 212 | err_ttm: |
@@ -231,7 +228,7 @@ static void virtio_gpu_cleanup_cap_cache(struct virtio_gpu_device *vgdev) | |||
231 | } | 228 | } |
232 | } | 229 | } |
233 | 230 | ||
234 | void virtio_gpu_driver_unload(struct drm_device *dev) | 231 | void virtio_gpu_deinit(struct drm_device *dev) |
235 | { | 232 | { |
236 | struct virtio_gpu_device *vgdev = dev->dev_private; | 233 | struct virtio_gpu_device *vgdev = dev->dev_private; |
237 | 234 | ||
@@ -239,6 +236,7 @@ void virtio_gpu_driver_unload(struct drm_device *dev) | |||
239 | flush_work(&vgdev->ctrlq.dequeue_work); | 236 | flush_work(&vgdev->ctrlq.dequeue_work); |
240 | flush_work(&vgdev->cursorq.dequeue_work); | 237 | flush_work(&vgdev->cursorq.dequeue_work); |
241 | flush_work(&vgdev->config_changed_work); | 238 | flush_work(&vgdev->config_changed_work); |
239 | vgdev->vdev->config->reset(vgdev->vdev); | ||
242 | vgdev->vdev->config->del_vqs(vgdev->vdev); | 240 | vgdev->vdev->config->del_vqs(vgdev->vdev); |
243 | 241 | ||
244 | virtio_gpu_modeset_fini(vgdev); | 242 | virtio_gpu_modeset_fini(vgdev); |
diff --git a/drivers/gpu/drm/virtio/virtgpu_plane.c b/drivers/gpu/drm/virtio/virtgpu_plane.c index ead5c53d4e21..024c2aa0c929 100644 --- a/drivers/gpu/drm/virtio/virtgpu_plane.c +++ b/drivers/gpu/drm/virtio/virtgpu_plane.c | |||
@@ -130,11 +130,12 @@ static void virtio_gpu_primary_plane_update(struct drm_plane *plane, | |||
130 | plane->state->src_h >> 16, | 130 | plane->state->src_h >> 16, |
131 | plane->state->src_x >> 16, | 131 | plane->state->src_x >> 16, |
132 | plane->state->src_y >> 16); | 132 | plane->state->src_y >> 16); |
133 | virtio_gpu_cmd_resource_flush(vgdev, handle, | 133 | if (handle) |
134 | plane->state->src_x >> 16, | 134 | virtio_gpu_cmd_resource_flush(vgdev, handle, |
135 | plane->state->src_y >> 16, | 135 | plane->state->src_x >> 16, |
136 | plane->state->src_w >> 16, | 136 | plane->state->src_y >> 16, |
137 | plane->state->src_h >> 16); | 137 | plane->state->src_w >> 16, |
138 | plane->state->src_h >> 16); | ||
138 | } | 139 | } |
139 | 140 | ||
140 | static int virtio_gpu_cursor_prepare_fb(struct drm_plane *plane, | 141 | static int virtio_gpu_cursor_prepare_fb(struct drm_plane *plane, |
@@ -168,8 +169,10 @@ static void virtio_gpu_cursor_cleanup_fb(struct drm_plane *plane, | |||
168 | return; | 169 | return; |
169 | 170 | ||
170 | vgfb = to_virtio_gpu_framebuffer(plane->state->fb); | 171 | vgfb = to_virtio_gpu_framebuffer(plane->state->fb); |
171 | if (vgfb->fence) | 172 | if (vgfb->fence) { |
172 | virtio_gpu_fence_cleanup(vgfb->fence); | 173 | dma_fence_put(&vgfb->fence->f); |
174 | vgfb->fence = NULL; | ||
175 | } | ||
173 | } | 176 | } |
174 | 177 | ||
175 | static void virtio_gpu_cursor_plane_update(struct drm_plane *plane, | 178 | static void virtio_gpu_cursor_plane_update(struct drm_plane *plane, |
diff --git a/drivers/gpu/drm/virtio/virtgpu_vq.c b/drivers/gpu/drm/virtio/virtgpu_vq.c index e27c4aedb809..6bc2008b0d0d 100644 --- a/drivers/gpu/drm/virtio/virtgpu_vq.c +++ b/drivers/gpu/drm/virtio/virtgpu_vq.c | |||
@@ -192,8 +192,16 @@ void virtio_gpu_dequeue_ctrl_func(struct work_struct *work) | |||
192 | 192 | ||
193 | list_for_each_entry_safe(entry, tmp, &reclaim_list, list) { | 193 | list_for_each_entry_safe(entry, tmp, &reclaim_list, list) { |
194 | resp = (struct virtio_gpu_ctrl_hdr *)entry->resp_buf; | 194 | resp = (struct virtio_gpu_ctrl_hdr *)entry->resp_buf; |
195 | if (resp->type != cpu_to_le32(VIRTIO_GPU_RESP_OK_NODATA)) | 195 | if (resp->type != cpu_to_le32(VIRTIO_GPU_RESP_OK_NODATA)) { |
196 | DRM_DEBUG("response 0x%x\n", le32_to_cpu(resp->type)); | 196 | if (resp->type >= cpu_to_le32(VIRTIO_GPU_RESP_ERR_UNSPEC)) { |
197 | struct virtio_gpu_ctrl_hdr *cmd; | ||
198 | cmd = (struct virtio_gpu_ctrl_hdr *)entry->buf; | ||
199 | DRM_ERROR("response 0x%x (command 0x%x)\n", | ||
200 | le32_to_cpu(resp->type), | ||
201 | le32_to_cpu(cmd->type)); | ||
202 | } else | ||
203 | DRM_DEBUG("response 0x%x\n", le32_to_cpu(resp->type)); | ||
204 | } | ||
197 | if (resp->flags & cpu_to_le32(VIRTIO_GPU_FLAG_FENCE)) { | 205 | if (resp->flags & cpu_to_le32(VIRTIO_GPU_FLAG_FENCE)) { |
198 | u64 f = le64_to_cpu(resp->fence_id); | 206 | u64 f = le64_to_cpu(resp->fence_id); |
199 | 207 | ||
diff --git a/drivers/gpu/drm/zte/zx_hdmi.c b/drivers/gpu/drm/zte/zx_hdmi.c index 78655269d843..9fc98bb4f3d9 100644 --- a/drivers/gpu/drm/zte/zx_hdmi.c +++ b/drivers/gpu/drm/zte/zx_hdmi.c | |||
@@ -125,7 +125,9 @@ static int zx_hdmi_config_video_avi(struct zx_hdmi *hdmi, | |||
125 | union hdmi_infoframe frame; | 125 | union hdmi_infoframe frame; |
126 | int ret; | 126 | int ret; |
127 | 127 | ||
128 | ret = drm_hdmi_avi_infoframe_from_display_mode(&frame.avi, mode, false); | 128 | ret = drm_hdmi_avi_infoframe_from_display_mode(&frame.avi, |
129 | &hdmi->connector, | ||
130 | mode); | ||
129 | if (ret) { | 131 | if (ret) { |
130 | DRM_DEV_ERROR(hdmi->dev, "failed to get avi infoframe: %d\n", | 132 | DRM_DEV_ERROR(hdmi->dev, "failed to get avi infoframe: %d\n", |
131 | ret); | 133 | ret); |
diff --git a/drivers/staging/vboxvideo/vbox_fb.c b/drivers/staging/vboxvideo/vbox_fb.c index 6b7aa23dfc0a..397496cf0bdf 100644 --- a/drivers/staging/vboxvideo/vbox_fb.c +++ b/drivers/staging/vboxvideo/vbox_fb.c | |||
@@ -95,11 +95,6 @@ int vboxfb_create(struct drm_fb_helper *helper, | |||
95 | 95 | ||
96 | strcpy(info->fix.id, "vboxdrmfb"); | 96 | strcpy(info->fix.id, "vboxdrmfb"); |
97 | 97 | ||
98 | /* | ||
99 | * The last flag forces a mode set on VT switches even if the kernel | ||
100 | * does not think it is needed. | ||
101 | */ | ||
102 | info->flags = FBINFO_DEFAULT | FBINFO_MISC_ALWAYS_SETPAR; | ||
103 | info->fbops = &vboxfb_ops; | 98 | info->fbops = &vboxfb_ops; |
104 | 99 | ||
105 | /* | 100 | /* |
diff --git a/include/drm/bridge/dw_hdmi.h b/include/drm/bridge/dw_hdmi.h index 9c56412bb2cf..9f93895dde88 100644 --- a/include/drm/bridge/dw_hdmi.h +++ b/include/drm/bridge/dw_hdmi.h | |||
@@ -10,9 +10,11 @@ | |||
10 | #ifndef __DW_HDMI__ | 10 | #ifndef __DW_HDMI__ |
11 | #define __DW_HDMI__ | 11 | #define __DW_HDMI__ |
12 | 12 | ||
13 | #include <drm/drmP.h> | 13 | struct drm_connector; |
14 | 14 | struct drm_display_mode; | |
15 | struct drm_encoder; | ||
15 | struct dw_hdmi; | 16 | struct dw_hdmi; |
17 | struct platform_device; | ||
16 | 18 | ||
17 | /** | 19 | /** |
18 | * DOC: Supported input formats and encodings | 20 | * DOC: Supported input formats and encodings |
diff --git a/include/drm/drmP.h b/include/drm/drmP.h index db94ef00940e..3f5c577c9dbd 100644 --- a/include/drm/drmP.h +++ b/include/drm/drmP.h | |||
@@ -94,23 +94,11 @@ struct dma_buf_attachment; | |||
94 | struct pci_dev; | 94 | struct pci_dev; |
95 | struct pci_controller; | 95 | struct pci_controller; |
96 | 96 | ||
97 | #define DRM_SWITCH_POWER_ON 0 | 97 | /* |
98 | #define DRM_SWITCH_POWER_OFF 1 | 98 | * NOTE: drmP.h is obsolete - do NOT add anything to this file |
99 | #define DRM_SWITCH_POWER_CHANGING 2 | 99 | * |
100 | #define DRM_SWITCH_POWER_DYNAMIC_OFF 3 | 100 | * Do not include drmP.h in new files. |
101 | 101 | * Work is ongoing to remove drmP.h includes from existing files | |
102 | /* returns true if currently okay to sleep */ | 102 | */ |
103 | static inline bool drm_can_sleep(void) | ||
104 | { | ||
105 | if (in_atomic() || in_dbg_master() || irqs_disabled()) | ||
106 | return false; | ||
107 | return true; | ||
108 | } | ||
109 | |||
110 | #if defined(CONFIG_DRM_DEBUG_SELFTEST_MODULE) | ||
111 | #define EXPORT_SYMBOL_FOR_TESTS_ONLY(x) EXPORT_SYMBOL(x) | ||
112 | #else | ||
113 | #define EXPORT_SYMBOL_FOR_TESTS_ONLY(x) | ||
114 | #endif | ||
115 | 103 | ||
116 | #endif | 104 | #endif |
diff --git a/include/drm/drm_atomic.h b/include/drm/drm_atomic.h index cac4a1b6b0e8..811b4a92568f 100644 --- a/include/drm/drm_atomic.h +++ b/include/drm/drm_atomic.h | |||
@@ -139,9 +139,9 @@ struct drm_crtc_commit { | |||
139 | /** | 139 | /** |
140 | * @abort_completion: | 140 | * @abort_completion: |
141 | * | 141 | * |
142 | * A flag that's set after drm_atomic_helper_setup_commit takes a second | 142 | * A flag that's set after drm_atomic_helper_setup_commit() takes a |
143 | * reference for the completion of $drm_crtc_state.event. It's used by | 143 | * second reference for the completion of $drm_crtc_state.event. It's |
144 | * the free code to remove the second reference if commit fails. | 144 | * used by the free code to remove the second reference if commit fails. |
145 | */ | 145 | */ |
146 | bool abort_completion; | 146 | bool abort_completion; |
147 | }; | 147 | }; |
diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h index f82701d49ea6..994161374a49 100644 --- a/include/drm/drm_connector.h +++ b/include/drm/drm_connector.h | |||
@@ -366,6 +366,12 @@ struct drm_display_info { | |||
366 | bool has_hdmi_infoframe; | 366 | bool has_hdmi_infoframe; |
367 | 367 | ||
368 | /** | 368 | /** |
369 | * @rgb_quant_range_selectable: Does the sink support selecting | ||
370 | * the RGB quantization range? | ||
371 | */ | ||
372 | bool rgb_quant_range_selectable; | ||
373 | |||
374 | /** | ||
369 | * @edid_hdmi_dc_modes: Mask of supported hdmi deep color modes. Even | 375 | * @edid_hdmi_dc_modes: Mask of supported hdmi deep color modes. Even |
370 | * more stuff redundant with @bus_formats. | 376 | * more stuff redundant with @bus_formats. |
371 | */ | 377 | */ |
diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h index 39c3900aab3c..85abd3fe9e83 100644 --- a/include/drm/drm_crtc.h +++ b/include/drm/drm_crtc.h | |||
@@ -1149,9 +1149,6 @@ static inline uint32_t drm_crtc_mask(const struct drm_crtc *crtc) | |||
1149 | return 1 << drm_crtc_index(crtc); | 1149 | return 1 << drm_crtc_index(crtc); |
1150 | } | 1150 | } |
1151 | 1151 | ||
1152 | int drm_crtc_force_disable(struct drm_crtc *crtc); | ||
1153 | int drm_crtc_force_disable_all(struct drm_device *dev); | ||
1154 | |||
1155 | int drm_mode_set_config_internal(struct drm_mode_set *set); | 1152 | int drm_mode_set_config_internal(struct drm_mode_set *set); |
1156 | struct drm_crtc *drm_crtc_from_index(struct drm_device *dev, int idx); | 1153 | struct drm_crtc *drm_crtc_from_index(struct drm_device *dev, int idx); |
1157 | 1154 | ||
diff --git a/include/drm/drm_crtc_helper.h b/include/drm/drm_crtc_helper.h index d65f034843ce..0ee9a96b70da 100644 --- a/include/drm/drm_crtc_helper.h +++ b/include/drm/drm_crtc_helper.h | |||
@@ -56,6 +56,7 @@ bool drm_helper_encoder_in_use(struct drm_encoder *encoder); | |||
56 | int drm_helper_connector_dpms(struct drm_connector *connector, int mode); | 56 | int drm_helper_connector_dpms(struct drm_connector *connector, int mode); |
57 | 57 | ||
58 | void drm_helper_resume_force_mode(struct drm_device *dev); | 58 | void drm_helper_resume_force_mode(struct drm_device *dev); |
59 | int drm_helper_force_disable_all(struct drm_device *dev); | ||
59 | 60 | ||
60 | /* drm_probe_helper.c */ | 61 | /* drm_probe_helper.c */ |
61 | int drm_helper_probe_single_connector_modes(struct drm_connector | 62 | int drm_helper_probe_single_connector_modes(struct drm_connector |
diff --git a/include/drm/drm_device.h b/include/drm/drm_device.h index 42411b3ea0c8..d5e092dccf3e 100644 --- a/include/drm/drm_device.h +++ b/include/drm/drm_device.h | |||
@@ -24,25 +24,79 @@ struct inode; | |||
24 | struct pci_dev; | 24 | struct pci_dev; |
25 | struct pci_controller; | 25 | struct pci_controller; |
26 | 26 | ||
27 | |||
27 | /** | 28 | /** |
28 | * DRM device structure. This structure represent a complete card that | 29 | * enum drm_switch_power - power state of drm device |
30 | */ | ||
31 | |||
32 | enum switch_power_state { | ||
33 | /** @DRM_SWITCH_POWER_ON: Power state is ON */ | ||
34 | DRM_SWITCH_POWER_ON = 0, | ||
35 | |||
36 | /** @DRM_SWITCH_POWER_OFF: Power state is OFF */ | ||
37 | DRM_SWITCH_POWER_OFF = 1, | ||
38 | |||
39 | /** @DRM_SWITCH_POWER_CHANGING: Power state is changing */ | ||
40 | DRM_SWITCH_POWER_CHANGING = 2, | ||
41 | |||
42 | /** @DRM_SWITCH_POWER_DYNAMIC_OFF: Suspended */ | ||
43 | DRM_SWITCH_POWER_DYNAMIC_OFF = 3, | ||
44 | }; | ||
45 | |||
46 | /** | ||
47 | * struct drm_device - DRM device structure | ||
48 | * | ||
49 | * This structure represent a complete card that | ||
29 | * may contain multiple heads. | 50 | * may contain multiple heads. |
30 | */ | 51 | */ |
31 | struct drm_device { | 52 | struct drm_device { |
32 | struct list_head legacy_dev_list;/**< list of devices per driver for stealth attach cleanup */ | 53 | /** |
33 | int if_version; /**< Highest interface version set */ | 54 | * @legacy_dev_list: |
34 | 55 | * | |
35 | /** \name Lifetime Management */ | 56 | * List of devices per driver for stealth attach cleanup |
36 | /*@{ */ | 57 | */ |
37 | struct kref ref; /**< Object ref-count */ | 58 | struct list_head legacy_dev_list; |
38 | struct device *dev; /**< Device structure of bus-device */ | 59 | |
39 | struct drm_driver *driver; /**< DRM driver managing the device */ | 60 | /** @if_version: Highest interface version set */ |
40 | void *dev_private; /**< DRM driver private data */ | 61 | int if_version; |
41 | struct drm_minor *primary; /**< Primary node */ | 62 | |
42 | struct drm_minor *render; /**< Render node */ | 63 | /** @ref: Object ref-count */ |
64 | struct kref ref; | ||
65 | |||
66 | /** @dev: Device structure of bus-device */ | ||
67 | struct device *dev; | ||
68 | |||
69 | /** @driver: DRM driver managing the device */ | ||
70 | struct drm_driver *driver; | ||
71 | |||
72 | /** | ||
73 | * @dev_private: | ||
74 | * | ||
75 | * DRM driver private data. Instead of using this pointer it is | ||
76 | * recommended that drivers use drm_dev_init() and embed struct | ||
77 | * &drm_device in their larger per-device structure. | ||
78 | */ | ||
79 | void *dev_private; | ||
80 | |||
81 | /** @primary: Primary node */ | ||
82 | struct drm_minor *primary; | ||
83 | |||
84 | /** @render: Render node */ | ||
85 | struct drm_minor *render; | ||
86 | |||
87 | /** | ||
88 | * @registered: | ||
89 | * | ||
90 | * Internally used by drm_dev_register() and drm_connector_register(). | ||
91 | */ | ||
43 | bool registered; | 92 | bool registered; |
44 | 93 | ||
45 | /* currently active master for this device. Protected by master_mutex */ | 94 | /** |
95 | * @master: | ||
96 | * | ||
97 | * Currently active master for this device. | ||
98 | * Protected by &master_mutex | ||
99 | */ | ||
46 | struct drm_master *master; | 100 | struct drm_master *master; |
47 | 101 | ||
48 | /** | 102 | /** |
@@ -63,76 +117,65 @@ struct drm_device { | |||
63 | */ | 117 | */ |
64 | bool unplugged; | 118 | bool unplugged; |
65 | 119 | ||
66 | struct inode *anon_inode; /**< inode for private address-space */ | 120 | /** @anon_inode: inode for private address-space */ |
67 | char *unique; /**< unique name of the device */ | 121 | struct inode *anon_inode; |
68 | /*@} */ | 122 | |
123 | /** @unique: Unique name of the device */ | ||
124 | char *unique; | ||
69 | 125 | ||
70 | /** \name Locks */ | 126 | /** |
71 | /*@{ */ | 127 | * @struct_mutex: |
72 | struct mutex struct_mutex; /**< For others */ | 128 | * |
73 | struct mutex master_mutex; /**< For drm_minor::master and drm_file::is_master */ | 129 | * Lock for others (not &drm_minor.master and &drm_file.is_master) |
74 | /*@} */ | 130 | */ |
131 | struct mutex struct_mutex; | ||
75 | 132 | ||
76 | /** \name Usage Counters */ | 133 | /** |
77 | /*@{ */ | 134 | * @master_mutex: |
78 | int open_count; /**< Outstanding files open, protected by drm_global_mutex. */ | 135 | * |
79 | spinlock_t buf_lock; /**< For drm_device::buf_use and a few other things. */ | 136 | * Lock for &drm_minor.master and &drm_file.is_master |
80 | int buf_use; /**< Buffers in use -- cannot alloc */ | 137 | */ |
81 | atomic_t buf_alloc; /**< Buffer allocation in progress */ | 138 | struct mutex master_mutex; |
82 | /*@} */ | 139 | |
140 | /** | ||
141 | * @open_count: | ||
142 | * | ||
143 | * Usage counter for outstanding files open, | ||
144 | * protected by drm_global_mutex | ||
145 | */ | ||
146 | int open_count; | ||
83 | 147 | ||
148 | /** @filelist_mutex: Protects @filelist. */ | ||
84 | struct mutex filelist_mutex; | 149 | struct mutex filelist_mutex; |
150 | /** | ||
151 | * @filelist: | ||
152 | * | ||
153 | * List of userspace clients, linked through &drm_file.lhead. | ||
154 | */ | ||
85 | struct list_head filelist; | 155 | struct list_head filelist; |
86 | 156 | ||
87 | /** | 157 | /** |
88 | * @filelist_internal: | 158 | * @filelist_internal: |
89 | * | 159 | * |
90 | * List of open DRM files for in-kernel clients. Protected by @filelist_mutex. | 160 | * List of open DRM files for in-kernel clients. |
161 | * Protected by &filelist_mutex. | ||
91 | */ | 162 | */ |
92 | struct list_head filelist_internal; | 163 | struct list_head filelist_internal; |
93 | 164 | ||
94 | /** | 165 | /** |
95 | * @clientlist_mutex: | 166 | * @clientlist_mutex: |
96 | * | 167 | * |
97 | * Protects @clientlist access. | 168 | * Protects &clientlist access. |
98 | */ | 169 | */ |
99 | struct mutex clientlist_mutex; | 170 | struct mutex clientlist_mutex; |
100 | 171 | ||
101 | /** | 172 | /** |
102 | * @clientlist: | 173 | * @clientlist: |
103 | * | 174 | * |
104 | * List of in-kernel clients. Protected by @clientlist_mutex. | 175 | * List of in-kernel clients. Protected by &clientlist_mutex. |
105 | */ | 176 | */ |
106 | struct list_head clientlist; | 177 | struct list_head clientlist; |
107 | 178 | ||
108 | /** \name Memory management */ | ||
109 | /*@{ */ | ||
110 | struct list_head maplist; /**< Linked list of regions */ | ||
111 | struct drm_open_hash map_hash; /**< User token hash table for maps */ | ||
112 | |||
113 | /** \name Context handle management */ | ||
114 | /*@{ */ | ||
115 | struct list_head ctxlist; /**< Linked list of context handles */ | ||
116 | struct mutex ctxlist_mutex; /**< For ctxlist */ | ||
117 | |||
118 | struct idr ctx_idr; | ||
119 | |||
120 | struct list_head vmalist; /**< List of vmas (for debugging) */ | ||
121 | |||
122 | /*@} */ | ||
123 | |||
124 | /** \name DMA support */ | ||
125 | /*@{ */ | ||
126 | struct drm_device_dma *dma; /**< Optional pointer for DMA support */ | ||
127 | /*@} */ | ||
128 | |||
129 | /** \name Context support */ | ||
130 | /*@{ */ | ||
131 | |||
132 | __volatile__ long context_flag; /**< Context swapping flag */ | ||
133 | int last_context; /**< Last current context */ | ||
134 | /*@} */ | ||
135 | |||
136 | /** | 179 | /** |
137 | * @irq_enabled: | 180 | * @irq_enabled: |
138 | * | 181 | * |
@@ -141,6 +184,10 @@ struct drm_device { | |||
141 | * to true manually. | 184 | * to true manually. |
142 | */ | 185 | */ |
143 | bool irq_enabled; | 186 | bool irq_enabled; |
187 | |||
188 | /** | ||
189 | * @irq: Used by the drm_irq_install() and drm_irq_unistall() helpers. | ||
190 | */ | ||
144 | int irq; | 191 | int irq; |
145 | 192 | ||
146 | /** | 193 | /** |
@@ -168,7 +215,16 @@ struct drm_device { | |||
168 | */ | 215 | */ |
169 | struct drm_vblank_crtc *vblank; | 216 | struct drm_vblank_crtc *vblank; |
170 | 217 | ||
171 | spinlock_t vblank_time_lock; /**< Protects vblank count and time updates during vblank enable/disable */ | 218 | /** |
219 | * @vblank_time_lock: | ||
220 | * | ||
221 | * Protects vblank count and time updates during vblank enable/disable | ||
222 | */ | ||
223 | spinlock_t vblank_time_lock; | ||
224 | /** | ||
225 | * @vbl_lock: Top-level vblank references lock, wraps the low-level | ||
226 | * @vblank_time_lock. | ||
227 | */ | ||
172 | spinlock_t vbl_lock; | 228 | spinlock_t vbl_lock; |
173 | 229 | ||
174 | /** | 230 | /** |
@@ -184,45 +240,61 @@ struct drm_device { | |||
184 | * races and imprecision over longer time periods, hence exposing a | 240 | * races and imprecision over longer time periods, hence exposing a |
185 | * hardware vblank counter is always recommended. | 241 | * hardware vblank counter is always recommended. |
186 | * | 242 | * |
187 | * If non-zeor, &drm_crtc_funcs.get_vblank_counter must be set. | 243 | * This is the statically configured device wide maximum. The driver |
244 | * can instead choose to use a runtime configurable per-crtc value | ||
245 | * &drm_vblank_crtc.max_vblank_count, in which case @max_vblank_count | ||
246 | * must be left at zero. See drm_crtc_set_max_vblank_count() on how | ||
247 | * to use the per-crtc value. | ||
248 | * | ||
249 | * If non-zero, &drm_crtc_funcs.get_vblank_counter must be set. | ||
188 | */ | 250 | */ |
189 | u32 max_vblank_count; /**< size of vblank counter register */ | 251 | u32 max_vblank_count; |
252 | |||
253 | /** @vblank_event_list: List of vblank events */ | ||
254 | struct list_head vblank_event_list; | ||
190 | 255 | ||
191 | /** | 256 | /** |
192 | * List of events | 257 | * @event_lock: |
258 | * | ||
259 | * Protects @vblank_event_list and event delivery in | ||
260 | * general. See drm_send_event() and drm_send_event_locked(). | ||
193 | */ | 261 | */ |
194 | struct list_head vblank_event_list; | ||
195 | spinlock_t event_lock; | 262 | spinlock_t event_lock; |
196 | 263 | ||
197 | /*@} */ | 264 | /** @agp: AGP data */ |
265 | struct drm_agp_head *agp; | ||
198 | 266 | ||
199 | struct drm_agp_head *agp; /**< AGP data */ | 267 | /** @pdev: PCI device structure */ |
268 | struct pci_dev *pdev; | ||
200 | 269 | ||
201 | struct pci_dev *pdev; /**< PCI device structure */ | ||
202 | #ifdef __alpha__ | 270 | #ifdef __alpha__ |
271 | /** @hose: PCI hose, only used on ALPHA platforms. */ | ||
203 | struct pci_controller *hose; | 272 | struct pci_controller *hose; |
204 | #endif | 273 | #endif |
274 | /** @num_crtcs: Number of CRTCs on this device */ | ||
275 | unsigned int num_crtcs; | ||
205 | 276 | ||
206 | struct drm_sg_mem *sg; /**< Scatter gather memory */ | 277 | /** @mode_config: Current mode config */ |
207 | unsigned int num_crtcs; /**< Number of CRTCs on this device */ | 278 | struct drm_mode_config mode_config; |
208 | 279 | ||
209 | struct { | 280 | /** @object_name_lock: GEM information */ |
210 | int context; | ||
211 | struct drm_hw_lock *lock; | ||
212 | } sigdata; | ||
213 | |||
214 | struct drm_local_map *agp_buffer_map; | ||
215 | unsigned int agp_buffer_token; | ||
216 | |||
217 | struct drm_mode_config mode_config; /**< Current mode config */ | ||
218 | |||
219 | /** \name GEM information */ | ||
220 | /*@{ */ | ||
221 | struct mutex object_name_lock; | 281 | struct mutex object_name_lock; |
282 | |||
283 | /** @object_name_idr: GEM information */ | ||
222 | struct idr object_name_idr; | 284 | struct idr object_name_idr; |
285 | |||
286 | /** @vma_offset_manager: GEM information */ | ||
223 | struct drm_vma_offset_manager *vma_offset_manager; | 287 | struct drm_vma_offset_manager *vma_offset_manager; |
224 | /*@} */ | 288 | |
225 | int switch_power_state; | 289 | /** |
290 | * @switch_power_state: | ||
291 | * | ||
292 | * Power state of the client. | ||
293 | * Used by drivers supporting the switcheroo driver. | ||
294 | * The state is maintained in the | ||
295 | * &vga_switcheroo_client_ops.set_gpu_state callback | ||
296 | */ | ||
297 | enum switch_power_state switch_power_state; | ||
226 | 298 | ||
227 | /** | 299 | /** |
228 | * @fb_helper: | 300 | * @fb_helper: |
@@ -231,6 +303,56 @@ struct drm_device { | |||
231 | * Set by drm_fb_helper_init() and cleared by drm_fb_helper_fini(). | 303 | * Set by drm_fb_helper_init() and cleared by drm_fb_helper_fini(). |
232 | */ | 304 | */ |
233 | struct drm_fb_helper *fb_helper; | 305 | struct drm_fb_helper *fb_helper; |
306 | |||
307 | /* Everything below here is for legacy driver, never use! */ | ||
308 | /* private: */ | ||
309 | |||
310 | /* Context handle management - linked list of context handles */ | ||
311 | struct list_head ctxlist; | ||
312 | |||
313 | /* Context handle management - mutex for &ctxlist */ | ||
314 | struct mutex ctxlist_mutex; | ||
315 | |||
316 | /* Context handle management */ | ||
317 | struct idr ctx_idr; | ||
318 | |||
319 | /* Memory management - linked list of regions */ | ||
320 | struct list_head maplist; | ||
321 | |||
322 | /* Memory management - user token hash table for maps */ | ||
323 | struct drm_open_hash map_hash; | ||
324 | |||
325 | /* Context handle management - list of vmas (for debugging) */ | ||
326 | struct list_head vmalist; | ||
327 | |||
328 | /* Optional pointer for DMA support */ | ||
329 | struct drm_device_dma *dma; | ||
330 | |||
331 | /* Context swapping flag */ | ||
332 | __volatile__ long context_flag; | ||
333 | |||
334 | /* Last current context */ | ||
335 | int last_context; | ||
336 | |||
337 | /* Lock for &buf_use and a few other things. */ | ||
338 | spinlock_t buf_lock; | ||
339 | |||
340 | /* Usage counter for buffers in use -- cannot alloc */ | ||
341 | int buf_use; | ||
342 | |||
343 | /* Buffer allocation in progress */ | ||
344 | atomic_t buf_alloc; | ||
345 | |||
346 | struct { | ||
347 | int context; | ||
348 | struct drm_hw_lock *lock; | ||
349 | } sigdata; | ||
350 | |||
351 | struct drm_local_map *agp_buffer_map; | ||
352 | unsigned int agp_buffer_token; | ||
353 | |||
354 | /* Scatter gather memory */ | ||
355 | struct drm_sg_mem *sg; | ||
234 | }; | 356 | }; |
235 | 357 | ||
236 | #endif | 358 | #endif |
diff --git a/include/drm/drm_dp_mst_helper.h b/include/drm/drm_dp_mst_helper.h index 371cc2816477..451d020f0137 100644 --- a/include/drm/drm_dp_mst_helper.h +++ b/include/drm/drm_dp_mst_helper.h | |||
@@ -44,7 +44,6 @@ struct drm_dp_vcpi { | |||
44 | 44 | ||
45 | /** | 45 | /** |
46 | * struct drm_dp_mst_port - MST port | 46 | * struct drm_dp_mst_port - MST port |
47 | * @kref: reference count for this port. | ||
48 | * @port_num: port number | 47 | * @port_num: port number |
49 | * @input: if this port is an input port. | 48 | * @input: if this port is an input port. |
50 | * @mcs: message capability status - DP 1.2 spec. | 49 | * @mcs: message capability status - DP 1.2 spec. |
@@ -67,7 +66,18 @@ struct drm_dp_vcpi { | |||
67 | * in the MST topology. | 66 | * in the MST topology. |
68 | */ | 67 | */ |
69 | struct drm_dp_mst_port { | 68 | struct drm_dp_mst_port { |
70 | struct kref kref; | 69 | /** |
70 | * @topology_kref: refcount for this port's lifetime in the topology, | ||
71 | * only the DP MST helpers should need to touch this | ||
72 | */ | ||
73 | struct kref topology_kref; | ||
74 | |||
75 | /** | ||
76 | * @malloc_kref: refcount for the memory allocation containing this | ||
77 | * structure. See drm_dp_mst_get_port_malloc() and | ||
78 | * drm_dp_mst_put_port_malloc(). | ||
79 | */ | ||
80 | struct kref malloc_kref; | ||
71 | 81 | ||
72 | u8 port_num; | 82 | u8 port_num; |
73 | bool input; | 83 | bool input; |
@@ -102,7 +112,6 @@ struct drm_dp_mst_port { | |||
102 | 112 | ||
103 | /** | 113 | /** |
104 | * struct drm_dp_mst_branch - MST branch device. | 114 | * struct drm_dp_mst_branch - MST branch device. |
105 | * @kref: reference count for this port. | ||
106 | * @rad: Relative Address to talk to this branch device. | 115 | * @rad: Relative Address to talk to this branch device. |
107 | * @lct: Link count total to talk to this branch device. | 116 | * @lct: Link count total to talk to this branch device. |
108 | * @num_ports: number of ports on the branch. | 117 | * @num_ports: number of ports on the branch. |
@@ -121,7 +130,19 @@ struct drm_dp_mst_port { | |||
121 | * to downstream port of parent branches. | 130 | * to downstream port of parent branches. |
122 | */ | 131 | */ |
123 | struct drm_dp_mst_branch { | 132 | struct drm_dp_mst_branch { |
124 | struct kref kref; | 133 | /** |
134 | * @topology_kref: refcount for this branch device's lifetime in the | ||
135 | * topology, only the DP MST helpers should need to touch this | ||
136 | */ | ||
137 | struct kref topology_kref; | ||
138 | |||
139 | /** | ||
140 | * @malloc_kref: refcount for the memory allocation containing this | ||
141 | * structure. See drm_dp_mst_get_mstb_malloc() and | ||
142 | * drm_dp_mst_put_mstb_malloc(). | ||
143 | */ | ||
144 | struct kref malloc_kref; | ||
145 | |||
125 | u8 rad[8]; | 146 | u8 rad[8]; |
126 | u8 lct; | 147 | u8 lct; |
127 | int num_ports; | 148 | int num_ports; |
@@ -404,9 +425,15 @@ struct drm_dp_payload { | |||
404 | 425 | ||
405 | #define to_dp_mst_topology_state(x) container_of(x, struct drm_dp_mst_topology_state, base) | 426 | #define to_dp_mst_topology_state(x) container_of(x, struct drm_dp_mst_topology_state, base) |
406 | 427 | ||
428 | struct drm_dp_vcpi_allocation { | ||
429 | struct drm_dp_mst_port *port; | ||
430 | int vcpi; | ||
431 | struct list_head next; | ||
432 | }; | ||
433 | |||
407 | struct drm_dp_mst_topology_state { | 434 | struct drm_dp_mst_topology_state { |
408 | struct drm_private_state base; | 435 | struct drm_private_state base; |
409 | int avail_slots; | 436 | struct list_head vcpis; |
410 | struct drm_dp_mst_topology_mgr *mgr; | 437 | struct drm_dp_mst_topology_mgr *mgr; |
411 | }; | 438 | }; |
412 | 439 | ||
@@ -617,13 +644,115 @@ void drm_dp_mst_topology_mgr_suspend(struct drm_dp_mst_topology_mgr *mgr); | |||
617 | int drm_dp_mst_topology_mgr_resume(struct drm_dp_mst_topology_mgr *mgr); | 644 | int drm_dp_mst_topology_mgr_resume(struct drm_dp_mst_topology_mgr *mgr); |
618 | struct drm_dp_mst_topology_state *drm_atomic_get_mst_topology_state(struct drm_atomic_state *state, | 645 | struct drm_dp_mst_topology_state *drm_atomic_get_mst_topology_state(struct drm_atomic_state *state, |
619 | struct drm_dp_mst_topology_mgr *mgr); | 646 | struct drm_dp_mst_topology_mgr *mgr); |
620 | int drm_dp_atomic_find_vcpi_slots(struct drm_atomic_state *state, | 647 | int __must_check |
621 | struct drm_dp_mst_topology_mgr *mgr, | 648 | drm_dp_atomic_find_vcpi_slots(struct drm_atomic_state *state, |
622 | struct drm_dp_mst_port *port, int pbn); | 649 | struct drm_dp_mst_topology_mgr *mgr, |
623 | int drm_dp_atomic_release_vcpi_slots(struct drm_atomic_state *state, | 650 | struct drm_dp_mst_port *port, int pbn); |
624 | struct drm_dp_mst_topology_mgr *mgr, | 651 | int __must_check |
625 | int slots); | 652 | drm_dp_atomic_release_vcpi_slots(struct drm_atomic_state *state, |
653 | struct drm_dp_mst_topology_mgr *mgr, | ||
654 | struct drm_dp_mst_port *port); | ||
626 | int drm_dp_send_power_updown_phy(struct drm_dp_mst_topology_mgr *mgr, | 655 | int drm_dp_send_power_updown_phy(struct drm_dp_mst_topology_mgr *mgr, |
627 | struct drm_dp_mst_port *port, bool power_up); | 656 | struct drm_dp_mst_port *port, bool power_up); |
657 | int __must_check drm_dp_mst_atomic_check(struct drm_atomic_state *state); | ||
658 | |||
659 | void drm_dp_mst_get_port_malloc(struct drm_dp_mst_port *port); | ||
660 | void drm_dp_mst_put_port_malloc(struct drm_dp_mst_port *port); | ||
661 | |||
662 | extern const struct drm_private_state_funcs drm_dp_mst_topology_state_funcs; | ||
663 | |||
664 | /** | ||
665 | * __drm_dp_mst_state_iter_get - private atomic state iterator function for | ||
666 | * macro-internal use | ||
667 | * @state: &struct drm_atomic_state pointer | ||
668 | * @mgr: pointer to the &struct drm_dp_mst_topology_mgr iteration cursor | ||
669 | * @old_state: optional pointer to the old &struct drm_dp_mst_topology_state | ||
670 | * iteration cursor | ||
671 | * @new_state: optional pointer to the new &struct drm_dp_mst_topology_state | ||
672 | * iteration cursor | ||
673 | * @i: int iteration cursor, for macro-internal use | ||
674 | * | ||
675 | * Used by for_each_oldnew_mst_mgr_in_state(), | ||
676 | * for_each_old_mst_mgr_in_state(), and for_each_new_mst_mgr_in_state(). Don't | ||
677 | * call this directly. | ||
678 | * | ||
679 | * Returns: | ||
680 | * True if the current &struct drm_private_obj is a &struct | ||
681 | * drm_dp_mst_topology_mgr, false otherwise. | ||
682 | */ | ||
683 | static inline bool | ||
684 | __drm_dp_mst_state_iter_get(struct drm_atomic_state *state, | ||
685 | struct drm_dp_mst_topology_mgr **mgr, | ||
686 | struct drm_dp_mst_topology_state **old_state, | ||
687 | struct drm_dp_mst_topology_state **new_state, | ||
688 | int i) | ||
689 | { | ||
690 | struct __drm_private_objs_state *objs_state = &state->private_objs[i]; | ||
691 | |||
692 | if (objs_state->ptr->funcs != &drm_dp_mst_topology_state_funcs) | ||
693 | return false; | ||
694 | |||
695 | *mgr = to_dp_mst_topology_mgr(objs_state->ptr); | ||
696 | if (old_state) | ||
697 | *old_state = to_dp_mst_topology_state(objs_state->old_state); | ||
698 | if (new_state) | ||
699 | *new_state = to_dp_mst_topology_state(objs_state->new_state); | ||
700 | |||
701 | return true; | ||
702 | } | ||
703 | |||
704 | /** | ||
705 | * for_each_oldnew_mst_mgr_in_state - iterate over all DP MST topology | ||
706 | * managers in an atomic update | ||
707 | * @__state: &struct drm_atomic_state pointer | ||
708 | * @mgr: &struct drm_dp_mst_topology_mgr iteration cursor | ||
709 | * @old_state: &struct drm_dp_mst_topology_state iteration cursor for the old | ||
710 | * state | ||
711 | * @new_state: &struct drm_dp_mst_topology_state iteration cursor for the new | ||
712 | * state | ||
713 | * @__i: int iteration cursor, for macro-internal use | ||
714 | * | ||
715 | * This iterates over all DRM DP MST topology managers in an atomic update, | ||
716 | * tracking both old and new state. This is useful in places where the state | ||
717 | * delta needs to be considered, for example in atomic check functions. | ||
718 | */ | ||
719 | #define for_each_oldnew_mst_mgr_in_state(__state, mgr, old_state, new_state, __i) \ | ||
720 | for ((__i) = 0; (__i) < (__state)->num_private_objs; (__i)++) \ | ||
721 | for_each_if(__drm_dp_mst_state_iter_get((__state), &(mgr), &(old_state), &(new_state), (__i))) | ||
722 | |||
723 | /** | ||
724 | * for_each_old_mst_mgr_in_state - iterate over all DP MST topology managers | ||
725 | * in an atomic update | ||
726 | * @__state: &struct drm_atomic_state pointer | ||
727 | * @mgr: &struct drm_dp_mst_topology_mgr iteration cursor | ||
728 | * @old_state: &struct drm_dp_mst_topology_state iteration cursor for the old | ||
729 | * state | ||
730 | * @__i: int iteration cursor, for macro-internal use | ||
731 | * | ||
732 | * This iterates over all DRM DP MST topology managers in an atomic update, | ||
733 | * tracking only the old state. This is useful in disable functions, where we | ||
734 | * need the old state the hardware is still in. | ||
735 | */ | ||
736 | #define for_each_old_mst_mgr_in_state(__state, mgr, old_state, __i) \ | ||
737 | for ((__i) = 0; (__i) < (__state)->num_private_objs; (__i)++) \ | ||
738 | for_each_if(__drm_dp_mst_state_iter_get((__state), &(mgr), &(old_state), NULL, (__i))) | ||
739 | |||
740 | /** | ||
741 | * for_each_new_mst_mgr_in_state - iterate over all DP MST topology managers | ||
742 | * in an atomic update | ||
743 | * @__state: &struct drm_atomic_state pointer | ||
744 | * @mgr: &struct drm_dp_mst_topology_mgr iteration cursor | ||
745 | * @new_state: &struct drm_dp_mst_topology_state iteration cursor for the new | ||
746 | * state | ||
747 | * @__i: int iteration cursor, for macro-internal use | ||
748 | * | ||
749 | * This iterates over all DRM DP MST topology managers in an atomic update, | ||
750 | * tracking only the new state. This is useful in enable functions, where we | ||
751 | * need the new state the hardware should be in when the atomic commit | ||
752 | * operation has completed. | ||
753 | */ | ||
754 | #define for_each_new_mst_mgr_in_state(__state, mgr, new_state, __i) \ | ||
755 | for ((__i) = 0; (__i) < (__state)->num_private_objs; (__i)++) \ | ||
756 | for_each_if(__drm_dp_mst_state_iter_get((__state), &(mgr), NULL, &(new_state), (__i))) | ||
628 | 757 | ||
629 | #endif | 758 | #endif |
diff --git a/include/drm/drm_edid.h b/include/drm/drm_edid.h index e3c404833115..8dc1a081fb36 100644 --- a/include/drm/drm_edid.h +++ b/include/drm/drm_edid.h | |||
@@ -352,18 +352,17 @@ drm_load_edid_firmware(struct drm_connector *connector) | |||
352 | 352 | ||
353 | int | 353 | int |
354 | drm_hdmi_avi_infoframe_from_display_mode(struct hdmi_avi_infoframe *frame, | 354 | drm_hdmi_avi_infoframe_from_display_mode(struct hdmi_avi_infoframe *frame, |
355 | const struct drm_display_mode *mode, | 355 | struct drm_connector *connector, |
356 | bool is_hdmi2_sink); | 356 | const struct drm_display_mode *mode); |
357 | int | 357 | int |
358 | drm_hdmi_vendor_infoframe_from_display_mode(struct hdmi_vendor_infoframe *frame, | 358 | drm_hdmi_vendor_infoframe_from_display_mode(struct hdmi_vendor_infoframe *frame, |
359 | struct drm_connector *connector, | 359 | struct drm_connector *connector, |
360 | const struct drm_display_mode *mode); | 360 | const struct drm_display_mode *mode); |
361 | void | 361 | void |
362 | drm_hdmi_avi_infoframe_quant_range(struct hdmi_avi_infoframe *frame, | 362 | drm_hdmi_avi_infoframe_quant_range(struct hdmi_avi_infoframe *frame, |
363 | struct drm_connector *connector, | ||
363 | const struct drm_display_mode *mode, | 364 | const struct drm_display_mode *mode, |
364 | enum hdmi_quantization_range rgb_quant_range, | 365 | enum hdmi_quantization_range rgb_quant_range); |
365 | bool rgb_quant_range_selectable, | ||
366 | bool is_hdmi2_sink); | ||
367 | 366 | ||
368 | /** | 367 | /** |
369 | * drm_eld_mnl - Get ELD monitor name length in bytes. | 368 | * drm_eld_mnl - Get ELD monitor name length in bytes. |
@@ -471,7 +470,6 @@ u8 drm_match_cea_mode(const struct drm_display_mode *to_match); | |||
471 | enum hdmi_picture_aspect drm_get_cea_aspect_ratio(const u8 video_code); | 470 | enum hdmi_picture_aspect drm_get_cea_aspect_ratio(const u8 video_code); |
472 | bool drm_detect_hdmi_monitor(struct edid *edid); | 471 | bool drm_detect_hdmi_monitor(struct edid *edid); |
473 | bool drm_detect_monitor_audio(struct edid *edid); | 472 | bool drm_detect_monitor_audio(struct edid *edid); |
474 | bool drm_rgb_quant_range_selectable(struct edid *edid); | ||
475 | enum hdmi_quantization_range | 473 | enum hdmi_quantization_range |
476 | drm_default_rgb_quant_range(const struct drm_display_mode *mode); | 474 | drm_default_rgb_quant_range(const struct drm_display_mode *mode); |
477 | int drm_add_modes_noedid(struct drm_connector *connector, | 475 | int drm_add_modes_noedid(struct drm_connector *connector, |
diff --git a/include/drm/drm_encoder_slave.h b/include/drm/drm_encoder_slave.h index 1107b4b1c599..a09864f6d684 100644 --- a/include/drm/drm_encoder_slave.h +++ b/include/drm/drm_encoder_slave.h | |||
@@ -27,7 +27,6 @@ | |||
27 | #ifndef __DRM_ENCODER_SLAVE_H__ | 27 | #ifndef __DRM_ENCODER_SLAVE_H__ |
28 | #define __DRM_ENCODER_SLAVE_H__ | 28 | #define __DRM_ENCODER_SLAVE_H__ |
29 | 29 | ||
30 | #include <drm/drmP.h> | ||
31 | #include <drm/drm_crtc.h> | 30 | #include <drm/drm_crtc.h> |
32 | #include <drm/drm_encoder.h> | 31 | #include <drm/drm_encoder.h> |
33 | 32 | ||
diff --git a/include/drm/drm_framebuffer.h b/include/drm/drm_framebuffer.h index c94acedfb08e..f0b34c977ec5 100644 --- a/include/drm/drm_framebuffer.h +++ b/include/drm/drm_framebuffer.h | |||
@@ -23,13 +23,17 @@ | |||
23 | #ifndef __DRM_FRAMEBUFFER_H__ | 23 | #ifndef __DRM_FRAMEBUFFER_H__ |
24 | #define __DRM_FRAMEBUFFER_H__ | 24 | #define __DRM_FRAMEBUFFER_H__ |
25 | 25 | ||
26 | #include <linux/list.h> | ||
27 | #include <linux/ctype.h> | 26 | #include <linux/ctype.h> |
27 | #include <linux/list.h> | ||
28 | #include <linux/sched.h> | ||
29 | |||
28 | #include <drm/drm_mode_object.h> | 30 | #include <drm/drm_mode_object.h> |
29 | 31 | ||
30 | struct drm_framebuffer; | 32 | struct drm_clip_rect; |
31 | struct drm_file; | ||
32 | struct drm_device; | 33 | struct drm_device; |
34 | struct drm_file; | ||
35 | struct drm_framebuffer; | ||
36 | struct drm_gem_object; | ||
33 | 37 | ||
34 | /** | 38 | /** |
35 | * struct drm_framebuffer_funcs - framebuffer hooks | 39 | * struct drm_framebuffer_funcs - framebuffer hooks |
diff --git a/include/drm/drm_gem_cma_helper.h b/include/drm/drm_gem_cma_helper.h index 07c504940ba1..947ac95eb24a 100644 --- a/include/drm/drm_gem_cma_helper.h +++ b/include/drm/drm_gem_cma_helper.h | |||
@@ -2,9 +2,12 @@ | |||
2 | #ifndef __DRM_GEM_CMA_HELPER_H__ | 2 | #ifndef __DRM_GEM_CMA_HELPER_H__ |
3 | #define __DRM_GEM_CMA_HELPER_H__ | 3 | #define __DRM_GEM_CMA_HELPER_H__ |
4 | 4 | ||
5 | #include <drm/drmP.h> | 5 | #include <drm/drm_file.h> |
6 | #include <drm/drm_ioctl.h> | ||
6 | #include <drm/drm_gem.h> | 7 | #include <drm/drm_gem.h> |
7 | 8 | ||
9 | struct drm_mode_create_dumb; | ||
10 | |||
8 | /** | 11 | /** |
9 | * struct drm_gem_cma_object - GEM object backed by CMA memory allocations | 12 | * struct drm_gem_cma_object - GEM object backed by CMA memory allocations |
10 | * @base: base GEM object | 13 | * @base: base GEM object |
diff --git a/include/drm/drm_modes.h b/include/drm/drm_modes.h index baded6514456..be4fed97e727 100644 --- a/include/drm/drm_modes.h +++ b/include/drm/drm_modes.h | |||
@@ -136,8 +136,7 @@ enum drm_mode_status { | |||
136 | .hdisplay = (hd), .hsync_start = (hss), .hsync_end = (hse), \ | 136 | .hdisplay = (hd), .hsync_start = (hss), .hsync_end = (hse), \ |
137 | .htotal = (ht), .hskew = (hsk), .vdisplay = (vd), \ | 137 | .htotal = (ht), .hskew = (hsk), .vdisplay = (vd), \ |
138 | .vsync_start = (vss), .vsync_end = (vse), .vtotal = (vt), \ | 138 | .vsync_start = (vss), .vsync_end = (vse), .vtotal = (vt), \ |
139 | .vscan = (vs), .flags = (f), \ | 139 | .vscan = (vs), .flags = (f) |
140 | .base.type = DRM_MODE_OBJECT_MODE | ||
141 | 140 | ||
142 | #define CRTC_INTERLACE_HALVE_V (1 << 0) /* halve V values for interlacing */ | 141 | #define CRTC_INTERLACE_HALVE_V (1 << 0) /* halve V values for interlacing */ |
143 | #define CRTC_STEREO_DOUBLE (1 << 1) /* adjust timings for stereo modes */ | 142 | #define CRTC_STEREO_DOUBLE (1 << 1) /* adjust timings for stereo modes */ |
@@ -214,20 +213,6 @@ struct drm_display_mode { | |||
214 | struct list_head head; | 213 | struct list_head head; |
215 | 214 | ||
216 | /** | 215 | /** |
217 | * @base: | ||
218 | * | ||
219 | * A display mode is a normal modeset object, possibly including public | ||
220 | * userspace id. | ||
221 | * | ||
222 | * FIXME: | ||
223 | * | ||
224 | * This can probably be removed since the entire concept of userspace | ||
225 | * managing modes explicitly has never landed in upstream kernel mode | ||
226 | * setting support. | ||
227 | */ | ||
228 | struct drm_mode_object base; | ||
229 | |||
230 | /** | ||
231 | * @name: | 216 | * @name: |
232 | * | 217 | * |
233 | * Human-readable name of the mode, filled out with drm_mode_set_name(). | 218 | * Human-readable name of the mode, filled out with drm_mode_set_name(). |
@@ -429,14 +414,14 @@ struct drm_display_mode { | |||
429 | /** | 414 | /** |
430 | * DRM_MODE_FMT - printf string for &struct drm_display_mode | 415 | * DRM_MODE_FMT - printf string for &struct drm_display_mode |
431 | */ | 416 | */ |
432 | #define DRM_MODE_FMT "%d:\"%s\" %d %d %d %d %d %d %d %d %d %d 0x%x 0x%x" | 417 | #define DRM_MODE_FMT "\"%s\": %d %d %d %d %d %d %d %d %d %d 0x%x 0x%x" |
433 | 418 | ||
434 | /** | 419 | /** |
435 | * DRM_MODE_ARG - printf arguments for &struct drm_display_mode | 420 | * DRM_MODE_ARG - printf arguments for &struct drm_display_mode |
436 | * @m: display mode | 421 | * @m: display mode |
437 | */ | 422 | */ |
438 | #define DRM_MODE_ARG(m) \ | 423 | #define DRM_MODE_ARG(m) \ |
439 | (m)->base.id, (m)->name, (m)->vrefresh, (m)->clock, \ | 424 | (m)->name, (m)->vrefresh, (m)->clock, \ |
440 | (m)->hdisplay, (m)->hsync_start, (m)->hsync_end, (m)->htotal, \ | 425 | (m)->hdisplay, (m)->hsync_start, (m)->hsync_end, (m)->htotal, \ |
441 | (m)->vdisplay, (m)->vsync_start, (m)->vsync_end, (m)->vtotal, \ | 426 | (m)->vdisplay, (m)->vsync_start, (m)->vsync_end, (m)->vtotal, \ |
442 | (m)->type, (m)->flags | 427 | (m)->type, (m)->flags |
diff --git a/include/drm/drm_util.h b/include/drm/drm_util.h index 88abdca89baa..8163d35f8327 100644 --- a/include/drm/drm_util.h +++ b/include/drm/drm_util.h | |||
@@ -26,7 +26,58 @@ | |||
26 | #ifndef _DRM_UTIL_H_ | 26 | #ifndef _DRM_UTIL_H_ |
27 | #define _DRM_UTIL_H_ | 27 | #define _DRM_UTIL_H_ |
28 | 28 | ||
29 | /* helper for handling conditionals in various for_each macros */ | 29 | /** |
30 | * DOC: drm utils | ||
31 | * | ||
32 | * Macros and inline functions that does not naturally belong in other places | ||
33 | */ | ||
34 | |||
35 | #include <linux/interrupt.h> | ||
36 | #include <linux/kgdb.h> | ||
37 | #include <linux/preempt.h> | ||
38 | #include <linux/smp.h> | ||
39 | |||
40 | /* | ||
41 | * Use EXPORT_SYMBOL_FOR_TESTS_ONLY() for functions that shall | ||
42 | * only be visible for drmselftests. | ||
43 | */ | ||
44 | #if defined(CONFIG_DRM_DEBUG_SELFTEST_MODULE) | ||
45 | #define EXPORT_SYMBOL_FOR_TESTS_ONLY(x) EXPORT_SYMBOL(x) | ||
46 | #else | ||
47 | #define EXPORT_SYMBOL_FOR_TESTS_ONLY(x) | ||
48 | #endif | ||
49 | |||
50 | /** | ||
51 | * for_each_if - helper for handling conditionals in various for_each macros | ||
52 | * @condition: The condition to check | ||
53 | * | ||
54 | * Typical use:: | ||
55 | * | ||
56 | * #define for_each_foo_bar(x, y) \' | ||
57 | * list_for_each_entry(x, y->list, head) \' | ||
58 | * for_each_if(x->something == SOMETHING) | ||
59 | * | ||
60 | * The for_each_if() macro makes the use of for_each_foo_bar() less error | ||
61 | * prone. | ||
62 | */ | ||
30 | #define for_each_if(condition) if (!(condition)) {} else | 63 | #define for_each_if(condition) if (!(condition)) {} else |
31 | 64 | ||
65 | /** | ||
66 | * drm_can_sleep - returns true if currently okay to sleep | ||
67 | * | ||
68 | * This function shall not be used in new code. | ||
69 | * The check for running in atomic context may not work - see linux/preempt.h. | ||
70 | * | ||
71 | * FIXME: All users of drm_can_sleep should be removed (see todo.rst) | ||
72 | * | ||
73 | * Returns: | ||
74 | * True if kgdb is active or we are in an atomic context or irqs are disabled | ||
75 | */ | ||
76 | static inline bool drm_can_sleep(void) | ||
77 | { | ||
78 | if (in_atomic() || in_dbg_master() || irqs_disabled()) | ||
79 | return false; | ||
80 | return true; | ||
81 | } | ||
82 | |||
32 | #endif | 83 | #endif |
diff --git a/include/drm/drm_vblank.h b/include/drm/drm_vblank.h index 6ad9630d4f48..e528bb2f659d 100644 --- a/include/drm/drm_vblank.h +++ b/include/drm/drm_vblank.h | |||
@@ -129,6 +129,26 @@ struct drm_vblank_crtc { | |||
129 | */ | 129 | */ |
130 | u32 last; | 130 | u32 last; |
131 | /** | 131 | /** |
132 | * @max_vblank_count: | ||
133 | * | ||
134 | * Maximum value of the vblank registers for this crtc. This value +1 | ||
135 | * will result in a wrap-around of the vblank register. It is used | ||
136 | * by the vblank core to handle wrap-arounds. | ||
137 | * | ||
138 | * If set to zero the vblank core will try to guess the elapsed vblanks | ||
139 | * between times when the vblank interrupt is disabled through | ||
140 | * high-precision timestamps. That approach is suffering from small | ||
141 | * races and imprecision over longer time periods, hence exposing a | ||
142 | * hardware vblank counter is always recommended. | ||
143 | * | ||
144 | * This is the runtime configurable per-crtc maximum set through | ||
145 | * drm_crtc_set_max_vblank_count(). If this is used the driver | ||
146 | * must leave the device wide &drm_device.max_vblank_count at zero. | ||
147 | * | ||
148 | * If non-zero, &drm_crtc_funcs.get_vblank_counter must be set. | ||
149 | */ | ||
150 | u32 max_vblank_count; | ||
151 | /** | ||
132 | * @inmodeset: Tracks whether the vblank is disabled due to a modeset. | 152 | * @inmodeset: Tracks whether the vblank is disabled due to a modeset. |
133 | * For legacy driver bit 2 additionally tracks whether an additional | 153 | * For legacy driver bit 2 additionally tracks whether an additional |
134 | * temporary vblank reference has been acquired to paper over the | 154 | * temporary vblank reference has been acquired to paper over the |
@@ -206,4 +226,6 @@ bool drm_calc_vbltimestamp_from_scanoutpos(struct drm_device *dev, | |||
206 | void drm_calc_timestamping_constants(struct drm_crtc *crtc, | 226 | void drm_calc_timestamping_constants(struct drm_crtc *crtc, |
207 | const struct drm_display_mode *mode); | 227 | const struct drm_display_mode *mode); |
208 | wait_queue_head_t *drm_crtc_vblank_waitqueue(struct drm_crtc *crtc); | 228 | wait_queue_head_t *drm_crtc_vblank_waitqueue(struct drm_crtc *crtc); |
229 | void drm_crtc_set_max_vblank_count(struct drm_crtc *crtc, | ||
230 | u32 max_vblank_count); | ||
209 | #endif | 231 | #endif |
diff --git a/include/uapi/drm/drm_fourcc.h b/include/uapi/drm/drm_fourcc.h index 0b44260a5ee9..41106c835747 100644 --- a/include/uapi/drm/drm_fourcc.h +++ b/include/uapi/drm/drm_fourcc.h | |||
@@ -581,10 +581,18 @@ extern "C" { | |||
581 | * Indicates the superblock size(s) used for the AFBC buffer. The buffer | 581 | * Indicates the superblock size(s) used for the AFBC buffer. The buffer |
582 | * size (in pixels) must be aligned to a multiple of the superblock size. | 582 | * size (in pixels) must be aligned to a multiple of the superblock size. |
583 | * Four lowest significant bits(LSBs) are reserved for block size. | 583 | * Four lowest significant bits(LSBs) are reserved for block size. |
584 | * | ||
585 | * Where one superblock size is specified, it applies to all planes of the | ||
586 | * buffer (e.g. 16x16, 32x8). When multiple superblock sizes are specified, | ||
587 | * the first applies to the Luma plane and the second applies to the Chroma | ||
588 | * plane(s). e.g. (32x8_64x4 means 32x8 Luma, with 64x4 Chroma). | ||
589 | * Multiple superblock sizes are only valid for multi-plane YCbCr formats. | ||
584 | */ | 590 | */ |
585 | #define AFBC_FORMAT_MOD_BLOCK_SIZE_MASK 0xf | 591 | #define AFBC_FORMAT_MOD_BLOCK_SIZE_MASK 0xf |
586 | #define AFBC_FORMAT_MOD_BLOCK_SIZE_16x16 (1ULL) | 592 | #define AFBC_FORMAT_MOD_BLOCK_SIZE_16x16 (1ULL) |
587 | #define AFBC_FORMAT_MOD_BLOCK_SIZE_32x8 (2ULL) | 593 | #define AFBC_FORMAT_MOD_BLOCK_SIZE_32x8 (2ULL) |
594 | #define AFBC_FORMAT_MOD_BLOCK_SIZE_64x4 (3ULL) | ||
595 | #define AFBC_FORMAT_MOD_BLOCK_SIZE_32x8_64x4 (4ULL) | ||
588 | 596 | ||
589 | /* | 597 | /* |
590 | * AFBC lossless colorspace transform | 598 | * AFBC lossless colorspace transform |
@@ -644,6 +652,21 @@ extern "C" { | |||
644 | */ | 652 | */ |
645 | #define AFBC_FORMAT_MOD_SC (1ULL << 9) | 653 | #define AFBC_FORMAT_MOD_SC (1ULL << 9) |
646 | 654 | ||
655 | /* | ||
656 | * AFBC double-buffer | ||
657 | * | ||
658 | * Indicates that the buffer is allocated in a layout safe for front-buffer | ||
659 | * rendering. | ||
660 | */ | ||
661 | #define AFBC_FORMAT_MOD_DB (1ULL << 10) | ||
662 | |||
663 | /* | ||
664 | * AFBC buffer content hints | ||
665 | * | ||
666 | * Indicates that the buffer includes per-superblock content hints. | ||
667 | */ | ||
668 | #define AFBC_FORMAT_MOD_BCH (1ULL << 11) | ||
669 | |||
647 | #if defined(__cplusplus) | 670 | #if defined(__cplusplus) |
648 | } | 671 | } |
649 | #endif | 672 | #endif |