History

Merge tag 'drm-misc-next-2017-10-20' of git://anongit.freedesktop.org/drm/drm-misc into drm-next

Final drm-misc feature pull for 4.15: UAPI Changes: - new madvise ioctl for vc4 (Boris) Core Changes: - plane commit tracking fixes (Maarten) - vgaarb improvements for fancy new platforms (aka ppc64 and arm64) by Bjorn Helgaas Driver Changes: - pile of new panel drivers: Toshiba LT089AC19000, Innolux AT043TN24 - more sun4i work to support A10/A20 Tcon and hdmi outputs - vc4: fix sleep in irq handler by making it threaded (Eric) - udl probe/edid read fixes (Robert Tarasov) And a bunch of misc small cleanups/refactors and doc fixes all over. * tag 'drm-misc-next-2017-10-20' of git://anongit.freedesktop.org/drm/drm-misc: (32 commits) drm/vc4: Fix sleeps during the IRQ handler for DSI transactions. drm/vc4: Add the DRM_IOCTL_VC4_GEM_MADVISE ioctl drm/panel: simple: add Toshiba LT089AC19000 dma-fence: remove duplicate word in comment drm/panel: simple: add delays for Innolux AT043TN24 drm/panel: simple: add bus flags for Innolux AT043TN24 drm/panel: simple: fix vertical timings for Innolux AT043TN24 drm/atomic-helper: check that drivers call drm_crtc_vblank_off drm: some KMS todo ideas vgaarb: Factor out EFI and fallback default device selection vgaarb: Select a default VGA device even if there's no legacy VGA drm/bridge: adv7511: Fix a use after free drm/sun4i: Add support for A20 display pipeline components drm/sun4i: Add support for A10 display pipeline components drm/sun4i: hdmi: Support HDMI controller on A10 drm/sun4i: tcon: Add support for A10 TCON drm/sun4i: backend: Support output muxing drm/sun4i: tcon: Move out the tcon0 common setup drm/sun4i: tcon: Don't rely on encoders to set the TCON mode drm/sun4i: tcon: Don't rely on encoders to enable the TCON ...

Dave Airlie committed 9 years ago

Commit fef1aa42 parents 3b677e4 af0c8c139 files · +1154 −356Browse files

Unified · Split

39 files
  1. Documentation/devicetree/bindings/display/panel/toshiba,lt089ac29000.txt +8 −0
  2. Documentation/devicetree/bindings/display/sunxi/sun4i-drm.txt +9 −0
  3. Documentation/gpu/todo.rst +12 −0
  4. arch/powerpc/kernel/pci-common.c +0 −12
  5. drivers/gpu/drm/armada/armada_crtc.c +11 −11
  6. drivers/gpu/drm/armada/armada_drv.c +1 −1
  7. drivers/gpu/drm/armada/armada_fb.c +4 −4
  8. drivers/gpu/drm/armada/armada_fbdev.c +3 −3
  9. drivers/gpu/drm/armada/armada_gem.c +6 −6
  10. drivers/gpu/drm/armada/armada_overlay.c +2 −2
  11. drivers/gpu/drm/bridge/adv7511/adv7511_drv.c +2 −2
  12. drivers/gpu/drm/drm_atomic_helper.c +18 −10
  13. drivers/gpu/drm/drm_gem_cma_helper.c +1 −1
  14. drivers/gpu/drm/panel/panel-simple.c +34 −2
  15. drivers/gpu/drm/sun4i/Makefile +17 −16
  16. drivers/gpu/drm/sun4i/sun4i_backend.c +72 −3
  17. drivers/gpu/drm/sun4i/sun4i_backend.h +2 −1
  18. drivers/gpu/drm/sun4i/sun4i_crtc.c +30 −2
  19. drivers/gpu/drm/sun4i/sun4i_drv.c +21 −60
  20. drivers/gpu/drm/sun4i/sun4i_hdmi_ddc_clk.c +0 −1
  21. drivers/gpu/drm/sun4i/sun4i_hdmi_enc.c +53 −15
  22. drivers/gpu/drm/sun4i/sun4i_hdmi_tmds_clk.c +0 −1
  23. drivers/gpu/drm/sun4i/sun4i_rgb.c +4 −25
  24. drivers/gpu/drm/sun4i/sun4i_tcon.c +119 −64
  25. drivers/gpu/drm/sun4i/sun4i_tcon.h +6 −17
  26. drivers/gpu/drm/sun4i/sun4i_tv.c +0 −12
  27. drivers/gpu/drm/udl/udl_connector.c +104 −50
  28. drivers/gpu/drm/udl/udl_connector.h +13 −0
  29. drivers/gpu/drm/udl/udl_drv.c +4 −0
  30. drivers/gpu/drm/udl/udl_main.c +5 −0
  31. drivers/gpu/drm/vc4/vc4_bo.c +279 −8
  32. drivers/gpu/drm/vc4/vc4_drv.c +9 −1
  33. drivers/gpu/drm/vc4/vc4_drv.h +30 −0
  34. drivers/gpu/drm/vc4/vc4_dsi.c +30 −2
  35. drivers/gpu/drm/vc4/vc4_gem.c +150 −6
  36. drivers/gpu/drm/vc4/vc4_plane.c +20 −0
  37. drivers/gpu/vga/vgaarb.c +55 −17
  38. include/linux/dma-fence.h +1 −1
  39. include/uapi/drm/vc4_drm.h +19 −0
