diff options
author | Dave Airlie <airlied@redhat.com> | 2017-05-17 22:57:06 -0400 |
---|---|---|
committer | Dave Airlie <airlied@redhat.com> | 2017-05-17 22:57:06 -0400 |
commit | e98c58e55f68f8785aebfab1f8c9a03d8de0afe1 (patch) | |
tree | 8357e8fda6efb0867ac39fc6b9211a579721d00a | |
parent | 2ea659a9ef488125eb46da6eb571de5eae5c43f6 (diff) | |
parent | 9cf8f5802f39d9991158b29033c852bccfc3a4d4 (diff) |
Merge tag 'drm-misc-next-2017-05-16' of git://anongit.freedesktop.org/git/drm-misc into drm-next
UAPI Changes:
- Return -ENODEV instead of -ENXIO when creating cma fb w/o valid gem (Daniel)
- Add aspect ratio and custom scaling propertis to connector state (Maarten)
Cross-subsystem Changes:
- None
Core Changes:
- Add Laurent as bridge reviewer and Andrzej as bridge maintainer (Archit)
- Maintain new STM driver through -misc (Yannick)
- Misc doc improvements (as is tradition) (Daniel)
- Add driver-private objects to atomic state (Dhinakaran)
- Deprecate preclose hook in modern drivers (use postclose) (Daniel)
- Add hwmode to vblank struct. This fixes mode access in irq context and reduced
a bunch of boilerplate (Daniel)
Driver Changes:
- vc4: Add out-fence support to vc4 V3D rendering (Eric)
- stm: Add stm32f429 display hw and am-480272h3tmqw-t01h panel support (Yannick)
- vc4: Remove 256MB cma limit from vc4 (Eric)
- dw-hdmi: Disable audio when inactive, instead of always enabled (Romain)
- zte: Add support for VGA to the ZTE driver (Shawn)
- i915: Track DP MST bandwidth and check it in atomic_check (Dhinakaran)
- vgem: Enable gem dmabuf import iface to facilitate ion testing (Laura)
- vc4: Add support for Cygnus (new dt compat string + couple bug fixes) (Eric)
- pl111: Add driver for pl111 CLCD display controller (Eric/Tom)
- vgem: Subclass drm_device instead of standalone platform device (Chris)
Cc: Archit Taneja <architt@codeaurora.org>
Cc: Eric Anholt <eric@anholt.net>
Cc: Yannick Fertre <yannick.fertre@st.com>
Cc: Romain Perier <romain.perier@collabora.com>
Cc: Navare, Manasi D <manasi.d.navare@intel.com>
Cc: Shawn Guo <shawn.guo@linaro.org>
Cc: Dhinakaran Pandiyan <dhinakaran.pandiyan@intel.com>
Cc: Laura Abbott <labbott@redhat.com>
Cc: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
Cc: Tom Cooksey <tom.cooksey@arm.com>
Cc: Daniel Vetter <daniel.vetter@intel.com>
Cc: Chris Wilson <chris@chris-wilson.co.uk>
* tag 'drm-misc-next-2017-05-16' of git://anongit.freedesktop.org/git/drm-misc: (72 commits)
drm: add missing declaration to drm_blend.h
drm/dp: Wait up all outstanding tx waiters
drm/dp: Read the tx msg state once after checking for an event
drm/prime: Forward declare struct device
drm/vblank: Lock down vblank->hwmode more
drm/vblank: drop the mode argument from drm_calc_vbltimestamp_from_scanoutpos
drm/vblank: Add FIXME comments about moving the vblank ts hooks
drm/vblank: Switch to bool in_vblank_irq in get_vblank_timestamp
drm/vblank: Switch drm_driver->get_vblank_timestamp to return a bool
drm/vgem: Convert to a struct drm_device subclass
gpu: drm: gma500: remove dead code
drm/sti: Adjust two checks for null pointers in sti_hqvdp_probe()
drm/sti: Fix typos in a comment line
drm/sti: Fix a typo in a comment line
drm/sti: Replace 17 seq_puts() calls by seq_putc()
drm/sti: Reduce function calls for sequence output at five places
drm/sti: use seq_puts to display a string
drm: Nerf the preclose callback for modern drivers
drm/exynos: Merge pre/postclose hooks
drm/tegra: switch to postclose
...
109 files changed, 4980 insertions, 927 deletions
diff --git a/Documentation/devicetree/bindings/display/brcm,bcm-vc4.txt b/Documentation/devicetree/bindings/display/brcm,bcm-vc4.txt index ca02d3e4db91..284e2b14cfbe 100644 --- a/Documentation/devicetree/bindings/display/brcm,bcm-vc4.txt +++ b/Documentation/devicetree/bindings/display/brcm,bcm-vc4.txt | |||
@@ -5,7 +5,7 @@ with HDMI output and the HVS (Hardware Video Scaler) for compositing | |||
5 | display planes. | 5 | display planes. |
6 | 6 | ||
7 | Required properties for VC4: | 7 | Required properties for VC4: |
8 | - compatible: Should be "brcm,bcm2835-vc4" | 8 | - compatible: Should be "brcm,bcm2835-vc4" or "brcm,cygnus-vc4" |
9 | 9 | ||
10 | Required properties for Pixel Valve: | 10 | Required properties for Pixel Valve: |
11 | - compatible: Should be one of "brcm,bcm2835-pixelvalve0", | 11 | - compatible: Should be one of "brcm,bcm2835-pixelvalve0", |
@@ -54,11 +54,14 @@ Required properties for VEC: | |||
54 | See bindings/interrupt-controller/brcm,bcm2835-armctrl-ic.txt | 54 | See bindings/interrupt-controller/brcm,bcm2835-armctrl-ic.txt |
55 | 55 | ||
56 | Required properties for V3D: | 56 | Required properties for V3D: |
57 | - compatible: Should be "brcm,bcm2835-v3d" | 57 | - compatible: Should be "brcm,bcm2835-v3d" or "brcm,cygnus-v3d" |
58 | - reg: Physical base address and length of the V3D's registers | 58 | - reg: Physical base address and length of the V3D's registers |
59 | - interrupts: The interrupt number | 59 | - interrupts: The interrupt number |
60 | See bindings/interrupt-controller/brcm,bcm2835-armctrl-ic.txt | 60 | See bindings/interrupt-controller/brcm,bcm2835-armctrl-ic.txt |
61 | 61 | ||
62 | Optional properties for V3D: | ||
63 | - clocks: The clock the unit runs on | ||
64 | |||
62 | Required properties for DSI: | 65 | Required properties for DSI: |
63 | - compatible: Should be "brcm,bcm2835-dsi0" or "brcm,bcm2835-dsi1" | 66 | - compatible: Should be "brcm,bcm2835-dsi0" or "brcm,bcm2835-dsi1" |
64 | - reg: Physical base address and length of the DSI block's registers | 67 | - reg: Physical base address and length of the DSI block's registers |
diff --git a/Documentation/devicetree/bindings/display/st,stm32-ltdc.txt b/Documentation/devicetree/bindings/display/st,stm32-ltdc.txt new file mode 100644 index 000000000000..8e1476941c0f --- /dev/null +++ b/Documentation/devicetree/bindings/display/st,stm32-ltdc.txt | |||
@@ -0,0 +1,36 @@ | |||
1 | * STMicroelectronics STM32 lcd-tft display controller | ||
2 | |||
3 | - ltdc: lcd-tft display controller host | ||
4 | must be a sub-node of st-display-subsystem | ||
5 | Required properties: | ||
6 | - compatible: "st,stm32-ltdc" | ||
7 | - reg: Physical base address of the IP registers and length of memory mapped region. | ||
8 | - clocks: A list of phandle + clock-specifier pairs, one for each | ||
9 | entry in 'clock-names'. | ||
10 | - clock-names: A list of clock names. For ltdc it should contain: | ||
11 | - "lcd" for the clock feeding the output pixel clock & IP clock. | ||
12 | - resets: reset to be used by the device (defined by use of RCC macro). | ||
13 | Required nodes: | ||
14 | - Video port for RGB output. | ||
15 | |||
16 | Example: | ||
17 | |||
18 | / { | ||
19 | ... | ||
20 | soc { | ||
21 | ... | ||
22 | ltdc: display-controller@40016800 { | ||
23 | compatible = "st,stm32-ltdc"; | ||
24 | reg = <0x40016800 0x200>; | ||
25 | interrupts = <88>, <89>; | ||
26 | resets = <&rcc STM32F4_APB2_RESET(LTDC)>; | ||
27 | clocks = <&rcc 1 CLK_LCD>; | ||
28 | clock-names = "lcd"; | ||
29 | |||
30 | port { | ||
31 | ltdc_out_rgb: endpoint { | ||
32 | }; | ||
33 | }; | ||
34 | }; | ||
35 | }; | ||
36 | }; | ||
diff --git a/Documentation/devicetree/bindings/display/zte,vou.txt b/Documentation/devicetree/bindings/display/zte,vou.txt index 9c356284232b..38476475fd60 100644 --- a/Documentation/devicetree/bindings/display/zte,vou.txt +++ b/Documentation/devicetree/bindings/display/zte,vou.txt | |||
@@ -58,6 +58,18 @@ Required properties: | |||
58 | integer cells. The first cell is the offset of SYSCTRL register used | 58 | integer cells. The first cell is the offset of SYSCTRL register used |
59 | to control TV Encoder DAC power, and the second cell is the bit mask. | 59 | to control TV Encoder DAC power, and the second cell is the bit mask. |
60 | 60 | ||
61 | * VGA output device | ||
62 | |||
63 | Required properties: | ||
64 | - compatible: should be "zte,zx296718-vga" | ||
65 | - reg: Physical base address and length of the VGA device IO region | ||
66 | - interrupts : VGA interrupt number to CPU | ||
67 | - clocks: Phandle with clock-specifier pointing to VGA I2C clock. | ||
68 | - clock-names: Must be "i2c_wclk". | ||
69 | - zte,vga-power-control: the phandle to SYSCTRL block followed by two | ||
70 | integer cells. The first cell is the offset of SYSCTRL register used | ||
71 | to control VGA DAC power, and the second cell is the bit mask. | ||
72 | |||
61 | Example: | 73 | Example: |
62 | 74 | ||
63 | vou: vou@1440000 { | 75 | vou: vou@1440000 { |
@@ -81,6 +93,15 @@ vou: vou@1440000 { | |||
81 | "main_wclk", "aux_wclk"; | 93 | "main_wclk", "aux_wclk"; |
82 | }; | 94 | }; |
83 | 95 | ||
96 | vga: vga@8000 { | ||
97 | compatible = "zte,zx296718-vga"; | ||
98 | reg = <0x8000 0x1000>; | ||
99 | interrupts = <GIC_SPI 86 IRQ_TYPE_LEVEL_HIGH>; | ||
100 | clocks = <&topcrm VGA_I2C_WCLK>; | ||
101 | clock-names = "i2c_wclk"; | ||
102 | zte,vga-power-control = <&sysctrl 0x170 0xe0>; | ||
103 | }; | ||
104 | |||
84 | hdmi: hdmi@c000 { | 105 | hdmi: hdmi@c000 { |
85 | compatible = "zte,zx296718-hdmi"; | 106 | compatible = "zte,zx296718-hdmi"; |
86 | reg = <0xc000 0x4000>; | 107 | reg = <0xc000 0x4000>; |
diff --git a/Documentation/gpu/index.rst b/Documentation/gpu/index.rst index c572f092739e..037a39ac1807 100644 --- a/Documentation/gpu/index.rst +++ b/Documentation/gpu/index.rst | |||
@@ -12,6 +12,7 @@ Linux GPU Driver Developer's Guide | |||
12 | drm-uapi | 12 | drm-uapi |
13 | i915 | 13 | i915 |
14 | meson | 14 | meson |
15 | pl111 | ||
15 | tinydrm | 16 | tinydrm |
16 | vc4 | 17 | vc4 |
17 | vga-switcheroo | 18 | vga-switcheroo |
diff --git a/Documentation/gpu/pl111.rst b/Documentation/gpu/pl111.rst new file mode 100644 index 000000000000..9b03736d33dd --- /dev/null +++ b/Documentation/gpu/pl111.rst | |||
@@ -0,0 +1,6 @@ | |||
1 | ========================================== | ||
2 | drm/pl111 ARM PrimeCell PL111 CLCD Driver | ||
3 | ========================================== | ||
4 | |||
5 | .. kernel-doc:: drivers/gpu/drm/pl111/pl111_drv.c | ||
6 | :doc: ARM PrimeCell PL111 CLCD Driver | ||
diff --git a/MAINTAINERS b/MAINTAINERS index f7d568b8f133..81cdd03a6ad0 100644 --- a/MAINTAINERS +++ b/MAINTAINERS | |||
@@ -4228,6 +4228,12 @@ F: include/drm/drm* | |||
4228 | F: include/uapi/drm/drm* | 4228 | F: include/uapi/drm/drm* |
4229 | F: include/linux/vga* | 4229 | F: include/linux/vga* |
4230 | 4230 | ||
4231 | DRM DRIVER FOR ARM PL111 CLCD | ||
4232 | M: Eric Anholt <eric@anholt.net> | ||
4233 | T: git git://anongit.freedesktop.org/drm/drm-misc | ||
4234 | S: Supported | ||
4235 | F: drivers/gpu/drm/pl111/ | ||
4236 | |||
4231 | DRM DRIVER FOR AST SERVER GRAPHICS CHIPS | 4237 | DRM DRIVER FOR AST SERVER GRAPHICS CHIPS |
4232 | M: Dave Airlie <airlied@redhat.com> | 4238 | M: Dave Airlie <airlied@redhat.com> |
4233 | S: Odd Fixes | 4239 | S: Odd Fixes |
@@ -4235,6 +4241,8 @@ F: drivers/gpu/drm/ast/ | |||
4235 | 4241 | ||
4236 | DRM DRIVERS FOR BRIDGE CHIPS | 4242 | DRM DRIVERS FOR BRIDGE CHIPS |
4237 | M: Archit Taneja <architt@codeaurora.org> | 4243 | M: Archit Taneja <architt@codeaurora.org> |
4244 | M: Andrzej Hajda <a.hajda@samsung.com> | ||
4245 | R: Laurent Pinchart <Laurent.pinchart@ideasonboard.com> | ||
4238 | S: Maintained | 4246 | S: Maintained |
4239 | T: git git://anongit.freedesktop.org/drm/drm-misc | 4247 | T: git git://anongit.freedesktop.org/drm/drm-misc |
4240 | F: drivers/gpu/drm/bridge/ | 4248 | F: drivers/gpu/drm/bridge/ |
@@ -4491,6 +4499,15 @@ S: Maintained | |||
4491 | F: drivers/gpu/drm/sti | 4499 | F: drivers/gpu/drm/sti |
4492 | F: Documentation/devicetree/bindings/display/st,stih4xx.txt | 4500 | F: Documentation/devicetree/bindings/display/st,stih4xx.txt |
4493 | 4501 | ||
4502 | DRM DRIVERS FOR STM | ||
4503 | M: Yannick Fertre <yannick.fertre@st.com> | ||
4504 | M: Philippe Cornu <philippe.cornu@st.com> | ||
4505 | L: dri-devel@lists.freedesktop.org | ||
4506 | T: git git://anongit.freedesktop.org/drm/drm-misc | ||
4507 | S: Maintained | ||
4508 | F: drivers/gpu/drm/stm | ||
4509 | F: Documentation/devicetree/bindings/display/st,stm32-ltdc.txt | ||
4510 | |||
4494 | DRM DRIVER FOR TDFX VIDEO CARDS | 4511 | DRM DRIVER FOR TDFX VIDEO CARDS |
4495 | S: Orphan / Obsolete | 4512 | S: Orphan / Obsolete |
4496 | F: drivers/gpu/drm/tdfx/ | 4513 | F: drivers/gpu/drm/tdfx/ |
diff --git a/drivers/dma-buf/dma-buf.c b/drivers/dma-buf/dma-buf.c index 512bdbc23bbb..4a038dcf5361 100644 --- a/drivers/dma-buf/dma-buf.c +++ b/drivers/dma-buf/dma-buf.c | |||
@@ -558,8 +558,8 @@ struct dma_buf_attachment *dma_buf_attach(struct dma_buf *dmabuf, | |||
558 | if (WARN_ON(!dmabuf || !dev)) | 558 | if (WARN_ON(!dmabuf || !dev)) |
559 | return ERR_PTR(-EINVAL); | 559 | return ERR_PTR(-EINVAL); |
560 | 560 | ||
561 | attach = kzalloc(sizeof(struct dma_buf_attachment), GFP_KERNEL); | 561 | attach = kzalloc(sizeof(*attach), GFP_KERNEL); |
562 | if (attach == NULL) | 562 | if (!attach) |
563 | return ERR_PTR(-ENOMEM); | 563 | return ERR_PTR(-ENOMEM); |
564 | 564 | ||
565 | attach->dev = dev; | 565 | attach->dev = dev; |
@@ -1122,9 +1122,7 @@ static int dma_buf_debug_show(struct seq_file *s, void *unused) | |||
1122 | attach_count = 0; | 1122 | attach_count = 0; |
1123 | 1123 | ||
1124 | list_for_each_entry(attach_obj, &buf_obj->attachments, node) { | 1124 | list_for_each_entry(attach_obj, &buf_obj->attachments, node) { |
1125 | seq_puts(s, "\t"); | 1125 | seq_printf(s, "\t%s\n", dev_name(attach_obj->dev)); |
1126 | |||
1127 | seq_printf(s, "%s\n", dev_name(attach_obj->dev)); | ||
1128 | attach_count++; | 1126 | attach_count++; |
1129 | } | 1127 | } |
1130 | 1128 | ||
diff --git a/drivers/dma-buf/dma-fence.c b/drivers/dma-buf/dma-fence.c index 0918d3f003d6..57da14c15987 100644 --- a/drivers/dma-buf/dma-fence.c +++ b/drivers/dma-buf/dma-fence.c | |||
@@ -402,6 +402,11 @@ dma_fence_default_wait(struct dma_fence *fence, bool intr, signed long timeout) | |||
402 | } | 402 | } |
403 | } | 403 | } |
404 | 404 | ||
405 | if (!timeout) { | ||
406 | ret = 0; | ||
407 | goto out; | ||
408 | } | ||
409 | |||
405 | cb.base.func = dma_fence_default_wait_cb; | 410 | cb.base.func = dma_fence_default_wait_cb; |
406 | cb.task = current; | 411 | cb.task = current; |
407 | list_add(&cb.base.node, &fence->cb_list); | 412 | list_add(&cb.base.node, &fence->cb_list); |
diff --git a/drivers/dma-buf/sync_debug.c b/drivers/dma-buf/sync_debug.c index c769dc653b34..a0d780ab68c3 100644 --- a/drivers/dma-buf/sync_debug.c +++ b/drivers/dma-buf/sync_debug.c | |||
@@ -110,7 +110,7 @@ static void sync_print_fence(struct seq_file *s, | |||
110 | } | 110 | } |
111 | } | 111 | } |
112 | 112 | ||
113 | seq_puts(s, "\n"); | 113 | seq_putc(s, '\n'); |
114 | } | 114 | } |
115 | 115 | ||
116 | static void sync_print_obj(struct seq_file *s, struct sync_timeline *obj) | 116 | static void sync_print_obj(struct seq_file *s, struct sync_timeline *obj) |
@@ -161,7 +161,7 @@ static int sync_debugfs_show(struct seq_file *s, void *unused) | |||
161 | sync_timeline_list); | 161 | sync_timeline_list); |
162 | 162 | ||
163 | sync_print_obj(s, obj); | 163 | sync_print_obj(s, obj); |
164 | seq_puts(s, "\n"); | 164 | seq_putc(s, '\n'); |
165 | } | 165 | } |
166 | spin_unlock_irqrestore(&sync_timeline_list_lock, flags); | 166 | spin_unlock_irqrestore(&sync_timeline_list_lock, flags); |
167 | 167 | ||
@@ -173,7 +173,7 @@ static int sync_debugfs_show(struct seq_file *s, void *unused) | |||
173 | container_of(pos, struct sync_file, sync_file_list); | 173 | container_of(pos, struct sync_file, sync_file_list); |
174 | 174 | ||
175 | sync_print_sync_file(s, sync_file); | 175 | sync_print_sync_file(s, sync_file); |
176 | seq_puts(s, "\n"); | 176 | seq_putc(s, '\n'); |
177 | } | 177 | } |
178 | spin_unlock_irqrestore(&sync_file_list_lock, flags); | 178 | spin_unlock_irqrestore(&sync_file_list_lock, flags); |
179 | return 0; | 179 | return 0; |
diff --git a/drivers/dma-buf/sync_file.c b/drivers/dma-buf/sync_file.c index 2321035f6204..dc89b1d484e8 100644 --- a/drivers/dma-buf/sync_file.c +++ b/drivers/dma-buf/sync_file.c | |||
@@ -41,8 +41,6 @@ static struct sync_file *sync_file_alloc(void) | |||
41 | if (IS_ERR(sync_file->file)) | 41 | if (IS_ERR(sync_file->file)) |
42 | goto err; | 42 | goto err; |
43 | 43 | ||
44 | kref_init(&sync_file->kref); | ||
45 | |||
46 | init_waitqueue_head(&sync_file->wq); | 44 | init_waitqueue_head(&sync_file->wq); |
47 | 45 | ||
48 | INIT_LIST_HEAD(&sync_file->cb.node); | 46 | INIT_LIST_HEAD(&sync_file->cb.node); |
@@ -277,22 +275,15 @@ err: | |||
277 | 275 | ||
278 | } | 276 | } |
279 | 277 | ||
280 | static void sync_file_free(struct kref *kref) | 278 | static int sync_file_release(struct inode *inode, struct file *file) |
281 | { | 279 | { |
282 | struct sync_file *sync_file = container_of(kref, struct sync_file, | 280 | struct sync_file *sync_file = file->private_data; |
283 | kref); | ||
284 | 281 | ||
285 | if (test_bit(POLL_ENABLED, &sync_file->fence->flags)) | 282 | if (test_bit(POLL_ENABLED, &sync_file->fence->flags)) |
286 | dma_fence_remove_callback(sync_file->fence, &sync_file->cb); | 283 | dma_fence_remove_callback(sync_file->fence, &sync_file->cb); |
287 | dma_fence_put(sync_file->fence); | 284 | dma_fence_put(sync_file->fence); |
288 | kfree(sync_file); | 285 | kfree(sync_file); |
289 | } | ||
290 | |||
291 | static int sync_file_release(struct inode *inode, struct file *file) | ||
292 | { | ||
293 | struct sync_file *sync_file = file->private_data; | ||
294 | 286 | ||
295 | kref_put(&sync_file->kref, sync_file_free); | ||
296 | return 0; | 287 | return 0; |
297 | } | 288 | } |
298 | 289 | ||
diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig index 78d7fc0ebb57..83cb2a88c204 100644 --- a/drivers/gpu/drm/Kconfig +++ b/drivers/gpu/drm/Kconfig | |||
@@ -246,6 +246,8 @@ source "drivers/gpu/drm/fsl-dcu/Kconfig" | |||
246 | 246 | ||
247 | source "drivers/gpu/drm/tegra/Kconfig" | 247 | source "drivers/gpu/drm/tegra/Kconfig" |
248 | 248 | ||
249 | source "drivers/gpu/drm/stm/Kconfig" | ||
250 | |||
249 | source "drivers/gpu/drm/panel/Kconfig" | 251 | source "drivers/gpu/drm/panel/Kconfig" |
250 | 252 | ||
251 | source "drivers/gpu/drm/bridge/Kconfig" | 253 | source "drivers/gpu/drm/bridge/Kconfig" |
@@ -274,6 +276,8 @@ source "drivers/gpu/drm/meson/Kconfig" | |||
274 | 276 | ||
275 | source "drivers/gpu/drm/tinydrm/Kconfig" | 277 | source "drivers/gpu/drm/tinydrm/Kconfig" |
276 | 278 | ||
279 | source "drivers/gpu/drm/pl111/Kconfig" | ||
280 | |||
277 | # Keep legacy drivers last | 281 | # Keep legacy drivers last |
278 | 282 | ||
279 | menuconfig DRM_LEGACY | 283 | menuconfig DRM_LEGACY |
diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile index 59f0f9b696eb..c156fecfb362 100644 --- a/drivers/gpu/drm/Makefile +++ b/drivers/gpu/drm/Makefile | |||
@@ -82,6 +82,7 @@ obj-$(CONFIG_DRM_BOCHS) += bochs/ | |||
82 | obj-$(CONFIG_DRM_VIRTIO_GPU) += virtio/ | 82 | obj-$(CONFIG_DRM_VIRTIO_GPU) += virtio/ |
83 | obj-$(CONFIG_DRM_MSM) += msm/ | 83 | obj-$(CONFIG_DRM_MSM) += msm/ |
84 | obj-$(CONFIG_DRM_TEGRA) += tegra/ | 84 | obj-$(CONFIG_DRM_TEGRA) += tegra/ |
85 | obj-$(CONFIG_DRM_STM) += stm/ | ||
85 | obj-$(CONFIG_DRM_STI) += sti/ | 86 | obj-$(CONFIG_DRM_STI) += sti/ |
86 | obj-$(CONFIG_DRM_IMX) += imx/ | 87 | obj-$(CONFIG_DRM_IMX) += imx/ |
87 | obj-$(CONFIG_DRM_MEDIATEK) += mediatek/ | 88 | obj-$(CONFIG_DRM_MEDIATEK) += mediatek/ |
@@ -96,3 +97,4 @@ obj-y += hisilicon/ | |||
96 | obj-$(CONFIG_DRM_ZTE) += zte/ | 97 | obj-$(CONFIG_DRM_ZTE) += zte/ |
97 | obj-$(CONFIG_DRM_MXSFB) += mxsfb/ | 98 | obj-$(CONFIG_DRM_MXSFB) += mxsfb/ |
98 | obj-$(CONFIG_DRM_TINYDRM) += tinydrm/ | 99 | obj-$(CONFIG_DRM_TINYDRM) += tinydrm/ |
100 | obj-$(CONFIG_DRM_PL111) += pl111/ | ||
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu.h b/drivers/gpu/drm/amd/amdgpu/amdgpu.h index 833c3c16501a..67cdab9241a4 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h | |||
@@ -1912,10 +1912,6 @@ int amdgpu_device_resume(struct drm_device *dev, bool resume, bool fbcon); | |||
1912 | u32 amdgpu_get_vblank_counter_kms(struct drm_device *dev, unsigned int pipe); | 1912 | u32 amdgpu_get_vblank_counter_kms(struct drm_device *dev, unsigned int pipe); |
1913 | int amdgpu_enable_vblank_kms(struct drm_device *dev, unsigned int pipe); | 1913 | int amdgpu_enable_vblank_kms(struct drm_device *dev, unsigned int pipe); |
1914 | void amdgpu_disable_vblank_kms(struct drm_device *dev, unsigned int pipe); | 1914 | void amdgpu_disable_vblank_kms(struct drm_device *dev, unsigned int pipe); |
1915 | int amdgpu_get_vblank_timestamp_kms(struct drm_device *dev, unsigned int pipe, | ||
1916 | int *max_error, | ||
1917 | struct timeval *vblank_time, | ||
1918 | unsigned flags); | ||
1919 | long amdgpu_kms_compat_ioctl(struct file *filp, unsigned int cmd, | 1915 | long amdgpu_kms_compat_ioctl(struct file *filp, unsigned int cmd, |
1920 | unsigned long arg); | 1916 | unsigned long arg); |
1921 | 1917 | ||
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c index f2d705e6a75a..5cb8f3e68447 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c | |||
@@ -715,6 +715,16 @@ static const struct file_operations amdgpu_driver_kms_fops = { | |||
715 | #endif | 715 | #endif |
716 | }; | 716 | }; |
717 | 717 | ||
718 | static bool | ||
719 | amdgpu_get_crtc_scanout_position(struct drm_device *dev, unsigned int pipe, | ||
720 | bool in_vblank_irq, int *vpos, int *hpos, | ||
721 | ktime_t *stime, ktime_t *etime, | ||
722 | const struct drm_display_mode *mode) | ||
723 | { | ||
724 | return amdgpu_get_crtc_scanoutpos(dev, pipe, 0, vpos, hpos, | ||
725 | stime, etime, mode); | ||
726 | } | ||
727 | |||
718 | static struct drm_driver kms_driver = { | 728 | static struct drm_driver kms_driver = { |
719 | .driver_features = | 729 | .driver_features = |
720 | DRIVER_USE_AGP | | 730 | DRIVER_USE_AGP | |
@@ -729,8 +739,8 @@ static struct drm_driver kms_driver = { | |||
729 | .get_vblank_counter = amdgpu_get_vblank_counter_kms, | 739 | .get_vblank_counter = amdgpu_get_vblank_counter_kms, |
730 | .enable_vblank = amdgpu_enable_vblank_kms, | 740 | .enable_vblank = amdgpu_enable_vblank_kms, |
731 | .disable_vblank = amdgpu_disable_vblank_kms, | 741 | .disable_vblank = amdgpu_disable_vblank_kms, |
732 | .get_vblank_timestamp = amdgpu_get_vblank_timestamp_kms, | 742 | .get_vblank_timestamp = drm_calc_vbltimestamp_from_scanoutpos, |
733 | .get_scanout_position = amdgpu_get_crtc_scanoutpos, | 743 | .get_scanout_position = amdgpu_get_crtc_scanout_position, |
734 | #if defined(CONFIG_DEBUG_FS) | 744 | #if defined(CONFIG_DEBUG_FS) |
735 | .debugfs_init = amdgpu_debugfs_init, | 745 | .debugfs_init = amdgpu_debugfs_init, |
736 | #endif | 746 | #endif |
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c index 96c341670782..dca4be970d13 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c | |||
@@ -945,47 +945,6 @@ void amdgpu_disable_vblank_kms(struct drm_device *dev, unsigned int pipe) | |||
945 | amdgpu_irq_put(adev, &adev->crtc_irq, idx); | 945 | amdgpu_irq_put(adev, &adev->crtc_irq, idx); |
946 | } | 946 | } |
947 | 947 | ||
948 | /** | ||
949 | * amdgpu_get_vblank_timestamp_kms - get vblank timestamp | ||
950 | * | ||
951 | * @dev: drm dev pointer | ||
952 | * @crtc: crtc to get the timestamp for | ||
953 | * @max_error: max error | ||
954 | * @vblank_time: time value | ||
955 | * @flags: flags passed to the driver | ||
956 | * | ||
957 | * Gets the timestamp on the requested crtc based on the | ||
958 | * scanout position. (all asics). | ||
959 | * Returns postive status flags on success, negative error on failure. | ||
960 | */ | ||
961 | int amdgpu_get_vblank_timestamp_kms(struct drm_device *dev, unsigned int pipe, | ||
962 | int *max_error, | ||
963 | struct timeval *vblank_time, | ||
964 | unsigned flags) | ||
965 | { | ||
966 | struct drm_crtc *crtc; | ||
967 | struct amdgpu_device *adev = dev->dev_private; | ||
968 | |||
969 | if (pipe >= dev->num_crtcs) { | ||
970 | DRM_ERROR("Invalid crtc %u\n", pipe); | ||
971 | return -EINVAL; | ||
972 | } | ||
973 | |||
974 | /* Get associated drm_crtc: */ | ||
975 | crtc = &adev->mode_info.crtcs[pipe]->base; | ||
976 | if (!crtc) { | ||
977 | /* This can occur on driver load if some component fails to | ||
978 | * initialize completely and driver is unloaded */ | ||
979 | DRM_ERROR("Uninitialized crtc %d\n", pipe); | ||
980 | return -EINVAL; | ||
981 | } | ||
982 | |||
983 | /* Helper routine in DRM core does all the work: */ | ||
984 | return drm_calc_vbltimestamp_from_scanoutpos(dev, pipe, max_error, | ||
985 | vblank_time, flags, | ||
986 | &crtc->hwmode); | ||
987 | } | ||
988 | |||
989 | const struct drm_ioctl_desc amdgpu_ioctls_kms[] = { | 948 | const struct drm_ioctl_desc amdgpu_ioctls_kms[] = { |
990 | DRM_IOCTL_DEF_DRV(AMDGPU_GEM_CREATE, amdgpu_gem_create_ioctl, DRM_AUTH|DRM_RENDER_ALLOW), | 949 | DRM_IOCTL_DEF_DRV(AMDGPU_GEM_CREATE, amdgpu_gem_create_ioctl, DRM_AUTH|DRM_RENDER_ALLOW), |
991 | DRM_IOCTL_DEF_DRV(AMDGPU_CTX, amdgpu_ctx_ioctl, DRM_AUTH|DRM_RENDER_ALLOW), | 950 | DRM_IOCTL_DEF_DRV(AMDGPU_CTX, amdgpu_ctx_ioctl, DRM_AUTH|DRM_RENDER_ALLOW), |
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h index dbd10618ec20..43a9d3aec6c4 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h | |||
@@ -534,6 +534,9 @@ struct amdgpu_framebuffer { | |||
534 | ((em) == ATOM_ENCODER_MODE_DP_MST)) | 534 | ((em) == ATOM_ENCODER_MODE_DP_MST)) |
535 | 535 | ||
536 | /* Driver internal use only flags of amdgpu_get_crtc_scanoutpos() */ | 536 | /* Driver internal use only flags of amdgpu_get_crtc_scanoutpos() */ |
537 | #define DRM_SCANOUTPOS_VALID (1 << 0) | ||
538 | #define DRM_SCANOUTPOS_IN_VBLANK (1 << 1) | ||
539 | #define DRM_SCANOUTPOS_ACCURATE (1 << 2) | ||
537 | #define USE_REAL_VBLANKSTART (1 << 30) | 540 | #define USE_REAL_VBLANKSTART (1 << 30) |
538 | #define GET_DISTANCE_TO_VBLANKSTART (1 << 31) | 541 | #define GET_DISTANCE_TO_VBLANKSTART (1 << 31) |
539 | 542 | ||
diff --git a/drivers/gpu/drm/bridge/sii902x.c b/drivers/gpu/drm/bridge/sii902x.c index 9126d0306ab5..9b87067c022c 100644 --- a/drivers/gpu/drm/bridge/sii902x.c +++ b/drivers/gpu/drm/bridge/sii902x.c | |||
@@ -160,7 +160,7 @@ static int sii902x_get_modes(struct drm_connector *connector) | |||
160 | time_before(jiffies, timeout)); | 160 | time_before(jiffies, timeout)); |
161 | 161 | ||
162 | if (!(status & SII902X_SYS_CTRL_DDC_BUS_GRTD)) { | 162 | if (!(status & SII902X_SYS_CTRL_DDC_BUS_GRTD)) { |
163 | dev_err(&sii902x->i2c->dev, "failed to acquire the i2c bus"); | 163 | dev_err(&sii902x->i2c->dev, "failed to acquire the i2c bus\n"); |
164 | return -ETIMEDOUT; | 164 | return -ETIMEDOUT; |
165 | } | 165 | } |
166 | 166 | ||
@@ -202,7 +202,7 @@ static int sii902x_get_modes(struct drm_connector *connector) | |||
202 | 202 | ||
203 | if (status & (SII902X_SYS_CTRL_DDC_BUS_REQ | | 203 | if (status & (SII902X_SYS_CTRL_DDC_BUS_REQ | |
204 | SII902X_SYS_CTRL_DDC_BUS_GRTD)) { | 204 | SII902X_SYS_CTRL_DDC_BUS_GRTD)) { |
205 | dev_err(&sii902x->i2c->dev, "failed to release the i2c bus"); | 205 | dev_err(&sii902x->i2c->dev, "failed to release the i2c bus\n"); |
206 | return -ETIMEDOUT; | 206 | return -ETIMEDOUT; |
207 | } | 207 | } |
208 | 208 | ||
@@ -298,7 +298,7 @@ static int sii902x_bridge_attach(struct drm_bridge *bridge) | |||
298 | 298 | ||
299 | if (!drm_core_check_feature(drm, DRIVER_ATOMIC)) { | 299 | if (!drm_core_check_feature(drm, DRIVER_ATOMIC)) { |
300 | dev_err(&sii902x->i2c->dev, | 300 | dev_err(&sii902x->i2c->dev, |
301 | "sii902x driver is only compatible with DRM devices supporting atomic updates"); | 301 | "sii902x driver is only compatible with DRM devices supporting atomic updates\n"); |
302 | return -ENOTSUPP; | 302 | return -ENOTSUPP; |
303 | } | 303 | } |
304 | 304 | ||
diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c index 4e1f54a675d8..8737de8c1c52 100644 --- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c +++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | |||
@@ -173,6 +173,8 @@ struct dw_hdmi { | |||
173 | 173 | ||
174 | unsigned int reg_shift; | 174 | unsigned int reg_shift; |
175 | struct regmap *regm; | 175 | struct regmap *regm; |
176 | void (*enable_audio)(struct dw_hdmi *hdmi); | ||
177 | void (*disable_audio)(struct dw_hdmi *hdmi); | ||
176 | }; | 178 | }; |
177 | 179 | ||
178 | #define HDMI_IH_PHY_STAT0_RX_SENSE \ | 180 | #define HDMI_IH_PHY_STAT0_RX_SENSE \ |
@@ -542,13 +544,41 @@ void dw_hdmi_set_sample_rate(struct dw_hdmi *hdmi, unsigned int rate) | |||
542 | } | 544 | } |
543 | EXPORT_SYMBOL_GPL(dw_hdmi_set_sample_rate); | 545 | EXPORT_SYMBOL_GPL(dw_hdmi_set_sample_rate); |
544 | 546 | ||
547 | static void hdmi_enable_audio_clk(struct dw_hdmi *hdmi, bool enable) | ||
548 | { | ||
549 | hdmi_modb(hdmi, enable ? 0 : HDMI_MC_CLKDIS_AUDCLK_DISABLE, | ||
550 | HDMI_MC_CLKDIS_AUDCLK_DISABLE, HDMI_MC_CLKDIS); | ||
551 | } | ||
552 | |||
553 | static void dw_hdmi_ahb_audio_enable(struct dw_hdmi *hdmi) | ||
554 | { | ||
555 | hdmi_set_cts_n(hdmi, hdmi->audio_cts, hdmi->audio_n); | ||
556 | } | ||
557 | |||
558 | static void dw_hdmi_ahb_audio_disable(struct dw_hdmi *hdmi) | ||
559 | { | ||
560 | hdmi_set_cts_n(hdmi, hdmi->audio_cts, 0); | ||
561 | } | ||
562 | |||
563 | static void dw_hdmi_i2s_audio_enable(struct dw_hdmi *hdmi) | ||
564 | { | ||
565 | hdmi_set_cts_n(hdmi, hdmi->audio_cts, hdmi->audio_n); | ||
566 | hdmi_enable_audio_clk(hdmi, true); | ||
567 | } | ||
568 | |||
569 | static void dw_hdmi_i2s_audio_disable(struct dw_hdmi *hdmi) | ||
570 | { | ||
571 | hdmi_enable_audio_clk(hdmi, false); | ||
572 | } | ||
573 | |||
545 | void dw_hdmi_audio_enable(struct dw_hdmi *hdmi) | 574 | void dw_hdmi_audio_enable(struct dw_hdmi *hdmi) |
546 | { | 575 | { |
547 | unsigned long flags; | 576 | unsigned long flags; |
548 | 577 | ||
549 | spin_lock_irqsave(&hdmi->audio_lock, flags); | 578 | spin_lock_irqsave(&hdmi->audio_lock, flags); |
550 | hdmi->audio_enable = true; | 579 | hdmi->audio_enable = true; |
551 | hdmi_set_cts_n(hdmi, hdmi->audio_cts, hdmi->audio_n); | 580 | if (hdmi->enable_audio) |
581 | hdmi->enable_audio(hdmi); | ||
552 | spin_unlock_irqrestore(&hdmi->audio_lock, flags); | 582 | spin_unlock_irqrestore(&hdmi->audio_lock, flags); |
553 | } | 583 | } |
554 | EXPORT_SYMBOL_GPL(dw_hdmi_audio_enable); | 584 | EXPORT_SYMBOL_GPL(dw_hdmi_audio_enable); |
@@ -559,7 +589,8 @@ void dw_hdmi_audio_disable(struct dw_hdmi *hdmi) | |||
559 | 589 | ||
560 | spin_lock_irqsave(&hdmi->audio_lock, flags); | 590 | spin_lock_irqsave(&hdmi->audio_lock, flags); |
561 | hdmi->audio_enable = false; | 591 | hdmi->audio_enable = false; |
562 | hdmi_set_cts_n(hdmi, hdmi->audio_cts, 0); | 592 | if (hdmi->disable_audio) |
593 | hdmi->disable_audio(hdmi); | ||
563 | spin_unlock_irqrestore(&hdmi->audio_lock, flags); | 594 | spin_unlock_irqrestore(&hdmi->audio_lock, flags); |
564 | } | 595 | } |
565 | EXPORT_SYMBOL_GPL(dw_hdmi_audio_disable); | 596 | EXPORT_SYMBOL_GPL(dw_hdmi_audio_disable); |
@@ -1573,11 +1604,6 @@ static void dw_hdmi_enable_video_path(struct dw_hdmi *hdmi) | |||
1573 | HDMI_MC_FLOWCTRL); | 1604 | HDMI_MC_FLOWCTRL); |
1574 | } | 1605 | } |
1575 | 1606 | ||
1576 | static void hdmi_enable_audio_clk(struct dw_hdmi *hdmi) | ||
1577 | { | ||
1578 | hdmi_modb(hdmi, 0, HDMI_MC_CLKDIS_AUDCLK_DISABLE, HDMI_MC_CLKDIS); | ||
1579 | } | ||
1580 | |||
1581 | /* Workaround to clear the overflow condition */ | 1607 | /* Workaround to clear the overflow condition */ |
1582 | static void dw_hdmi_clear_overflow(struct dw_hdmi *hdmi) | 1608 | static void dw_hdmi_clear_overflow(struct dw_hdmi *hdmi) |
1583 | { | 1609 | { |
@@ -1691,7 +1717,7 @@ static int dw_hdmi_setup(struct dw_hdmi *hdmi, struct drm_display_mode *mode) | |||
1691 | 1717 | ||
1692 | /* HDMI Initialization Step E - Configure audio */ | 1718 | /* HDMI Initialization Step E - Configure audio */ |
1693 | hdmi_clk_regenerator_update_pixel_clock(hdmi); | 1719 | hdmi_clk_regenerator_update_pixel_clock(hdmi); |
1694 | hdmi_enable_audio_clk(hdmi); | 1720 | hdmi_enable_audio_clk(hdmi, true); |
1695 | } | 1721 | } |
1696 | 1722 | ||
1697 | /* not for DVI mode */ | 1723 | /* not for DVI mode */ |
@@ -2403,6 +2429,8 @@ __dw_hdmi_probe(struct platform_device *pdev, | |||
2403 | audio.irq = irq; | 2429 | audio.irq = irq; |
2404 | audio.hdmi = hdmi; | 2430 | audio.hdmi = hdmi; |
2405 | audio.eld = hdmi->connector.eld; | 2431 | audio.eld = hdmi->connector.eld; |
2432 | hdmi->enable_audio = dw_hdmi_ahb_audio_enable; | ||
2433 | hdmi->disable_audio = dw_hdmi_ahb_audio_disable; | ||
2406 | 2434 | ||
2407 | pdevinfo.name = "dw-hdmi-ahb-audio"; | 2435 | pdevinfo.name = "dw-hdmi-ahb-audio"; |
2408 | pdevinfo.data = &audio; | 2436 | pdevinfo.data = &audio; |
@@ -2415,6 +2443,8 @@ __dw_hdmi_probe(struct platform_device *pdev, | |||
2415 | audio.hdmi = hdmi; | 2443 | audio.hdmi = hdmi; |
2416 | audio.write = hdmi_writeb; | 2444 | audio.write = hdmi_writeb; |
2417 | audio.read = hdmi_readb; | 2445 | audio.read = hdmi_readb; |
2446 | hdmi->enable_audio = dw_hdmi_i2s_audio_enable; | ||
2447 | hdmi->disable_audio = dw_hdmi_i2s_audio_disable; | ||
2418 | 2448 | ||
2419 | pdevinfo.name = "dw-hdmi-i2s-audio"; | 2449 | pdevinfo.name = "dw-hdmi-i2s-audio"; |
2420 | pdevinfo.data = &audio; | 2450 | pdevinfo.data = &audio; |
diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c index f32506a7c1d6..cdec19a86af3 100644 --- a/drivers/gpu/drm/drm_atomic.c +++ b/drivers/gpu/drm/drm_atomic.c | |||
@@ -57,6 +57,7 @@ void drm_atomic_state_default_release(struct drm_atomic_state *state) | |||
57 | kfree(state->connectors); | 57 | kfree(state->connectors); |
58 | kfree(state->crtcs); | 58 | kfree(state->crtcs); |
59 | kfree(state->planes); | 59 | kfree(state->planes); |
60 | kfree(state->private_objs); | ||
60 | } | 61 | } |
61 | EXPORT_SYMBOL(drm_atomic_state_default_release); | 62 | EXPORT_SYMBOL(drm_atomic_state_default_release); |
62 | 63 | ||
@@ -184,6 +185,17 @@ void drm_atomic_state_default_clear(struct drm_atomic_state *state) | |||
184 | state->planes[i].ptr = NULL; | 185 | state->planes[i].ptr = NULL; |
185 | state->planes[i].state = NULL; | 186 | state->planes[i].state = NULL; |
186 | } | 187 | } |
188 | |||
189 | for (i = 0; i < state->num_private_objs; i++) { | ||
190 | void *obj_state = state->private_objs[i].obj_state; | ||
191 | |||
192 | state->private_objs[i].funcs->destroy_state(obj_state); | ||
193 | state->private_objs[i].obj = NULL; | ||
194 | state->private_objs[i].obj_state = NULL; | ||
195 | state->private_objs[i].funcs = NULL; | ||
196 | } | ||
197 | state->num_private_objs = 0; | ||
198 | |||
187 | } | 199 | } |
188 | EXPORT_SYMBOL(drm_atomic_state_default_clear); | 200 | EXPORT_SYMBOL(drm_atomic_state_default_clear); |
189 | 201 | ||
@@ -425,7 +437,7 @@ drm_atomic_replace_property_blob(struct drm_property_blob **blob, | |||
425 | } | 437 | } |
426 | 438 | ||
427 | static int | 439 | static int |
428 | drm_atomic_replace_property_blob_from_id(struct drm_crtc *crtc, | 440 | drm_atomic_replace_property_blob_from_id(struct drm_device *dev, |
429 | struct drm_property_blob **blob, | 441 | struct drm_property_blob **blob, |
430 | uint64_t blob_id, | 442 | uint64_t blob_id, |
431 | ssize_t expected_size, | 443 | ssize_t expected_size, |
@@ -434,7 +446,7 @@ drm_atomic_replace_property_blob_from_id(struct drm_crtc *crtc, | |||
434 | struct drm_property_blob *new_blob = NULL; | 446 | struct drm_property_blob *new_blob = NULL; |
435 | 447 | ||
436 | if (blob_id != 0) { | 448 | if (blob_id != 0) { |
437 | new_blob = drm_property_lookup_blob(crtc->dev, blob_id); | 449 | new_blob = drm_property_lookup_blob(dev, blob_id); |
438 | if (new_blob == NULL) | 450 | if (new_blob == NULL) |
439 | return -EINVAL; | 451 | return -EINVAL; |
440 | 452 | ||
@@ -483,7 +495,7 @@ int drm_atomic_crtc_set_property(struct drm_crtc *crtc, | |||
483 | drm_property_blob_put(mode); | 495 | drm_property_blob_put(mode); |
484 | return ret; | 496 | return ret; |
485 | } else if (property == config->degamma_lut_property) { | 497 | } else if (property == config->degamma_lut_property) { |
486 | ret = drm_atomic_replace_property_blob_from_id(crtc, | 498 | ret = drm_atomic_replace_property_blob_from_id(dev, |
487 | &state->degamma_lut, | 499 | &state->degamma_lut, |
488 | val, | 500 | val, |
489 | -1, | 501 | -1, |
@@ -491,7 +503,7 @@ int drm_atomic_crtc_set_property(struct drm_crtc *crtc, | |||
491 | state->color_mgmt_changed |= replaced; | 503 | state->color_mgmt_changed |= replaced; |
492 | return ret; | 504 | return ret; |
493 | } else if (property == config->ctm_property) { | 505 | } else if (property == config->ctm_property) { |
494 | ret = drm_atomic_replace_property_blob_from_id(crtc, | 506 | ret = drm_atomic_replace_property_blob_from_id(dev, |
495 | &state->ctm, | 507 | &state->ctm, |
496 | val, | 508 | val, |
497 | sizeof(struct drm_color_ctm), | 509 | sizeof(struct drm_color_ctm), |
@@ -499,7 +511,7 @@ int drm_atomic_crtc_set_property(struct drm_crtc *crtc, | |||
499 | state->color_mgmt_changed |= replaced; | 511 | state->color_mgmt_changed |= replaced; |
500 | return ret; | 512 | return ret; |
501 | } else if (property == config->gamma_lut_property) { | 513 | } else if (property == config->gamma_lut_property) { |
502 | ret = drm_atomic_replace_property_blob_from_id(crtc, | 514 | ret = drm_atomic_replace_property_blob_from_id(dev, |
503 | &state->gamma_lut, | 515 | &state->gamma_lut, |
504 | val, | 516 | val, |
505 | -1, | 517 | -1, |
@@ -978,6 +990,59 @@ static void drm_atomic_plane_print_state(struct drm_printer *p, | |||
978 | } | 990 | } |
979 | 991 | ||
980 | /** | 992 | /** |
993 | * drm_atomic_get_private_obj_state - get private object state | ||
994 | * @state: global atomic state | ||
995 | * @obj: private object to get the state for | ||
996 | * @funcs: pointer to the struct of function pointers that identify the object | ||
997 | * type | ||
998 | * | ||
999 | * This function returns the private object state for the given private object, | ||
1000 | * allocating the state if needed. It does not grab any locks as the caller is | ||
1001 | * expected to care of any required locking. | ||
1002 | * | ||
1003 | * RETURNS: | ||
1004 | * | ||
1005 | * Either the allocated state or the error code encoded into a pointer. | ||
1006 | */ | ||
1007 | void * | ||
1008 | drm_atomic_get_private_obj_state(struct drm_atomic_state *state, void *obj, | ||
1009 | const struct drm_private_state_funcs *funcs) | ||
1010 | { | ||
1011 | int index, num_objs, i; | ||
1012 | size_t size; | ||
1013 | struct __drm_private_objs_state *arr; | ||
1014 | |||
1015 | for (i = 0; i < state->num_private_objs; i++) | ||
1016 | if (obj == state->private_objs[i].obj && | ||
1017 | state->private_objs[i].obj_state) | ||
1018 | return state->private_objs[i].obj_state; | ||
1019 | |||
1020 | num_objs = state->num_private_objs + 1; | ||
1021 | size = sizeof(*state->private_objs) * num_objs; | ||
1022 | arr = krealloc(state->private_objs, size, GFP_KERNEL); | ||
1023 | if (!arr) | ||
1024 | return ERR_PTR(-ENOMEM); | ||
1025 | |||
1026 | state->private_objs = arr; | ||
1027 | index = state->num_private_objs; | ||
1028 | memset(&state->private_objs[index], 0, sizeof(*state->private_objs)); | ||
1029 | |||
1030 | state->private_objs[index].obj_state = funcs->duplicate_state(state, obj); | ||
1031 | if (!state->private_objs[index].obj_state) | ||
1032 | return ERR_PTR(-ENOMEM); | ||
1033 | |||
1034 | state->private_objs[index].obj = obj; | ||
1035 | state->private_objs[index].funcs = funcs; | ||
1036 | state->num_private_objs = num_objs; | ||
1037 | |||
1038 | DRM_DEBUG_ATOMIC("Added new private object state %p to %p\n", | ||
1039 | state->private_objs[index].obj_state, state); | ||
1040 | |||
1041 | return state->private_objs[index].obj_state; | ||
1042 | } | ||
1043 | EXPORT_SYMBOL(drm_atomic_get_private_obj_state); | ||
1044 | |||
1045 | /** | ||
981 | * drm_atomic_get_connector_state - get connector state | 1046 | * drm_atomic_get_connector_state - get connector state |
982 | * @state: global atomic state object | 1047 | * @state: global atomic state object |
983 | * @connector: connector to get state object for | 1048 | * @connector: connector to get state object for |
@@ -1123,6 +1188,10 @@ int drm_atomic_connector_set_property(struct drm_connector *connector, | |||
1123 | */ | 1188 | */ |
1124 | if (state->link_status != DRM_LINK_STATUS_GOOD) | 1189 | if (state->link_status != DRM_LINK_STATUS_GOOD) |
1125 | state->link_status = val; | 1190 | state->link_status = val; |
1191 | } else if (property == config->aspect_ratio_property) { | ||
1192 | state->picture_aspect_ratio = val; | ||
1193 | } else if (property == connector->scaling_mode_property) { | ||
1194 | state->scaling_mode = val; | ||
1126 | } else if (connector->funcs->atomic_set_property) { | 1195 | } else if (connector->funcs->atomic_set_property) { |
1127 | return connector->funcs->atomic_set_property(connector, | 1196 | return connector->funcs->atomic_set_property(connector, |
1128 | state, property, val); | 1197 | state, property, val); |
@@ -1199,6 +1268,10 @@ drm_atomic_connector_get_property(struct drm_connector *connector, | |||
1199 | *val = state->tv.hue; | 1268 | *val = state->tv.hue; |
1200 | } else if (property == config->link_status_property) { | 1269 | } else if (property == config->link_status_property) { |
1201 | *val = state->link_status; | 1270 | *val = state->link_status; |
1271 | } else if (property == config->aspect_ratio_property) { | ||
1272 | *val = state->picture_aspect_ratio; | ||
1273 | } else if (property == connector->scaling_mode_property) { | ||
1274 | *val = state->scaling_mode; | ||
1202 | } else if (connector->funcs->atomic_get_property) { | 1275 | } else if (connector->funcs->atomic_get_property) { |
1203 | return connector->funcs->atomic_get_property(connector, | 1276 | return connector->funcs->atomic_get_property(connector, |
1204 | state, property, val); | 1277 | state, property, val); |
@@ -1618,7 +1691,7 @@ int drm_atomic_commit(struct drm_atomic_state *state) | |||
1618 | if (ret) | 1691 | if (ret) |
1619 | return ret; | 1692 | return ret; |
1620 | 1693 | ||
1621 | DRM_DEBUG_ATOMIC("commiting %p\n", state); | 1694 | DRM_DEBUG_ATOMIC("committing %p\n", state); |
1622 | 1695 | ||
1623 | return config->funcs->atomic_commit(state->dev, state, false); | 1696 | return config->funcs->atomic_commit(state->dev, state, false); |
1624 | } | 1697 | } |
@@ -1647,7 +1720,7 @@ int drm_atomic_nonblocking_commit(struct drm_atomic_state *state) | |||
1647 | if (ret) | 1720 | if (ret) |
1648 | return ret; | 1721 | return ret; |
1649 | 1722 | ||
1650 | DRM_DEBUG_ATOMIC("commiting %p nonblocking\n", state); | 1723 | DRM_DEBUG_ATOMIC("committing %p nonblocking\n", state); |
1651 | 1724 | ||
1652 | return config->funcs->atomic_commit(state->dev, state, true); | 1725 | return config->funcs->atomic_commit(state->dev, state, true); |
1653 | } | 1726 | } |
diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c index 8be9719284b0..6426339427a4 100644 --- a/drivers/gpu/drm/drm_atomic_helper.c +++ b/drivers/gpu/drm/drm_atomic_helper.c | |||
@@ -1070,8 +1070,8 @@ EXPORT_SYMBOL(drm_atomic_helper_commit_modeset_enables); | |||
1070 | * | 1070 | * |
1071 | * Note that @pre_swap is needed since the point where we block for fences moves | 1071 | * Note that @pre_swap is needed since the point where we block for fences moves |
1072 | * around depending upon whether an atomic commit is blocking or | 1072 | * around depending upon whether an atomic commit is blocking or |
1073 | * non-blocking. For async commit all waiting needs to happen after | 1073 | * non-blocking. For non-blocking commit all waiting needs to happen after |
1074 | * drm_atomic_helper_swap_state() is called, but for synchronous commits we want | 1074 | * drm_atomic_helper_swap_state() is called, but for blocking commits we want |
1075 | * to wait **before** we do anything that can't be easily rolled back. That is | 1075 | * to wait **before** we do anything that can't be easily rolled back. That is |
1076 | * before we call drm_atomic_helper_swap_state(). | 1076 | * before we call drm_atomic_helper_swap_state(). |
1077 | * | 1077 | * |
@@ -2032,6 +2032,8 @@ void drm_atomic_helper_swap_state(struct drm_atomic_state *state, | |||
2032 | struct drm_plane *plane; | 2032 | struct drm_plane *plane; |
2033 | struct drm_plane_state *old_plane_state, *new_plane_state; | 2033 | struct drm_plane_state *old_plane_state, *new_plane_state; |
2034 | struct drm_crtc_commit *commit; | 2034 | struct drm_crtc_commit *commit; |
2035 | void *obj, *obj_state; | ||
2036 | const struct drm_private_state_funcs *funcs; | ||
2035 | 2037 | ||
2036 | if (stall) { | 2038 | if (stall) { |
2037 | for_each_new_crtc_in_state(state, crtc, new_crtc_state, i) { | 2039 | for_each_new_crtc_in_state(state, crtc, new_crtc_state, i) { |
@@ -2092,6 +2094,9 @@ void drm_atomic_helper_swap_state(struct drm_atomic_state *state, | |||
2092 | state->planes[i].state = old_plane_state; | 2094 | state->planes[i].state = old_plane_state; |
2093 | plane->state = new_plane_state; | 2095 | plane->state = new_plane_state; |
2094 | } | 2096 | } |
2097 | |||
2098 | __for_each_private_obj(state, obj, obj_state, i, funcs) | ||
2099 | funcs->swap_state(obj, &state->private_objs[i].obj_state); | ||
2095 | } | 2100 | } |
2096 | EXPORT_SYMBOL(drm_atomic_helper_swap_state); | 2101 | EXPORT_SYMBOL(drm_atomic_helper_swap_state); |
2097 | 2102 | ||
@@ -3517,7 +3522,8 @@ EXPORT_SYMBOL(drm_atomic_helper_connector_destroy_state); | |||
3517 | * | 3522 | * |
3518 | * Implements support for legacy gamma correction table for drivers | 3523 | * Implements support for legacy gamma correction table for drivers |
3519 | * that support color management through the DEGAMMA_LUT/GAMMA_LUT | 3524 | * that support color management through the DEGAMMA_LUT/GAMMA_LUT |
3520 | * properties. | 3525 | * properties. See drm_crtc_enable_color_mgmt() and the containing chapter for |
3526 | * how the atomic color management and gamma tables work. | ||
3521 | */ | 3527 | */ |
3522 | int drm_atomic_helper_legacy_gamma_set(struct drm_crtc *crtc, | 3528 | int drm_atomic_helper_legacy_gamma_set(struct drm_crtc *crtc, |
3523 | u16 *red, u16 *green, u16 *blue, | 3529 | u16 *red, u16 *green, u16 *blue, |
diff --git a/drivers/gpu/drm/drm_color_mgmt.c b/drivers/gpu/drm/drm_color_mgmt.c index 533f3a3e6877..3eda500fc005 100644 --- a/drivers/gpu/drm/drm_color_mgmt.c +++ b/drivers/gpu/drm/drm_color_mgmt.c | |||
@@ -43,7 +43,8 @@ | |||
43 | * | 43 | * |
44 | * Setting this to NULL (blob property value set to 0) means a | 44 | * Setting this to NULL (blob property value set to 0) means a |
45 | * linear/pass-thru gamma table should be used. This is generally the | 45 | * linear/pass-thru gamma table should be used. This is generally the |
46 | * driver boot-up state too. | 46 | * driver boot-up state too. Drivers can access this blob through |
47 | * &drm_crtc_state.degamma_lut. | ||
47 | * | 48 | * |
48 | * “DEGAMMA_LUT_SIZE”: | 49 | * “DEGAMMA_LUT_SIZE”: |
49 | * Unsinged range property to give the size of the lookup table to be set | 50 | * Unsinged range property to give the size of the lookup table to be set |
@@ -60,7 +61,8 @@ | |||
60 | * | 61 | * |
61 | * Setting this to NULL (blob property value set to 0) means a | 62 | * Setting this to NULL (blob property value set to 0) means a |
62 | * unit/pass-thru matrix should be used. This is generally the driver | 63 | * unit/pass-thru matrix should be used. This is generally the driver |
63 | * boot-up state too. | 64 | * boot-up state too. Drivers can access the blob for the color conversion |
65 | * matrix through &drm_crtc_state.ctm. | ||
64 | * | 66 | * |
65 | * “GAMMA_LUT”: | 67 | * “GAMMA_LUT”: |
66 | * Blob property to set the gamma lookup table (LUT) mapping pixel data | 68 | * Blob property to set the gamma lookup table (LUT) mapping pixel data |
@@ -72,7 +74,8 @@ | |||
72 | * | 74 | * |
73 | * Setting this to NULL (blob property value set to 0) means a | 75 | * Setting this to NULL (blob property value set to 0) means a |
74 | * linear/pass-thru gamma table should be used. This is generally the | 76 | * linear/pass-thru gamma table should be used. This is generally the |
75 | * driver boot-up state too. | 77 | * driver boot-up state too. Drivers can access this blob through |
78 | * &drm_crtc_state.gamma_lut. | ||
76 | * | 79 | * |
77 | * “GAMMA_LUT_SIZE”: | 80 | * “GAMMA_LUT_SIZE”: |
78 | * Unsigned range property to give the size of the lookup table to be set | 81 | * Unsigned range property to give the size of the lookup table to be set |
diff --git a/drivers/gpu/drm/drm_connector.c b/drivers/gpu/drm/drm_connector.c index 9f847615ac74..5cd61aff7857 100644 --- a/drivers/gpu/drm/drm_connector.c +++ b/drivers/gpu/drm/drm_connector.c | |||
@@ -941,6 +941,10 @@ EXPORT_SYMBOL(drm_mode_create_tv_properties); | |||
941 | * | 941 | * |
942 | * Called by a driver the first time it's needed, must be attached to desired | 942 | * Called by a driver the first time it's needed, must be attached to desired |
943 | * connectors. | 943 | * connectors. |
944 | * | ||
945 | * Atomic drivers should use drm_connector_attach_scaling_mode_property() | ||
946 | * instead to correctly assign &drm_connector_state.picture_aspect_ratio | ||
947 | * in the atomic state. | ||
944 | */ | 948 | */ |
945 | int drm_mode_create_scaling_mode_property(struct drm_device *dev) | 949 | int drm_mode_create_scaling_mode_property(struct drm_device *dev) |
946 | { | 950 | { |
@@ -961,6 +965,66 @@ int drm_mode_create_scaling_mode_property(struct drm_device *dev) | |||
961 | EXPORT_SYMBOL(drm_mode_create_scaling_mode_property); | 965 | EXPORT_SYMBOL(drm_mode_create_scaling_mode_property); |
962 | 966 | ||
963 | /** | 967 | /** |
968 | * drm_connector_attach_scaling_mode_property - attach atomic scaling mode property | ||
969 | * @connector: connector to attach scaling mode property on. | ||
970 | * @scaling_mode_mask: or'ed mask of BIT(%DRM_MODE_SCALE_\*). | ||
971 | * | ||
972 | * This is used to add support for scaling mode to atomic drivers. | ||
973 | * The scaling mode will be set to &drm_connector_state.picture_aspect_ratio | ||
974 | * and can be used from &drm_connector_helper_funcs->atomic_check for validation. | ||
975 | * | ||
976 | * This is the atomic version of drm_mode_create_scaling_mode_property(). | ||
977 | * | ||
978 | * Returns: | ||
979 | * Zero on success, negative errno on failure. | ||
980 | */ | ||
981 | int drm_connector_attach_scaling_mode_property(struct drm_connector *connector, | ||
982 | u32 scaling_mode_mask) | ||
983 | { | ||
984 | struct drm_device *dev = connector->dev; | ||
985 | struct drm_property *scaling_mode_property; | ||
986 | int i, j = 0; | ||
987 | const unsigned valid_scaling_mode_mask = | ||
988 | (1U << ARRAY_SIZE(drm_scaling_mode_enum_list)) - 1; | ||
989 | |||
990 | if (WARN_ON(hweight32(scaling_mode_mask) < 2 || | ||
991 | scaling_mode_mask & ~valid_scaling_mode_mask)) | ||
992 | return -EINVAL; | ||
993 | |||
994 | scaling_mode_property = | ||
995 | drm_property_create(dev, DRM_MODE_PROP_ENUM, "scaling mode", | ||
996 | hweight32(scaling_mode_mask)); | ||
997 | |||
998 | if (!scaling_mode_property) | ||
999 | return -ENOMEM; | ||
1000 | |||
1001 | for (i = 0; i < ARRAY_SIZE(drm_scaling_mode_enum_list); i++) { | ||
1002 | int ret; | ||
1003 | |||
1004 | if (!(BIT(i) & scaling_mode_mask)) | ||
1005 | continue; | ||
1006 | |||
1007 | ret = drm_property_add_enum(scaling_mode_property, j++, | ||
1008 | drm_scaling_mode_enum_list[i].type, | ||
1009 | drm_scaling_mode_enum_list[i].name); | ||
1010 | |||
1011 | if (ret) { | ||
1012 | drm_property_destroy(dev, scaling_mode_property); | ||
1013 | |||
1014 | return ret; | ||
1015 | } | ||
1016 | } | ||
1017 | |||
1018 | drm_object_attach_property(&connector->base, | ||
1019 | scaling_mode_property, 0); | ||
1020 | |||
1021 | connector->scaling_mode_property = scaling_mode_property; | ||
1022 | |||
1023 | return 0; | ||
1024 | } | ||
1025 | EXPORT_SYMBOL(drm_connector_attach_scaling_mode_property); | ||
1026 | |||
1027 | /** | ||
964 | * drm_mode_create_aspect_ratio_property - create aspect ratio property | 1028 | * drm_mode_create_aspect_ratio_property - create aspect ratio property |
965 | * @dev: DRM device | 1029 | * @dev: DRM device |
966 | * | 1030 | * |
diff --git a/drivers/gpu/drm/drm_dp_mst_topology.c b/drivers/gpu/drm/drm_dp_mst_topology.c index d3fc7e4e85b7..222eb1a8549b 100644 --- a/drivers/gpu/drm/drm_dp_mst_topology.c +++ b/drivers/gpu/drm/drm_dp_mst_topology.c | |||
@@ -737,16 +737,16 @@ static void drm_dp_mst_put_payload_id(struct drm_dp_mst_topology_mgr *mgr, | |||
737 | static bool check_txmsg_state(struct drm_dp_mst_topology_mgr *mgr, | 737 | static bool check_txmsg_state(struct drm_dp_mst_topology_mgr *mgr, |
738 | struct drm_dp_sideband_msg_tx *txmsg) | 738 | struct drm_dp_sideband_msg_tx *txmsg) |
739 | { | 739 | { |
740 | bool ret; | 740 | unsigned int state; |
741 | 741 | ||
742 | /* | 742 | /* |
743 | * All updates to txmsg->state are protected by mgr->qlock, and the two | 743 | * All updates to txmsg->state are protected by mgr->qlock, and the two |
744 | * cases we check here are terminal states. For those the barriers | 744 | * cases we check here are terminal states. For those the barriers |
745 | * provided by the wake_up/wait_event pair are enough. | 745 | * provided by the wake_up/wait_event pair are enough. |
746 | */ | 746 | */ |
747 | ret = (txmsg->state == DRM_DP_SIDEBAND_TX_RX || | 747 | state = READ_ONCE(txmsg->state); |
748 | txmsg->state == DRM_DP_SIDEBAND_TX_TIMEOUT); | 748 | return (state == DRM_DP_SIDEBAND_TX_RX || |
749 | return ret; | 749 | state == DRM_DP_SIDEBAND_TX_TIMEOUT); |
750 | } | 750 | } |
751 | 751 | ||
752 | static int drm_dp_mst_wait_tx_reply(struct drm_dp_mst_branch *mstb, | 752 | static int drm_dp_mst_wait_tx_reply(struct drm_dp_mst_branch *mstb, |
@@ -855,7 +855,7 @@ static void drm_dp_destroy_mst_branch_device(struct kref *kref) | |||
855 | mutex_unlock(&mstb->mgr->qlock); | 855 | mutex_unlock(&mstb->mgr->qlock); |
856 | 856 | ||
857 | if (wake_tx) | 857 | if (wake_tx) |
858 | wake_up(&mstb->mgr->tx_waitq); | 858 | wake_up_all(&mstb->mgr->tx_waitq); |
859 | 859 | ||
860 | kref_put(kref, drm_dp_free_mst_branch_device); | 860 | kref_put(kref, drm_dp_free_mst_branch_device); |
861 | } | 861 | } |
@@ -1510,7 +1510,7 @@ static void process_single_down_tx_qlock(struct drm_dp_mst_topology_mgr *mgr) | |||
1510 | if (txmsg->seqno != -1) | 1510 | if (txmsg->seqno != -1) |
1511 | txmsg->dst->tx_slots[txmsg->seqno] = NULL; | 1511 | txmsg->dst->tx_slots[txmsg->seqno] = NULL; |
1512 | txmsg->state = DRM_DP_SIDEBAND_TX_TIMEOUT; | 1512 | txmsg->state = DRM_DP_SIDEBAND_TX_TIMEOUT; |
1513 | wake_up(&mgr->tx_waitq); | 1513 | wake_up_all(&mgr->tx_waitq); |
1514 | } | 1514 | } |
1515 | } | 1515 | } |
1516 | 1516 | ||
@@ -2258,7 +2258,7 @@ static int drm_dp_mst_handle_down_rep(struct drm_dp_mst_topology_mgr *mgr) | |||
2258 | mstb->tx_slots[slot] = NULL; | 2258 | mstb->tx_slots[slot] = NULL; |
2259 | mutex_unlock(&mgr->qlock); | 2259 | mutex_unlock(&mgr->qlock); |
2260 | 2260 | ||
2261 | wake_up(&mgr->tx_waitq); | 2261 | wake_up_all(&mgr->tx_waitq); |
2262 | } | 2262 | } |
2263 | return ret; | 2263 | return ret; |
2264 | } | 2264 | } |
@@ -2498,6 +2498,81 @@ static int drm_dp_init_vcpi(struct drm_dp_mst_topology_mgr *mgr, | |||
2498 | } | 2498 | } |
2499 | 2499 | ||
2500 | /** | 2500 | /** |
2501 | * drm_dp_atomic_find_vcpi_slots() - Find and add vcpi slots to the state | ||
2502 | * @state: global atomic state | ||
2503 | * @mgr: MST topology manager for the port | ||
2504 | * @port: port to find vcpi slots for | ||
2505 | * @pbn: bandwidth required for the mode in PBN | ||
2506 | * | ||
2507 | * RETURNS: | ||
2508 | * Total slots in the atomic state assigned for this port or error | ||
2509 | */ | ||
2510 | int drm_dp_atomic_find_vcpi_slots(struct drm_atomic_state *state, | ||
2511 | struct drm_dp_mst_topology_mgr *mgr, | ||
2512 | struct drm_dp_mst_port *port, int pbn) | ||
2513 | { | ||
2514 | struct drm_dp_mst_topology_state *topology_state; | ||
2515 | int req_slots; | ||
2516 | |||
2517 | topology_state = drm_atomic_get_mst_topology_state(state, mgr); | ||
2518 | if (topology_state == NULL) | ||
2519 | return -ENOMEM; | ||
2520 | |||
2521 | port = drm_dp_get_validated_port_ref(mgr, port); | ||
2522 | if (port == NULL) | ||
2523 | return -EINVAL; | ||
2524 | req_slots = DIV_ROUND_UP(pbn, mgr->pbn_div); | ||
2525 | DRM_DEBUG_KMS("vcpi slots req=%d, avail=%d\n", | ||
2526 | req_slots, topology_state->avail_slots); | ||
2527 | |||
2528 | if (req_slots > topology_state->avail_slots) { | ||
2529 | drm_dp_put_port(port); | ||
2530 | return -ENOSPC; | ||
2531 | } | ||
2532 | |||
2533 | topology_state->avail_slots -= req_slots; | ||
2534 | DRM_DEBUG_KMS("vcpi slots avail=%d", topology_state->avail_slots); | ||
2535 | |||
2536 | drm_dp_put_port(port); | ||
2537 | return req_slots; | ||
2538 | } | ||
2539 | EXPORT_SYMBOL(drm_dp_atomic_find_vcpi_slots); | ||
2540 | |||
2541 | /** | ||
2542 | * drm_dp_atomic_release_vcpi_slots() - Release allocated vcpi slots | ||
2543 | * @state: global atomic state | ||
2544 | * @mgr: MST topology manager for the port | ||
2545 | * @slots: number of vcpi slots to release | ||
2546 | * | ||
2547 | * RETURNS: | ||
2548 | * 0 if @slots were added back to &drm_dp_mst_topology_state->avail_slots or | ||
2549 | * negative error code | ||
2550 | */ | ||
2551 | int drm_dp_atomic_release_vcpi_slots(struct drm_atomic_state *state, | ||
2552 | struct drm_dp_mst_topology_mgr *mgr, | ||
2553 | int slots) | ||
2554 | { | ||
2555 | struct drm_dp_mst_topology_state *topology_state; | ||
2556 | |||
2557 | topology_state = drm_atomic_get_mst_topology_state(state, mgr); | ||
2558 | if (topology_state == NULL) | ||
2559 | return -ENOMEM; | ||
2560 | |||
2561 | /* We cannot rely on port->vcpi.num_slots to update | ||
2562 | * topology_state->avail_slots as the port may not exist if the parent | ||
2563 | * branch device was unplugged. This should be fixed by tracking | ||
2564 | * per-port slot allocation in drm_dp_mst_topology_state instead of | ||
2565 | * depending on the caller to tell us how many slots to release. | ||
2566 | */ | ||
2567 | topology_state->avail_slots += slots; | ||
2568 | DRM_DEBUG_KMS("vcpi slots released=%d, avail=%d\n", | ||
2569 | slots, topology_state->avail_slots); | ||
2570 | |||
2571 | return 0; | ||
2572 | } | ||
2573 | EXPORT_SYMBOL(drm_dp_atomic_release_vcpi_slots); | ||
2574 | |||
2575 | /** | ||
2501 | * drm_dp_mst_allocate_vcpi() - Allocate a virtual channel | 2576 | * drm_dp_mst_allocate_vcpi() - Allocate a virtual channel |
2502 | * @mgr: manager for this port | 2577 | * @mgr: manager for this port |
2503 | * @port: port to allocate a virtual channel for. | 2578 | * @port: port to allocate a virtual channel for. |
@@ -2936,6 +3011,69 @@ static void drm_dp_destroy_connector_work(struct work_struct *work) | |||
2936 | (*mgr->cbs->hotplug)(mgr); | 3011 | (*mgr->cbs->hotplug)(mgr); |
2937 | } | 3012 | } |
2938 | 3013 | ||
3014 | void *drm_dp_mst_duplicate_state(struct drm_atomic_state *state, void *obj) | ||
3015 | { | ||
3016 | struct drm_dp_mst_topology_mgr *mgr = obj; | ||
3017 | struct drm_dp_mst_topology_state *new_mst_state; | ||
3018 | |||
3019 | if (WARN_ON(!mgr->state)) | ||
3020 | return NULL; | ||
3021 | |||
3022 | new_mst_state = kmemdup(mgr->state, sizeof(*new_mst_state), GFP_KERNEL); | ||
3023 | if (new_mst_state) | ||
3024 | new_mst_state->state = state; | ||
3025 | return new_mst_state; | ||
3026 | } | ||
3027 | |||
3028 | void drm_dp_mst_swap_state(void *obj, void **obj_state_ptr) | ||
3029 | { | ||
3030 | struct drm_dp_mst_topology_mgr *mgr = obj; | ||
3031 | struct drm_dp_mst_topology_state **topology_state_ptr; | ||
3032 | |||
3033 | topology_state_ptr = (struct drm_dp_mst_topology_state **)obj_state_ptr; | ||
3034 | |||
3035 | mgr->state->state = (*topology_state_ptr)->state; | ||
3036 | swap(*topology_state_ptr, mgr->state); | ||
3037 | mgr->state->state = NULL; | ||
3038 | } | ||
3039 | |||
3040 | void drm_dp_mst_destroy_state(void *obj_state) | ||
3041 | { | ||
3042 | kfree(obj_state); | ||
3043 | } | ||
3044 | |||
3045 | static const struct drm_private_state_funcs mst_state_funcs = { | ||
3046 | .duplicate_state = drm_dp_mst_duplicate_state, | ||
3047 | .swap_state = drm_dp_mst_swap_state, | ||
3048 | .destroy_state = drm_dp_mst_destroy_state, | ||
3049 | }; | ||
3050 | |||
3051 | /** | ||
3052 | * drm_atomic_get_mst_topology_state: get MST topology state | ||
3053 | * | ||
3054 | * @state: global atomic state | ||
3055 | * @mgr: MST topology manager, also the private object in this case | ||
3056 | * | ||
3057 | * This function wraps drm_atomic_get_priv_obj_state() passing in the MST atomic | ||
3058 | * state vtable so that the private object state returned is that of a MST | ||
3059 | * topology object. Also, drm_atomic_get_private_obj_state() expects the caller | ||
3060 | * to care of the locking, so warn if don't hold the connection_mutex. | ||
3061 | * | ||
3062 | * RETURNS: | ||
3063 | * | ||
3064 | * The MST topology state or error pointer. | ||
3065 | */ | ||
3066 | struct drm_dp_mst_topology_state *drm_atomic_get_mst_topology_state(struct drm_atomic_state *state, | ||
3067 | struct drm_dp_mst_topology_mgr *mgr) | ||
3068 | { | ||
3069 | struct drm_device *dev = mgr->dev; | ||
3070 | |||
3071 | WARN_ON(!drm_modeset_is_locked(&dev->mode_config.connection_mutex)); | ||
3072 | return drm_atomic_get_private_obj_state(state, mgr, | ||
3073 | &mst_state_funcs); | ||
3074 | } | ||
3075 | EXPORT_SYMBOL(drm_atomic_get_mst_topology_state); | ||
3076 | |||
2939 | /** | 3077 | /** |
2940 | * drm_dp_mst_topology_mgr_init - initialise a topology manager | 3078 | * drm_dp_mst_topology_mgr_init - initialise a topology manager |
2941 | * @mgr: manager struct to initialise | 3079 | * @mgr: manager struct to initialise |
@@ -2980,6 +3118,15 @@ int drm_dp_mst_topology_mgr_init(struct drm_dp_mst_topology_mgr *mgr, | |||
2980 | if (test_calc_pbn_mode() < 0) | 3118 | if (test_calc_pbn_mode() < 0) |
2981 | DRM_ERROR("MST PBN self-test failed\n"); | 3119 | DRM_ERROR("MST PBN self-test failed\n"); |
2982 | 3120 | ||
3121 | mgr->state = kzalloc(sizeof(*mgr->state), GFP_KERNEL); | ||
3122 | if (mgr->state == NULL) | ||
3123 | return -ENOMEM; | ||
3124 | mgr->state->mgr = mgr; | ||
3125 | |||
3126 | /* max. time slots - one slot for MTP header */ | ||
3127 | mgr->state->avail_slots = 63; | ||
3128 | mgr->funcs = &mst_state_funcs; | ||
3129 | |||
2983 | return 0; | 3130 | return 0; |
2984 | } | 3131 | } |
2985 | EXPORT_SYMBOL(drm_dp_mst_topology_mgr_init); | 3132 | EXPORT_SYMBOL(drm_dp_mst_topology_mgr_init); |
@@ -3000,6 +3147,9 @@ void drm_dp_mst_topology_mgr_destroy(struct drm_dp_mst_topology_mgr *mgr) | |||
3000 | mutex_unlock(&mgr->payload_lock); | 3147 | mutex_unlock(&mgr->payload_lock); |
3001 | mgr->dev = NULL; | 3148 | mgr->dev = NULL; |
3002 | mgr->aux = NULL; | 3149 | mgr->aux = NULL; |
3150 | kfree(mgr->state); | ||
3151 | mgr->state = NULL; | ||
3152 | mgr->funcs = NULL; | ||
3003 | } | 3153 | } |
3004 | EXPORT_SYMBOL(drm_dp_mst_topology_mgr_destroy); | 3154 | EXPORT_SYMBOL(drm_dp_mst_topology_mgr_destroy); |
3005 | 3155 | ||
diff --git a/drivers/gpu/drm/drm_fb_cma_helper.c b/drivers/gpu/drm/drm_fb_cma_helper.c index 50abd1faf38f..53f9bdf470d7 100644 --- a/drivers/gpu/drm/drm_fb_cma_helper.c +++ b/drivers/gpu/drm/drm_fb_cma_helper.c | |||
@@ -189,7 +189,7 @@ struct drm_framebuffer *drm_fb_cma_create_with_funcs(struct drm_device *dev, | |||
189 | obj = drm_gem_object_lookup(file_priv, mode_cmd->handles[i]); | 189 | obj = drm_gem_object_lookup(file_priv, mode_cmd->handles[i]); |
190 | if (!obj) { | 190 | if (!obj) { |
191 | dev_err(dev->dev, "Failed to lookup GEM object\n"); | 191 | dev_err(dev->dev, "Failed to lookup GEM object\n"); |
192 | ret = -ENXIO; | 192 | ret = -ENOENT; |
193 | goto err_gem_object_put; | 193 | goto err_gem_object_put; |
194 | } | 194 | } |
195 | 195 | ||
@@ -260,6 +260,33 @@ struct drm_gem_cma_object *drm_fb_cma_get_gem_obj(struct drm_framebuffer *fb, | |||
260 | EXPORT_SYMBOL_GPL(drm_fb_cma_get_gem_obj); | 260 | EXPORT_SYMBOL_GPL(drm_fb_cma_get_gem_obj); |
261 | 261 | ||
262 | /** | 262 | /** |
263 | * drm_fb_cma_get_gem_addr() - Get physical address for framebuffer | ||
264 | * @fb: The framebuffer | ||
265 | * @state: Which state of drm plane | ||
266 | * @plane: Which plane | ||
267 | * Return the CMA GEM address for given framebuffer. | ||
268 | * | ||
269 | * This function will usually be called from the PLANE callback functions. | ||
270 | */ | ||
271 | dma_addr_t drm_fb_cma_get_gem_addr(struct drm_framebuffer *fb, | ||
272 | struct drm_plane_state *state, | ||
273 | unsigned int plane) | ||
274 | { | ||
275 | struct drm_fb_cma *fb_cma = to_fb_cma(fb); | ||
276 | dma_addr_t paddr; | ||
277 | |||
278 | if (plane >= 4) | ||
279 | return 0; | ||
280 | |||
281 | paddr = fb_cma->obj[plane]->paddr + fb->offsets[plane]; | ||
282 | paddr += fb->format->cpp[plane] * (state->src_x >> 16); | ||
283 | paddr += fb->pitches[plane] * (state->src_y >> 16); | ||
284 | |||
285 | return paddr; | ||
286 | } | ||
287 | EXPORT_SYMBOL_GPL(drm_fb_cma_get_gem_addr); | ||
288 | |||
289 | /** | ||
263 | * drm_fb_cma_prepare_fb() - Prepare CMA framebuffer | 290 | * drm_fb_cma_prepare_fb() - Prepare CMA framebuffer |
264 | * @plane: Which plane | 291 | * @plane: Which plane |
265 | * @state: Plane state attach fence to | 292 | * @state: Plane state attach fence to |
diff --git a/drivers/gpu/drm/drm_file.c b/drivers/gpu/drm/drm_file.c index 3783b659cd38..caad93dab54b 100644 --- a/drivers/gpu/drm/drm_file.c +++ b/drivers/gpu/drm/drm_file.c | |||
@@ -351,9 +351,8 @@ void drm_lastclose(struct drm_device * dev) | |||
351 | * | 351 | * |
352 | * This function must be used by drivers as their &file_operations.release | 352 | * This function must be used by drivers as their &file_operations.release |
353 | * method. It frees any resources associated with the open file, and calls the | 353 | * method. It frees any resources associated with the open file, and calls the |
354 | * &drm_driver.preclose and &drm_driver.lastclose driver callbacks. If this is | 354 | * &drm_driver.postclose driver callback. If this is the last open file for the |
355 | * the last open file for the DRM device also proceeds to call the | 355 | * DRM device also proceeds to call the &drm_driver.lastclose driver callback. |
356 | * &drm_driver.lastclose driver callback. | ||
357 | * | 356 | * |
358 | * RETURNS: | 357 | * RETURNS: |
359 | * | 358 | * |
@@ -373,7 +372,8 @@ int drm_release(struct inode *inode, struct file *filp) | |||
373 | list_del(&file_priv->lhead); | 372 | list_del(&file_priv->lhead); |
374 | mutex_unlock(&dev->filelist_mutex); | 373 | mutex_unlock(&dev->filelist_mutex); |
375 | 374 | ||
376 | if (dev->driver->preclose) | 375 | if (drm_core_check_feature(dev, DRIVER_LEGACY) && |
376 | dev->driver->preclose) | ||
377 | dev->driver->preclose(dev, file_priv); | 377 | dev->driver->preclose(dev, file_priv); |
378 | 378 | ||
379 | /* ======================================================== | 379 | /* ======================================================== |
diff --git a/drivers/gpu/drm/drm_irq.c b/drivers/gpu/drm/drm_irq.c index 8c866cac62dd..c7debaad67f8 100644 --- a/drivers/gpu/drm/drm_irq.c +++ b/drivers/gpu/drm/drm_irq.c | |||
@@ -54,7 +54,7 @@ | |||
54 | 54 | ||
55 | static bool | 55 | static bool |
56 | drm_get_last_vbltimestamp(struct drm_device *dev, unsigned int pipe, | 56 | drm_get_last_vbltimestamp(struct drm_device *dev, unsigned int pipe, |
57 | struct timeval *tvblank, unsigned flags); | 57 | struct timeval *tvblank, bool in_vblank_irq); |
58 | 58 | ||
59 | static unsigned int drm_timestamp_precision = 20; /* Default to 20 usecs. */ | 59 | static unsigned int drm_timestamp_precision = 20; /* Default to 20 usecs. */ |
60 | 60 | ||
@@ -138,7 +138,7 @@ static void drm_reset_vblank_timestamp(struct drm_device *dev, unsigned int pipe | |||
138 | */ | 138 | */ |
139 | do { | 139 | do { |
140 | cur_vblank = __get_vblank_counter(dev, pipe); | 140 | cur_vblank = __get_vblank_counter(dev, pipe); |
141 | rc = drm_get_last_vbltimestamp(dev, pipe, &t_vblank, 0); | 141 | rc = drm_get_last_vbltimestamp(dev, pipe, &t_vblank, false); |
142 | } while (cur_vblank != __get_vblank_counter(dev, pipe) && --count > 0); | 142 | } while (cur_vblank != __get_vblank_counter(dev, pipe) && --count > 0); |
143 | 143 | ||
144 | /* | 144 | /* |
@@ -171,7 +171,7 @@ static void drm_reset_vblank_timestamp(struct drm_device *dev, unsigned int pipe | |||
171 | * device vblank fields. | 171 | * device vblank fields. |
172 | */ | 172 | */ |
173 | static void drm_update_vblank_count(struct drm_device *dev, unsigned int pipe, | 173 | static void drm_update_vblank_count(struct drm_device *dev, unsigned int pipe, |
174 | unsigned long flags) | 174 | bool in_vblank_irq) |
175 | { | 175 | { |
176 | struct drm_vblank_crtc *vblank = &dev->vblank[pipe]; | 176 | struct drm_vblank_crtc *vblank = &dev->vblank[pipe]; |
177 | u32 cur_vblank, diff; | 177 | u32 cur_vblank, diff; |
@@ -194,7 +194,7 @@ static void drm_update_vblank_count(struct drm_device *dev, unsigned int pipe, | |||
194 | */ | 194 | */ |
195 | do { | 195 | do { |
196 | cur_vblank = __get_vblank_counter(dev, pipe); | 196 | cur_vblank = __get_vblank_counter(dev, pipe); |
197 | rc = drm_get_last_vbltimestamp(dev, pipe, &t_vblank, flags); | 197 | rc = drm_get_last_vbltimestamp(dev, pipe, &t_vblank, in_vblank_irq); |
198 | } while (cur_vblank != __get_vblank_counter(dev, pipe) && --count > 0); | 198 | } while (cur_vblank != __get_vblank_counter(dev, pipe) && --count > 0); |
199 | 199 | ||
200 | if (dev->max_vblank_count != 0) { | 200 | if (dev->max_vblank_count != 0) { |
@@ -214,13 +214,13 @@ static void drm_update_vblank_count(struct drm_device *dev, unsigned int pipe, | |||
214 | */ | 214 | */ |
215 | diff = DIV_ROUND_CLOSEST_ULL(diff_ns, framedur_ns); | 215 | diff = DIV_ROUND_CLOSEST_ULL(diff_ns, framedur_ns); |
216 | 216 | ||
217 | if (diff == 0 && flags & DRM_CALLED_FROM_VBLIRQ) | 217 | if (diff == 0 && in_vblank_irq) |
218 | DRM_DEBUG_VBL("crtc %u: Redundant vblirq ignored." | 218 | DRM_DEBUG_VBL("crtc %u: Redundant vblirq ignored." |
219 | " diff_ns = %lld, framedur_ns = %d)\n", | 219 | " diff_ns = %lld, framedur_ns = %d)\n", |
220 | pipe, (long long) diff_ns, framedur_ns); | 220 | pipe, (long long) diff_ns, framedur_ns); |
221 | } else { | 221 | } else { |
222 | /* some kind of default for drivers w/o accurate vbl timestamping */ | 222 | /* some kind of default for drivers w/o accurate vbl timestamping */ |
223 | diff = (flags & DRM_CALLED_FROM_VBLIRQ) != 0; | 223 | diff = in_vblank_irq ? 1 : 0; |
224 | } | 224 | } |
225 | 225 | ||
226 | /* | 226 | /* |
@@ -253,7 +253,7 @@ static void drm_update_vblank_count(struct drm_device *dev, unsigned int pipe, | |||
253 | * Otherwise reinitialize delayed at next vblank interrupt and assign 0 | 253 | * Otherwise reinitialize delayed at next vblank interrupt and assign 0 |
254 | * for now, to mark the vblanktimestamp as invalid. | 254 | * for now, to mark the vblanktimestamp as invalid. |
255 | */ | 255 | */ |
256 | if (!rc && (flags & DRM_CALLED_FROM_VBLIRQ) == 0) | 256 | if (!rc && in_vblank_irq) |
257 | t_vblank = (struct timeval) {0, 0}; | 257 | t_vblank = (struct timeval) {0, 0}; |
258 | 258 | ||
259 | store_vblank(dev, pipe, diff, &t_vblank, cur_vblank); | 259 | store_vblank(dev, pipe, diff, &t_vblank, cur_vblank); |
@@ -291,7 +291,7 @@ u32 drm_accurate_vblank_count(struct drm_crtc *crtc) | |||
291 | 291 | ||
292 | spin_lock_irqsave(&dev->vblank_time_lock, flags); | 292 | spin_lock_irqsave(&dev->vblank_time_lock, flags); |
293 | 293 | ||
294 | drm_update_vblank_count(dev, pipe, 0); | 294 | drm_update_vblank_count(dev, pipe, false); |
295 | vblank = drm_vblank_count(dev, pipe); | 295 | vblank = drm_vblank_count(dev, pipe); |
296 | 296 | ||
297 | spin_unlock_irqrestore(&dev->vblank_time_lock, flags); | 297 | spin_unlock_irqrestore(&dev->vblank_time_lock, flags); |
@@ -349,7 +349,7 @@ static void vblank_disable_and_save(struct drm_device *dev, unsigned int pipe) | |||
349 | * this time. This makes the count account for the entire time | 349 | * this time. This makes the count account for the entire time |
350 | * between drm_crtc_vblank_on() and drm_crtc_vblank_off(). | 350 | * between drm_crtc_vblank_on() and drm_crtc_vblank_off(). |
351 | */ | 351 | */ |
352 | drm_update_vblank_count(dev, pipe, 0); | 352 | drm_update_vblank_count(dev, pipe, false); |
353 | 353 | ||
354 | spin_unlock_irqrestore(&dev->vblank_time_lock, irqflags); | 354 | spin_unlock_irqrestore(&dev->vblank_time_lock, irqflags); |
355 | } | 355 | } |
@@ -684,6 +684,7 @@ void drm_calc_timestamping_constants(struct drm_crtc *crtc, | |||
684 | 684 | ||
685 | vblank->linedur_ns = linedur_ns; | 685 | vblank->linedur_ns = linedur_ns; |
686 | vblank->framedur_ns = framedur_ns; | 686 | vblank->framedur_ns = framedur_ns; |
687 | vblank->hwmode = *mode; | ||
687 | 688 | ||
688 | DRM_DEBUG("crtc %u: hwmode: htotal %d, vtotal %d, vdisplay %d\n", | 689 | DRM_DEBUG("crtc %u: hwmode: htotal %d, vtotal %d, vdisplay %d\n", |
689 | crtc->base.id, mode->crtc_htotal, | 690 | crtc->base.id, mode->crtc_htotal, |
@@ -700,10 +701,10 @@ EXPORT_SYMBOL(drm_calc_timestamping_constants); | |||
700 | * @max_error: Desired maximum allowable error in timestamps (nanosecs) | 701 | * @max_error: Desired maximum allowable error in timestamps (nanosecs) |
701 | * On return contains true maximum error of timestamp | 702 | * On return contains true maximum error of timestamp |
702 | * @vblank_time: Pointer to struct timeval which should receive the timestamp | 703 | * @vblank_time: Pointer to struct timeval which should receive the timestamp |
703 | * @flags: Flags to pass to driver: | 704 | * @in_vblank_irq: |
704 | * 0 = Default, | 705 | * True when called from drm_crtc_handle_vblank(). Some drivers |
705 | * DRM_CALLED_FROM_VBLIRQ = If function is called from vbl IRQ handler | 706 | * need to apply some workarounds for gpu-specific vblank irq quirks |
706 | * @mode: mode which defines the scanout timings | 707 | * if flag is set. |
707 | * | 708 | * |
708 | * Implements calculation of exact vblank timestamps from given drm_display_mode | 709 | * Implements calculation of exact vblank timestamps from given drm_display_mode |
709 | * timings and current video scanout position of a CRTC. This can be called from | 710 | * timings and current video scanout position of a CRTC. This can be called from |
@@ -723,52 +724,62 @@ EXPORT_SYMBOL(drm_calc_timestamping_constants); | |||
723 | * returns as no operation if a doublescan or interlaced video mode is | 724 | * returns as no operation if a doublescan or interlaced video mode is |
724 | * active. Higher level code is expected to handle this. | 725 | * active. Higher level code is expected to handle this. |
725 | * | 726 | * |
726 | * Returns: | 727 | * This function can be used to implement the &drm_driver.get_vblank_timestamp |
727 | * Negative value on error, failure or if not supported in current | 728 | * directly, if the driver implements the &drm_driver.get_scanout_position hook. |
728 | * video mode: | ||
729 | * | ||
730 | * -EINVAL Invalid CRTC. | ||
731 | * -EAGAIN Temporary unavailable, e.g., called before initial modeset. | ||
732 | * -ENOTSUPP Function not supported in current display mode. | ||
733 | * -EIO Failed, e.g., due to failed scanout position query. | ||
734 | * | 729 | * |
735 | * Returns or'ed positive status flags on success: | 730 | * Note that atomic drivers must call drm_calc_timestamping_constants() before |
731 | * enabling a CRTC. The atomic helpers already take care of that in | ||
732 | * drm_atomic_helper_update_legacy_modeset_state(). | ||
736 | * | 733 | * |
737 | * DRM_VBLANKTIME_SCANOUTPOS_METHOD - Signal this method used for timestamping. | 734 | * Returns: |
738 | * DRM_VBLANKTIME_INVBL - Timestamp taken while scanout was in vblank interval. | ||
739 | * | 735 | * |
736 | * Returns true on success, and false on failure, i.e. when no accurate | ||
737 | * timestamp could be acquired. | ||
740 | */ | 738 | */ |
741 | int drm_calc_vbltimestamp_from_scanoutpos(struct drm_device *dev, | 739 | bool drm_calc_vbltimestamp_from_scanoutpos(struct drm_device *dev, |
742 | unsigned int pipe, | 740 | unsigned int pipe, |
743 | int *max_error, | 741 | int *max_error, |
744 | struct timeval *vblank_time, | 742 | struct timeval *vblank_time, |
745 | unsigned flags, | 743 | bool in_vblank_irq) |
746 | const struct drm_display_mode *mode) | ||
747 | { | 744 | { |
748 | struct timeval tv_etime; | 745 | struct timeval tv_etime; |
749 | ktime_t stime, etime; | 746 | ktime_t stime, etime; |
750 | unsigned int vbl_status; | 747 | bool vbl_status; |
751 | int ret = DRM_VBLANKTIME_SCANOUTPOS_METHOD; | 748 | struct drm_crtc *crtc; |
749 | const struct drm_display_mode *mode; | ||
750 | struct drm_vblank_crtc *vblank = &dev->vblank[pipe]; | ||
752 | int vpos, hpos, i; | 751 | int vpos, hpos, i; |
753 | int delta_ns, duration_ns; | 752 | int delta_ns, duration_ns; |
754 | 753 | ||
755 | if (pipe >= dev->num_crtcs) { | 754 | if (!drm_core_check_feature(dev, DRIVER_MODESET)) |
755 | return false; | ||
756 | |||
757 | crtc = drm_crtc_from_index(dev, pipe); | ||
758 | |||
759 | if (pipe >= dev->num_crtcs || !crtc) { | ||
756 | DRM_ERROR("Invalid crtc %u\n", pipe); | 760 | DRM_ERROR("Invalid crtc %u\n", pipe); |
757 | return -EINVAL; | 761 | return false; |
758 | } | 762 | } |
759 | 763 | ||
760 | /* Scanout position query not supported? Should not happen. */ | 764 | /* Scanout position query not supported? Should not happen. */ |
761 | if (!dev->driver->get_scanout_position) { | 765 | if (!dev->driver->get_scanout_position) { |
762 | DRM_ERROR("Called from driver w/o get_scanout_position()!?\n"); | 766 | DRM_ERROR("Called from driver w/o get_scanout_position()!?\n"); |
763 | return -EIO; | 767 | return false; |
764 | } | 768 | } |
765 | 769 | ||
770 | if (drm_drv_uses_atomic_modeset(dev)) | ||
771 | mode = &vblank->hwmode; | ||
772 | else | ||
773 | mode = &crtc->hwmode; | ||
774 | |||
766 | /* If mode timing undefined, just return as no-op: | 775 | /* If mode timing undefined, just return as no-op: |
767 | * Happens during initial modesetting of a crtc. | 776 | * Happens during initial modesetting of a crtc. |
768 | */ | 777 | */ |
769 | if (mode->crtc_clock == 0) { | 778 | if (mode->crtc_clock == 0) { |
770 | DRM_DEBUG("crtc %u: Noop due to uninitialized mode.\n", pipe); | 779 | DRM_DEBUG("crtc %u: Noop due to uninitialized mode.\n", pipe); |
771 | return -EAGAIN; | 780 | WARN_ON_ONCE(drm_drv_uses_atomic_modeset(dev)); |
781 | |||
782 | return false; | ||
772 | } | 783 | } |
773 | 784 | ||
774 | /* Get current scanout position with system timestamp. | 785 | /* Get current scanout position with system timestamp. |
@@ -783,16 +794,17 @@ int drm_calc_vbltimestamp_from_scanoutpos(struct drm_device *dev, | |||
783 | * Get vertical and horizontal scanout position vpos, hpos, | 794 | * Get vertical and horizontal scanout position vpos, hpos, |
784 | * and bounding timestamps stime, etime, pre/post query. | 795 | * and bounding timestamps stime, etime, pre/post query. |
785 | */ | 796 | */ |
786 | vbl_status = dev->driver->get_scanout_position(dev, pipe, flags, | 797 | vbl_status = dev->driver->get_scanout_position(dev, pipe, |
798 | in_vblank_irq, | ||
787 | &vpos, &hpos, | 799 | &vpos, &hpos, |
788 | &stime, &etime, | 800 | &stime, &etime, |
789 | mode); | 801 | mode); |
790 | 802 | ||
791 | /* Return as no-op if scanout query unsupported or failed. */ | 803 | /* Return as no-op if scanout query unsupported or failed. */ |
792 | if (!(vbl_status & DRM_SCANOUTPOS_VALID)) { | 804 | if (!vbl_status) { |
793 | DRM_DEBUG("crtc %u : scanoutpos query failed [0x%x].\n", | 805 | DRM_DEBUG("crtc %u : scanoutpos query failed.\n", |
794 | pipe, vbl_status); | 806 | pipe); |
795 | return -EIO; | 807 | return false; |
796 | } | 808 | } |
797 | 809 | ||
798 | /* Compute uncertainty in timestamp of scanout position query. */ | 810 | /* Compute uncertainty in timestamp of scanout position query. */ |
@@ -830,13 +842,13 @@ int drm_calc_vbltimestamp_from_scanoutpos(struct drm_device *dev, | |||
830 | etime = ktime_sub_ns(etime, delta_ns); | 842 | etime = ktime_sub_ns(etime, delta_ns); |
831 | *vblank_time = ktime_to_timeval(etime); | 843 | *vblank_time = ktime_to_timeval(etime); |
832 | 844 | ||
833 | DRM_DEBUG_VBL("crtc %u : v 0x%x p(%d,%d)@ %ld.%ld -> %ld.%ld [e %d us, %d rep]\n", | 845 | DRM_DEBUG_VBL("crtc %u : v p(%d,%d)@ %ld.%ld -> %ld.%ld [e %d us, %d rep]\n", |
834 | pipe, vbl_status, hpos, vpos, | 846 | pipe, hpos, vpos, |
835 | (long)tv_etime.tv_sec, (long)tv_etime.tv_usec, | 847 | (long)tv_etime.tv_sec, (long)tv_etime.tv_usec, |
836 | (long)vblank_time->tv_sec, (long)vblank_time->tv_usec, | 848 | (long)vblank_time->tv_sec, (long)vblank_time->tv_usec, |
837 | duration_ns/1000, i); | 849 | duration_ns/1000, i); |
838 | 850 | ||
839 | return ret; | 851 | return true; |
840 | } | 852 | } |
841 | EXPORT_SYMBOL(drm_calc_vbltimestamp_from_scanoutpos); | 853 | EXPORT_SYMBOL(drm_calc_vbltimestamp_from_scanoutpos); |
842 | 854 | ||
@@ -854,9 +866,10 @@ static struct timeval get_drm_timestamp(void) | |||
854 | * @dev: DRM device | 866 | * @dev: DRM device |
855 | * @pipe: index of CRTC whose vblank timestamp to retrieve | 867 | * @pipe: index of CRTC whose vblank timestamp to retrieve |
856 | * @tvblank: Pointer to target struct timeval which should receive the timestamp | 868 | * @tvblank: Pointer to target struct timeval which should receive the timestamp |
857 | * @flags: Flags to pass to driver: | 869 | * @in_vblank_irq: |
858 | * 0 = Default, | 870 | * True when called from drm_crtc_handle_vblank(). Some drivers |
859 | * DRM_CALLED_FROM_VBLIRQ = If function is called from vbl IRQ handler | 871 | * need to apply some workarounds for gpu-specific vblank irq quirks |
872 | * if flag is set. | ||
860 | * | 873 | * |
861 | * Fetches the system timestamp corresponding to the time of the most recent | 874 | * Fetches the system timestamp corresponding to the time of the most recent |
862 | * vblank interval on specified CRTC. May call into kms-driver to | 875 | * vblank interval on specified CRTC. May call into kms-driver to |
@@ -870,27 +883,25 @@ static struct timeval get_drm_timestamp(void) | |||
870 | */ | 883 | */ |
871 | static bool | 884 | static bool |
872 | drm_get_last_vbltimestamp(struct drm_device *dev, unsigned int pipe, | 885 | drm_get_last_vbltimestamp(struct drm_device *dev, unsigned int pipe, |
873 | struct timeval *tvblank, unsigned flags) | 886 | struct timeval *tvblank, bool in_vblank_irq) |
874 | { | 887 | { |
875 | int ret; | 888 | bool ret = false; |
876 | 889 | ||
877 | /* Define requested maximum error on timestamps (nanoseconds). */ | 890 | /* Define requested maximum error on timestamps (nanoseconds). */ |
878 | int max_error = (int) drm_timestamp_precision * 1000; | 891 | int max_error = (int) drm_timestamp_precision * 1000; |
879 | 892 | ||
880 | /* Query driver if possible and precision timestamping enabled. */ | 893 | /* Query driver if possible and precision timestamping enabled. */ |
881 | if (dev->driver->get_vblank_timestamp && (max_error > 0)) { | 894 | if (dev->driver->get_vblank_timestamp && (max_error > 0)) |
882 | ret = dev->driver->get_vblank_timestamp(dev, pipe, &max_error, | 895 | ret = dev->driver->get_vblank_timestamp(dev, pipe, &max_error, |
883 | tvblank, flags); | 896 | tvblank, in_vblank_irq); |
884 | if (ret > 0) | ||
885 | return true; | ||
886 | } | ||
887 | 897 | ||
888 | /* GPU high precision timestamp query unsupported or failed. | 898 | /* GPU high precision timestamp query unsupported or failed. |
889 | * Return current monotonic/gettimeofday timestamp as best estimate. | 899 | * Return current monotonic/gettimeofday timestamp as best estimate. |
890 | */ | 900 | */ |
891 | *tvblank = get_drm_timestamp(); | 901 | if (!ret) |
902 | *tvblank = get_drm_timestamp(); | ||
892 | 903 | ||
893 | return false; | 904 | return ret; |
894 | } | 905 | } |
895 | 906 | ||
896 | /** | 907 | /** |
@@ -1329,6 +1340,10 @@ void drm_crtc_vblank_off(struct drm_crtc *crtc) | |||
1329 | send_vblank_event(dev, e, seq, &now); | 1340 | send_vblank_event(dev, e, seq, &now); |
1330 | } | 1341 | } |
1331 | spin_unlock_irqrestore(&dev->event_lock, irqflags); | 1342 | spin_unlock_irqrestore(&dev->event_lock, irqflags); |
1343 | |||
1344 | /* Will be reset by the modeset helpers when re-enabling the crtc by | ||
1345 | * calling drm_calc_timestamping_constants(). */ | ||
1346 | vblank->hwmode.crtc_clock = 0; | ||
1332 | } | 1347 | } |
1333 | EXPORT_SYMBOL(drm_crtc_vblank_off); | 1348 | EXPORT_SYMBOL(drm_crtc_vblank_off); |
1334 | 1349 | ||
@@ -1760,7 +1775,7 @@ bool drm_handle_vblank(struct drm_device *dev, unsigned int pipe) | |||
1760 | return false; | 1775 | return false; |
1761 | } | 1776 | } |
1762 | 1777 | ||
1763 | drm_update_vblank_count(dev, pipe, DRM_CALLED_FROM_VBLIRQ); | 1778 | drm_update_vblank_count(dev, pipe, true); |
1764 | 1779 | ||
1765 | spin_unlock(&dev->vblank_time_lock); | 1780 | spin_unlock(&dev->vblank_time_lock); |
1766 | 1781 | ||
diff --git a/drivers/gpu/drm/drm_plane_helper.c b/drivers/gpu/drm/drm_plane_helper.c index b84a295230fc..2c27f6f5a668 100644 --- a/drivers/gpu/drm/drm_plane_helper.c +++ b/drivers/gpu/drm/drm_plane_helper.c | |||
@@ -381,6 +381,7 @@ EXPORT_SYMBOL(drm_primary_helper_update); | |||
381 | /** | 381 | /** |
382 | * drm_primary_helper_disable() - Helper for primary plane disable | 382 | * drm_primary_helper_disable() - Helper for primary plane disable |
383 | * @plane: plane to disable | 383 | * @plane: plane to disable |
384 | * @ctx: lock acquire context, not used here | ||
384 | * | 385 | * |
385 | * Provides a default plane disable handler for primary planes. This is handler | 386 | * Provides a default plane disable handler for primary planes. This is handler |
386 | * is called in response to a userspace SetPlane operation on the plane with a | 387 | * is called in response to a userspace SetPlane operation on the plane with a |
@@ -510,12 +511,10 @@ int drm_plane_helper_commit(struct drm_plane *plane, | |||
510 | if (plane_funcs->cleanup_fb) | 511 | if (plane_funcs->cleanup_fb) |
511 | plane_funcs->cleanup_fb(plane, plane_state); | 512 | plane_funcs->cleanup_fb(plane, plane_state); |
512 | out: | 513 | out: |
513 | if (plane_state) { | 514 | if (plane->funcs->atomic_destroy_state) |
514 | if (plane->funcs->atomic_destroy_state) | 515 | plane->funcs->atomic_destroy_state(plane, plane_state); |
515 | plane->funcs->atomic_destroy_state(plane, plane_state); | 516 | else |
516 | else | 517 | drm_atomic_helper_plane_destroy_state(plane, plane_state); |
517 | drm_atomic_helper_plane_destroy_state(plane, plane_state); | ||
518 | } | ||
519 | 518 | ||
520 | return ret; | 519 | return ret; |
521 | } | 520 | } |
diff --git a/drivers/gpu/drm/drm_prime.c b/drivers/gpu/drm/drm_prime.c index 954eb848b5e2..22408badc617 100644 --- a/drivers/gpu/drm/drm_prime.c +++ b/drivers/gpu/drm/drm_prime.c | |||
@@ -595,15 +595,18 @@ out_unlock: | |||
595 | EXPORT_SYMBOL(drm_gem_prime_handle_to_fd); | 595 | EXPORT_SYMBOL(drm_gem_prime_handle_to_fd); |
596 | 596 | ||
597 | /** | 597 | /** |
598 | * drm_gem_prime_import - helper library implementation of the import callback | 598 | * drm_gem_prime_import_dev - core implementation of the import callback |
599 | * @dev: drm_device to import into | 599 | * @dev: drm_device to import into |
600 | * @dma_buf: dma-buf object to import | 600 | * @dma_buf: dma-buf object to import |
601 | * @attach_dev: struct device to dma_buf attach | ||
601 | * | 602 | * |
602 | * This is the implementation of the gem_prime_import functions for GEM drivers | 603 | * This is the core of drm_gem_prime_import. It's designed to be called by |
603 | * using the PRIME helpers. | 604 | * drivers who want to use a different device structure than dev->dev for |
605 | * attaching via dma_buf. | ||
604 | */ | 606 | */ |
605 | struct drm_gem_object *drm_gem_prime_import(struct drm_device *dev, | 607 | struct drm_gem_object *drm_gem_prime_import_dev(struct drm_device *dev, |
606 | struct dma_buf *dma_buf) | 608 | struct dma_buf *dma_buf, |
609 | struct device *attach_dev) | ||
607 | { | 610 | { |
608 | struct dma_buf_attachment *attach; | 611 | struct dma_buf_attachment *attach; |
609 | struct sg_table *sgt; | 612 | struct sg_table *sgt; |
@@ -625,7 +628,7 @@ struct drm_gem_object *drm_gem_prime_import(struct drm_device *dev, | |||
625 | if (!dev->driver->gem_prime_import_sg_table) | 628 | if (!dev->driver->gem_prime_import_sg_table) |
626 | return ERR_PTR(-EINVAL); | 629 | return ERR_PTR(-EINVAL); |
627 | 630 | ||
628 | attach = dma_buf_attach(dma_buf, dev->dev); | 631 | attach = dma_buf_attach(dma_buf, attach_dev); |
629 | if (IS_ERR(attach)) | 632 | if (IS_ERR(attach)) |
630 | return ERR_CAST(attach); | 633 | return ERR_CAST(attach); |
631 | 634 | ||
@@ -655,6 +658,21 @@ fail_detach: | |||
655 | 658 | ||
656 | return ERR_PTR(ret); | 659 | return ERR_PTR(ret); |
657 | } | 660 | } |
661 | EXPORT_SYMBOL(drm_gem_prime_import_dev); | ||
662 | |||
663 | /** | ||
664 | * drm_gem_prime_import - helper library implementation of the import callback | ||
665 | * @dev: drm_device to import into | ||
666 | * @dma_buf: dma-buf object to import | ||
667 | * | ||
668 | * This is the implementation of the gem_prime_import functions for GEM drivers | ||
669 | * using the PRIME helpers. | ||
670 | */ | ||
671 | struct drm_gem_object *drm_gem_prime_import(struct drm_device *dev, | ||
672 | struct dma_buf *dma_buf) | ||
673 | { | ||
674 | return drm_gem_prime_import_dev(dev, dma_buf, dev->dev); | ||
675 | } | ||
658 | EXPORT_SYMBOL(drm_gem_prime_import); | 676 | EXPORT_SYMBOL(drm_gem_prime_import); |
659 | 677 | ||
660 | /** | 678 | /** |
diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.c b/drivers/gpu/drm/exynos/exynos_drm_drv.c index 09d3c4c3c858..50294a7bd29d 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_drv.c +++ b/drivers/gpu/drm/exynos/exynos_drm_drv.c | |||
@@ -82,14 +82,9 @@ err_file_priv_free: | |||
82 | return ret; | 82 | return ret; |
83 | } | 83 | } |
84 | 84 | ||
85 | static void exynos_drm_preclose(struct drm_device *dev, | ||
86 | struct drm_file *file) | ||
87 | { | ||
88 | exynos_drm_subdrv_close(dev, file); | ||
89 | } | ||
90 | |||
91 | static void exynos_drm_postclose(struct drm_device *dev, struct drm_file *file) | 85 | static void exynos_drm_postclose(struct drm_device *dev, struct drm_file *file) |
92 | { | 86 | { |
87 | exynos_drm_subdrv_close(dev, file); | ||
93 | kfree(file->driver_priv); | 88 | kfree(file->driver_priv); |
94 | file->driver_priv = NULL; | 89 | file->driver_priv = NULL; |
95 | } | 90 | } |
@@ -145,7 +140,6 @@ static struct drm_driver exynos_drm_driver = { | |||
145 | .driver_features = DRIVER_MODESET | DRIVER_GEM | DRIVER_PRIME | 140 | .driver_features = DRIVER_MODESET | DRIVER_GEM | DRIVER_PRIME |
146 | | DRIVER_ATOMIC | DRIVER_RENDER, | 141 | | DRIVER_ATOMIC | DRIVER_RENDER, |
147 | .open = exynos_drm_open, | 142 | .open = exynos_drm_open, |
148 | .preclose = exynos_drm_preclose, | ||
149 | .lastclose = exynos_drm_lastclose, | 143 | .lastclose = exynos_drm_lastclose, |
150 | .postclose = exynos_drm_postclose, | 144 | .postclose = exynos_drm_postclose, |
151 | .gem_free_object_unlocked = exynos_drm_gem_free_object, | 145 | .gem_free_object_unlocked = exynos_drm_gem_free_object, |
diff --git a/drivers/gpu/drm/gma500/mdfld_tpo_vid.c b/drivers/gpu/drm/gma500/mdfld_tpo_vid.c index d8d4170725b2..d40628e6810d 100644 --- a/drivers/gpu/drm/gma500/mdfld_tpo_vid.c +++ b/drivers/gpu/drm/gma500/mdfld_tpo_vid.c | |||
@@ -32,53 +32,20 @@ static struct drm_display_mode *tpo_vid_get_config_mode(struct drm_device *dev) | |||
32 | struct drm_display_mode *mode; | 32 | struct drm_display_mode *mode; |
33 | struct drm_psb_private *dev_priv = dev->dev_private; | 33 | struct drm_psb_private *dev_priv = dev->dev_private; |
34 | struct oaktrail_timing_info *ti = &dev_priv->gct_data.DTD; | 34 | struct oaktrail_timing_info *ti = &dev_priv->gct_data.DTD; |
35 | bool use_gct = false; | ||
36 | 35 | ||
37 | mode = kzalloc(sizeof(*mode), GFP_KERNEL); | 36 | mode = kzalloc(sizeof(*mode), GFP_KERNEL); |
38 | if (!mode) | 37 | if (!mode) |
39 | return NULL; | 38 | return NULL; |
40 | 39 | ||
41 | if (use_gct) { | 40 | mode->hdisplay = 864; |
42 | mode->hdisplay = (ti->hactive_hi << 8) | ti->hactive_lo; | 41 | mode->vdisplay = 480; |
43 | mode->vdisplay = (ti->vactive_hi << 8) | ti->vactive_lo; | 42 | mode->hsync_start = 873; |
44 | mode->hsync_start = mode->hdisplay + | 43 | mode->hsync_end = 876; |
45 | ((ti->hsync_offset_hi << 8) | | 44 | mode->htotal = 887; |
46 | ti->hsync_offset_lo); | 45 | mode->vsync_start = 487; |
47 | mode->hsync_end = mode->hsync_start + | 46 | mode->vsync_end = 490; |
48 | ((ti->hsync_pulse_width_hi << 8) | | 47 | mode->vtotal = 499; |
49 | ti->hsync_pulse_width_lo); | 48 | mode->clock = 33264; |
50 | mode->htotal = mode->hdisplay + ((ti->hblank_hi << 8) | | ||
51 | ti->hblank_lo); | ||
52 | mode->vsync_start = | ||
53 | mode->vdisplay + ((ti->vsync_offset_hi << 8) | | ||
54 | ti->vsync_offset_lo); | ||
55 | mode->vsync_end = | ||
56 | mode->vsync_start + ((ti->vsync_pulse_width_hi << 8) | | ||
57 | ti->vsync_pulse_width_lo); | ||
58 | mode->vtotal = mode->vdisplay + | ||
59 | ((ti->vblank_hi << 8) | ti->vblank_lo); | ||
60 | mode->clock = ti->pixel_clock * 10; | ||
61 | |||
62 | dev_dbg(dev->dev, "hdisplay is %d\n", mode->hdisplay); | ||
63 | dev_dbg(dev->dev, "vdisplay is %d\n", mode->vdisplay); | ||
64 | dev_dbg(dev->dev, "HSS is %d\n", mode->hsync_start); | ||
65 | dev_dbg(dev->dev, "HSE is %d\n", mode->hsync_end); | ||
66 | dev_dbg(dev->dev, "htotal is %d\n", mode->htotal); | ||
67 | dev_dbg(dev->dev, "VSS is %d\n", mode->vsync_start); | ||
68 | dev_dbg(dev->dev, "VSE is %d\n", mode->vsync_end); | ||
69 | dev_dbg(dev->dev, "vtotal is %d\n", mode->vtotal); | ||
70 | dev_dbg(dev->dev, "clock is %d\n", mode->clock); | ||
71 | } else { | ||
72 | mode->hdisplay = 864; | ||
73 | mode->vdisplay = 480; | ||
74 | mode->hsync_start = 873; | ||
75 | mode->hsync_end = 876; | ||
76 | mode->htotal = 887; | ||
77 | mode->vsync_start = 487; | ||
78 | mode->vsync_end = 490; | ||
79 | mode->vtotal = 499; | ||
80 | mode->clock = 33264; | ||
81 | } | ||
82 | 49 | ||
83 | drm_mode_set_name(mode); | 50 | drm_mode_set_name(mode); |
84 | drm_mode_set_crtcinfo(mode, 0); | 51 | drm_mode_set_crtcinfo(mode, 0); |
diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index fd97fe00cd0d..04493ef1d2f7 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c | |||
@@ -720,9 +720,7 @@ static u32 i915_get_vblank_counter(struct drm_device *dev, unsigned int pipe) | |||
720 | struct drm_i915_private *dev_priv = to_i915(dev); | 720 | struct drm_i915_private *dev_priv = to_i915(dev); |
721 | i915_reg_t high_frame, low_frame; | 721 | i915_reg_t high_frame, low_frame; |
722 | u32 high1, high2, low, pixel, vbl_start, hsync_start, htotal; | 722 | u32 high1, high2, low, pixel, vbl_start, hsync_start, htotal; |
723 | struct intel_crtc *intel_crtc = intel_get_crtc_for_pipe(dev_priv, | 723 | const struct drm_display_mode *mode = &dev->vblank[pipe].hwmode; |
724 | pipe); | ||
725 | const struct drm_display_mode *mode = &intel_crtc->base.hwmode; | ||
726 | unsigned long irqflags; | 724 | unsigned long irqflags; |
727 | 725 | ||
728 | htotal = mode->crtc_htotal; | 726 | htotal = mode->crtc_htotal; |
@@ -779,13 +777,17 @@ static int __intel_get_crtc_scanline(struct intel_crtc *crtc) | |||
779 | { | 777 | { |
780 | struct drm_device *dev = crtc->base.dev; | 778 | struct drm_device *dev = crtc->base.dev; |
781 | struct drm_i915_private *dev_priv = to_i915(dev); | 779 | struct drm_i915_private *dev_priv = to_i915(dev); |
782 | const struct drm_display_mode *mode = &crtc->base.hwmode; | 780 | const struct drm_display_mode *mode; |
781 | struct drm_vblank_crtc *vblank; | ||
783 | enum pipe pipe = crtc->pipe; | 782 | enum pipe pipe = crtc->pipe; |
784 | int position, vtotal; | 783 | int position, vtotal; |
785 | 784 | ||
786 | if (!crtc->active) | 785 | if (!crtc->active) |
787 | return -1; | 786 | return -1; |
788 | 787 | ||
788 | vblank = &crtc->base.dev->vblank[drm_crtc_index(&crtc->base)]; | ||
789 | mode = &vblank->hwmode; | ||
790 | |||
789 | vtotal = mode->crtc_vtotal; | 791 | vtotal = mode->crtc_vtotal; |
790 | if (mode->flags & DRM_MODE_FLAG_INTERLACE) | 792 | if (mode->flags & DRM_MODE_FLAG_INTERLACE) |
791 | vtotal /= 2; | 793 | vtotal /= 2; |
@@ -827,10 +829,10 @@ static int __intel_get_crtc_scanline(struct intel_crtc *crtc) | |||
827 | return (position + crtc->scanline_offset) % vtotal; | 829 | return (position + crtc->scanline_offset) % vtotal; |
828 | } | 830 | } |
829 | 831 | ||
830 | static int i915_get_crtc_scanoutpos(struct drm_device *dev, unsigned int pipe, | 832 | static bool i915_get_crtc_scanoutpos(struct drm_device *dev, unsigned int pipe, |
831 | unsigned int flags, int *vpos, int *hpos, | 833 | bool in_vblank_irq, int *vpos, int *hpos, |
832 | ktime_t *stime, ktime_t *etime, | 834 | ktime_t *stime, ktime_t *etime, |
833 | const struct drm_display_mode *mode) | 835 | const struct drm_display_mode *mode) |
834 | { | 836 | { |
835 | struct drm_i915_private *dev_priv = to_i915(dev); | 837 | struct drm_i915_private *dev_priv = to_i915(dev); |
836 | struct intel_crtc *intel_crtc = intel_get_crtc_for_pipe(dev_priv, | 838 | struct intel_crtc *intel_crtc = intel_get_crtc_for_pipe(dev_priv, |
@@ -838,13 +840,12 @@ static int i915_get_crtc_scanoutpos(struct drm_device *dev, unsigned int pipe, | |||
838 | int position; | 840 | int position; |
839 | int vbl_start, vbl_end, hsync_start, htotal, vtotal; | 841 | int vbl_start, vbl_end, hsync_start, htotal, vtotal; |
840 | bool in_vbl = true; | 842 | bool in_vbl = true; |
841 | int ret = 0; | ||
842 | unsigned long irqflags; | 843 | unsigned long irqflags; |
843 | 844 | ||
844 | if (WARN_ON(!mode->crtc_clock)) { | 845 | if (WARN_ON(!mode->crtc_clock)) { |
845 | DRM_DEBUG_DRIVER("trying to get scanoutpos for disabled " | 846 | DRM_DEBUG_DRIVER("trying to get scanoutpos for disabled " |
846 | "pipe %c\n", pipe_name(pipe)); | 847 | "pipe %c\n", pipe_name(pipe)); |
847 | return 0; | 848 | return false; |
848 | } | 849 | } |
849 | 850 | ||
850 | htotal = mode->crtc_htotal; | 851 | htotal = mode->crtc_htotal; |
@@ -859,8 +860,6 @@ static int i915_get_crtc_scanoutpos(struct drm_device *dev, unsigned int pipe, | |||
859 | vtotal /= 2; | 860 | vtotal /= 2; |
860 | } | 861 | } |
861 | 862 | ||
862 | ret |= DRM_SCANOUTPOS_VALID | DRM_SCANOUTPOS_ACCURATE; | ||
863 | |||
864 | /* | 863 | /* |
865 | * Lock uncore.lock, as we will do multiple timing critical raw | 864 | * Lock uncore.lock, as we will do multiple timing critical raw |
866 | * register reads, potentially with preemption disabled, so the | 865 | * register reads, potentially with preemption disabled, so the |
@@ -944,11 +943,7 @@ static int i915_get_crtc_scanoutpos(struct drm_device *dev, unsigned int pipe, | |||
944 | *hpos = position - (*vpos * htotal); | 943 | *hpos = position - (*vpos * htotal); |
945 | } | 944 | } |
946 | 945 | ||
947 | /* In vblank? */ | 946 | return true; |
948 | if (in_vbl) | ||
949 | ret |= DRM_SCANOUTPOS_IN_VBLANK; | ||
950 | |||
951 | return ret; | ||
952 | } | 947 | } |
953 | 948 | ||
954 | int intel_get_crtc_scanline(struct intel_crtc *crtc) | 949 | int intel_get_crtc_scanline(struct intel_crtc *crtc) |
@@ -964,37 +959,6 @@ int intel_get_crtc_scanline(struct intel_crtc *crtc) | |||
964 | return position; | 959 | return position; |
965 | } | 960 | } |
966 | 961 | ||
967 | static int i915_get_vblank_timestamp(struct drm_device *dev, unsigned int pipe, | ||
968 | int *max_error, | ||
969 | struct timeval *vblank_time, | ||
970 | unsigned flags) | ||
971 | { | ||
972 | struct drm_i915_private *dev_priv = to_i915(dev); | ||
973 | struct intel_crtc *crtc; | ||
974 | |||
975 | if (pipe >= INTEL_INFO(dev_priv)->num_pipes) { | ||
976 | DRM_ERROR("Invalid crtc %u\n", pipe); | ||
977 | return -EINVAL; | ||
978 | } | ||
979 | |||
980 | /* Get drm_crtc to timestamp: */ | ||
981 | crtc = intel_get_crtc_for_pipe(dev_priv, pipe); | ||
982 | if (crtc == NULL) { | ||
983 | DRM_ERROR("Invalid crtc %u\n", pipe); | ||
984 | return -EINVAL; | ||
985 | } | ||
986 | |||
987 | if (!crtc->base.hwmode.crtc_clock) { | ||
988 | DRM_DEBUG_KMS("crtc %u is disabled\n", pipe); | ||
989 | return -EBUSY; | ||
990 | } | ||
991 | |||
992 | /* Helper routine in DRM core does all the work: */ | ||
993 | return drm_calc_vbltimestamp_from_scanoutpos(dev, pipe, max_error, | ||
994 | vblank_time, flags, | ||
995 | &crtc->base.hwmode); | ||
996 | } | ||
997 | |||
998 | static void ironlake_rps_change_irq_handler(struct drm_i915_private *dev_priv) | 962 | static void ironlake_rps_change_irq_handler(struct drm_i915_private *dev_priv) |
999 | { | 963 | { |
1000 | u32 busy_up, busy_down, max_avg, min_avg; | 964 | u32 busy_up, busy_down, max_avg, min_avg; |
@@ -4294,7 +4258,7 @@ void intel_irq_init(struct drm_i915_private *dev_priv) | |||
4294 | 4258 | ||
4295 | dev_priv->hotplug.hpd_storm_threshold = HPD_STORM_DEFAULT_THRESHOLD; | 4259 | dev_priv->hotplug.hpd_storm_threshold = HPD_STORM_DEFAULT_THRESHOLD; |
4296 | 4260 | ||
4297 | dev->driver->get_vblank_timestamp = i915_get_vblank_timestamp; | 4261 | dev->driver->get_vblank_timestamp = drm_calc_vbltimestamp_from_scanoutpos; |
4298 | dev->driver->get_scanout_position = i915_get_crtc_scanoutpos; | 4262 | dev->driver->get_scanout_position = i915_get_crtc_scanoutpos; |
4299 | 4263 | ||
4300 | if (IS_CHERRYVIEW(dev_priv)) { | 4264 | if (IS_CHERRYVIEW(dev_priv)) { |
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 3617927af269..2f2bb623cf5f 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c | |||
@@ -11444,12 +11444,6 @@ intel_modeset_update_crtc_state(struct drm_atomic_state *state) | |||
11444 | for_each_new_crtc_in_state(state, crtc, new_crtc_state, i) { | 11444 | for_each_new_crtc_in_state(state, crtc, new_crtc_state, i) { |
11445 | to_intel_crtc(crtc)->config = to_intel_crtc_state(new_crtc_state); | 11445 | to_intel_crtc(crtc)->config = to_intel_crtc_state(new_crtc_state); |
11446 | 11446 | ||
11447 | /* Update hwmode for vblank functions */ | ||
11448 | if (new_crtc_state->active) | ||
11449 | crtc->hwmode = new_crtc_state->adjusted_mode; | ||
11450 | else | ||
11451 | crtc->hwmode.crtc_clock = 0; | ||
11452 | |||
11453 | /* | 11447 | /* |
11454 | * Update legacy state to satisfy fbc code. This can | 11448 | * Update legacy state to satisfy fbc code. This can |
11455 | * be removed when fbc uses the atomic state. | 11449 | * be removed when fbc uses the atomic state. |
@@ -15425,8 +15419,6 @@ static void intel_modeset_readout_hw_state(struct drm_device *dev) | |||
15425 | to_intel_crtc_state(crtc->base.state); | 15419 | to_intel_crtc_state(crtc->base.state); |
15426 | int pixclk = 0; | 15420 | int pixclk = 0; |
15427 | 15421 | ||
15428 | crtc->base.hwmode = crtc_state->base.adjusted_mode; | ||
15429 | |||
15430 | memset(&crtc->base.mode, 0, sizeof(crtc->base.mode)); | 15422 | memset(&crtc->base.mode, 0, sizeof(crtc->base.mode)); |
15431 | if (crtc_state->base.active) { | 15423 | if (crtc_state->base.active) { |
15432 | intel_mode_from_pipe_config(&crtc->base.mode, crtc_state); | 15424 | intel_mode_from_pipe_config(&crtc->base.mode, crtc_state); |
@@ -15456,7 +15448,8 @@ static void intel_modeset_readout_hw_state(struct drm_device *dev) | |||
15456 | if (IS_BROADWELL(dev_priv) && crtc_state->ips_enabled) | 15448 | if (IS_BROADWELL(dev_priv) && crtc_state->ips_enabled) |
15457 | pixclk = DIV_ROUND_UP(pixclk * 100, 95); | 15449 | pixclk = DIV_ROUND_UP(pixclk * 100, 95); |
15458 | 15450 | ||
15459 | drm_calc_timestamping_constants(&crtc->base, &crtc->base.hwmode); | 15451 | drm_calc_timestamping_constants(&crtc->base, |
15452 | &crtc_state->base.adjusted_mode); | ||
15460 | update_scanline_offset(crtc); | 15453 | update_scanline_offset(crtc); |
15461 | } | 15454 | } |
15462 | 15455 | ||
diff --git a/drivers/gpu/drm/i915/intel_dp_mst.c b/drivers/gpu/drm/i915/intel_dp_mst.c index c1f62eb07c07..1dee9933005f 100644 --- a/drivers/gpu/drm/i915/intel_dp_mst.c +++ b/drivers/gpu/drm/i915/intel_dp_mst.c | |||
@@ -39,7 +39,7 @@ static bool intel_dp_mst_compute_config(struct intel_encoder *encoder, | |||
39 | struct intel_dp *intel_dp = &intel_dig_port->dp; | 39 | struct intel_dp *intel_dp = &intel_dig_port->dp; |
40 | struct intel_connector *connector = | 40 | struct intel_connector *connector = |
41 | to_intel_connector(conn_state->connector); | 41 | to_intel_connector(conn_state->connector); |
42 | struct drm_atomic_state *state; | 42 | struct drm_atomic_state *state = pipe_config->base.state; |
43 | int bpp; | 43 | int bpp; |
44 | int lane_count, slots; | 44 | int lane_count, slots; |
45 | const struct drm_display_mode *adjusted_mode = &pipe_config->base.adjusted_mode; | 45 | const struct drm_display_mode *adjusted_mode = &pipe_config->base.adjusted_mode; |
@@ -57,20 +57,24 @@ static bool intel_dp_mst_compute_config(struct intel_encoder *encoder, | |||
57 | * seem to suggest we should do otherwise. | 57 | * seem to suggest we should do otherwise. |
58 | */ | 58 | */ |
59 | lane_count = drm_dp_max_lane_count(intel_dp->dpcd); | 59 | lane_count = drm_dp_max_lane_count(intel_dp->dpcd); |
60 | |||
61 | pipe_config->lane_count = lane_count; | 60 | pipe_config->lane_count = lane_count; |
62 | 61 | ||
63 | pipe_config->pipe_bpp = bpp; | 62 | pipe_config->pipe_bpp = bpp; |
64 | pipe_config->port_clock = intel_dp_max_link_rate(intel_dp); | ||
65 | 63 | ||
66 | state = pipe_config->base.state; | 64 | pipe_config->port_clock = intel_dp_max_link_rate(intel_dp); |
67 | 65 | ||
68 | if (drm_dp_mst_port_has_audio(&intel_dp->mst_mgr, connector->port)) | 66 | if (drm_dp_mst_port_has_audio(&intel_dp->mst_mgr, connector->port)) |
69 | pipe_config->has_audio = true; | 67 | pipe_config->has_audio = true; |
70 | mst_pbn = drm_dp_calc_pbn_mode(adjusted_mode->crtc_clock, bpp); | ||
71 | 68 | ||
69 | mst_pbn = drm_dp_calc_pbn_mode(adjusted_mode->crtc_clock, bpp); | ||
72 | pipe_config->pbn = mst_pbn; | 70 | pipe_config->pbn = mst_pbn; |
73 | slots = drm_dp_find_vcpi_slots(&intel_dp->mst_mgr, mst_pbn); | 71 | |
72 | slots = drm_dp_atomic_find_vcpi_slots(state, &intel_dp->mst_mgr, | ||
73 | connector->port, mst_pbn); | ||
74 | if (slots < 0) { | ||
75 | DRM_DEBUG_KMS("failed finding vcpi slots:%d\n", slots); | ||
76 | return false; | ||
77 | } | ||
74 | 78 | ||
75 | intel_link_compute_m_n(bpp, lane_count, | 79 | intel_link_compute_m_n(bpp, lane_count, |
76 | adjusted_mode->crtc_clock, | 80 | adjusted_mode->crtc_clock, |
@@ -80,7 +84,38 @@ static bool intel_dp_mst_compute_config(struct intel_encoder *encoder, | |||
80 | pipe_config->dp_m_n.tu = slots; | 84 | pipe_config->dp_m_n.tu = slots; |
81 | 85 | ||
82 | return true; | 86 | return true; |
87 | } | ||
83 | 88 | ||
89 | static int intel_dp_mst_atomic_check(struct drm_connector *connector, | ||
90 | struct drm_connector_state *new_conn_state) | ||
91 | { | ||
92 | struct drm_atomic_state *state = new_conn_state->state; | ||
93 | struct drm_connector_state *old_conn_state; | ||
94 | struct drm_crtc *old_crtc; | ||
95 | struct drm_crtc_state *crtc_state; | ||
96 | int slots, ret = 0; | ||
97 | |||
98 | old_conn_state = drm_atomic_get_old_connector_state(state, connector); | ||
99 | old_crtc = old_conn_state->crtc; | ||
100 | if (!old_crtc) | ||
101 | return ret; | ||
102 | |||
103 | crtc_state = drm_atomic_get_new_crtc_state(state, old_crtc); | ||
104 | slots = to_intel_crtc_state(crtc_state)->dp_m_n.tu; | ||
105 | if (drm_atomic_crtc_needs_modeset(crtc_state) && slots > 0) { | ||
106 | struct drm_dp_mst_topology_mgr *mgr; | ||
107 | struct drm_encoder *old_encoder; | ||
108 | |||
109 | old_encoder = old_conn_state->best_encoder; | ||
110 | mgr = &enc_to_mst(old_encoder)->primary->dp.mst_mgr; | ||
111 | |||
112 | ret = drm_dp_atomic_release_vcpi_slots(state, mgr, slots); | ||
113 | if (ret) | ||
114 | DRM_DEBUG_KMS("failed releasing %d vcpi slots:%d\n", slots, ret); | ||
115 | else | ||
116 | to_intel_crtc_state(crtc_state)->dp_m_n.tu = 0; | ||
117 | } | ||
118 | return ret; | ||
84 | } | 119 | } |
85 | 120 | ||
86 | static void intel_mst_disable_dp(struct intel_encoder *encoder, | 121 | static void intel_mst_disable_dp(struct intel_encoder *encoder, |
@@ -387,6 +422,7 @@ static const struct drm_connector_helper_funcs intel_dp_mst_connector_helper_fun | |||
387 | .mode_valid = intel_dp_mst_mode_valid, | 422 | .mode_valid = intel_dp_mst_mode_valid, |
388 | .atomic_best_encoder = intel_mst_atomic_best_encoder, | 423 | .atomic_best_encoder = intel_mst_atomic_best_encoder, |
389 | .best_encoder = intel_mst_best_encoder, | 424 | .best_encoder = intel_mst_best_encoder, |
425 | .atomic_check = intel_dp_mst_atomic_check, | ||
390 | }; | 426 | }; |
391 | 427 | ||
392 | static void intel_dp_mst_encoder_destroy(struct drm_encoder *encoder) | 428 | static void intel_dp_mst_encoder_destroy(struct drm_encoder *encoder) |
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index aaee3949a422..48ea8d9d49fe 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h | |||
@@ -869,7 +869,6 @@ struct intel_hdmi { | |||
869 | bool has_audio; | 869 | bool has_audio; |
870 | enum hdmi_force_audio force_audio; | 870 | enum hdmi_force_audio force_audio; |
871 | bool rgb_quant_range_selectable; | 871 | bool rgb_quant_range_selectable; |
872 | enum hdmi_picture_aspect aspect_ratio; | ||
873 | struct intel_connector *attached_connector; | 872 | struct intel_connector *attached_connector; |
874 | void (*write_infoframe)(struct drm_encoder *encoder, | 873 | void (*write_infoframe)(struct drm_encoder *encoder, |
875 | const struct intel_crtc_state *crtc_state, | 874 | const struct intel_crtc_state *crtc_state, |
diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c index 1d623b5e09d6..c6b8207724fa 100644 --- a/drivers/gpu/drm/i915/intel_hdmi.c +++ b/drivers/gpu/drm/i915/intel_hdmi.c | |||
@@ -1403,7 +1403,7 @@ bool intel_hdmi_compute_config(struct intel_encoder *encoder, | |||
1403 | } | 1403 | } |
1404 | 1404 | ||
1405 | /* Set user selected PAR to incoming mode's member */ | 1405 | /* Set user selected PAR to incoming mode's member */ |
1406 | adjusted_mode->picture_aspect_ratio = intel_hdmi->aspect_ratio; | 1406 | adjusted_mode->picture_aspect_ratio = conn_state->picture_aspect_ratio; |
1407 | 1407 | ||
1408 | pipe_config->lane_count = 4; | 1408 | pipe_config->lane_count = 4; |
1409 | 1409 | ||
@@ -1649,19 +1649,7 @@ intel_hdmi_set_property(struct drm_connector *connector, | |||
1649 | } | 1649 | } |
1650 | 1650 | ||
1651 | if (property == connector->dev->mode_config.aspect_ratio_property) { | 1651 | if (property == connector->dev->mode_config.aspect_ratio_property) { |
1652 | switch (val) { | 1652 | connector->state->picture_aspect_ratio = val; |
1653 | case DRM_MODE_PICTURE_ASPECT_NONE: | ||
1654 | intel_hdmi->aspect_ratio = HDMI_PICTURE_ASPECT_NONE; | ||
1655 | break; | ||
1656 | case DRM_MODE_PICTURE_ASPECT_4_3: | ||
1657 | intel_hdmi->aspect_ratio = HDMI_PICTURE_ASPECT_4_3; | ||
1658 | break; | ||
1659 | case DRM_MODE_PICTURE_ASPECT_16_9: | ||
1660 | intel_hdmi->aspect_ratio = HDMI_PICTURE_ASPECT_16_9; | ||
1661 | break; | ||
1662 | default: | ||
1663 | return -EINVAL; | ||
1664 | } | ||
1665 | goto done; | 1653 | goto done; |
1666 | } | 1654 | } |
1667 | 1655 | ||
@@ -1823,7 +1811,7 @@ intel_hdmi_add_properties(struct intel_hdmi *intel_hdmi, struct drm_connector *c | |||
1823 | intel_attach_broadcast_rgb_property(connector); | 1811 | intel_attach_broadcast_rgb_property(connector); |
1824 | intel_hdmi->color_range_auto = true; | 1812 | intel_hdmi->color_range_auto = true; |
1825 | intel_attach_aspect_ratio_property(connector); | 1813 | intel_attach_aspect_ratio_property(connector); |
1826 | intel_hdmi->aspect_ratio = HDMI_PICTURE_ASPECT_NONE; | 1814 | connector->state->picture_aspect_ratio = HDMI_PICTURE_ASPECT_NONE; |
1827 | } | 1815 | } |
1828 | 1816 | ||
1829 | /* | 1817 | /* |
diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c index 816a6f5a3fd9..ef6fa87b2f8a 100644 --- a/drivers/gpu/drm/i915/intel_sdvo.c +++ b/drivers/gpu/drm/i915/intel_sdvo.c | |||
@@ -107,11 +107,6 @@ struct intel_sdvo { | |||
107 | bool color_range_auto; | 107 | bool color_range_auto; |
108 | 108 | ||
109 | /** | 109 | /** |
110 | * HDMI user specified aspect ratio | ||
111 | */ | ||
112 | enum hdmi_picture_aspect aspect_ratio; | ||
113 | |||
114 | /** | ||
115 | * This is set if we're going to treat the device as TV-out. | 110 | * This is set if we're going to treat the device as TV-out. |
116 | * | 111 | * |
117 | * While we have these nice friendly flags for output types that ought | 112 | * While we have these nice friendly flags for output types that ought |
@@ -1186,7 +1181,7 @@ static bool intel_sdvo_compute_config(struct intel_encoder *encoder, | |||
1186 | 1181 | ||
1187 | /* Set user selected PAR to incoming mode's member */ | 1182 | /* Set user selected PAR to incoming mode's member */ |
1188 | if (intel_sdvo->is_hdmi) | 1183 | if (intel_sdvo->is_hdmi) |
1189 | adjusted_mode->picture_aspect_ratio = intel_sdvo->aspect_ratio; | 1184 | adjusted_mode->picture_aspect_ratio = conn_state->picture_aspect_ratio; |
1190 | 1185 | ||
1191 | return true; | 1186 | return true; |
1192 | } | 1187 | } |
@@ -2067,19 +2062,7 @@ intel_sdvo_set_property(struct drm_connector *connector, | |||
2067 | } | 2062 | } |
2068 | 2063 | ||
2069 | if (property == connector->dev->mode_config.aspect_ratio_property) { | 2064 | if (property == connector->dev->mode_config.aspect_ratio_property) { |
2070 | switch (val) { | 2065 | connector->state->picture_aspect_ratio = val; |
2071 | case DRM_MODE_PICTURE_ASPECT_NONE: | ||
2072 | intel_sdvo->aspect_ratio = HDMI_PICTURE_ASPECT_NONE; | ||
2073 | break; | ||
2074 | case DRM_MODE_PICTURE_ASPECT_4_3: | ||
2075 | intel_sdvo->aspect_ratio = HDMI_PICTURE_ASPECT_4_3; | ||
2076 | break; | ||
2077 | case DRM_MODE_PICTURE_ASPECT_16_9: | ||
2078 | intel_sdvo->aspect_ratio = HDMI_PICTURE_ASPECT_16_9; | ||
2079 | break; | ||
2080 | default: | ||
2081 | return -EINVAL; | ||
2082 | } | ||
2083 | goto done; | 2066 | goto done; |
2084 | } | 2067 | } |
2085 | 2068 | ||
@@ -2418,7 +2401,7 @@ intel_sdvo_add_hdmi_properties(struct intel_sdvo *intel_sdvo, | |||
2418 | intel_sdvo->color_range_auto = true; | 2401 | intel_sdvo->color_range_auto = true; |
2419 | } | 2402 | } |
2420 | intel_attach_aspect_ratio_property(&connector->base.base); | 2403 | intel_attach_aspect_ratio_property(&connector->base.base); |
2421 | intel_sdvo->aspect_ratio = HDMI_PICTURE_ASPECT_NONE; | 2404 | connector->base.base.state->picture_aspect_ratio = HDMI_PICTURE_ASPECT_NONE; |
2422 | } | 2405 | } |
2423 | 2406 | ||
2424 | static struct intel_sdvo_connector *intel_sdvo_connector_alloc(void) | 2407 | static struct intel_sdvo_connector *intel_sdvo_connector_alloc(void) |
diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c index d3d6b4cae1e6..e2b3346ead48 100644 --- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c +++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c | |||
@@ -527,31 +527,28 @@ static struct drm_encoder *get_encoder_from_crtc(struct drm_crtc *crtc) | |||
527 | return NULL; | 527 | return NULL; |
528 | } | 528 | } |
529 | 529 | ||
530 | static int mdp5_get_scanoutpos(struct drm_device *dev, unsigned int pipe, | 530 | static bool mdp5_get_scanoutpos(struct drm_device *dev, unsigned int pipe, |
531 | unsigned int flags, int *vpos, int *hpos, | 531 | bool in_vblank_irq, int *vpos, int *hpos, |
532 | ktime_t *stime, ktime_t *etime, | 532 | ktime_t *stime, ktime_t *etime, |
533 | const struct drm_display_mode *mode) | 533 | const struct drm_display_mode *mode) |
534 | { | 534 | { |
535 | struct msm_drm_private *priv = dev->dev_private; | 535 | struct msm_drm_private *priv = dev->dev_private; |
536 | struct drm_crtc *crtc; | 536 | struct drm_crtc *crtc; |
537 | struct drm_encoder *encoder; | 537 | struct drm_encoder *encoder; |
538 | int line, vsw, vbp, vactive_start, vactive_end, vfp_end; | 538 | int line, vsw, vbp, vactive_start, vactive_end, vfp_end; |
539 | int ret = 0; | ||
540 | 539 | ||
541 | crtc = priv->crtcs[pipe]; | 540 | crtc = priv->crtcs[pipe]; |
542 | if (!crtc) { | 541 | if (!crtc) { |
543 | DRM_ERROR("Invalid crtc %d\n", pipe); | 542 | DRM_ERROR("Invalid crtc %d\n", pipe); |
544 | return 0; | 543 | return false; |
545 | } | 544 | } |
546 | 545 | ||
547 | encoder = get_encoder_from_crtc(crtc); | 546 | encoder = get_encoder_from_crtc(crtc); |
548 | if (!encoder) { | 547 | if (!encoder) { |
549 | DRM_ERROR("no encoder found for crtc %d\n", pipe); | 548 | DRM_ERROR("no encoder found for crtc %d\n", pipe); |
550 | return 0; | 549 | return false; |
551 | } | 550 | } |
552 | 551 | ||
553 | ret |= DRM_SCANOUTPOS_VALID | DRM_SCANOUTPOS_ACCURATE; | ||
554 | |||
555 | vsw = mode->crtc_vsync_end - mode->crtc_vsync_start; | 552 | vsw = mode->crtc_vsync_end - mode->crtc_vsync_start; |
556 | vbp = mode->crtc_vtotal - mode->crtc_vsync_end; | 553 | vbp = mode->crtc_vtotal - mode->crtc_vsync_end; |
557 | 554 | ||
@@ -575,10 +572,8 @@ static int mdp5_get_scanoutpos(struct drm_device *dev, unsigned int pipe, | |||
575 | 572 | ||
576 | if (line < vactive_start) { | 573 | if (line < vactive_start) { |
577 | line -= vactive_start; | 574 | line -= vactive_start; |
578 | ret |= DRM_SCANOUTPOS_IN_VBLANK; | ||
579 | } else if (line > vactive_end) { | 575 | } else if (line > vactive_end) { |
580 | line = line - vfp_end - vactive_start; | 576 | line = line - vfp_end - vactive_start; |
581 | ret |= DRM_SCANOUTPOS_IN_VBLANK; | ||
582 | } else { | 577 | } else { |
583 | line -= vactive_start; | 578 | line -= vactive_start; |
584 | } | 579 | } |
@@ -589,31 +584,7 @@ static int mdp5_get_scanoutpos(struct drm_device *dev, unsigned int pipe, | |||
589 | if (etime) | 584 | if (etime) |
590 | *etime = ktime_get(); | 585 | *etime = ktime_get(); |
591 | 586 | ||
592 | return ret; | 587 | return true; |
593 | } | ||
594 | |||
595 | static int mdp5_get_vblank_timestamp(struct drm_device *dev, unsigned int pipe, | ||
596 | int *max_error, | ||
597 | struct timeval *vblank_time, | ||
598 | unsigned flags) | ||
599 | { | ||
600 | struct msm_drm_private *priv = dev->dev_private; | ||
601 | struct drm_crtc *crtc; | ||
602 | |||
603 | if (pipe < 0 || pipe >= priv->num_crtcs) { | ||
604 | DRM_ERROR("Invalid crtc %d\n", pipe); | ||
605 | return -EINVAL; | ||
606 | } | ||
607 | |||
608 | crtc = priv->crtcs[pipe]; | ||
609 | if (!crtc) { | ||
610 | DRM_ERROR("Invalid crtc %d\n", pipe); | ||
611 | return -EINVAL; | ||
612 | } | ||
613 | |||
614 | return drm_calc_vbltimestamp_from_scanoutpos(dev, pipe, max_error, | ||
615 | vblank_time, flags, | ||
616 | &crtc->mode); | ||
617 | } | 588 | } |
618 | 589 | ||
619 | static u32 mdp5_get_vblank_counter(struct drm_device *dev, unsigned int pipe) | 590 | static u32 mdp5_get_vblank_counter(struct drm_device *dev, unsigned int pipe) |
@@ -725,7 +696,7 @@ struct msm_kms *mdp5_kms_init(struct drm_device *dev) | |||
725 | dev->mode_config.max_width = 0xffff; | 696 | dev->mode_config.max_width = 0xffff; |
726 | dev->mode_config.max_height = 0xffff; | 697 | dev->mode_config.max_height = 0xffff; |
727 | 698 | ||
728 | dev->driver->get_vblank_timestamp = mdp5_get_vblank_timestamp; | 699 | dev->driver->get_vblank_timestamp = drm_calc_vbltimestamp_from_scanoutpos; |
729 | dev->driver->get_scanout_position = mdp5_get_scanoutpos; | 700 | dev->driver->get_scanout_position = mdp5_get_scanoutpos; |
730 | dev->driver->get_vblank_counter = mdp5_get_vblank_counter; | 701 | dev->driver->get_vblank_counter = mdp5_get_vblank_counter; |
731 | dev->max_vblank_count = 0xffffffff; | 702 | dev->max_vblank_count = 0xffffffff; |
diff --git a/drivers/gpu/drm/nouveau/nouveau_display.c b/drivers/gpu/drm/nouveau/nouveau_display.c index 21b10f9840c9..6718c84fb862 100644 --- a/drivers/gpu/drm/nouveau/nouveau_display.c +++ b/drivers/gpu/drm/nouveau/nouveau_display.c | |||
@@ -98,7 +98,7 @@ calc(int blanks, int blanke, int total, int line) | |||
98 | return line; | 98 | return line; |
99 | } | 99 | } |
100 | 100 | ||
101 | static int | 101 | static bool |
102 | nouveau_display_scanoutpos_head(struct drm_crtc *crtc, int *vpos, int *hpos, | 102 | nouveau_display_scanoutpos_head(struct drm_crtc *crtc, int *vpos, int *hpos, |
103 | ktime_t *stime, ktime_t *etime) | 103 | ktime_t *stime, ktime_t *etime) |
104 | { | 104 | { |
@@ -111,16 +111,16 @@ nouveau_display_scanoutpos_head(struct drm_crtc *crtc, int *vpos, int *hpos, | |||
111 | }; | 111 | }; |
112 | struct nouveau_display *disp = nouveau_display(crtc->dev); | 112 | struct nouveau_display *disp = nouveau_display(crtc->dev); |
113 | struct drm_vblank_crtc *vblank = &crtc->dev->vblank[drm_crtc_index(crtc)]; | 113 | struct drm_vblank_crtc *vblank = &crtc->dev->vblank[drm_crtc_index(crtc)]; |
114 | int ret, retry = 20; | 114 | int retry = 20; |
115 | bool ret = false; | ||
115 | 116 | ||
116 | do { | 117 | do { |
117 | ret = nvif_mthd(&disp->disp, 0, &args, sizeof(args)); | 118 | ret = nvif_mthd(&disp->disp, 0, &args, sizeof(args)); |
118 | if (ret != 0) | 119 | if (ret != 0) |
119 | return 0; | 120 | return false; |
120 | 121 | ||
121 | if (args.scan.vline) { | 122 | if (args.scan.vline) { |
122 | ret |= DRM_SCANOUTPOS_ACCURATE; | 123 | ret = true; |
123 | ret |= DRM_SCANOUTPOS_VALID; | ||
124 | break; | 124 | break; |
125 | } | 125 | } |
126 | 126 | ||
@@ -133,14 +133,12 @@ nouveau_display_scanoutpos_head(struct drm_crtc *crtc, int *vpos, int *hpos, | |||
133 | if (stime) *stime = ns_to_ktime(args.scan.time[0]); | 133 | if (stime) *stime = ns_to_ktime(args.scan.time[0]); |
134 | if (etime) *etime = ns_to_ktime(args.scan.time[1]); | 134 | if (etime) *etime = ns_to_ktime(args.scan.time[1]); |
135 | 135 | ||
136 | if (*vpos < 0) | ||
137 | ret |= DRM_SCANOUTPOS_IN_VBLANK; | ||
138 | return ret; | 136 | return ret; |
139 | } | 137 | } |
140 | 138 | ||
141 | int | 139 | bool |
142 | nouveau_display_scanoutpos(struct drm_device *dev, unsigned int pipe, | 140 | nouveau_display_scanoutpos(struct drm_device *dev, unsigned int pipe, |
143 | unsigned int flags, int *vpos, int *hpos, | 141 | bool in_vblank_irq, int *vpos, int *hpos, |
144 | ktime_t *stime, ktime_t *etime, | 142 | ktime_t *stime, ktime_t *etime, |
145 | const struct drm_display_mode *mode) | 143 | const struct drm_display_mode *mode) |
146 | { | 144 | { |
@@ -153,28 +151,7 @@ nouveau_display_scanoutpos(struct drm_device *dev, unsigned int pipe, | |||
153 | } | 151 | } |
154 | } | 152 | } |
155 | 153 | ||
156 | return 0; | 154 | return false; |
157 | } | ||
158 | |||
159 | int | ||
160 | nouveau_display_vblstamp(struct drm_device *dev, unsigned int pipe, | ||
161 | int *max_error, struct timeval *time, unsigned flags) | ||
162 | { | ||
163 | struct drm_crtc *crtc; | ||
164 | |||
165 | list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { | ||
166 | if (nouveau_crtc(crtc)->index == pipe) { | ||
167 | struct drm_display_mode *mode; | ||
168 | if (drm_drv_uses_atomic_modeset(dev)) | ||
169 | mode = &crtc->state->adjusted_mode; | ||
170 | else | ||
171 | mode = &crtc->hwmode; | ||
172 | return drm_calc_vbltimestamp_from_scanoutpos(dev, | ||
173 | pipe, max_error, time, flags, mode); | ||
174 | } | ||
175 | } | ||
176 | |||
177 | return -EINVAL; | ||
178 | } | 155 | } |
179 | 156 | ||
180 | static void | 157 | static void |
diff --git a/drivers/gpu/drm/nouveau/nouveau_display.h b/drivers/gpu/drm/nouveau/nouveau_display.h index e1d772d39488..201aec2ea5b8 100644 --- a/drivers/gpu/drm/nouveau/nouveau_display.h +++ b/drivers/gpu/drm/nouveau/nouveau_display.h | |||
@@ -68,11 +68,9 @@ int nouveau_display_suspend(struct drm_device *dev, bool runtime); | |||
68 | void nouveau_display_resume(struct drm_device *dev, bool runtime); | 68 | void nouveau_display_resume(struct drm_device *dev, bool runtime); |
69 | int nouveau_display_vblank_enable(struct drm_device *, unsigned int); | 69 | int nouveau_display_vblank_enable(struct drm_device *, unsigned int); |
70 | void nouveau_display_vblank_disable(struct drm_device *, unsigned int); | 70 | void nouveau_display_vblank_disable(struct drm_device *, unsigned int); |
71 | int nouveau_display_scanoutpos(struct drm_device *, unsigned int, | 71 | bool nouveau_display_scanoutpos(struct drm_device *, unsigned int, |
72 | unsigned int, int *, int *, ktime_t *, | 72 | bool, int *, int *, ktime_t *, |
73 | ktime_t *, const struct drm_display_mode *); | 73 | ktime_t *, const struct drm_display_mode *); |
74 | int nouveau_display_vblstamp(struct drm_device *, unsigned int, int *, | ||
75 | struct timeval *, unsigned); | ||
76 | 74 | ||
77 | int nouveau_crtc_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb, | 75 | int nouveau_crtc_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb, |
78 | struct drm_pending_vblank_event *event, | 76 | struct drm_pending_vblank_event *event, |
diff --git a/drivers/gpu/drm/nouveau/nouveau_drm.c b/drivers/gpu/drm/nouveau/nouveau_drm.c index 2b6ac24ce690..1f751a3f570c 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drm.c +++ b/drivers/gpu/drm/nouveau/nouveau_drm.c | |||
@@ -881,7 +881,7 @@ done: | |||
881 | } | 881 | } |
882 | 882 | ||
883 | static void | 883 | static void |
884 | nouveau_drm_preclose(struct drm_device *dev, struct drm_file *fpriv) | 884 | nouveau_drm_postclose(struct drm_device *dev, struct drm_file *fpriv) |
885 | { | 885 | { |
886 | struct nouveau_cli *cli = nouveau_cli(fpriv); | 886 | struct nouveau_cli *cli = nouveau_cli(fpriv); |
887 | struct nouveau_drm *drm = nouveau_drm(dev); | 887 | struct nouveau_drm *drm = nouveau_drm(dev); |
@@ -897,12 +897,6 @@ nouveau_drm_preclose(struct drm_device *dev, struct drm_file *fpriv) | |||
897 | list_del(&cli->head); | 897 | list_del(&cli->head); |
898 | mutex_unlock(&drm->client.mutex); | 898 | mutex_unlock(&drm->client.mutex); |
899 | 899 | ||
900 | } | ||
901 | |||
902 | static void | ||
903 | nouveau_drm_postclose(struct drm_device *dev, struct drm_file *fpriv) | ||
904 | { | ||
905 | struct nouveau_cli *cli = nouveau_cli(fpriv); | ||
906 | nouveau_cli_fini(cli); | 900 | nouveau_cli_fini(cli); |
907 | kfree(cli); | 901 | kfree(cli); |
908 | pm_runtime_mark_last_busy(dev->dev); | 902 | pm_runtime_mark_last_busy(dev->dev); |
@@ -974,7 +968,6 @@ driver_stub = { | |||
974 | .load = nouveau_drm_load, | 968 | .load = nouveau_drm_load, |
975 | .unload = nouveau_drm_unload, | 969 | .unload = nouveau_drm_unload, |
976 | .open = nouveau_drm_open, | 970 | .open = nouveau_drm_open, |
977 | .preclose = nouveau_drm_preclose, | ||
978 | .postclose = nouveau_drm_postclose, | 971 | .postclose = nouveau_drm_postclose, |
979 | .lastclose = nouveau_vga_lastclose, | 972 | .lastclose = nouveau_vga_lastclose, |
980 | 973 | ||
@@ -985,7 +978,7 @@ driver_stub = { | |||
985 | .enable_vblank = nouveau_display_vblank_enable, | 978 | .enable_vblank = nouveau_display_vblank_enable, |
986 | .disable_vblank = nouveau_display_vblank_disable, | 979 | .disable_vblank = nouveau_display_vblank_disable, |
987 | .get_scanout_position = nouveau_display_scanoutpos, | 980 | .get_scanout_position = nouveau_display_scanoutpos, |
988 | .get_vblank_timestamp = nouveau_display_vblstamp, | 981 | .get_vblank_timestamp = drm_calc_vbltimestamp_from_scanoutpos, |
989 | 982 | ||
990 | .ioctls = nouveau_ioctls, | 983 | .ioctls = nouveau_ioctls, |
991 | .num_ioctls = ARRAY_SIZE(nouveau_ioctls), | 984 | .num_ioctls = ARRAY_SIZE(nouveau_ioctls), |
diff --git a/drivers/gpu/drm/pl111/Kconfig b/drivers/gpu/drm/pl111/Kconfig new file mode 100644 index 000000000000..ede49efd531f --- /dev/null +++ b/drivers/gpu/drm/pl111/Kconfig | |||
@@ -0,0 +1,12 @@ | |||
1 | config DRM_PL111 | ||
2 | tristate "DRM Support for PL111 CLCD Controller" | ||
3 | depends on DRM | ||
4 | depends on ARM || ARM64 || COMPILE_TEST | ||
5 | select DRM_KMS_HELPER | ||
6 | select DRM_KMS_CMA_HELPER | ||
7 | select DRM_GEM_CMA_HELPER | ||
8 | select VT_HW_CONSOLE_BINDING if FRAMEBUFFER_CONSOLE | ||
9 | help | ||
10 | Choose this option for DRM support for the PL111 CLCD controller. | ||
11 | If M is selected the module will be called pl111_drm. | ||
12 | |||
diff --git a/drivers/gpu/drm/pl111/Makefile b/drivers/gpu/drm/pl111/Makefile new file mode 100644 index 000000000000..01caee727c13 --- /dev/null +++ b/drivers/gpu/drm/pl111/Makefile | |||
@@ -0,0 +1,5 @@ | |||
1 | pl111_drm-y += pl111_connector.o \ | ||
2 | pl111_display.o \ | ||
3 | pl111_drv.o | ||
4 | |||
5 | obj-$(CONFIG_DRM_PL111) += pl111_drm.o | ||
diff --git a/drivers/gpu/drm/pl111/pl111_connector.c b/drivers/gpu/drm/pl111/pl111_connector.c new file mode 100644 index 000000000000..3f213d7e7692 --- /dev/null +++ b/drivers/gpu/drm/pl111/pl111_connector.c | |||
@@ -0,0 +1,127 @@ | |||
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 | .dpms = drm_atomic_helper_connector_dpms, | ||
73 | .reset = drm_atomic_helper_connector_reset, | ||
74 | .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, | ||
75 | .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, | ||
76 | }; | ||
77 | |||
78 | const struct drm_connector_helper_funcs connector_helper_funcs = { | ||
79 | .get_modes = pl111_connector_helper_get_modes, | ||
80 | }; | ||
81 | |||
82 | /* Walks the OF graph to find the panel node and then asks DRM to look | ||
83 | * up the panel. | ||
84 | */ | ||
85 | static struct drm_panel *pl111_get_panel(struct device *dev) | ||
86 | { | ||
87 | struct device_node *endpoint, *panel_node; | ||
88 | struct device_node *np = dev->of_node; | ||
89 | struct drm_panel *panel; | ||
90 | |||
91 | endpoint = of_graph_get_next_endpoint(np, NULL); | ||
92 | if (!endpoint) { | ||
93 | dev_err(dev, "no endpoint to fetch panel\n"); | ||
94 | return NULL; | ||
95 | } | ||
96 | |||
97 | /* don't proceed if we have an endpoint but no panel_node tied to it */ | ||
98 | panel_node = of_graph_get_remote_port_parent(endpoint); | ||
99 | of_node_put(endpoint); | ||
100 | if (!panel_node) { | ||
101 | dev_err(dev, "no valid panel node\n"); | ||
102 | return NULL; | ||
103 | } | ||
104 | |||
105 | panel = of_drm_find_panel(panel_node); | ||
106 | of_node_put(panel_node); | ||
107 | |||
108 | return panel; | ||
109 | } | ||
110 | |||
111 | int pl111_connector_init(struct drm_device *dev) | ||
112 | { | ||
113 | struct pl111_drm_dev_private *priv = dev->dev_private; | ||
114 | struct pl111_drm_connector *pl111_connector = &priv->connector; | ||
115 | struct drm_connector *connector = &pl111_connector->connector; | ||
116 | |||
117 | drm_connector_init(dev, connector, &connector_funcs, | ||
118 | DRM_MODE_CONNECTOR_DPI); | ||
119 | drm_connector_helper_add(connector, &connector_helper_funcs); | ||
120 | |||
121 | pl111_connector->panel = pl111_get_panel(dev->dev); | ||
122 | if (pl111_connector->panel) | ||
123 | drm_panel_attach(pl111_connector->panel, connector); | ||
124 | |||
125 | return 0; | ||
126 | } | ||
127 | |||
diff --git a/drivers/gpu/drm/pl111/pl111_display.c b/drivers/gpu/drm/pl111/pl111_display.c new file mode 100644 index 000000000000..39a5c33bce7d --- /dev/null +++ b/drivers/gpu/drm/pl111/pl111_display.c | |||
@@ -0,0 +1,344 @@ | |||
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 | #include <linux/amba/clcd-regs.h> | ||
18 | #include <linux/clk.h> | ||
19 | #include <linux/version.h> | ||
20 | #include <linux/dma-buf.h> | ||
21 | #include <linux/of_graph.h> | ||
22 | |||
23 | #include <drm/drmP.h> | ||
24 | #include <drm/drm_panel.h> | ||
25 | #include <drm/drm_gem_cma_helper.h> | ||
26 | #include <drm/drm_fb_cma_helper.h> | ||
27 | |||
28 | #include "pl111_drm.h" | ||
29 | |||
30 | irqreturn_t pl111_irq(int irq, void *data) | ||
31 | { | ||
32 | struct pl111_drm_dev_private *priv = data; | ||
33 | u32 irq_stat; | ||
34 | irqreturn_t status = IRQ_NONE; | ||
35 | |||
36 | irq_stat = readl(priv->regs + CLCD_PL111_MIS); | ||
37 | |||
38 | if (!irq_stat) | ||
39 | return IRQ_NONE; | ||
40 | |||
41 | if (irq_stat & CLCD_IRQ_NEXTBASE_UPDATE) { | ||
42 | drm_crtc_handle_vblank(&priv->pipe.crtc); | ||
43 | |||
44 | status = IRQ_HANDLED; | ||
45 | } | ||
46 | |||
47 | /* Clear the interrupt once done */ | ||
48 | writel(irq_stat, priv->regs + CLCD_PL111_ICR); | ||
49 | |||
50 | return status; | ||
51 | } | ||
52 | |||
53 | static u32 pl111_get_fb_offset(struct drm_plane_state *pstate) | ||
54 | { | ||
55 | struct drm_framebuffer *fb = pstate->fb; | ||
56 | struct drm_gem_cma_object *obj = drm_fb_cma_get_gem_obj(fb, 0); | ||
57 | |||
58 | return (obj->paddr + | ||
59 | fb->offsets[0] + | ||
60 | fb->format->cpp[0] * pstate->src_x + | ||
61 | fb->pitches[0] * pstate->src_y); | ||
62 | } | ||
63 | |||
64 | static int pl111_display_check(struct drm_simple_display_pipe *pipe, | ||
65 | struct drm_plane_state *pstate, | ||
66 | struct drm_crtc_state *cstate) | ||
67 | { | ||
68 | const struct drm_display_mode *mode = &cstate->mode; | ||
69 | struct drm_framebuffer *old_fb = pipe->plane.state->fb; | ||
70 | struct drm_framebuffer *fb = pstate->fb; | ||
71 | |||
72 | if (mode->hdisplay % 16) | ||
73 | return -EINVAL; | ||
74 | |||
75 | if (fb) { | ||
76 | u32 offset = pl111_get_fb_offset(pstate); | ||
77 | |||
78 | /* FB base address must be dword aligned. */ | ||
79 | if (offset & 3) | ||
80 | return -EINVAL; | ||
81 | |||
82 | /* There's no pitch register -- the mode's hdisplay | ||
83 | * controls it. | ||
84 | */ | ||
85 | if (fb->pitches[0] != mode->hdisplay * fb->format->cpp[0]) | ||
86 | return -EINVAL; | ||
87 | |||
88 | /* We can't change the FB format in a flicker-free | ||
89 | * manner (and only update it during CRTC enable). | ||
90 | */ | ||
91 | if (old_fb && old_fb->format != fb->format) | ||
92 | cstate->mode_changed = true; | ||
93 | } | ||
94 | |||
95 | return 0; | ||
96 | } | ||
97 | |||
98 | static void pl111_display_enable(struct drm_simple_display_pipe *pipe, | ||
99 | struct drm_crtc_state *cstate) | ||
100 | { | ||
101 | struct drm_crtc *crtc = &pipe->crtc; | ||
102 | struct drm_plane *plane = &pipe->plane; | ||
103 | struct drm_device *drm = crtc->dev; | ||
104 | struct pl111_drm_dev_private *priv = drm->dev_private; | ||
105 | const struct drm_display_mode *mode = &cstate->mode; | ||
106 | struct drm_framebuffer *fb = plane->state->fb; | ||
107 | struct drm_connector *connector = &priv->connector.connector; | ||
108 | u32 cntl; | ||
109 | u32 ppl, hsw, hfp, hbp; | ||
110 | u32 lpp, vsw, vfp, vbp; | ||
111 | u32 cpl; | ||
112 | int ret; | ||
113 | |||
114 | ret = clk_set_rate(priv->clk, mode->clock * 1000); | ||
115 | if (ret) { | ||
116 | dev_err(drm->dev, | ||
117 | "Failed to set pixel clock rate to %d: %d\n", | ||
118 | mode->clock * 1000, ret); | ||
119 | } | ||
120 | |||
121 | clk_prepare_enable(priv->clk); | ||
122 | |||
123 | ppl = (mode->hdisplay / 16) - 1; | ||
124 | hsw = mode->hsync_end - mode->hsync_start - 1; | ||
125 | hfp = mode->hsync_start - mode->hdisplay - 1; | ||
126 | hbp = mode->htotal - mode->hsync_end - 1; | ||
127 | |||
128 | lpp = mode->vdisplay - 1; | ||
129 | vsw = mode->vsync_end - mode->vsync_start - 1; | ||
130 | vfp = mode->vsync_start - mode->vdisplay; | ||
131 | vbp = mode->vtotal - mode->vsync_end; | ||
132 | |||
133 | cpl = mode->hdisplay - 1; | ||
134 | |||
135 | writel((ppl << 2) | | ||
136 | (hsw << 8) | | ||
137 | (hfp << 16) | | ||
138 | (hbp << 24), | ||
139 | priv->regs + CLCD_TIM0); | ||
140 | writel(lpp | | ||
141 | (vsw << 10) | | ||
142 | (vfp << 16) | | ||
143 | (vbp << 24), | ||
144 | priv->regs + CLCD_TIM1); | ||
145 | /* XXX: We currently always use CLCDCLK with no divisor. We | ||
146 | * could probably reduce power consumption by using HCLK | ||
147 | * (apb_pclk) with a divisor when it gets us near our target | ||
148 | * pixel clock. | ||
149 | */ | ||
150 | writel(((mode->flags & DRM_MODE_FLAG_NHSYNC) ? TIM2_IHS : 0) | | ||
151 | ((mode->flags & DRM_MODE_FLAG_NVSYNC) ? TIM2_IVS : 0) | | ||
152 | ((connector->display_info.bus_flags & | ||
153 | DRM_BUS_FLAG_DE_LOW) ? TIM2_IOE : 0) | | ||
154 | ((connector->display_info.bus_flags & | ||
155 | DRM_BUS_FLAG_PIXDATA_NEGEDGE) ? TIM2_IPC : 0) | | ||
156 | TIM2_BCD | | ||
157 | (cpl << 16), | ||
158 | priv->regs + CLCD_TIM2); | ||
159 | writel(0, priv->regs + CLCD_TIM3); | ||
160 | |||
161 | drm_panel_prepare(priv->connector.panel); | ||
162 | |||
163 | /* Enable and Power Up */ | ||
164 | cntl = CNTL_LCDEN | CNTL_LCDTFT | CNTL_LCDPWR | CNTL_LCDVCOMP(1); | ||
165 | |||
166 | /* Note that the the hardware's format reader takes 'r' from | ||
167 | * the low bit, while DRM formats list channels from high bit | ||
168 | * to low bit as you read left to right. | ||
169 | */ | ||
170 | switch (fb->format->format) { | ||
171 | case DRM_FORMAT_ABGR8888: | ||
172 | case DRM_FORMAT_XBGR8888: | ||
173 | cntl |= CNTL_LCDBPP24; | ||
174 | break; | ||
175 | case DRM_FORMAT_ARGB8888: | ||
176 | case DRM_FORMAT_XRGB8888: | ||
177 | cntl |= CNTL_LCDBPP24 | CNTL_BGR; | ||
178 | break; | ||
179 | case DRM_FORMAT_BGR565: | ||
180 | cntl |= CNTL_LCDBPP16_565; | ||
181 | break; | ||
182 | case DRM_FORMAT_RGB565: | ||
183 | cntl |= CNTL_LCDBPP16_565 | CNTL_BGR; | ||
184 | break; | ||
185 | case DRM_FORMAT_ABGR1555: | ||
186 | case DRM_FORMAT_XBGR1555: | ||
187 | cntl |= CNTL_LCDBPP16; | ||
188 | break; | ||
189 | case DRM_FORMAT_ARGB1555: | ||
190 | case DRM_FORMAT_XRGB1555: | ||
191 | cntl |= CNTL_LCDBPP16 | CNTL_BGR; | ||
192 | break; | ||
193 | case DRM_FORMAT_ABGR4444: | ||
194 | case DRM_FORMAT_XBGR4444: | ||
195 | cntl |= CNTL_LCDBPP16_444; | ||
196 | break; | ||
197 | case DRM_FORMAT_ARGB4444: | ||
198 | case DRM_FORMAT_XRGB4444: | ||
199 | cntl |= CNTL_LCDBPP16_444 | CNTL_BGR; | ||
200 | break; | ||
201 | default: | ||
202 | WARN_ONCE(true, "Unknown FB format 0x%08x\n", | ||
203 | fb->format->format); | ||
204 | break; | ||
205 | } | ||
206 | |||
207 | writel(cntl, priv->regs + CLCD_PL111_CNTL); | ||
208 | |||
209 | drm_panel_enable(priv->connector.panel); | ||
210 | |||
211 | drm_crtc_vblank_on(crtc); | ||
212 | } | ||
213 | |||
214 | void pl111_display_disable(struct drm_simple_display_pipe *pipe) | ||
215 | { | ||
216 | struct drm_crtc *crtc = &pipe->crtc; | ||
217 | struct drm_device *drm = crtc->dev; | ||
218 | struct pl111_drm_dev_private *priv = drm->dev_private; | ||
219 | |||
220 | drm_crtc_vblank_off(crtc); | ||
221 | |||
222 | drm_panel_disable(priv->connector.panel); | ||
223 | |||
224 | /* Disable and Power Down */ | ||
225 | writel(0, priv->regs + CLCD_PL111_CNTL); | ||
226 | |||
227 | drm_panel_unprepare(priv->connector.panel); | ||
228 | |||
229 | clk_disable_unprepare(priv->clk); | ||
230 | } | ||
231 | |||
232 | static void pl111_display_update(struct drm_simple_display_pipe *pipe, | ||
233 | struct drm_plane_state *old_pstate) | ||
234 | { | ||
235 | struct drm_crtc *crtc = &pipe->crtc; | ||
236 | struct drm_device *drm = crtc->dev; | ||
237 | struct pl111_drm_dev_private *priv = drm->dev_private; | ||
238 | struct drm_pending_vblank_event *event = crtc->state->event; | ||
239 | struct drm_plane *plane = &pipe->plane; | ||
240 | struct drm_plane_state *pstate = plane->state; | ||
241 | struct drm_framebuffer *fb = pstate->fb; | ||
242 | |||
243 | if (fb) { | ||
244 | u32 addr = pl111_get_fb_offset(pstate); | ||
245 | |||
246 | writel(addr, priv->regs + CLCD_UBAS); | ||
247 | } | ||
248 | |||
249 | if (event) { | ||
250 | crtc->state->event = NULL; | ||
251 | |||
252 | spin_lock_irq(&crtc->dev->event_lock); | ||
253 | if (crtc->state->active && drm_crtc_vblank_get(crtc) == 0) | ||
254 | drm_crtc_arm_vblank_event(crtc, event); | ||
255 | else | ||
256 | drm_crtc_send_vblank_event(crtc, event); | ||
257 | spin_unlock_irq(&crtc->dev->event_lock); | ||
258 | } | ||
259 | } | ||
260 | |||
261 | int pl111_enable_vblank(struct drm_device *drm, unsigned int crtc) | ||
262 | { | ||
263 | struct pl111_drm_dev_private *priv = drm->dev_private; | ||
264 | |||
265 | writel(CLCD_IRQ_NEXTBASE_UPDATE, priv->regs + CLCD_PL111_IENB); | ||
266 | |||
267 | return 0; | ||
268 | } | ||
269 | |||
270 | void pl111_disable_vblank(struct drm_device *drm, unsigned int crtc) | ||
271 | { | ||
272 | struct pl111_drm_dev_private *priv = drm->dev_private; | ||
273 | |||
274 | writel(0, priv->regs + CLCD_PL111_IENB); | ||
275 | } | ||
276 | |||
277 | static int pl111_display_prepare_fb(struct drm_simple_display_pipe *pipe, | ||
278 | struct drm_plane_state *plane_state) | ||
279 | { | ||
280 | return drm_fb_cma_prepare_fb(&pipe->plane, plane_state); | ||
281 | } | ||
282 | |||
283 | const struct drm_simple_display_pipe_funcs pl111_display_funcs = { | ||
284 | .check = pl111_display_check, | ||
285 | .enable = pl111_display_enable, | ||
286 | .disable = pl111_display_disable, | ||
287 | .update = pl111_display_update, | ||
288 | .prepare_fb = pl111_display_prepare_fb, | ||
289 | }; | ||
290 | |||
291 | int pl111_display_init(struct drm_device *drm) | ||
292 | { | ||
293 | struct pl111_drm_dev_private *priv = drm->dev_private; | ||
294 | struct device *dev = drm->dev; | ||
295 | struct device_node *endpoint; | ||
296 | u32 tft_r0b0g0[3]; | ||
297 | int ret; | ||
298 | static const u32 formats[] = { | ||
299 | DRM_FORMAT_ABGR8888, | ||
300 | DRM_FORMAT_XBGR8888, | ||
301 | DRM_FORMAT_ARGB8888, | ||
302 | DRM_FORMAT_XRGB8888, | ||
303 | DRM_FORMAT_BGR565, | ||
304 | DRM_FORMAT_RGB565, | ||
305 | DRM_FORMAT_ABGR1555, | ||
306 | DRM_FORMAT_XBGR1555, | ||
307 | DRM_FORMAT_ARGB1555, | ||
308 | DRM_FORMAT_XRGB1555, | ||
309 | DRM_FORMAT_ABGR4444, | ||
310 | DRM_FORMAT_XBGR4444, | ||
311 | DRM_FORMAT_ARGB4444, | ||
312 | DRM_FORMAT_XRGB4444, | ||
313 | }; | ||
314 | |||
315 | endpoint = of_graph_get_next_endpoint(dev->of_node, NULL); | ||
316 | if (!endpoint) | ||
317 | return -ENODEV; | ||
318 | |||
319 | if (of_property_read_u32_array(endpoint, | ||
320 | "arm,pl11x,tft-r0g0b0-pads", | ||
321 | tft_r0b0g0, | ||
322 | ARRAY_SIZE(tft_r0b0g0)) != 0) { | ||
323 | dev_err(dev, "arm,pl11x,tft-r0g0b0-pads should be 3 ints\n"); | ||
324 | of_node_put(endpoint); | ||
325 | return -ENOENT; | ||
326 | } | ||
327 | of_node_put(endpoint); | ||
328 | |||
329 | if (tft_r0b0g0[0] != 0 || | ||
330 | tft_r0b0g0[1] != 8 || | ||
331 | tft_r0b0g0[2] != 16) { | ||
332 | dev_err(dev, "arm,pl11x,tft-r0g0b0-pads != [0,8,16] not yet supported\n"); | ||
333 | return -EINVAL; | ||
334 | } | ||
335 | |||
336 | ret = drm_simple_display_pipe_init(drm, &priv->pipe, | ||
337 | &pl111_display_funcs, | ||
338 | formats, ARRAY_SIZE(formats), | ||
339 | &priv->connector.connector); | ||
340 | if (ret) | ||
341 | return ret; | ||
342 | |||
343 | return 0; | ||
344 | } | ||
diff --git a/drivers/gpu/drm/pl111/pl111_drm.h b/drivers/gpu/drm/pl111/pl111_drm.h new file mode 100644 index 000000000000..f381593921b7 --- /dev/null +++ b/drivers/gpu/drm/pl111/pl111_drm.h | |||
@@ -0,0 +1,56 @@ | |||
1 | /* | ||
2 | * | ||
3 | * (C) COPYRIGHT 2012-2013 ARM Limited. All rights reserved. | ||
4 | * | ||
5 | * | ||
6 | * Parts of this file were based on sources as follows: | ||
7 | * | ||
8 | * Copyright (c) 2006-2008 Intel Corporation | ||
9 | * Copyright (c) 2007 Dave Airlie <airlied@linux.ie> | ||
10 | * Copyright (C) 2011 Texas Instruments | ||
11 | * | ||
12 | * This program is free software and is provided to you under the terms of the | ||
13 | * GNU General Public License version 2 as published by the Free Software | ||
14 | * Foundation, and any use by you of this program is subject to the terms of | ||
15 | * such GNU licence. | ||
16 | * | ||
17 | */ | ||
18 | |||
19 | #ifndef _PL111_DRM_H_ | ||
20 | #define _PL111_DRM_H_ | ||
21 | |||
22 | #include <drm/drm_gem.h> | ||
23 | #include <drm/drm_simple_kms_helper.h> | ||
24 | |||
25 | #define CLCD_IRQ_NEXTBASE_UPDATE BIT(2) | ||
26 | |||
27 | struct pl111_drm_connector { | ||
28 | struct drm_connector connector; | ||
29 | struct drm_panel *panel; | ||
30 | }; | ||
31 | |||
32 | struct pl111_drm_dev_private { | ||
33 | struct drm_device *drm; | ||
34 | |||
35 | struct pl111_drm_connector connector; | ||
36 | struct drm_simple_display_pipe pipe; | ||
37 | struct drm_fbdev_cma *fbdev; | ||
38 | |||
39 | void *regs; | ||
40 | struct clk *clk; | ||
41 | }; | ||
42 | |||
43 | #define to_pl111_connector(x) \ | ||
44 | container_of(x, struct pl111_drm_connector, connector) | ||
45 | |||
46 | int pl111_display_init(struct drm_device *dev); | ||
47 | int pl111_enable_vblank(struct drm_device *drm, unsigned int crtc); | ||
48 | void pl111_disable_vblank(struct drm_device *drm, unsigned int crtc); | ||
49 | irqreturn_t pl111_irq(int irq, void *data); | ||
50 | int pl111_connector_init(struct drm_device *dev); | ||
51 | int pl111_encoder_init(struct drm_device *dev); | ||
52 | int pl111_dumb_create(struct drm_file *file_priv, | ||
53 | struct drm_device *dev, | ||
54 | struct drm_mode_create_dumb *args); | ||
55 | |||
56 | #endif /* _PL111_DRM_H_ */ | ||
diff --git a/drivers/gpu/drm/pl111/pl111_drv.c b/drivers/gpu/drm/pl111/pl111_drv.c new file mode 100644 index 000000000000..936403f65508 --- /dev/null +++ b/drivers/gpu/drm/pl111/pl111_drv.c | |||
@@ -0,0 +1,272 @@ | |||
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 | * DOC: ARM PrimeCell PL111 CLCD Driver | ||
19 | * | ||
20 | * The PL111 is a simple LCD controller that can support TFT and STN | ||
21 | * displays. This driver exposes a standard KMS interface for them. | ||
22 | * | ||
23 | * This driver uses the same Device Tree binding as the fbdev CLCD | ||
24 | * driver. While the fbdev driver supports panels that may be | ||
25 | * connected to the CLCD internally to the CLCD driver, in DRM the | ||
26 | * panels get split out to drivers/gpu/drm/panels/. This means that, | ||
27 | * in converting from using fbdev to using DRM, you also need to write | ||
28 | * a panel driver (which may be as simple as an entry in | ||
29 | * panel-simple.c). | ||
30 | * | ||
31 | * The driver currently doesn't expose the cursor. The DRM API for | ||
32 | * cursors requires support for 64x64 ARGB8888 cursor images, while | ||
33 | * the hardware can only support 64x64 monochrome with masking | ||
34 | * cursors. While one could imagine trying to hack something together | ||
35 | * to look at the ARGB8888 and program reasonable in monochrome, we | ||
36 | * just don't expose the cursor at all instead, and leave cursor | ||
37 | * support to the X11 software cursor layer. | ||
38 | * | ||
39 | * TODO: | ||
40 | * | ||
41 | * - Fix race between setting plane base address and getting IRQ for | ||
42 | * vsync firing the pageflip completion. | ||
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 | ||
48 | * supported formats. | ||
49 | * | ||
50 | * - Read back hardware state at boot to skip reprogramming the | ||
51 | * hardware when doing a no-op modeset. | ||
52 | * | ||
53 | * - Use the internal clock divisor to reduce power consumption by | ||
54 | * using HCLK (apb_pclk) when appropriate. | ||
55 | */ | ||
56 | |||
57 | #include <linux/amba/bus.h> | ||
58 | #include <linux/amba/clcd-regs.h> | ||
59 | #include <linux/version.h> | ||
60 | #include <linux/shmem_fs.h> | ||
61 | #include <linux/dma-buf.h> | ||
62 | #include <linux/module.h> | ||
63 | #include <linux/slab.h> | ||
64 | |||
65 | #include <drm/drmP.h> | ||
66 | #include <drm/drm_atomic_helper.h> | ||
67 | #include <drm/drm_crtc_helper.h> | ||
68 | #include <drm/drm_gem_cma_helper.h> | ||
69 | #include <drm/drm_fb_cma_helper.h> | ||
70 | |||
71 | #include "pl111_drm.h" | ||
72 | |||
73 | #define DRIVER_DESC "DRM module for PL111" | ||
74 | |||
75 | struct drm_mode_config_funcs mode_config_funcs = { | ||
76 | .fb_create = drm_fb_cma_create, | ||
77 | .atomic_check = drm_atomic_helper_check, | ||
78 | .atomic_commit = drm_atomic_helper_commit, | ||
79 | }; | ||
80 | |||
81 | static int pl111_modeset_init(struct drm_device *dev) | ||
82 | { | ||
83 | struct drm_mode_config *mode_config; | ||
84 | struct pl111_drm_dev_private *priv = dev->dev_private; | ||
85 | int ret = 0; | ||
86 | |||
87 | drm_mode_config_init(dev); | ||
88 | mode_config = &dev->mode_config; | ||
89 | mode_config->funcs = &mode_config_funcs; | ||
90 | mode_config->min_width = 1; | ||
91 | mode_config->max_width = 1024; | ||
92 | mode_config->min_height = 1; | ||
93 | mode_config->max_height = 768; | ||
94 | |||
95 | ret = pl111_connector_init(dev); | ||
96 | if (ret) { | ||
97 | dev_err(dev->dev, "Failed to create pl111_drm_connector\n"); | ||
98 | goto out_config; | ||
99 | } | ||
100 | |||
101 | /* Don't actually attach if we didn't find a drm_panel | ||
102 | * attached to us. This will allow a kernel to include both | ||
103 | * the fbdev pl111 driver and this one, and choose between | ||
104 | * them based on which subsystem has support for the panel. | ||
105 | */ | ||
106 | if (!priv->connector.panel) { | ||
107 | dev_info(dev->dev, | ||
108 | "Disabling due to lack of DRM panel device.\n"); | ||
109 | ret = -ENODEV; | ||
110 | goto out_config; | ||
111 | } | ||
112 | |||
113 | ret = pl111_display_init(dev); | ||
114 | if (ret != 0) { | ||
115 | dev_err(dev->dev, "Failed to init display\n"); | ||
116 | goto out_config; | ||
117 | } | ||
118 | |||
119 | ret = drm_vblank_init(dev, 1); | ||
120 | if (ret != 0) { | ||
121 | dev_err(dev->dev, "Failed to init vblank\n"); | ||
122 | goto out_config; | ||
123 | } | ||
124 | |||
125 | drm_mode_config_reset(dev); | ||
126 | |||
127 | priv->fbdev = drm_fbdev_cma_init(dev, 32, | ||
128 | dev->mode_config.num_connector); | ||
129 | |||
130 | drm_kms_helper_poll_init(dev); | ||
131 | |||
132 | goto finish; | ||
133 | |||
134 | out_config: | ||
135 | drm_mode_config_cleanup(dev); | ||
136 | finish: | ||
137 | return ret; | ||
138 | } | ||
139 | |||
140 | DEFINE_DRM_GEM_CMA_FOPS(drm_fops); | ||
141 | |||
142 | static void pl111_lastclose(struct drm_device *dev) | ||
143 | { | ||
144 | struct pl111_drm_dev_private *priv = dev->dev_private; | ||
145 | |||
146 | drm_fbdev_cma_restore_mode(priv->fbdev); | ||
147 | } | ||
148 | |||
149 | static struct drm_driver pl111_drm_driver = { | ||
150 | .driver_features = | ||
151 | DRIVER_MODESET | DRIVER_GEM | DRIVER_PRIME | DRIVER_ATOMIC, | ||
152 | .lastclose = pl111_lastclose, | ||
153 | .ioctls = NULL, | ||
154 | .fops = &drm_fops, | ||
155 | .name = "pl111", | ||
156 | .desc = DRIVER_DESC, | ||
157 | .date = "20170317", | ||
158 | .major = 1, | ||
159 | .minor = 0, | ||
160 | .patchlevel = 0, | ||
161 | .dumb_create = drm_gem_cma_dumb_create, | ||
162 | .dumb_destroy = drm_gem_dumb_destroy, | ||
163 | .dumb_map_offset = drm_gem_cma_dumb_map_offset, | ||
164 | .gem_free_object = drm_gem_cma_free_object, | ||
165 | .gem_vm_ops = &drm_gem_cma_vm_ops, | ||
166 | |||
167 | .enable_vblank = pl111_enable_vblank, | ||
168 | .disable_vblank = pl111_disable_vblank, | ||
169 | |||
170 | .prime_handle_to_fd = drm_gem_prime_handle_to_fd, | ||
171 | .prime_fd_to_handle = drm_gem_prime_fd_to_handle, | ||
172 | .gem_prime_import = drm_gem_prime_import, | ||
173 | .gem_prime_import_sg_table = drm_gem_cma_prime_import_sg_table, | ||
174 | .gem_prime_export = drm_gem_prime_export, | ||
175 | .gem_prime_get_sg_table = drm_gem_cma_prime_get_sg_table, | ||
176 | }; | ||
177 | |||
178 | #ifdef CONFIG_ARM_AMBA | ||
179 | static int pl111_amba_probe(struct amba_device *amba_dev, | ||
180 | const struct amba_id *id) | ||
181 | { | ||
182 | struct device *dev = &amba_dev->dev; | ||
183 | struct pl111_drm_dev_private *priv; | ||
184 | struct drm_device *drm; | ||
185 | int ret; | ||
186 | |||
187 | priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); | ||
188 | if (!priv) | ||
189 | return -ENOMEM; | ||
190 | |||
191 | drm = drm_dev_alloc(&pl111_drm_driver, dev); | ||
192 | if (IS_ERR(drm)) | ||
193 | return PTR_ERR(drm); | ||
194 | amba_set_drvdata(amba_dev, drm); | ||
195 | priv->drm = drm; | ||
196 | drm->dev_private = priv; | ||
197 | |||
198 | priv->clk = devm_clk_get(dev, "clcdclk"); | ||
199 | if (IS_ERR(priv->clk)) { | ||
200 | dev_err(dev, "CLCD: unable to get clk.\n"); | ||
201 | ret = PTR_ERR(priv->clk); | ||
202 | goto dev_unref; | ||
203 | } | ||
204 | |||
205 | priv->regs = devm_ioremap_resource(dev, &amba_dev->res); | ||
206 | if (!priv->regs) { | ||
207 | dev_err(dev, "%s failed mmio\n", __func__); | ||
208 | return -EINVAL; | ||
209 | } | ||
210 | |||
211 | /* turn off interrupts before requesting the irq */ | ||
212 | writel(0, priv->regs + CLCD_PL111_IENB); | ||
213 | |||
214 | ret = devm_request_irq(dev, amba_dev->irq[0], pl111_irq, 0, | ||
215 | "pl111", priv); | ||
216 | if (ret != 0) { | ||
217 | dev_err(dev, "%s failed irq %d\n", __func__, ret); | ||
218 | return ret; | ||
219 | } | ||
220 | |||
221 | ret = pl111_modeset_init(drm); | ||
222 | if (ret != 0) | ||
223 | goto dev_unref; | ||
224 | |||
225 | ret = drm_dev_register(drm, 0); | ||
226 | if (ret < 0) | ||
227 | goto dev_unref; | ||
228 | |||
229 | return 0; | ||
230 | |||
231 | dev_unref: | ||
232 | drm_dev_unref(drm); | ||
233 | return ret; | ||
234 | } | ||
235 | |||
236 | static int pl111_amba_remove(struct amba_device *amba_dev) | ||
237 | { | ||
238 | struct drm_device *drm = amba_get_drvdata(amba_dev); | ||
239 | struct pl111_drm_dev_private *priv = drm->dev_private; | ||
240 | |||
241 | drm_dev_unregister(drm); | ||
242 | if (priv->fbdev) | ||
243 | drm_fbdev_cma_fini(priv->fbdev); | ||
244 | drm_mode_config_cleanup(drm); | ||
245 | drm_dev_unref(drm); | ||
246 | |||
247 | return 0; | ||
248 | } | ||
249 | |||
250 | static struct amba_id pl111_id_table[] = { | ||
251 | { | ||
252 | .id = 0x00041111, | ||
253 | .mask = 0x000fffff, | ||
254 | }, | ||
255 | {0, 0}, | ||
256 | }; | ||
257 | |||
258 | static struct amba_driver pl111_amba_driver = { | ||
259 | .drv = { | ||
260 | .name = "drm-clcd-pl111", | ||
261 | }, | ||
262 | .probe = pl111_amba_probe, | ||
263 | .remove = pl111_amba_remove, | ||
264 | .id_table = pl111_id_table, | ||
265 | }; | ||
266 | |||
267 | module_amba_driver(pl111_amba_driver); | ||
268 | #endif /* CONFIG_ARM_AMBA */ | ||
269 | |||
270 | MODULE_DESCRIPTION(DRIVER_DESC); | ||
271 | MODULE_AUTHOR("ARM Ltd."); | ||
272 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/gpu/drm/radeon/radeon_drv.c b/drivers/gpu/drm/radeon/radeon_drv.c index 93d45aa5c3d4..ef8a75940980 100644 --- a/drivers/gpu/drm/radeon/radeon_drv.c +++ b/drivers/gpu/drm/radeon/radeon_drv.c | |||
@@ -115,10 +115,6 @@ int radeon_resume_kms(struct drm_device *dev, bool resume, bool fbcon); | |||
115 | u32 radeon_get_vblank_counter_kms(struct drm_device *dev, unsigned int pipe); | 115 | u32 radeon_get_vblank_counter_kms(struct drm_device *dev, unsigned int pipe); |
116 | int radeon_enable_vblank_kms(struct drm_device *dev, unsigned int pipe); | 116 | int radeon_enable_vblank_kms(struct drm_device *dev, unsigned int pipe); |
117 | void radeon_disable_vblank_kms(struct drm_device *dev, unsigned int pipe); | 117 | void radeon_disable_vblank_kms(struct drm_device *dev, unsigned int pipe); |
118 | int radeon_get_vblank_timestamp_kms(struct drm_device *dev, unsigned int pipe, | ||
119 | int *max_error, | ||
120 | struct timeval *vblank_time, | ||
121 | unsigned flags); | ||
122 | void radeon_driver_irq_preinstall_kms(struct drm_device *dev); | 118 | void radeon_driver_irq_preinstall_kms(struct drm_device *dev); |
123 | int radeon_driver_irq_postinstall_kms(struct drm_device *dev); | 119 | int radeon_driver_irq_postinstall_kms(struct drm_device *dev); |
124 | void radeon_driver_irq_uninstall_kms(struct drm_device *dev); | 120 | void radeon_driver_irq_uninstall_kms(struct drm_device *dev); |
@@ -530,6 +526,16 @@ static const struct file_operations radeon_driver_kms_fops = { | |||
530 | #endif | 526 | #endif |
531 | }; | 527 | }; |
532 | 528 | ||
529 | static bool | ||
530 | radeon_get_crtc_scanout_position(struct drm_device *dev, unsigned int pipe, | ||
531 | bool in_vblank_irq, int *vpos, int *hpos, | ||
532 | ktime_t *stime, ktime_t *etime, | ||
533 | const struct drm_display_mode *mode) | ||
534 | { | ||
535 | return radeon_get_crtc_scanoutpos(dev, pipe, 0, vpos, hpos, | ||
536 | stime, etime, mode); | ||
537 | } | ||
538 | |||
533 | static struct drm_driver kms_driver = { | 539 | static struct drm_driver kms_driver = { |
534 | .driver_features = | 540 | .driver_features = |
535 | DRIVER_USE_AGP | | 541 | DRIVER_USE_AGP | |
@@ -544,8 +550,8 @@ static struct drm_driver kms_driver = { | |||
544 | .get_vblank_counter = radeon_get_vblank_counter_kms, | 550 | .get_vblank_counter = radeon_get_vblank_counter_kms, |
545 | .enable_vblank = radeon_enable_vblank_kms, | 551 | .enable_vblank = radeon_enable_vblank_kms, |
546 | .disable_vblank = radeon_disable_vblank_kms, | 552 | .disable_vblank = radeon_disable_vblank_kms, |
547 | .get_vblank_timestamp = radeon_get_vblank_timestamp_kms, | 553 | .get_vblank_timestamp = drm_calc_vbltimestamp_from_scanoutpos, |
548 | .get_scanout_position = radeon_get_crtc_scanoutpos, | 554 | .get_scanout_position = radeon_get_crtc_scanout_position, |
549 | .irq_preinstall = radeon_driver_irq_preinstall_kms, | 555 | .irq_preinstall = radeon_driver_irq_preinstall_kms, |
550 | .irq_postinstall = radeon_driver_irq_postinstall_kms, | 556 | .irq_postinstall = radeon_driver_irq_postinstall_kms, |
551 | .irq_uninstall = radeon_driver_irq_uninstall_kms, | 557 | .irq_uninstall = radeon_driver_irq_uninstall_kms, |
diff --git a/drivers/gpu/drm/radeon/radeon_kms.c b/drivers/gpu/drm/radeon/radeon_kms.c index e3e7cb1d10a2..6a68d440bc44 100644 --- a/drivers/gpu/drm/radeon/radeon_kms.c +++ b/drivers/gpu/drm/radeon/radeon_kms.c | |||
@@ -858,43 +858,6 @@ void radeon_disable_vblank_kms(struct drm_device *dev, int crtc) | |||
858 | spin_unlock_irqrestore(&rdev->irq.lock, irqflags); | 858 | spin_unlock_irqrestore(&rdev->irq.lock, irqflags); |
859 | } | 859 | } |
860 | 860 | ||
861 | /** | ||
862 | * radeon_get_vblank_timestamp_kms - get vblank timestamp | ||
863 | * | ||
864 | * @dev: drm dev pointer | ||
865 | * @crtc: crtc to get the timestamp for | ||
866 | * @max_error: max error | ||
867 | * @vblank_time: time value | ||
868 | * @flags: flags passed to the driver | ||
869 | * | ||
870 | * Gets the timestamp on the requested crtc based on the | ||
871 | * scanout position. (all asics). | ||
872 | * Returns postive status flags on success, negative error on failure. | ||
873 | */ | ||
874 | int radeon_get_vblank_timestamp_kms(struct drm_device *dev, int crtc, | ||
875 | int *max_error, | ||
876 | struct timeval *vblank_time, | ||
877 | unsigned flags) | ||
878 | { | ||
879 | struct drm_crtc *drmcrtc; | ||
880 | struct radeon_device *rdev = dev->dev_private; | ||
881 | |||
882 | if (crtc < 0 || crtc >= dev->num_crtcs) { | ||
883 | DRM_ERROR("Invalid crtc %d\n", crtc); | ||
884 | return -EINVAL; | ||
885 | } | ||
886 | |||
887 | /* Get associated drm_crtc: */ | ||
888 | drmcrtc = &rdev->mode_info.crtcs[crtc]->base; | ||
889 | if (!drmcrtc) | ||
890 | return -EINVAL; | ||
891 | |||
892 | /* Helper routine in DRM core does all the work: */ | ||
893 | return drm_calc_vbltimestamp_from_scanoutpos(dev, crtc, max_error, | ||
894 | vblank_time, flags, | ||
895 | &drmcrtc->hwmode); | ||
896 | } | ||
897 | |||
898 | const struct drm_ioctl_desc radeon_ioctls_kms[] = { | 861 | const struct drm_ioctl_desc radeon_ioctls_kms[] = { |
899 | DRM_IOCTL_DEF_DRV(RADEON_CP_INIT, drm_invalid_op, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), | 862 | DRM_IOCTL_DEF_DRV(RADEON_CP_INIT, drm_invalid_op, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), |
900 | DRM_IOCTL_DEF_DRV(RADEON_CP_START, drm_invalid_op, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), | 863 | DRM_IOCTL_DEF_DRV(RADEON_CP_START, drm_invalid_op, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), |
diff --git a/drivers/gpu/drm/radeon/radeon_mode.h b/drivers/gpu/drm/radeon/radeon_mode.h index ad282648fc8b..00f5ec5c12c7 100644 --- a/drivers/gpu/drm/radeon/radeon_mode.h +++ b/drivers/gpu/drm/radeon/radeon_mode.h | |||
@@ -691,6 +691,9 @@ struct atom_voltage_table | |||
691 | }; | 691 | }; |
692 | 692 | ||
693 | /* Driver internal use only flags of radeon_get_crtc_scanoutpos() */ | 693 | /* Driver internal use only flags of radeon_get_crtc_scanoutpos() */ |
694 | #define DRM_SCANOUTPOS_VALID (1 << 0) | ||
695 | #define DRM_SCANOUTPOS_IN_VBLANK (1 << 1) | ||
696 | #define DRM_SCANOUTPOS_ACCURATE (1 << 2) | ||
694 | #define USE_REAL_VBLANKSTART (1 << 30) | 697 | #define USE_REAL_VBLANKSTART (1 << 30) |
695 | #define GET_DISTANCE_TO_VBLANKSTART (1 << 31) | 698 | #define GET_DISTANCE_TO_VBLANKSTART (1 << 31) |
696 | 699 | ||
diff --git a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c index d8fa7a9c9240..1bccd827d2e4 100644 --- a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c +++ b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c | |||
@@ -104,26 +104,18 @@ static void analogix_dp_psr_work(struct work_struct *work) | |||
104 | { | 104 | { |
105 | struct rockchip_dp_device *dp = | 105 | struct rockchip_dp_device *dp = |
106 | container_of(work, typeof(*dp), psr_work); | 106 | container_of(work, typeof(*dp), psr_work); |
107 | struct drm_crtc *crtc = dp->encoder.crtc; | ||
108 | int psr_state = dp->psr_state; | ||
109 | int vact_end; | ||
110 | int ret; | 107 | int ret; |
111 | unsigned long flags; | 108 | unsigned long flags; |
112 | 109 | ||
113 | if (!crtc) | 110 | ret = rockchip_drm_wait_vact_end(dp->encoder.crtc, |
114 | return; | 111 | PSR_WAIT_LINE_FLAG_TIMEOUT_MS); |
115 | |||
116 | vact_end = crtc->mode.vtotal - crtc->mode.vsync_start + crtc->mode.vdisplay; | ||
117 | |||
118 | ret = rockchip_drm_wait_line_flag(dp->encoder.crtc, vact_end, | ||
119 | PSR_WAIT_LINE_FLAG_TIMEOUT_MS); | ||
120 | if (ret) { | 112 | if (ret) { |
121 | dev_err(dp->dev, "line flag interrupt did not arrive\n"); | 113 | dev_err(dp->dev, "line flag interrupt did not arrive\n"); |
122 | return; | 114 | return; |
123 | } | 115 | } |
124 | 116 | ||
125 | spin_lock_irqsave(&dp->psr_lock, flags); | 117 | spin_lock_irqsave(&dp->psr_lock, flags); |
126 | if (psr_state == EDP_VSC_PSR_STATE_ACTIVE) | 118 | if (dp->psr_state == EDP_VSC_PSR_STATE_ACTIVE) |
127 | analogix_dp_enable_psr(dp->dev); | 119 | analogix_dp_enable_psr(dp->dev); |
128 | else | 120 | else |
129 | analogix_dp_disable_psr(dp->dev); | 121 | analogix_dp_disable_psr(dp->dev); |
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_drv.h b/drivers/gpu/drm/rockchip/rockchip_drm_drv.h index a48fcce3f5f6..47905faf5586 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_drv.h +++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.h | |||
@@ -62,8 +62,7 @@ int rockchip_drm_dma_attach_device(struct drm_device *drm_dev, | |||
62 | struct device *dev); | 62 | struct device *dev); |
63 | void rockchip_drm_dma_detach_device(struct drm_device *drm_dev, | 63 | void rockchip_drm_dma_detach_device(struct drm_device *drm_dev, |
64 | struct device *dev); | 64 | struct device *dev); |
65 | int rockchip_drm_wait_line_flag(struct drm_crtc *crtc, unsigned int line_num, | 65 | int rockchip_drm_wait_vact_end(struct drm_crtc *crtc, unsigned int mstimeout); |
66 | unsigned int mstimeout); | ||
67 | 66 | ||
68 | extern struct platform_driver cdn_dp_driver; | 67 | extern struct platform_driver cdn_dp_driver; |
69 | extern struct platform_driver dw_hdmi_rockchip_pltfm_driver; | 68 | extern struct platform_driver dw_hdmi_rockchip_pltfm_driver; |
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c index 3f7a82d1e095..40a5e6ef6f2c 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c | |||
@@ -468,7 +468,7 @@ static bool vop_line_flag_irq_is_enabled(struct vop *vop) | |||
468 | return !!line_flag_irq; | 468 | return !!line_flag_irq; |
469 | } | 469 | } |
470 | 470 | ||
471 | static void vop_line_flag_irq_enable(struct vop *vop, int line_num) | 471 | static void vop_line_flag_irq_enable(struct vop *vop) |
472 | { | 472 | { |
473 | unsigned long flags; | 473 | unsigned long flags; |
474 | 474 | ||
@@ -477,7 +477,6 @@ static void vop_line_flag_irq_enable(struct vop *vop, int line_num) | |||
477 | 477 | ||
478 | spin_lock_irqsave(&vop->irq_lock, flags); | 478 | spin_lock_irqsave(&vop->irq_lock, flags); |
479 | 479 | ||
480 | VOP_CTRL_SET(vop, line_flag_num[0], line_num); | ||
481 | VOP_INTR_SET_TYPE(vop, clear, LINE_FLAG_INTR, 1); | 480 | VOP_INTR_SET_TYPE(vop, clear, LINE_FLAG_INTR, 1); |
482 | VOP_INTR_SET_TYPE(vop, enable, LINE_FLAG_INTR, 1); | 481 | VOP_INTR_SET_TYPE(vop, enable, LINE_FLAG_INTR, 1); |
483 | 482 | ||
@@ -981,6 +980,8 @@ static void vop_crtc_enable(struct drm_crtc *crtc) | |||
981 | VOP_CTRL_SET(vop, vact_st_end, val); | 980 | VOP_CTRL_SET(vop, vact_st_end, val); |
982 | VOP_CTRL_SET(vop, vpost_st_end, val); | 981 | VOP_CTRL_SET(vop, vpost_st_end, val); |
983 | 982 | ||
983 | VOP_CTRL_SET(vop, line_flag_num[0], vact_end); | ||
984 | |||
984 | clk_set_rate(vop->dclk, adjusted_mode->clock * 1000); | 985 | clk_set_rate(vop->dclk, adjusted_mode->clock * 1000); |
985 | 986 | ||
986 | VOP_CTRL_SET(vop, standby, 0); | 987 | VOP_CTRL_SET(vop, standby, 0); |
@@ -1507,19 +1508,16 @@ static void vop_win_init(struct vop *vop) | |||
1507 | } | 1508 | } |
1508 | 1509 | ||
1509 | /** | 1510 | /** |
1510 | * rockchip_drm_wait_line_flag - acqiure the give line flag event | 1511 | * rockchip_drm_wait_vact_end |
1511 | * @crtc: CRTC to enable line flag | 1512 | * @crtc: CRTC to enable line flag |
1512 | * @line_num: interested line number | ||
1513 | * @mstimeout: millisecond for timeout | 1513 | * @mstimeout: millisecond for timeout |
1514 | * | 1514 | * |
1515 | * Driver would hold here until the interested line flag interrupt have | 1515 | * Wait for vact_end line flag irq or timeout. |
1516 | * happened or timeout to wait. | ||
1517 | * | 1516 | * |
1518 | * Returns: | 1517 | * Returns: |
1519 | * Zero on success, negative errno on failure. | 1518 | * Zero on success, negative errno on failure. |
1520 | */ | 1519 | */ |
1521 | int rockchip_drm_wait_line_flag(struct drm_crtc *crtc, unsigned int line_num, | 1520 | int rockchip_drm_wait_vact_end(struct drm_crtc *crtc, unsigned int mstimeout) |
1522 | unsigned int mstimeout) | ||
1523 | { | 1521 | { |
1524 | struct vop *vop = to_vop(crtc); | 1522 | struct vop *vop = to_vop(crtc); |
1525 | unsigned long jiffies_left; | 1523 | unsigned long jiffies_left; |
@@ -1527,14 +1525,14 @@ int rockchip_drm_wait_line_flag(struct drm_crtc *crtc, unsigned int line_num, | |||
1527 | if (!crtc || !vop->is_enabled) | 1525 | if (!crtc || !vop->is_enabled) |
1528 | return -ENODEV; | 1526 | return -ENODEV; |
1529 | 1527 | ||
1530 | if (line_num > crtc->mode.vtotal || mstimeout <= 0) | 1528 | if (mstimeout <= 0) |
1531 | return -EINVAL; | 1529 | return -EINVAL; |
1532 | 1530 | ||
1533 | if (vop_line_flag_irq_is_enabled(vop)) | 1531 | if (vop_line_flag_irq_is_enabled(vop)) |
1534 | return -EBUSY; | 1532 | return -EBUSY; |
1535 | 1533 | ||
1536 | reinit_completion(&vop->line_flag_completion); | 1534 | reinit_completion(&vop->line_flag_completion); |
1537 | vop_line_flag_irq_enable(vop, line_num); | 1535 | vop_line_flag_irq_enable(vop); |
1538 | 1536 | ||
1539 | jiffies_left = wait_for_completion_timeout(&vop->line_flag_completion, | 1537 | jiffies_left = wait_for_completion_timeout(&vop->line_flag_completion, |
1540 | msecs_to_jiffies(mstimeout)); | 1538 | msecs_to_jiffies(mstimeout)); |
@@ -1547,7 +1545,7 @@ int rockchip_drm_wait_line_flag(struct drm_crtc *crtc, unsigned int line_num, | |||
1547 | 1545 | ||
1548 | return 0; | 1546 | return 0; |
1549 | } | 1547 | } |
1550 | EXPORT_SYMBOL(rockchip_drm_wait_line_flag); | 1548 | EXPORT_SYMBOL(rockchip_drm_wait_vact_end); |
1551 | 1549 | ||
1552 | static int vop_bind(struct device *dev, struct device *master, void *data) | 1550 | static int vop_bind(struct device *dev, struct device *master, void *data) |
1553 | { | 1551 | { |
diff --git a/drivers/gpu/drm/selftests/test-drm_mm.c b/drivers/gpu/drm/selftests/test-drm_mm.c index fa356f5dae27..dfdd858eda0a 100644 --- a/drivers/gpu/drm/selftests/test-drm_mm.c +++ b/drivers/gpu/drm/selftests/test-drm_mm.c | |||
@@ -514,6 +514,8 @@ static int igt_reserve(void *ignored) | |||
514 | ret = __igt_reserve(count, size + 1); | 514 | ret = __igt_reserve(count, size + 1); |
515 | if (ret) | 515 | if (ret) |
516 | return ret; | 516 | return ret; |
517 | |||
518 | cond_resched(); | ||
517 | } | 519 | } |
518 | 520 | ||
519 | return 0; | 521 | return 0; |
@@ -712,6 +714,10 @@ static int igt_insert(void *ignored) | |||
712 | return ret; | 714 | return ret; |
713 | 715 | ||
714 | ret = __igt_insert(count, size + 1, false); | 716 | ret = __igt_insert(count, size + 1, false); |
717 | if (ret) | ||
718 | return ret; | ||
719 | |||
720 | cond_resched(); | ||
715 | } | 721 | } |
716 | 722 | ||
717 | return 0; | 723 | return 0; |
@@ -741,6 +747,10 @@ static int igt_replace(void *ignored) | |||
741 | return ret; | 747 | return ret; |
742 | 748 | ||
743 | ret = __igt_insert(count, size + 1, true); | 749 | ret = __igt_insert(count, size + 1, true); |
750 | if (ret) | ||
751 | return ret; | ||
752 | |||
753 | cond_resched(); | ||
744 | } | 754 | } |
745 | 755 | ||
746 | return 0; | 756 | return 0; |
@@ -1011,6 +1021,8 @@ static int igt_insert_range(void *ignored) | |||
1011 | ret = __igt_insert_range(count, size, max/4+1, 3*max/4-1); | 1021 | ret = __igt_insert_range(count, size, max/4+1, 3*max/4-1); |
1012 | if (ret) | 1022 | if (ret) |
1013 | return ret; | 1023 | return ret; |
1024 | |||
1025 | cond_resched(); | ||
1014 | } | 1026 | } |
1015 | 1027 | ||
1016 | return 0; | 1028 | return 0; |
@@ -1056,6 +1068,7 @@ static int igt_align(void *ignored) | |||
1056 | drm_mm_for_each_node_safe(node, next, &mm) | 1068 | drm_mm_for_each_node_safe(node, next, &mm) |
1057 | drm_mm_remove_node(node); | 1069 | drm_mm_remove_node(node); |
1058 | DRM_MM_BUG_ON(!drm_mm_clean(&mm)); | 1070 | DRM_MM_BUG_ON(!drm_mm_clean(&mm)); |
1071 | cond_resched(); | ||
1059 | } | 1072 | } |
1060 | 1073 | ||
1061 | ret = 0; | 1074 | ret = 0; |
@@ -1097,6 +1110,8 @@ static int igt_align_pot(int max) | |||
1097 | align, bit); | 1110 | align, bit); |
1098 | goto out; | 1111 | goto out; |
1099 | } | 1112 | } |
1113 | |||
1114 | cond_resched(); | ||
1100 | } | 1115 | } |
1101 | 1116 | ||
1102 | ret = 0; | 1117 | ret = 0; |
@@ -1471,6 +1486,8 @@ static int igt_evict(void *ignored) | |||
1471 | goto out; | 1486 | goto out; |
1472 | } | 1487 | } |
1473 | } | 1488 | } |
1489 | |||
1490 | cond_resched(); | ||
1474 | } | 1491 | } |
1475 | 1492 | ||
1476 | ret = 0; | 1493 | ret = 0; |
@@ -1566,6 +1583,8 @@ static int igt_evict_range(void *ignored) | |||
1566 | goto out; | 1583 | goto out; |
1567 | } | 1584 | } |
1568 | } | 1585 | } |
1586 | |||
1587 | cond_resched(); | ||
1569 | } | 1588 | } |
1570 | 1589 | ||
1571 | ret = 0; | 1590 | ret = 0; |
@@ -1683,6 +1702,7 @@ static int igt_topdown(void *ignored) | |||
1683 | drm_mm_for_each_node_safe(node, next, &mm) | 1702 | drm_mm_for_each_node_safe(node, next, &mm) |
1684 | drm_mm_remove_node(node); | 1703 | drm_mm_remove_node(node); |
1685 | DRM_MM_BUG_ON(!drm_mm_clean(&mm)); | 1704 | DRM_MM_BUG_ON(!drm_mm_clean(&mm)); |
1705 | cond_resched(); | ||
1686 | } | 1706 | } |
1687 | 1707 | ||
1688 | ret = 0; | 1708 | ret = 0; |
@@ -1783,6 +1803,7 @@ static int igt_bottomup(void *ignored) | |||
1783 | drm_mm_for_each_node_safe(node, next, &mm) | 1803 | drm_mm_for_each_node_safe(node, next, &mm) |
1784 | drm_mm_remove_node(node); | 1804 | drm_mm_remove_node(node); |
1785 | DRM_MM_BUG_ON(!drm_mm_clean(&mm)); | 1805 | DRM_MM_BUG_ON(!drm_mm_clean(&mm)); |
1806 | cond_resched(); | ||
1786 | } | 1807 | } |
1787 | 1808 | ||
1788 | ret = 0; | 1809 | ret = 0; |
@@ -1970,6 +1991,8 @@ static int igt_color(void *ignored) | |||
1970 | drm_mm_remove_node(node); | 1991 | drm_mm_remove_node(node); |
1971 | kfree(node); | 1992 | kfree(node); |
1972 | } | 1993 | } |
1994 | |||
1995 | cond_resched(); | ||
1973 | } | 1996 | } |
1974 | 1997 | ||
1975 | ret = 0; | 1998 | ret = 0; |
@@ -2047,6 +2070,7 @@ static int evict_color(struct drm_mm *mm, | |||
2047 | } | 2070 | } |
2048 | } | 2071 | } |
2049 | 2072 | ||
2073 | cond_resched(); | ||
2050 | return 0; | 2074 | return 0; |
2051 | } | 2075 | } |
2052 | 2076 | ||
@@ -2132,6 +2156,8 @@ static int igt_color_evict(void *ignored) | |||
2132 | goto out; | 2156 | goto out; |
2133 | } | 2157 | } |
2134 | } | 2158 | } |
2159 | |||
2160 | cond_resched(); | ||
2135 | } | 2161 | } |
2136 | 2162 | ||
2137 | ret = 0; | 2163 | ret = 0; |
@@ -2231,6 +2257,8 @@ static int igt_color_evict_range(void *ignored) | |||
2231 | goto out; | 2257 | goto out; |
2232 | } | 2258 | } |
2233 | } | 2259 | } |
2260 | |||
2261 | cond_resched(); | ||
2234 | } | 2262 | } |
2235 | 2263 | ||
2236 | ret = 0; | 2264 | ret = 0; |
diff --git a/drivers/gpu/drm/sti/sti_cursor.c b/drivers/gpu/drm/sti/sti_cursor.c index cca75bddb9ad..5b3a41f74f21 100644 --- a/drivers/gpu/drm/sti/sti_cursor.c +++ b/drivers/gpu/drm/sti/sti_cursor.c | |||
@@ -33,7 +33,7 @@ | |||
33 | #define STI_CURS_MAX_SIZE 128 | 33 | #define STI_CURS_MAX_SIZE 128 |
34 | 34 | ||
35 | /* | 35 | /* |
36 | * pixmap dma buffer stucture | 36 | * pixmap dma buffer structure |
37 | * | 37 | * |
38 | * @paddr: physical address | 38 | * @paddr: physical address |
39 | * @size: buffer size | 39 | * @size: buffer size |
@@ -121,8 +121,7 @@ static int cursor_dbg_show(struct seq_file *s, void *data) | |||
121 | cursor_dbg_cml(s, cursor, readl(cursor->regs + CUR_CML)); | 121 | cursor_dbg_cml(s, cursor, readl(cursor->regs + CUR_CML)); |
122 | DBGFS_DUMP(CUR_AWS); | 122 | DBGFS_DUMP(CUR_AWS); |
123 | DBGFS_DUMP(CUR_AWE); | 123 | DBGFS_DUMP(CUR_AWE); |
124 | seq_puts(s, "\n"); | 124 | seq_putc(s, '\n'); |
125 | |||
126 | return 0; | 125 | return 0; |
127 | } | 126 | } |
128 | 127 | ||
diff --git a/drivers/gpu/drm/sti/sti_dvo.c b/drivers/gpu/drm/sti/sti_dvo.c index bb23318a44b7..24ebc6b2f34d 100644 --- a/drivers/gpu/drm/sti/sti_dvo.c +++ b/drivers/gpu/drm/sti/sti_dvo.c | |||
@@ -186,8 +186,7 @@ static int dvo_dbg_show(struct seq_file *s, void *data) | |||
186 | DBGFS_DUMP(DVO_LUT_PROG_MID); | 186 | DBGFS_DUMP(DVO_LUT_PROG_MID); |
187 | DBGFS_DUMP(DVO_LUT_PROG_HIGH); | 187 | DBGFS_DUMP(DVO_LUT_PROG_HIGH); |
188 | dvo_dbg_awg_microcode(s, dvo->regs + DVO_DIGSYNC_INSTR_I); | 188 | dvo_dbg_awg_microcode(s, dvo->regs + DVO_DIGSYNC_INSTR_I); |
189 | seq_puts(s, "\n"); | 189 | seq_putc(s, '\n'); |
190 | |||
191 | return 0; | 190 | return 0; |
192 | } | 191 | } |
193 | 192 | ||
diff --git a/drivers/gpu/drm/sti/sti_gdp.c b/drivers/gpu/drm/sti/sti_gdp.c index 88f16cdf6a4b..5ee0503945c8 100644 --- a/drivers/gpu/drm/sti/sti_gdp.c +++ b/drivers/gpu/drm/sti/sti_gdp.c | |||
@@ -149,7 +149,7 @@ static void gdp_dbg_ctl(struct seq_file *s, int val) | |||
149 | seq_puts(s, "\tColor:"); | 149 | seq_puts(s, "\tColor:"); |
150 | for (i = 0; i < ARRAY_SIZE(gdp_format_to_str); i++) { | 150 | for (i = 0; i < ARRAY_SIZE(gdp_format_to_str); i++) { |
151 | if (gdp_format_to_str[i].format == (val & 0x1F)) { | 151 | if (gdp_format_to_str[i].format == (val & 0x1F)) { |
152 | seq_printf(s, gdp_format_to_str[i].name); | 152 | seq_puts(s, gdp_format_to_str[i].name); |
153 | break; | 153 | break; |
154 | } | 154 | } |
155 | } | 155 | } |
@@ -266,8 +266,7 @@ static void gdp_node_dump_node(struct seq_file *s, struct sti_gdp_node *node) | |||
266 | seq_printf(s, "\n\tKEY2 0x%08X", node->gam_gdp_key2); | 266 | seq_printf(s, "\n\tKEY2 0x%08X", node->gam_gdp_key2); |
267 | seq_printf(s, "\n\tPPT 0x%08X", node->gam_gdp_ppt); | 267 | seq_printf(s, "\n\tPPT 0x%08X", node->gam_gdp_ppt); |
268 | gdp_dbg_ppt(s, node->gam_gdp_ppt); | 268 | gdp_dbg_ppt(s, node->gam_gdp_ppt); |
269 | seq_printf(s, "\n\tCML 0x%08X", node->gam_gdp_cml); | 269 | seq_printf(s, "\n\tCML 0x%08X\n", node->gam_gdp_cml); |
270 | seq_puts(s, "\n"); | ||
271 | } | 270 | } |
272 | 271 | ||
273 | static int gdp_node_dbg_show(struct seq_file *s, void *arg) | 272 | static int gdp_node_dbg_show(struct seq_file *s, void *arg) |
diff --git a/drivers/gpu/drm/sti/sti_hda.c b/drivers/gpu/drm/sti/sti_hda.c index 0c0a75bc8bc3..d6ed909d9d75 100644 --- a/drivers/gpu/drm/sti/sti_hda.c +++ b/drivers/gpu/drm/sti/sti_hda.c | |||
@@ -320,8 +320,7 @@ static void hda_dbg_awg_microcode(struct seq_file *s, void __iomem *reg) | |||
320 | { | 320 | { |
321 | unsigned int i; | 321 | unsigned int i; |
322 | 322 | ||
323 | seq_puts(s, "\n\n"); | 323 | seq_puts(s, "\n\n HDA AWG microcode:"); |
324 | seq_puts(s, " HDA AWG microcode:"); | ||
325 | for (i = 0; i < AWG_MAX_INST; i++) { | 324 | for (i = 0; i < AWG_MAX_INST; i++) { |
326 | if (i % 8 == 0) | 325 | if (i % 8 == 0) |
327 | seq_printf(s, "\n %04X:", i); | 326 | seq_printf(s, "\n %04X:", i); |
@@ -333,8 +332,7 @@ static void hda_dbg_video_dacs_ctrl(struct seq_file *s, void __iomem *reg) | |||
333 | { | 332 | { |
334 | u32 val = readl(reg); | 333 | u32 val = readl(reg); |
335 | 334 | ||
336 | seq_puts(s, "\n"); | 335 | seq_printf(s, "\n\n %-25s 0x%08X", "VIDEO_DACS_CONTROL", val); |
337 | seq_printf(s, "\n %-25s 0x%08X", "VIDEO_DACS_CONTROL", val); | ||
338 | seq_puts(s, "\tHD DACs "); | 336 | seq_puts(s, "\tHD DACs "); |
339 | seq_puts(s, val & DAC_CFG_HD_HZUVW_OFF_MASK ? "disabled" : "enabled"); | 337 | seq_puts(s, val & DAC_CFG_HD_HZUVW_OFF_MASK ? "disabled" : "enabled"); |
340 | } | 338 | } |
@@ -356,8 +354,7 @@ static int hda_dbg_show(struct seq_file *s, void *data) | |||
356 | hda_dbg_awg_microcode(s, hda->regs + HDA_SYNC_AWGI); | 354 | hda_dbg_awg_microcode(s, hda->regs + HDA_SYNC_AWGI); |
357 | if (hda->video_dacs_ctrl) | 355 | if (hda->video_dacs_ctrl) |
358 | hda_dbg_video_dacs_ctrl(s, hda->video_dacs_ctrl); | 356 | hda_dbg_video_dacs_ctrl(s, hda->video_dacs_ctrl); |
359 | seq_puts(s, "\n"); | 357 | seq_putc(s, '\n'); |
360 | |||
361 | return 0; | 358 | return 0; |
362 | } | 359 | } |
363 | 360 | ||
diff --git a/drivers/gpu/drm/sti/sti_hdmi.c b/drivers/gpu/drm/sti/sti_hdmi.c index 243905b6ae59..a59c95a8081b 100644 --- a/drivers/gpu/drm/sti/sti_hdmi.c +++ b/drivers/gpu/drm/sti/sti_hdmi.c | |||
@@ -592,7 +592,7 @@ static void hdmi_dbg_cfg(struct seq_file *s, int val) | |||
592 | { | 592 | { |
593 | int tmp; | 593 | int tmp; |
594 | 594 | ||
595 | seq_puts(s, "\t"); | 595 | seq_putc(s, '\t'); |
596 | tmp = val & HDMI_CFG_HDMI_NOT_DVI; | 596 | tmp = val & HDMI_CFG_HDMI_NOT_DVI; |
597 | DBGFS_PRINT_STR("mode:", tmp ? "HDMI" : "DVI"); | 597 | DBGFS_PRINT_STR("mode:", tmp ? "HDMI" : "DVI"); |
598 | seq_puts(s, "\t\t\t\t\t"); | 598 | seq_puts(s, "\t\t\t\t\t"); |
@@ -616,7 +616,7 @@ static void hdmi_dbg_sta(struct seq_file *s, int val) | |||
616 | { | 616 | { |
617 | int tmp; | 617 | int tmp; |
618 | 618 | ||
619 | seq_puts(s, "\t"); | 619 | seq_putc(s, '\t'); |
620 | tmp = (val & HDMI_STA_DLL_LCK); | 620 | tmp = (val & HDMI_STA_DLL_LCK); |
621 | DBGFS_PRINT_STR("pll:", tmp ? "locked" : "not locked"); | 621 | DBGFS_PRINT_STR("pll:", tmp ? "locked" : "not locked"); |
622 | seq_puts(s, "\t\t\t\t\t"); | 622 | seq_puts(s, "\t\t\t\t\t"); |
@@ -632,7 +632,7 @@ static void hdmi_dbg_sw_di_cfg(struct seq_file *s, int val) | |||
632 | "once every field", | 632 | "once every field", |
633 | "once every frame"}; | 633 | "once every frame"}; |
634 | 634 | ||
635 | seq_puts(s, "\t"); | 635 | seq_putc(s, '\t'); |
636 | tmp = (val & HDMI_IFRAME_CFG_DI_N(HDMI_IFRAME_MASK, 1)); | 636 | tmp = (val & HDMI_IFRAME_CFG_DI_N(HDMI_IFRAME_MASK, 1)); |
637 | DBGFS_PRINT_STR("Data island 1:", en_di[tmp]); | 637 | DBGFS_PRINT_STR("Data island 1:", en_di[tmp]); |
638 | seq_puts(s, "\t\t\t\t\t"); | 638 | seq_puts(s, "\t\t\t\t\t"); |
@@ -664,16 +664,16 @@ static int hdmi_dbg_show(struct seq_file *s, void *data) | |||
664 | DBGFS_DUMP("\n", HDMI_STA); | 664 | DBGFS_DUMP("\n", HDMI_STA); |
665 | hdmi_dbg_sta(s, hdmi_read(hdmi, HDMI_STA)); | 665 | hdmi_dbg_sta(s, hdmi_read(hdmi, HDMI_STA)); |
666 | DBGFS_DUMP("", HDMI_ACTIVE_VID_XMIN); | 666 | DBGFS_DUMP("", HDMI_ACTIVE_VID_XMIN); |
667 | seq_puts(s, "\t"); | 667 | seq_putc(s, '\t'); |
668 | DBGFS_PRINT_INT("Xmin:", hdmi_read(hdmi, HDMI_ACTIVE_VID_XMIN)); | 668 | DBGFS_PRINT_INT("Xmin:", hdmi_read(hdmi, HDMI_ACTIVE_VID_XMIN)); |
669 | DBGFS_DUMP("", HDMI_ACTIVE_VID_XMAX); | 669 | DBGFS_DUMP("", HDMI_ACTIVE_VID_XMAX); |
670 | seq_puts(s, "\t"); | 670 | seq_putc(s, '\t'); |
671 | DBGFS_PRINT_INT("Xmax:", hdmi_read(hdmi, HDMI_ACTIVE_VID_XMAX)); | 671 | DBGFS_PRINT_INT("Xmax:", hdmi_read(hdmi, HDMI_ACTIVE_VID_XMAX)); |
672 | DBGFS_DUMP("", HDMI_ACTIVE_VID_YMIN); | 672 | DBGFS_DUMP("", HDMI_ACTIVE_VID_YMIN); |
673 | seq_puts(s, "\t"); | 673 | seq_putc(s, '\t'); |
674 | DBGFS_PRINT_INT("Ymin:", hdmi_read(hdmi, HDMI_ACTIVE_VID_YMIN)); | 674 | DBGFS_PRINT_INT("Ymin:", hdmi_read(hdmi, HDMI_ACTIVE_VID_YMIN)); |
675 | DBGFS_DUMP("", HDMI_ACTIVE_VID_YMAX); | 675 | DBGFS_DUMP("", HDMI_ACTIVE_VID_YMAX); |
676 | seq_puts(s, "\t"); | 676 | seq_putc(s, '\t'); |
677 | DBGFS_PRINT_INT("Ymax:", hdmi_read(hdmi, HDMI_ACTIVE_VID_YMAX)); | 677 | DBGFS_PRINT_INT("Ymax:", hdmi_read(hdmi, HDMI_ACTIVE_VID_YMAX)); |
678 | DBGFS_DUMP("", HDMI_SW_DI_CFG); | 678 | DBGFS_DUMP("", HDMI_SW_DI_CFG); |
679 | hdmi_dbg_sw_di_cfg(s, hdmi_read(hdmi, HDMI_SW_DI_CFG)); | 679 | hdmi_dbg_sw_di_cfg(s, hdmi_read(hdmi, HDMI_SW_DI_CFG)); |
@@ -692,8 +692,7 @@ static int hdmi_dbg_show(struct seq_file *s, void *data) | |||
692 | DBGFS_DUMP_DI(HDMI_SW_DI_N_PKT_WORD4, HDMI_IFRAME_SLOT_AVI); | 692 | DBGFS_DUMP_DI(HDMI_SW_DI_N_PKT_WORD4, HDMI_IFRAME_SLOT_AVI); |
693 | DBGFS_DUMP_DI(HDMI_SW_DI_N_PKT_WORD5, HDMI_IFRAME_SLOT_AVI); | 693 | DBGFS_DUMP_DI(HDMI_SW_DI_N_PKT_WORD5, HDMI_IFRAME_SLOT_AVI); |
694 | DBGFS_DUMP_DI(HDMI_SW_DI_N_PKT_WORD6, HDMI_IFRAME_SLOT_AVI); | 694 | DBGFS_DUMP_DI(HDMI_SW_DI_N_PKT_WORD6, HDMI_IFRAME_SLOT_AVI); |
695 | seq_puts(s, "\n"); | 695 | seq_printf(s, "\n\n AUDIO Infoframe (Data Island slot N=%d):", |
696 | seq_printf(s, "\n AUDIO Infoframe (Data Island slot N=%d):", | ||
697 | HDMI_IFRAME_SLOT_AUDIO); | 696 | HDMI_IFRAME_SLOT_AUDIO); |
698 | DBGFS_DUMP_DI(HDMI_SW_DI_N_HEAD_WORD, HDMI_IFRAME_SLOT_AUDIO); | 697 | DBGFS_DUMP_DI(HDMI_SW_DI_N_HEAD_WORD, HDMI_IFRAME_SLOT_AUDIO); |
699 | DBGFS_DUMP_DI(HDMI_SW_DI_N_PKT_WORD0, HDMI_IFRAME_SLOT_AUDIO); | 698 | DBGFS_DUMP_DI(HDMI_SW_DI_N_PKT_WORD0, HDMI_IFRAME_SLOT_AUDIO); |
@@ -703,8 +702,7 @@ static int hdmi_dbg_show(struct seq_file *s, void *data) | |||
703 | DBGFS_DUMP_DI(HDMI_SW_DI_N_PKT_WORD4, HDMI_IFRAME_SLOT_AUDIO); | 702 | DBGFS_DUMP_DI(HDMI_SW_DI_N_PKT_WORD4, HDMI_IFRAME_SLOT_AUDIO); |
704 | DBGFS_DUMP_DI(HDMI_SW_DI_N_PKT_WORD5, HDMI_IFRAME_SLOT_AUDIO); | 703 | DBGFS_DUMP_DI(HDMI_SW_DI_N_PKT_WORD5, HDMI_IFRAME_SLOT_AUDIO); |
705 | DBGFS_DUMP_DI(HDMI_SW_DI_N_PKT_WORD6, HDMI_IFRAME_SLOT_AUDIO); | 704 | DBGFS_DUMP_DI(HDMI_SW_DI_N_PKT_WORD6, HDMI_IFRAME_SLOT_AUDIO); |
706 | seq_puts(s, "\n"); | 705 | seq_printf(s, "\n\n VENDOR SPECIFIC Infoframe (Data Island slot N=%d):", |
707 | seq_printf(s, "\n VENDOR SPECIFIC Infoframe (Data Island slot N=%d):", | ||
708 | HDMI_IFRAME_SLOT_VENDOR); | 706 | HDMI_IFRAME_SLOT_VENDOR); |
709 | DBGFS_DUMP_DI(HDMI_SW_DI_N_HEAD_WORD, HDMI_IFRAME_SLOT_VENDOR); | 707 | DBGFS_DUMP_DI(HDMI_SW_DI_N_HEAD_WORD, HDMI_IFRAME_SLOT_VENDOR); |
710 | DBGFS_DUMP_DI(HDMI_SW_DI_N_PKT_WORD0, HDMI_IFRAME_SLOT_VENDOR); | 708 | DBGFS_DUMP_DI(HDMI_SW_DI_N_PKT_WORD0, HDMI_IFRAME_SLOT_VENDOR); |
@@ -714,8 +712,7 @@ static int hdmi_dbg_show(struct seq_file *s, void *data) | |||
714 | DBGFS_DUMP_DI(HDMI_SW_DI_N_PKT_WORD4, HDMI_IFRAME_SLOT_VENDOR); | 712 | DBGFS_DUMP_DI(HDMI_SW_DI_N_PKT_WORD4, HDMI_IFRAME_SLOT_VENDOR); |
715 | DBGFS_DUMP_DI(HDMI_SW_DI_N_PKT_WORD5, HDMI_IFRAME_SLOT_VENDOR); | 713 | DBGFS_DUMP_DI(HDMI_SW_DI_N_PKT_WORD5, HDMI_IFRAME_SLOT_VENDOR); |
716 | DBGFS_DUMP_DI(HDMI_SW_DI_N_PKT_WORD6, HDMI_IFRAME_SLOT_VENDOR); | 714 | DBGFS_DUMP_DI(HDMI_SW_DI_N_PKT_WORD6, HDMI_IFRAME_SLOT_VENDOR); |
717 | seq_puts(s, "\n"); | 715 | seq_putc(s, '\n'); |
718 | |||
719 | return 0; | 716 | return 0; |
720 | } | 717 | } |
721 | 718 | ||
diff --git a/drivers/gpu/drm/sti/sti_hqvdp.c b/drivers/gpu/drm/sti/sti_hqvdp.c index 66f843148ef7..a1c161f77804 100644 --- a/drivers/gpu/drm/sti/sti_hqvdp.c +++ b/drivers/gpu/drm/sti/sti_hqvdp.c | |||
@@ -625,8 +625,7 @@ static int hqvdp_dbg_show(struct seq_file *s, void *data) | |||
625 | hqvdp_dbg_dump_cmd(s, (struct sti_hqvdp_cmd *)virt); | 625 | hqvdp_dbg_dump_cmd(s, (struct sti_hqvdp_cmd *)virt); |
626 | } | 626 | } |
627 | 627 | ||
628 | seq_puts(s, "\n"); | 628 | seq_putc(s, '\n'); |
629 | |||
630 | return 0; | 629 | return 0; |
631 | } | 630 | } |
632 | 631 | ||
@@ -1357,12 +1356,12 @@ static int sti_hqvdp_probe(struct platform_device *pdev) | |||
1357 | 1356 | ||
1358 | /* Get Memory resources */ | 1357 | /* Get Memory resources */ |
1359 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 1358 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
1360 | if (res == NULL) { | 1359 | if (!res) { |
1361 | DRM_ERROR("Get memory resource failed\n"); | 1360 | DRM_ERROR("Get memory resource failed\n"); |
1362 | return -ENXIO; | 1361 | return -ENXIO; |
1363 | } | 1362 | } |
1364 | hqvdp->regs = devm_ioremap(dev, res->start, resource_size(res)); | 1363 | hqvdp->regs = devm_ioremap(dev, res->start, resource_size(res)); |
1365 | if (hqvdp->regs == NULL) { | 1364 | if (!hqvdp->regs) { |
1366 | DRM_ERROR("Register mapping failed\n"); | 1365 | DRM_ERROR("Register mapping failed\n"); |
1367 | return -ENXIO; | 1366 | return -ENXIO; |
1368 | } | 1367 | } |
diff --git a/drivers/gpu/drm/sti/sti_mixer.c b/drivers/gpu/drm/sti/sti_mixer.c index 4ddc58f7fe2e..2bd1d46fe1cd 100644 --- a/drivers/gpu/drm/sti/sti_mixer.c +++ b/drivers/gpu/drm/sti/sti_mixer.c | |||
@@ -162,8 +162,7 @@ static int mixer_dbg_show(struct seq_file *s, void *arg) | |||
162 | DBGFS_DUMP(GAM_MIXER_MBP); | 162 | DBGFS_DUMP(GAM_MIXER_MBP); |
163 | DBGFS_DUMP(GAM_MIXER_MX0); | 163 | DBGFS_DUMP(GAM_MIXER_MX0); |
164 | mixer_dbg_mxn(s, mixer->regs + GAM_MIXER_MX0); | 164 | mixer_dbg_mxn(s, mixer->regs + GAM_MIXER_MX0); |
165 | seq_puts(s, "\n"); | 165 | seq_putc(s, '\n'); |
166 | |||
167 | return 0; | 166 | return 0; |
168 | } | 167 | } |
169 | 168 | ||
diff --git a/drivers/gpu/drm/sti/sti_tvout.c b/drivers/gpu/drm/sti/sti_tvout.c index 8b8ea717c121..8959fcc743a8 100644 --- a/drivers/gpu/drm/sti/sti_tvout.c +++ b/drivers/gpu/drm/sti/sti_tvout.c | |||
@@ -459,7 +459,7 @@ static void tvout_dbg_vip(struct seq_file *s, int val) | |||
459 | "Aux (color matrix by-passed)", | 459 | "Aux (color matrix by-passed)", |
460 | "", "", "", "", "", "Force value"}; | 460 | "", "", "", "", "", "Force value"}; |
461 | 461 | ||
462 | seq_puts(s, "\t"); | 462 | seq_putc(s, '\t'); |
463 | mask = TVO_VIP_REORDER_MASK << TVO_VIP_REORDER_R_SHIFT; | 463 | mask = TVO_VIP_REORDER_MASK << TVO_VIP_REORDER_R_SHIFT; |
464 | r = (val & mask) >> TVO_VIP_REORDER_R_SHIFT; | 464 | r = (val & mask) >> TVO_VIP_REORDER_R_SHIFT; |
465 | mask = TVO_VIP_REORDER_MASK << TVO_VIP_REORDER_G_SHIFT; | 465 | mask = TVO_VIP_REORDER_MASK << TVO_VIP_REORDER_G_SHIFT; |
@@ -558,8 +558,7 @@ static int tvout_dbg_show(struct seq_file *s, void *data) | |||
558 | DBGFS_DUMP(TVO_CSC_AUX_M6); | 558 | DBGFS_DUMP(TVO_CSC_AUX_M6); |
559 | DBGFS_DUMP(TVO_CSC_AUX_M7); | 559 | DBGFS_DUMP(TVO_CSC_AUX_M7); |
560 | DBGFS_DUMP(TVO_AUX_IN_VID_FORMAT); | 560 | DBGFS_DUMP(TVO_AUX_IN_VID_FORMAT); |
561 | seq_puts(s, "\n"); | 561 | seq_putc(s, '\n'); |
562 | |||
563 | return 0; | 562 | return 0; |
564 | } | 563 | } |
565 | 564 | ||
@@ -847,7 +846,7 @@ static int sti_tvout_probe(struct platform_device *pdev) | |||
847 | 846 | ||
848 | tvout->dev = dev; | 847 | tvout->dev = dev; |
849 | 848 | ||
850 | /* get Memory ressources */ | 849 | /* get memory resources */ |
851 | res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "tvout-reg"); | 850 | res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "tvout-reg"); |
852 | if (!res) { | 851 | if (!res) { |
853 | DRM_ERROR("Invalid glue resource\n"); | 852 | DRM_ERROR("Invalid glue resource\n"); |
diff --git a/drivers/gpu/drm/sti/sti_vid.c b/drivers/gpu/drm/sti/sti_vid.c index 2ad59892b57e..577a3341d3c1 100644 --- a/drivers/gpu/drm/sti/sti_vid.c +++ b/drivers/gpu/drm/sti/sti_vid.c | |||
@@ -61,7 +61,7 @@ | |||
61 | static void vid_dbg_ctl(struct seq_file *s, int val) | 61 | static void vid_dbg_ctl(struct seq_file *s, int val) |
62 | { | 62 | { |
63 | val = val >> 30; | 63 | val = val >> 30; |
64 | seq_puts(s, "\t"); | 64 | seq_putc(s, '\t'); |
65 | 65 | ||
66 | if (!(val & 1)) | 66 | if (!(val & 1)) |
67 | seq_puts(s, "NOT "); | 67 | seq_puts(s, "NOT "); |
@@ -114,8 +114,7 @@ static int vid_dbg_show(struct seq_file *s, void *arg) | |||
114 | DBGFS_DUMP(VID_BC); | 114 | DBGFS_DUMP(VID_BC); |
115 | DBGFS_DUMP(VID_TINT); | 115 | DBGFS_DUMP(VID_TINT); |
116 | DBGFS_DUMP(VID_CSAT); | 116 | DBGFS_DUMP(VID_CSAT); |
117 | seq_puts(s, "\n"); | 117 | seq_putc(s, '\n'); |
118 | |||
119 | return 0; | 118 | return 0; |
120 | } | 119 | } |
121 | 120 | ||
diff --git a/drivers/gpu/drm/stm/Kconfig b/drivers/gpu/drm/stm/Kconfig new file mode 100644 index 000000000000..2c4817fb0890 --- /dev/null +++ b/drivers/gpu/drm/stm/Kconfig | |||
@@ -0,0 +1,16 @@ | |||
1 | config DRM_STM | ||
2 | tristate "DRM Support for STMicroelectronics SoC Series" | ||
3 | depends on DRM && (ARCH_STM32 || ARCH_MULTIPLATFORM) | ||
4 | select DRM_KMS_HELPER | ||
5 | select DRM_GEM_CMA_HELPER | ||
6 | select DRM_KMS_CMA_HELPER | ||
7 | select DRM_PANEL | ||
8 | select VIDEOMODE_HELPERS | ||
9 | select FB_PROVIDE_GET_FB_UNMAPPED_AREA | ||
10 | default y | ||
11 | |||
12 | help | ||
13 | Enable support for the on-chip display controller on | ||
14 | STMicroelectronics STM32 MCUs. | ||
15 | To compile this driver as a module, choose M here: the module | ||
16 | will be called stm-drm. | ||
diff --git a/drivers/gpu/drm/stm/Makefile b/drivers/gpu/drm/stm/Makefile new file mode 100644 index 000000000000..e114d45dbd42 --- /dev/null +++ b/drivers/gpu/drm/stm/Makefile | |||
@@ -0,0 +1,7 @@ | |||
1 | ccflags-y := -Iinclude/drm | ||
2 | |||
3 | stm-drm-y := \ | ||
4 | drv.o \ | ||
5 | ltdc.o | ||
6 | |||
7 | obj-$(CONFIG_DRM_STM) += stm-drm.o | ||
diff --git a/drivers/gpu/drm/stm/drv.c b/drivers/gpu/drm/stm/drv.c new file mode 100644 index 000000000000..83ab48f1fd00 --- /dev/null +++ b/drivers/gpu/drm/stm/drv.c | |||
@@ -0,0 +1,221 @@ | |||
1 | /* | ||
2 | * Copyright (C) STMicroelectronics SA 2017 | ||
3 | * | ||
4 | * Authors: Philippe Cornu <philippe.cornu@st.com> | ||
5 | * Yannick Fertre <yannick.fertre@st.com> | ||
6 | * Fabien Dessenne <fabien.dessenne@st.com> | ||
7 | * Mickael Reulier <mickael.reulier@st.com> | ||
8 | * | ||
9 | * License terms: GNU General Public License (GPL), version 2 | ||
10 | */ | ||
11 | |||
12 | #include <linux/component.h> | ||
13 | #include <linux/of_platform.h> | ||
14 | |||
15 | #include <drm/drm_atomic.h> | ||
16 | #include <drm/drm_atomic_helper.h> | ||
17 | #include <drm/drm_crtc_helper.h> | ||
18 | #include <drm/drm_fb_cma_helper.h> | ||
19 | #include <drm/drm_gem_cma_helper.h> | ||
20 | |||
21 | #include "ltdc.h" | ||
22 | |||
23 | #define DRIVER_NAME "stm" | ||
24 | #define DRIVER_DESC "STMicroelectronics SoC DRM" | ||
25 | #define DRIVER_DATE "20170330" | ||
26 | #define DRIVER_MAJOR 1 | ||
27 | #define DRIVER_MINOR 0 | ||
28 | #define DRIVER_PATCH_LEVEL 0 | ||
29 | |||
30 | #define STM_MAX_FB_WIDTH 2048 | ||
31 | #define STM_MAX_FB_HEIGHT 2048 /* same as width to handle orientation */ | ||
32 | |||
33 | static void drv_output_poll_changed(struct drm_device *ddev) | ||
34 | { | ||
35 | struct ltdc_device *ldev = ddev->dev_private; | ||
36 | |||
37 | drm_fbdev_cma_hotplug_event(ldev->fbdev); | ||
38 | } | ||
39 | |||
40 | static const struct drm_mode_config_funcs drv_mode_config_funcs = { | ||
41 | .fb_create = drm_fb_cma_create, | ||
42 | .output_poll_changed = drv_output_poll_changed, | ||
43 | .atomic_check = drm_atomic_helper_check, | ||
44 | .atomic_commit = drm_atomic_helper_commit, | ||
45 | }; | ||
46 | |||
47 | static void drv_lastclose(struct drm_device *ddev) | ||
48 | { | ||
49 | struct ltdc_device *ldev = ddev->dev_private; | ||
50 | |||
51 | DRM_DEBUG("%s\n", __func__); | ||
52 | |||
53 | drm_fbdev_cma_restore_mode(ldev->fbdev); | ||
54 | } | ||
55 | |||
56 | DEFINE_DRM_GEM_CMA_FOPS(drv_driver_fops); | ||
57 | |||
58 | static struct drm_driver drv_driver = { | ||
59 | .driver_features = DRIVER_MODESET | DRIVER_GEM | DRIVER_PRIME | | ||
60 | DRIVER_ATOMIC, | ||
61 | .lastclose = drv_lastclose, | ||
62 | .name = DRIVER_NAME, | ||
63 | .desc = DRIVER_DESC, | ||
64 | .date = DRIVER_DATE, | ||
65 | .major = DRIVER_MAJOR, | ||
66 | .minor = DRIVER_MINOR, | ||
67 | .patchlevel = DRIVER_PATCH_LEVEL, | ||
68 | .fops = &drv_driver_fops, | ||
69 | .dumb_create = drm_gem_cma_dumb_create, | ||
70 | .dumb_map_offset = drm_gem_cma_dumb_map_offset, | ||
71 | .dumb_destroy = drm_gem_dumb_destroy, | ||
72 | .prime_handle_to_fd = drm_gem_prime_handle_to_fd, | ||
73 | .prime_fd_to_handle = drm_gem_prime_fd_to_handle, | ||
74 | .gem_free_object_unlocked = drm_gem_cma_free_object, | ||
75 | .gem_vm_ops = &drm_gem_cma_vm_ops, | ||
76 | .gem_prime_export = drm_gem_prime_export, | ||
77 | .gem_prime_import = drm_gem_prime_import, | ||
78 | .gem_prime_get_sg_table = drm_gem_cma_prime_get_sg_table, | ||
79 | .gem_prime_import_sg_table = drm_gem_cma_prime_import_sg_table, | ||
80 | .gem_prime_vmap = drm_gem_cma_prime_vmap, | ||
81 | .gem_prime_vunmap = drm_gem_cma_prime_vunmap, | ||
82 | .gem_prime_mmap = drm_gem_cma_prime_mmap, | ||
83 | .enable_vblank = ltdc_crtc_enable_vblank, | ||
84 | .disable_vblank = ltdc_crtc_disable_vblank, | ||
85 | }; | ||
86 | |||
87 | static int drv_load(struct drm_device *ddev) | ||
88 | { | ||
89 | struct platform_device *pdev = to_platform_device(ddev->dev); | ||
90 | struct drm_fbdev_cma *fbdev; | ||
91 | struct ltdc_device *ldev; | ||
92 | int ret; | ||
93 | |||
94 | DRM_DEBUG("%s\n", __func__); | ||
95 | |||
96 | ldev = devm_kzalloc(ddev->dev, sizeof(*ldev), GFP_KERNEL); | ||
97 | if (!ldev) | ||
98 | return -ENOMEM; | ||
99 | |||
100 | ddev->dev_private = (void *)ldev; | ||
101 | |||
102 | drm_mode_config_init(ddev); | ||
103 | |||
104 | /* | ||
105 | * set max width and height as default value. | ||
106 | * this value would be used to check framebuffer size limitation | ||
107 | * at drm_mode_addfb(). | ||
108 | */ | ||
109 | ddev->mode_config.min_width = 0; | ||
110 | ddev->mode_config.min_height = 0; | ||
111 | ddev->mode_config.max_width = STM_MAX_FB_WIDTH; | ||
112 | ddev->mode_config.max_height = STM_MAX_FB_HEIGHT; | ||
113 | ddev->mode_config.funcs = &drv_mode_config_funcs; | ||
114 | |||
115 | ret = ltdc_load(ddev); | ||
116 | if (ret) | ||
117 | goto err; | ||
118 | |||
119 | drm_mode_config_reset(ddev); | ||
120 | drm_kms_helper_poll_init(ddev); | ||
121 | |||
122 | if (ddev->mode_config.num_connector) { | ||
123 | ldev = ddev->dev_private; | ||
124 | fbdev = drm_fbdev_cma_init(ddev, 16, | ||
125 | ddev->mode_config.num_connector); | ||
126 | if (IS_ERR(fbdev)) { | ||
127 | DRM_DEBUG("Warning: fails to create fbdev\n"); | ||
128 | fbdev = NULL; | ||
129 | } | ||
130 | ldev->fbdev = fbdev; | ||
131 | } | ||
132 | |||
133 | platform_set_drvdata(pdev, ddev); | ||
134 | |||
135 | return 0; | ||
136 | err: | ||
137 | drm_mode_config_cleanup(ddev); | ||
138 | return ret; | ||
139 | } | ||
140 | |||
141 | static void drv_unload(struct drm_device *ddev) | ||
142 | { | ||
143 | struct ltdc_device *ldev = ddev->dev_private; | ||
144 | |||
145 | DRM_DEBUG("%s\n", __func__); | ||
146 | |||
147 | if (ldev->fbdev) { | ||
148 | drm_fbdev_cma_fini(ldev->fbdev); | ||
149 | ldev->fbdev = NULL; | ||
150 | } | ||
151 | drm_kms_helper_poll_fini(ddev); | ||
152 | ltdc_unload(ddev); | ||
153 | drm_mode_config_cleanup(ddev); | ||
154 | } | ||
155 | |||
156 | static int stm_drm_platform_probe(struct platform_device *pdev) | ||
157 | { | ||
158 | struct device *dev = &pdev->dev; | ||
159 | struct drm_device *ddev; | ||
160 | int ret; | ||
161 | |||
162 | DRM_DEBUG("%s\n", __func__); | ||
163 | |||
164 | dma_set_coherent_mask(dev, DMA_BIT_MASK(32)); | ||
165 | |||
166 | ddev = drm_dev_alloc(&drv_driver, dev); | ||
167 | if (IS_ERR(ddev)) | ||
168 | return PTR_ERR(ddev); | ||
169 | |||
170 | ret = drv_load(ddev); | ||
171 | if (ret) | ||
172 | goto err_unref; | ||
173 | |||
174 | ret = drm_dev_register(ddev, 0); | ||
175 | if (ret) | ||
176 | goto err_unref; | ||
177 | |||
178 | return 0; | ||
179 | |||
180 | err_unref: | ||
181 | drm_dev_unref(ddev); | ||
182 | |||
183 | return ret; | ||
184 | } | ||
185 | |||
186 | static int stm_drm_platform_remove(struct platform_device *pdev) | ||
187 | { | ||
188 | struct drm_device *ddev = platform_get_drvdata(pdev); | ||
189 | |||
190 | DRM_DEBUG("%s\n", __func__); | ||
191 | |||
192 | drm_dev_unregister(ddev); | ||
193 | drv_unload(ddev); | ||
194 | drm_dev_unref(ddev); | ||
195 | |||
196 | return 0; | ||
197 | } | ||
198 | |||
199 | static const struct of_device_id drv_dt_ids[] = { | ||
200 | { .compatible = "st,stm32-ltdc"}, | ||
201 | { /* end node */ }, | ||
202 | }; | ||
203 | MODULE_DEVICE_TABLE(of, drv_dt_ids); | ||
204 | |||
205 | static struct platform_driver stm_drm_platform_driver = { | ||
206 | .probe = stm_drm_platform_probe, | ||
207 | .remove = stm_drm_platform_remove, | ||
208 | .driver = { | ||
209 | .name = DRIVER_NAME, | ||
210 | .of_match_table = drv_dt_ids, | ||
211 | }, | ||
212 | }; | ||
213 | |||
214 | module_platform_driver(stm_drm_platform_driver); | ||
215 | |||
216 | MODULE_AUTHOR("Philippe Cornu <philippe.cornu@st.com>"); | ||
217 | MODULE_AUTHOR("Yannick Fertre <yannick.fertre@st.com>"); | ||
218 | MODULE_AUTHOR("Fabien Dessenne <fabien.dessenne@st.com>"); | ||
219 | MODULE_AUTHOR("Mickael Reulier <mickael.reulier@st.com>"); | ||
220 | MODULE_DESCRIPTION("STMicroelectronics ST DRM LTDC driver"); | ||
221 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/drivers/gpu/drm/stm/ltdc.c b/drivers/gpu/drm/stm/ltdc.c new file mode 100644 index 000000000000..a40418cda74a --- /dev/null +++ b/drivers/gpu/drm/stm/ltdc.c | |||
@@ -0,0 +1,1160 @@ | |||
1 | /* | ||
2 | * Copyright (C) STMicroelectronics SA 2017 | ||
3 | * | ||
4 | * Authors: Philippe Cornu <philippe.cornu@st.com> | ||
5 | * Yannick Fertre <yannick.fertre@st.com> | ||
6 | * Fabien Dessenne <fabien.dessenne@st.com> | ||
7 | * Mickael Reulier <mickael.reulier@st.com> | ||
8 | * | ||
9 | * License terms: GNU General Public License (GPL), version 2 | ||
10 | */ | ||
11 | |||
12 | #include <linux/clk.h> | ||
13 | #include <linux/component.h> | ||
14 | #include <linux/of_address.h> | ||
15 | #include <linux/of_graph.h> | ||
16 | #include <linux/reset.h> | ||
17 | |||
18 | #include <drm/drm_atomic.h> | ||
19 | #include <drm/drm_atomic_helper.h> | ||
20 | #include <drm/drm_crtc_helper.h> | ||
21 | #include <drm/drm_fb_cma_helper.h> | ||
22 | #include <drm/drm_gem_cma_helper.h> | ||
23 | #include <drm/drm_of.h> | ||
24 | #include <drm/drm_panel.h> | ||
25 | #include <drm/drm_plane_helper.h> | ||
26 | |||
27 | #include <video/videomode.h> | ||
28 | |||
29 | #include "ltdc.h" | ||
30 | |||
31 | #define NB_CRTC 1 | ||
32 | #define CRTC_MASK GENMASK(NB_CRTC - 1, 0) | ||
33 | |||
34 | #define MAX_IRQ 4 | ||
35 | |||
36 | #define HWVER_10200 0x010200 | ||
37 | #define HWVER_10300 0x010300 | ||
38 | #define HWVER_20101 0x020101 | ||
39 | |||
40 | /* | ||
41 | * The address of some registers depends on the HW version: such registers have | ||
42 | * an extra offset specified with reg_ofs. | ||
43 | */ | ||
44 | #define REG_OFS_NONE 0 | ||
45 | #define REG_OFS_4 4 /* Insertion of "Layer Configuration 2" reg */ | ||
46 | #define REG_OFS (ldev->caps.reg_ofs) | ||
47 | #define LAY_OFS 0x80 /* Register Offset between 2 layers */ | ||
48 | |||
49 | /* Global register offsets */ | ||
50 | #define LTDC_IDR 0x0000 /* IDentification */ | ||
51 | #define LTDC_LCR 0x0004 /* Layer Count */ | ||
52 | #define LTDC_SSCR 0x0008 /* Synchronization Size Configuration */ | ||
53 | #define LTDC_BPCR 0x000C /* Back Porch Configuration */ | ||
54 | #define LTDC_AWCR 0x0010 /* Active Width Configuration */ | ||
55 | #define LTDC_TWCR 0x0014 /* Total Width Configuration */ | ||
56 | #define LTDC_GCR 0x0018 /* Global Control */ | ||
57 | #define LTDC_GC1R 0x001C /* Global Configuration 1 */ | ||
58 | #define LTDC_GC2R 0x0020 /* Global Configuration 2 */ | ||
59 | #define LTDC_SRCR 0x0024 /* Shadow Reload Configuration */ | ||
60 | #define LTDC_GACR 0x0028 /* GAmma Correction */ | ||
61 | #define LTDC_BCCR 0x002C /* Background Color Configuration */ | ||
62 | #define LTDC_IER 0x0034 /* Interrupt Enable */ | ||
63 | #define LTDC_ISR 0x0038 /* Interrupt Status */ | ||
64 | #define LTDC_ICR 0x003C /* Interrupt Clear */ | ||
65 | #define LTDC_LIPCR 0x0040 /* Line Interrupt Position Configuration */ | ||
66 | #define LTDC_CPSR 0x0044 /* Current Position Status */ | ||
67 | #define LTDC_CDSR 0x0048 /* Current Display Status */ | ||
68 | |||
69 | /* Layer register offsets */ | ||
70 | #define LTDC_L1LC1R (0x0080) /* L1 Layer Configuration 1 */ | ||
71 | #define LTDC_L1LC2R (0x0084) /* L1 Layer Configuration 2 */ | ||
72 | #define LTDC_L1CR (0x0084 + REG_OFS) /* L1 Control */ | ||
73 | #define LTDC_L1WHPCR (0x0088 + REG_OFS) /* L1 Window Hor Position Config */ | ||
74 | #define LTDC_L1WVPCR (0x008C + REG_OFS) /* L1 Window Vert Position Config */ | ||
75 | #define LTDC_L1CKCR (0x0090 + REG_OFS) /* L1 Color Keying Configuration */ | ||
76 | #define LTDC_L1PFCR (0x0094 + REG_OFS) /* L1 Pixel Format Configuration */ | ||
77 | #define LTDC_L1CACR (0x0098 + REG_OFS) /* L1 Constant Alpha Config */ | ||
78 | #define LTDC_L1DCCR (0x009C + REG_OFS) /* L1 Default Color Configuration */ | ||
79 | #define LTDC_L1BFCR (0x00A0 + REG_OFS) /* L1 Blend Factors Configuration */ | ||
80 | #define LTDC_L1FBBCR (0x00A4 + REG_OFS) /* L1 FrameBuffer Bus Control */ | ||
81 | #define LTDC_L1AFBCR (0x00A8 + REG_OFS) /* L1 AuxFB Control */ | ||
82 | #define LTDC_L1CFBAR (0x00AC + REG_OFS) /* L1 Color FrameBuffer Address */ | ||
83 | #define LTDC_L1CFBLR (0x00B0 + REG_OFS) /* L1 Color FrameBuffer Length */ | ||
84 | #define LTDC_L1CFBLNR (0x00B4 + REG_OFS) /* L1 Color FrameBuffer Line Nb */ | ||
85 | #define LTDC_L1AFBAR (0x00B8 + REG_OFS) /* L1 AuxFB Address */ | ||
86 | #define LTDC_L1AFBLR (0x00BC + REG_OFS) /* L1 AuxFB Length */ | ||
87 | #define LTDC_L1AFBLNR (0x00C0 + REG_OFS) /* L1 AuxFB Line Number */ | ||
88 | #define LTDC_L1CLUTWR (0x00C4 + REG_OFS) /* L1 CLUT Write */ | ||
89 | #define LTDC_L1YS1R (0x00E0 + REG_OFS) /* L1 YCbCr Scale 1 */ | ||
90 | #define LTDC_L1YS2R (0x00E4 + REG_OFS) /* L1 YCbCr Scale 2 */ | ||
91 | |||
92 | /* Bit definitions */ | ||
93 | #define SSCR_VSH GENMASK(10, 0) /* Vertical Synchronization Height */ | ||
94 | #define SSCR_HSW GENMASK(27, 16) /* Horizontal Synchronization Width */ | ||
95 | |||
96 | #define BPCR_AVBP GENMASK(10, 0) /* Accumulated Vertical Back Porch */ | ||
97 | #define BPCR_AHBP GENMASK(27, 16) /* Accumulated Horizontal Back Porch */ | ||
98 | |||
99 | #define AWCR_AAH GENMASK(10, 0) /* Accumulated Active Height */ | ||
100 | #define AWCR_AAW GENMASK(27, 16) /* Accumulated Active Width */ | ||
101 | |||
102 | #define TWCR_TOTALH GENMASK(10, 0) /* TOTAL Height */ | ||
103 | #define TWCR_TOTALW GENMASK(27, 16) /* TOTAL Width */ | ||
104 | |||
105 | #define GCR_LTDCEN BIT(0) /* LTDC ENable */ | ||
106 | #define GCR_DEN BIT(16) /* Dither ENable */ | ||
107 | #define GCR_PCPOL BIT(28) /* Pixel Clock POLarity */ | ||
108 | #define GCR_DEPOL BIT(29) /* Data Enable POLarity */ | ||
109 | #define GCR_VSPOL BIT(30) /* Vertical Synchro POLarity */ | ||
110 | #define GCR_HSPOL BIT(31) /* Horizontal Synchro POLarity */ | ||
111 | |||
112 | #define GC1R_WBCH GENMASK(3, 0) /* Width of Blue CHannel output */ | ||
113 | #define GC1R_WGCH GENMASK(7, 4) /* Width of Green Channel output */ | ||
114 | #define GC1R_WRCH GENMASK(11, 8) /* Width of Red Channel output */ | ||
115 | #define GC1R_PBEN BIT(12) /* Precise Blending ENable */ | ||
116 | #define GC1R_DT GENMASK(15, 14) /* Dithering Technique */ | ||
117 | #define GC1R_GCT GENMASK(19, 17) /* Gamma Correction Technique */ | ||
118 | #define GC1R_SHREN BIT(21) /* SHadow Registers ENabled */ | ||
119 | #define GC1R_BCP BIT(22) /* Background Colour Programmable */ | ||
120 | #define GC1R_BBEN BIT(23) /* Background Blending ENabled */ | ||
121 | #define GC1R_LNIP BIT(24) /* Line Number IRQ Position */ | ||
122 | #define GC1R_TP BIT(25) /* Timing Programmable */ | ||
123 | #define GC1R_IPP BIT(26) /* IRQ Polarity Programmable */ | ||
124 | #define GC1R_SPP BIT(27) /* Sync Polarity Programmable */ | ||
125 | #define GC1R_DWP BIT(28) /* Dither Width Programmable */ | ||
126 | #define GC1R_STREN BIT(29) /* STatus Registers ENabled */ | ||
127 | #define GC1R_BMEN BIT(31) /* Blind Mode ENabled */ | ||
128 | |||
129 | #define GC2R_EDCA BIT(0) /* External Display Control Ability */ | ||
130 | #define GC2R_STSAEN BIT(1) /* Slave Timing Sync Ability ENabled */ | ||
131 | #define GC2R_DVAEN BIT(2) /* Dual-View Ability ENabled */ | ||
132 | #define GC2R_DPAEN BIT(3) /* Dual-Port Ability ENabled */ | ||
133 | #define GC2R_BW GENMASK(6, 4) /* Bus Width (log2 of nb of bytes) */ | ||
134 | #define GC2R_EDCEN BIT(7) /* External Display Control ENabled */ | ||
135 | |||
136 | #define SRCR_IMR BIT(0) /* IMmediate Reload */ | ||
137 | #define SRCR_VBR BIT(1) /* Vertical Blanking Reload */ | ||
138 | |||
139 | #define BCCR_BCBLACK 0x00 /* Background Color BLACK */ | ||
140 | #define BCCR_BCBLUE GENMASK(7, 0) /* Background Color BLUE */ | ||
141 | #define BCCR_BCGREEN GENMASK(15, 8) /* Background Color GREEN */ | ||
142 | #define BCCR_BCRED GENMASK(23, 16) /* Background Color RED */ | ||
143 | #define BCCR_BCWHITE GENMASK(23, 0) /* Background Color WHITE */ | ||
144 | |||
145 | #define IER_LIE BIT(0) /* Line Interrupt Enable */ | ||
146 | #define IER_FUIE BIT(1) /* Fifo Underrun Interrupt Enable */ | ||
147 | #define IER_TERRIE BIT(2) /* Transfer ERRor Interrupt Enable */ | ||
148 | #define IER_RRIE BIT(3) /* Register Reload Interrupt enable */ | ||
149 | |||
150 | #define ISR_LIF BIT(0) /* Line Interrupt Flag */ | ||
151 | #define ISR_FUIF BIT(1) /* Fifo Underrun Interrupt Flag */ | ||
152 | #define ISR_TERRIF BIT(2) /* Transfer ERRor Interrupt Flag */ | ||
153 | #define ISR_RRIF BIT(3) /* Register Reload Interrupt Flag */ | ||
154 | |||
155 | #define LXCR_LEN BIT(0) /* Layer ENable */ | ||
156 | #define LXCR_COLKEN BIT(1) /* Color Keying Enable */ | ||
157 | #define LXCR_CLUTEN BIT(4) /* Color Look-Up Table ENable */ | ||
158 | |||
159 | #define LXWHPCR_WHSTPOS GENMASK(11, 0) /* Window Horizontal StarT POSition */ | ||
160 | #define LXWHPCR_WHSPPOS GENMASK(27, 16) /* Window Horizontal StoP POSition */ | ||
161 | |||
162 | #define LXWVPCR_WVSTPOS GENMASK(10, 0) /* Window Vertical StarT POSition */ | ||
163 | #define LXWVPCR_WVSPPOS GENMASK(26, 16) /* Window Vertical StoP POSition */ | ||
164 | |||
165 | #define LXPFCR_PF GENMASK(2, 0) /* Pixel Format */ | ||
166 | |||
167 | #define LXCACR_CONSTA GENMASK(7, 0) /* CONSTant Alpha */ | ||
168 | |||
169 | #define LXBFCR_BF2 GENMASK(2, 0) /* Blending Factor 2 */ | ||
170 | #define LXBFCR_BF1 GENMASK(10, 8) /* Blending Factor 1 */ | ||
171 | |||
172 | #define LXCFBLR_CFBLL GENMASK(12, 0) /* Color Frame Buffer Line Length */ | ||
173 | #define LXCFBLR_CFBP GENMASK(28, 16) /* Color Frame Buffer Pitch in bytes */ | ||
174 | |||
175 | #define LXCFBLNR_CFBLN GENMASK(10, 0) /* Color Frame Buffer Line Number */ | ||
176 | |||
177 | #define HSPOL_AL 0 /* Horizontal Sync POLarity Active Low */ | ||
178 | #define VSPOL_AL 0 /* Vertical Sync POLarity Active Low */ | ||
179 | #define DEPOL_AL 0 /* Data Enable POLarity Active Low */ | ||
180 | #define PCPOL_IPC 0 /* Input Pixel Clock */ | ||
181 | #define HSPOL_AH GCR_HSPOL /* Horizontal Sync POLarity Active High */ | ||
182 | #define VSPOL_AH GCR_VSPOL /* Vertical Sync POLarity Active High */ | ||
183 | #define DEPOL_AH GCR_DEPOL /* Data Enable POLarity Active High */ | ||
184 | #define PCPOL_IIPC GCR_PCPOL /* Inverted Input Pixel Clock */ | ||
185 | #define CONSTA_MAX 0xFF /* CONSTant Alpha MAX= 1.0 */ | ||
186 | #define BF1_PAXCA 0x600 /* Pixel Alpha x Constant Alpha */ | ||
187 | #define BF1_CA 0x400 /* Constant Alpha */ | ||
188 | #define BF2_1PAXCA 0x007 /* 1 - (Pixel Alpha x Constant Alpha) */ | ||
189 | #define BF2_1CA 0x005 /* 1 - Constant Alpha */ | ||
190 | |||
191 | #define NB_PF 8 /* Max nb of HW pixel format */ | ||
192 | |||
193 | enum ltdc_pix_fmt { | ||
194 | PF_NONE, | ||
195 | /* RGB formats */ | ||
196 | PF_ARGB8888, /* ARGB [32 bits] */ | ||
197 | PF_RGBA8888, /* RGBA [32 bits] */ | ||
198 | PF_RGB888, /* RGB [24 bits] */ | ||
199 | PF_RGB565, /* RGB [16 bits] */ | ||
200 | PF_ARGB1555, /* ARGB A:1 bit RGB:15 bits [16 bits] */ | ||
201 | PF_ARGB4444, /* ARGB A:4 bits R/G/B: 4 bits each [16 bits] */ | ||
202 | /* Indexed formats */ | ||
203 | PF_L8, /* Indexed 8 bits [8 bits] */ | ||
204 | PF_AL44, /* Alpha:4 bits + indexed 4 bits [8 bits] */ | ||
205 | PF_AL88 /* Alpha:8 bits + indexed 8 bits [16 bits] */ | ||
206 | }; | ||
207 | |||
208 | /* The index gives the encoding of the pixel format for an HW version */ | ||
209 | static const enum ltdc_pix_fmt ltdc_pix_fmt_a0[NB_PF] = { | ||
210 | PF_ARGB8888, /* 0x00 */ | ||
211 | PF_RGB888, /* 0x01 */ | ||
212 | PF_RGB565, /* 0x02 */ | ||
213 | PF_ARGB1555, /* 0x03 */ | ||
214 | PF_ARGB4444, /* 0x04 */ | ||
215 | PF_L8, /* 0x05 */ | ||
216 | PF_AL44, /* 0x06 */ | ||
217 | PF_AL88 /* 0x07 */ | ||
218 | }; | ||
219 | |||
220 | static const enum ltdc_pix_fmt ltdc_pix_fmt_a1[NB_PF] = { | ||
221 | PF_ARGB8888, /* 0x00 */ | ||
222 | PF_RGB888, /* 0x01 */ | ||
223 | PF_RGB565, /* 0x02 */ | ||
224 | PF_RGBA8888, /* 0x03 */ | ||
225 | PF_AL44, /* 0x04 */ | ||
226 | PF_L8, /* 0x05 */ | ||
227 | PF_ARGB1555, /* 0x06 */ | ||
228 | PF_ARGB4444 /* 0x07 */ | ||
229 | }; | ||
230 | |||
231 | static inline u32 reg_read(void __iomem *base, u32 reg) | ||
232 | { | ||
233 | return readl_relaxed(base + reg); | ||
234 | } | ||
235 | |||
236 | static inline void reg_write(void __iomem *base, u32 reg, u32 val) | ||
237 | { | ||
238 | writel_relaxed(val, base + reg); | ||
239 | } | ||
240 | |||
241 | static inline void reg_set(void __iomem *base, u32 reg, u32 mask) | ||
242 | { | ||
243 | reg_write(base, reg, reg_read(base, reg) | mask); | ||
244 | } | ||
245 | |||
246 | static inline void reg_clear(void __iomem *base, u32 reg, u32 mask) | ||
247 | { | ||
248 | reg_write(base, reg, reg_read(base, reg) & ~mask); | ||
249 | } | ||
250 | |||
251 | static inline void reg_update_bits(void __iomem *base, u32 reg, u32 mask, | ||
252 | u32 val) | ||
253 | { | ||
254 | reg_write(base, reg, (reg_read(base, reg) & ~mask) | val); | ||
255 | } | ||
256 | |||
257 | static inline struct ltdc_device *crtc_to_ltdc(struct drm_crtc *crtc) | ||
258 | { | ||
259 | return (struct ltdc_device *)crtc->dev->dev_private; | ||
260 | } | ||
261 | |||
262 | static inline struct ltdc_device *plane_to_ltdc(struct drm_plane *plane) | ||
263 | { | ||
264 | return (struct ltdc_device *)plane->dev->dev_private; | ||
265 | } | ||
266 | |||
267 | static inline struct ltdc_device *encoder_to_ltdc(struct drm_encoder *enc) | ||
268 | { | ||
269 | return (struct ltdc_device *)enc->dev->dev_private; | ||
270 | } | ||
271 | |||
272 | static inline struct ltdc_device *connector_to_ltdc(struct drm_connector *con) | ||
273 | { | ||
274 | return (struct ltdc_device *)con->dev->dev_private; | ||
275 | } | ||
276 | |||
277 | static inline enum ltdc_pix_fmt to_ltdc_pixelformat(u32 drm_fmt) | ||
278 | { | ||
279 | enum ltdc_pix_fmt pf; | ||
280 | |||
281 | switch (drm_fmt) { | ||
282 | case DRM_FORMAT_ARGB8888: | ||
283 | case DRM_FORMAT_XRGB8888: | ||
284 | pf = PF_ARGB8888; | ||
285 | break; | ||
286 | case DRM_FORMAT_RGBA8888: | ||
287 | case DRM_FORMAT_RGBX8888: | ||
288 | pf = PF_RGBA8888; | ||
289 | break; | ||
290 | case DRM_FORMAT_RGB888: | ||
291 | pf = PF_RGB888; | ||
292 | break; | ||
293 | case DRM_FORMAT_RGB565: | ||
294 | pf = PF_RGB565; | ||
295 | break; | ||
296 | case DRM_FORMAT_ARGB1555: | ||
297 | case DRM_FORMAT_XRGB1555: | ||
298 | pf = PF_ARGB1555; | ||
299 | break; | ||
300 | case DRM_FORMAT_ARGB4444: | ||
301 | case DRM_FORMAT_XRGB4444: | ||
302 | pf = PF_ARGB4444; | ||
303 | break; | ||
304 | case DRM_FORMAT_C8: | ||
305 | pf = PF_L8; | ||
306 | break; | ||
307 | default: | ||
308 | pf = PF_NONE; | ||
309 | break; | ||
310 | /* Note: There are no DRM_FORMAT for AL44 and AL88 */ | ||
311 | } | ||
312 | |||
313 | return pf; | ||
314 | } | ||
315 | |||
316 | static inline u32 to_drm_pixelformat(enum ltdc_pix_fmt pf) | ||
317 | { | ||
318 | switch (pf) { | ||
319 | case PF_ARGB8888: | ||
320 | return DRM_FORMAT_ARGB8888; | ||
321 | case PF_RGBA8888: | ||
322 | return DRM_FORMAT_RGBA8888; | ||
323 | case PF_RGB888: | ||
324 | return DRM_FORMAT_RGB888; | ||
325 | case PF_RGB565: | ||
326 | return DRM_FORMAT_RGB565; | ||
327 | case PF_ARGB1555: | ||
328 | return DRM_FORMAT_ARGB1555; | ||
329 | case PF_ARGB4444: | ||
330 | return DRM_FORMAT_ARGB4444; | ||
331 | case PF_L8: | ||
332 | return DRM_FORMAT_C8; | ||
333 | case PF_AL44: /* No DRM support */ | ||
334 | case PF_AL88: /* No DRM support */ | ||
335 | case PF_NONE: | ||
336 | default: | ||
337 | return 0; | ||
338 | } | ||
339 | } | ||
340 | |||
341 | static irqreturn_t ltdc_irq_thread(int irq, void *arg) | ||
342 | { | ||
343 | struct drm_device *ddev = arg; | ||
344 | struct ltdc_device *ldev = ddev->dev_private; | ||
345 | struct drm_crtc *crtc = drm_crtc_from_index(ddev, 0); | ||
346 | |||
347 | /* Line IRQ : trigger the vblank event */ | ||
348 | if (ldev->irq_status & ISR_LIF) | ||
349 | drm_crtc_handle_vblank(crtc); | ||
350 | |||
351 | /* Save FIFO Underrun & Transfer Error status */ | ||
352 | mutex_lock(&ldev->err_lock); | ||
353 | if (ldev->irq_status & ISR_FUIF) | ||
354 | ldev->error_status |= ISR_FUIF; | ||
355 | if (ldev->irq_status & ISR_TERRIF) | ||
356 | ldev->error_status |= ISR_TERRIF; | ||
357 | mutex_unlock(&ldev->err_lock); | ||
358 | |||
359 | return IRQ_HANDLED; | ||
360 | } | ||
361 | |||
362 | static irqreturn_t ltdc_irq(int irq, void *arg) | ||
363 | { | ||
364 | struct drm_device *ddev = arg; | ||
365 | struct ltdc_device *ldev = ddev->dev_private; | ||
366 | |||
367 | /* Read & Clear the interrupt status */ | ||
368 | ldev->irq_status = reg_read(ldev->regs, LTDC_ISR); | ||
369 | reg_write(ldev->regs, LTDC_ICR, ldev->irq_status); | ||
370 | |||
371 | return IRQ_WAKE_THREAD; | ||
372 | } | ||
373 | |||
374 | /* | ||
375 | * DRM_CRTC | ||
376 | */ | ||
377 | |||
378 | static void ltdc_crtc_load_lut(struct drm_crtc *crtc) | ||
379 | { | ||
380 | struct ltdc_device *ldev = crtc_to_ltdc(crtc); | ||
381 | unsigned int i, lay; | ||
382 | |||
383 | for (lay = 0; lay < ldev->caps.nb_layers; lay++) | ||
384 | for (i = 0; i < 256; i++) | ||
385 | reg_write(ldev->regs, LTDC_L1CLUTWR + lay * LAY_OFS, | ||
386 | ldev->clut[i]); | ||
387 | } | ||
388 | |||
389 | static void ltdc_crtc_enable(struct drm_crtc *crtc) | ||
390 | { | ||
391 | struct ltdc_device *ldev = crtc_to_ltdc(crtc); | ||
392 | |||
393 | DRM_DEBUG_DRIVER("\n"); | ||
394 | |||
395 | /* Sets the background color value */ | ||
396 | reg_write(ldev->regs, LTDC_BCCR, BCCR_BCBLACK); | ||
397 | |||
398 | /* Enable IRQ */ | ||
399 | reg_set(ldev->regs, LTDC_IER, IER_RRIE | IER_FUIE | IER_TERRIE); | ||
400 | |||
401 | /* Immediately commit the planes */ | ||
402 | reg_set(ldev->regs, LTDC_SRCR, SRCR_IMR); | ||
403 | |||
404 | /* Enable LTDC */ | ||
405 | reg_set(ldev->regs, LTDC_GCR, GCR_LTDCEN); | ||
406 | |||
407 | drm_crtc_vblank_on(crtc); | ||
408 | } | ||
409 | |||
410 | static void ltdc_crtc_disable(struct drm_crtc *crtc) | ||
411 | { | ||
412 | struct ltdc_device *ldev = crtc_to_ltdc(crtc); | ||
413 | |||
414 | DRM_DEBUG_DRIVER("\n"); | ||
415 | |||
416 | drm_crtc_vblank_off(crtc); | ||
417 | |||
418 | /* disable LTDC */ | ||
419 | reg_clear(ldev->regs, LTDC_GCR, GCR_LTDCEN); | ||
420 | |||
421 | /* disable IRQ */ | ||
422 | reg_clear(ldev->regs, LTDC_IER, IER_RRIE | IER_FUIE | IER_TERRIE); | ||
423 | |||
424 | /* immediately commit disable of layers before switching off LTDC */ | ||
425 | reg_set(ldev->regs, LTDC_SRCR, SRCR_IMR); | ||
426 | } | ||
427 | |||
428 | static void ltdc_crtc_mode_set_nofb(struct drm_crtc *crtc) | ||
429 | { | ||
430 | struct ltdc_device *ldev = crtc_to_ltdc(crtc); | ||
431 | struct drm_display_mode *mode = &crtc->state->adjusted_mode; | ||
432 | struct videomode vm; | ||
433 | int rate = mode->clock * 1000; | ||
434 | u32 hsync, vsync, accum_hbp, accum_vbp, accum_act_w, accum_act_h; | ||
435 | u32 total_width, total_height; | ||
436 | u32 val; | ||
437 | |||
438 | drm_display_mode_to_videomode(mode, &vm); | ||
439 | |||
440 | DRM_DEBUG_DRIVER("CRTC:%d mode:%s\n", crtc->base.id, mode->name); | ||
441 | DRM_DEBUG_DRIVER("Video mode: %dx%d", vm.hactive, vm.vactive); | ||
442 | DRM_DEBUG_DRIVER(" hfp %d hbp %d hsl %d vfp %d vbp %d vsl %d\n", | ||
443 | vm.hfront_porch, vm.hback_porch, vm.hsync_len, | ||
444 | vm.vfront_porch, vm.vback_porch, vm.vsync_len); | ||
445 | |||
446 | /* Convert video timings to ltdc timings */ | ||
447 | hsync = vm.hsync_len - 1; | ||
448 | vsync = vm.vsync_len - 1; | ||
449 | accum_hbp = hsync + vm.hback_porch; | ||
450 | accum_vbp = vsync + vm.vback_porch; | ||
451 | accum_act_w = accum_hbp + vm.hactive; | ||
452 | accum_act_h = accum_vbp + vm.vactive; | ||
453 | total_width = accum_act_w + vm.hfront_porch; | ||
454 | total_height = accum_act_h + vm.vfront_porch; | ||
455 | |||
456 | clk_disable(ldev->pixel_clk); | ||
457 | |||
458 | if (clk_set_rate(ldev->pixel_clk, rate) < 0) { | ||
459 | DRM_ERROR("Cannot set rate (%dHz) for pixel clk\n", rate); | ||
460 | return; | ||
461 | } | ||
462 | |||
463 | clk_enable(ldev->pixel_clk); | ||
464 | |||
465 | /* Configures the HS, VS, DE and PC polarities. */ | ||
466 | val = HSPOL_AL | HSPOL_AL | DEPOL_AL | PCPOL_IPC; | ||
467 | |||
468 | if (vm.flags & DISPLAY_FLAGS_HSYNC_HIGH) | ||
469 | val |= HSPOL_AH; | ||
470 | |||
471 | if (vm.flags & DISPLAY_FLAGS_VSYNC_HIGH) | ||
472 | val |= VSPOL_AH; | ||
473 | |||
474 | if (vm.flags & DISPLAY_FLAGS_DE_HIGH) | ||
475 | val |= DEPOL_AH; | ||
476 | |||
477 | if (vm.flags & DISPLAY_FLAGS_PIXDATA_NEGEDGE) | ||
478 | val |= PCPOL_IIPC; | ||
479 | |||
480 | reg_update_bits(ldev->regs, LTDC_GCR, | ||
481 | GCR_HSPOL | GCR_VSPOL | GCR_DEPOL | GCR_PCPOL, val); | ||
482 | |||
483 | /* Set Synchronization size */ | ||
484 | val = (hsync << 16) | vsync; | ||
485 | reg_update_bits(ldev->regs, LTDC_SSCR, SSCR_VSH | SSCR_HSW, val); | ||
486 | |||
487 | /* Set Accumulated Back porch */ | ||
488 | val = (accum_hbp << 16) | accum_vbp; | ||
489 | reg_update_bits(ldev->regs, LTDC_BPCR, BPCR_AVBP | BPCR_AHBP, val); | ||
490 | |||
491 | /* Set Accumulated Active Width */ | ||
492 | val = (accum_act_w << 16) | accum_act_h; | ||
493 | reg_update_bits(ldev->regs, LTDC_AWCR, AWCR_AAW | AWCR_AAH, val); | ||
494 | |||
495 | /* Set total width & height */ | ||
496 | val = (total_width << 16) | total_height; | ||
497 | reg_update_bits(ldev->regs, LTDC_TWCR, TWCR_TOTALH | TWCR_TOTALW, val); | ||
498 | |||
499 | reg_write(ldev->regs, LTDC_LIPCR, (accum_act_h + 1)); | ||
500 | } | ||
501 | |||
502 | static void ltdc_crtc_atomic_flush(struct drm_crtc *crtc, | ||
503 | struct drm_crtc_state *old_crtc_state) | ||
504 | { | ||
505 | struct ltdc_device *ldev = crtc_to_ltdc(crtc); | ||
506 | struct drm_pending_vblank_event *event = crtc->state->event; | ||
507 | |||
508 | DRM_DEBUG_ATOMIC("\n"); | ||
509 | |||
510 | /* Commit shadow registers = update planes at next vblank */ | ||
511 | reg_set(ldev->regs, LTDC_SRCR, SRCR_VBR); | ||
512 | |||
513 | if (event) { | ||
514 | crtc->state->event = NULL; | ||
515 | |||
516 | spin_lock_irq(&crtc->dev->event_lock); | ||
517 | if (drm_crtc_vblank_get(crtc) == 0) | ||
518 | drm_crtc_arm_vblank_event(crtc, event); | ||
519 | else | ||
520 | drm_crtc_send_vblank_event(crtc, event); | ||
521 | spin_unlock_irq(&crtc->dev->event_lock); | ||
522 | } | ||
523 | } | ||
524 | |||
525 | static struct drm_crtc_helper_funcs ltdc_crtc_helper_funcs = { | ||
526 | .load_lut = ltdc_crtc_load_lut, | ||
527 | .enable = ltdc_crtc_enable, | ||
528 | .disable = ltdc_crtc_disable, | ||
529 | .mode_set_nofb = ltdc_crtc_mode_set_nofb, | ||
530 | .atomic_flush = ltdc_crtc_atomic_flush, | ||
531 | }; | ||
532 | |||
533 | int ltdc_crtc_enable_vblank(struct drm_device *ddev, unsigned int pipe) | ||
534 | { | ||
535 | struct ltdc_device *ldev = ddev->dev_private; | ||
536 | |||
537 | DRM_DEBUG_DRIVER("\n"); | ||
538 | reg_set(ldev->regs, LTDC_IER, IER_LIE); | ||
539 | |||
540 | return 0; | ||
541 | } | ||
542 | |||
543 | void ltdc_crtc_disable_vblank(struct drm_device *ddev, unsigned int pipe) | ||
544 | { | ||
545 | struct ltdc_device *ldev = ddev->dev_private; | ||
546 | |||
547 | DRM_DEBUG_DRIVER("\n"); | ||
548 | reg_clear(ldev->regs, LTDC_IER, IER_LIE); | ||
549 | } | ||
550 | |||
551 | static struct drm_crtc_funcs ltdc_crtc_funcs = { | ||
552 | .destroy = drm_crtc_cleanup, | ||
553 | .set_config = drm_atomic_helper_set_config, | ||
554 | .page_flip = drm_atomic_helper_page_flip, | ||
555 | .reset = drm_atomic_helper_crtc_reset, | ||
556 | .atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state, | ||
557 | .atomic_destroy_state = drm_atomic_helper_crtc_destroy_state, | ||
558 | }; | ||
559 | |||
560 | /* | ||
561 | * DRM_PLANE | ||
562 | */ | ||
563 | |||
564 | static int ltdc_plane_atomic_check(struct drm_plane *plane, | ||
565 | struct drm_plane_state *state) | ||
566 | { | ||
567 | struct drm_framebuffer *fb = state->fb; | ||
568 | u32 src_x, src_y, src_w, src_h; | ||
569 | |||
570 | DRM_DEBUG_DRIVER("\n"); | ||
571 | |||
572 | if (!fb) | ||
573 | return 0; | ||
574 | |||
575 | /* convert src_ from 16:16 format */ | ||
576 | src_x = state->src_x >> 16; | ||
577 | src_y = state->src_y >> 16; | ||
578 | src_w = state->src_w >> 16; | ||
579 | src_h = state->src_h >> 16; | ||
580 | |||
581 | /* Reject scaling */ | ||
582 | if ((src_w != state->crtc_w) || (src_h != state->crtc_h)) { | ||
583 | DRM_ERROR("Scaling is not supported"); | ||
584 | return -EINVAL; | ||
585 | } | ||
586 | |||
587 | return 0; | ||
588 | } | ||
589 | |||
590 | static void ltdc_plane_atomic_update(struct drm_plane *plane, | ||
591 | struct drm_plane_state *oldstate) | ||
592 | { | ||
593 | struct ltdc_device *ldev = plane_to_ltdc(plane); | ||
594 | struct drm_plane_state *state = plane->state; | ||
595 | struct drm_framebuffer *fb = state->fb; | ||
596 | u32 lofs = plane->index * LAY_OFS; | ||
597 | u32 x0 = state->crtc_x; | ||
598 | u32 x1 = state->crtc_x + state->crtc_w - 1; | ||
599 | u32 y0 = state->crtc_y; | ||
600 | u32 y1 = state->crtc_y + state->crtc_h - 1; | ||
601 | u32 src_x, src_y, src_w, src_h; | ||
602 | u32 val, pitch_in_bytes, line_length, paddr, ahbp, avbp, bpcr; | ||
603 | enum ltdc_pix_fmt pf; | ||
604 | |||
605 | if (!state->crtc || !fb) { | ||
606 | DRM_DEBUG_DRIVER("fb or crtc NULL"); | ||
607 | return; | ||
608 | } | ||
609 | |||
610 | /* convert src_ from 16:16 format */ | ||
611 | src_x = state->src_x >> 16; | ||
612 | src_y = state->src_y >> 16; | ||
613 | src_w = state->src_w >> 16; | ||
614 | src_h = state->src_h >> 16; | ||
615 | |||
616 | DRM_DEBUG_DRIVER( | ||
617 | "plane:%d fb:%d (%dx%d)@(%d,%d) -> (%dx%d)@(%d,%d)\n", | ||
618 | plane->base.id, fb->base.id, | ||
619 | src_w, src_h, src_x, src_y, | ||
620 | state->crtc_w, state->crtc_h, state->crtc_x, state->crtc_y); | ||
621 | |||
622 | bpcr = reg_read(ldev->regs, LTDC_BPCR); | ||
623 | ahbp = (bpcr & BPCR_AHBP) >> 16; | ||
624 | avbp = bpcr & BPCR_AVBP; | ||
625 | |||
626 | /* Configures the horizontal start and stop position */ | ||
627 | val = ((x1 + 1 + ahbp) << 16) + (x0 + 1 + ahbp); | ||
628 | reg_update_bits(ldev->regs, LTDC_L1WHPCR + lofs, | ||
629 | LXWHPCR_WHSTPOS | LXWHPCR_WHSPPOS, val); | ||
630 | |||
631 | /* Configures the vertical start and stop position */ | ||
632 | val = ((y1 + 1 + avbp) << 16) + (y0 + 1 + avbp); | ||
633 | reg_update_bits(ldev->regs, LTDC_L1WVPCR + lofs, | ||
634 | LXWVPCR_WVSTPOS | LXWVPCR_WVSPPOS, val); | ||
635 | |||
636 | /* Specifies the pixel format */ | ||
637 | pf = to_ltdc_pixelformat(fb->format->format); | ||
638 | for (val = 0; val < NB_PF; val++) | ||
639 | if (ldev->caps.pix_fmt_hw[val] == pf) | ||
640 | break; | ||
641 | |||
642 | if (val == NB_PF) { | ||
643 | DRM_ERROR("Pixel format %.4s not supported\n", | ||
644 | (char *)&fb->format->format); | ||
645 | val = 0; /* set by default ARGB 32 bits */ | ||
646 | } | ||
647 | reg_update_bits(ldev->regs, LTDC_L1PFCR + lofs, LXPFCR_PF, val); | ||
648 | |||
649 | /* Configures the color frame buffer pitch in bytes & line length */ | ||
650 | pitch_in_bytes = fb->pitches[0]; | ||
651 | line_length = drm_format_plane_cpp(fb->format->format, 0) * | ||
652 | (x1 - x0 + 1) + (ldev->caps.bus_width >> 3) - 1; | ||
653 | val = ((pitch_in_bytes << 16) | line_length); | ||
654 | reg_update_bits(ldev->regs, LTDC_L1CFBLR + lofs, | ||
655 | LXCFBLR_CFBLL | LXCFBLR_CFBP, val); | ||
656 | |||
657 | /* Specifies the constant alpha value */ | ||
658 | val = CONSTA_MAX; | ||
659 | reg_update_bits(ldev->regs, LTDC_L1CACR + lofs, | ||
660 | LXCACR_CONSTA, val); | ||
661 | |||
662 | /* Specifies the blending factors */ | ||
663 | val = BF1_PAXCA | BF2_1PAXCA; | ||
664 | reg_update_bits(ldev->regs, LTDC_L1BFCR + lofs, | ||
665 | LXBFCR_BF2 | LXBFCR_BF1, val); | ||
666 | |||
667 | /* Configures the frame buffer line number */ | ||
668 | val = y1 - y0 + 1; | ||
669 | reg_update_bits(ldev->regs, LTDC_L1CFBLNR + lofs, | ||
670 | LXCFBLNR_CFBLN, val); | ||
671 | |||
672 | /* Sets the FB address */ | ||
673 | paddr = (u32)drm_fb_cma_get_gem_addr(fb, state, 0); | ||
674 | |||
675 | DRM_DEBUG_DRIVER("fb: phys 0x%08x", paddr); | ||
676 | reg_write(ldev->regs, LTDC_L1CFBAR + lofs, paddr); | ||
677 | |||
678 | /* Enable layer and CLUT if needed */ | ||
679 | val = fb->format->format == DRM_FORMAT_C8 ? LXCR_CLUTEN : 0; | ||
680 | val |= LXCR_LEN; | ||
681 | reg_update_bits(ldev->regs, LTDC_L1CR + lofs, | ||
682 | LXCR_LEN | LXCR_CLUTEN, val); | ||
683 | |||
684 | mutex_lock(&ldev->err_lock); | ||
685 | if (ldev->error_status & ISR_FUIF) { | ||
686 | DRM_DEBUG_DRIVER("Fifo underrun\n"); | ||
687 | ldev->error_status &= ~ISR_FUIF; | ||
688 | } | ||
689 | if (ldev->error_status & ISR_TERRIF) { | ||
690 | DRM_DEBUG_DRIVER("Transfer error\n"); | ||
691 | ldev->error_status &= ~ISR_TERRIF; | ||
692 | } | ||
693 | mutex_unlock(&ldev->err_lock); | ||
694 | } | ||
695 | |||
696 | static void ltdc_plane_atomic_disable(struct drm_plane *plane, | ||
697 | struct drm_plane_state *oldstate) | ||
698 | { | ||
699 | struct ltdc_device *ldev = plane_to_ltdc(plane); | ||
700 | u32 lofs = plane->index * LAY_OFS; | ||
701 | |||
702 | /* disable layer */ | ||
703 | reg_clear(ldev->regs, LTDC_L1CR + lofs, LXCR_LEN); | ||
704 | |||
705 | DRM_DEBUG_DRIVER("CRTC:%d plane:%d\n", | ||
706 | oldstate->crtc->base.id, plane->base.id); | ||
707 | } | ||
708 | |||
709 | static struct drm_plane_funcs ltdc_plane_funcs = { | ||
710 | .update_plane = drm_atomic_helper_update_plane, | ||
711 | .disable_plane = drm_atomic_helper_disable_plane, | ||
712 | .destroy = drm_plane_cleanup, | ||
713 | .set_property = drm_atomic_helper_plane_set_property, | ||
714 | .reset = drm_atomic_helper_plane_reset, | ||
715 | .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state, | ||
716 | .atomic_destroy_state = drm_atomic_helper_plane_destroy_state, | ||
717 | }; | ||
718 | |||
719 | static const struct drm_plane_helper_funcs ltdc_plane_helper_funcs = { | ||
720 | .atomic_check = ltdc_plane_atomic_check, | ||
721 | .atomic_update = ltdc_plane_atomic_update, | ||
722 | .atomic_disable = ltdc_plane_atomic_disable, | ||
723 | }; | ||
724 | |||
725 | static struct drm_plane *ltdc_plane_create(struct drm_device *ddev, | ||
726 | enum drm_plane_type type) | ||
727 | { | ||
728 | unsigned long possible_crtcs = CRTC_MASK; | ||
729 | struct ltdc_device *ldev = ddev->dev_private; | ||
730 | struct device *dev = ddev->dev; | ||
731 | struct drm_plane *plane; | ||
732 | unsigned int i, nb_fmt = 0; | ||
733 | u32 formats[NB_PF]; | ||
734 | u32 drm_fmt; | ||
735 | int ret; | ||
736 | |||
737 | /* Get supported pixel formats */ | ||
738 | for (i = 0; i < NB_PF; i++) { | ||
739 | drm_fmt = to_drm_pixelformat(ldev->caps.pix_fmt_hw[i]); | ||
740 | if (!drm_fmt) | ||
741 | continue; | ||
742 | formats[nb_fmt++] = drm_fmt; | ||
743 | } | ||
744 | |||
745 | plane = devm_kzalloc(dev, sizeof(*plane), GFP_KERNEL); | ||
746 | if (!plane) | ||
747 | return 0; | ||
748 | |||
749 | ret = drm_universal_plane_init(ddev, plane, possible_crtcs, | ||
750 | <dc_plane_funcs, formats, nb_fmt, | ||
751 | type, NULL); | ||
752 | if (ret < 0) | ||
753 | return 0; | ||
754 | |||
755 | drm_plane_helper_add(plane, <dc_plane_helper_funcs); | ||
756 | |||
757 | DRM_DEBUG_DRIVER("plane:%d created\n", plane->base.id); | ||
758 | |||
759 | return plane; | ||
760 | } | ||
761 | |||
762 | static void ltdc_plane_destroy_all(struct drm_device *ddev) | ||
763 | { | ||
764 | struct drm_plane *plane, *plane_temp; | ||
765 | |||
766 | list_for_each_entry_safe(plane, plane_temp, | ||
767 | &ddev->mode_config.plane_list, head) | ||
768 | drm_plane_cleanup(plane); | ||
769 | } | ||
770 | |||
771 | static int ltdc_crtc_init(struct drm_device *ddev, struct drm_crtc *crtc) | ||
772 | { | ||
773 | struct ltdc_device *ldev = ddev->dev_private; | ||
774 | struct drm_plane *primary, *overlay; | ||
775 | unsigned int i; | ||
776 | int res; | ||
777 | |||
778 | primary = ltdc_plane_create(ddev, DRM_PLANE_TYPE_PRIMARY); | ||
779 | if (!primary) { | ||
780 | DRM_ERROR("Can not create primary plane\n"); | ||
781 | return -EINVAL; | ||
782 | } | ||
783 | |||
784 | res = drm_crtc_init_with_planes(ddev, crtc, primary, NULL, | ||
785 | <dc_crtc_funcs, NULL); | ||
786 | if (res) { | ||
787 | DRM_ERROR("Can not initialize CRTC\n"); | ||
788 | goto cleanup; | ||
789 | } | ||
790 | |||
791 | drm_crtc_helper_add(crtc, <dc_crtc_helper_funcs); | ||
792 | |||
793 | DRM_DEBUG_DRIVER("CRTC:%d created\n", crtc->base.id); | ||
794 | |||
795 | /* Add planes. Note : the first layer is used by primary plane */ | ||
796 | for (i = 1; i < ldev->caps.nb_layers; i++) { | ||
797 | overlay = ltdc_plane_create(ddev, DRM_PLANE_TYPE_OVERLAY); | ||
798 | if (!overlay) { | ||
799 | res = -ENOMEM; | ||
800 | DRM_ERROR("Can not create overlay plane %d\n", i); | ||
801 | goto cleanup; | ||
802 | } | ||
803 | } | ||
804 | |||
805 | return 0; | ||
806 | |||
807 | cleanup: | ||
808 | ltdc_plane_destroy_all(ddev); | ||
809 | return res; | ||
810 | } | ||
811 | |||
812 | /* | ||
813 | * DRM_ENCODER | ||
814 | */ | ||
815 | |||
816 | static void ltdc_rgb_encoder_enable(struct drm_encoder *encoder) | ||
817 | { | ||
818 | struct ltdc_device *ldev = encoder_to_ltdc(encoder); | ||
819 | |||
820 | DRM_DEBUG_DRIVER("\n"); | ||
821 | |||
822 | drm_panel_prepare(ldev->panel); | ||
823 | drm_panel_enable(ldev->panel); | ||
824 | } | ||
825 | |||
826 | static void ltdc_rgb_encoder_disable(struct drm_encoder *encoder) | ||
827 | { | ||
828 | struct ltdc_device *ldev = encoder_to_ltdc(encoder); | ||
829 | |||
830 | DRM_DEBUG_DRIVER("\n"); | ||
831 | |||
832 | drm_panel_disable(ldev->panel); | ||
833 | drm_panel_unprepare(ldev->panel); | ||
834 | } | ||
835 | |||
836 | static const struct drm_encoder_helper_funcs ltdc_rgb_encoder_helper_funcs = { | ||
837 | .enable = ltdc_rgb_encoder_enable, | ||
838 | .disable = ltdc_rgb_encoder_disable, | ||
839 | }; | ||
840 | |||
841 | static const struct drm_encoder_funcs ltdc_rgb_encoder_funcs = { | ||
842 | .destroy = drm_encoder_cleanup, | ||
843 | }; | ||
844 | |||
845 | static struct drm_encoder *ltdc_rgb_encoder_create(struct drm_device *ddev) | ||
846 | { | ||
847 | struct drm_encoder *encoder; | ||
848 | |||
849 | encoder = devm_kzalloc(ddev->dev, sizeof(*encoder), GFP_KERNEL); | ||
850 | if (!encoder) | ||
851 | return NULL; | ||
852 | |||
853 | encoder->possible_crtcs = CRTC_MASK; | ||
854 | encoder->possible_clones = 0; /* No cloning support */ | ||
855 | |||
856 | drm_encoder_init(ddev, encoder, <dc_rgb_encoder_funcs, | ||
857 | DRM_MODE_ENCODER_DPI, NULL); | ||
858 | |||
859 | drm_encoder_helper_add(encoder, <dc_rgb_encoder_helper_funcs); | ||
860 | |||
861 | DRM_DEBUG_DRIVER("RGB encoder:%d created\n", encoder->base.id); | ||
862 | |||
863 | return encoder; | ||
864 | } | ||
865 | |||
866 | /* | ||
867 | * DRM_CONNECTOR | ||
868 | */ | ||
869 | |||
870 | static int ltdc_rgb_connector_get_modes(struct drm_connector *connector) | ||
871 | { | ||
872 | struct drm_device *ddev = connector->dev; | ||
873 | struct ltdc_device *ldev = ddev->dev_private; | ||
874 | int ret = 0; | ||
875 | |||
876 | DRM_DEBUG_DRIVER("\n"); | ||
877 | |||
878 | if (ldev->panel) | ||
879 | ret = drm_panel_get_modes(ldev->panel); | ||
880 | |||
881 | return ret < 0 ? 0 : ret; | ||
882 | } | ||
883 | |||
884 | static struct drm_connector_helper_funcs ltdc_rgb_connector_helper_funcs = { | ||
885 | .get_modes = ltdc_rgb_connector_get_modes, | ||
886 | }; | ||
887 | |||
888 | static enum drm_connector_status | ||
889 | ltdc_rgb_connector_detect(struct drm_connector *connector, bool force) | ||
890 | { | ||
891 | struct ltdc_device *ldev = connector_to_ltdc(connector); | ||
892 | |||
893 | return ldev->panel ? connector_status_connected : | ||
894 | connector_status_disconnected; | ||
895 | } | ||
896 | |||
897 | static void ltdc_rgb_connector_destroy(struct drm_connector *connector) | ||
898 | { | ||
899 | DRM_DEBUG_DRIVER("\n"); | ||
900 | |||
901 | drm_connector_unregister(connector); | ||
902 | drm_connector_cleanup(connector); | ||
903 | } | ||
904 | |||
905 | static const struct drm_connector_funcs ltdc_rgb_connector_funcs = { | ||
906 | .dpms = drm_atomic_helper_connector_dpms, | ||
907 | .fill_modes = drm_helper_probe_single_connector_modes, | ||
908 | .detect = ltdc_rgb_connector_detect, | ||
909 | .destroy = ltdc_rgb_connector_destroy, | ||
910 | .reset = drm_atomic_helper_connector_reset, | ||
911 | .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, | ||
912 | .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, | ||
913 | }; | ||
914 | |||
915 | struct drm_connector *ltdc_rgb_connector_create(struct drm_device *ddev) | ||
916 | { | ||
917 | struct drm_connector *connector; | ||
918 | int err; | ||
919 | |||
920 | connector = devm_kzalloc(ddev->dev, sizeof(*connector), GFP_KERNEL); | ||
921 | if (!connector) { | ||
922 | DRM_ERROR("Failed to allocate connector\n"); | ||
923 | return NULL; | ||
924 | } | ||
925 | |||
926 | connector->polled = DRM_CONNECTOR_POLL_HPD; | ||
927 | |||
928 | err = drm_connector_init(ddev, connector, <dc_rgb_connector_funcs, | ||
929 | DRM_MODE_CONNECTOR_DPI); | ||
930 | if (err) { | ||
931 | DRM_ERROR("Failed to initialize connector\n"); | ||
932 | return NULL; | ||
933 | } | ||
934 | |||
935 | drm_connector_helper_add(connector, <dc_rgb_connector_helper_funcs); | ||
936 | |||
937 | DRM_DEBUG_DRIVER("RGB connector:%d created\n", connector->base.id); | ||
938 | |||
939 | return connector; | ||
940 | } | ||
941 | |||
942 | static int ltdc_get_caps(struct drm_device *ddev) | ||
943 | { | ||
944 | struct ltdc_device *ldev = ddev->dev_private; | ||
945 | u32 bus_width_log2, lcr, gc2r; | ||
946 | |||
947 | /* at least 1 layer must be managed */ | ||
948 | lcr = reg_read(ldev->regs, LTDC_LCR); | ||
949 | |||
950 | ldev->caps.nb_layers = max_t(int, lcr, 1); | ||
951 | |||
952 | /* set data bus width */ | ||
953 | gc2r = reg_read(ldev->regs, LTDC_GC2R); | ||
954 | bus_width_log2 = (gc2r & GC2R_BW) >> 4; | ||
955 | ldev->caps.bus_width = 8 << bus_width_log2; | ||
956 | ldev->caps.hw_version = reg_read(ldev->regs, LTDC_IDR); | ||
957 | |||
958 | switch (ldev->caps.hw_version) { | ||
959 | case HWVER_10200: | ||
960 | case HWVER_10300: | ||
961 | ldev->caps.reg_ofs = REG_OFS_NONE; | ||
962 | ldev->caps.pix_fmt_hw = ltdc_pix_fmt_a0; | ||
963 | break; | ||
964 | case HWVER_20101: | ||
965 | ldev->caps.reg_ofs = REG_OFS_4; | ||
966 | ldev->caps.pix_fmt_hw = ltdc_pix_fmt_a1; | ||
967 | break; | ||
968 | default: | ||
969 | return -ENODEV; | ||
970 | } | ||
971 | |||
972 | return 0; | ||
973 | } | ||
974 | |||
975 | static struct drm_panel *ltdc_get_panel(struct drm_device *ddev) | ||
976 | { | ||
977 | struct device *dev = ddev->dev; | ||
978 | struct device_node *np = dev->of_node; | ||
979 | struct device_node *entity, *port = NULL; | ||
980 | struct drm_panel *panel = NULL; | ||
981 | |||
982 | DRM_DEBUG_DRIVER("\n"); | ||
983 | |||
984 | /* | ||
985 | * Parse ltdc node to get remote port and find RGB panel / HDMI slave | ||
986 | * If a dsi or a bridge (hdmi, lvds...) is connected to ltdc, | ||
987 | * a remote port & RGB panel will not be found. | ||
988 | */ | ||
989 | for_each_endpoint_of_node(np, entity) { | ||
990 | if (!of_device_is_available(entity)) | ||
991 | continue; | ||
992 | |||
993 | port = of_graph_get_remote_port_parent(entity); | ||
994 | if (port) { | ||
995 | panel = of_drm_find_panel(port); | ||
996 | of_node_put(port); | ||
997 | if (panel) { | ||
998 | DRM_DEBUG_DRIVER("remote panel %s\n", | ||
999 | port->full_name); | ||
1000 | } else { | ||
1001 | DRM_DEBUG_DRIVER("panel missing\n"); | ||
1002 | of_node_put(entity); | ||
1003 | } | ||
1004 | } | ||
1005 | } | ||
1006 | |||
1007 | return panel; | ||
1008 | } | ||
1009 | |||
1010 | int ltdc_load(struct drm_device *ddev) | ||
1011 | { | ||
1012 | struct platform_device *pdev = to_platform_device(ddev->dev); | ||
1013 | struct ltdc_device *ldev = ddev->dev_private; | ||
1014 | struct device *dev = ddev->dev; | ||
1015 | struct device_node *np = dev->of_node; | ||
1016 | struct drm_encoder *encoder; | ||
1017 | struct drm_connector *connector = NULL; | ||
1018 | struct drm_crtc *crtc; | ||
1019 | struct reset_control *rstc; | ||
1020 | struct resource res; | ||
1021 | int irq, ret, i; | ||
1022 | |||
1023 | DRM_DEBUG_DRIVER("\n"); | ||
1024 | |||
1025 | ldev->panel = ltdc_get_panel(ddev); | ||
1026 | if (!ldev->panel) | ||
1027 | return -EPROBE_DEFER; | ||
1028 | |||
1029 | rstc = of_reset_control_get(np, NULL); | ||
1030 | |||
1031 | mutex_init(&ldev->err_lock); | ||
1032 | |||
1033 | ldev->pixel_clk = devm_clk_get(dev, "lcd"); | ||
1034 | if (IS_ERR(ldev->pixel_clk)) { | ||
1035 | DRM_ERROR("Unable to get lcd clock\n"); | ||
1036 | return -ENODEV; | ||
1037 | } | ||
1038 | |||
1039 | if (clk_prepare_enable(ldev->pixel_clk)) { | ||
1040 | DRM_ERROR("Unable to prepare pixel clock\n"); | ||
1041 | return -ENODEV; | ||
1042 | } | ||
1043 | |||
1044 | if (of_address_to_resource(np, 0, &res)) { | ||
1045 | DRM_ERROR("Unable to get resource\n"); | ||
1046 | return -ENODEV; | ||
1047 | } | ||
1048 | |||
1049 | ldev->regs = devm_ioremap_resource(dev, &res); | ||
1050 | if (IS_ERR(ldev->regs)) { | ||
1051 | DRM_ERROR("Unable to get ltdc registers\n"); | ||
1052 | return PTR_ERR(ldev->regs); | ||
1053 | } | ||
1054 | |||
1055 | for (i = 0; i < MAX_IRQ; i++) { | ||
1056 | irq = platform_get_irq(pdev, i); | ||
1057 | if (irq < 0) | ||
1058 | continue; | ||
1059 | |||
1060 | ret = devm_request_threaded_irq(dev, irq, ltdc_irq, | ||
1061 | ltdc_irq_thread, IRQF_ONESHOT, | ||
1062 | dev_name(dev), ddev); | ||
1063 | if (ret) { | ||
1064 | DRM_ERROR("Failed to register LTDC interrupt\n"); | ||
1065 | return ret; | ||
1066 | } | ||
1067 | } | ||
1068 | |||
1069 | if (!IS_ERR(rstc)) | ||
1070 | reset_control_deassert(rstc); | ||
1071 | |||
1072 | /* Disable interrupts */ | ||
1073 | reg_clear(ldev->regs, LTDC_IER, | ||
1074 | IER_LIE | IER_RRIE | IER_FUIE | IER_TERRIE); | ||
1075 | |||
1076 | ret = ltdc_get_caps(ddev); | ||
1077 | if (ret) { | ||
1078 | DRM_ERROR("hardware identifier (0x%08x) not supported!\n", | ||
1079 | ldev->caps.hw_version); | ||
1080 | return ret; | ||
1081 | } | ||
1082 | |||
1083 | DRM_INFO("ltdc hw version 0x%08x - ready\n", ldev->caps.hw_version); | ||
1084 | |||
1085 | if (ldev->panel) { | ||
1086 | encoder = ltdc_rgb_encoder_create(ddev); | ||
1087 | if (!encoder) { | ||
1088 | DRM_ERROR("Failed to create RGB encoder\n"); | ||
1089 | ret = -EINVAL; | ||
1090 | goto err; | ||
1091 | } | ||
1092 | |||
1093 | connector = ltdc_rgb_connector_create(ddev); | ||
1094 | if (!connector) { | ||
1095 | DRM_ERROR("Failed to create RGB connector\n"); | ||
1096 | ret = -EINVAL; | ||
1097 | goto err; | ||
1098 | } | ||
1099 | |||
1100 | ret = drm_mode_connector_attach_encoder(connector, encoder); | ||
1101 | if (ret) { | ||
1102 | DRM_ERROR("Failed to attach connector to encoder\n"); | ||
1103 | goto err; | ||
1104 | } | ||
1105 | |||
1106 | drm_panel_attach(ldev->panel, connector); | ||
1107 | } | ||
1108 | |||
1109 | crtc = devm_kzalloc(dev, sizeof(*crtc), GFP_KERNEL); | ||
1110 | if (!crtc) { | ||
1111 | DRM_ERROR("Failed to allocate crtc\n"); | ||
1112 | ret = -ENOMEM; | ||
1113 | goto err; | ||
1114 | } | ||
1115 | |||
1116 | ret = ltdc_crtc_init(ddev, crtc); | ||
1117 | if (ret) { | ||
1118 | DRM_ERROR("Failed to init crtc\n"); | ||
1119 | goto err; | ||
1120 | } | ||
1121 | |||
1122 | ret = drm_vblank_init(ddev, NB_CRTC); | ||
1123 | if (ret) { | ||
1124 | DRM_ERROR("Failed calling drm_vblank_init()\n"); | ||
1125 | goto err; | ||
1126 | } | ||
1127 | |||
1128 | /* Allow usage of vblank without having to call drm_irq_install */ | ||
1129 | ddev->irq_enabled = 1; | ||
1130 | |||
1131 | return 0; | ||
1132 | err: | ||
1133 | if (ldev->panel) | ||
1134 | drm_panel_detach(ldev->panel); | ||
1135 | |||
1136 | clk_disable_unprepare(ldev->pixel_clk); | ||
1137 | |||
1138 | return ret; | ||
1139 | } | ||
1140 | |||
1141 | void ltdc_unload(struct drm_device *ddev) | ||
1142 | { | ||
1143 | struct ltdc_device *ldev = ddev->dev_private; | ||
1144 | |||
1145 | DRM_DEBUG_DRIVER("\n"); | ||
1146 | |||
1147 | drm_vblank_cleanup(ddev); | ||
1148 | |||
1149 | if (ldev->panel) | ||
1150 | drm_panel_detach(ldev->panel); | ||
1151 | |||
1152 | clk_disable_unprepare(ldev->pixel_clk); | ||
1153 | } | ||
1154 | |||
1155 | MODULE_AUTHOR("Philippe Cornu <philippe.cornu@st.com>"); | ||
1156 | MODULE_AUTHOR("Yannick Fertre <yannick.fertre@st.com>"); | ||
1157 | MODULE_AUTHOR("Fabien Dessenne <fabien.dessenne@st.com>"); | ||
1158 | MODULE_AUTHOR("Mickael Reulier <mickael.reulier@st.com>"); | ||
1159 | MODULE_DESCRIPTION("STMicroelectronics ST DRM LTDC driver"); | ||
1160 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/drivers/gpu/drm/stm/ltdc.h b/drivers/gpu/drm/stm/ltdc.h new file mode 100644 index 000000000000..d7a9c736ac1e --- /dev/null +++ b/drivers/gpu/drm/stm/ltdc.h | |||
@@ -0,0 +1,40 @@ | |||
1 | /* | ||
2 | * Copyright (C) STMicroelectronics SA 2017 | ||
3 | * | ||
4 | * Authors: Philippe Cornu <philippe.cornu@st.com> | ||
5 | * Yannick Fertre <yannick.fertre@st.com> | ||
6 | * Fabien Dessenne <fabien.dessenne@st.com> | ||
7 | * Mickael Reulier <mickael.reulier@st.com> | ||
8 | * | ||
9 | * License terms: GNU General Public License (GPL), version 2 | ||
10 | */ | ||
11 | |||
12 | #ifndef _LTDC_H_ | ||
13 | #define _LTDC_H_ | ||
14 | |||
15 | struct ltdc_caps { | ||
16 | u32 hw_version; /* hardware version */ | ||
17 | u32 nb_layers; /* number of supported layers */ | ||
18 | u32 reg_ofs; /* register offset for applicable regs */ | ||
19 | u32 bus_width; /* bus width (32 or 64 bits) */ | ||
20 | const u32 *pix_fmt_hw; /* supported pixel formats */ | ||
21 | }; | ||
22 | |||
23 | struct ltdc_device { | ||
24 | struct drm_fbdev_cma *fbdev; | ||
25 | void __iomem *regs; | ||
26 | struct clk *pixel_clk; /* lcd pixel clock */ | ||
27 | struct drm_panel *panel; | ||
28 | struct mutex err_lock; /* protecting error_status */ | ||
29 | struct ltdc_caps caps; | ||
30 | u32 clut[256]; /* color look up table */ | ||
31 | u32 error_status; | ||
32 | u32 irq_status; | ||
33 | }; | ||
34 | |||
35 | int ltdc_crtc_enable_vblank(struct drm_device *dev, unsigned int pipe); | ||
36 | void ltdc_crtc_disable_vblank(struct drm_device *dev, unsigned int pipe); | ||
37 | int ltdc_load(struct drm_device *ddev); | ||
38 | void ltdc_unload(struct drm_device *ddev); | ||
39 | |||
40 | #endif | ||
diff --git a/drivers/gpu/drm/tegra/drm.c b/drivers/gpu/drm/tegra/drm.c index 9a1e34e48f64..51c48a8e00ec 100644 --- a/drivers/gpu/drm/tegra/drm.c +++ b/drivers/gpu/drm/tegra/drm.c | |||
@@ -892,7 +892,7 @@ static int tegra_drm_context_cleanup(int id, void *p, void *data) | |||
892 | return 0; | 892 | return 0; |
893 | } | 893 | } |
894 | 894 | ||
895 | static void tegra_drm_preclose(struct drm_device *drm, struct drm_file *file) | 895 | static void tegra_drm_postclose(struct drm_device *drm, struct drm_file *file) |
896 | { | 896 | { |
897 | struct tegra_drm_file *fpriv = file->driver_priv; | 897 | struct tegra_drm_file *fpriv = file->driver_priv; |
898 | 898 | ||
@@ -960,7 +960,7 @@ static struct drm_driver tegra_drm_driver = { | |||
960 | .load = tegra_drm_load, | 960 | .load = tegra_drm_load, |
961 | .unload = tegra_drm_unload, | 961 | .unload = tegra_drm_unload, |
962 | .open = tegra_drm_open, | 962 | .open = tegra_drm_open, |
963 | .preclose = tegra_drm_preclose, | 963 | .postclose = tegra_drm_postclose, |
964 | .lastclose = tegra_drm_lastclose, | 964 | .lastclose = tegra_drm_lastclose, |
965 | 965 | ||
966 | #if defined(CONFIG_DEBUG_FS) | 966 | #if defined(CONFIG_DEBUG_FS) |
diff --git a/drivers/gpu/drm/vc4/Makefile b/drivers/gpu/drm/vc4/Makefile index 61f45d122bd0..ab687fba4916 100644 --- a/drivers/gpu/drm/vc4/Makefile +++ b/drivers/gpu/drm/vc4/Makefile | |||
@@ -9,6 +9,7 @@ vc4-y := \ | |||
9 | vc4_drv.o \ | 9 | vc4_drv.o \ |
10 | vc4_dpi.o \ | 10 | vc4_dpi.o \ |
11 | vc4_dsi.o \ | 11 | vc4_dsi.o \ |
12 | vc4_fence.o \ | ||
12 | vc4_kms.o \ | 13 | vc4_kms.o \ |
13 | vc4_gem.o \ | 14 | vc4_gem.o \ |
14 | vc4_hdmi.o \ | 15 | vc4_hdmi.o \ |
diff --git a/drivers/gpu/drm/vc4/vc4_bo.c b/drivers/gpu/drm/vc4/vc4_bo.c index af29432a6471..80b2f9e55c5c 100644 --- a/drivers/gpu/drm/vc4/vc4_bo.c +++ b/drivers/gpu/drm/vc4/vc4_bo.c | |||
@@ -19,6 +19,8 @@ | |||
19 | * rendering can return quickly. | 19 | * rendering can return quickly. |
20 | */ | 20 | */ |
21 | 21 | ||
22 | #include <linux/dma-buf.h> | ||
23 | |||
22 | #include "vc4_drv.h" | 24 | #include "vc4_drv.h" |
23 | #include "uapi/drm/vc4_drm.h" | 25 | #include "uapi/drm/vc4_drm.h" |
24 | 26 | ||
@@ -88,6 +90,10 @@ static void vc4_bo_destroy(struct vc4_bo *bo) | |||
88 | 90 | ||
89 | vc4->bo_stats.num_allocated--; | 91 | vc4->bo_stats.num_allocated--; |
90 | vc4->bo_stats.size_allocated -= obj->size; | 92 | vc4->bo_stats.size_allocated -= obj->size; |
93 | |||
94 | if (bo->resv == &bo->_resv) | ||
95 | reservation_object_fini(bo->resv); | ||
96 | |||
91 | drm_gem_cma_free_object(obj); | 97 | drm_gem_cma_free_object(obj); |
92 | } | 98 | } |
93 | 99 | ||
@@ -244,8 +250,12 @@ struct vc4_bo *vc4_bo_create(struct drm_device *dev, size_t unaligned_size, | |||
244 | return ERR_PTR(-ENOMEM); | 250 | return ERR_PTR(-ENOMEM); |
245 | } | 251 | } |
246 | } | 252 | } |
253 | bo = to_vc4_bo(&cma_obj->base); | ||
247 | 254 | ||
248 | return to_vc4_bo(&cma_obj->base); | 255 | bo->resv = &bo->_resv; |
256 | reservation_object_init(bo->resv); | ||
257 | |||
258 | return bo; | ||
249 | } | 259 | } |
250 | 260 | ||
251 | int vc4_dumb_create(struct drm_file *file_priv, | 261 | int vc4_dumb_create(struct drm_file *file_priv, |
@@ -369,6 +379,13 @@ static void vc4_bo_cache_time_timer(unsigned long data) | |||
369 | schedule_work(&vc4->bo_cache.time_work); | 379 | schedule_work(&vc4->bo_cache.time_work); |
370 | } | 380 | } |
371 | 381 | ||
382 | struct reservation_object *vc4_prime_res_obj(struct drm_gem_object *obj) | ||
383 | { | ||
384 | struct vc4_bo *bo = to_vc4_bo(obj); | ||
385 | |||
386 | return bo->resv; | ||
387 | } | ||
388 | |||
372 | struct dma_buf * | 389 | struct dma_buf * |
373 | vc4_prime_export(struct drm_device *dev, struct drm_gem_object *obj, int flags) | 390 | vc4_prime_export(struct drm_device *dev, struct drm_gem_object *obj, int flags) |
374 | { | 391 | { |
@@ -440,6 +457,24 @@ void *vc4_prime_vmap(struct drm_gem_object *obj) | |||
440 | return drm_gem_cma_prime_vmap(obj); | 457 | return drm_gem_cma_prime_vmap(obj); |
441 | } | 458 | } |
442 | 459 | ||
460 | struct drm_gem_object * | ||
461 | vc4_prime_import_sg_table(struct drm_device *dev, | ||
462 | struct dma_buf_attachment *attach, | ||
463 | struct sg_table *sgt) | ||
464 | { | ||
465 | struct drm_gem_object *obj; | ||
466 | struct vc4_bo *bo; | ||
467 | |||
468 | obj = drm_gem_cma_prime_import_sg_table(dev, attach, sgt); | ||
469 | if (IS_ERR(obj)) | ||
470 | return obj; | ||
471 | |||
472 | bo = to_vc4_bo(obj); | ||
473 | bo->resv = attach->dmabuf->resv; | ||
474 | |||
475 | return obj; | ||
476 | } | ||
477 | |||
443 | int vc4_create_bo_ioctl(struct drm_device *dev, void *data, | 478 | int vc4_create_bo_ioctl(struct drm_device *dev, void *data, |
444 | struct drm_file *file_priv) | 479 | struct drm_file *file_priv) |
445 | { | 480 | { |
diff --git a/drivers/gpu/drm/vc4/vc4_crtc.c b/drivers/gpu/drm/vc4/vc4_crtc.c index d86c8cce3182..1b4dbe9e1c6d 100644 --- a/drivers/gpu/drm/vc4/vc4_crtc.c +++ b/drivers/gpu/drm/vc4/vc4_crtc.c | |||
@@ -151,10 +151,10 @@ int vc4_crtc_debugfs_regs(struct seq_file *m, void *unused) | |||
151 | } | 151 | } |
152 | #endif | 152 | #endif |
153 | 153 | ||
154 | int vc4_crtc_get_scanoutpos(struct drm_device *dev, unsigned int crtc_id, | 154 | bool vc4_crtc_get_scanoutpos(struct drm_device *dev, unsigned int crtc_id, |
155 | unsigned int flags, int *vpos, int *hpos, | 155 | bool in_vblank_irq, int *vpos, int *hpos, |
156 | ktime_t *stime, ktime_t *etime, | 156 | ktime_t *stime, ktime_t *etime, |
157 | const struct drm_display_mode *mode) | 157 | const struct drm_display_mode *mode) |
158 | { | 158 | { |
159 | struct vc4_dev *vc4 = to_vc4_dev(dev); | 159 | struct vc4_dev *vc4 = to_vc4_dev(dev); |
160 | struct drm_crtc *crtc = drm_crtc_from_index(dev, crtc_id); | 160 | struct drm_crtc *crtc = drm_crtc_from_index(dev, crtc_id); |
@@ -162,7 +162,7 @@ int vc4_crtc_get_scanoutpos(struct drm_device *dev, unsigned int crtc_id, | |||
162 | u32 val; | 162 | u32 val; |
163 | int fifo_lines; | 163 | int fifo_lines; |
164 | int vblank_lines; | 164 | int vblank_lines; |
165 | int ret = 0; | 165 | bool ret = false; |
166 | 166 | ||
167 | /* preempt_disable_rt() should go right here in PREEMPT_RT patchset. */ | 167 | /* preempt_disable_rt() should go right here in PREEMPT_RT patchset. */ |
168 | 168 | ||
@@ -198,7 +198,7 @@ int vc4_crtc_get_scanoutpos(struct drm_device *dev, unsigned int crtc_id, | |||
198 | fifo_lines = vc4_crtc->cob_size / mode->crtc_hdisplay; | 198 | fifo_lines = vc4_crtc->cob_size / mode->crtc_hdisplay; |
199 | 199 | ||
200 | if (fifo_lines > 0) | 200 | if (fifo_lines > 0) |
201 | ret |= DRM_SCANOUTPOS_VALID; | 201 | ret = true; |
202 | 202 | ||
203 | /* HVS more than fifo_lines into frame for compositing? */ | 203 | /* HVS more than fifo_lines into frame for compositing? */ |
204 | if (*vpos > fifo_lines) { | 204 | if (*vpos > fifo_lines) { |
@@ -216,7 +216,6 @@ int vc4_crtc_get_scanoutpos(struct drm_device *dev, unsigned int crtc_id, | |||
216 | */ | 216 | */ |
217 | *vpos -= fifo_lines + 1; | 217 | *vpos -= fifo_lines + 1; |
218 | 218 | ||
219 | ret |= DRM_SCANOUTPOS_ACCURATE; | ||
220 | return ret; | 219 | return ret; |
221 | } | 220 | } |
222 | 221 | ||
@@ -229,10 +228,9 @@ int vc4_crtc_get_scanoutpos(struct drm_device *dev, unsigned int crtc_id, | |||
229 | * We can't get meaningful readings wrt. scanline position of the PV | 228 | * We can't get meaningful readings wrt. scanline position of the PV |
230 | * and need to make things up in a approximative but consistent way. | 229 | * and need to make things up in a approximative but consistent way. |
231 | */ | 230 | */ |
232 | ret |= DRM_SCANOUTPOS_IN_VBLANK; | ||
233 | vblank_lines = mode->vtotal - mode->vdisplay; | 231 | vblank_lines = mode->vtotal - mode->vdisplay; |
234 | 232 | ||
235 | if (flags & DRM_CALLED_FROM_VBLIRQ) { | 233 | if (in_vblank_irq) { |
236 | /* | 234 | /* |
237 | * Assume the irq handler got called close to first | 235 | * Assume the irq handler got called close to first |
238 | * line of vblank, so PV has about a full vblank | 236 | * line of vblank, so PV has about a full vblank |
@@ -254,9 +252,10 @@ int vc4_crtc_get_scanoutpos(struct drm_device *dev, unsigned int crtc_id, | |||
254 | * we are at the very beginning of vblank, as the hvs just | 252 | * we are at the very beginning of vblank, as the hvs just |
255 | * started refilling, and the stime and etime timestamps | 253 | * started refilling, and the stime and etime timestamps |
256 | * truly correspond to start of vblank. | 254 | * truly correspond to start of vblank. |
255 | * | ||
256 | * Unfortunately there's no way to report this to upper levels | ||
257 | * and make it more useful. | ||
257 | */ | 258 | */ |
258 | if ((val & SCALER_DISPSTATX_FULL) != SCALER_DISPSTATX_FULL) | ||
259 | ret |= DRM_SCANOUTPOS_ACCURATE; | ||
260 | } else { | 259 | } else { |
261 | /* | 260 | /* |
262 | * No clue where we are inside vblank. Return a vpos of zero, | 261 | * No clue where we are inside vblank. Return a vpos of zero, |
@@ -270,19 +269,6 @@ int vc4_crtc_get_scanoutpos(struct drm_device *dev, unsigned int crtc_id, | |||
270 | return ret; | 269 | return ret; |
271 | } | 270 | } |
272 | 271 | ||
273 | int vc4_crtc_get_vblank_timestamp(struct drm_device *dev, unsigned int crtc_id, | ||
274 | int *max_error, struct timeval *vblank_time, | ||
275 | unsigned flags) | ||
276 | { | ||
277 | struct drm_crtc *crtc = drm_crtc_from_index(dev, crtc_id); | ||
278 | struct drm_crtc_state *state = crtc->state; | ||
279 | |||
280 | /* Helper routine in DRM core does all the work: */ | ||
281 | return drm_calc_vbltimestamp_from_scanoutpos(dev, crtc_id, max_error, | ||
282 | vblank_time, flags, | ||
283 | &state->adjusted_mode); | ||
284 | } | ||
285 | |||
286 | static void vc4_crtc_destroy(struct drm_crtc *crtc) | 272 | static void vc4_crtc_destroy(struct drm_crtc *crtc) |
287 | { | 273 | { |
288 | drm_crtc_cleanup(crtc); | 274 | drm_crtc_cleanup(crtc); |
diff --git a/drivers/gpu/drm/vc4/vc4_drv.c b/drivers/gpu/drm/vc4/vc4_drv.c index 61e674baf3a6..863974942c66 100644 --- a/drivers/gpu/drm/vc4/vc4_drv.c +++ b/drivers/gpu/drm/vc4/vc4_drv.c | |||
@@ -154,7 +154,7 @@ static struct drm_driver vc4_drm_driver = { | |||
154 | .irq_uninstall = vc4_irq_uninstall, | 154 | .irq_uninstall = vc4_irq_uninstall, |
155 | 155 | ||
156 | .get_scanout_position = vc4_crtc_get_scanoutpos, | 156 | .get_scanout_position = vc4_crtc_get_scanoutpos, |
157 | .get_vblank_timestamp = vc4_crtc_get_vblank_timestamp, | 157 | .get_vblank_timestamp = drm_calc_vbltimestamp_from_scanoutpos, |
158 | 158 | ||
159 | #if defined(CONFIG_DEBUG_FS) | 159 | #if defined(CONFIG_DEBUG_FS) |
160 | .debugfs_init = vc4_debugfs_init, | 160 | .debugfs_init = vc4_debugfs_init, |
@@ -168,8 +168,9 @@ static struct drm_driver vc4_drm_driver = { | |||
168 | .prime_fd_to_handle = drm_gem_prime_fd_to_handle, | 168 | .prime_fd_to_handle = drm_gem_prime_fd_to_handle, |
169 | .gem_prime_import = drm_gem_prime_import, | 169 | .gem_prime_import = drm_gem_prime_import, |
170 | .gem_prime_export = vc4_prime_export, | 170 | .gem_prime_export = vc4_prime_export, |
171 | .gem_prime_res_obj = vc4_prime_res_obj, | ||
171 | .gem_prime_get_sg_table = drm_gem_cma_prime_get_sg_table, | 172 | .gem_prime_get_sg_table = drm_gem_cma_prime_get_sg_table, |
172 | .gem_prime_import_sg_table = drm_gem_cma_prime_import_sg_table, | 173 | .gem_prime_import_sg_table = vc4_prime_import_sg_table, |
173 | .gem_prime_vmap = vc4_prime_vmap, | 174 | .gem_prime_vmap = vc4_prime_vmap, |
174 | .gem_prime_vunmap = drm_gem_cma_prime_vunmap, | 175 | .gem_prime_vunmap = drm_gem_cma_prime_vunmap, |
175 | .gem_prime_mmap = vc4_prime_mmap, | 176 | .gem_prime_mmap = vc4_prime_mmap, |
@@ -334,6 +335,7 @@ static int vc4_platform_drm_remove(struct platform_device *pdev) | |||
334 | 335 | ||
335 | static const struct of_device_id vc4_of_match[] = { | 336 | static const struct of_device_id vc4_of_match[] = { |
336 | { .compatible = "brcm,bcm2835-vc4", }, | 337 | { .compatible = "brcm,bcm2835-vc4", }, |
338 | { .compatible = "brcm,cygnus-vc4", }, | ||
337 | {}, | 339 | {}, |
338 | }; | 340 | }; |
339 | MODULE_DEVICE_TABLE(of, vc4_of_match); | 341 | MODULE_DEVICE_TABLE(of, vc4_of_match); |
diff --git a/drivers/gpu/drm/vc4/vc4_drv.h b/drivers/gpu/drm/vc4/vc4_drv.h index dffce6293d87..5ba281361fb7 100644 --- a/drivers/gpu/drm/vc4/vc4_drv.h +++ b/drivers/gpu/drm/vc4/vc4_drv.h | |||
@@ -8,7 +8,9 @@ | |||
8 | 8 | ||
9 | #include "drmP.h" | 9 | #include "drmP.h" |
10 | #include "drm_gem_cma_helper.h" | 10 | #include "drm_gem_cma_helper.h" |
11 | #include "drm_gem_cma_helper.h" | ||
11 | 12 | ||
13 | #include <linux/reservation.h> | ||
12 | #include <drm/drm_encoder.h> | 14 | #include <drm/drm_encoder.h> |
13 | 15 | ||
14 | struct vc4_dev { | 16 | struct vc4_dev { |
@@ -56,6 +58,8 @@ struct vc4_dev { | |||
56 | /* Protects bo_cache and the BO stats. */ | 58 | /* Protects bo_cache and the BO stats. */ |
57 | struct mutex bo_lock; | 59 | struct mutex bo_lock; |
58 | 60 | ||
61 | uint64_t dma_fence_context; | ||
62 | |||
59 | /* Sequence number for the last job queued in bin_job_list. | 63 | /* Sequence number for the last job queued in bin_job_list. |
60 | * Starts at 0 (no jobs emitted). | 64 | * Starts at 0 (no jobs emitted). |
61 | */ | 65 | */ |
@@ -95,12 +99,23 @@ struct vc4_dev { | |||
95 | */ | 99 | */ |
96 | struct list_head seqno_cb_list; | 100 | struct list_head seqno_cb_list; |
97 | 101 | ||
98 | /* The binner overflow memory that's currently set up in | 102 | /* The memory used for storing binner tile alloc, tile state, |
99 | * BPOA/BPOS registers. When overflow occurs and a new one is | 103 | * and overflow memory allocations. This is freed when V3D |
100 | * allocated, the previous one will be moved to | 104 | * powers down. |
101 | * vc4->current_exec's free list. | 105 | */ |
106 | struct vc4_bo *bin_bo; | ||
107 | |||
108 | /* Size of blocks allocated within bin_bo. */ | ||
109 | uint32_t bin_alloc_size; | ||
110 | |||
111 | /* Bitmask of the bin_alloc_size chunks in bin_bo that are | ||
112 | * used. | ||
102 | */ | 113 | */ |
103 | struct vc4_bo *overflow_mem; | 114 | uint32_t bin_alloc_used; |
115 | |||
116 | /* Bitmask of the current bin_alloc used for overflow memory. */ | ||
117 | uint32_t bin_alloc_overflow; | ||
118 | |||
104 | struct work_struct overflow_mem_work; | 119 | struct work_struct overflow_mem_work; |
105 | 120 | ||
106 | int power_refcount; | 121 | int power_refcount; |
@@ -150,6 +165,10 @@ struct vc4_bo { | |||
150 | * DRM_IOCTL_VC4_CREATE_SHADER_BO. | 165 | * DRM_IOCTL_VC4_CREATE_SHADER_BO. |
151 | */ | 166 | */ |
152 | struct vc4_validated_shader_info *validated_shader; | 167 | struct vc4_validated_shader_info *validated_shader; |
168 | |||
169 | /* normally (resv == &_resv) except for imported bo's */ | ||
170 | struct reservation_object *resv; | ||
171 | struct reservation_object _resv; | ||
153 | }; | 172 | }; |
154 | 173 | ||
155 | static inline struct vc4_bo * | 174 | static inline struct vc4_bo * |
@@ -158,6 +177,19 @@ to_vc4_bo(struct drm_gem_object *bo) | |||
158 | return (struct vc4_bo *)bo; | 177 | return (struct vc4_bo *)bo; |
159 | } | 178 | } |
160 | 179 | ||
180 | struct vc4_fence { | ||
181 | struct dma_fence base; | ||
182 | struct drm_device *dev; | ||
183 | /* vc4 seqno for signaled() test */ | ||
184 | uint64_t seqno; | ||
185 | }; | ||
186 | |||
187 | static inline struct vc4_fence * | ||
188 | to_vc4_fence(struct dma_fence *fence) | ||
189 | { | ||
190 | return (struct vc4_fence *)fence; | ||
191 | } | ||
192 | |||
161 | struct vc4_seqno_cb { | 193 | struct vc4_seqno_cb { |
162 | struct work_struct work; | 194 | struct work_struct work; |
163 | uint64_t seqno; | 195 | uint64_t seqno; |
@@ -168,6 +200,7 @@ struct vc4_v3d { | |||
168 | struct vc4_dev *vc4; | 200 | struct vc4_dev *vc4; |
169 | struct platform_device *pdev; | 201 | struct platform_device *pdev; |
170 | void __iomem *regs; | 202 | void __iomem *regs; |
203 | struct clk *clk; | ||
171 | }; | 204 | }; |
172 | 205 | ||
173 | struct vc4_hvs { | 206 | struct vc4_hvs { |
@@ -230,6 +263,8 @@ struct vc4_exec_info { | |||
230 | /* Latest write_seqno of any BO that binning depends on. */ | 263 | /* Latest write_seqno of any BO that binning depends on. */ |
231 | uint64_t bin_dep_seqno; | 264 | uint64_t bin_dep_seqno; |
232 | 265 | ||
266 | struct dma_fence *fence; | ||
267 | |||
233 | /* Last current addresses the hardware was processing when the | 268 | /* Last current addresses the hardware was processing when the |
234 | * hangcheck timer checked on us. | 269 | * hangcheck timer checked on us. |
235 | */ | 270 | */ |
@@ -293,8 +328,12 @@ struct vc4_exec_info { | |||
293 | bool found_increment_semaphore_packet; | 328 | bool found_increment_semaphore_packet; |
294 | bool found_flush; | 329 | bool found_flush; |
295 | uint8_t bin_tiles_x, bin_tiles_y; | 330 | uint8_t bin_tiles_x, bin_tiles_y; |
296 | struct drm_gem_cma_object *tile_bo; | 331 | /* Physical address of the start of the tile alloc array |
332 | * (where each tile's binned CL will start) | ||
333 | */ | ||
297 | uint32_t tile_alloc_offset; | 334 | uint32_t tile_alloc_offset; |
335 | /* Bitmask of which binner slots are freed when this job completes. */ | ||
336 | uint32_t bin_slots; | ||
298 | 337 | ||
299 | /** | 338 | /** |
300 | * Computed addresses pointing into exec_bo where we start the | 339 | * Computed addresses pointing into exec_bo where we start the |
@@ -436,7 +475,11 @@ int vc4_mmap_bo_ioctl(struct drm_device *dev, void *data, | |||
436 | int vc4_get_hang_state_ioctl(struct drm_device *dev, void *data, | 475 | int vc4_get_hang_state_ioctl(struct drm_device *dev, void *data, |
437 | struct drm_file *file_priv); | 476 | struct drm_file *file_priv); |
438 | int vc4_mmap(struct file *filp, struct vm_area_struct *vma); | 477 | int vc4_mmap(struct file *filp, struct vm_area_struct *vma); |
478 | struct reservation_object *vc4_prime_res_obj(struct drm_gem_object *obj); | ||
439 | int vc4_prime_mmap(struct drm_gem_object *obj, struct vm_area_struct *vma); | 479 | int vc4_prime_mmap(struct drm_gem_object *obj, struct vm_area_struct *vma); |
480 | struct drm_gem_object *vc4_prime_import_sg_table(struct drm_device *dev, | ||
481 | struct dma_buf_attachment *attach, | ||
482 | struct sg_table *sgt); | ||
440 | void *vc4_prime_vmap(struct drm_gem_object *obj); | 483 | void *vc4_prime_vmap(struct drm_gem_object *obj); |
441 | void vc4_bo_cache_init(struct drm_device *dev); | 484 | void vc4_bo_cache_init(struct drm_device *dev); |
442 | void vc4_bo_cache_destroy(struct drm_device *dev); | 485 | void vc4_bo_cache_destroy(struct drm_device *dev); |
@@ -446,13 +489,10 @@ int vc4_bo_stats_debugfs(struct seq_file *m, void *arg); | |||
446 | extern struct platform_driver vc4_crtc_driver; | 489 | extern struct platform_driver vc4_crtc_driver; |
447 | bool vc4_event_pending(struct drm_crtc *crtc); | 490 | bool vc4_event_pending(struct drm_crtc *crtc); |
448 | int vc4_crtc_debugfs_regs(struct seq_file *m, void *arg); | 491 | int vc4_crtc_debugfs_regs(struct seq_file *m, void *arg); |
449 | int vc4_crtc_get_scanoutpos(struct drm_device *dev, unsigned int crtc_id, | 492 | bool vc4_crtc_get_scanoutpos(struct drm_device *dev, unsigned int crtc_id, |
450 | unsigned int flags, int *vpos, int *hpos, | 493 | bool in_vblank_irq, int *vpos, int *hpos, |
451 | ktime_t *stime, ktime_t *etime, | 494 | ktime_t *stime, ktime_t *etime, |
452 | const struct drm_display_mode *mode); | 495 | const struct drm_display_mode *mode); |
453 | int vc4_crtc_get_vblank_timestamp(struct drm_device *dev, unsigned int crtc_id, | ||
454 | int *max_error, struct timeval *vblank_time, | ||
455 | unsigned flags); | ||
456 | 496 | ||
457 | /* vc4_debugfs.c */ | 497 | /* vc4_debugfs.c */ |
458 | int vc4_debugfs_init(struct drm_minor *minor); | 498 | int vc4_debugfs_init(struct drm_minor *minor); |
@@ -468,6 +508,9 @@ int vc4_dpi_debugfs_regs(struct seq_file *m, void *unused); | |||
468 | extern struct platform_driver vc4_dsi_driver; | 508 | extern struct platform_driver vc4_dsi_driver; |
469 | int vc4_dsi_debugfs_regs(struct seq_file *m, void *unused); | 509 | int vc4_dsi_debugfs_regs(struct seq_file *m, void *unused); |
470 | 510 | ||
511 | /* vc4_fence.c */ | ||
512 | extern const struct dma_fence_ops vc4_fence_ops; | ||
513 | |||
471 | /* vc4_gem.c */ | 514 | /* vc4_gem.c */ |
472 | void vc4_gem_init(struct drm_device *dev); | 515 | void vc4_gem_init(struct drm_device *dev); |
473 | void vc4_gem_destroy(struct drm_device *dev); | 516 | void vc4_gem_destroy(struct drm_device *dev); |
@@ -522,6 +565,7 @@ void vc4_plane_async_set_fb(struct drm_plane *plane, | |||
522 | extern struct platform_driver vc4_v3d_driver; | 565 | extern struct platform_driver vc4_v3d_driver; |
523 | int vc4_v3d_debugfs_ident(struct seq_file *m, void *unused); | 566 | int vc4_v3d_debugfs_ident(struct seq_file *m, void *unused); |
524 | int vc4_v3d_debugfs_regs(struct seq_file *m, void *unused); | 567 | int vc4_v3d_debugfs_regs(struct seq_file *m, void *unused); |
568 | int vc4_v3d_get_bin_slot(struct vc4_dev *vc4); | ||
525 | 569 | ||
526 | /* vc4_validate.c */ | 570 | /* vc4_validate.c */ |
527 | int | 571 | int |
diff --git a/drivers/gpu/drm/vc4/vc4_fence.c b/drivers/gpu/drm/vc4/vc4_fence.c new file mode 100644 index 000000000000..dbf5a5a5d5f5 --- /dev/null +++ b/drivers/gpu/drm/vc4/vc4_fence.c | |||
@@ -0,0 +1,56 @@ | |||
1 | /* | ||
2 | * Copyright © 2017 Broadcom | ||
3 | * | ||
4 | * Permission is hereby granted, free of charge, to any person obtaining a | ||
5 | * copy of this software and associated documentation files (the "Software"), | ||
6 | * to deal in the Software without restriction, including without limitation | ||
7 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||
8 | * and/or sell copies of the Software, and to permit persons to whom the | ||
9 | * Software is furnished to do so, subject to the following conditions: | ||
10 | * | ||
11 | * The above copyright notice and this permission notice (including the next | ||
12 | * paragraph) shall be included in all copies or substantial portions of the | ||
13 | * Software. | ||
14 | * | ||
15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||
18 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | ||
20 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS | ||
21 | * IN THE SOFTWARE. | ||
22 | */ | ||
23 | |||
24 | #include "vc4_drv.h" | ||
25 | |||
26 | static const char *vc4_fence_get_driver_name(struct dma_fence *fence) | ||
27 | { | ||
28 | return "vc4"; | ||
29 | } | ||
30 | |||
31 | static const char *vc4_fence_get_timeline_name(struct dma_fence *fence) | ||
32 | { | ||
33 | return "vc4-v3d"; | ||
34 | } | ||
35 | |||
36 | static bool vc4_fence_enable_signaling(struct dma_fence *fence) | ||
37 | { | ||
38 | return true; | ||
39 | } | ||
40 | |||
41 | static bool vc4_fence_signaled(struct dma_fence *fence) | ||
42 | { | ||
43 | struct vc4_fence *f = to_vc4_fence(fence); | ||
44 | struct vc4_dev *vc4 = to_vc4_dev(f->dev); | ||
45 | |||
46 | return vc4->finished_seqno >= f->seqno; | ||
47 | } | ||
48 | |||
49 | const struct dma_fence_ops vc4_fence_ops = { | ||
50 | .get_driver_name = vc4_fence_get_driver_name, | ||
51 | .get_timeline_name = vc4_fence_get_timeline_name, | ||
52 | .enable_signaling = vc4_fence_enable_signaling, | ||
53 | .signaled = vc4_fence_signaled, | ||
54 | .wait = dma_fence_default_wait, | ||
55 | .release = dma_fence_free, | ||
56 | }; | ||
diff --git a/drivers/gpu/drm/vc4/vc4_gem.c b/drivers/gpu/drm/vc4/vc4_gem.c index e9c381c42139..735412e3725a 100644 --- a/drivers/gpu/drm/vc4/vc4_gem.c +++ b/drivers/gpu/drm/vc4/vc4_gem.c | |||
@@ -463,6 +463,8 @@ vc4_update_bo_seqnos(struct vc4_exec_info *exec, uint64_t seqno) | |||
463 | for (i = 0; i < exec->bo_count; i++) { | 463 | for (i = 0; i < exec->bo_count; i++) { |
464 | bo = to_vc4_bo(&exec->bo[i]->base); | 464 | bo = to_vc4_bo(&exec->bo[i]->base); |
465 | bo->seqno = seqno; | 465 | bo->seqno = seqno; |
466 | |||
467 | reservation_object_add_shared_fence(bo->resv, exec->fence); | ||
466 | } | 468 | } |
467 | 469 | ||
468 | list_for_each_entry(bo, &exec->unref_list, unref_head) { | 470 | list_for_each_entry(bo, &exec->unref_list, unref_head) { |
@@ -472,7 +474,103 @@ vc4_update_bo_seqnos(struct vc4_exec_info *exec, uint64_t seqno) | |||
472 | for (i = 0; i < exec->rcl_write_bo_count; i++) { | 474 | for (i = 0; i < exec->rcl_write_bo_count; i++) { |
473 | bo = to_vc4_bo(&exec->rcl_write_bo[i]->base); | 475 | bo = to_vc4_bo(&exec->rcl_write_bo[i]->base); |
474 | bo->write_seqno = seqno; | 476 | bo->write_seqno = seqno; |
477 | |||
478 | reservation_object_add_excl_fence(bo->resv, exec->fence); | ||
479 | } | ||
480 | } | ||
481 | |||
482 | static void | ||
483 | vc4_unlock_bo_reservations(struct drm_device *dev, | ||
484 | struct vc4_exec_info *exec, | ||
485 | struct ww_acquire_ctx *acquire_ctx) | ||
486 | { | ||
487 | int i; | ||
488 | |||
489 | for (i = 0; i < exec->bo_count; i++) { | ||
490 | struct vc4_bo *bo = to_vc4_bo(&exec->bo[i]->base); | ||
491 | |||
492 | ww_mutex_unlock(&bo->resv->lock); | ||
493 | } | ||
494 | |||
495 | ww_acquire_fini(acquire_ctx); | ||
496 | } | ||
497 | |||
498 | /* Takes the reservation lock on all the BOs being referenced, so that | ||
499 | * at queue submit time we can update the reservations. | ||
500 | * | ||
501 | * We don't lock the RCL the tile alloc/state BOs, or overflow memory | ||
502 | * (all of which are on exec->unref_list). They're entirely private | ||
503 | * to vc4, so we don't attach dma-buf fences to them. | ||
504 | */ | ||
505 | static int | ||
506 | vc4_lock_bo_reservations(struct drm_device *dev, | ||
507 | struct vc4_exec_info *exec, | ||
508 | struct ww_acquire_ctx *acquire_ctx) | ||
509 | { | ||
510 | int contended_lock = -1; | ||
511 | int i, ret; | ||
512 | struct vc4_bo *bo; | ||
513 | |||
514 | ww_acquire_init(acquire_ctx, &reservation_ww_class); | ||
515 | |||
516 | retry: | ||
517 | if (contended_lock != -1) { | ||
518 | bo = to_vc4_bo(&exec->bo[contended_lock]->base); | ||
519 | ret = ww_mutex_lock_slow_interruptible(&bo->resv->lock, | ||
520 | acquire_ctx); | ||
521 | if (ret) { | ||
522 | ww_acquire_done(acquire_ctx); | ||
523 | return ret; | ||
524 | } | ||
525 | } | ||
526 | |||
527 | for (i = 0; i < exec->bo_count; i++) { | ||
528 | if (i == contended_lock) | ||
529 | continue; | ||
530 | |||
531 | bo = to_vc4_bo(&exec->bo[i]->base); | ||
532 | |||
533 | ret = ww_mutex_lock_interruptible(&bo->resv->lock, acquire_ctx); | ||
534 | if (ret) { | ||
535 | int j; | ||
536 | |||
537 | for (j = 0; j < i; j++) { | ||
538 | bo = to_vc4_bo(&exec->bo[j]->base); | ||
539 | ww_mutex_unlock(&bo->resv->lock); | ||
540 | } | ||
541 | |||
542 | if (contended_lock != -1 && contended_lock >= i) { | ||
543 | bo = to_vc4_bo(&exec->bo[contended_lock]->base); | ||
544 | |||
545 | ww_mutex_unlock(&bo->resv->lock); | ||
546 | } | ||
547 | |||
548 | if (ret == -EDEADLK) { | ||
549 | contended_lock = i; | ||
550 | goto retry; | ||
551 | } | ||
552 | |||
553 | ww_acquire_done(acquire_ctx); | ||
554 | return ret; | ||
555 | } | ||
475 | } | 556 | } |
557 | |||
558 | ww_acquire_done(acquire_ctx); | ||
559 | |||
560 | /* Reserve space for our shared (read-only) fence references, | ||
561 | * before we commit the CL to the hardware. | ||
562 | */ | ||
563 | for (i = 0; i < exec->bo_count; i++) { | ||
564 | bo = to_vc4_bo(&exec->bo[i]->base); | ||
565 | |||
566 | ret = reservation_object_reserve_shared(bo->resv); | ||
567 | if (ret) { | ||
568 | vc4_unlock_bo_reservations(dev, exec, acquire_ctx); | ||
569 | return ret; | ||
570 | } | ||
571 | } | ||
572 | |||
573 | return 0; | ||
476 | } | 574 | } |
477 | 575 | ||
478 | /* Queues a struct vc4_exec_info for execution. If no job is | 576 | /* Queues a struct vc4_exec_info for execution. If no job is |
@@ -484,19 +582,34 @@ vc4_update_bo_seqnos(struct vc4_exec_info *exec, uint64_t seqno) | |||
484 | * then bump the end address. That's a change for a later date, | 582 | * then bump the end address. That's a change for a later date, |
485 | * though. | 583 | * though. |
486 | */ | 584 | */ |
487 | static void | 585 | static int |
488 | vc4_queue_submit(struct drm_device *dev, struct vc4_exec_info *exec) | 586 | vc4_queue_submit(struct drm_device *dev, struct vc4_exec_info *exec, |
587 | struct ww_acquire_ctx *acquire_ctx) | ||
489 | { | 588 | { |
490 | struct vc4_dev *vc4 = to_vc4_dev(dev); | 589 | struct vc4_dev *vc4 = to_vc4_dev(dev); |
491 | uint64_t seqno; | 590 | uint64_t seqno; |
492 | unsigned long irqflags; | 591 | unsigned long irqflags; |
592 | struct vc4_fence *fence; | ||
593 | |||
594 | fence = kzalloc(sizeof(*fence), GFP_KERNEL); | ||
595 | if (!fence) | ||
596 | return -ENOMEM; | ||
597 | fence->dev = dev; | ||
493 | 598 | ||
494 | spin_lock_irqsave(&vc4->job_lock, irqflags); | 599 | spin_lock_irqsave(&vc4->job_lock, irqflags); |
495 | 600 | ||
496 | seqno = ++vc4->emit_seqno; | 601 | seqno = ++vc4->emit_seqno; |
497 | exec->seqno = seqno; | 602 | exec->seqno = seqno; |
603 | |||
604 | dma_fence_init(&fence->base, &vc4_fence_ops, &vc4->job_lock, | ||
605 | vc4->dma_fence_context, exec->seqno); | ||
606 | fence->seqno = exec->seqno; | ||
607 | exec->fence = &fence->base; | ||
608 | |||
498 | vc4_update_bo_seqnos(exec, seqno); | 609 | vc4_update_bo_seqnos(exec, seqno); |
499 | 610 | ||
611 | vc4_unlock_bo_reservations(dev, exec, acquire_ctx); | ||
612 | |||
500 | list_add_tail(&exec->head, &vc4->bin_job_list); | 613 | list_add_tail(&exec->head, &vc4->bin_job_list); |
501 | 614 | ||
502 | /* If no job was executing, kick ours off. Otherwise, it'll | 615 | /* If no job was executing, kick ours off. Otherwise, it'll |
@@ -509,6 +622,8 @@ vc4_queue_submit(struct drm_device *dev, struct vc4_exec_info *exec) | |||
509 | } | 622 | } |
510 | 623 | ||
511 | spin_unlock_irqrestore(&vc4->job_lock, irqflags); | 624 | spin_unlock_irqrestore(&vc4->job_lock, irqflags); |
625 | |||
626 | return 0; | ||
512 | } | 627 | } |
513 | 628 | ||
514 | /** | 629 | /** |
@@ -705,8 +820,15 @@ static void | |||
705 | vc4_complete_exec(struct drm_device *dev, struct vc4_exec_info *exec) | 820 | vc4_complete_exec(struct drm_device *dev, struct vc4_exec_info *exec) |
706 | { | 821 | { |
707 | struct vc4_dev *vc4 = to_vc4_dev(dev); | 822 | struct vc4_dev *vc4 = to_vc4_dev(dev); |
823 | unsigned long irqflags; | ||
708 | unsigned i; | 824 | unsigned i; |
709 | 825 | ||
826 | /* If we got force-completed because of GPU reset rather than | ||
827 | * through our IRQ handler, signal the fence now. | ||
828 | */ | ||
829 | if (exec->fence) | ||
830 | dma_fence_signal(exec->fence); | ||
831 | |||
710 | if (exec->bo) { | 832 | if (exec->bo) { |
711 | for (i = 0; i < exec->bo_count; i++) | 833 | for (i = 0; i < exec->bo_count; i++) |
712 | drm_gem_object_unreference_unlocked(&exec->bo[i]->base); | 834 | drm_gem_object_unreference_unlocked(&exec->bo[i]->base); |
@@ -720,6 +842,11 @@ vc4_complete_exec(struct drm_device *dev, struct vc4_exec_info *exec) | |||
720 | drm_gem_object_unreference_unlocked(&bo->base.base); | 842 | drm_gem_object_unreference_unlocked(&bo->base.base); |
721 | } | 843 | } |
722 | 844 | ||
845 | /* Free up the allocation of any bin slots we used. */ | ||
846 | spin_lock_irqsave(&vc4->job_lock, irqflags); | ||
847 | vc4->bin_alloc_used &= ~exec->bin_slots; | ||
848 | spin_unlock_irqrestore(&vc4->job_lock, irqflags); | ||
849 | |||
723 | mutex_lock(&vc4->power_lock); | 850 | mutex_lock(&vc4->power_lock); |
724 | if (--vc4->power_refcount == 0) { | 851 | if (--vc4->power_refcount == 0) { |
725 | pm_runtime_mark_last_busy(&vc4->v3d->pdev->dev); | 852 | pm_runtime_mark_last_busy(&vc4->v3d->pdev->dev); |
@@ -874,6 +1001,7 @@ vc4_submit_cl_ioctl(struct drm_device *dev, void *data, | |||
874 | struct vc4_dev *vc4 = to_vc4_dev(dev); | 1001 | struct vc4_dev *vc4 = to_vc4_dev(dev); |
875 | struct drm_vc4_submit_cl *args = data; | 1002 | struct drm_vc4_submit_cl *args = data; |
876 | struct vc4_exec_info *exec; | 1003 | struct vc4_exec_info *exec; |
1004 | struct ww_acquire_ctx acquire_ctx; | ||
877 | int ret = 0; | 1005 | int ret = 0; |
878 | 1006 | ||
879 | if ((args->flags & ~VC4_SUBMIT_CL_USE_CLEAR_COLOR) != 0) { | 1007 | if ((args->flags & ~VC4_SUBMIT_CL_USE_CLEAR_COLOR) != 0) { |
@@ -888,13 +1016,16 @@ vc4_submit_cl_ioctl(struct drm_device *dev, void *data, | |||
888 | } | 1016 | } |
889 | 1017 | ||
890 | mutex_lock(&vc4->power_lock); | 1018 | mutex_lock(&vc4->power_lock); |
891 | if (vc4->power_refcount++ == 0) | 1019 | if (vc4->power_refcount++ == 0) { |
892 | ret = pm_runtime_get_sync(&vc4->v3d->pdev->dev); | 1020 | ret = pm_runtime_get_sync(&vc4->v3d->pdev->dev); |
893 | mutex_unlock(&vc4->power_lock); | 1021 | if (ret < 0) { |
894 | if (ret < 0) { | 1022 | mutex_unlock(&vc4->power_lock); |
895 | kfree(exec); | 1023 | vc4->power_refcount--; |
896 | return ret; | 1024 | kfree(exec); |
1025 | return ret; | ||
1026 | } | ||
897 | } | 1027 | } |
1028 | mutex_unlock(&vc4->power_lock); | ||
898 | 1029 | ||
899 | exec->args = args; | 1030 | exec->args = args; |
900 | INIT_LIST_HEAD(&exec->unref_list); | 1031 | INIT_LIST_HEAD(&exec->unref_list); |
@@ -916,12 +1047,18 @@ vc4_submit_cl_ioctl(struct drm_device *dev, void *data, | |||
916 | if (ret) | 1047 | if (ret) |
917 | goto fail; | 1048 | goto fail; |
918 | 1049 | ||
1050 | ret = vc4_lock_bo_reservations(dev, exec, &acquire_ctx); | ||
1051 | if (ret) | ||
1052 | goto fail; | ||
1053 | |||
919 | /* Clear this out of the struct we'll be putting in the queue, | 1054 | /* Clear this out of the struct we'll be putting in the queue, |
920 | * since it's part of our stack. | 1055 | * since it's part of our stack. |
921 | */ | 1056 | */ |
922 | exec->args = NULL; | 1057 | exec->args = NULL; |
923 | 1058 | ||
924 | vc4_queue_submit(dev, exec); | 1059 | ret = vc4_queue_submit(dev, exec, &acquire_ctx); |
1060 | if (ret) | ||
1061 | goto fail; | ||
925 | 1062 | ||
926 | /* Return the seqno for our job. */ | 1063 | /* Return the seqno for our job. */ |
927 | args->seqno = vc4->emit_seqno; | 1064 | args->seqno = vc4->emit_seqno; |
@@ -939,6 +1076,8 @@ vc4_gem_init(struct drm_device *dev) | |||
939 | { | 1076 | { |
940 | struct vc4_dev *vc4 = to_vc4_dev(dev); | 1077 | struct vc4_dev *vc4 = to_vc4_dev(dev); |
941 | 1078 | ||
1079 | vc4->dma_fence_context = dma_fence_context_alloc(1); | ||
1080 | |||
942 | INIT_LIST_HEAD(&vc4->bin_job_list); | 1081 | INIT_LIST_HEAD(&vc4->bin_job_list); |
943 | INIT_LIST_HEAD(&vc4->render_job_list); | 1082 | INIT_LIST_HEAD(&vc4->render_job_list); |
944 | INIT_LIST_HEAD(&vc4->job_done_list); | 1083 | INIT_LIST_HEAD(&vc4->job_done_list); |
@@ -968,9 +1107,9 @@ vc4_gem_destroy(struct drm_device *dev) | |||
968 | /* V3D should already have disabled its interrupt and cleared | 1107 | /* V3D should already have disabled its interrupt and cleared |
969 | * the overflow allocation registers. Now free the object. | 1108 | * the overflow allocation registers. Now free the object. |
970 | */ | 1109 | */ |
971 | if (vc4->overflow_mem) { | 1110 | if (vc4->bin_bo) { |
972 | drm_gem_object_unreference_unlocked(&vc4->overflow_mem->base.base); | 1111 | drm_gem_object_put_unlocked(&vc4->bin_bo->base.base); |
973 | vc4->overflow_mem = NULL; | 1112 | vc4->bin_bo = NULL; |
974 | } | 1113 | } |
975 | 1114 | ||
976 | if (vc4->hang_state) | 1115 | if (vc4->hang_state) |
diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c index e9cbe269710b..3c2723f6345c 100644 --- a/drivers/gpu/drm/vc4/vc4_hdmi.c +++ b/drivers/gpu/drm/vc4/vc4_hdmi.c | |||
@@ -51,6 +51,7 @@ | |||
51 | #include "linux/of_address.h" | 51 | #include "linux/of_address.h" |
52 | #include "linux/of_gpio.h" | 52 | #include "linux/of_gpio.h" |
53 | #include "linux/of_platform.h" | 53 | #include "linux/of_platform.h" |
54 | #include "linux/pm_runtime.h" | ||
54 | #include "linux/rational.h" | 55 | #include "linux/rational.h" |
55 | #include "sound/dmaengine_pcm.h" | 56 | #include "sound/dmaengine_pcm.h" |
56 | #include "sound/pcm_drm_eld.h" | 57 | #include "sound/pcm_drm_eld.h" |
@@ -449,13 +450,38 @@ static void vc4_hdmi_set_infoframes(struct drm_encoder *encoder) | |||
449 | vc4_hdmi_set_spd_infoframe(encoder); | 450 | vc4_hdmi_set_spd_infoframe(encoder); |
450 | } | 451 | } |
451 | 452 | ||
452 | static void vc4_hdmi_encoder_mode_set(struct drm_encoder *encoder, | 453 | static void vc4_hdmi_encoder_disable(struct drm_encoder *encoder) |
453 | struct drm_display_mode *unadjusted_mode, | 454 | { |
454 | struct drm_display_mode *mode) | 455 | struct drm_device *dev = encoder->dev; |
456 | struct vc4_dev *vc4 = to_vc4_dev(dev); | ||
457 | struct vc4_hdmi *hdmi = vc4->hdmi; | ||
458 | int ret; | ||
459 | |||
460 | HDMI_WRITE(VC4_HDMI_RAM_PACKET_CONFIG, 0); | ||
461 | |||
462 | HDMI_WRITE(VC4_HDMI_TX_PHY_RESET_CTL, 0xf << 16); | ||
463 | HD_WRITE(VC4_HD_VID_CTL, | ||
464 | HD_READ(VC4_HD_VID_CTL) & ~VC4_HD_VID_CTL_ENABLE); | ||
465 | |||
466 | HD_WRITE(VC4_HD_M_CTL, VC4_HD_M_SW_RST); | ||
467 | udelay(1); | ||
468 | HD_WRITE(VC4_HD_M_CTL, 0); | ||
469 | |||
470 | clk_disable_unprepare(hdmi->hsm_clock); | ||
471 | clk_disable_unprepare(hdmi->pixel_clock); | ||
472 | |||
473 | ret = pm_runtime_put(&hdmi->pdev->dev); | ||
474 | if (ret < 0) | ||
475 | DRM_ERROR("Failed to release power domain: %d\n", ret); | ||
476 | } | ||
477 | |||
478 | static void vc4_hdmi_encoder_enable(struct drm_encoder *encoder) | ||
455 | { | 479 | { |
480 | struct drm_display_mode *mode = &encoder->crtc->state->adjusted_mode; | ||
456 | struct vc4_hdmi_encoder *vc4_encoder = to_vc4_hdmi_encoder(encoder); | 481 | struct vc4_hdmi_encoder *vc4_encoder = to_vc4_hdmi_encoder(encoder); |
457 | struct drm_device *dev = encoder->dev; | 482 | struct drm_device *dev = encoder->dev; |
458 | struct vc4_dev *vc4 = to_vc4_dev(dev); | 483 | struct vc4_dev *vc4 = to_vc4_dev(dev); |
484 | struct vc4_hdmi *hdmi = vc4->hdmi; | ||
459 | bool debug_dump_regs = false; | 485 | bool debug_dump_regs = false; |
460 | bool hsync_pos = mode->flags & DRM_MODE_FLAG_PHSYNC; | 486 | bool hsync_pos = mode->flags & DRM_MODE_FLAG_PHSYNC; |
461 | bool vsync_pos = mode->flags & DRM_MODE_FLAG_PVSYNC; | 487 | bool vsync_pos = mode->flags & DRM_MODE_FLAG_PVSYNC; |
@@ -475,6 +501,64 @@ static void vc4_hdmi_encoder_mode_set(struct drm_encoder *encoder, | |||
475 | interlaced, | 501 | interlaced, |
476 | VC4_HDMI_VERTB_VBP)); | 502 | VC4_HDMI_VERTB_VBP)); |
477 | u32 csc_ctl; | 503 | u32 csc_ctl; |
504 | int ret; | ||
505 | |||
506 | ret = pm_runtime_get_sync(&hdmi->pdev->dev); | ||
507 | if (ret < 0) { | ||
508 | DRM_ERROR("Failed to retain power domain: %d\n", ret); | ||
509 | return; | ||
510 | } | ||
511 | |||
512 | /* This is the rate that is set by the firmware. The number | ||
513 | * needs to be a bit higher than the pixel clock rate | ||
514 | * (generally 148.5Mhz). | ||
515 | */ | ||
516 | ret = clk_set_rate(hdmi->hsm_clock, 163682864); | ||
517 | if (ret) { | ||
518 | DRM_ERROR("Failed to set HSM clock rate: %d\n", ret); | ||
519 | return; | ||
520 | } | ||
521 | |||
522 | ret = clk_set_rate(hdmi->pixel_clock, | ||
523 | mode->clock * 1000 * | ||
524 | ((mode->flags & DRM_MODE_FLAG_DBLCLK) ? 2 : 1)); | ||
525 | if (ret) { | ||
526 | DRM_ERROR("Failed to set pixel clock rate: %d\n", ret); | ||
527 | return; | ||
528 | } | ||
529 | |||
530 | ret = clk_prepare_enable(hdmi->pixel_clock); | ||
531 | if (ret) { | ||
532 | DRM_ERROR("Failed to turn on pixel clock: %d\n", ret); | ||
533 | return; | ||
534 | } | ||
535 | |||
536 | ret = clk_prepare_enable(hdmi->hsm_clock); | ||
537 | if (ret) { | ||
538 | DRM_ERROR("Failed to turn on HDMI state machine clock: %d\n", | ||
539 | ret); | ||
540 | clk_disable_unprepare(hdmi->pixel_clock); | ||
541 | return; | ||
542 | } | ||
543 | |||
544 | HD_WRITE(VC4_HD_M_CTL, VC4_HD_M_SW_RST); | ||
545 | udelay(1); | ||
546 | HD_WRITE(VC4_HD_M_CTL, 0); | ||
547 | |||
548 | HD_WRITE(VC4_HD_M_CTL, VC4_HD_M_ENABLE); | ||
549 | |||
550 | HDMI_WRITE(VC4_HDMI_SW_RESET_CONTROL, | ||
551 | VC4_HDMI_SW_RESET_HDMI | | ||
552 | VC4_HDMI_SW_RESET_FORMAT_DETECT); | ||
553 | |||
554 | HDMI_WRITE(VC4_HDMI_SW_RESET_CONTROL, 0); | ||
555 | |||
556 | /* PHY should be in reset, like | ||
557 | * vc4_hdmi_encoder_disable() does. | ||
558 | */ | ||
559 | HDMI_WRITE(VC4_HDMI_TX_PHY_RESET_CTL, 0xf << 16); | ||
560 | |||
561 | HDMI_WRITE(VC4_HDMI_TX_PHY_RESET_CTL, 0); | ||
478 | 562 | ||
479 | if (debug_dump_regs) { | 563 | if (debug_dump_regs) { |
480 | DRM_INFO("HDMI regs before:\n"); | 564 | DRM_INFO("HDMI regs before:\n"); |
@@ -483,9 +567,6 @@ static void vc4_hdmi_encoder_mode_set(struct drm_encoder *encoder, | |||
483 | 567 | ||
484 | HD_WRITE(VC4_HD_VID_CTL, 0); | 568 | HD_WRITE(VC4_HD_VID_CTL, 0); |
485 | 569 | ||
486 | clk_set_rate(vc4->hdmi->pixel_clock, mode->clock * 1000 * | ||
487 | ((mode->flags & DRM_MODE_FLAG_DBLCLK) ? 2 : 1)); | ||
488 | |||
489 | HDMI_WRITE(VC4_HDMI_SCHEDULER_CONTROL, | 570 | HDMI_WRITE(VC4_HDMI_SCHEDULER_CONTROL, |
490 | HDMI_READ(VC4_HDMI_SCHEDULER_CONTROL) | | 571 | HDMI_READ(VC4_HDMI_SCHEDULER_CONTROL) | |
491 | VC4_HDMI_SCHEDULER_CONTROL_MANUAL_FORMAT | | 572 | VC4_HDMI_SCHEDULER_CONTROL_MANUAL_FORMAT | |
@@ -559,28 +640,6 @@ static void vc4_hdmi_encoder_mode_set(struct drm_encoder *encoder, | |||
559 | DRM_INFO("HDMI regs after:\n"); | 640 | DRM_INFO("HDMI regs after:\n"); |
560 | vc4_hdmi_dump_regs(dev); | 641 | vc4_hdmi_dump_regs(dev); |
561 | } | 642 | } |
562 | } | ||
563 | |||
564 | static void vc4_hdmi_encoder_disable(struct drm_encoder *encoder) | ||
565 | { | ||
566 | struct drm_device *dev = encoder->dev; | ||
567 | struct vc4_dev *vc4 = to_vc4_dev(dev); | ||
568 | |||
569 | HDMI_WRITE(VC4_HDMI_RAM_PACKET_CONFIG, 0); | ||
570 | |||
571 | HDMI_WRITE(VC4_HDMI_TX_PHY_RESET_CTL, 0xf << 16); | ||
572 | HD_WRITE(VC4_HD_VID_CTL, | ||
573 | HD_READ(VC4_HD_VID_CTL) & ~VC4_HD_VID_CTL_ENABLE); | ||
574 | } | ||
575 | |||
576 | static void vc4_hdmi_encoder_enable(struct drm_encoder *encoder) | ||
577 | { | ||
578 | struct vc4_hdmi_encoder *vc4_encoder = to_vc4_hdmi_encoder(encoder); | ||
579 | struct drm_device *dev = encoder->dev; | ||
580 | struct vc4_dev *vc4 = to_vc4_dev(dev); | ||
581 | int ret; | ||
582 | |||
583 | HDMI_WRITE(VC4_HDMI_TX_PHY_RESET_CTL, 0); | ||
584 | 643 | ||
585 | HD_WRITE(VC4_HD_VID_CTL, | 644 | HD_WRITE(VC4_HD_VID_CTL, |
586 | HD_READ(VC4_HD_VID_CTL) | | 645 | HD_READ(VC4_HD_VID_CTL) | |
@@ -646,7 +705,6 @@ static void vc4_hdmi_encoder_enable(struct drm_encoder *encoder) | |||
646 | } | 705 | } |
647 | 706 | ||
648 | static const struct drm_encoder_helper_funcs vc4_hdmi_encoder_helper_funcs = { | 707 | static const struct drm_encoder_helper_funcs vc4_hdmi_encoder_helper_funcs = { |
649 | .mode_set = vc4_hdmi_encoder_mode_set, | ||
650 | .disable = vc4_hdmi_encoder_disable, | 708 | .disable = vc4_hdmi_encoder_disable, |
651 | .enable = vc4_hdmi_encoder_enable, | 709 | .enable = vc4_hdmi_encoder_enable, |
652 | }; | 710 | }; |
@@ -1147,33 +1205,6 @@ static int vc4_hdmi_bind(struct device *dev, struct device *master, void *data) | |||
1147 | return -EPROBE_DEFER; | 1205 | return -EPROBE_DEFER; |
1148 | } | 1206 | } |
1149 | 1207 | ||
1150 | /* Enable the clocks at startup. We can't quite recover from | ||
1151 | * turning off the pixel clock during disable/enables yet, so | ||
1152 | * it's always running. | ||
1153 | */ | ||
1154 | ret = clk_prepare_enable(hdmi->pixel_clock); | ||
1155 | if (ret) { | ||
1156 | DRM_ERROR("Failed to turn on pixel clock: %d\n", ret); | ||
1157 | goto err_put_i2c; | ||
1158 | } | ||
1159 | |||
1160 | /* This is the rate that is set by the firmware. The number | ||
1161 | * needs to be a bit higher than the pixel clock rate | ||
1162 | * (generally 148.5Mhz). | ||
1163 | */ | ||
1164 | ret = clk_set_rate(hdmi->hsm_clock, 163682864); | ||
1165 | if (ret) { | ||
1166 | DRM_ERROR("Failed to set HSM clock rate: %d\n", ret); | ||
1167 | goto err_unprepare_pix; | ||
1168 | } | ||
1169 | |||
1170 | ret = clk_prepare_enable(hdmi->hsm_clock); | ||
1171 | if (ret) { | ||
1172 | DRM_ERROR("Failed to turn on HDMI state machine clock: %d\n", | ||
1173 | ret); | ||
1174 | goto err_unprepare_pix; | ||
1175 | } | ||
1176 | |||
1177 | /* Only use the GPIO HPD pin if present in the DT, otherwise | 1208 | /* Only use the GPIO HPD pin if present in the DT, otherwise |
1178 | * we'll use the HDMI core's register. | 1209 | * we'll use the HDMI core's register. |
1179 | */ | 1210 | */ |
@@ -1185,7 +1216,7 @@ static int vc4_hdmi_bind(struct device *dev, struct device *master, void *data) | |||
1185 | &hpd_gpio_flags); | 1216 | &hpd_gpio_flags); |
1186 | if (hdmi->hpd_gpio < 0) { | 1217 | if (hdmi->hpd_gpio < 0) { |
1187 | ret = hdmi->hpd_gpio; | 1218 | ret = hdmi->hpd_gpio; |
1188 | goto err_unprepare_hsm; | 1219 | goto err_put_i2c; |
1189 | } | 1220 | } |
1190 | 1221 | ||
1191 | hdmi->hpd_active_low = hpd_gpio_flags & OF_GPIO_ACTIVE_LOW; | 1222 | hdmi->hpd_active_low = hpd_gpio_flags & OF_GPIO_ACTIVE_LOW; |
@@ -1193,25 +1224,7 @@ static int vc4_hdmi_bind(struct device *dev, struct device *master, void *data) | |||
1193 | 1224 | ||
1194 | vc4->hdmi = hdmi; | 1225 | vc4->hdmi = hdmi; |
1195 | 1226 | ||
1196 | /* HDMI core must be enabled. */ | 1227 | pm_runtime_enable(dev); |
1197 | if (!(HD_READ(VC4_HD_M_CTL) & VC4_HD_M_ENABLE)) { | ||
1198 | HD_WRITE(VC4_HD_M_CTL, VC4_HD_M_SW_RST); | ||
1199 | udelay(1); | ||
1200 | HD_WRITE(VC4_HD_M_CTL, 0); | ||
1201 | |||
1202 | HD_WRITE(VC4_HD_M_CTL, VC4_HD_M_ENABLE); | ||
1203 | |||
1204 | HDMI_WRITE(VC4_HDMI_SW_RESET_CONTROL, | ||
1205 | VC4_HDMI_SW_RESET_HDMI | | ||
1206 | VC4_HDMI_SW_RESET_FORMAT_DETECT); | ||
1207 | |||
1208 | HDMI_WRITE(VC4_HDMI_SW_RESET_CONTROL, 0); | ||
1209 | |||
1210 | /* PHY should be in reset, like | ||
1211 | * vc4_hdmi_encoder_disable() does. | ||
1212 | */ | ||
1213 | HDMI_WRITE(VC4_HDMI_TX_PHY_RESET_CTL, 0xf << 16); | ||
1214 | } | ||
1215 | 1228 | ||
1216 | drm_encoder_init(drm, hdmi->encoder, &vc4_hdmi_encoder_funcs, | 1229 | drm_encoder_init(drm, hdmi->encoder, &vc4_hdmi_encoder_funcs, |
1217 | DRM_MODE_ENCODER_TMDS, NULL); | 1230 | DRM_MODE_ENCODER_TMDS, NULL); |
@@ -1231,10 +1244,7 @@ static int vc4_hdmi_bind(struct device *dev, struct device *master, void *data) | |||
1231 | 1244 | ||
1232 | err_destroy_encoder: | 1245 | err_destroy_encoder: |
1233 | vc4_hdmi_encoder_destroy(hdmi->encoder); | 1246 | vc4_hdmi_encoder_destroy(hdmi->encoder); |
1234 | err_unprepare_hsm: | 1247 | pm_runtime_disable(dev); |
1235 | clk_disable_unprepare(hdmi->hsm_clock); | ||
1236 | err_unprepare_pix: | ||
1237 | clk_disable_unprepare(hdmi->pixel_clock); | ||
1238 | err_put_i2c: | 1248 | err_put_i2c: |
1239 | put_device(&hdmi->ddc->dev); | 1249 | put_device(&hdmi->ddc->dev); |
1240 | 1250 | ||
@@ -1253,8 +1263,8 @@ static void vc4_hdmi_unbind(struct device *dev, struct device *master, | |||
1253 | vc4_hdmi_connector_destroy(hdmi->connector); | 1263 | vc4_hdmi_connector_destroy(hdmi->connector); |
1254 | vc4_hdmi_encoder_destroy(hdmi->encoder); | 1264 | vc4_hdmi_encoder_destroy(hdmi->encoder); |
1255 | 1265 | ||
1256 | clk_disable_unprepare(hdmi->pixel_clock); | 1266 | pm_runtime_disable(dev); |
1257 | clk_disable_unprepare(hdmi->hsm_clock); | 1267 | |
1258 | put_device(&hdmi->ddc->dev); | 1268 | put_device(&hdmi->ddc->dev); |
1259 | 1269 | ||
1260 | vc4->hdmi = NULL; | 1270 | vc4->hdmi = NULL; |
diff --git a/drivers/gpu/drm/vc4/vc4_irq.c b/drivers/gpu/drm/vc4/vc4_irq.c index cdc6e6760705..7d7af3a93d94 100644 --- a/drivers/gpu/drm/vc4/vc4_irq.c +++ b/drivers/gpu/drm/vc4/vc4_irq.c | |||
@@ -59,50 +59,45 @@ vc4_overflow_mem_work(struct work_struct *work) | |||
59 | { | 59 | { |
60 | struct vc4_dev *vc4 = | 60 | struct vc4_dev *vc4 = |
61 | container_of(work, struct vc4_dev, overflow_mem_work); | 61 | container_of(work, struct vc4_dev, overflow_mem_work); |
62 | struct drm_device *dev = vc4->dev; | 62 | struct vc4_bo *bo = vc4->bin_bo; |
63 | struct vc4_bo *bo; | 63 | int bin_bo_slot; |
64 | struct vc4_exec_info *exec; | ||
65 | unsigned long irqflags; | ||
64 | 66 | ||
65 | bo = vc4_bo_create(dev, 256 * 1024, true); | 67 | bin_bo_slot = vc4_v3d_get_bin_slot(vc4); |
66 | if (IS_ERR(bo)) { | 68 | if (bin_bo_slot < 0) { |
67 | DRM_ERROR("Couldn't allocate binner overflow mem\n"); | 69 | DRM_ERROR("Couldn't allocate binner overflow mem\n"); |
68 | return; | 70 | return; |
69 | } | 71 | } |
70 | 72 | ||
71 | /* If there's a job executing currently, then our previous | 73 | spin_lock_irqsave(&vc4->job_lock, irqflags); |
72 | * overflow allocation is getting used in that job and we need | 74 | |
73 | * to queue it to be released when the job is done. But if no | 75 | if (vc4->bin_alloc_overflow) { |
74 | * job is executing at all, then we can free the old overflow | 76 | /* If we had overflow memory allocated previously, |
75 | * object direcctly. | 77 | * then that chunk will free when the current bin job |
76 | * | 78 | * is done. If we don't have a bin job running, then |
77 | * No lock necessary for this pointer since we're the only | 79 | * the chunk will be done whenever the list of render |
78 | * ones that update the pointer, and our workqueue won't | 80 | * jobs has drained. |
79 | * reenter. | 81 | */ |
80 | */ | 82 | exec = vc4_first_bin_job(vc4); |
81 | if (vc4->overflow_mem) { | 83 | if (!exec) |
82 | struct vc4_exec_info *current_exec; | 84 | exec = vc4_last_render_job(vc4); |
83 | unsigned long irqflags; | 85 | if (exec) { |
84 | 86 | exec->bin_slots |= vc4->bin_alloc_overflow; | |
85 | spin_lock_irqsave(&vc4->job_lock, irqflags); | 87 | } else { |
86 | current_exec = vc4_first_bin_job(vc4); | 88 | /* There's nothing queued in the hardware, so |
87 | if (!current_exec) | 89 | * the old slot is free immediately. |
88 | current_exec = vc4_last_render_job(vc4); | 90 | */ |
89 | if (current_exec) { | 91 | vc4->bin_alloc_used &= ~vc4->bin_alloc_overflow; |
90 | vc4->overflow_mem->seqno = current_exec->seqno; | ||
91 | list_add_tail(&vc4->overflow_mem->unref_head, | ||
92 | ¤t_exec->unref_list); | ||
93 | vc4->overflow_mem = NULL; | ||
94 | } | 92 | } |
95 | spin_unlock_irqrestore(&vc4->job_lock, irqflags); | ||
96 | } | 93 | } |
94 | vc4->bin_alloc_overflow = BIT(bin_bo_slot); | ||
97 | 95 | ||
98 | if (vc4->overflow_mem) | 96 | V3D_WRITE(V3D_BPOA, bo->base.paddr + bin_bo_slot * vc4->bin_alloc_size); |
99 | drm_gem_object_unreference_unlocked(&vc4->overflow_mem->base.base); | ||
100 | vc4->overflow_mem = bo; | ||
101 | |||
102 | V3D_WRITE(V3D_BPOA, bo->base.paddr); | ||
103 | V3D_WRITE(V3D_BPOS, bo->base.base.size); | 97 | V3D_WRITE(V3D_BPOS, bo->base.base.size); |
104 | V3D_WRITE(V3D_INTCTL, V3D_INT_OUTOMEM); | 98 | V3D_WRITE(V3D_INTCTL, V3D_INT_OUTOMEM); |
105 | V3D_WRITE(V3D_INTENA, V3D_INT_OUTOMEM); | 99 | V3D_WRITE(V3D_INTENA, V3D_INT_OUTOMEM); |
100 | spin_unlock_irqrestore(&vc4->job_lock, irqflags); | ||
106 | } | 101 | } |
107 | 102 | ||
108 | static void | 103 | static void |
@@ -142,6 +137,10 @@ vc4_irq_finish_render_job(struct drm_device *dev) | |||
142 | 137 | ||
143 | vc4->finished_seqno++; | 138 | vc4->finished_seqno++; |
144 | list_move_tail(&exec->head, &vc4->job_done_list); | 139 | list_move_tail(&exec->head, &vc4->job_done_list); |
140 | if (exec->fence) { | ||
141 | dma_fence_signal_locked(exec->fence); | ||
142 | exec->fence = NULL; | ||
143 | } | ||
145 | vc4_submit_next_render_job(dev); | 144 | vc4_submit_next_render_job(dev); |
146 | 145 | ||
147 | wake_up_all(&vc4->job_wait_queue); | 146 | wake_up_all(&vc4->job_wait_queue); |
diff --git a/drivers/gpu/drm/vc4/vc4_kms.c b/drivers/gpu/drm/vc4/vc4_kms.c index ad7925a9e0ea..237a504f11f0 100644 --- a/drivers/gpu/drm/vc4/vc4_kms.c +++ b/drivers/gpu/drm/vc4/vc4_kms.c | |||
@@ -230,10 +230,12 @@ int vc4_kms_load(struct drm_device *dev) | |||
230 | 230 | ||
231 | drm_mode_config_reset(dev); | 231 | drm_mode_config_reset(dev); |
232 | 232 | ||
233 | vc4->fbdev = drm_fbdev_cma_init(dev, 32, | 233 | if (dev->mode_config.num_connector) { |
234 | dev->mode_config.num_connector); | 234 | vc4->fbdev = drm_fbdev_cma_init(dev, 32, |
235 | if (IS_ERR(vc4->fbdev)) | 235 | dev->mode_config.num_connector); |
236 | vc4->fbdev = NULL; | 236 | if (IS_ERR(vc4->fbdev)) |
237 | vc4->fbdev = NULL; | ||
238 | } | ||
237 | 239 | ||
238 | drm_kms_helper_poll_init(dev); | 240 | drm_kms_helper_poll_init(dev); |
239 | 241 | ||
diff --git a/drivers/gpu/drm/vc4/vc4_render_cl.c b/drivers/gpu/drm/vc4/vc4_render_cl.c index 4339471f517f..5dc19429d4ae 100644 --- a/drivers/gpu/drm/vc4/vc4_render_cl.c +++ b/drivers/gpu/drm/vc4/vc4_render_cl.c | |||
@@ -182,8 +182,7 @@ static void emit_tile(struct vc4_exec_info *exec, | |||
182 | 182 | ||
183 | if (has_bin) { | 183 | if (has_bin) { |
184 | rcl_u8(setup, VC4_PACKET_BRANCH_TO_SUB_LIST); | 184 | rcl_u8(setup, VC4_PACKET_BRANCH_TO_SUB_LIST); |
185 | rcl_u32(setup, (exec->tile_bo->paddr + | 185 | rcl_u32(setup, (exec->tile_alloc_offset + |
186 | exec->tile_alloc_offset + | ||
187 | (y * exec->bin_tiles_x + x) * 32)); | 186 | (y * exec->bin_tiles_x + x) * 32)); |
188 | } | 187 | } |
189 | 188 | ||
diff --git a/drivers/gpu/drm/vc4/vc4_v3d.c b/drivers/gpu/drm/vc4/vc4_v3d.c index 7cc346ad9b0b..c53afec34586 100644 --- a/drivers/gpu/drm/vc4/vc4_v3d.c +++ b/drivers/gpu/drm/vc4/vc4_v3d.c | |||
@@ -16,6 +16,7 @@ | |||
16 | * this program. If not, see <http://www.gnu.org/licenses/>. | 16 | * this program. If not, see <http://www.gnu.org/licenses/>. |
17 | */ | 17 | */ |
18 | 18 | ||
19 | #include "linux/clk.h" | ||
19 | #include "linux/component.h" | 20 | #include "linux/component.h" |
20 | #include "linux/pm_runtime.h" | 21 | #include "linux/pm_runtime.h" |
21 | #include "vc4_drv.h" | 22 | #include "vc4_drv.h" |
@@ -156,6 +157,144 @@ static void vc4_v3d_init_hw(struct drm_device *dev) | |||
156 | V3D_WRITE(V3D_VPMBASE, 0); | 157 | V3D_WRITE(V3D_VPMBASE, 0); |
157 | } | 158 | } |
158 | 159 | ||
160 | int vc4_v3d_get_bin_slot(struct vc4_dev *vc4) | ||
161 | { | ||
162 | struct drm_device *dev = vc4->dev; | ||
163 | unsigned long irqflags; | ||
164 | int slot; | ||
165 | uint64_t seqno = 0; | ||
166 | struct vc4_exec_info *exec; | ||
167 | |||
168 | try_again: | ||
169 | spin_lock_irqsave(&vc4->job_lock, irqflags); | ||
170 | slot = ffs(~vc4->bin_alloc_used); | ||
171 | if (slot != 0) { | ||
172 | /* Switch from ffs() bit index to a 0-based index. */ | ||
173 | slot--; | ||
174 | vc4->bin_alloc_used |= BIT(slot); | ||
175 | spin_unlock_irqrestore(&vc4->job_lock, irqflags); | ||
176 | return slot; | ||
177 | } | ||
178 | |||
179 | /* Couldn't find an open slot. Wait for render to complete | ||
180 | * and try again. | ||
181 | */ | ||
182 | exec = vc4_last_render_job(vc4); | ||
183 | if (exec) | ||
184 | seqno = exec->seqno; | ||
185 | spin_unlock_irqrestore(&vc4->job_lock, irqflags); | ||
186 | |||
187 | if (seqno) { | ||
188 | int ret = vc4_wait_for_seqno(dev, seqno, ~0ull, true); | ||
189 | |||
190 | if (ret == 0) | ||
191 | goto try_again; | ||
192 | |||
193 | return ret; | ||
194 | } | ||
195 | |||
196 | return -ENOMEM; | ||
197 | } | ||
198 | |||
199 | /** | ||
200 | * vc4_allocate_bin_bo() - allocates the memory that will be used for | ||
201 | * tile binning. | ||
202 | * | ||
203 | * The binner has a limitation that the addresses in the tile state | ||
204 | * buffer that point into the tile alloc buffer or binner overflow | ||
205 | * memory only have 28 bits (256MB), and the top 4 on the bus for | ||
206 | * tile alloc references end up coming from the tile state buffer's | ||
207 | * address. | ||
208 | * | ||
209 | * To work around this, we allocate a single large buffer while V3D is | ||
210 | * in use, make sure that it has the top 4 bits constant across its | ||
211 | * entire extent, and then put the tile state, tile alloc, and binner | ||
212 | * overflow memory inside that buffer. | ||
213 | * | ||
214 | * This creates a limitation where we may not be able to execute a job | ||
215 | * if it doesn't fit within the buffer that we allocated up front. | ||
216 | * However, it turns out that 16MB is "enough for anybody", and | ||
217 | * real-world applications run into allocation failures from the | ||
218 | * overall CMA pool before they make scenes complicated enough to run | ||
219 | * out of bin space. | ||
220 | */ | ||
221 | int | ||
222 | vc4_allocate_bin_bo(struct drm_device *drm) | ||
223 | { | ||
224 | struct vc4_dev *vc4 = to_vc4_dev(drm); | ||
225 | struct vc4_v3d *v3d = vc4->v3d; | ||
226 | uint32_t size = 16 * 1024 * 1024; | ||
227 | int ret = 0; | ||
228 | struct list_head list; | ||
229 | |||
230 | /* We may need to try allocating more than once to get a BO | ||
231 | * that doesn't cross 256MB. Track the ones we've allocated | ||
232 | * that failed so far, so that we can free them when we've got | ||
233 | * one that succeeded (if we freed them right away, our next | ||
234 | * allocation would probably be the same chunk of memory). | ||
235 | */ | ||
236 | INIT_LIST_HEAD(&list); | ||
237 | |||
238 | while (true) { | ||
239 | struct vc4_bo *bo = vc4_bo_create(drm, size, true); | ||
240 | |||
241 | if (IS_ERR(bo)) { | ||
242 | ret = PTR_ERR(bo); | ||
243 | |||
244 | dev_err(&v3d->pdev->dev, | ||
245 | "Failed to allocate memory for tile binning: " | ||
246 | "%d. You may need to enable CMA or give it " | ||
247 | "more memory.", | ||
248 | ret); | ||
249 | break; | ||
250 | } | ||
251 | |||
252 | /* Check if this BO won't trigger the addressing bug. */ | ||
253 | if ((bo->base.paddr & 0xf0000000) == | ||
254 | ((bo->base.paddr + bo->base.base.size - 1) & 0xf0000000)) { | ||
255 | vc4->bin_bo = bo; | ||
256 | |||
257 | /* Set up for allocating 512KB chunks of | ||
258 | * binner memory. The biggest allocation we | ||
259 | * need to do is for the initial tile alloc + | ||
260 | * tile state buffer. We can render to a | ||
261 | * maximum of ((2048*2048) / (32*32) = 4096 | ||
262 | * tiles in a frame (until we do floating | ||
263 | * point rendering, at which point it would be | ||
264 | * 8192). Tile state is 48b/tile (rounded to | ||
265 | * a page), and tile alloc is 32b/tile | ||
266 | * (rounded to a page), plus a page of extra, | ||
267 | * for a total of 320kb for our worst-case. | ||
268 | * We choose 512kb so that it divides evenly | ||
269 | * into our 16MB, and the rest of the 512kb | ||
270 | * will be used as storage for the overflow | ||
271 | * from the initial 32b CL per bin. | ||
272 | */ | ||
273 | vc4->bin_alloc_size = 512 * 1024; | ||
274 | vc4->bin_alloc_used = 0; | ||
275 | vc4->bin_alloc_overflow = 0; | ||
276 | WARN_ON_ONCE(sizeof(vc4->bin_alloc_used) * 8 != | ||
277 | bo->base.base.size / vc4->bin_alloc_size); | ||
278 | |||
279 | break; | ||
280 | } | ||
281 | |||
282 | /* Put it on the list to free later, and try again. */ | ||
283 | list_add(&bo->unref_head, &list); | ||
284 | } | ||
285 | |||
286 | /* Free all the BOs we allocated but didn't choose. */ | ||
287 | while (!list_empty(&list)) { | ||
288 | struct vc4_bo *bo = list_last_entry(&list, | ||
289 | struct vc4_bo, unref_head); | ||
290 | |||
291 | list_del(&bo->unref_head); | ||
292 | drm_gem_object_put_unlocked(&bo->base.base); | ||
293 | } | ||
294 | |||
295 | return ret; | ||
296 | } | ||
297 | |||
159 | #ifdef CONFIG_PM | 298 | #ifdef CONFIG_PM |
160 | static int vc4_v3d_runtime_suspend(struct device *dev) | 299 | static int vc4_v3d_runtime_suspend(struct device *dev) |
161 | { | 300 | { |
@@ -164,6 +303,11 @@ static int vc4_v3d_runtime_suspend(struct device *dev) | |||
164 | 303 | ||
165 | vc4_irq_uninstall(vc4->dev); | 304 | vc4_irq_uninstall(vc4->dev); |
166 | 305 | ||
306 | drm_gem_object_put_unlocked(&vc4->bin_bo->base.base); | ||
307 | vc4->bin_bo = NULL; | ||
308 | |||
309 | clk_disable_unprepare(v3d->clk); | ||
310 | |||
167 | return 0; | 311 | return 0; |
168 | } | 312 | } |
169 | 313 | ||
@@ -171,6 +315,15 @@ static int vc4_v3d_runtime_resume(struct device *dev) | |||
171 | { | 315 | { |
172 | struct vc4_v3d *v3d = dev_get_drvdata(dev); | 316 | struct vc4_v3d *v3d = dev_get_drvdata(dev); |
173 | struct vc4_dev *vc4 = v3d->vc4; | 317 | struct vc4_dev *vc4 = v3d->vc4; |
318 | int ret; | ||
319 | |||
320 | ret = vc4_allocate_bin_bo(vc4->dev); | ||
321 | if (ret) | ||
322 | return ret; | ||
323 | |||
324 | ret = clk_prepare_enable(v3d->clk); | ||
325 | if (ret != 0) | ||
326 | return ret; | ||
174 | 327 | ||
175 | vc4_v3d_init_hw(vc4->dev); | 328 | vc4_v3d_init_hw(vc4->dev); |
176 | vc4_irq_postinstall(vc4->dev); | 329 | vc4_irq_postinstall(vc4->dev); |
@@ -202,12 +355,38 @@ static int vc4_v3d_bind(struct device *dev, struct device *master, void *data) | |||
202 | vc4->v3d = v3d; | 355 | vc4->v3d = v3d; |
203 | v3d->vc4 = vc4; | 356 | v3d->vc4 = vc4; |
204 | 357 | ||
358 | v3d->clk = devm_clk_get(dev, NULL); | ||
359 | if (IS_ERR(v3d->clk)) { | ||
360 | int ret = PTR_ERR(v3d->clk); | ||
361 | |||
362 | if (ret == -ENOENT) { | ||
363 | /* bcm2835 didn't have a clock reference in the DT. */ | ||
364 | ret = 0; | ||
365 | v3d->clk = NULL; | ||
366 | } else { | ||
367 | if (ret != -EPROBE_DEFER) | ||
368 | dev_err(dev, "Failed to get V3D clock: %d\n", | ||
369 | ret); | ||
370 | return ret; | ||
371 | } | ||
372 | } | ||
373 | |||
205 | if (V3D_READ(V3D_IDENT0) != V3D_EXPECTED_IDENT0) { | 374 | if (V3D_READ(V3D_IDENT0) != V3D_EXPECTED_IDENT0) { |
206 | DRM_ERROR("V3D_IDENT0 read 0x%08x instead of 0x%08x\n", | 375 | DRM_ERROR("V3D_IDENT0 read 0x%08x instead of 0x%08x\n", |
207 | V3D_READ(V3D_IDENT0), V3D_EXPECTED_IDENT0); | 376 | V3D_READ(V3D_IDENT0), V3D_EXPECTED_IDENT0); |
208 | return -EINVAL; | 377 | return -EINVAL; |
209 | } | 378 | } |
210 | 379 | ||
380 | ret = clk_prepare_enable(v3d->clk); | ||
381 | if (ret != 0) | ||
382 | return ret; | ||
383 | |||
384 | ret = vc4_allocate_bin_bo(drm); | ||
385 | if (ret) { | ||
386 | clk_disable_unprepare(v3d->clk); | ||
387 | return ret; | ||
388 | } | ||
389 | |||
211 | /* Reset the binner overflow address/size at setup, to be sure | 390 | /* Reset the binner overflow address/size at setup, to be sure |
212 | * we don't reuse an old one. | 391 | * we don't reuse an old one. |
213 | */ | 392 | */ |
@@ -271,6 +450,7 @@ static int vc4_v3d_dev_remove(struct platform_device *pdev) | |||
271 | 450 | ||
272 | static const struct of_device_id vc4_v3d_dt_match[] = { | 451 | static const struct of_device_id vc4_v3d_dt_match[] = { |
273 | { .compatible = "brcm,bcm2835-v3d" }, | 452 | { .compatible = "brcm,bcm2835-v3d" }, |
453 | { .compatible = "brcm,cygnus-v3d" }, | ||
274 | { .compatible = "brcm,vc4-v3d" }, | 454 | { .compatible = "brcm,vc4-v3d" }, |
275 | {} | 455 | {} |
276 | }; | 456 | }; |
diff --git a/drivers/gpu/drm/vc4/vc4_validate.c b/drivers/gpu/drm/vc4/vc4_validate.c index da6f1e138e8d..3de8f11595c0 100644 --- a/drivers/gpu/drm/vc4/vc4_validate.c +++ b/drivers/gpu/drm/vc4/vc4_validate.c | |||
@@ -348,10 +348,11 @@ static int | |||
348 | validate_tile_binning_config(VALIDATE_ARGS) | 348 | validate_tile_binning_config(VALIDATE_ARGS) |
349 | { | 349 | { |
350 | struct drm_device *dev = exec->exec_bo->base.dev; | 350 | struct drm_device *dev = exec->exec_bo->base.dev; |
351 | struct vc4_bo *tile_bo; | 351 | struct vc4_dev *vc4 = to_vc4_dev(dev); |
352 | uint8_t flags; | 352 | uint8_t flags; |
353 | uint32_t tile_state_size, tile_alloc_size; | 353 | uint32_t tile_state_size; |
354 | uint32_t tile_count; | 354 | uint32_t tile_count, bin_addr; |
355 | int bin_slot; | ||
355 | 356 | ||
356 | if (exec->found_tile_binning_mode_config_packet) { | 357 | if (exec->found_tile_binning_mode_config_packet) { |
357 | DRM_ERROR("Duplicate VC4_PACKET_TILE_BINNING_MODE_CONFIG\n"); | 358 | DRM_ERROR("Duplicate VC4_PACKET_TILE_BINNING_MODE_CONFIG\n"); |
@@ -377,13 +378,28 @@ validate_tile_binning_config(VALIDATE_ARGS) | |||
377 | return -EINVAL; | 378 | return -EINVAL; |
378 | } | 379 | } |
379 | 380 | ||
381 | bin_slot = vc4_v3d_get_bin_slot(vc4); | ||
382 | if (bin_slot < 0) { | ||
383 | if (bin_slot != -EINTR && bin_slot != -ERESTARTSYS) { | ||
384 | DRM_ERROR("Failed to allocate binner memory: %d\n", | ||
385 | bin_slot); | ||
386 | } | ||
387 | return bin_slot; | ||
388 | } | ||
389 | |||
390 | /* The slot we allocated will only be used by this job, and is | ||
391 | * free when the job completes rendering. | ||
392 | */ | ||
393 | exec->bin_slots |= BIT(bin_slot); | ||
394 | bin_addr = vc4->bin_bo->base.paddr + bin_slot * vc4->bin_alloc_size; | ||
395 | |||
380 | /* The tile state data array is 48 bytes per tile, and we put it at | 396 | /* The tile state data array is 48 bytes per tile, and we put it at |
381 | * the start of a BO containing both it and the tile alloc. | 397 | * the start of a BO containing both it and the tile alloc. |
382 | */ | 398 | */ |
383 | tile_state_size = 48 * tile_count; | 399 | tile_state_size = 48 * tile_count; |
384 | 400 | ||
385 | /* Since the tile alloc array will follow us, align. */ | 401 | /* Since the tile alloc array will follow us, align. */ |
386 | exec->tile_alloc_offset = roundup(tile_state_size, 4096); | 402 | exec->tile_alloc_offset = bin_addr + roundup(tile_state_size, 4096); |
387 | 403 | ||
388 | *(uint8_t *)(validated + 14) = | 404 | *(uint8_t *)(validated + 14) = |
389 | ((flags & ~(VC4_BIN_CONFIG_ALLOC_INIT_BLOCK_SIZE_MASK | | 405 | ((flags & ~(VC4_BIN_CONFIG_ALLOC_INIT_BLOCK_SIZE_MASK | |
@@ -394,35 +410,13 @@ validate_tile_binning_config(VALIDATE_ARGS) | |||
394 | VC4_SET_FIELD(VC4_BIN_CONFIG_ALLOC_BLOCK_SIZE_128, | 410 | VC4_SET_FIELD(VC4_BIN_CONFIG_ALLOC_BLOCK_SIZE_128, |
395 | VC4_BIN_CONFIG_ALLOC_BLOCK_SIZE)); | 411 | VC4_BIN_CONFIG_ALLOC_BLOCK_SIZE)); |
396 | 412 | ||
397 | /* Initial block size. */ | ||
398 | tile_alloc_size = 32 * tile_count; | ||
399 | |||
400 | /* | ||
401 | * The initial allocation gets rounded to the next 256 bytes before | ||
402 | * the hardware starts fulfilling further allocations. | ||
403 | */ | ||
404 | tile_alloc_size = roundup(tile_alloc_size, 256); | ||
405 | |||
406 | /* Add space for the extra allocations. This is what gets used first, | ||
407 | * before overflow memory. It must have at least 4096 bytes, but we | ||
408 | * want to avoid overflow memory usage if possible. | ||
409 | */ | ||
410 | tile_alloc_size += 1024 * 1024; | ||
411 | |||
412 | tile_bo = vc4_bo_create(dev, exec->tile_alloc_offset + tile_alloc_size, | ||
413 | true); | ||
414 | exec->tile_bo = &tile_bo->base; | ||
415 | if (IS_ERR(exec->tile_bo)) | ||
416 | return PTR_ERR(exec->tile_bo); | ||
417 | list_add_tail(&tile_bo->unref_head, &exec->unref_list); | ||
418 | |||
419 | /* tile alloc address. */ | 413 | /* tile alloc address. */ |
420 | *(uint32_t *)(validated + 0) = (exec->tile_bo->paddr + | 414 | *(uint32_t *)(validated + 0) = exec->tile_alloc_offset; |
421 | exec->tile_alloc_offset); | ||
422 | /* tile alloc size. */ | 415 | /* tile alloc size. */ |
423 | *(uint32_t *)(validated + 4) = tile_alloc_size; | 416 | *(uint32_t *)(validated + 4) = (bin_addr + vc4->bin_alloc_size - |
417 | exec->tile_alloc_offset); | ||
424 | /* tile state address. */ | 418 | /* tile state address. */ |
425 | *(uint32_t *)(validated + 8) = exec->tile_bo->paddr; | 419 | *(uint32_t *)(validated + 8) = bin_addr; |
426 | 420 | ||
427 | return 0; | 421 | return 0; |
428 | } | 422 | } |
diff --git a/drivers/gpu/drm/vgem/vgem_drv.c b/drivers/gpu/drm/vgem/vgem_drv.c index 9fee38a942c4..4b23ba049632 100644 --- a/drivers/gpu/drm/vgem/vgem_drv.c +++ b/drivers/gpu/drm/vgem/vgem_drv.c | |||
@@ -42,10 +42,20 @@ | |||
42 | #define DRIVER_MAJOR 1 | 42 | #define DRIVER_MAJOR 1 |
43 | #define DRIVER_MINOR 0 | 43 | #define DRIVER_MINOR 0 |
44 | 44 | ||
45 | static struct vgem_device { | ||
46 | struct drm_device drm; | ||
47 | struct platform_device *platform; | ||
48 | } *vgem_device; | ||
49 | |||
45 | static void vgem_gem_free_object(struct drm_gem_object *obj) | 50 | static void vgem_gem_free_object(struct drm_gem_object *obj) |
46 | { | 51 | { |
47 | struct drm_vgem_gem_object *vgem_obj = to_vgem_bo(obj); | 52 | struct drm_vgem_gem_object *vgem_obj = to_vgem_bo(obj); |
48 | 53 | ||
54 | drm_free_large(vgem_obj->pages); | ||
55 | |||
56 | if (obj->import_attach) | ||
57 | drm_prime_gem_destroy(obj, vgem_obj->table); | ||
58 | |||
49 | drm_gem_object_release(obj); | 59 | drm_gem_object_release(obj); |
50 | kfree(vgem_obj); | 60 | kfree(vgem_obj); |
51 | } | 61 | } |
@@ -56,26 +66,49 @@ static int vgem_gem_fault(struct vm_fault *vmf) | |||
56 | struct drm_vgem_gem_object *obj = vma->vm_private_data; | 66 | struct drm_vgem_gem_object *obj = vma->vm_private_data; |
57 | /* We don't use vmf->pgoff since that has the fake offset */ | 67 | /* We don't use vmf->pgoff since that has the fake offset */ |
58 | unsigned long vaddr = vmf->address; | 68 | unsigned long vaddr = vmf->address; |
59 | struct page *page; | 69 | int ret; |
60 | 70 | loff_t num_pages; | |
61 | page = shmem_read_mapping_page(file_inode(obj->base.filp)->i_mapping, | 71 | pgoff_t page_offset; |
62 | (vaddr - vma->vm_start) >> PAGE_SHIFT); | 72 | page_offset = (vaddr - vma->vm_start) >> PAGE_SHIFT; |
63 | if (!IS_ERR(page)) { | 73 | |
64 | vmf->page = page; | 74 | num_pages = DIV_ROUND_UP(obj->base.size, PAGE_SIZE); |
65 | return 0; | 75 | |
66 | } else switch (PTR_ERR(page)) { | 76 | if (page_offset > num_pages) |
67 | case -ENOSPC: | 77 | return VM_FAULT_SIGBUS; |
68 | case -ENOMEM: | 78 | |
69 | return VM_FAULT_OOM; | 79 | if (obj->pages) { |
70 | case -EBUSY: | 80 | get_page(obj->pages[page_offset]); |
71 | return VM_FAULT_RETRY; | 81 | vmf->page = obj->pages[page_offset]; |
72 | case -EFAULT: | 82 | ret = 0; |
73 | case -EINVAL: | 83 | } else { |
74 | return VM_FAULT_SIGBUS; | 84 | struct page *page; |
75 | default: | 85 | |
76 | WARN_ON_ONCE(PTR_ERR(page)); | 86 | page = shmem_read_mapping_page( |
77 | return VM_FAULT_SIGBUS; | 87 | file_inode(obj->base.filp)->i_mapping, |
88 | page_offset); | ||
89 | if (!IS_ERR(page)) { | ||
90 | vmf->page = page; | ||
91 | ret = 0; | ||
92 | } else switch (PTR_ERR(page)) { | ||
93 | case -ENOSPC: | ||
94 | case -ENOMEM: | ||
95 | ret = VM_FAULT_OOM; | ||
96 | break; | ||
97 | case -EBUSY: | ||
98 | ret = VM_FAULT_RETRY; | ||
99 | break; | ||
100 | case -EFAULT: | ||
101 | case -EINVAL: | ||
102 | ret = VM_FAULT_SIGBUS; | ||
103 | break; | ||
104 | default: | ||
105 | WARN_ON(PTR_ERR(page)); | ||
106 | ret = VM_FAULT_SIGBUS; | ||
107 | break; | ||
108 | } | ||
109 | |||
78 | } | 110 | } |
111 | return ret; | ||
79 | } | 112 | } |
80 | 113 | ||
81 | static const struct vm_operations_struct vgem_gem_vm_ops = { | 114 | static const struct vm_operations_struct vgem_gem_vm_ops = { |
@@ -112,12 +145,8 @@ static void vgem_postclose(struct drm_device *dev, struct drm_file *file) | |||
112 | kfree(vfile); | 145 | kfree(vfile); |
113 | } | 146 | } |
114 | 147 | ||
115 | /* ioctls */ | 148 | static struct drm_vgem_gem_object *__vgem_gem_create(struct drm_device *dev, |
116 | 149 | unsigned long size) | |
117 | static struct drm_gem_object *vgem_gem_create(struct drm_device *dev, | ||
118 | struct drm_file *file, | ||
119 | unsigned int *handle, | ||
120 | unsigned long size) | ||
121 | { | 150 | { |
122 | struct drm_vgem_gem_object *obj; | 151 | struct drm_vgem_gem_object *obj; |
123 | int ret; | 152 | int ret; |
@@ -127,8 +156,31 @@ static struct drm_gem_object *vgem_gem_create(struct drm_device *dev, | |||
127 | return ERR_PTR(-ENOMEM); | 156 | return ERR_PTR(-ENOMEM); |
128 | 157 | ||
129 | ret = drm_gem_object_init(dev, &obj->base, roundup(size, PAGE_SIZE)); | 158 | ret = drm_gem_object_init(dev, &obj->base, roundup(size, PAGE_SIZE)); |
130 | if (ret) | 159 | if (ret) { |
131 | goto err_free; | 160 | kfree(obj); |
161 | return ERR_PTR(ret); | ||
162 | } | ||
163 | |||
164 | return obj; | ||
165 | } | ||
166 | |||
167 | static void __vgem_gem_destroy(struct drm_vgem_gem_object *obj) | ||
168 | { | ||
169 | drm_gem_object_release(&obj->base); | ||
170 | kfree(obj); | ||
171 | } | ||
172 | |||
173 | static struct drm_gem_object *vgem_gem_create(struct drm_device *dev, | ||
174 | struct drm_file *file, | ||
175 | unsigned int *handle, | ||
176 | unsigned long size) | ||
177 | { | ||
178 | struct drm_vgem_gem_object *obj; | ||
179 | int ret; | ||
180 | |||
181 | obj = __vgem_gem_create(dev, size); | ||
182 | if (IS_ERR(obj)) | ||
183 | return ERR_CAST(obj); | ||
132 | 184 | ||
133 | ret = drm_gem_handle_create(file, &obj->base, handle); | 185 | ret = drm_gem_handle_create(file, &obj->base, handle); |
134 | drm_gem_object_unreference_unlocked(&obj->base); | 186 | drm_gem_object_unreference_unlocked(&obj->base); |
@@ -137,9 +189,8 @@ static struct drm_gem_object *vgem_gem_create(struct drm_device *dev, | |||
137 | 189 | ||
138 | return &obj->base; | 190 | return &obj->base; |
139 | 191 | ||
140 | err_free: | ||
141 | kfree(obj); | ||
142 | err: | 192 | err: |
193 | __vgem_gem_destroy(obj); | ||
143 | return ERR_PTR(ret); | 194 | return ERR_PTR(ret); |
144 | } | 195 | } |
145 | 196 | ||
@@ -256,6 +307,37 @@ static struct sg_table *vgem_prime_get_sg_table(struct drm_gem_object *obj) | |||
256 | return st; | 307 | return st; |
257 | } | 308 | } |
258 | 309 | ||
310 | static struct drm_gem_object* vgem_prime_import(struct drm_device *dev, | ||
311 | struct dma_buf *dma_buf) | ||
312 | { | ||
313 | struct vgem_device *vgem = container_of(dev, typeof(*vgem), drm); | ||
314 | |||
315 | return drm_gem_prime_import_dev(dev, dma_buf, &vgem->platform->dev); | ||
316 | } | ||
317 | |||
318 | static struct drm_gem_object *vgem_prime_import_sg_table(struct drm_device *dev, | ||
319 | struct dma_buf_attachment *attach, struct sg_table *sg) | ||
320 | { | ||
321 | struct drm_vgem_gem_object *obj; | ||
322 | int npages; | ||
323 | |||
324 | obj = __vgem_gem_create(dev, attach->dmabuf->size); | ||
325 | if (IS_ERR(obj)) | ||
326 | return ERR_CAST(obj); | ||
327 | |||
328 | npages = PAGE_ALIGN(attach->dmabuf->size) / PAGE_SIZE; | ||
329 | |||
330 | obj->table = sg; | ||
331 | obj->pages = drm_malloc_ab(npages, sizeof(struct page *)); | ||
332 | if (!obj->pages) { | ||
333 | __vgem_gem_destroy(obj); | ||
334 | return ERR_PTR(-ENOMEM); | ||
335 | } | ||
336 | drm_prime_sg_to_page_addr_arrays(obj->table, obj->pages, NULL, | ||
337 | npages); | ||
338 | return &obj->base; | ||
339 | } | ||
340 | |||
259 | static void *vgem_prime_vmap(struct drm_gem_object *obj) | 341 | static void *vgem_prime_vmap(struct drm_gem_object *obj) |
260 | { | 342 | { |
261 | long n_pages = obj->size >> PAGE_SHIFT; | 343 | long n_pages = obj->size >> PAGE_SHIFT; |
@@ -300,8 +382,19 @@ static int vgem_prime_mmap(struct drm_gem_object *obj, | |||
300 | return 0; | 382 | return 0; |
301 | } | 383 | } |
302 | 384 | ||
385 | static void vgem_release(struct drm_device *dev) | ||
386 | { | ||
387 | struct vgem_device *vgem = container_of(dev, typeof(*vgem), drm); | ||
388 | |||
389 | platform_device_unregister(vgem->platform); | ||
390 | drm_dev_fini(&vgem->drm); | ||
391 | |||
392 | kfree(vgem); | ||
393 | } | ||
394 | |||
303 | static struct drm_driver vgem_driver = { | 395 | static struct drm_driver vgem_driver = { |
304 | .driver_features = DRIVER_GEM | DRIVER_PRIME, | 396 | .driver_features = DRIVER_GEM | DRIVER_PRIME, |
397 | .release = vgem_release, | ||
305 | .open = vgem_open, | 398 | .open = vgem_open, |
306 | .postclose = vgem_postclose, | 399 | .postclose = vgem_postclose, |
307 | .gem_free_object_unlocked = vgem_gem_free_object, | 400 | .gem_free_object_unlocked = vgem_gem_free_object, |
@@ -314,8 +407,11 @@ static struct drm_driver vgem_driver = { | |||
314 | .dumb_map_offset = vgem_gem_dumb_map, | 407 | .dumb_map_offset = vgem_gem_dumb_map, |
315 | 408 | ||
316 | .prime_handle_to_fd = drm_gem_prime_handle_to_fd, | 409 | .prime_handle_to_fd = drm_gem_prime_handle_to_fd, |
410 | .prime_fd_to_handle = drm_gem_prime_fd_to_handle, | ||
317 | .gem_prime_pin = vgem_prime_pin, | 411 | .gem_prime_pin = vgem_prime_pin, |
412 | .gem_prime_import = vgem_prime_import, | ||
318 | .gem_prime_export = drm_gem_prime_export, | 413 | .gem_prime_export = drm_gem_prime_export, |
414 | .gem_prime_import_sg_table = vgem_prime_import_sg_table, | ||
319 | .gem_prime_get_sg_table = vgem_prime_get_sg_table, | 415 | .gem_prime_get_sg_table = vgem_prime_get_sg_table, |
320 | .gem_prime_vmap = vgem_prime_vmap, | 416 | .gem_prime_vmap = vgem_prime_vmap, |
321 | .gem_prime_vunmap = vgem_prime_vunmap, | 417 | .gem_prime_vunmap = vgem_prime_vunmap, |
@@ -328,34 +424,48 @@ static struct drm_driver vgem_driver = { | |||
328 | .minor = DRIVER_MINOR, | 424 | .minor = DRIVER_MINOR, |
329 | }; | 425 | }; |
330 | 426 | ||
331 | static struct drm_device *vgem_device; | ||
332 | |||
333 | static int __init vgem_init(void) | 427 | static int __init vgem_init(void) |
334 | { | 428 | { |
335 | int ret; | 429 | int ret; |
336 | 430 | ||
337 | vgem_device = drm_dev_alloc(&vgem_driver, NULL); | 431 | vgem_device = kzalloc(sizeof(*vgem_device), GFP_KERNEL); |
338 | if (IS_ERR(vgem_device)) { | 432 | if (!vgem_device) |
339 | ret = PTR_ERR(vgem_device); | 433 | return -ENOMEM; |
340 | goto out; | 434 | |
435 | ret = drm_dev_init(&vgem_device->drm, &vgem_driver, NULL); | ||
436 | if (ret) | ||
437 | goto out_free; | ||
438 | |||
439 | vgem_device->platform = | ||
440 | platform_device_register_simple("vgem", -1, NULL, 0); | ||
441 | if (!vgem_device->platform) { | ||
442 | ret = -ENODEV; | ||
443 | goto out_fini; | ||
341 | } | 444 | } |
342 | 445 | ||
343 | ret = drm_dev_register(vgem_device, 0); | 446 | dma_coerce_mask_and_coherent(&vgem_device->platform->dev, |
447 | DMA_BIT_MASK(64)); | ||
448 | |||
449 | /* Final step: expose the device/driver to userspace */ | ||
450 | ret = drm_dev_register(&vgem_device->drm, 0); | ||
344 | if (ret) | 451 | if (ret) |
345 | goto out_unref; | 452 | goto out_unregister; |
346 | 453 | ||
347 | return 0; | 454 | return 0; |
348 | 455 | ||
349 | out_unref: | 456 | out_unregister: |
350 | drm_dev_unref(vgem_device); | 457 | platform_device_unregister(vgem_device->platform); |
351 | out: | 458 | out_fini: |
459 | drm_dev_fini(&vgem_device->drm); | ||
460 | out_free: | ||
461 | kfree(vgem_device); | ||
352 | return ret; | 462 | return ret; |
353 | } | 463 | } |
354 | 464 | ||
355 | static void __exit vgem_exit(void) | 465 | static void __exit vgem_exit(void) |
356 | { | 466 | { |
357 | drm_dev_unregister(vgem_device); | 467 | drm_dev_unregister(&vgem_device->drm); |
358 | drm_dev_unref(vgem_device); | 468 | drm_dev_unref(&vgem_device->drm); |
359 | } | 469 | } |
360 | 470 | ||
361 | module_init(vgem_init); | 471 | module_init(vgem_init); |
diff --git a/drivers/gpu/drm/vgem/vgem_drv.h b/drivers/gpu/drm/vgem/vgem_drv.h index cb59c7ab98b9..1aae01419112 100644 --- a/drivers/gpu/drm/vgem/vgem_drv.h +++ b/drivers/gpu/drm/vgem/vgem_drv.h | |||
@@ -43,6 +43,8 @@ struct vgem_file { | |||
43 | #define to_vgem_bo(x) container_of(x, struct drm_vgem_gem_object, base) | 43 | #define to_vgem_bo(x) container_of(x, struct drm_vgem_gem_object, base) |
44 | struct drm_vgem_gem_object { | 44 | struct drm_vgem_gem_object { |
45 | struct drm_gem_object base; | 45 | struct drm_gem_object base; |
46 | struct page **pages; | ||
47 | struct sg_table *table; | ||
46 | }; | 48 | }; |
47 | 49 | ||
48 | int vgem_fence_open(struct vgem_file *file); | 50 | int vgem_fence_open(struct vgem_file *file); |
diff --git a/drivers/gpu/drm/zte/Makefile b/drivers/gpu/drm/zte/Makefile index 01352b56c418..9df7766a7f9d 100644 --- a/drivers/gpu/drm/zte/Makefile +++ b/drivers/gpu/drm/zte/Makefile | |||
@@ -3,6 +3,7 @@ zxdrm-y := \ | |||
3 | zx_hdmi.o \ | 3 | zx_hdmi.o \ |
4 | zx_plane.o \ | 4 | zx_plane.o \ |
5 | zx_tvenc.o \ | 5 | zx_tvenc.o \ |
6 | zx_vga.o \ | ||
6 | zx_vou.o | 7 | zx_vou.o |
7 | 8 | ||
8 | obj-$(CONFIG_DRM_ZTE) += zxdrm.o | 9 | obj-$(CONFIG_DRM_ZTE) += zxdrm.o |
diff --git a/drivers/gpu/drm/zte/zx_common_regs.h b/drivers/gpu/drm/zte/zx_common_regs.h new file mode 100644 index 000000000000..2afd80664c51 --- /dev/null +++ b/drivers/gpu/drm/zte/zx_common_regs.h | |||
@@ -0,0 +1,31 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2017 Sanechips Technology Co., Ltd. | ||
3 | * Copyright 2017 Linaro Ltd. | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify | ||
6 | * it under the terms of the GNU General Public License version 2 as | ||
7 | * published by the Free Software Foundation. | ||
8 | */ | ||
9 | |||
10 | #ifndef __ZX_COMMON_REGS_H__ | ||
11 | #define __ZX_COMMON_REGS_H__ | ||
12 | |||
13 | /* CSC registers */ | ||
14 | #define CSC_CTRL0 0x30 | ||
15 | #define CSC_COV_MODE_SHIFT 16 | ||
16 | #define CSC_COV_MODE_MASK (0xffff << CSC_COV_MODE_SHIFT) | ||
17 | #define CSC_BT601_IMAGE_RGB2YCBCR 0 | ||
18 | #define CSC_BT601_IMAGE_YCBCR2RGB 1 | ||
19 | #define CSC_BT601_VIDEO_RGB2YCBCR 2 | ||
20 | #define CSC_BT601_VIDEO_YCBCR2RGB 3 | ||
21 | #define CSC_BT709_IMAGE_RGB2YCBCR 4 | ||
22 | #define CSC_BT709_IMAGE_YCBCR2RGB 5 | ||
23 | #define CSC_BT709_VIDEO_RGB2YCBCR 6 | ||
24 | #define CSC_BT709_VIDEO_YCBCR2RGB 7 | ||
25 | #define CSC_BT2020_IMAGE_RGB2YCBCR 8 | ||
26 | #define CSC_BT2020_IMAGE_YCBCR2RGB 9 | ||
27 | #define CSC_BT2020_VIDEO_RGB2YCBCR 10 | ||
28 | #define CSC_BT2020_VIDEO_YCBCR2RGB 11 | ||
29 | #define CSC_WORK_ENABLE BIT(0) | ||
30 | |||
31 | #endif /* __ZX_COMMON_REGS_H__ */ | ||
diff --git a/drivers/gpu/drm/zte/zx_drm_drv.c b/drivers/gpu/drm/zte/zx_drm_drv.c index 614e854f6be5..490aafc99610 100644 --- a/drivers/gpu/drm/zte/zx_drm_drv.c +++ b/drivers/gpu/drm/zte/zx_drm_drv.c | |||
@@ -233,6 +233,7 @@ static struct platform_driver *drivers[] = { | |||
233 | &zx_crtc_driver, | 233 | &zx_crtc_driver, |
234 | &zx_hdmi_driver, | 234 | &zx_hdmi_driver, |
235 | &zx_tvenc_driver, | 235 | &zx_tvenc_driver, |
236 | &zx_vga_driver, | ||
236 | &zx_drm_platform_driver, | 237 | &zx_drm_platform_driver, |
237 | }; | 238 | }; |
238 | 239 | ||
diff --git a/drivers/gpu/drm/zte/zx_drm_drv.h b/drivers/gpu/drm/zte/zx_drm_drv.h index 5ca035b079c7..2a8cdc5f8be4 100644 --- a/drivers/gpu/drm/zte/zx_drm_drv.h +++ b/drivers/gpu/drm/zte/zx_drm_drv.h | |||
@@ -14,6 +14,7 @@ | |||
14 | extern struct platform_driver zx_crtc_driver; | 14 | extern struct platform_driver zx_crtc_driver; |
15 | extern struct platform_driver zx_hdmi_driver; | 15 | extern struct platform_driver zx_hdmi_driver; |
16 | extern struct platform_driver zx_tvenc_driver; | 16 | extern struct platform_driver zx_tvenc_driver; |
17 | extern struct platform_driver zx_vga_driver; | ||
17 | 18 | ||
18 | static inline u32 zx_readl(void __iomem *reg) | 19 | static inline u32 zx_readl(void __iomem *reg) |
19 | { | 20 | { |
diff --git a/drivers/gpu/drm/zte/zx_plane.c b/drivers/gpu/drm/zte/zx_plane.c index d646ac931663..4a6252720c10 100644 --- a/drivers/gpu/drm/zte/zx_plane.c +++ b/drivers/gpu/drm/zte/zx_plane.c | |||
@@ -16,6 +16,7 @@ | |||
16 | #include <drm/drm_plane_helper.h> | 16 | #include <drm/drm_plane_helper.h> |
17 | #include <drm/drmP.h> | 17 | #include <drm/drmP.h> |
18 | 18 | ||
19 | #include "zx_common_regs.h" | ||
19 | #include "zx_drm_drv.h" | 20 | #include "zx_drm_drv.h" |
20 | #include "zx_plane.h" | 21 | #include "zx_plane.h" |
21 | #include "zx_plane_regs.h" | 22 | #include "zx_plane_regs.h" |
diff --git a/drivers/gpu/drm/zte/zx_plane_regs.h b/drivers/gpu/drm/zte/zx_plane_regs.h index 65f271aeabed..9c655f59f9f7 100644 --- a/drivers/gpu/drm/zte/zx_plane_regs.h +++ b/drivers/gpu/drm/zte/zx_plane_regs.h | |||
@@ -77,24 +77,6 @@ | |||
77 | #define LUMA_STRIDE(x) (((x) << LUMA_STRIDE_SHIFT) & LUMA_STRIDE_MASK) | 77 | #define LUMA_STRIDE(x) (((x) << LUMA_STRIDE_SHIFT) & LUMA_STRIDE_MASK) |
78 | #define CHROMA_STRIDE(x) (((x) << CHROMA_STRIDE_SHIFT) & CHROMA_STRIDE_MASK) | 78 | #define CHROMA_STRIDE(x) (((x) << CHROMA_STRIDE_SHIFT) & CHROMA_STRIDE_MASK) |
79 | 79 | ||
80 | /* CSC registers */ | ||
81 | #define CSC_CTRL0 0x30 | ||
82 | #define CSC_COV_MODE_SHIFT 16 | ||
83 | #define CSC_COV_MODE_MASK (0xffff << CSC_COV_MODE_SHIFT) | ||
84 | #define CSC_BT601_IMAGE_RGB2YCBCR 0 | ||
85 | #define CSC_BT601_IMAGE_YCBCR2RGB 1 | ||
86 | #define CSC_BT601_VIDEO_RGB2YCBCR 2 | ||
87 | #define CSC_BT601_VIDEO_YCBCR2RGB 3 | ||
88 | #define CSC_BT709_IMAGE_RGB2YCBCR 4 | ||
89 | #define CSC_BT709_IMAGE_YCBCR2RGB 5 | ||
90 | #define CSC_BT709_VIDEO_RGB2YCBCR 6 | ||
91 | #define CSC_BT709_VIDEO_YCBCR2RGB 7 | ||
92 | #define CSC_BT2020_IMAGE_RGB2YCBCR 8 | ||
93 | #define CSC_BT2020_IMAGE_YCBCR2RGB 9 | ||
94 | #define CSC_BT2020_VIDEO_RGB2YCBCR 10 | ||
95 | #define CSC_BT2020_VIDEO_YCBCR2RGB 11 | ||
96 | #define CSC_WORK_ENABLE BIT(0) | ||
97 | |||
98 | /* RSZ registers */ | 80 | /* RSZ registers */ |
99 | #define RSZ_SRC_CFG 0x00 | 81 | #define RSZ_SRC_CFG 0x00 |
100 | #define RSZ_DEST_CFG 0x04 | 82 | #define RSZ_DEST_CFG 0x04 |
diff --git a/drivers/gpu/drm/zte/zx_vga.c b/drivers/gpu/drm/zte/zx_vga.c new file mode 100644 index 000000000000..1e0811f775cb --- /dev/null +++ b/drivers/gpu/drm/zte/zx_vga.c | |||
@@ -0,0 +1,531 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2017 Sanechips Technology Co., Ltd. | ||
3 | * Copyright 2017 Linaro Ltd. | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify | ||
6 | * it under the terms of the GNU General Public License version 2 as | ||
7 | * published by the Free Software Foundation. | ||
8 | */ | ||
9 | |||
10 | #include <linux/clk.h> | ||
11 | #include <linux/component.h> | ||
12 | #include <linux/mfd/syscon.h> | ||
13 | #include <linux/regmap.h> | ||
14 | |||
15 | #include <drm/drm_atomic_helper.h> | ||
16 | #include <drm/drm_crtc_helper.h> | ||
17 | #include <drm/drmP.h> | ||
18 | |||
19 | #include "zx_drm_drv.h" | ||
20 | #include "zx_vga_regs.h" | ||
21 | #include "zx_vou.h" | ||
22 | |||
23 | struct zx_vga_pwrctrl { | ||
24 | struct regmap *regmap; | ||
25 | u32 reg; | ||
26 | u32 mask; | ||
27 | }; | ||
28 | |||
29 | struct zx_vga_i2c { | ||
30 | struct i2c_adapter adap; | ||
31 | struct mutex lock; | ||
32 | }; | ||
33 | |||
34 | struct zx_vga { | ||
35 | struct drm_connector connector; | ||
36 | struct drm_encoder encoder; | ||
37 | struct zx_vga_i2c *ddc; | ||
38 | struct device *dev; | ||
39 | void __iomem *mmio; | ||
40 | struct clk *i2c_wclk; | ||
41 | struct zx_vga_pwrctrl pwrctrl; | ||
42 | struct completion complete; | ||
43 | bool connected; | ||
44 | }; | ||
45 | |||
46 | #define to_zx_vga(x) container_of(x, struct zx_vga, x) | ||
47 | |||
48 | static void zx_vga_encoder_enable(struct drm_encoder *encoder) | ||
49 | { | ||
50 | struct zx_vga *vga = to_zx_vga(encoder); | ||
51 | struct zx_vga_pwrctrl *pwrctrl = &vga->pwrctrl; | ||
52 | |||
53 | /* Set bit to power up VGA DACs */ | ||
54 | regmap_update_bits(pwrctrl->regmap, pwrctrl->reg, pwrctrl->mask, | ||
55 | pwrctrl->mask); | ||
56 | |||
57 | vou_inf_enable(VOU_VGA, encoder->crtc); | ||
58 | } | ||
59 | |||
60 | static void zx_vga_encoder_disable(struct drm_encoder *encoder) | ||
61 | { | ||
62 | struct zx_vga *vga = to_zx_vga(encoder); | ||
63 | struct zx_vga_pwrctrl *pwrctrl = &vga->pwrctrl; | ||
64 | |||
65 | vou_inf_disable(VOU_VGA, encoder->crtc); | ||
66 | |||
67 | /* Clear bit to power down VGA DACs */ | ||
68 | regmap_update_bits(pwrctrl->regmap, pwrctrl->reg, pwrctrl->mask, 0); | ||
69 | } | ||
70 | |||
71 | static const struct drm_encoder_helper_funcs zx_vga_encoder_helper_funcs = { | ||
72 | .enable = zx_vga_encoder_enable, | ||
73 | .disable = zx_vga_encoder_disable, | ||
74 | }; | ||
75 | |||
76 | static const struct drm_encoder_funcs zx_vga_encoder_funcs = { | ||
77 | .destroy = drm_encoder_cleanup, | ||
78 | }; | ||
79 | |||
80 | static int zx_vga_connector_get_modes(struct drm_connector *connector) | ||
81 | { | ||
82 | struct zx_vga *vga = to_zx_vga(connector); | ||
83 | struct edid *edid; | ||
84 | int ret; | ||
85 | |||
86 | /* | ||
87 | * Clear both detection bits to switch I2C bus from device | ||
88 | * detecting to EDID reading. | ||
89 | */ | ||
90 | zx_writel(vga->mmio + VGA_AUTO_DETECT_SEL, 0); | ||
91 | |||
92 | edid = drm_get_edid(connector, &vga->ddc->adap); | ||
93 | if (!edid) { | ||
94 | /* | ||
95 | * If EDID reading fails, we set the device state into | ||
96 | * disconnected. Locking is not required here, since the | ||
97 | * VGA_AUTO_DETECT_SEL register write in irq handler cannot | ||
98 | * be triggered when both detection bits are cleared as above. | ||
99 | */ | ||
100 | zx_writel(vga->mmio + VGA_AUTO_DETECT_SEL, | ||
101 | VGA_DETECT_SEL_NO_DEVICE); | ||
102 | vga->connected = false; | ||
103 | return 0; | ||
104 | } | ||
105 | |||
106 | /* | ||
107 | * As edid reading succeeds, device must be connected, so we set | ||
108 | * up detection bit for unplug interrupt here. | ||
109 | */ | ||
110 | zx_writel(vga->mmio + VGA_AUTO_DETECT_SEL, VGA_DETECT_SEL_HAS_DEVICE); | ||
111 | |||
112 | drm_mode_connector_update_edid_property(connector, edid); | ||
113 | ret = drm_add_edid_modes(connector, edid); | ||
114 | kfree(edid); | ||
115 | |||
116 | return ret; | ||
117 | } | ||
118 | |||
119 | static enum drm_mode_status | ||
120 | zx_vga_connector_mode_valid(struct drm_connector *connector, | ||
121 | struct drm_display_mode *mode) | ||
122 | { | ||
123 | return MODE_OK; | ||
124 | } | ||
125 | |||
126 | static struct drm_connector_helper_funcs zx_vga_connector_helper_funcs = { | ||
127 | .get_modes = zx_vga_connector_get_modes, | ||
128 | .mode_valid = zx_vga_connector_mode_valid, | ||
129 | }; | ||
130 | |||
131 | static enum drm_connector_status | ||
132 | zx_vga_connector_detect(struct drm_connector *connector, bool force) | ||
133 | { | ||
134 | struct zx_vga *vga = to_zx_vga(connector); | ||
135 | |||
136 | return vga->connected ? connector_status_connected : | ||
137 | connector_status_disconnected; | ||
138 | } | ||
139 | |||
140 | static const struct drm_connector_funcs zx_vga_connector_funcs = { | ||
141 | .dpms = drm_atomic_helper_connector_dpms, | ||
142 | .fill_modes = drm_helper_probe_single_connector_modes, | ||
143 | .detect = zx_vga_connector_detect, | ||
144 | .destroy = drm_connector_cleanup, | ||
145 | .reset = drm_atomic_helper_connector_reset, | ||
146 | .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, | ||
147 | .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, | ||
148 | }; | ||
149 | |||
150 | static int zx_vga_register(struct drm_device *drm, struct zx_vga *vga) | ||
151 | { | ||
152 | struct drm_encoder *encoder = &vga->encoder; | ||
153 | struct drm_connector *connector = &vga->connector; | ||
154 | struct device *dev = vga->dev; | ||
155 | int ret; | ||
156 | |||
157 | encoder->possible_crtcs = VOU_CRTC_MASK; | ||
158 | |||
159 | ret = drm_encoder_init(drm, encoder, &zx_vga_encoder_funcs, | ||
160 | DRM_MODE_ENCODER_DAC, NULL); | ||
161 | if (ret) { | ||
162 | DRM_DEV_ERROR(dev, "failed to init encoder: %d\n", ret); | ||
163 | return ret; | ||
164 | }; | ||
165 | |||
166 | drm_encoder_helper_add(encoder, &zx_vga_encoder_helper_funcs); | ||
167 | |||
168 | vga->connector.polled = DRM_CONNECTOR_POLL_HPD; | ||
169 | |||
170 | ret = drm_connector_init(drm, connector, &zx_vga_connector_funcs, | ||
171 | DRM_MODE_CONNECTOR_VGA); | ||
172 | if (ret) { | ||
173 | DRM_DEV_ERROR(dev, "failed to init connector: %d\n", ret); | ||
174 | goto clean_encoder; | ||
175 | }; | ||
176 | |||
177 | drm_connector_helper_add(connector, &zx_vga_connector_helper_funcs); | ||
178 | |||
179 | ret = drm_mode_connector_attach_encoder(connector, encoder); | ||
180 | if (ret) { | ||
181 | DRM_DEV_ERROR(dev, "failed to attach encoder: %d\n", ret); | ||
182 | goto clean_connector; | ||
183 | }; | ||
184 | |||
185 | return 0; | ||
186 | |||
187 | clean_connector: | ||
188 | drm_connector_cleanup(connector); | ||
189 | clean_encoder: | ||
190 | drm_encoder_cleanup(encoder); | ||
191 | return ret; | ||
192 | } | ||
193 | |||
194 | static int zx_vga_pwrctrl_init(struct zx_vga *vga) | ||
195 | { | ||
196 | struct zx_vga_pwrctrl *pwrctrl = &vga->pwrctrl; | ||
197 | struct device *dev = vga->dev; | ||
198 | struct of_phandle_args out_args; | ||
199 | struct regmap *regmap; | ||
200 | int ret; | ||
201 | |||
202 | ret = of_parse_phandle_with_fixed_args(dev->of_node, | ||
203 | "zte,vga-power-control", 2, 0, &out_args); | ||
204 | if (ret) | ||
205 | return ret; | ||
206 | |||
207 | regmap = syscon_node_to_regmap(out_args.np); | ||
208 | if (IS_ERR(regmap)) { | ||
209 | ret = PTR_ERR(regmap); | ||
210 | goto out; | ||
211 | } | ||
212 | |||
213 | pwrctrl->regmap = regmap; | ||
214 | pwrctrl->reg = out_args.args[0]; | ||
215 | pwrctrl->mask = out_args.args[1]; | ||
216 | |||
217 | out: | ||
218 | of_node_put(out_args.np); | ||
219 | return ret; | ||
220 | } | ||
221 | |||
222 | static int zx_vga_i2c_read(struct zx_vga *vga, struct i2c_msg *msg) | ||
223 | { | ||
224 | int len = msg->len; | ||
225 | u8 *buf = msg->buf; | ||
226 | u32 offset = 0; | ||
227 | int i; | ||
228 | |||
229 | reinit_completion(&vga->complete); | ||
230 | |||
231 | /* Select combo write */ | ||
232 | zx_writel_mask(vga->mmio + VGA_CMD_CFG, VGA_CMD_COMBO, VGA_CMD_COMBO); | ||
233 | zx_writel_mask(vga->mmio + VGA_CMD_CFG, VGA_CMD_RW, 0); | ||
234 | |||
235 | while (len > 0) { | ||
236 | u32 cnt; | ||
237 | |||
238 | /* Clear RX FIFO */ | ||
239 | zx_writel_mask(vga->mmio + VGA_RXF_CTRL, VGA_RX_FIFO_CLEAR, | ||
240 | VGA_RX_FIFO_CLEAR); | ||
241 | |||
242 | /* Data offset to read from */ | ||
243 | zx_writel(vga->mmio + VGA_SUB_ADDR, offset); | ||
244 | |||
245 | /* Kick off the transfer */ | ||
246 | zx_writel_mask(vga->mmio + VGA_CMD_CFG, VGA_CMD_TRANS, | ||
247 | VGA_CMD_TRANS); | ||
248 | |||
249 | if (!wait_for_completion_timeout(&vga->complete, | ||
250 | msecs_to_jiffies(1000))) { | ||
251 | DRM_DEV_ERROR(vga->dev, "transfer timeout\n"); | ||
252 | return -ETIMEDOUT; | ||
253 | } | ||
254 | |||
255 | cnt = zx_readl(vga->mmio + VGA_RXF_STATUS); | ||
256 | cnt = (cnt & VGA_RXF_COUNT_MASK) >> VGA_RXF_COUNT_SHIFT; | ||
257 | /* FIFO status may report more data than we need to read */ | ||
258 | cnt = min_t(u32, len, cnt); | ||
259 | |||
260 | for (i = 0; i < cnt; i++) | ||
261 | *buf++ = zx_readl(vga->mmio + VGA_DATA); | ||
262 | |||
263 | len -= cnt; | ||
264 | offset += cnt; | ||
265 | } | ||
266 | |||
267 | return 0; | ||
268 | } | ||
269 | |||
270 | static int zx_vga_i2c_write(struct zx_vga *vga, struct i2c_msg *msg) | ||
271 | { | ||
272 | /* | ||
273 | * The DDC I2C adapter is only for reading EDID data, so we assume | ||
274 | * that the write to this adapter must be the EDID data offset. | ||
275 | */ | ||
276 | if ((msg->len != 1) || ((msg->addr != DDC_ADDR))) | ||
277 | return -EINVAL; | ||
278 | |||
279 | /* Hardware will take care of the slave address shifting */ | ||
280 | zx_writel(vga->mmio + VGA_DEVICE_ADDR, msg->addr); | ||
281 | |||
282 | return 0; | ||
283 | } | ||
284 | |||
285 | static int zx_vga_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, | ||
286 | int num) | ||
287 | { | ||
288 | struct zx_vga *vga = i2c_get_adapdata(adap); | ||
289 | struct zx_vga_i2c *ddc = vga->ddc; | ||
290 | int ret = 0; | ||
291 | int i; | ||
292 | |||
293 | mutex_lock(&ddc->lock); | ||
294 | |||
295 | for (i = 0; i < num; i++) { | ||
296 | if (msgs[i].flags & I2C_M_RD) | ||
297 | ret = zx_vga_i2c_read(vga, &msgs[i]); | ||
298 | else | ||
299 | ret = zx_vga_i2c_write(vga, &msgs[i]); | ||
300 | |||
301 | if (ret < 0) | ||
302 | break; | ||
303 | } | ||
304 | |||
305 | if (!ret) | ||
306 | ret = num; | ||
307 | |||
308 | mutex_unlock(&ddc->lock); | ||
309 | |||
310 | return ret; | ||
311 | } | ||
312 | |||
313 | static u32 zx_vga_i2c_func(struct i2c_adapter *adapter) | ||
314 | { | ||
315 | return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; | ||
316 | } | ||
317 | |||
318 | static const struct i2c_algorithm zx_vga_algorithm = { | ||
319 | .master_xfer = zx_vga_i2c_xfer, | ||
320 | .functionality = zx_vga_i2c_func, | ||
321 | }; | ||
322 | |||
323 | static int zx_vga_ddc_register(struct zx_vga *vga) | ||
324 | { | ||
325 | struct device *dev = vga->dev; | ||
326 | struct i2c_adapter *adap; | ||
327 | struct zx_vga_i2c *ddc; | ||
328 | int ret; | ||
329 | |||
330 | ddc = devm_kzalloc(dev, sizeof(*ddc), GFP_KERNEL); | ||
331 | if (!ddc) | ||
332 | return -ENOMEM; | ||
333 | |||
334 | vga->ddc = ddc; | ||
335 | mutex_init(&ddc->lock); | ||
336 | |||
337 | adap = &ddc->adap; | ||
338 | adap->owner = THIS_MODULE; | ||
339 | adap->class = I2C_CLASS_DDC; | ||
340 | adap->dev.parent = dev; | ||
341 | adap->algo = &zx_vga_algorithm; | ||
342 | snprintf(adap->name, sizeof(adap->name), "zx vga i2c"); | ||
343 | |||
344 | ret = i2c_add_adapter(adap); | ||
345 | if (ret) { | ||
346 | DRM_DEV_ERROR(dev, "failed to add I2C adapter: %d\n", ret); | ||
347 | return ret; | ||
348 | } | ||
349 | |||
350 | i2c_set_adapdata(adap, vga); | ||
351 | |||
352 | return 0; | ||
353 | } | ||
354 | |||
355 | static irqreturn_t zx_vga_irq_thread(int irq, void *dev_id) | ||
356 | { | ||
357 | struct zx_vga *vga = dev_id; | ||
358 | |||
359 | drm_helper_hpd_irq_event(vga->connector.dev); | ||
360 | |||
361 | return IRQ_HANDLED; | ||
362 | } | ||
363 | |||
364 | static irqreturn_t zx_vga_irq_handler(int irq, void *dev_id) | ||
365 | { | ||
366 | struct zx_vga *vga = dev_id; | ||
367 | u32 status; | ||
368 | |||
369 | status = zx_readl(vga->mmio + VGA_I2C_STATUS); | ||
370 | |||
371 | /* Clear interrupt status */ | ||
372 | zx_writel_mask(vga->mmio + VGA_I2C_STATUS, VGA_CLEAR_IRQ, | ||
373 | VGA_CLEAR_IRQ); | ||
374 | |||
375 | if (status & VGA_DEVICE_CONNECTED) { | ||
376 | /* | ||
377 | * Since VGA_DETECT_SEL bits need to be reset for switching DDC | ||
378 | * bus from device detection to EDID read, rather than setting | ||
379 | * up HAS_DEVICE bit here, we need to do that in .get_modes | ||
380 | * hook for unplug detecting after EDID read succeeds. | ||
381 | */ | ||
382 | vga->connected = true; | ||
383 | return IRQ_WAKE_THREAD; | ||
384 | } | ||
385 | |||
386 | if (status & VGA_DEVICE_DISCONNECTED) { | ||
387 | zx_writel(vga->mmio + VGA_AUTO_DETECT_SEL, | ||
388 | VGA_DETECT_SEL_NO_DEVICE); | ||
389 | vga->connected = false; | ||
390 | return IRQ_WAKE_THREAD; | ||
391 | } | ||
392 | |||
393 | if (status & VGA_TRANS_DONE) { | ||
394 | complete(&vga->complete); | ||
395 | return IRQ_HANDLED; | ||
396 | } | ||
397 | |||
398 | return IRQ_NONE; | ||
399 | } | ||
400 | |||
401 | static void zx_vga_hw_init(struct zx_vga *vga) | ||
402 | { | ||
403 | unsigned long ref = clk_get_rate(vga->i2c_wclk); | ||
404 | int div; | ||
405 | |||
406 | /* | ||
407 | * Set up I2C fast speed divider per formula below to get 400kHz. | ||
408 | * scl = ref / ((div + 1) * 4) | ||
409 | */ | ||
410 | div = DIV_ROUND_UP(ref / 1000, 400 * 4) - 1; | ||
411 | zx_writel(vga->mmio + VGA_CLK_DIV_FS, div); | ||
412 | |||
413 | /* Set up device detection */ | ||
414 | zx_writel(vga->mmio + VGA_AUTO_DETECT_PARA, 0x80); | ||
415 | zx_writel(vga->mmio + VGA_AUTO_DETECT_SEL, VGA_DETECT_SEL_NO_DEVICE); | ||
416 | |||
417 | /* | ||
418 | * We need to poke monitor via DDC bus to get connection irq | ||
419 | * start working. | ||
420 | */ | ||
421 | zx_writel(vga->mmio + VGA_DEVICE_ADDR, DDC_ADDR); | ||
422 | zx_writel_mask(vga->mmio + VGA_CMD_CFG, VGA_CMD_TRANS, VGA_CMD_TRANS); | ||
423 | } | ||
424 | |||
425 | static int zx_vga_bind(struct device *dev, struct device *master, void *data) | ||
426 | { | ||
427 | struct platform_device *pdev = to_platform_device(dev); | ||
428 | struct drm_device *drm = data; | ||
429 | struct resource *res; | ||
430 | struct zx_vga *vga; | ||
431 | int irq; | ||
432 | int ret; | ||
433 | |||
434 | vga = devm_kzalloc(dev, sizeof(*vga), GFP_KERNEL); | ||
435 | if (!vga) | ||
436 | return -ENOMEM; | ||
437 | |||
438 | vga->dev = dev; | ||
439 | dev_set_drvdata(dev, vga); | ||
440 | |||
441 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
442 | vga->mmio = devm_ioremap_resource(dev, res); | ||
443 | if (IS_ERR(vga->mmio)) | ||
444 | return PTR_ERR(vga->mmio); | ||
445 | |||
446 | irq = platform_get_irq(pdev, 0); | ||
447 | if (irq < 0) | ||
448 | return irq; | ||
449 | |||
450 | vga->i2c_wclk = devm_clk_get(dev, "i2c_wclk"); | ||
451 | if (IS_ERR(vga->i2c_wclk)) { | ||
452 | ret = PTR_ERR(vga->i2c_wclk); | ||
453 | DRM_DEV_ERROR(dev, "failed to get i2c_wclk: %d\n", ret); | ||
454 | return ret; | ||
455 | } | ||
456 | |||
457 | ret = zx_vga_pwrctrl_init(vga); | ||
458 | if (ret) { | ||
459 | DRM_DEV_ERROR(dev, "failed to init power control: %d\n", ret); | ||
460 | return ret; | ||
461 | } | ||
462 | |||
463 | ret = zx_vga_ddc_register(vga); | ||
464 | if (ret) { | ||
465 | DRM_DEV_ERROR(dev, "failed to register ddc: %d\n", ret); | ||
466 | return ret; | ||
467 | } | ||
468 | |||
469 | ret = zx_vga_register(drm, vga); | ||
470 | if (ret) { | ||
471 | DRM_DEV_ERROR(dev, "failed to register vga: %d\n", ret); | ||
472 | return ret; | ||
473 | } | ||
474 | |||
475 | init_completion(&vga->complete); | ||
476 | |||
477 | ret = devm_request_threaded_irq(dev, irq, zx_vga_irq_handler, | ||
478 | zx_vga_irq_thread, IRQF_SHARED, | ||
479 | dev_name(dev), vga); | ||
480 | if (ret) { | ||
481 | DRM_DEV_ERROR(dev, "failed to request threaded irq: %d\n", ret); | ||
482 | return ret; | ||
483 | } | ||
484 | |||
485 | ret = clk_prepare_enable(vga->i2c_wclk); | ||
486 | if (ret) | ||
487 | return ret; | ||
488 | |||
489 | zx_vga_hw_init(vga); | ||
490 | |||
491 | return 0; | ||
492 | } | ||
493 | |||
494 | static void zx_vga_unbind(struct device *dev, struct device *master, | ||
495 | void *data) | ||
496 | { | ||
497 | struct zx_vga *vga = dev_get_drvdata(dev); | ||
498 | |||
499 | clk_disable_unprepare(vga->i2c_wclk); | ||
500 | } | ||
501 | |||
502 | static const struct component_ops zx_vga_component_ops = { | ||
503 | .bind = zx_vga_bind, | ||
504 | .unbind = zx_vga_unbind, | ||
505 | }; | ||
506 | |||
507 | static int zx_vga_probe(struct platform_device *pdev) | ||
508 | { | ||
509 | return component_add(&pdev->dev, &zx_vga_component_ops); | ||
510 | } | ||
511 | |||
512 | static int zx_vga_remove(struct platform_device *pdev) | ||
513 | { | ||
514 | component_del(&pdev->dev, &zx_vga_component_ops); | ||
515 | return 0; | ||
516 | } | ||
517 | |||
518 | static const struct of_device_id zx_vga_of_match[] = { | ||
519 | { .compatible = "zte,zx296718-vga", }, | ||
520 | { /* end */ }, | ||
521 | }; | ||
522 | MODULE_DEVICE_TABLE(of, zx_vga_of_match); | ||
523 | |||
524 | struct platform_driver zx_vga_driver = { | ||
525 | .probe = zx_vga_probe, | ||
526 | .remove = zx_vga_remove, | ||
527 | .driver = { | ||
528 | .name = "zx-vga", | ||
529 | .of_match_table = zx_vga_of_match, | ||
530 | }, | ||
531 | }; | ||
diff --git a/drivers/gpu/drm/zte/zx_vga_regs.h b/drivers/gpu/drm/zte/zx_vga_regs.h new file mode 100644 index 000000000000..feaa345fe6a6 --- /dev/null +++ b/drivers/gpu/drm/zte/zx_vga_regs.h | |||
@@ -0,0 +1,36 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2017 Sanechips Technology Co., Ltd. | ||
3 | * Copyright 2017 Linaro Ltd. | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify | ||
6 | * it under the terms of the GNU General Public License version 2 as | ||
7 | * published by the Free Software Foundation. | ||
8 | */ | ||
9 | |||
10 | #ifndef __ZX_VGA_REGS_H__ | ||
11 | #define __ZX_VGA_REGS_H__ | ||
12 | |||
13 | #define VGA_CMD_CFG 0x04 | ||
14 | #define VGA_CMD_TRANS BIT(6) | ||
15 | #define VGA_CMD_COMBO BIT(5) | ||
16 | #define VGA_CMD_RW BIT(4) | ||
17 | #define VGA_SUB_ADDR 0x0c | ||
18 | #define VGA_DEVICE_ADDR 0x10 | ||
19 | #define VGA_CLK_DIV_FS 0x14 | ||
20 | #define VGA_RXF_CTRL 0x20 | ||
21 | #define VGA_RX_FIFO_CLEAR BIT(7) | ||
22 | #define VGA_DATA 0x24 | ||
23 | #define VGA_I2C_STATUS 0x28 | ||
24 | #define VGA_DEVICE_DISCONNECTED BIT(7) | ||
25 | #define VGA_DEVICE_CONNECTED BIT(6) | ||
26 | #define VGA_CLEAR_IRQ BIT(4) | ||
27 | #define VGA_TRANS_DONE BIT(0) | ||
28 | #define VGA_RXF_STATUS 0x30 | ||
29 | #define VGA_RXF_COUNT_SHIFT 2 | ||
30 | #define VGA_RXF_COUNT_MASK GENMASK(7, 2) | ||
31 | #define VGA_AUTO_DETECT_PARA 0x34 | ||
32 | #define VGA_AUTO_DETECT_SEL 0x38 | ||
33 | #define VGA_DETECT_SEL_HAS_DEVICE BIT(1) | ||
34 | #define VGA_DETECT_SEL_NO_DEVICE BIT(0) | ||
35 | |||
36 | #endif /* __ZX_VGA_REGS_H__ */ | ||
diff --git a/drivers/gpu/drm/zte/zx_vou.c b/drivers/gpu/drm/zte/zx_vou.c index b500c8dd0d9d..5fbd10b60ee5 100644 --- a/drivers/gpu/drm/zte/zx_vou.c +++ b/drivers/gpu/drm/zte/zx_vou.c | |||
@@ -23,6 +23,7 @@ | |||
23 | #include <drm/drm_plane_helper.h> | 23 | #include <drm/drm_plane_helper.h> |
24 | #include <drm/drmP.h> | 24 | #include <drm/drmP.h> |
25 | 25 | ||
26 | #include "zx_common_regs.h" | ||
26 | #include "zx_drm_drv.h" | 27 | #include "zx_drm_drv.h" |
27 | #include "zx_plane.h" | 28 | #include "zx_plane.h" |
28 | #include "zx_vou.h" | 29 | #include "zx_vou.h" |
@@ -122,6 +123,8 @@ struct zx_crtc { | |||
122 | struct drm_plane *primary; | 123 | struct drm_plane *primary; |
123 | struct zx_vou_hw *vou; | 124 | struct zx_vou_hw *vou; |
124 | void __iomem *chnreg; | 125 | void __iomem *chnreg; |
126 | void __iomem *chncsc; | ||
127 | void __iomem *dither; | ||
125 | const struct zx_crtc_regs *regs; | 128 | const struct zx_crtc_regs *regs; |
126 | const struct zx_crtc_bits *bits; | 129 | const struct zx_crtc_bits *bits; |
127 | enum vou_chn_type chn_type; | 130 | enum vou_chn_type chn_type; |
@@ -204,6 +207,11 @@ static struct vou_inf vou_infs[] = { | |||
204 | .clocks_en_bits = BIT(15), | 207 | .clocks_en_bits = BIT(15), |
205 | .clocks_sel_bits = BIT(11) | BIT(0), | 208 | .clocks_sel_bits = BIT(11) | BIT(0), |
206 | }, | 209 | }, |
210 | [VOU_VGA] = { | ||
211 | .data_sel = VOU_RGB_888, | ||
212 | .clocks_en_bits = BIT(1), | ||
213 | .clocks_sel_bits = BIT(10), | ||
214 | }, | ||
207 | }; | 215 | }; |
208 | 216 | ||
209 | static inline struct zx_vou_hw *crtc_to_vou(struct drm_crtc *crtc) | 217 | static inline struct zx_vou_hw *crtc_to_vou(struct drm_crtc *crtc) |
@@ -227,9 +235,26 @@ void vou_inf_enable(enum vou_inf_id id, struct drm_crtc *crtc) | |||
227 | struct zx_crtc *zcrtc = to_zx_crtc(crtc); | 235 | struct zx_crtc *zcrtc = to_zx_crtc(crtc); |
228 | struct zx_vou_hw *vou = zcrtc->vou; | 236 | struct zx_vou_hw *vou = zcrtc->vou; |
229 | struct vou_inf *inf = &vou_infs[id]; | 237 | struct vou_inf *inf = &vou_infs[id]; |
238 | void __iomem *dither = zcrtc->dither; | ||
239 | void __iomem *csc = zcrtc->chncsc; | ||
230 | bool is_main = zcrtc->chn_type == VOU_CHN_MAIN; | 240 | bool is_main = zcrtc->chn_type == VOU_CHN_MAIN; |
231 | u32 data_sel_shift = id << 1; | 241 | u32 data_sel_shift = id << 1; |
232 | 242 | ||
243 | if (inf->data_sel != VOU_YUV444) { | ||
244 | /* Enable channel CSC for RGB output */ | ||
245 | zx_writel_mask(csc + CSC_CTRL0, CSC_COV_MODE_MASK, | ||
246 | CSC_BT709_IMAGE_YCBCR2RGB << CSC_COV_MODE_SHIFT); | ||
247 | zx_writel_mask(csc + CSC_CTRL0, CSC_WORK_ENABLE, | ||
248 | CSC_WORK_ENABLE); | ||
249 | |||
250 | /* Bypass Dither block for RGB output */ | ||
251 | zx_writel_mask(dither + OSD_DITHER_CTRL0, DITHER_BYSPASS, | ||
252 | DITHER_BYSPASS); | ||
253 | } else { | ||
254 | zx_writel_mask(csc + CSC_CTRL0, CSC_WORK_ENABLE, 0); | ||
255 | zx_writel_mask(dither + OSD_DITHER_CTRL0, DITHER_BYSPASS, 0); | ||
256 | } | ||
257 | |||
233 | /* Select data format */ | 258 | /* Select data format */ |
234 | zx_writel_mask(vou->vouctl + VOU_INF_DATA_SEL, 0x3 << data_sel_shift, | 259 | zx_writel_mask(vou->vouctl + VOU_INF_DATA_SEL, 0x3 << data_sel_shift, |
235 | inf->data_sel << data_sel_shift); | 260 | inf->data_sel << data_sel_shift); |
@@ -525,20 +550,24 @@ static int zx_crtc_init(struct drm_device *drm, struct zx_vou_hw *vou, | |||
525 | 550 | ||
526 | if (chn_type == VOU_CHN_MAIN) { | 551 | if (chn_type == VOU_CHN_MAIN) { |
527 | zplane->layer = vou->osd + MAIN_GL_OFFSET; | 552 | zplane->layer = vou->osd + MAIN_GL_OFFSET; |
528 | zplane->csc = vou->osd + MAIN_CSC_OFFSET; | 553 | zplane->csc = vou->osd + MAIN_GL_CSC_OFFSET; |
529 | zplane->hbsc = vou->osd + MAIN_HBSC_OFFSET; | 554 | zplane->hbsc = vou->osd + MAIN_HBSC_OFFSET; |
530 | zplane->rsz = vou->otfppu + MAIN_RSZ_OFFSET; | 555 | zplane->rsz = vou->otfppu + MAIN_RSZ_OFFSET; |
531 | zplane->bits = &zx_gl_bits[0]; | 556 | zplane->bits = &zx_gl_bits[0]; |
532 | zcrtc->chnreg = vou->osd + OSD_MAIN_CHN; | 557 | zcrtc->chnreg = vou->osd + OSD_MAIN_CHN; |
558 | zcrtc->chncsc = vou->osd + MAIN_CHN_CSC_OFFSET; | ||
559 | zcrtc->dither = vou->osd + MAIN_DITHER_OFFSET; | ||
533 | zcrtc->regs = &main_crtc_regs; | 560 | zcrtc->regs = &main_crtc_regs; |
534 | zcrtc->bits = &main_crtc_bits; | 561 | zcrtc->bits = &main_crtc_bits; |
535 | } else { | 562 | } else { |
536 | zplane->layer = vou->osd + AUX_GL_OFFSET; | 563 | zplane->layer = vou->osd + AUX_GL_OFFSET; |
537 | zplane->csc = vou->osd + AUX_CSC_OFFSET; | 564 | zplane->csc = vou->osd + AUX_GL_CSC_OFFSET; |
538 | zplane->hbsc = vou->osd + AUX_HBSC_OFFSET; | 565 | zplane->hbsc = vou->osd + AUX_HBSC_OFFSET; |
539 | zplane->rsz = vou->otfppu + AUX_RSZ_OFFSET; | 566 | zplane->rsz = vou->otfppu + AUX_RSZ_OFFSET; |
540 | zplane->bits = &zx_gl_bits[1]; | 567 | zplane->bits = &zx_gl_bits[1]; |
541 | zcrtc->chnreg = vou->osd + OSD_AUX_CHN; | 568 | zcrtc->chnreg = vou->osd + OSD_AUX_CHN; |
569 | zcrtc->chncsc = vou->osd + AUX_CHN_CSC_OFFSET; | ||
570 | zcrtc->dither = vou->osd + AUX_DITHER_OFFSET; | ||
542 | zcrtc->regs = &aux_crtc_regs; | 571 | zcrtc->regs = &aux_crtc_regs; |
543 | zcrtc->bits = &aux_crtc_bits; | 572 | zcrtc->bits = &aux_crtc_bits; |
544 | } | 573 | } |
@@ -705,9 +734,6 @@ static void vou_hw_init(struct zx_vou_hw *vou) | |||
705 | /* Release reset for all VOU modules */ | 734 | /* Release reset for all VOU modules */ |
706 | zx_writel(vou->vouctl + VOU_SOFT_RST, ~0); | 735 | zx_writel(vou->vouctl + VOU_SOFT_RST, ~0); |
707 | 736 | ||
708 | /* Enable clock auto-gating for all VOU modules */ | ||
709 | zx_writel(vou->vouctl + VOU_CLK_REQEN, ~0); | ||
710 | |||
711 | /* Enable all VOU module clocks */ | 737 | /* Enable all VOU module clocks */ |
712 | zx_writel(vou->vouctl + VOU_CLK_EN, ~0); | 738 | zx_writel(vou->vouctl + VOU_CLK_EN, ~0); |
713 | 739 | ||
diff --git a/drivers/gpu/drm/zte/zx_vou_regs.h b/drivers/gpu/drm/zte/zx_vou_regs.h index c066ef123434..5a218351b497 100644 --- a/drivers/gpu/drm/zte/zx_vou_regs.h +++ b/drivers/gpu/drm/zte/zx_vou_regs.h | |||
@@ -13,13 +13,17 @@ | |||
13 | 13 | ||
14 | /* Sub-module offset */ | 14 | /* Sub-module offset */ |
15 | #define MAIN_GL_OFFSET 0x130 | 15 | #define MAIN_GL_OFFSET 0x130 |
16 | #define MAIN_CSC_OFFSET 0x580 | 16 | #define MAIN_GL_CSC_OFFSET 0x580 |
17 | #define MAIN_CHN_CSC_OFFSET 0x6c0 | ||
17 | #define MAIN_HBSC_OFFSET 0x820 | 18 | #define MAIN_HBSC_OFFSET 0x820 |
19 | #define MAIN_DITHER_OFFSET 0x960 | ||
18 | #define MAIN_RSZ_OFFSET 0x600 /* OTFPPU sub-module */ | 20 | #define MAIN_RSZ_OFFSET 0x600 /* OTFPPU sub-module */ |
19 | 21 | ||
20 | #define AUX_GL_OFFSET 0x200 | 22 | #define AUX_GL_OFFSET 0x200 |
21 | #define AUX_CSC_OFFSET 0x5d0 | 23 | #define AUX_GL_CSC_OFFSET 0x5d0 |
24 | #define AUX_CHN_CSC_OFFSET 0x710 | ||
22 | #define AUX_HBSC_OFFSET 0x860 | 25 | #define AUX_HBSC_OFFSET 0x860 |
26 | #define AUX_DITHER_OFFSET 0x970 | ||
23 | #define AUX_RSZ_OFFSET 0x800 | 27 | #define AUX_RSZ_OFFSET 0x800 |
24 | 28 | ||
25 | #define OSD_VL0_OFFSET 0x040 | 29 | #define OSD_VL0_OFFSET 0x040 |
@@ -78,6 +82,10 @@ | |||
78 | #define CHN_INTERLACE_BUF_CTRL 0x24 | 82 | #define CHN_INTERLACE_BUF_CTRL 0x24 |
79 | #define CHN_INTERLACE_EN BIT(2) | 83 | #define CHN_INTERLACE_EN BIT(2) |
80 | 84 | ||
85 | /* Dither registers */ | ||
86 | #define OSD_DITHER_CTRL0 0x00 | ||
87 | #define DITHER_BYSPASS BIT(31) | ||
88 | |||
81 | /* TIMING_CTRL registers */ | 89 | /* TIMING_CTRL registers */ |
82 | #define TIMING_TC_ENABLE 0x04 | 90 | #define TIMING_TC_ENABLE 0x04 |
83 | #define AUX_TC_EN BIT(1) | 91 | #define AUX_TC_EN BIT(1) |
diff --git a/include/drm/drmP.h b/include/drm/drmP.h index e1daa4f343cd..52085832f711 100644 --- a/include/drm/drmP.h +++ b/include/drm/drmP.h | |||
@@ -320,15 +320,6 @@ struct pci_controller; | |||
320 | #define DRM_IF_VERSION(maj, min) (maj << 16 | min) | 320 | #define DRM_IF_VERSION(maj, min) (maj << 16 | min) |
321 | 321 | ||
322 | 322 | ||
323 | /* Flags and return codes for get_vblank_timestamp() driver function. */ | ||
324 | #define DRM_CALLED_FROM_VBLIRQ 1 | ||
325 | #define DRM_VBLANKTIME_SCANOUTPOS_METHOD (1 << 0) | ||
326 | |||
327 | /* get_scanout_position() return flags */ | ||
328 | #define DRM_SCANOUTPOS_VALID (1 << 0) | ||
329 | #define DRM_SCANOUTPOS_IN_VBLANK (1 << 1) | ||
330 | #define DRM_SCANOUTPOS_ACCURATE (1 << 2) | ||
331 | |||
332 | /** | 323 | /** |
333 | * DRM device structure. This structure represent a complete card that | 324 | * DRM device structure. This structure represent a complete card that |
334 | * may contain multiple heads. | 325 | * may contain multiple heads. |
diff --git a/include/drm/drm_atomic.h b/include/drm/drm_atomic.h index 788daf756f48..8645dcdef031 100644 --- a/include/drm/drm_atomic.h +++ b/include/drm/drm_atomic.h | |||
@@ -155,6 +155,53 @@ struct __drm_connnectors_state { | |||
155 | }; | 155 | }; |
156 | 156 | ||
157 | /** | 157 | /** |
158 | * struct drm_private_state_funcs - atomic state functions for private objects | ||
159 | * | ||
160 | * These hooks are used by atomic helpers to create, swap and destroy states of | ||
161 | * private objects. The structure itself is used as a vtable to identify the | ||
162 | * associated private object type. Each private object type that needs to be | ||
163 | * added to the atomic states is expected to have an implementation of these | ||
164 | * hooks and pass a pointer to it's drm_private_state_funcs struct to | ||
165 | * drm_atomic_get_private_obj_state(). | ||
166 | */ | ||
167 | struct drm_private_state_funcs { | ||
168 | /** | ||
169 | * @duplicate_state: | ||
170 | * | ||
171 | * Duplicate the current state of the private object and return it. It | ||
172 | * is an error to call this before obj->state has been initialized. | ||
173 | * | ||
174 | * RETURNS: | ||
175 | * | ||
176 | * Duplicated atomic state or NULL when obj->state is not | ||
177 | * initialized or allocation failed. | ||
178 | */ | ||
179 | void *(*duplicate_state)(struct drm_atomic_state *state, void *obj); | ||
180 | |||
181 | /** | ||
182 | * @swap_state: | ||
183 | * | ||
184 | * This function swaps the existing state of a private object @obj with | ||
185 | * it's newly created state, the pointer to which is passed as | ||
186 | * @obj_state_ptr. | ||
187 | */ | ||
188 | void (*swap_state)(void *obj, void **obj_state_ptr); | ||
189 | |||
190 | /** | ||
191 | * @destroy_state: | ||
192 | * | ||
193 | * Frees the private object state created with @duplicate_state. | ||
194 | */ | ||
195 | void (*destroy_state)(void *obj_state); | ||
196 | }; | ||
197 | |||
198 | struct __drm_private_objs_state { | ||
199 | void *obj; | ||
200 | void *obj_state; | ||
201 | const struct drm_private_state_funcs *funcs; | ||
202 | }; | ||
203 | |||
204 | /** | ||
158 | * struct drm_atomic_state - the global state object for atomic updates | 205 | * struct drm_atomic_state - the global state object for atomic updates |
159 | * @ref: count of all references to this state (will not be freed until zero) | 206 | * @ref: count of all references to this state (will not be freed until zero) |
160 | * @dev: parent DRM device | 207 | * @dev: parent DRM device |
@@ -164,6 +211,8 @@ struct __drm_connnectors_state { | |||
164 | * @crtcs: pointer to array of CRTC pointers | 211 | * @crtcs: pointer to array of CRTC pointers |
165 | * @num_connector: size of the @connectors and @connector_states arrays | 212 | * @num_connector: size of the @connectors and @connector_states arrays |
166 | * @connectors: pointer to array of structures with per-connector data | 213 | * @connectors: pointer to array of structures with per-connector data |
214 | * @num_private_objs: size of the @private_objs array | ||
215 | * @private_objs: pointer to array of private object pointers | ||
167 | * @acquire_ctx: acquire context for this atomic modeset state update | 216 | * @acquire_ctx: acquire context for this atomic modeset state update |
168 | */ | 217 | */ |
169 | struct drm_atomic_state { | 218 | struct drm_atomic_state { |
@@ -176,6 +225,8 @@ struct drm_atomic_state { | |||
176 | struct __drm_crtcs_state *crtcs; | 225 | struct __drm_crtcs_state *crtcs; |
177 | int num_connector; | 226 | int num_connector; |
178 | struct __drm_connnectors_state *connectors; | 227 | struct __drm_connnectors_state *connectors; |
228 | int num_private_objs; | ||
229 | struct __drm_private_objs_state *private_objs; | ||
179 | 230 | ||
180 | struct drm_modeset_acquire_ctx *acquire_ctx; | 231 | struct drm_modeset_acquire_ctx *acquire_ctx; |
181 | 232 | ||
@@ -268,6 +319,11 @@ int drm_atomic_connector_set_property(struct drm_connector *connector, | |||
268 | struct drm_connector_state *state, struct drm_property *property, | 319 | struct drm_connector_state *state, struct drm_property *property, |
269 | uint64_t val); | 320 | uint64_t val); |
270 | 321 | ||
322 | void * __must_check | ||
323 | drm_atomic_get_private_obj_state(struct drm_atomic_state *state, | ||
324 | void *obj, | ||
325 | const struct drm_private_state_funcs *funcs); | ||
326 | |||
271 | /** | 327 | /** |
272 | * drm_atomic_get_existing_crtc_state - get crtc state, if it exists | 328 | * drm_atomic_get_existing_crtc_state - get crtc state, if it exists |
273 | * @state: global atomic state object | 329 | * @state: global atomic state object |
@@ -753,6 +809,45 @@ void drm_state_dump(struct drm_device *dev, struct drm_printer *p); | |||
753 | for_each_if (plane) | 809 | for_each_if (plane) |
754 | 810 | ||
755 | /** | 811 | /** |
812 | * __for_each_private_obj - iterate over all private objects | ||
813 | * @__state: &struct drm_atomic_state pointer | ||
814 | * @obj: private object iteration cursor | ||
815 | * @obj_state: private object state iteration cursor | ||
816 | * @__i: int iteration cursor, for macro-internal use | ||
817 | * @__funcs: &struct drm_private_state_funcs iteration cursor | ||
818 | * | ||
819 | * This macro iterates over the array containing private object data in atomic | ||
820 | * state | ||
821 | */ | ||
822 | #define __for_each_private_obj(__state, obj, obj_state, __i, __funcs) \ | ||
823 | for ((__i) = 0; \ | ||
824 | (__i) < (__state)->num_private_objs && \ | ||
825 | ((obj) = (__state)->private_objs[__i].obj, \ | ||
826 | (__funcs) = (__state)->private_objs[__i].funcs, \ | ||
827 | (obj_state) = (__state)->private_objs[__i].obj_state, \ | ||
828 | 1); \ | ||
829 | (__i)++) \ | ||
830 | |||
831 | /** | ||
832 | * for_each_private_obj - iterate over a specify type of private object | ||
833 | * @__state: &struct drm_atomic_state pointer | ||
834 | * @obj_funcs: &struct drm_private_state_funcs function table to filter | ||
835 | * private objects | ||
836 | * @obj: private object iteration cursor | ||
837 | * @obj_state: private object state iteration cursor | ||
838 | * @__i: int iteration cursor, for macro-internal use | ||
839 | * @__funcs: &struct drm_private_state_funcs iteration cursor | ||
840 | * | ||
841 | * This macro iterates over the private objects state array while filtering the | ||
842 | * objects based on the vfunc table that is passed as @obj_funcs. New macros | ||
843 | * can be created by passing in the vfunc table associated with a specific | ||
844 | * private object. | ||
845 | */ | ||
846 | #define for_each_private_obj(__state, obj_funcs, obj, obj_state, __i, __funcs) \ | ||
847 | __for_each_private_obj(__state, obj, obj_state, __i, __funcs) \ | ||
848 | for_each_if (__funcs == obj_funcs) | ||
849 | |||
850 | /** | ||
756 | * drm_atomic_crtc_needs_modeset - compute combined modeset need | 851 | * drm_atomic_crtc_needs_modeset - compute combined modeset need |
757 | * @state: &drm_crtc_state for the CRTC | 852 | * @state: &drm_crtc_state for the CRTC |
758 | * | 853 | * |
diff --git a/include/drm/drm_blend.h b/include/drm/drm_blend.h index 13221cf9b3eb..bc9e596be4c2 100644 --- a/include/drm/drm_blend.h +++ b/include/drm/drm_blend.h | |||
@@ -28,6 +28,7 @@ | |||
28 | 28 | ||
29 | struct drm_device; | 29 | struct drm_device; |
30 | struct drm_atomic_state; | 30 | struct drm_atomic_state; |
31 | struct drm_plane; | ||
31 | 32 | ||
32 | /* | 33 | /* |
33 | * Rotation property bits. DRM_ROTATE_<degrees> rotates the image by the | 34 | * Rotation property bits. DRM_ROTATE_<degrees> rotates the image by the |
diff --git a/include/drm/drm_color_mgmt.h b/include/drm/drm_color_mgmt.h index bce4a532836d..03a59cbce621 100644 --- a/include/drm/drm_color_mgmt.h +++ b/include/drm/drm_color_mgmt.h | |||
@@ -25,6 +25,8 @@ | |||
25 | 25 | ||
26 | #include <linux/ctype.h> | 26 | #include <linux/ctype.h> |
27 | 27 | ||
28 | struct drm_crtc; | ||
29 | |||
28 | uint32_t drm_color_lut_extract(uint32_t user_input, uint32_t bit_precision); | 30 | uint32_t drm_color_lut_extract(uint32_t user_input, uint32_t bit_precision); |
29 | 31 | ||
30 | void drm_crtc_enable_color_mgmt(struct drm_crtc *crtc, | 32 | void drm_crtc_enable_color_mgmt(struct drm_crtc *crtc, |
diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h index 4eeda120e46d..9c15993b9071 100644 --- a/include/drm/drm_connector.h +++ b/include/drm/drm_connector.h | |||
@@ -25,6 +25,7 @@ | |||
25 | 25 | ||
26 | #include <linux/list.h> | 26 | #include <linux/list.h> |
27 | #include <linux/ctype.h> | 27 | #include <linux/ctype.h> |
28 | #include <linux/hdmi.h> | ||
28 | #include <drm/drm_mode_object.h> | 29 | #include <drm/drm_mode_object.h> |
29 | 30 | ||
30 | #include <uapi/drm/drm_mode.h> | 31 | #include <uapi/drm/drm_mode.h> |
@@ -326,6 +327,21 @@ struct drm_connector_state { | |||
326 | struct drm_atomic_state *state; | 327 | struct drm_atomic_state *state; |
327 | 328 | ||
328 | struct drm_tv_connector_state tv; | 329 | struct drm_tv_connector_state tv; |
330 | |||
331 | /** | ||
332 | * @picture_aspect_ratio: Connector property to control the | ||
333 | * HDMI infoframe aspect ratio setting. | ||
334 | * | ||
335 | * The %DRM_MODE_PICTURE_ASPECT_\* values much match the | ||
336 | * values for &enum hdmi_picture_aspect | ||
337 | */ | ||
338 | enum hdmi_picture_aspect picture_aspect_ratio; | ||
339 | |||
340 | /** | ||
341 | * @scaling_mode: Connector property to control the | ||
342 | * upscaling, mostly used for built-in panels. | ||
343 | */ | ||
344 | unsigned int scaling_mode; | ||
329 | }; | 345 | }; |
330 | 346 | ||
331 | /** | 347 | /** |
@@ -675,6 +691,7 @@ struct drm_cmdline_mode { | |||
675 | * @tile_v_loc: vertical location of this tile | 691 | * @tile_v_loc: vertical location of this tile |
676 | * @tile_h_size: horizontal size of this tile. | 692 | * @tile_h_size: horizontal size of this tile. |
677 | * @tile_v_size: vertical size of this tile. | 693 | * @tile_v_size: vertical size of this tile. |
694 | * @scaling_mode_property: Optional atomic property to control the upscaling. | ||
678 | * | 695 | * |
679 | * Each connector may be connected to one or more CRTCs, or may be clonable by | 696 | * Each connector may be connected to one or more CRTCs, or may be clonable by |
680 | * another connector if they can share a CRTC. Each connector also has a specific | 697 | * another connector if they can share a CRTC. Each connector also has a specific |
@@ -754,6 +771,8 @@ struct drm_connector { | |||
754 | struct drm_property_blob *edid_blob_ptr; | 771 | struct drm_property_blob *edid_blob_ptr; |
755 | struct drm_object_properties properties; | 772 | struct drm_object_properties properties; |
756 | 773 | ||
774 | struct drm_property *scaling_mode_property; | ||
775 | |||
757 | /** | 776 | /** |
758 | * @path_blob_ptr: | 777 | * @path_blob_ptr: |
759 | * | 778 | * |
@@ -953,6 +972,8 @@ int drm_mode_create_tv_properties(struct drm_device *dev, | |||
953 | unsigned int num_modes, | 972 | unsigned int num_modes, |
954 | const char * const modes[]); | 973 | const char * const modes[]); |
955 | int drm_mode_create_scaling_mode_property(struct drm_device *dev); | 974 | int drm_mode_create_scaling_mode_property(struct drm_device *dev); |
975 | int drm_connector_attach_scaling_mode_property(struct drm_connector *connector, | ||
976 | u32 scaling_mode_mask); | ||
956 | int drm_mode_create_aspect_ratio_property(struct drm_device *dev); | 977 | int drm_mode_create_aspect_ratio_property(struct drm_device *dev); |
957 | int drm_mode_create_suggested_offset_properties(struct drm_device *dev); | 978 | int drm_mode_create_suggested_offset_properties(struct drm_device *dev); |
958 | 979 | ||
diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h index a8176a836e25..adf4e91a9399 100644 --- a/include/drm/drm_crtc.h +++ b/include/drm/drm_crtc.h | |||
@@ -93,11 +93,6 @@ struct drm_plane_helper_funcs; | |||
93 | * @adjusted_mode: for use by helpers and drivers to compute adjusted mode timings | 93 | * @adjusted_mode: for use by helpers and drivers to compute adjusted mode timings |
94 | * @mode: current mode timings | 94 | * @mode: current mode timings |
95 | * @mode_blob: &drm_property_blob for @mode | 95 | * @mode_blob: &drm_property_blob for @mode |
96 | * @degamma_lut: Lookup table for converting framebuffer pixel data | ||
97 | * before apply the conversion matrix | ||
98 | * @ctm: Transformation matrix | ||
99 | * @gamma_lut: Lookup table for converting pixel data after the | ||
100 | * conversion matrix | ||
101 | * @state: backpointer to global drm_atomic_state | 96 | * @state: backpointer to global drm_atomic_state |
102 | * | 97 | * |
103 | * Note that the distinction between @enable and @active is rather subtile: | 98 | * Note that the distinction between @enable and @active is rather subtile: |
@@ -144,9 +139,30 @@ struct drm_crtc_state { | |||
144 | /* blob property to expose current mode to atomic userspace */ | 139 | /* blob property to expose current mode to atomic userspace */ |
145 | struct drm_property_blob *mode_blob; | 140 | struct drm_property_blob *mode_blob; |
146 | 141 | ||
147 | /* blob property to expose color management to userspace */ | 142 | /** |
143 | * @degamma_lut: | ||
144 | * | ||
145 | * Lookup table for converting framebuffer pixel data before apply the | ||
146 | * color conversion matrix @ctm. See drm_crtc_enable_color_mgmt(). The | ||
147 | * blob (if not NULL) is an array of &struct drm_color_lut. | ||
148 | */ | ||
148 | struct drm_property_blob *degamma_lut; | 149 | struct drm_property_blob *degamma_lut; |
150 | |||
151 | /** | ||
152 | * @ctm: | ||
153 | * | ||
154 | * Color transformation matrix. See drm_crtc_enable_color_mgmt(). The | ||
155 | * blob (if not NULL) is a &struct drm_color_ctm. | ||
156 | */ | ||
149 | struct drm_property_blob *ctm; | 157 | struct drm_property_blob *ctm; |
158 | |||
159 | /** | ||
160 | * @gamma_lut: | ||
161 | * | ||
162 | * Lookup table for converting pixel data after the color conversion | ||
163 | * matrix @ctm. See drm_crtc_enable_color_mgmt(). The blob (if not | ||
164 | * NULL) is an array of &struct drm_color_lut. | ||
165 | */ | ||
150 | struct drm_property_blob *gamma_lut; | 166 | struct drm_property_blob *gamma_lut; |
151 | 167 | ||
152 | /** | 168 | /** |
@@ -313,6 +329,12 @@ struct drm_crtc_funcs { | |||
313 | * | 329 | * |
314 | * This callback is optional. | 330 | * This callback is optional. |
315 | * | 331 | * |
332 | * Atomic drivers who want to support gamma tables should implement the | ||
333 | * atomic color management support, enabled by calling | ||
334 | * drm_crtc_enable_color_mgmt(), which then supports the legacy gamma | ||
335 | * interface through the drm_atomic_helper_legacy_gamma_set() | ||
336 | * compatibility implementation. | ||
337 | * | ||
316 | * NOTE: | 338 | * NOTE: |
317 | * | 339 | * |
318 | * Drivers that support gamma tables and also fbdev emulation through | 340 | * Drivers that support gamma tables and also fbdev emulation through |
diff --git a/include/drm/drm_dp_helper.h b/include/drm/drm_dp_helper.h index c0bd0d7651a9..f7007e544f29 100644 --- a/include/drm/drm_dp_helper.h +++ b/include/drm/drm_dp_helper.h | |||
@@ -179,6 +179,111 @@ | |||
179 | 179 | ||
180 | #define DP_GUID 0x030 /* 1.2 */ | 180 | #define DP_GUID 0x030 /* 1.2 */ |
181 | 181 | ||
182 | #define DP_DSC_SUPPORT 0x060 /* DP 1.4 */ | ||
183 | # define DP_DSC_DECOMPRESSION_IS_SUPPORTED (1 << 0) | ||
184 | |||
185 | #define DP_DSC_REV 0x061 | ||
186 | # define DP_DSC_MAJOR_MASK (0xf << 0) | ||
187 | # define DP_DSC_MINOR_MASK (0xf << 4) | ||
188 | # define DP_DSC_MAJOR_SHIFT 0 | ||
189 | # define DP_DSC_MINOR_SHIFT 4 | ||
190 | |||
191 | #define DP_DSC_RC_BUF_BLK_SIZE 0x062 | ||
192 | # define DP_DSC_RC_BUF_BLK_SIZE_1 0x0 | ||
193 | # define DP_DSC_RC_BUF_BLK_SIZE_4 0x1 | ||
194 | # define DP_DSC_RC_BUF_BLK_SIZE_16 0x2 | ||
195 | # define DP_DSC_RC_BUF_BLK_SIZE_64 0x3 | ||
196 | |||
197 | #define DP_DSC_RC_BUF_SIZE 0x063 | ||
198 | |||
199 | #define DP_DSC_SLICE_CAP_1 0x064 | ||
200 | # define DP_DSC_1_PER_DP_DSC_SINK (1 << 0) | ||
201 | # define DP_DSC_2_PER_DP_DSC_SINK (1 << 1) | ||
202 | # define DP_DSC_4_PER_DP_DSC_SINK (1 << 3) | ||
203 | # define DP_DSC_6_PER_DP_DSC_SINK (1 << 4) | ||
204 | # define DP_DSC_8_PER_DP_DSC_SINK (1 << 5) | ||
205 | # define DP_DSC_10_PER_DP_DSC_SINK (1 << 6) | ||
206 | # define DP_DSC_12_PER_DP_DSC_SINK (1 << 7) | ||
207 | |||
208 | #define DP_DSC_LINE_BUF_BIT_DEPTH 0x065 | ||
209 | # define DP_DSC_LINE_BUF_BIT_DEPTH_MASK (0xf << 0) | ||
210 | # define DP_DSC_LINE_BUF_BIT_DEPTH_9 0x0 | ||
211 | # define DP_DSC_LINE_BUF_BIT_DEPTH_10 0x1 | ||
212 | # define DP_DSC_LINE_BUF_BIT_DEPTH_11 0x2 | ||
213 | # define DP_DSC_LINE_BUF_BIT_DEPTH_12 0x3 | ||
214 | # define DP_DSC_LINE_BUF_BIT_DEPTH_13 0x4 | ||
215 | # define DP_DSC_LINE_BUF_BIT_DEPTH_14 0x5 | ||
216 | # define DP_DSC_LINE_BUF_BIT_DEPTH_15 0x6 | ||
217 | # define DP_DSC_LINE_BUF_BIT_DEPTH_16 0x7 | ||
218 | # define DP_DSC_LINE_BUF_BIT_DEPTH_8 0x8 | ||
219 | |||
220 | #define DP_DSC_BLK_PREDICTION_SUPPORT 0x066 | ||
221 | # define DP_DSC_BLK_PREDICTION_IS_SUPPORTED (1 << 0) | ||
222 | |||
223 | #define DP_DSC_MAX_BITS_PER_PIXEL_LOW 0x067 /* eDP 1.4 */ | ||
224 | |||
225 | #define DP_DSC_MAX_BITS_PER_PIXEL_HI 0x068 /* eDP 1.4 */ | ||
226 | |||
227 | #define DP_DSC_DEC_COLOR_FORMAT_CAP 0x069 | ||
228 | # define DP_DSC_RGB (1 << 0) | ||
229 | # define DP_DSC_YCbCr444 (1 << 1) | ||
230 | # define DP_DSC_YCbCr422_Simple (1 << 2) | ||
231 | # define DP_DSC_YCbCr422_Native (1 << 3) | ||
232 | # define DP_DSC_YCbCr420_Native (1 << 4) | ||
233 | |||
234 | #define DP_DSC_DEC_COLOR_DEPTH_CAP 0x06A | ||
235 | # define DP_DSC_8_BPC (1 << 1) | ||
236 | # define DP_DSC_10_BPC (1 << 2) | ||
237 | # define DP_DSC_12_BPC (1 << 3) | ||
238 | |||
239 | #define DP_DSC_PEAK_THROUGHPUT 0x06B | ||
240 | # define DP_DSC_THROUGHPUT_MODE_0_MASK (0xf << 0) | ||
241 | # define DP_DSC_THROUGHPUT_MODE_0_SHIFT 0 | ||
242 | # define DP_DSC_THROUGHPUT_MODE_0_340 (1 << 0) | ||
243 | # define DP_DSC_THROUGHPUT_MODE_0_400 (2 << 0) | ||
244 | # define DP_DSC_THROUGHPUT_MODE_0_450 (3 << 0) | ||
245 | # define DP_DSC_THROUGHPUT_MODE_0_500 (4 << 0) | ||
246 | # define DP_DSC_THROUGHPUT_MODE_0_550 (5 << 0) | ||
247 | # define DP_DSC_THROUGHPUT_MODE_0_600 (6 << 0) | ||
248 | # define DP_DSC_THROUGHPUT_MODE_0_650 (7 << 0) | ||
249 | # define DP_DSC_THROUGHPUT_MODE_0_700 (8 << 0) | ||
250 | # define DP_DSC_THROUGHPUT_MODE_0_750 (9 << 0) | ||
251 | # define DP_DSC_THROUGHPUT_MODE_0_800 (10 << 0) | ||
252 | # define DP_DSC_THROUGHPUT_MODE_0_850 (11 << 0) | ||
253 | # define DP_DSC_THROUGHPUT_MODE_0_900 (12 << 0) | ||
254 | # define DP_DSC_THROUGHPUT_MODE_0_950 (13 << 0) | ||
255 | # define DP_DSC_THROUGHPUT_MODE_0_1000 (14 << 0) | ||
256 | # define DP_DSC_THROUGHPUT_MODE_1_MASK (0xf << 4) | ||
257 | # define DP_DSC_THROUGHPUT_MODE_1_SHIFT 4 | ||
258 | # define DP_DSC_THROUGHPUT_MODE_1_340 (1 << 4) | ||
259 | # define DP_DSC_THROUGHPUT_MODE_1_400 (2 << 4) | ||
260 | # define DP_DSC_THROUGHPUT_MODE_1_450 (3 << 4) | ||
261 | # define DP_DSC_THROUGHPUT_MODE_1_500 (4 << 4) | ||
262 | # define DP_DSC_THROUGHPUT_MODE_1_550 (5 << 4) | ||
263 | # define DP_DSC_THROUGHPUT_MODE_1_600 (6 << 4) | ||
264 | # define DP_DSC_THROUGHPUT_MODE_1_650 (7 << 4) | ||
265 | # define DP_DSC_THROUGHPUT_MODE_1_700 (8 << 4) | ||
266 | # define DP_DSC_THROUGHPUT_MODE_1_750 (9 << 4) | ||
267 | # define DP_DSC_THROUGHPUT_MODE_1_800 (10 << 4) | ||
268 | # define DP_DSC_THROUGHPUT_MODE_1_850 (11 << 4) | ||
269 | # define DP_DSC_THROUGHPUT_MODE_1_900 (12 << 4) | ||
270 | # define DP_DSC_THROUGHPUT_MODE_1_950 (13 << 4) | ||
271 | # define DP_DSC_THROUGHPUT_MODE_1_1000 (14 << 4) | ||
272 | |||
273 | #define DP_DSC_MAX_SLICE_WIDTH 0x06C | ||
274 | |||
275 | #define DP_DSC_SLICE_CAP_2 0x06D | ||
276 | # define DP_DSC_16_PER_DP_DSC_SINK (1 << 0) | ||
277 | # define DP_DSC_20_PER_DP_DSC_SINK (1 << 1) | ||
278 | # define DP_DSC_24_PER_DP_DSC_SINK (1 << 2) | ||
279 | |||
280 | #define DP_DSC_BITS_PER_PIXEL_INC 0x06F | ||
281 | # define DP_DSC_BITS_PER_PIXEL_1_16 0x0 | ||
282 | # define DP_DSC_BITS_PER_PIXEL_1_8 0x1 | ||
283 | # define DP_DSC_BITS_PER_PIXEL_1_4 0x2 | ||
284 | # define DP_DSC_BITS_PER_PIXEL_1_2 0x3 | ||
285 | # define DP_DSC_BITS_PER_PIXEL_1 0x4 | ||
286 | |||
182 | #define DP_PSR_SUPPORT 0x070 /* XXX 1.2? */ | 287 | #define DP_PSR_SUPPORT 0x070 /* XXX 1.2? */ |
183 | # define DP_PSR_IS_SUPPORTED 1 | 288 | # define DP_PSR_IS_SUPPORTED 1 |
184 | # define DP_PSR2_IS_SUPPORTED 2 /* eDP 1.4 */ | 289 | # define DP_PSR2_IS_SUPPORTED 2 /* eDP 1.4 */ |
@@ -339,6 +444,8 @@ | |||
339 | #define DP_AUX_FRAME_SYNC_VALUE 0x15c /* eDP 1.4 */ | 444 | #define DP_AUX_FRAME_SYNC_VALUE 0x15c /* eDP 1.4 */ |
340 | # define DP_AUX_FRAME_SYNC_VALID (1 << 0) | 445 | # define DP_AUX_FRAME_SYNC_VALID (1 << 0) |
341 | 446 | ||
447 | #define DP_DSC_ENABLE 0x160 /* DP 1.4 */ | ||
448 | |||
342 | #define DP_PSR_EN_CFG 0x170 /* XXX 1.2? */ | 449 | #define DP_PSR_EN_CFG 0x170 /* XXX 1.2? */ |
343 | # define DP_PSR_ENABLE (1 << 0) | 450 | # define DP_PSR_ENABLE (1 << 0) |
344 | # define DP_PSR_MAIN_LINK_ACTIVE (1 << 1) | 451 | # define DP_PSR_MAIN_LINK_ACTIVE (1 << 1) |
@@ -603,6 +710,9 @@ | |||
603 | #define DP_DEVICE_SERVICE_IRQ_VECTOR_ESI0 0x2003 /* 1.2 */ | 710 | #define DP_DEVICE_SERVICE_IRQ_VECTOR_ESI0 0x2003 /* 1.2 */ |
604 | 711 | ||
605 | #define DP_DEVICE_SERVICE_IRQ_VECTOR_ESI1 0x2004 /* 1.2 */ | 712 | #define DP_DEVICE_SERVICE_IRQ_VECTOR_ESI1 0x2004 /* 1.2 */ |
713 | # define DP_RX_GTC_MSTR_REQ_STATUS_CHANGE (1 << 0) | ||
714 | # define DP_LOCK_ACQUISITION_REQUEST (1 << 1) | ||
715 | # define DP_CEC_IRQ (1 << 2) | ||
606 | 716 | ||
607 | #define DP_LINK_SERVICE_IRQ_VECTOR_ESI0 0x2005 /* 1.2 */ | 717 | #define DP_LINK_SERVICE_IRQ_VECTOR_ESI0 0x2005 /* 1.2 */ |
608 | 718 | ||
@@ -636,6 +746,62 @@ | |||
636 | # define DP_VSC_EXT_CEA_SDP_SUPPORTED (1 << 6) /* DP 1.4 */ | 746 | # define DP_VSC_EXT_CEA_SDP_SUPPORTED (1 << 6) /* DP 1.4 */ |
637 | # define DP_VSC_EXT_CEA_SDP_CHAINING_SUPPORTED (1 << 7) /* DP 1.4 */ | 747 | # define DP_VSC_EXT_CEA_SDP_CHAINING_SUPPORTED (1 << 7) /* DP 1.4 */ |
638 | 748 | ||
749 | /* HDMI CEC tunneling over AUX DP 1.3 section 5.3.3.3.1 DPCD 1.4+ */ | ||
750 | #define DP_CEC_TUNNELING_CAPABILITY 0x3000 | ||
751 | # define DP_CEC_TUNNELING_CAPABLE (1 << 0) | ||
752 | # define DP_CEC_SNOOPING_CAPABLE (1 << 1) | ||
753 | # define DP_CEC_MULTIPLE_LA_CAPABLE (1 << 2) | ||
754 | |||
755 | #define DP_CEC_TUNNELING_CONTROL 0x3001 | ||
756 | # define DP_CEC_TUNNELING_ENABLE (1 << 0) | ||
757 | # define DP_CEC_SNOOPING_ENABLE (1 << 1) | ||
758 | |||
759 | #define DP_CEC_RX_MESSAGE_INFO 0x3002 | ||
760 | # define DP_CEC_RX_MESSAGE_LEN_MASK (0xf << 0) | ||
761 | # define DP_CEC_RX_MESSAGE_LEN_SHIFT 0 | ||
762 | # define DP_CEC_RX_MESSAGE_HPD_STATE (1 << 4) | ||
763 | # define DP_CEC_RX_MESSAGE_HPD_LOST (1 << 5) | ||
764 | # define DP_CEC_RX_MESSAGE_ACKED (1 << 6) | ||
765 | # define DP_CEC_RX_MESSAGE_ENDED (1 << 7) | ||
766 | |||
767 | #define DP_CEC_TX_MESSAGE_INFO 0x3003 | ||
768 | # define DP_CEC_TX_MESSAGE_LEN_MASK (0xf << 0) | ||
769 | # define DP_CEC_TX_MESSAGE_LEN_SHIFT 0 | ||
770 | # define DP_CEC_TX_RETRY_COUNT_MASK (0x7 << 4) | ||
771 | # define DP_CEC_TX_RETRY_COUNT_SHIFT 4 | ||
772 | # define DP_CEC_TX_MESSAGE_SEND (1 << 7) | ||
773 | |||
774 | #define DP_CEC_TUNNELING_IRQ_FLAGS 0x3004 | ||
775 | # define DP_CEC_RX_MESSAGE_INFO_VALID (1 << 0) | ||
776 | # define DP_CEC_RX_MESSAGE_OVERFLOW (1 << 1) | ||
777 | # define DP_CEC_TX_MESSAGE_SENT (1 << 4) | ||
778 | # define DP_CEC_TX_LINE_ERROR (1 << 5) | ||
779 | # define DP_CEC_TX_ADDRESS_NACK_ERROR (1 << 6) | ||
780 | # define DP_CEC_TX_DATA_NACK_ERROR (1 << 7) | ||
781 | |||
782 | #define DP_CEC_LOGICAL_ADDRESS_MASK 0x300E /* 0x300F word */ | ||
783 | # define DP_CEC_LOGICAL_ADDRESS_0 (1 << 0) | ||
784 | # define DP_CEC_LOGICAL_ADDRESS_1 (1 << 1) | ||
785 | # define DP_CEC_LOGICAL_ADDRESS_2 (1 << 2) | ||
786 | # define DP_CEC_LOGICAL_ADDRESS_3 (1 << 3) | ||
787 | # define DP_CEC_LOGICAL_ADDRESS_4 (1 << 4) | ||
788 | # define DP_CEC_LOGICAL_ADDRESS_5 (1 << 5) | ||
789 | # define DP_CEC_LOGICAL_ADDRESS_6 (1 << 6) | ||
790 | # define DP_CEC_LOGICAL_ADDRESS_7 (1 << 7) | ||
791 | #define DP_CEC_LOGICAL_ADDRESS_MASK_2 0x300F /* 0x300E word */ | ||
792 | # define DP_CEC_LOGICAL_ADDRESS_8 (1 << 0) | ||
793 | # define DP_CEC_LOGICAL_ADDRESS_9 (1 << 1) | ||
794 | # define DP_CEC_LOGICAL_ADDRESS_10 (1 << 2) | ||
795 | # define DP_CEC_LOGICAL_ADDRESS_11 (1 << 3) | ||
796 | # define DP_CEC_LOGICAL_ADDRESS_12 (1 << 4) | ||
797 | # define DP_CEC_LOGICAL_ADDRESS_13 (1 << 5) | ||
798 | # define DP_CEC_LOGICAL_ADDRESS_14 (1 << 6) | ||
799 | # define DP_CEC_LOGICAL_ADDRESS_15 (1 << 7) | ||
800 | |||
801 | #define DP_CEC_RX_MESSAGE_BUFFER 0x3010 | ||
802 | #define DP_CEC_TX_MESSAGE_BUFFER 0x3020 | ||
803 | #define DP_CEC_MESSAGE_BUFFER_LENGTH 0x10 | ||
804 | |||
639 | /* DP 1.2 Sideband message defines */ | 805 | /* DP 1.2 Sideband message defines */ |
640 | /* peer device type - DP 1.2a Table 2-92 */ | 806 | /* peer device type - DP 1.2a Table 2-92 */ |
641 | #define DP_PEER_DEVICE_NONE 0x0 | 807 | #define DP_PEER_DEVICE_NONE 0x0 |
diff --git a/include/drm/drm_dp_mst_helper.h b/include/drm/drm_dp_mst_helper.h index 5b024764666c..177ab6f86855 100644 --- a/include/drm/drm_dp_mst_helper.h +++ b/include/drm/drm_dp_mst_helper.h | |||
@@ -24,6 +24,7 @@ | |||
24 | 24 | ||
25 | #include <linux/types.h> | 25 | #include <linux/types.h> |
26 | #include <drm/drm_dp_helper.h> | 26 | #include <drm/drm_dp_helper.h> |
27 | #include <drm/drm_atomic.h> | ||
27 | 28 | ||
28 | struct drm_dp_mst_branch; | 29 | struct drm_dp_mst_branch; |
29 | 30 | ||
@@ -403,6 +404,12 @@ struct drm_dp_payload { | |||
403 | int vcpi; | 404 | int vcpi; |
404 | }; | 405 | }; |
405 | 406 | ||
407 | struct drm_dp_mst_topology_state { | ||
408 | int avail_slots; | ||
409 | struct drm_atomic_state *state; | ||
410 | struct drm_dp_mst_topology_mgr *mgr; | ||
411 | }; | ||
412 | |||
406 | /** | 413 | /** |
407 | * struct drm_dp_mst_topology_mgr - DisplayPort MST manager | 414 | * struct drm_dp_mst_topology_mgr - DisplayPort MST manager |
408 | * | 415 | * |
@@ -481,6 +488,16 @@ struct drm_dp_mst_topology_mgr { | |||
481 | int pbn_div; | 488 | int pbn_div; |
482 | 489 | ||
483 | /** | 490 | /** |
491 | * @state: State information for topology manager | ||
492 | */ | ||
493 | struct drm_dp_mst_topology_state *state; | ||
494 | |||
495 | /** | ||
496 | * @funcs: Atomic helper callbacks | ||
497 | */ | ||
498 | const struct drm_private_state_funcs *funcs; | ||
499 | |||
500 | /** | ||
484 | * @qlock: protects @tx_msg_downq, the &drm_dp_mst_branch.txslost and | 501 | * @qlock: protects @tx_msg_downq, the &drm_dp_mst_branch.txslost and |
485 | * &drm_dp_sideband_msg_tx.state once they are queued | 502 | * &drm_dp_sideband_msg_tx.state once they are queued |
486 | */ | 503 | */ |
@@ -596,4 +613,13 @@ void drm_dp_mst_dump_topology(struct seq_file *m, | |||
596 | 613 | ||
597 | void drm_dp_mst_topology_mgr_suspend(struct drm_dp_mst_topology_mgr *mgr); | 614 | void drm_dp_mst_topology_mgr_suspend(struct drm_dp_mst_topology_mgr *mgr); |
598 | int drm_dp_mst_topology_mgr_resume(struct drm_dp_mst_topology_mgr *mgr); | 615 | int drm_dp_mst_topology_mgr_resume(struct drm_dp_mst_topology_mgr *mgr); |
616 | struct drm_dp_mst_topology_state *drm_atomic_get_mst_topology_state(struct drm_atomic_state *state, | ||
617 | struct drm_dp_mst_topology_mgr *mgr); | ||
618 | int drm_dp_atomic_find_vcpi_slots(struct drm_atomic_state *state, | ||
619 | struct drm_dp_mst_topology_mgr *mgr, | ||
620 | struct drm_dp_mst_port *port, int pbn); | ||
621 | int drm_dp_atomic_release_vcpi_slots(struct drm_atomic_state *state, | ||
622 | struct drm_dp_mst_topology_mgr *mgr, | ||
623 | int slots); | ||
624 | |||
599 | #endif | 625 | #endif |
diff --git a/include/drm/drm_drv.h b/include/drm/drm_drv.h index 53b98321df9b..e64e33b9dd26 100644 --- a/include/drm/drm_drv.h +++ b/include/drm/drm_drv.h | |||
@@ -104,23 +104,6 @@ struct drm_driver { | |||
104 | int (*open) (struct drm_device *, struct drm_file *); | 104 | int (*open) (struct drm_device *, struct drm_file *); |
105 | 105 | ||
106 | /** | 106 | /** |
107 | * @preclose: | ||
108 | * | ||
109 | * One of the driver callbacks when a new &struct drm_file is closed. | ||
110 | * Useful for tearing down driver-private data structures allocated in | ||
111 | * @open like buffer allocators, execution contexts or similar things. | ||
112 | * | ||
113 | * Since the display/modeset side of DRM can only be owned by exactly | ||
114 | * one &struct drm_file (see &drm_file.is_master and &drm_device.master) | ||
115 | * there should never be a need to tear down any modeset related | ||
116 | * resources in this callback. Doing so would be a driver design bug. | ||
117 | * | ||
118 | * FIXME: It is not really clear why there's both @preclose and | ||
119 | * @postclose. Without a really good reason, use @postclose only. | ||
120 | */ | ||
121 | void (*preclose) (struct drm_device *, struct drm_file *file_priv); | ||
122 | |||
123 | /** | ||
124 | * @postclose: | 107 | * @postclose: |
125 | * | 108 | * |
126 | * One of the driver callbacks when a new &struct drm_file is closed. | 109 | * One of the driver callbacks when a new &struct drm_file is closed. |
@@ -131,9 +114,6 @@ struct drm_driver { | |||
131 | * one &struct drm_file (see &drm_file.is_master and &drm_device.master) | 114 | * one &struct drm_file (see &drm_file.is_master and &drm_device.master) |
132 | * there should never be a need to tear down any modeset related | 115 | * there should never be a need to tear down any modeset related |
133 | * resources in this callback. Doing so would be a driver design bug. | 116 | * resources in this callback. Doing so would be a driver design bug. |
134 | * | ||
135 | * FIXME: It is not really clear why there's both @preclose and | ||
136 | * @postclose. Without a really good reason, use @postclose only. | ||
137 | */ | 117 | */ |
138 | void (*postclose) (struct drm_device *, struct drm_file *); | 118 | void (*postclose) (struct drm_device *, struct drm_file *); |
139 | 119 | ||
@@ -150,7 +130,7 @@ struct drm_driver { | |||
150 | * state changes, e.g. in conjunction with the :ref:`vga_switcheroo` | 130 | * state changes, e.g. in conjunction with the :ref:`vga_switcheroo` |
151 | * infrastructure. | 131 | * infrastructure. |
152 | * | 132 | * |
153 | * This is called after @preclose and @postclose have been called. | 133 | * This is called after @postclose hook has been called. |
154 | * | 134 | * |
155 | * NOTE: | 135 | * NOTE: |
156 | * | 136 | * |
@@ -261,8 +241,10 @@ struct drm_driver { | |||
261 | * DRM device. | 241 | * DRM device. |
262 | * pipe: | 242 | * pipe: |
263 | * Id of the crtc to query. | 243 | * Id of the crtc to query. |
264 | * flags: | 244 | * in_vblank_irq: |
265 | * Flags from the caller (DRM_CALLED_FROM_VBLIRQ or 0). | 245 | * True when called from drm_crtc_handle_vblank(). Some drivers |
246 | * need to apply some workarounds for gpu-specific vblank irq quirks | ||
247 | * if flag is set. | ||
266 | * vpos: | 248 | * vpos: |
267 | * Target location for current vertical scanout position. | 249 | * Target location for current vertical scanout position. |
268 | * hpos: | 250 | * hpos: |
@@ -283,22 +265,19 @@ struct drm_driver { | |||
283 | * | 265 | * |
284 | * Returns: | 266 | * Returns: |
285 | * | 267 | * |
286 | * Flags, or'ed together as follows: | 268 | * True on success, false if a reliable scanout position counter could |
269 | * not be read out. | ||
287 | * | 270 | * |
288 | * DRM_SCANOUTPOS_VALID: | 271 | * FIXME: |
289 | * Query successful. | ||
290 | * DRM_SCANOUTPOS_INVBL: | ||
291 | * Inside vblank. | ||
292 | * DRM_SCANOUTPOS_ACCURATE: Returned position is accurate. A lack of | ||
293 | * this flag means that returned position may be offset by a | ||
294 | * constant but unknown small number of scanlines wrt. real scanout | ||
295 | * position. | ||
296 | * | 272 | * |
273 | * Since this is a helper to implement @get_vblank_timestamp, we should | ||
274 | * move it to &struct drm_crtc_helper_funcs, like all the other | ||
275 | * helper-internal hooks. | ||
297 | */ | 276 | */ |
298 | int (*get_scanout_position) (struct drm_device *dev, unsigned int pipe, | 277 | bool (*get_scanout_position) (struct drm_device *dev, unsigned int pipe, |
299 | unsigned int flags, int *vpos, int *hpos, | 278 | bool in_vblank_irq, int *vpos, int *hpos, |
300 | ktime_t *stime, ktime_t *etime, | 279 | ktime_t *stime, ktime_t *etime, |
301 | const struct drm_display_mode *mode); | 280 | const struct drm_display_mode *mode); |
302 | 281 | ||
303 | /** | 282 | /** |
304 | * @get_vblank_timestamp: | 283 | * @get_vblank_timestamp: |
@@ -328,22 +307,25 @@ struct drm_driver { | |||
328 | * Returns true upper bound on error for timestamp. | 307 | * Returns true upper bound on error for timestamp. |
329 | * vblank_time: | 308 | * vblank_time: |
330 | * Target location for returned vblank timestamp. | 309 | * Target location for returned vblank timestamp. |
331 | * flags: | 310 | * in_vblank_irq: |
332 | * 0 = Defaults, no special treatment needed. | 311 | * True when called from drm_crtc_handle_vblank(). Some drivers |
333 | * DRM_CALLED_FROM_VBLIRQ = Function is called from vblank | 312 | * need to apply some workarounds for gpu-specific vblank irq quirks |
334 | * irq handler. Some drivers need to apply some workarounds | 313 | * if flag is set. |
335 | * for gpu-specific vblank irq quirks if flag is set. | ||
336 | * | 314 | * |
337 | * Returns: | 315 | * Returns: |
338 | * | 316 | * |
339 | * Zero if timestamping isn't supported in current display mode or a | 317 | * True on success, false on failure, which means the core should |
340 | * negative number on failure. A positive status code on success, | 318 | * fallback to a simple timestamp taken in drm_crtc_handle_vblank(). |
341 | * which describes how the vblank_time timestamp was computed. | 319 | * |
320 | * FIXME: | ||
321 | * | ||
322 | * We should move this hook to &struct drm_crtc_funcs like all the other | ||
323 | * vblank hooks. | ||
342 | */ | 324 | */ |
343 | int (*get_vblank_timestamp) (struct drm_device *dev, unsigned int pipe, | 325 | bool (*get_vblank_timestamp) (struct drm_device *dev, unsigned int pipe, |
344 | int *max_error, | 326 | int *max_error, |
345 | struct timeval *vblank_time, | 327 | struct timeval *vblank_time, |
346 | unsigned flags); | 328 | bool in_vblank_irq); |
347 | 329 | ||
348 | /* these have to be filled in */ | 330 | /* these have to be filled in */ |
349 | 331 | ||
@@ -516,6 +498,7 @@ struct drm_driver { | |||
516 | /* List of devices hanging off this driver with stealth attach. */ | 498 | /* List of devices hanging off this driver with stealth attach. */ |
517 | struct list_head legacy_dev_list; | 499 | struct list_head legacy_dev_list; |
518 | int (*firstopen) (struct drm_device *); | 500 | int (*firstopen) (struct drm_device *); |
501 | void (*preclose) (struct drm_device *, struct drm_file *file_priv); | ||
519 | int (*dma_ioctl) (struct drm_device *dev, void *data, struct drm_file *file_priv); | 502 | int (*dma_ioctl) (struct drm_device *dev, void *data, struct drm_file *file_priv); |
520 | int (*dma_quiescent) (struct drm_device *); | 503 | int (*dma_quiescent) (struct drm_device *); |
521 | int (*context_dtor) (struct drm_device *dev, int context); | 504 | int (*context_dtor) (struct drm_device *dev, int context); |
diff --git a/include/drm/drm_fb_cma_helper.h b/include/drm/drm_fb_cma_helper.h index a5ecc0a58260..199a63f48659 100644 --- a/include/drm/drm_fb_cma_helper.h +++ b/include/drm/drm_fb_cma_helper.h | |||
@@ -41,6 +41,10 @@ struct drm_framebuffer *drm_fb_cma_create(struct drm_device *dev, | |||
41 | struct drm_gem_cma_object *drm_fb_cma_get_gem_obj(struct drm_framebuffer *fb, | 41 | struct drm_gem_cma_object *drm_fb_cma_get_gem_obj(struct drm_framebuffer *fb, |
42 | unsigned int plane); | 42 | unsigned int plane); |
43 | 43 | ||
44 | dma_addr_t drm_fb_cma_get_gem_addr(struct drm_framebuffer *fb, | ||
45 | struct drm_plane_state *state, | ||
46 | unsigned int plane); | ||
47 | |||
44 | int drm_fb_cma_prepare_fb(struct drm_plane *plane, | 48 | int drm_fb_cma_prepare_fb(struct drm_plane *plane, |
45 | struct drm_plane_state *state); | 49 | struct drm_plane_state *state); |
46 | 50 | ||
diff --git a/include/drm/drm_gem_cma_helper.h b/include/drm/drm_gem_cma_helper.h index f962d33667cf..b42529e0fae0 100644 --- a/include/drm/drm_gem_cma_helper.h +++ b/include/drm/drm_gem_cma_helper.h | |||
@@ -26,6 +26,13 @@ to_drm_gem_cma_obj(struct drm_gem_object *gem_obj) | |||
26 | return container_of(gem_obj, struct drm_gem_cma_object, base); | 26 | return container_of(gem_obj, struct drm_gem_cma_object, base); |
27 | } | 27 | } |
28 | 28 | ||
29 | #ifndef CONFIG_MMU | ||
30 | #define DRM_GEM_CMA_UNMAPPED_AREA_FOPS \ | ||
31 | .get_unmapped_area = drm_gem_cma_get_unmapped_area, | ||
32 | #else | ||
33 | #define DRM_GEM_CMA_UNMAPPED_AREA_FOPS | ||
34 | #endif | ||
35 | |||
29 | /** | 36 | /** |
30 | * DEFINE_DRM_GEM_CMA_FOPS() - macro to generate file operations for CMA drivers | 37 | * DEFINE_DRM_GEM_CMA_FOPS() - macro to generate file operations for CMA drivers |
31 | * @name: name for the generated structure | 38 | * @name: name for the generated structure |
@@ -50,6 +57,7 @@ to_drm_gem_cma_obj(struct drm_gem_object *gem_obj) | |||
50 | .read = drm_read,\ | 57 | .read = drm_read,\ |
51 | .llseek = noop_llseek,\ | 58 | .llseek = noop_llseek,\ |
52 | .mmap = drm_gem_cma_mmap,\ | 59 | .mmap = drm_gem_cma_mmap,\ |
60 | DRM_GEM_CMA_UNMAPPED_AREA_FOPS \ | ||
53 | } | 61 | } |
54 | 62 | ||
55 | /* free GEM object */ | 63 | /* free GEM object */ |
@@ -85,15 +93,6 @@ unsigned long drm_gem_cma_get_unmapped_area(struct file *filp, | |||
85 | unsigned long len, | 93 | unsigned long len, |
86 | unsigned long pgoff, | 94 | unsigned long pgoff, |
87 | unsigned long flags); | 95 | unsigned long flags); |
88 | #else | ||
89 | static inline unsigned long drm_gem_cma_get_unmapped_area(struct file *filp, | ||
90 | unsigned long addr, | ||
91 | unsigned long len, | ||
92 | unsigned long pgoff, | ||
93 | unsigned long flags) | ||
94 | { | ||
95 | return -EINVAL; | ||
96 | } | ||
97 | #endif | 96 | #endif |
98 | 97 | ||
99 | #ifdef CONFIG_DEBUG_FS | 98 | #ifdef CONFIG_DEBUG_FS |
diff --git a/include/drm/drm_irq.h b/include/drm/drm_irq.h index cf0be6594c8c..569ca86d4e1f 100644 --- a/include/drm/drm_irq.h +++ b/include/drm/drm_irq.h | |||
@@ -121,6 +121,18 @@ struct drm_vblank_crtc { | |||
121 | * drm_calc_timestamping_constants(). | 121 | * drm_calc_timestamping_constants(). |
122 | */ | 122 | */ |
123 | int linedur_ns; | 123 | int linedur_ns; |
124 | |||
125 | /** | ||
126 | * @hwmode: | ||
127 | * | ||
128 | * Cache of the current hardware display mode. Only valid when @enabled | ||
129 | * is set. This is used by helpers like | ||
130 | * drm_calc_vbltimestamp_from_scanoutpos(). We can't just access the | ||
131 | * hardware mode by e.g. looking at &drm_crtc_state.adjusted_mode, | ||
132 | * because that one is really hard to get from interrupt context. | ||
133 | */ | ||
134 | struct drm_display_mode hwmode; | ||
135 | |||
124 | /** | 136 | /** |
125 | * @enabled: Tracks the enabling state of the corresponding &drm_crtc to | 137 | * @enabled: Tracks the enabling state of the corresponding &drm_crtc to |
126 | * avoid double-disabling and hence corrupting saved state. Needed by | 138 | * avoid double-disabling and hence corrupting saved state. Needed by |
@@ -153,11 +165,10 @@ void drm_crtc_vblank_on(struct drm_crtc *crtc); | |||
153 | void drm_vblank_cleanup(struct drm_device *dev); | 165 | void drm_vblank_cleanup(struct drm_device *dev); |
154 | u32 drm_accurate_vblank_count(struct drm_crtc *crtc); | 166 | u32 drm_accurate_vblank_count(struct drm_crtc *crtc); |
155 | 167 | ||
156 | int drm_calc_vbltimestamp_from_scanoutpos(struct drm_device *dev, | 168 | bool drm_calc_vbltimestamp_from_scanoutpos(struct drm_device *dev, |
157 | unsigned int pipe, int *max_error, | 169 | unsigned int pipe, int *max_error, |
158 | struct timeval *vblank_time, | 170 | struct timeval *vblank_time, |
159 | unsigned flags, | 171 | bool in_vblank_irq); |
160 | const struct drm_display_mode *mode); | ||
161 | void drm_calc_timestamping_constants(struct drm_crtc *crtc, | 172 | void drm_calc_timestamping_constants(struct drm_crtc *crtc, |
162 | const struct drm_display_mode *mode); | 173 | const struct drm_display_mode *mode); |
163 | 174 | ||
diff --git a/include/drm/drm_prime.h b/include/drm/drm_prime.h index 0b2a235c4be0..59ccab402e85 100644 --- a/include/drm/drm_prime.h +++ b/include/drm/drm_prime.h | |||
@@ -50,6 +50,8 @@ struct drm_prime_file_private { | |||
50 | struct rb_root handles; | 50 | struct rb_root handles; |
51 | }; | 51 | }; |
52 | 52 | ||
53 | struct device; | ||
54 | |||
53 | struct dma_buf_export_info; | 55 | struct dma_buf_export_info; |
54 | struct dma_buf; | 56 | struct dma_buf; |
55 | 57 | ||
@@ -65,6 +67,11 @@ int drm_gem_prime_handle_to_fd(struct drm_device *dev, | |||
65 | int *prime_fd); | 67 | int *prime_fd); |
66 | struct drm_gem_object *drm_gem_prime_import(struct drm_device *dev, | 68 | struct drm_gem_object *drm_gem_prime_import(struct drm_device *dev, |
67 | struct dma_buf *dma_buf); | 69 | struct dma_buf *dma_buf); |
70 | |||
71 | struct drm_gem_object *drm_gem_prime_import_dev(struct drm_device *dev, | ||
72 | struct dma_buf *dma_buf, | ||
73 | struct device *attach_dev); | ||
74 | |||
68 | int drm_gem_prime_fd_to_handle(struct drm_device *dev, | 75 | int drm_gem_prime_fd_to_handle(struct drm_device *dev, |
69 | struct drm_file *file_priv, int prime_fd, uint32_t *handle); | 76 | struct drm_file *file_priv, int prime_fd, uint32_t *handle); |
70 | struct dma_buf *drm_gem_dmabuf_export(struct drm_device *dev, | 77 | struct dma_buf *drm_gem_dmabuf_export(struct drm_device *dev, |
diff --git a/include/linux/amba/clcd-regs.h b/include/linux/amba/clcd-regs.h new file mode 100644 index 000000000000..69c0e2143003 --- /dev/null +++ b/include/linux/amba/clcd-regs.h | |||
@@ -0,0 +1,81 @@ | |||
1 | /* | ||
2 | * David A Rusling | ||
3 | * | ||
4 | * Copyright (C) 2001 ARM Limited | ||
5 | * | ||
6 | * This file is subject to the terms and conditions of the GNU General Public | ||
7 | * License. See the file COPYING in the main directory of this archive | ||
8 | * for more details. | ||
9 | */ | ||
10 | |||
11 | #ifndef AMBA_CLCD_REGS_H | ||
12 | #define AMBA_CLCD_REGS_H | ||
13 | |||
14 | /* | ||
15 | * CLCD Controller Internal Register addresses | ||
16 | */ | ||
17 | #define CLCD_TIM0 0x00000000 | ||
18 | #define CLCD_TIM1 0x00000004 | ||
19 | #define CLCD_TIM2 0x00000008 | ||
20 | #define CLCD_TIM3 0x0000000c | ||
21 | #define CLCD_UBAS 0x00000010 | ||
22 | #define CLCD_LBAS 0x00000014 | ||
23 | |||
24 | #define CLCD_PL110_IENB 0x00000018 | ||
25 | #define CLCD_PL110_CNTL 0x0000001c | ||
26 | #define CLCD_PL110_STAT 0x00000020 | ||
27 | #define CLCD_PL110_INTR 0x00000024 | ||
28 | #define CLCD_PL110_UCUR 0x00000028 | ||
29 | #define CLCD_PL110_LCUR 0x0000002C | ||
30 | |||
31 | #define CLCD_PL111_CNTL 0x00000018 | ||
32 | #define CLCD_PL111_IENB 0x0000001c | ||
33 | #define CLCD_PL111_RIS 0x00000020 | ||
34 | #define CLCD_PL111_MIS 0x00000024 | ||
35 | #define CLCD_PL111_ICR 0x00000028 | ||
36 | #define CLCD_PL111_UCUR 0x0000002c | ||
37 | #define CLCD_PL111_LCUR 0x00000030 | ||
38 | |||
39 | #define CLCD_PALL 0x00000200 | ||
40 | #define CLCD_PALETTE 0x00000200 | ||
41 | |||
42 | #define TIM2_CLKSEL (1 << 5) | ||
43 | #define TIM2_IVS (1 << 11) | ||
44 | #define TIM2_IHS (1 << 12) | ||
45 | #define TIM2_IPC (1 << 13) | ||
46 | #define TIM2_IOE (1 << 14) | ||
47 | #define TIM2_BCD (1 << 26) | ||
48 | |||
49 | #define CNTL_LCDEN (1 << 0) | ||
50 | #define CNTL_LCDBPP1 (0 << 1) | ||
51 | #define CNTL_LCDBPP2 (1 << 1) | ||
52 | #define CNTL_LCDBPP4 (2 << 1) | ||
53 | #define CNTL_LCDBPP8 (3 << 1) | ||
54 | #define CNTL_LCDBPP16 (4 << 1) | ||
55 | #define CNTL_LCDBPP16_565 (6 << 1) | ||
56 | #define CNTL_LCDBPP16_444 (7 << 1) | ||
57 | #define CNTL_LCDBPP24 (5 << 1) | ||
58 | #define CNTL_LCDBW (1 << 4) | ||
59 | #define CNTL_LCDTFT (1 << 5) | ||
60 | #define CNTL_LCDMONO8 (1 << 6) | ||
61 | #define CNTL_LCDDUAL (1 << 7) | ||
62 | #define CNTL_BGR (1 << 8) | ||
63 | #define CNTL_BEBO (1 << 9) | ||
64 | #define CNTL_BEPO (1 << 10) | ||
65 | #define CNTL_LCDPWR (1 << 11) | ||
66 | #define CNTL_LCDVCOMP(x) ((x) << 12) | ||
67 | #define CNTL_LDMAFIFOTIME (1 << 15) | ||
68 | #define CNTL_WATERMARK (1 << 16) | ||
69 | |||
70 | /* ST Microelectronics variant bits */ | ||
71 | #define CNTL_ST_1XBPP_444 0x0 | ||
72 | #define CNTL_ST_1XBPP_5551 (1 << 17) | ||
73 | #define CNTL_ST_1XBPP_565 (1 << 18) | ||
74 | #define CNTL_ST_CDWID_12 0x0 | ||
75 | #define CNTL_ST_CDWID_16 (1 << 19) | ||
76 | #define CNTL_ST_CDWID_18 (1 << 20) | ||
77 | #define CNTL_ST_CDWID_24 ((1 << 19)|(1 << 20)) | ||
78 | #define CNTL_ST_CEAEN (1 << 21) | ||
79 | #define CNTL_ST_LCDBPP24_PACKED (6 << 1) | ||
80 | |||
81 | #endif /* AMBA_CLCD_REGS_H */ | ||
diff --git a/include/linux/amba/clcd.h b/include/linux/amba/clcd.h index 1035879b322c..d0c3be77c18e 100644 --- a/include/linux/amba/clcd.h +++ b/include/linux/amba/clcd.h | |||
@@ -10,73 +10,7 @@ | |||
10 | * for more details. | 10 | * for more details. |
11 | */ | 11 | */ |
12 | #include <linux/fb.h> | 12 | #include <linux/fb.h> |
13 | 13 | #include <linux/amba/clcd-regs.h> | |
14 | /* | ||
15 | * CLCD Controller Internal Register addresses | ||
16 | */ | ||
17 | #define CLCD_TIM0 0x00000000 | ||
18 | #define CLCD_TIM1 0x00000004 | ||
19 | #define CLCD_TIM2 0x00000008 | ||
20 | #define CLCD_TIM3 0x0000000c | ||
21 | #define CLCD_UBAS 0x00000010 | ||
22 | #define CLCD_LBAS 0x00000014 | ||
23 | |||
24 | #define CLCD_PL110_IENB 0x00000018 | ||
25 | #define CLCD_PL110_CNTL 0x0000001c | ||
26 | #define CLCD_PL110_STAT 0x00000020 | ||
27 | #define CLCD_PL110_INTR 0x00000024 | ||
28 | #define CLCD_PL110_UCUR 0x00000028 | ||
29 | #define CLCD_PL110_LCUR 0x0000002C | ||
30 | |||
31 | #define CLCD_PL111_CNTL 0x00000018 | ||
32 | #define CLCD_PL111_IENB 0x0000001c | ||
33 | #define CLCD_PL111_RIS 0x00000020 | ||
34 | #define CLCD_PL111_MIS 0x00000024 | ||
35 | #define CLCD_PL111_ICR 0x00000028 | ||
36 | #define CLCD_PL111_UCUR 0x0000002c | ||
37 | #define CLCD_PL111_LCUR 0x00000030 | ||
38 | |||
39 | #define CLCD_PALL 0x00000200 | ||
40 | #define CLCD_PALETTE 0x00000200 | ||
41 | |||
42 | #define TIM2_CLKSEL (1 << 5) | ||
43 | #define TIM2_IVS (1 << 11) | ||
44 | #define TIM2_IHS (1 << 12) | ||
45 | #define TIM2_IPC (1 << 13) | ||
46 | #define TIM2_IOE (1 << 14) | ||
47 | #define TIM2_BCD (1 << 26) | ||
48 | |||
49 | #define CNTL_LCDEN (1 << 0) | ||
50 | #define CNTL_LCDBPP1 (0 << 1) | ||
51 | #define CNTL_LCDBPP2 (1 << 1) | ||
52 | #define CNTL_LCDBPP4 (2 << 1) | ||
53 | #define CNTL_LCDBPP8 (3 << 1) | ||
54 | #define CNTL_LCDBPP16 (4 << 1) | ||
55 | #define CNTL_LCDBPP16_565 (6 << 1) | ||
56 | #define CNTL_LCDBPP16_444 (7 << 1) | ||
57 | #define CNTL_LCDBPP24 (5 << 1) | ||
58 | #define CNTL_LCDBW (1 << 4) | ||
59 | #define CNTL_LCDTFT (1 << 5) | ||
60 | #define CNTL_LCDMONO8 (1 << 6) | ||
61 | #define CNTL_LCDDUAL (1 << 7) | ||
62 | #define CNTL_BGR (1 << 8) | ||
63 | #define CNTL_BEBO (1 << 9) | ||
64 | #define CNTL_BEPO (1 << 10) | ||
65 | #define CNTL_LCDPWR (1 << 11) | ||
66 | #define CNTL_LCDVCOMP(x) ((x) << 12) | ||
67 | #define CNTL_LDMAFIFOTIME (1 << 15) | ||
68 | #define CNTL_WATERMARK (1 << 16) | ||
69 | |||
70 | /* ST Microelectronics variant bits */ | ||
71 | #define CNTL_ST_1XBPP_444 0x0 | ||
72 | #define CNTL_ST_1XBPP_5551 (1 << 17) | ||
73 | #define CNTL_ST_1XBPP_565 (1 << 18) | ||
74 | #define CNTL_ST_CDWID_12 0x0 | ||
75 | #define CNTL_ST_CDWID_16 (1 << 19) | ||
76 | #define CNTL_ST_CDWID_18 (1 << 20) | ||
77 | #define CNTL_ST_CDWID_24 ((1 << 19)|(1 << 20)) | ||
78 | #define CNTL_ST_CEAEN (1 << 21) | ||
79 | #define CNTL_ST_LCDBPP24_PACKED (6 << 1) | ||
80 | 14 | ||
81 | enum { | 15 | enum { |
82 | /* individual formats */ | 16 | /* individual formats */ |
diff --git a/include/linux/sync_file.h b/include/linux/sync_file.h index 3e3ab84fc4cd..d37beefdfbd5 100644 --- a/include/linux/sync_file.h +++ b/include/linux/sync_file.h | |||
@@ -14,7 +14,6 @@ | |||
14 | #define _LINUX_SYNC_FILE_H | 14 | #define _LINUX_SYNC_FILE_H |
15 | 15 | ||
16 | #include <linux/types.h> | 16 | #include <linux/types.h> |
17 | #include <linux/kref.h> | ||
18 | #include <linux/ktime.h> | 17 | #include <linux/ktime.h> |
19 | #include <linux/list.h> | 18 | #include <linux/list.h> |
20 | #include <linux/spinlock.h> | 19 | #include <linux/spinlock.h> |
@@ -24,7 +23,6 @@ | |||
24 | /** | 23 | /** |
25 | * struct sync_file - sync file to export to the userspace | 24 | * struct sync_file - sync file to export to the userspace |
26 | * @file: file representing this fence | 25 | * @file: file representing this fence |
27 | * @kref: reference count on fence. | ||
28 | * @name: name of sync_file. Useful for debugging | 26 | * @name: name of sync_file. Useful for debugging |
29 | * @sync_file_list: membership in global file list | 27 | * @sync_file_list: membership in global file list |
30 | * @wq: wait queue for fence signaling | 28 | * @wq: wait queue for fence signaling |
@@ -33,7 +31,6 @@ | |||
33 | */ | 31 | */ |
34 | struct sync_file { | 32 | struct sync_file { |
35 | struct file *file; | 33 | struct file *file; |
36 | struct kref kref; | ||
37 | char name[32]; | 34 | char name[32]; |
38 | #ifdef CONFIG_DEBUG_FS | 35 | #ifdef CONFIG_DEBUG_FS |
39 | struct list_head sync_file_list; | 36 | struct list_head sync_file_list; |