diff options
author | Dave Airlie <airlied@redhat.com> | 2017-09-27 15:45:27 -0400 |
---|---|---|
committer | Dave Airlie <airlied@redhat.com> | 2017-09-27 15:46:15 -0400 |
commit | 29baa82aa55f40d67cfc8138c944fd8880c27e8e (patch) | |
tree | 19119a07d3ec8eb1407a68b48ec627239ee3e681 | |
parent | e19b205be43d11bff638cad4487008c48d21c103 (diff) | |
parent | ac6c35a4d8c77083525044a192cb1a8711381e94 (diff) |
Merge tag 'drm-misc-next-2017-09-20' of git://anongit.freedesktop.org/git/drm-misc into drm-next
UAPI Changes:
Cross-subsystem Changes:
Core Changes:
- DP SDP defines (Ville)
- polish for scdc helpers (Thierry Reding)
- fix lifetimes for connector/plane state across crtc changes (Maarten
Lankhorst).
- sparse fixes (Ville+Thierry)
- make legacy kms ioctls all interruptible (Maarten)
- push edid override into the edid helpers (out of probe helpers)
(Jani)
- DP ESI defines for link status (DK)
Driver Changes:
- drm-panel is now in drm-misc!
- minor panel-simple cleanups/refactoring by various folks
- drm_bridge_add cleanup (Inki Dae)
- constify a few i2c_device_id structs (Arvind Yadav)
- More patches from Noralf's fb/gem helper cleanup
- bridge/synopsis: reset fix (Philippe Cornu)
- fix tracepoint include handling in drivers (Thierry)
- rockchip: lvds support (Sandy Huang)
- move sun4i into drm-misc fold (Maxime Ripard)
- sun4i: refactor driver load + support TCON backend/layer muxing
(Chen-Yu Tsai)
- pl111: support more pl11x variants (Linus Walleij)
- bridge/adv7511: robustify probing/edid handling (Lars-Petersen
Clausen)
New hw support:
- S6E63J0X03 panel (Hoegeun Kwon)
- OTM8009A panel (Philippe CORNU)
- Seiko 43WVF1G panel (Marco Franchi)
- tve200 driver (Linus Walleij)
Plus assorted of tiny patches all over, including our first outreachy
patches from applicants for the winter round!
* tag 'drm-misc-next-2017-09-20' of git://anongit.freedesktop.org/git/drm-misc: (101 commits)
drm: add backwards compatibility support for drm_kms_helper.edid_firmware
drm: handle override and firmware EDID at drm_do_get_edid() level
drm/dp: DPCD register defines for link status within ESI field
drm/rockchip: Replace dev_* with DRM_DEV_*
drm/tinydrm: Drop driver registered message
drm/gem-fb-helper: Use debug message on gem lookup failure
drm/imx: Use drm_gem_fb_create() and drm_gem_fb_prepare_fb()
drm/bridge: adv7511: Constify HDMI CODEC platform data
drm/bridge: adv7511: Enable connector polling when no interrupt is specified
drm/bridge: adv7511: Remove private copy of the EDID
drm/bridge: adv7511: Properly update EDID when no EDID was found
drm/crtc: Convert setcrtc ioctl locking to interruptible.
drm/atomic: Convert pageflip ioctl locking to interruptible.
drm/legacy: Convert setplane ioctl locking to interruptible.
drm/legacy: Convert cursor ioctl locking to interruptible.
drm/atomic: Convert atomic ioctl locking to interruptible.
drm/atomic: Prepare drm_modeset_lock infrastructure for interruptible waiting, v2.
drm/tve200: Clean up panel bridging
drm/doc: Update todo.rst
drm/dp/mst: Sideband message transaction to power up/down nodes
...
124 files changed, 4775 insertions, 960 deletions
diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt index 05496622b4ef..b24108f2a438 100644 --- a/Documentation/admin-guide/kernel-parameters.txt +++ b/Documentation/admin-guide/kernel-parameters.txt | |||
@@ -854,7 +854,7 @@ | |||
854 | The filter can be disabled or changed to another | 854 | The filter can be disabled or changed to another |
855 | driver later using sysfs. | 855 | driver later using sysfs. |
856 | 856 | ||
857 | drm_kms_helper.edid_firmware=[<connector>:]<file>[,[<connector>:]<file>] | 857 | drm.edid_firmware=[<connector>:]<file>[,[<connector>:]<file>] |
858 | Broken monitors, graphic adapters, KVMs and EDIDless | 858 | Broken monitors, graphic adapters, KVMs and EDIDless |
859 | panels may send no or incorrect EDID data sets. | 859 | panels may send no or incorrect EDID data sets. |
860 | This parameter allows to specify an EDID data sets | 860 | This parameter allows to specify an EDID data sets |
diff --git a/Documentation/devicetree/bindings/display/faraday,tve200.txt b/Documentation/devicetree/bindings/display/faraday,tve200.txt new file mode 100644 index 000000000000..82e3bc0b7485 --- /dev/null +++ b/Documentation/devicetree/bindings/display/faraday,tve200.txt | |||
@@ -0,0 +1,54 @@ | |||
1 | * Faraday TV Encoder TVE200 | ||
2 | |||
3 | Required properties: | ||
4 | |||
5 | - compatible: must be one of: | ||
6 | "faraday,tve200" | ||
7 | "cortina,gemini-tvc", "faraday,tve200" | ||
8 | |||
9 | - reg: base address and size of the control registers block | ||
10 | |||
11 | - interrupts: contains an interrupt specifier for the interrupt | ||
12 | line from the TVE200 | ||
13 | |||
14 | - clock-names: should contain "PCLK" for the clock line clocking the | ||
15 | silicon and "TVE" for the 27MHz clock to the video driver | ||
16 | |||
17 | - clocks: contains phandle and clock specifier pairs for the entries | ||
18 | in the clock-names property. See | ||
19 | Documentation/devicetree/bindings/clock/clock-bindings.txt | ||
20 | |||
21 | Optional properties: | ||
22 | |||
23 | - resets: contains the reset line phandle for the block | ||
24 | |||
25 | Required sub-nodes: | ||
26 | |||
27 | - port: describes LCD panel signals, following the common binding | ||
28 | for video transmitter interfaces; see | ||
29 | Documentation/devicetree/bindings/media/video-interfaces.txt | ||
30 | This port should have the properties: | ||
31 | reg = <0>; | ||
32 | It should have one endpoint connected to a remote endpoint where | ||
33 | the display is connected. | ||
34 | |||
35 | Example: | ||
36 | |||
37 | display-controller@6a000000 { | ||
38 | #address-cells = <1>; | ||
39 | #size-cells = <0>; | ||
40 | compatible = "faraday,tve200"; | ||
41 | reg = <0x6a000000 0x1000>; | ||
42 | interrupts = <13 IRQ_TYPE_EDGE_RISING>; | ||
43 | resets = <&syscon GEMINI_RESET_TVC>; | ||
44 | clocks = <&syscon GEMINI_CLK_GATE_TVC>, | ||
45 | <&syscon GEMINI_CLK_TVC>; | ||
46 | clock-names = "PCLK", "TVE"; | ||
47 | |||
48 | port@0 { | ||
49 | reg = <0>; | ||
50 | display_out: endpoint { | ||
51 | remote-endpoint = <&panel_in>; | ||
52 | }; | ||
53 | }; | ||
54 | }; | ||
diff --git a/Documentation/devicetree/bindings/display/panel/orisetech,otm8009a.txt b/Documentation/devicetree/bindings/display/panel/orisetech,otm8009a.txt new file mode 100644 index 000000000000..6862028e7b2e --- /dev/null +++ b/Documentation/devicetree/bindings/display/panel/orisetech,otm8009a.txt | |||
@@ -0,0 +1,21 @@ | |||
1 | Orise Tech OTM8009A 3.97" 480x800 TFT LCD panel (MIPI-DSI video mode) | ||
2 | |||
3 | The Orise Tech OTM8009A is a 3.97" 480x800 TFT LCD panel connected using | ||
4 | a MIPI-DSI video interface. Its backlight is managed through the DSI link. | ||
5 | |||
6 | Required properties: | ||
7 | - compatible: "orisetech,otm8009a" | ||
8 | - reg: the virtual channel number of a DSI peripheral | ||
9 | |||
10 | Optional properties: | ||
11 | - reset-gpios: a GPIO spec for the reset pin (active low). | ||
12 | |||
13 | Example: | ||
14 | &dsi { | ||
15 | ... | ||
16 | panel@0 { | ||
17 | compatible = "orisetech,otm8009a"; | ||
18 | reg = <0>; | ||
19 | reset-gpios = <&gpioh 7 GPIO_ACTIVE_LOW>; | ||
20 | }; | ||
21 | }; | ||
diff --git a/Documentation/devicetree/bindings/display/panel/samsung,s6e63j0x03.txt b/Documentation/devicetree/bindings/display/panel/samsung,s6e63j0x03.txt new file mode 100644 index 000000000000..3f1a8392af7f --- /dev/null +++ b/Documentation/devicetree/bindings/display/panel/samsung,s6e63j0x03.txt | |||
@@ -0,0 +1,24 @@ | |||
1 | Samsung S6E63J0X03 1.63" 320x320 AMOLED panel (interface: MIPI-DSI command mode) | ||
2 | |||
3 | Required properties: | ||
4 | - compatible: "samsung,s6e63j0x03" | ||
5 | - reg: the virtual channel number of a DSI peripheral | ||
6 | - vdd3-supply: I/O voltage supply | ||
7 | - vci-supply: voltage supply for analog circuits | ||
8 | - reset-gpios: a GPIO spec for the reset pin (active low) | ||
9 | - te-gpios: a GPIO spec for the tearing effect synchronization signal | ||
10 | gpio pin (active high) | ||
11 | |||
12 | Example: | ||
13 | &dsi { | ||
14 | ... | ||
15 | |||
16 | panel@0 { | ||
17 | compatible = "samsung,s6e63j0x03"; | ||
18 | reg = <0>; | ||
19 | vdd3-supply = <&ldo16_reg>; | ||
20 | vci-supply = <&ldo20_reg>; | ||
21 | reset-gpios = <&gpe0 1 GPIO_ACTIVE_LOW>; | ||
22 | te-gpios = <&gpx0 6 GPIO_ACTIVE_HIGH>; | ||
23 | }; | ||
24 | }; | ||
diff --git a/Documentation/devicetree/bindings/display/panel/seiko,43wvf1g.txt b/Documentation/devicetree/bindings/display/panel/seiko,43wvf1g.txt new file mode 100644 index 000000000000..aae57ef36cdd --- /dev/null +++ b/Documentation/devicetree/bindings/display/panel/seiko,43wvf1g.txt | |||
@@ -0,0 +1,23 @@ | |||
1 | Seiko Instruments Inc. 4.3" WVGA (800 x RGB x 480) TFT with Touch-Panel | ||
2 | |||
3 | Required properties: | ||
4 | - compatible: should be "sii,43wvf1g". | ||
5 | - "dvdd-supply": 3v3 digital regulator. | ||
6 | - "avdd-supply": 5v analog regulator. | ||
7 | |||
8 | Optional properties: | ||
9 | - backlight: phandle for the backlight control. | ||
10 | |||
11 | Example: | ||
12 | |||
13 | panel { | ||
14 | compatible = "sii,43wvf1g"; | ||
15 | backlight = <&backlight_display>; | ||
16 | dvdd-supply = <®_lcd_3v3>; | ||
17 | avdd-supply = <®_lcd_5v>; | ||
18 | port { | ||
19 | panel_in: endpoint { | ||
20 | remote-endpoint = <&display_out>; | ||
21 | }; | ||
22 | }; | ||
23 | }; | ||
diff --git a/Documentation/devicetree/bindings/display/rockchip/rockchip-lvds.txt b/Documentation/devicetree/bindings/display/rockchip/rockchip-lvds.txt new file mode 100644 index 000000000000..da6939efdb43 --- /dev/null +++ b/Documentation/devicetree/bindings/display/rockchip/rockchip-lvds.txt | |||
@@ -0,0 +1,99 @@ | |||
1 | Rockchip RK3288 LVDS interface | ||
2 | ================================ | ||
3 | |||
4 | Required properties: | ||
5 | - compatible: matching the soc type, one of | ||
6 | - "rockchip,rk3288-lvds"; | ||
7 | |||
8 | - reg: physical base address of the controller and length | ||
9 | of memory mapped region. | ||
10 | - clocks: must include clock specifiers corresponding to entries in the | ||
11 | clock-names property. | ||
12 | - clock-names: must contain "pclk_lvds" | ||
13 | |||
14 | - avdd1v0-supply: regulator phandle for 1.0V analog power | ||
15 | - avdd1v8-supply: regulator phandle for 1.8V analog power | ||
16 | - avdd3v3-supply: regulator phandle for 3.3V analog power | ||
17 | |||
18 | - rockchip,grf: phandle to the general register files syscon | ||
19 | - rockchip,output: "rgb", "lvds" or "duallvds", This describes the output interface | ||
20 | |||
21 | Optional properties: | ||
22 | - pinctrl-names: must contain a "lcdc" entry. | ||
23 | - pinctrl-0: pin control group to be used for this controller. | ||
24 | |||
25 | Required nodes: | ||
26 | |||
27 | The lvds has two video ports as described by | ||
28 | Documentation/devicetree/bindings/media/video-interfaces.txt | ||
29 | Their connections are modeled using the OF graph bindings specified in | ||
30 | Documentation/devicetree/bindings/graph.txt. | ||
31 | |||
32 | - video port 0 for the VOP input, the remote endpoint maybe vopb or vopl | ||
33 | - video port 1 for either a panel or subsequent encoder | ||
34 | |||
35 | the lvds panel described by | ||
36 | Documentation/devicetree/bindings/display/panel/simple-panel.txt | ||
37 | |||
38 | Panel required properties: | ||
39 | - ports for remote LVDS output | ||
40 | |||
41 | Panel optional properties: | ||
42 | - data-mapping: should be "vesa-24","jeida-24" or "jeida-18". | ||
43 | This describes decribed by: | ||
44 | Documentation/devicetree/bindings/display/panel/panel-lvds.txt | ||
45 | |||
46 | Example: | ||
47 | |||
48 | lvds_panel: lvds-panel { | ||
49 | compatible = "auo,b101ean01"; | ||
50 | enable-gpios = <&gpio7 21 GPIO_ACTIVE_HIGH>; | ||
51 | data-mapping = "jeida-24"; | ||
52 | |||
53 | ports { | ||
54 | panel_in_lvds: endpoint { | ||
55 | remote-endpoint = <&lvds_out_panel>; | ||
56 | }; | ||
57 | }; | ||
58 | }; | ||
59 | |||
60 | For Rockchip RK3288: | ||
61 | |||
62 | lvds: lvds@ff96c000 { | ||
63 | compatible = "rockchip,rk3288-lvds"; | ||
64 | rockchip,grf = <&grf>; | ||
65 | reg = <0xff96c000 0x4000>; | ||
66 | clocks = <&cru PCLK_LVDS_PHY>; | ||
67 | clock-names = "pclk_lvds"; | ||
68 | pinctrl-names = "lcdc"; | ||
69 | pinctrl-0 = <&lcdc_ctl>; | ||
70 | avdd1v0-supply = <&vdd10_lcd>; | ||
71 | avdd1v8-supply = <&vcc18_lcd>; | ||
72 | avdd3v3-supply = <&vcca_33>; | ||
73 | rockchip,output = "rgb"; | ||
74 | ports { | ||
75 | #address-cells = <1>; | ||
76 | #size-cells = <0>; | ||
77 | |||
78 | lvds_in: port@0 { | ||
79 | reg = <0>; | ||
80 | |||
81 | lvds_in_vopb: endpoint@0 { | ||
82 | reg = <0>; | ||
83 | remote-endpoint = <&vopb_out_lvds>; | ||
84 | }; | ||
85 | lvds_in_vopl: endpoint@1 { | ||
86 | reg = <1>; | ||
87 | remote-endpoint = <&vopl_out_lvds>; | ||
88 | }; | ||
89 | }; | ||
90 | |||
91 | lvds_out: port@1 { | ||
92 | reg = <1>; | ||
93 | |||
94 | lvds_out_panel: endpoint { | ||
95 | remote-endpoint = <&panel_in_lvds>; | ||
96 | }; | ||
97 | }; | ||
98 | }; | ||
99 | }; | ||
diff --git a/Documentation/devicetree/bindings/vendor-prefixes.txt b/Documentation/devicetree/bindings/vendor-prefixes.txt index 1afd298eddd7..6cf1dc5bc77e 100644 --- a/Documentation/devicetree/bindings/vendor-prefixes.txt +++ b/Documentation/devicetree/bindings/vendor-prefixes.txt | |||
@@ -248,6 +248,7 @@ ontat On Tat Industrial Company | |||
248 | opencores OpenCores.org | 248 | opencores OpenCores.org |
249 | option Option NV | 249 | option Option NV |
250 | ORCL Oracle Corporation | 250 | ORCL Oracle Corporation |
251 | orisetech Orise Technology | ||
251 | ortustech Ortus Technology Co., Ltd. | 252 | ortustech Ortus Technology Co., Ltd. |
252 | ovti OmniVision Technologies | 253 | ovti OmniVision Technologies |
253 | oxsemi Oxford Semiconductor, Ltd. | 254 | oxsemi Oxford Semiconductor, Ltd. |
diff --git a/Documentation/gpu/drm-uapi.rst b/Documentation/gpu/drm-uapi.rst index 679373b4a03f..a2214cc1f821 100644 --- a/Documentation/gpu/drm-uapi.rst +++ b/Documentation/gpu/drm-uapi.rst | |||
@@ -168,6 +168,61 @@ IOCTL Support on Device Nodes | |||
168 | .. kernel-doc:: drivers/gpu/drm/drm_ioctl.c | 168 | .. kernel-doc:: drivers/gpu/drm/drm_ioctl.c |
169 | :doc: driver specific ioctls | 169 | :doc: driver specific ioctls |
170 | 170 | ||
171 | Recommended IOCTL Return Values | ||
172 | ------------------------------- | ||
173 | |||
174 | In theory a driver's IOCTL callback is only allowed to return very few error | ||
175 | codes. In practice it's good to abuse a few more. This section documents common | ||
176 | practice within the DRM subsystem: | ||
177 | |||
178 | ENOENT: | ||
179 | Strictly this should only be used when a file doesn't exist e.g. when | ||
180 | calling the open() syscall. We reuse that to signal any kind of object | ||
181 | lookup failure, e.g. for unknown GEM buffer object handles, unknown KMS | ||
182 | object handles and similar cases. | ||
183 | |||
184 | ENOSPC: | ||
185 | Some drivers use this to differentiate "out of kernel memory" from "out | ||
186 | of VRAM". Sometimes also applies to other limited gpu resources used for | ||
187 | rendering (e.g. when you have a special limited compression buffer). | ||
188 | Sometimes resource allocation/reservation issues in command submission | ||
189 | IOCTLs are also signalled through EDEADLK. | ||
190 | |||
191 | Simply running out of kernel/system memory is signalled through ENOMEM. | ||
192 | |||
193 | EPERM/EACCESS: | ||
194 | Returned for an operation that is valid, but needs more privileges. | ||
195 | E.g. root-only or much more common, DRM master-only operations return | ||
196 | this when when called by unpriviledged clients. There's no clear | ||
197 | difference between EACCESS and EPERM. | ||
198 | |||
199 | ENODEV: | ||
200 | Feature (like PRIME, modesetting, GEM) is not supported by the driver. | ||
201 | |||
202 | ENXIO: | ||
203 | Remote failure, either a hardware transaction (like i2c), but also used | ||
204 | when the exporting driver of a shared dma-buf or fence doesn't support a | ||
205 | feature needed. | ||
206 | |||
207 | EINTR: | ||
208 | DRM drivers assume that userspace restarts all IOCTLs. Any DRM IOCTL can | ||
209 | return EINTR and in such a case should be restarted with the IOCTL | ||
210 | parameters left unchanged. | ||
211 | |||
212 | EIO: | ||
213 | The GPU died and couldn't be resurrected through a reset. Modesetting | ||
214 | hardware failures are signalled through the "link status" connector | ||
215 | property. | ||
216 | |||
217 | EINVAL: | ||
218 | Catch-all for anything that is an invalid argument combination which | ||
219 | cannot work. | ||
220 | |||
221 | IOCTL also use other error codes like ETIME, EFAULT, EBUSY, ENOTTY but their | ||
222 | usage is in line with the common meanings. The above list tries to just document | ||
223 | DRM specific patterns. Note that ENOTTY has the slightly unintuitive meaning of | ||
224 | "this IOCTL does not exist", and is used exactly as such in DRM. | ||
225 | |||
171 | .. kernel-doc:: include/drm/drm_ioctl.h | 226 | .. kernel-doc:: include/drm/drm_ioctl.h |
172 | :internal: | 227 | :internal: |
173 | 228 | ||
diff --git a/Documentation/gpu/index.rst b/Documentation/gpu/index.rst index 35d673bf9b56..c36586dad29d 100644 --- a/Documentation/gpu/index.rst +++ b/Documentation/gpu/index.rst | |||
@@ -15,6 +15,7 @@ Linux GPU Driver Developer's Guide | |||
15 | pl111 | 15 | pl111 |
16 | tegra | 16 | tegra |
17 | tinydrm | 17 | tinydrm |
18 | tve200 | ||
18 | vc4 | 19 | vc4 |
19 | vga-switcheroo | 20 | vga-switcheroo |
20 | vgaarbiter | 21 | vgaarbiter |
diff --git a/Documentation/gpu/todo.rst b/Documentation/gpu/todo.rst index 22af55d06ab8..de9512afd611 100644 --- a/Documentation/gpu/todo.rst +++ b/Documentation/gpu/todo.rst | |||
@@ -75,17 +75,6 @@ helpers. | |||
75 | 75 | ||
76 | Contact: Ville Syrjälä, Daniel Vetter, driver maintainers | 76 | Contact: Ville Syrjälä, Daniel Vetter, driver maintainers |
77 | 77 | ||
78 | Implement deferred fbdev setup in the helper | ||
79 | -------------------------------------------- | ||
80 | |||
81 | Many (especially embedded drivers) want to delay fbdev setup until there's a | ||
82 | real screen plugged in. This is to avoid the dreaded fallback to the low-res | ||
83 | fbdev default. Many drivers have a hacked-up (and often broken) version of this, | ||
84 | better to do it once in the shared helpers. Thierry has a patch series, but that | ||
85 | one needs to be rebased and final polish applied. | ||
86 | |||
87 | Contact: Thierry Reding, Daniel Vetter, driver maintainers | ||
88 | |||
89 | Convert early atomic drivers to async commit helpers | 78 | Convert early atomic drivers to async commit helpers |
90 | ---------------------------------------------------- | 79 | ---------------------------------------------------- |
91 | 80 | ||
@@ -138,6 +127,8 @@ interfaces to fix these issues: | |||
138 | the acquire context explicitly on stack and then also pass it down into | 127 | the acquire context explicitly on stack and then also pass it down into |
139 | drivers explicitly so that the legacy-on-atomic functions can use them. | 128 | drivers explicitly so that the legacy-on-atomic functions can use them. |
140 | 129 | ||
130 | Except for some driver code this is done. | ||
131 | |||
141 | * A bunch of the vtable hooks are now in the wrong place: DRM has a split | 132 | * A bunch of the vtable hooks are now in the wrong place: DRM has a split |
142 | between core vfunc tables (named ``drm_foo_funcs``), which are used to | 133 | between core vfunc tables (named ``drm_foo_funcs``), which are used to |
143 | implement the userspace ABI. And then there's the optional hooks for the | 134 | implement the userspace ABI. And then there's the optional hooks for the |
@@ -151,6 +142,8 @@ interfaces to fix these issues: | |||
151 | connector at runtime. That's almost all of them, and would allow us to get | 142 | connector at runtime. That's almost all of them, and would allow us to get |
152 | rid of a lot of ``best_encoder`` boilerplate in drivers. | 143 | rid of a lot of ``best_encoder`` boilerplate in drivers. |
153 | 144 | ||
145 | This was almost done, but new drivers added a few more cases again. | ||
146 | |||
154 | Contact: Daniel Vetter | 147 | Contact: Daniel Vetter |
155 | 148 | ||
156 | Get rid of dev->struct_mutex from GEM drivers | 149 | Get rid of dev->struct_mutex from GEM drivers |
@@ -177,6 +170,17 @@ following drivers still use ``struct_mutex``: ``msm``, ``omapdrm`` and | |||
177 | 170 | ||
178 | Contact: Daniel Vetter, respective driver maintainers | 171 | Contact: Daniel Vetter, respective driver maintainers |
179 | 172 | ||
173 | Convert instances of dev_info/dev_err/dev_warn to their DRM_DEV_* equivalent | ||
174 | ---------------------------------------------------------------------------- | ||
175 | |||
176 | For drivers which could have multiple instances, it is necessary to | ||
177 | differentiate between which is which in the logs. Since DRM_INFO/WARN/ERROR | ||
178 | don't do this, drivers used dev_info/warn/err to make this differentiation. We | ||
179 | now have DRM_DEV_* variants of the drm print macros, so we can start to convert | ||
180 | those drivers back to using drm-formwatted specific log messages. | ||
181 | |||
182 | Contact: Sean Paul, Maintainer of the driver you plan to convert | ||
183 | |||
180 | Core refactorings | 184 | Core refactorings |
181 | ================= | 185 | ================= |
182 | 186 | ||
diff --git a/Documentation/gpu/tve200.rst b/Documentation/gpu/tve200.rst new file mode 100644 index 000000000000..69b17b324e12 --- /dev/null +++ b/Documentation/gpu/tve200.rst | |||
@@ -0,0 +1,6 @@ | |||
1 | ================================== | ||
2 | drm/tve200 Faraday TV Encoder 200 | ||
3 | ================================== | ||
4 | |||
5 | .. kernel-doc:: drivers/gpu/drm/tve200/tve200_drv.c | ||
6 | :doc: Faraday TV Encoder 200 | ||
diff --git a/MAINTAINERS b/MAINTAINERS index 6671f375f7fc..7ab4c373c370 100644 --- a/MAINTAINERS +++ b/MAINTAINERS | |||
@@ -4366,6 +4366,12 @@ T: git git://anongit.freedesktop.org/drm/drm-misc | |||
4366 | S: Maintained | 4366 | S: Maintained |
4367 | F: drivers/gpu/drm/bochs/ | 4367 | F: drivers/gpu/drm/bochs/ |
4368 | 4368 | ||
4369 | DRM DRIVER FOR FARADAY TVE200 TV ENCODER | ||
4370 | M: Linus Walleij <linus.walleij@linaro.org> | ||
4371 | T: git git://anongit.freedesktop.org/drm/drm-misc | ||
4372 | S: Maintained | ||
4373 | F: drivers/gpu/drm/tve200/ | ||
4374 | |||
4369 | DRM DRIVER FOR INTEL I810 VIDEO CARDS | 4375 | DRM DRIVER FOR INTEL I810 VIDEO CARDS |
4370 | S: Orphan / Obsolete | 4376 | S: Orphan / Obsolete |
4371 | F: drivers/gpu/drm/i810/ | 4377 | F: drivers/gpu/drm/i810/ |
@@ -4509,7 +4515,7 @@ L: dri-devel@lists.freedesktop.org | |||
4509 | S: Supported | 4515 | S: Supported |
4510 | F: drivers/gpu/drm/sun4i/ | 4516 | F: drivers/gpu/drm/sun4i/ |
4511 | F: Documentation/devicetree/bindings/display/sunxi/sun4i-drm.txt | 4517 | F: Documentation/devicetree/bindings/display/sunxi/sun4i-drm.txt |
4512 | T: git git://git.kernel.org/pub/scm/linux/kernel/git/mripard/linux.git | 4518 | T: git git://anongit.freedesktop.org/drm/drm-misc |
4513 | 4519 | ||
4514 | DRM DRIVERS FOR AMLOGIC SOCS | 4520 | DRM DRIVERS FOR AMLOGIC SOCS |
4515 | M: Neil Armstrong <narmstrong@baylibre.com> | 4521 | M: Neil Armstrong <narmstrong@baylibre.com> |
@@ -4693,7 +4699,7 @@ T: git git://anongit.freedesktop.org/drm/drm-misc | |||
4693 | DRM PANEL DRIVERS | 4699 | DRM PANEL DRIVERS |
4694 | M: Thierry Reding <thierry.reding@gmail.com> | 4700 | M: Thierry Reding <thierry.reding@gmail.com> |
4695 | L: dri-devel@lists.freedesktop.org | 4701 | L: dri-devel@lists.freedesktop.org |
4696 | T: git git://anongit.freedesktop.org/tegra/linux.git | 4702 | T: git git://anongit.freedesktop.org/drm/drm-misc |
4697 | S: Maintained | 4703 | S: Maintained |
4698 | F: drivers/gpu/drm/drm_panel.c | 4704 | F: drivers/gpu/drm/drm_panel.c |
4699 | F: drivers/gpu/drm/panel/ | 4705 | F: drivers/gpu/drm/panel/ |
diff --git a/drivers/dma-buf/sw_sync.c b/drivers/dma-buf/sw_sync.c index 38cc7389a6c1..24f83f9eeaed 100644 --- a/drivers/dma-buf/sw_sync.c +++ b/drivers/dma-buf/sw_sync.c | |||
@@ -321,8 +321,16 @@ static int sw_sync_debugfs_open(struct inode *inode, struct file *file) | |||
321 | static int sw_sync_debugfs_release(struct inode *inode, struct file *file) | 321 | static int sw_sync_debugfs_release(struct inode *inode, struct file *file) |
322 | { | 322 | { |
323 | struct sync_timeline *obj = file->private_data; | 323 | struct sync_timeline *obj = file->private_data; |
324 | struct sync_pt *pt, *next; | ||
325 | |||
326 | spin_lock_irq(&obj->lock); | ||
327 | |||
328 | list_for_each_entry_safe(pt, next, &obj->pt_list, link) { | ||
329 | dma_fence_set_error(&pt->base, -ENOENT); | ||
330 | dma_fence_signal_locked(&pt->base); | ||
331 | } | ||
324 | 332 | ||
325 | smp_wmb(); | 333 | spin_unlock_irq(&obj->lock); |
326 | 334 | ||
327 | sync_timeline_put(obj); | 335 | sync_timeline_put(obj); |
328 | return 0; | 336 | return 0; |
diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig index 83cb2a88c204..c9f09fc298bb 100644 --- a/drivers/gpu/drm/Kconfig +++ b/drivers/gpu/drm/Kconfig | |||
@@ -110,7 +110,7 @@ config DRM_FBDEV_OVERALLOC | |||
110 | 110 | ||
111 | config DRM_LOAD_EDID_FIRMWARE | 111 | config DRM_LOAD_EDID_FIRMWARE |
112 | bool "Allow to specify an EDID data set instead of probing for it" | 112 | bool "Allow to specify an EDID data set instead of probing for it" |
113 | depends on DRM_KMS_HELPER | 113 | depends on DRM |
114 | help | 114 | help |
115 | Say Y here, if you want to use EDID data to be loaded from the | 115 | Say Y here, if you want to use EDID data to be loaded from the |
116 | /lib/firmware directory or one of the provided built-in | 116 | /lib/firmware directory or one of the provided built-in |
@@ -278,6 +278,8 @@ source "drivers/gpu/drm/tinydrm/Kconfig" | |||
278 | 278 | ||
279 | source "drivers/gpu/drm/pl111/Kconfig" | 279 | source "drivers/gpu/drm/pl111/Kconfig" |
280 | 280 | ||
281 | source "drivers/gpu/drm/tve200/Kconfig" | ||
282 | |||
281 | # Keep legacy drivers last | 283 | # Keep legacy drivers last |
282 | 284 | ||
283 | menuconfig DRM_LEGACY | 285 | menuconfig DRM_LEGACY |
diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile index a8acc197dec3..0ee184f56a60 100644 --- a/drivers/gpu/drm/Makefile +++ b/drivers/gpu/drm/Makefile | |||
@@ -28,6 +28,7 @@ drm-$(CONFIG_DRM_PANEL) += drm_panel.o | |||
28 | drm-$(CONFIG_OF) += drm_of.o | 28 | drm-$(CONFIG_OF) += drm_of.o |
29 | drm-$(CONFIG_AGP) += drm_agpsupport.o | 29 | drm-$(CONFIG_AGP) += drm_agpsupport.o |
30 | drm-$(CONFIG_DEBUG_FS) += drm_debugfs.o drm_debugfs_crc.o | 30 | drm-$(CONFIG_DEBUG_FS) += drm_debugfs.o drm_debugfs_crc.o |
31 | drm-$(CONFIG_DRM_LOAD_EDID_FIRMWARE) += drm_edid_load.o | ||
31 | 32 | ||
32 | drm_kms_helper-y := drm_crtc_helper.o drm_dp_helper.o drm_probe_helper.o \ | 33 | drm_kms_helper-y := drm_crtc_helper.o drm_dp_helper.o drm_probe_helper.o \ |
33 | drm_plane_helper.o drm_dp_mst_topology.o drm_atomic_helper.o \ | 34 | drm_plane_helper.o drm_dp_mst_topology.o drm_atomic_helper.o \ |
@@ -36,7 +37,6 @@ drm_kms_helper-y := drm_crtc_helper.o drm_dp_helper.o drm_probe_helper.o \ | |||
36 | drm_scdc_helper.o drm_gem_framebuffer_helper.o | 37 | drm_scdc_helper.o drm_gem_framebuffer_helper.o |
37 | 38 | ||
38 | drm_kms_helper-$(CONFIG_DRM_PANEL_BRIDGE) += bridge/panel.o | 39 | drm_kms_helper-$(CONFIG_DRM_PANEL_BRIDGE) += bridge/panel.o |
39 | drm_kms_helper-$(CONFIG_DRM_LOAD_EDID_FIRMWARE) += drm_edid_load.o | ||
40 | drm_kms_helper-$(CONFIG_DRM_FBDEV_EMULATION) += drm_fb_helper.o | 40 | drm_kms_helper-$(CONFIG_DRM_FBDEV_EMULATION) += drm_fb_helper.o |
41 | drm_kms_helper-$(CONFIG_DRM_KMS_CMA_HELPER) += drm_fb_cma_helper.o | 41 | drm_kms_helper-$(CONFIG_DRM_KMS_CMA_HELPER) += drm_fb_cma_helper.o |
42 | drm_kms_helper-$(CONFIG_DRM_DP_AUX_CHARDEV) += drm_dp_aux_dev.o | 42 | drm_kms_helper-$(CONFIG_DRM_DP_AUX_CHARDEV) += drm_dp_aux_dev.o |
@@ -44,8 +44,6 @@ drm_kms_helper-$(CONFIG_DRM_DP_AUX_CHARDEV) += drm_dp_aux_dev.o | |||
44 | obj-$(CONFIG_DRM_KMS_HELPER) += drm_kms_helper.o | 44 | obj-$(CONFIG_DRM_KMS_HELPER) += drm_kms_helper.o |
45 | obj-$(CONFIG_DRM_DEBUG_MM_SELFTEST) += selftests/ | 45 | obj-$(CONFIG_DRM_DEBUG_MM_SELFTEST) += selftests/ |
46 | 46 | ||
47 | CFLAGS_drm_trace_points.o := -I$(src) | ||
48 | |||
49 | obj-$(CONFIG_DRM) += drm.o | 47 | obj-$(CONFIG_DRM) += drm.o |
50 | obj-$(CONFIG_DRM_MIPI_DSI) += drm_mipi_dsi.o | 48 | obj-$(CONFIG_DRM_MIPI_DSI) += drm_mipi_dsi.o |
51 | obj-$(CONFIG_DRM_ARM) += arm/ | 49 | obj-$(CONFIG_DRM_ARM) += arm/ |
@@ -100,3 +98,4 @@ obj-$(CONFIG_DRM_ZTE) += zte/ | |||
100 | obj-$(CONFIG_DRM_MXSFB) += mxsfb/ | 98 | obj-$(CONFIG_DRM_MXSFB) += mxsfb/ |
101 | obj-$(CONFIG_DRM_TINYDRM) += tinydrm/ | 99 | obj-$(CONFIG_DRM_TINYDRM) += tinydrm/ |
102 | obj-$(CONFIG_DRM_PL111) += pl111/ | 100 | obj-$(CONFIG_DRM_PL111) += pl111/ |
101 | obj-$(CONFIG_DRM_TVE200) += tve200/ | ||
diff --git a/drivers/gpu/drm/arc/arcpgu_drv.c b/drivers/gpu/drm/arc/arcpgu_drv.c index 289eda54e5aa..074fd4ea7ece 100644 --- a/drivers/gpu/drm/arc/arcpgu_drv.c +++ b/drivers/gpu/drm/arc/arcpgu_drv.c | |||
@@ -18,6 +18,7 @@ | |||
18 | #include <drm/drm_crtc_helper.h> | 18 | #include <drm/drm_crtc_helper.h> |
19 | #include <drm/drm_fb_cma_helper.h> | 19 | #include <drm/drm_fb_cma_helper.h> |
20 | #include <drm/drm_gem_cma_helper.h> | 20 | #include <drm/drm_gem_cma_helper.h> |
21 | #include <drm/drm_gem_framebuffer_helper.h> | ||
21 | #include <drm/drm_atomic_helper.h> | 22 | #include <drm/drm_atomic_helper.h> |
22 | #include <linux/of_reserved_mem.h> | 23 | #include <linux/of_reserved_mem.h> |
23 | 24 | ||
@@ -32,7 +33,7 @@ static void arcpgu_fb_output_poll_changed(struct drm_device *dev) | |||
32 | } | 33 | } |
33 | 34 | ||
34 | static const struct drm_mode_config_funcs arcpgu_drm_modecfg_funcs = { | 35 | static const struct drm_mode_config_funcs arcpgu_drm_modecfg_funcs = { |
35 | .fb_create = drm_fb_cma_create, | 36 | .fb_create = drm_gem_fb_create, |
36 | .output_poll_changed = arcpgu_fb_output_poll_changed, | 37 | .output_poll_changed = arcpgu_fb_output_poll_changed, |
37 | .atomic_check = drm_atomic_helper_check, | 38 | .atomic_check = drm_atomic_helper_check, |
38 | .atomic_commit = drm_atomic_helper_commit, | 39 | .atomic_commit = drm_atomic_helper_commit, |
diff --git a/drivers/gpu/drm/arm/hdlcd_drv.c b/drivers/gpu/drm/arm/hdlcd_drv.c index f9bda7b0d2ec..764d0c83710c 100644 --- a/drivers/gpu/drm/arm/hdlcd_drv.c +++ b/drivers/gpu/drm/arm/hdlcd_drv.c | |||
@@ -25,6 +25,7 @@ | |||
25 | #include <drm/drm_fb_helper.h> | 25 | #include <drm/drm_fb_helper.h> |
26 | #include <drm/drm_fb_cma_helper.h> | 26 | #include <drm/drm_fb_cma_helper.h> |
27 | #include <drm/drm_gem_cma_helper.h> | 27 | #include <drm/drm_gem_cma_helper.h> |
28 | #include <drm/drm_gem_framebuffer_helper.h> | ||
28 | #include <drm/drm_of.h> | 29 | #include <drm/drm_of.h> |
29 | 30 | ||
30 | #include "hdlcd_drv.h" | 31 | #include "hdlcd_drv.h" |
@@ -106,7 +107,7 @@ static void hdlcd_fb_output_poll_changed(struct drm_device *drm) | |||
106 | } | 107 | } |
107 | 108 | ||
108 | static const struct drm_mode_config_funcs hdlcd_mode_config_funcs = { | 109 | static const struct drm_mode_config_funcs hdlcd_mode_config_funcs = { |
109 | .fb_create = drm_fb_cma_create, | 110 | .fb_create = drm_gem_fb_create, |
110 | .output_poll_changed = hdlcd_fb_output_poll_changed, | 111 | .output_poll_changed = hdlcd_fb_output_poll_changed, |
111 | .atomic_check = drm_atomic_helper_check, | 112 | .atomic_check = drm_atomic_helper_check, |
112 | .atomic_commit = drm_atomic_helper_commit, | 113 | .atomic_commit = drm_atomic_helper_commit, |
diff --git a/drivers/gpu/drm/arm/malidp_drv.c b/drivers/gpu/drm/arm/malidp_drv.c index 1a57cc28955e..b8944666a18f 100644 --- a/drivers/gpu/drm/arm/malidp_drv.c +++ b/drivers/gpu/drm/arm/malidp_drv.c | |||
@@ -26,6 +26,7 @@ | |||
26 | #include <drm/drm_crtc_helper.h> | 26 | #include <drm/drm_crtc_helper.h> |
27 | #include <drm/drm_fb_cma_helper.h> | 27 | #include <drm/drm_fb_cma_helper.h> |
28 | #include <drm/drm_gem_cma_helper.h> | 28 | #include <drm/drm_gem_cma_helper.h> |
29 | #include <drm/drm_gem_framebuffer_helper.h> | ||
29 | #include <drm/drm_of.h> | 30 | #include <drm/drm_of.h> |
30 | 31 | ||
31 | #include "malidp_drv.h" | 32 | #include "malidp_drv.h" |
@@ -249,7 +250,7 @@ static const struct drm_mode_config_helper_funcs malidp_mode_config_helpers = { | |||
249 | }; | 250 | }; |
250 | 251 | ||
251 | static const struct drm_mode_config_funcs malidp_mode_config_funcs = { | 252 | static const struct drm_mode_config_funcs malidp_mode_config_funcs = { |
252 | .fb_create = drm_fb_cma_create, | 253 | .fb_create = drm_gem_fb_create, |
253 | .output_poll_changed = malidp_output_poll_changed, | 254 | .output_poll_changed = malidp_output_poll_changed, |
254 | .atomic_check = drm_atomic_helper_check, | 255 | .atomic_check = drm_atomic_helper_check, |
255 | .atomic_commit = drm_atomic_helper_commit, | 256 | .atomic_commit = drm_atomic_helper_commit, |
diff --git a/drivers/gpu/drm/armada/Makefile b/drivers/gpu/drm/armada/Makefile index 64c0b4546fb2..a18f156c8b66 100644 --- a/drivers/gpu/drm/armada/Makefile +++ b/drivers/gpu/drm/armada/Makefile | |||
@@ -4,5 +4,3 @@ armada-y += armada_510.o | |||
4 | armada-$(CONFIG_DEBUG_FS) += armada_debugfs.o | 4 | armada-$(CONFIG_DEBUG_FS) += armada_debugfs.o |
5 | 5 | ||
6 | obj-$(CONFIG_DRM_ARMADA) := armada.o | 6 | obj-$(CONFIG_DRM_ARMADA) := armada.o |
7 | |||
8 | CFLAGS_armada_trace.o := -I$(src) | ||
diff --git a/drivers/gpu/drm/armada/armada_drv.c b/drivers/gpu/drm/armada/armada_drv.c index 0b3227c039d7..2fbd9d3393e8 100644 --- a/drivers/gpu/drm/armada/armada_drv.c +++ b/drivers/gpu/drm/armada/armada_drv.c | |||
@@ -70,8 +70,6 @@ static struct drm_driver armada_drm_driver = { | |||
70 | .gem_prime_export = armada_gem_prime_export, | 70 | .gem_prime_export = armada_gem_prime_export, |
71 | .gem_prime_import = armada_gem_prime_import, | 71 | .gem_prime_import = armada_gem_prime_import, |
72 | .dumb_create = armada_gem_dumb_create, | 72 | .dumb_create = armada_gem_dumb_create, |
73 | .dumb_map_offset = armada_gem_dumb_map_offset, | ||
74 | .dumb_destroy = armada_gem_dumb_destroy, | ||
75 | .gem_vm_ops = &armada_gem_vm_ops, | 73 | .gem_vm_ops = &armada_gem_vm_ops, |
76 | .major = 1, | 74 | .major = 1, |
77 | .minor = 0, | 75 | .minor = 0, |
diff --git a/drivers/gpu/drm/armada/armada_gem.c b/drivers/gpu/drm/armada/armada_gem.c index a76ca21d063b..79835380d5c6 100644 --- a/drivers/gpu/drm/armada/armada_gem.c +++ b/drivers/gpu/drm/armada/armada_gem.c | |||
@@ -270,42 +270,6 @@ int armada_gem_dumb_create(struct drm_file *file, struct drm_device *dev, | |||
270 | return ret; | 270 | return ret; |
271 | } | 271 | } |
272 | 272 | ||
273 | int armada_gem_dumb_map_offset(struct drm_file *file, struct drm_device *dev, | ||
274 | uint32_t handle, uint64_t *offset) | ||
275 | { | ||
276 | struct armada_gem_object *obj; | ||
277 | int ret = 0; | ||
278 | |||
279 | obj = armada_gem_object_lookup(file, handle); | ||
280 | if (!obj) { | ||
281 | DRM_ERROR("failed to lookup gem object\n"); | ||
282 | return -EINVAL; | ||
283 | } | ||
284 | |||
285 | /* Don't allow imported objects to be mapped */ | ||
286 | if (obj->obj.import_attach) { | ||
287 | ret = -EINVAL; | ||
288 | goto err_unref; | ||
289 | } | ||
290 | |||
291 | ret = drm_gem_create_mmap_offset(&obj->obj); | ||
292 | if (ret == 0) { | ||
293 | *offset = drm_vma_node_offset_addr(&obj->obj.vma_node); | ||
294 | DRM_DEBUG_DRIVER("handle %#x offset %llx\n", handle, *offset); | ||
295 | } | ||
296 | |||
297 | err_unref: | ||
298 | drm_gem_object_unreference_unlocked(&obj->obj); | ||
299 | |||
300 | return ret; | ||
301 | } | ||
302 | |||
303 | int armada_gem_dumb_destroy(struct drm_file *file, struct drm_device *dev, | ||
304 | uint32_t handle) | ||
305 | { | ||
306 | return drm_gem_handle_delete(file, handle); | ||
307 | } | ||
308 | |||
309 | /* Private driver gem ioctls */ | 273 | /* Private driver gem ioctls */ |
310 | int armada_gem_create_ioctl(struct drm_device *dev, void *data, | 274 | int armada_gem_create_ioctl(struct drm_device *dev, void *data, |
311 | struct drm_file *file) | 275 | struct drm_file *file) |
diff --git a/drivers/gpu/drm/armada/armada_gem.h b/drivers/gpu/drm/armada/armada_gem.h index 6e524e0676bb..1ac90792b166 100644 --- a/drivers/gpu/drm/armada/armada_gem.h +++ b/drivers/gpu/drm/armada/armada_gem.h | |||
@@ -35,10 +35,6 @@ struct armada_gem_object *armada_gem_alloc_private_object(struct drm_device *, | |||
35 | size_t); | 35 | size_t); |
36 | int armada_gem_dumb_create(struct drm_file *, struct drm_device *, | 36 | int armada_gem_dumb_create(struct drm_file *, struct drm_device *, |
37 | struct drm_mode_create_dumb *); | 37 | struct drm_mode_create_dumb *); |
38 | int armada_gem_dumb_map_offset(struct drm_file *, struct drm_device *, | ||
39 | uint32_t, uint64_t *); | ||
40 | int armada_gem_dumb_destroy(struct drm_file *, struct drm_device *, | ||
41 | uint32_t); | ||
42 | struct dma_buf *armada_gem_prime_export(struct drm_device *dev, | 38 | struct dma_buf *armada_gem_prime_export(struct drm_device *dev, |
43 | struct drm_gem_object *obj, int flags); | 39 | struct drm_gem_object *obj, int flags); |
44 | struct drm_gem_object *armada_gem_prime_import(struct drm_device *, | 40 | struct drm_gem_object *armada_gem_prime_import(struct drm_device *, |
diff --git a/drivers/gpu/drm/armada/armada_trace.h b/drivers/gpu/drm/armada/armada_trace.h index dc0cba70fd1a..be245a24610f 100644 --- a/drivers/gpu/drm/armada/armada_trace.h +++ b/drivers/gpu/drm/armada/armada_trace.h | |||
@@ -62,5 +62,5 @@ TRACE_EVENT(armada_ovl_plane_work, | |||
62 | 62 | ||
63 | /* This part must be outside protection */ | 63 | /* This part must be outside protection */ |
64 | #undef TRACE_INCLUDE_PATH | 64 | #undef TRACE_INCLUDE_PATH |
65 | #define TRACE_INCLUDE_PATH . | 65 | #define TRACE_INCLUDE_PATH ../../drivers/gpu/drm/armada |
66 | #include <trace/define_trace.h> | 66 | #include <trace/define_trace.h> |
diff --git a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c index 74d66e11f688..c6e8061ffcfc 100644 --- a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c +++ b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c | |||
@@ -458,7 +458,7 @@ static irqreturn_t atmel_hlcdc_dc_irq_handler(int irq, void *data) | |||
458 | static struct drm_framebuffer *atmel_hlcdc_fb_create(struct drm_device *dev, | 458 | static struct drm_framebuffer *atmel_hlcdc_fb_create(struct drm_device *dev, |
459 | struct drm_file *file_priv, const struct drm_mode_fb_cmd2 *mode_cmd) | 459 | struct drm_file *file_priv, const struct drm_mode_fb_cmd2 *mode_cmd) |
460 | { | 460 | { |
461 | return drm_fb_cma_create(dev, file_priv, mode_cmd); | 461 | return drm_gem_fb_create(dev, file_priv, mode_cmd); |
462 | } | 462 | } |
463 | 463 | ||
464 | static void atmel_hlcdc_fb_output_poll_changed(struct drm_device *dev) | 464 | static void atmel_hlcdc_fb_output_poll_changed(struct drm_device *dev) |
diff --git a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.h b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.h index 4237b0446721..6833ee253cfa 100644 --- a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.h +++ b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.h | |||
@@ -34,6 +34,7 @@ | |||
34 | #include <drm/drm_crtc_helper.h> | 34 | #include <drm/drm_crtc_helper.h> |
35 | #include <drm/drm_fb_cma_helper.h> | 35 | #include <drm/drm_fb_cma_helper.h> |
36 | #include <drm/drm_gem_cma_helper.h> | 36 | #include <drm/drm_gem_cma_helper.h> |
37 | #include <drm/drm_gem_framebuffer_helper.h> | ||
37 | #include <drm/drm_panel.h> | 38 | #include <drm/drm_panel.h> |
38 | #include <drm/drm_plane_helper.h> | 39 | #include <drm/drm_plane_helper.h> |
39 | #include <drm/drmP.h> | 40 | #include <drm/drmP.h> |
diff --git a/drivers/gpu/drm/bridge/adv7511/adv7511.h b/drivers/gpu/drm/bridge/adv7511/adv7511.h index fe18a5d2d84b..12ef2d8ee110 100644 --- a/drivers/gpu/drm/bridge/adv7511/adv7511.h +++ b/drivers/gpu/drm/bridge/adv7511/adv7511.h | |||
@@ -328,8 +328,6 @@ struct adv7511 { | |||
328 | enum adv7511_sync_polarity hsync_polarity; | 328 | enum adv7511_sync_polarity hsync_polarity; |
329 | bool rgb; | 329 | bool rgb; |
330 | 330 | ||
331 | struct edid *edid; | ||
332 | |||
333 | struct gpio_desc *gpio_pd; | 331 | struct gpio_desc *gpio_pd; |
334 | 332 | ||
335 | struct regulator_bulk_data *supplies; | 333 | struct regulator_bulk_data *supplies; |
diff --git a/drivers/gpu/drm/bridge/adv7511/adv7511_audio.c b/drivers/gpu/drm/bridge/adv7511/adv7511_audio.c index 67469c26bae8..1b4783d45c53 100644 --- a/drivers/gpu/drm/bridge/adv7511/adv7511_audio.c +++ b/drivers/gpu/drm/bridge/adv7511/adv7511_audio.c | |||
@@ -210,7 +210,7 @@ static const struct hdmi_codec_ops adv7511_codec_ops = { | |||
210 | .get_dai_id = adv7511_hdmi_i2s_get_dai_id, | 210 | .get_dai_id = adv7511_hdmi_i2s_get_dai_id, |
211 | }; | 211 | }; |
212 | 212 | ||
213 | static struct hdmi_codec_pdata codec_data = { | 213 | static const struct hdmi_codec_pdata codec_data = { |
214 | .ops = &adv7511_codec_ops, | 214 | .ops = &adv7511_codec_ops, |
215 | .max_i2s_channels = 2, | 215 | .max_i2s_channels = 2, |
216 | .i2s = 1, | 216 | .i2s = 1, |
diff --git a/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c b/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c index b2431aee7887..bd7dbae1119e 100644 --- a/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c +++ b/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c | |||
@@ -199,17 +199,14 @@ static const uint16_t adv7511_csc_ycbcr_to_rgb[] = { | |||
199 | 199 | ||
200 | static void adv7511_set_config_csc(struct adv7511 *adv7511, | 200 | static void adv7511_set_config_csc(struct adv7511 *adv7511, |
201 | struct drm_connector *connector, | 201 | struct drm_connector *connector, |
202 | bool rgb) | 202 | bool rgb, bool hdmi_mode) |
203 | { | 203 | { |
204 | struct adv7511_video_config config; | 204 | struct adv7511_video_config config; |
205 | bool output_format_422, output_format_ycbcr; | 205 | bool output_format_422, output_format_ycbcr; |
206 | unsigned int mode; | 206 | unsigned int mode; |
207 | uint8_t infoframe[17]; | 207 | uint8_t infoframe[17]; |
208 | 208 | ||
209 | if (adv7511->edid) | 209 | config.hdmi_mode = hdmi_mode; |
210 | config.hdmi_mode = drm_detect_hdmi_monitor(adv7511->edid); | ||
211 | else | ||
212 | config.hdmi_mode = false; | ||
213 | 210 | ||
214 | hdmi_avi_infoframe_init(&config.avi_infoframe); | 211 | hdmi_avi_infoframe_init(&config.avi_infoframe); |
215 | 212 | ||
@@ -589,15 +586,14 @@ static int adv7511_get_modes(struct adv7511 *adv7511, | |||
589 | if (!adv7511->powered) | 586 | if (!adv7511->powered) |
590 | __adv7511_power_off(adv7511); | 587 | __adv7511_power_off(adv7511); |
591 | 588 | ||
592 | kfree(adv7511->edid); | ||
593 | adv7511->edid = edid; | ||
594 | if (!edid) | ||
595 | return 0; | ||
596 | 589 | ||
597 | drm_mode_connector_update_edid_property(connector, edid); | 590 | drm_mode_connector_update_edid_property(connector, edid); |
598 | count = drm_add_edid_modes(connector, edid); | 591 | count = drm_add_edid_modes(connector, edid); |
599 | 592 | ||
600 | adv7511_set_config_csc(adv7511, connector, adv7511->rgb); | 593 | adv7511_set_config_csc(adv7511, connector, adv7511->rgb, |
594 | drm_detect_hdmi_monitor(edid)); | ||
595 | |||
596 | kfree(edid); | ||
601 | 597 | ||
602 | return count; | 598 | return count; |
603 | } | 599 | } |
@@ -833,7 +829,11 @@ static int adv7511_bridge_attach(struct drm_bridge *bridge) | |||
833 | return -ENODEV; | 829 | return -ENODEV; |
834 | } | 830 | } |
835 | 831 | ||
836 | adv->connector.polled = DRM_CONNECTOR_POLL_HPD; | 832 | if (adv->i2c_main->irq) |
833 | adv->connector.polled = DRM_CONNECTOR_POLL_HPD; | ||
834 | else | ||
835 | adv->connector.polled = DRM_CONNECTOR_POLL_CONNECT | | ||
836 | DRM_CONNECTOR_POLL_DISCONNECT; | ||
837 | 837 | ||
838 | ret = drm_connector_init(bridge->dev, &adv->connector, | 838 | ret = drm_connector_init(bridge->dev, &adv->connector, |
839 | &adv7511_connector_funcs, | 839 | &adv7511_connector_funcs, |
@@ -1158,8 +1158,6 @@ static int adv7511_remove(struct i2c_client *i2c) | |||
1158 | 1158 | ||
1159 | i2c_unregister_device(adv7511->i2c_edid); | 1159 | i2c_unregister_device(adv7511->i2c_edid); |
1160 | 1160 | ||
1161 | kfree(adv7511->edid); | ||
1162 | |||
1163 | return 0; | 1161 | return 0; |
1164 | } | 1162 | } |
1165 | 1163 | ||
diff --git a/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c b/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c index 63c7a01b7053..f4f633a0dffa 100644 --- a/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c +++ b/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c | |||
@@ -30,19 +30,20 @@ | |||
30 | #include <video/mipi_display.h> | 30 | #include <video/mipi_display.h> |
31 | 31 | ||
32 | #define DSI_VERSION 0x00 | 32 | #define DSI_VERSION 0x00 |
33 | |||
33 | #define DSI_PWR_UP 0x04 | 34 | #define DSI_PWR_UP 0x04 |
34 | #define RESET 0 | 35 | #define RESET 0 |
35 | #define POWERUP BIT(0) | 36 | #define POWERUP BIT(0) |
36 | 37 | ||
37 | #define DSI_CLKMGR_CFG 0x08 | 38 | #define DSI_CLKMGR_CFG 0x08 |
38 | #define TO_CLK_DIVIDSION(div) (((div) & 0xff) << 8) | 39 | #define TO_CLK_DIVISION(div) (((div) & 0xff) << 8) |
39 | #define TX_ESC_CLK_DIVIDSION(div) (((div) & 0xff) << 0) | 40 | #define TX_ESC_CLK_DIVISION(div) ((div) & 0xff) |
40 | 41 | ||
41 | #define DSI_DPI_VCID 0x0c | 42 | #define DSI_DPI_VCID 0x0c |
42 | #define DPI_VID(vid) (((vid) & 0x3) << 0) | 43 | #define DPI_VCID(vcid) ((vcid) & 0x3) |
43 | 44 | ||
44 | #define DSI_DPI_COLOR_CODING 0x10 | 45 | #define DSI_DPI_COLOR_CODING 0x10 |
45 | #define EN18_LOOSELY BIT(8) | 46 | #define LOOSELY18_EN BIT(8) |
46 | #define DPI_COLOR_CODING_16BIT_1 0x0 | 47 | #define DPI_COLOR_CODING_16BIT_1 0x0 |
47 | #define DPI_COLOR_CODING_16BIT_2 0x1 | 48 | #define DPI_COLOR_CODING_16BIT_2 0x1 |
48 | #define DPI_COLOR_CODING_16BIT_3 0x2 | 49 | #define DPI_COLOR_CODING_16BIT_3 0x2 |
@@ -61,22 +62,25 @@ | |||
61 | #define OUTVACT_LPCMD_TIME(p) (((p) & 0xff) << 16) | 62 | #define OUTVACT_LPCMD_TIME(p) (((p) & 0xff) << 16) |
62 | #define INVACT_LPCMD_TIME(p) ((p) & 0xff) | 63 | #define INVACT_LPCMD_TIME(p) ((p) & 0xff) |
63 | 64 | ||
65 | #define DSI_DBI_VCID 0x1c | ||
64 | #define DSI_DBI_CFG 0x20 | 66 | #define DSI_DBI_CFG 0x20 |
67 | #define DSI_DBI_PARTITIONING_EN 0x24 | ||
65 | #define DSI_DBI_CMDSIZE 0x28 | 68 | #define DSI_DBI_CMDSIZE 0x28 |
66 | 69 | ||
67 | #define DSI_PCKHDL_CFG 0x2c | 70 | #define DSI_PCKHDL_CFG 0x2c |
68 | #define EN_CRC_RX BIT(4) | 71 | #define CRC_RX_EN BIT(4) |
69 | #define EN_ECC_RX BIT(3) | 72 | #define ECC_RX_EN BIT(3) |
70 | #define EN_BTA BIT(2) | 73 | #define BTA_EN BIT(2) |
71 | #define EN_EOTP_RX BIT(1) | 74 | #define EOTP_RX_EN BIT(1) |
72 | #define EN_EOTP_TX BIT(0) | 75 | #define EOTP_TX_EN BIT(0) |
76 | |||
77 | #define DSI_GEN_VCID 0x30 | ||
73 | 78 | ||
74 | #define DSI_MODE_CFG 0x34 | 79 | #define DSI_MODE_CFG 0x34 |
75 | #define ENABLE_VIDEO_MODE 0 | 80 | #define ENABLE_VIDEO_MODE 0 |
76 | #define ENABLE_CMD_MODE BIT(0) | 81 | #define ENABLE_CMD_MODE BIT(0) |
77 | 82 | ||
78 | #define DSI_VID_MODE_CFG 0x38 | 83 | #define DSI_VID_MODE_CFG 0x38 |
79 | #define FRAME_BTA_ACK BIT(14) | ||
80 | #define ENABLE_LOW_POWER (0x3f << 8) | 84 | #define ENABLE_LOW_POWER (0x3f << 8) |
81 | #define ENABLE_LOW_POWER_MASK (0x3f << 8) | 85 | #define ENABLE_LOW_POWER_MASK (0x3f << 8) |
82 | #define VID_MODE_TYPE_NON_BURST_SYNC_PULSES 0x0 | 86 | #define VID_MODE_TYPE_NON_BURST_SYNC_PULSES 0x0 |
@@ -85,8 +89,13 @@ | |||
85 | #define VID_MODE_TYPE_MASK 0x3 | 89 | #define VID_MODE_TYPE_MASK 0x3 |
86 | 90 | ||
87 | #define DSI_VID_PKT_SIZE 0x3c | 91 | #define DSI_VID_PKT_SIZE 0x3c |
88 | #define VID_PKT_SIZE(p) (((p) & 0x3fff) << 0) | 92 | #define VID_PKT_SIZE(p) ((p) & 0x3fff) |
89 | #define VID_PKT_MAX_SIZE 0x3fff | 93 | |
94 | #define DSI_VID_NUM_CHUNKS 0x40 | ||
95 | #define VID_NUM_CHUNKS(c) ((c) & 0x1fff) | ||
96 | |||
97 | #define DSI_VID_NULL_SIZE 0x44 | ||
98 | #define VID_NULL_SIZE(b) ((b) & 0x1fff) | ||
90 | 99 | ||
91 | #define DSI_VID_HSA_TIME 0x48 | 100 | #define DSI_VID_HSA_TIME 0x48 |
92 | #define DSI_VID_HBP_TIME 0x4c | 101 | #define DSI_VID_HBP_TIME 0x4c |
@@ -95,6 +104,8 @@ | |||
95 | #define DSI_VID_VBP_LINES 0x58 | 104 | #define DSI_VID_VBP_LINES 0x58 |
96 | #define DSI_VID_VFP_LINES 0x5c | 105 | #define DSI_VID_VFP_LINES 0x5c |
97 | #define DSI_VID_VACTIVE_LINES 0x60 | 106 | #define DSI_VID_VACTIVE_LINES 0x60 |
107 | #define DSI_EDPI_CMD_SIZE 0x64 | ||
108 | |||
98 | #define DSI_CMD_MODE_CFG 0x68 | 109 | #define DSI_CMD_MODE_CFG 0x68 |
99 | #define MAX_RD_PKT_SIZE_LP BIT(24) | 110 | #define MAX_RD_PKT_SIZE_LP BIT(24) |
100 | #define DCS_LW_TX_LP BIT(19) | 111 | #define DCS_LW_TX_LP BIT(19) |
@@ -108,8 +119,8 @@ | |||
108 | #define GEN_SW_2P_TX_LP BIT(10) | 119 | #define GEN_SW_2P_TX_LP BIT(10) |
109 | #define GEN_SW_1P_TX_LP BIT(9) | 120 | #define GEN_SW_1P_TX_LP BIT(9) |
110 | #define GEN_SW_0P_TX_LP BIT(8) | 121 | #define GEN_SW_0P_TX_LP BIT(8) |
111 | #define EN_ACK_RQST BIT(1) | 122 | #define ACK_RQST_EN BIT(1) |
112 | #define EN_TEAR_FX BIT(0) | 123 | #define TEAR_FX_EN BIT(0) |
113 | 124 | ||
114 | #define CMD_MODE_ALL_LP (MAX_RD_PKT_SIZE_LP | \ | 125 | #define CMD_MODE_ALL_LP (MAX_RD_PKT_SIZE_LP | \ |
115 | DCS_LW_TX_LP | \ | 126 | DCS_LW_TX_LP | \ |
@@ -125,27 +136,31 @@ | |||
125 | GEN_SW_0P_TX_LP) | 136 | GEN_SW_0P_TX_LP) |
126 | 137 | ||
127 | #define DSI_GEN_HDR 0x6c | 138 | #define DSI_GEN_HDR 0x6c |
139 | /* TODO These 2 defines will be reworked thanks to mipi_dsi_create_packet() */ | ||
128 | #define GEN_HDATA(data) (((data) & 0xffff) << 8) | 140 | #define GEN_HDATA(data) (((data) & 0xffff) << 8) |
129 | #define GEN_HDATA_MASK (0xffff << 8) | ||
130 | #define GEN_HTYPE(type) (((type) & 0xff) << 0) | 141 | #define GEN_HTYPE(type) (((type) & 0xff) << 0) |
131 | #define GEN_HTYPE_MASK 0xff | ||
132 | 142 | ||
133 | #define DSI_GEN_PLD_DATA 0x70 | 143 | #define DSI_GEN_PLD_DATA 0x70 |
134 | 144 | ||
135 | #define DSI_CMD_PKT_STATUS 0x74 | 145 | #define DSI_CMD_PKT_STATUS 0x74 |
136 | #define GEN_CMD_EMPTY BIT(0) | ||
137 | #define GEN_CMD_FULL BIT(1) | ||
138 | #define GEN_PLD_W_EMPTY BIT(2) | ||
139 | #define GEN_PLD_W_FULL BIT(3) | ||
140 | #define GEN_PLD_R_EMPTY BIT(4) | ||
141 | #define GEN_PLD_R_FULL BIT(5) | ||
142 | #define GEN_RD_CMD_BUSY BIT(6) | 146 | #define GEN_RD_CMD_BUSY BIT(6) |
147 | #define GEN_PLD_R_FULL BIT(5) | ||
148 | #define GEN_PLD_R_EMPTY BIT(4) | ||
149 | #define GEN_PLD_W_FULL BIT(3) | ||
150 | #define GEN_PLD_W_EMPTY BIT(2) | ||
151 | #define GEN_CMD_FULL BIT(1) | ||
152 | #define GEN_CMD_EMPTY BIT(0) | ||
143 | 153 | ||
144 | #define DSI_TO_CNT_CFG 0x78 | 154 | #define DSI_TO_CNT_CFG 0x78 |
145 | #define HSTX_TO_CNT(p) (((p) & 0xffff) << 16) | 155 | #define HSTX_TO_CNT(p) (((p) & 0xffff) << 16) |
146 | #define LPRX_TO_CNT(p) ((p) & 0xffff) | 156 | #define LPRX_TO_CNT(p) ((p) & 0xffff) |
147 | 157 | ||
158 | #define DSI_HS_RD_TO_CNT 0x7c | ||
159 | #define DSI_LP_RD_TO_CNT 0x80 | ||
160 | #define DSI_HS_WR_TO_CNT 0x84 | ||
161 | #define DSI_LP_WR_TO_CNT 0x88 | ||
148 | #define DSI_BTA_TO_CNT 0x8c | 162 | #define DSI_BTA_TO_CNT 0x8c |
163 | |||
149 | #define DSI_LPCLK_CTRL 0x94 | 164 | #define DSI_LPCLK_CTRL 0x94 |
150 | #define AUTO_CLKLANE_CTRL BIT(1) | 165 | #define AUTO_CLKLANE_CTRL BIT(1) |
151 | #define PHY_TXREQUESTCLKHS BIT(0) | 166 | #define PHY_TXREQUESTCLKHS BIT(0) |
@@ -154,6 +169,7 @@ | |||
154 | #define PHY_CLKHS2LP_TIME(lbcc) (((lbcc) & 0x3ff) << 16) | 169 | #define PHY_CLKHS2LP_TIME(lbcc) (((lbcc) & 0x3ff) << 16) |
155 | #define PHY_CLKLP2HS_TIME(lbcc) ((lbcc) & 0x3ff) | 170 | #define PHY_CLKLP2HS_TIME(lbcc) ((lbcc) & 0x3ff) |
156 | 171 | ||
172 | /* TODO Next register is slightly different between 1.30 & 1.31 IP version */ | ||
157 | #define DSI_PHY_TMR_CFG 0x9c | 173 | #define DSI_PHY_TMR_CFG 0x9c |
158 | #define PHY_HS2LP_TIME(lbcc) (((lbcc) & 0xff) << 24) | 174 | #define PHY_HS2LP_TIME(lbcc) (((lbcc) & 0xff) << 24) |
159 | #define PHY_LP2HS_TIME(lbcc) (((lbcc) & 0xff) << 16) | 175 | #define PHY_LP2HS_TIME(lbcc) (((lbcc) & 0xff) << 16) |
@@ -170,12 +186,15 @@ | |||
170 | #define PHY_UNSHUTDOWNZ BIT(0) | 186 | #define PHY_UNSHUTDOWNZ BIT(0) |
171 | 187 | ||
172 | #define DSI_PHY_IF_CFG 0xa4 | 188 | #define DSI_PHY_IF_CFG 0xa4 |
173 | #define N_LANES(n) ((((n) - 1) & 0x3) << 0) | ||
174 | #define PHY_STOP_WAIT_TIME(cycle) (((cycle) & 0xff) << 8) | 189 | #define PHY_STOP_WAIT_TIME(cycle) (((cycle) & 0xff) << 8) |
190 | #define N_LANES(n) (((n) - 1) & 0x3) | ||
191 | |||
192 | #define DSI_PHY_ULPS_CTRL 0xa8 | ||
193 | #define DSI_PHY_TX_TRIGGERS 0xac | ||
175 | 194 | ||
176 | #define DSI_PHY_STATUS 0xb0 | 195 | #define DSI_PHY_STATUS 0xb0 |
177 | #define LOCK BIT(0) | 196 | #define PHY_STOP_STATE_CLK_LANE BIT(2) |
178 | #define STOP_STATE_CLK_LANE BIT(2) | 197 | #define PHY_LOCK BIT(0) |
179 | 198 | ||
180 | #define DSI_PHY_TST_CTRL0 0xb4 | 199 | #define DSI_PHY_TST_CTRL0 0xb4 |
181 | #define PHY_TESTCLK BIT(1) | 200 | #define PHY_TESTCLK BIT(1) |
@@ -187,12 +206,13 @@ | |||
187 | #define PHY_TESTEN BIT(16) | 206 | #define PHY_TESTEN BIT(16) |
188 | #define PHY_UNTESTEN 0 | 207 | #define PHY_UNTESTEN 0 |
189 | #define PHY_TESTDOUT(n) (((n) & 0xff) << 8) | 208 | #define PHY_TESTDOUT(n) (((n) & 0xff) << 8) |
190 | #define PHY_TESTDIN(n) (((n) & 0xff) << 0) | 209 | #define PHY_TESTDIN(n) ((n) & 0xff) |
191 | 210 | ||
192 | #define DSI_INT_ST0 0xbc | 211 | #define DSI_INT_ST0 0xbc |
193 | #define DSI_INT_ST1 0xc0 | 212 | #define DSI_INT_ST1 0xc0 |
194 | #define DSI_INT_MSK0 0xc4 | 213 | #define DSI_INT_MSK0 0xc4 |
195 | #define DSI_INT_MSK1 0xc8 | 214 | #define DSI_INT_MSK1 0xc8 |
215 | #define DSI_PHY_TMR_RD_CFG 0xf4 | ||
196 | 216 | ||
197 | #define PHY_STATUS_TIMEOUT_US 10000 | 217 | #define PHY_STATUS_TIMEOUT_US 10000 |
198 | #define CMD_PKT_STATUS_TIMEOUT_US 20000 | 218 | #define CMD_PKT_STATUS_TIMEOUT_US 20000 |
@@ -307,7 +327,7 @@ static void dw_mipi_message_config(struct dw_mipi_dsi *dsi, | |||
307 | u32 val = 0; | 327 | u32 val = 0; |
308 | 328 | ||
309 | if (msg->flags & MIPI_DSI_MSG_REQ_ACK) | 329 | if (msg->flags & MIPI_DSI_MSG_REQ_ACK) |
310 | val |= EN_ACK_RQST; | 330 | val |= ACK_RQST_EN; |
311 | if (lpm) | 331 | if (lpm) |
312 | val |= CMD_MODE_ALL_LP; | 332 | val |= CMD_MODE_ALL_LP; |
313 | 333 | ||
@@ -506,8 +526,8 @@ static void dw_mipi_dsi_init(struct dw_mipi_dsi *dsi) | |||
506 | * timeout clock division should be computed with the | 526 | * timeout clock division should be computed with the |
507 | * high speed transmission counter timeout and byte lane... | 527 | * high speed transmission counter timeout and byte lane... |
508 | */ | 528 | */ |
509 | dsi_write(dsi, DSI_CLKMGR_CFG, TO_CLK_DIVIDSION(10) | | 529 | dsi_write(dsi, DSI_CLKMGR_CFG, TO_CLK_DIVISION(10) | |
510 | TX_ESC_CLK_DIVIDSION(esc_clk_division)); | 530 | TX_ESC_CLK_DIVISION(esc_clk_division)); |
511 | } | 531 | } |
512 | 532 | ||
513 | static void dw_mipi_dsi_dpi_config(struct dw_mipi_dsi *dsi, | 533 | static void dw_mipi_dsi_dpi_config(struct dw_mipi_dsi *dsi, |
@@ -520,7 +540,7 @@ static void dw_mipi_dsi_dpi_config(struct dw_mipi_dsi *dsi, | |||
520 | color = DPI_COLOR_CODING_24BIT; | 540 | color = DPI_COLOR_CODING_24BIT; |
521 | break; | 541 | break; |
522 | case MIPI_DSI_FMT_RGB666: | 542 | case MIPI_DSI_FMT_RGB666: |
523 | color = DPI_COLOR_CODING_18BIT_2 | EN18_LOOSELY; | 543 | color = DPI_COLOR_CODING_18BIT_2 | LOOSELY18_EN; |
524 | break; | 544 | break; |
525 | case MIPI_DSI_FMT_RGB666_PACKED: | 545 | case MIPI_DSI_FMT_RGB666_PACKED: |
526 | color = DPI_COLOR_CODING_18BIT_1; | 546 | color = DPI_COLOR_CODING_18BIT_1; |
@@ -535,7 +555,7 @@ static void dw_mipi_dsi_dpi_config(struct dw_mipi_dsi *dsi, | |||
535 | if (mode->flags & DRM_MODE_FLAG_NHSYNC) | 555 | if (mode->flags & DRM_MODE_FLAG_NHSYNC) |
536 | val |= HSYNC_ACTIVE_LOW; | 556 | val |= HSYNC_ACTIVE_LOW; |
537 | 557 | ||
538 | dsi_write(dsi, DSI_DPI_VCID, DPI_VID(dsi->channel)); | 558 | dsi_write(dsi, DSI_DPI_VCID, DPI_VCID(dsi->channel)); |
539 | dsi_write(dsi, DSI_DPI_COLOR_CODING, color); | 559 | dsi_write(dsi, DSI_DPI_COLOR_CODING, color); |
540 | dsi_write(dsi, DSI_DPI_CFG_POL, val); | 560 | dsi_write(dsi, DSI_DPI_CFG_POL, val); |
541 | /* | 561 | /* |
@@ -550,7 +570,7 @@ static void dw_mipi_dsi_dpi_config(struct dw_mipi_dsi *dsi, | |||
550 | 570 | ||
551 | static void dw_mipi_dsi_packet_handler_config(struct dw_mipi_dsi *dsi) | 571 | static void dw_mipi_dsi_packet_handler_config(struct dw_mipi_dsi *dsi) |
552 | { | 572 | { |
553 | dsi_write(dsi, DSI_PCKHDL_CFG, EN_CRC_RX | EN_ECC_RX | EN_BTA); | 573 | dsi_write(dsi, DSI_PCKHDL_CFG, CRC_RX_EN | ECC_RX_EN | BTA_EN); |
554 | } | 574 | } |
555 | 575 | ||
556 | static void dw_mipi_dsi_video_packet_config(struct dw_mipi_dsi *dsi, | 576 | static void dw_mipi_dsi_video_packet_config(struct dw_mipi_dsi *dsi, |
@@ -571,7 +591,7 @@ static void dw_mipi_dsi_command_mode_config(struct dw_mipi_dsi *dsi) | |||
571 | /* | 591 | /* |
572 | * TODO dw drv improvements | 592 | * TODO dw drv improvements |
573 | * compute high speed transmission counter timeout according | 593 | * compute high speed transmission counter timeout according |
574 | * to the timeout clock division (TO_CLK_DIVIDSION) and byte lane... | 594 | * to the timeout clock division (TO_CLK_DIVISION) and byte lane... |
575 | */ | 595 | */ |
576 | dsi_write(dsi, DSI_TO_CNT_CFG, HSTX_TO_CNT(1000) | LPRX_TO_CNT(1000)); | 596 | dsi_write(dsi, DSI_TO_CNT_CFG, HSTX_TO_CNT(1000) | LPRX_TO_CNT(1000)); |
577 | /* | 597 | /* |
@@ -684,13 +704,13 @@ static void dw_mipi_dsi_dphy_enable(struct dw_mipi_dsi *dsi) | |||
684 | dsi_write(dsi, DSI_PHY_RSTZ, PHY_ENFORCEPLL | PHY_ENABLECLK | | 704 | dsi_write(dsi, DSI_PHY_RSTZ, PHY_ENFORCEPLL | PHY_ENABLECLK | |
685 | PHY_UNRSTZ | PHY_UNSHUTDOWNZ); | 705 | PHY_UNRSTZ | PHY_UNSHUTDOWNZ); |
686 | 706 | ||
687 | ret = readl_poll_timeout(dsi->base + DSI_PHY_STATUS, | 707 | ret = readl_poll_timeout(dsi->base + DSI_PHY_STATUS, val, |
688 | val, val & LOCK, 1000, PHY_STATUS_TIMEOUT_US); | 708 | val & PHY_LOCK, 1000, PHY_STATUS_TIMEOUT_US); |
689 | if (ret < 0) | 709 | if (ret < 0) |
690 | DRM_DEBUG_DRIVER("failed to wait phy lock state\n"); | 710 | DRM_DEBUG_DRIVER("failed to wait phy lock state\n"); |
691 | 711 | ||
692 | ret = readl_poll_timeout(dsi->base + DSI_PHY_STATUS, | 712 | ret = readl_poll_timeout(dsi->base + DSI_PHY_STATUS, |
693 | val, val & STOP_STATE_CLK_LANE, 1000, | 713 | val, val & PHY_STOP_STATE_CLK_LANE, 1000, |
694 | PHY_STATUS_TIMEOUT_US); | 714 | PHY_STATUS_TIMEOUT_US); |
695 | if (ret < 0) | 715 | if (ret < 0) |
696 | DRM_DEBUG_DRIVER("failed to wait phy clk lane stop state\n"); | 716 | DRM_DEBUG_DRIVER("failed to wait phy clk lane stop state\n"); |
@@ -865,15 +885,14 @@ __dw_mipi_dsi_probe(struct platform_device *pdev, | |||
865 | * Note that the reset was not defined in the initial device tree, so | 885 | * Note that the reset was not defined in the initial device tree, so |
866 | * we have to be prepared for it not being found. | 886 | * we have to be prepared for it not being found. |
867 | */ | 887 | */ |
868 | apb_rst = devm_reset_control_get(dev, "apb"); | 888 | apb_rst = devm_reset_control_get_optional_exclusive(dev, "apb"); |
869 | if (IS_ERR(apb_rst)) { | 889 | if (IS_ERR(apb_rst)) { |
870 | ret = PTR_ERR(apb_rst); | 890 | ret = PTR_ERR(apb_rst); |
871 | if (ret == -ENOENT) { | 891 | |
872 | apb_rst = NULL; | 892 | if (ret != -EPROBE_DEFER) |
873 | } else { | ||
874 | dev_err(dev, "Unable to get reset control: %d\n", ret); | 893 | dev_err(dev, "Unable to get reset control: %d\n", ret); |
875 | return ERR_PTR(ret); | 894 | |
876 | } | 895 | return ERR_PTR(ret); |
877 | } | 896 | } |
878 | 897 | ||
879 | if (apb_rst) { | 898 | if (apb_rst) { |
diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c index 2fd383d7253a..366c56fe5f58 100644 --- a/drivers/gpu/drm/drm_atomic.c +++ b/drivers/gpu/drm/drm_atomic.c | |||
@@ -163,13 +163,6 @@ void drm_atomic_state_default_clear(struct drm_atomic_state *state) | |||
163 | crtc->funcs->atomic_destroy_state(crtc, | 163 | crtc->funcs->atomic_destroy_state(crtc, |
164 | state->crtcs[i].state); | 164 | state->crtcs[i].state); |
165 | 165 | ||
166 | if (state->crtcs[i].commit) { | ||
167 | kfree(state->crtcs[i].commit->event); | ||
168 | state->crtcs[i].commit->event = NULL; | ||
169 | drm_crtc_commit_put(state->crtcs[i].commit); | ||
170 | } | ||
171 | |||
172 | state->crtcs[i].commit = NULL; | ||
173 | state->crtcs[i].ptr = NULL; | 166 | state->crtcs[i].ptr = NULL; |
174 | state->crtcs[i].state = NULL; | 167 | state->crtcs[i].state = NULL; |
175 | } | 168 | } |
@@ -199,6 +192,10 @@ void drm_atomic_state_default_clear(struct drm_atomic_state *state) | |||
199 | } | 192 | } |
200 | state->num_private_objs = 0; | 193 | state->num_private_objs = 0; |
201 | 194 | ||
195 | if (state->fake_commit) { | ||
196 | drm_crtc_commit_put(state->fake_commit); | ||
197 | state->fake_commit = NULL; | ||
198 | } | ||
202 | } | 199 | } |
203 | EXPORT_SYMBOL(drm_atomic_state_default_clear); | 200 | EXPORT_SYMBOL(drm_atomic_state_default_clear); |
204 | 201 | ||
@@ -2237,7 +2234,7 @@ int drm_mode_atomic_ioctl(struct drm_device *dev, | |||
2237 | (arg->flags & DRM_MODE_PAGE_FLIP_EVENT)) | 2234 | (arg->flags & DRM_MODE_PAGE_FLIP_EVENT)) |
2238 | return -EINVAL; | 2235 | return -EINVAL; |
2239 | 2236 | ||
2240 | drm_modeset_acquire_init(&ctx, 0); | 2237 | drm_modeset_acquire_init(&ctx, DRM_MODESET_ACQUIRE_INTERRUPTIBLE); |
2241 | 2238 | ||
2242 | state = drm_atomic_state_alloc(dev); | 2239 | state = drm_atomic_state_alloc(dev); |
2243 | if (!state) | 2240 | if (!state) |
@@ -2350,8 +2347,9 @@ out: | |||
2350 | 2347 | ||
2351 | if (ret == -EDEADLK) { | 2348 | if (ret == -EDEADLK) { |
2352 | drm_atomic_state_clear(state); | 2349 | drm_atomic_state_clear(state); |
2353 | drm_modeset_backoff(&ctx); | 2350 | ret = drm_modeset_backoff(&ctx); |
2354 | goto retry; | 2351 | if (!ret) |
2352 | goto retry; | ||
2355 | } | 2353 | } |
2356 | 2354 | ||
2357 | drm_atomic_state_put(state); | 2355 | drm_atomic_state_put(state); |
diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c index 4e53aae9a1fb..01c34bc5b5b0 100644 --- a/drivers/gpu/drm/drm_atomic_helper.c +++ b/drivers/gpu/drm/drm_atomic_helper.c | |||
@@ -1262,12 +1262,12 @@ EXPORT_SYMBOL(drm_atomic_helper_wait_for_vblanks); | |||
1262 | void drm_atomic_helper_wait_for_flip_done(struct drm_device *dev, | 1262 | void drm_atomic_helper_wait_for_flip_done(struct drm_device *dev, |
1263 | struct drm_atomic_state *old_state) | 1263 | struct drm_atomic_state *old_state) |
1264 | { | 1264 | { |
1265 | struct drm_crtc_state *unused; | 1265 | struct drm_crtc_state *new_crtc_state; |
1266 | struct drm_crtc *crtc; | 1266 | struct drm_crtc *crtc; |
1267 | int i; | 1267 | int i; |
1268 | 1268 | ||
1269 | for_each_new_crtc_in_state(old_state, crtc, unused, i) { | 1269 | for_each_new_crtc_in_state(old_state, crtc, new_crtc_state, i) { |
1270 | struct drm_crtc_commit *commit = old_state->crtcs[i].commit; | 1270 | struct drm_crtc_commit *commit = new_crtc_state->commit; |
1271 | int ret; | 1271 | int ret; |
1272 | 1272 | ||
1273 | if (!commit) | 1273 | if (!commit) |
@@ -1388,35 +1388,31 @@ int drm_atomic_helper_async_check(struct drm_device *dev, | |||
1388 | { | 1388 | { |
1389 | struct drm_crtc *crtc; | 1389 | struct drm_crtc *crtc; |
1390 | struct drm_crtc_state *crtc_state; | 1390 | struct drm_crtc_state *crtc_state; |
1391 | struct drm_crtc_commit *commit; | 1391 | struct drm_plane *plane; |
1392 | struct drm_plane *__plane, *plane = NULL; | 1392 | struct drm_plane_state *old_plane_state, *new_plane_state; |
1393 | struct drm_plane_state *__plane_state, *plane_state = NULL; | ||
1394 | const struct drm_plane_helper_funcs *funcs; | 1393 | const struct drm_plane_helper_funcs *funcs; |
1395 | int i, j, n_planes = 0; | 1394 | int i, n_planes = 0; |
1396 | 1395 | ||
1397 | for_each_new_crtc_in_state(state, crtc, crtc_state, i) { | 1396 | for_each_new_crtc_in_state(state, crtc, crtc_state, i) { |
1398 | if (drm_atomic_crtc_needs_modeset(crtc_state)) | 1397 | if (drm_atomic_crtc_needs_modeset(crtc_state)) |
1399 | return -EINVAL; | 1398 | return -EINVAL; |
1400 | } | 1399 | } |
1401 | 1400 | ||
1402 | for_each_new_plane_in_state(state, __plane, __plane_state, i) { | 1401 | for_each_oldnew_plane_in_state(state, plane, old_plane_state, new_plane_state, i) |
1403 | n_planes++; | 1402 | n_planes++; |
1404 | plane = __plane; | ||
1405 | plane_state = __plane_state; | ||
1406 | } | ||
1407 | 1403 | ||
1408 | /* FIXME: we support only single plane updates for now */ | 1404 | /* FIXME: we support only single plane updates for now */ |
1409 | if (!plane || n_planes != 1) | 1405 | if (n_planes != 1) |
1410 | return -EINVAL; | 1406 | return -EINVAL; |
1411 | 1407 | ||
1412 | if (!plane_state->crtc) | 1408 | if (!new_plane_state->crtc) |
1413 | return -EINVAL; | 1409 | return -EINVAL; |
1414 | 1410 | ||
1415 | funcs = plane->helper_private; | 1411 | funcs = plane->helper_private; |
1416 | if (!funcs->atomic_async_update) | 1412 | if (!funcs->atomic_async_update) |
1417 | return -EINVAL; | 1413 | return -EINVAL; |
1418 | 1414 | ||
1419 | if (plane_state->fence) | 1415 | if (new_plane_state->fence) |
1420 | return -EINVAL; | 1416 | return -EINVAL; |
1421 | 1417 | ||
1422 | /* | 1418 | /* |
@@ -1424,31 +1420,11 @@ int drm_atomic_helper_async_check(struct drm_device *dev, | |||
1424 | * the plane. This prevents our async update's changes from getting | 1420 | * the plane. This prevents our async update's changes from getting |
1425 | * overridden by a previous synchronous update's state. | 1421 | * overridden by a previous synchronous update's state. |
1426 | */ | 1422 | */ |
1427 | for_each_new_crtc_in_state(state, crtc, crtc_state, i) { | 1423 | if (old_plane_state->commit && |
1428 | if (plane->crtc != crtc) | 1424 | !try_wait_for_completion(&old_plane_state->commit->hw_done)) |
1429 | continue; | 1425 | return -EBUSY; |
1430 | 1426 | ||
1431 | spin_lock(&crtc->commit_lock); | 1427 | return funcs->atomic_async_check(plane, new_plane_state); |
1432 | commit = list_first_entry_or_null(&crtc->commit_list, | ||
1433 | struct drm_crtc_commit, | ||
1434 | commit_entry); | ||
1435 | if (!commit) { | ||
1436 | spin_unlock(&crtc->commit_lock); | ||
1437 | continue; | ||
1438 | } | ||
1439 | spin_unlock(&crtc->commit_lock); | ||
1440 | |||
1441 | if (!crtc->state->state) | ||
1442 | continue; | ||
1443 | |||
1444 | for_each_plane_in_state(crtc->state->state, __plane, | ||
1445 | __plane_state, j) { | ||
1446 | if (__plane == plane) | ||
1447 | return -EINVAL; | ||
1448 | } | ||
1449 | } | ||
1450 | |||
1451 | return funcs->atomic_async_check(plane, plane_state); | ||
1452 | } | 1428 | } |
1453 | EXPORT_SYMBOL(drm_atomic_helper_async_check); | 1429 | EXPORT_SYMBOL(drm_atomic_helper_async_check); |
1454 | 1430 | ||
@@ -1633,8 +1609,7 @@ static int stall_checks(struct drm_crtc *crtc, bool nonblock) | |||
1633 | return -EBUSY; | 1609 | return -EBUSY; |
1634 | } | 1610 | } |
1635 | } else if (i == 1) { | 1611 | } else if (i == 1) { |
1636 | stall_commit = commit; | 1612 | stall_commit = drm_crtc_commit_get(commit); |
1637 | drm_crtc_commit_get(stall_commit); | ||
1638 | break; | 1613 | break; |
1639 | } | 1614 | } |
1640 | 1615 | ||
@@ -1668,6 +1643,38 @@ static void release_crtc_commit(struct completion *completion) | |||
1668 | drm_crtc_commit_put(commit); | 1643 | drm_crtc_commit_put(commit); |
1669 | } | 1644 | } |
1670 | 1645 | ||
1646 | static void init_commit(struct drm_crtc_commit *commit, struct drm_crtc *crtc) | ||
1647 | { | ||
1648 | init_completion(&commit->flip_done); | ||
1649 | init_completion(&commit->hw_done); | ||
1650 | init_completion(&commit->cleanup_done); | ||
1651 | INIT_LIST_HEAD(&commit->commit_entry); | ||
1652 | kref_init(&commit->ref); | ||
1653 | commit->crtc = crtc; | ||
1654 | } | ||
1655 | |||
1656 | static struct drm_crtc_commit * | ||
1657 | crtc_or_fake_commit(struct drm_atomic_state *state, struct drm_crtc *crtc) | ||
1658 | { | ||
1659 | if (crtc) { | ||
1660 | struct drm_crtc_state *new_crtc_state; | ||
1661 | |||
1662 | new_crtc_state = drm_atomic_get_new_crtc_state(state, crtc); | ||
1663 | |||
1664 | return new_crtc_state->commit; | ||
1665 | } | ||
1666 | |||
1667 | if (!state->fake_commit) { | ||
1668 | state->fake_commit = kzalloc(sizeof(*state->fake_commit), GFP_KERNEL); | ||
1669 | if (!state->fake_commit) | ||
1670 | return NULL; | ||
1671 | |||
1672 | init_commit(state->fake_commit, NULL); | ||
1673 | } | ||
1674 | |||
1675 | return state->fake_commit; | ||
1676 | } | ||
1677 | |||
1671 | /** | 1678 | /** |
1672 | * drm_atomic_helper_setup_commit - setup possibly nonblocking commit | 1679 | * drm_atomic_helper_setup_commit - setup possibly nonblocking commit |
1673 | * @state: new modeset state to be committed | 1680 | * @state: new modeset state to be committed |
@@ -1716,6 +1723,10 @@ int drm_atomic_helper_setup_commit(struct drm_atomic_state *state, | |||
1716 | { | 1723 | { |
1717 | struct drm_crtc *crtc; | 1724 | struct drm_crtc *crtc; |
1718 | struct drm_crtc_state *old_crtc_state, *new_crtc_state; | 1725 | struct drm_crtc_state *old_crtc_state, *new_crtc_state; |
1726 | struct drm_connector *conn; | ||
1727 | struct drm_connector_state *old_conn_state, *new_conn_state; | ||
1728 | struct drm_plane *plane; | ||
1729 | struct drm_plane_state *old_plane_state, *new_plane_state; | ||
1719 | struct drm_crtc_commit *commit; | 1730 | struct drm_crtc_commit *commit; |
1720 | int i, ret; | 1731 | int i, ret; |
1721 | 1732 | ||
@@ -1724,14 +1735,9 @@ int drm_atomic_helper_setup_commit(struct drm_atomic_state *state, | |||
1724 | if (!commit) | 1735 | if (!commit) |
1725 | return -ENOMEM; | 1736 | return -ENOMEM; |
1726 | 1737 | ||
1727 | init_completion(&commit->flip_done); | 1738 | init_commit(commit, crtc); |
1728 | init_completion(&commit->hw_done); | ||
1729 | init_completion(&commit->cleanup_done); | ||
1730 | INIT_LIST_HEAD(&commit->commit_entry); | ||
1731 | kref_init(&commit->ref); | ||
1732 | commit->crtc = crtc; | ||
1733 | 1739 | ||
1734 | state->crtcs[i].commit = commit; | 1740 | new_crtc_state->commit = commit; |
1735 | 1741 | ||
1736 | ret = stall_checks(crtc, nonblock); | 1742 | ret = stall_checks(crtc, nonblock); |
1737 | if (ret) | 1743 | if (ret) |
@@ -1765,25 +1771,46 @@ int drm_atomic_helper_setup_commit(struct drm_atomic_state *state, | |||
1765 | drm_crtc_commit_get(commit); | 1771 | drm_crtc_commit_get(commit); |
1766 | } | 1772 | } |
1767 | 1773 | ||
1768 | return 0; | 1774 | for_each_oldnew_connector_in_state(state, conn, old_conn_state, new_conn_state, i) { |
1769 | } | 1775 | /* commit tracked through new_crtc_state->commit, no need to do it explicitly */ |
1770 | EXPORT_SYMBOL(drm_atomic_helper_setup_commit); | 1776 | if (new_conn_state->crtc) |
1777 | continue; | ||
1771 | 1778 | ||
1779 | /* Userspace is not allowed to get ahead of the previous | ||
1780 | * commit with nonblocking ones. */ | ||
1781 | if (nonblock && old_conn_state->commit && | ||
1782 | !try_wait_for_completion(&old_conn_state->commit->flip_done)) | ||
1783 | return -EBUSY; | ||
1772 | 1784 | ||
1773 | static struct drm_crtc_commit *preceeding_commit(struct drm_crtc *crtc) | 1785 | commit = crtc_or_fake_commit(state, old_conn_state->crtc); |
1774 | { | 1786 | if (!commit) |
1775 | struct drm_crtc_commit *commit; | 1787 | return -ENOMEM; |
1776 | int i = 0; | ||
1777 | 1788 | ||
1778 | list_for_each_entry(commit, &crtc->commit_list, commit_entry) { | 1789 | new_conn_state->commit = drm_crtc_commit_get(commit); |
1779 | /* skip the first entry, that's the current commit */ | 1790 | } |
1780 | if (i == 1) | 1791 | |
1781 | return commit; | 1792 | for_each_oldnew_plane_in_state(state, plane, old_plane_state, new_plane_state, i) { |
1782 | i++; | 1793 | /* |
1794 | * Unlike connectors, always track planes explicitly for | ||
1795 | * async pageflip support. | ||
1796 | */ | ||
1797 | |||
1798 | /* Userspace is not allowed to get ahead of the previous | ||
1799 | * commit with nonblocking ones. */ | ||
1800 | if (nonblock && old_plane_state->commit && | ||
1801 | !try_wait_for_completion(&old_plane_state->commit->flip_done)) | ||
1802 | return -EBUSY; | ||
1803 | |||
1804 | commit = crtc_or_fake_commit(state, old_plane_state->crtc); | ||
1805 | if (!commit) | ||
1806 | return -ENOMEM; | ||
1807 | |||
1808 | new_plane_state->commit = drm_crtc_commit_get(commit); | ||
1783 | } | 1809 | } |
1784 | 1810 | ||
1785 | return NULL; | 1811 | return 0; |
1786 | } | 1812 | } |
1813 | EXPORT_SYMBOL(drm_atomic_helper_setup_commit); | ||
1787 | 1814 | ||
1788 | /** | 1815 | /** |
1789 | * drm_atomic_helper_wait_for_dependencies - wait for required preceeding commits | 1816 | * drm_atomic_helper_wait_for_dependencies - wait for required preceeding commits |
@@ -1800,17 +1827,17 @@ static struct drm_crtc_commit *preceeding_commit(struct drm_crtc *crtc) | |||
1800 | void drm_atomic_helper_wait_for_dependencies(struct drm_atomic_state *old_state) | 1827 | void drm_atomic_helper_wait_for_dependencies(struct drm_atomic_state *old_state) |
1801 | { | 1828 | { |
1802 | struct drm_crtc *crtc; | 1829 | struct drm_crtc *crtc; |
1803 | struct drm_crtc_state *new_crtc_state; | 1830 | struct drm_crtc_state *old_crtc_state; |
1831 | struct drm_plane *plane; | ||
1832 | struct drm_plane_state *old_plane_state; | ||
1833 | struct drm_connector *conn; | ||
1834 | struct drm_connector_state *old_conn_state; | ||
1804 | struct drm_crtc_commit *commit; | 1835 | struct drm_crtc_commit *commit; |
1805 | int i; | 1836 | int i; |
1806 | long ret; | 1837 | long ret; |
1807 | 1838 | ||
1808 | for_each_new_crtc_in_state(old_state, crtc, new_crtc_state, i) { | 1839 | for_each_old_crtc_in_state(old_state, crtc, old_crtc_state, i) { |
1809 | spin_lock(&crtc->commit_lock); | 1840 | commit = old_crtc_state->commit; |
1810 | commit = preceeding_commit(crtc); | ||
1811 | if (commit) | ||
1812 | drm_crtc_commit_get(commit); | ||
1813 | spin_unlock(&crtc->commit_lock); | ||
1814 | 1841 | ||
1815 | if (!commit) | 1842 | if (!commit) |
1816 | continue; | 1843 | continue; |
@@ -1828,8 +1855,48 @@ void drm_atomic_helper_wait_for_dependencies(struct drm_atomic_state *old_state) | |||
1828 | if (ret == 0) | 1855 | if (ret == 0) |
1829 | DRM_ERROR("[CRTC:%d:%s] flip_done timed out\n", | 1856 | DRM_ERROR("[CRTC:%d:%s] flip_done timed out\n", |
1830 | crtc->base.id, crtc->name); | 1857 | crtc->base.id, crtc->name); |
1858 | } | ||
1859 | |||
1860 | for_each_old_connector_in_state(old_state, conn, old_conn_state, i) { | ||
1861 | commit = old_conn_state->commit; | ||
1831 | 1862 | ||
1832 | drm_crtc_commit_put(commit); | 1863 | if (!commit) |
1864 | continue; | ||
1865 | |||
1866 | ret = wait_for_completion_timeout(&commit->hw_done, | ||
1867 | 10*HZ); | ||
1868 | if (ret == 0) | ||
1869 | DRM_ERROR("[CONNECTOR:%d:%s] hw_done timed out\n", | ||
1870 | conn->base.id, conn->name); | ||
1871 | |||
1872 | /* Currently no support for overwriting flips, hence | ||
1873 | * stall for previous one to execute completely. */ | ||
1874 | ret = wait_for_completion_timeout(&commit->flip_done, | ||
1875 | 10*HZ); | ||
1876 | if (ret == 0) | ||
1877 | DRM_ERROR("[CONNECTOR:%d:%s] flip_done timed out\n", | ||
1878 | conn->base.id, conn->name); | ||
1879 | } | ||
1880 | |||
1881 | for_each_old_plane_in_state(old_state, plane, old_plane_state, i) { | ||
1882 | commit = old_plane_state->commit; | ||
1883 | |||
1884 | if (!commit) | ||
1885 | continue; | ||
1886 | |||
1887 | ret = wait_for_completion_timeout(&commit->hw_done, | ||
1888 | 10*HZ); | ||
1889 | if (ret == 0) | ||
1890 | DRM_ERROR("[PLANE:%d:%s] hw_done timed out\n", | ||
1891 | plane->base.id, plane->name); | ||
1892 | |||
1893 | /* Currently no support for overwriting flips, hence | ||
1894 | * stall for previous one to execute completely. */ | ||
1895 | ret = wait_for_completion_timeout(&commit->flip_done, | ||
1896 | 10*HZ); | ||
1897 | if (ret == 0) | ||
1898 | DRM_ERROR("[PLANE:%d:%s] flip_done timed out\n", | ||
1899 | plane->base.id, plane->name); | ||
1833 | } | 1900 | } |
1834 | } | 1901 | } |
1835 | EXPORT_SYMBOL(drm_atomic_helper_wait_for_dependencies); | 1902 | EXPORT_SYMBOL(drm_atomic_helper_wait_for_dependencies); |
@@ -1852,19 +1919,34 @@ EXPORT_SYMBOL(drm_atomic_helper_wait_for_dependencies); | |||
1852 | void drm_atomic_helper_commit_hw_done(struct drm_atomic_state *old_state) | 1919 | void drm_atomic_helper_commit_hw_done(struct drm_atomic_state *old_state) |
1853 | { | 1920 | { |
1854 | struct drm_crtc *crtc; | 1921 | struct drm_crtc *crtc; |
1855 | struct drm_crtc_state *new_crtc_state; | 1922 | struct drm_crtc_state *old_crtc_state, *new_crtc_state; |
1856 | struct drm_crtc_commit *commit; | 1923 | struct drm_crtc_commit *commit; |
1857 | int i; | 1924 | int i; |
1858 | 1925 | ||
1859 | for_each_new_crtc_in_state(old_state, crtc, new_crtc_state, i) { | 1926 | for_each_oldnew_crtc_in_state(old_state, crtc, old_crtc_state, new_crtc_state, i) { |
1860 | commit = old_state->crtcs[i].commit; | 1927 | commit = new_crtc_state->commit; |
1861 | if (!commit) | 1928 | if (!commit) |
1862 | continue; | 1929 | continue; |
1863 | 1930 | ||
1931 | /* | ||
1932 | * copy new_crtc_state->commit to old_crtc_state->commit, | ||
1933 | * it's unsafe to touch new_crtc_state after hw_done, | ||
1934 | * but we still need to do so in cleanup_done(). | ||
1935 | */ | ||
1936 | if (old_crtc_state->commit) | ||
1937 | drm_crtc_commit_put(old_crtc_state->commit); | ||
1938 | |||
1939 | old_crtc_state->commit = drm_crtc_commit_get(commit); | ||
1940 | |||
1864 | /* backend must have consumed any event by now */ | 1941 | /* backend must have consumed any event by now */ |
1865 | WARN_ON(new_crtc_state->event); | 1942 | WARN_ON(new_crtc_state->event); |
1866 | complete_all(&commit->hw_done); | 1943 | complete_all(&commit->hw_done); |
1867 | } | 1944 | } |
1945 | |||
1946 | if (old_state->fake_commit) { | ||
1947 | complete_all(&old_state->fake_commit->hw_done); | ||
1948 | complete_all(&old_state->fake_commit->flip_done); | ||
1949 | } | ||
1868 | } | 1950 | } |
1869 | EXPORT_SYMBOL(drm_atomic_helper_commit_hw_done); | 1951 | EXPORT_SYMBOL(drm_atomic_helper_commit_hw_done); |
1870 | 1952 | ||
@@ -1882,39 +1964,25 @@ EXPORT_SYMBOL(drm_atomic_helper_commit_hw_done); | |||
1882 | void drm_atomic_helper_commit_cleanup_done(struct drm_atomic_state *old_state) | 1964 | void drm_atomic_helper_commit_cleanup_done(struct drm_atomic_state *old_state) |
1883 | { | 1965 | { |
1884 | struct drm_crtc *crtc; | 1966 | struct drm_crtc *crtc; |
1885 | struct drm_crtc_state *new_crtc_state; | 1967 | struct drm_crtc_state *old_crtc_state; |
1886 | struct drm_crtc_commit *commit; | 1968 | struct drm_crtc_commit *commit; |
1887 | int i; | 1969 | int i; |
1888 | long ret; | ||
1889 | 1970 | ||
1890 | for_each_new_crtc_in_state(old_state, crtc, new_crtc_state, i) { | 1971 | for_each_old_crtc_in_state(old_state, crtc, old_crtc_state, i) { |
1891 | commit = old_state->crtcs[i].commit; | 1972 | commit = old_crtc_state->commit; |
1892 | if (WARN_ON(!commit)) | 1973 | if (WARN_ON(!commit)) |
1893 | continue; | 1974 | continue; |
1894 | 1975 | ||
1895 | complete_all(&commit->cleanup_done); | 1976 | complete_all(&commit->cleanup_done); |
1896 | WARN_ON(!try_wait_for_completion(&commit->hw_done)); | 1977 | WARN_ON(!try_wait_for_completion(&commit->hw_done)); |
1897 | 1978 | ||
1898 | /* commit_list borrows our reference, need to remove before we | ||
1899 | * clean up our drm_atomic_state. But only after it actually | ||
1900 | * completed, otherwise subsequent commits won't stall properly. */ | ||
1901 | if (try_wait_for_completion(&commit->flip_done)) | ||
1902 | goto del_commit; | ||
1903 | |||
1904 | /* We must wait for the vblank event to signal our completion | ||
1905 | * before releasing our reference, since the vblank work does | ||
1906 | * not hold a reference of its own. */ | ||
1907 | ret = wait_for_completion_timeout(&commit->flip_done, | ||
1908 | 10*HZ); | ||
1909 | if (ret == 0) | ||
1910 | DRM_ERROR("[CRTC:%d:%s] flip_done timed out\n", | ||
1911 | crtc->base.id, crtc->name); | ||
1912 | |||
1913 | del_commit: | ||
1914 | spin_lock(&crtc->commit_lock); | 1979 | spin_lock(&crtc->commit_lock); |
1915 | list_del(&commit->commit_entry); | 1980 | list_del(&commit->commit_entry); |
1916 | spin_unlock(&crtc->commit_lock); | 1981 | spin_unlock(&crtc->commit_lock); |
1917 | } | 1982 | } |
1983 | |||
1984 | if (old_state->fake_commit) | ||
1985 | complete_all(&old_state->fake_commit->cleanup_done); | ||
1918 | } | 1986 | } |
1919 | EXPORT_SYMBOL(drm_atomic_helper_commit_cleanup_done); | 1987 | EXPORT_SYMBOL(drm_atomic_helper_commit_cleanup_done); |
1920 | 1988 | ||
@@ -2294,20 +2362,44 @@ int drm_atomic_helper_swap_state(struct drm_atomic_state *state, | |||
2294 | struct drm_private_state *old_obj_state, *new_obj_state; | 2362 | struct drm_private_state *old_obj_state, *new_obj_state; |
2295 | 2363 | ||
2296 | if (stall) { | 2364 | if (stall) { |
2297 | for_each_new_crtc_in_state(state, crtc, new_crtc_state, i) { | 2365 | /* |
2298 | spin_lock(&crtc->commit_lock); | 2366 | * We have to stall for hw_done here before |
2299 | commit = list_first_entry_or_null(&crtc->commit_list, | 2367 | * drm_atomic_helper_wait_for_dependencies() because flip |
2300 | struct drm_crtc_commit, commit_entry); | 2368 | * depth > 1 is not yet supported by all drivers. As long as |
2301 | if (commit) | 2369 | * obj->state is directly dereferenced anywhere in the drivers |
2302 | drm_crtc_commit_get(commit); | 2370 | * atomic_commit_tail function, then it's unsafe to swap state |
2303 | spin_unlock(&crtc->commit_lock); | 2371 | * before drm_atomic_helper_commit_hw_done() is called. |
2372 | */ | ||
2373 | |||
2374 | for_each_old_crtc_in_state(state, crtc, old_crtc_state, i) { | ||
2375 | commit = old_crtc_state->commit; | ||
2376 | |||
2377 | if (!commit) | ||
2378 | continue; | ||
2379 | |||
2380 | ret = wait_for_completion_interruptible(&commit->hw_done); | ||
2381 | if (ret) | ||
2382 | return ret; | ||
2383 | } | ||
2384 | |||
2385 | for_each_old_connector_in_state(state, connector, old_conn_state, i) { | ||
2386 | commit = old_conn_state->commit; | ||
2304 | 2387 | ||
2305 | if (!commit) | 2388 | if (!commit) |
2306 | continue; | 2389 | continue; |
2307 | 2390 | ||
2308 | ret = wait_for_completion_interruptible(&commit->hw_done); | 2391 | ret = wait_for_completion_interruptible(&commit->hw_done); |
2309 | drm_crtc_commit_put(commit); | 2392 | if (ret) |
2393 | return ret; | ||
2394 | } | ||
2310 | 2395 | ||
2396 | for_each_old_plane_in_state(state, plane, old_plane_state, i) { | ||
2397 | commit = old_plane_state->commit; | ||
2398 | |||
2399 | if (!commit) | ||
2400 | continue; | ||
2401 | |||
2402 | ret = wait_for_completion_interruptible(&commit->hw_done); | ||
2311 | if (ret) | 2403 | if (ret) |
2312 | return ret; | 2404 | return ret; |
2313 | } | 2405 | } |
@@ -2332,13 +2424,13 @@ int drm_atomic_helper_swap_state(struct drm_atomic_state *state, | |||
2332 | state->crtcs[i].state = old_crtc_state; | 2424 | state->crtcs[i].state = old_crtc_state; |
2333 | crtc->state = new_crtc_state; | 2425 | crtc->state = new_crtc_state; |
2334 | 2426 | ||
2335 | if (state->crtcs[i].commit) { | 2427 | if (new_crtc_state->commit) { |
2336 | spin_lock(&crtc->commit_lock); | 2428 | spin_lock(&crtc->commit_lock); |
2337 | list_add(&state->crtcs[i].commit->commit_entry, | 2429 | list_add(&new_crtc_state->commit->commit_entry, |
2338 | &crtc->commit_list); | 2430 | &crtc->commit_list); |
2339 | spin_unlock(&crtc->commit_lock); | 2431 | spin_unlock(&crtc->commit_lock); |
2340 | 2432 | ||
2341 | state->crtcs[i].commit->event = NULL; | 2433 | new_crtc_state->commit->event = NULL; |
2342 | } | 2434 | } |
2343 | } | 2435 | } |
2344 | 2436 | ||
@@ -3186,6 +3278,7 @@ void __drm_atomic_helper_crtc_duplicate_state(struct drm_crtc *crtc, | |||
3186 | state->connectors_changed = false; | 3278 | state->connectors_changed = false; |
3187 | state->color_mgmt_changed = false; | 3279 | state->color_mgmt_changed = false; |
3188 | state->zpos_changed = false; | 3280 | state->zpos_changed = false; |
3281 | state->commit = NULL; | ||
3189 | state->event = NULL; | 3282 | state->event = NULL; |
3190 | state->pageflip_flags = 0; | 3283 | state->pageflip_flags = 0; |
3191 | } | 3284 | } |
@@ -3224,6 +3317,12 @@ EXPORT_SYMBOL(drm_atomic_helper_crtc_duplicate_state); | |||
3224 | */ | 3317 | */ |
3225 | void __drm_atomic_helper_crtc_destroy_state(struct drm_crtc_state *state) | 3318 | void __drm_atomic_helper_crtc_destroy_state(struct drm_crtc_state *state) |
3226 | { | 3319 | { |
3320 | if (state->commit) { | ||
3321 | kfree(state->commit->event); | ||
3322 | state->commit->event = NULL; | ||
3323 | drm_crtc_commit_put(state->commit); | ||
3324 | } | ||
3325 | |||
3227 | drm_property_blob_put(state->mode_blob); | 3326 | drm_property_blob_put(state->mode_blob); |
3228 | drm_property_blob_put(state->degamma_lut); | 3327 | drm_property_blob_put(state->degamma_lut); |
3229 | drm_property_blob_put(state->ctm); | 3328 | drm_property_blob_put(state->ctm); |
@@ -3286,6 +3385,7 @@ void __drm_atomic_helper_plane_duplicate_state(struct drm_plane *plane, | |||
3286 | drm_framebuffer_get(state->fb); | 3385 | drm_framebuffer_get(state->fb); |
3287 | 3386 | ||
3288 | state->fence = NULL; | 3387 | state->fence = NULL; |
3388 | state->commit = NULL; | ||
3289 | } | 3389 | } |
3290 | EXPORT_SYMBOL(__drm_atomic_helper_plane_duplicate_state); | 3390 | EXPORT_SYMBOL(__drm_atomic_helper_plane_duplicate_state); |
3291 | 3391 | ||
@@ -3327,6 +3427,9 @@ void __drm_atomic_helper_plane_destroy_state(struct drm_plane_state *state) | |||
3327 | 3427 | ||
3328 | if (state->fence) | 3428 | if (state->fence) |
3329 | dma_fence_put(state->fence); | 3429 | dma_fence_put(state->fence); |
3430 | |||
3431 | if (state->commit) | ||
3432 | drm_crtc_commit_put(state->commit); | ||
3330 | } | 3433 | } |
3331 | EXPORT_SYMBOL(__drm_atomic_helper_plane_destroy_state); | 3434 | EXPORT_SYMBOL(__drm_atomic_helper_plane_destroy_state); |
3332 | 3435 | ||
@@ -3405,6 +3508,7 @@ __drm_atomic_helper_connector_duplicate_state(struct drm_connector *connector, | |||
3405 | memcpy(state, connector->state, sizeof(*state)); | 3508 | memcpy(state, connector->state, sizeof(*state)); |
3406 | if (state->crtc) | 3509 | if (state->crtc) |
3407 | drm_connector_get(connector); | 3510 | drm_connector_get(connector); |
3511 | state->commit = NULL; | ||
3408 | } | 3512 | } |
3409 | EXPORT_SYMBOL(__drm_atomic_helper_connector_duplicate_state); | 3513 | EXPORT_SYMBOL(__drm_atomic_helper_connector_duplicate_state); |
3410 | 3514 | ||
@@ -3531,6 +3635,9 @@ __drm_atomic_helper_connector_destroy_state(struct drm_connector_state *state) | |||
3531 | { | 3635 | { |
3532 | if (state->crtc) | 3636 | if (state->crtc) |
3533 | drm_connector_put(state->connector); | 3637 | drm_connector_put(state->connector); |
3638 | |||
3639 | if (state->commit) | ||
3640 | drm_crtc_commit_put(state->commit); | ||
3534 | } | 3641 | } |
3535 | EXPORT_SYMBOL(__drm_atomic_helper_connector_destroy_state); | 3642 | EXPORT_SYMBOL(__drm_atomic_helper_connector_destroy_state); |
3536 | 3643 | ||
diff --git a/drivers/gpu/drm/drm_bridge.c b/drivers/gpu/drm/drm_bridge.c index dc8cdfe1dcac..1638bfe9627c 100644 --- a/drivers/gpu/drm/drm_bridge.c +++ b/drivers/gpu/drm/drm_bridge.c | |||
@@ -67,17 +67,12 @@ static LIST_HEAD(bridge_list); | |||
67 | * drm_bridge_add - add the given bridge to the global bridge list | 67 | * drm_bridge_add - add the given bridge to the global bridge list |
68 | * | 68 | * |
69 | * @bridge: bridge control structure | 69 | * @bridge: bridge control structure |
70 | * | ||
71 | * RETURNS: | ||
72 | * Unconditionally returns Zero. | ||
73 | */ | 70 | */ |
74 | int drm_bridge_add(struct drm_bridge *bridge) | 71 | void drm_bridge_add(struct drm_bridge *bridge) |
75 | { | 72 | { |
76 | mutex_lock(&bridge_lock); | 73 | mutex_lock(&bridge_lock); |
77 | list_add_tail(&bridge->list, &bridge_list); | 74 | list_add_tail(&bridge->list, &bridge_list); |
78 | mutex_unlock(&bridge_lock); | 75 | mutex_unlock(&bridge_lock); |
79 | |||
80 | return 0; | ||
81 | } | 76 | } |
82 | EXPORT_SYMBOL(drm_bridge_add); | 77 | EXPORT_SYMBOL(drm_bridge_add); |
83 | 78 | ||
diff --git a/drivers/gpu/drm/drm_connector.c b/drivers/gpu/drm/drm_connector.c index ba9f36cef68c..bb2e60f5feb6 100644 --- a/drivers/gpu/drm/drm_connector.c +++ b/drivers/gpu/drm/drm_connector.c | |||
@@ -615,7 +615,6 @@ static const struct drm_prop_enum_list drm_link_status_enum_list[] = { | |||
615 | { DRM_MODE_LINK_STATUS_GOOD, "Good" }, | 615 | { DRM_MODE_LINK_STATUS_GOOD, "Good" }, |
616 | { DRM_MODE_LINK_STATUS_BAD, "Bad" }, | 616 | { DRM_MODE_LINK_STATUS_BAD, "Bad" }, |
617 | }; | 617 | }; |
618 | DRM_ENUM_NAME_FN(drm_get_link_status_name, drm_link_status_enum_list) | ||
619 | 618 | ||
620 | /** | 619 | /** |
621 | * drm_display_info_set_bus_formats - set the supported bus formats | 620 | * drm_display_info_set_bus_formats - set the supported bus formats |
diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index 5af25ce5bf7c..68b4e976d5e0 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c | |||
@@ -577,7 +577,7 @@ int drm_mode_setcrtc(struct drm_device *dev, void *data, | |||
577 | DRM_DEBUG_KMS("[CRTC:%d:%s]\n", crtc->base.id, crtc->name); | 577 | DRM_DEBUG_KMS("[CRTC:%d:%s]\n", crtc->base.id, crtc->name); |
578 | 578 | ||
579 | mutex_lock(&crtc->dev->mode_config.mutex); | 579 | mutex_lock(&crtc->dev->mode_config.mutex); |
580 | drm_modeset_acquire_init(&ctx, 0); | 580 | drm_modeset_acquire_init(&ctx, DRM_MODESET_ACQUIRE_INTERRUPTIBLE); |
581 | retry: | 581 | retry: |
582 | ret = drm_modeset_lock_all_ctx(crtc->dev, &ctx); | 582 | ret = drm_modeset_lock_all_ctx(crtc->dev, &ctx); |
583 | if (ret) | 583 | if (ret) |
@@ -717,8 +717,9 @@ out: | |||
717 | kfree(connector_set); | 717 | kfree(connector_set); |
718 | drm_mode_destroy(dev, mode); | 718 | drm_mode_destroy(dev, mode); |
719 | if (ret == -EDEADLK) { | 719 | if (ret == -EDEADLK) { |
720 | drm_modeset_backoff(&ctx); | 720 | ret = drm_modeset_backoff(&ctx); |
721 | goto retry; | 721 | if (!ret) |
722 | goto retry; | ||
722 | } | 723 | } |
723 | drm_modeset_drop_locks(&ctx); | 724 | drm_modeset_drop_locks(&ctx); |
724 | drm_modeset_acquire_fini(&ctx); | 725 | drm_modeset_acquire_fini(&ctx); |
diff --git a/drivers/gpu/drm/drm_debugfs_crc.c b/drivers/gpu/drm/drm_debugfs_crc.c index f9e26dda56d6..9dd879589a2c 100644 --- a/drivers/gpu/drm/drm_debugfs_crc.c +++ b/drivers/gpu/drm/drm_debugfs_crc.c | |||
@@ -155,7 +155,7 @@ static int crtc_crc_open(struct inode *inode, struct file *filep) | |||
155 | int ret = 0; | 155 | int ret = 0; |
156 | 156 | ||
157 | if (drm_drv_uses_atomic_modeset(crtc->dev)) { | 157 | if (drm_drv_uses_atomic_modeset(crtc->dev)) { |
158 | ret = drm_modeset_lock_interruptible(&crtc->mutex, NULL); | 158 | ret = drm_modeset_lock_single_interruptible(&crtc->mutex); |
159 | if (ret) | 159 | if (ret) |
160 | return ret; | 160 | return ret; |
161 | 161 | ||
diff --git a/drivers/gpu/drm/drm_dp_mst_topology.c b/drivers/gpu/drm/drm_dp_mst_topology.c index 41b492f99955..70dcfa58d3c2 100644 --- a/drivers/gpu/drm/drm_dp_mst_topology.c +++ b/drivers/gpu/drm/drm_dp_mst_topology.c | |||
@@ -294,6 +294,12 @@ static void drm_dp_encode_sideband_req(struct drm_dp_sideband_msg_req_body *req, | |||
294 | memcpy(&buf[idx], req->u.i2c_write.bytes, req->u.i2c_write.num_bytes); | 294 | memcpy(&buf[idx], req->u.i2c_write.bytes, req->u.i2c_write.num_bytes); |
295 | idx += req->u.i2c_write.num_bytes; | 295 | idx += req->u.i2c_write.num_bytes; |
296 | break; | 296 | break; |
297 | |||
298 | case DP_POWER_DOWN_PHY: | ||
299 | case DP_POWER_UP_PHY: | ||
300 | buf[idx] = (req->u.port_num.port_number & 0xf) << 4; | ||
301 | idx++; | ||
302 | break; | ||
297 | } | 303 | } |
298 | raw->cur_len = idx; | 304 | raw->cur_len = idx; |
299 | } | 305 | } |
@@ -538,6 +544,21 @@ fail_len: | |||
538 | return false; | 544 | return false; |
539 | } | 545 | } |
540 | 546 | ||
547 | static bool drm_dp_sideband_parse_power_updown_phy_ack(struct drm_dp_sideband_msg_rx *raw, | ||
548 | struct drm_dp_sideband_msg_reply_body *repmsg) | ||
549 | { | ||
550 | int idx = 1; | ||
551 | |||
552 | repmsg->u.port_number.port_number = (raw->msg[idx] >> 4) & 0xf; | ||
553 | idx++; | ||
554 | if (idx > raw->curlen) { | ||
555 | DRM_DEBUG_KMS("power up/down phy parse length fail %d %d\n", | ||
556 | idx, raw->curlen); | ||
557 | return false; | ||
558 | } | ||
559 | return true; | ||
560 | } | ||
561 | |||
541 | static bool drm_dp_sideband_parse_reply(struct drm_dp_sideband_msg_rx *raw, | 562 | static bool drm_dp_sideband_parse_reply(struct drm_dp_sideband_msg_rx *raw, |
542 | struct drm_dp_sideband_msg_reply_body *msg) | 563 | struct drm_dp_sideband_msg_reply_body *msg) |
543 | { | 564 | { |
@@ -567,6 +588,9 @@ static bool drm_dp_sideband_parse_reply(struct drm_dp_sideband_msg_rx *raw, | |||
567 | return drm_dp_sideband_parse_enum_path_resources_ack(raw, msg); | 588 | return drm_dp_sideband_parse_enum_path_resources_ack(raw, msg); |
568 | case DP_ALLOCATE_PAYLOAD: | 589 | case DP_ALLOCATE_PAYLOAD: |
569 | return drm_dp_sideband_parse_allocate_payload_ack(raw, msg); | 590 | return drm_dp_sideband_parse_allocate_payload_ack(raw, msg); |
591 | case DP_POWER_DOWN_PHY: | ||
592 | case DP_POWER_UP_PHY: | ||
593 | return drm_dp_sideband_parse_power_updown_phy_ack(raw, msg); | ||
570 | default: | 594 | default: |
571 | DRM_ERROR("Got unknown reply 0x%02x\n", msg->req_type); | 595 | DRM_ERROR("Got unknown reply 0x%02x\n", msg->req_type); |
572 | return false; | 596 | return false; |
@@ -693,6 +717,22 @@ static int build_allocate_payload(struct drm_dp_sideband_msg_tx *msg, int port_n | |||
693 | return 0; | 717 | return 0; |
694 | } | 718 | } |
695 | 719 | ||
720 | static int build_power_updown_phy(struct drm_dp_sideband_msg_tx *msg, | ||
721 | int port_num, bool power_up) | ||
722 | { | ||
723 | struct drm_dp_sideband_msg_req_body req; | ||
724 | |||
725 | if (power_up) | ||
726 | req.req_type = DP_POWER_UP_PHY; | ||
727 | else | ||
728 | req.req_type = DP_POWER_DOWN_PHY; | ||
729 | |||
730 | req.u.port_num.port_number = port_num; | ||
731 | drm_dp_encode_sideband_req(&req, msg); | ||
732 | msg->path_msg = true; | ||
733 | return 0; | ||
734 | } | ||
735 | |||
696 | static int drm_dp_mst_assign_payload_id(struct drm_dp_mst_topology_mgr *mgr, | 736 | static int drm_dp_mst_assign_payload_id(struct drm_dp_mst_topology_mgr *mgr, |
697 | struct drm_dp_vcpi *vcpi) | 737 | struct drm_dp_vcpi *vcpi) |
698 | { | 738 | { |
@@ -1724,6 +1764,40 @@ fail_put: | |||
1724 | return ret; | 1764 | return ret; |
1725 | } | 1765 | } |
1726 | 1766 | ||
1767 | int drm_dp_send_power_updown_phy(struct drm_dp_mst_topology_mgr *mgr, | ||
1768 | struct drm_dp_mst_port *port, bool power_up) | ||
1769 | { | ||
1770 | struct drm_dp_sideband_msg_tx *txmsg; | ||
1771 | int len, ret; | ||
1772 | |||
1773 | port = drm_dp_get_validated_port_ref(mgr, port); | ||
1774 | if (!port) | ||
1775 | return -EINVAL; | ||
1776 | |||
1777 | txmsg = kzalloc(sizeof(*txmsg), GFP_KERNEL); | ||
1778 | if (!txmsg) { | ||
1779 | drm_dp_put_port(port); | ||
1780 | return -ENOMEM; | ||
1781 | } | ||
1782 | |||
1783 | txmsg->dst = port->parent; | ||
1784 | len = build_power_updown_phy(txmsg, port->port_num, power_up); | ||
1785 | drm_dp_queue_down_tx(mgr, txmsg); | ||
1786 | |||
1787 | ret = drm_dp_mst_wait_tx_reply(port->parent, txmsg); | ||
1788 | if (ret > 0) { | ||
1789 | if (txmsg->reply.reply_type == 1) | ||
1790 | ret = -EINVAL; | ||
1791 | else | ||
1792 | ret = 0; | ||
1793 | } | ||
1794 | kfree(txmsg); | ||
1795 | drm_dp_put_port(port); | ||
1796 | |||
1797 | return ret; | ||
1798 | } | ||
1799 | EXPORT_SYMBOL(drm_dp_send_power_updown_phy); | ||
1800 | |||
1727 | static int drm_dp_create_payload_step1(struct drm_dp_mst_topology_mgr *mgr, | 1801 | static int drm_dp_create_payload_step1(struct drm_dp_mst_topology_mgr *mgr, |
1728 | int id, | 1802 | int id, |
1729 | struct drm_dp_payload *payload) | 1803 | struct drm_dp_payload *payload) |
diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index 6bb6337be920..00ddabfbf980 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c | |||
@@ -1533,6 +1533,10 @@ static void connector_bad_edid(struct drm_connector *connector, | |||
1533 | * level, drivers must make all reasonable efforts to expose it as an I2C | 1533 | * level, drivers must make all reasonable efforts to expose it as an I2C |
1534 | * adapter and use drm_get_edid() instead of abusing this function. | 1534 | * adapter and use drm_get_edid() instead of abusing this function. |
1535 | * | 1535 | * |
1536 | * The EDID may be overridden using debugfs override_edid or firmare EDID | ||
1537 | * (drm_load_edid_firmware() and drm.edid_firmware parameter), in this priority | ||
1538 | * order. Having either of them bypasses actual EDID reads. | ||
1539 | * | ||
1536 | * Return: Pointer to valid EDID or NULL if we couldn't find any. | 1540 | * Return: Pointer to valid EDID or NULL if we couldn't find any. |
1537 | */ | 1541 | */ |
1538 | struct edid *drm_do_get_edid(struct drm_connector *connector, | 1542 | struct edid *drm_do_get_edid(struct drm_connector *connector, |
@@ -1542,6 +1546,17 @@ struct edid *drm_do_get_edid(struct drm_connector *connector, | |||
1542 | { | 1546 | { |
1543 | int i, j = 0, valid_extensions = 0; | 1547 | int i, j = 0, valid_extensions = 0; |
1544 | u8 *edid, *new; | 1548 | u8 *edid, *new; |
1549 | struct edid *override = NULL; | ||
1550 | |||
1551 | if (connector->override_edid) | ||
1552 | override = drm_edid_duplicate((const struct edid *) | ||
1553 | connector->edid_blob_ptr->data); | ||
1554 | |||
1555 | if (!override) | ||
1556 | override = drm_load_edid_firmware(connector); | ||
1557 | |||
1558 | if (!IS_ERR_OR_NULL(override)) | ||
1559 | return override; | ||
1545 | 1560 | ||
1546 | if ((edid = kmalloc(EDID_LENGTH, GFP_KERNEL)) == NULL) | 1561 | if ((edid = kmalloc(EDID_LENGTH, GFP_KERNEL)) == NULL) |
1547 | return NULL; | 1562 | return NULL; |
diff --git a/drivers/gpu/drm/drm_edid_load.c b/drivers/gpu/drm/drm_edid_load.c index 1c0495acf341..a4915099aaa9 100644 --- a/drivers/gpu/drm/drm_edid_load.c +++ b/drivers/gpu/drm/drm_edid_load.c | |||
@@ -31,6 +31,22 @@ module_param_string(edid_firmware, edid_firmware, sizeof(edid_firmware), 0644); | |||
31 | MODULE_PARM_DESC(edid_firmware, "Do not probe monitor, use specified EDID blob " | 31 | MODULE_PARM_DESC(edid_firmware, "Do not probe monitor, use specified EDID blob " |
32 | "from built-in data or /lib/firmware instead. "); | 32 | "from built-in data or /lib/firmware instead. "); |
33 | 33 | ||
34 | /* Use only for backward compatibility with drm_kms_helper.edid_firmware */ | ||
35 | int __drm_set_edid_firmware_path(const char *path) | ||
36 | { | ||
37 | scnprintf(edid_firmware, sizeof(edid_firmware), "%s", path); | ||
38 | |||
39 | return 0; | ||
40 | } | ||
41 | EXPORT_SYMBOL(__drm_set_edid_firmware_path); | ||
42 | |||
43 | /* Use only for backward compatibility with drm_kms_helper.edid_firmware */ | ||
44 | int __drm_get_edid_firmware_path(char *buf, size_t bufsize) | ||
45 | { | ||
46 | return scnprintf(buf, bufsize, "%s", edid_firmware); | ||
47 | } | ||
48 | EXPORT_SYMBOL(__drm_get_edid_firmware_path); | ||
49 | |||
34 | #define GENERIC_EDIDS 6 | 50 | #define GENERIC_EDIDS 6 |
35 | static const char * const generic_edid_name[GENERIC_EDIDS] = { | 51 | static const char * const generic_edid_name[GENERIC_EDIDS] = { |
36 | "edid/800x600.bin", | 52 | "edid/800x600.bin", |
diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c index 1b8f013ffa65..6a31d13f2f81 100644 --- a/drivers/gpu/drm/drm_fb_helper.c +++ b/drivers/gpu/drm/drm_fb_helper.c | |||
@@ -910,6 +910,9 @@ void drm_fb_helper_fini(struct drm_fb_helper *fb_helper) | |||
910 | if (!drm_fbdev_emulation || !fb_helper) | 910 | if (!drm_fbdev_emulation || !fb_helper) |
911 | return; | 911 | return; |
912 | 912 | ||
913 | cancel_work_sync(&fb_helper->resume_work); | ||
914 | cancel_work_sync(&fb_helper->dirty_work); | ||
915 | |||
913 | info = fb_helper->fbdev; | 916 | info = fb_helper->fbdev; |
914 | if (info) { | 917 | if (info) { |
915 | if (info->cmap.len) | 918 | if (info->cmap.len) |
@@ -918,9 +921,6 @@ void drm_fb_helper_fini(struct drm_fb_helper *fb_helper) | |||
918 | } | 921 | } |
919 | fb_helper->fbdev = NULL; | 922 | fb_helper->fbdev = NULL; |
920 | 923 | ||
921 | cancel_work_sync(&fb_helper->resume_work); | ||
922 | cancel_work_sync(&fb_helper->dirty_work); | ||
923 | |||
924 | mutex_lock(&kernel_fb_helper_lock); | 924 | mutex_lock(&kernel_fb_helper_lock); |
925 | if (!list_empty(&fb_helper->kernel_fb_list)) { | 925 | if (!list_empty(&fb_helper->kernel_fb_list)) { |
926 | list_del(&fb_helper->kernel_fb_list); | 926 | list_del(&fb_helper->kernel_fb_list); |
diff --git a/drivers/gpu/drm/drm_gem.c b/drivers/gpu/drm/drm_gem.c index c55f338e380b..7199bba68c37 100644 --- a/drivers/gpu/drm/drm_gem.c +++ b/drivers/gpu/drm/drm_gem.c | |||
@@ -334,6 +334,12 @@ int drm_gem_dumb_map_offset(struct drm_file *file, struct drm_device *dev, | |||
334 | if (!obj) | 334 | if (!obj) |
335 | return -ENOENT; | 335 | return -ENOENT; |
336 | 336 | ||
337 | /* Don't allow imported objects to be mapped */ | ||
338 | if (obj->import_attach) { | ||
339 | ret = -EINVAL; | ||
340 | goto out; | ||
341 | } | ||
342 | |||
337 | ret = drm_gem_create_mmap_offset(obj); | 343 | ret = drm_gem_create_mmap_offset(obj); |
338 | if (ret) | 344 | if (ret) |
339 | goto out; | 345 | goto out; |
diff --git a/drivers/gpu/drm/drm_gem_framebuffer_helper.c b/drivers/gpu/drm/drm_gem_framebuffer_helper.c index d54a083dc5dd..fc7e995541c9 100644 --- a/drivers/gpu/drm/drm_gem_framebuffer_helper.c +++ b/drivers/gpu/drm/drm_gem_framebuffer_helper.c | |||
@@ -154,7 +154,7 @@ drm_gem_fb_create_with_funcs(struct drm_device *dev, struct drm_file *file, | |||
154 | 154 | ||
155 | objs[i] = drm_gem_object_lookup(file, mode_cmd->handles[i]); | 155 | objs[i] = drm_gem_object_lookup(file, mode_cmd->handles[i]); |
156 | if (!objs[i]) { | 156 | if (!objs[i]) { |
157 | DRM_DEV_ERROR(dev->dev, "Failed to lookup GEM\n"); | 157 | DRM_DEBUG_KMS("Failed to lookup GEM object\n"); |
158 | ret = -ENOENT; | 158 | ret = -ENOENT; |
159 | goto err_gem_object_put; | 159 | goto err_gem_object_put; |
160 | } | 160 | } |
@@ -232,7 +232,7 @@ int drm_gem_fb_prepare_fb(struct drm_plane *plane, | |||
232 | struct dma_buf *dma_buf; | 232 | struct dma_buf *dma_buf; |
233 | struct dma_fence *fence; | 233 | struct dma_fence *fence; |
234 | 234 | ||
235 | if ((plane->state->fb == state->fb) || !state->fb) | 235 | if (plane->state->fb == state->fb || !state->fb) |
236 | return 0; | 236 | return 0; |
237 | 237 | ||
238 | dma_buf = drm_gem_fb_get_obj(state->fb, 0)->dma_buf; | 238 | dma_buf = drm_gem_fb_get_obj(state->fb, 0)->dma_buf; |
diff --git a/drivers/gpu/drm/drm_kms_helper_common.c b/drivers/gpu/drm/drm_kms_helper_common.c index 6e35a56a6102..93e2b30fe1a5 100644 --- a/drivers/gpu/drm/drm_kms_helper_common.c +++ b/drivers/gpu/drm/drm_kms_helper_common.c | |||
@@ -26,6 +26,7 @@ | |||
26 | */ | 26 | */ |
27 | 27 | ||
28 | #include <linux/module.h> | 28 | #include <linux/module.h> |
29 | #include <drm/drmP.h> | ||
29 | 30 | ||
30 | #include "drm_crtc_helper_internal.h" | 31 | #include "drm_crtc_helper_internal.h" |
31 | 32 | ||
@@ -33,6 +34,33 @@ MODULE_AUTHOR("David Airlie, Jesse Barnes"); | |||
33 | MODULE_DESCRIPTION("DRM KMS helper"); | 34 | MODULE_DESCRIPTION("DRM KMS helper"); |
34 | MODULE_LICENSE("GPL and additional rights"); | 35 | MODULE_LICENSE("GPL and additional rights"); |
35 | 36 | ||
37 | #if IS_ENABLED(CONFIG_DRM_LOAD_EDID_FIRMWARE) | ||
38 | |||
39 | /* Backward compatibility for drm_kms_helper.edid_firmware */ | ||
40 | static int edid_firmware_set(const char *val, const struct kernel_param *kp) | ||
41 | { | ||
42 | DRM_NOTE("drm_kms_firmware.edid_firmware is deprecated, please use drm.edid_firmware intead.\n"); | ||
43 | |||
44 | return __drm_set_edid_firmware_path(val); | ||
45 | } | ||
46 | |||
47 | static int edid_firmware_get(char *buffer, const struct kernel_param *kp) | ||
48 | { | ||
49 | return __drm_get_edid_firmware_path(buffer, PAGE_SIZE); | ||
50 | } | ||
51 | |||
52 | static const struct kernel_param_ops edid_firmware_ops = { | ||
53 | .set = edid_firmware_set, | ||
54 | .get = edid_firmware_get, | ||
55 | }; | ||
56 | |||
57 | module_param_cb(edid_firmware, &edid_firmware_ops, NULL, 0644); | ||
58 | __MODULE_PARM_TYPE(edid_firmware, "charp"); | ||
59 | MODULE_PARM_DESC(edid_firmware, | ||
60 | "DEPRECATED. Use drm.edid_firmware module parameter instead."); | ||
61 | |||
62 | #endif | ||
63 | |||
36 | static int __init drm_kms_helper_init(void) | 64 | static int __init drm_kms_helper_init(void) |
37 | { | 65 | { |
38 | int ret; | 66 | int ret; |
diff --git a/drivers/gpu/drm/drm_mode_object.c b/drivers/gpu/drm/drm_mode_object.c index 1055533792f3..7a1ea91d3343 100644 --- a/drivers/gpu/drm/drm_mode_object.c +++ b/drivers/gpu/drm/drm_mode_object.c | |||
@@ -247,8 +247,9 @@ int drm_object_property_set_value(struct drm_mode_object *obj, | |||
247 | } | 247 | } |
248 | EXPORT_SYMBOL(drm_object_property_set_value); | 248 | EXPORT_SYMBOL(drm_object_property_set_value); |
249 | 249 | ||
250 | int __drm_object_property_get_value(struct drm_mode_object *obj, | 250 | static int __drm_object_property_get_value(struct drm_mode_object *obj, |
251 | struct drm_property *property, uint64_t *val) | 251 | struct drm_property *property, |
252 | uint64_t *val) | ||
252 | { | 253 | { |
253 | int i; | 254 | int i; |
254 | 255 | ||
diff --git a/drivers/gpu/drm/drm_modeset_lock.c b/drivers/gpu/drm/drm_modeset_lock.c index af4e906c630d..e123497da0ca 100644 --- a/drivers/gpu/drm/drm_modeset_lock.c +++ b/drivers/gpu/drm/drm_modeset_lock.c | |||
@@ -39,23 +39,28 @@ | |||
39 | * | 39 | * |
40 | * The basic usage pattern is to:: | 40 | * The basic usage pattern is to:: |
41 | * | 41 | * |
42 | * drm_modeset_acquire_init(&ctx) | 42 | * drm_modeset_acquire_init(ctx, DRM_MODESET_ACQUIRE_INTERRUPTIBLE) |
43 | * retry: | 43 | * retry: |
44 | * foreach (lock in random_ordered_set_of_locks) { | 44 | * foreach (lock in random_ordered_set_of_locks) { |
45 | * ret = drm_modeset_lock(lock, &ctx) | 45 | * ret = drm_modeset_lock(lock, ctx) |
46 | * if (ret == -EDEADLK) { | 46 | * if (ret == -EDEADLK) { |
47 | * drm_modeset_backoff(&ctx); | 47 | * ret = drm_modeset_backoff(ctx); |
48 | * goto retry; | 48 | * if (!ret) |
49 | * goto retry; | ||
49 | * } | 50 | * } |
51 | * if (ret) | ||
52 | * goto out; | ||
50 | * } | 53 | * } |
51 | * ... do stuff ... | 54 | * ... do stuff ... |
52 | * drm_modeset_drop_locks(&ctx); | 55 | * out: |
53 | * drm_modeset_acquire_fini(&ctx); | 56 | * drm_modeset_drop_locks(ctx); |
57 | * drm_modeset_acquire_fini(ctx); | ||
54 | * | 58 | * |
55 | * If all that is needed is a single modeset lock, then the &struct | 59 | * If all that is needed is a single modeset lock, then the &struct |
56 | * drm_modeset_acquire_ctx is not needed and the locking can be simplified | 60 | * drm_modeset_acquire_ctx is not needed and the locking can be simplified |
57 | * by passing a NULL instead of ctx in the drm_modeset_lock() | 61 | * by passing a NULL instead of ctx in the drm_modeset_lock() call or |
58 | * call and, when done, by calling drm_modeset_unlock(). | 62 | * calling drm_modeset_lock_single_interruptible(). To unlock afterwards |
63 | * call drm_modeset_unlock(). | ||
59 | * | 64 | * |
60 | * On top of these per-object locks using &ww_mutex there's also an overall | 65 | * On top of these per-object locks using &ww_mutex there's also an overall |
61 | * &drm_mode_config.mutex, for protecting everything else. Mostly this means | 66 | * &drm_mode_config.mutex, for protecting everything else. Mostly this means |
@@ -178,7 +183,11 @@ EXPORT_SYMBOL(drm_warn_on_modeset_not_all_locked); | |||
178 | /** | 183 | /** |
179 | * drm_modeset_acquire_init - initialize acquire context | 184 | * drm_modeset_acquire_init - initialize acquire context |
180 | * @ctx: the acquire context | 185 | * @ctx: the acquire context |
181 | * @flags: for future | 186 | * @flags: 0 or %DRM_MODESET_ACQUIRE_INTERRUPTIBLE |
187 | * | ||
188 | * When passing %DRM_MODESET_ACQUIRE_INTERRUPTIBLE to @flags, | ||
189 | * all calls to drm_modeset_lock() will perform an interruptible | ||
190 | * wait. | ||
182 | */ | 191 | */ |
183 | void drm_modeset_acquire_init(struct drm_modeset_acquire_ctx *ctx, | 192 | void drm_modeset_acquire_init(struct drm_modeset_acquire_ctx *ctx, |
184 | uint32_t flags) | 193 | uint32_t flags) |
@@ -186,6 +195,9 @@ void drm_modeset_acquire_init(struct drm_modeset_acquire_ctx *ctx, | |||
186 | memset(ctx, 0, sizeof(*ctx)); | 195 | memset(ctx, 0, sizeof(*ctx)); |
187 | ww_acquire_init(&ctx->ww_ctx, &crtc_ww_class); | 196 | ww_acquire_init(&ctx->ww_ctx, &crtc_ww_class); |
188 | INIT_LIST_HEAD(&ctx->locked); | 197 | INIT_LIST_HEAD(&ctx->locked); |
198 | |||
199 | if (flags & DRM_MODESET_ACQUIRE_INTERRUPTIBLE) | ||
200 | ctx->interruptible = true; | ||
189 | } | 201 | } |
190 | EXPORT_SYMBOL(drm_modeset_acquire_init); | 202 | EXPORT_SYMBOL(drm_modeset_acquire_init); |
191 | 203 | ||
@@ -261,8 +273,19 @@ static inline int modeset_lock(struct drm_modeset_lock *lock, | |||
261 | return ret; | 273 | return ret; |
262 | } | 274 | } |
263 | 275 | ||
264 | static int modeset_backoff(struct drm_modeset_acquire_ctx *ctx, | 276 | /** |
265 | bool interruptible) | 277 | * drm_modeset_backoff - deadlock avoidance backoff |
278 | * @ctx: the acquire context | ||
279 | * | ||
280 | * If deadlock is detected (ie. drm_modeset_lock() returns -EDEADLK), | ||
281 | * you must call this function to drop all currently held locks and | ||
282 | * block until the contended lock becomes available. | ||
283 | * | ||
284 | * This function returns 0 on success, or -ERESTARTSYS if this context | ||
285 | * is initialized with %DRM_MODESET_ACQUIRE_INTERRUPTIBLE and the | ||
286 | * wait has been interrupted. | ||
287 | */ | ||
288 | int drm_modeset_backoff(struct drm_modeset_acquire_ctx *ctx) | ||
266 | { | 289 | { |
267 | struct drm_modeset_lock *contended = ctx->contended; | 290 | struct drm_modeset_lock *contended = ctx->contended; |
268 | 291 | ||
@@ -273,36 +296,11 @@ static int modeset_backoff(struct drm_modeset_acquire_ctx *ctx, | |||
273 | 296 | ||
274 | drm_modeset_drop_locks(ctx); | 297 | drm_modeset_drop_locks(ctx); |
275 | 298 | ||
276 | return modeset_lock(contended, ctx, interruptible, true); | 299 | return modeset_lock(contended, ctx, ctx->interruptible, true); |
277 | } | ||
278 | |||
279 | /** | ||
280 | * drm_modeset_backoff - deadlock avoidance backoff | ||
281 | * @ctx: the acquire context | ||
282 | * | ||
283 | * If deadlock is detected (ie. drm_modeset_lock() returns -EDEADLK), | ||
284 | * you must call this function to drop all currently held locks and | ||
285 | * block until the contended lock becomes available. | ||
286 | */ | ||
287 | void drm_modeset_backoff(struct drm_modeset_acquire_ctx *ctx) | ||
288 | { | ||
289 | modeset_backoff(ctx, false); | ||
290 | } | 300 | } |
291 | EXPORT_SYMBOL(drm_modeset_backoff); | 301 | EXPORT_SYMBOL(drm_modeset_backoff); |
292 | 302 | ||
293 | /** | 303 | /** |
294 | * drm_modeset_backoff_interruptible - deadlock avoidance backoff | ||
295 | * @ctx: the acquire context | ||
296 | * | ||
297 | * Interruptible version of drm_modeset_backoff() | ||
298 | */ | ||
299 | int drm_modeset_backoff_interruptible(struct drm_modeset_acquire_ctx *ctx) | ||
300 | { | ||
301 | return modeset_backoff(ctx, true); | ||
302 | } | ||
303 | EXPORT_SYMBOL(drm_modeset_backoff_interruptible); | ||
304 | |||
305 | /** | ||
306 | * drm_modeset_lock_init - initialize lock | 304 | * drm_modeset_lock_init - initialize lock |
307 | * @lock: lock to init | 305 | * @lock: lock to init |
308 | */ | 306 | */ |
@@ -324,14 +322,18 @@ EXPORT_SYMBOL(drm_modeset_lock_init); | |||
324 | * deadlock scenario has been detected and it is an error to attempt | 322 | * deadlock scenario has been detected and it is an error to attempt |
325 | * to take any more locks without first calling drm_modeset_backoff(). | 323 | * to take any more locks without first calling drm_modeset_backoff(). |
326 | * | 324 | * |
325 | * If the @ctx is not NULL and initialized with | ||
326 | * %DRM_MODESET_ACQUIRE_INTERRUPTIBLE, this function will fail with | ||
327 | * -ERESTARTSYS when interrupted. | ||
328 | * | ||
327 | * If @ctx is NULL then the function call behaves like a normal, | 329 | * If @ctx is NULL then the function call behaves like a normal, |
328 | * non-nesting mutex_lock() call. | 330 | * uninterruptible non-nesting mutex_lock() call. |
329 | */ | 331 | */ |
330 | int drm_modeset_lock(struct drm_modeset_lock *lock, | 332 | int drm_modeset_lock(struct drm_modeset_lock *lock, |
331 | struct drm_modeset_acquire_ctx *ctx) | 333 | struct drm_modeset_acquire_ctx *ctx) |
332 | { | 334 | { |
333 | if (ctx) | 335 | if (ctx) |
334 | return modeset_lock(lock, ctx, false, false); | 336 | return modeset_lock(lock, ctx, ctx->interruptible, false); |
335 | 337 | ||
336 | ww_mutex_lock(&lock->mutex, NULL); | 338 | ww_mutex_lock(&lock->mutex, NULL); |
337 | return 0; | 339 | return 0; |
@@ -339,21 +341,19 @@ int drm_modeset_lock(struct drm_modeset_lock *lock, | |||
339 | EXPORT_SYMBOL(drm_modeset_lock); | 341 | EXPORT_SYMBOL(drm_modeset_lock); |
340 | 342 | ||
341 | /** | 343 | /** |
342 | * drm_modeset_lock_interruptible - take modeset lock | 344 | * drm_modeset_lock_single_interruptible - take a single modeset lock |
343 | * @lock: lock to take | 345 | * @lock: lock to take |
344 | * @ctx: acquire ctx | ||
345 | * | 346 | * |
346 | * Interruptible version of drm_modeset_lock() | 347 | * This function behaves as drm_modeset_lock() with a NULL context, |
348 | * but performs interruptible waits. | ||
349 | * | ||
350 | * This function returns 0 on success, or -ERESTARTSYS when interrupted. | ||
347 | */ | 351 | */ |
348 | int drm_modeset_lock_interruptible(struct drm_modeset_lock *lock, | 352 | int drm_modeset_lock_single_interruptible(struct drm_modeset_lock *lock) |
349 | struct drm_modeset_acquire_ctx *ctx) | ||
350 | { | 353 | { |
351 | if (ctx) | ||
352 | return modeset_lock(lock, ctx, true, false); | ||
353 | |||
354 | return ww_mutex_lock_interruptible(&lock->mutex, NULL); | 354 | return ww_mutex_lock_interruptible(&lock->mutex, NULL); |
355 | } | 355 | } |
356 | EXPORT_SYMBOL(drm_modeset_lock_interruptible); | 356 | EXPORT_SYMBOL(drm_modeset_lock_single_interruptible); |
357 | 357 | ||
358 | /** | 358 | /** |
359 | * drm_modeset_unlock - drop modeset lock | 359 | * drm_modeset_unlock - drop modeset lock |
diff --git a/drivers/gpu/drm/drm_plane.c b/drivers/gpu/drm/drm_plane.c index 7a00351d5b5d..72cba9805edc 100644 --- a/drivers/gpu/drm/drm_plane.c +++ b/drivers/gpu/drm/drm_plane.c | |||
@@ -667,7 +667,7 @@ static int setplane_internal(struct drm_plane *plane, | |||
667 | struct drm_modeset_acquire_ctx ctx; | 667 | struct drm_modeset_acquire_ctx ctx; |
668 | int ret; | 668 | int ret; |
669 | 669 | ||
670 | drm_modeset_acquire_init(&ctx, 0); | 670 | drm_modeset_acquire_init(&ctx, DRM_MODESET_ACQUIRE_INTERRUPTIBLE); |
671 | retry: | 671 | retry: |
672 | ret = drm_modeset_lock_all_ctx(plane->dev, &ctx); | 672 | ret = drm_modeset_lock_all_ctx(plane->dev, &ctx); |
673 | if (ret) | 673 | if (ret) |
@@ -678,8 +678,9 @@ retry: | |||
678 | 678 | ||
679 | fail: | 679 | fail: |
680 | if (ret == -EDEADLK) { | 680 | if (ret == -EDEADLK) { |
681 | drm_modeset_backoff(&ctx); | 681 | ret = drm_modeset_backoff(&ctx); |
682 | goto retry; | 682 | if (!ret) |
683 | goto retry; | ||
683 | } | 684 | } |
684 | drm_modeset_drop_locks(&ctx); | 685 | drm_modeset_drop_locks(&ctx); |
685 | drm_modeset_acquire_fini(&ctx); | 686 | drm_modeset_acquire_fini(&ctx); |
@@ -834,7 +835,7 @@ static int drm_mode_cursor_common(struct drm_device *dev, | |||
834 | return -ENOENT; | 835 | return -ENOENT; |
835 | } | 836 | } |
836 | 837 | ||
837 | drm_modeset_acquire_init(&ctx, 0); | 838 | drm_modeset_acquire_init(&ctx, DRM_MODESET_ACQUIRE_INTERRUPTIBLE); |
838 | retry: | 839 | retry: |
839 | ret = drm_modeset_lock(&crtc->mutex, &ctx); | 840 | ret = drm_modeset_lock(&crtc->mutex, &ctx); |
840 | if (ret) | 841 | if (ret) |
@@ -876,8 +877,9 @@ retry: | |||
876 | } | 877 | } |
877 | out: | 878 | out: |
878 | if (ret == -EDEADLK) { | 879 | if (ret == -EDEADLK) { |
879 | drm_modeset_backoff(&ctx); | 880 | ret = drm_modeset_backoff(&ctx); |
880 | goto retry; | 881 | if (!ret) |
882 | goto retry; | ||
881 | } | 883 | } |
882 | 884 | ||
883 | drm_modeset_drop_locks(&ctx); | 885 | drm_modeset_drop_locks(&ctx); |
@@ -985,7 +987,7 @@ int drm_mode_page_flip_ioctl(struct drm_device *dev, | |||
985 | return -EINVAL; | 987 | return -EINVAL; |
986 | } | 988 | } |
987 | 989 | ||
988 | drm_modeset_acquire_init(&ctx, 0); | 990 | drm_modeset_acquire_init(&ctx, DRM_MODESET_ACQUIRE_INTERRUPTIBLE); |
989 | retry: | 991 | retry: |
990 | ret = drm_modeset_lock(&crtc->mutex, &ctx); | 992 | ret = drm_modeset_lock(&crtc->mutex, &ctx); |
991 | if (ret) | 993 | if (ret) |
@@ -1074,8 +1076,9 @@ out: | |||
1074 | crtc->primary->old_fb = NULL; | 1076 | crtc->primary->old_fb = NULL; |
1075 | 1077 | ||
1076 | if (ret == -EDEADLK) { | 1078 | if (ret == -EDEADLK) { |
1077 | drm_modeset_backoff(&ctx); | 1079 | ret = drm_modeset_backoff(&ctx); |
1078 | goto retry; | 1080 | if (!ret) |
1081 | goto retry; | ||
1079 | } | 1082 | } |
1080 | 1083 | ||
1081 | drm_modeset_drop_locks(&ctx); | 1084 | drm_modeset_drop_locks(&ctx); |
diff --git a/drivers/gpu/drm/drm_probe_helper.c b/drivers/gpu/drm/drm_probe_helper.c index 904966cde32b..5840aabbf24e 100644 --- a/drivers/gpu/drm/drm_probe_helper.c +++ b/drivers/gpu/drm/drm_probe_helper.c | |||
@@ -353,8 +353,6 @@ EXPORT_SYMBOL(drm_helper_probe_detect); | |||
353 | * drm_mode_probed_add(). New modes start their life with status as OK. | 353 | * drm_mode_probed_add(). New modes start their life with status as OK. |
354 | * Modes are added from a single source using the following priority order. | 354 | * Modes are added from a single source using the following priority order. |
355 | * | 355 | * |
356 | * - debugfs 'override_edid' (used for testing only) | ||
357 | * - firmware EDID (drm_load_edid_firmware()) | ||
358 | * - &drm_connector_helper_funcs.get_modes vfunc | 356 | * - &drm_connector_helper_funcs.get_modes vfunc |
359 | * - if the connector status is connector_status_connected, standard | 357 | * - if the connector status is connector_status_connected, standard |
360 | * VESA DMT modes up to 1024x768 are automatically added | 358 | * VESA DMT modes up to 1024x768 are automatically added |
@@ -483,22 +481,7 @@ retry: | |||
483 | goto prune; | 481 | goto prune; |
484 | } | 482 | } |
485 | 483 | ||
486 | if (connector->override_edid) { | 484 | count = (*connector_funcs->get_modes)(connector); |
487 | struct edid *edid = (struct edid *) connector->edid_blob_ptr->data; | ||
488 | |||
489 | count = drm_add_edid_modes(connector, edid); | ||
490 | drm_edid_to_eld(connector, edid); | ||
491 | } else { | ||
492 | struct edid *edid = drm_load_edid_firmware(connector); | ||
493 | if (!IS_ERR_OR_NULL(edid)) { | ||
494 | drm_mode_connector_update_edid_property(connector, edid); | ||
495 | count = drm_add_edid_modes(connector, edid); | ||
496 | drm_edid_to_eld(connector, edid); | ||
497 | kfree(edid); | ||
498 | } | ||
499 | if (count == 0) | ||
500 | count = (*connector_funcs->get_modes)(connector); | ||
501 | } | ||
502 | 485 | ||
503 | if (count == 0 && connector->status == connector_status_connected) | 486 | if (count == 0 && connector->status == connector_status_connected) |
504 | count = drm_add_modes_noedid(connector, 1024, 768); | 487 | count = drm_add_modes_noedid(connector, 1024, 768); |
diff --git a/drivers/gpu/drm/drm_scdc_helper.c b/drivers/gpu/drm/drm_scdc_helper.c index 935653eb3616..657ea5ab6c3f 100644 --- a/drivers/gpu/drm/drm_scdc_helper.c +++ b/drivers/gpu/drm/drm_scdc_helper.c | |||
@@ -134,7 +134,6 @@ EXPORT_SYMBOL(drm_scdc_write); | |||
134 | * Returns: | 134 | * Returns: |
135 | * True if the scrambling is enabled, false otherwise. | 135 | * True if the scrambling is enabled, false otherwise. |
136 | */ | 136 | */ |
137 | |||
138 | bool drm_scdc_get_scrambling_status(struct i2c_adapter *adapter) | 137 | bool drm_scdc_get_scrambling_status(struct i2c_adapter *adapter) |
139 | { | 138 | { |
140 | u8 status; | 139 | u8 status; |
@@ -142,7 +141,7 @@ bool drm_scdc_get_scrambling_status(struct i2c_adapter *adapter) | |||
142 | 141 | ||
143 | ret = drm_scdc_readb(adapter, SCDC_SCRAMBLER_STATUS, &status); | 142 | ret = drm_scdc_readb(adapter, SCDC_SCRAMBLER_STATUS, &status); |
144 | if (ret < 0) { | 143 | if (ret < 0) { |
145 | DRM_ERROR("Failed to read scrambling status, error %d\n", ret); | 144 | DRM_ERROR("Failed to read scrambling status: %d\n", ret); |
146 | return false; | 145 | return false; |
147 | } | 146 | } |
148 | 147 | ||
@@ -162,7 +161,6 @@ EXPORT_SYMBOL(drm_scdc_get_scrambling_status); | |||
162 | * Returns: | 161 | * Returns: |
163 | * True if scrambling is set/reset successfully, false otherwise. | 162 | * True if scrambling is set/reset successfully, false otherwise. |
164 | */ | 163 | */ |
165 | |||
166 | bool drm_scdc_set_scrambling(struct i2c_adapter *adapter, bool enable) | 164 | bool drm_scdc_set_scrambling(struct i2c_adapter *adapter, bool enable) |
167 | { | 165 | { |
168 | u8 config; | 166 | u8 config; |
@@ -170,7 +168,7 @@ bool drm_scdc_set_scrambling(struct i2c_adapter *adapter, bool enable) | |||
170 | 168 | ||
171 | ret = drm_scdc_readb(adapter, SCDC_TMDS_CONFIG, &config); | 169 | ret = drm_scdc_readb(adapter, SCDC_TMDS_CONFIG, &config); |
172 | if (ret < 0) { | 170 | if (ret < 0) { |
173 | DRM_ERROR("Failed to read tmds config, err=%d\n", ret); | 171 | DRM_ERROR("Failed to read TMDS config: %d\n", ret); |
174 | return false; | 172 | return false; |
175 | } | 173 | } |
176 | 174 | ||
@@ -181,7 +179,7 @@ bool drm_scdc_set_scrambling(struct i2c_adapter *adapter, bool enable) | |||
181 | 179 | ||
182 | ret = drm_scdc_writeb(adapter, SCDC_TMDS_CONFIG, config); | 180 | ret = drm_scdc_writeb(adapter, SCDC_TMDS_CONFIG, config); |
183 | if (ret < 0) { | 181 | if (ret < 0) { |
184 | DRM_ERROR("Failed to enable scrambling, error %d\n", ret); | 182 | DRM_ERROR("Failed to enable scrambling: %d\n", ret); |
185 | return false; | 183 | return false; |
186 | } | 184 | } |
187 | 185 | ||
@@ -225,7 +223,7 @@ bool drm_scdc_set_high_tmds_clock_ratio(struct i2c_adapter *adapter, bool set) | |||
225 | 223 | ||
226 | ret = drm_scdc_readb(adapter, SCDC_TMDS_CONFIG, &config); | 224 | ret = drm_scdc_readb(adapter, SCDC_TMDS_CONFIG, &config); |
227 | if (ret < 0) { | 225 | if (ret < 0) { |
228 | DRM_ERROR("Failed to read tmds config, err=%d\n", ret); | 226 | DRM_ERROR("Failed to read TMDS config: %d\n", ret); |
229 | return false; | 227 | return false; |
230 | } | 228 | } |
231 | 229 | ||
@@ -236,7 +234,7 @@ bool drm_scdc_set_high_tmds_clock_ratio(struct i2c_adapter *adapter, bool set) | |||
236 | 234 | ||
237 | ret = drm_scdc_writeb(adapter, SCDC_TMDS_CONFIG, config); | 235 | ret = drm_scdc_writeb(adapter, SCDC_TMDS_CONFIG, config); |
238 | if (ret < 0) { | 236 | if (ret < 0) { |
239 | DRM_ERROR("Failed to set TMDS clock ratio, error %d\n", ret); | 237 | DRM_ERROR("Failed to set TMDS clock ratio: %d\n", ret); |
240 | return false; | 238 | return false; |
241 | } | 239 | } |
242 | 240 | ||
diff --git a/drivers/gpu/drm/drm_syncobj.c b/drivers/gpu/drm/drm_syncobj.c index 0422b8c2c2e7..26d60615b4d4 100644 --- a/drivers/gpu/drm/drm_syncobj.c +++ b/drivers/gpu/drm/drm_syncobj.c | |||
@@ -417,8 +417,8 @@ static int drm_syncobj_fd_to_handle(struct drm_file *file_private, | |||
417 | return 0; | 417 | return 0; |
418 | } | 418 | } |
419 | 419 | ||
420 | int drm_syncobj_import_sync_file_fence(struct drm_file *file_private, | 420 | static int drm_syncobj_import_sync_file_fence(struct drm_file *file_private, |
421 | int fd, int handle) | 421 | int fd, int handle) |
422 | { | 422 | { |
423 | struct dma_fence *fence = sync_file_get_fence(fd); | 423 | struct dma_fence *fence = sync_file_get_fence(fd); |
424 | struct drm_syncobj *syncobj; | 424 | struct drm_syncobj *syncobj; |
@@ -438,8 +438,8 @@ int drm_syncobj_import_sync_file_fence(struct drm_file *file_private, | |||
438 | return 0; | 438 | return 0; |
439 | } | 439 | } |
440 | 440 | ||
441 | int drm_syncobj_export_sync_file(struct drm_file *file_private, | 441 | static int drm_syncobj_export_sync_file(struct drm_file *file_private, |
442 | int handle, int *p_fd) | 442 | int handle, int *p_fd) |
443 | { | 443 | { |
444 | int ret; | 444 | int ret; |
445 | struct dma_fence *fence; | 445 | struct dma_fence *fence; |
diff --git a/drivers/gpu/drm/drm_trace.h b/drivers/gpu/drm/drm_trace.h index 14c5a777682e..16c64d067e67 100644 --- a/drivers/gpu/drm/drm_trace.h +++ b/drivers/gpu/drm/drm_trace.h | |||
@@ -61,5 +61,5 @@ TRACE_EVENT(drm_vblank_event_delivered, | |||
61 | 61 | ||
62 | /* This part must be outside protection */ | 62 | /* This part must be outside protection */ |
63 | #undef TRACE_INCLUDE_PATH | 63 | #undef TRACE_INCLUDE_PATH |
64 | #define TRACE_INCLUDE_PATH . | 64 | #define TRACE_INCLUDE_PATH ../../drivers/gpu/drm |
65 | #include <trace/define_trace.h> | 65 | #include <trace/define_trace.h> |
diff --git a/drivers/gpu/drm/exynos/exynos_drm_mic.c b/drivers/gpu/drm/exynos/exynos_drm_mic.c index ba4a32b132ba..2174814273e2 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_mic.c +++ b/drivers/gpu/drm/exynos/exynos_drm_mic.c | |||
@@ -420,11 +420,7 @@ static int exynos_mic_probe(struct platform_device *pdev) | |||
420 | mic->bridge.funcs = &mic_bridge_funcs; | 420 | mic->bridge.funcs = &mic_bridge_funcs; |
421 | mic->bridge.of_node = dev->of_node; | 421 | mic->bridge.of_node = dev->of_node; |
422 | 422 | ||
423 | ret = drm_bridge_add(&mic->bridge); | 423 | drm_bridge_add(&mic->bridge); |
424 | if (ret) { | ||
425 | DRM_ERROR("mic: Failed to add MIC to the global bridge list\n"); | ||
426 | return ret; | ||
427 | } | ||
428 | 424 | ||
429 | pm_runtime_enable(dev); | 425 | pm_runtime_enable(dev); |
430 | 426 | ||
diff --git a/drivers/gpu/drm/gma500/cdv_intel_dp.c b/drivers/gpu/drm/gma500/cdv_intel_dp.c index c52f9adf5e04..a4bb89b7878f 100644 --- a/drivers/gpu/drm/gma500/cdv_intel_dp.c +++ b/drivers/gpu/drm/gma500/cdv_intel_dp.c | |||
@@ -1901,10 +1901,8 @@ cdv_intel_dp_destroy(struct drm_connector *connector) | |||
1901 | 1901 | ||
1902 | if (is_edp(gma_encoder)) { | 1902 | if (is_edp(gma_encoder)) { |
1903 | /* cdv_intel_panel_destroy_backlight(connector->dev); */ | 1903 | /* cdv_intel_panel_destroy_backlight(connector->dev); */ |
1904 | if (intel_dp->panel_fixed_mode) { | 1904 | kfree(intel_dp->panel_fixed_mode); |
1905 | kfree(intel_dp->panel_fixed_mode); | 1905 | intel_dp->panel_fixed_mode = NULL; |
1906 | intel_dp->panel_fixed_mode = NULL; | ||
1907 | } | ||
1908 | } | 1906 | } |
1909 | i2c_del_adapter(&intel_dp->adapter); | 1907 | i2c_del_adapter(&intel_dp->adapter); |
1910 | drm_connector_unregister(connector); | 1908 | drm_connector_unregister(connector); |
diff --git a/drivers/gpu/drm/gma500/mdfld_intel_display.c b/drivers/gpu/drm/gma500/mdfld_intel_display.c index 531e4450c000..5c066448be5b 100644 --- a/drivers/gpu/drm/gma500/mdfld_intel_display.c +++ b/drivers/gpu/drm/gma500/mdfld_intel_display.c | |||
@@ -99,7 +99,7 @@ void mdfldWaitForPipeEnable(struct drm_device *dev, int pipe) | |||
99 | /* Wait for for the pipe enable to take effect. */ | 99 | /* Wait for for the pipe enable to take effect. */ |
100 | for (count = 0; count < COUNT_MAX; count++) { | 100 | for (count = 0; count < COUNT_MAX; count++) { |
101 | temp = REG_READ(map->conf); | 101 | temp = REG_READ(map->conf); |
102 | if ((temp & PIPEACONF_PIPE_STATE) == 1) | 102 | if (temp & PIPEACONF_PIPE_STATE) |
103 | break; | 103 | break; |
104 | } | 104 | } |
105 | } | 105 | } |
diff --git a/drivers/gpu/drm/i2c/ch7006_drv.c b/drivers/gpu/drm/i2c/ch7006_drv.c index e9e8ae2ec06b..544a8a2d3562 100644 --- a/drivers/gpu/drm/i2c/ch7006_drv.c +++ b/drivers/gpu/drm/i2c/ch7006_drv.c | |||
@@ -485,7 +485,7 @@ static int ch7006_encoder_init(struct i2c_client *client, | |||
485 | return 0; | 485 | return 0; |
486 | } | 486 | } |
487 | 487 | ||
488 | static struct i2c_device_id ch7006_ids[] = { | 488 | static const struct i2c_device_id ch7006_ids[] = { |
489 | { "ch7006", 0 }, | 489 | { "ch7006", 0 }, |
490 | { } | 490 | { } |
491 | }; | 491 | }; |
diff --git a/drivers/gpu/drm/i2c/sil164_drv.c b/drivers/gpu/drm/i2c/sil164_drv.c index db0b03fb0ff1..ecaa58757529 100644 --- a/drivers/gpu/drm/i2c/sil164_drv.c +++ b/drivers/gpu/drm/i2c/sil164_drv.c | |||
@@ -415,7 +415,7 @@ sil164_encoder_init(struct i2c_client *client, | |||
415 | return 0; | 415 | return 0; |
416 | } | 416 | } |
417 | 417 | ||
418 | static struct i2c_device_id sil164_ids[] = { | 418 | static const struct i2c_device_id sil164_ids[] = { |
419 | { "sil164", 0 }, | 419 | { "sil164", 0 }, |
420 | { } | 420 | { } |
421 | }; | 421 | }; |
diff --git a/drivers/gpu/drm/i2c/tda998x_drv.c b/drivers/gpu/drm/i2c/tda998x_drv.c index 54e3255dde13..4d1f45acf2cd 100644 --- a/drivers/gpu/drm/i2c/tda998x_drv.c +++ b/drivers/gpu/drm/i2c/tda998x_drv.c | |||
@@ -1746,7 +1746,7 @@ static const struct of_device_id tda998x_dt_ids[] = { | |||
1746 | MODULE_DEVICE_TABLE(of, tda998x_dt_ids); | 1746 | MODULE_DEVICE_TABLE(of, tda998x_dt_ids); |
1747 | #endif | 1747 | #endif |
1748 | 1748 | ||
1749 | static struct i2c_device_id tda998x_ids[] = { | 1749 | static const struct i2c_device_id tda998x_ids[] = { |
1750 | { "tda998x", 0 }, | 1750 | { "tda998x", 0 }, |
1751 | { } | 1751 | { } |
1752 | }; | 1752 | }; |
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 18d9da53282b..b6b175aa5d25 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h | |||
@@ -707,8 +707,7 @@ struct drm_i915_display_funcs { | |||
707 | struct drm_atomic_state *old_state); | 707 | struct drm_atomic_state *old_state); |
708 | void (*crtc_disable)(struct intel_crtc_state *old_crtc_state, | 708 | void (*crtc_disable)(struct intel_crtc_state *old_crtc_state, |
709 | struct drm_atomic_state *old_state); | 709 | struct drm_atomic_state *old_state); |
710 | void (*update_crtcs)(struct drm_atomic_state *state, | 710 | void (*update_crtcs)(struct drm_atomic_state *state); |
711 | unsigned int *crtc_vblank_mask); | ||
712 | void (*audio_codec_enable)(struct drm_connector *connector, | 711 | void (*audio_codec_enable)(struct drm_connector *connector, |
713 | struct intel_encoder *encoder, | 712 | struct intel_encoder *encoder, |
714 | const struct drm_display_mode *adjusted_mode); | 713 | const struct drm_display_mode *adjusted_mode); |
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 00cd17c76fdc..4b34fa6954f9 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c | |||
@@ -12129,73 +12129,10 @@ u32 intel_crtc_get_vblank_counter(struct intel_crtc *crtc) | |||
12129 | return dev->driver->get_vblank_counter(dev, crtc->pipe); | 12129 | return dev->driver->get_vblank_counter(dev, crtc->pipe); |
12130 | } | 12130 | } |
12131 | 12131 | ||
12132 | static void intel_atomic_wait_for_vblanks(struct drm_device *dev, | ||
12133 | struct drm_i915_private *dev_priv, | ||
12134 | unsigned crtc_mask) | ||
12135 | { | ||
12136 | unsigned last_vblank_count[I915_MAX_PIPES]; | ||
12137 | enum pipe pipe; | ||
12138 | int ret; | ||
12139 | |||
12140 | if (!crtc_mask) | ||
12141 | return; | ||
12142 | |||
12143 | for_each_pipe(dev_priv, pipe) { | ||
12144 | struct intel_crtc *crtc = intel_get_crtc_for_pipe(dev_priv, | ||
12145 | pipe); | ||
12146 | |||
12147 | if (!((1 << pipe) & crtc_mask)) | ||
12148 | continue; | ||
12149 | |||
12150 | ret = drm_crtc_vblank_get(&crtc->base); | ||
12151 | if (WARN_ON(ret != 0)) { | ||
12152 | crtc_mask &= ~(1 << pipe); | ||
12153 | continue; | ||
12154 | } | ||
12155 | |||
12156 | last_vblank_count[pipe] = drm_crtc_vblank_count(&crtc->base); | ||
12157 | } | ||
12158 | |||
12159 | for_each_pipe(dev_priv, pipe) { | ||
12160 | struct intel_crtc *crtc = intel_get_crtc_for_pipe(dev_priv, | ||
12161 | pipe); | ||
12162 | long lret; | ||
12163 | |||
12164 | if (!((1 << pipe) & crtc_mask)) | ||
12165 | continue; | ||
12166 | |||
12167 | lret = wait_event_timeout(dev->vblank[pipe].queue, | ||
12168 | last_vblank_count[pipe] != | ||
12169 | drm_crtc_vblank_count(&crtc->base), | ||
12170 | msecs_to_jiffies(50)); | ||
12171 | |||
12172 | WARN(!lret, "pipe %c vblank wait timed out\n", pipe_name(pipe)); | ||
12173 | |||
12174 | drm_crtc_vblank_put(&crtc->base); | ||
12175 | } | ||
12176 | } | ||
12177 | |||
12178 | static bool needs_vblank_wait(struct intel_crtc_state *crtc_state) | ||
12179 | { | ||
12180 | /* fb updated, need to unpin old fb */ | ||
12181 | if (crtc_state->fb_changed) | ||
12182 | return true; | ||
12183 | |||
12184 | /* wm changes, need vblank before final wm's */ | ||
12185 | if (crtc_state->update_wm_post) | ||
12186 | return true; | ||
12187 | |||
12188 | if (crtc_state->wm.need_postvbl_update) | ||
12189 | return true; | ||
12190 | |||
12191 | return false; | ||
12192 | } | ||
12193 | |||
12194 | static void intel_update_crtc(struct drm_crtc *crtc, | 12132 | static void intel_update_crtc(struct drm_crtc *crtc, |
12195 | struct drm_atomic_state *state, | 12133 | struct drm_atomic_state *state, |
12196 | struct drm_crtc_state *old_crtc_state, | 12134 | struct drm_crtc_state *old_crtc_state, |
12197 | struct drm_crtc_state *new_crtc_state, | 12135 | struct drm_crtc_state *new_crtc_state) |
12198 | unsigned int *crtc_vblank_mask) | ||
12199 | { | 12136 | { |
12200 | struct drm_device *dev = crtc->dev; | 12137 | struct drm_device *dev = crtc->dev; |
12201 | struct drm_i915_private *dev_priv = to_i915(dev); | 12138 | struct drm_i915_private *dev_priv = to_i915(dev); |
@@ -12218,13 +12155,9 @@ static void intel_update_crtc(struct drm_crtc *crtc, | |||
12218 | } | 12155 | } |
12219 | 12156 | ||
12220 | drm_atomic_helper_commit_planes_on_crtc(old_crtc_state); | 12157 | drm_atomic_helper_commit_planes_on_crtc(old_crtc_state); |
12221 | |||
12222 | if (needs_vblank_wait(pipe_config)) | ||
12223 | *crtc_vblank_mask |= drm_crtc_mask(crtc); | ||
12224 | } | 12158 | } |
12225 | 12159 | ||
12226 | static void intel_update_crtcs(struct drm_atomic_state *state, | 12160 | static void intel_update_crtcs(struct drm_atomic_state *state) |
12227 | unsigned int *crtc_vblank_mask) | ||
12228 | { | 12161 | { |
12229 | struct drm_crtc *crtc; | 12162 | struct drm_crtc *crtc; |
12230 | struct drm_crtc_state *old_crtc_state, *new_crtc_state; | 12163 | struct drm_crtc_state *old_crtc_state, *new_crtc_state; |
@@ -12235,12 +12168,11 @@ static void intel_update_crtcs(struct drm_atomic_state *state, | |||
12235 | continue; | 12168 | continue; |
12236 | 12169 | ||
12237 | intel_update_crtc(crtc, state, old_crtc_state, | 12170 | intel_update_crtc(crtc, state, old_crtc_state, |
12238 | new_crtc_state, crtc_vblank_mask); | 12171 | new_crtc_state); |
12239 | } | 12172 | } |
12240 | } | 12173 | } |
12241 | 12174 | ||
12242 | static void skl_update_crtcs(struct drm_atomic_state *state, | 12175 | static void skl_update_crtcs(struct drm_atomic_state *state) |
12243 | unsigned int *crtc_vblank_mask) | ||
12244 | { | 12176 | { |
12245 | struct drm_i915_private *dev_priv = to_i915(state->dev); | 12177 | struct drm_i915_private *dev_priv = to_i915(state->dev); |
12246 | struct intel_atomic_state *intel_state = to_intel_atomic_state(state); | 12178 | struct intel_atomic_state *intel_state = to_intel_atomic_state(state); |
@@ -12299,7 +12231,7 @@ static void skl_update_crtcs(struct drm_atomic_state *state, | |||
12299 | vbl_wait = true; | 12231 | vbl_wait = true; |
12300 | 12232 | ||
12301 | intel_update_crtc(crtc, state, old_crtc_state, | 12233 | intel_update_crtc(crtc, state, old_crtc_state, |
12302 | new_crtc_state, crtc_vblank_mask); | 12234 | new_crtc_state); |
12303 | 12235 | ||
12304 | if (vbl_wait) | 12236 | if (vbl_wait) |
12305 | intel_wait_for_vblank(dev_priv, pipe); | 12237 | intel_wait_for_vblank(dev_priv, pipe); |
@@ -12361,7 +12293,6 @@ static void intel_atomic_commit_tail(struct drm_atomic_state *state) | |||
12361 | struct intel_crtc_state *intel_cstate; | 12293 | struct intel_crtc_state *intel_cstate; |
12362 | bool hw_check = intel_state->modeset; | 12294 | bool hw_check = intel_state->modeset; |
12363 | u64 put_domains[I915_MAX_PIPES] = {}; | 12295 | u64 put_domains[I915_MAX_PIPES] = {}; |
12364 | unsigned crtc_vblank_mask = 0; | ||
12365 | int i; | 12296 | int i; |
12366 | 12297 | ||
12367 | intel_atomic_commit_fence_wait(intel_state); | 12298 | intel_atomic_commit_fence_wait(intel_state); |
@@ -12451,7 +12382,7 @@ static void intel_atomic_commit_tail(struct drm_atomic_state *state) | |||
12451 | } | 12382 | } |
12452 | 12383 | ||
12453 | /* Now enable the clocks, plane, pipe, and connectors that we set up. */ | 12384 | /* Now enable the clocks, plane, pipe, and connectors that we set up. */ |
12454 | dev_priv->display.update_crtcs(state, &crtc_vblank_mask); | 12385 | dev_priv->display.update_crtcs(state); |
12455 | 12386 | ||
12456 | /* FIXME: We should call drm_atomic_helper_commit_hw_done() here | 12387 | /* FIXME: We should call drm_atomic_helper_commit_hw_done() here |
12457 | * already, but still need the state for the delayed optimization. To | 12388 | * already, but still need the state for the delayed optimization. To |
@@ -12462,8 +12393,7 @@ static void intel_atomic_commit_tail(struct drm_atomic_state *state) | |||
12462 | * - switch over to the vblank wait helper in the core after that since | 12393 | * - switch over to the vblank wait helper in the core after that since |
12463 | * we don't need out special handling any more. | 12394 | * we don't need out special handling any more. |
12464 | */ | 12395 | */ |
12465 | if (!state->legacy_cursor_update) | 12396 | drm_atomic_helper_wait_for_flip_done(dev, state); |
12466 | intel_atomic_wait_for_vblanks(dev, dev_priv, crtc_vblank_mask); | ||
12467 | 12397 | ||
12468 | /* | 12398 | /* |
12469 | * Now that the vblank has passed, we can go ahead and program the | 12399 | * Now that the vblank has passed, we can go ahead and program the |
@@ -13061,6 +12991,14 @@ intel_legacy_cursor_update(struct drm_plane *plane, | |||
13061 | goto slow; | 12991 | goto slow; |
13062 | 12992 | ||
13063 | old_plane_state = plane->state; | 12993 | old_plane_state = plane->state; |
12994 | /* | ||
12995 | * Don't do an async update if there is an outstanding commit modifying | ||
12996 | * the plane. This prevents our async update's changes from getting | ||
12997 | * overridden by a previous synchronous update's state. | ||
12998 | */ | ||
12999 | if (old_plane_state->commit && | ||
13000 | !try_wait_for_completion(&old_plane_state->commit->hw_done)) | ||
13001 | goto slow; | ||
13064 | 13002 | ||
13065 | /* | 13003 | /* |
13066 | * If any parameters change that may affect watermarks, | 13004 | * If any parameters change that may affect watermarks, |
@@ -13120,17 +13058,12 @@ intel_legacy_cursor_update(struct drm_plane *plane, | |||
13120 | } | 13058 | } |
13121 | 13059 | ||
13122 | old_fb = old_plane_state->fb; | 13060 | old_fb = old_plane_state->fb; |
13123 | old_vma = to_intel_plane_state(old_plane_state)->vma; | ||
13124 | 13061 | ||
13125 | i915_gem_track_fb(intel_fb_obj(old_fb), intel_fb_obj(fb), | 13062 | i915_gem_track_fb(intel_fb_obj(old_fb), intel_fb_obj(fb), |
13126 | intel_plane->frontbuffer_bit); | 13063 | intel_plane->frontbuffer_bit); |
13127 | 13064 | ||
13128 | /* Swap plane state */ | 13065 | /* Swap plane state */ |
13129 | new_plane_state->fence = old_plane_state->fence; | 13066 | plane->state = new_plane_state; |
13130 | *to_intel_plane_state(old_plane_state) = *to_intel_plane_state(new_plane_state); | ||
13131 | new_plane_state->fence = NULL; | ||
13132 | new_plane_state->fb = old_fb; | ||
13133 | to_intel_plane_state(new_plane_state)->vma = NULL; | ||
13134 | 13067 | ||
13135 | if (plane->state->visible) { | 13068 | if (plane->state->visible) { |
13136 | trace_intel_update_plane(plane, to_intel_crtc(crtc)); | 13069 | trace_intel_update_plane(plane, to_intel_crtc(crtc)); |
@@ -13142,13 +13075,17 @@ intel_legacy_cursor_update(struct drm_plane *plane, | |||
13142 | intel_plane->disable_plane(intel_plane, to_intel_crtc(crtc)); | 13075 | intel_plane->disable_plane(intel_plane, to_intel_crtc(crtc)); |
13143 | } | 13076 | } |
13144 | 13077 | ||
13078 | old_vma = fetch_and_zero(&to_intel_plane_state(old_plane_state)->vma); | ||
13145 | if (old_vma) | 13079 | if (old_vma) |
13146 | intel_unpin_fb_vma(old_vma); | 13080 | intel_unpin_fb_vma(old_vma); |
13147 | 13081 | ||
13148 | out_unlock: | 13082 | out_unlock: |
13149 | mutex_unlock(&dev_priv->drm.struct_mutex); | 13083 | mutex_unlock(&dev_priv->drm.struct_mutex); |
13150 | out_free: | 13084 | out_free: |
13151 | intel_plane_destroy_state(plane, new_plane_state); | 13085 | if (ret) |
13086 | intel_plane_destroy_state(plane, new_plane_state); | ||
13087 | else | ||
13088 | intel_plane_destroy_state(plane, old_plane_state); | ||
13152 | return ret; | 13089 | return ret; |
13153 | 13090 | ||
13154 | slow: | 13091 | slow: |
diff --git a/drivers/gpu/drm/imx/imx-drm-core.c b/drivers/gpu/drm/imx/imx-drm-core.c index f91cb72d0830..93c7e3f9b4a8 100644 --- a/drivers/gpu/drm/imx/imx-drm-core.c +++ b/drivers/gpu/drm/imx/imx-drm-core.c | |||
@@ -24,6 +24,7 @@ | |||
24 | #include <drm/drm_fb_helper.h> | 24 | #include <drm/drm_fb_helper.h> |
25 | #include <drm/drm_crtc_helper.h> | 25 | #include <drm/drm_crtc_helper.h> |
26 | #include <drm/drm_gem_cma_helper.h> | 26 | #include <drm/drm_gem_cma_helper.h> |
27 | #include <drm/drm_gem_framebuffer_helper.h> | ||
27 | #include <drm/drm_fb_cma_helper.h> | 28 | #include <drm/drm_fb_cma_helper.h> |
28 | #include <drm/drm_plane_helper.h> | 29 | #include <drm/drm_plane_helper.h> |
29 | #include <drm/drm_of.h> | 30 | #include <drm/drm_of.h> |
@@ -105,7 +106,7 @@ static int imx_drm_atomic_check(struct drm_device *dev, | |||
105 | } | 106 | } |
106 | 107 | ||
107 | static const struct drm_mode_config_funcs imx_drm_mode_config_funcs = { | 108 | static const struct drm_mode_config_funcs imx_drm_mode_config_funcs = { |
108 | .fb_create = drm_fb_cma_create, | 109 | .fb_create = drm_gem_fb_create, |
109 | .output_poll_changed = imx_drm_output_poll_changed, | 110 | .output_poll_changed = imx_drm_output_poll_changed, |
110 | .atomic_check = imx_drm_atomic_check, | 111 | .atomic_check = imx_drm_atomic_check, |
111 | .atomic_commit = drm_atomic_helper_commit, | 112 | .atomic_commit = drm_atomic_helper_commit, |
diff --git a/drivers/gpu/drm/imx/ipuv3-plane.c b/drivers/gpu/drm/imx/ipuv3-plane.c index cf98596c7ce1..247c60e6bed2 100644 --- a/drivers/gpu/drm/imx/ipuv3-plane.c +++ b/drivers/gpu/drm/imx/ipuv3-plane.c | |||
@@ -18,6 +18,7 @@ | |||
18 | #include <drm/drm_atomic_helper.h> | 18 | #include <drm/drm_atomic_helper.h> |
19 | #include <drm/drm_fb_cma_helper.h> | 19 | #include <drm/drm_fb_cma_helper.h> |
20 | #include <drm/drm_gem_cma_helper.h> | 20 | #include <drm/drm_gem_cma_helper.h> |
21 | #include <drm/drm_gem_framebuffer_helper.h> | ||
21 | #include <drm/drm_plane_helper.h> | 22 | #include <drm/drm_plane_helper.h> |
22 | 23 | ||
23 | #include "video/imx-ipu-v3.h" | 24 | #include "video/imx-ipu-v3.h" |
@@ -690,7 +691,7 @@ static void ipu_plane_atomic_update(struct drm_plane *plane, | |||
690 | } | 691 | } |
691 | 692 | ||
692 | static const struct drm_plane_helper_funcs ipu_plane_helper_funcs = { | 693 | static const struct drm_plane_helper_funcs ipu_plane_helper_funcs = { |
693 | .prepare_fb = drm_fb_cma_prepare_fb, | 694 | .prepare_fb = drm_gem_fb_prepare_fb, |
694 | .atomic_check = ipu_plane_atomic_check, | 695 | .atomic_check = ipu_plane_atomic_check, |
695 | .atomic_disable = ipu_plane_atomic_disable, | 696 | .atomic_disable = ipu_plane_atomic_disable, |
696 | .atomic_update = ipu_plane_atomic_update, | 697 | .atomic_update = ipu_plane_atomic_update, |
diff --git a/drivers/gpu/drm/mediatek/mtk_hdmi.c b/drivers/gpu/drm/mediatek/mtk_hdmi.c index 690c67507cbc..3ff502771ba2 100644 --- a/drivers/gpu/drm/mediatek/mtk_hdmi.c +++ b/drivers/gpu/drm/mediatek/mtk_hdmi.c | |||
@@ -1696,11 +1696,7 @@ static int mtk_drm_hdmi_probe(struct platform_device *pdev) | |||
1696 | 1696 | ||
1697 | hdmi->bridge.funcs = &mtk_hdmi_bridge_funcs; | 1697 | hdmi->bridge.funcs = &mtk_hdmi_bridge_funcs; |
1698 | hdmi->bridge.of_node = pdev->dev.of_node; | 1698 | hdmi->bridge.of_node = pdev->dev.of_node; |
1699 | ret = drm_bridge_add(&hdmi->bridge); | 1699 | drm_bridge_add(&hdmi->bridge); |
1700 | if (ret) { | ||
1701 | dev_err(dev, "failed to add bridge, ret = %d\n", ret); | ||
1702 | return ret; | ||
1703 | } | ||
1704 | 1700 | ||
1705 | ret = mtk_hdmi_clk_enable_audio(hdmi); | 1701 | ret = mtk_hdmi_clk_enable_audio(hdmi); |
1706 | if (ret) { | 1702 | if (ret) { |
diff --git a/drivers/gpu/drm/panel/Kconfig b/drivers/gpu/drm/panel/Kconfig index d84a031fae24..718d8ce15b1f 100644 --- a/drivers/gpu/drm/panel/Kconfig +++ b/drivers/gpu/drm/panel/Kconfig | |||
@@ -63,6 +63,15 @@ config DRM_PANEL_LG_LG4573 | |||
63 | Say Y here if you want to enable support for LG4573 RGB panel. | 63 | Say Y here if you want to enable support for LG4573 RGB panel. |
64 | To compile this driver as a module, choose M here. | 64 | To compile this driver as a module, choose M here. |
65 | 65 | ||
66 | config DRM_PANEL_ORISETECH_OTM8009A | ||
67 | tristate "Orise Technology otm8009a 480x800 dsi 2dl panel" | ||
68 | depends on OF | ||
69 | depends on DRM_MIPI_DSI | ||
70 | depends on BACKLIGHT_CLASS_DEVICE | ||
71 | help | ||
72 | Say Y here if you want to enable support for Orise Technology | ||
73 | otm8009a 480x800 dsi 2dl panel. | ||
74 | |||
66 | config DRM_PANEL_PANASONIC_VVX10F034N00 | 75 | config DRM_PANEL_PANASONIC_VVX10F034N00 |
67 | tristate "Panasonic VVX10F034N00 1920x1200 video mode panel" | 76 | tristate "Panasonic VVX10F034N00 1920x1200 video mode panel" |
68 | depends on OF | 77 | depends on OF |
@@ -80,12 +89,28 @@ config DRM_PANEL_SAMSUNG_S6E3HA2 | |||
80 | depends on BACKLIGHT_CLASS_DEVICE | 89 | depends on BACKLIGHT_CLASS_DEVICE |
81 | select VIDEOMODE_HELPERS | 90 | select VIDEOMODE_HELPERS |
82 | 91 | ||
92 | config DRM_PANEL_SAMSUNG_S6E63J0X03 | ||
93 | tristate "Samsung S6E63J0X03 DSI command mode panel" | ||
94 | depends on OF | ||
95 | depends on DRM_MIPI_DSI | ||
96 | depends on BACKLIGHT_CLASS_DEVICE | ||
97 | select VIDEOMODE_HELPERS | ||
98 | |||
83 | config DRM_PANEL_SAMSUNG_S6E8AA0 | 99 | config DRM_PANEL_SAMSUNG_S6E8AA0 |
84 | tristate "Samsung S6E8AA0 DSI video mode panel" | 100 | tristate "Samsung S6E8AA0 DSI video mode panel" |
85 | depends on OF | 101 | depends on OF |
86 | select DRM_MIPI_DSI | 102 | select DRM_MIPI_DSI |
87 | select VIDEOMODE_HELPERS | 103 | select VIDEOMODE_HELPERS |
88 | 104 | ||
105 | config DRM_PANEL_SEIKO_43WVF1G | ||
106 | tristate "Seiko 43WVF1G panel" | ||
107 | depends on OF | ||
108 | depends on BACKLIGHT_CLASS_DEVICE | ||
109 | select VIDEOMODE_HELPERS | ||
110 | help | ||
111 | Say Y here if you want to enable support for the Seiko | ||
112 | 43WVF1G controller for 800x480 LCD panels | ||
113 | |||
89 | config DRM_PANEL_SHARP_LQ101R1SX01 | 114 | config DRM_PANEL_SHARP_LQ101R1SX01 |
90 | tristate "Sharp LQ101R1SX01 panel" | 115 | tristate "Sharp LQ101R1SX01 panel" |
91 | depends on OF | 116 | depends on OF |
diff --git a/drivers/gpu/drm/panel/Makefile b/drivers/gpu/drm/panel/Makefile index 9f6610d08b00..c8483fdd5b9b 100644 --- a/drivers/gpu/drm/panel/Makefile +++ b/drivers/gpu/drm/panel/Makefile | |||
@@ -3,10 +3,13 @@ obj-$(CONFIG_DRM_PANEL_SIMPLE) += panel-simple.o | |||
3 | obj-$(CONFIG_DRM_PANEL_INNOLUX_P079ZCA) += panel-innolux-p079zca.o | 3 | obj-$(CONFIG_DRM_PANEL_INNOLUX_P079ZCA) += panel-innolux-p079zca.o |
4 | obj-$(CONFIG_DRM_PANEL_JDI_LT070ME05000) += panel-jdi-lt070me05000.o | 4 | obj-$(CONFIG_DRM_PANEL_JDI_LT070ME05000) += panel-jdi-lt070me05000.o |
5 | obj-$(CONFIG_DRM_PANEL_LG_LG4573) += panel-lg-lg4573.o | 5 | obj-$(CONFIG_DRM_PANEL_LG_LG4573) += panel-lg-lg4573.o |
6 | obj-$(CONFIG_DRM_PANEL_ORISETECH_OTM8009A) += panel-orisetech-otm8009a.o | ||
6 | obj-$(CONFIG_DRM_PANEL_PANASONIC_VVX10F034N00) += panel-panasonic-vvx10f034n00.o | 7 | obj-$(CONFIG_DRM_PANEL_PANASONIC_VVX10F034N00) += panel-panasonic-vvx10f034n00.o |
7 | obj-$(CONFIG_DRM_PANEL_SAMSUNG_LD9040) += panel-samsung-ld9040.o | 8 | obj-$(CONFIG_DRM_PANEL_SAMSUNG_LD9040) += panel-samsung-ld9040.o |
8 | obj-$(CONFIG_DRM_PANEL_SAMSUNG_S6E3HA2) += panel-samsung-s6e3ha2.o | 9 | obj-$(CONFIG_DRM_PANEL_SAMSUNG_S6E3HA2) += panel-samsung-s6e3ha2.o |
10 | obj-$(CONFIG_DRM_PANEL_SAMSUNG_S6E63J0X03) += panel-samsung-s6e63j0x03.o | ||
9 | obj-$(CONFIG_DRM_PANEL_SAMSUNG_S6E8AA0) += panel-samsung-s6e8aa0.o | 11 | obj-$(CONFIG_DRM_PANEL_SAMSUNG_S6E8AA0) += panel-samsung-s6e8aa0.o |
12 | obj-$(CONFIG_DRM_PANEL_SEIKO_43WVF1G) += panel-seiko-43wvf1g.o | ||
10 | obj-$(CONFIG_DRM_PANEL_SHARP_LQ101R1SX01) += panel-sharp-lq101r1sx01.o | 13 | obj-$(CONFIG_DRM_PANEL_SHARP_LQ101R1SX01) += panel-sharp-lq101r1sx01.o |
11 | obj-$(CONFIG_DRM_PANEL_SHARP_LS043T1LE01) += panel-sharp-ls043t1le01.o | 14 | obj-$(CONFIG_DRM_PANEL_SHARP_LS043T1LE01) += panel-sharp-ls043t1le01.o |
12 | obj-$(CONFIG_DRM_PANEL_SITRONIX_ST7789V) += panel-sitronix-st7789v.o | 15 | obj-$(CONFIG_DRM_PANEL_SITRONIX_ST7789V) += panel-sitronix-st7789v.o |
diff --git a/drivers/gpu/drm/panel/panel-orisetech-otm8009a.c b/drivers/gpu/drm/panel/panel-orisetech-otm8009a.c new file mode 100644 index 000000000000..c189cd6329c8 --- /dev/null +++ b/drivers/gpu/drm/panel/panel-orisetech-otm8009a.c | |||
@@ -0,0 +1,491 @@ | |||
1 | /* | ||
2 | * Copyright (C) STMicroelectronics SA 2017 | ||
3 | * | ||
4 | * Authors: Philippe Cornu <philippe.cornu@st.com> | ||
5 | * Yannick Fertre <yannick.fertre@st.com> | ||
6 | * | ||
7 | * License terms: GNU General Public License (GPL), version 2 | ||
8 | */ | ||
9 | #include <drm/drmP.h> | ||
10 | #include <drm/drm_mipi_dsi.h> | ||
11 | #include <drm/drm_panel.h> | ||
12 | #include <linux/backlight.h> | ||
13 | #include <linux/gpio/consumer.h> | ||
14 | #include <video/mipi_display.h> | ||
15 | |||
16 | #define DRV_NAME "orisetech_otm8009a" | ||
17 | |||
18 | #define OTM8009A_BACKLIGHT_DEFAULT 240 | ||
19 | #define OTM8009A_BACKLIGHT_MAX 255 | ||
20 | |||
21 | /* Manufacturer Command Set */ | ||
22 | #define MCS_ADRSFT 0x0000 /* Address Shift Function */ | ||
23 | #define MCS_PANSET 0xB3A6 /* Panel Type Setting */ | ||
24 | #define MCS_SD_CTRL 0xC0A2 /* Source Driver Timing Setting */ | ||
25 | #define MCS_P_DRV_M 0xC0B4 /* Panel Driving Mode */ | ||
26 | #define MCS_OSC_ADJ 0xC181 /* Oscillator Adjustment for Idle/Normal mode */ | ||
27 | #define MCS_RGB_VID_SET 0xC1A1 /* RGB Video Mode Setting */ | ||
28 | #define MCS_SD_PCH_CTRL 0xC480 /* Source Driver Precharge Control */ | ||
29 | #define MCS_NO_DOC1 0xC48A /* Command not documented */ | ||
30 | #define MCS_PWR_CTRL1 0xC580 /* Power Control Setting 1 */ | ||
31 | #define MCS_PWR_CTRL2 0xC590 /* Power Control Setting 2 for Normal Mode */ | ||
32 | #define MCS_PWR_CTRL4 0xC5B0 /* Power Control Setting 4 for DC Voltage */ | ||
33 | #define MCS_PANCTRLSET1 0xCB80 /* Panel Control Setting 1 */ | ||
34 | #define MCS_PANCTRLSET2 0xCB90 /* Panel Control Setting 2 */ | ||
35 | #define MCS_PANCTRLSET3 0xCBA0 /* Panel Control Setting 3 */ | ||
36 | #define MCS_PANCTRLSET4 0xCBB0 /* Panel Control Setting 4 */ | ||
37 | #define MCS_PANCTRLSET5 0xCBC0 /* Panel Control Setting 5 */ | ||
38 | #define MCS_PANCTRLSET6 0xCBD0 /* Panel Control Setting 6 */ | ||
39 | #define MCS_PANCTRLSET7 0xCBE0 /* Panel Control Setting 7 */ | ||
40 | #define MCS_PANCTRLSET8 0xCBF0 /* Panel Control Setting 8 */ | ||
41 | #define MCS_PANU2D1 0xCC80 /* Panel U2D Setting 1 */ | ||
42 | #define MCS_PANU2D2 0xCC90 /* Panel U2D Setting 2 */ | ||
43 | #define MCS_PANU2D3 0xCCA0 /* Panel U2D Setting 3 */ | ||
44 | #define MCS_PAND2U1 0xCCB0 /* Panel D2U Setting 1 */ | ||
45 | #define MCS_PAND2U2 0xCCC0 /* Panel D2U Setting 2 */ | ||
46 | #define MCS_PAND2U3 0xCCD0 /* Panel D2U Setting 3 */ | ||
47 | #define MCS_GOAVST 0xCE80 /* GOA VST Setting */ | ||
48 | #define MCS_GOACLKA1 0xCEA0 /* GOA CLKA1 Setting */ | ||
49 | #define MCS_GOACLKA3 0xCEB0 /* GOA CLKA3 Setting */ | ||
50 | #define MCS_GOAECLK 0xCFC0 /* GOA ECLK Setting */ | ||
51 | #define MCS_NO_DOC2 0xCFD0 /* Command not documented */ | ||
52 | #define MCS_GVDDSET 0xD800 /* GVDD/NGVDD */ | ||
53 | #define MCS_VCOMDC 0xD900 /* VCOM Voltage Setting */ | ||
54 | #define MCS_GMCT2_2P 0xE100 /* Gamma Correction 2.2+ Setting */ | ||
55 | #define MCS_GMCT2_2N 0xE200 /* Gamma Correction 2.2- Setting */ | ||
56 | #define MCS_NO_DOC3 0xF5B6 /* Command not documented */ | ||
57 | #define MCS_CMD2_ENA1 0xFF00 /* Enable Access Command2 "CMD2" */ | ||
58 | #define MCS_CMD2_ENA2 0xFF80 /* Enable Access Orise Command2 */ | ||
59 | |||
60 | struct otm8009a { | ||
61 | struct device *dev; | ||
62 | struct drm_panel panel; | ||
63 | struct backlight_device *bl_dev; | ||
64 | struct gpio_desc *reset_gpio; | ||
65 | bool prepared; | ||
66 | bool enabled; | ||
67 | }; | ||
68 | |||
69 | static const struct drm_display_mode default_mode = { | ||
70 | .clock = 32729, | ||
71 | .hdisplay = 480, | ||
72 | .hsync_start = 480 + 120, | ||
73 | .hsync_end = 480 + 120 + 63, | ||
74 | .htotal = 480 + 120 + 63 + 120, | ||
75 | .vdisplay = 800, | ||
76 | .vsync_start = 800 + 12, | ||
77 | .vsync_end = 800 + 12 + 12, | ||
78 | .vtotal = 800 + 12 + 12 + 12, | ||
79 | .vrefresh = 50, | ||
80 | .flags = 0, | ||
81 | .width_mm = 52, | ||
82 | .height_mm = 86, | ||
83 | }; | ||
84 | |||
85 | static inline struct otm8009a *panel_to_otm8009a(struct drm_panel *panel) | ||
86 | { | ||
87 | return container_of(panel, struct otm8009a, panel); | ||
88 | } | ||
89 | |||
90 | static void otm8009a_dcs_write_buf(struct otm8009a *ctx, const void *data, | ||
91 | size_t len) | ||
92 | { | ||
93 | struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev); | ||
94 | |||
95 | if (mipi_dsi_dcs_write_buffer(dsi, data, len) < 0) | ||
96 | DRM_WARN("mipi dsi dcs write buffer failed\n"); | ||
97 | } | ||
98 | |||
99 | #define dcs_write_seq(ctx, seq...) \ | ||
100 | ({ \ | ||
101 | static const u8 d[] = { seq }; \ | ||
102 | otm8009a_dcs_write_buf(ctx, d, ARRAY_SIZE(d)); \ | ||
103 | }) | ||
104 | |||
105 | #define dcs_write_cmd_at(ctx, cmd, seq...) \ | ||
106 | ({ \ | ||
107 | dcs_write_seq(ctx, MCS_ADRSFT, (cmd) & 0xFF); \ | ||
108 | dcs_write_seq(ctx, (cmd) >> 8, seq); \ | ||
109 | }) | ||
110 | |||
111 | static int otm8009a_init_sequence(struct otm8009a *ctx) | ||
112 | { | ||
113 | struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev); | ||
114 | int ret; | ||
115 | |||
116 | /* Enter CMD2 */ | ||
117 | dcs_write_cmd_at(ctx, MCS_CMD2_ENA1, 0x80, 0x09, 0x01); | ||
118 | |||
119 | /* Enter Orise Command2 */ | ||
120 | dcs_write_cmd_at(ctx, MCS_CMD2_ENA2, 0x80, 0x09); | ||
121 | |||
122 | dcs_write_cmd_at(ctx, MCS_SD_PCH_CTRL, 0x30); | ||
123 | mdelay(10); | ||
124 | |||
125 | dcs_write_cmd_at(ctx, MCS_NO_DOC1, 0x40); | ||
126 | mdelay(10); | ||
127 | |||
128 | dcs_write_cmd_at(ctx, MCS_PWR_CTRL4 + 1, 0xA9); | ||
129 | dcs_write_cmd_at(ctx, MCS_PWR_CTRL2 + 1, 0x34); | ||
130 | dcs_write_cmd_at(ctx, MCS_P_DRV_M, 0x50); | ||
131 | dcs_write_cmd_at(ctx, MCS_VCOMDC, 0x4E); | ||
132 | dcs_write_cmd_at(ctx, MCS_OSC_ADJ, 0x66); /* 65Hz */ | ||
133 | dcs_write_cmd_at(ctx, MCS_PWR_CTRL2 + 2, 0x01); | ||
134 | dcs_write_cmd_at(ctx, MCS_PWR_CTRL2 + 5, 0x34); | ||
135 | dcs_write_cmd_at(ctx, MCS_PWR_CTRL2 + 4, 0x33); | ||
136 | dcs_write_cmd_at(ctx, MCS_GVDDSET, 0x79, 0x79); | ||
137 | dcs_write_cmd_at(ctx, MCS_SD_CTRL + 1, 0x1B); | ||
138 | dcs_write_cmd_at(ctx, MCS_PWR_CTRL1 + 2, 0x83); | ||
139 | dcs_write_cmd_at(ctx, MCS_SD_PCH_CTRL + 1, 0x83); | ||
140 | dcs_write_cmd_at(ctx, MCS_RGB_VID_SET, 0x0E); | ||
141 | dcs_write_cmd_at(ctx, MCS_PANSET, 0x00, 0x01); | ||
142 | |||
143 | dcs_write_cmd_at(ctx, MCS_GOAVST, 0x85, 0x01, 0x00, 0x84, 0x01, 0x00); | ||
144 | dcs_write_cmd_at(ctx, MCS_GOACLKA1, 0x18, 0x04, 0x03, 0x39, 0x00, 0x00, | ||
145 | 0x00, 0x18, 0x03, 0x03, 0x3A, 0x00, 0x00, 0x00); | ||
146 | dcs_write_cmd_at(ctx, MCS_GOACLKA3, 0x18, 0x02, 0x03, 0x3B, 0x00, 0x00, | ||
147 | 0x00, 0x18, 0x01, 0x03, 0x3C, 0x00, 0x00, 0x00); | ||
148 | dcs_write_cmd_at(ctx, MCS_GOAECLK, 0x01, 0x01, 0x20, 0x20, 0x00, 0x00, | ||
149 | 0x01, 0x02, 0x00, 0x00); | ||
150 | |||
151 | dcs_write_cmd_at(ctx, MCS_NO_DOC2, 0x00); | ||
152 | |||
153 | dcs_write_cmd_at(ctx, MCS_PANCTRLSET1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); | ||
154 | dcs_write_cmd_at(ctx, MCS_PANCTRLSET2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | ||
155 | 0, 0, 0, 0, 0); | ||
156 | dcs_write_cmd_at(ctx, MCS_PANCTRLSET3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | ||
157 | 0, 0, 0, 0, 0); | ||
158 | dcs_write_cmd_at(ctx, MCS_PANCTRLSET4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); | ||
159 | dcs_write_cmd_at(ctx, MCS_PANCTRLSET5, 0, 4, 4, 4, 4, 4, 0, 0, 0, 0, | ||
160 | 0, 0, 0, 0, 0); | ||
161 | dcs_write_cmd_at(ctx, MCS_PANCTRLSET6, 0, 0, 0, 0, 0, 0, 4, 4, 4, 4, | ||
162 | 4, 0, 0, 0, 0); | ||
163 | dcs_write_cmd_at(ctx, MCS_PANCTRLSET7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); | ||
164 | dcs_write_cmd_at(ctx, MCS_PANCTRLSET8, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, | ||
165 | 0xFF, 0xFF, 0xFF, 0xFF, 0xFF); | ||
166 | |||
167 | dcs_write_cmd_at(ctx, MCS_PANU2D1, 0x00, 0x26, 0x09, 0x0B, 0x01, 0x25, | ||
168 | 0x00, 0x00, 0x00, 0x00); | ||
169 | dcs_write_cmd_at(ctx, MCS_PANU2D2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
170 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x26, 0x0A, 0x0C, 0x02); | ||
171 | dcs_write_cmd_at(ctx, MCS_PANU2D3, 0x25, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
172 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00); | ||
173 | dcs_write_cmd_at(ctx, MCS_PAND2U1, 0x00, 0x25, 0x0C, 0x0A, 0x02, 0x26, | ||
174 | 0x00, 0x00, 0x00, 0x00); | ||
175 | dcs_write_cmd_at(ctx, MCS_PAND2U2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
176 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x25, 0x0B, 0x09, 0x01); | ||
177 | dcs_write_cmd_at(ctx, MCS_PAND2U3, 0x26, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
178 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00); | ||
179 | |||
180 | dcs_write_cmd_at(ctx, MCS_PWR_CTRL1 + 1, 0x66); | ||
181 | |||
182 | dcs_write_cmd_at(ctx, MCS_NO_DOC3, 0x06); | ||
183 | |||
184 | dcs_write_cmd_at(ctx, MCS_GMCT2_2P, 0x00, 0x09, 0x0F, 0x0E, 0x07, 0x10, | ||
185 | 0x0B, 0x0A, 0x04, 0x07, 0x0B, 0x08, 0x0F, 0x10, 0x0A, | ||
186 | 0x01); | ||
187 | dcs_write_cmd_at(ctx, MCS_GMCT2_2N, 0x00, 0x09, 0x0F, 0x0E, 0x07, 0x10, | ||
188 | 0x0B, 0x0A, 0x04, 0x07, 0x0B, 0x08, 0x0F, 0x10, 0x0A, | ||
189 | 0x01); | ||
190 | |||
191 | /* Exit CMD2 */ | ||
192 | dcs_write_cmd_at(ctx, MCS_CMD2_ENA1, 0xFF, 0xFF, 0xFF); | ||
193 | |||
194 | ret = mipi_dsi_dcs_nop(dsi); | ||
195 | if (ret) | ||
196 | return ret; | ||
197 | |||
198 | ret = mipi_dsi_dcs_exit_sleep_mode(dsi); | ||
199 | if (ret) | ||
200 | return ret; | ||
201 | |||
202 | /* Wait for sleep out exit */ | ||
203 | mdelay(120); | ||
204 | |||
205 | /* Default portrait 480x800 rgb24 */ | ||
206 | dcs_write_seq(ctx, MIPI_DCS_SET_ADDRESS_MODE, 0x00); | ||
207 | |||
208 | ret = mipi_dsi_dcs_set_column_address(dsi, 0, | ||
209 | default_mode.hdisplay - 1); | ||
210 | if (ret) | ||
211 | return ret; | ||
212 | |||
213 | ret = mipi_dsi_dcs_set_page_address(dsi, 0, default_mode.vdisplay - 1); | ||
214 | if (ret) | ||
215 | return ret; | ||
216 | |||
217 | /* See otm8009a driver documentation for pixel format descriptions */ | ||
218 | ret = mipi_dsi_dcs_set_pixel_format(dsi, MIPI_DCS_PIXEL_FMT_24BIT | | ||
219 | MIPI_DCS_PIXEL_FMT_24BIT << 4); | ||
220 | if (ret) | ||
221 | return ret; | ||
222 | |||
223 | /* Disable CABC feature */ | ||
224 | dcs_write_seq(ctx, MIPI_DCS_WRITE_POWER_SAVE, 0x00); | ||
225 | |||
226 | ret = mipi_dsi_dcs_set_display_on(dsi); | ||
227 | if (ret) | ||
228 | return ret; | ||
229 | |||
230 | ret = mipi_dsi_dcs_nop(dsi); | ||
231 | if (ret) | ||
232 | return ret; | ||
233 | |||
234 | /* Send Command GRAM memory write (no parameters) */ | ||
235 | dcs_write_seq(ctx, MIPI_DCS_WRITE_MEMORY_START); | ||
236 | |||
237 | return 0; | ||
238 | } | ||
239 | |||
240 | static int otm8009a_disable(struct drm_panel *panel) | ||
241 | { | ||
242 | struct otm8009a *ctx = panel_to_otm8009a(panel); | ||
243 | struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev); | ||
244 | int ret; | ||
245 | |||
246 | if (!ctx->enabled) | ||
247 | return 0; /* This is not an issue so we return 0 here */ | ||
248 | |||
249 | /* Power off the backlight. Note: end-user still controls brightness */ | ||
250 | ctx->bl_dev->props.power = FB_BLANK_POWERDOWN; | ||
251 | ret = backlight_update_status(ctx->bl_dev); | ||
252 | if (ret) | ||
253 | return ret; | ||
254 | |||
255 | ret = mipi_dsi_dcs_set_display_off(dsi); | ||
256 | if (ret) | ||
257 | return ret; | ||
258 | |||
259 | ret = mipi_dsi_dcs_enter_sleep_mode(dsi); | ||
260 | if (ret) | ||
261 | return ret; | ||
262 | |||
263 | msleep(120); | ||
264 | |||
265 | ctx->enabled = false; | ||
266 | |||
267 | return 0; | ||
268 | } | ||
269 | |||
270 | static int otm8009a_unprepare(struct drm_panel *panel) | ||
271 | { | ||
272 | struct otm8009a *ctx = panel_to_otm8009a(panel); | ||
273 | |||
274 | if (!ctx->prepared) | ||
275 | return 0; | ||
276 | |||
277 | if (ctx->reset_gpio) { | ||
278 | gpiod_set_value_cansleep(ctx->reset_gpio, 1); | ||
279 | msleep(20); | ||
280 | } | ||
281 | |||
282 | ctx->prepared = false; | ||
283 | |||
284 | return 0; | ||
285 | } | ||
286 | |||
287 | static int otm8009a_prepare(struct drm_panel *panel) | ||
288 | { | ||
289 | struct otm8009a *ctx = panel_to_otm8009a(panel); | ||
290 | int ret; | ||
291 | |||
292 | if (ctx->prepared) | ||
293 | return 0; | ||
294 | |||
295 | if (ctx->reset_gpio) { | ||
296 | gpiod_set_value_cansleep(ctx->reset_gpio, 0); | ||
297 | gpiod_set_value_cansleep(ctx->reset_gpio, 1); | ||
298 | msleep(20); | ||
299 | gpiod_set_value_cansleep(ctx->reset_gpio, 0); | ||
300 | msleep(100); | ||
301 | } | ||
302 | |||
303 | ret = otm8009a_init_sequence(ctx); | ||
304 | if (ret) | ||
305 | return ret; | ||
306 | |||
307 | ctx->prepared = true; | ||
308 | |||
309 | /* | ||
310 | * Power on the backlight. Note: end-user still controls brightness | ||
311 | * Note: ctx->prepared must be true before updating the backlight. | ||
312 | */ | ||
313 | ctx->bl_dev->props.power = FB_BLANK_UNBLANK; | ||
314 | backlight_update_status(ctx->bl_dev); | ||
315 | |||
316 | return 0; | ||
317 | } | ||
318 | |||
319 | static int otm8009a_enable(struct drm_panel *panel) | ||
320 | { | ||
321 | struct otm8009a *ctx = panel_to_otm8009a(panel); | ||
322 | |||
323 | ctx->enabled = true; | ||
324 | |||
325 | return 0; | ||
326 | } | ||
327 | |||
328 | static int otm8009a_get_modes(struct drm_panel *panel) | ||
329 | { | ||
330 | struct drm_display_mode *mode; | ||
331 | |||
332 | mode = drm_mode_duplicate(panel->drm, &default_mode); | ||
333 | if (!mode) { | ||
334 | DRM_ERROR("failed to add mode %ux%ux@%u\n", | ||
335 | default_mode.hdisplay, default_mode.vdisplay, | ||
336 | default_mode.vrefresh); | ||
337 | return -ENOMEM; | ||
338 | } | ||
339 | |||
340 | drm_mode_set_name(mode); | ||
341 | |||
342 | mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED; | ||
343 | drm_mode_probed_add(panel->connector, mode); | ||
344 | |||
345 | panel->connector->display_info.width_mm = mode->width_mm; | ||
346 | panel->connector->display_info.height_mm = mode->height_mm; | ||
347 | |||
348 | return 1; | ||
349 | } | ||
350 | |||
351 | static const struct drm_panel_funcs otm8009a_drm_funcs = { | ||
352 | .disable = otm8009a_disable, | ||
353 | .unprepare = otm8009a_unprepare, | ||
354 | .prepare = otm8009a_prepare, | ||
355 | .enable = otm8009a_enable, | ||
356 | .get_modes = otm8009a_get_modes, | ||
357 | }; | ||
358 | |||
359 | /* | ||
360 | * DSI-BASED BACKLIGHT | ||
361 | */ | ||
362 | |||
363 | static int otm8009a_backlight_update_status(struct backlight_device *bd) | ||
364 | { | ||
365 | struct otm8009a *ctx = bl_get_data(bd); | ||
366 | u8 data[2]; | ||
367 | |||
368 | if (!ctx->prepared) { | ||
369 | DRM_DEBUG("lcd not ready yet for setting its backlight!\n"); | ||
370 | return -ENXIO; | ||
371 | } | ||
372 | |||
373 | if (bd->props.power <= FB_BLANK_NORMAL) { | ||
374 | /* Power on the backlight with the requested brightness | ||
375 | * Note We can not use mipi_dsi_dcs_set_display_brightness() | ||
376 | * as otm8009a driver support only 8-bit brightness (1 param). | ||
377 | */ | ||
378 | data[0] = MIPI_DCS_SET_DISPLAY_BRIGHTNESS; | ||
379 | data[1] = bd->props.brightness; | ||
380 | otm8009a_dcs_write_buf(ctx, data, ARRAY_SIZE(data)); | ||
381 | |||
382 | /* set Brightness Control & Backlight on */ | ||
383 | data[1] = 0x24; | ||
384 | |||
385 | } else { | ||
386 | /* Power off the backlight: set Brightness Control & Bl off */ | ||
387 | data[1] = 0; | ||
388 | } | ||
389 | |||
390 | /* Update Brightness Control & Backlight */ | ||
391 | data[0] = MIPI_DCS_WRITE_CONTROL_DISPLAY; | ||
392 | otm8009a_dcs_write_buf(ctx, data, ARRAY_SIZE(data)); | ||
393 | |||
394 | return 0; | ||
395 | } | ||
396 | |||
397 | static const struct backlight_ops otm8009a_backlight_ops = { | ||
398 | .update_status = otm8009a_backlight_update_status, | ||
399 | }; | ||
400 | |||
401 | static int otm8009a_probe(struct mipi_dsi_device *dsi) | ||
402 | { | ||
403 | struct device *dev = &dsi->dev; | ||
404 | struct otm8009a *ctx; | ||
405 | int ret; | ||
406 | |||
407 | ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL); | ||
408 | if (!ctx) | ||
409 | return -ENOMEM; | ||
410 | |||
411 | ctx->reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW); | ||
412 | if (IS_ERR(ctx->reset_gpio)) { | ||
413 | dev_err(dev, "cannot get reset-gpio\n"); | ||
414 | return PTR_ERR(ctx->reset_gpio); | ||
415 | } | ||
416 | |||
417 | mipi_dsi_set_drvdata(dsi, ctx); | ||
418 | |||
419 | ctx->dev = dev; | ||
420 | |||
421 | dsi->lanes = 2; | ||
422 | dsi->format = MIPI_DSI_FMT_RGB888; | ||
423 | dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST | | ||
424 | MIPI_DSI_MODE_LPM; | ||
425 | |||
426 | drm_panel_init(&ctx->panel); | ||
427 | ctx->panel.dev = dev; | ||
428 | ctx->panel.funcs = &otm8009a_drm_funcs; | ||
429 | |||
430 | ctx->bl_dev = backlight_device_register(DRV_NAME "_backlight", dev, ctx, | ||
431 | &otm8009a_backlight_ops, NULL); | ||
432 | if (IS_ERR(ctx->bl_dev)) { | ||
433 | dev_err(dev, "failed to register backlight device\n"); | ||
434 | return PTR_ERR(ctx->bl_dev); | ||
435 | } | ||
436 | |||
437 | ctx->bl_dev->props.max_brightness = OTM8009A_BACKLIGHT_MAX; | ||
438 | ctx->bl_dev->props.brightness = OTM8009A_BACKLIGHT_DEFAULT; | ||
439 | ctx->bl_dev->props.power = FB_BLANK_POWERDOWN; | ||
440 | ctx->bl_dev->props.type = BACKLIGHT_RAW; | ||
441 | |||
442 | drm_panel_add(&ctx->panel); | ||
443 | |||
444 | ret = mipi_dsi_attach(dsi); | ||
445 | if (ret < 0) { | ||
446 | dev_err(dev, "mipi_dsi_attach failed. Is host ready?\n"); | ||
447 | drm_panel_remove(&ctx->panel); | ||
448 | backlight_device_unregister(ctx->bl_dev); | ||
449 | return ret; | ||
450 | } | ||
451 | |||
452 | DRM_INFO(DRV_NAME "_panel %ux%u@%u %ubpp dsi %udl - ready\n", | ||
453 | default_mode.hdisplay, default_mode.vdisplay, | ||
454 | default_mode.vrefresh, | ||
455 | mipi_dsi_pixel_format_to_bpp(dsi->format), dsi->lanes); | ||
456 | |||
457 | return 0; | ||
458 | } | ||
459 | |||
460 | static int otm8009a_remove(struct mipi_dsi_device *dsi) | ||
461 | { | ||
462 | struct otm8009a *ctx = mipi_dsi_get_drvdata(dsi); | ||
463 | |||
464 | mipi_dsi_detach(dsi); | ||
465 | drm_panel_remove(&ctx->panel); | ||
466 | |||
467 | backlight_device_unregister(ctx->bl_dev); | ||
468 | |||
469 | return 0; | ||
470 | } | ||
471 | |||
472 | static const struct of_device_id orisetech_otm8009a_of_match[] = { | ||
473 | { .compatible = "orisetech,otm8009a" }, | ||
474 | { } | ||
475 | }; | ||
476 | MODULE_DEVICE_TABLE(of, orisetech_otm8009a_of_match); | ||
477 | |||
478 | static struct mipi_dsi_driver orisetech_otm8009a_driver = { | ||
479 | .probe = otm8009a_probe, | ||
480 | .remove = otm8009a_remove, | ||
481 | .driver = { | ||
482 | .name = DRV_NAME "_panel", | ||
483 | .of_match_table = orisetech_otm8009a_of_match, | ||
484 | }, | ||
485 | }; | ||
486 | module_mipi_dsi_driver(orisetech_otm8009a_driver); | ||
487 | |||
488 | MODULE_AUTHOR("Philippe Cornu <philippe.cornu@st.com>"); | ||
489 | MODULE_AUTHOR("Yannick Fertre <yannick.fertre@st.com>"); | ||
490 | MODULE_DESCRIPTION("DRM driver for Orise Tech OTM8009A MIPI DSI panel"); | ||
491 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/drivers/gpu/drm/panel/panel-samsung-s6e63j0x03.c b/drivers/gpu/drm/panel/panel-samsung-s6e63j0x03.c new file mode 100644 index 000000000000..aeb32aa58899 --- /dev/null +++ b/drivers/gpu/drm/panel/panel-samsung-s6e63j0x03.c | |||
@@ -0,0 +1,532 @@ | |||
1 | /* | ||
2 | * MIPI-DSI based S6E63J0X03 AMOLED lcd 1.63 inch panel driver. | ||
3 | * | ||
4 | * Copyright (c) 2014-2017 Samsung Electronics Co., Ltd | ||
5 | * | ||
6 | * Inki Dae <inki.dae@samsung.com> | ||
7 | * Hoegeun Kwon <hoegeun.kwon@samsung.com> | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or modify | ||
10 | * it under the terms of the GNU General Public License version 2 as | ||
11 | * published by the Free Software Foundation. | ||
12 | */ | ||
13 | |||
14 | #include <drm/drmP.h> | ||
15 | #include <drm/drm_mipi_dsi.h> | ||
16 | #include <drm/drm_panel.h> | ||
17 | #include <linux/backlight.h> | ||
18 | #include <linux/gpio/consumer.h> | ||
19 | #include <linux/regulator/consumer.h> | ||
20 | #include <video/mipi_display.h> | ||
21 | |||
22 | #define MCS_LEVEL2_KEY 0xf0 | ||
23 | #define MCS_MTP_KEY 0xf1 | ||
24 | #define MCS_MTP_SET3 0xd4 | ||
25 | |||
26 | #define MAX_BRIGHTNESS 100 | ||
27 | #define DEFAULT_BRIGHTNESS 80 | ||
28 | |||
29 | #define NUM_GAMMA_STEPS 9 | ||
30 | #define GAMMA_CMD_CNT 28 | ||
31 | |||
32 | #define FIRST_COLUMN 20 | ||
33 | |||
34 | struct s6e63j0x03 { | ||
35 | struct device *dev; | ||
36 | struct drm_panel panel; | ||
37 | struct backlight_device *bl_dev; | ||
38 | |||
39 | struct regulator_bulk_data supplies[2]; | ||
40 | struct gpio_desc *reset_gpio; | ||
41 | }; | ||
42 | |||
43 | static const struct drm_display_mode default_mode = { | ||
44 | .clock = 4649, | ||
45 | .hdisplay = 320, | ||
46 | .hsync_start = 320 + 1, | ||
47 | .hsync_end = 320 + 1 + 1, | ||
48 | .htotal = 320 + 1 + 1 + 1, | ||
49 | .vdisplay = 320, | ||
50 | .vsync_start = 320 + 150, | ||
51 | .vsync_end = 320 + 150 + 1, | ||
52 | .vtotal = 320 + 150 + 1 + 2, | ||
53 | .vrefresh = 30, | ||
54 | .flags = 0, | ||
55 | }; | ||
56 | |||
57 | static const unsigned char gamma_tbl[NUM_GAMMA_STEPS][GAMMA_CMD_CNT] = { | ||
58 | { /* Gamma 10 */ | ||
59 | MCS_MTP_SET3, | ||
60 | 0x00, 0x00, 0x00, 0x7f, 0x7f, 0x7f, 0x52, 0x6b, 0x6f, 0x26, | ||
61 | 0x28, 0x2d, 0x28, 0x26, 0x27, 0x33, 0x34, 0x32, 0x36, 0x36, | ||
62 | 0x35, 0x00, 0xab, 0x00, 0xae, 0x00, 0xbf | ||
63 | }, | ||
64 | { /* gamma 30 */ | ||
65 | MCS_MTP_SET3, | ||
66 | 0x00, 0x00, 0x00, 0x70, 0x7f, 0x7f, 0x4e, 0x64, 0x69, 0x26, | ||
67 | 0x27, 0x2a, 0x28, 0x29, 0x27, 0x31, 0x32, 0x31, 0x35, 0x34, | ||
68 | 0x35, 0x00, 0xc4, 0x00, 0xca, 0x00, 0xdc | ||
69 | }, | ||
70 | { /* gamma 60 */ | ||
71 | MCS_MTP_SET3, | ||
72 | 0x00, 0x00, 0x00, 0x65, 0x7b, 0x7d, 0x5f, 0x67, 0x68, 0x2a, | ||
73 | 0x28, 0x29, 0x28, 0x2a, 0x27, 0x31, 0x2f, 0x30, 0x34, 0x33, | ||
74 | 0x34, 0x00, 0xd9, 0x00, 0xe4, 0x00, 0xf5 | ||
75 | }, | ||
76 | { /* gamma 90 */ | ||
77 | MCS_MTP_SET3, | ||
78 | 0x00, 0x00, 0x00, 0x4d, 0x6f, 0x71, 0x67, 0x6a, 0x6c, 0x29, | ||
79 | 0x28, 0x28, 0x28, 0x29, 0x27, 0x30, 0x2e, 0x30, 0x32, 0x31, | ||
80 | 0x31, 0x00, 0xea, 0x00, 0xf6, 0x01, 0x09 | ||
81 | }, | ||
82 | { /* gamma 120 */ | ||
83 | MCS_MTP_SET3, | ||
84 | 0x00, 0x00, 0x00, 0x3d, 0x66, 0x68, 0x69, 0x69, 0x69, 0x28, | ||
85 | 0x28, 0x27, 0x28, 0x28, 0x27, 0x30, 0x2e, 0x2f, 0x31, 0x31, | ||
86 | 0x30, 0x00, 0xf9, 0x01, 0x05, 0x01, 0x1b | ||
87 | }, | ||
88 | { /* gamma 150 */ | ||
89 | MCS_MTP_SET3, | ||
90 | 0x00, 0x00, 0x00, 0x31, 0x51, 0x53, 0x66, 0x66, 0x67, 0x28, | ||
91 | 0x29, 0x27, 0x28, 0x27, 0x27, 0x2e, 0x2d, 0x2e, 0x31, 0x31, | ||
92 | 0x30, 0x01, 0x04, 0x01, 0x11, 0x01, 0x29 | ||
93 | }, | ||
94 | { /* gamma 200 */ | ||
95 | MCS_MTP_SET3, | ||
96 | 0x00, 0x00, 0x00, 0x2f, 0x4f, 0x51, 0x67, 0x65, 0x65, 0x29, | ||
97 | 0x2a, 0x28, 0x27, 0x25, 0x26, 0x2d, 0x2c, 0x2c, 0x30, 0x30, | ||
98 | 0x30, 0x01, 0x14, 0x01, 0x23, 0x01, 0x3b | ||
99 | }, | ||
100 | { /* gamma 240 */ | ||
101 | MCS_MTP_SET3, | ||
102 | 0x00, 0x00, 0x00, 0x2c, 0x4d, 0x50, 0x65, 0x63, 0x64, 0x2a, | ||
103 | 0x2c, 0x29, 0x26, 0x24, 0x25, 0x2c, 0x2b, 0x2b, 0x30, 0x30, | ||
104 | 0x30, 0x01, 0x1e, 0x01, 0x2f, 0x01, 0x47 | ||
105 | }, | ||
106 | { /* gamma 300 */ | ||
107 | MCS_MTP_SET3, | ||
108 | 0x00, 0x00, 0x00, 0x38, 0x61, 0x64, 0x65, 0x63, 0x64, 0x28, | ||
109 | 0x2a, 0x27, 0x26, 0x23, 0x25, 0x2b, 0x2b, 0x2a, 0x30, 0x2f, | ||
110 | 0x30, 0x01, 0x2d, 0x01, 0x3f, 0x01, 0x57 | ||
111 | } | ||
112 | }; | ||
113 | |||
114 | static inline struct s6e63j0x03 *panel_to_s6e63j0x03(struct drm_panel *panel) | ||
115 | { | ||
116 | return container_of(panel, struct s6e63j0x03, panel); | ||
117 | } | ||
118 | |||
119 | static inline ssize_t s6e63j0x03_dcs_write_seq(struct s6e63j0x03 *ctx, | ||
120 | const void *seq, size_t len) | ||
121 | { | ||
122 | struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev); | ||
123 | |||
124 | return mipi_dsi_dcs_write_buffer(dsi, seq, len); | ||
125 | } | ||
126 | |||
127 | #define s6e63j0x03_dcs_write_seq_static(ctx, seq...) \ | ||
128 | ({ \ | ||
129 | static const u8 d[] = { seq }; \ | ||
130 | s6e63j0x03_dcs_write_seq(ctx, d, ARRAY_SIZE(d)); \ | ||
131 | }) | ||
132 | |||
133 | static inline int s6e63j0x03_enable_lv2_command(struct s6e63j0x03 *ctx) | ||
134 | { | ||
135 | return s6e63j0x03_dcs_write_seq_static(ctx, MCS_LEVEL2_KEY, 0x5a, 0x5a); | ||
136 | } | ||
137 | |||
138 | static inline int s6e63j0x03_apply_mtp_key(struct s6e63j0x03 *ctx, bool on) | ||
139 | { | ||
140 | if (on) | ||
141 | return s6e63j0x03_dcs_write_seq_static(ctx, | ||
142 | MCS_MTP_KEY, 0x5a, 0x5a); | ||
143 | |||
144 | return s6e63j0x03_dcs_write_seq_static(ctx, MCS_MTP_KEY, 0xa5, 0xa5); | ||
145 | } | ||
146 | |||
147 | static int s6e63j0x03_power_on(struct s6e63j0x03 *ctx) | ||
148 | { | ||
149 | int ret; | ||
150 | |||
151 | ret = regulator_bulk_enable(ARRAY_SIZE(ctx->supplies), ctx->supplies); | ||
152 | if (ret < 0) | ||
153 | return ret; | ||
154 | |||
155 | msleep(30); | ||
156 | |||
157 | gpiod_set_value(ctx->reset_gpio, 1); | ||
158 | usleep_range(1000, 2000); | ||
159 | gpiod_set_value(ctx->reset_gpio, 0); | ||
160 | usleep_range(5000, 6000); | ||
161 | |||
162 | return 0; | ||
163 | } | ||
164 | |||
165 | static int s6e63j0x03_power_off(struct s6e63j0x03 *ctx) | ||
166 | { | ||
167 | return regulator_bulk_disable(ARRAY_SIZE(ctx->supplies), ctx->supplies); | ||
168 | } | ||
169 | |||
170 | static unsigned int s6e63j0x03_get_brightness_index(unsigned int brightness) | ||
171 | { | ||
172 | unsigned int index; | ||
173 | |||
174 | index = brightness / (MAX_BRIGHTNESS / NUM_GAMMA_STEPS); | ||
175 | |||
176 | if (index >= NUM_GAMMA_STEPS) | ||
177 | index = NUM_GAMMA_STEPS - 1; | ||
178 | |||
179 | return index; | ||
180 | } | ||
181 | |||
182 | static int s6e63j0x03_update_gamma(struct s6e63j0x03 *ctx, | ||
183 | unsigned int brightness) | ||
184 | { | ||
185 | struct backlight_device *bl_dev = ctx->bl_dev; | ||
186 | unsigned int index = s6e63j0x03_get_brightness_index(brightness); | ||
187 | int ret; | ||
188 | |||
189 | ret = s6e63j0x03_apply_mtp_key(ctx, true); | ||
190 | if (ret < 0) | ||
191 | return ret; | ||
192 | |||
193 | ret = s6e63j0x03_dcs_write_seq(ctx, gamma_tbl[index], GAMMA_CMD_CNT); | ||
194 | if (ret < 0) | ||
195 | return ret; | ||
196 | |||
197 | ret = s6e63j0x03_apply_mtp_key(ctx, false); | ||
198 | if (ret < 0) | ||
199 | return ret; | ||
200 | |||
201 | bl_dev->props.brightness = brightness; | ||
202 | |||
203 | return 0; | ||
204 | } | ||
205 | |||
206 | static int s6e63j0x03_set_brightness(struct backlight_device *bl_dev) | ||
207 | { | ||
208 | struct s6e63j0x03 *ctx = bl_get_data(bl_dev); | ||
209 | unsigned int brightness = bl_dev->props.brightness; | ||
210 | |||
211 | return s6e63j0x03_update_gamma(ctx, brightness); | ||
212 | } | ||
213 | |||
214 | static const struct backlight_ops s6e63j0x03_bl_ops = { | ||
215 | .update_status = s6e63j0x03_set_brightness, | ||
216 | }; | ||
217 | |||
218 | static int s6e63j0x03_disable(struct drm_panel *panel) | ||
219 | { | ||
220 | struct s6e63j0x03 *ctx = panel_to_s6e63j0x03(panel); | ||
221 | struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev); | ||
222 | int ret; | ||
223 | |||
224 | ret = mipi_dsi_dcs_set_display_off(dsi); | ||
225 | if (ret < 0) | ||
226 | return ret; | ||
227 | |||
228 | ctx->bl_dev->props.power = FB_BLANK_NORMAL; | ||
229 | |||
230 | ret = mipi_dsi_dcs_enter_sleep_mode(dsi); | ||
231 | if (ret < 0) | ||
232 | return ret; | ||
233 | |||
234 | msleep(120); | ||
235 | |||
236 | return 0; | ||
237 | } | ||
238 | |||
239 | static int s6e63j0x03_unprepare(struct drm_panel *panel) | ||
240 | { | ||
241 | struct s6e63j0x03 *ctx = panel_to_s6e63j0x03(panel); | ||
242 | int ret; | ||
243 | |||
244 | ret = s6e63j0x03_power_off(ctx); | ||
245 | if (ret < 0) | ||
246 | return ret; | ||
247 | |||
248 | ctx->bl_dev->props.power = FB_BLANK_POWERDOWN; | ||
249 | |||
250 | return 0; | ||
251 | } | ||
252 | |||
253 | static int s6e63j0x03_panel_init(struct s6e63j0x03 *ctx) | ||
254 | { | ||
255 | struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev); | ||
256 | int ret; | ||
257 | |||
258 | ret = s6e63j0x03_enable_lv2_command(ctx); | ||
259 | if (ret < 0) | ||
260 | return ret; | ||
261 | |||
262 | ret = s6e63j0x03_apply_mtp_key(ctx, true); | ||
263 | if (ret < 0) | ||
264 | return ret; | ||
265 | |||
266 | /* set porch adjustment */ | ||
267 | ret = s6e63j0x03_dcs_write_seq_static(ctx, 0xf2, 0x1c, 0x28); | ||
268 | if (ret < 0) | ||
269 | return ret; | ||
270 | |||
271 | /* set frame freq */ | ||
272 | ret = s6e63j0x03_dcs_write_seq_static(ctx, 0xb5, 0x00, 0x02, 0x00); | ||
273 | if (ret < 0) | ||
274 | return ret; | ||
275 | |||
276 | /* set caset, paset */ | ||
277 | ret = mipi_dsi_dcs_set_column_address(dsi, FIRST_COLUMN, | ||
278 | default_mode.hdisplay - 1 + FIRST_COLUMN); | ||
279 | if (ret < 0) | ||
280 | return ret; | ||
281 | |||
282 | ret = mipi_dsi_dcs_set_page_address(dsi, 0, default_mode.vdisplay - 1); | ||
283 | if (ret < 0) | ||
284 | return ret; | ||
285 | |||
286 | /* set ltps timming 0, 1 */ | ||
287 | ret = s6e63j0x03_dcs_write_seq_static(ctx, 0xf8, 0x08, 0x08, 0x08, 0x17, | ||
288 | 0x00, 0x2a, 0x02, 0x26, 0x00, 0x00, 0x02, 0x00, 0x00); | ||
289 | if (ret < 0) | ||
290 | return ret; | ||
291 | |||
292 | ret = s6e63j0x03_dcs_write_seq_static(ctx, 0xf7, 0x02); | ||
293 | if (ret < 0) | ||
294 | return ret; | ||
295 | |||
296 | /* set param pos te_edge */ | ||
297 | ret = s6e63j0x03_dcs_write_seq_static(ctx, 0xb0, 0x01); | ||
298 | if (ret < 0) | ||
299 | return ret; | ||
300 | |||
301 | /* set te rising edge */ | ||
302 | ret = s6e63j0x03_dcs_write_seq_static(ctx, 0xe2, 0x0f); | ||
303 | if (ret < 0) | ||
304 | return ret; | ||
305 | |||
306 | /* set param pos default */ | ||
307 | ret = s6e63j0x03_dcs_write_seq_static(ctx, 0xb0, 0x00); | ||
308 | if (ret < 0) | ||
309 | return ret; | ||
310 | |||
311 | ret = mipi_dsi_dcs_exit_sleep_mode(dsi); | ||
312 | if (ret < 0) | ||
313 | return ret; | ||
314 | |||
315 | ret = s6e63j0x03_apply_mtp_key(ctx, false); | ||
316 | if (ret < 0) | ||
317 | return ret; | ||
318 | |||
319 | return 0; | ||
320 | } | ||
321 | |||
322 | static int s6e63j0x03_prepare(struct drm_panel *panel) | ||
323 | { | ||
324 | struct s6e63j0x03 *ctx = panel_to_s6e63j0x03(panel); | ||
325 | int ret; | ||
326 | |||
327 | ret = s6e63j0x03_power_on(ctx); | ||
328 | if (ret < 0) | ||
329 | return ret; | ||
330 | |||
331 | ret = s6e63j0x03_panel_init(ctx); | ||
332 | if (ret < 0) | ||
333 | goto err; | ||
334 | |||
335 | ctx->bl_dev->props.power = FB_BLANK_NORMAL; | ||
336 | |||
337 | return 0; | ||
338 | |||
339 | err: | ||
340 | s6e63j0x03_power_off(ctx); | ||
341 | return ret; | ||
342 | } | ||
343 | |||
344 | static int s6e63j0x03_enable(struct drm_panel *panel) | ||
345 | { | ||
346 | struct s6e63j0x03 *ctx = panel_to_s6e63j0x03(panel); | ||
347 | struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev); | ||
348 | int ret; | ||
349 | |||
350 | msleep(120); | ||
351 | |||
352 | ret = s6e63j0x03_apply_mtp_key(ctx, true); | ||
353 | if (ret < 0) | ||
354 | return ret; | ||
355 | |||
356 | /* set elvss_cond */ | ||
357 | ret = s6e63j0x03_dcs_write_seq_static(ctx, 0xb1, 0x00, 0x09); | ||
358 | if (ret < 0) | ||
359 | return ret; | ||
360 | |||
361 | /* set pos */ | ||
362 | ret = s6e63j0x03_dcs_write_seq_static(ctx, | ||
363 | MIPI_DCS_SET_ADDRESS_MODE, 0x40); | ||
364 | if (ret < 0) | ||
365 | return ret; | ||
366 | |||
367 | /* set default white brightness */ | ||
368 | ret = mipi_dsi_dcs_set_display_brightness(dsi, 0x00ff); | ||
369 | if (ret < 0) | ||
370 | return ret; | ||
371 | |||
372 | /* set white ctrl */ | ||
373 | ret = s6e63j0x03_dcs_write_seq_static(ctx, | ||
374 | MIPI_DCS_WRITE_CONTROL_DISPLAY, 0x20); | ||
375 | if (ret < 0) | ||
376 | return ret; | ||
377 | |||
378 | /* set acl off */ | ||
379 | ret = s6e63j0x03_dcs_write_seq_static(ctx, | ||
380 | MIPI_DCS_WRITE_POWER_SAVE, 0x00); | ||
381 | if (ret < 0) | ||
382 | return ret; | ||
383 | |||
384 | ret = mipi_dsi_dcs_set_tear_on(dsi, MIPI_DSI_DCS_TEAR_MODE_VBLANK); | ||
385 | if (ret < 0) | ||
386 | return ret; | ||
387 | |||
388 | ret = s6e63j0x03_apply_mtp_key(ctx, false); | ||
389 | if (ret < 0) | ||
390 | return ret; | ||
391 | |||
392 | ret = mipi_dsi_dcs_set_display_on(dsi); | ||
393 | if (ret < 0) | ||
394 | return ret; | ||
395 | |||
396 | ctx->bl_dev->props.power = FB_BLANK_UNBLANK; | ||
397 | |||
398 | return 0; | ||
399 | } | ||
400 | |||
401 | static int s6e63j0x03_get_modes(struct drm_panel *panel) | ||
402 | { | ||
403 | struct drm_connector *connector = panel->connector; | ||
404 | struct drm_display_mode *mode; | ||
405 | |||
406 | mode = drm_mode_duplicate(panel->drm, &default_mode); | ||
407 | if (!mode) { | ||
408 | DRM_ERROR("failed to add mode %ux%ux@%u\n", | ||
409 | default_mode.hdisplay, default_mode.vdisplay, | ||
410 | default_mode.vrefresh); | ||
411 | return -ENOMEM; | ||
412 | } | ||
413 | |||
414 | drm_mode_set_name(mode); | ||
415 | |||
416 | mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED; | ||
417 | drm_mode_probed_add(connector, mode); | ||
418 | |||
419 | connector->display_info.width_mm = 29; | ||
420 | connector->display_info.height_mm = 29; | ||
421 | |||
422 | return 1; | ||
423 | } | ||
424 | |||
425 | static const struct drm_panel_funcs s6e63j0x03_funcs = { | ||
426 | .disable = s6e63j0x03_disable, | ||
427 | .unprepare = s6e63j0x03_unprepare, | ||
428 | .prepare = s6e63j0x03_prepare, | ||
429 | .enable = s6e63j0x03_enable, | ||
430 | .get_modes = s6e63j0x03_get_modes, | ||
431 | }; | ||
432 | |||
433 | static int s6e63j0x03_probe(struct mipi_dsi_device *dsi) | ||
434 | { | ||
435 | struct device *dev = &dsi->dev; | ||
436 | struct s6e63j0x03 *ctx; | ||
437 | int ret; | ||
438 | |||
439 | ctx = devm_kzalloc(dev, sizeof(struct s6e63j0x03), GFP_KERNEL); | ||
440 | if (!ctx) | ||
441 | return -ENOMEM; | ||
442 | |||
443 | mipi_dsi_set_drvdata(dsi, ctx); | ||
444 | |||
445 | ctx->dev = dev; | ||
446 | |||
447 | dsi->lanes = 1; | ||
448 | dsi->format = MIPI_DSI_FMT_RGB888; | ||
449 | dsi->mode_flags = MIPI_DSI_MODE_EOT_PACKET; | ||
450 | |||
451 | ctx->supplies[0].supply = "vdd3"; | ||
452 | ctx->supplies[1].supply = "vci"; | ||
453 | ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(ctx->supplies), | ||
454 | ctx->supplies); | ||
455 | if (ret < 0) { | ||
456 | dev_err(dev, "failed to get regulators: %d\n", ret); | ||
457 | return ret; | ||
458 | } | ||
459 | |||
460 | ctx->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW); | ||
461 | if (IS_ERR(ctx->reset_gpio)) { | ||
462 | dev_err(dev, "cannot get reset-gpio: %ld\n", | ||
463 | PTR_ERR(ctx->reset_gpio)); | ||
464 | return PTR_ERR(ctx->reset_gpio); | ||
465 | } | ||
466 | |||
467 | drm_panel_init(&ctx->panel); | ||
468 | ctx->panel.dev = dev; | ||
469 | ctx->panel.funcs = &s6e63j0x03_funcs; | ||
470 | |||
471 | ctx->bl_dev = backlight_device_register("s6e63j0x03", dev, ctx, | ||
472 | &s6e63j0x03_bl_ops, NULL); | ||
473 | if (IS_ERR(ctx->bl_dev)) { | ||
474 | dev_err(dev, "failed to register backlight device\n"); | ||
475 | return PTR_ERR(ctx->bl_dev); | ||
476 | } | ||
477 | |||
478 | ctx->bl_dev->props.max_brightness = MAX_BRIGHTNESS; | ||
479 | ctx->bl_dev->props.brightness = DEFAULT_BRIGHTNESS; | ||
480 | ctx->bl_dev->props.power = FB_BLANK_POWERDOWN; | ||
481 | |||
482 | ret = drm_panel_add(&ctx->panel); | ||
483 | if (ret < 0) | ||
484 | goto unregister_backlight; | ||
485 | |||
486 | ret = mipi_dsi_attach(dsi); | ||
487 | if (ret < 0) | ||
488 | goto remove_panel; | ||
489 | |||
490 | return ret; | ||
491 | |||
492 | remove_panel: | ||
493 | drm_panel_remove(&ctx->panel); | ||
494 | |||
495 | unregister_backlight: | ||
496 | backlight_device_unregister(ctx->bl_dev); | ||
497 | |||
498 | return ret; | ||
499 | } | ||
500 | |||
501 | static int s6e63j0x03_remove(struct mipi_dsi_device *dsi) | ||
502 | { | ||
503 | struct s6e63j0x03 *ctx = mipi_dsi_get_drvdata(dsi); | ||
504 | |||
505 | mipi_dsi_detach(dsi); | ||
506 | drm_panel_remove(&ctx->panel); | ||
507 | |||
508 | backlight_device_unregister(ctx->bl_dev); | ||
509 | |||
510 | return 0; | ||
511 | } | ||
512 | |||
513 | static const struct of_device_id s6e63j0x03_of_match[] = { | ||
514 | { .compatible = "samsung,s6e63j0x03" }, | ||
515 | { } | ||
516 | }; | ||
517 | MODULE_DEVICE_TABLE(of, s6e63j0x03_of_match); | ||
518 | |||
519 | static struct mipi_dsi_driver s6e63j0x03_driver = { | ||
520 | .probe = s6e63j0x03_probe, | ||
521 | .remove = s6e63j0x03_remove, | ||
522 | .driver = { | ||
523 | .name = "panel_samsung_s6e63j0x03", | ||
524 | .of_match_table = s6e63j0x03_of_match, | ||
525 | }, | ||
526 | }; | ||
527 | module_mipi_dsi_driver(s6e63j0x03_driver); | ||
528 | |||
529 | MODULE_AUTHOR("Inki Dae <inki.dae@samsung.com>"); | ||
530 | MODULE_AUTHOR("Hoegeun Kwon <hoegeun.kwon@samsung.com>"); | ||
531 | MODULE_DESCRIPTION("MIPI-DSI based s6e63j0x03 AMOLED LCD Panel Driver"); | ||
532 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/drivers/gpu/drm/panel/panel-seiko-43wvf1g.c b/drivers/gpu/drm/panel/panel-seiko-43wvf1g.c new file mode 100644 index 000000000000..71c09ed436ae --- /dev/null +++ b/drivers/gpu/drm/panel/panel-seiko-43wvf1g.c | |||
@@ -0,0 +1,372 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2017 NXP Semiconductors. | ||
3 | * Author: Marco Franchi <marco.franchi@nxp.com> | ||
4 | * | ||
5 | * Based on Panel Simple driver by Thierry Reding <treding@nvidia.com> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or | ||
8 | * modify it under the terms of the GNU General Public License version | ||
9 | * 2 as published by the Free Software Foundation. | ||
10 | */ | ||
11 | |||
12 | #include <linux/backlight.h> | ||
13 | #include <linux/module.h> | ||
14 | #include <linux/of.h> | ||
15 | #include <linux/regulator/consumer.h> | ||
16 | |||
17 | #include <drm/drmP.h> | ||
18 | #include <drm/drm_crtc.h> | ||
19 | #include <drm/drm_panel.h> | ||
20 | |||
21 | #include <video/display_timing.h> | ||
22 | #include <video/videomode.h> | ||
23 | |||
24 | struct seiko_panel_desc { | ||
25 | const struct drm_display_mode *modes; | ||
26 | unsigned int num_modes; | ||
27 | const struct display_timing *timings; | ||
28 | unsigned int num_timings; | ||
29 | |||
30 | unsigned int bpc; | ||
31 | |||
32 | /** | ||
33 | * @width: width (in millimeters) of the panel's active display area | ||
34 | * @height: height (in millimeters) of the panel's active display area | ||
35 | */ | ||
36 | struct { | ||
37 | unsigned int width; | ||
38 | unsigned int height; | ||
39 | } size; | ||
40 | |||
41 | u32 bus_format; | ||
42 | u32 bus_flags; | ||
43 | }; | ||
44 | |||
45 | struct seiko_panel { | ||
46 | struct drm_panel base; | ||
47 | bool prepared; | ||
48 | bool enabled; | ||
49 | const struct seiko_panel_desc *desc; | ||
50 | struct backlight_device *backlight; | ||
51 | struct regulator *dvdd; | ||
52 | struct regulator *avdd; | ||
53 | }; | ||
54 | |||
55 | static inline struct seiko_panel *to_seiko_panel(struct drm_panel *panel) | ||
56 | { | ||
57 | return container_of(panel, struct seiko_panel, base); | ||
58 | } | ||
59 | |||
60 | static int seiko_panel_get_fixed_modes(struct seiko_panel *panel) | ||
61 | { | ||
62 | struct drm_connector *connector = panel->base.connector; | ||
63 | struct drm_device *drm = panel->base.drm; | ||
64 | struct drm_display_mode *mode; | ||
65 | unsigned int i, num = 0; | ||
66 | |||
67 | if (!panel->desc) | ||
68 | return 0; | ||
69 | |||
70 | for (i = 0; i < panel->desc->num_timings; i++) { | ||
71 | const struct display_timing *dt = &panel->desc->timings[i]; | ||
72 | struct videomode vm; | ||
73 | |||
74 | videomode_from_timing(dt, &vm); | ||
75 | mode = drm_mode_create(drm); | ||
76 | if (!mode) { | ||
77 | dev_err(drm->dev, "failed to add mode %ux%u\n", | ||
78 | dt->hactive.typ, dt->vactive.typ); | ||
79 | continue; | ||
80 | } | ||
81 | |||
82 | drm_display_mode_from_videomode(&vm, mode); | ||
83 | |||
84 | mode->type |= DRM_MODE_TYPE_DRIVER; | ||
85 | |||
86 | if (panel->desc->num_timings == 1) | ||
87 | mode->type |= DRM_MODE_TYPE_PREFERRED; | ||
88 | |||
89 | drm_mode_probed_add(connector, mode); | ||
90 | num++; | ||
91 | } | ||
92 | |||
93 | for (i = 0; i < panel->desc->num_modes; i++) { | ||
94 | const struct drm_display_mode *m = &panel->desc->modes[i]; | ||
95 | |||
96 | mode = drm_mode_duplicate(drm, m); | ||
97 | if (!mode) { | ||
98 | dev_err(drm->dev, "failed to add mode %ux%u@%u\n", | ||
99 | m->hdisplay, m->vdisplay, m->vrefresh); | ||
100 | continue; | ||
101 | } | ||
102 | |||
103 | mode->type |= DRM_MODE_TYPE_DRIVER; | ||
104 | |||
105 | if (panel->desc->num_modes == 1) | ||
106 | mode->type |= DRM_MODE_TYPE_PREFERRED; | ||
107 | |||
108 | drm_mode_set_name(mode); | ||
109 | |||
110 | drm_mode_probed_add(connector, mode); | ||
111 | num++; | ||
112 | } | ||
113 | |||
114 | connector->display_info.bpc = panel->desc->bpc; | ||
115 | connector->display_info.width_mm = panel->desc->size.width; | ||
116 | connector->display_info.height_mm = panel->desc->size.height; | ||
117 | if (panel->desc->bus_format) | ||
118 | drm_display_info_set_bus_formats(&connector->display_info, | ||
119 | &panel->desc->bus_format, 1); | ||
120 | connector->display_info.bus_flags = panel->desc->bus_flags; | ||
121 | |||
122 | return num; | ||
123 | } | ||
124 | |||
125 | static int seiko_panel_disable(struct drm_panel *panel) | ||
126 | { | ||
127 | struct seiko_panel *p = to_seiko_panel(panel); | ||
128 | |||
129 | if (!p->enabled) | ||
130 | return 0; | ||
131 | |||
132 | if (p->backlight) { | ||
133 | p->backlight->props.power = FB_BLANK_POWERDOWN; | ||
134 | p->backlight->props.state |= BL_CORE_FBBLANK; | ||
135 | backlight_update_status(p->backlight); | ||
136 | } | ||
137 | |||
138 | p->enabled = false; | ||
139 | |||
140 | return 0; | ||
141 | } | ||
142 | |||
143 | static int seiko_panel_unprepare(struct drm_panel *panel) | ||
144 | { | ||
145 | struct seiko_panel *p = to_seiko_panel(panel); | ||
146 | |||
147 | if (!p->prepared) | ||
148 | return 0; | ||
149 | |||
150 | regulator_disable(p->avdd); | ||
151 | |||
152 | /* Add a 100ms delay as per the panel datasheet */ | ||
153 | msleep(100); | ||
154 | |||
155 | regulator_disable(p->dvdd); | ||
156 | |||
157 | p->prepared = false; | ||
158 | |||
159 | return 0; | ||
160 | } | ||
161 | |||
162 | static int seiko_panel_prepare(struct drm_panel *panel) | ||
163 | { | ||
164 | struct seiko_panel *p = to_seiko_panel(panel); | ||
165 | int err; | ||
166 | |||
167 | if (p->prepared) | ||
168 | return 0; | ||
169 | |||
170 | err = regulator_enable(p->dvdd); | ||
171 | if (err < 0) { | ||
172 | dev_err(panel->dev, "failed to enable dvdd: %d\n", err); | ||
173 | return err; | ||
174 | } | ||
175 | |||
176 | /* Add a 100ms delay as per the panel datasheet */ | ||
177 | msleep(100); | ||
178 | |||
179 | err = regulator_enable(p->avdd); | ||
180 | if (err < 0) { | ||
181 | dev_err(panel->dev, "failed to enable avdd: %d\n", err); | ||
182 | goto disable_dvdd; | ||
183 | } | ||
184 | |||
185 | p->prepared = true; | ||
186 | |||
187 | return 0; | ||
188 | |||
189 | disable_dvdd: | ||
190 | regulator_disable(p->dvdd); | ||
191 | return err; | ||
192 | } | ||
193 | |||
194 | static int seiko_panel_enable(struct drm_panel *panel) | ||
195 | { | ||
196 | struct seiko_panel *p = to_seiko_panel(panel); | ||
197 | |||
198 | if (p->enabled) | ||
199 | return 0; | ||
200 | |||
201 | if (p->backlight) { | ||
202 | p->backlight->props.state &= ~BL_CORE_FBBLANK; | ||
203 | p->backlight->props.power = FB_BLANK_UNBLANK; | ||
204 | backlight_update_status(p->backlight); | ||
205 | } | ||
206 | |||
207 | p->enabled = true; | ||
208 | |||
209 | return 0; | ||
210 | } | ||
211 | |||
212 | static int seiko_panel_get_modes(struct drm_panel *panel) | ||
213 | { | ||
214 | struct seiko_panel *p = to_seiko_panel(panel); | ||
215 | |||
216 | /* add hard-coded panel modes */ | ||
217 | return seiko_panel_get_fixed_modes(p); | ||
218 | } | ||
219 | |||
220 | static int seiko_panel_get_timings(struct drm_panel *panel, | ||
221 | unsigned int num_timings, | ||
222 | struct display_timing *timings) | ||
223 | { | ||
224 | struct seiko_panel *p = to_seiko_panel(panel); | ||
225 | unsigned int i; | ||
226 | |||
227 | if (p->desc->num_timings < num_timings) | ||
228 | num_timings = p->desc->num_timings; | ||
229 | |||
230 | if (timings) | ||
231 | for (i = 0; i < num_timings; i++) | ||
232 | timings[i] = p->desc->timings[i]; | ||
233 | |||
234 | return p->desc->num_timings; | ||
235 | } | ||
236 | |||
237 | static const struct drm_panel_funcs seiko_panel_funcs = { | ||
238 | .disable = seiko_panel_disable, | ||
239 | .unprepare = seiko_panel_unprepare, | ||
240 | .prepare = seiko_panel_prepare, | ||
241 | .enable = seiko_panel_enable, | ||
242 | .get_modes = seiko_panel_get_modes, | ||
243 | .get_timings = seiko_panel_get_timings, | ||
244 | }; | ||
245 | |||
246 | static int seiko_panel_probe(struct device *dev, | ||
247 | const struct seiko_panel_desc *desc) | ||
248 | { | ||
249 | struct device_node *backlight; | ||
250 | struct seiko_panel *panel; | ||
251 | int err; | ||
252 | |||
253 | panel = devm_kzalloc(dev, sizeof(*panel), GFP_KERNEL); | ||
254 | if (!panel) | ||
255 | return -ENOMEM; | ||
256 | |||
257 | panel->enabled = false; | ||
258 | panel->prepared = false; | ||
259 | panel->desc = desc; | ||
260 | |||
261 | panel->dvdd = devm_regulator_get(dev, "dvdd"); | ||
262 | if (IS_ERR(panel->dvdd)) | ||
263 | return PTR_ERR(panel->dvdd); | ||
264 | |||
265 | panel->avdd = devm_regulator_get(dev, "avdd"); | ||
266 | if (IS_ERR(panel->avdd)) | ||
267 | return PTR_ERR(panel->avdd); | ||
268 | |||
269 | backlight = of_parse_phandle(dev->of_node, "backlight", 0); | ||
270 | if (backlight) { | ||
271 | panel->backlight = of_find_backlight_by_node(backlight); | ||
272 | of_node_put(backlight); | ||
273 | |||
274 | if (!panel->backlight) | ||
275 | return -EPROBE_DEFER; | ||
276 | } | ||
277 | |||
278 | drm_panel_init(&panel->base); | ||
279 | panel->base.dev = dev; | ||
280 | panel->base.funcs = &seiko_panel_funcs; | ||
281 | |||
282 | err = drm_panel_add(&panel->base); | ||
283 | if (err < 0) | ||
284 | return err; | ||
285 | |||
286 | dev_set_drvdata(dev, panel); | ||
287 | |||
288 | return 0; | ||
289 | } | ||
290 | |||
291 | static int seiko_panel_remove(struct platform_device *pdev) | ||
292 | { | ||
293 | struct seiko_panel *panel = dev_get_drvdata(&pdev->dev); | ||
294 | |||
295 | drm_panel_detach(&panel->base); | ||
296 | drm_panel_remove(&panel->base); | ||
297 | |||
298 | seiko_panel_disable(&panel->base); | ||
299 | |||
300 | if (panel->backlight) | ||
301 | put_device(&panel->backlight->dev); | ||
302 | |||
303 | return 0; | ||
304 | } | ||
305 | |||
306 | static void seiko_panel_shutdown(struct platform_device *pdev) | ||
307 | { | ||
308 | struct seiko_panel *panel = dev_get_drvdata(&pdev->dev); | ||
309 | |||
310 | seiko_panel_disable(&panel->base); | ||
311 | } | ||
312 | |||
313 | static const struct display_timing seiko_43wvf1g_timing = { | ||
314 | .pixelclock = { 33500000, 33500000, 33500000 }, | ||
315 | .hactive = { 800, 800, 800 }, | ||
316 | .hfront_porch = { 164, 164, 164 }, | ||
317 | .hback_porch = { 89, 89, 89 }, | ||
318 | .hsync_len = { 10, 10, 10 }, | ||
319 | .vactive = { 480, 480, 480 }, | ||
320 | .vfront_porch = { 10, 10, 10 }, | ||
321 | .vback_porch = { 23, 23, 23 }, | ||
322 | .vsync_len = { 10, 10, 10 }, | ||
323 | .flags = DISPLAY_FLAGS_DE_LOW, | ||
324 | }; | ||
325 | |||
326 | static const struct seiko_panel_desc seiko_43wvf1g = { | ||
327 | .timings = &seiko_43wvf1g_timing, | ||
328 | .num_timings = 1, | ||
329 | .bpc = 8, | ||
330 | .size = { | ||
331 | .width = 93, | ||
332 | .height = 57, | ||
333 | }, | ||
334 | .bus_format = MEDIA_BUS_FMT_RGB888_1X24, | ||
335 | .bus_flags = DRM_BUS_FLAG_DE_HIGH | DRM_BUS_FLAG_PIXDATA_NEGEDGE, | ||
336 | }; | ||
337 | |||
338 | static const struct of_device_id platform_of_match[] = { | ||
339 | { | ||
340 | .compatible = "sii,43wvf1g", | ||
341 | .data = &seiko_43wvf1g, | ||
342 | }, { | ||
343 | /* sentinel */ | ||
344 | } | ||
345 | }; | ||
346 | MODULE_DEVICE_TABLE(of, platform_of_match); | ||
347 | |||
348 | static int seiko_panel_platform_probe(struct platform_device *pdev) | ||
349 | { | ||
350 | const struct of_device_id *id; | ||
351 | |||
352 | id = of_match_node(platform_of_match, pdev->dev.of_node); | ||
353 | if (!id) | ||
354 | return -ENODEV; | ||
355 | |||
356 | return seiko_panel_probe(&pdev->dev, id->data); | ||
357 | } | ||
358 | |||
359 | static struct platform_driver seiko_panel_platform_driver = { | ||
360 | .driver = { | ||
361 | .name = "seiko_panel", | ||
362 | .of_match_table = platform_of_match, | ||
363 | }, | ||
364 | .probe = seiko_panel_platform_probe, | ||
365 | .remove = seiko_panel_remove, | ||
366 | .shutdown = seiko_panel_shutdown, | ||
367 | }; | ||
368 | module_platform_driver(seiko_panel_platform_driver); | ||
369 | |||
370 | MODULE_AUTHOR("Marco Franchi <marco.franchi@nxp.com"); | ||
371 | MODULE_DESCRIPTION("Seiko 43WVF1G panel driver"); | ||
372 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/drivers/gpu/drm/panel/panel-simple.c b/drivers/gpu/drm/panel/panel-simple.c index 474fa759e06e..a3c96d2ea41c 100644 --- a/drivers/gpu/drm/panel/panel-simple.c +++ b/drivers/gpu/drm/panel/panel-simple.c | |||
@@ -187,8 +187,7 @@ static int panel_simple_unprepare(struct drm_panel *panel) | |||
187 | if (!p->prepared) | 187 | if (!p->prepared) |
188 | return 0; | 188 | return 0; |
189 | 189 | ||
190 | if (p->enable_gpio) | 190 | gpiod_set_value_cansleep(p->enable_gpio, 0); |
191 | gpiod_set_value_cansleep(p->enable_gpio, 0); | ||
192 | 191 | ||
193 | regulator_disable(p->supply); | 192 | regulator_disable(p->supply); |
194 | 193 | ||
@@ -214,8 +213,7 @@ static int panel_simple_prepare(struct drm_panel *panel) | |||
214 | return err; | 213 | return err; |
215 | } | 214 | } |
216 | 215 | ||
217 | if (p->enable_gpio) | 216 | gpiod_set_value_cansleep(p->enable_gpio, 1); |
218 | gpiod_set_value_cansleep(p->enable_gpio, 1); | ||
219 | 217 | ||
220 | if (p->desc->delay.prepare) | 218 | if (p->desc->delay.prepare) |
221 | msleep(p->desc->delay.prepare); | 219 | msleep(p->desc->delay.prepare); |
@@ -315,7 +313,8 @@ static int panel_simple_probe(struct device *dev, const struct panel_desc *desc) | |||
315 | GPIOD_OUT_LOW); | 313 | GPIOD_OUT_LOW); |
316 | if (IS_ERR(panel->enable_gpio)) { | 314 | if (IS_ERR(panel->enable_gpio)) { |
317 | err = PTR_ERR(panel->enable_gpio); | 315 | err = PTR_ERR(panel->enable_gpio); |
318 | dev_err(dev, "failed to request GPIO: %d\n", err); | 316 | if (err != -EPROBE_DEFER) |
317 | dev_err(dev, "failed to request GPIO: %d\n", err); | ||
319 | return err; | 318 | return err; |
320 | } | 319 | } |
321 | 320 | ||
@@ -369,6 +368,7 @@ static int panel_simple_remove(struct device *dev) | |||
369 | drm_panel_remove(&panel->base); | 368 | drm_panel_remove(&panel->base); |
370 | 369 | ||
371 | panel_simple_disable(&panel->base); | 370 | panel_simple_disable(&panel->base); |
371 | panel_simple_unprepare(&panel->base); | ||
372 | 372 | ||
373 | if (panel->ddc) | 373 | if (panel->ddc) |
374 | put_device(&panel->ddc->dev); | 374 | put_device(&panel->ddc->dev); |
@@ -384,6 +384,7 @@ static void panel_simple_shutdown(struct device *dev) | |||
384 | struct panel_simple *panel = dev_get_drvdata(dev); | 384 | struct panel_simple *panel = dev_get_drvdata(dev); |
385 | 385 | ||
386 | panel_simple_disable(&panel->base); | 386 | panel_simple_disable(&panel->base); |
387 | panel_simple_unprepare(&panel->base); | ||
387 | } | 388 | } |
388 | 389 | ||
389 | static const struct drm_display_mode ampire_am_480272h3tmqw_t01h_mode = { | 390 | static const struct drm_display_mode ampire_am_480272h3tmqw_t01h_mode = { |
@@ -1522,8 +1523,8 @@ static const struct panel_desc olimex_lcd_olinuxino_43ts = { | |||
1522 | .modes = &olimex_lcd_olinuxino_43ts_mode, | 1523 | .modes = &olimex_lcd_olinuxino_43ts_mode, |
1523 | .num_modes = 1, | 1524 | .num_modes = 1, |
1524 | .size = { | 1525 | .size = { |
1525 | .width = 105, | 1526 | .width = 95, |
1526 | .height = 67, | 1527 | .height = 54, |
1527 | }, | 1528 | }, |
1528 | .bus_format = MEDIA_BUS_FMT_RGB888_1X24, | 1529 | .bus_format = MEDIA_BUS_FMT_RGB888_1X24, |
1529 | }; | 1530 | }; |
diff --git a/drivers/gpu/drm/pl111/Kconfig b/drivers/gpu/drm/pl111/Kconfig index bbfba87cd1a8..e5e2abd66491 100644 --- a/drivers/gpu/drm/pl111/Kconfig +++ b/drivers/gpu/drm/pl111/Kconfig | |||
@@ -6,7 +6,8 @@ config DRM_PL111 | |||
6 | select DRM_KMS_HELPER | 6 | select DRM_KMS_HELPER |
7 | select DRM_KMS_CMA_HELPER | 7 | select DRM_KMS_CMA_HELPER |
8 | select DRM_GEM_CMA_HELPER | 8 | select DRM_GEM_CMA_HELPER |
9 | select DRM_PANEL | 9 | select DRM_BRIDGE |
10 | select DRM_PANEL_BRIDGE | ||
10 | select VT_HW_CONSOLE_BINDING if FRAMEBUFFER_CONSOLE | 11 | select VT_HW_CONSOLE_BINDING if FRAMEBUFFER_CONSOLE |
11 | help | 12 | help |
12 | Choose this option for DRM support for the PL111 CLCD controller. | 13 | Choose this option for DRM support for the PL111 CLCD controller. |
diff --git a/drivers/gpu/drm/pl111/Makefile b/drivers/gpu/drm/pl111/Makefile index 59483d610ef5..fce1453a93e1 100644 --- a/drivers/gpu/drm/pl111/Makefile +++ b/drivers/gpu/drm/pl111/Makefile | |||
@@ -1,5 +1,5 @@ | |||
1 | pl111_drm-y += pl111_connector.o \ | 1 | pl111_drm-y += pl111_display.o \ |
2 | pl111_display.o \ | 2 | pl111_versatile.o \ |
3 | pl111_drv.o | 3 | pl111_drv.o |
4 | 4 | ||
5 | pl111_drm-$(CONFIG_DEBUG_FS) += pl111_debugfs.o | 5 | pl111_drm-$(CONFIG_DEBUG_FS) += pl111_debugfs.o |
diff --git a/drivers/gpu/drm/pl111/pl111_connector.c b/drivers/gpu/drm/pl111/pl111_connector.c deleted file mode 100644 index d335f9a29ce4..000000000000 --- a/drivers/gpu/drm/pl111/pl111_connector.c +++ /dev/null | |||
@@ -1,126 +0,0 @@ | |||
1 | /* | ||
2 | * (C) COPYRIGHT 2012-2013 ARM Limited. All rights reserved. | ||
3 | * | ||
4 | * Parts of this file were based on sources as follows: | ||
5 | * | ||
6 | * Copyright (c) 2006-2008 Intel Corporation | ||
7 | * Copyright (c) 2007 Dave Airlie <airlied@linux.ie> | ||
8 | * Copyright (C) 2011 Texas Instruments | ||
9 | * | ||
10 | * This program is free software and is provided to you under the terms of the | ||
11 | * GNU General Public License version 2 as published by the Free Software | ||
12 | * Foundation, and any use by you of this program is subject to the terms of | ||
13 | * such GNU licence. | ||
14 | * | ||
15 | */ | ||
16 | |||
17 | /** | ||
18 | * pl111_drm_connector.c | ||
19 | * Implementation of the connector functions for PL111 DRM | ||
20 | */ | ||
21 | #include <linux/amba/clcd-regs.h> | ||
22 | #include <linux/version.h> | ||
23 | #include <linux/shmem_fs.h> | ||
24 | #include <linux/dma-buf.h> | ||
25 | |||
26 | #include <drm/drmP.h> | ||
27 | #include <drm/drm_atomic_helper.h> | ||
28 | #include <drm/drm_crtc_helper.h> | ||
29 | #include <drm/drm_of.h> | ||
30 | #include <drm/drm_panel.h> | ||
31 | |||
32 | #include "pl111_drm.h" | ||
33 | |||
34 | static void pl111_connector_destroy(struct drm_connector *connector) | ||
35 | { | ||
36 | struct pl111_drm_connector *pl111_connector = | ||
37 | to_pl111_connector(connector); | ||
38 | |||
39 | if (pl111_connector->panel) | ||
40 | drm_panel_detach(pl111_connector->panel); | ||
41 | |||
42 | drm_connector_unregister(connector); | ||
43 | drm_connector_cleanup(connector); | ||
44 | } | ||
45 | |||
46 | static enum drm_connector_status pl111_connector_detect(struct drm_connector | ||
47 | *connector, bool force) | ||
48 | { | ||
49 | struct pl111_drm_connector *pl111_connector = | ||
50 | to_pl111_connector(connector); | ||
51 | |||
52 | return (pl111_connector->panel ? | ||
53 | connector_status_connected : | ||
54 | connector_status_disconnected); | ||
55 | } | ||
56 | |||
57 | static int pl111_connector_helper_get_modes(struct drm_connector *connector) | ||
58 | { | ||
59 | struct pl111_drm_connector *pl111_connector = | ||
60 | to_pl111_connector(connector); | ||
61 | |||
62 | if (!pl111_connector->panel) | ||
63 | return 0; | ||
64 | |||
65 | return drm_panel_get_modes(pl111_connector->panel); | ||
66 | } | ||
67 | |||
68 | const struct drm_connector_funcs connector_funcs = { | ||
69 | .fill_modes = drm_helper_probe_single_connector_modes, | ||
70 | .destroy = pl111_connector_destroy, | ||
71 | .detect = pl111_connector_detect, | ||
72 | .reset = drm_atomic_helper_connector_reset, | ||
73 | .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, | ||
74 | .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, | ||
75 | }; | ||
76 | |||
77 | const struct drm_connector_helper_funcs connector_helper_funcs = { | ||
78 | .get_modes = pl111_connector_helper_get_modes, | ||
79 | }; | ||
80 | |||
81 | /* Walks the OF graph to find the panel node and then asks DRM to look | ||
82 | * up the panel. | ||
83 | */ | ||
84 | static struct drm_panel *pl111_get_panel(struct device *dev) | ||
85 | { | ||
86 | struct device_node *endpoint, *panel_node; | ||
87 | struct device_node *np = dev->of_node; | ||
88 | struct drm_panel *panel; | ||
89 | |||
90 | endpoint = of_graph_get_next_endpoint(np, NULL); | ||
91 | if (!endpoint) { | ||
92 | dev_err(dev, "no endpoint to fetch panel\n"); | ||
93 | return NULL; | ||
94 | } | ||
95 | |||
96 | /* don't proceed if we have an endpoint but no panel_node tied to it */ | ||
97 | panel_node = of_graph_get_remote_port_parent(endpoint); | ||
98 | of_node_put(endpoint); | ||
99 | if (!panel_node) { | ||
100 | dev_err(dev, "no valid panel node\n"); | ||
101 | return NULL; | ||
102 | } | ||
103 | |||
104 | panel = of_drm_find_panel(panel_node); | ||
105 | of_node_put(panel_node); | ||
106 | |||
107 | return panel; | ||
108 | } | ||
109 | |||
110 | int pl111_connector_init(struct drm_device *dev) | ||
111 | { | ||
112 | struct pl111_drm_dev_private *priv = dev->dev_private; | ||
113 | struct pl111_drm_connector *pl111_connector = &priv->connector; | ||
114 | struct drm_connector *connector = &pl111_connector->connector; | ||
115 | |||
116 | drm_connector_init(dev, connector, &connector_funcs, | ||
117 | DRM_MODE_CONNECTOR_DPI); | ||
118 | drm_connector_helper_add(connector, &connector_helper_funcs); | ||
119 | |||
120 | pl111_connector->panel = pl111_get_panel(dev->dev); | ||
121 | if (pl111_connector->panel) | ||
122 | drm_panel_attach(pl111_connector->panel, connector); | ||
123 | |||
124 | return 0; | ||
125 | } | ||
126 | |||
diff --git a/drivers/gpu/drm/pl111/pl111_debugfs.c b/drivers/gpu/drm/pl111/pl111_debugfs.c index 0d9dee199b2c..7ddc7e3b9e7d 100644 --- a/drivers/gpu/drm/pl111/pl111_debugfs.c +++ b/drivers/gpu/drm/pl111/pl111_debugfs.c | |||
@@ -22,8 +22,14 @@ static const struct { | |||
22 | REGDEF(CLCD_TIM2), | 22 | REGDEF(CLCD_TIM2), |
23 | REGDEF(CLCD_TIM3), | 23 | REGDEF(CLCD_TIM3), |
24 | REGDEF(CLCD_UBAS), | 24 | REGDEF(CLCD_UBAS), |
25 | REGDEF(CLCD_LBAS), | ||
25 | REGDEF(CLCD_PL111_CNTL), | 26 | REGDEF(CLCD_PL111_CNTL), |
26 | REGDEF(CLCD_PL111_IENB), | 27 | REGDEF(CLCD_PL111_IENB), |
28 | REGDEF(CLCD_PL111_RIS), | ||
29 | REGDEF(CLCD_PL111_MIS), | ||
30 | REGDEF(CLCD_PL111_ICR), | ||
31 | REGDEF(CLCD_PL111_UCUR), | ||
32 | REGDEF(CLCD_PL111_LCUR), | ||
27 | }; | 33 | }; |
28 | 34 | ||
29 | int pl111_debugfs_regs(struct seq_file *m, void *unused) | 35 | int pl111_debugfs_regs(struct seq_file *m, void *unused) |
diff --git a/drivers/gpu/drm/pl111/pl111_display.c b/drivers/gpu/drm/pl111/pl111_display.c index b58c988d9da0..06c4bf756b69 100644 --- a/drivers/gpu/drm/pl111/pl111_display.c +++ b/drivers/gpu/drm/pl111/pl111_display.c | |||
@@ -21,7 +21,6 @@ | |||
21 | #include <linux/of_graph.h> | 21 | #include <linux/of_graph.h> |
22 | 22 | ||
23 | #include <drm/drmP.h> | 23 | #include <drm/drmP.h> |
24 | #include <drm/drm_panel.h> | ||
25 | #include <drm/drm_gem_cma_helper.h> | 24 | #include <drm/drm_gem_cma_helper.h> |
26 | #include <drm/drm_gem_framebuffer_helper.h> | 25 | #include <drm/drm_gem_framebuffer_helper.h> |
27 | #include <drm/drm_fb_cma_helper.h> | 26 | #include <drm/drm_fb_cma_helper.h> |
@@ -94,7 +93,7 @@ static void pl111_display_enable(struct drm_simple_display_pipe *pipe, | |||
94 | struct pl111_drm_dev_private *priv = drm->dev_private; | 93 | struct pl111_drm_dev_private *priv = drm->dev_private; |
95 | const struct drm_display_mode *mode = &cstate->mode; | 94 | const struct drm_display_mode *mode = &cstate->mode; |
96 | struct drm_framebuffer *fb = plane->state->fb; | 95 | struct drm_framebuffer *fb = plane->state->fb; |
97 | struct drm_connector *connector = &priv->connector.connector; | 96 | struct drm_connector *connector = priv->connector; |
98 | u32 cntl; | 97 | u32 cntl; |
99 | u32 ppl, hsw, hfp, hbp; | 98 | u32 ppl, hsw, hfp, hbp; |
100 | u32 lpp, vsw, vfp, vbp; | 99 | u32 lpp, vsw, vfp, vbp; |
@@ -156,10 +155,8 @@ static void pl111_display_enable(struct drm_simple_display_pipe *pipe, | |||
156 | 155 | ||
157 | writel(0, priv->regs + CLCD_TIM3); | 156 | writel(0, priv->regs + CLCD_TIM3); |
158 | 157 | ||
159 | drm_panel_prepare(priv->connector.panel); | 158 | /* Hard-code TFT panel */ |
160 | 159 | cntl = CNTL_LCDEN | CNTL_LCDTFT | CNTL_LCDVCOMP(1); | |
161 | /* Enable and Power Up */ | ||
162 | cntl = CNTL_LCDEN | CNTL_LCDTFT | CNTL_LCDPWR | CNTL_LCDVCOMP(1); | ||
163 | 160 | ||
164 | /* Note that the the hardware's format reader takes 'r' from | 161 | /* Note that the the hardware's format reader takes 'r' from |
165 | * the low bit, while DRM formats list channels from high bit | 162 | * the low bit, while DRM formats list channels from high bit |
@@ -202,9 +199,21 @@ static void pl111_display_enable(struct drm_simple_display_pipe *pipe, | |||
202 | break; | 199 | break; |
203 | } | 200 | } |
204 | 201 | ||
205 | writel(cntl, priv->regs + CLCD_PL111_CNTL); | 202 | /* Power sequence: first enable and chill */ |
203 | writel(cntl, priv->regs + priv->ctrl); | ||
204 | |||
205 | /* | ||
206 | * We expect this delay to stabilize the contrast | ||
207 | * voltage Vee as stipulated by the manual | ||
208 | */ | ||
209 | msleep(20); | ||
210 | |||
211 | if (priv->variant_display_enable) | ||
212 | priv->variant_display_enable(drm, fb->format->format); | ||
206 | 213 | ||
207 | drm_panel_enable(priv->connector.panel); | 214 | /* Power Up */ |
215 | cntl |= CNTL_LCDPWR; | ||
216 | writel(cntl, priv->regs + priv->ctrl); | ||
208 | 217 | ||
209 | drm_crtc_vblank_on(crtc); | 218 | drm_crtc_vblank_on(crtc); |
210 | } | 219 | } |
@@ -214,15 +223,28 @@ void pl111_display_disable(struct drm_simple_display_pipe *pipe) | |||
214 | struct drm_crtc *crtc = &pipe->crtc; | 223 | struct drm_crtc *crtc = &pipe->crtc; |
215 | struct drm_device *drm = crtc->dev; | 224 | struct drm_device *drm = crtc->dev; |
216 | struct pl111_drm_dev_private *priv = drm->dev_private; | 225 | struct pl111_drm_dev_private *priv = drm->dev_private; |
226 | u32 cntl; | ||
217 | 227 | ||
218 | drm_crtc_vblank_off(crtc); | 228 | drm_crtc_vblank_off(crtc); |
219 | 229 | ||
220 | drm_panel_disable(priv->connector.panel); | 230 | /* Power Down */ |
231 | cntl = readl(priv->regs + priv->ctrl); | ||
232 | if (cntl & CNTL_LCDPWR) { | ||
233 | cntl &= ~CNTL_LCDPWR; | ||
234 | writel(cntl, priv->regs + priv->ctrl); | ||
235 | } | ||
236 | |||
237 | /* | ||
238 | * We expect this delay to stabilize the contrast voltage Vee as | ||
239 | * stipulated by the manual | ||
240 | */ | ||
241 | msleep(20); | ||
221 | 242 | ||
222 | /* Disable and Power Down */ | 243 | if (priv->variant_display_disable) |
223 | writel(0, priv->regs + CLCD_PL111_CNTL); | 244 | priv->variant_display_disable(drm); |
224 | 245 | ||
225 | drm_panel_unprepare(priv->connector.panel); | 246 | /* Disable */ |
247 | writel(0, priv->regs + priv->ctrl); | ||
226 | 248 | ||
227 | clk_disable_unprepare(priv->clk); | 249 | clk_disable_unprepare(priv->clk); |
228 | } | 250 | } |
@@ -260,7 +282,7 @@ int pl111_enable_vblank(struct drm_device *drm, unsigned int crtc) | |||
260 | { | 282 | { |
261 | struct pl111_drm_dev_private *priv = drm->dev_private; | 283 | struct pl111_drm_dev_private *priv = drm->dev_private; |
262 | 284 | ||
263 | writel(CLCD_IRQ_NEXTBASE_UPDATE, priv->regs + CLCD_PL111_IENB); | 285 | writel(CLCD_IRQ_NEXTBASE_UPDATE, priv->regs + priv->ienb); |
264 | 286 | ||
265 | return 0; | 287 | return 0; |
266 | } | 288 | } |
@@ -269,7 +291,7 @@ void pl111_disable_vblank(struct drm_device *drm, unsigned int crtc) | |||
269 | { | 291 | { |
270 | struct pl111_drm_dev_private *priv = drm->dev_private; | 292 | struct pl111_drm_dev_private *priv = drm->dev_private; |
271 | 293 | ||
272 | writel(0, priv->regs + CLCD_PL111_IENB); | 294 | writel(0, priv->regs + priv->ienb); |
273 | } | 295 | } |
274 | 296 | ||
275 | static int pl111_display_prepare_fb(struct drm_simple_display_pipe *pipe, | 297 | static int pl111_display_prepare_fb(struct drm_simple_display_pipe *pipe, |
@@ -413,22 +435,6 @@ int pl111_display_init(struct drm_device *drm) | |||
413 | struct device_node *endpoint; | 435 | struct device_node *endpoint; |
414 | u32 tft_r0b0g0[3]; | 436 | u32 tft_r0b0g0[3]; |
415 | int ret; | 437 | int ret; |
416 | static const u32 formats[] = { | ||
417 | DRM_FORMAT_ABGR8888, | ||
418 | DRM_FORMAT_XBGR8888, | ||
419 | DRM_FORMAT_ARGB8888, | ||
420 | DRM_FORMAT_XRGB8888, | ||
421 | DRM_FORMAT_BGR565, | ||
422 | DRM_FORMAT_RGB565, | ||
423 | DRM_FORMAT_ABGR1555, | ||
424 | DRM_FORMAT_XBGR1555, | ||
425 | DRM_FORMAT_ARGB1555, | ||
426 | DRM_FORMAT_XRGB1555, | ||
427 | DRM_FORMAT_ABGR4444, | ||
428 | DRM_FORMAT_XBGR4444, | ||
429 | DRM_FORMAT_ARGB4444, | ||
430 | DRM_FORMAT_XRGB4444, | ||
431 | }; | ||
432 | 438 | ||
433 | endpoint = of_graph_get_next_endpoint(dev->of_node, NULL); | 439 | endpoint = of_graph_get_next_endpoint(dev->of_node, NULL); |
434 | if (!endpoint) | 440 | if (!endpoint) |
@@ -444,21 +450,16 @@ int pl111_display_init(struct drm_device *drm) | |||
444 | } | 450 | } |
445 | of_node_put(endpoint); | 451 | of_node_put(endpoint); |
446 | 452 | ||
447 | if (tft_r0b0g0[0] != 0 || | ||
448 | tft_r0b0g0[1] != 8 || | ||
449 | tft_r0b0g0[2] != 16) { | ||
450 | dev_err(dev, "arm,pl11x,tft-r0g0b0-pads != [0,8,16] not yet supported\n"); | ||
451 | return -EINVAL; | ||
452 | } | ||
453 | |||
454 | ret = pl111_init_clock_divider(drm); | 453 | ret = pl111_init_clock_divider(drm); |
455 | if (ret) | 454 | if (ret) |
456 | return ret; | 455 | return ret; |
457 | 456 | ||
458 | ret = drm_simple_display_pipe_init(drm, &priv->pipe, | 457 | ret = drm_simple_display_pipe_init(drm, &priv->pipe, |
459 | &pl111_display_funcs, | 458 | &pl111_display_funcs, |
460 | formats, ARRAY_SIZE(formats), | 459 | priv->variant->formats, |
461 | NULL, &priv->connector.connector); | 460 | priv->variant->nformats, |
461 | NULL, | ||
462 | priv->connector); | ||
462 | if (ret) | 463 | if (ret) |
463 | return ret; | 464 | return ret; |
464 | 465 | ||
diff --git a/drivers/gpu/drm/pl111/pl111_drm.h b/drivers/gpu/drm/pl111/pl111_drm.h index 5c685bfc8fdc..440f53ebee8c 100644 --- a/drivers/gpu/drm/pl111/pl111_drm.h +++ b/drivers/gpu/drm/pl111/pl111_drm.h | |||
@@ -21,25 +21,43 @@ | |||
21 | 21 | ||
22 | #include <drm/drm_gem.h> | 22 | #include <drm/drm_gem.h> |
23 | #include <drm/drm_simple_kms_helper.h> | 23 | #include <drm/drm_simple_kms_helper.h> |
24 | #include <drm/drm_connector.h> | ||
25 | #include <drm/drm_encoder.h> | ||
26 | #include <drm/drm_panel.h> | ||
27 | #include <drm/drm_bridge.h> | ||
24 | #include <linux/clk-provider.h> | 28 | #include <linux/clk-provider.h> |
29 | #include <linux/interrupt.h> | ||
25 | 30 | ||
26 | #define CLCD_IRQ_NEXTBASE_UPDATE BIT(2) | 31 | #define CLCD_IRQ_NEXTBASE_UPDATE BIT(2) |
27 | 32 | ||
28 | struct drm_minor; | 33 | struct drm_minor; |
29 | 34 | ||
30 | struct pl111_drm_connector { | 35 | /** |
31 | struct drm_connector connector; | 36 | * struct pl111_variant_data - encodes IP differences |
32 | struct drm_panel *panel; | 37 | * @name: the name of this variant |
38 | * @is_pl110: this is the early PL110 variant | ||
39 | * @formats: array of supported pixel formats on this variant | ||
40 | * @nformats: the length of the array of supported pixel formats | ||
41 | */ | ||
42 | struct pl111_variant_data { | ||
43 | const char *name; | ||
44 | bool is_pl110; | ||
45 | const u32 *formats; | ||
46 | unsigned int nformats; | ||
33 | }; | 47 | }; |
34 | 48 | ||
35 | struct pl111_drm_dev_private { | 49 | struct pl111_drm_dev_private { |
36 | struct drm_device *drm; | 50 | struct drm_device *drm; |
37 | 51 | ||
38 | struct pl111_drm_connector connector; | 52 | struct drm_connector *connector; |
53 | struct drm_panel *panel; | ||
54 | struct drm_bridge *bridge; | ||
39 | struct drm_simple_display_pipe pipe; | 55 | struct drm_simple_display_pipe pipe; |
40 | struct drm_fbdev_cma *fbdev; | 56 | struct drm_fbdev_cma *fbdev; |
41 | 57 | ||
42 | void *regs; | 58 | void *regs; |
59 | u32 ienb; | ||
60 | u32 ctrl; | ||
43 | /* The pixel clock (a reference to our clock divider off of CLCDCLK). */ | 61 | /* The pixel clock (a reference to our clock divider off of CLCDCLK). */ |
44 | struct clk *clk; | 62 | struct clk *clk; |
45 | /* pl111's internal clock divider. */ | 63 | /* pl111's internal clock divider. */ |
@@ -48,20 +66,15 @@ struct pl111_drm_dev_private { | |||
48 | * subsystem and pl111_display_enable(). | 66 | * subsystem and pl111_display_enable(). |
49 | */ | 67 | */ |
50 | spinlock_t tim2_lock; | 68 | spinlock_t tim2_lock; |
69 | const struct pl111_variant_data *variant; | ||
70 | void (*variant_display_enable) (struct drm_device *drm, u32 format); | ||
71 | void (*variant_display_disable) (struct drm_device *drm); | ||
51 | }; | 72 | }; |
52 | 73 | ||
53 | #define to_pl111_connector(x) \ | ||
54 | container_of(x, struct pl111_drm_connector, connector) | ||
55 | |||
56 | int pl111_display_init(struct drm_device *dev); | 74 | int pl111_display_init(struct drm_device *dev); |
57 | int pl111_enable_vblank(struct drm_device *drm, unsigned int crtc); | 75 | int pl111_enable_vblank(struct drm_device *drm, unsigned int crtc); |
58 | void pl111_disable_vblank(struct drm_device *drm, unsigned int crtc); | 76 | void pl111_disable_vblank(struct drm_device *drm, unsigned int crtc); |
59 | irqreturn_t pl111_irq(int irq, void *data); | 77 | irqreturn_t pl111_irq(int irq, void *data); |
60 | int pl111_connector_init(struct drm_device *dev); | ||
61 | int pl111_encoder_init(struct drm_device *dev); | ||
62 | int pl111_dumb_create(struct drm_file *file_priv, | ||
63 | struct drm_device *dev, | ||
64 | struct drm_mode_create_dumb *args); | ||
65 | int pl111_debugfs_init(struct drm_minor *minor); | 78 | int pl111_debugfs_init(struct drm_minor *minor); |
66 | 79 | ||
67 | #endif /* _PL111_DRM_H_ */ | 80 | #endif /* _PL111_DRM_H_ */ |
diff --git a/drivers/gpu/drm/pl111/pl111_drv.c b/drivers/gpu/drm/pl111/pl111_drv.c index 581c452cede1..201d57d5cb54 100644 --- a/drivers/gpu/drm/pl111/pl111_drv.c +++ b/drivers/gpu/drm/pl111/pl111_drv.c | |||
@@ -41,9 +41,6 @@ | |||
41 | * - Fix race between setting plane base address and getting IRQ for | 41 | * - Fix race between setting plane base address and getting IRQ for |
42 | * vsync firing the pageflip completion. | 42 | * vsync firing the pageflip completion. |
43 | * | 43 | * |
44 | * - Expose the correct set of formats we can support based on the | ||
45 | * "arm,pl11x,tft-r0g0b0-pads" DT property. | ||
46 | * | ||
47 | * - Use the "max-memory-bandwidth" DT property to filter the | 44 | * - Use the "max-memory-bandwidth" DT property to filter the |
48 | * supported formats. | 45 | * supported formats. |
49 | * | 46 | * |
@@ -68,8 +65,12 @@ | |||
68 | #include <drm/drm_gem_cma_helper.h> | 65 | #include <drm/drm_gem_cma_helper.h> |
69 | #include <drm/drm_gem_framebuffer_helper.h> | 66 | #include <drm/drm_gem_framebuffer_helper.h> |
70 | #include <drm/drm_fb_cma_helper.h> | 67 | #include <drm/drm_fb_cma_helper.h> |
68 | #include <drm/drm_of.h> | ||
69 | #include <drm/drm_bridge.h> | ||
70 | #include <drm/drm_panel.h> | ||
71 | 71 | ||
72 | #include "pl111_drm.h" | 72 | #include "pl111_drm.h" |
73 | #include "pl111_versatile.h" | ||
73 | 74 | ||
74 | #define DRIVER_DESC "DRM module for PL111" | 75 | #define DRIVER_DESC "DRM module for PL111" |
75 | 76 | ||
@@ -83,6 +84,8 @@ static int pl111_modeset_init(struct drm_device *dev) | |||
83 | { | 84 | { |
84 | struct drm_mode_config *mode_config; | 85 | struct drm_mode_config *mode_config; |
85 | struct pl111_drm_dev_private *priv = dev->dev_private; | 86 | struct pl111_drm_dev_private *priv = dev->dev_private; |
87 | struct drm_panel *panel; | ||
88 | struct drm_bridge *bridge; | ||
86 | int ret = 0; | 89 | int ret = 0; |
87 | 90 | ||
88 | drm_mode_config_init(dev); | 91 | drm_mode_config_init(dev); |
@@ -93,34 +96,43 @@ static int pl111_modeset_init(struct drm_device *dev) | |||
93 | mode_config->min_height = 1; | 96 | mode_config->min_height = 1; |
94 | mode_config->max_height = 768; | 97 | mode_config->max_height = 768; |
95 | 98 | ||
96 | ret = pl111_connector_init(dev); | 99 | ret = drm_of_find_panel_or_bridge(dev->dev->of_node, |
97 | if (ret) { | 100 | 0, 0, &panel, &bridge); |
98 | dev_err(dev->dev, "Failed to create pl111_drm_connector\n"); | 101 | if (ret && ret != -ENODEV) |
99 | goto out_config; | 102 | return ret; |
100 | } | 103 | if (panel) { |
101 | 104 | bridge = drm_panel_bridge_add(panel, | |
102 | /* Don't actually attach if we didn't find a drm_panel | 105 | DRM_MODE_CONNECTOR_Unknown); |
103 | * attached to us. This will allow a kernel to include both | 106 | if (IS_ERR(bridge)) { |
104 | * the fbdev pl111 driver and this one, and choose between | 107 | ret = PTR_ERR(bridge); |
105 | * them based on which subsystem has support for the panel. | 108 | goto out_config; |
106 | */ | 109 | } |
107 | if (!priv->connector.panel) { | 110 | /* |
108 | dev_info(dev->dev, | 111 | * TODO: when we are using a different bridge than a panel |
109 | "Disabling due to lack of DRM panel device.\n"); | 112 | * (such as a dumb VGA connector) we need to devise a different |
110 | ret = -ENODEV; | 113 | * method to get the connector out of the bridge. |
111 | goto out_config; | 114 | */ |
112 | } | 115 | } |
113 | 116 | ||
114 | ret = pl111_display_init(dev); | 117 | ret = pl111_display_init(dev); |
115 | if (ret != 0) { | 118 | if (ret != 0) { |
116 | dev_err(dev->dev, "Failed to init display\n"); | 119 | dev_err(dev->dev, "Failed to init display\n"); |
117 | goto out_config; | 120 | goto out_bridge; |
118 | } | 121 | } |
119 | 122 | ||
123 | ret = drm_simple_display_pipe_attach_bridge(&priv->pipe, | ||
124 | bridge); | ||
125 | if (ret) | ||
126 | return ret; | ||
127 | |||
128 | priv->bridge = bridge; | ||
129 | priv->panel = panel; | ||
130 | priv->connector = panel->connector; | ||
131 | |||
120 | ret = drm_vblank_init(dev, 1); | 132 | ret = drm_vblank_init(dev, 1); |
121 | if (ret != 0) { | 133 | if (ret != 0) { |
122 | dev_err(dev->dev, "Failed to init vblank\n"); | 134 | dev_err(dev->dev, "Failed to init vblank\n"); |
123 | goto out_config; | 135 | goto out_bridge; |
124 | } | 136 | } |
125 | 137 | ||
126 | drm_mode_config_reset(dev); | 138 | drm_mode_config_reset(dev); |
@@ -132,6 +144,9 @@ static int pl111_modeset_init(struct drm_device *dev) | |||
132 | 144 | ||
133 | goto finish; | 145 | goto finish; |
134 | 146 | ||
147 | out_bridge: | ||
148 | if (panel) | ||
149 | drm_panel_bridge_remove(bridge); | ||
135 | out_config: | 150 | out_config: |
136 | drm_mode_config_cleanup(dev); | 151 | drm_mode_config_cleanup(dev); |
137 | finish: | 152 | finish: |
@@ -183,6 +198,7 @@ static int pl111_amba_probe(struct amba_device *amba_dev, | |||
183 | { | 198 | { |
184 | struct device *dev = &amba_dev->dev; | 199 | struct device *dev = &amba_dev->dev; |
185 | struct pl111_drm_dev_private *priv; | 200 | struct pl111_drm_dev_private *priv; |
201 | struct pl111_variant_data *variant = id->data; | ||
186 | struct drm_device *drm; | 202 | struct drm_device *drm; |
187 | int ret; | 203 | int ret; |
188 | 204 | ||
@@ -196,6 +212,33 @@ static int pl111_amba_probe(struct amba_device *amba_dev, | |||
196 | amba_set_drvdata(amba_dev, drm); | 212 | amba_set_drvdata(amba_dev, drm); |
197 | priv->drm = drm; | 213 | priv->drm = drm; |
198 | drm->dev_private = priv; | 214 | drm->dev_private = priv; |
215 | priv->variant = variant; | ||
216 | |||
217 | /* | ||
218 | * The PL110 and PL111 variants have two registers | ||
219 | * swapped: interrupt enable and control. For this reason | ||
220 | * we use offsets that we can change per variant. | ||
221 | */ | ||
222 | if (variant->is_pl110) { | ||
223 | /* | ||
224 | * The ARM Versatile boards are even more special: | ||
225 | * their PrimeCell ID say they are PL110 but the | ||
226 | * control and interrupt enable registers are anyway | ||
227 | * swapped to the PL111 order so they are not following | ||
228 | * the PL110 datasheet. | ||
229 | */ | ||
230 | if (of_machine_is_compatible("arm,versatile-ab") || | ||
231 | of_machine_is_compatible("arm,versatile-pb")) { | ||
232 | priv->ienb = CLCD_PL111_IENB; | ||
233 | priv->ctrl = CLCD_PL111_CNTL; | ||
234 | } else { | ||
235 | priv->ienb = CLCD_PL110_IENB; | ||
236 | priv->ctrl = CLCD_PL110_CNTL; | ||
237 | } | ||
238 | } else { | ||
239 | priv->ienb = CLCD_PL111_IENB; | ||
240 | priv->ctrl = CLCD_PL111_CNTL; | ||
241 | } | ||
199 | 242 | ||
200 | priv->regs = devm_ioremap_resource(dev, &amba_dev->res); | 243 | priv->regs = devm_ioremap_resource(dev, &amba_dev->res); |
201 | if (IS_ERR(priv->regs)) { | 244 | if (IS_ERR(priv->regs)) { |
@@ -204,15 +247,19 @@ static int pl111_amba_probe(struct amba_device *amba_dev, | |||
204 | } | 247 | } |
205 | 248 | ||
206 | /* turn off interrupts before requesting the irq */ | 249 | /* turn off interrupts before requesting the irq */ |
207 | writel(0, priv->regs + CLCD_PL111_IENB); | 250 | writel(0, priv->regs + priv->ienb); |
208 | 251 | ||
209 | ret = devm_request_irq(dev, amba_dev->irq[0], pl111_irq, 0, | 252 | ret = devm_request_irq(dev, amba_dev->irq[0], pl111_irq, 0, |
210 | "pl111", priv); | 253 | variant->name, priv); |
211 | if (ret != 0) { | 254 | if (ret != 0) { |
212 | dev_err(dev, "%s failed irq %d\n", __func__, ret); | 255 | dev_err(dev, "%s failed irq %d\n", __func__, ret); |
213 | return ret; | 256 | return ret; |
214 | } | 257 | } |
215 | 258 | ||
259 | ret = pl111_versatile_init(dev, priv); | ||
260 | if (ret) | ||
261 | goto dev_unref; | ||
262 | |||
216 | ret = pl111_modeset_init(drm); | 263 | ret = pl111_modeset_init(drm); |
217 | if (ret != 0) | 264 | if (ret != 0) |
218 | goto dev_unref; | 265 | goto dev_unref; |
@@ -236,16 +283,70 @@ static int pl111_amba_remove(struct amba_device *amba_dev) | |||
236 | drm_dev_unregister(drm); | 283 | drm_dev_unregister(drm); |
237 | if (priv->fbdev) | 284 | if (priv->fbdev) |
238 | drm_fbdev_cma_fini(priv->fbdev); | 285 | drm_fbdev_cma_fini(priv->fbdev); |
286 | if (priv->panel) | ||
287 | drm_panel_bridge_remove(priv->bridge); | ||
239 | drm_mode_config_cleanup(drm); | 288 | drm_mode_config_cleanup(drm); |
240 | drm_dev_unref(drm); | 289 | drm_dev_unref(drm); |
241 | 290 | ||
242 | return 0; | 291 | return 0; |
243 | } | 292 | } |
244 | 293 | ||
245 | static struct amba_id pl111_id_table[] = { | 294 | /* |
295 | * This variant exist in early versions like the ARM Integrator | ||
296 | * and this version lacks the 565 and 444 pixel formats. | ||
297 | */ | ||
298 | static const u32 pl110_pixel_formats[] = { | ||
299 | DRM_FORMAT_ABGR8888, | ||
300 | DRM_FORMAT_XBGR8888, | ||
301 | DRM_FORMAT_ARGB8888, | ||
302 | DRM_FORMAT_XRGB8888, | ||
303 | DRM_FORMAT_ABGR1555, | ||
304 | DRM_FORMAT_XBGR1555, | ||
305 | DRM_FORMAT_ARGB1555, | ||
306 | DRM_FORMAT_XRGB1555, | ||
307 | }; | ||
308 | |||
309 | static const struct pl111_variant_data pl110_variant = { | ||
310 | .name = "PL110", | ||
311 | .is_pl110 = true, | ||
312 | .formats = pl110_pixel_formats, | ||
313 | .nformats = ARRAY_SIZE(pl110_pixel_formats), | ||
314 | }; | ||
315 | |||
316 | /* RealView, Versatile Express etc use this modern variant */ | ||
317 | static const u32 pl111_pixel_formats[] = { | ||
318 | DRM_FORMAT_ABGR8888, | ||
319 | DRM_FORMAT_XBGR8888, | ||
320 | DRM_FORMAT_ARGB8888, | ||
321 | DRM_FORMAT_XRGB8888, | ||
322 | DRM_FORMAT_BGR565, | ||
323 | DRM_FORMAT_RGB565, | ||
324 | DRM_FORMAT_ABGR1555, | ||
325 | DRM_FORMAT_XBGR1555, | ||
326 | DRM_FORMAT_ARGB1555, | ||
327 | DRM_FORMAT_XRGB1555, | ||
328 | DRM_FORMAT_ABGR4444, | ||
329 | DRM_FORMAT_XBGR4444, | ||
330 | DRM_FORMAT_ARGB4444, | ||
331 | DRM_FORMAT_XRGB4444, | ||
332 | }; | ||
333 | |||
334 | static const struct pl111_variant_data pl111_variant = { | ||
335 | .name = "PL111", | ||
336 | .formats = pl111_pixel_formats, | ||
337 | .nformats = ARRAY_SIZE(pl111_pixel_formats), | ||
338 | }; | ||
339 | |||
340 | static const struct amba_id pl111_id_table[] = { | ||
341 | { | ||
342 | .id = 0x00041110, | ||
343 | .mask = 0x000fffff, | ||
344 | .data = (void*)&pl110_variant, | ||
345 | }, | ||
246 | { | 346 | { |
247 | .id = 0x00041111, | 347 | .id = 0x00041111, |
248 | .mask = 0x000fffff, | 348 | .mask = 0x000fffff, |
349 | .data = (void*)&pl111_variant, | ||
249 | }, | 350 | }, |
250 | {0, 0}, | 351 | {0, 0}, |
251 | }; | 352 | }; |
diff --git a/drivers/gpu/drm/pl111/pl111_versatile.c b/drivers/gpu/drm/pl111/pl111_versatile.c new file mode 100644 index 000000000000..97d4af6925a3 --- /dev/null +++ b/drivers/gpu/drm/pl111/pl111_versatile.c | |||
@@ -0,0 +1,270 @@ | |||
1 | #include <linux/device.h> | ||
2 | #include <linux/of.h> | ||
3 | #include <linux/regmap.h> | ||
4 | #include <linux/mfd/syscon.h> | ||
5 | #include <linux/bitops.h> | ||
6 | #include <linux/module.h> | ||
7 | #include <drm/drmP.h> | ||
8 | #include "pl111_versatile.h" | ||
9 | #include "pl111_drm.h" | ||
10 | |||
11 | static struct regmap *versatile_syscon_map; | ||
12 | |||
13 | /* | ||
14 | * We detect the different syscon types from the compatible strings. | ||
15 | */ | ||
16 | enum versatile_clcd { | ||
17 | INTEGRATOR_CLCD_CM, | ||
18 | VERSATILE_CLCD, | ||
19 | REALVIEW_CLCD_EB, | ||
20 | REALVIEW_CLCD_PB1176, | ||
21 | REALVIEW_CLCD_PB11MP, | ||
22 | REALVIEW_CLCD_PBA8, | ||
23 | REALVIEW_CLCD_PBX, | ||
24 | }; | ||
25 | |||
26 | static const struct of_device_id versatile_clcd_of_match[] = { | ||
27 | { | ||
28 | .compatible = "arm,core-module-integrator", | ||
29 | .data = (void *)INTEGRATOR_CLCD_CM, | ||
30 | }, | ||
31 | { | ||
32 | .compatible = "arm,versatile-sysreg", | ||
33 | .data = (void *)VERSATILE_CLCD, | ||
34 | }, | ||
35 | { | ||
36 | .compatible = "arm,realview-eb-syscon", | ||
37 | .data = (void *)REALVIEW_CLCD_EB, | ||
38 | }, | ||
39 | { | ||
40 | .compatible = "arm,realview-pb1176-syscon", | ||
41 | .data = (void *)REALVIEW_CLCD_PB1176, | ||
42 | }, | ||
43 | { | ||
44 | .compatible = "arm,realview-pb11mp-syscon", | ||
45 | .data = (void *)REALVIEW_CLCD_PB11MP, | ||
46 | }, | ||
47 | { | ||
48 | .compatible = "arm,realview-pba8-syscon", | ||
49 | .data = (void *)REALVIEW_CLCD_PBA8, | ||
50 | }, | ||
51 | { | ||
52 | .compatible = "arm,realview-pbx-syscon", | ||
53 | .data = (void *)REALVIEW_CLCD_PBX, | ||
54 | }, | ||
55 | {}, | ||
56 | }; | ||
57 | |||
58 | /* | ||
59 | * Core module CLCD control on the Integrator/CP, bits | ||
60 | * 8 thru 19 of the CM_CONTROL register controls a bunch | ||
61 | * of CLCD settings. | ||
62 | */ | ||
63 | #define INTEGRATOR_HDR_CTRL_OFFSET 0x0C | ||
64 | #define INTEGRATOR_CLCD_LCDBIASEN BIT(8) | ||
65 | #define INTEGRATOR_CLCD_LCDBIASUP BIT(9) | ||
66 | #define INTEGRATOR_CLCD_LCDBIASDN BIT(10) | ||
67 | /* Bits 11,12,13 controls the LCD type */ | ||
68 | #define INTEGRATOR_CLCD_LCDMUX_MASK (BIT(11)|BIT(12)|BIT(13)) | ||
69 | #define INTEGRATOR_CLCD_LCDMUX_LCD24 BIT(11) | ||
70 | #define INTEGRATOR_CLCD_LCDMUX_VGA565 BIT(12) | ||
71 | #define INTEGRATOR_CLCD_LCDMUX_SHARP (BIT(11)|BIT(12)) | ||
72 | #define INTEGRATOR_CLCD_LCDMUX_VGA555 BIT(13) | ||
73 | #define INTEGRATOR_CLCD_LCDMUX_VGA24 (BIT(11)|BIT(12)|BIT(13)) | ||
74 | #define INTEGRATOR_CLCD_LCD0_EN BIT(14) | ||
75 | #define INTEGRATOR_CLCD_LCD1_EN BIT(15) | ||
76 | /* R/L flip on Sharp */ | ||
77 | #define INTEGRATOR_CLCD_LCD_STATIC1 BIT(16) | ||
78 | /* U/D flip on Sharp */ | ||
79 | #define INTEGRATOR_CLCD_LCD_STATIC2 BIT(17) | ||
80 | /* No connection on Sharp */ | ||
81 | #define INTEGRATOR_CLCD_LCD_STATIC BIT(18) | ||
82 | /* 0 = 24bit VGA, 1 = 18bit VGA */ | ||
83 | #define INTEGRATOR_CLCD_LCD_N24BITEN BIT(19) | ||
84 | |||
85 | #define INTEGRATOR_CLCD_MASK (INTEGRATOR_CLCD_LCDBIASEN | \ | ||
86 | INTEGRATOR_CLCD_LCDBIASUP | \ | ||
87 | INTEGRATOR_CLCD_LCDBIASDN | \ | ||
88 | INTEGRATOR_CLCD_LCDMUX_MASK | \ | ||
89 | INTEGRATOR_CLCD_LCD0_EN | \ | ||
90 | INTEGRATOR_CLCD_LCD1_EN | \ | ||
91 | INTEGRATOR_CLCD_LCD_STATIC1 | \ | ||
92 | INTEGRATOR_CLCD_LCD_STATIC2 | \ | ||
93 | INTEGRATOR_CLCD_LCD_STATIC | \ | ||
94 | INTEGRATOR_CLCD_LCD_N24BITEN) | ||
95 | |||
96 | static void pl111_integrator_enable(struct drm_device *drm, u32 format) | ||
97 | { | ||
98 | u32 val; | ||
99 | |||
100 | dev_info(drm->dev, "enable Integrator CLCD connectors\n"); | ||
101 | |||
102 | /* FIXME: really needed? */ | ||
103 | val = INTEGRATOR_CLCD_LCD_STATIC1 | INTEGRATOR_CLCD_LCD_STATIC2 | | ||
104 | INTEGRATOR_CLCD_LCD0_EN | INTEGRATOR_CLCD_LCD1_EN; | ||
105 | |||
106 | switch (format) { | ||
107 | case DRM_FORMAT_XBGR8888: | ||
108 | case DRM_FORMAT_XRGB8888: | ||
109 | break; | ||
110 | case DRM_FORMAT_BGR565: | ||
111 | case DRM_FORMAT_RGB565: | ||
112 | /* truecolor RGB565 */ | ||
113 | val |= INTEGRATOR_CLCD_LCDMUX_VGA565; | ||
114 | break; | ||
115 | case DRM_FORMAT_XBGR1555: | ||
116 | case DRM_FORMAT_XRGB1555: | ||
117 | /* Pseudocolor, RGB555, BGR555 */ | ||
118 | val |= INTEGRATOR_CLCD_LCDMUX_VGA555; | ||
119 | break; | ||
120 | default: | ||
121 | dev_err(drm->dev, "unhandled format on Integrator 0x%08x\n", | ||
122 | format); | ||
123 | break; | ||
124 | } | ||
125 | |||
126 | regmap_update_bits(versatile_syscon_map, | ||
127 | INTEGRATOR_HDR_CTRL_OFFSET, | ||
128 | INTEGRATOR_CLCD_MASK, | ||
129 | val); | ||
130 | } | ||
131 | |||
132 | /* | ||
133 | * This configuration register in the Versatile and RealView | ||
134 | * family is uniformly present but appears more and more | ||
135 | * unutilized starting with the RealView series. | ||
136 | */ | ||
137 | #define SYS_CLCD 0x50 | ||
138 | #define SYS_CLCD_MODE_MASK (BIT(0)|BIT(1)) | ||
139 | #define SYS_CLCD_MODE_888 0 | ||
140 | #define SYS_CLCD_MODE_5551 BIT(0) | ||
141 | #define SYS_CLCD_MODE_565_R_LSB BIT(1) | ||
142 | #define SYS_CLCD_MODE_565_B_LSB (BIT(0)|BIT(1)) | ||
143 | #define SYS_CLCD_CONNECTOR_MASK (BIT(2)|BIT(3)|BIT(4)|BIT(5)) | ||
144 | #define SYS_CLCD_NLCDIOON BIT(2) | ||
145 | #define SYS_CLCD_VDDPOSSWITCH BIT(3) | ||
146 | #define SYS_CLCD_PWR3V5SWITCH BIT(4) | ||
147 | #define SYS_CLCD_VDDNEGSWITCH BIT(5) | ||
148 | |||
149 | static void pl111_versatile_disable(struct drm_device *drm) | ||
150 | { | ||
151 | dev_info(drm->dev, "disable Versatile CLCD connectors\n"); | ||
152 | regmap_update_bits(versatile_syscon_map, | ||
153 | SYS_CLCD, | ||
154 | SYS_CLCD_CONNECTOR_MASK, | ||
155 | 0); | ||
156 | } | ||
157 | |||
158 | static void pl111_versatile_enable(struct drm_device *drm, u32 format) | ||
159 | { | ||
160 | u32 val = 0; | ||
161 | |||
162 | dev_info(drm->dev, "enable Versatile CLCD connectors\n"); | ||
163 | |||
164 | switch (format) { | ||
165 | case DRM_FORMAT_ABGR8888: | ||
166 | case DRM_FORMAT_XBGR8888: | ||
167 | case DRM_FORMAT_ARGB8888: | ||
168 | case DRM_FORMAT_XRGB8888: | ||
169 | val |= SYS_CLCD_MODE_888; | ||
170 | break; | ||
171 | case DRM_FORMAT_BGR565: | ||
172 | val |= SYS_CLCD_MODE_565_R_LSB; | ||
173 | break; | ||
174 | case DRM_FORMAT_RGB565: | ||
175 | val |= SYS_CLCD_MODE_565_B_LSB; | ||
176 | break; | ||
177 | case DRM_FORMAT_ABGR1555: | ||
178 | case DRM_FORMAT_XBGR1555: | ||
179 | case DRM_FORMAT_ARGB1555: | ||
180 | case DRM_FORMAT_XRGB1555: | ||
181 | val |= SYS_CLCD_MODE_5551; | ||
182 | break; | ||
183 | default: | ||
184 | dev_err(drm->dev, "unhandled format on Versatile 0x%08x\n", | ||
185 | format); | ||
186 | break; | ||
187 | } | ||
188 | |||
189 | /* Set up the MUX */ | ||
190 | regmap_update_bits(versatile_syscon_map, | ||
191 | SYS_CLCD, | ||
192 | SYS_CLCD_MODE_MASK, | ||
193 | val); | ||
194 | |||
195 | /* Then enable the display */ | ||
196 | regmap_update_bits(versatile_syscon_map, | ||
197 | SYS_CLCD, | ||
198 | SYS_CLCD_CONNECTOR_MASK, | ||
199 | SYS_CLCD_NLCDIOON | SYS_CLCD_PWR3V5SWITCH); | ||
200 | } | ||
201 | |||
202 | static void pl111_realview_clcd_disable(struct drm_device *drm) | ||
203 | { | ||
204 | dev_info(drm->dev, "disable RealView CLCD connectors\n"); | ||
205 | regmap_update_bits(versatile_syscon_map, | ||
206 | SYS_CLCD, | ||
207 | SYS_CLCD_CONNECTOR_MASK, | ||
208 | 0); | ||
209 | } | ||
210 | |||
211 | static void pl111_realview_clcd_enable(struct drm_device *drm, u32 format) | ||
212 | { | ||
213 | dev_info(drm->dev, "enable RealView CLCD connectors\n"); | ||
214 | regmap_update_bits(versatile_syscon_map, | ||
215 | SYS_CLCD, | ||
216 | SYS_CLCD_CONNECTOR_MASK, | ||
217 | SYS_CLCD_NLCDIOON | SYS_CLCD_PWR3V5SWITCH); | ||
218 | } | ||
219 | |||
220 | int pl111_versatile_init(struct device *dev, struct pl111_drm_dev_private *priv) | ||
221 | { | ||
222 | const struct of_device_id *clcd_id; | ||
223 | enum versatile_clcd versatile_clcd_type; | ||
224 | struct device_node *np; | ||
225 | struct regmap *map; | ||
226 | |||
227 | np = of_find_matching_node_and_match(NULL, versatile_clcd_of_match, | ||
228 | &clcd_id); | ||
229 | if (!np) { | ||
230 | /* Non-ARM reference designs, just bail out */ | ||
231 | return 0; | ||
232 | } | ||
233 | versatile_clcd_type = (enum versatile_clcd)clcd_id->data; | ||
234 | |||
235 | map = syscon_node_to_regmap(np); | ||
236 | if (IS_ERR(map)) { | ||
237 | dev_err(dev, "no Versatile syscon regmap\n"); | ||
238 | return PTR_ERR(map); | ||
239 | } | ||
240 | |||
241 | switch (versatile_clcd_type) { | ||
242 | case INTEGRATOR_CLCD_CM: | ||
243 | versatile_syscon_map = map; | ||
244 | priv->variant_display_enable = pl111_integrator_enable; | ||
245 | dev_info(dev, "set up callbacks for Integrator PL110\n"); | ||
246 | break; | ||
247 | case VERSATILE_CLCD: | ||
248 | versatile_syscon_map = map; | ||
249 | priv->variant_display_enable = pl111_versatile_enable; | ||
250 | priv->variant_display_disable = pl111_versatile_disable; | ||
251 | dev_info(dev, "set up callbacks for Versatile PL110+\n"); | ||
252 | break; | ||
253 | case REALVIEW_CLCD_EB: | ||
254 | case REALVIEW_CLCD_PB1176: | ||
255 | case REALVIEW_CLCD_PB11MP: | ||
256 | case REALVIEW_CLCD_PBA8: | ||
257 | case REALVIEW_CLCD_PBX: | ||
258 | versatile_syscon_map = map; | ||
259 | priv->variant_display_enable = pl111_realview_clcd_enable; | ||
260 | priv->variant_display_disable = pl111_realview_clcd_disable; | ||
261 | dev_info(dev, "set up callbacks for RealView PL111\n"); | ||
262 | break; | ||
263 | default: | ||
264 | dev_info(dev, "unknown Versatile system controller\n"); | ||
265 | break; | ||
266 | } | ||
267 | |||
268 | return 0; | ||
269 | } | ||
270 | EXPORT_SYMBOL_GPL(pl111_versatile_init); | ||
diff --git a/drivers/gpu/drm/pl111/pl111_versatile.h b/drivers/gpu/drm/pl111/pl111_versatile.h new file mode 100644 index 000000000000..41aa6d969dc6 --- /dev/null +++ b/drivers/gpu/drm/pl111/pl111_versatile.h | |||
@@ -0,0 +1,9 @@ | |||
1 | #include <linux/device.h> | ||
2 | #include "pl111_drm.h" | ||
3 | |||
4 | #ifndef PL111_VERSATILE_H | ||
5 | #define PL111_VERSATILE_H | ||
6 | |||
7 | int pl111_versatile_init(struct device *dev, struct pl111_drm_dev_private *priv); | ||
8 | |||
9 | #endif | ||
diff --git a/drivers/gpu/drm/rockchip/Kconfig b/drivers/gpu/drm/rockchip/Kconfig index dcc539ba85d6..0c31f0a27b9c 100644 --- a/drivers/gpu/drm/rockchip/Kconfig +++ b/drivers/gpu/drm/rockchip/Kconfig | |||
@@ -57,4 +57,12 @@ config ROCKCHIP_INNO_HDMI | |||
57 | for the Innosilicon HDMI driver. If you want to enable | 57 | for the Innosilicon HDMI driver. If you want to enable |
58 | HDMI on RK3036 based SoC, you should select this option. | 58 | HDMI on RK3036 based SoC, you should select this option. |
59 | 59 | ||
60 | config ROCKCHIP_LVDS | ||
61 | bool "Rockchip LVDS support" | ||
62 | depends on DRM_ROCKCHIP | ||
63 | help | ||
64 | Choose this option to enable support for Rockchip LVDS controllers. | ||
65 | Rockchip rk3288 SoC has LVDS TX Controller can be used, and it | ||
66 | support LVDS, rgb, dual LVDS output mode. say Y to enable its | ||
67 | driver. | ||
60 | endif | 68 | endif |
diff --git a/drivers/gpu/drm/rockchip/Makefile b/drivers/gpu/drm/rockchip/Makefile index fa8dc9d9aac2..a881d2cc4f25 100644 --- a/drivers/gpu/drm/rockchip/Makefile +++ b/drivers/gpu/drm/rockchip/Makefile | |||
@@ -12,5 +12,6 @@ rockchipdrm-$(CONFIG_ROCKCHIP_CDN_DP) += cdn-dp-core.o cdn-dp-reg.o | |||
12 | rockchipdrm-$(CONFIG_ROCKCHIP_DW_HDMI) += dw_hdmi-rockchip.o | 12 | rockchipdrm-$(CONFIG_ROCKCHIP_DW_HDMI) += dw_hdmi-rockchip.o |
13 | rockchipdrm-$(CONFIG_ROCKCHIP_DW_MIPI_DSI) += dw-mipi-dsi.o | 13 | rockchipdrm-$(CONFIG_ROCKCHIP_DW_MIPI_DSI) += dw-mipi-dsi.o |
14 | rockchipdrm-$(CONFIG_ROCKCHIP_INNO_HDMI) += inno_hdmi.o | 14 | rockchipdrm-$(CONFIG_ROCKCHIP_INNO_HDMI) += inno_hdmi.o |
15 | rockchipdrm-$(CONFIG_ROCKCHIP_LVDS) += rockchip_lvds.o | ||
15 | 16 | ||
16 | obj-$(CONFIG_DRM_ROCKCHIP) += rockchipdrm.o | 17 | obj-$(CONFIG_DRM_ROCKCHIP) += rockchipdrm.o |
diff --git a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c index 9606121fa185..4d3f6ad0abdd 100644 --- a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c +++ b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c | |||
@@ -88,7 +88,7 @@ static void analogix_dp_psr_set(struct drm_encoder *encoder, bool enabled) | |||
88 | if (!analogix_dp_psr_supported(dp->dev)) | 88 | if (!analogix_dp_psr_supported(dp->dev)) |
89 | return; | 89 | return; |
90 | 90 | ||
91 | dev_dbg(dp->dev, "%s PSR...\n", enabled ? "Entry" : "Exit"); | 91 | DRM_DEV_DEBUG(dp->dev, "%s PSR...\n", enabled ? "Entry" : "Exit"); |
92 | 92 | ||
93 | spin_lock_irqsave(&dp->psr_lock, flags); | 93 | spin_lock_irqsave(&dp->psr_lock, flags); |
94 | if (enabled) | 94 | if (enabled) |
@@ -110,7 +110,7 @@ static void analogix_dp_psr_work(struct work_struct *work) | |||
110 | ret = rockchip_drm_wait_vact_end(dp->encoder.crtc, | 110 | ret = rockchip_drm_wait_vact_end(dp->encoder.crtc, |
111 | PSR_WAIT_LINE_FLAG_TIMEOUT_MS); | 111 | PSR_WAIT_LINE_FLAG_TIMEOUT_MS); |
112 | if (ret) { | 112 | if (ret) { |
113 | dev_err(dp->dev, "line flag interrupt did not arrive\n"); | 113 | DRM_DEV_ERROR(dp->dev, "line flag interrupt did not arrive\n"); |
114 | return; | 114 | return; |
115 | } | 115 | } |
116 | 116 | ||
@@ -140,13 +140,13 @@ static int rockchip_dp_poweron(struct analogix_dp_plat_data *plat_data) | |||
140 | 140 | ||
141 | ret = clk_prepare_enable(dp->pclk); | 141 | ret = clk_prepare_enable(dp->pclk); |
142 | if (ret < 0) { | 142 | if (ret < 0) { |
143 | dev_err(dp->dev, "failed to enable pclk %d\n", ret); | 143 | DRM_DEV_ERROR(dp->dev, "failed to enable pclk %d\n", ret); |
144 | return ret; | 144 | return ret; |
145 | } | 145 | } |
146 | 146 | ||
147 | ret = rockchip_dp_pre_init(dp); | 147 | ret = rockchip_dp_pre_init(dp); |
148 | if (ret < 0) { | 148 | if (ret < 0) { |
149 | dev_err(dp->dev, "failed to dp pre init %d\n", ret); | 149 | DRM_DEV_ERROR(dp->dev, "failed to dp pre init %d\n", ret); |
150 | clk_disable_unprepare(dp->pclk); | 150 | clk_disable_unprepare(dp->pclk); |
151 | return ret; | 151 | return ret; |
152 | } | 152 | } |
@@ -211,17 +211,17 @@ static void rockchip_dp_drm_encoder_enable(struct drm_encoder *encoder) | |||
211 | else | 211 | else |
212 | val = dp->data->lcdsel_big; | 212 | val = dp->data->lcdsel_big; |
213 | 213 | ||
214 | dev_dbg(dp->dev, "vop %s output to dp\n", (ret) ? "LIT" : "BIG"); | 214 | DRM_DEV_DEBUG(dp->dev, "vop %s output to dp\n", (ret) ? "LIT" : "BIG"); |
215 | 215 | ||
216 | ret = clk_prepare_enable(dp->grfclk); | 216 | ret = clk_prepare_enable(dp->grfclk); |
217 | if (ret < 0) { | 217 | if (ret < 0) { |
218 | dev_err(dp->dev, "failed to enable grfclk %d\n", ret); | 218 | DRM_DEV_ERROR(dp->dev, "failed to enable grfclk %d\n", ret); |
219 | return; | 219 | return; |
220 | } | 220 | } |
221 | 221 | ||
222 | ret = regmap_write(dp->grf, dp->data->lcdsel_grf_reg, val); | 222 | ret = regmap_write(dp->grf, dp->data->lcdsel_grf_reg, val); |
223 | if (ret != 0) | 223 | if (ret != 0) |
224 | dev_err(dp->dev, "Could not write to GRF: %d\n", ret); | 224 | DRM_DEV_ERROR(dp->dev, "Could not write to GRF: %d\n", ret); |
225 | 225 | ||
226 | clk_disable_unprepare(dp->grfclk); | 226 | clk_disable_unprepare(dp->grfclk); |
227 | } | 227 | } |
@@ -277,7 +277,7 @@ static int rockchip_dp_init(struct rockchip_dp_device *dp) | |||
277 | 277 | ||
278 | dp->grf = syscon_regmap_lookup_by_phandle(np, "rockchip,grf"); | 278 | dp->grf = syscon_regmap_lookup_by_phandle(np, "rockchip,grf"); |
279 | if (IS_ERR(dp->grf)) { | 279 | if (IS_ERR(dp->grf)) { |
280 | dev_err(dev, "failed to get rockchip,grf property\n"); | 280 | DRM_DEV_ERROR(dev, "failed to get rockchip,grf property\n"); |
281 | return PTR_ERR(dp->grf); | 281 | return PTR_ERR(dp->grf); |
282 | } | 282 | } |
283 | 283 | ||
@@ -287,31 +287,31 @@ static int rockchip_dp_init(struct rockchip_dp_device *dp) | |||
287 | } else if (PTR_ERR(dp->grfclk) == -EPROBE_DEFER) { | 287 | } else if (PTR_ERR(dp->grfclk) == -EPROBE_DEFER) { |
288 | return -EPROBE_DEFER; | 288 | return -EPROBE_DEFER; |
289 | } else if (IS_ERR(dp->grfclk)) { | 289 | } else if (IS_ERR(dp->grfclk)) { |
290 | dev_err(dev, "failed to get grf clock\n"); | 290 | DRM_DEV_ERROR(dev, "failed to get grf clock\n"); |
291 | return PTR_ERR(dp->grfclk); | 291 | return PTR_ERR(dp->grfclk); |
292 | } | 292 | } |
293 | 293 | ||
294 | dp->pclk = devm_clk_get(dev, "pclk"); | 294 | dp->pclk = devm_clk_get(dev, "pclk"); |
295 | if (IS_ERR(dp->pclk)) { | 295 | if (IS_ERR(dp->pclk)) { |
296 | dev_err(dev, "failed to get pclk property\n"); | 296 | DRM_DEV_ERROR(dev, "failed to get pclk property\n"); |
297 | return PTR_ERR(dp->pclk); | 297 | return PTR_ERR(dp->pclk); |
298 | } | 298 | } |
299 | 299 | ||
300 | dp->rst = devm_reset_control_get(dev, "dp"); | 300 | dp->rst = devm_reset_control_get(dev, "dp"); |
301 | if (IS_ERR(dp->rst)) { | 301 | if (IS_ERR(dp->rst)) { |
302 | dev_err(dev, "failed to get dp reset control\n"); | 302 | DRM_DEV_ERROR(dev, "failed to get dp reset control\n"); |
303 | return PTR_ERR(dp->rst); | 303 | return PTR_ERR(dp->rst); |
304 | } | 304 | } |
305 | 305 | ||
306 | ret = clk_prepare_enable(dp->pclk); | 306 | ret = clk_prepare_enable(dp->pclk); |
307 | if (ret < 0) { | 307 | if (ret < 0) { |
308 | dev_err(dp->dev, "failed to enable pclk %d\n", ret); | 308 | DRM_DEV_ERROR(dp->dev, "failed to enable pclk %d\n", ret); |
309 | return ret; | 309 | return ret; |
310 | } | 310 | } |
311 | 311 | ||
312 | ret = rockchip_dp_pre_init(dp); | 312 | ret = rockchip_dp_pre_init(dp); |
313 | if (ret < 0) { | 313 | if (ret < 0) { |
314 | dev_err(dp->dev, "failed to pre init %d\n", ret); | 314 | DRM_DEV_ERROR(dp->dev, "failed to pre init %d\n", ret); |
315 | clk_disable_unprepare(dp->pclk); | 315 | clk_disable_unprepare(dp->pclk); |
316 | return ret; | 316 | return ret; |
317 | } | 317 | } |
diff --git a/drivers/gpu/drm/rockchip/cdn-dp-reg.c b/drivers/gpu/drm/rockchip/cdn-dp-reg.c index b14d211f6c21..eb3042c6d1b2 100644 --- a/drivers/gpu/drm/rockchip/cdn-dp-reg.c +++ b/drivers/gpu/drm/rockchip/cdn-dp-reg.c | |||
@@ -323,7 +323,7 @@ int cdn_dp_load_firmware(struct cdn_dp_device *dp, const u32 *i_mem, | |||
323 | reg = readl(dp->regs + VER_LIB_H_ADDR) & 0xff; | 323 | reg = readl(dp->regs + VER_LIB_H_ADDR) & 0xff; |
324 | dp->fw_version |= reg << 24; | 324 | dp->fw_version |= reg << 24; |
325 | 325 | ||
326 | dev_dbg(dp->dev, "firmware version: %x\n", dp->fw_version); | 326 | DRM_DEV_DEBUG(dp->dev, "firmware version: %x\n", dp->fw_version); |
327 | 327 | ||
328 | return 0; | 328 | return 0; |
329 | } | 329 | } |
diff --git a/drivers/gpu/drm/rockchip/dw-mipi-dsi.c b/drivers/gpu/drm/rockchip/dw-mipi-dsi.c index 9a20b9dc27c8..b15755b6129c 100644 --- a/drivers/gpu/drm/rockchip/dw-mipi-dsi.c +++ b/drivers/gpu/drm/rockchip/dw-mipi-dsi.c | |||
@@ -430,9 +430,9 @@ static int dw_mipi_dsi_phy_init(struct dw_mipi_dsi *dsi) | |||
430 | 430 | ||
431 | testdin = max_mbps_to_testdin(dsi->lane_mbps); | 431 | testdin = max_mbps_to_testdin(dsi->lane_mbps); |
432 | if (testdin < 0) { | 432 | if (testdin < 0) { |
433 | dev_err(dsi->dev, | 433 | DRM_DEV_ERROR(dsi->dev, |
434 | "failed to get testdin for %dmbps lane clock\n", | 434 | "failed to get testdin for %dmbps lane clock\n", |
435 | dsi->lane_mbps); | 435 | dsi->lane_mbps); |
436 | return testdin; | 436 | return testdin; |
437 | } | 437 | } |
438 | 438 | ||
@@ -443,7 +443,7 @@ static int dw_mipi_dsi_phy_init(struct dw_mipi_dsi *dsi) | |||
443 | 443 | ||
444 | ret = clk_prepare_enable(dsi->phy_cfg_clk); | 444 | ret = clk_prepare_enable(dsi->phy_cfg_clk); |
445 | if (ret) { | 445 | if (ret) { |
446 | dev_err(dsi->dev, "Failed to enable phy_cfg_clk\n"); | 446 | DRM_DEV_ERROR(dsi->dev, "Failed to enable phy_cfg_clk\n"); |
447 | return ret; | 447 | return ret; |
448 | } | 448 | } |
449 | 449 | ||
@@ -501,7 +501,7 @@ static int dw_mipi_dsi_phy_init(struct dw_mipi_dsi *dsi) | |||
501 | ret = readl_poll_timeout(dsi->base + DSI_PHY_STATUS, | 501 | ret = readl_poll_timeout(dsi->base + DSI_PHY_STATUS, |
502 | val, val & LOCK, 1000, PHY_STATUS_TIMEOUT_US); | 502 | val, val & LOCK, 1000, PHY_STATUS_TIMEOUT_US); |
503 | if (ret < 0) { | 503 | if (ret < 0) { |
504 | dev_err(dsi->dev, "failed to wait for phy lock state\n"); | 504 | DRM_DEV_ERROR(dsi->dev, "failed to wait for phy lock state\n"); |
505 | goto phy_init_end; | 505 | goto phy_init_end; |
506 | } | 506 | } |
507 | 507 | ||
@@ -509,8 +509,8 @@ static int dw_mipi_dsi_phy_init(struct dw_mipi_dsi *dsi) | |||
509 | val, val & STOP_STATE_CLK_LANE, 1000, | 509 | val, val & STOP_STATE_CLK_LANE, 1000, |
510 | PHY_STATUS_TIMEOUT_US); | 510 | PHY_STATUS_TIMEOUT_US); |
511 | if (ret < 0) | 511 | if (ret < 0) |
512 | dev_err(dsi->dev, | 512 | DRM_DEV_ERROR(dsi->dev, |
513 | "failed to wait for phy clk lane stop state\n"); | 513 | "failed to wait for phy clk lane stop state\n"); |
514 | 514 | ||
515 | phy_init_end: | 515 | phy_init_end: |
516 | clk_disable_unprepare(dsi->phy_cfg_clk); | 516 | clk_disable_unprepare(dsi->phy_cfg_clk); |
@@ -529,8 +529,9 @@ static int dw_mipi_dsi_get_lane_bps(struct dw_mipi_dsi *dsi, | |||
529 | 529 | ||
530 | bpp = mipi_dsi_pixel_format_to_bpp(dsi->format); | 530 | bpp = mipi_dsi_pixel_format_to_bpp(dsi->format); |
531 | if (bpp < 0) { | 531 | if (bpp < 0) { |
532 | dev_err(dsi->dev, "failed to get bpp for pixel format %d\n", | 532 | DRM_DEV_ERROR(dsi->dev, |
533 | dsi->format); | 533 | "failed to get bpp for pixel format %d\n", |
534 | dsi->format); | ||
534 | return bpp; | 535 | return bpp; |
535 | } | 536 | } |
536 | 537 | ||
@@ -541,7 +542,8 @@ static int dw_mipi_dsi_get_lane_bps(struct dw_mipi_dsi *dsi, | |||
541 | if (tmp < max_mbps) | 542 | if (tmp < max_mbps) |
542 | target_mbps = tmp; | 543 | target_mbps = tmp; |
543 | else | 544 | else |
544 | dev_err(dsi->dev, "DPHY clock frequency is out of range\n"); | 545 | DRM_DEV_ERROR(dsi->dev, |
546 | "DPHY clock frequency is out of range\n"); | ||
545 | } | 547 | } |
546 | 548 | ||
547 | pllref = DIV_ROUND_UP(clk_get_rate(dsi->pllref_clk), USEC_PER_SEC); | 549 | pllref = DIV_ROUND_UP(clk_get_rate(dsi->pllref_clk), USEC_PER_SEC); |
@@ -582,8 +584,9 @@ static int dw_mipi_dsi_host_attach(struct mipi_dsi_host *host, | |||
582 | struct dw_mipi_dsi *dsi = host_to_dsi(host); | 584 | struct dw_mipi_dsi *dsi = host_to_dsi(host); |
583 | 585 | ||
584 | if (device->lanes > dsi->pdata->max_data_lanes) { | 586 | if (device->lanes > dsi->pdata->max_data_lanes) { |
585 | dev_err(dsi->dev, "the number of data lanes(%u) is too many\n", | 587 | DRM_DEV_ERROR(dsi->dev, |
586 | device->lanes); | 588 | "the number of data lanes(%u) is too many\n", |
589 | device->lanes); | ||
587 | return -EINVAL; | 590 | return -EINVAL; |
588 | } | 591 | } |
589 | 592 | ||
@@ -632,7 +635,8 @@ static int dw_mipi_dsi_gen_pkt_hdr_write(struct dw_mipi_dsi *dsi, u32 hdr_val) | |||
632 | val, !(val & GEN_CMD_FULL), 1000, | 635 | val, !(val & GEN_CMD_FULL), 1000, |
633 | CMD_PKT_STATUS_TIMEOUT_US); | 636 | CMD_PKT_STATUS_TIMEOUT_US); |
634 | if (ret < 0) { | 637 | if (ret < 0) { |
635 | dev_err(dsi->dev, "failed to get available command FIFO\n"); | 638 | DRM_DEV_ERROR(dsi->dev, |
639 | "failed to get available command FIFO\n"); | ||
636 | return ret; | 640 | return ret; |
637 | } | 641 | } |
638 | 642 | ||
@@ -643,7 +647,7 @@ static int dw_mipi_dsi_gen_pkt_hdr_write(struct dw_mipi_dsi *dsi, u32 hdr_val) | |||
643 | val, (val & mask) == mask, | 647 | val, (val & mask) == mask, |
644 | 1000, CMD_PKT_STATUS_TIMEOUT_US); | 648 | 1000, CMD_PKT_STATUS_TIMEOUT_US); |
645 | if (ret < 0) { | 649 | if (ret < 0) { |
646 | dev_err(dsi->dev, "failed to write command FIFO\n"); | 650 | DRM_DEV_ERROR(dsi->dev, "failed to write command FIFO\n"); |
647 | return ret; | 651 | return ret; |
648 | } | 652 | } |
649 | 653 | ||
@@ -663,8 +667,9 @@ static int dw_mipi_dsi_dcs_short_write(struct dw_mipi_dsi *dsi, | |||
663 | data |= tx_buf[1] << 8; | 667 | data |= tx_buf[1] << 8; |
664 | 668 | ||
665 | if (msg->tx_len > 2) { | 669 | if (msg->tx_len > 2) { |
666 | dev_err(dsi->dev, "too long tx buf length %zu for short write\n", | 670 | DRM_DEV_ERROR(dsi->dev, |
667 | msg->tx_len); | 671 | "too long tx buf length %zu for short write\n", |
672 | msg->tx_len); | ||
668 | return -EINVAL; | 673 | return -EINVAL; |
669 | } | 674 | } |
670 | 675 | ||
@@ -682,8 +687,9 @@ static int dw_mipi_dsi_dcs_long_write(struct dw_mipi_dsi *dsi, | |||
682 | u32 val; | 687 | u32 val; |
683 | 688 | ||
684 | if (msg->tx_len < 3) { | 689 | if (msg->tx_len < 3) { |
685 | dev_err(dsi->dev, "wrong tx buf length %zu for long write\n", | 690 | DRM_DEV_ERROR(dsi->dev, |
686 | msg->tx_len); | 691 | "wrong tx buf length %zu for long write\n", |
692 | msg->tx_len); | ||
687 | return -EINVAL; | 693 | return -EINVAL; |
688 | } | 694 | } |
689 | 695 | ||
@@ -704,8 +710,8 @@ static int dw_mipi_dsi_dcs_long_write(struct dw_mipi_dsi *dsi, | |||
704 | val, !(val & GEN_PLD_W_FULL), 1000, | 710 | val, !(val & GEN_PLD_W_FULL), 1000, |
705 | CMD_PKT_STATUS_TIMEOUT_US); | 711 | CMD_PKT_STATUS_TIMEOUT_US); |
706 | if (ret < 0) { | 712 | if (ret < 0) { |
707 | dev_err(dsi->dev, | 713 | DRM_DEV_ERROR(dsi->dev, |
708 | "failed to get available write payload FIFO\n"); | 714 | "failed to get available write payload FIFO\n"); |
709 | return ret; | 715 | return ret; |
710 | } | 716 | } |
711 | } | 717 | } |
@@ -731,8 +737,8 @@ static ssize_t dw_mipi_dsi_host_transfer(struct mipi_dsi_host *host, | |||
731 | ret = dw_mipi_dsi_dcs_long_write(dsi, msg); | 737 | ret = dw_mipi_dsi_dcs_long_write(dsi, msg); |
732 | break; | 738 | break; |
733 | default: | 739 | default: |
734 | dev_err(dsi->dev, "unsupported message type 0x%02x\n", | 740 | DRM_DEV_ERROR(dsi->dev, "unsupported message type 0x%02x\n", |
735 | msg->type); | 741 | msg->type); |
736 | ret = -EINVAL; | 742 | ret = -EINVAL; |
737 | } | 743 | } |
738 | 744 | ||
@@ -935,7 +941,7 @@ static void dw_mipi_dsi_encoder_disable(struct drm_encoder *encoder) | |||
935 | return; | 941 | return; |
936 | 942 | ||
937 | if (clk_prepare_enable(dsi->pclk)) { | 943 | if (clk_prepare_enable(dsi->pclk)) { |
938 | dev_err(dsi->dev, "%s: Failed to enable pclk\n", __func__); | 944 | DRM_DEV_ERROR(dsi->dev, "Failed to enable pclk\n"); |
939 | return; | 945 | return; |
940 | } | 946 | } |
941 | 947 | ||
@@ -967,7 +973,7 @@ static void dw_mipi_dsi_encoder_enable(struct drm_encoder *encoder) | |||
967 | return; | 973 | return; |
968 | 974 | ||
969 | if (clk_prepare_enable(dsi->pclk)) { | 975 | if (clk_prepare_enable(dsi->pclk)) { |
970 | dev_err(dsi->dev, "%s: Failed to enable pclk\n", __func__); | 976 | DRM_DEV_ERROR(dsi->dev, "Failed to enable pclk\n"); |
971 | return; | 977 | return; |
972 | } | 978 | } |
973 | 979 | ||
@@ -991,7 +997,7 @@ static void dw_mipi_dsi_encoder_enable(struct drm_encoder *encoder) | |||
991 | */ | 997 | */ |
992 | ret = clk_prepare_enable(dsi->grf_clk); | 998 | ret = clk_prepare_enable(dsi->grf_clk); |
993 | if (ret) { | 999 | if (ret) { |
994 | dev_err(dsi->dev, "Failed to enable grf_clk: %d\n", ret); | 1000 | DRM_DEV_ERROR(dsi->dev, "Failed to enable grf_clk: %d\n", ret); |
995 | return; | 1001 | return; |
996 | } | 1002 | } |
997 | 1003 | ||
@@ -1004,7 +1010,7 @@ static void dw_mipi_dsi_encoder_enable(struct drm_encoder *encoder) | |||
1004 | 1010 | ||
1005 | dw_mipi_dsi_set_mode(dsi, DW_MIPI_DSI_CMD_MODE); | 1011 | dw_mipi_dsi_set_mode(dsi, DW_MIPI_DSI_CMD_MODE); |
1006 | if (drm_panel_prepare(dsi->panel)) | 1012 | if (drm_panel_prepare(dsi->panel)) |
1007 | dev_err(dsi->dev, "failed to prepare panel\n"); | 1013 | DRM_DEV_ERROR(dsi->dev, "failed to prepare panel\n"); |
1008 | 1014 | ||
1009 | dw_mipi_dsi_set_mode(dsi, DW_MIPI_DSI_VID_MODE); | 1015 | dw_mipi_dsi_set_mode(dsi, DW_MIPI_DSI_VID_MODE); |
1010 | drm_panel_enable(dsi->panel); | 1016 | drm_panel_enable(dsi->panel); |
@@ -1017,7 +1023,8 @@ static void dw_mipi_dsi_encoder_enable(struct drm_encoder *encoder) | |||
1017 | val = pdata->dsi0_en_bit << 16; | 1023 | val = pdata->dsi0_en_bit << 16; |
1018 | 1024 | ||
1019 | regmap_write(dsi->grf_regmap, pdata->grf_switch_reg, val); | 1025 | regmap_write(dsi->grf_regmap, pdata->grf_switch_reg, val); |
1020 | dev_dbg(dsi->dev, "vop %s output to dsi0\n", (mux) ? "LIT" : "BIG"); | 1026 | DRM_DEV_DEBUG(dsi->dev, |
1027 | "vop %s output to dsi0\n", (mux) ? "LIT" : "BIG"); | ||
1021 | dsi->dpms_mode = DRM_MODE_DPMS_ON; | 1028 | dsi->dpms_mode = DRM_MODE_DPMS_ON; |
1022 | 1029 | ||
1023 | clk_disable_unprepare(dsi->grf_clk); | 1030 | clk_disable_unprepare(dsi->grf_clk); |
@@ -1111,7 +1118,7 @@ static int dw_mipi_dsi_register(struct drm_device *drm, | |||
1111 | ret = drm_encoder_init(drm, &dsi->encoder, &dw_mipi_dsi_encoder_funcs, | 1118 | ret = drm_encoder_init(drm, &dsi->encoder, &dw_mipi_dsi_encoder_funcs, |
1112 | DRM_MODE_ENCODER_DSI, NULL); | 1119 | DRM_MODE_ENCODER_DSI, NULL); |
1113 | if (ret) { | 1120 | if (ret) { |
1114 | dev_err(dev, "Failed to initialize encoder with drm\n"); | 1121 | DRM_DEV_ERROR(dev, "Failed to initialize encoder with drm\n"); |
1115 | return ret; | 1122 | return ret; |
1116 | } | 1123 | } |
1117 | 1124 | ||
@@ -1133,7 +1140,7 @@ static int rockchip_mipi_parse_dt(struct dw_mipi_dsi *dsi) | |||
1133 | 1140 | ||
1134 | dsi->grf_regmap = syscon_regmap_lookup_by_phandle(np, "rockchip,grf"); | 1141 | dsi->grf_regmap = syscon_regmap_lookup_by_phandle(np, "rockchip,grf"); |
1135 | if (IS_ERR(dsi->grf_regmap)) { | 1142 | if (IS_ERR(dsi->grf_regmap)) { |
1136 | dev_err(dsi->dev, "Unable to get rockchip,grf\n"); | 1143 | DRM_DEV_ERROR(dsi->dev, "Unable to get rockchip,grf\n"); |
1137 | return PTR_ERR(dsi->grf_regmap); | 1144 | return PTR_ERR(dsi->grf_regmap); |
1138 | } | 1145 | } |
1139 | 1146 | ||
@@ -1205,14 +1212,15 @@ static int dw_mipi_dsi_bind(struct device *dev, struct device *master, | |||
1205 | dsi->pllref_clk = devm_clk_get(dev, "ref"); | 1212 | dsi->pllref_clk = devm_clk_get(dev, "ref"); |
1206 | if (IS_ERR(dsi->pllref_clk)) { | 1213 | if (IS_ERR(dsi->pllref_clk)) { |
1207 | ret = PTR_ERR(dsi->pllref_clk); | 1214 | ret = PTR_ERR(dsi->pllref_clk); |
1208 | dev_err(dev, "Unable to get pll reference clock: %d\n", ret); | 1215 | DRM_DEV_ERROR(dev, |
1216 | "Unable to get pll reference clock: %d\n", ret); | ||
1209 | return ret; | 1217 | return ret; |
1210 | } | 1218 | } |
1211 | 1219 | ||
1212 | dsi->pclk = devm_clk_get(dev, "pclk"); | 1220 | dsi->pclk = devm_clk_get(dev, "pclk"); |
1213 | if (IS_ERR(dsi->pclk)) { | 1221 | if (IS_ERR(dsi->pclk)) { |
1214 | ret = PTR_ERR(dsi->pclk); | 1222 | ret = PTR_ERR(dsi->pclk); |
1215 | dev_err(dev, "Unable to get pclk: %d\n", ret); | 1223 | DRM_DEV_ERROR(dev, "Unable to get pclk: %d\n", ret); |
1216 | return ret; | 1224 | return ret; |
1217 | } | 1225 | } |
1218 | 1226 | ||
@@ -1226,7 +1234,8 @@ static int dw_mipi_dsi_bind(struct device *dev, struct device *master, | |||
1226 | if (ret == -ENOENT) { | 1234 | if (ret == -ENOENT) { |
1227 | apb_rst = NULL; | 1235 | apb_rst = NULL; |
1228 | } else { | 1236 | } else { |
1229 | dev_err(dev, "Unable to get reset control: %d\n", ret); | 1237 | DRM_DEV_ERROR(dev, |
1238 | "Unable to get reset control: %d\n", ret); | ||
1230 | return ret; | 1239 | return ret; |
1231 | } | 1240 | } |
1232 | } | 1241 | } |
@@ -1234,7 +1243,7 @@ static int dw_mipi_dsi_bind(struct device *dev, struct device *master, | |||
1234 | if (apb_rst) { | 1243 | if (apb_rst) { |
1235 | ret = clk_prepare_enable(dsi->pclk); | 1244 | ret = clk_prepare_enable(dsi->pclk); |
1236 | if (ret) { | 1245 | if (ret) { |
1237 | dev_err(dev, "%s: Failed to enable pclk\n", __func__); | 1246 | DRM_DEV_ERROR(dev, "Failed to enable pclk\n"); |
1238 | return ret; | 1247 | return ret; |
1239 | } | 1248 | } |
1240 | 1249 | ||
@@ -1249,7 +1258,8 @@ static int dw_mipi_dsi_bind(struct device *dev, struct device *master, | |||
1249 | dsi->phy_cfg_clk = devm_clk_get(dev, "phy_cfg"); | 1258 | dsi->phy_cfg_clk = devm_clk_get(dev, "phy_cfg"); |
1250 | if (IS_ERR(dsi->phy_cfg_clk)) { | 1259 | if (IS_ERR(dsi->phy_cfg_clk)) { |
1251 | ret = PTR_ERR(dsi->phy_cfg_clk); | 1260 | ret = PTR_ERR(dsi->phy_cfg_clk); |
1252 | dev_err(dev, "Unable to get phy_cfg_clk: %d\n", ret); | 1261 | DRM_DEV_ERROR(dev, |
1262 | "Unable to get phy_cfg_clk: %d\n", ret); | ||
1253 | return ret; | 1263 | return ret; |
1254 | } | 1264 | } |
1255 | } | 1265 | } |
@@ -1258,20 +1268,20 @@ static int dw_mipi_dsi_bind(struct device *dev, struct device *master, | |||
1258 | dsi->grf_clk = devm_clk_get(dev, "grf"); | 1268 | dsi->grf_clk = devm_clk_get(dev, "grf"); |
1259 | if (IS_ERR(dsi->grf_clk)) { | 1269 | if (IS_ERR(dsi->grf_clk)) { |
1260 | ret = PTR_ERR(dsi->grf_clk); | 1270 | ret = PTR_ERR(dsi->grf_clk); |
1261 | dev_err(dev, "Unable to get grf_clk: %d\n", ret); | 1271 | DRM_DEV_ERROR(dev, "Unable to get grf_clk: %d\n", ret); |
1262 | return ret; | 1272 | return ret; |
1263 | } | 1273 | } |
1264 | } | 1274 | } |
1265 | 1275 | ||
1266 | ret = clk_prepare_enable(dsi->pllref_clk); | 1276 | ret = clk_prepare_enable(dsi->pllref_clk); |
1267 | if (ret) { | 1277 | if (ret) { |
1268 | dev_err(dev, "%s: Failed to enable pllref_clk\n", __func__); | 1278 | DRM_DEV_ERROR(dev, "Failed to enable pllref_clk\n"); |
1269 | return ret; | 1279 | return ret; |
1270 | } | 1280 | } |
1271 | 1281 | ||
1272 | ret = dw_mipi_dsi_register(drm, dsi); | 1282 | ret = dw_mipi_dsi_register(drm, dsi); |
1273 | if (ret) { | 1283 | if (ret) { |
1274 | dev_err(dev, "Failed to register mipi_dsi: %d\n", ret); | 1284 | DRM_DEV_ERROR(dev, "Failed to register mipi_dsi: %d\n", ret); |
1275 | goto err_pllref; | 1285 | goto err_pllref; |
1276 | } | 1286 | } |
1277 | 1287 | ||
@@ -1281,7 +1291,7 @@ static int dw_mipi_dsi_bind(struct device *dev, struct device *master, | |||
1281 | dsi->dsi_host.dev = dev; | 1291 | dsi->dsi_host.dev = dev; |
1282 | ret = mipi_dsi_host_register(&dsi->dsi_host); | 1292 | ret = mipi_dsi_host_register(&dsi->dsi_host); |
1283 | if (ret) { | 1293 | if (ret) { |
1284 | dev_err(dev, "Failed to register MIPI host: %d\n", ret); | 1294 | DRM_DEV_ERROR(dev, "Failed to register MIPI host: %d\n", ret); |
1285 | goto err_cleanup; | 1295 | goto err_cleanup; |
1286 | } | 1296 | } |
1287 | 1297 | ||
diff --git a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c index ccd5d595ada7..1eb02a82fd91 100644 --- a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c +++ b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c | |||
@@ -168,7 +168,7 @@ static int rockchip_hdmi_parse_dt(struct rockchip_hdmi *hdmi) | |||
168 | 168 | ||
169 | hdmi->regmap = syscon_regmap_lookup_by_phandle(np, "rockchip,grf"); | 169 | hdmi->regmap = syscon_regmap_lookup_by_phandle(np, "rockchip,grf"); |
170 | if (IS_ERR(hdmi->regmap)) { | 170 | if (IS_ERR(hdmi->regmap)) { |
171 | dev_err(hdmi->dev, "Unable to get rockchip,grf\n"); | 171 | DRM_DEV_ERROR(hdmi->dev, "Unable to get rockchip,grf\n"); |
172 | return PTR_ERR(hdmi->regmap); | 172 | return PTR_ERR(hdmi->regmap); |
173 | } | 173 | } |
174 | 174 | ||
@@ -178,7 +178,7 @@ static int rockchip_hdmi_parse_dt(struct rockchip_hdmi *hdmi) | |||
178 | } else if (PTR_ERR(hdmi->vpll_clk) == -EPROBE_DEFER) { | 178 | } else if (PTR_ERR(hdmi->vpll_clk) == -EPROBE_DEFER) { |
179 | return -EPROBE_DEFER; | 179 | return -EPROBE_DEFER; |
180 | } else if (IS_ERR(hdmi->vpll_clk)) { | 180 | } else if (IS_ERR(hdmi->vpll_clk)) { |
181 | dev_err(hdmi->dev, "failed to get grf clock\n"); | 181 | DRM_DEV_ERROR(hdmi->dev, "failed to get grf clock\n"); |
182 | return PTR_ERR(hdmi->vpll_clk); | 182 | return PTR_ERR(hdmi->vpll_clk); |
183 | } | 183 | } |
184 | 184 | ||
@@ -188,13 +188,14 @@ static int rockchip_hdmi_parse_dt(struct rockchip_hdmi *hdmi) | |||
188 | } else if (PTR_ERR(hdmi->grf_clk) == -EPROBE_DEFER) { | 188 | } else if (PTR_ERR(hdmi->grf_clk) == -EPROBE_DEFER) { |
189 | return -EPROBE_DEFER; | 189 | return -EPROBE_DEFER; |
190 | } else if (IS_ERR(hdmi->grf_clk)) { | 190 | } else if (IS_ERR(hdmi->grf_clk)) { |
191 | dev_err(hdmi->dev, "failed to get grf clock\n"); | 191 | DRM_DEV_ERROR(hdmi->dev, "failed to get grf clock\n"); |
192 | return PTR_ERR(hdmi->grf_clk); | 192 | return PTR_ERR(hdmi->grf_clk); |
193 | } | 193 | } |
194 | 194 | ||
195 | ret = clk_prepare_enable(hdmi->vpll_clk); | 195 | ret = clk_prepare_enable(hdmi->vpll_clk); |
196 | if (ret) { | 196 | if (ret) { |
197 | dev_err(hdmi->dev, "Failed to enable HDMI vpll: %d\n", ret); | 197 | DRM_DEV_ERROR(hdmi->dev, |
198 | "Failed to enable HDMI vpll: %d\n", ret); | ||
198 | return ret; | 199 | return ret; |
199 | } | 200 | } |
200 | 201 | ||
@@ -259,17 +260,17 @@ static void dw_hdmi_rockchip_encoder_enable(struct drm_encoder *encoder) | |||
259 | 260 | ||
260 | ret = clk_prepare_enable(hdmi->grf_clk); | 261 | ret = clk_prepare_enable(hdmi->grf_clk); |
261 | if (ret < 0) { | 262 | if (ret < 0) { |
262 | dev_err(hdmi->dev, "failed to enable grfclk %d\n", ret); | 263 | DRM_DEV_ERROR(hdmi->dev, "failed to enable grfclk %d\n", ret); |
263 | return; | 264 | return; |
264 | } | 265 | } |
265 | 266 | ||
266 | ret = regmap_write(hdmi->regmap, hdmi->chip_data->lcdsel_grf_reg, val); | 267 | ret = regmap_write(hdmi->regmap, hdmi->chip_data->lcdsel_grf_reg, val); |
267 | if (ret != 0) | 268 | if (ret != 0) |
268 | dev_err(hdmi->dev, "Could not write to GRF: %d\n", ret); | 269 | DRM_DEV_ERROR(hdmi->dev, "Could not write to GRF: %d\n", ret); |
269 | 270 | ||
270 | clk_disable_unprepare(hdmi->grf_clk); | 271 | clk_disable_unprepare(hdmi->grf_clk); |
271 | dev_dbg(hdmi->dev, "vop %s output to hdmi\n", | 272 | DRM_DEV_DEBUG(hdmi->dev, "vop %s output to hdmi\n", |
272 | ret ? "LIT" : "BIG"); | 273 | ret ? "LIT" : "BIG"); |
273 | } | 274 | } |
274 | 275 | ||
275 | static int | 276 | static int |
@@ -368,7 +369,7 @@ static int dw_hdmi_rockchip_bind(struct device *dev, struct device *master, | |||
368 | 369 | ||
369 | ret = rockchip_hdmi_parse_dt(hdmi); | 370 | ret = rockchip_hdmi_parse_dt(hdmi); |
370 | if (ret) { | 371 | if (ret) { |
371 | dev_err(hdmi->dev, "Unable to parse OF data\n"); | 372 | DRM_DEV_ERROR(hdmi->dev, "Unable to parse OF data\n"); |
372 | return ret; | 373 | return ret; |
373 | } | 374 | } |
374 | 375 | ||
diff --git a/drivers/gpu/drm/rockchip/inno_hdmi.c b/drivers/gpu/drm/rockchip/inno_hdmi.c index 7a251a54e792..ee584d87111f 100644 --- a/drivers/gpu/drm/rockchip/inno_hdmi.c +++ b/drivers/gpu/drm/rockchip/inno_hdmi.c | |||
@@ -224,7 +224,7 @@ static void inno_hdmi_set_pwr_mode(struct inno_hdmi *hdmi, int mode) | |||
224 | break; | 224 | break; |
225 | 225 | ||
226 | default: | 226 | default: |
227 | dev_err(hdmi->dev, "Unknown power mode %d\n", mode); | 227 | DRM_DEV_ERROR(hdmi->dev, "Unknown power mode %d\n", mode); |
228 | } | 228 | } |
229 | } | 229 | } |
230 | 230 | ||
@@ -742,8 +742,9 @@ static int inno_hdmi_i2c_xfer(struct i2c_adapter *adap, | |||
742 | hdmi_writeb(hdmi, HDMI_INTERRUPT_STATUS1, m_INT_EDID_READY); | 742 | hdmi_writeb(hdmi, HDMI_INTERRUPT_STATUS1, m_INT_EDID_READY); |
743 | 743 | ||
744 | for (i = 0; i < num; i++) { | 744 | for (i = 0; i < num; i++) { |
745 | dev_dbg(hdmi->dev, "xfer: num: %d/%d, len: %d, flags: %#x\n", | 745 | DRM_DEV_DEBUG(hdmi->dev, |
746 | i + 1, num, msgs[i].len, msgs[i].flags); | 746 | "xfer: num: %d/%d, len: %d, flags: %#x\n", |
747 | i + 1, num, msgs[i].len, msgs[i].flags); | ||
747 | 748 | ||
748 | if (msgs[i].flags & I2C_M_RD) | 749 | if (msgs[i].flags & I2C_M_RD) |
749 | ret = inno_hdmi_i2c_read(hdmi, &msgs[i]); | 750 | ret = inno_hdmi_i2c_read(hdmi, &msgs[i]); |
@@ -806,7 +807,7 @@ static struct i2c_adapter *inno_hdmi_i2c_adapter(struct inno_hdmi *hdmi) | |||
806 | 807 | ||
807 | hdmi->i2c = i2c; | 808 | hdmi->i2c = i2c; |
808 | 809 | ||
809 | dev_info(hdmi->dev, "registered %s I2C bus driver\n", adap->name); | 810 | DRM_DEV_INFO(hdmi->dev, "registered %s I2C bus driver\n", adap->name); |
810 | 811 | ||
811 | return adap; | 812 | return adap; |
812 | } | 813 | } |
@@ -838,13 +839,14 @@ static int inno_hdmi_bind(struct device *dev, struct device *master, | |||
838 | 839 | ||
839 | hdmi->pclk = devm_clk_get(hdmi->dev, "pclk"); | 840 | hdmi->pclk = devm_clk_get(hdmi->dev, "pclk"); |
840 | if (IS_ERR(hdmi->pclk)) { | 841 | if (IS_ERR(hdmi->pclk)) { |
841 | dev_err(hdmi->dev, "Unable to get HDMI pclk clk\n"); | 842 | DRM_DEV_ERROR(hdmi->dev, "Unable to get HDMI pclk clk\n"); |
842 | return PTR_ERR(hdmi->pclk); | 843 | return PTR_ERR(hdmi->pclk); |
843 | } | 844 | } |
844 | 845 | ||
845 | ret = clk_prepare_enable(hdmi->pclk); | 846 | ret = clk_prepare_enable(hdmi->pclk); |
846 | if (ret) { | 847 | if (ret) { |
847 | dev_err(hdmi->dev, "Cannot enable HDMI pclk clock: %d\n", ret); | 848 | DRM_DEV_ERROR(hdmi->dev, |
849 | "Cannot enable HDMI pclk clock: %d\n", ret); | ||
848 | return ret; | 850 | return ret; |
849 | } | 851 | } |
850 | 852 | ||
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_drv.c b/drivers/gpu/drm/rockchip/rockchip_drm_drv.c index ff3d0f5efbb1..76d63de5921d 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_drv.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.c | |||
@@ -58,7 +58,7 @@ int rockchip_drm_dma_attach_device(struct drm_device *drm_dev, | |||
58 | 58 | ||
59 | ret = iommu_attach_device(private->domain, dev); | 59 | ret = iommu_attach_device(private->domain, dev); |
60 | if (ret) { | 60 | if (ret) { |
61 | dev_err(dev, "Failed to attach iommu device\n"); | 61 | DRM_DEV_ERROR(dev, "Failed to attach iommu device\n"); |
62 | return ret; | 62 | return ret; |
63 | } | 63 | } |
64 | 64 | ||
@@ -373,8 +373,9 @@ static int rockchip_drm_platform_of_probe(struct device *dev) | |||
373 | 373 | ||
374 | iommu = of_parse_phandle(port->parent, "iommus", 0); | 374 | iommu = of_parse_phandle(port->parent, "iommus", 0); |
375 | if (!iommu || !of_device_is_available(iommu->parent)) { | 375 | if (!iommu || !of_device_is_available(iommu->parent)) { |
376 | dev_dbg(dev, "no iommu attached for %pOF, using non-iommu buffers\n", | 376 | DRM_DEV_DEBUG(dev, |
377 | port->parent); | 377 | "no iommu attached for %pOF, using non-iommu buffers\n", |
378 | port->parent); | ||
378 | /* | 379 | /* |
379 | * if there is a crtc not support iommu, force set all | 380 | * if there is a crtc not support iommu, force set all |
380 | * crtc use non-iommu buffer. | 381 | * crtc use non-iommu buffer. |
@@ -389,12 +390,13 @@ static int rockchip_drm_platform_of_probe(struct device *dev) | |||
389 | } | 390 | } |
390 | 391 | ||
391 | if (i == 0) { | 392 | if (i == 0) { |
392 | dev_err(dev, "missing 'ports' property\n"); | 393 | DRM_DEV_ERROR(dev, "missing 'ports' property\n"); |
393 | return -ENODEV; | 394 | return -ENODEV; |
394 | } | 395 | } |
395 | 396 | ||
396 | if (!found) { | 397 | if (!found) { |
397 | dev_err(dev, "No available vop found for display-subsystem.\n"); | 398 | DRM_DEV_ERROR(dev, |
399 | "No available vop found for display-subsystem.\n"); | ||
398 | return -ENODEV; | 400 | return -ENODEV; |
399 | } | 401 | } |
400 | 402 | ||
@@ -453,6 +455,8 @@ static int __init rockchip_drm_init(void) | |||
453 | 455 | ||
454 | num_rockchip_sub_drivers = 0; | 456 | num_rockchip_sub_drivers = 0; |
455 | ADD_ROCKCHIP_SUB_DRIVER(vop_platform_driver, CONFIG_DRM_ROCKCHIP); | 457 | ADD_ROCKCHIP_SUB_DRIVER(vop_platform_driver, CONFIG_DRM_ROCKCHIP); |
458 | ADD_ROCKCHIP_SUB_DRIVER(rockchip_lvds_driver, | ||
459 | CONFIG_ROCKCHIP_LVDS); | ||
456 | ADD_ROCKCHIP_SUB_DRIVER(rockchip_dp_driver, | 460 | ADD_ROCKCHIP_SUB_DRIVER(rockchip_dp_driver, |
457 | CONFIG_ROCKCHIP_ANALOGIX_DP); | 461 | CONFIG_ROCKCHIP_ANALOGIX_DP); |
458 | ADD_ROCKCHIP_SUB_DRIVER(cdn_dp_driver, CONFIG_ROCKCHIP_CDN_DP); | 462 | ADD_ROCKCHIP_SUB_DRIVER(cdn_dp_driver, CONFIG_ROCKCHIP_CDN_DP); |
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_drv.h b/drivers/gpu/drm/rockchip/rockchip_drm_drv.h index c7e96b82cf63..498dfbc52cec 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_drv.h +++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.h | |||
@@ -69,5 +69,6 @@ extern struct platform_driver dw_hdmi_rockchip_pltfm_driver; | |||
69 | extern struct platform_driver dw_mipi_dsi_driver; | 69 | extern struct platform_driver dw_mipi_dsi_driver; |
70 | extern struct platform_driver inno_hdmi_driver; | 70 | extern struct platform_driver inno_hdmi_driver; |
71 | extern struct platform_driver rockchip_dp_driver; | 71 | extern struct platform_driver rockchip_dp_driver; |
72 | extern struct platform_driver rockchip_lvds_driver; | ||
72 | extern struct platform_driver vop_platform_driver; | 73 | extern struct platform_driver vop_platform_driver; |
73 | #endif /* _ROCKCHIP_DRM_DRV_H_ */ | 74 | #endif /* _ROCKCHIP_DRM_DRV_H_ */ |
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_fb.c b/drivers/gpu/drm/rockchip/rockchip_drm_fb.c index 70773041785b..cd2ace0c3caa 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_fb.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_fb.c | |||
@@ -100,8 +100,9 @@ rockchip_fb_alloc(struct drm_device *dev, const struct drm_mode_fb_cmd2 *mode_cm | |||
100 | ret = drm_framebuffer_init(dev, &rockchip_fb->fb, | 100 | ret = drm_framebuffer_init(dev, &rockchip_fb->fb, |
101 | &rockchip_drm_fb_funcs); | 101 | &rockchip_drm_fb_funcs); |
102 | if (ret) { | 102 | if (ret) { |
103 | dev_err(dev->dev, "Failed to initialize framebuffer: %d\n", | 103 | DRM_DEV_ERROR(dev->dev, |
104 | ret); | 104 | "Failed to initialize framebuffer: %d\n", |
105 | ret); | ||
105 | kfree(rockchip_fb); | 106 | kfree(rockchip_fb); |
106 | return ERR_PTR(ret); | 107 | return ERR_PTR(ret); |
107 | } | 108 | } |
@@ -134,7 +135,8 @@ rockchip_user_fb_create(struct drm_device *dev, struct drm_file *file_priv, | |||
134 | 135 | ||
135 | obj = drm_gem_object_lookup(file_priv, mode_cmd->handles[i]); | 136 | obj = drm_gem_object_lookup(file_priv, mode_cmd->handles[i]); |
136 | if (!obj) { | 137 | if (!obj) { |
137 | dev_err(dev->dev, "Failed to lookup GEM object\n"); | 138 | DRM_DEV_ERROR(dev->dev, |
139 | "Failed to lookup GEM object\n"); | ||
138 | ret = -ENXIO; | 140 | ret = -ENXIO; |
139 | goto err_gem_object_unreference; | 141 | goto err_gem_object_unreference; |
140 | } | 142 | } |
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_fbdev.c b/drivers/gpu/drm/rockchip/rockchip_drm_fbdev.c index 724579ebf947..e6650553f5d6 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_fbdev.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_fbdev.c | |||
@@ -76,7 +76,7 @@ static int rockchip_drm_fbdev_create(struct drm_fb_helper *helper, | |||
76 | 76 | ||
77 | fbi = drm_fb_helper_alloc_fbi(helper); | 77 | fbi = drm_fb_helper_alloc_fbi(helper); |
78 | if (IS_ERR(fbi)) { | 78 | if (IS_ERR(fbi)) { |
79 | dev_err(dev->dev, "Failed to create framebuffer info.\n"); | 79 | DRM_DEV_ERROR(dev->dev, "Failed to create framebuffer info.\n"); |
80 | ret = PTR_ERR(fbi); | 80 | ret = PTR_ERR(fbi); |
81 | goto out; | 81 | goto out; |
82 | } | 82 | } |
@@ -84,7 +84,8 @@ static int rockchip_drm_fbdev_create(struct drm_fb_helper *helper, | |||
84 | helper->fb = rockchip_drm_framebuffer_init(dev, &mode_cmd, | 84 | helper->fb = rockchip_drm_framebuffer_init(dev, &mode_cmd, |
85 | private->fbdev_bo); | 85 | private->fbdev_bo); |
86 | if (IS_ERR(helper->fb)) { | 86 | if (IS_ERR(helper->fb)) { |
87 | dev_err(dev->dev, "Failed to allocate DRM framebuffer.\n"); | 87 | DRM_DEV_ERROR(dev->dev, |
88 | "Failed to allocate DRM framebuffer.\n"); | ||
88 | ret = PTR_ERR(helper->fb); | 89 | ret = PTR_ERR(helper->fb); |
89 | goto out; | 90 | goto out; |
90 | } | 91 | } |
@@ -138,21 +139,24 @@ int rockchip_drm_fbdev_init(struct drm_device *dev) | |||
138 | 139 | ||
139 | ret = drm_fb_helper_init(dev, helper, ROCKCHIP_MAX_CONNECTOR); | 140 | ret = drm_fb_helper_init(dev, helper, ROCKCHIP_MAX_CONNECTOR); |
140 | if (ret < 0) { | 141 | if (ret < 0) { |
141 | dev_err(dev->dev, "Failed to initialize drm fb helper - %d.\n", | 142 | DRM_DEV_ERROR(dev->dev, |
142 | ret); | 143 | "Failed to initialize drm fb helper - %d.\n", |
144 | ret); | ||
143 | return ret; | 145 | return ret; |
144 | } | 146 | } |
145 | 147 | ||
146 | ret = drm_fb_helper_single_add_all_connectors(helper); | 148 | ret = drm_fb_helper_single_add_all_connectors(helper); |
147 | if (ret < 0) { | 149 | if (ret < 0) { |
148 | dev_err(dev->dev, "Failed to add connectors - %d.\n", ret); | 150 | DRM_DEV_ERROR(dev->dev, |
151 | "Failed to add connectors - %d.\n", ret); | ||
149 | goto err_drm_fb_helper_fini; | 152 | goto err_drm_fb_helper_fini; |
150 | } | 153 | } |
151 | 154 | ||
152 | ret = drm_fb_helper_initial_config(helper, PREFERRED_BPP); | 155 | ret = drm_fb_helper_initial_config(helper, PREFERRED_BPP); |
153 | if (ret < 0) { | 156 | if (ret < 0) { |
154 | dev_err(dev->dev, "Failed to set initial hw config - %d.\n", | 157 | DRM_DEV_ERROR(dev->dev, |
155 | ret); | 158 | "Failed to set initial hw config - %d.\n", |
159 | ret); | ||
156 | goto err_drm_fb_helper_fini; | 160 | goto err_drm_fb_helper_fini; |
157 | } | 161 | } |
158 | 162 | ||
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c index bf9ed0e63973..19128b4dea54 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c | |||
@@ -160,7 +160,7 @@ static void vop_reg_set(struct vop *vop, const struct vop_reg *reg, | |||
160 | int offset, mask, shift; | 160 | int offset, mask, shift; |
161 | 161 | ||
162 | if (!reg || !reg->mask) { | 162 | if (!reg || !reg->mask) { |
163 | dev_dbg(vop->dev, "Warning: not support %s\n", reg_name); | 163 | DRM_DEV_DEBUG(vop->dev, "Warning: not support %s\n", reg_name); |
164 | return; | 164 | return; |
165 | } | 165 | } |
166 | 166 | ||
@@ -499,7 +499,7 @@ static int vop_enable(struct drm_crtc *crtc) | |||
499 | 499 | ||
500 | ret = pm_runtime_get_sync(vop->dev); | 500 | ret = pm_runtime_get_sync(vop->dev); |
501 | if (ret < 0) { | 501 | if (ret < 0) { |
502 | dev_err(vop->dev, "failed to get pm runtime: %d\n", ret); | 502 | DRM_DEV_ERROR(vop->dev, "failed to get pm runtime: %d\n", ret); |
503 | return ret; | 503 | return ret; |
504 | } | 504 | } |
505 | 505 | ||
@@ -523,7 +523,8 @@ static int vop_enable(struct drm_crtc *crtc) | |||
523 | */ | 523 | */ |
524 | ret = rockchip_drm_dma_attach_device(vop->drm_dev, vop->dev); | 524 | ret = rockchip_drm_dma_attach_device(vop->drm_dev, vop->dev); |
525 | if (ret) { | 525 | if (ret) { |
526 | dev_err(vop->dev, "failed to attach dma mapping, %d\n", ret); | 526 | DRM_DEV_ERROR(vop->dev, |
527 | "failed to attach dma mapping, %d\n", ret); | ||
527 | goto err_disable_aclk; | 528 | goto err_disable_aclk; |
528 | } | 529 | } |
529 | 530 | ||
@@ -1361,42 +1362,42 @@ static int vop_initial(struct vop *vop) | |||
1361 | 1362 | ||
1362 | vop->hclk = devm_clk_get(vop->dev, "hclk_vop"); | 1363 | vop->hclk = devm_clk_get(vop->dev, "hclk_vop"); |
1363 | if (IS_ERR(vop->hclk)) { | 1364 | if (IS_ERR(vop->hclk)) { |
1364 | dev_err(vop->dev, "failed to get hclk source\n"); | 1365 | DRM_DEV_ERROR(vop->dev, "failed to get hclk source\n"); |
1365 | return PTR_ERR(vop->hclk); | 1366 | return PTR_ERR(vop->hclk); |
1366 | } | 1367 | } |
1367 | vop->aclk = devm_clk_get(vop->dev, "aclk_vop"); | 1368 | vop->aclk = devm_clk_get(vop->dev, "aclk_vop"); |
1368 | if (IS_ERR(vop->aclk)) { | 1369 | if (IS_ERR(vop->aclk)) { |
1369 | dev_err(vop->dev, "failed to get aclk source\n"); | 1370 | DRM_DEV_ERROR(vop->dev, "failed to get aclk source\n"); |
1370 | return PTR_ERR(vop->aclk); | 1371 | return PTR_ERR(vop->aclk); |
1371 | } | 1372 | } |
1372 | vop->dclk = devm_clk_get(vop->dev, "dclk_vop"); | 1373 | vop->dclk = devm_clk_get(vop->dev, "dclk_vop"); |
1373 | if (IS_ERR(vop->dclk)) { | 1374 | if (IS_ERR(vop->dclk)) { |
1374 | dev_err(vop->dev, "failed to get dclk source\n"); | 1375 | DRM_DEV_ERROR(vop->dev, "failed to get dclk source\n"); |
1375 | return PTR_ERR(vop->dclk); | 1376 | return PTR_ERR(vop->dclk); |
1376 | } | 1377 | } |
1377 | 1378 | ||
1378 | ret = pm_runtime_get_sync(vop->dev); | 1379 | ret = pm_runtime_get_sync(vop->dev); |
1379 | if (ret < 0) { | 1380 | if (ret < 0) { |
1380 | dev_err(vop->dev, "failed to get pm runtime: %d\n", ret); | 1381 | DRM_DEV_ERROR(vop->dev, "failed to get pm runtime: %d\n", ret); |
1381 | return ret; | 1382 | return ret; |
1382 | } | 1383 | } |
1383 | 1384 | ||
1384 | ret = clk_prepare(vop->dclk); | 1385 | ret = clk_prepare(vop->dclk); |
1385 | if (ret < 0) { | 1386 | if (ret < 0) { |
1386 | dev_err(vop->dev, "failed to prepare dclk\n"); | 1387 | DRM_DEV_ERROR(vop->dev, "failed to prepare dclk\n"); |
1387 | goto err_put_pm_runtime; | 1388 | goto err_put_pm_runtime; |
1388 | } | 1389 | } |
1389 | 1390 | ||
1390 | /* Enable both the hclk and aclk to setup the vop */ | 1391 | /* Enable both the hclk and aclk to setup the vop */ |
1391 | ret = clk_prepare_enable(vop->hclk); | 1392 | ret = clk_prepare_enable(vop->hclk); |
1392 | if (ret < 0) { | 1393 | if (ret < 0) { |
1393 | dev_err(vop->dev, "failed to prepare/enable hclk\n"); | 1394 | DRM_DEV_ERROR(vop->dev, "failed to prepare/enable hclk\n"); |
1394 | goto err_unprepare_dclk; | 1395 | goto err_unprepare_dclk; |
1395 | } | 1396 | } |
1396 | 1397 | ||
1397 | ret = clk_prepare_enable(vop->aclk); | 1398 | ret = clk_prepare_enable(vop->aclk); |
1398 | if (ret < 0) { | 1399 | if (ret < 0) { |
1399 | dev_err(vop->dev, "failed to prepare/enable aclk\n"); | 1400 | DRM_DEV_ERROR(vop->dev, "failed to prepare/enable aclk\n"); |
1400 | goto err_disable_hclk; | 1401 | goto err_disable_hclk; |
1401 | } | 1402 | } |
1402 | 1403 | ||
@@ -1405,7 +1406,7 @@ static int vop_initial(struct vop *vop) | |||
1405 | */ | 1406 | */ |
1406 | ahb_rst = devm_reset_control_get(vop->dev, "ahb"); | 1407 | ahb_rst = devm_reset_control_get(vop->dev, "ahb"); |
1407 | if (IS_ERR(ahb_rst)) { | 1408 | if (IS_ERR(ahb_rst)) { |
1408 | dev_err(vop->dev, "failed to get ahb reset\n"); | 1409 | DRM_DEV_ERROR(vop->dev, "failed to get ahb reset\n"); |
1409 | ret = PTR_ERR(ahb_rst); | 1410 | ret = PTR_ERR(ahb_rst); |
1410 | goto err_disable_aclk; | 1411 | goto err_disable_aclk; |
1411 | } | 1412 | } |
@@ -1434,7 +1435,7 @@ static int vop_initial(struct vop *vop) | |||
1434 | */ | 1435 | */ |
1435 | vop->dclk_rst = devm_reset_control_get(vop->dev, "dclk"); | 1436 | vop->dclk_rst = devm_reset_control_get(vop->dev, "dclk"); |
1436 | if (IS_ERR(vop->dclk_rst)) { | 1437 | if (IS_ERR(vop->dclk_rst)) { |
1437 | dev_err(vop->dev, "failed to get dclk reset\n"); | 1438 | DRM_DEV_ERROR(vop->dev, "failed to get dclk reset\n"); |
1438 | ret = PTR_ERR(vop->dclk_rst); | 1439 | ret = PTR_ERR(vop->dclk_rst); |
1439 | goto err_disable_aclk; | 1440 | goto err_disable_aclk; |
1440 | } | 1441 | } |
@@ -1511,7 +1512,7 @@ int rockchip_drm_wait_vact_end(struct drm_crtc *crtc, unsigned int mstimeout) | |||
1511 | vop_line_flag_irq_disable(vop); | 1512 | vop_line_flag_irq_disable(vop); |
1512 | 1513 | ||
1513 | if (jiffies_left == 0) { | 1514 | if (jiffies_left == 0) { |
1514 | dev_err(vop->dev, "Timeout waiting for IRQ\n"); | 1515 | DRM_DEV_ERROR(vop->dev, "Timeout waiting for IRQ\n"); |
1515 | return -ETIMEDOUT; | 1516 | return -ETIMEDOUT; |
1516 | } | 1517 | } |
1517 | 1518 | ||
@@ -1558,7 +1559,7 @@ static int vop_bind(struct device *dev, struct device *master, void *data) | |||
1558 | 1559 | ||
1559 | irq = platform_get_irq(pdev, 0); | 1560 | irq = platform_get_irq(pdev, 0); |
1560 | if (irq < 0) { | 1561 | if (irq < 0) { |
1561 | dev_err(dev, "cannot find irq for vop\n"); | 1562 | DRM_DEV_ERROR(dev, "cannot find irq for vop\n"); |
1562 | return irq; | 1563 | return irq; |
1563 | } | 1564 | } |
1564 | vop->irq = (unsigned int)irq; | 1565 | vop->irq = (unsigned int)irq; |
@@ -1584,7 +1585,8 @@ static int vop_bind(struct device *dev, struct device *master, void *data) | |||
1584 | 1585 | ||
1585 | ret = vop_initial(vop); | 1586 | ret = vop_initial(vop); |
1586 | if (ret < 0) { | 1587 | if (ret < 0) { |
1587 | dev_err(&pdev->dev, "cannot initial vop dev - err %d\n", ret); | 1588 | DRM_DEV_ERROR(&pdev->dev, |
1589 | "cannot initial vop dev - err %d\n", ret); | ||
1588 | goto err_disable_pm_runtime; | 1590 | goto err_disable_pm_runtime; |
1589 | } | 1591 | } |
1590 | 1592 | ||
diff --git a/drivers/gpu/drm/rockchip/rockchip_lvds.c b/drivers/gpu/drm/rockchip/rockchip_lvds.c new file mode 100644 index 000000000000..c5fbe533796c --- /dev/null +++ b/drivers/gpu/drm/rockchip/rockchip_lvds.c | |||
@@ -0,0 +1,581 @@ | |||
1 | /* | ||
2 | * Copyright (C) Fuzhou Rockchip Electronics Co.Ltd | ||
3 | * Author: | ||
4 | * Mark Yao <mark.yao@rock-chips.com> | ||
5 | * Sandy Huang <hjc@rock-chips.com> | ||
6 | * | ||
7 | * This software is licensed under the terms of the GNU General Public | ||
8 | * License version 2, as published by the Free Software Foundation, and | ||
9 | * may be copied, distributed, and modified under those terms. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | */ | ||
16 | |||
17 | #include <drm/drmP.h> | ||
18 | #include <drm/drm_atomic_helper.h> | ||
19 | #include <drm/drm_crtc_helper.h> | ||
20 | #include <drm/drm_dp_helper.h> | ||
21 | #include <drm/drm_panel.h> | ||
22 | #include <drm/drm_of.h> | ||
23 | |||
24 | #include <linux/component.h> | ||
25 | #include <linux/clk.h> | ||
26 | #include <linux/mfd/syscon.h> | ||
27 | #include <linux/of_graph.h> | ||
28 | #include <linux/pm_runtime.h> | ||
29 | #include <linux/regmap.h> | ||
30 | #include <linux/reset.h> | ||
31 | |||
32 | #include "rockchip_drm_drv.h" | ||
33 | #include "rockchip_drm_vop.h" | ||
34 | #include "rockchip_lvds.h" | ||
35 | |||
36 | #define DISPLAY_OUTPUT_RGB 0 | ||
37 | #define DISPLAY_OUTPUT_LVDS 1 | ||
38 | #define DISPLAY_OUTPUT_DUAL_LVDS 2 | ||
39 | |||
40 | #define connector_to_lvds(c) \ | ||
41 | container_of(c, struct rockchip_lvds, connector) | ||
42 | |||
43 | #define encoder_to_lvds(c) \ | ||
44 | container_of(c, struct rockchip_lvds, encoder) | ||
45 | |||
46 | /** | ||
47 | * rockchip_lvds_soc_data - rockchip lvds Soc private data | ||
48 | * @ch1_offset: lvds channel 1 registe offset | ||
49 | * grf_soc_con6: general registe offset for LVDS contrl | ||
50 | * grf_soc_con7: general registe offset for LVDS contrl | ||
51 | * has_vop_sel: to indicate whether need to choose from different VOP. | ||
52 | */ | ||
53 | struct rockchip_lvds_soc_data { | ||
54 | u32 ch1_offset; | ||
55 | int grf_soc_con6; | ||
56 | int grf_soc_con7; | ||
57 | bool has_vop_sel; | ||
58 | }; | ||
59 | |||
60 | struct rockchip_lvds { | ||
61 | struct device *dev; | ||
62 | void __iomem *regs; | ||
63 | struct regmap *grf; | ||
64 | struct clk *pclk; | ||
65 | const struct rockchip_lvds_soc_data *soc_data; | ||
66 | int output; /* rgb lvds or dual lvds output */ | ||
67 | int format; /* vesa or jeida format */ | ||
68 | struct drm_device *drm_dev; | ||
69 | struct drm_panel *panel; | ||
70 | struct drm_bridge *bridge; | ||
71 | struct drm_connector connector; | ||
72 | struct drm_encoder encoder; | ||
73 | struct dev_pin_info *pins; | ||
74 | }; | ||
75 | |||
76 | static inline void lvds_writel(struct rockchip_lvds *lvds, u32 offset, u32 val) | ||
77 | { | ||
78 | writel_relaxed(val, lvds->regs + offset); | ||
79 | if (lvds->output == DISPLAY_OUTPUT_LVDS) | ||
80 | return; | ||
81 | writel_relaxed(val, lvds->regs + offset + lvds->soc_data->ch1_offset); | ||
82 | } | ||
83 | |||
84 | static inline int lvds_name_to_format(const char *s) | ||
85 | { | ||
86 | if (strncmp(s, "jeida-18", 8) == 0) | ||
87 | return LVDS_JEIDA_18; | ||
88 | else if (strncmp(s, "jeida-24", 8) == 0) | ||
89 | return LVDS_JEIDA_24; | ||
90 | else if (strncmp(s, "vesa-24", 7) == 0) | ||
91 | return LVDS_VESA_24; | ||
92 | |||
93 | return -EINVAL; | ||
94 | } | ||
95 | |||
96 | static inline int lvds_name_to_output(const char *s) | ||
97 | { | ||
98 | if (strncmp(s, "rgb", 3) == 0) | ||
99 | return DISPLAY_OUTPUT_RGB; | ||
100 | else if (strncmp(s, "lvds", 4) == 0) | ||
101 | return DISPLAY_OUTPUT_LVDS; | ||
102 | else if (strncmp(s, "duallvds", 8) == 0) | ||
103 | return DISPLAY_OUTPUT_DUAL_LVDS; | ||
104 | |||
105 | return -EINVAL; | ||
106 | } | ||
107 | |||
108 | static int rockchip_lvds_poweron(struct rockchip_lvds *lvds) | ||
109 | { | ||
110 | int ret; | ||
111 | u32 val; | ||
112 | |||
113 | ret = clk_enable(lvds->pclk); | ||
114 | if (ret < 0) { | ||
115 | DRM_DEV_ERROR(lvds->dev, "failed to enable lvds pclk %d\n", ret); | ||
116 | return ret; | ||
117 | } | ||
118 | ret = pm_runtime_get_sync(lvds->dev); | ||
119 | if (ret < 0) { | ||
120 | DRM_DEV_ERROR(lvds->dev, "failed to get pm runtime: %d\n", ret); | ||
121 | clk_disable(lvds->pclk); | ||
122 | return ret; | ||
123 | } | ||
124 | val = RK3288_LVDS_CH0_REG0_LANE4_EN | RK3288_LVDS_CH0_REG0_LANE3_EN | | ||
125 | RK3288_LVDS_CH0_REG0_LANE2_EN | RK3288_LVDS_CH0_REG0_LANE1_EN | | ||
126 | RK3288_LVDS_CH0_REG0_LANE0_EN; | ||
127 | if (lvds->output == DISPLAY_OUTPUT_RGB) { | ||
128 | val |= RK3288_LVDS_CH0_REG0_TTL_EN | | ||
129 | RK3288_LVDS_CH0_REG0_LANECK_EN; | ||
130 | lvds_writel(lvds, RK3288_LVDS_CH0_REG0, val); | ||
131 | lvds_writel(lvds, RK3288_LVDS_CH0_REG2, | ||
132 | RK3288_LVDS_PLL_FBDIV_REG2(0x46)); | ||
133 | lvds_writel(lvds, RK3288_LVDS_CH0_REG4, | ||
134 | RK3288_LVDS_CH0_REG4_LANECK_TTL_MODE | | ||
135 | RK3288_LVDS_CH0_REG4_LANE4_TTL_MODE | | ||
136 | RK3288_LVDS_CH0_REG4_LANE3_TTL_MODE | | ||
137 | RK3288_LVDS_CH0_REG4_LANE2_TTL_MODE | | ||
138 | RK3288_LVDS_CH0_REG4_LANE1_TTL_MODE | | ||
139 | RK3288_LVDS_CH0_REG4_LANE0_TTL_MODE); | ||
140 | lvds_writel(lvds, RK3288_LVDS_CH0_REG5, | ||
141 | RK3288_LVDS_CH0_REG5_LANECK_TTL_DATA | | ||
142 | RK3288_LVDS_CH0_REG5_LANE4_TTL_DATA | | ||
143 | RK3288_LVDS_CH0_REG5_LANE3_TTL_DATA | | ||
144 | RK3288_LVDS_CH0_REG5_LANE2_TTL_DATA | | ||
145 | RK3288_LVDS_CH0_REG5_LANE1_TTL_DATA | | ||
146 | RK3288_LVDS_CH0_REG5_LANE0_TTL_DATA); | ||
147 | } else { | ||
148 | val |= RK3288_LVDS_CH0_REG0_LVDS_EN | | ||
149 | RK3288_LVDS_CH0_REG0_LANECK_EN; | ||
150 | lvds_writel(lvds, RK3288_LVDS_CH0_REG0, val); | ||
151 | lvds_writel(lvds, RK3288_LVDS_CH0_REG1, | ||
152 | RK3288_LVDS_CH0_REG1_LANECK_BIAS | | ||
153 | RK3288_LVDS_CH0_REG1_LANE4_BIAS | | ||
154 | RK3288_LVDS_CH0_REG1_LANE3_BIAS | | ||
155 | RK3288_LVDS_CH0_REG1_LANE2_BIAS | | ||
156 | RK3288_LVDS_CH0_REG1_LANE1_BIAS | | ||
157 | RK3288_LVDS_CH0_REG1_LANE0_BIAS); | ||
158 | lvds_writel(lvds, RK3288_LVDS_CH0_REG2, | ||
159 | RK3288_LVDS_CH0_REG2_RESERVE_ON | | ||
160 | RK3288_LVDS_CH0_REG2_LANECK_LVDS_MODE | | ||
161 | RK3288_LVDS_CH0_REG2_LANE4_LVDS_MODE | | ||
162 | RK3288_LVDS_CH0_REG2_LANE3_LVDS_MODE | | ||
163 | RK3288_LVDS_CH0_REG2_LANE2_LVDS_MODE | | ||
164 | RK3288_LVDS_CH0_REG2_LANE1_LVDS_MODE | | ||
165 | RK3288_LVDS_CH0_REG2_LANE0_LVDS_MODE | | ||
166 | RK3288_LVDS_PLL_FBDIV_REG2(0x46)); | ||
167 | lvds_writel(lvds, RK3288_LVDS_CH0_REG4, 0x00); | ||
168 | lvds_writel(lvds, RK3288_LVDS_CH0_REG5, 0x00); | ||
169 | } | ||
170 | lvds_writel(lvds, RK3288_LVDS_CH0_REG3, RK3288_LVDS_PLL_FBDIV_REG3(0x46)); | ||
171 | lvds_writel(lvds, RK3288_LVDS_CH0_REGD, RK3288_LVDS_PLL_PREDIV_REGD(0x0a)); | ||
172 | lvds_writel(lvds, RK3288_LVDS_CH0_REG20, RK3288_LVDS_CH0_REG20_LSB); | ||
173 | |||
174 | lvds_writel(lvds, RK3288_LVDS_CFG_REGC, RK3288_LVDS_CFG_REGC_PLL_ENABLE); | ||
175 | lvds_writel(lvds, RK3288_LVDS_CFG_REG21, RK3288_LVDS_CFG_REG21_TX_ENABLE); | ||
176 | |||
177 | return 0; | ||
178 | } | ||
179 | |||
180 | static void rockchip_lvds_poweroff(struct rockchip_lvds *lvds) | ||
181 | { | ||
182 | int ret; | ||
183 | u32 val; | ||
184 | |||
185 | lvds_writel(lvds, RK3288_LVDS_CFG_REG21, RK3288_LVDS_CFG_REG21_TX_ENABLE); | ||
186 | lvds_writel(lvds, RK3288_LVDS_CFG_REGC, RK3288_LVDS_CFG_REGC_PLL_ENABLE); | ||
187 | val = LVDS_DUAL | LVDS_TTL_EN | LVDS_CH0_EN | LVDS_CH1_EN | LVDS_PWRDN; | ||
188 | val |= val << 16; | ||
189 | ret = regmap_write(lvds->grf, lvds->soc_data->grf_soc_con7, val); | ||
190 | if (ret != 0) | ||
191 | DRM_DEV_ERROR(lvds->dev, "Could not write to GRF: %d\n", ret); | ||
192 | |||
193 | pm_runtime_put(lvds->dev); | ||
194 | clk_disable(lvds->pclk); | ||
195 | } | ||
196 | |||
197 | static const struct drm_connector_funcs rockchip_lvds_connector_funcs = { | ||
198 | .fill_modes = drm_helper_probe_single_connector_modes, | ||
199 | .destroy = drm_connector_cleanup, | ||
200 | .reset = drm_atomic_helper_connector_reset, | ||
201 | .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, | ||
202 | .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, | ||
203 | }; | ||
204 | |||
205 | static int rockchip_lvds_connector_get_modes(struct drm_connector *connector) | ||
206 | { | ||
207 | struct rockchip_lvds *lvds = connector_to_lvds(connector); | ||
208 | struct drm_panel *panel = lvds->panel; | ||
209 | |||
210 | return drm_panel_get_modes(panel); | ||
211 | } | ||
212 | |||
213 | static const | ||
214 | struct drm_connector_helper_funcs rockchip_lvds_connector_helper_funcs = { | ||
215 | .get_modes = rockchip_lvds_connector_get_modes, | ||
216 | }; | ||
217 | |||
218 | static void rockchip_lvds_grf_config(struct drm_encoder *encoder, | ||
219 | struct drm_display_mode *mode) | ||
220 | { | ||
221 | struct rockchip_lvds *lvds = encoder_to_lvds(encoder); | ||
222 | u8 pin_hsync = (mode->flags & DRM_MODE_FLAG_PHSYNC) ? 1 : 0; | ||
223 | u8 pin_dclk = (mode->flags & DRM_MODE_FLAG_PCSYNC) ? 1 : 0; | ||
224 | u32 val; | ||
225 | int ret; | ||
226 | |||
227 | /* iomux to LCD data/sync mode */ | ||
228 | if (lvds->output == DISPLAY_OUTPUT_RGB) | ||
229 | if (lvds->pins && !IS_ERR(lvds->pins->default_state)) | ||
230 | pinctrl_select_state(lvds->pins->p, | ||
231 | lvds->pins->default_state); | ||
232 | val = lvds->format | LVDS_CH0_EN; | ||
233 | if (lvds->output == DISPLAY_OUTPUT_RGB) | ||
234 | val |= LVDS_TTL_EN | LVDS_CH1_EN; | ||
235 | else if (lvds->output == DISPLAY_OUTPUT_DUAL_LVDS) | ||
236 | val |= LVDS_DUAL | LVDS_CH1_EN; | ||
237 | |||
238 | if ((mode->htotal - mode->hsync_start) & 0x01) | ||
239 | val |= LVDS_START_PHASE_RST_1; | ||
240 | |||
241 | val |= (pin_dclk << 8) | (pin_hsync << 9); | ||
242 | val |= (0xffff << 16); | ||
243 | ret = regmap_write(lvds->grf, lvds->soc_data->grf_soc_con7, val); | ||
244 | if (ret != 0) { | ||
245 | DRM_DEV_ERROR(lvds->dev, "Could not write to GRF: %d\n", ret); | ||
246 | return; | ||
247 | } | ||
248 | } | ||
249 | |||
250 | static int rockchip_lvds_set_vop_source(struct rockchip_lvds *lvds, | ||
251 | struct drm_encoder *encoder) | ||
252 | { | ||
253 | u32 val; | ||
254 | int ret; | ||
255 | |||
256 | if (!lvds->soc_data->has_vop_sel) | ||
257 | return 0; | ||
258 | |||
259 | ret = drm_of_encoder_active_endpoint_id(lvds->dev->of_node, encoder); | ||
260 | if (ret < 0) | ||
261 | return ret; | ||
262 | |||
263 | val = RK3288_LVDS_SOC_CON6_SEL_VOP_LIT << 16; | ||
264 | if (ret) | ||
265 | val |= RK3288_LVDS_SOC_CON6_SEL_VOP_LIT; | ||
266 | |||
267 | ret = regmap_write(lvds->grf, lvds->soc_data->grf_soc_con6, val); | ||
268 | if (ret < 0) | ||
269 | return ret; | ||
270 | |||
271 | return 0; | ||
272 | } | ||
273 | |||
274 | static int | ||
275 | rockchip_lvds_encoder_atomic_check(struct drm_encoder *encoder, | ||
276 | struct drm_crtc_state *crtc_state, | ||
277 | struct drm_connector_state *conn_state) | ||
278 | { | ||
279 | struct rockchip_crtc_state *s = to_rockchip_crtc_state(crtc_state); | ||
280 | |||
281 | s->output_mode = ROCKCHIP_OUT_MODE_P888; | ||
282 | s->output_type = DRM_MODE_CONNECTOR_LVDS; | ||
283 | |||
284 | return 0; | ||
285 | } | ||
286 | |||
287 | static void rockchip_lvds_encoder_enable(struct drm_encoder *encoder) | ||
288 | { | ||
289 | struct rockchip_lvds *lvds = encoder_to_lvds(encoder); | ||
290 | struct drm_display_mode *mode = &encoder->crtc->state->adjusted_mode; | ||
291 | int ret; | ||
292 | |||
293 | drm_panel_prepare(lvds->panel); | ||
294 | ret = rockchip_lvds_poweron(lvds); | ||
295 | if (ret < 0) { | ||
296 | DRM_DEV_ERROR(lvds->dev, "failed to power on lvds: %d\n", ret); | ||
297 | drm_panel_unprepare(lvds->panel); | ||
298 | } | ||
299 | rockchip_lvds_grf_config(encoder, mode); | ||
300 | rockchip_lvds_set_vop_source(lvds, encoder); | ||
301 | drm_panel_enable(lvds->panel); | ||
302 | } | ||
303 | |||
304 | static void rockchip_lvds_encoder_disable(struct drm_encoder *encoder) | ||
305 | { | ||
306 | struct rockchip_lvds *lvds = encoder_to_lvds(encoder); | ||
307 | |||
308 | drm_panel_disable(lvds->panel); | ||
309 | rockchip_lvds_poweroff(lvds); | ||
310 | drm_panel_unprepare(lvds->panel); | ||
311 | } | ||
312 | |||
313 | static const | ||
314 | struct drm_encoder_helper_funcs rockchip_lvds_encoder_helper_funcs = { | ||
315 | .enable = rockchip_lvds_encoder_enable, | ||
316 | .disable = rockchip_lvds_encoder_disable, | ||
317 | .atomic_check = rockchip_lvds_encoder_atomic_check, | ||
318 | }; | ||
319 | |||
320 | static const struct drm_encoder_funcs rockchip_lvds_encoder_funcs = { | ||
321 | .destroy = drm_encoder_cleanup, | ||
322 | }; | ||
323 | |||
324 | static const struct rockchip_lvds_soc_data rk3288_lvds_data = { | ||
325 | .ch1_offset = 0x100, | ||
326 | .grf_soc_con6 = 0x025c, | ||
327 | .grf_soc_con7 = 0x0260, | ||
328 | .has_vop_sel = true, | ||
329 | }; | ||
330 | |||
331 | static const struct of_device_id rockchip_lvds_dt_ids[] = { | ||
332 | { | ||
333 | .compatible = "rockchip,rk3288-lvds", | ||
334 | .data = &rk3288_lvds_data | ||
335 | }, | ||
336 | {} | ||
337 | }; | ||
338 | MODULE_DEVICE_TABLE(of, rockchip_lvds_dt_ids); | ||
339 | |||
340 | static int rockchip_lvds_bind(struct device *dev, struct device *master, | ||
341 | void *data) | ||
342 | { | ||
343 | struct rockchip_lvds *lvds = dev_get_drvdata(dev); | ||
344 | struct drm_device *drm_dev = data; | ||
345 | struct drm_encoder *encoder; | ||
346 | struct drm_connector *connector; | ||
347 | struct device_node *remote = NULL; | ||
348 | struct device_node *port, *endpoint; | ||
349 | int ret; | ||
350 | const char *name; | ||
351 | u32 endpoint_id; | ||
352 | |||
353 | lvds->drm_dev = drm_dev; | ||
354 | port = of_graph_get_port_by_id(dev->of_node, 1); | ||
355 | if (!port) { | ||
356 | DRM_DEV_ERROR(dev, | ||
357 | "can't found port point, please init lvds panel port!\n"); | ||
358 | return -EINVAL; | ||
359 | } | ||
360 | for_each_child_of_node(port, endpoint) { | ||
361 | of_property_read_u32(endpoint, "reg", &endpoint_id); | ||
362 | ret = drm_of_find_panel_or_bridge(dev->of_node, 1, endpoint_id, | ||
363 | &lvds->panel, &lvds->bridge); | ||
364 | if (!ret) | ||
365 | break; | ||
366 | } | ||
367 | if (ret) { | ||
368 | DRM_DEV_ERROR(dev, "failed to find panel and bridge node\n"); | ||
369 | ret = -EPROBE_DEFER; | ||
370 | goto err_put_port; | ||
371 | } | ||
372 | if (lvds->panel) | ||
373 | remote = lvds->panel->dev->of_node; | ||
374 | else | ||
375 | remote = lvds->bridge->of_node; | ||
376 | if (of_property_read_string(dev->of_node, "rockchip,output", &name)) | ||
377 | /* default set it as output rgb */ | ||
378 | lvds->output = DISPLAY_OUTPUT_RGB; | ||
379 | else | ||
380 | lvds->output = lvds_name_to_output(name); | ||
381 | |||
382 | if (lvds->output < 0) { | ||
383 | DRM_DEV_ERROR(dev, "invalid output type [%s]\n", name); | ||
384 | ret = lvds->output; | ||
385 | goto err_put_remote; | ||
386 | } | ||
387 | |||
388 | if (of_property_read_string(remote, "data-mapping", &name)) | ||
389 | /* default set it as format vesa 18 */ | ||
390 | lvds->format = LVDS_VESA_18; | ||
391 | else | ||
392 | lvds->format = lvds_name_to_format(name); | ||
393 | |||
394 | if (lvds->format < 0) { | ||
395 | DRM_DEV_ERROR(dev, "invalid data-mapping format [%s]\n", name); | ||
396 | ret = lvds->format; | ||
397 | goto err_put_remote; | ||
398 | } | ||
399 | |||
400 | encoder = &lvds->encoder; | ||
401 | encoder->possible_crtcs = drm_of_find_possible_crtcs(drm_dev, | ||
402 | dev->of_node); | ||
403 | |||
404 | ret = drm_encoder_init(drm_dev, encoder, &rockchip_lvds_encoder_funcs, | ||
405 | DRM_MODE_ENCODER_LVDS, NULL); | ||
406 | if (ret < 0) { | ||
407 | DRM_DEV_ERROR(drm_dev->dev, | ||
408 | "failed to initialize encoder: %d\n", ret); | ||
409 | goto err_put_remote; | ||
410 | } | ||
411 | |||
412 | drm_encoder_helper_add(encoder, &rockchip_lvds_encoder_helper_funcs); | ||
413 | |||
414 | if (lvds->panel) { | ||
415 | connector = &lvds->connector; | ||
416 | connector->dpms = DRM_MODE_DPMS_OFF; | ||
417 | ret = drm_connector_init(drm_dev, connector, | ||
418 | &rockchip_lvds_connector_funcs, | ||
419 | DRM_MODE_CONNECTOR_LVDS); | ||
420 | if (ret < 0) { | ||
421 | DRM_DEV_ERROR(drm_dev->dev, | ||
422 | "failed to initialize connector: %d\n", ret); | ||
423 | goto err_free_encoder; | ||
424 | } | ||
425 | |||
426 | drm_connector_helper_add(connector, | ||
427 | &rockchip_lvds_connector_helper_funcs); | ||
428 | |||
429 | ret = drm_mode_connector_attach_encoder(connector, encoder); | ||
430 | if (ret < 0) { | ||
431 | DRM_DEV_ERROR(drm_dev->dev, | ||
432 | "failed to attach encoder: %d\n", ret); | ||
433 | goto err_free_connector; | ||
434 | } | ||
435 | |||
436 | ret = drm_panel_attach(lvds->panel, connector); | ||
437 | if (ret < 0) { | ||
438 | DRM_DEV_ERROR(drm_dev->dev, | ||
439 | "failed to attach panel: %d\n", ret); | ||
440 | goto err_free_connector; | ||
441 | } | ||
442 | } else { | ||
443 | lvds->bridge->encoder = encoder; | ||
444 | ret = drm_bridge_attach(encoder, lvds->bridge, NULL); | ||
445 | if (ret) { | ||
446 | DRM_DEV_ERROR(drm_dev->dev, | ||
447 | "failed to attach bridge: %d\n", ret); | ||
448 | goto err_free_encoder; | ||
449 | } | ||
450 | encoder->bridge = lvds->bridge; | ||
451 | } | ||
452 | |||
453 | pm_runtime_enable(dev); | ||
454 | of_node_put(remote); | ||
455 | of_node_put(port); | ||
456 | |||
457 | return 0; | ||
458 | |||
459 | err_free_connector: | ||
460 | drm_connector_cleanup(connector); | ||
461 | err_free_encoder: | ||
462 | drm_encoder_cleanup(encoder); | ||
463 | err_put_remote: | ||
464 | of_node_put(remote); | ||
465 | err_put_port: | ||
466 | of_node_put(port); | ||
467 | |||
468 | return ret; | ||
469 | } | ||
470 | |||
471 | static void rockchip_lvds_unbind(struct device *dev, struct device *master, | ||
472 | void *data) | ||
473 | { | ||
474 | struct rockchip_lvds *lvds = dev_get_drvdata(dev); | ||
475 | |||
476 | rockchip_lvds_encoder_disable(&lvds->encoder); | ||
477 | if (lvds->panel) | ||
478 | drm_panel_detach(lvds->panel); | ||
479 | pm_runtime_disable(dev); | ||
480 | drm_connector_cleanup(&lvds->connector); | ||
481 | drm_encoder_cleanup(&lvds->encoder); | ||
482 | } | ||
483 | |||
484 | static const struct component_ops rockchip_lvds_component_ops = { | ||
485 | .bind = rockchip_lvds_bind, | ||
486 | .unbind = rockchip_lvds_unbind, | ||
487 | }; | ||
488 | |||
489 | static int rockchip_lvds_probe(struct platform_device *pdev) | ||
490 | { | ||
491 | struct device *dev = &pdev->dev; | ||
492 | struct rockchip_lvds *lvds; | ||
493 | const struct of_device_id *match; | ||
494 | struct resource *res; | ||
495 | int ret; | ||
496 | |||
497 | if (!dev->of_node) | ||
498 | return -ENODEV; | ||
499 | |||
500 | lvds = devm_kzalloc(&pdev->dev, sizeof(*lvds), GFP_KERNEL); | ||
501 | if (!lvds) | ||
502 | return -ENOMEM; | ||
503 | |||
504 | lvds->dev = dev; | ||
505 | match = of_match_node(rockchip_lvds_dt_ids, dev->of_node); | ||
506 | if (!match) | ||
507 | return -ENODEV; | ||
508 | lvds->soc_data = match->data; | ||
509 | |||
510 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
511 | lvds->regs = devm_ioremap_resource(&pdev->dev, res); | ||
512 | if (IS_ERR(lvds->regs)) | ||
513 | return PTR_ERR(lvds->regs); | ||
514 | |||
515 | lvds->pclk = devm_clk_get(&pdev->dev, "pclk_lvds"); | ||
516 | if (IS_ERR(lvds->pclk)) { | ||
517 | DRM_DEV_ERROR(dev, "could not get pclk_lvds\n"); | ||
518 | return PTR_ERR(lvds->pclk); | ||
519 | } | ||
520 | |||
521 | lvds->pins = devm_kzalloc(lvds->dev, sizeof(*lvds->pins), | ||
522 | GFP_KERNEL); | ||
523 | if (!lvds->pins) | ||
524 | return -ENOMEM; | ||
525 | |||
526 | lvds->pins->p = devm_pinctrl_get(lvds->dev); | ||
527 | if (IS_ERR(lvds->pins->p)) { | ||
528 | DRM_DEV_ERROR(dev, "no pinctrl handle\n"); | ||
529 | devm_kfree(lvds->dev, lvds->pins); | ||
530 | lvds->pins = NULL; | ||
531 | } else { | ||
532 | lvds->pins->default_state = | ||
533 | pinctrl_lookup_state(lvds->pins->p, "lcdc"); | ||
534 | if (IS_ERR(lvds->pins->default_state)) { | ||
535 | DRM_DEV_ERROR(dev, "no default pinctrl state\n"); | ||
536 | devm_kfree(lvds->dev, lvds->pins); | ||
537 | lvds->pins = NULL; | ||
538 | } | ||
539 | } | ||
540 | |||
541 | lvds->grf = syscon_regmap_lookup_by_phandle(dev->of_node, | ||
542 | "rockchip,grf"); | ||
543 | if (IS_ERR(lvds->grf)) { | ||
544 | DRM_DEV_ERROR(dev, "missing rockchip,grf property\n"); | ||
545 | return PTR_ERR(lvds->grf); | ||
546 | } | ||
547 | |||
548 | dev_set_drvdata(dev, lvds); | ||
549 | |||
550 | ret = clk_prepare(lvds->pclk); | ||
551 | if (ret < 0) { | ||
552 | DRM_DEV_ERROR(dev, "failed to prepare pclk_lvds\n"); | ||
553 | return ret; | ||
554 | } | ||
555 | ret = component_add(&pdev->dev, &rockchip_lvds_component_ops); | ||
556 | if (ret < 0) { | ||
557 | DRM_DEV_ERROR(dev, "failed to add component\n"); | ||
558 | clk_unprepare(lvds->pclk); | ||
559 | } | ||
560 | |||
561 | return ret; | ||
562 | } | ||
563 | |||
564 | static int rockchip_lvds_remove(struct platform_device *pdev) | ||
565 | { | ||
566 | struct rockchip_lvds *lvds = dev_get_drvdata(&pdev->dev); | ||
567 | |||
568 | component_del(&pdev->dev, &rockchip_lvds_component_ops); | ||
569 | clk_unprepare(lvds->pclk); | ||
570 | |||
571 | return 0; | ||
572 | } | ||
573 | |||
574 | struct platform_driver rockchip_lvds_driver = { | ||
575 | .probe = rockchip_lvds_probe, | ||
576 | .remove = rockchip_lvds_remove, | ||
577 | .driver = { | ||
578 | .name = "rockchip-lvds", | ||
579 | .of_match_table = of_match_ptr(rockchip_lvds_dt_ids), | ||
580 | }, | ||
581 | }; | ||
diff --git a/drivers/gpu/drm/rockchip/rockchip_lvds.h b/drivers/gpu/drm/rockchip/rockchip_lvds.h new file mode 100644 index 000000000000..15810b737809 --- /dev/null +++ b/drivers/gpu/drm/rockchip/rockchip_lvds.h | |||
@@ -0,0 +1,114 @@ | |||
1 | /* | ||
2 | * Copyright (C) Fuzhou Rockchip Electronics Co.Ltd | ||
3 | * Author: | ||
4 | * Sandy Huang <hjc@rock-chips.com> | ||
5 | * Mark Yao <mark.yao@rock-chips.com> | ||
6 | * | ||
7 | * This software is licensed under the terms of the GNU General Public | ||
8 | * License version 2, as published by the Free Software Foundation, and | ||
9 | * may be copied, distributed, and modified under those terms. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | */ | ||
16 | |||
17 | #ifndef _ROCKCHIP_LVDS_ | ||
18 | #define _ROCKCHIP_LVDS_ | ||
19 | |||
20 | #define RK3288_LVDS_CH0_REG0 0x00 | ||
21 | #define RK3288_LVDS_CH0_REG0_LVDS_EN BIT(7) | ||
22 | #define RK3288_LVDS_CH0_REG0_TTL_EN BIT(6) | ||
23 | #define RK3288_LVDS_CH0_REG0_LANECK_EN BIT(5) | ||
24 | #define RK3288_LVDS_CH0_REG0_LANE4_EN BIT(4) | ||
25 | #define RK3288_LVDS_CH0_REG0_LANE3_EN BIT(3) | ||
26 | #define RK3288_LVDS_CH0_REG0_LANE2_EN BIT(2) | ||
27 | #define RK3288_LVDS_CH0_REG0_LANE1_EN BIT(1) | ||
28 | #define RK3288_LVDS_CH0_REG0_LANE0_EN BIT(0) | ||
29 | |||
30 | #define RK3288_LVDS_CH0_REG1 0x04 | ||
31 | #define RK3288_LVDS_CH0_REG1_LANECK_BIAS BIT(5) | ||
32 | #define RK3288_LVDS_CH0_REG1_LANE4_BIAS BIT(4) | ||
33 | #define RK3288_LVDS_CH0_REG1_LANE3_BIAS BIT(3) | ||
34 | #define RK3288_LVDS_CH0_REG1_LANE2_BIAS BIT(2) | ||
35 | #define RK3288_LVDS_CH0_REG1_LANE1_BIAS BIT(1) | ||
36 | #define RK3288_LVDS_CH0_REG1_LANE0_BIAS BIT(0) | ||
37 | |||
38 | #define RK3288_LVDS_CH0_REG2 0x08 | ||
39 | #define RK3288_LVDS_CH0_REG2_RESERVE_ON BIT(7) | ||
40 | #define RK3288_LVDS_CH0_REG2_LANECK_LVDS_MODE BIT(6) | ||
41 | #define RK3288_LVDS_CH0_REG2_LANE4_LVDS_MODE BIT(5) | ||
42 | #define RK3288_LVDS_CH0_REG2_LANE3_LVDS_MODE BIT(4) | ||
43 | #define RK3288_LVDS_CH0_REG2_LANE2_LVDS_MODE BIT(3) | ||
44 | #define RK3288_LVDS_CH0_REG2_LANE1_LVDS_MODE BIT(2) | ||
45 | #define RK3288_LVDS_CH0_REG2_LANE0_LVDS_MODE BIT(1) | ||
46 | #define RK3288_LVDS_CH0_REG2_PLL_FBDIV8 BIT(0) | ||
47 | |||
48 | #define RK3288_LVDS_CH0_REG3 0x0c | ||
49 | #define RK3288_LVDS_CH0_REG3_PLL_FBDIV_MASK 0xff | ||
50 | |||
51 | #define RK3288_LVDS_CH0_REG4 0x10 | ||
52 | #define RK3288_LVDS_CH0_REG4_LANECK_TTL_MODE BIT(5) | ||
53 | #define RK3288_LVDS_CH0_REG4_LANE4_TTL_MODE BIT(4) | ||
54 | #define RK3288_LVDS_CH0_REG4_LANE3_TTL_MODE BIT(3) | ||
55 | #define RK3288_LVDS_CH0_REG4_LANE2_TTL_MODE BIT(2) | ||
56 | #define RK3288_LVDS_CH0_REG4_LANE1_TTL_MODE BIT(1) | ||
57 | #define RK3288_LVDS_CH0_REG4_LANE0_TTL_MODE BIT(0) | ||
58 | |||
59 | #define RK3288_LVDS_CH0_REG5 0x14 | ||
60 | #define RK3288_LVDS_CH0_REG5_LANECK_TTL_DATA BIT(5) | ||
61 | #define RK3288_LVDS_CH0_REG5_LANE4_TTL_DATA BIT(4) | ||
62 | #define RK3288_LVDS_CH0_REG5_LANE3_TTL_DATA BIT(3) | ||
63 | #define RK3288_LVDS_CH0_REG5_LANE2_TTL_DATA BIT(2) | ||
64 | #define RK3288_LVDS_CH0_REG5_LANE1_TTL_DATA BIT(1) | ||
65 | #define RK3288_LVDS_CH0_REG5_LANE0_TTL_DATA BIT(0) | ||
66 | |||
67 | #define RK3288_LVDS_CFG_REGC 0x30 | ||
68 | #define RK3288_LVDS_CFG_REGC_PLL_ENABLE 0x00 | ||
69 | #define RK3288_LVDS_CFG_REGC_PLL_DISABLE 0xff | ||
70 | |||
71 | #define RK3288_LVDS_CH0_REGD 0x34 | ||
72 | #define RK3288_LVDS_CH0_REGD_PLL_PREDIV_MASK 0x1f | ||
73 | |||
74 | #define RK3288_LVDS_CH0_REG20 0x80 | ||
75 | #define RK3288_LVDS_CH0_REG20_MSB 0x45 | ||
76 | #define RK3288_LVDS_CH0_REG20_LSB 0x44 | ||
77 | |||
78 | #define RK3288_LVDS_CFG_REG21 0x84 | ||
79 | #define RK3288_LVDS_CFG_REG21_TX_ENABLE 0x92 | ||
80 | #define RK3288_LVDS_CFG_REG21_TX_DISABLE 0x00 | ||
81 | #define RK3288_LVDS_CH1_OFFSET 0x100 | ||
82 | |||
83 | /* fbdiv value is split over 2 registers, with bit8 in reg2 */ | ||
84 | #define RK3288_LVDS_PLL_FBDIV_REG2(_fbd) \ | ||
85 | (_fbd & BIT(8) ? RK3288_LVDS_CH0_REG2_PLL_FBDIV8 : 0) | ||
86 | #define RK3288_LVDS_PLL_FBDIV_REG3(_fbd) \ | ||
87 | (_fbd & RK3288_LVDS_CH0_REG3_PLL_FBDIV_MASK) | ||
88 | #define RK3288_LVDS_PLL_PREDIV_REGD(_pd) \ | ||
89 | (_pd & RK3288_LVDS_CH0_REGD_PLL_PREDIV_MASK) | ||
90 | |||
91 | #define RK3288_LVDS_SOC_CON6_SEL_VOP_LIT BIT(3) | ||
92 | |||
93 | #define LVDS_FMT_MASK (0x07 << 16) | ||
94 | #define LVDS_MSB BIT(3) | ||
95 | #define LVDS_DUAL BIT(4) | ||
96 | #define LVDS_FMT_1 BIT(5) | ||
97 | #define LVDS_TTL_EN BIT(6) | ||
98 | #define LVDS_START_PHASE_RST_1 BIT(7) | ||
99 | #define LVDS_DCLK_INV BIT(8) | ||
100 | #define LVDS_CH0_EN BIT(11) | ||
101 | #define LVDS_CH1_EN BIT(12) | ||
102 | #define LVDS_PWRDN BIT(15) | ||
103 | |||
104 | #define LVDS_24BIT (0 << 1) | ||
105 | #define LVDS_18BIT (1 << 1) | ||
106 | #define LVDS_FORMAT_VESA (0 << 0) | ||
107 | #define LVDS_FORMAT_JEIDA (1 << 0) | ||
108 | |||
109 | #define LVDS_VESA_24 0 | ||
110 | #define LVDS_JEIDA_24 1 | ||
111 | #define LVDS_VESA_18 2 | ||
112 | #define LVDS_JEIDA_18 3 | ||
113 | |||
114 | #endif /* _ROCKCHIP_LVDS_ */ | ||
diff --git a/drivers/gpu/drm/rockchip/rockchip_vop_reg.c b/drivers/gpu/drm/rockchip/rockchip_vop_reg.c index 94de7b9f6fde..4a39049e901a 100644 --- a/drivers/gpu/drm/rockchip/rockchip_vop_reg.c +++ b/drivers/gpu/drm/rockchip/rockchip_vop_reg.c | |||
@@ -533,7 +533,7 @@ static int vop_probe(struct platform_device *pdev) | |||
533 | struct device *dev = &pdev->dev; | 533 | struct device *dev = &pdev->dev; |
534 | 534 | ||
535 | if (!dev->of_node) { | 535 | if (!dev->of_node) { |
536 | dev_err(dev, "can't find vop devices\n"); | 536 | DRM_DEV_ERROR(dev, "can't find vop devices\n"); |
537 | return -ENODEV; | 537 | return -ENODEV; |
538 | } | 538 | } |
539 | 539 | ||
diff --git a/drivers/gpu/drm/sti/sti_drv.c b/drivers/gpu/drm/sti/sti_drv.c index 1700c542cd93..9e9343101738 100644 --- a/drivers/gpu/drm/sti/sti_drv.c +++ b/drivers/gpu/drm/sti/sti_drv.c | |||
@@ -16,6 +16,7 @@ | |||
16 | #include <drm/drm_atomic_helper.h> | 16 | #include <drm/drm_atomic_helper.h> |
17 | #include <drm/drm_crtc_helper.h> | 17 | #include <drm/drm_crtc_helper.h> |
18 | #include <drm/drm_gem_cma_helper.h> | 18 | #include <drm/drm_gem_cma_helper.h> |
19 | #include <drm/drm_gem_framebuffer_helper.h> | ||
19 | #include <drm/drm_fb_cma_helper.h> | 20 | #include <drm/drm_fb_cma_helper.h> |
20 | #include <drm/drm_of.h> | 21 | #include <drm/drm_of.h> |
21 | 22 | ||
@@ -145,7 +146,7 @@ static void sti_output_poll_changed(struct drm_device *ddev) | |||
145 | } | 146 | } |
146 | 147 | ||
147 | static const struct drm_mode_config_funcs sti_mode_config_funcs = { | 148 | static const struct drm_mode_config_funcs sti_mode_config_funcs = { |
148 | .fb_create = drm_fb_cma_create, | 149 | .fb_create = drm_gem_fb_create, |
149 | .output_poll_changed = sti_output_poll_changed, | 150 | .output_poll_changed = sti_output_poll_changed, |
150 | .atomic_check = sti_atomic_check, | 151 | .atomic_check = sti_atomic_check, |
151 | .atomic_commit = drm_atomic_helper_commit, | 152 | .atomic_commit = drm_atomic_helper_commit, |
diff --git a/drivers/gpu/drm/sti/sti_dvo.c b/drivers/gpu/drm/sti/sti_dvo.c index 852bf2293b05..83314aee65cb 100644 --- a/drivers/gpu/drm/sti/sti_dvo.c +++ b/drivers/gpu/drm/sti/sti_dvo.c | |||
@@ -463,11 +463,7 @@ static int sti_dvo_bind(struct device *dev, struct device *master, void *data) | |||
463 | bridge->driver_private = dvo; | 463 | bridge->driver_private = dvo; |
464 | bridge->funcs = &sti_dvo_bridge_funcs; | 464 | bridge->funcs = &sti_dvo_bridge_funcs; |
465 | bridge->of_node = dvo->dev.of_node; | 465 | bridge->of_node = dvo->dev.of_node; |
466 | err = drm_bridge_add(bridge); | 466 | drm_bridge_add(bridge); |
467 | if (err) { | ||
468 | DRM_ERROR("Failed to add bridge\n"); | ||
469 | return err; | ||
470 | } | ||
471 | 467 | ||
472 | err = drm_bridge_attach(encoder, bridge, NULL); | 468 | err = drm_bridge_attach(encoder, bridge, NULL); |
473 | if (err) { | 469 | if (err) { |
diff --git a/drivers/gpu/drm/stm/drv.c b/drivers/gpu/drm/stm/drv.c index b333b37f3f89..c857663eafc2 100644 --- a/drivers/gpu/drm/stm/drv.c +++ b/drivers/gpu/drm/stm/drv.c | |||
@@ -17,6 +17,7 @@ | |||
17 | #include <drm/drm_crtc_helper.h> | 17 | #include <drm/drm_crtc_helper.h> |
18 | #include <drm/drm_fb_cma_helper.h> | 18 | #include <drm/drm_fb_cma_helper.h> |
19 | #include <drm/drm_gem_cma_helper.h> | 19 | #include <drm/drm_gem_cma_helper.h> |
20 | #include <drm/drm_gem_framebuffer_helper.h> | ||
20 | 21 | ||
21 | #include "ltdc.h" | 22 | #include "ltdc.h" |
22 | 23 | ||
@@ -31,7 +32,7 @@ static void drv_output_poll_changed(struct drm_device *ddev) | |||
31 | } | 32 | } |
32 | 33 | ||
33 | static const struct drm_mode_config_funcs drv_mode_config_funcs = { | 34 | static const struct drm_mode_config_funcs drv_mode_config_funcs = { |
34 | .fb_create = drm_fb_cma_create, | 35 | .fb_create = drm_gem_fb_create, |
35 | .output_poll_changed = drv_output_poll_changed, | 36 | .output_poll_changed = drv_output_poll_changed, |
36 | .atomic_check = drm_atomic_helper_check, | 37 | .atomic_check = drm_atomic_helper_check, |
37 | .atomic_commit = drm_atomic_helper_commit, | 38 | .atomic_commit = drm_atomic_helper_commit, |
diff --git a/drivers/gpu/drm/stm/dw_mipi_dsi-stm.c b/drivers/gpu/drm/stm/dw_mipi_dsi-stm.c index 568c5d0461ea..e5b6310240fe 100644 --- a/drivers/gpu/drm/stm/dw_mipi_dsi-stm.c +++ b/drivers/gpu/drm/stm/dw_mipi_dsi-stm.c | |||
@@ -113,11 +113,13 @@ static enum dsi_color dsi_color_from_mipi(enum mipi_dsi_pixel_format fmt) | |||
113 | 113 | ||
114 | static int dsi_pll_get_clkout_khz(int clkin_khz, int idf, int ndiv, int odf) | 114 | static int dsi_pll_get_clkout_khz(int clkin_khz, int idf, int ndiv, int odf) |
115 | { | 115 | { |
116 | int divisor = idf * odf; | ||
117 | |||
116 | /* prevent from division by 0 */ | 118 | /* prevent from division by 0 */ |
117 | if (idf * odf) | 119 | if (!divisor) |
118 | return DIV_ROUND_CLOSEST(clkin_khz * ndiv, idf * odf); | 120 | return 0; |
119 | 121 | ||
120 | return 0; | 122 | return DIV_ROUND_CLOSEST(clkin_khz * ndiv, divisor); |
121 | } | 123 | } |
122 | 124 | ||
123 | static int dsi_pll_get_params(int clkin_khz, int clkout_khz, | 125 | static int dsi_pll_get_params(int clkin_khz, int clkout_khz, |
diff --git a/drivers/gpu/drm/sun4i/sun4i_drv.c b/drivers/gpu/drm/sun4i/sun4i_drv.c index ace59651892f..a2012638d5f7 100644 --- a/drivers/gpu/drm/sun4i/sun4i_drv.c +++ b/drivers/gpu/drm/sun4i/sun4i_drv.c | |||
@@ -106,11 +106,6 @@ static int sun4i_drv_bind(struct device *dev) | |||
106 | goto free_drm; | 106 | goto free_drm; |
107 | } | 107 | } |
108 | 108 | ||
109 | /* drm_vblank_init calls kcalloc, which can fail */ | ||
110 | ret = drm_vblank_init(drm, 1); | ||
111 | if (ret) | ||
112 | goto free_mem_region; | ||
113 | |||
114 | drm_mode_config_init(drm); | 109 | drm_mode_config_init(drm); |
115 | 110 | ||
116 | ret = component_bind_all(drm->dev, drm); | 111 | ret = component_bind_all(drm->dev, drm); |
@@ -119,6 +114,11 @@ static int sun4i_drv_bind(struct device *dev) | |||
119 | goto cleanup_mode_config; | 114 | goto cleanup_mode_config; |
120 | } | 115 | } |
121 | 116 | ||
117 | /* drm_vblank_init calls kcalloc, which can fail */ | ||
118 | ret = drm_vblank_init(drm, drm->mode_config.num_crtc); | ||
119 | if (ret) | ||
120 | goto free_mem_region; | ||
121 | |||
122 | drm->irq_enabled = true; | 122 | drm->irq_enabled = true; |
123 | 123 | ||
124 | /* Remove early framebuffers (ie. simplefb) */ | 124 | /* Remove early framebuffers (ie. simplefb) */ |
@@ -200,11 +200,39 @@ static int compare_of(struct device *dev, void *data) | |||
200 | return dev->of_node == data; | 200 | return dev->of_node == data; |
201 | } | 201 | } |
202 | 202 | ||
203 | /* | ||
204 | * The encoder drivers use drm_of_find_possible_crtcs to get upstream | ||
205 | * crtcs from the device tree using of_graph. For the results to be | ||
206 | * correct, encoders must be probed/bound after _all_ crtcs have been | ||
207 | * created. The existing code uses a depth first recursive traversal | ||
208 | * of the of_graph, which means the encoders downstream of the TCON | ||
209 | * get add right after the first TCON. The second TCON or CRTC will | ||
210 | * never be properly associated with encoders connected to it. | ||
211 | * | ||
212 | * Also, in a dual display pipeline setup, both frontends can feed | ||
213 | * either backend, and both backends can feed either TCON, we want | ||
214 | * all components of the same type to be added before the next type | ||
215 | * in the pipeline. Fortunately, the pipelines are perfectly symmetric, | ||
216 | * i.e. components of the same type are at the same depth when counted | ||
217 | * from the frontend. The only exception is the third pipeline in | ||
218 | * the A80 SoC, which we do not support anyway. | ||
219 | * | ||
220 | * Hence we can use a breadth first search traversal order to add | ||
221 | * components. We do not need to check for duplicates. The component | ||
222 | * matching system handles this for us. | ||
223 | */ | ||
224 | struct endpoint_list { | ||
225 | struct device_node *node; | ||
226 | struct list_head list; | ||
227 | }; | ||
228 | |||
203 | static int sun4i_drv_add_endpoints(struct device *dev, | 229 | static int sun4i_drv_add_endpoints(struct device *dev, |
230 | struct list_head *endpoints, | ||
204 | struct component_match **match, | 231 | struct component_match **match, |
205 | struct device_node *node) | 232 | struct device_node *node) |
206 | { | 233 | { |
207 | struct device_node *port, *ep, *remote; | 234 | struct device_node *port, *ep, *remote; |
235 | struct endpoint_list *endpoint; | ||
208 | int count = 0; | 236 | int count = 0; |
209 | 237 | ||
210 | /* | 238 | /* |
@@ -264,10 +292,15 @@ static int sun4i_drv_add_endpoints(struct device *dev, | |||
264 | } | 292 | } |
265 | } | 293 | } |
266 | 294 | ||
267 | /* Walk down our tree */ | 295 | /* Add downstream nodes to the queue */ |
268 | count += sun4i_drv_add_endpoints(dev, match, remote); | 296 | endpoint = kzalloc(sizeof(*endpoint), GFP_KERNEL); |
297 | if (!endpoint) { | ||
298 | of_node_put(remote); | ||
299 | return -ENOMEM; | ||
300 | } | ||
269 | 301 | ||
270 | of_node_put(remote); | 302 | endpoint->node = remote; |
303 | list_add_tail(&endpoint->list, endpoints); | ||
271 | } | 304 | } |
272 | 305 | ||
273 | return count; | 306 | return count; |
@@ -277,7 +310,9 @@ static int sun4i_drv_probe(struct platform_device *pdev) | |||
277 | { | 310 | { |
278 | struct component_match *match = NULL; | 311 | struct component_match *match = NULL; |
279 | struct device_node *np = pdev->dev.of_node; | 312 | struct device_node *np = pdev->dev.of_node; |
280 | int i, count = 0; | 313 | struct endpoint_list *endpoint, *endpoint_temp; |
314 | int i, ret, count = 0; | ||
315 | LIST_HEAD(endpoints); | ||
281 | 316 | ||
282 | for (i = 0;; i++) { | 317 | for (i = 0;; i++) { |
283 | struct device_node *pipeline = of_parse_phandle(np, | 318 | struct device_node *pipeline = of_parse_phandle(np, |
@@ -286,12 +321,31 @@ static int sun4i_drv_probe(struct platform_device *pdev) | |||
286 | if (!pipeline) | 321 | if (!pipeline) |
287 | break; | 322 | break; |
288 | 323 | ||
289 | count += sun4i_drv_add_endpoints(&pdev->dev, &match, | 324 | endpoint = kzalloc(sizeof(*endpoint), GFP_KERNEL); |
290 | pipeline); | 325 | if (!endpoint) { |
291 | of_node_put(pipeline); | 326 | ret = -ENOMEM; |
327 | goto err_free_endpoints; | ||
328 | } | ||
292 | 329 | ||
293 | DRM_DEBUG_DRIVER("Queued %d outputs on pipeline %d\n", | 330 | endpoint->node = pipeline; |
294 | count, i); | 331 | list_add_tail(&endpoint->list, &endpoints); |
332 | } | ||
333 | |||
334 | list_for_each_entry_safe(endpoint, endpoint_temp, &endpoints, list) { | ||
335 | /* process this endpoint */ | ||
336 | ret = sun4i_drv_add_endpoints(&pdev->dev, &endpoints, &match, | ||
337 | endpoint->node); | ||
338 | |||
339 | /* sun4i_drv_add_endpoints can fail to allocate memory */ | ||
340 | if (ret < 0) | ||
341 | goto err_free_endpoints; | ||
342 | |||
343 | count += ret; | ||
344 | |||
345 | /* delete and cleanup the current entry */ | ||
346 | list_del(&endpoint->list); | ||
347 | of_node_put(endpoint->node); | ||
348 | kfree(endpoint); | ||
295 | } | 349 | } |
296 | 350 | ||
297 | if (count) | 351 | if (count) |
@@ -300,6 +354,15 @@ static int sun4i_drv_probe(struct platform_device *pdev) | |||
300 | match); | 354 | match); |
301 | else | 355 | else |
302 | return 0; | 356 | return 0; |
357 | |||
358 | err_free_endpoints: | ||
359 | list_for_each_entry_safe(endpoint, endpoint_temp, &endpoints, list) { | ||
360 | list_del(&endpoint->list); | ||
361 | of_node_put(endpoint->node); | ||
362 | kfree(endpoint); | ||
363 | } | ||
364 | |||
365 | return ret; | ||
303 | } | 366 | } |
304 | 367 | ||
305 | static int sun4i_drv_remove(struct platform_device *pdev) | 368 | static int sun4i_drv_remove(struct platform_device *pdev) |
diff --git a/drivers/gpu/drm/sun4i/sun4i_tcon.c b/drivers/gpu/drm/sun4i/sun4i_tcon.c index d9791292553e..e853dfe51389 100644 --- a/drivers/gpu/drm/sun4i/sun4i_tcon.c +++ b/drivers/gpu/drm/sun4i/sun4i_tcon.c | |||
@@ -463,42 +463,170 @@ static int sun4i_tcon_init_regmap(struct device *dev, | |||
463 | * function in fact searches the corresponding engine, and the ID is | 463 | * function in fact searches the corresponding engine, and the ID is |
464 | * requested via the get_id function of the engine. | 464 | * requested via the get_id function of the engine. |
465 | */ | 465 | */ |
466 | static struct sunxi_engine *sun4i_tcon_find_engine(struct sun4i_drv *drv, | 466 | static struct sunxi_engine * |
467 | struct device_node *node) | 467 | sun4i_tcon_find_engine_traverse(struct sun4i_drv *drv, |
468 | struct device_node *node) | ||
468 | { | 469 | { |
469 | struct device_node *port, *ep, *remote; | 470 | struct device_node *port, *ep, *remote; |
470 | struct sunxi_engine *engine; | 471 | struct sunxi_engine *engine = ERR_PTR(-EINVAL); |
471 | 472 | ||
472 | port = of_graph_get_port_by_id(node, 0); | 473 | port = of_graph_get_port_by_id(node, 0); |
473 | if (!port) | 474 | if (!port) |
474 | return ERR_PTR(-EINVAL); | 475 | return ERR_PTR(-EINVAL); |
475 | 476 | ||
477 | /* | ||
478 | * This only works if there is only one path from the TCON | ||
479 | * to any display engine. Otherwise the probe order of the | ||
480 | * TCONs and display engines is not guaranteed. They may | ||
481 | * either bind to the wrong one, or worse, bind to the same | ||
482 | * one if additional checks are not done. | ||
483 | * | ||
484 | * Bail out if there are multiple input connections. | ||
485 | */ | ||
486 | if (of_get_available_child_count(port) != 1) | ||
487 | goto out_put_port; | ||
488 | |||
489 | /* Get the first connection without specifying an ID */ | ||
490 | ep = of_get_next_available_child(port, NULL); | ||
491 | if (!ep) | ||
492 | goto out_put_port; | ||
493 | |||
494 | remote = of_graph_get_remote_port_parent(ep); | ||
495 | if (!remote) | ||
496 | goto out_put_ep; | ||
497 | |||
498 | /* does this node match any registered engines? */ | ||
499 | list_for_each_entry(engine, &drv->engine_list, list) | ||
500 | if (remote == engine->node) | ||
501 | goto out_put_remote; | ||
502 | |||
503 | /* keep looking through upstream ports */ | ||
504 | engine = sun4i_tcon_find_engine_traverse(drv, remote); | ||
505 | |||
506 | out_put_remote: | ||
507 | of_node_put(remote); | ||
508 | out_put_ep: | ||
509 | of_node_put(ep); | ||
510 | out_put_port: | ||
511 | of_node_put(port); | ||
512 | |||
513 | return engine; | ||
514 | } | ||
515 | |||
516 | /* | ||
517 | * The device tree binding says that the remote endpoint ID of any | ||
518 | * connection between components, up to and including the TCON, of | ||
519 | * the display pipeline should be equal to the actual ID of the local | ||
520 | * component. Thus we can look at any one of the input connections of | ||
521 | * the TCONs, and use that connection's remote endpoint ID as our own. | ||
522 | * | ||
523 | * Since the user of this function already finds the input port, | ||
524 | * the port is passed in directly without further checks. | ||
525 | */ | ||
526 | static int sun4i_tcon_of_get_id_from_port(struct device_node *port) | ||
527 | { | ||
528 | struct device_node *ep; | ||
529 | int ret = -EINVAL; | ||
530 | |||
531 | /* try finding an upstream endpoint */ | ||
476 | for_each_available_child_of_node(port, ep) { | 532 | for_each_available_child_of_node(port, ep) { |
477 | remote = of_graph_get_remote_port_parent(ep); | 533 | struct device_node *remote; |
534 | u32 reg; | ||
535 | |||
536 | remote = of_graph_get_remote_endpoint(ep); | ||
478 | if (!remote) | 537 | if (!remote) |
479 | continue; | 538 | continue; |
480 | 539 | ||
481 | /* does this node match any registered engines? */ | 540 | ret = of_property_read_u32(remote, "reg", ®); |
482 | list_for_each_entry(engine, &drv->engine_list, list) { | 541 | if (ret) |
483 | if (remote == engine->node) { | 542 | continue; |
484 | of_node_put(remote); | ||
485 | of_node_put(port); | ||
486 | return engine; | ||
487 | } | ||
488 | } | ||
489 | 543 | ||
490 | /* keep looking through upstream ports */ | 544 | ret = reg; |
491 | engine = sun4i_tcon_find_engine(drv, remote); | ||
492 | if (!IS_ERR(engine)) { | ||
493 | of_node_put(remote); | ||
494 | of_node_put(port); | ||
495 | return engine; | ||
496 | } | ||
497 | } | 545 | } |
498 | 546 | ||
547 | return ret; | ||
548 | } | ||
549 | |||
550 | /* | ||
551 | * Once we know the TCON's id, we can look through the list of | ||
552 | * engines to find a matching one. We assume all engines have | ||
553 | * been probed and added to the list. | ||
554 | */ | ||
555 | static struct sunxi_engine *sun4i_tcon_get_engine_by_id(struct sun4i_drv *drv, | ||
556 | int id) | ||
557 | { | ||
558 | struct sunxi_engine *engine; | ||
559 | |||
560 | list_for_each_entry(engine, &drv->engine_list, list) | ||
561 | if (engine->id == id) | ||
562 | return engine; | ||
563 | |||
499 | return ERR_PTR(-EINVAL); | 564 | return ERR_PTR(-EINVAL); |
500 | } | 565 | } |
501 | 566 | ||
567 | /* | ||
568 | * On SoCs with the old display pipeline design (Display Engine 1.0), | ||
569 | * we assumed the TCON was always tied to just one backend. However | ||
570 | * this proved not to be the case. On the A31, the TCON can select | ||
571 | * either backend as its source. On the A20 (and likely on the A10), | ||
572 | * the backend can choose which TCON to output to. | ||
573 | * | ||
574 | * The device tree binding says that the remote endpoint ID of any | ||
575 | * connection between components, up to and including the TCON, of | ||
576 | * the display pipeline should be equal to the actual ID of the local | ||
577 | * component. Thus we should be able to look at any one of the input | ||
578 | * connections of the TCONs, and use that connection's remote endpoint | ||
579 | * ID as our own. | ||
580 | * | ||
581 | * However the connections between the backend and TCON were assumed | ||
582 | * to be always singular, and their endpoit IDs were all incorrectly | ||
583 | * set to 0. This means for these old device trees, we cannot just look | ||
584 | * up the remote endpoint ID of a TCON input endpoint. TCON1 would be | ||
585 | * incorrectly identified as TCON0. | ||
586 | * | ||
587 | * This function first checks if the TCON node has 2 input endpoints. | ||
588 | * If so, then the device tree is a corrected version, and it will use | ||
589 | * sun4i_tcon_of_get_id() and sun4i_tcon_get_engine_by_id() from above | ||
590 | * to fetch the ID and engine directly. If not, then it is likely an | ||
591 | * old device trees, where the endpoint IDs were incorrect, but did not | ||
592 | * have endpoint connections between the backend and TCON across | ||
593 | * different display pipelines. It will fall back to the old method of | ||
594 | * traversing the of_graph to try and find a matching engine by device | ||
595 | * node. | ||
596 | * | ||
597 | * In the case of single display pipeline device trees, either method | ||
598 | * works. | ||
599 | */ | ||
600 | static struct sunxi_engine *sun4i_tcon_find_engine(struct sun4i_drv *drv, | ||
601 | struct device_node *node) | ||
602 | { | ||
603 | struct device_node *port; | ||
604 | struct sunxi_engine *engine; | ||
605 | |||
606 | port = of_graph_get_port_by_id(node, 0); | ||
607 | if (!port) | ||
608 | return ERR_PTR(-EINVAL); | ||
609 | |||
610 | /* | ||
611 | * Is this a corrected device tree with cross pipeline | ||
612 | * connections between the backend and TCON? | ||
613 | */ | ||
614 | if (of_get_child_count(port) > 1) { | ||
615 | /* Get our ID directly from an upstream endpoint */ | ||
616 | int id = sun4i_tcon_of_get_id_from_port(port); | ||
617 | |||
618 | /* Get our engine by matching our ID */ | ||
619 | engine = sun4i_tcon_get_engine_by_id(drv, id); | ||
620 | |||
621 | of_node_put(port); | ||
622 | return engine; | ||
623 | } | ||
624 | |||
625 | /* Fallback to old method by traversing input endpoints */ | ||
626 | of_node_put(port); | ||
627 | return sun4i_tcon_find_engine_traverse(drv, node); | ||
628 | } | ||
629 | |||
502 | static int sun4i_tcon_bind(struct device *dev, struct device *master, | 630 | static int sun4i_tcon_bind(struct device *dev, struct device *master, |
503 | void *data) | 631 | void *data) |
504 | { | 632 | { |
@@ -530,10 +658,7 @@ static int sun4i_tcon_bind(struct device *dev, struct device *master, | |||
530 | } | 658 | } |
531 | 659 | ||
532 | /* Make sure our TCON is reset */ | 660 | /* Make sure our TCON is reset */ |
533 | if (!reset_control_status(tcon->lcd_rst)) | 661 | ret = reset_control_reset(tcon->lcd_rst); |
534 | reset_control_assert(tcon->lcd_rst); | ||
535 | |||
536 | ret = reset_control_deassert(tcon->lcd_rst); | ||
537 | if (ret) { | 662 | if (ret) { |
538 | dev_err(dev, "Couldn't deassert our reset line\n"); | 663 | dev_err(dev, "Couldn't deassert our reset line\n"); |
539 | return ret; | 664 | return ret; |
@@ -574,6 +699,25 @@ static int sun4i_tcon_bind(struct device *dev, struct device *master, | |||
574 | if (ret < 0) | 699 | if (ret < 0) |
575 | goto err_free_clocks; | 700 | goto err_free_clocks; |
576 | 701 | ||
702 | if (tcon->quirks->needs_de_be_mux) { | ||
703 | /* | ||
704 | * We assume there is no dynamic muxing of backends | ||
705 | * and TCONs, so we select the backend with same ID. | ||
706 | * | ||
707 | * While dynamic selection might be interesting, since | ||
708 | * the CRTC is tied to the TCON, while the layers are | ||
709 | * tied to the backends, this means, we will need to | ||
710 | * switch between groups of layers. There might not be | ||
711 | * a way to represent this constraint in DRM. | ||
712 | */ | ||
713 | regmap_update_bits(tcon->regs, SUN4I_TCON0_CTL_REG, | ||
714 | SUN4I_TCON0_CTL_SRC_SEL_MASK, | ||
715 | tcon->id); | ||
716 | regmap_update_bits(tcon->regs, SUN4I_TCON1_CTL_REG, | ||
717 | SUN4I_TCON1_CTL_SRC_SEL_MASK, | ||
718 | tcon->id); | ||
719 | } | ||
720 | |||
577 | list_add_tail(&tcon->list, &drv->tcon_list); | 721 | list_add_tail(&tcon->list, &drv->tcon_list); |
578 | 722 | ||
579 | return 0; | 723 | return 0; |
@@ -629,11 +773,13 @@ static const struct sun4i_tcon_quirks sun5i_a13_quirks = { | |||
629 | }; | 773 | }; |
630 | 774 | ||
631 | static const struct sun4i_tcon_quirks sun6i_a31_quirks = { | 775 | static const struct sun4i_tcon_quirks sun6i_a31_quirks = { |
632 | .has_channel_1 = true, | 776 | .has_channel_1 = true, |
777 | .needs_de_be_mux = true, | ||
633 | }; | 778 | }; |
634 | 779 | ||
635 | static const struct sun4i_tcon_quirks sun6i_a31s_quirks = { | 780 | static const struct sun4i_tcon_quirks sun6i_a31s_quirks = { |
636 | .has_channel_1 = true, | 781 | .has_channel_1 = true, |
782 | .needs_de_be_mux = true, | ||
637 | }; | 783 | }; |
638 | 784 | ||
639 | static const struct sun4i_tcon_quirks sun8i_a33_quirks = { | 785 | static const struct sun4i_tcon_quirks sun8i_a33_quirks = { |
diff --git a/drivers/gpu/drm/sun4i/sun4i_tcon.h b/drivers/gpu/drm/sun4i/sun4i_tcon.h index 552c88ec16be..5a219d1ccc26 100644 --- a/drivers/gpu/drm/sun4i/sun4i_tcon.h +++ b/drivers/gpu/drm/sun4i/sun4i_tcon.h | |||
@@ -37,6 +37,7 @@ | |||
37 | #define SUN4I_TCON0_CTL_TCON_ENABLE BIT(31) | 37 | #define SUN4I_TCON0_CTL_TCON_ENABLE BIT(31) |
38 | #define SUN4I_TCON0_CTL_CLK_DELAY_MASK GENMASK(8, 4) | 38 | #define SUN4I_TCON0_CTL_CLK_DELAY_MASK GENMASK(8, 4) |
39 | #define SUN4I_TCON0_CTL_CLK_DELAY(delay) ((delay << 4) & SUN4I_TCON0_CTL_CLK_DELAY_MASK) | 39 | #define SUN4I_TCON0_CTL_CLK_DELAY(delay) ((delay << 4) & SUN4I_TCON0_CTL_CLK_DELAY_MASK) |
40 | #define SUN4I_TCON0_CTL_SRC_SEL_MASK GENMASK(2, 0) | ||
40 | 41 | ||
41 | #define SUN4I_TCON0_DCLK_REG 0x44 | 42 | #define SUN4I_TCON0_DCLK_REG 0x44 |
42 | #define SUN4I_TCON0_DCLK_GATE_BIT (31) | 43 | #define SUN4I_TCON0_DCLK_GATE_BIT (31) |
@@ -85,6 +86,7 @@ | |||
85 | #define SUN4I_TCON1_CTL_INTERLACE_ENABLE BIT(20) | 86 | #define SUN4I_TCON1_CTL_INTERLACE_ENABLE BIT(20) |
86 | #define SUN4I_TCON1_CTL_CLK_DELAY_MASK GENMASK(8, 4) | 87 | #define SUN4I_TCON1_CTL_CLK_DELAY_MASK GENMASK(8, 4) |
87 | #define SUN4I_TCON1_CTL_CLK_DELAY(delay) ((delay << 4) & SUN4I_TCON1_CTL_CLK_DELAY_MASK) | 88 | #define SUN4I_TCON1_CTL_CLK_DELAY(delay) ((delay << 4) & SUN4I_TCON1_CTL_CLK_DELAY_MASK) |
89 | #define SUN4I_TCON1_CTL_SRC_SEL_MASK GENMASK(1, 0) | ||
88 | 90 | ||
89 | #define SUN4I_TCON1_BASIC0_REG 0x94 | 91 | #define SUN4I_TCON1_BASIC0_REG 0x94 |
90 | #define SUN4I_TCON1_BASIC0_X(width) ((((width) - 1) & 0xfff) << 16) | 92 | #define SUN4I_TCON1_BASIC0_X(width) ((((width) - 1) & 0xfff) << 16) |
@@ -146,6 +148,7 @@ | |||
146 | struct sun4i_tcon_quirks { | 148 | struct sun4i_tcon_quirks { |
147 | bool has_unknown_mux; /* sun5i has undocumented mux */ | 149 | bool has_unknown_mux; /* sun5i has undocumented mux */ |
148 | bool has_channel_1; /* a33 does not have channel 1 */ | 150 | bool has_channel_1; /* a33 does not have channel 1 */ |
151 | bool needs_de_be_mux; /* sun6i needs mux to select backend */ | ||
149 | }; | 152 | }; |
150 | 153 | ||
151 | struct sun4i_tcon { | 154 | struct sun4i_tcon { |
diff --git a/drivers/gpu/drm/tilcdc/tilcdc_drv.c b/drivers/gpu/drm/tilcdc/tilcdc_drv.c index b0d70f943cec..146ac9a5a2fd 100644 --- a/drivers/gpu/drm/tilcdc/tilcdc_drv.c +++ b/drivers/gpu/drm/tilcdc/tilcdc_drv.c | |||
@@ -23,6 +23,7 @@ | |||
23 | #include <drm/drm_atomic.h> | 23 | #include <drm/drm_atomic.h> |
24 | #include <drm/drm_atomic_helper.h> | 24 | #include <drm/drm_atomic_helper.h> |
25 | #include <drm/drm_fb_helper.h> | 25 | #include <drm/drm_fb_helper.h> |
26 | #include <drm/drm_gem_framebuffer_helper.h> | ||
26 | 27 | ||
27 | #include "tilcdc_drv.h" | 28 | #include "tilcdc_drv.h" |
28 | #include "tilcdc_regs.h" | 29 | #include "tilcdc_regs.h" |
@@ -65,7 +66,7 @@ static struct of_device_id tilcdc_of_match[]; | |||
65 | static struct drm_framebuffer *tilcdc_fb_create(struct drm_device *dev, | 66 | static struct drm_framebuffer *tilcdc_fb_create(struct drm_device *dev, |
66 | struct drm_file *file_priv, const struct drm_mode_fb_cmd2 *mode_cmd) | 67 | struct drm_file *file_priv, const struct drm_mode_fb_cmd2 *mode_cmd) |
67 | { | 68 | { |
68 | return drm_fb_cma_create(dev, file_priv, mode_cmd); | 69 | return drm_gem_fb_create(dev, file_priv, mode_cmd); |
69 | } | 70 | } |
70 | 71 | ||
71 | static void tilcdc_fb_output_poll_changed(struct drm_device *dev) | 72 | static void tilcdc_fb_output_poll_changed(struct drm_device *dev) |
diff --git a/drivers/gpu/drm/tinydrm/mi0283qt.c b/drivers/gpu/drm/tinydrm/mi0283qt.c index 7e5bb7d6f655..7fd26912f2ba 100644 --- a/drivers/gpu/drm/tinydrm/mi0283qt.c +++ b/drivers/gpu/drm/tinydrm/mi0283qt.c | |||
@@ -163,7 +163,6 @@ MODULE_DEVICE_TABLE(spi, mi0283qt_id); | |||
163 | static int mi0283qt_probe(struct spi_device *spi) | 163 | static int mi0283qt_probe(struct spi_device *spi) |
164 | { | 164 | { |
165 | struct device *dev = &spi->dev; | 165 | struct device *dev = &spi->dev; |
166 | struct tinydrm_device *tdev; | ||
167 | struct mipi_dbi *mipi; | 166 | struct mipi_dbi *mipi; |
168 | struct gpio_desc *dc; | 167 | struct gpio_desc *dc; |
169 | u32 rotation = 0; | 168 | u32 rotation = 0; |
@@ -215,20 +214,9 @@ static int mi0283qt_probe(struct spi_device *spi) | |||
215 | return ret; | 214 | return ret; |
216 | } | 215 | } |
217 | 216 | ||
218 | tdev = &mipi->tinydrm; | ||
219 | |||
220 | ret = devm_tinydrm_register(tdev); | ||
221 | if (ret) | ||
222 | return ret; | ||
223 | |||
224 | spi_set_drvdata(spi, mipi); | 217 | spi_set_drvdata(spi, mipi); |
225 | 218 | ||
226 | DRM_DEBUG_DRIVER("Initialized %s:%s @%uMHz on minor %d\n", | 219 | return devm_tinydrm_register(&mipi->tinydrm); |
227 | tdev->drm->driver->name, dev_name(dev), | ||
228 | spi->max_speed_hz / 1000000, | ||
229 | tdev->drm->primary->index); | ||
230 | |||
231 | return 0; | ||
232 | } | 220 | } |
233 | 221 | ||
234 | static void mi0283qt_shutdown(struct spi_device *spi) | 222 | static void mi0283qt_shutdown(struct spi_device *spi) |
diff --git a/drivers/gpu/drm/tinydrm/mipi-dbi.c b/drivers/gpu/drm/tinydrm/mipi-dbi.c index 2caeabcd3458..f0dedc244944 100644 --- a/drivers/gpu/drm/tinydrm/mipi-dbi.c +++ b/drivers/gpu/drm/tinydrm/mipi-dbi.c | |||
@@ -842,6 +842,8 @@ int mipi_dbi_spi_init(struct spi_device *spi, struct mipi_dbi *mipi, | |||
842 | return -ENOMEM; | 842 | return -ENOMEM; |
843 | } | 843 | } |
844 | 844 | ||
845 | DRM_DEBUG_DRIVER("SPI speed: %uMHz\n", spi->max_speed_hz / 1000000); | ||
846 | |||
845 | return 0; | 847 | return 0; |
846 | } | 848 | } |
847 | EXPORT_SYMBOL(mipi_dbi_spi_init); | 849 | EXPORT_SYMBOL(mipi_dbi_spi_init); |
diff --git a/drivers/gpu/drm/tinydrm/repaper.c b/drivers/gpu/drm/tinydrm/repaper.c index 30dc97b3ff21..5fbe14715c83 100644 --- a/drivers/gpu/drm/tinydrm/repaper.c +++ b/drivers/gpu/drm/tinydrm/repaper.c | |||
@@ -1078,19 +1078,11 @@ static int repaper_probe(struct spi_device *spi) | |||
1078 | return ret; | 1078 | return ret; |
1079 | 1079 | ||
1080 | drm_mode_config_reset(tdev->drm); | 1080 | drm_mode_config_reset(tdev->drm); |
1081 | |||
1082 | ret = devm_tinydrm_register(tdev); | ||
1083 | if (ret) | ||
1084 | return ret; | ||
1085 | |||
1086 | spi_set_drvdata(spi, tdev); | 1081 | spi_set_drvdata(spi, tdev); |
1087 | 1082 | ||
1088 | DRM_DEBUG_DRIVER("Initialized %s:%s @%uMHz on minor %d\n", | 1083 | DRM_DEBUG_DRIVER("SPI speed: %uMHz\n", spi->max_speed_hz / 1000000); |
1089 | tdev->drm->driver->name, dev_name(dev), | ||
1090 | spi->max_speed_hz / 1000000, | ||
1091 | tdev->drm->primary->index); | ||
1092 | 1084 | ||
1093 | return 0; | 1085 | return devm_tinydrm_register(tdev); |
1094 | } | 1086 | } |
1095 | 1087 | ||
1096 | static void repaper_shutdown(struct spi_device *spi) | 1088 | static void repaper_shutdown(struct spi_device *spi) |
diff --git a/drivers/gpu/drm/tinydrm/st7586.c b/drivers/gpu/drm/tinydrm/st7586.c index b439956a07f4..07b4d312784c 100644 --- a/drivers/gpu/drm/tinydrm/st7586.c +++ b/drivers/gpu/drm/tinydrm/st7586.c | |||
@@ -343,7 +343,6 @@ MODULE_DEVICE_TABLE(spi, st7586_id); | |||
343 | static int st7586_probe(struct spi_device *spi) | 343 | static int st7586_probe(struct spi_device *spi) |
344 | { | 344 | { |
345 | struct device *dev = &spi->dev; | 345 | struct device *dev = &spi->dev; |
346 | struct tinydrm_device *tdev; | ||
347 | struct mipi_dbi *mipi; | 346 | struct mipi_dbi *mipi; |
348 | struct gpio_desc *a0; | 347 | struct gpio_desc *a0; |
349 | u32 rotation = 0; | 348 | u32 rotation = 0; |
@@ -388,20 +387,9 @@ static int st7586_probe(struct spi_device *spi) | |||
388 | if (ret) | 387 | if (ret) |
389 | return ret; | 388 | return ret; |
390 | 389 | ||
391 | tdev = &mipi->tinydrm; | ||
392 | |||
393 | ret = devm_tinydrm_register(tdev); | ||
394 | if (ret) | ||
395 | return ret; | ||
396 | |||
397 | spi_set_drvdata(spi, mipi); | 390 | spi_set_drvdata(spi, mipi); |
398 | 391 | ||
399 | DRM_DEBUG_DRIVER("Initialized %s:%s @%uMHz on minor %d\n", | 392 | return devm_tinydrm_register(&mipi->tinydrm); |
400 | tdev->drm->driver->name, dev_name(dev), | ||
401 | spi->max_speed_hz / 1000000, | ||
402 | tdev->drm->primary->index); | ||
403 | |||
404 | return 0; | ||
405 | } | 393 | } |
406 | 394 | ||
407 | static void st7586_shutdown(struct spi_device *spi) | 395 | static void st7586_shutdown(struct spi_device *spi) |
diff --git a/drivers/gpu/drm/tve200/Kconfig b/drivers/gpu/drm/tve200/Kconfig new file mode 100644 index 000000000000..c5f03bf4570c --- /dev/null +++ b/drivers/gpu/drm/tve200/Kconfig | |||
@@ -0,0 +1,16 @@ | |||
1 | config DRM_TVE200 | ||
2 | tristate "DRM Support for Faraday TV Encoder TVE200" | ||
3 | depends on DRM | ||
4 | depends on CMA | ||
5 | depends on ARM || COMPILE_TEST | ||
6 | depends on OF | ||
7 | select DRM_BRIDGE | ||
8 | select DRM_PANEL_BRIDGE | ||
9 | select DRM_KMS_HELPER | ||
10 | select DRM_KMS_CMA_HELPER | ||
11 | select DRM_GEM_CMA_HELPER | ||
12 | select VT_HW_CONSOLE_BINDING if FRAMEBUFFER_CONSOLE | ||
13 | help | ||
14 | Choose this option for DRM support for the Faraday TV Encoder | ||
15 | TVE200 Controller. | ||
16 | If M is selected the module will be called tve200_drm. | ||
diff --git a/drivers/gpu/drm/tve200/Makefile b/drivers/gpu/drm/tve200/Makefile new file mode 100644 index 000000000000..6b7a6a1dcbf8 --- /dev/null +++ b/drivers/gpu/drm/tve200/Makefile | |||
@@ -0,0 +1,4 @@ | |||
1 | tve200_drm-y += tve200_display.o \ | ||
2 | tve200_drv.o | ||
3 | |||
4 | obj-$(CONFIG_DRM_TVE200) += tve200_drm.o | ||
diff --git a/drivers/gpu/drm/tve200/tve200_display.c b/drivers/gpu/drm/tve200/tve200_display.c new file mode 100644 index 000000000000..18457de47bbc --- /dev/null +++ b/drivers/gpu/drm/tve200/tve200_display.c | |||
@@ -0,0 +1,337 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2017 Linus Walleij <linus.walleij@linaro.org> | ||
3 | * Parts of this file were based on sources as follows: | ||
4 | * | ||
5 | * Copyright (C) 2006-2008 Intel Corporation | ||
6 | * Copyright (C) 2007 Amos Lee <amos_lee@storlinksemi.com> | ||
7 | * Copyright (C) 2007 Dave Airlie <airlied@linux.ie> | ||
8 | * Copyright (C) 2011 Texas Instruments | ||
9 | * Copyright (C) 2017 Eric Anholt | ||
10 | * | ||
11 | * This program is free software and is provided to you under the terms of the | ||
12 | * GNU General Public License version 2 as published by the Free Software | ||
13 | * Foundation, and any use by you of this program is subject to the terms of | ||
14 | * such GNU licence. | ||
15 | */ | ||
16 | #include <linux/clk.h> | ||
17 | #include <linux/version.h> | ||
18 | #include <linux/dma-buf.h> | ||
19 | #include <linux/of_graph.h> | ||
20 | |||
21 | #include <drm/drmP.h> | ||
22 | #include <drm/drm_panel.h> | ||
23 | #include <drm/drm_gem_cma_helper.h> | ||
24 | #include <drm/drm_fb_cma_helper.h> | ||
25 | |||
26 | #include "tve200_drm.h" | ||
27 | |||
28 | irqreturn_t tve200_irq(int irq, void *data) | ||
29 | { | ||
30 | struct tve200_drm_dev_private *priv = data; | ||
31 | u32 stat; | ||
32 | u32 val; | ||
33 | |||
34 | stat = readl(priv->regs + TVE200_INT_STAT); | ||
35 | |||
36 | if (!stat) | ||
37 | return IRQ_NONE; | ||
38 | |||
39 | /* | ||
40 | * Vblank IRQ | ||
41 | * | ||
42 | * The hardware is a bit tilted: the line stays high after clearing | ||
43 | * the vblank IRQ, firing many more interrupts. We counter this | ||
44 | * by toggling the IRQ back and forth from firing at vblank and | ||
45 | * firing at start of active image, which works around the problem | ||
46 | * since those occur strictly in sequence, and we get two IRQs for each | ||
47 | * frame, one at start of Vblank (that we make call into the CRTC) and | ||
48 | * another one at the start of the image (that we discard). | ||
49 | */ | ||
50 | if (stat & TVE200_INT_V_STATUS) { | ||
51 | val = readl(priv->regs + TVE200_CTRL); | ||
52 | /* We have an actual start of vsync */ | ||
53 | if (!(val & TVE200_VSTSTYPE_BITS)) { | ||
54 | drm_crtc_handle_vblank(&priv->pipe.crtc); | ||
55 | /* Toggle trigger to start of active image */ | ||
56 | val |= TVE200_VSTSTYPE_VAI; | ||
57 | } else { | ||
58 | /* Toggle trigger back to start of vsync */ | ||
59 | val &= ~TVE200_VSTSTYPE_BITS; | ||
60 | } | ||
61 | writel(val, priv->regs + TVE200_CTRL); | ||
62 | } else | ||
63 | dev_err(priv->drm->dev, "stray IRQ %08x\n", stat); | ||
64 | |||
65 | /* Clear the interrupt once done */ | ||
66 | writel(stat, priv->regs + TVE200_INT_CLR); | ||
67 | |||
68 | return IRQ_HANDLED; | ||
69 | } | ||
70 | |||
71 | static int tve200_display_check(struct drm_simple_display_pipe *pipe, | ||
72 | struct drm_plane_state *pstate, | ||
73 | struct drm_crtc_state *cstate) | ||
74 | { | ||
75 | const struct drm_display_mode *mode = &cstate->mode; | ||
76 | struct drm_framebuffer *old_fb = pipe->plane.state->fb; | ||
77 | struct drm_framebuffer *fb = pstate->fb; | ||
78 | |||
79 | /* | ||
80 | * We support these specific resolutions and nothing else. | ||
81 | */ | ||
82 | if (!(mode->hdisplay == 352 && mode->vdisplay == 240) && /* SIF(525) */ | ||
83 | !(mode->hdisplay == 352 && mode->vdisplay == 288) && /* CIF(625) */ | ||
84 | !(mode->hdisplay == 640 && mode->vdisplay == 480) && /* VGA */ | ||
85 | !(mode->hdisplay == 720 && mode->vdisplay == 480) && /* D1 */ | ||
86 | !(mode->hdisplay == 720 && mode->vdisplay == 576)) { /* D1 */ | ||
87 | DRM_DEBUG_KMS("unsupported display mode (%u x %u)\n", | ||
88 | mode->hdisplay, mode->vdisplay); | ||
89 | return -EINVAL; | ||
90 | } | ||
91 | |||
92 | if (fb) { | ||
93 | u32 offset = drm_fb_cma_get_gem_addr(fb, pstate, 0); | ||
94 | |||
95 | /* FB base address must be dword aligned. */ | ||
96 | if (offset & 3) { | ||
97 | DRM_DEBUG_KMS("FB not 32-bit aligned\n"); | ||
98 | return -EINVAL; | ||
99 | } | ||
100 | |||
101 | /* | ||
102 | * There's no pitch register, the mode's hdisplay | ||
103 | * controls this. | ||
104 | */ | ||
105 | if (fb->pitches[0] != mode->hdisplay * fb->format->cpp[0]) { | ||
106 | DRM_DEBUG_KMS("can't handle pitches\n"); | ||
107 | return -EINVAL; | ||
108 | } | ||
109 | |||
110 | /* | ||
111 | * We can't change the FB format in a flicker-free | ||
112 | * manner (and only update it during CRTC enable). | ||
113 | */ | ||
114 | if (old_fb && old_fb->format != fb->format) | ||
115 | cstate->mode_changed = true; | ||
116 | } | ||
117 | |||
118 | return 0; | ||
119 | } | ||
120 | |||
121 | static void tve200_display_enable(struct drm_simple_display_pipe *pipe, | ||
122 | struct drm_crtc_state *cstate) | ||
123 | { | ||
124 | struct drm_crtc *crtc = &pipe->crtc; | ||
125 | struct drm_plane *plane = &pipe->plane; | ||
126 | struct drm_device *drm = crtc->dev; | ||
127 | struct tve200_drm_dev_private *priv = drm->dev_private; | ||
128 | const struct drm_display_mode *mode = &cstate->mode; | ||
129 | struct drm_framebuffer *fb = plane->state->fb; | ||
130 | struct drm_connector *connector = priv->connector; | ||
131 | u32 format = fb->format->format; | ||
132 | u32 ctrl1 = 0; | ||
133 | |||
134 | clk_prepare_enable(priv->clk); | ||
135 | |||
136 | /* Function 1 */ | ||
137 | ctrl1 |= TVE200_CTRL_CSMODE; | ||
138 | /* Interlace mode for CCIR656: parameterize? */ | ||
139 | ctrl1 |= TVE200_CTRL_NONINTERLACE; | ||
140 | /* 32 words per burst */ | ||
141 | ctrl1 |= TVE200_CTRL_BURST_32_WORDS; | ||
142 | /* 16 retries */ | ||
143 | ctrl1 |= TVE200_CTRL_RETRYCNT_16; | ||
144 | /* NTSC mode: parametrize? */ | ||
145 | ctrl1 |= TVE200_CTRL_NTSC; | ||
146 | |||
147 | /* Vsync IRQ at start of Vsync at first */ | ||
148 | ctrl1 |= TVE200_VSTSTYPE_VSYNC; | ||
149 | |||
150 | if (connector->display_info.bus_flags & DRM_BUS_FLAG_PIXDATA_NEGEDGE) | ||
151 | ctrl1 |= TVE200_CTRL_TVCLKP; | ||
152 | |||
153 | if ((mode->hdisplay == 352 && mode->vdisplay == 240) || /* SIF(525) */ | ||
154 | (mode->hdisplay == 352 && mode->vdisplay == 288)) { /* CIF(625) */ | ||
155 | ctrl1 |= TVE200_CTRL_IPRESOL_CIF; | ||
156 | dev_info(drm->dev, "CIF mode\n"); | ||
157 | } else if (mode->hdisplay == 640 && mode->vdisplay == 480) { | ||
158 | ctrl1 |= TVE200_CTRL_IPRESOL_VGA; | ||
159 | dev_info(drm->dev, "VGA mode\n"); | ||
160 | } else if ((mode->hdisplay == 720 && mode->vdisplay == 480) || | ||
161 | (mode->hdisplay == 720 && mode->vdisplay == 576)) { | ||
162 | ctrl1 |= TVE200_CTRL_IPRESOL_D1; | ||
163 | dev_info(drm->dev, "D1 mode\n"); | ||
164 | } | ||
165 | |||
166 | if (format & DRM_FORMAT_BIG_ENDIAN) { | ||
167 | ctrl1 |= TVE200_CTRL_BBBP; | ||
168 | format &= ~DRM_FORMAT_BIG_ENDIAN; | ||
169 | } | ||
170 | |||
171 | switch (format) { | ||
172 | case DRM_FORMAT_XRGB8888: | ||
173 | ctrl1 |= TVE200_IPDMOD_RGB888; | ||
174 | break; | ||
175 | case DRM_FORMAT_RGB565: | ||
176 | ctrl1 |= TVE200_IPDMOD_RGB565; | ||
177 | break; | ||
178 | case DRM_FORMAT_XRGB1555: | ||
179 | ctrl1 |= TVE200_IPDMOD_RGB555; | ||
180 | break; | ||
181 | case DRM_FORMAT_XBGR8888: | ||
182 | ctrl1 |= TVE200_IPDMOD_RGB888 | TVE200_BGR; | ||
183 | break; | ||
184 | case DRM_FORMAT_BGR565: | ||
185 | ctrl1 |= TVE200_IPDMOD_RGB565 | TVE200_BGR; | ||
186 | break; | ||
187 | case DRM_FORMAT_XBGR1555: | ||
188 | ctrl1 |= TVE200_IPDMOD_RGB555 | TVE200_BGR; | ||
189 | break; | ||
190 | case DRM_FORMAT_YUYV: | ||
191 | ctrl1 |= TVE200_IPDMOD_YUV422; | ||
192 | ctrl1 |= TVE200_CTRL_YCBCRODR_CR0Y1CB0Y0; | ||
193 | break; | ||
194 | case DRM_FORMAT_YVYU: | ||
195 | ctrl1 |= TVE200_IPDMOD_YUV422; | ||
196 | ctrl1 |= TVE200_CTRL_YCBCRODR_CB0Y1CR0Y0; | ||
197 | break; | ||
198 | case DRM_FORMAT_UYVY: | ||
199 | ctrl1 |= TVE200_IPDMOD_YUV422; | ||
200 | ctrl1 |= TVE200_CTRL_YCBCRODR_Y1CR0Y0CB0; | ||
201 | break; | ||
202 | case DRM_FORMAT_VYUY: | ||
203 | ctrl1 |= TVE200_IPDMOD_YUV422; | ||
204 | ctrl1 |= TVE200_CTRL_YCBCRODR_Y1CB0Y0CR0; | ||
205 | break; | ||
206 | case DRM_FORMAT_YUV420: | ||
207 | ctrl1 |= TVE200_CTRL_YUV420; | ||
208 | ctrl1 |= TVE200_IPDMOD_YUV420; | ||
209 | break; | ||
210 | default: | ||
211 | dev_err(drm->dev, "Unknown FB format 0x%08x\n", | ||
212 | fb->format->format); | ||
213 | break; | ||
214 | } | ||
215 | |||
216 | ctrl1 |= TVE200_TVEEN; | ||
217 | |||
218 | /* Turn it on */ | ||
219 | writel(ctrl1, priv->regs + TVE200_CTRL); | ||
220 | |||
221 | drm_crtc_vblank_on(crtc); | ||
222 | } | ||
223 | |||
224 | void tve200_display_disable(struct drm_simple_display_pipe *pipe) | ||
225 | { | ||
226 | struct drm_crtc *crtc = &pipe->crtc; | ||
227 | struct drm_device *drm = crtc->dev; | ||
228 | struct tve200_drm_dev_private *priv = drm->dev_private; | ||
229 | |||
230 | drm_crtc_vblank_off(crtc); | ||
231 | |||
232 | /* Disable and Power Down */ | ||
233 | writel(0, priv->regs + TVE200_CTRL); | ||
234 | |||
235 | clk_disable_unprepare(priv->clk); | ||
236 | } | ||
237 | |||
238 | static void tve200_display_update(struct drm_simple_display_pipe *pipe, | ||
239 | struct drm_plane_state *old_pstate) | ||
240 | { | ||
241 | struct drm_crtc *crtc = &pipe->crtc; | ||
242 | struct drm_device *drm = crtc->dev; | ||
243 | struct tve200_drm_dev_private *priv = drm->dev_private; | ||
244 | struct drm_pending_vblank_event *event = crtc->state->event; | ||
245 | struct drm_plane *plane = &pipe->plane; | ||
246 | struct drm_plane_state *pstate = plane->state; | ||
247 | struct drm_framebuffer *fb = pstate->fb; | ||
248 | |||
249 | if (fb) { | ||
250 | /* For RGB, the Y component is used as base address */ | ||
251 | writel(drm_fb_cma_get_gem_addr(fb, pstate, 0), | ||
252 | priv->regs + TVE200_Y_FRAME_BASE_ADDR); | ||
253 | |||
254 | /* For three plane YUV we need two more addresses */ | ||
255 | if (fb->format->format == DRM_FORMAT_YUV420) { | ||
256 | writel(drm_fb_cma_get_gem_addr(fb, pstate, 1), | ||
257 | priv->regs + TVE200_U_FRAME_BASE_ADDR); | ||
258 | writel(drm_fb_cma_get_gem_addr(fb, pstate, 2), | ||
259 | priv->regs + TVE200_V_FRAME_BASE_ADDR); | ||
260 | } | ||
261 | } | ||
262 | |||
263 | if (event) { | ||
264 | crtc->state->event = NULL; | ||
265 | |||
266 | spin_lock_irq(&crtc->dev->event_lock); | ||
267 | if (crtc->state->active && drm_crtc_vblank_get(crtc) == 0) | ||
268 | drm_crtc_arm_vblank_event(crtc, event); | ||
269 | else | ||
270 | drm_crtc_send_vblank_event(crtc, event); | ||
271 | spin_unlock_irq(&crtc->dev->event_lock); | ||
272 | } | ||
273 | } | ||
274 | |||
275 | int tve200_enable_vblank(struct drm_device *drm, unsigned int crtc) | ||
276 | { | ||
277 | struct tve200_drm_dev_private *priv = drm->dev_private; | ||
278 | |||
279 | writel(TVE200_INT_V_STATUS, priv->regs + TVE200_INT_EN); | ||
280 | return 0; | ||
281 | } | ||
282 | |||
283 | void tve200_disable_vblank(struct drm_device *drm, unsigned int crtc) | ||
284 | { | ||
285 | struct tve200_drm_dev_private *priv = drm->dev_private; | ||
286 | |||
287 | writel(0, priv->regs + TVE200_INT_EN); | ||
288 | } | ||
289 | |||
290 | static int tve200_display_prepare_fb(struct drm_simple_display_pipe *pipe, | ||
291 | struct drm_plane_state *plane_state) | ||
292 | { | ||
293 | return drm_fb_cma_prepare_fb(&pipe->plane, plane_state); | ||
294 | } | ||
295 | |||
296 | const struct drm_simple_display_pipe_funcs tve200_display_funcs = { | ||
297 | .check = tve200_display_check, | ||
298 | .enable = tve200_display_enable, | ||
299 | .disable = tve200_display_disable, | ||
300 | .update = tve200_display_update, | ||
301 | .prepare_fb = tve200_display_prepare_fb, | ||
302 | }; | ||
303 | |||
304 | int tve200_display_init(struct drm_device *drm) | ||
305 | { | ||
306 | struct tve200_drm_dev_private *priv = drm->dev_private; | ||
307 | int ret; | ||
308 | static const u32 formats[] = { | ||
309 | DRM_FORMAT_XRGB8888, | ||
310 | DRM_FORMAT_XBGR8888, | ||
311 | DRM_FORMAT_RGB565, | ||
312 | DRM_FORMAT_BGR565, | ||
313 | DRM_FORMAT_XRGB1555, | ||
314 | DRM_FORMAT_XBGR1555, | ||
315 | /* | ||
316 | * The controller actually supports any YCbCr ordering, | ||
317 | * for packed YCbCr. This just lists the orderings that | ||
318 | * DRM supports. | ||
319 | */ | ||
320 | DRM_FORMAT_YUYV, | ||
321 | DRM_FORMAT_YVYU, | ||
322 | DRM_FORMAT_UYVY, | ||
323 | DRM_FORMAT_VYUY, | ||
324 | /* This uses three planes */ | ||
325 | DRM_FORMAT_YUV420, | ||
326 | }; | ||
327 | |||
328 | ret = drm_simple_display_pipe_init(drm, &priv->pipe, | ||
329 | &tve200_display_funcs, | ||
330 | formats, ARRAY_SIZE(formats), | ||
331 | NULL, | ||
332 | priv->connector); | ||
333 | if (ret) | ||
334 | return ret; | ||
335 | |||
336 | return 0; | ||
337 | } | ||
diff --git a/drivers/gpu/drm/tve200/tve200_drm.h b/drivers/gpu/drm/tve200/tve200_drm.h new file mode 100644 index 000000000000..628b79324c48 --- /dev/null +++ b/drivers/gpu/drm/tve200/tve200_drm.h | |||
@@ -0,0 +1,126 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2017 Linus Walleij <linus.walleij@linaro.org> | ||
3 | * Parts of this file were based on sources as follows: | ||
4 | * | ||
5 | * Copyright (C) 2006-2008 Intel Corporation | ||
6 | * Copyright (C) 2007 Amos Lee <amos_lee@storlinksemi.com> | ||
7 | * Copyright (C) 2007 Dave Airlie <airlied@linux.ie> | ||
8 | * Copyright (C) 2011 Texas Instruments | ||
9 | * Copyright (C) 2017 Eric Anholt | ||
10 | * | ||
11 | * This program is free software and is provided to you under the terms of the | ||
12 | * GNU General Public License version 2 as published by the Free Software | ||
13 | * Foundation, and any use by you of this program is subject to the terms of | ||
14 | * such GNU licence. | ||
15 | */ | ||
16 | |||
17 | #ifndef _TVE200_DRM_H_ | ||
18 | #define _TVE200_DRM_H_ | ||
19 | |||
20 | /* Bits 2-31 are valid physical base addresses */ | ||
21 | #define TVE200_Y_FRAME_BASE_ADDR 0x00 | ||
22 | #define TVE200_U_FRAME_BASE_ADDR 0x04 | ||
23 | #define TVE200_V_FRAME_BASE_ADDR 0x08 | ||
24 | |||
25 | #define TVE200_INT_EN 0x0C | ||
26 | #define TVE200_INT_CLR 0x10 | ||
27 | #define TVE200_INT_STAT 0x14 | ||
28 | #define TVE200_INT_BUS_ERR BIT(7) | ||
29 | #define TVE200_INT_V_STATUS BIT(6) /* vertical blank */ | ||
30 | #define TVE200_INT_V_NEXT_FRAME BIT(5) | ||
31 | #define TVE200_INT_U_NEXT_FRAME BIT(4) | ||
32 | #define TVE200_INT_Y_NEXT_FRAME BIT(3) | ||
33 | #define TVE200_INT_V_FIFO_UNDERRUN BIT(2) | ||
34 | #define TVE200_INT_U_FIFO_UNDERRUN BIT(1) | ||
35 | #define TVE200_INT_Y_FIFO_UNDERRUN BIT(0) | ||
36 | #define TVE200_FIFO_UNDERRUNS (TVE200_INT_V_FIFO_UNDERRUN | \ | ||
37 | TVE200_INT_U_FIFO_UNDERRUN | \ | ||
38 | TVE200_INT_Y_FIFO_UNDERRUN) | ||
39 | |||
40 | #define TVE200_CTRL 0x18 | ||
41 | #define TVE200_CTRL_YUV420 BIT(31) | ||
42 | #define TVE200_CTRL_CSMODE BIT(30) | ||
43 | #define TVE200_CTRL_NONINTERLACE BIT(28) /* 0 = non-interlace CCIR656 */ | ||
44 | #define TVE200_CTRL_TVCLKP BIT(27) /* Inverted clock phase */ | ||
45 | /* Bits 24..26 define the burst size after arbitration on the bus */ | ||
46 | #define TVE200_CTRL_BURST_4_WORDS (0 << 24) | ||
47 | #define TVE200_CTRL_BURST_8_WORDS (1 << 24) | ||
48 | #define TVE200_CTRL_BURST_16_WORDS (2 << 24) | ||
49 | #define TVE200_CTRL_BURST_32_WORDS (3 << 24) | ||
50 | #define TVE200_CTRL_BURST_64_WORDS (4 << 24) | ||
51 | #define TVE200_CTRL_BURST_128_WORDS (5 << 24) | ||
52 | #define TVE200_CTRL_BURST_256_WORDS (6 << 24) | ||
53 | #define TVE200_CTRL_BURST_0_WORDS (7 << 24) /* ? */ | ||
54 | /* | ||
55 | * Bits 16..23 is the retry count*16 before issueing a new AHB transfer | ||
56 | * on the AHB bus. | ||
57 | */ | ||
58 | #define TVE200_CTRL_RETRYCNT_MASK GENMASK(23, 16) | ||
59 | #define TVE200_CTRL_RETRYCNT_16 (1 << 16) | ||
60 | #define TVE200_CTRL_BBBP BIT(15) /* 0 = little-endian */ | ||
61 | /* Bits 12..14 define the YCbCr ordering */ | ||
62 | #define TVE200_CTRL_YCBCRODR_CB0Y0CR0Y1 (0 << 12) | ||
63 | #define TVE200_CTRL_YCBCRODR_Y0CB0Y1CR0 (1 << 12) | ||
64 | #define TVE200_CTRL_YCBCRODR_CR0Y0CB0Y1 (2 << 12) | ||
65 | #define TVE200_CTRL_YCBCRODR_Y1CB0Y0CR0 (3 << 12) | ||
66 | #define TVE200_CTRL_YCBCRODR_CR0Y1CB0Y0 (4 << 12) | ||
67 | #define TVE200_CTRL_YCBCRODR_Y1CR0Y0CB0 (5 << 12) | ||
68 | #define TVE200_CTRL_YCBCRODR_CB0Y1CR0Y0 (6 << 12) | ||
69 | #define TVE200_CTRL_YCBCRODR_Y0CR0Y1CB0 (7 << 12) | ||
70 | /* Bits 10..11 define the input resolution (framebuffer size) */ | ||
71 | #define TVE200_CTRL_IPRESOL_CIF (0 << 10) | ||
72 | #define TVE200_CTRL_IPRESOL_VGA (1 << 10) | ||
73 | #define TVE200_CTRL_IPRESOL_D1 (2 << 10) | ||
74 | #define TVE200_CTRL_NTSC BIT(9) /* 0 = PAL, 1 = NTSC */ | ||
75 | #define TVE200_CTRL_INTERLACE BIT(8) /* 1 = interlace, only for D1 */ | ||
76 | #define TVE200_IPDMOD_RGB555 (0 << 6) /* TVE200_CTRL_YUV420 = 0 */ | ||
77 | #define TVE200_IPDMOD_RGB565 (1 << 6) | ||
78 | #define TVE200_IPDMOD_RGB888 (2 << 6) | ||
79 | #define TVE200_IPDMOD_YUV420 (2 << 6) /* TVE200_CTRL_YUV420 = 1 */ | ||
80 | #define TVE200_IPDMOD_YUV422 (3 << 6) | ||
81 | /* Bits 4 & 5 define when to fire the vblank IRQ */ | ||
82 | #define TVE200_VSTSTYPE_VSYNC (0 << 4) /* start of vsync */ | ||
83 | #define TVE200_VSTSTYPE_VBP (1 << 4) /* start of v back porch */ | ||
84 | #define TVE200_VSTSTYPE_VAI (2 << 4) /* start of v active image */ | ||
85 | #define TVE200_VSTSTYPE_VFP (3 << 4) /* start of v front porch */ | ||
86 | #define TVE200_VSTSTYPE_BITS (BIT(4) | BIT(5)) | ||
87 | #define TVE200_BGR BIT(1) /* 0 = RGB, 1 = BGR */ | ||
88 | #define TVE200_TVEEN BIT(0) /* Enable TVE block */ | ||
89 | |||
90 | #define TVE200_CTRL_2 0x1c | ||
91 | #define TVE200_CTRL_3 0x20 | ||
92 | |||
93 | #define TVE200_CTRL_4 0x24 | ||
94 | #define TVE200_CTRL_4_RESET BIT(0) /* triggers reset of TVE200 */ | ||
95 | |||
96 | #include <drm/drm_gem.h> | ||
97 | #include <drm/drm_simple_kms_helper.h> | ||
98 | |||
99 | struct tve200_drm_dev_private { | ||
100 | struct drm_device *drm; | ||
101 | |||
102 | struct drm_connector *connector; | ||
103 | struct drm_panel *panel; | ||
104 | struct drm_bridge *bridge; | ||
105 | struct drm_simple_display_pipe pipe; | ||
106 | struct drm_fbdev_cma *fbdev; | ||
107 | |||
108 | void *regs; | ||
109 | struct clk *pclk; | ||
110 | struct clk *clk; | ||
111 | }; | ||
112 | |||
113 | #define to_tve200_connector(x) \ | ||
114 | container_of(x, struct tve200_drm_connector, connector) | ||
115 | |||
116 | int tve200_display_init(struct drm_device *dev); | ||
117 | int tve200_enable_vblank(struct drm_device *drm, unsigned int crtc); | ||
118 | void tve200_disable_vblank(struct drm_device *drm, unsigned int crtc); | ||
119 | irqreturn_t tve200_irq(int irq, void *data); | ||
120 | int tve200_connector_init(struct drm_device *dev); | ||
121 | int tve200_encoder_init(struct drm_device *dev); | ||
122 | int tve200_dumb_create(struct drm_file *file_priv, | ||
123 | struct drm_device *dev, | ||
124 | struct drm_mode_create_dumb *args); | ||
125 | |||
126 | #endif /* _TVE200_DRM_H_ */ | ||
diff --git a/drivers/gpu/drm/tve200/tve200_drv.c b/drivers/gpu/drm/tve200/tve200_drv.c new file mode 100644 index 000000000000..eae38b669f0a --- /dev/null +++ b/drivers/gpu/drm/tve200/tve200_drv.c | |||
@@ -0,0 +1,302 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2017 Linus Walleij <linus.walleij@linaro.org> | ||
3 | * Parts of this file were based on sources as follows: | ||
4 | * | ||
5 | * Copyright (C) 2006-2008 Intel Corporation | ||
6 | * Copyright (C) 2007 Amos Lee <amos_lee@storlinksemi.com> | ||
7 | * Copyright (C) 2007 Dave Airlie <airlied@linux.ie> | ||
8 | * Copyright (C) 2011 Texas Instruments | ||
9 | * Copyright (C) 2017 Eric Anholt | ||
10 | * | ||
11 | * This program is free software and is provided to you under the terms of the | ||
12 | * GNU General Public License version 2 as published by the Free Software | ||
13 | * Foundation, and any use by you of this program is subject to the terms of | ||
14 | * such GNU licence. | ||
15 | */ | ||
16 | |||
17 | /** | ||
18 | * DOC: Faraday TV Encoder TVE200 DRM Driver | ||
19 | * | ||
20 | * The Faraday TV Encoder TVE200 is also known as the Gemini TV Interface | ||
21 | * Controller (TVC) and is found in the Gemini Chipset from Storlink | ||
22 | * Semiconductor (later Storm Semiconductor, later Cortina Systems) | ||
23 | * but also in the Grain Media GM8180 chipset. On the Gemini the module | ||
24 | * is connected to 8 data lines and a single clock line, comprising an | ||
25 | * 8-bit BT.656 interface. | ||
26 | * | ||
27 | * This is a very basic YUV display driver. The datasheet specifies that | ||
28 | * it supports the ITU BT.656 standard. It requires a 27 MHz clock which is | ||
29 | * the hallmark of any TV encoder supporting both PAL and NTSC. | ||
30 | * | ||
31 | * This driver exposes a standard KMS interface for this TV encoder. | ||
32 | */ | ||
33 | |||
34 | #include <linux/clk.h> | ||
35 | #include <linux/dma-buf.h> | ||
36 | #include <linux/irq.h> | ||
37 | #include <linux/io.h> | ||
38 | #include <linux/module.h> | ||
39 | #include <linux/platform_device.h> | ||
40 | #include <linux/shmem_fs.h> | ||
41 | #include <linux/slab.h> | ||
42 | #include <linux/version.h> | ||
43 | |||
44 | #include <drm/drmP.h> | ||
45 | #include <drm/drm_atomic_helper.h> | ||
46 | #include <drm/drm_crtc_helper.h> | ||
47 | #include <drm/drm_gem_cma_helper.h> | ||
48 | #include <drm/drm_fb_cma_helper.h> | ||
49 | #include <drm/drm_panel.h> | ||
50 | #include <drm/drm_of.h> | ||
51 | #include <drm/drm_bridge.h> | ||
52 | |||
53 | #include "tve200_drm.h" | ||
54 | |||
55 | #define DRIVER_DESC "DRM module for Faraday TVE200" | ||
56 | |||
57 | static const struct drm_mode_config_funcs mode_config_funcs = { | ||
58 | .fb_create = drm_fb_cma_create, | ||
59 | .atomic_check = drm_atomic_helper_check, | ||
60 | .atomic_commit = drm_atomic_helper_commit, | ||
61 | }; | ||
62 | |||
63 | static int tve200_modeset_init(struct drm_device *dev) | ||
64 | { | ||
65 | struct drm_mode_config *mode_config; | ||
66 | struct tve200_drm_dev_private *priv = dev->dev_private; | ||
67 | struct drm_panel *panel; | ||
68 | struct drm_bridge *bridge; | ||
69 | int ret = 0; | ||
70 | |||
71 | drm_mode_config_init(dev); | ||
72 | mode_config = &dev->mode_config; | ||
73 | mode_config->funcs = &mode_config_funcs; | ||
74 | mode_config->min_width = 352; | ||
75 | mode_config->max_width = 720; | ||
76 | mode_config->min_height = 240; | ||
77 | mode_config->max_height = 576; | ||
78 | |||
79 | ret = drm_of_find_panel_or_bridge(dev->dev->of_node, | ||
80 | 0, 0, &panel, &bridge); | ||
81 | if (ret && ret != -ENODEV) | ||
82 | return ret; | ||
83 | if (panel) { | ||
84 | bridge = drm_panel_bridge_add(panel, | ||
85 | DRM_MODE_CONNECTOR_Unknown); | ||
86 | if (IS_ERR(bridge)) { | ||
87 | ret = PTR_ERR(bridge); | ||
88 | goto out_bridge; | ||
89 | } | ||
90 | } else { | ||
91 | /* | ||
92 | * TODO: when we are using a different bridge than a panel | ||
93 | * (such as a dumb VGA connector) we need to devise a different | ||
94 | * method to get the connector out of the bridge. | ||
95 | */ | ||
96 | dev_err(dev->dev, "the bridge is not a panel\n"); | ||
97 | goto out_bridge; | ||
98 | } | ||
99 | |||
100 | ret = tve200_display_init(dev); | ||
101 | if (ret) { | ||
102 | dev_err(dev->dev, "failed to init display\n"); | ||
103 | goto out_bridge; | ||
104 | } | ||
105 | |||
106 | ret = drm_simple_display_pipe_attach_bridge(&priv->pipe, | ||
107 | bridge); | ||
108 | if (ret) { | ||
109 | dev_err(dev->dev, "failed to attach bridge\n"); | ||
110 | goto out_bridge; | ||
111 | } | ||
112 | |||
113 | priv->panel = panel; | ||
114 | priv->connector = panel->connector; | ||
115 | priv->bridge = bridge; | ||
116 | |||
117 | dev_info(dev->dev, "attached to panel %s\n", | ||
118 | dev_name(panel->dev)); | ||
119 | |||
120 | ret = drm_vblank_init(dev, 1); | ||
121 | if (ret) { | ||
122 | dev_err(dev->dev, "failed to init vblank\n"); | ||
123 | goto out_bridge; | ||
124 | } | ||
125 | |||
126 | drm_mode_config_reset(dev); | ||
127 | |||
128 | /* | ||
129 | * Passing in 16 here will make the RGB656 mode the default | ||
130 | * Passing in 32 will use XRGB8888 mode | ||
131 | */ | ||
132 | priv->fbdev = drm_fbdev_cma_init(dev, 16, | ||
133 | dev->mode_config.num_connector); | ||
134 | drm_kms_helper_poll_init(dev); | ||
135 | |||
136 | goto finish; | ||
137 | |||
138 | out_bridge: | ||
139 | if (panel) | ||
140 | drm_panel_bridge_remove(bridge); | ||
141 | drm_mode_config_cleanup(dev); | ||
142 | finish: | ||
143 | return ret; | ||
144 | } | ||
145 | |||
146 | DEFINE_DRM_GEM_CMA_FOPS(drm_fops); | ||
147 | |||
148 | static void tve200_lastclose(struct drm_device *dev) | ||
149 | { | ||
150 | struct tve200_drm_dev_private *priv = dev->dev_private; | ||
151 | |||
152 | drm_fbdev_cma_restore_mode(priv->fbdev); | ||
153 | } | ||
154 | |||
155 | static struct drm_driver tve200_drm_driver = { | ||
156 | .driver_features = | ||
157 | DRIVER_MODESET | DRIVER_GEM | DRIVER_PRIME | DRIVER_ATOMIC, | ||
158 | .lastclose = tve200_lastclose, | ||
159 | .ioctls = NULL, | ||
160 | .fops = &drm_fops, | ||
161 | .name = "tve200", | ||
162 | .desc = DRIVER_DESC, | ||
163 | .date = "20170703", | ||
164 | .major = 1, | ||
165 | .minor = 0, | ||
166 | .patchlevel = 0, | ||
167 | .dumb_create = drm_gem_cma_dumb_create, | ||
168 | .gem_free_object_unlocked = drm_gem_cma_free_object, | ||
169 | .gem_vm_ops = &drm_gem_cma_vm_ops, | ||
170 | |||
171 | .enable_vblank = tve200_enable_vblank, | ||
172 | .disable_vblank = tve200_disable_vblank, | ||
173 | |||
174 | .prime_handle_to_fd = drm_gem_prime_handle_to_fd, | ||
175 | .prime_fd_to_handle = drm_gem_prime_fd_to_handle, | ||
176 | .gem_prime_import = drm_gem_prime_import, | ||
177 | .gem_prime_export = drm_gem_prime_export, | ||
178 | .gem_prime_get_sg_table = drm_gem_cma_prime_get_sg_table, | ||
179 | .gem_prime_import_sg_table = drm_gem_cma_prime_import_sg_table, | ||
180 | .gem_prime_vmap = drm_gem_cma_prime_vmap, | ||
181 | .gem_prime_vunmap = drm_gem_cma_prime_vunmap, | ||
182 | .gem_prime_mmap = drm_gem_cma_prime_mmap, | ||
183 | }; | ||
184 | |||
185 | static int tve200_probe(struct platform_device *pdev) | ||
186 | { | ||
187 | struct device *dev = &pdev->dev; | ||
188 | struct tve200_drm_dev_private *priv; | ||
189 | struct drm_device *drm; | ||
190 | struct resource *res; | ||
191 | int irq; | ||
192 | int ret; | ||
193 | |||
194 | priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); | ||
195 | if (!priv) | ||
196 | return -ENOMEM; | ||
197 | |||
198 | drm = drm_dev_alloc(&tve200_drm_driver, dev); | ||
199 | if (IS_ERR(drm)) | ||
200 | return PTR_ERR(drm); | ||
201 | platform_set_drvdata(pdev, drm); | ||
202 | priv->drm = drm; | ||
203 | drm->dev_private = priv; | ||
204 | |||
205 | /* Clock the silicon so we can access the registers */ | ||
206 | priv->pclk = devm_clk_get(dev, "PCLK"); | ||
207 | if (IS_ERR(priv->pclk)) { | ||
208 | dev_err(dev, "unable to get PCLK\n"); | ||
209 | ret = PTR_ERR(priv->pclk); | ||
210 | goto dev_unref; | ||
211 | } | ||
212 | ret = clk_prepare_enable(priv->pclk); | ||
213 | if (ret) { | ||
214 | dev_err(dev, "failed to enable PCLK\n"); | ||
215 | goto dev_unref; | ||
216 | } | ||
217 | |||
218 | /* This clock is for the pixels (27MHz) */ | ||
219 | priv->clk = devm_clk_get(dev, "TVE"); | ||
220 | if (IS_ERR(priv->clk)) { | ||
221 | dev_err(dev, "unable to get TVE clock\n"); | ||
222 | ret = PTR_ERR(priv->clk); | ||
223 | goto clk_disable; | ||
224 | } | ||
225 | |||
226 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
227 | priv->regs = devm_ioremap_resource(dev, res); | ||
228 | if (!priv->regs) { | ||
229 | dev_err(dev, "%s failed mmio\n", __func__); | ||
230 | ret = -EINVAL; | ||
231 | goto clk_disable; | ||
232 | } | ||
233 | |||
234 | irq = platform_get_irq(pdev, 0); | ||
235 | if (!irq) { | ||
236 | ret = -EINVAL; | ||
237 | goto clk_disable; | ||
238 | } | ||
239 | |||
240 | /* turn off interrupts before requesting the irq */ | ||
241 | writel(0, priv->regs + TVE200_INT_EN); | ||
242 | |||
243 | ret = devm_request_irq(dev, irq, tve200_irq, 0, "tve200", priv); | ||
244 | if (ret) { | ||
245 | dev_err(dev, "failed to request irq %d\n", ret); | ||
246 | goto clk_disable; | ||
247 | } | ||
248 | |||
249 | ret = tve200_modeset_init(drm); | ||
250 | if (ret) | ||
251 | goto clk_disable; | ||
252 | |||
253 | ret = drm_dev_register(drm, 0); | ||
254 | if (ret < 0) | ||
255 | goto clk_disable; | ||
256 | |||
257 | return 0; | ||
258 | |||
259 | clk_disable: | ||
260 | clk_disable_unprepare(priv->pclk); | ||
261 | dev_unref: | ||
262 | drm_dev_unref(drm); | ||
263 | return ret; | ||
264 | } | ||
265 | |||
266 | static int tve200_remove(struct platform_device *pdev) | ||
267 | { | ||
268 | struct drm_device *drm = platform_get_drvdata(pdev); | ||
269 | struct tve200_drm_dev_private *priv = drm->dev_private; | ||
270 | |||
271 | drm_dev_unregister(drm); | ||
272 | if (priv->fbdev) | ||
273 | drm_fbdev_cma_fini(priv->fbdev); | ||
274 | if (priv->panel) | ||
275 | drm_panel_bridge_remove(priv->bridge); | ||
276 | drm_mode_config_cleanup(drm); | ||
277 | clk_disable_unprepare(priv->pclk); | ||
278 | drm_dev_unref(drm); | ||
279 | |||
280 | return 0; | ||
281 | } | ||
282 | |||
283 | static const struct of_device_id tve200_of_match[] = { | ||
284 | { | ||
285 | .compatible = "faraday,tve200", | ||
286 | }, | ||
287 | {}, | ||
288 | }; | ||
289 | |||
290 | static struct platform_driver tve200_driver = { | ||
291 | .driver = { | ||
292 | .name = "tve200", | ||
293 | .of_match_table = of_match_ptr(tve200_of_match), | ||
294 | }, | ||
295 | .probe = tve200_probe, | ||
296 | .remove = tve200_remove, | ||
297 | }; | ||
298 | module_platform_driver(tve200_driver); | ||
299 | |||
300 | MODULE_DESCRIPTION(DRIVER_DESC); | ||
301 | MODULE_AUTHOR("Linus Walleij <linus.walleij@linaro.org>"); | ||
302 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/gpu/drm/vc4/Makefile b/drivers/gpu/drm/vc4/Makefile index 25bd5d30415d..719a771f3d5c 100644 --- a/drivers/gpu/drm/vc4/Makefile +++ b/drivers/gpu/drm/vc4/Makefile | |||
@@ -24,5 +24,3 @@ vc4-y := \ | |||
24 | vc4-$(CONFIG_DEBUG_FS) += vc4_debugfs.o | 24 | vc4-$(CONFIG_DEBUG_FS) += vc4_debugfs.o |
25 | 25 | ||
26 | obj-$(CONFIG_DRM_VC4) += vc4.o | 26 | obj-$(CONFIG_DRM_VC4) += vc4.o |
27 | |||
28 | CFLAGS_vc4_trace_points.o := -I$(src) | ||
diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c index 937da8dd65b8..fa37a1c07cf6 100644 --- a/drivers/gpu/drm/vc4/vc4_hdmi.c +++ b/drivers/gpu/drm/vc4/vc4_hdmi.c | |||
@@ -309,16 +309,13 @@ static const struct drm_connector_helper_funcs vc4_hdmi_connector_helper_funcs = | |||
309 | static struct drm_connector *vc4_hdmi_connector_init(struct drm_device *dev, | 309 | static struct drm_connector *vc4_hdmi_connector_init(struct drm_device *dev, |
310 | struct drm_encoder *encoder) | 310 | struct drm_encoder *encoder) |
311 | { | 311 | { |
312 | struct drm_connector *connector = NULL; | 312 | struct drm_connector *connector; |
313 | struct vc4_hdmi_connector *hdmi_connector; | 313 | struct vc4_hdmi_connector *hdmi_connector; |
314 | int ret = 0; | ||
315 | 314 | ||
316 | hdmi_connector = devm_kzalloc(dev->dev, sizeof(*hdmi_connector), | 315 | hdmi_connector = devm_kzalloc(dev->dev, sizeof(*hdmi_connector), |
317 | GFP_KERNEL); | 316 | GFP_KERNEL); |
318 | if (!hdmi_connector) { | 317 | if (!hdmi_connector) |
319 | ret = -ENOMEM; | 318 | return ERR_PTR(-ENOMEM); |
320 | goto fail; | ||
321 | } | ||
322 | connector = &hdmi_connector->base; | 319 | connector = &hdmi_connector->base; |
323 | 320 | ||
324 | hdmi_connector->encoder = encoder; | 321 | hdmi_connector->encoder = encoder; |
@@ -336,12 +333,6 @@ static struct drm_connector *vc4_hdmi_connector_init(struct drm_device *dev, | |||
336 | drm_mode_connector_attach_encoder(connector, encoder); | 333 | drm_mode_connector_attach_encoder(connector, encoder); |
337 | 334 | ||
338 | return connector; | 335 | return connector; |
339 | |||
340 | fail: | ||
341 | if (connector) | ||
342 | vc4_hdmi_connector_destroy(connector); | ||
343 | |||
344 | return ERR_PTR(ret); | ||
345 | } | 336 | } |
346 | 337 | ||
347 | static void vc4_hdmi_encoder_destroy(struct drm_encoder *encoder) | 338 | static void vc4_hdmi_encoder_destroy(struct drm_encoder *encoder) |
diff --git a/drivers/gpu/drm/vc4/vc4_trace.h b/drivers/gpu/drm/vc4/vc4_trace.h index ad7b1ea720c2..deafb32923e1 100644 --- a/drivers/gpu/drm/vc4/vc4_trace.h +++ b/drivers/gpu/drm/vc4/vc4_trace.h | |||
@@ -59,5 +59,5 @@ TRACE_EVENT(vc4_wait_for_seqno_end, | |||
59 | 59 | ||
60 | /* This part must be outside protection */ | 60 | /* This part must be outside protection */ |
61 | #undef TRACE_INCLUDE_PATH | 61 | #undef TRACE_INCLUDE_PATH |
62 | #define TRACE_INCLUDE_PATH . | 62 | #define TRACE_INCLUDE_PATH ../../drivers/gpu/drm/vc4 |
63 | #include <trace/define_trace.h> | 63 | #include <trace/define_trace.h> |
diff --git a/drivers/gpu/drm/zte/zx_drm_drv.c b/drivers/gpu/drm/zte/zx_drm_drv.c index 45244828fc1f..e8b8266c0cde 100644 --- a/drivers/gpu/drm/zte/zx_drm_drv.c +++ b/drivers/gpu/drm/zte/zx_drm_drv.c | |||
@@ -22,6 +22,7 @@ | |||
22 | #include <drm/drm_fb_cma_helper.h> | 22 | #include <drm/drm_fb_cma_helper.h> |
23 | #include <drm/drm_fb_helper.h> | 23 | #include <drm/drm_fb_helper.h> |
24 | #include <drm/drm_gem_cma_helper.h> | 24 | #include <drm/drm_gem_cma_helper.h> |
25 | #include <drm/drm_gem_framebuffer_helper.h> | ||
25 | #include <drm/drm_of.h> | 26 | #include <drm/drm_of.h> |
26 | #include <drm/drmP.h> | 27 | #include <drm/drmP.h> |
27 | 28 | ||
@@ -40,7 +41,7 @@ static void zx_drm_fb_output_poll_changed(struct drm_device *drm) | |||
40 | } | 41 | } |
41 | 42 | ||
42 | static const struct drm_mode_config_funcs zx_drm_mode_config_funcs = { | 43 | static const struct drm_mode_config_funcs zx_drm_mode_config_funcs = { |
43 | .fb_create = drm_fb_cma_create, | 44 | .fb_create = drm_gem_fb_create, |
44 | .output_poll_changed = zx_drm_fb_output_poll_changed, | 45 | .output_poll_changed = zx_drm_fb_output_poll_changed, |
45 | .atomic_check = drm_atomic_helper_check, | 46 | .atomic_check = drm_atomic_helper_check, |
46 | .atomic_commit = drm_atomic_helper_commit, | 47 | .atomic_commit = drm_atomic_helper_commit, |
diff --git a/include/drm/drm_atomic.h b/include/drm/drm_atomic.h index 8a5808eb5628..5834580d75bc 100644 --- a/include/drm/drm_atomic.h +++ b/include/drm/drm_atomic.h | |||
@@ -144,7 +144,6 @@ struct __drm_planes_state { | |||
144 | struct __drm_crtcs_state { | 144 | struct __drm_crtcs_state { |
145 | struct drm_crtc *ptr; | 145 | struct drm_crtc *ptr; |
146 | struct drm_crtc_state *state, *old_state, *new_state; | 146 | struct drm_crtc_state *state, *old_state, *new_state; |
147 | struct drm_crtc_commit *commit; | ||
148 | s32 __user *out_fence_ptr; | 147 | s32 __user *out_fence_ptr; |
149 | unsigned last_vblank_count; | 148 | unsigned last_vblank_count; |
150 | }; | 149 | }; |
@@ -237,6 +236,18 @@ struct drm_atomic_state { | |||
237 | struct drm_modeset_acquire_ctx *acquire_ctx; | 236 | struct drm_modeset_acquire_ctx *acquire_ctx; |
238 | 237 | ||
239 | /** | 238 | /** |
239 | * @fake_commit: | ||
240 | * | ||
241 | * Used for signaling unbound planes/connectors. | ||
242 | * When a connector or plane is not bound to any CRTC, it's still important | ||
243 | * to preserve linearity to prevent the atomic states from being freed to early. | ||
244 | * | ||
245 | * This commit (if set) is not bound to any crtc, but will be completed when | ||
246 | * drm_atomic_helper_commit_hw_done() is called. | ||
247 | */ | ||
248 | struct drm_crtc_commit *fake_commit; | ||
249 | |||
250 | /** | ||
240 | * @commit_work: | 251 | * @commit_work: |
241 | * | 252 | * |
242 | * Work item which can be used by the driver or helpers to execute the | 253 | * Work item which can be used by the driver or helpers to execute the |
@@ -252,10 +263,14 @@ void __drm_crtc_commit_free(struct kref *kref); | |||
252 | * @commit: CRTC commit | 263 | * @commit: CRTC commit |
253 | * | 264 | * |
254 | * Increases the reference of @commit. | 265 | * Increases the reference of @commit. |
266 | * | ||
267 | * Returns: | ||
268 | * The pointer to @commit, with reference increased. | ||
255 | */ | 269 | */ |
256 | static inline void drm_crtc_commit_get(struct drm_crtc_commit *commit) | 270 | static inline struct drm_crtc_commit *drm_crtc_commit_get(struct drm_crtc_commit *commit) |
257 | { | 271 | { |
258 | kref_get(&commit->ref); | 272 | kref_get(&commit->ref); |
273 | return commit; | ||
259 | } | 274 | } |
260 | 275 | ||
261 | /** | 276 | /** |
@@ -555,31 +570,6 @@ int __must_check drm_atomic_nonblocking_commit(struct drm_atomic_state *state); | |||
555 | void drm_state_dump(struct drm_device *dev, struct drm_printer *p); | 570 | void drm_state_dump(struct drm_device *dev, struct drm_printer *p); |
556 | 571 | ||
557 | /** | 572 | /** |
558 | * for_each_connector_in_state - iterate over all connectors in an atomic update | ||
559 | * @__state: &struct drm_atomic_state pointer | ||
560 | * @connector: &struct drm_connector iteration cursor | ||
561 | * @connector_state: &struct drm_connector_state iteration cursor | ||
562 | * @__i: int iteration cursor, for macro-internal use | ||
563 | * | ||
564 | * This iterates over all connectors in an atomic update. Note that before the | ||
565 | * software state is committed (by calling drm_atomic_helper_swap_state(), this | ||
566 | * points to the new state, while afterwards it points to the old state. Due to | ||
567 | * this tricky confusion this macro is deprecated. | ||
568 | * | ||
569 | * FIXME: | ||
570 | * | ||
571 | * Replace all usage of this with one of the explicit iterators below and then | ||
572 | * remove this macro. | ||
573 | */ | ||
574 | #define for_each_connector_in_state(__state, connector, connector_state, __i) \ | ||
575 | for ((__i) = 0; \ | ||
576 | (__i) < (__state)->num_connector && \ | ||
577 | ((connector) = (__state)->connectors[__i].ptr, \ | ||
578 | (connector_state) = (__state)->connectors[__i].state, 1); \ | ||
579 | (__i)++) \ | ||
580 | for_each_if (connector) | ||
581 | |||
582 | /** | ||
583 | * for_each_oldnew_connector_in_state - iterate over all connectors in an atomic update | 573 | * for_each_oldnew_connector_in_state - iterate over all connectors in an atomic update |
584 | * @__state: &struct drm_atomic_state pointer | 574 | * @__state: &struct drm_atomic_state pointer |
585 | * @connector: &struct drm_connector iteration cursor | 575 | * @connector: &struct drm_connector iteration cursor |
@@ -643,31 +633,6 @@ void drm_state_dump(struct drm_device *dev, struct drm_printer *p); | |||
643 | for_each_if (connector) | 633 | for_each_if (connector) |
644 | 634 | ||
645 | /** | 635 | /** |
646 | * for_each_crtc_in_state - iterate over all connectors in an atomic update | ||
647 | * @__state: &struct drm_atomic_state pointer | ||
648 | * @crtc: &struct drm_crtc iteration cursor | ||
649 | * @crtc_state: &struct drm_crtc_state iteration cursor | ||
650 | * @__i: int iteration cursor, for macro-internal use | ||
651 | * | ||
652 | * This iterates over all CRTCs in an atomic update. Note that before the | ||
653 | * software state is committed (by calling drm_atomic_helper_swap_state(), this | ||
654 | * points to the new state, while afterwards it points to the old state. Due to | ||
655 | * this tricky confusion this macro is deprecated. | ||
656 | * | ||
657 | * FIXME: | ||
658 | * | ||
659 | * Replace all usage of this with one of the explicit iterators below and then | ||
660 | * remove this macro. | ||
661 | */ | ||
662 | #define for_each_crtc_in_state(__state, crtc, crtc_state, __i) \ | ||
663 | for ((__i) = 0; \ | ||
664 | (__i) < (__state)->dev->mode_config.num_crtc && \ | ||
665 | ((crtc) = (__state)->crtcs[__i].ptr, \ | ||
666 | (crtc_state) = (__state)->crtcs[__i].state, 1); \ | ||
667 | (__i)++) \ | ||
668 | for_each_if (crtc_state) | ||
669 | |||
670 | /** | ||
671 | * for_each_oldnew_crtc_in_state - iterate over all CRTCs in an atomic update | 636 | * for_each_oldnew_crtc_in_state - iterate over all CRTCs in an atomic update |
672 | * @__state: &struct drm_atomic_state pointer | 637 | * @__state: &struct drm_atomic_state pointer |
673 | * @crtc: &struct drm_crtc iteration cursor | 638 | * @crtc: &struct drm_crtc iteration cursor |
@@ -727,31 +692,6 @@ void drm_state_dump(struct drm_device *dev, struct drm_printer *p); | |||
727 | for_each_if (crtc) | 692 | for_each_if (crtc) |
728 | 693 | ||
729 | /** | 694 | /** |
730 | * for_each_plane_in_state - iterate over all planes in an atomic update | ||
731 | * @__state: &struct drm_atomic_state pointer | ||
732 | * @plane: &struct drm_plane iteration cursor | ||
733 | * @plane_state: &struct drm_plane_state iteration cursor | ||
734 | * @__i: int iteration cursor, for macro-internal use | ||
735 | * | ||
736 | * This iterates over all planes in an atomic update. Note that before the | ||
737 | * software state is committed (by calling drm_atomic_helper_swap_state(), this | ||
738 | * points to the new state, while afterwards it points to the old state. Due to | ||
739 | * this tricky confusion this macro is deprecated. | ||
740 | * | ||
741 | * FIXME: | ||
742 | * | ||
743 | * Replace all usage of this with one of the explicit iterators below and then | ||
744 | * remove this macro. | ||
745 | */ | ||
746 | #define for_each_plane_in_state(__state, plane, plane_state, __i) \ | ||
747 | for ((__i) = 0; \ | ||
748 | (__i) < (__state)->dev->mode_config.num_total_plane && \ | ||
749 | ((plane) = (__state)->planes[__i].ptr, \ | ||
750 | (plane_state) = (__state)->planes[__i].state, 1); \ | ||
751 | (__i)++) \ | ||
752 | for_each_if (plane_state) | ||
753 | |||
754 | /** | ||
755 | * for_each_oldnew_plane_in_state - iterate over all planes in an atomic update | 695 | * for_each_oldnew_plane_in_state - iterate over all planes in an atomic update |
756 | * @__state: &struct drm_atomic_state pointer | 696 | * @__state: &struct drm_atomic_state pointer |
757 | * @plane: &struct drm_plane iteration cursor | 697 | * @plane: &struct drm_plane iteration cursor |
diff --git a/include/drm/drm_bridge.h b/include/drm/drm_bridge.h index 6522d4cbc9d9..682d01ba920c 100644 --- a/include/drm/drm_bridge.h +++ b/include/drm/drm_bridge.h | |||
@@ -245,7 +245,7 @@ struct drm_bridge { | |||
245 | void *driver_private; | 245 | void *driver_private; |
246 | }; | 246 | }; |
247 | 247 | ||
248 | int drm_bridge_add(struct drm_bridge *bridge); | 248 | void drm_bridge_add(struct drm_bridge *bridge); |
249 | void drm_bridge_remove(struct drm_bridge *bridge); | 249 | void drm_bridge_remove(struct drm_bridge *bridge); |
250 | struct drm_bridge *of_drm_find_bridge(struct device_node *np); | 250 | struct drm_bridge *of_drm_find_bridge(struct device_node *np); |
251 | int drm_bridge_attach(struct drm_encoder *encoder, struct drm_bridge *bridge, | 251 | int drm_bridge_attach(struct drm_encoder *encoder, struct drm_bridge *bridge, |
diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h index ea8da401c93c..b34904dc8b9b 100644 --- a/include/drm/drm_connector.h +++ b/include/drm/drm_connector.h | |||
@@ -347,6 +347,13 @@ struct drm_connector_state { | |||
347 | 347 | ||
348 | struct drm_atomic_state *state; | 348 | struct drm_atomic_state *state; |
349 | 349 | ||
350 | /** | ||
351 | * @commit: Tracks the pending commit to prevent use-after-free conditions. | ||
352 | * | ||
353 | * Is only set when @crtc is NULL. | ||
354 | */ | ||
355 | struct drm_crtc_commit *commit; | ||
356 | |||
350 | struct drm_tv_connector_state tv; | 357 | struct drm_tv_connector_state tv; |
351 | 358 | ||
352 | /** | 359 | /** |
@@ -888,8 +895,7 @@ struct drm_connector { | |||
888 | * This is protected by @drm_mode_config.connection_mutex. Note that | 895 | * This is protected by @drm_mode_config.connection_mutex. Note that |
889 | * nonblocking atomic commits access the current connector state without | 896 | * nonblocking atomic commits access the current connector state without |
890 | * taking locks. Either by going through the &struct drm_atomic_state | 897 | * taking locks. Either by going through the &struct drm_atomic_state |
891 | * pointers, see for_each_connector_in_state(), | 898 | * pointers, see for_each_oldnew_connector_in_state(), |
892 | * for_each_oldnew_connector_in_state(), | ||
893 | * for_each_old_connector_in_state() and | 899 | * for_each_old_connector_in_state() and |
894 | * for_each_new_connector_in_state(). Or through careful ordering of | 900 | * for_each_new_connector_in_state(). Or through careful ordering of |
895 | * atomic commit operations as implemented in the atomic helpers, see | 901 | * atomic commit operations as implemented in the atomic helpers, see |
diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h index 1a642020e306..80c97210eda5 100644 --- a/include/drm/drm_crtc.h +++ b/include/drm/drm_crtc.h | |||
@@ -253,6 +253,15 @@ struct drm_crtc_state { | |||
253 | */ | 253 | */ |
254 | struct drm_pending_vblank_event *event; | 254 | struct drm_pending_vblank_event *event; |
255 | 255 | ||
256 | /** | ||
257 | * @commit: | ||
258 | * | ||
259 | * This tracks how the commit for this update proceeds through the | ||
260 | * various phases. This is never cleared, except when we destroy the | ||
261 | * state, so that subsequent commits can synchronize with previous ones. | ||
262 | */ | ||
263 | struct drm_crtc_commit *commit; | ||
264 | |||
256 | struct drm_atomic_state *state; | 265 | struct drm_atomic_state *state; |
257 | }; | 266 | }; |
258 | 267 | ||
@@ -797,10 +806,10 @@ struct drm_crtc { | |||
797 | * This is protected by @mutex. Note that nonblocking atomic commits | 806 | * This is protected by @mutex. Note that nonblocking atomic commits |
798 | * access the current CRTC state without taking locks. Either by going | 807 | * access the current CRTC state without taking locks. Either by going |
799 | * through the &struct drm_atomic_state pointers, see | 808 | * through the &struct drm_atomic_state pointers, see |
800 | * for_each_crtc_in_state(), for_each_oldnew_crtc_in_state(), | 809 | * for_each_oldnew_crtc_in_state(), for_each_old_crtc_in_state() and |
801 | * for_each_old_crtc_in_state() and for_each_new_crtc_in_state(). Or | 810 | * for_each_new_crtc_in_state(). Or through careful ordering of atomic |
802 | * through careful ordering of atomic commit operations as implemented | 811 | * commit operations as implemented in the atomic helpers, see |
803 | * in the atomic helpers, see &struct drm_crtc_commit. | 812 | * &struct drm_crtc_commit. |
804 | */ | 813 | */ |
805 | struct drm_crtc_state *state; | 814 | struct drm_crtc_state *state; |
806 | 815 | ||
@@ -808,10 +817,16 @@ struct drm_crtc { | |||
808 | * @commit_list: | 817 | * @commit_list: |
809 | * | 818 | * |
810 | * List of &drm_crtc_commit structures tracking pending commits. | 819 | * List of &drm_crtc_commit structures tracking pending commits. |
811 | * Protected by @commit_lock. This list doesn't hold its own full | 820 | * Protected by @commit_lock. This list holds its own full reference, |
812 | * reference, but burrows it from the ongoing commit. Commit entries | 821 | * as does the ongoing commit. |
813 | * must be removed from this list once the commit is fully completed, | 822 | * |
814 | * but before it's correspoding &drm_atomic_state gets destroyed. | 823 | * "Note that the commit for a state change is also tracked in |
824 | * &drm_crtc_state.commit. For accessing the immediately preceding | ||
825 | * commit in an atomic update it is recommended to just use that | ||
826 | * pointer in the old CRTC state, since accessing that doesn't need | ||
827 | * any locking or list-walking. @commit_list should only be used to | ||
828 | * stall for framebuffer cleanup that's signalled through | ||
829 | * &drm_crtc_commit.cleanup_done." | ||
815 | */ | 830 | */ |
816 | struct list_head commit_list; | 831 | struct list_head commit_list; |
817 | 832 | ||
diff --git a/include/drm/drm_dp_helper.h b/include/drm/drm_dp_helper.h index b17476a6909c..11c39f15f1b3 100644 --- a/include/drm/drm_dp_helper.h +++ b/include/drm/drm_dp_helper.h | |||
@@ -738,6 +738,11 @@ | |||
738 | #define DP_RECEIVER_ALPM_STATUS 0x200b /* eDP 1.4 */ | 738 | #define DP_RECEIVER_ALPM_STATUS 0x200b /* eDP 1.4 */ |
739 | # define DP_ALPM_LOCK_TIMEOUT_ERROR (1 << 0) | 739 | # define DP_ALPM_LOCK_TIMEOUT_ERROR (1 << 0) |
740 | 740 | ||
741 | #define DP_LANE0_1_STATUS_ESI 0x200c /* status same as 0x202 */ | ||
742 | #define DP_LANE2_3_STATUS_ESI 0x200d /* status same as 0x203 */ | ||
743 | #define DP_LANE_ALIGN_STATUS_UPDATED_ESI 0x200e /* status same as 0x204 */ | ||
744 | #define DP_SINK_STATUS_ESI 0x200f /* status same as 0x205 */ | ||
745 | |||
741 | #define DP_DPRX_FEATURE_ENUMERATION_LIST 0x2210 /* DP 1.3 */ | 746 | #define DP_DPRX_FEATURE_ENUMERATION_LIST 0x2210 /* DP 1.3 */ |
742 | # define DP_GTC_CAP (1 << 0) /* DP 1.3 */ | 747 | # define DP_GTC_CAP (1 << 0) /* DP 1.3 */ |
743 | # define DP_SST_SPLIT_SDP_CAP (1 << 1) /* DP 1.4 */ | 748 | # define DP_SST_SPLIT_SDP_CAP (1 << 1) /* DP 1.4 */ |
@@ -871,6 +876,18 @@ void drm_dp_link_train_channel_eq_delay(const u8 dpcd[DP_RECEIVER_CAP_SIZE]); | |||
871 | u8 drm_dp_link_rate_to_bw_code(int link_rate); | 876 | u8 drm_dp_link_rate_to_bw_code(int link_rate); |
872 | int drm_dp_bw_code_to_link_rate(u8 link_bw); | 877 | int drm_dp_bw_code_to_link_rate(u8 link_bw); |
873 | 878 | ||
879 | #define DP_SDP_AUDIO_TIMESTAMP 0x01 | ||
880 | #define DP_SDP_AUDIO_STREAM 0x02 | ||
881 | #define DP_SDP_EXTENSION 0x04 /* DP 1.1 */ | ||
882 | #define DP_SDP_AUDIO_COPYMANAGEMENT 0x05 /* DP 1.2 */ | ||
883 | #define DP_SDP_ISRC 0x06 /* DP 1.2 */ | ||
884 | #define DP_SDP_VSC 0x07 /* DP 1.2 */ | ||
885 | #define DP_SDP_CAMERA_GENERIC(i) (0x08 + (i)) /* 0-7, DP 1.3 */ | ||
886 | #define DP_SDP_PPS 0x10 /* DP 1.4 */ | ||
887 | #define DP_SDP_VSC_EXT_VESA 0x20 /* DP 1.4 */ | ||
888 | #define DP_SDP_VSC_EXT_CEA 0x21 /* DP 1.4 */ | ||
889 | /* 0x80+ CEA-861 infoframe types */ | ||
890 | |||
874 | struct edp_sdp_header { | 891 | struct edp_sdp_header { |
875 | u8 HB0; /* Secondary Data Packet ID */ | 892 | u8 HB0; /* Secondary Data Packet ID */ |
876 | u8 HB1; /* Secondary Data Packet Type */ | 893 | u8 HB1; /* Secondary Data Packet Type */ |
diff --git a/include/drm/drm_dp_mst_helper.h b/include/drm/drm_dp_mst_helper.h index d55abb75f29a..7f78d26a0766 100644 --- a/include/drm/drm_dp_mst_helper.h +++ b/include/drm/drm_dp_mst_helper.h | |||
@@ -631,5 +631,7 @@ int drm_dp_atomic_find_vcpi_slots(struct drm_atomic_state *state, | |||
631 | int drm_dp_atomic_release_vcpi_slots(struct drm_atomic_state *state, | 631 | int drm_dp_atomic_release_vcpi_slots(struct drm_atomic_state *state, |
632 | struct drm_dp_mst_topology_mgr *mgr, | 632 | struct drm_dp_mst_topology_mgr *mgr, |
633 | int slots); | 633 | int slots); |
634 | int drm_dp_send_power_updown_phy(struct drm_dp_mst_topology_mgr *mgr, | ||
635 | struct drm_dp_mst_port *port, bool power_up); | ||
634 | 636 | ||
635 | #endif | 637 | #endif |
diff --git a/include/drm/drm_edid.h b/include/drm/drm_edid.h index 1e1908a6b1d6..6f35909b8add 100644 --- a/include/drm/drm_edid.h +++ b/include/drm/drm_edid.h | |||
@@ -341,6 +341,8 @@ int drm_av_sync_delay(struct drm_connector *connector, | |||
341 | 341 | ||
342 | #ifdef CONFIG_DRM_LOAD_EDID_FIRMWARE | 342 | #ifdef CONFIG_DRM_LOAD_EDID_FIRMWARE |
343 | struct edid *drm_load_edid_firmware(struct drm_connector *connector); | 343 | struct edid *drm_load_edid_firmware(struct drm_connector *connector); |
344 | int __drm_set_edid_firmware_path(const char *path); | ||
345 | int __drm_get_edid_firmware_path(char *buf, size_t bufsize); | ||
344 | #else | 346 | #else |
345 | static inline struct edid * | 347 | static inline struct edid * |
346 | drm_load_edid_firmware(struct drm_connector *connector) | 348 | drm_load_edid_firmware(struct drm_connector *connector) |
diff --git a/include/drm/drm_gem_framebuffer_helper.h b/include/drm/drm_gem_framebuffer_helper.h index db9cfa07235e..5ca7cdc3f527 100644 --- a/include/drm/drm_gem_framebuffer_helper.h +++ b/include/drm/drm_gem_framebuffer_helper.h | |||
@@ -2,8 +2,8 @@ | |||
2 | #define __DRM_GEM_FB_HELPER_H__ | 2 | #define __DRM_GEM_FB_HELPER_H__ |
3 | 3 | ||
4 | struct drm_device; | 4 | struct drm_device; |
5 | struct drm_file; | ||
6 | struct drm_fb_helper_surface_size; | 5 | struct drm_fb_helper_surface_size; |
6 | struct drm_file; | ||
7 | struct drm_framebuffer; | 7 | struct drm_framebuffer; |
8 | struct drm_framebuffer_funcs; | 8 | struct drm_framebuffer_funcs; |
9 | struct drm_gem_object; | 9 | struct drm_gem_object; |
diff --git a/include/drm/drm_modeset_helper_vtables.h b/include/drm/drm_modeset_helper_vtables.h index c55cf3ff6847..16646c44b7df 100644 --- a/include/drm/drm_modeset_helper_vtables.h +++ b/include/drm/drm_modeset_helper_vtables.h | |||
@@ -314,7 +314,7 @@ struct drm_crtc_helper_funcs { | |||
314 | * implementation in drm_atomic_helper_check(). | 314 | * implementation in drm_atomic_helper_check(). |
315 | * | 315 | * |
316 | * When using drm_atomic_helper_check_planes() this hook is called | 316 | * When using drm_atomic_helper_check_planes() this hook is called |
317 | * after the &drm_plane_helper_funcs.atomc_check hook for planes, which | 317 | * after the &drm_plane_helper_funcs.atomic_check hook for planes, which |
318 | * allows drivers to assign shared resources requested by planes in this | 318 | * allows drivers to assign shared resources requested by planes in this |
319 | * callback here. For more complicated dependencies the driver can call | 319 | * callback here. For more complicated dependencies the driver can call |
320 | * the provided check helpers multiple times until the computed state | 320 | * the provided check helpers multiple times until the computed state |
diff --git a/include/drm/drm_modeset_lock.h b/include/drm/drm_modeset_lock.h index 4b27c2bb955c..a685d1bb21f2 100644 --- a/include/drm/drm_modeset_lock.h +++ b/include/drm/drm_modeset_lock.h | |||
@@ -34,6 +34,7 @@ struct drm_modeset_lock; | |||
34 | * @contended: used internally for -EDEADLK handling | 34 | * @contended: used internally for -EDEADLK handling |
35 | * @locked: list of held locks | 35 | * @locked: list of held locks |
36 | * @trylock_only: trylock mode used in atomic contexts/panic notifiers | 36 | * @trylock_only: trylock mode used in atomic contexts/panic notifiers |
37 | * @interruptible: whether interruptible locking should be used. | ||
37 | * | 38 | * |
38 | * Each thread competing for a set of locks must use one acquire | 39 | * Each thread competing for a set of locks must use one acquire |
39 | * ctx. And if any lock fxn returns -EDEADLK, it must backoff and | 40 | * ctx. And if any lock fxn returns -EDEADLK, it must backoff and |
@@ -59,6 +60,9 @@ struct drm_modeset_acquire_ctx { | |||
59 | * Trylock mode, use only for panic handlers! | 60 | * Trylock mode, use only for panic handlers! |
60 | */ | 61 | */ |
61 | bool trylock_only; | 62 | bool trylock_only; |
63 | |||
64 | /* Perform interruptible waits on this context. */ | ||
65 | bool interruptible; | ||
62 | }; | 66 | }; |
63 | 67 | ||
64 | /** | 68 | /** |
@@ -82,12 +86,13 @@ struct drm_modeset_lock { | |||
82 | struct list_head head; | 86 | struct list_head head; |
83 | }; | 87 | }; |
84 | 88 | ||
89 | #define DRM_MODESET_ACQUIRE_INTERRUPTIBLE BIT(0) | ||
90 | |||
85 | void drm_modeset_acquire_init(struct drm_modeset_acquire_ctx *ctx, | 91 | void drm_modeset_acquire_init(struct drm_modeset_acquire_ctx *ctx, |
86 | uint32_t flags); | 92 | uint32_t flags); |
87 | void drm_modeset_acquire_fini(struct drm_modeset_acquire_ctx *ctx); | 93 | void drm_modeset_acquire_fini(struct drm_modeset_acquire_ctx *ctx); |
88 | void drm_modeset_drop_locks(struct drm_modeset_acquire_ctx *ctx); | 94 | void drm_modeset_drop_locks(struct drm_modeset_acquire_ctx *ctx); |
89 | void drm_modeset_backoff(struct drm_modeset_acquire_ctx *ctx); | 95 | int drm_modeset_backoff(struct drm_modeset_acquire_ctx *ctx); |
90 | int drm_modeset_backoff_interruptible(struct drm_modeset_acquire_ctx *ctx); | ||
91 | 96 | ||
92 | void drm_modeset_lock_init(struct drm_modeset_lock *lock); | 97 | void drm_modeset_lock_init(struct drm_modeset_lock *lock); |
93 | 98 | ||
@@ -111,8 +116,7 @@ static inline bool drm_modeset_is_locked(struct drm_modeset_lock *lock) | |||
111 | 116 | ||
112 | int drm_modeset_lock(struct drm_modeset_lock *lock, | 117 | int drm_modeset_lock(struct drm_modeset_lock *lock, |
113 | struct drm_modeset_acquire_ctx *ctx); | 118 | struct drm_modeset_acquire_ctx *ctx); |
114 | int drm_modeset_lock_interruptible(struct drm_modeset_lock *lock, | 119 | int __must_check drm_modeset_lock_single_interruptible(struct drm_modeset_lock *lock); |
115 | struct drm_modeset_acquire_ctx *ctx); | ||
116 | void drm_modeset_unlock(struct drm_modeset_lock *lock); | 120 | void drm_modeset_unlock(struct drm_modeset_lock *lock); |
117 | 121 | ||
118 | struct drm_device; | 122 | struct drm_device; |
diff --git a/include/drm/drm_plane.h b/include/drm/drm_plane.h index 73f90f9d057f..82a217bd77f0 100644 --- a/include/drm/drm_plane.h +++ b/include/drm/drm_plane.h | |||
@@ -123,6 +123,14 @@ struct drm_plane_state { | |||
123 | */ | 123 | */ |
124 | bool visible; | 124 | bool visible; |
125 | 125 | ||
126 | /** | ||
127 | * @commit: Tracks the pending commit to prevent use-after-free conditions, | ||
128 | * and for async plane updates. | ||
129 | * | ||
130 | * May be NULL. | ||
131 | */ | ||
132 | struct drm_crtc_commit *commit; | ||
133 | |||
126 | struct drm_atomic_state *state; | 134 | struct drm_atomic_state *state; |
127 | }; | 135 | }; |
128 | 136 | ||
@@ -531,10 +539,10 @@ struct drm_plane { | |||
531 | * This is protected by @mutex. Note that nonblocking atomic commits | 539 | * This is protected by @mutex. Note that nonblocking atomic commits |
532 | * access the current plane state without taking locks. Either by going | 540 | * access the current plane state without taking locks. Either by going |
533 | * through the &struct drm_atomic_state pointers, see | 541 | * through the &struct drm_atomic_state pointers, see |
534 | * for_each_plane_in_state(), for_each_oldnew_plane_in_state(), | 542 | * for_each_oldnew_plane_in_state(), for_each_old_plane_in_state() and |
535 | * for_each_old_plane_in_state() and for_each_new_plane_in_state(). Or | 543 | * for_each_new_plane_in_state(). Or through careful ordering of atomic |
536 | * through careful ordering of atomic commit operations as implemented | 544 | * commit operations as implemented in the atomic helpers, see |
537 | * in the atomic helpers, see &struct drm_crtc_commit. | 545 | * &struct drm_crtc_commit. |
538 | */ | 546 | */ |
539 | struct drm_plane_state *state; | 547 | struct drm_plane_state *state; |
540 | 548 | ||
diff --git a/include/linux/sync_file.h b/include/linux/sync_file.h index 0ad87c434ae6..790ca021203a 100644 --- a/include/linux/sync_file.h +++ b/include/linux/sync_file.h | |||
@@ -25,8 +25,12 @@ | |||
25 | * @file: file representing this fence | 25 | * @file: file representing this fence |
26 | * @sync_file_list: membership in global file list | 26 | * @sync_file_list: membership in global file list |
27 | * @wq: wait queue for fence signaling | 27 | * @wq: wait queue for fence signaling |
28 | * @flags: flags for the sync_file | ||
28 | * @fence: fence with the fences in the sync_file | 29 | * @fence: fence with the fences in the sync_file |
29 | * @cb: fence callback information | 30 | * @cb: fence callback information |
31 | * | ||
32 | * flags: | ||
33 | * POLL_ENABLED: whether userspace is currently poll()'ing or not | ||
30 | */ | 34 | */ |
31 | struct sync_file { | 35 | struct sync_file { |
32 | struct file *file; | 36 | struct file *file; |
diff --git a/include/uapi/drm/drm_mode.h b/include/uapi/drm/drm_mode.h index 54fc38c3c3f1..34b6bb34b002 100644 --- a/include/uapi/drm/drm_mode.h +++ b/include/uapi/drm/drm_mode.h | |||
@@ -749,9 +749,9 @@ struct drm_format_modifier { | |||
749 | * If the number formats grew to 128, and formats 98-102 are | 749 | * If the number formats grew to 128, and formats 98-102 are |
750 | * supported with the modifier: | 750 | * supported with the modifier: |
751 | * | 751 | * |
752 | * 0x0000003c00000000 0000000000000000 | 752 | * 0x0000007c00000000 0000000000000000 |
753 | * ^ | 753 | * ^ |
754 | * |__offset = 64, formats = 0x3c00000000 | 754 | * |__offset = 64, formats = 0x7c00000000 |
755 | * | 755 | * |
756 | */ | 756 | */ |
757 | __u64 formats; | 757 | __u64 formats; |