Documentation/devicetree/bindings/display/panel/toshiba,lt089ac29000.txt+8−0
@@ -0,0 +1,8 @@
1Toshiba 8.9" WXGA (1280x768) TFT LCD panel
2
3Required properties:
4- compatible: should be "toshiba,lt089ac29000.txt"
5- power-supply: as specified in the base binding
6
7This binding is compatible with the simple-panel binding, which is specified
8in simple-panel.txt in this directory.
Documentation/devicetree/bindings/display/sunxi/sun4i-drm.txt+9−0
@@ -40,6 +40,7 @@ CEC. It is one end of the pipeline. · 39 unmodified lines
40 40
41Required properties:41Required properties:
42 - compatible: value must be one of:42 - compatible: value must be one of:
43 * allwinner,sun4i-a10-hdmi
43 * allwinner,sun5i-a10s-hdmi44 * allwinner,sun5i-a10s-hdmi
44 * allwinner,sun6i-a31-hdmi45 * allwinner,sun6i-a31-hdmi
45 - reg: base address and size of memory-mapped region46 - reg: base address and size of memory-mapped region
@@ -86,9 +87,11 @@ The TCON acts as a timing controller for RGB, LVDS and TV interfaces. · 40 unmodified lines
86 87
87Required properties:88Required properties:
88 - compatible: value must be either:89 - compatible: value must be either:
90 * allwinner,sun4i-a10-tcon
89 * allwinner,sun5i-a13-tcon91 * allwinner,sun5i-a13-tcon
90 * allwinner,sun6i-a31-tcon92 * allwinner,sun6i-a31-tcon
91 * allwinner,sun6i-a31s-tcon93 * allwinner,sun6i-a31s-tcon
94 * allwinner,sun7i-a20-tcon
92 * allwinner,sun8i-a33-tcon95 * allwinner,sun8i-a33-tcon
93 * allwinner,sun8i-v3s-tcon96 * allwinner,sun8i-v3s-tcon
94 - reg: base address and size of memory-mapped region97 - reg: base address and size of memory-mapped region
@@ -153,8 +156,10 @@ system. · 58 unmodified lines
153 156
154Required properties:157Required properties:
155 - compatible: value must be one of:158 - compatible: value must be one of:
159 * allwinner,sun4i-a10-display-backend
156 * allwinner,sun5i-a13-display-backend160 * allwinner,sun5i-a13-display-backend
157 * allwinner,sun6i-a31-display-backend161 * allwinner,sun6i-a31-display-backend
162 * allwinner,sun7i-a20-display-backend
158 * allwinner,sun8i-a33-display-backend163 * allwinner,sun8i-a33-display-backend
159 - reg: base address and size of the memory-mapped region.164 - reg: base address and size of the memory-mapped region.
160 - interrupts: interrupt associated to this IP165 - interrupts: interrupt associated to this IP
@@ -185,8 +190,10 @@ deinterlacing and color space conversion. · 24 unmodified lines
185 190
186Required properties:191Required properties:
187 - compatible: value must be one of:192 - compatible: value must be one of:
193 * allwinner,sun4i-a10-display-frontend
188 * allwinner,sun5i-a13-display-frontend194 * allwinner,sun5i-a13-display-frontend
189 * allwinner,sun6i-a31-display-frontend195 * allwinner,sun6i-a31-display-frontend
196 * allwinner,sun7i-a20-display-frontend
190 * allwinner,sun8i-a33-display-frontend197 * allwinner,sun8i-a33-display-frontend
191 - reg: base address and size of the memory-mapped region.198 - reg: base address and size of the memory-mapped region.
192 - interrupts: interrupt associated to this IP199 - interrupts: interrupt associated to this IP
@@ -231,10 +238,12 @@ extra node. · 38 unmodified lines
231 238
232Required properties:239Required properties:
233 - compatible: value must be one of:240 - compatible: value must be one of:
241 * allwinner,sun4i-a10-display-engine
234 * allwinner,sun5i-a10s-display-engine242 * allwinner,sun5i-a10s-display-engine
235 * allwinner,sun5i-a13-display-engine243 * allwinner,sun5i-a13-display-engine
236 * allwinner,sun6i-a31-display-engine244 * allwinner,sun6i-a31-display-engine
237 * allwinner,sun6i-a31s-display-engine245 * allwinner,sun6i-a31s-display-engine
246 * allwinner,sun7i-a20-display-engine
238 * allwinner,sun8i-a33-display-engine247 * allwinner,sun8i-a33-display-engine
239 * allwinner,sun8i-v3s-display-engine248 * allwinner,sun8i-v3s-display-engine
240 249
Documentation/gpu/todo.rst+12−0
@@ -304,6 +304,18 @@ There's a bunch of issues with it: · 303 unmodified lines
304 304
305Contact: Daniel Vetter305Contact: Daniel Vetter
306 306
307KMS cleanups
308------------
309
310Some of these date from the very introduction of KMS in 2008 ...
311
312- drm_mode_config.crtc_idr is misnamed, since it contains all KMS object. Should
313 be renamed to drm_mode_config.object_idr.
314
315- drm_display_mode doesn't need to be derived from drm_mode_object. That's
316 leftovers from older (never merged into upstream) KMS designs where modes
317 where set using their ID, including support to add/remove modes.
318
307Better Testing319Better Testing
308==============320==============
309 321
arch/powerpc/kernel/pci-common.c+0−12
@@ -1740,15 +1740,3 @@ static void fixup_hide_host_resource_fsl(struct pci_dev *dev) · 1739 unmodified lines
1740}1740}
1741DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_MOTOROLA, PCI_ANY_ID, fixup_hide_host_resource_fsl);1741DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_MOTOROLA, PCI_ANY_ID, fixup_hide_host_resource_fsl);
1742DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_FREESCALE, PCI_ANY_ID, fixup_hide_host_resource_fsl);1742DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_FREESCALE, PCI_ANY_ID, fixup_hide_host_resource_fsl);
1743
1744static void fixup_vga(struct pci_dev *pdev)
1745{
1746 u16 cmd;
1747
1748 pci_read_config_word(pdev, PCI_COMMAND, &cmd);
1749 if ((cmd & (PCI_COMMAND_IO | PCI_COMMAND_MEMORY)) || !vga_default_device())
1750 vga_set_default_device(pdev);
1751
1752}
1753DECLARE_PCI_FIXUP_CLASS_FINAL(PCI_ANY_ID, PCI_ANY_ID,
1754 PCI_CLASS_DISPLAY_VGA, 8, fixup_vga);
drivers/gpu/drm/armada/armada_crtc.c+11−11
@@ -298,7 +298,7 @@ static void armada_drm_crtc_finish_fb(struct armada_crtc *dcrtc, · 297 unmodified lines
298 298
299 if (force) {299 if (force) {
300 /* Display is disabled, so just drop the old fb */300 /* Display is disabled, so just drop the old fb */
301 drm_framebuffer_unreference(fb);301 drm_framebuffer_put(fb);
302 return;302 return;
303 }303 }
304 304
@@ -321,7 +321,7 @@ static void armada_drm_crtc_finish_fb(struct armada_crtc *dcrtc, · 16 unmodified lines
321 * the best. The worst that will happen is the buffer gets321 * the best. The worst that will happen is the buffer gets
322 * reused before it has finished being displayed.322 * reused before it has finished being displayed.
323 */323 */
324 drm_framebuffer_unreference(fb);324 drm_framebuffer_put(fb);
325}325}
326 326
327static void armada_drm_vblank_off(struct armada_crtc *dcrtc)327static void armada_drm_vblank_off(struct armada_crtc *dcrtc)
@@ -577,7 +577,7 @@ static int armada_drm_crtc_mode_set(struct drm_crtc *crtc, · 249 unmodified lines
577 unsigned i;577 unsigned i;
578 bool interlaced;578 bool interlaced;
579 579
580 drm_framebuffer_reference(crtc->primary->fb);580 drm_framebuffer_get(crtc->primary->fb);
581 581
582 interlaced = !!(adj->flags & DRM_MODE_FLAG_INTERLACE);582 interlaced = !!(adj->flags & DRM_MODE_FLAG_INTERLACE);
583 583
@@ -718,7 +718,7 @@ static int armada_drm_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y, · 134 unmodified lines
718 MAX_SCHEDULE_TIMEOUT);718 MAX_SCHEDULE_TIMEOUT);
719 719
720 /* Take a reference to the new fb as we're using it */720 /* Take a reference to the new fb as we're using it */
721 drm_framebuffer_reference(crtc->primary->fb);721 drm_framebuffer_get(crtc->primary->fb);
722 722
723 /* Update the base in the CRTC */723 /* Update the base in the CRTC */
724 armada_drm_crtc_update_regs(dcrtc, regs);724 armada_drm_crtc_update_regs(dcrtc, regs);
@@ -742,7 +742,7 @@ void armada_drm_crtc_plane_disable(struct armada_crtc *dcrtc, · 17 unmodified lines
742 * primary plane.742 * primary plane.
743 */743 */
744 if (plane->fb)744 if (plane->fb)
745 drm_framebuffer_unreference(plane->fb);745 drm_framebuffer_put(plane->fb);
746 746
747 /* Power down the Y/U/V FIFOs */747 /* Power down the Y/U/V FIFOs */
748 sram_para1 = CFG_PDWN16x66 | CFG_PDWN32x66;748 sram_para1 = CFG_PDWN16x66 | CFG_PDWN32x66;
@@ -947,13 +947,13 @@ static int armada_drm_crtc_cursor_set(struct drm_crtc *crtc, · 198 unmodified lines
947 947
948 /* Must be a kernel-mapped object */948 /* Must be a kernel-mapped object */
949 if (!obj->addr) {949 if (!obj->addr) {
950 drm_gem_object_unreference_unlocked(&obj->obj);950 drm_gem_object_put_unlocked(&obj->obj);
951 return -EINVAL;951 return -EINVAL;
952 }952 }
953 953
954 if (obj->obj.size < w * h * 4) {954 if (obj->obj.size < w * h * 4) {
955 DRM_ERROR("buffer is too small\n");955 DRM_ERROR("buffer is too small\n");
956 drm_gem_object_unreference_unlocked(&obj->obj);956 drm_gem_object_put_unlocked(&obj->obj);
957 return -ENOMEM;957 return -ENOMEM;
958 }958 }
959 }959 }
@@ -961,7 +961,7 @@ static int armada_drm_crtc_cursor_set(struct drm_crtc *crtc, · 1 unmodified line
961 if (dcrtc->cursor_obj) {961 if (dcrtc->cursor_obj) {
962 dcrtc->cursor_obj->update = NULL;962 dcrtc->cursor_obj->update = NULL;
963 dcrtc->cursor_obj->update_data = NULL;963 dcrtc->cursor_obj->update_data = NULL;
964 drm_gem_object_unreference_unlocked(&dcrtc->cursor_obj->obj);964 drm_gem_object_put_unlocked(&dcrtc->cursor_obj->obj);
965 }965 }
966 dcrtc->cursor_obj = obj;966 dcrtc->cursor_obj = obj;
967 dcrtc->cursor_w = w;967 dcrtc->cursor_w = w;
@@ -997,7 +997,7 @@ static void armada_drm_crtc_destroy(struct drm_crtc *crtc) · 29 unmodified lines
997 struct armada_private *priv = crtc->dev->dev_private;997 struct armada_private *priv = crtc->dev->dev_private;
998 998
999 if (dcrtc->cursor_obj)999 if (dcrtc->cursor_obj)
1000 drm_gem_object_unreference_unlocked(&dcrtc->cursor_obj->obj);1000 drm_gem_object_put_unlocked(&dcrtc->cursor_obj->obj);
1001 1001
1002 priv->dcrtc[dcrtc->num] = NULL;1002 priv->dcrtc[dcrtc->num] = NULL;
1003 drm_crtc_cleanup(&dcrtc->crtc);1003 drm_crtc_cleanup(&dcrtc->crtc);
@@ -1045,12 +1045,12 @@ static int armada_drm_crtc_page_flip(struct drm_crtc *crtc, · 41 unmodified lines
1045 * Ensure that we hold a reference on the new framebuffer.1045 * Ensure that we hold a reference on the new framebuffer.
1046 * This has to match the behaviour in mode_set.1046 * This has to match the behaviour in mode_set.
1047 */1047 */
1048 drm_framebuffer_reference(fb);1048 drm_framebuffer_get(fb);
1049 1049
1050 ret = armada_drm_crtc_queue_frame_work(dcrtc, work);1050 ret = armada_drm_crtc_queue_frame_work(dcrtc, work);
1051 if (ret) {1051 if (ret) {
1052 /* Undo our reference above */1052 /* Undo our reference above */
1053 drm_framebuffer_unreference(fb);1053 drm_framebuffer_put(fb);
1054 kfree(work);1054 kfree(work);
1055 return ret;1055 return ret;
1056 }1056 }
drivers/gpu/drm/armada/armada_drv.c+1−1
@@ -25,7 +25,7 @@ static void armada_drm_unref_work(struct work_struct *work) · 24 unmodified lines
25 struct drm_framebuffer *fb;25 struct drm_framebuffer *fb;
26 26
27 while (kfifo_get(&priv->fb_unref, &fb))27 while (kfifo_get(&priv->fb_unref, &fb))
28 drm_framebuffer_unreference(fb);28 drm_framebuffer_put(fb);
29}29}
30 30
31/* Must be called with dev->event_lock held */31/* Must be called with dev->event_lock held */
drivers/gpu/drm/armada/armada_fb.c+4−4
@@ -17,7 +17,7 @@ static void armada_fb_destroy(struct drm_framebuffer *fb) · 16 unmodified lines
17 struct armada_framebuffer *dfb = drm_fb_to_armada_fb(fb);17 struct armada_framebuffer *dfb = drm_fb_to_armada_fb(fb);
18 18
19 drm_framebuffer_cleanup(&dfb->fb);19 drm_framebuffer_cleanup(&dfb->fb);
20 drm_gem_object_unreference_unlocked(&dfb->obj->obj);20 drm_gem_object_put_unlocked(&dfb->obj->obj);
21 kfree(dfb);21 kfree(dfb);
22}22}
23 23
@@ -94,7 +94,7 @@ struct armada_framebuffer *armada_framebuffer_create(struct drm_device *dev, · 70 unmodified lines
94 * the above call, but the caller will drop their reference94 * the above call, but the caller will drop their reference
95 * to it. Hence we need to take our own reference.95 * to it. Hence we need to take our own reference.
96 */96 */
97 drm_gem_object_reference(&obj->obj);97 drm_gem_object_get(&obj->obj);
98 98
99 return dfb;99 return dfb;
100}100}
@@ -143,12 +143,12 @@ static struct drm_framebuffer *armada_fb_create(struct drm_device *dev, · 42 unmodified lines
143 goto err;143 goto err;
144 }144 }
145 145
146 drm_gem_object_unreference_unlocked(&obj->obj);146 drm_gem_object_put_unlocked(&obj->obj);
147 147
148 return &dfb->fb;148 return &dfb->fb;
149 149
150 err_unref:150 err_unref:
151 drm_gem_object_unreference_unlocked(&obj->obj);151 drm_gem_object_put_unlocked(&obj->obj);
152 err:152 err:
153 DRM_ERROR("failed to initialize framebuffer: %d\n", ret);153 DRM_ERROR("failed to initialize framebuffer: %d\n", ret);
154 return ERR_PTR(ret);154 return ERR_PTR(ret);
drivers/gpu/drm/armada/armada_fbdev.c+3−3
@@ -51,13 +51,13 @@ static int armada_fb_create(struct drm_fb_helper *fbh, · 50 unmodified lines
51 51
52 ret = armada_gem_linear_back(dev, obj);52 ret = armada_gem_linear_back(dev, obj);
53 if (ret) {53 if (ret) {
54 drm_gem_object_unreference_unlocked(&obj->obj);54 drm_gem_object_put_unlocked(&obj->obj);
55 return ret;55 return ret;
56 }56 }
57 57
58 ptr = armada_gem_map_object(dev, obj);58 ptr = armada_gem_map_object(dev, obj);
59 if (!ptr) {59 if (!ptr) {
60 drm_gem_object_unreference_unlocked(&obj->obj);60 drm_gem_object_put_unlocked(&obj->obj);
61 return -ENOMEM;61 return -ENOMEM;
62 }62 }
63 63
@@ -67,7 +67,7 @@ static int armada_fb_create(struct drm_fb_helper *fbh, · 3 unmodified lines
67 * A reference is now held by the framebuffer object if67 * A reference is now held by the framebuffer object if
68 * successful, otherwise this drops the ref for the error path.68 * successful, otherwise this drops the ref for the error path.
69 */69 */
70 drm_gem_object_unreference_unlocked(&obj->obj);70 drm_gem_object_put_unlocked(&obj->obj);
71 71
72 if (IS_ERR(dfb))72 if (IS_ERR(dfb))
73 return PTR_ERR(dfb);73 return PTR_ERR(dfb);
drivers/gpu/drm/armada/armada_gem.c+6−6
@@ -265,7 +265,7 @@ int armada_gem_dumb_create(struct drm_file *file, struct drm_device *dev, · 264 unmodified lines
265 /* drop reference from allocate - handle holds it now */265 /* drop reference from allocate - handle holds it now */
266 DRM_DEBUG_DRIVER("obj %p size %zu handle %#x\n", dobj, size, handle);266 DRM_DEBUG_DRIVER("obj %p size %zu handle %#x\n", dobj, size, handle);
267 err:267 err:
268 drm_gem_object_unreference_unlocked(&dobj->obj);268 drm_gem_object_put_unlocked(&dobj->obj);
269 return ret;269 return ret;
270}270}
271 271
@@ -297,7 +297,7 @@ int armada_gem_create_ioctl(struct drm_device *dev, void *data, · 25 unmodified lines
297 /* drop reference from allocate - handle holds it now */297 /* drop reference from allocate - handle holds it now */
298 DRM_DEBUG_DRIVER("obj %p size %zu handle %#x\n", dobj, size, handle);298 DRM_DEBUG_DRIVER("obj %p size %zu handle %#x\n", dobj, size, handle);
299 err:299 err:
300 drm_gem_object_unreference_unlocked(&dobj->obj);300 drm_gem_object_put_unlocked(&dobj->obj);
301 return ret;301 return ret;
302}302}
303 303
@@ -314,13 +314,13 @@ int armada_gem_mmap_ioctl(struct drm_device *dev, void *data, · 10 unmodified lines
314 return -ENOENT;314 return -ENOENT;
315 315
316 if (!dobj->obj.filp) {316 if (!dobj->obj.filp) {
317 drm_gem_object_unreference_unlocked(&dobj->obj);317 drm_gem_object_put_unlocked(&dobj->obj);
318 return -EINVAL;318 return -EINVAL;
319 }319 }
320 320
321 addr = vm_mmap(dobj->obj.filp, 0, args->size, PROT_READ | PROT_WRITE,321 addr = vm_mmap(dobj->obj.filp, 0, args->size, PROT_READ | PROT_WRITE,
322 MAP_SHARED, args->offset);322 MAP_SHARED, args->offset);
323 drm_gem_object_unreference_unlocked(&dobj->obj);323 drm_gem_object_put_unlocked(&dobj->obj);
324 if (IS_ERR_VALUE(addr))324 if (IS_ERR_VALUE(addr))
325 return addr;325 return addr;
326 326
@@ -375,7 +375,7 @@ int armada_gem_pwrite_ioctl(struct drm_device *dev, void *data, · 48 unmodified lines
375 }375 }
376 376
377 unref:377 unref:
378 drm_gem_object_unreference_unlocked(&dobj->obj);378 drm_gem_object_put_unlocked(&dobj->obj);
379 return ret;379 return ret;
380}380}
381 381
@@ -524,7 +524,7 @@ armada_gem_prime_import(struct drm_device *dev, struct dma_buf *buf) · 142 unmodified lines
524 * Importing our own dmabuf(s) increases the524 * Importing our own dmabuf(s) increases the
525 * refcount on the gem object itself.525 * refcount on the gem object itself.
526 */526 */
527 drm_gem_object_reference(obj);527 drm_gem_object_get(obj);
528 return obj;528 return obj;
529 }529 }
530 }530 }
drivers/gpu/drm/armada/armada_overlay.c+2−2
@@ -177,7 +177,7 @@ armada_ovl_plane_update(struct drm_plane *plane, struct drm_crtc *crtc, · 176 unmodified lines
177 * Take a reference on the new framebuffer - we want to177 * Take a reference on the new framebuffer - we want to
178 * hold on to it while the hardware is displaying it.178 * hold on to it while the hardware is displaying it.
179 */179 */
180 drm_framebuffer_reference(fb);180 drm_framebuffer_get(fb);
181 181
182 if (plane->fb)182 if (plane->fb)
183 armada_ovl_retire_fb(dplane, plane->fb);183 armada_ovl_retire_fb(dplane, plane->fb);
@@ -278,7 +278,7 @@ static int armada_ovl_plane_disable(struct drm_plane *plane, · 94 unmodified lines
278 278
279 fb = xchg(&dplane->old_fb, NULL);279 fb = xchg(&dplane->old_fb, NULL);
280 if (fb)280 if (fb)
281 drm_framebuffer_unreference(fb);281 drm_framebuffer_put(fb);
282 282
283 return 0;283 return 0;
284}284}
drivers/gpu/drm/bridge/adv7511/adv7511_drv.c+2−2
@@ -607,10 +607,10 @@ static int adv7511_get_modes(struct adv7511 *adv7511, · 606 unmodified lines
607 adv7511_set_config_csc(adv7511, connector, adv7511->rgb,607 adv7511_set_config_csc(adv7511, connector, adv7511->rgb,
608 drm_detect_hdmi_monitor(edid));608 drm_detect_hdmi_monitor(edid));
609 609
610 kfree(edid);
611
612 cec_s_phys_addr_from_edid(adv7511->cec_adap, edid);610 cec_s_phys_addr_from_edid(adv7511->cec_adap, edid);
613 611
612 kfree(edid);
613
614 return count;614 return count;
615}615}
616 616
drivers/gpu/drm/drm_atomic_helper.c+18−10
@@ -860,6 +860,7 @@ disable_outputs(struct drm_device *dev, struct drm_atomic_state *old_state) · 859 unmodified lines
860 860
861 for_each_oldnew_crtc_in_state(old_state, crtc, old_crtc_state, new_crtc_state, i) {861 for_each_oldnew_crtc_in_state(old_state, crtc, old_crtc_state, new_crtc_state, i) {
862 const struct drm_crtc_helper_funcs *funcs;862 const struct drm_crtc_helper_funcs *funcs;
863 int ret;
863 864
864 /* Shut down everything that needs a full modeset. */865 /* Shut down everything that needs a full modeset. */
865 if (!drm_atomic_crtc_needs_modeset(new_crtc_state))866 if (!drm_atomic_crtc_needs_modeset(new_crtc_state))
@@ -883,6 +884,14 @@ disable_outputs(struct drm_device *dev, struct drm_atomic_state *old_state) · 17 unmodified lines
883 funcs->disable(crtc);884 funcs->disable(crtc);
884 else885 else
885 funcs->dpms(crtc, DRM_MODE_DPMS_OFF);886 funcs->dpms(crtc, DRM_MODE_DPMS_OFF);
887
888 if (!(dev->irq_enabled && dev->num_crtcs))
889 continue;
890
891 ret = drm_crtc_vblank_get(crtc);
892 WARN_ONCE(ret != -EINVAL, "driver forgot to call drm_crtc_vblank_off()\n");
893 if (ret == 0)
894 drm_crtc_vblank_put(crtc);
886 }895 }
887}896}
888 897
@@ -1772,16 +1781,16 @@ int drm_atomic_helper_setup_commit(struct drm_atomic_state *state, · 883 unmodified lines
1772 }1781 }
1773 1782
1774 for_each_oldnew_connector_in_state(state, conn, old_conn_state, new_conn_state, i) {1783 for_each_oldnew_connector_in_state(state, conn, old_conn_state, new_conn_state, i) {
1775 /* commit tracked through new_crtc_state->commit, no need to do it explicitly */
1776 if (new_conn_state->crtc)
1777 continue;
1778
1779 /* Userspace is not allowed to get ahead of the previous1784 /* Userspace is not allowed to get ahead of the previous
1780 * commit with nonblocking ones. */1785 * commit with nonblocking ones. */
1781 if (nonblock && old_conn_state->commit &&1786 if (nonblock && old_conn_state->commit &&
1782 !try_wait_for_completion(&old_conn_state->commit->flip_done))1787 !try_wait_for_completion(&old_conn_state->commit->flip_done))
1783 return -EBUSY;1788 return -EBUSY;
1784 1789
1790 /* commit tracked through new_crtc_state->commit, no need to do it explicitly */
1791 if (new_conn_state->crtc)
1792 continue;
1793
1785 commit = crtc_or_fake_commit(state, old_conn_state->crtc);1794 commit = crtc_or_fake_commit(state, old_conn_state->crtc);
1786 if (!commit)1795 if (!commit)
1787 return -ENOMEM;1796 return -ENOMEM;
@@ -1790,18 +1799,17 @@ int drm_atomic_helper_setup_commit(struct drm_atomic_state *state, · 2 unmodified lines
1790 }1799 }
1791 1800
1792 for_each_oldnew_plane_in_state(state, plane, old_plane_state, new_plane_state, i) {1801 for_each_oldnew_plane_in_state(state, plane, old_plane_state, new_plane_state, i) {
1793 /*
1794 * Unlike connectors, always track planes explicitly for
1795 * async pageflip support.
1796 */
1797
1798 /* Userspace is not allowed to get ahead of the previous1802 /* Userspace is not allowed to get ahead of the previous
1799 * commit with nonblocking ones. */1803 * commit with nonblocking ones. */
1800 if (nonblock && old_plane_state->commit &&1804 if (nonblock && old_plane_state->commit &&
1801 !try_wait_for_completion(&old_plane_state->commit->flip_done))1805 !try_wait_for_completion(&old_plane_state->commit->flip_done))
1802 return -EBUSY;1806 return -EBUSY;
1803 1807
1804 commit = crtc_or_fake_commit(state, old_plane_state->crtc);1808 /*
1809 * Unlike connectors, always track planes explicitly for
1810 * async pageflip support.
1811 */
1812 commit = crtc_or_fake_commit(state, new_plane_state->crtc ?: old_plane_state->crtc);
1805 if (!commit)1813 if (!commit)
1806 return -ENOMEM;1814 return -ENOMEM;
1807 1815
drivers/gpu/drm/drm_gem_cma_helper.c+1−1
@@ -112,7 +112,7 @@ struct drm_gem_cma_object *drm_gem_cma_create(struct drm_device *drm, · 111 unmodified lines
112 cma_obj->vaddr = dma_alloc_wc(drm->dev, size, &cma_obj->paddr,112 cma_obj->vaddr = dma_alloc_wc(drm->dev, size, &cma_obj->paddr,
113 GFP_KERNEL | __GFP_NOWARN);113 GFP_KERNEL | __GFP_NOWARN);
114 if (!cma_obj->vaddr) {114 if (!cma_obj->vaddr) {
115 dev_err(drm->dev, "failed to allocate buffer with size %zu\n",115 dev_dbg(drm->dev, "failed to allocate buffer with size %zu\n",
116 size);116 size);
117 ret = -ENOMEM;117 ret = -ENOMEM;
118 goto error;118 goto error;
drivers/gpu/drm/panel/panel-simple.c+34−2
@@ -1008,6 +1008,10 @@ static const struct panel_desc hitachi_tx23d38vm0caa = { · 1007 unmodified lines
1008 .width = 195,1008 .width = 195,
1009 .height = 117,1009 .height = 117,
1010 },1010 },
1011 .delay = {
1012 .enable = 160,
1013 .disable = 160,
1014 },
1011};1015};
1012 1016
1013static const struct drm_display_mode innolux_at043tn24_mode = {1017static const struct drm_display_mode innolux_at043tn24_mode = {
@@ -1018,8 +1022,8 @@ static const struct drm_display_mode innolux_at043tn24_mode = { · 4 unmodified lines
1018 .htotal = 480 + 2 + 41 + 2,1022 .htotal = 480 + 2 + 41 + 2,
1019 .vdisplay = 272,1023 .vdisplay = 272,
1020 .vsync_start = 272 + 2,1024 .vsync_start = 272 + 2,
1021 .vsync_end = 272 + 2 + 11,1025 .vsync_end = 272 + 2 + 10,
1022 .vtotal = 272 + 2 + 11 + 2,1026 .vtotal = 272 + 2 + 10 + 2,
1023 .vrefresh = 60,1027 .vrefresh = 60,
1024 .flags = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC,1028 .flags = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC,
1025};1029};
@@ -1033,6 +1037,7 @@ static const struct panel_desc innolux_at043tn24 = { · 7 unmodified lines
1033 .height = 54,1037 .height = 54,
1034 },1038 },
1035 .bus_format = MEDIA_BUS_FMT_RGB888_1X24,1039 .bus_format = MEDIA_BUS_FMT_RGB888_1X24,
1040 .bus_flags = DRM_BUS_FLAG_DE_HIGH | DRM_BUS_FLAG_PIXDATA_POSEDGE,
1036};1041};
1037 1042
1038static const struct drm_display_mode innolux_at070tn92_mode = {1043static const struct drm_display_mode innolux_at070tn92_mode = {
@@ -1832,6 +1837,30 @@ static const struct panel_desc tianma_tm070jdhg30 = { · 793 unmodified lines
1832 .bus_format = MEDIA_BUS_FMT_RGB888_1X7X4_SPWG,1837 .bus_format = MEDIA_BUS_FMT_RGB888_1X7X4_SPWG,
1833};1838};
1834 1839
1840static const struct drm_display_mode toshiba_lt089ac29000_mode = {
1841 .clock = 79500,
1842 .hdisplay = 1280,
1843 .hsync_start = 1280 + 192,
1844 .hsync_end = 1280 + 192 + 128,
1845 .htotal = 1280 + 192 + 128 + 64,
1846 .vdisplay = 768,
1847 .vsync_start = 768 + 20,
1848 .vsync_end = 768 + 20 + 7,
1849 .vtotal = 768 + 20 + 7 + 3,
1850 .vrefresh = 60,
1851};
1852
1853static const struct panel_desc toshiba_lt089ac29000 = {
1854 .modes = &toshiba_lt089ac29000_mode,
1855 .num_modes = 1,
1856 .size = {
1857 .width = 194,
1858 .height = 116,
1859 },
1860 .bus_format = MEDIA_BUS_FMT_RGB888_1X24,
1861 .bus_flags = DRM_BUS_FLAG_DE_HIGH | DRM_BUS_FLAG_PIXDATA_POSEDGE,
1862};
1863
1835static const struct drm_display_mode tpk_f07a_0102_mode = {1864static const struct drm_display_mode tpk_f07a_0102_mode = {
1836 .clock = 33260,1865 .clock = 33260,
1837 .hdisplay = 800,1866 .hdisplay = 800,
@@ -2113,6 +2142,9 @@ static const struct of_device_id platform_of_match[] = { · 275 unmodified lines
2113 }, {2142 }, {
2114 .compatible = "tianma,tm070jdhg30",2143 .compatible = "tianma,tm070jdhg30",
2115 .data = &tianma_tm070jdhg30,2144 .data = &tianma_tm070jdhg30,
2145 }, {
2146 .compatible = "toshiba,lt089ac29000",
2147 .data = &toshiba_lt089ac29000,
2116 }, {2148 }, {
2117 .compatible = "tpk,f07a-0102",2149 .compatible = "tpk,f07a-0102",
2118 .data = &tpk_f07a_0102,2150 .data = &tpk_f07a_0102,
drivers/gpu/drm/sun4i/Makefile+17−16
@@ -1,24 +1,25 @@
1sun4i-drm-y += sun4i_drv.o1sun4i-backend-y += sun4i_backend.o sun4i_layer.o
2sun4i-drm-y += sun4i_framebuffer.o
3 2
4sun4i-drm-hdmi-y += sun4i_hdmi_enc.o3sun4i-drm-y += sun4i_drv.o
5sun4i-drm-hdmi-y += sun4i_hdmi_i2c.o4sun4i-drm-y += sun4i_framebuffer.o
6sun4i-drm-hdmi-y += sun4i_hdmi_ddc_clk.o
7sun4i-drm-hdmi-y += sun4i_hdmi_tmds_clk.o
8 5
9sun4i-tcon-y += sun4i_tcon.o6sun4i-drm-hdmi-y += sun4i_hdmi_ddc_clk.o
10sun4i-tcon-y += sun4i_rgb.o7sun4i-drm-hdmi-y += sun4i_hdmi_enc.o
11sun4i-tcon-y += sun4i_dotclock.o8sun4i-drm-hdmi-y += sun4i_hdmi_i2c.o
12sun4i-tcon-y += sun4i_crtc.o9sun4i-drm-hdmi-y += sun4i_hdmi_tmds_clk.o
13 10
14sun4i-backend-y += sun4i_backend.o sun4i_layer.o11sun8i-mixer-y += sun8i_mixer.o sun8i_layer.o
15 12
16sun8i-mixer-y += sun8i_mixer.o sun8i_layer.o13sun4i-tcon-y += sun4i_crtc.o
14sun4i-tcon-y += sun4i_dotclock.o
15sun4i-tcon-y += sun4i_tcon.o
16sun4i-tcon-y += sun4i_rgb.o
17 17
18obj-$(CONFIG_DRM_SUN4I) += sun4i-drm.o sun4i-tcon.o18obj-$(CONFIG_DRM_SUN4I) += sun4i-drm.o
19obj-$(CONFIG_DRM_SUN4I) += sun6i_drc.o19obj-$(CONFIG_DRM_SUN4I) += sun4i-tcon.o
20obj-$(CONFIG_DRM_SUN4I) += sun4i_tv.o20obj-$(CONFIG_DRM_SUN4I) += sun4i_tv.o
21obj-$(CONFIG_DRM_SUN4I) += sun6i_drc.o
21 22
22obj-$(CONFIG_DRM_SUN4I_BACKEND) += sun4i-backend.o23obj-$(CONFIG_DRM_SUN4I_BACKEND) += sun4i-backend.o
23obj-$(CONFIG_DRM_SUN4I_HDMI) += sun4i-drm-hdmi.o24obj-$(CONFIG_DRM_SUN4I_HDMI) += sun4i-drm-hdmi.o
24obj-$(CONFIG_DRM_SUN8I_MIXER) += sun8i-mixer.o25obj-$(CONFIG_DRM_SUN8I_MIXER) += sun8i-mixer.o
drivers/gpu/drm/sun4i/sun4i_backend.c+72−3
@@ -20,6 +20,7 @@ · 19 unmodified lines
20 20
21#include <linux/component.h>21#include <linux/component.h>
22#include <linux/list.h>22#include <linux/list.h>
23#include <linux/of_device.h>
23#include <linux/of_graph.h>24#include <linux/of_graph.h>
24#include <linux/reset.h>25#include <linux/reset.h>
25 26
@@ -28,6 +29,11 @@ · 2 unmodified lines
28#include "sun4i_layer.h"29#include "sun4i_layer.h"
29#include "sunxi_engine.h"30#include "sunxi_engine.h"
30 31
32struct sun4i_backend_quirks {
33 /* backend <-> TCON muxing selection done in backend */
34 bool needs_output_muxing;
35};
36
31static const u32 sunxi_rgb2yuv_coef[12] = {37static const u32 sunxi_rgb2yuv_coef[12] = {
32 0x00000107, 0x00000204, 0x00000064, 0x00000108,38 0x00000107, 0x00000204, 0x00000064, 0x00000108,
33 0x00003f69, 0x00003ed6, 0x000001c1, 0x00000808,39 0x00003f69, 0x00003ed6, 0x000001c1, 0x00000808,
@@ -216,6 +222,13 @@ int sun4i_backend_update_layer_buffer(struct sun4i_backend *backend, · 182 unmodified lines
216 paddr = drm_fb_cma_get_gem_addr(fb, state, 0);222 paddr = drm_fb_cma_get_gem_addr(fb, state, 0);
217 DRM_DEBUG_DRIVER("Setting buffer address to %pad\n", &paddr);223 DRM_DEBUG_DRIVER("Setting buffer address to %pad\n", &paddr);
218 224
225 /*
226 * backend DMA accesses DRAM directly, bypassing the system
227 * bus. As such, the address range is different and the buffer
228 * address needs to be corrected.
229 */
230 paddr -= PHYS_OFFSET;
231
219 /* Write the 32 lower bits of the address (in bits) */232 /* Write the 32 lower bits of the address (in bits) */
220 lo_paddr = paddr << 3;233 lo_paddr = paddr << 3;
221 DRM_DEBUG_DRIVER("Setting address lower bits to 0x%x\n", lo_paddr);234 DRM_DEBUG_DRIVER("Setting address lower bits to 0x%x\n", lo_paddr);
@@ -338,6 +351,7 @@ static int sun4i_backend_bind(struct device *dev, struct device *master, · 116 unmodified lines
338 struct drm_device *drm = data;351 struct drm_device *drm = data;
339 struct sun4i_drv *drv = drm->dev_private;352 struct sun4i_drv *drv = drm->dev_private;
340 struct sun4i_backend *backend;353 struct sun4i_backend *backend;
354 const struct sun4i_backend_quirks *quirks;
341 struct resource *res;355 struct resource *res;
342 void __iomem *regs;356 void __iomem *regs;
343 int i, ret;357 int i, ret;
@@ -432,6 +446,27 @@ static int sun4i_backend_bind(struct device *dev, struct device *master, · 88 unmodified lines
432 SUN4I_BACKEND_MODCTL_DEBE_EN |446 SUN4I_BACKEND_MODCTL_DEBE_EN |
433 SUN4I_BACKEND_MODCTL_START_CTL);447 SUN4I_BACKEND_MODCTL_START_CTL);
434 448
449 /* Set output selection if needed */
450 quirks = of_device_get_match_data(dev);
451 if (quirks->needs_output_muxing) {
452 /*
453 * We assume there is no dynamic muxing of backends
454 * and TCONs, so we select the backend with same ID.
455 *
456 * While dynamic selection might be interesting, since
457 * the CRTC is tied to the TCON, while the layers are
458 * tied to the backends, this means, we will need to
459 * switch between groups of layers. There might not be
460 * a way to represent this constraint in DRM.
461 */
462 regmap_update_bits(backend->engine.regs,
463 SUN4I_BACKEND_MODCTL_REG,
464 SUN4I_BACKEND_MODCTL_OUT_SEL,
465 (backend->engine.id
466 ? SUN4I_BACKEND_MODCTL_OUT_LCD1
467 : SUN4I_BACKEND_MODCTL_OUT_LCD0));
468 }
469
435 return 0;470 return 0;
436 471
437err_disable_ram_clk:472err_disable_ram_clk:
@@ -479,10 +514,44 @@ static int sun4i_backend_remove(struct platform_device *pdev) · 41 unmodified lines
479 return 0;514 return 0;
480}515}
481 516
517static const struct sun4i_backend_quirks sun4i_backend_quirks = {
518 .needs_output_muxing = true,
519};
520
521static const struct sun4i_backend_quirks sun5i_backend_quirks = {
522};
523
524static const struct sun4i_backend_quirks sun6i_backend_quirks = {
525};
526
527static const struct sun4i_backend_quirks sun7i_backend_quirks = {
528 .needs_output_muxing = true,
529};
530
531static const struct sun4i_backend_quirks sun8i_a33_backend_quirks = {
532};
533
482static const struct of_device_id sun4i_backend_of_table[] = {534static const struct of_device_id sun4i_backend_of_table[] = {
483 { .compatible = "allwinner,sun5i-a13-display-backend" },535 {
484 { .compatible = "allwinner,sun6i-a31-display-backend" },536 .compatible = "allwinner,sun4i-a10-display-backend",
485 { .compatible = "allwinner,sun8i-a33-display-backend" },537 .data = &sun4i_backend_quirks,
538 },
539 {
540 .compatible = "allwinner,sun5i-a13-display-backend",
541 .data = &sun5i_backend_quirks,
542 },
543 {
544 .compatible = "allwinner,sun6i-a31-display-backend",
545 .data = &sun6i_backend_quirks,
546 },
547 {
548 .compatible = "allwinner,sun7i-a20-display-backend",
549 .data = &sun7i_backend_quirks,
550 },
551 {
552 .compatible = "allwinner,sun8i-a33-display-backend",
553 .data = &sun8i_a33_backend_quirks,
554 },
486 { }555 { }
487};556};
488MODULE_DEVICE_TABLE(of, sun4i_backend_of_table);557MODULE_DEVICE_TABLE(of, sun4i_backend_of_table);
drivers/gpu/drm/sun4i/sun4i_backend.h+2−1
@@ -25,7 +25,8 @@ · 24 unmodified lines
25#define SUN4I_BACKEND_MODCTL_LINE_SEL BIT(29)25#define SUN4I_BACKEND_MODCTL_LINE_SEL BIT(29)
26#define SUN4I_BACKEND_MODCTL_ITLMOD_EN BIT(28)26#define SUN4I_BACKEND_MODCTL_ITLMOD_EN BIT(28)
27#define SUN4I_BACKEND_MODCTL_OUT_SEL GENMASK(22, 20)27#define SUN4I_BACKEND_MODCTL_OUT_SEL GENMASK(22, 20)
28#define SUN4I_BACKEND_MODCTL_OUT_LCD (0 << 20)28#define SUN4I_BACKEND_MODCTL_OUT_LCD0 (0 << 20)
29#define SUN4I_BACKEND_MODCTL_OUT_LCD1 (1 << 20)
29#define SUN4I_BACKEND_MODCTL_OUT_FE0 (6 << 20)30#define SUN4I_BACKEND_MODCTL_OUT_FE0 (6 << 20)
30#define SUN4I_BACKEND_MODCTL_OUT_FE1 (7 << 20)31#define SUN4I_BACKEND_MODCTL_OUT_FE1 (7 << 20)
31#define SUN4I_BACKEND_MODCTL_HWC_EN BIT(16)32#define SUN4I_BACKEND_MODCTL_HWC_EN BIT(16)
drivers/gpu/drm/sun4i/sun4i_crtc.c+30−2
@@ -30,6 +30,22 @@ · 29 unmodified lines
30#include "sunxi_engine.h"30#include "sunxi_engine.h"
31#include "sun4i_tcon.h"31#include "sun4i_tcon.h"
32 32
33/*
34 * While this isn't really working in the DRM theory, in practice we
35 * can only ever have one encoder per TCON since we have a mux in our
36 * TCON.
37 */
38static struct drm_encoder *sun4i_crtc_get_encoder(struct drm_crtc *crtc)
39{
40 struct drm_encoder *encoder;
41
42 drm_for_each_encoder(encoder, crtc->dev)
43 if (encoder->crtc == crtc)
44 return encoder;
45
46 return NULL;
47}
48
33static void sun4i_crtc_atomic_begin(struct drm_crtc *crtc,49static void sun4i_crtc_atomic_begin(struct drm_crtc *crtc,
34 struct drm_crtc_state *old_state)50 struct drm_crtc_state *old_state)
35{51{
@@ -72,11 +88,12 @@ static void sun4i_crtc_atomic_flush(struct drm_crtc *crtc, · 36 unmodified lines
72static void sun4i_crtc_atomic_disable(struct drm_crtc *crtc,88static void sun4i_crtc_atomic_disable(struct drm_crtc *crtc,
73 struct drm_crtc_state *old_state)89 struct drm_crtc_state *old_state)
74{90{
91 struct drm_encoder *encoder = sun4i_crtc_get_encoder(crtc);
75 struct sun4i_crtc *scrtc = drm_crtc_to_sun4i_crtc(crtc);92 struct sun4i_crtc *scrtc = drm_crtc_to_sun4i_crtc(crtc);
76 93
77 DRM_DEBUG_DRIVER("Disabling the CRTC\n");94 DRM_DEBUG_DRIVER("Disabling the CRTC\n");
78 95
79 sun4i_tcon_disable(scrtc->tcon);96 sun4i_tcon_set_status(scrtc->tcon, encoder, false);
80 97
81 if (crtc->state->event && !crtc->state->active) {98 if (crtc->state->event && !crtc->state->active) {
82 spin_lock_irq(&crtc->dev->event_lock);99 spin_lock_irq(&crtc->dev->event_lock);
@@ -90,11 +107,21 @@ static void sun4i_crtc_atomic_disable(struct drm_crtc *crtc, · 7 unmodified lines
90static void sun4i_crtc_atomic_enable(struct drm_crtc *crtc,107static void sun4i_crtc_atomic_enable(struct drm_crtc *crtc,
91 struct drm_crtc_state *old_state)108 struct drm_crtc_state *old_state)
92{109{
110 struct drm_encoder *encoder = sun4i_crtc_get_encoder(crtc);
93 struct sun4i_crtc *scrtc = drm_crtc_to_sun4i_crtc(crtc);111 struct sun4i_crtc *scrtc = drm_crtc_to_sun4i_crtc(crtc);
94 112
95 DRM_DEBUG_DRIVER("Enabling the CRTC\n");113 DRM_DEBUG_DRIVER("Enabling the CRTC\n");
96 114
97 sun4i_tcon_enable(scrtc->tcon);115 sun4i_tcon_set_status(scrtc->tcon, encoder, true);
116}
117
118static void sun4i_crtc_mode_set_nofb(struct drm_crtc *crtc)
119{
120 struct drm_display_mode *mode = &crtc->state->adjusted_mode;
121 struct drm_encoder *encoder = sun4i_crtc_get_encoder(crtc);
122 struct sun4i_crtc *scrtc = drm_crtc_to_sun4i_crtc(crtc);
123
124 sun4i_tcon_mode_set(scrtc->tcon, encoder, mode);
98}125}
99 126
100static const struct drm_crtc_helper_funcs sun4i_crtc_helper_funcs = {127static const struct drm_crtc_helper_funcs sun4i_crtc_helper_funcs = {
@@ -102,6 +129,7 @@ static const struct drm_crtc_helper_funcs sun4i_crtc_helper_funcs = { · 1 unmodified line
102 .atomic_flush = sun4i_crtc_atomic_flush,129 .atomic_flush = sun4i_crtc_atomic_flush,
103 .atomic_enable = sun4i_crtc_atomic_enable,130 .atomic_enable = sun4i_crtc_atomic_enable,
104 .atomic_disable = sun4i_crtc_atomic_disable,131 .atomic_disable = sun4i_crtc_atomic_disable,
132 .mode_set_nofb = sun4i_crtc_mode_set_nofb,
105};133};
106 134
107static int sun4i_crtc_enable_vblank(struct drm_crtc *crtc)135static int sun4i_crtc_enable_vblank(struct drm_crtc *crtc)
drivers/gpu/drm/sun4i/sun4i_drv.c+21−60
@@ -11,6 +11,7 @@ · 10 unmodified lines
11 */11 */
12 12
13#include <linux/component.h>13#include <linux/component.h>
14#include <linux/kfifo.h>
14#include <linux/of_graph.h>15#include <linux/of_graph.h>
15#include <linux/of_reserved_mem.h>16#include <linux/of_reserved_mem.h>
16 17
@@ -177,16 +178,20 @@ static bool sun4i_drv_node_is_connector(struct device_node *node) · 160 unmodified lines
177 178
178static bool sun4i_drv_node_is_frontend(struct device_node *node)179static bool sun4i_drv_node_is_frontend(struct device_node *node)
179{180{
180 return of_device_is_compatible(node, "allwinner,sun5i-a13-display-frontend") ||181 return of_device_is_compatible(node, "allwinner,sun4i-a10-display-frontend") ||
182 of_device_is_compatible(node, "allwinner,sun5i-a13-display-frontend") ||
181 of_device_is_compatible(node, "allwinner,sun6i-a31-display-frontend") ||183 of_device_is_compatible(node, "allwinner,sun6i-a31-display-frontend") ||
184 of_device_is_compatible(node, "allwinner,sun7i-a20-display-frontend") ||
182 of_device_is_compatible(node, "allwinner,sun8i-a33-display-frontend");185 of_device_is_compatible(node, "allwinner,sun8i-a33-display-frontend");
183}186}
184 187
185static bool sun4i_drv_node_is_tcon(struct device_node *node)188static bool sun4i_drv_node_is_tcon(struct device_node *node)
186{189{
187 return of_device_is_compatible(node, "allwinner,sun5i-a13-tcon") ||190 return of_device_is_compatible(node, "allwinner,sun4i-a10-tcon") ||
191 of_device_is_compatible(node, "allwinner,sun5i-a13-tcon") ||
188 of_device_is_compatible(node, "allwinner,sun6i-a31-tcon") ||192 of_device_is_compatible(node, "allwinner,sun6i-a31-tcon") ||
189 of_device_is_compatible(node, "allwinner,sun6i-a31s-tcon") ||193 of_device_is_compatible(node, "allwinner,sun6i-a31s-tcon") ||
194 of_device_is_compatible(node, "allwinner,sun7i-a20-tcon") ||
190 of_device_is_compatible(node, "allwinner,sun8i-a33-tcon") ||195 of_device_is_compatible(node, "allwinner,sun8i-a33-tcon") ||
191 of_device_is_compatible(node, "allwinner,sun8i-v3s-tcon");196 of_device_is_compatible(node, "allwinner,sun8i-v3s-tcon");
192}197}
@@ -222,29 +227,15 @@ static int compare_of(struct device *dev, void *data) · 29 unmodified lines
222 * matching system handles this for us.227 * matching system handles this for us.
223 */228 */
224struct endpoint_list {229struct endpoint_list {
225 struct device_node *node;230 DECLARE_KFIFO(fifo, struct device_node *, 16);
226 struct list_head list;
227};231};
228 232
229static bool node_is_in_list(struct list_head *endpoints,
230 struct device_node *node)
231{
232 struct endpoint_list *endpoint;
233
234 list_for_each_entry(endpoint, endpoints, list)
235 if (endpoint->node == node)
236 return true;
237
238 return false;
239}
240
241static int sun4i_drv_add_endpoints(struct device *dev,233static int sun4i_drv_add_endpoints(struct device *dev,
242 struct list_head *endpoints,234 struct endpoint_list *list,
243 struct component_match **match,235 struct component_match **match,
244 struct device_node *node)236 struct device_node *node)
245{237{
246 struct device_node *port, *ep, *remote;238 struct device_node *port, *ep, *remote;
247 struct endpoint_list *endpoint;
248 int count = 0;239 int count = 0;
249 240
250 /*241 /*
@@ -304,19 +295,7 @@ static int sun4i_drv_add_endpoints(struct device *dev, · 53 unmodified lines
304 }295 }
305 }296 }
306 297
307 /* skip downstream node if it is already in the queue */298 kfifo_put(&list->fifo, remote);
308 if (node_is_in_list(endpoints, remote))
309 continue;
310
311 /* Add downstream nodes to the queue */
312 endpoint = kzalloc(sizeof(*endpoint), GFP_KERNEL);
313 if (!endpoint) {
314 of_node_put(remote);
315 return -ENOMEM;
316 }
317
318 endpoint->node = remote;
319 list_add_tail(&endpoint->list, endpoints);
320 }299 }
321 300
322 return count;301 return count;
@@ -325,10 +304,11 @@ static int sun4i_drv_add_endpoints(struct device *dev, · 2 unmodified lines
325static int sun4i_drv_probe(struct platform_device *pdev)304static int sun4i_drv_probe(struct platform_device *pdev)
326{305{
327 struct component_match *match = NULL;306 struct component_match *match = NULL;
328 struct device_node *np = pdev->dev.of_node;307 struct device_node *np = pdev->dev.of_node, *endpoint;
329 struct endpoint_list *endpoint, *endpoint_temp;308 struct endpoint_list list;
330 int i, ret, count = 0;309 int i, ret, count = 0;
331 LIST_HEAD(endpoints);310
311 INIT_KFIFO(list.fifo);
332 312
333 for (i = 0;; i++) {313 for (i = 0;; i++) {
334 struct device_node *pipeline = of_parse_phandle(np,314 struct device_node *pipeline = of_parse_phandle(np,
@@ -337,31 +317,19 @@ static int sun4i_drv_probe(struct platform_device *pdev) · 2 unmodified lines
337 if (!pipeline)317 if (!pipeline)
338 break;318 break;
339 319
340 endpoint = kzalloc(sizeof(*endpoint), GFP_KERNEL);320 kfifo_put(&list.fifo, pipeline);
341 if (!endpoint) {
342 ret = -ENOMEM;
343 goto err_free_endpoints;
344 }
345
346 endpoint->node = pipeline;
347 list_add_tail(&endpoint->list, &endpoints);
348 }321 }
349 322
350 list_for_each_entry_safe(endpoint, endpoint_temp, &endpoints, list) {323 while (kfifo_get(&list.fifo, &endpoint)) {
351 /* process this endpoint */324 /* process this endpoint */
352 ret = sun4i_drv_add_endpoints(&pdev->dev, &endpoints, &match,325 ret = sun4i_drv_add_endpoints(&pdev->dev, &list, &match,
353 endpoint->node);326 endpoint);
354 327
355 /* sun4i_drv_add_endpoints can fail to allocate memory */328 /* sun4i_drv_add_endpoints can fail to allocate memory */
356 if (ret < 0)329 if (ret < 0)
357 goto err_free_endpoints;330 return ret;
358 331
359 count += ret;332 count += ret;
360
361 /* delete and cleanup the current entry */
362 list_del(&endpoint->list);
363 of_node_put(endpoint->node);
364 kfree(endpoint);
365 }333 }
366 334
367 if (count)335 if (count)
@@ -370,15 +338,6 @@ static int sun4i_drv_probe(struct platform_device *pdev) · 2 unmodified lines
370 match);338 match);
371 else339 else
372 return 0;340 return 0;
373
374err_free_endpoints:
375 list_for_each_entry_safe(endpoint, endpoint_temp, &endpoints, list) {
376 list_del(&endpoint->list);
377 of_node_put(endpoint->node);
378 kfree(endpoint);
379 }
380
381 return ret;
382}341}
383 342
384static int sun4i_drv_remove(struct platform_device *pdev)343static int sun4i_drv_remove(struct platform_device *pdev)
@@ -387,10 +346,12 @@ static int sun4i_drv_remove(struct platform_device *pdev) · 2 unmodified lines
387}346}
388 347
389static const struct of_device_id sun4i_drv_of_table[] = {348static const struct of_device_id sun4i_drv_of_table[] = {
349 { .compatible = "allwinner,sun4i-a10-display-engine" },
390 { .compatible = "allwinner,sun5i-a10s-display-engine" },350 { .compatible = "allwinner,sun5i-a10s-display-engine" },
391 { .compatible = "allwinner,sun5i-a13-display-engine" },351 { .compatible = "allwinner,sun5i-a13-display-engine" },
392 { .compatible = "allwinner,sun6i-a31-display-engine" },352 { .compatible = "allwinner,sun6i-a31-display-engine" },
393 { .compatible = "allwinner,sun6i-a31s-display-engine" },353 { .compatible = "allwinner,sun6i-a31s-display-engine" },
354 { .compatible = "allwinner,sun7i-a20-display-engine" },
394 { .compatible = "allwinner,sun8i-a33-display-engine" },355 { .compatible = "allwinner,sun8i-a33-display-engine" },
395 { .compatible = "allwinner,sun8i-v3s-display-engine" },356 { .compatible = "allwinner,sun8i-v3s-display-engine" },
396 { }357 { }
drivers/gpu/drm/sun4i/sun4i_hdmi_ddc_clk.c+0−1
@@ -13,7 +13,6 @@ · 12 unmodified lines
13#include <linux/clk-provider.h>13#include <linux/clk-provider.h>
14#include <linux/regmap.h>14#include <linux/regmap.h>
15 15
16#include "sun4i_tcon.h"
17#include "sun4i_hdmi.h"16#include "sun4i_hdmi.h"
18 17
19struct sun4i_ddc {18struct sun4i_ddc {
drivers/gpu/drm/sun4i/sun4i_hdmi_enc.c+53−15
@@ -30,7 +30,6 @@ · 29 unmodified lines
30#include "sun4i_crtc.h"30#include "sun4i_crtc.h"
31#include "sun4i_drv.h"31#include "sun4i_drv.h"
32#include "sun4i_hdmi.h"32#include "sun4i_hdmi.h"
33#include "sun4i_tcon.h"
34 33
35static inline struct sun4i_hdmi *34static inline struct sun4i_hdmi *
36drm_encoder_to_sun4i_hdmi(struct drm_encoder *encoder)35drm_encoder_to_sun4i_hdmi(struct drm_encoder *encoder)
@@ -86,8 +85,6 @@ static int sun4i_hdmi_atomic_check(struct drm_encoder *encoder, · 49 unmodified lines
86static void sun4i_hdmi_disable(struct drm_encoder *encoder)85static void sun4i_hdmi_disable(struct drm_encoder *encoder)
87{86{
88 struct sun4i_hdmi *hdmi = drm_encoder_to_sun4i_hdmi(encoder);87 struct sun4i_hdmi *hdmi = drm_encoder_to_sun4i_hdmi(encoder);
89 struct sun4i_crtc *crtc = drm_crtc_to_sun4i_crtc(encoder->crtc);
90 struct sun4i_tcon *tcon = crtc->tcon;
91 u32 val;88 u32 val;
92 89
93 DRM_DEBUG_DRIVER("Disabling the HDMI Output\n");90 DRM_DEBUG_DRIVER("Disabling the HDMI Output\n");
@@ -95,22 +92,16 @@ static void sun4i_hdmi_disable(struct drm_encoder *encoder) · 1 unmodified line
95 val = readl(hdmi->base + SUN4I_HDMI_VID_CTRL_REG);92 val = readl(hdmi->base + SUN4I_HDMI_VID_CTRL_REG);
96 val &= ~SUN4I_HDMI_VID_CTRL_ENABLE;93 val &= ~SUN4I_HDMI_VID_CTRL_ENABLE;
97 writel(val, hdmi->base + SUN4I_HDMI_VID_CTRL_REG);94 writel(val, hdmi->base + SUN4I_HDMI_VID_CTRL_REG);
98
99 sun4i_tcon_channel_disable(tcon, 1);
100}95}
101 96
102static void sun4i_hdmi_enable(struct drm_encoder *encoder)97static void sun4i_hdmi_enable(struct drm_encoder *encoder)
103{98{
104 struct drm_display_mode *mode = &encoder->crtc->state->adjusted_mode;99 struct drm_display_mode *mode = &encoder->crtc->state->adjusted_mode;
105 struct sun4i_hdmi *hdmi = drm_encoder_to_sun4i_hdmi(encoder);100 struct sun4i_hdmi *hdmi = drm_encoder_to_sun4i_hdmi(encoder);
106 struct sun4i_crtc *crtc = drm_crtc_to_sun4i_crtc(encoder->crtc);
107 struct sun4i_tcon *tcon = crtc->tcon;
108 u32 val = 0;101 u32 val = 0;
109 102
110 DRM_DEBUG_DRIVER("Enabling the HDMI Output\n");103 DRM_DEBUG_DRIVER("Enabling the HDMI Output\n");
111 104
112 sun4i_tcon_channel_enable(tcon, 1);
113
114 sun4i_hdmi_setup_avi_infoframes(hdmi, mode);105 sun4i_hdmi_setup_avi_infoframes(hdmi, mode);
115 val |= SUN4I_HDMI_PKT_CTRL_TYPE(0, SUN4I_HDMI_PKT_AVI);106 val |= SUN4I_HDMI_PKT_CTRL_TYPE(0, SUN4I_HDMI_PKT_AVI);
116 val |= SUN4I_HDMI_PKT_CTRL_TYPE(1, SUN4I_HDMI_PKT_END);107 val |= SUN4I_HDMI_PKT_CTRL_TYPE(1, SUN4I_HDMI_PKT_END);
@@ -128,15 +119,9 @@ static void sun4i_hdmi_mode_set(struct drm_encoder *encoder, · 11 unmodified lines
128 struct drm_display_mode *adjusted_mode)119 struct drm_display_mode *adjusted_mode)
129{120{
130 struct sun4i_hdmi *hdmi = drm_encoder_to_sun4i_hdmi(encoder);121 struct sun4i_hdmi *hdmi = drm_encoder_to_sun4i_hdmi(encoder);
131 struct sun4i_crtc *crtc = drm_crtc_to_sun4i_crtc(encoder->crtc);
132 struct sun4i_tcon *tcon = crtc->tcon;
133 unsigned int x, y;122 unsigned int x, y;
134 u32 val;123 u32 val;
135 124
136 sun4i_tcon1_mode_set(tcon, mode);
137 sun4i_tcon_set_mux(tcon, 1, encoder);
138
139 clk_set_rate(tcon->sclk1, mode->crtc_clock * 1000);
140 clk_set_rate(hdmi->mod_clk, mode->crtc_clock * 1000);125 clk_set_rate(hdmi->mod_clk, mode->crtc_clock * 1000);
141 clk_set_rate(hdmi->tmds_clk, mode->crtc_clock * 1000);126 clk_set_rate(hdmi->tmds_clk, mode->crtc_clock * 1000);
142 127
@@ -289,6 +274,58 @@ static const struct cec_pin_ops sun4i_hdmi_cec_pin_ops = { · 146 unmodified lines
289#define SUN4I_HDMI_PAD_CTRL1_MASK (GENMASK(24, 7) | GENMASK(5, 0))274#define SUN4I_HDMI_PAD_CTRL1_MASK (GENMASK(24, 7) | GENMASK(5, 0))
290#define SUN4I_HDMI_PLL_CTRL_MASK (GENMASK(31, 8) | GENMASK(3, 0))275#define SUN4I_HDMI_PLL_CTRL_MASK (GENMASK(31, 8) | GENMASK(3, 0))
291 276
277/* Only difference from sun5i is AMP is 4 instead of 6 */
278static const struct sun4i_hdmi_variant sun4i_variant = {
279 .pad_ctrl0_init_val = SUN4I_HDMI_PAD_CTRL0_TXEN |
280 SUN4I_HDMI_PAD_CTRL0_CKEN |
281 SUN4I_HDMI_PAD_CTRL0_PWENG |
282 SUN4I_HDMI_PAD_CTRL0_PWEND |
283 SUN4I_HDMI_PAD_CTRL0_PWENC |
284 SUN4I_HDMI_PAD_CTRL0_LDODEN |
285 SUN4I_HDMI_PAD_CTRL0_LDOCEN |
286 SUN4I_HDMI_PAD_CTRL0_BIASEN,
287 .pad_ctrl1_init_val = SUN4I_HDMI_PAD_CTRL1_REG_AMP(4) |
288 SUN4I_HDMI_PAD_CTRL1_REG_EMP(2) |
289 SUN4I_HDMI_PAD_CTRL1_REG_DENCK |
290 SUN4I_HDMI_PAD_CTRL1_REG_DEN |
291 SUN4I_HDMI_PAD_CTRL1_EMPCK_OPT |
292 SUN4I_HDMI_PAD_CTRL1_EMP_OPT |
293 SUN4I_HDMI_PAD_CTRL1_AMPCK_OPT |
294 SUN4I_HDMI_PAD_CTRL1_AMP_OPT,
295 .pll_ctrl_init_val = SUN4I_HDMI_PLL_CTRL_VCO_S(8) |
296 SUN4I_HDMI_PLL_CTRL_CS(7) |
297 SUN4I_HDMI_PLL_CTRL_CP_S(15) |
298 SUN4I_HDMI_PLL_CTRL_S(7) |
299 SUN4I_HDMI_PLL_CTRL_VCO_GAIN(4) |
300 SUN4I_HDMI_PLL_CTRL_SDIV2 |
301 SUN4I_HDMI_PLL_CTRL_LDO2_EN |
302 SUN4I_HDMI_PLL_CTRL_LDO1_EN |
303 SUN4I_HDMI_PLL_CTRL_HV_IS_33 |
304 SUN4I_HDMI_PLL_CTRL_BWS |
305 SUN4I_HDMI_PLL_CTRL_PLL_EN,
306
307 .ddc_clk_reg = REG_FIELD(SUN4I_HDMI_DDC_CLK_REG, 0, 6),
308 .ddc_clk_pre_divider = 2,
309 .ddc_clk_m_offset = 1,
310
311 .field_ddc_en = REG_FIELD(SUN4I_HDMI_DDC_CTRL_REG, 31, 31),
312 .field_ddc_start = REG_FIELD(SUN4I_HDMI_DDC_CTRL_REG, 30, 30),
313 .field_ddc_reset = REG_FIELD(SUN4I_HDMI_DDC_CTRL_REG, 0, 0),
314 .field_ddc_addr_reg = REG_FIELD(SUN4I_HDMI_DDC_ADDR_REG, 0, 31),
315 .field_ddc_slave_addr = REG_FIELD(SUN4I_HDMI_DDC_ADDR_REG, 0, 6),
316 .field_ddc_int_status = REG_FIELD(SUN4I_HDMI_DDC_INT_STATUS_REG, 0, 8),
317 .field_ddc_fifo_clear = REG_FIELD(SUN4I_HDMI_DDC_FIFO_CTRL_REG, 31, 31),
318 .field_ddc_fifo_rx_thres = REG_FIELD(SUN4I_HDMI_DDC_FIFO_CTRL_REG, 4, 7),
319 .field_ddc_fifo_tx_thres = REG_FIELD(SUN4I_HDMI_DDC_FIFO_CTRL_REG, 0, 3),
320 .field_ddc_byte_count = REG_FIELD(SUN4I_HDMI_DDC_BYTE_COUNT_REG, 0, 9),
321 .field_ddc_cmd = REG_FIELD(SUN4I_HDMI_DDC_CMD_REG, 0, 2),
322 .field_ddc_sda_en = REG_FIELD(SUN4I_HDMI_DDC_LINE_CTRL_REG, 9, 9),
323 .field_ddc_sck_en = REG_FIELD(SUN4I_HDMI_DDC_LINE_CTRL_REG, 8, 8),
324
325 .ddc_fifo_reg = SUN4I_HDMI_DDC_FIFO_DATA_REG,
326 .ddc_fifo_has_dir = true,
327};
328
292static const struct sun4i_hdmi_variant sun5i_variant = {329static const struct sun4i_hdmi_variant sun5i_variant = {
293 .pad_ctrl0_init_val = SUN4I_HDMI_PAD_CTRL0_TXEN |330 .pad_ctrl0_init_val = SUN4I_HDMI_PAD_CTRL0_TXEN |
294 SUN4I_HDMI_PAD_CTRL0_CKEN |331 SUN4I_HDMI_PAD_CTRL0_CKEN |
@@ -613,6 +650,7 @@ static int sun4i_hdmi_remove(struct platform_device *pdev) · 318 unmodified lines
613}650}
614 651
615static const struct of_device_id sun4i_hdmi_of_table[] = {652static const struct of_device_id sun4i_hdmi_of_table[] = {
653 { .compatible = "allwinner,sun4i-a10-hdmi", .data = &sun4i_variant, },
616 { .compatible = "allwinner,sun5i-a10s-hdmi", .data = &sun5i_variant, },654 { .compatible = "allwinner,sun5i-a10s-hdmi", .data = &sun5i_variant, },
617 { .compatible = "allwinner,sun6i-a31-hdmi", .data = &sun6i_variant, },655 { .compatible = "allwinner,sun6i-a31-hdmi", .data = &sun6i_variant, },
618 { }656 { }
drivers/gpu/drm/sun4i/sun4i_hdmi_tmds_clk.c+0−1
@@ -12,7 +12,6 @@ · 11 unmodified lines
12 12
13#include <linux/clk-provider.h>13#include <linux/clk-provider.h>
14 14
15#include "sun4i_tcon.h"
16#include "sun4i_hdmi.h"15#include "sun4i_hdmi.h"
17 16
18struct sun4i_tmds {17struct sun4i_tmds {
drivers/gpu/drm/sun4i/sun4i_rgb.c+4−25
@@ -134,13 +134,10 @@ static void sun4i_rgb_encoder_enable(struct drm_encoder *encoder) · 133 unmodified lines
134 134
135 DRM_DEBUG_DRIVER("Enabling RGB output\n");135 DRM_DEBUG_DRIVER("Enabling RGB output\n");
136 136
137 if (!IS_ERR(tcon->panel))137 if (!IS_ERR(tcon->panel)) {
138 drm_panel_prepare(tcon->panel);138 drm_panel_prepare(tcon->panel);
139
140 sun4i_tcon_channel_enable(tcon, 0);
141
142 if (!IS_ERR(tcon->panel))
143 drm_panel_enable(tcon->panel);139 drm_panel_enable(tcon->panel);
140 }
144}141}
145 142
146static void sun4i_rgb_encoder_disable(struct drm_encoder *encoder)143static void sun4i_rgb_encoder_disable(struct drm_encoder *encoder)
@@ -150,31 +147,13 @@ static void sun4i_rgb_encoder_disable(struct drm_encoder *encoder) · 3 unmodified lines
150 147
151 DRM_DEBUG_DRIVER("Disabling RGB output\n");148 DRM_DEBUG_DRIVER("Disabling RGB output\n");
152 149
153 if (!IS_ERR(tcon->panel))150 if (!IS_ERR(tcon->panel)) {
154 drm_panel_disable(tcon->panel);151 drm_panel_disable(tcon->panel);
155
156 sun4i_tcon_channel_disable(tcon, 0);
157
158 if (!IS_ERR(tcon->panel))
159 drm_panel_unprepare(tcon->panel);152 drm_panel_unprepare(tcon->panel);
160}153 }
161
162static void sun4i_rgb_encoder_mode_set(struct drm_encoder *encoder,
163 struct drm_display_mode *mode,
164 struct drm_display_mode *adjusted_mode)
165{
166 struct sun4i_rgb *rgb = drm_encoder_to_sun4i_rgb(encoder);
167 struct sun4i_tcon *tcon = rgb->tcon;
168
169 sun4i_tcon0_mode_set(tcon, mode);
170 sun4i_tcon_set_mux(tcon, 0, encoder);
171
172 /* FIXME: This seems to be board specific */
173 clk_set_phase(tcon->dclk, 120);
174}154}
175 155
176static struct drm_encoder_helper_funcs sun4i_rgb_enc_helper_funcs = {156static struct drm_encoder_helper_funcs sun4i_rgb_enc_helper_funcs = {
177 .mode_set = sun4i_rgb_encoder_mode_set,
178 .disable = sun4i_rgb_encoder_disable,157 .disable = sun4i_rgb_encoder_disable,
179 .enable = sun4i_rgb_encoder_enable,158 .enable = sun4i_rgb_encoder_enable,
180};159};
drivers/gpu/drm/sun4i/sun4i_tcon.c+119−64
@@ -35,66 +35,61 @@ · 34 unmodified lines
35#include "sun4i_tcon.h"35#include "sun4i_tcon.h"
36#include "sunxi_engine.h"36#include "sunxi_engine.h"
37 37
38void sun4i_tcon_disable(struct sun4i_tcon *tcon)38static void sun4i_tcon_channel_set_status(struct sun4i_tcon *tcon, int channel,
39 bool enabled)
39{40{
40 DRM_DEBUG_DRIVER("Disabling TCON\n");41 struct clk *clk;
41 42
42 /* Disable the TCON */43 switch (channel) {
43 regmap_update_bits(tcon->regs, SUN4I_TCON_GCTL_REG,44 case 0:
44 SUN4I_TCON_GCTL_TCON_ENABLE, 0);
45}
46EXPORT_SYMBOL(sun4i_tcon_disable);
47
48void sun4i_tcon_enable(struct sun4i_tcon *tcon)
49{
50 DRM_DEBUG_DRIVER("Enabling TCON\n");
51
52 /* Enable the TCON */
53 regmap_update_bits(tcon->regs, SUN4I_TCON_GCTL_REG,
54 SUN4I_TCON_GCTL_TCON_ENABLE,
55 SUN4I_TCON_GCTL_TCON_ENABLE);
56}
57EXPORT_SYMBOL(sun4i_tcon_enable);
58
59void sun4i_tcon_channel_disable(struct sun4i_tcon *tcon, int channel)
60{
61 DRM_DEBUG_DRIVER("Disabling TCON channel %d\n", channel);
62
63 /* Disable the TCON's channel */
64 if (channel == 0) {
65 regmap_update_bits(tcon->regs, SUN4I_TCON0_CTL_REG,45 regmap_update_bits(tcon->regs, SUN4I_TCON0_CTL_REG,
66 SUN4I_TCON0_CTL_TCON_ENABLE, 0);46 SUN4I_TCON0_CTL_TCON_ENABLE,
67 clk_disable_unprepare(tcon->dclk);47 enabled ? SUN4I_TCON0_CTL_TCON_ENABLE : 0);
48 clk = tcon->dclk;
49 break;
50 case 1:
51 WARN_ON(!tcon->quirks->has_channel_1);
52 regmap_update_bits(tcon->regs, SUN4I_TCON1_CTL_REG,
53 SUN4I_TCON1_CTL_TCON_ENABLE,
54 enabled ? SUN4I_TCON1_CTL_TCON_ENABLE : 0);
55 clk = tcon->sclk1;
56 break;
57 default:
58 DRM_WARN("Unknown channel... doing nothing\n");
68 return;59 return;
69 }60 }
70 61
71 WARN_ON(!tcon->quirks->has_channel_1);62 if (enabled)
72 regmap_update_bits(tcon->regs, SUN4I_TCON1_CTL_REG,63 clk_prepare_enable(clk);
73 SUN4I_TCON1_CTL_TCON_ENABLE, 0);64 else
74 clk_disable_unprepare(tcon->sclk1);65 clk_disable_unprepare(clk);
75}66}
76EXPORT_SYMBOL(sun4i_tcon_channel_disable);
77 67
78void sun4i_tcon_channel_enable(struct sun4i_tcon *tcon, int channel)68void sun4i_tcon_set_status(struct sun4i_tcon *tcon,
69 const struct drm_encoder *encoder,
70 bool enabled)
79{71{
80 DRM_DEBUG_DRIVER("Enabling TCON channel %d\n", channel);72 int channel;
81 73
82 /* Enable the TCON's channel */74 switch (encoder->encoder_type) {
83 if (channel == 0) {75 case DRM_MODE_ENCODER_NONE:
84 regmap_update_bits(tcon->regs, SUN4I_TCON0_CTL_REG,76 channel = 0;
85 SUN4I_TCON0_CTL_TCON_ENABLE,77 break;
86 SUN4I_TCON0_CTL_TCON_ENABLE);78 case DRM_MODE_ENCODER_TMDS:
87 clk_prepare_enable(tcon->dclk);79 case DRM_MODE_ENCODER_TVDAC:
80 channel = 1;
81 break;
82 default:
83 DRM_DEBUG_DRIVER("Unknown encoder type, doing nothing...\n");
88 return;84 return;
89 }85 }
90 86
91 WARN_ON(!tcon->quirks->has_channel_1);87 regmap_update_bits(tcon->regs, SUN4I_TCON_GCTL_REG,
92 regmap_update_bits(tcon->regs, SUN4I_TCON1_CTL_REG,88 SUN4I_TCON_GCTL_TCON_ENABLE,
93 SUN4I_TCON1_CTL_TCON_ENABLE,89 enabled ? SUN4I_TCON_GCTL_TCON_ENABLE : 0);
94 SUN4I_TCON1_CTL_TCON_ENABLE);90
95 clk_prepare_enable(tcon->sclk1);91 sun4i_tcon_channel_set_status(tcon, channel, enabled);
96}92}
97EXPORT_SYMBOL(sun4i_tcon_channel_enable);
98 93
99void sun4i_tcon_enable_vblank(struct sun4i_tcon *tcon, bool enable)94void sun4i_tcon_enable_vblank(struct sun4i_tcon *tcon, bool enable)
100{95{
@@ -134,7 +129,7 @@ static struct sun4i_tcon *sun4i_get_tcon0(struct drm_device *drm) · 33 unmodified lines
134}129}
135 130
136void sun4i_tcon_set_mux(struct sun4i_tcon *tcon, int channel,131void sun4i_tcon_set_mux(struct sun4i_tcon *tcon, int channel,
137 struct drm_encoder *encoder)132 const struct drm_encoder *encoder)
138{133{
139 int ret = -ENOTSUPP;134 int ret = -ENOTSUPP;
140 135
@@ -144,9 +139,8 @@ void sun4i_tcon_set_mux(struct sun4i_tcon *tcon, int channel, · 3 unmodified lines
144 DRM_DEBUG_DRIVER("Muxing encoder %s to CRTC %s: %d\n",139 DRM_DEBUG_DRIVER("Muxing encoder %s to CRTC %s: %d\n",
145 encoder->name, encoder->crtc->name, ret);140 encoder->name, encoder->crtc->name, ret);
146}141}
147EXPORT_SYMBOL(sun4i_tcon_set_mux);
148 142
149static int sun4i_tcon_get_clk_delay(struct drm_display_mode *mode,143static int sun4i_tcon_get_clk_delay(const struct drm_display_mode *mode,
150 int channel)144 int channel)
151{145{
152 int delay = mode->vtotal - mode->vdisplay;146 int delay = mode->vtotal - mode->vdisplay;
@@ -164,15 +158,26 @@ static int sun4i_tcon_get_clk_delay(struct drm_display_mode *mode, · 11 unmodified lines
164 return delay;158 return delay;
165}159}
166 160
167void sun4i_tcon0_mode_set(struct sun4i_tcon *tcon,161static void sun4i_tcon0_mode_set_common(struct sun4i_tcon *tcon,
168 struct drm_display_mode *mode)162 const struct drm_display_mode *mode)
163{
164 /* Configure the dot clock */
165 clk_set_rate(tcon->dclk, mode->crtc_clock * 1000);
166
167 /* Set the resolution */
168 regmap_write(tcon->regs, SUN4I_TCON0_BASIC0_REG,
169 SUN4I_TCON0_BASIC0_X(mode->crtc_hdisplay) |
170 SUN4I_TCON0_BASIC0_Y(mode->crtc_vdisplay));
171}
172
173static void sun4i_tcon0_mode_set_rgb(struct sun4i_tcon *tcon,
174 const struct drm_display_mode *mode)
169{175{
170 unsigned int bp, hsync, vsync;176 unsigned int bp, hsync, vsync;
171 u8 clk_delay;177 u8 clk_delay;
172 u32 val = 0;178 u32 val = 0;
173 179
174 /* Configure the dot clock */180 sun4i_tcon0_mode_set_common(tcon, mode);
175 clk_set_rate(tcon->dclk, mode->crtc_clock * 1000);
176 181
177 /* Adjust clock delay */182 /* Adjust clock delay */
178 clk_delay = sun4i_tcon_get_clk_delay(mode, 0);183 clk_delay = sun4i_tcon_get_clk_delay(mode, 0);
@@ -180,11 +185,6 @@ void sun4i_tcon0_mode_set(struct sun4i_tcon *tcon, · 1 unmodified line
180 SUN4I_TCON0_CTL_CLK_DELAY_MASK,185 SUN4I_TCON0_CTL_CLK_DELAY_MASK,
181 SUN4I_TCON0_CTL_CLK_DELAY(clk_delay));186 SUN4I_TCON0_CTL_CLK_DELAY(clk_delay));
182 187
183 /* Set the resolution */
184 regmap_write(tcon->regs, SUN4I_TCON0_BASIC0_REG,
185 SUN4I_TCON0_BASIC0_X(mode->crtc_hdisplay) |
186 SUN4I_TCON0_BASIC0_Y(mode->crtc_vdisplay));
187
188 /*188 /*
189 * This is called a backporch in the register documentation,189 * This is called a backporch in the register documentation,
190 * but it really is the back porch + hsync190 * but it really is the back porch + hsync
@@ -238,10 +238,9 @@ void sun4i_tcon0_mode_set(struct sun4i_tcon *tcon, · 47 unmodified lines
238 /* Enable the output on the pins */238 /* Enable the output on the pins */
239 regmap_write(tcon->regs, SUN4I_TCON0_IO_TRI_REG, 0);239 regmap_write(tcon->regs, SUN4I_TCON0_IO_TRI_REG, 0);
240}240}
241EXPORT_SYMBOL(sun4i_tcon0_mode_set);
242 241
243void sun4i_tcon1_mode_set(struct sun4i_tcon *tcon,242static void sun4i_tcon1_mode_set(struct sun4i_tcon *tcon,
244 struct drm_display_mode *mode)243 const struct drm_display_mode *mode)
245{244{
246 unsigned int bp, hsync, vsync, vtotal;245 unsigned int bp, hsync, vsync, vtotal;
247 u8 clk_delay;246 u8 clk_delay;
@@ -329,7 +328,26 @@ void sun4i_tcon1_mode_set(struct sun4i_tcon *tcon, · 81 unmodified lines
329 SUN4I_TCON_GCTL_IOMAP_MASK,328 SUN4I_TCON_GCTL_IOMAP_MASK,
330 SUN4I_TCON_GCTL_IOMAP_TCON1);329 SUN4I_TCON_GCTL_IOMAP_TCON1);
331}330}
332EXPORT_SYMBOL(sun4i_tcon1_mode_set);331
332void sun4i_tcon_mode_set(struct sun4i_tcon *tcon,
333 const struct drm_encoder *encoder,
334 const struct drm_display_mode *mode)
335{
336 switch (encoder->encoder_type) {
337 case DRM_MODE_ENCODER_NONE:
338 sun4i_tcon0_mode_set_rgb(tcon, mode);
339 sun4i_tcon_set_mux(tcon, 0, encoder);
340 break;
341 case DRM_MODE_ENCODER_TVDAC:
342 case DRM_MODE_ENCODER_TMDS:
343 sun4i_tcon1_mode_set(tcon, mode);
344 sun4i_tcon_set_mux(tcon, 1, encoder);
345 break;
346 default:
347 DRM_DEBUG_DRIVER("Unknown encoder type, doing nothing...\n");
348 }
349}
350EXPORT_SYMBOL(sun4i_tcon_mode_set);
333 351
334static void sun4i_tcon_finish_page_flip(struct drm_device *dev,352static void sun4i_tcon_finish_page_flip(struct drm_device *dev,
335 struct sun4i_crtc *scrtc)353 struct sun4i_crtc *scrtc)
@@ -782,8 +800,32 @@ static int sun4i_tcon_remove(struct platform_device *pdev) · 446 unmodified lines
782}800}
783 801
784/* platform specific TCON muxing callbacks */802/* platform specific TCON muxing callbacks */
803static int sun4i_a10_tcon_set_mux(struct sun4i_tcon *tcon,
804 const struct drm_encoder *encoder)
805{
806 struct sun4i_tcon *tcon0 = sun4i_get_tcon0(encoder->dev);
807 u32 shift;
808
809 if (!tcon0)
810 return -EINVAL;
811
812 switch (encoder->encoder_type) {
813 case DRM_MODE_ENCODER_TMDS:
814 /* HDMI */
815 shift = 8;
816 break;
817 default:
818 return -EINVAL;
819 }
820
821 regmap_update_bits(tcon0->regs, SUN4I_TCON_MUX_CTRL_REG,
822 0x3 << shift, tcon->id << shift);
823
824 return 0;
825}
826
785static int sun5i_a13_tcon_set_mux(struct sun4i_tcon *tcon,827static int sun5i_a13_tcon_set_mux(struct sun4i_tcon *tcon,
786 struct drm_encoder *encoder)828 const struct drm_encoder *encoder)
787{829{
788 u32 val;830 u32 val;
789 831
@@ -799,7 +841,7 @@ static int sun5i_a13_tcon_set_mux(struct sun4i_tcon *tcon, · 9 unmodified lines
799}841}
800 842
801static int sun6i_tcon_set_mux(struct sun4i_tcon *tcon,843static int sun6i_tcon_set_mux(struct sun4i_tcon *tcon,
802 struct drm_encoder *encoder)844 const struct drm_encoder *encoder)
803{845{
804 struct sun4i_tcon *tcon0 = sun4i_get_tcon0(encoder->dev);846 struct sun4i_tcon *tcon0 = sun4i_get_tcon0(encoder->dev);
805 u32 shift;847 u32 shift;
@@ -823,6 +865,11 @@ static int sun6i_tcon_set_mux(struct sun4i_tcon *tcon, · 17 unmodified lines
823 return 0;865 return 0;
824}866}
825 867
868static const struct sun4i_tcon_quirks sun4i_a10_quirks = {
869 .has_channel_1 = true,
870 .set_mux = sun4i_a10_tcon_set_mux,
871};
872
826static const struct sun4i_tcon_quirks sun5i_a13_quirks = {873static const struct sun4i_tcon_quirks sun5i_a13_quirks = {
827 .has_channel_1 = true,874 .has_channel_1 = true,
828 .set_mux = sun5i_a13_tcon_set_mux,875 .set_mux = sun5i_a13_tcon_set_mux,
@@ -839,6 +886,12 @@ static const struct sun4i_tcon_quirks sun6i_a31s_quirks = { · 10 unmodified lines
839 .needs_de_be_mux = true,886 .needs_de_be_mux = true,
840};887};
841 888
889static const struct sun4i_tcon_quirks sun7i_a20_quirks = {
890 .has_channel_1 = true,
891 /* Same display pipeline structure as A10 */
892 .set_mux = sun4i_a10_tcon_set_mux,
893};
894
842static const struct sun4i_tcon_quirks sun8i_a33_quirks = {895static const struct sun4i_tcon_quirks sun8i_a33_quirks = {
843 /* nothing is supported */896 /* nothing is supported */
844};897};
@@ -848,9 +901,11 @@ static const struct sun4i_tcon_quirks sun8i_v3s_quirks = { · 3 unmodified lines
848};901};
849 902
850static const struct of_device_id sun4i_tcon_of_table[] = {903static const struct of_device_id sun4i_tcon_of_table[] = {
904 { .compatible = "allwinner,sun4i-a10-tcon", .data = &sun4i_a10_quirks },
851 { .compatible = "allwinner,sun5i-a13-tcon", .data = &sun5i_a13_quirks },905 { .compatible = "allwinner,sun5i-a13-tcon", .data = &sun5i_a13_quirks },
852 { .compatible = "allwinner,sun6i-a31-tcon", .data = &sun6i_a31_quirks },906 { .compatible = "allwinner,sun6i-a31-tcon", .data = &sun6i_a31_quirks },
853 { .compatible = "allwinner,sun6i-a31s-tcon", .data = &sun6i_a31s_quirks },907 { .compatible = "allwinner,sun6i-a31s-tcon", .data = &sun6i_a31s_quirks },
908 { .compatible = "allwinner,sun7i-a20-tcon", .data = &sun7i_a20_quirks },
854 { .compatible = "allwinner,sun8i-a33-tcon", .data = &sun8i_a33_quirks },909 { .compatible = "allwinner,sun8i-a33-tcon", .data = &sun8i_a33_quirks },
855 { .compatible = "allwinner,sun8i-v3s-tcon", .data = &sun8i_v3s_quirks },910 { .compatible = "allwinner,sun8i-v3s-tcon", .data = &sun8i_v3s_quirks },
856 { }911 { }
drivers/gpu/drm/sun4i/sun4i_tcon.h+6−17
@@ -152,7 +152,7 @@ struct sun4i_tcon_quirks { · 151 unmodified lines
152 bool needs_de_be_mux; /* sun6i needs mux to select backend */152 bool needs_de_be_mux; /* sun6i needs mux to select backend */
153 153
154 /* callback to handle tcon muxing options */154 /* callback to handle tcon muxing options */
155 int (*set_mux)(struct sun4i_tcon *, struct drm_encoder *);155 int (*set_mux)(struct sun4i_tcon *, const struct drm_encoder *);
156};156};
157 157
158struct sun4i_tcon {158struct sun4i_tcon {
@@ -190,22 +190,11 @@ struct sun4i_tcon { · 31 unmodified lines
190struct drm_bridge *sun4i_tcon_find_bridge(struct device_node *node);190struct drm_bridge *sun4i_tcon_find_bridge(struct device_node *node);
191struct drm_panel *sun4i_tcon_find_panel(struct device_node *node);191struct drm_panel *sun4i_tcon_find_panel(struct device_node *node);
192 192
193/* Global Control */
194void sun4i_tcon_disable(struct sun4i_tcon *tcon);
195void sun4i_tcon_enable(struct sun4i_tcon *tcon);
196
197/* Channel Control */
198void sun4i_tcon_channel_disable(struct sun4i_tcon *tcon, int channel);
199void sun4i_tcon_channel_enable(struct sun4i_tcon *tcon, int channel);
200
201void sun4i_tcon_enable_vblank(struct sun4i_tcon *tcon, bool enable);193void sun4i_tcon_enable_vblank(struct sun4i_tcon *tcon, bool enable);
202 194void sun4i_tcon_mode_set(struct sun4i_tcon *tcon,
203/* Mode Related Controls */195 const struct drm_encoder *encoder,
204void sun4i_tcon_set_mux(struct sun4i_tcon *tcon, int channel,196 const struct drm_display_mode *mode);
205 struct drm_encoder *encoder);197void sun4i_tcon_set_status(struct sun4i_tcon *crtc,
206void sun4i_tcon0_mode_set(struct sun4i_tcon *tcon,198 const struct drm_encoder *encoder, bool enable);
207 struct drm_display_mode *mode);
208void sun4i_tcon1_mode_set(struct sun4i_tcon *tcon,
209 struct drm_display_mode *mode);
210 199
211#endif /* __SUN4I_TCON_H__ */200#endif /* __SUN4I_TCON_H__ */
drivers/gpu/drm/sun4i/sun4i_tv.c+0−12
@@ -24,7 +24,6 @@ · 23 unmodified lines
24 24
25#include "sun4i_crtc.h"25#include "sun4i_crtc.h"
26#include "sun4i_drv.h"26#include "sun4i_drv.h"
27#include "sun4i_tcon.h"
28#include "sunxi_engine.h"27#include "sunxi_engine.h"
29 28
30#define SUN4I_TVE_EN_REG 0x00029#define SUN4I_TVE_EN_REG 0x000
@@ -345,12 +344,9 @@ static void sun4i_tv_disable(struct drm_encoder *encoder) · 314 unmodified lines
345{344{
346 struct sun4i_tv *tv = drm_encoder_to_sun4i_tv(encoder);345 struct sun4i_tv *tv = drm_encoder_to_sun4i_tv(encoder);
347 struct sun4i_crtc *crtc = drm_crtc_to_sun4i_crtc(encoder->crtc);346 struct sun4i_crtc *crtc = drm_crtc_to_sun4i_crtc(encoder->crtc);
348 struct sun4i_tcon *tcon = crtc->tcon;
349 347
350 DRM_DEBUG_DRIVER("Disabling the TV Output\n");348 DRM_DEBUG_DRIVER("Disabling the TV Output\n");
351 349
352 sun4i_tcon_channel_disable(tcon, 1);
353
354 regmap_update_bits(tv->regs, SUN4I_TVE_EN_REG,350 regmap_update_bits(tv->regs, SUN4I_TVE_EN_REG,
355 SUN4I_TVE_EN_ENABLE,351 SUN4I_TVE_EN_ENABLE,
356 0);352 0);
@@ -362,7 +358,6 @@ static void sun4i_tv_enable(struct drm_encoder *encoder) · 5 unmodified lines
362{358{
363 struct sun4i_tv *tv = drm_encoder_to_sun4i_tv(encoder);359 struct sun4i_tv *tv = drm_encoder_to_sun4i_tv(encoder);
364 struct sun4i_crtc *crtc = drm_crtc_to_sun4i_crtc(encoder->crtc);360 struct sun4i_crtc *crtc = drm_crtc_to_sun4i_crtc(encoder->crtc);
365 struct sun4i_tcon *tcon = crtc->tcon;
366 361
367 DRM_DEBUG_DRIVER("Enabling the TV Output\n");362 DRM_DEBUG_DRIVER("Enabling the TV Output\n");
368 363
@@ -371,8 +366,6 @@ static void sun4i_tv_enable(struct drm_encoder *encoder) · 2 unmodified lines
371 regmap_update_bits(tv->regs, SUN4I_TVE_EN_REG,366 regmap_update_bits(tv->regs, SUN4I_TVE_EN_REG,
372 SUN4I_TVE_EN_ENABLE,367 SUN4I_TVE_EN_ENABLE,
373 SUN4I_TVE_EN_ENABLE);368 SUN4I_TVE_EN_ENABLE);
374
375 sun4i_tcon_channel_enable(tcon, 1);
376}369}
377 370
378static void sun4i_tv_mode_set(struct drm_encoder *encoder,371static void sun4i_tv_mode_set(struct drm_encoder *encoder,
@@ -380,13 +373,8 @@ static void sun4i_tv_mode_set(struct drm_encoder *encoder, · 1 unmodified line
380 struct drm_display_mode *adjusted_mode)373 struct drm_display_mode *adjusted_mode)
381{374{
382 struct sun4i_tv *tv = drm_encoder_to_sun4i_tv(encoder);375 struct sun4i_tv *tv = drm_encoder_to_sun4i_tv(encoder);
383 struct sun4i_crtc *crtc = drm_crtc_to_sun4i_crtc(encoder->crtc);
384 struct sun4i_tcon *tcon = crtc->tcon;
385 const struct tv_mode *tv_mode = sun4i_tv_find_tv_by_mode(mode);376 const struct tv_mode *tv_mode = sun4i_tv_find_tv_by_mode(mode);
386 377
387 sun4i_tcon1_mode_set(tcon, mode);
388 sun4i_tcon_set_mux(tcon, 1, encoder);
389
390 /* Enable and map the DAC to the output */378 /* Enable and map the DAC to the output */
391 regmap_update_bits(tv->regs, SUN4I_TVE_EN_REG,379 regmap_update_bits(tv->regs, SUN4I_TVE_EN_REG,
392 SUN4I_TVE_EN_DAC_MAP_MASK,380 SUN4I_TVE_EN_DAC_MAP_MASK,
drivers/gpu/drm/udl/udl_connector.c+104−50
@@ -14,70 +14,95 @@ · 13 unmodified lines
14#include <drm/drm_crtc.h>14#include <drm/drm_crtc.h>
15#include <drm/drm_edid.h>15#include <drm/drm_edid.h>
16#include <drm/drm_crtc_helper.h>16#include <drm/drm_crtc_helper.h>
17#include "udl_connector.h"
17#include "udl_drv.h"18#include "udl_drv.h"
18 19
19/* dummy connector to just get EDID,20static bool udl_get_edid_block(struct udl_device *udl, int block_idx,
20 all UDL appear to have a DVI-D */21 u8 *buff)
21
22static u8 *udl_get_edid(struct udl_device *udl)
23{22{
24 u8 *block;
25 char *rbuf;
26 int ret, i;23 int ret, i;
24 u8 *read_buff;
27 25
28 block = kmalloc(EDID_LENGTH, GFP_KERNEL);26 read_buff = kmalloc(2, GFP_KERNEL);
29 if (block == NULL)27 if (!read_buff)
30 return NULL;28 return false;
31
32 rbuf = kmalloc(2, GFP_KERNEL);
33 if (rbuf == NULL)
34 goto error;
35 29
36 for (i = 0; i < EDID_LENGTH; i++) {30 for (i = 0; i < EDID_LENGTH; i++) {
31 int bval = (i + block_idx * EDID_LENGTH) << 8;
37 ret = usb_control_msg(udl->udev,32 ret = usb_control_msg(udl->udev,
38 usb_rcvctrlpipe(udl->udev, 0), (0x02),33 usb_rcvctrlpipe(udl->udev, 0),
39 (0x80 | (0x02 << 5)), i << 8, 0xA1, rbuf, 2,34 (0x02), (0x80 | (0x02 << 5)), bval,
40 HZ);35 0xA1, read_buff, 2, HZ);
41 if (ret < 1) {36 if (ret < 1) {
42 DRM_ERROR("Read EDID byte %d failed err %x\n", i, ret);37 DRM_ERROR("Read EDID byte %d failed err %x\n", i, ret);
43 goto error;38 kfree(read_buff);
39 return false;
44 }40 }
45 block[i] = rbuf[1];41 buff[i] = read_buff[1];
46 }42 }
47 43
48 kfree(rbuf);44 kfree(read_buff);
49 return block;45 return true;
50
51error:
52 kfree(block);
53 kfree(rbuf);
54 return NULL;
55}46}
56 47
57static int udl_get_modes(struct drm_connector *connector)48static bool udl_get_edid(struct udl_device *udl, u8 **result_buff,
49 int *result_buff_size)
58{50{
59 struct udl_device *udl = connector->dev->dev_private;51 int i, extensions;
60 struct edid *edid;52 u8 *block_buff = NULL, *buff_ptr;
61 int ret;53
62 54 block_buff = kmalloc(EDID_LENGTH, GFP_KERNEL);
63 edid = (struct edid *)udl_get_edid(udl);55 if (block_buff == NULL)
64 if (!edid) {56 return false;
65 drm_mode_connector_update_edid_property(connector, NULL);57
66 return 0;58 if (udl_get_edid_block(udl, 0, block_buff) &&
59 memchr_inv(block_buff, 0, EDID_LENGTH)) {
60 extensions = ((struct edid *)block_buff)->extensions;
61 if (extensions > 0) {
62 /* we have to read all extensions one by one */
63 *result_buff_size = EDID_LENGTH * (extensions + 1);
64 *result_buff = kmalloc(*result_buff_size, GFP_KERNEL);
65 buff_ptr = *result_buff;
66 if (buff_ptr == NULL) {
67 kfree(block_buff);
68 return false;
69 }
70 memcpy(buff_ptr, block_buff, EDID_LENGTH);
71 kfree(block_buff);
72 buff_ptr += EDID_LENGTH;
73 for (i = 1; i < extensions; ++i) {
74 if (udl_get_edid_block(udl, i, buff_ptr)) {
75 buff_ptr += EDID_LENGTH;
76 } else {
77 kfree(*result_buff);
78 *result_buff = NULL;
79 return false;
80 }
81 }
82 return true;
83 }
84 /* we have only base edid block */
85 *result_buff = block_buff;
86 *result_buff_size = EDID_LENGTH;
87 return true;
67 }88 }
68 89
69 /*90 kfree(block_buff);
70 * We only read the main block, but if the monitor reports extension91
71 * blocks then the drm edid code expects them to be present, so patch92 return false;
72 * the extension count to 0.93}
73 */94
74 edid->checksum += edid->extensions;95static int udl_get_modes(struct drm_connector *connector)
75 edid->extensions = 0;96{
76 97 struct udl_drm_connector *udl_connector =
77 drm_mode_connector_update_edid_property(connector, edid);98 container_of(connector,
78 ret = drm_add_edid_modes(connector, edid);99 struct udl_drm_connector,
79 kfree(edid);100 connector);
80 return ret;101
102 drm_mode_connector_update_edid_property(connector, udl_connector->edid);
103 if (udl_connector->edid)
104 return drm_add_edid_modes(connector, udl_connector->edid);
105 return 0;
81}106}
82 107
83static int udl_mode_valid(struct drm_connector *connector,108static int udl_mode_valid(struct drm_connector *connector,
@@ -96,8 +121,26 @@ static int udl_mode_valid(struct drm_connector *connector, · 12 unmodified lines
96static enum drm_connector_status121static enum drm_connector_status
97udl_detect(struct drm_connector *connector, bool force)122udl_detect(struct drm_connector *connector, bool force)
98{123{
99 if (drm_dev_is_unplugged(connector->dev))124 u8 *edid_buff = NULL;
125 int edid_buff_size = 0;
126 struct udl_device *udl = connector->dev->dev_private;
127 struct udl_drm_connector *udl_connector =
128 container_of(connector,
129 struct udl_drm_connector,
130 connector);
131
132 /* cleanup previous edid */
133 if (udl_connector->edid != NULL) {
134 kfree(udl_connector->edid);
135 udl_connector->edid = NULL;
136 }
137
138
139 if (!udl_get_edid(udl, &edid_buff, &edid_buff_size))
100 return connector_status_disconnected;140 return connector_status_disconnected;
141
142 udl_connector->edid = (struct edid *)edid_buff;
143
101 return connector_status_connected;144 return connector_status_connected;
102}145}
103 146
@@ -117,8 +160,14 @@ static int udl_connector_set_property(struct drm_connector *connector, · 13 unmodified lines
117 160
118static void udl_connector_destroy(struct drm_connector *connector)161static void udl_connector_destroy(struct drm_connector *connector)
119{162{
163 struct udl_drm_connector *udl_connector =
164 container_of(connector,
165 struct udl_drm_connector,
166 connector);
167
120 drm_connector_unregister(connector);168 drm_connector_unregister(connector);
121 drm_connector_cleanup(connector);169 drm_connector_cleanup(connector);
170 kfree(udl_connector->edid);
122 kfree(connector);171 kfree(connector);
123}172}
124 173
@@ -138,17 +187,22 @@ static const struct drm_connector_funcs udl_connector_funcs = { · 13 unmodified lines
138 187
139int udl_connector_init(struct drm_device *dev, struct drm_encoder *encoder)188int udl_connector_init(struct drm_device *dev, struct drm_encoder *encoder)
140{189{
190 struct udl_drm_connector *udl_connector;
141 struct drm_connector *connector;191 struct drm_connector *connector;
142 192
143 connector = kzalloc(sizeof(struct drm_connector), GFP_KERNEL);193 udl_connector = kzalloc(sizeof(struct udl_drm_connector), GFP_KERNEL);
144 if (!connector)194 if (!udl_connector)
145 return -ENOMEM;195 return -ENOMEM;
146 196
147 drm_connector_init(dev, connector, &udl_connector_funcs, DRM_MODE_CONNECTOR_DVII);197 connector = &udl_connector->connector;
198 drm_connector_init(dev, connector, &udl_connector_funcs,
199 DRM_MODE_CONNECTOR_DVII);
148 drm_connector_helper_add(connector, &udl_connector_helper_funcs);200 drm_connector_helper_add(connector, &udl_connector_helper_funcs);
149 201
150 drm_connector_register(connector);202 drm_connector_register(connector);
151 drm_mode_connector_attach_encoder(connector, encoder);203 drm_mode_connector_attach_encoder(connector, encoder);
204 connector->polled = DRM_CONNECTOR_POLL_HPD |
205 DRM_CONNECTOR_POLL_CONNECT | DRM_CONNECTOR_POLL_DISCONNECT;
152 206
153 return 0;207 return 0;
154}208}
drivers/gpu/drm/udl/udl_connector.h+13−0
@@ -0,0 +1,13 @@
1#ifndef __UDL_CONNECTOR_H__
2#define __UDL_CONNECTOR_H__
3
4#include <drm/drm_crtc.h>
5
6struct udl_drm_connector {
7 struct drm_connector connector;
8 /* last udl_detect edid */
9 struct edid *edid;
10};
11
12
13#endif //__UDL_CONNECTOR_H__
drivers/gpu/drm/udl/udl_drv.c+4−0
@@ -14,6 +14,9 @@ · 13 unmodified lines
14static int udl_usb_suspend(struct usb_interface *interface,14static int udl_usb_suspend(struct usb_interface *interface,
15 pm_message_t message)15 pm_message_t message)
16{16{
17 struct drm_device *dev = usb_get_intfdata(interface);
18
19 drm_kms_helper_poll_disable(dev);
17 return 0;20 return 0;
18}21}
19 22
@@ -21,6 +24,7 @@ static int udl_usb_resume(struct usb_interface *interface) · 1 unmodified line
21{24{
22 struct drm_device *dev = usb_get_intfdata(interface);25 struct drm_device *dev = usb_get_intfdata(interface);
23 26
27 drm_kms_helper_poll_enable(dev);
24 udl_modeset_restore(dev);28 udl_modeset_restore(dev);
25 return 0;29 return 0;
26}30}
drivers/gpu/drm/udl/udl_main.c+5−0
@@ -11,6 +11,7 @@ · 10 unmodified lines
11 * more details.11 * more details.
12 */12 */
13#include <drm/drmP.h>13#include <drm/drmP.h>
14#include <drm/drm_crtc_helper.h>
14#include "udl_drv.h"15#include "udl_drv.h"
15 16
16/* -BULK_SIZE as per usb-skeleton. Can we get full page and avoid overhead? */17/* -BULK_SIZE as per usb-skeleton. Can we get full page and avoid overhead? */
@@ -350,6 +351,8 @@ int udl_driver_load(struct drm_device *dev, unsigned long flags) · 333 unmodified lines
350 if (ret)351 if (ret)
351 goto err_fb;352 goto err_fb;
352 353
354 drm_kms_helper_poll_init(dev);
355
353 return 0;356 return 0;
354err_fb:357err_fb:
355 udl_fbdev_cleanup(dev);358 udl_fbdev_cleanup(dev);
@@ -371,6 +374,8 @@ void udl_driver_unload(struct drm_device *dev) · 15 unmodified lines
371{374{
372 struct udl_device *udl = dev->dev_private;375 struct udl_device *udl = dev->dev_private;
373 376
377 drm_kms_helper_poll_fini(dev);
378
374 if (udl->urbs.count)379 if (udl->urbs.count)
375 udl_free_urb_list(dev);380 udl_free_urb_list(dev);
376 381
drivers/gpu/drm/vc4/vc4_bo.c+279−8
@@ -53,6 +53,17 @@ static void vc4_bo_stats_dump(struct vc4_dev *vc4) · 52 unmodified lines
53 vc4->bo_labels[i].size_allocated / 1024,53 vc4->bo_labels[i].size_allocated / 1024,
54 vc4->bo_labels[i].num_allocated);54 vc4->bo_labels[i].num_allocated);
55 }55 }
56
57 mutex_lock(&vc4->purgeable.lock);
58 if (vc4->purgeable.num)
59 DRM_INFO("%30s: %6zdkb BOs (%d)\n", "userspace BO cache",
60 vc4->purgeable.size / 1024, vc4->purgeable.num);
61
62 if (vc4->purgeable.purged_num)
63 DRM_INFO("%30s: %6zdkb BOs (%d)\n", "total purged BO",
64 vc4->purgeable.purged_size / 1024,
65 vc4->purgeable.purged_num);
66 mutex_unlock(&vc4->purgeable.lock);
56}67}
57 68
58#ifdef CONFIG_DEBUG_FS69#ifdef CONFIG_DEBUG_FS
@@ -75,6 +86,17 @@ int vc4_bo_stats_debugfs(struct seq_file *m, void *unused) · 16 unmodified lines
75 }86 }
76 mutex_unlock(&vc4->bo_lock);87 mutex_unlock(&vc4->bo_lock);
77 88
89 mutex_lock(&vc4->purgeable.lock);
90 if (vc4->purgeable.num)
91 seq_printf(m, "%30s: %6dkb BOs (%d)\n", "userspace BO cache",
92 vc4->purgeable.size / 1024, vc4->purgeable.num);
93
94 if (vc4->purgeable.purged_num)
95 seq_printf(m, "%30s: %6dkb BOs (%d)\n", "total purged BO",
96 vc4->purgeable.purged_size / 1024,
97 vc4->purgeable.purged_num);
98 mutex_unlock(&vc4->purgeable.lock);
99
78 return 0;100 return 0;
79}101}
80#endif102#endif
@@ -247,6 +269,109 @@ static void vc4_bo_cache_purge(struct drm_device *dev) · 166 unmodified lines
247 mutex_unlock(&vc4->bo_lock);269 mutex_unlock(&vc4->bo_lock);
248}270}
249 271
272void vc4_bo_add_to_purgeable_pool(struct vc4_bo *bo)
273{
274 struct vc4_dev *vc4 = to_vc4_dev(bo->base.base.dev);
275
276 mutex_lock(&vc4->purgeable.lock);
277 list_add_tail(&bo->size_head, &vc4->purgeable.list);
278 vc4->purgeable.num++;
279 vc4->purgeable.size += bo->base.base.size;
280 mutex_unlock(&vc4->purgeable.lock);
281}
282
283static void vc4_bo_remove_from_purgeable_pool_locked(struct vc4_bo *bo)
284{
285 struct vc4_dev *vc4 = to_vc4_dev(bo->base.base.dev);
286
287 /* list_del_init() is used here because the caller might release
288 * the purgeable lock in order to acquire the madv one and update the
289 * madv status.
290 * During this short period of time a user might decide to mark
291 * the BO as unpurgeable, and if bo->madv is set to
292 * VC4_MADV_DONTNEED it will try to remove the BO from the
293 * purgeable list which will fail if the ->next/prev fields
294 * are set to LIST_POISON1/LIST_POISON2 (which is what
295 * list_del() does).
296 * Re-initializing the list element guarantees that list_del()
297 * will work correctly even if it's a NOP.
298 */
299 list_del_init(&bo->size_head);
300 vc4->purgeable.num--;
301 vc4->purgeable.size -= bo->base.base.size;
302}
303
304void vc4_bo_remove_from_purgeable_pool(struct vc4_bo *bo)
305{
306 struct vc4_dev *vc4 = to_vc4_dev(bo->base.base.dev);
307
308 mutex_lock(&vc4->purgeable.lock);
309 vc4_bo_remove_from_purgeable_pool_locked(bo);
310 mutex_unlock(&vc4->purgeable.lock);
311}
312
313static void vc4_bo_purge(struct drm_gem_object *obj)
314{
315 struct vc4_bo *bo = to_vc4_bo(obj);
316 struct drm_device *dev = obj->dev;
317
318 WARN_ON(!mutex_is_locked(&bo->madv_lock));
319 WARN_ON(bo->madv != VC4_MADV_DONTNEED);
320
321 drm_vma_node_unmap(&obj->vma_node, dev->anon_inode->i_mapping);
322
323 dma_free_wc(dev->dev, obj->size, bo->base.vaddr, bo->base.paddr);
324 bo->base.vaddr = NULL;
325 bo->madv = __VC4_MADV_PURGED;
326}
327
328static void vc4_bo_userspace_cache_purge(struct drm_device *dev)
329{
330 struct vc4_dev *vc4 = to_vc4_dev(dev);
331
332 mutex_lock(&vc4->purgeable.lock);
333 while (!list_empty(&vc4->purgeable.list)) {
334 struct vc4_bo *bo = list_first_entry(&vc4->purgeable.list,
335 struct vc4_bo, size_head);
336 struct drm_gem_object *obj = &bo->base.base;
337 size_t purged_size = 0;
338
339 vc4_bo_remove_from_purgeable_pool_locked(bo);
340
341 /* Release the purgeable lock while we're purging the BO so
342 * that other people can continue inserting things in the
343 * purgeable pool without having to wait for all BOs to be
344 * purged.
345 */
346 mutex_unlock(&vc4->purgeable.lock);
347 mutex_lock(&bo->madv_lock);
348
349 /* Since we released the purgeable pool lock before acquiring
350 * the BO madv one, the user may have marked the BO as WILLNEED
351 * and re-used it in the meantime.
352 * Before purging the BO we need to make sure
353 * - it is still marked as DONTNEED
354 * - it has not been re-inserted in the purgeable list
355 * - it is not used by HW blocks
356 * If one of these conditions is not met, just skip the entry.
357 */
358 if (bo->madv == VC4_MADV_DONTNEED &&
359 list_empty(&bo->size_head) &&
360 !refcount_read(&bo->usecnt)) {
361 purged_size = bo->base.base.size;
362 vc4_bo_purge(obj);
363 }
364 mutex_unlock(&bo->madv_lock);
365 mutex_lock(&vc4->purgeable.lock);
366
367 if (purged_size) {
368 vc4->purgeable.purged_size += purged_size;
369 vc4->purgeable.purged_num++;
370 }
371 }
372 mutex_unlock(&vc4->purgeable.lock);
373}
374
250static struct vc4_bo *vc4_bo_get_from_cache(struct drm_device *dev,375static struct vc4_bo *vc4_bo_get_from_cache(struct drm_device *dev,
251 uint32_t size,376 uint32_t size,
252 enum vc4_kernel_bo_type type)377 enum vc4_kernel_bo_type type)
@@ -293,6 +418,9 @@ struct drm_gem_object *vc4_create_object(struct drm_device *dev, size_t size) · 40 unmodified lines
293 if (!bo)418 if (!bo)
294 return ERR_PTR(-ENOMEM);419 return ERR_PTR(-ENOMEM);
295 420
421 bo->madv = VC4_MADV_WILLNEED;
422 refcount_set(&bo->usecnt, 0);
423 mutex_init(&bo->madv_lock);
296 mutex_lock(&vc4->bo_lock);424 mutex_lock(&vc4->bo_lock);
297 bo->label = VC4_BO_TYPE_KERNEL;425 bo->label = VC4_BO_TYPE_KERNEL;
298 vc4->bo_labels[VC4_BO_TYPE_KERNEL].num_allocated++;426 vc4->bo_labels[VC4_BO_TYPE_KERNEL].num_allocated++;
@@ -330,16 +458,38 @@ struct vc4_bo *vc4_bo_create(struct drm_device *dev, size_t unaligned_size, · 31 unmodified lines
330 * CMA allocations we've got laying around and try again.458 * CMA allocations we've got laying around and try again.
331 */459 */
332 vc4_bo_cache_purge(dev);460 vc4_bo_cache_purge(dev);
461 cma_obj = drm_gem_cma_create(dev, size);
462 }
333 463
464 if (IS_ERR(cma_obj)) {
465 /*
466 * Still not enough CMA memory, purge the userspace BO
467 * cache and retry.
468 * This is sub-optimal since we purge the whole userspace
469 * BO cache which forces user that want to re-use the BO to
470 * restore its initial content.
471 * Ideally, we should purge entries one by one and retry
472 * after each to see if CMA allocation succeeds. Or even
473 * better, try to find an entry with at least the same
474 * size.
475 */
476 vc4_bo_userspace_cache_purge(dev);
334 cma_obj = drm_gem_cma_create(dev, size);477 cma_obj = drm_gem_cma_create(dev, size);
335 if (IS_ERR(cma_obj)) {478 }
336 DRM_ERROR("Failed to allocate from CMA:\n");479
337 vc4_bo_stats_dump(vc4);480 if (IS_ERR(cma_obj)) {
338 return ERR_PTR(-ENOMEM);481 DRM_ERROR("Failed to allocate from CMA:\n");
339 }482 vc4_bo_stats_dump(vc4);
483 return ERR_PTR(-ENOMEM);
340 }484 }
341 bo = to_vc4_bo(&cma_obj->base);485 bo = to_vc4_bo(&cma_obj->base);
342 486
487 /* By default, BOs do not support the MADV ioctl. This will be enabled
488 * only on BOs that are exposed to userspace (V3D, V3D_SHADER and DUMB
489 * BOs).
490 */
491 bo->madv = __VC4_MADV_NOTSUPP;
492
343 mutex_lock(&vc4->bo_lock);493 mutex_lock(&vc4->bo_lock);
344 vc4_bo_set_label(&cma_obj->base, type);494 vc4_bo_set_label(&cma_obj->base, type);
345 mutex_unlock(&vc4->bo_lock);495 mutex_unlock(&vc4->bo_lock);
@@ -365,6 +515,8 @@ int vc4_dumb_create(struct drm_file *file_priv, · 19 unmodified lines
365 if (IS_ERR(bo))515 if (IS_ERR(bo))
366 return PTR_ERR(bo);516 return PTR_ERR(bo);
367 517
518 bo->madv = VC4_MADV_WILLNEED;
519
368 ret = drm_gem_handle_create(file_priv, &bo->base.base, &args->handle);520 ret = drm_gem_handle_create(file_priv, &bo->base.base, &args->handle);
369 drm_gem_object_put_unlocked(&bo->base.base);521 drm_gem_object_put_unlocked(&bo->base.base);
370 522
@@ -403,6 +555,12 @@ void vc4_free_object(struct drm_gem_object *gem_bo) · 32 unmodified lines
403 struct vc4_bo *bo = to_vc4_bo(gem_bo);555 struct vc4_bo *bo = to_vc4_bo(gem_bo);
404 struct list_head *cache_list;556 struct list_head *cache_list;
405 557
558 /* Remove the BO from the purgeable list. */
559 mutex_lock(&bo->madv_lock);
560 if (bo->madv == VC4_MADV_DONTNEED && !refcount_read(&bo->usecnt))
561 vc4_bo_remove_from_purgeable_pool(bo);
562 mutex_unlock(&bo->madv_lock);
563
406 mutex_lock(&vc4->bo_lock);564 mutex_lock(&vc4->bo_lock);
407 /* If the object references someone else's memory, we can't cache it.565 /* If the object references someone else's memory, we can't cache it.
408 */566 */
@@ -418,7 +576,8 @@ void vc4_free_object(struct drm_gem_object *gem_bo) · 9 unmodified lines
418 }576 }
419 577
420 /* If this object was partially constructed but CMA allocation578 /* If this object was partially constructed but CMA allocation
421 * had failed, just free it.579 * had failed, just free it. Can also happen when the BO has been
580 * purged.
422 */581 */
423 if (!bo->base.vaddr) {582 if (!bo->base.vaddr) {
424 vc4_bo_destroy(bo);583 vc4_bo_destroy(bo);
@@ -437,6 +596,10 @@ void vc4_free_object(struct drm_gem_object *gem_bo) · 12 unmodified lines
437 bo->validated_shader = NULL;596 bo->validated_shader = NULL;
438 }597 }
439 598
599 /* Reset madv and usecnt before adding the BO to the cache. */
600 bo->madv = __VC4_MADV_NOTSUPP;
601 refcount_set(&bo->usecnt, 0);
602
440 bo->t_format = false;603 bo->t_format = false;
441 bo->free_time = jiffies;604 bo->free_time = jiffies;
442 list_add(&bo->size_head, cache_list);605 list_add(&bo->size_head, cache_list);
@@ -461,6 +624,56 @@ static void vc4_bo_cache_time_work(struct work_struct *work) · 18 unmodified lines
461 mutex_unlock(&vc4->bo_lock);624 mutex_unlock(&vc4->bo_lock);
462}625}
463 626
627int vc4_bo_inc_usecnt(struct vc4_bo *bo)
628{
629 int ret;
630
631 /* Fast path: if the BO is already retained by someone, no need to
632 * check the madv status.
633 */
634 if (refcount_inc_not_zero(&bo->usecnt))
635 return 0;
636
637 mutex_lock(&bo->madv_lock);
638 switch (bo->madv) {
639 case VC4_MADV_WILLNEED:
640 refcount_inc(&bo->usecnt);
641 ret = 0;
642 break;
643 case VC4_MADV_DONTNEED:
644 /* We shouldn't use a BO marked as purgeable if at least
645 * someone else retained its content by incrementing usecnt.
646 * Luckily the BO hasn't been purged yet, but something wrong
647 * is happening here. Just throw an error instead of
648 * authorizing this use case.
649 */
650 case __VC4_MADV_PURGED:
651 /* We can't use a purged BO. */
652 default:
653 /* Invalid madv value. */
654 ret = -EINVAL;
655 break;
656 }
657 mutex_unlock(&bo->madv_lock);
658
659 return ret;
660}
661
662void vc4_bo_dec_usecnt(struct vc4_bo *bo)
663{
664 /* Fast path: if the BO is still retained by someone, no need to test
665 * the madv value.
666 */
667 if (refcount_dec_not_one(&bo->usecnt))
668 return;
669
670 mutex_lock(&bo->madv_lock);
671 if (refcount_dec_and_test(&bo->usecnt) &&
672 bo->madv == VC4_MADV_DONTNEED)
673 vc4_bo_add_to_purgeable_pool(bo);
674 mutex_unlock(&bo->madv_lock);
675}
676
464static void vc4_bo_cache_time_timer(unsigned long data)677static void vc4_bo_cache_time_timer(unsigned long data)
465{678{
466 struct drm_device *dev = (struct drm_device *)data;679 struct drm_device *dev = (struct drm_device *)data;
@@ -480,18 +693,52 @@ struct dma_buf * · 13 unmodified lines
480vc4_prime_export(struct drm_device *dev, struct drm_gem_object *obj, int flags)693vc4_prime_export(struct drm_device *dev, struct drm_gem_object *obj, int flags)
481{694{
482 struct vc4_bo *bo = to_vc4_bo(obj);695 struct vc4_bo *bo = to_vc4_bo(obj);
696 struct dma_buf *dmabuf;
697 int ret;
483 698
484 if (bo->validated_shader) {699 if (bo->validated_shader) {
485 DRM_DEBUG("Attempting to export shader BO\n");700 DRM_DEBUG("Attempting to export shader BO\n");
486 return ERR_PTR(-EINVAL);701 return ERR_PTR(-EINVAL);
487 }702 }
488 703
489 return drm_gem_prime_export(dev, obj, flags);704 /* Note: as soon as the BO is exported it becomes unpurgeable, because
705 * noone ever decrements the usecnt even if the reference held by the
706 * exported BO is released. This shouldn't be a problem since we don't
707 * expect exported BOs to be marked as purgeable.
708 */
709 ret = vc4_bo_inc_usecnt(bo);
710 if (ret) {
711 DRM_ERROR("Failed to increment BO usecnt\n");
712 return ERR_PTR(ret);
713 }
714
715 dmabuf = drm_gem_prime_export(dev, obj, flags);
716 if (IS_ERR(dmabuf))
717 vc4_bo_dec_usecnt(bo);
718
719 return dmabuf;
720}
721
722int vc4_fault(struct vm_fault *vmf)
723{
724 struct vm_area_struct *vma = vmf->vma;
725 struct drm_gem_object *obj = vma->vm_private_data;
726 struct vc4_bo *bo = to_vc4_bo(obj);
727
728 /* The only reason we would end up here is when user-space accesses
729 * BO's memory after it's been purged.
730 */
731 mutex_lock(&bo->madv_lock);
732 WARN_ON(bo->madv != __VC4_MADV_PURGED);
733 mutex_unlock(&bo->madv_lock);
734
735 return VM_FAULT_SIGBUS;
490}736}
491 737
492int vc4_mmap(struct file *filp, struct vm_area_struct *vma)738int vc4_mmap(struct file *filp, struct vm_area_struct *vma)
493{739{
494 struct drm_gem_object *gem_obj;740 struct drm_gem_object *gem_obj;
741 unsigned long vm_pgoff;
495 struct vc4_bo *bo;742 struct vc4_bo *bo;
496 int ret;743 int ret;
497 744
@@ -507,16 +754,36 @@ int vc4_mmap(struct file *filp, struct vm_area_struct *vma) · 9 unmodified lines
507 return -EINVAL;754 return -EINVAL;
508 }755 }
509 756
757 if (bo->madv != VC4_MADV_WILLNEED) {
758 DRM_DEBUG("mmaping of %s BO not allowed\n",
759 bo->madv == VC4_MADV_DONTNEED ?
760 "purgeable" : "purged");
761 return -EINVAL;
762 }
763
510 /*764 /*
511 * Clear the VM_PFNMAP flag that was set by drm_gem_mmap(), and set the765 * Clear the VM_PFNMAP flag that was set by drm_gem_mmap(), and set the
512 * vm_pgoff (used as a fake buffer offset by DRM) to 0 as we want to map766 * vm_pgoff (used as a fake buffer offset by DRM) to 0 as we want to map
513 * the whole buffer.767 * the whole buffer.
514 */768 */
515 vma->vm_flags &= ~VM_PFNMAP;769 vma->vm_flags &= ~VM_PFNMAP;
516 vma->vm_pgoff = 0;
517 770
771 /* This ->vm_pgoff dance is needed to make all parties happy:
772 * - dma_mmap_wc() uses ->vm_pgoff as an offset within the allocated
773 * mem-region, hence the need to set it to zero (the value set by
774 * the DRM core is a virtual offset encoding the GEM object-id)
775 * - the mmap() core logic needs ->vm_pgoff to be restored to its
776 * initial value before returning from this function because it
777 * encodes the offset of this GEM in the dev->anon_inode pseudo-file
778 * and this information will be used when we invalidate userspace
779 * mappings with drm_vma_node_unmap() (called from vc4_gem_purge()).
780 */
781 vm_pgoff = vma->vm_pgoff;
782 vma->vm_pgoff = 0;
518 ret = dma_mmap_wc(bo->base.base.dev->dev, vma, bo->base.vaddr,783 ret = dma_mmap_wc(bo->base.base.dev->dev, vma, bo->base.vaddr,
519 bo->base.paddr, vma->vm_end - vma->vm_start);784 bo->base.paddr, vma->vm_end - vma->vm_start);
785 vma->vm_pgoff = vm_pgoff;
786
520 if (ret)787 if (ret)
521 drm_gem_vm_close(vma);788 drm_gem_vm_close(vma);
522 789
@@ -580,6 +847,8 @@ int vc4_create_bo_ioctl(struct drm_device *dev, void *data, · 57 unmodified lines
580 if (IS_ERR(bo))847 if (IS_ERR(bo))
581 return PTR_ERR(bo);848 return PTR_ERR(bo);
582 849
850 bo->madv = VC4_MADV_WILLNEED;
851
583 ret = drm_gem_handle_create(file_priv, &bo->base.base, &args->handle);852 ret = drm_gem_handle_create(file_priv, &bo->base.base, &args->handle);
584 drm_gem_object_put_unlocked(&bo->base.base);853 drm_gem_object_put_unlocked(&bo->base.base);
585 854
@@ -633,6 +902,8 @@ vc4_create_shader_bo_ioctl(struct drm_device *dev, void *data, · 47 unmodified lines
633 if (IS_ERR(bo))902 if (IS_ERR(bo))
634 return PTR_ERR(bo);903 return PTR_ERR(bo);
635 904
905 bo->madv = VC4_MADV_WILLNEED;
906
636 if (copy_from_user(bo->base.vaddr,907 if (copy_from_user(bo->base.vaddr,
637 (void __user *)(uintptr_t)args->data,908 (void __user *)(uintptr_t)args->data,
638 args->size)) {909 args->size)) {
drivers/gpu/drm/vc4/vc4_drv.c+9−1
@@ -100,6 +100,7 @@ static int vc4_get_param_ioctl(struct drm_device *dev, void *data, · 99 unmodified lines
100 case DRM_VC4_PARAM_SUPPORTS_ETC1:100 case DRM_VC4_PARAM_SUPPORTS_ETC1:
101 case DRM_VC4_PARAM_SUPPORTS_THREADED_FS:101 case DRM_VC4_PARAM_SUPPORTS_THREADED_FS:
102 case DRM_VC4_PARAM_SUPPORTS_FIXED_RCL_ORDER:102 case DRM_VC4_PARAM_SUPPORTS_FIXED_RCL_ORDER:
103 case DRM_VC4_PARAM_SUPPORTS_MADVISE:
103 args->value = true;104 args->value = true;
104 break;105 break;
105 default:106 default:
@@ -117,6 +118,12 @@ static void vc4_lastclose(struct drm_device *dev) · 11 unmodified lines
117 drm_fbdev_cma_restore_mode(vc4->fbdev);118 drm_fbdev_cma_restore_mode(vc4->fbdev);
118}119}
119 120
121static const struct vm_operations_struct vc4_vm_ops = {
122 .fault = vc4_fault,
123 .open = drm_gem_vm_open,
124 .close = drm_gem_vm_close,
125};
126
120static const struct file_operations vc4_drm_fops = {127static const struct file_operations vc4_drm_fops = {
121 .owner = THIS_MODULE,128 .owner = THIS_MODULE,
122 .open = drm_open,129 .open = drm_open,
@@ -142,6 +149,7 @@ static const struct drm_ioctl_desc vc4_drm_ioctls[] = { · 19 unmodified lines
142 DRM_IOCTL_DEF_DRV(VC4_SET_TILING, vc4_set_tiling_ioctl, DRM_RENDER_ALLOW),149 DRM_IOCTL_DEF_DRV(VC4_SET_TILING, vc4_set_tiling_ioctl, DRM_RENDER_ALLOW),
143 DRM_IOCTL_DEF_DRV(VC4_GET_TILING, vc4_get_tiling_ioctl, DRM_RENDER_ALLOW),150 DRM_IOCTL_DEF_DRV(VC4_GET_TILING, vc4_get_tiling_ioctl, DRM_RENDER_ALLOW),
144 DRM_IOCTL_DEF_DRV(VC4_LABEL_BO, vc4_label_bo_ioctl, DRM_RENDER_ALLOW),151 DRM_IOCTL_DEF_DRV(VC4_LABEL_BO, vc4_label_bo_ioctl, DRM_RENDER_ALLOW),
152 DRM_IOCTL_DEF_DRV(VC4_GEM_MADVISE, vc4_gem_madvise_ioctl, DRM_RENDER_ALLOW),
145};153};
146 154
147static struct drm_driver vc4_drm_driver = {155static struct drm_driver vc4_drm_driver = {
@@ -166,7 +174,7 @@ static struct drm_driver vc4_drm_driver = { · 18 unmodified lines
166 174
167 .gem_create_object = vc4_create_object,175 .gem_create_object = vc4_create_object,
168 .gem_free_object_unlocked = vc4_free_object,176 .gem_free_object_unlocked = vc4_free_object,
169 .gem_vm_ops = &drm_gem_cma_vm_ops,177 .gem_vm_ops = &vc4_vm_ops,
170 178
171 .prime_handle_to_fd = drm_gem_prime_handle_to_fd,179 .prime_handle_to_fd = drm_gem_prime_handle_to_fd,
172 .prime_fd_to_handle = drm_gem_prime_fd_to_handle,180 .prime_fd_to_handle = drm_gem_prime_fd_to_handle,
drivers/gpu/drm/vc4/vc4_drv.h+30−0
@@ -74,6 +74,19 @@ struct vc4_dev { · 73 unmodified lines
74 /* Protects bo_cache and bo_labels. */74 /* Protects bo_cache and bo_labels. */
75 struct mutex bo_lock;75 struct mutex bo_lock;
76 76
77 /* Purgeable BO pool. All BOs in this pool can have their memory
78 * reclaimed if the driver is unable to allocate new BOs. We also
79 * keep stats related to the purge mechanism here.
80 */
81 struct {
82 struct list_head list;
83 unsigned int num;
84 size_t size;
85 unsigned int purged_num;
86 size_t purged_size;
87 struct mutex lock;
88 } purgeable;
89
77 uint64_t dma_fence_context;90 uint64_t dma_fence_context;
78 91
79 /* Sequence number for the last job queued in bin_job_list.92 /* Sequence number for the last job queued in bin_job_list.
@@ -192,6 +205,16 @@ struct vc4_bo { · 112 unmodified lines
192 * for user-allocated labels.205 * for user-allocated labels.
193 */206 */
194 int label;207 int label;
208
209 /* Count the number of active users. This is needed to determine
210 * whether we can move the BO to the purgeable list or not (when the BO
211 * is used by the GPU or the display engine we can't purge it).
212 */
213 refcount_t usecnt;
214
215 /* Store purgeable/purged state here */
216 u32 madv;
217 struct mutex madv_lock;
195};218};
196 219
197static inline struct vc4_bo *220static inline struct vc4_bo *
@@ -503,6 +526,7 @@ int vc4_get_hang_state_ioctl(struct drm_device *dev, void *data, · 305 unmodified lines
503 struct drm_file *file_priv);526 struct drm_file *file_priv);
504int vc4_label_bo_ioctl(struct drm_device *dev, void *data,527int vc4_label_bo_ioctl(struct drm_device *dev, void *data,
505 struct drm_file *file_priv);528 struct drm_file *file_priv);
529int vc4_fault(struct vm_fault *vmf);
506int vc4_mmap(struct file *filp, struct vm_area_struct *vma);530int vc4_mmap(struct file *filp, struct vm_area_struct *vma);
507struct reservation_object *vc4_prime_res_obj(struct drm_gem_object *obj);531struct reservation_object *vc4_prime_res_obj(struct drm_gem_object *obj);
508int vc4_prime_mmap(struct drm_gem_object *obj, struct vm_area_struct *vma);532int vc4_prime_mmap(struct drm_gem_object *obj, struct vm_area_struct *vma);
@@ -513,6 +537,10 @@ void *vc4_prime_vmap(struct drm_gem_object *obj); · 4 unmodified lines
513int vc4_bo_cache_init(struct drm_device *dev);537int vc4_bo_cache_init(struct drm_device *dev);
514void vc4_bo_cache_destroy(struct drm_device *dev);538void vc4_bo_cache_destroy(struct drm_device *dev);
515int vc4_bo_stats_debugfs(struct seq_file *m, void *arg);539int vc4_bo_stats_debugfs(struct seq_file *m, void *arg);
540int vc4_bo_inc_usecnt(struct vc4_bo *bo);
541void vc4_bo_dec_usecnt(struct vc4_bo *bo);
542void vc4_bo_add_to_purgeable_pool(struct vc4_bo *bo);
543void vc4_bo_remove_from_purgeable_pool(struct vc4_bo *bo);
516 544
517/* vc4_crtc.c */545/* vc4_crtc.c */
518extern struct platform_driver vc4_crtc_driver;546extern struct platform_driver vc4_crtc_driver;
@@ -557,6 +585,8 @@ void vc4_job_handle_completed(struct vc4_dev *vc4); · 38 unmodified lines
557int vc4_queue_seqno_cb(struct drm_device *dev,585int vc4_queue_seqno_cb(struct drm_device *dev,
558 struct vc4_seqno_cb *cb, uint64_t seqno,586 struct vc4_seqno_cb *cb, uint64_t seqno,
559 void (*func)(struct vc4_seqno_cb *cb));587 void (*func)(struct vc4_seqno_cb *cb));
588int vc4_gem_madvise_ioctl(struct drm_device *dev, void *data,
589 struct drm_file *file_priv);
560 590
561/* vc4_hdmi.c */591/* vc4_hdmi.c */
562extern struct platform_driver vc4_hdmi_driver;592extern struct platform_driver vc4_hdmi_driver;
drivers/gpu/drm/vc4/vc4_dsi.c+30−2
@@ -1360,6 +1360,27 @@ static void dsi_handle_error(struct vc4_dsi *dsi, · 1359 unmodified lines
1360 *ret = IRQ_HANDLED;1360 *ret = IRQ_HANDLED;
1361}1361}
1362 1362
1363/*
1364 * Initial handler for port 1 where we need the reg_dma workaround.
1365 * The register DMA writes sleep, so we can't do it in the top half.
1366 * Instead we use IRQF_ONESHOT so that the IRQ gets disabled in the
1367 * parent interrupt contrller until our interrupt thread is done.
1368 */
1369static irqreturn_t vc4_dsi_irq_defer_to_thread_handler(int irq, void *data)
1370{
1371 struct vc4_dsi *dsi = data;
1372 u32 stat = DSI_PORT_READ(INT_STAT);
1373
1374 if (!stat)
1375 return IRQ_NONE;
1376
1377 return IRQ_WAKE_THREAD;
1378}
1379
1380/*
1381 * Normal IRQ handler for port 0, or the threaded IRQ handler for port
1382 * 1 where we need the reg_dma workaround.
1383 */
1363static irqreturn_t vc4_dsi_irq_handler(int irq, void *data)1384static irqreturn_t vc4_dsi_irq_handler(int irq, void *data)
1364{1385{
1365 struct vc4_dsi *dsi = data;1386 struct vc4_dsi *dsi = data;
@@ -1539,8 +1560,15 @@ static int vc4_dsi_bind(struct device *dev, struct device *master, void *data) · 173 unmodified lines
1539 /* Clear any existing interrupt state. */1560 /* Clear any existing interrupt state. */
1540 DSI_PORT_WRITE(INT_STAT, DSI_PORT_READ(INT_STAT));1561 DSI_PORT_WRITE(INT_STAT, DSI_PORT_READ(INT_STAT));
1541 1562
1542 ret = devm_request_irq(dev, platform_get_irq(pdev, 0),1563 if (dsi->reg_dma_mem)
1543 vc4_dsi_irq_handler, 0, "vc4 dsi", dsi);1564 ret = devm_request_threaded_irq(dev, platform_get_irq(pdev, 0),
1565 vc4_dsi_irq_defer_to_thread_handler,
1566 vc4_dsi_irq_handler,
1567 IRQF_ONESHOT,
1568 "vc4 dsi", dsi);
1569 else
1570 ret = devm_request_irq(dev, platform_get_irq(pdev, 0),
1571 vc4_dsi_irq_handler, 0, "vc4 dsi", dsi);
1544 if (ret) {1572 if (ret) {
1545 if (ret != -EPROBE_DEFER)1573 if (ret != -EPROBE_DEFER)
1546 dev_err(dev, "Failed to get interrupt: %d\n", ret);1574 dev_err(dev, "Failed to get interrupt: %d\n", ret);
drivers/gpu/drm/vc4/vc4_gem.c+150−6
@@ -188,11 +188,22 @@ vc4_save_hang_state(struct drm_device *dev) · 187 unmodified lines
188 continue;188 continue;
189 189
190 for (j = 0; j < exec[i]->bo_count; j++) {190 for (j = 0; j < exec[i]->bo_count; j++) {
191 bo = to_vc4_bo(&exec[i]->bo[j]->base);
192
193 /* Retain BOs just in case they were marked purgeable.
194 * This prevents the BO from being purged before
195 * someone had a chance to dump the hang state.
196 */
197 WARN_ON(!refcount_read(&bo->usecnt));
198 refcount_inc(&bo->usecnt);
191 drm_gem_object_get(&exec[i]->bo[j]->base);199 drm_gem_object_get(&exec[i]->bo[j]->base);
192 kernel_state->bo[j + prev_idx] = &exec[i]->bo[j]->base;200 kernel_state->bo[j + prev_idx] = &exec[i]->bo[j]->base;
193 }201 }
194 202
195 list_for_each_entry(bo, &exec[i]->unref_list, unref_head) {203 list_for_each_entry(bo, &exec[i]->unref_list, unref_head) {
204 /* No need to retain BOs coming from the ->unref_list
205 * because they are naturally unpurgeable.
206 */
196 drm_gem_object_get(&bo->base.base);207 drm_gem_object_get(&bo->base.base);
197 kernel_state->bo[j + prev_idx] = &bo->base.base;208 kernel_state->bo[j + prev_idx] = &bo->base.base;
198 j++;209 j++;
@@ -233,6 +244,26 @@ vc4_save_hang_state(struct drm_device *dev) · 34 unmodified lines
233 state->fdbgs = V3D_READ(V3D_FDBGS);244 state->fdbgs = V3D_READ(V3D_FDBGS);
234 state->errstat = V3D_READ(V3D_ERRSTAT);245 state->errstat = V3D_READ(V3D_ERRSTAT);
235 246
247 /* We need to turn purgeable BOs into unpurgeable ones so that
248 * userspace has a chance to dump the hang state before the kernel
249 * decides to purge those BOs.
250 * Note that BO consistency at dump time cannot be guaranteed. For
251 * example, if the owner of these BOs decides to re-use them or mark
252 * them purgeable again there's nothing we can do to prevent it.
253 */
254 for (i = 0; i < kernel_state->user_state.bo_count; i++) {
255 struct vc4_bo *bo = to_vc4_bo(kernel_state->bo[i]);
256
257 if (bo->madv == __VC4_MADV_NOTSUPP)
258 continue;
259
260 mutex_lock(&bo->madv_lock);
261 if (!WARN_ON(bo->madv == __VC4_MADV_PURGED))
262 bo->madv = VC4_MADV_WILLNEED;
263 refcount_dec(&bo->usecnt);
264 mutex_unlock(&bo->madv_lock);
265 }
266
236 spin_lock_irqsave(&vc4->job_lock, irqflags);267 spin_lock_irqsave(&vc4->job_lock, irqflags);
237 if (vc4->hang_state) {268 if (vc4->hang_state) {
238 spin_unlock_irqrestore(&vc4->job_lock, irqflags);269 spin_unlock_irqrestore(&vc4->job_lock, irqflags);
@@ -639,9 +670,6 @@ vc4_queue_submit(struct drm_device *dev, struct vc4_exec_info *exec, · 400 unmodified lines
639 * The command validator needs to reference BOs by their index within670 * The command validator needs to reference BOs by their index within
640 * the submitted job's BO list. This does the validation of the job's671 * the submitted job's BO list. This does the validation of the job's
641 * BO list and reference counting for the lifetime of the job.672 * BO list and reference counting for the lifetime of the job.
642 *
643 * Note that this function doesn't need to unreference the BOs on
644 * failure, because that will happen at vc4_complete_exec() time.
645 */673 */
646static int674static int
647vc4_cl_lookup_bos(struct drm_device *dev,675vc4_cl_lookup_bos(struct drm_device *dev,
@@ -693,16 +721,47 @@ vc4_cl_lookup_bos(struct drm_device *dev, · 45 unmodified lines
693 DRM_DEBUG("Failed to look up GEM BO %d: %d\n",721 DRM_DEBUG("Failed to look up GEM BO %d: %d\n",
694 i, handles[i]);722 i, handles[i]);
695 ret = -EINVAL;723 ret = -EINVAL;
696 spin_unlock(&file_priv->table_lock);724 break;
697 goto fail;
698 }725 }
726
699 drm_gem_object_get(bo);727 drm_gem_object_get(bo);
700 exec->bo[i] = (struct drm_gem_cma_object *)bo;728 exec->bo[i] = (struct drm_gem_cma_object *)bo;
701 }729 }
702 spin_unlock(&file_priv->table_lock);730 spin_unlock(&file_priv->table_lock);
703 731
732 if (ret)
733 goto fail_put_bo;
734
735 for (i = 0; i < exec->bo_count; i++) {
736 ret = vc4_bo_inc_usecnt(to_vc4_bo(&exec->bo[i]->base));
737 if (ret)
738 goto fail_dec_usecnt;
739 }
740
741 kvfree(handles);
742 return 0;
743
744fail_dec_usecnt:
745 /* Decrease usecnt on acquired objects.
746 * We cannot rely on vc4_complete_exec() to release resources here,
747 * because vc4_complete_exec() has no information about which BO has
748 * had its ->usecnt incremented.
749 * To make things easier we just free everything explicitly and set
750 * exec->bo to NULL so that vc4_complete_exec() skips the 'BO release'
751 * step.
752 */
753 for (i-- ; i >= 0; i--)
754 vc4_bo_dec_usecnt(to_vc4_bo(&exec->bo[i]->base));
755
756fail_put_bo:
757 /* Release any reference to acquired objects. */
758 for (i = 0; i < exec->bo_count && exec->bo[i]; i++)
759 drm_gem_object_put_unlocked(&exec->bo[i]->base);
760
704fail:761fail:
705 kvfree(handles);762 kvfree(handles);
763 kvfree(exec->bo);
764 exec->bo = NULL;
706 return ret;765 return ret;
707}766}
708 767
@@ -833,8 +892,12 @@ vc4_complete_exec(struct drm_device *dev, struct vc4_exec_info *exec) · 124 unmodified lines
833 dma_fence_signal(exec->fence);892 dma_fence_signal(exec->fence);
834 893
835 if (exec->bo) {894 if (exec->bo) {
836 for (i = 0; i < exec->bo_count; i++)895 for (i = 0; i < exec->bo_count; i++) {
896 struct vc4_bo *bo = to_vc4_bo(&exec->bo[i]->base);
897
898 vc4_bo_dec_usecnt(bo);
837 drm_gem_object_put_unlocked(&exec->bo[i]->base);899 drm_gem_object_put_unlocked(&exec->bo[i]->base);
900 }
838 kvfree(exec->bo);901 kvfree(exec->bo);
839 }902 }
840 903
@@ -1098,6 +1161,9 @@ vc4_gem_init(struct drm_device *dev) · 257 unmodified lines
1098 INIT_WORK(&vc4->job_done_work, vc4_job_done_work);1161 INIT_WORK(&vc4->job_done_work, vc4_job_done_work);
1099 1162
1100 mutex_init(&vc4->power_lock);1163 mutex_init(&vc4->power_lock);
1164
1165 INIT_LIST_HEAD(&vc4->purgeable.list);
1166 mutex_init(&vc4->purgeable.lock);
1101}1167}
1102 1168
1103void1169void
@@ -1121,3 +1187,81 @@ vc4_gem_destroy(struct drm_device *dev) · 17 unmodified lines
1121 if (vc4->hang_state)1187 if (vc4->hang_state)
1122 vc4_free_hang_state(dev, vc4->hang_state);1188 vc4_free_hang_state(dev, vc4->hang_state);
1123}1189}
1190
1191int vc4_gem_madvise_ioctl(struct drm_device *dev, void *data,
1192 struct drm_file *file_priv)
1193{
1194 struct drm_vc4_gem_madvise *args = data;
1195 struct drm_gem_object *gem_obj;
1196 struct vc4_bo *bo;
1197 int ret;
1198
1199 switch (args->madv) {
1200 case VC4_MADV_DONTNEED:
1201 case VC4_MADV_WILLNEED:
1202 break;
1203 default:
1204 return -EINVAL;
1205 }
1206
1207 if (args->pad != 0)
1208 return -EINVAL;
1209
1210 gem_obj = drm_gem_object_lookup(file_priv, args->handle);
1211 if (!gem_obj) {
1212 DRM_DEBUG("Failed to look up GEM BO %d\n", args->handle);
1213 return -ENOENT;
1214 }
1215
1216 bo = to_vc4_bo(gem_obj);
1217
1218 /* Only BOs exposed to userspace can be purged. */
1219 if (bo->madv == __VC4_MADV_NOTSUPP) {
1220 DRM_DEBUG("madvise not supported on this BO\n");
1221 ret = -EINVAL;
1222 goto out_put_gem;
1223 }
1224
1225 /* Not sure it's safe to purge imported BOs. Let's just assume it's
1226 * not until proven otherwise.
1227 */
1228 if (gem_obj->import_attach) {
1229 DRM_DEBUG("madvise not supported on imported BOs\n");
1230 ret = -EINVAL;
1231 goto out_put_gem;
1232 }
1233
1234 mutex_lock(&bo->madv_lock);
1235
1236 if (args->madv == VC4_MADV_DONTNEED && bo->madv == VC4_MADV_WILLNEED &&
1237 !refcount_read(&bo->usecnt)) {
1238 /* If the BO is about to be marked as purgeable, is not used
1239 * and is not already purgeable or purged, add it to the
1240 * purgeable list.
1241 */
1242 vc4_bo_add_to_purgeable_pool(bo);
1243 } else if (args->madv == VC4_MADV_WILLNEED &&
1244 bo->madv == VC4_MADV_DONTNEED &&
1245 !refcount_read(&bo->usecnt)) {
1246 /* The BO has not been purged yet, just remove it from
1247 * the purgeable list.
1248 */
1249 vc4_bo_remove_from_purgeable_pool(bo);
1250 }
1251
1252 /* Save the purged state. */
1253 args->retained = bo->madv != __VC4_MADV_PURGED;
1254
1255 /* Update internal madv state only if the bo was not purged. */
1256 if (bo->madv != __VC4_MADV_PURGED)
1257 bo->madv = args->madv;
1258
1259 mutex_unlock(&bo->madv_lock);
1260
1261 ret = 0;
1262
1263out_put_gem:
1264 drm_gem_object_put_unlocked(gem_obj);
1265
1266 return ret;
1267}
drivers/gpu/drm/vc4/vc4_plane.c+20−0
@@ -23,6 +23,7 @@ · 22 unmodified lines
23#include <drm/drm_fb_cma_helper.h>23#include <drm/drm_fb_cma_helper.h>
24#include <drm/drm_plane_helper.h>24#include <drm/drm_plane_helper.h>
25 25
26#include "uapi/drm/vc4_drm.h"
26#include "vc4_drv.h"27#include "vc4_drv.h"
27#include "vc4_regs.h"28#include "vc4_regs.h"
28 29
@@ -774,21 +775,40 @@ static int vc4_prepare_fb(struct drm_plane *plane, · 745 unmodified lines
774{775{
775 struct vc4_bo *bo;776 struct vc4_bo *bo;
776 struct dma_fence *fence;777 struct dma_fence *fence;
778 int ret;
777 779
778 if ((plane->state->fb == state->fb) || !state->fb)780 if ((plane->state->fb == state->fb) || !state->fb)
779 return 0;781 return 0;
780 782
781 bo = to_vc4_bo(&drm_fb_cma_get_gem_obj(state->fb, 0)->base);783 bo = to_vc4_bo(&drm_fb_cma_get_gem_obj(state->fb, 0)->base);
784
785 ret = vc4_bo_inc_usecnt(bo);
786 if (ret)
787 return ret;
788
782 fence = reservation_object_get_excl_rcu(bo->resv);789 fence = reservation_object_get_excl_rcu(bo->resv);
783 drm_atomic_set_fence_for_plane(state, fence);790 drm_atomic_set_fence_for_plane(state, fence);
784 791
785 return 0;792 return 0;
786}793}
787 794
795static void vc4_cleanup_fb(struct drm_plane *plane,
796 struct drm_plane_state *state)
797{
798 struct vc4_bo *bo;
799
800 if (plane->state->fb == state->fb || !state->fb)
801 return;
802
803 bo = to_vc4_bo(&drm_fb_cma_get_gem_obj(state->fb, 0)->base);
804 vc4_bo_dec_usecnt(bo);
805}
806
788static const struct drm_plane_helper_funcs vc4_plane_helper_funcs = {807static const struct drm_plane_helper_funcs vc4_plane_helper_funcs = {
789 .atomic_check = vc4_plane_atomic_check,808 .atomic_check = vc4_plane_atomic_check,
790 .atomic_update = vc4_plane_atomic_update,809 .atomic_update = vc4_plane_atomic_update,
791 .prepare_fb = vc4_prepare_fb,810 .prepare_fb = vc4_prepare_fb,
811 .cleanup_fb = vc4_cleanup_fb,
792};812};
793 813
794static void vc4_plane_destroy(struct drm_plane *plane)814static void vc4_plane_destroy(struct drm_plane *plane)
drivers/gpu/vga/vgaarb.c+55−17
@@ -1402,29 +1402,14 @@ static struct miscdevice vga_arb_device = { · 1401 unmodified lines
1402 MISC_DYNAMIC_MINOR, "vga_arbiter", &vga_arb_device_fops1402 MISC_DYNAMIC_MINOR, "vga_arbiter", &vga_arb_device_fops
1403};1403};
1404 1404
1405static int __init vga_arb_device_init(void)1405static void __init vga_arb_select_default_device(void)
1406{1406{
1407 int rc;
1408 struct pci_dev *pdev;1407 struct pci_dev *pdev;
1409 struct vga_device *vgadev;1408 struct vga_device *vgadev;
1410 1409
1411 rc = misc_register(&vga_arb_device);1410#if defined(CONFIG_X86) || defined(CONFIG_IA64)
1412 if (rc < 0)
1413 pr_err("error %d registering device\n", rc);
1414
1415 bus_register_notifier(&pci_bus_type, &pci_notifier);
1416
1417 /* We add all pci devices satisfying vga class in the arbiter by
1418 * default */
1419 pdev = NULL;
1420 while ((pdev =
1421 pci_get_subsys(PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
1422 PCI_ANY_ID, pdev)) != NULL)
1423 vga_arbiter_add_pci_device(pdev);
1424
1425 list_for_each_entry(vgadev, &vga_list, list) {1411 list_for_each_entry(vgadev, &vga_list, list) {
1426 struct device *dev = &vgadev->pdev->dev;1412 struct device *dev = &vgadev->pdev->dev;
1427#if defined(CONFIG_X86) || defined(CONFIG_IA64)
1428 /*1413 /*
1429 * Override vga_arbiter_add_pci_device()'s I/O based detection1414 * Override vga_arbiter_add_pci_device()'s I/O based detection
1430 * as it may take the wrong device (e.g. on Apple system under1415 * as it may take the wrong device (e.g. on Apple system under
@@ -1461,13 +1446,66 @@ static int __init vga_arb_device_init(void) · 30 unmodified lines
1461 vgaarb_info(dev, "overriding boot device\n");1446 vgaarb_info(dev, "overriding boot device\n");
1462 vga_set_default_device(vgadev->pdev);1447 vga_set_default_device(vgadev->pdev);
1463 }1448 }
1449 }
1464#endif1450#endif
1451
1452 if (!vga_default_device()) {
1453 list_for_each_entry(vgadev, &vga_list, list) {
1454 struct device *dev = &vgadev->pdev->dev;
1455 u16 cmd;
1456
1457 pdev = vgadev->pdev;
1458 pci_read_config_word(pdev, PCI_COMMAND, &cmd);
1459 if (cmd & (PCI_COMMAND_IO | PCI_COMMAND_MEMORY)) {
1460 vgaarb_info(dev, "setting as boot device (VGA legacy resources not available)\n");
1461 vga_set_default_device(pdev);
1462 break;
1463 }
1464 }
1465 }
1466
1467 if (!vga_default_device()) {
1468 vgadev = list_first_entry_or_null(&vga_list,
1469 struct vga_device, list);
1470 if (vgadev) {
1471 struct device *dev = &vgadev->pdev->dev;
1472 vgaarb_info(dev, "setting as boot device (VGA legacy resources not available)\n");
1473 vga_set_default_device(vgadev->pdev);
1474 }
1475 }
1476}
1477
1478static int __init vga_arb_device_init(void)
1479{
1480 int rc;
1481 struct pci_dev *pdev;
1482 struct vga_device *vgadev;
1483
1484 rc = misc_register(&vga_arb_device);
1485 if (rc < 0)
1486 pr_err("error %d registering device\n", rc);
1487
1488 bus_register_notifier(&pci_bus_type, &pci_notifier);
1489
1490 /* We add all PCI devices satisfying VGA class in the arbiter by
1491 * default */
1492 pdev = NULL;
1493 while ((pdev =
1494 pci_get_subsys(PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
1495 PCI_ANY_ID, pdev)) != NULL)
1496 vga_arbiter_add_pci_device(pdev);
1497
1498 list_for_each_entry(vgadev, &vga_list, list) {
1499 struct device *dev = &vgadev->pdev->dev;
1500
1465 if (vgadev->bridge_has_one_vga)1501 if (vgadev->bridge_has_one_vga)
1466 vgaarb_info(dev, "bridge control possible\n");1502 vgaarb_info(dev, "bridge control possible\n");
1467 else1503 else
1468 vgaarb_info(dev, "no bridge control possible\n");1504 vgaarb_info(dev, "no bridge control possible\n");
1469 }1505 }
1470 1506
1507 vga_arb_select_default_device();
1508
1471 pr_info("loaded\n");1509 pr_info("loaded\n");
1472 return rc;1510 return rc;
1473}1511}
include/linux/dma-fence.h+1−1
@@ -128,7 +128,7 @@ struct dma_fence_cb { · 127 unmodified lines
128 * implementation know that there is another driver waiting on128 * implementation know that there is another driver waiting on
129 * the signal (ie. hw->sw case).129 * the signal (ie. hw->sw case).
130 *130 *
131 * This function can be called called from atomic context, but not131 * This function can be called from atomic context, but not
132 * from irq context, so normal spinlocks can be used.132 * from irq context, so normal spinlocks can be used.
133 *133 *
134 * A return value of false indicates the fence already passed,134 * A return value of false indicates the fence already passed,
include/uapi/drm/vc4_drm.h+19−0
@@ -41,6 +41,7 @@ extern "C" { · 40 unmodified lines
41#define DRM_VC4_SET_TILING 0x0841#define DRM_VC4_SET_TILING 0x08
42#define DRM_VC4_GET_TILING 0x0942#define DRM_VC4_GET_TILING 0x09
43#define DRM_VC4_LABEL_BO 0x0a43#define DRM_VC4_LABEL_BO 0x0a
44#define DRM_VC4_GEM_MADVISE 0x0b
44 45
45#define DRM_IOCTL_VC4_SUBMIT_CL DRM_IOWR(DRM_COMMAND_BASE + DRM_VC4_SUBMIT_CL, struct drm_vc4_submit_cl)46#define DRM_IOCTL_VC4_SUBMIT_CL DRM_IOWR(DRM_COMMAND_BASE + DRM_VC4_SUBMIT_CL, struct drm_vc4_submit_cl)
46#define DRM_IOCTL_VC4_WAIT_SEQNO DRM_IOWR(DRM_COMMAND_BASE + DRM_VC4_WAIT_SEQNO, struct drm_vc4_wait_seqno)47#define DRM_IOCTL_VC4_WAIT_SEQNO DRM_IOWR(DRM_COMMAND_BASE + DRM_VC4_WAIT_SEQNO, struct drm_vc4_wait_seqno)
@@ -53,6 +54,7 @@ extern "C" { · 6 unmodified lines
53#define DRM_IOCTL_VC4_SET_TILING DRM_IOWR(DRM_COMMAND_BASE + DRM_VC4_SET_TILING, struct drm_vc4_set_tiling)54#define DRM_IOCTL_VC4_SET_TILING DRM_IOWR(DRM_COMMAND_BASE + DRM_VC4_SET_TILING, struct drm_vc4_set_tiling)
54#define DRM_IOCTL_VC4_GET_TILING DRM_IOWR(DRM_COMMAND_BASE + DRM_VC4_GET_TILING, struct drm_vc4_get_tiling)55#define DRM_IOCTL_VC4_GET_TILING DRM_IOWR(DRM_COMMAND_BASE + DRM_VC4_GET_TILING, struct drm_vc4_get_tiling)
55#define DRM_IOCTL_VC4_LABEL_BO DRM_IOWR(DRM_COMMAND_BASE + DRM_VC4_LABEL_BO, struct drm_vc4_label_bo)56#define DRM_IOCTL_VC4_LABEL_BO DRM_IOWR(DRM_COMMAND_BASE + DRM_VC4_LABEL_BO, struct drm_vc4_label_bo)
57#define DRM_IOCTL_VC4_GEM_MADVISE DRM_IOWR(DRM_COMMAND_BASE + DRM_VC4_GEM_MADVISE, struct drm_vc4_gem_madvise)
56 58
57struct drm_vc4_submit_rcl_surface {59struct drm_vc4_submit_rcl_surface {
58 __u32 hindex; /* Handle index, or ~0 if not present. */60 __u32 hindex; /* Handle index, or ~0 if not present. */
@@ -305,6 +307,7 @@ struct drm_vc4_get_hang_state { · 246 unmodified lines
305#define DRM_VC4_PARAM_SUPPORTS_ETC1 4307#define DRM_VC4_PARAM_SUPPORTS_ETC1 4
306#define DRM_VC4_PARAM_SUPPORTS_THREADED_FS 5308#define DRM_VC4_PARAM_SUPPORTS_THREADED_FS 5
307#define DRM_VC4_PARAM_SUPPORTS_FIXED_RCL_ORDER 6309#define DRM_VC4_PARAM_SUPPORTS_FIXED_RCL_ORDER 6
310#define DRM_VC4_PARAM_SUPPORTS_MADVISE 7
308 311
309struct drm_vc4_get_param {312struct drm_vc4_get_param {
310 __u32 param;313 __u32 param;
@@ -333,6 +336,22 @@ struct drm_vc4_label_bo { · 22 unmodified lines
333 __u64 name;336 __u64 name;
334};337};
335 338
339/*
340 * States prefixed with '__' are internal states and cannot be passed to the
341 * DRM_IOCTL_VC4_GEM_MADVISE ioctl.
342 */
343#define VC4_MADV_WILLNEED 0
344#define VC4_MADV_DONTNEED 1
345#define __VC4_MADV_PURGED 2
346#define __VC4_MADV_NOTSUPP 3
347
348struct drm_vc4_gem_madvise {
349 __u32 handle;
350 __u32 madv;
351 __u32 retained;
352 __u32 pad;
353};
354
336#if defined(__cplusplus)355#if defined(__cplusplus)
337}356}
338#endif357#endif