diff options
123 files changed, 3251 insertions, 827 deletions
diff --git a/Documentation/devicetree/bindings/display/bridge/ti,ths8135.txt b/Documentation/devicetree/bindings/display/bridge/ti,ths813x.txt index 6ec1a880ac18..df3d7c1ac09e 100644 --- a/Documentation/devicetree/bindings/display/bridge/ti,ths8135.txt +++ b/Documentation/devicetree/bindings/display/bridge/ti,ths813x.txt | |||
@@ -1,11 +1,16 @@ | |||
1 | THS8135 Video DAC | 1 | THS8134 and THS8135 Video DAC |
2 | ----------------- | 2 | ----------------------------- |
3 | 3 | ||
4 | This is the binding for Texas Instruments THS8135 Video DAC bridge. | 4 | This is the binding for Texas Instruments THS8134, THS8134A, THS8134B and |
5 | THS8135 Video DAC bridges. | ||
5 | 6 | ||
6 | Required properties: | 7 | Required properties: |
7 | 8 | ||
8 | - compatible: Must be "ti,ths8135" | 9 | - compatible: Must be one of |
10 | "ti,ths8134" | ||
11 | "ti,ths8134a," "ti,ths8134" | ||
12 | "ti,ths8134b", "ti,ths8134" | ||
13 | "ti,ths8135" | ||
9 | 14 | ||
10 | Required nodes: | 15 | Required nodes: |
11 | 16 | ||
diff --git a/Documentation/devicetree/bindings/display/panel/arm,versatile-tft-panel.txt b/Documentation/devicetree/bindings/display/panel/arm,versatile-tft-panel.txt new file mode 100644 index 000000000000..248141c3c7e3 --- /dev/null +++ b/Documentation/devicetree/bindings/display/panel/arm,versatile-tft-panel.txt | |||
@@ -0,0 +1,31 @@ | |||
1 | ARM Versatile TFT Panels | ||
2 | |||
3 | These panels are connected to the daughterboards found on the | ||
4 | ARM Versatile reference designs. | ||
5 | |||
6 | This device node must appear as a child to a "syscon"-compatible | ||
7 | node. | ||
8 | |||
9 | Required properties: | ||
10 | - compatible: should be "arm,versatile-tft-panel" | ||
11 | |||
12 | Required subnodes: | ||
13 | - port: see display/panel/panel-common.txt, graph.txt | ||
14 | |||
15 | |||
16 | Example: | ||
17 | |||
18 | sysreg@0 { | ||
19 | compatible = "arm,versatile-sysreg", "syscon", "simple-mfd"; | ||
20 | reg = <0x00000 0x1000>; | ||
21 | |||
22 | panel: display@0 { | ||
23 | compatible = "arm,versatile-tft-panel"; | ||
24 | |||
25 | port { | ||
26 | panel_in: endpoint { | ||
27 | remote-endpoint = <&foo>; | ||
28 | }; | ||
29 | }; | ||
30 | }; | ||
31 | }; | ||
diff --git a/Documentation/devicetree/bindings/display/st,stm32-ltdc.txt b/Documentation/devicetree/bindings/display/st,stm32-ltdc.txt index 029252253ad4..3eb1b48b47dd 100644 --- a/Documentation/devicetree/bindings/display/st,stm32-ltdc.txt +++ b/Documentation/devicetree/bindings/display/st,stm32-ltdc.txt | |||
@@ -98,7 +98,7 @@ Example 2: DSI panel | |||
98 | compatible = "st,stm32-dsi"; | 98 | compatible = "st,stm32-dsi"; |
99 | reg = <0x40016c00 0x800>; | 99 | reg = <0x40016c00 0x800>; |
100 | clocks = <&rcc 1 CLK_F469_DSI>, <&clk_hse>; | 100 | clocks = <&rcc 1 CLK_F469_DSI>, <&clk_hse>; |
101 | clock-names = "ref", "pclk"; | 101 | clock-names = "pclk", "ref"; |
102 | resets = <&rcc STM32F4_APB2_RESET(DSI)>; | 102 | resets = <&rcc STM32F4_APB2_RESET(DSI)>; |
103 | reset-names = "apb"; | 103 | reset-names = "apb"; |
104 | 104 | ||
diff --git a/MAINTAINERS b/MAINTAINERS index 3bdc260e36b7..2afba909724c 100644 --- a/MAINTAINERS +++ b/MAINTAINERS | |||
@@ -4456,6 +4456,13 @@ T: git git://anongit.freedesktop.org/drm/drm-misc | |||
4456 | S: Supported | 4456 | S: Supported |
4457 | F: drivers/gpu/drm/pl111/ | 4457 | F: drivers/gpu/drm/pl111/ |
4458 | 4458 | ||
4459 | DRM DRIVER FOR ARM VERSATILE TFT PANELS | ||
4460 | M: Linus Walleij <linus.walleij@linaro.org> | ||
4461 | T: git git://anongit.freedesktop.org/drm/drm-misc | ||
4462 | S: Maintained | ||
4463 | F: drivers/gpu/drm/panel/panel-arm-versatile.c | ||
4464 | F: Documentation/devicetree/bindings/display/panel/arm,versatile-tft-panel.txt | ||
4465 | |||
4459 | DRM DRIVER FOR AST SERVER GRAPHICS CHIPS | 4466 | DRM DRIVER FOR AST SERVER GRAPHICS CHIPS |
4460 | M: Dave Airlie <airlied@redhat.com> | 4467 | M: Dave Airlie <airlied@redhat.com> |
4461 | S: Odd Fixes | 4468 | S: Odd Fixes |
@@ -4610,8 +4617,8 @@ F: include/uapi/drm/ | |||
4610 | F: include/linux/vga* | 4617 | F: include/linux/vga* |
4611 | 4618 | ||
4612 | DRM DRIVERS AND MISC GPU PATCHES | 4619 | DRM DRIVERS AND MISC GPU PATCHES |
4613 | M: Daniel Vetter <daniel.vetter@intel.com> | ||
4614 | M: Gustavo Padovan <gustavo@padovan.org> | 4620 | M: Gustavo Padovan <gustavo@padovan.org> |
4621 | M: Maarten Lankhorst <maarten.lankhorst@linux.intel.com> | ||
4615 | M: Sean Paul <seanpaul@chromium.org> | 4622 | M: Sean Paul <seanpaul@chromium.org> |
4616 | W: https://01.org/linuxgraphics/gfx-docs/maintainer-tools/drm-misc.html | 4623 | W: https://01.org/linuxgraphics/gfx-docs/maintainer-tools/drm-misc.html |
4617 | S: Maintained | 4624 | S: Maintained |
diff --git a/drivers/dma-buf/reservation.c b/drivers/dma-buf/reservation.c index 04ebe2204c12..314eb1071cce 100644 --- a/drivers/dma-buf/reservation.c +++ b/drivers/dma-buf/reservation.c | |||
@@ -374,8 +374,9 @@ EXPORT_SYMBOL(reservation_object_copy_fences); | |||
374 | * @pshared: the array of shared fence ptrs returned (array is krealloc'd to | 374 | * @pshared: the array of shared fence ptrs returned (array is krealloc'd to |
375 | * the required size, and must be freed by caller) | 375 | * the required size, and must be freed by caller) |
376 | * | 376 | * |
377 | * RETURNS | 377 | * Retrieve all fences from the reservation object. If the pointer for the |
378 | * Zero or -errno | 378 | * exclusive fence is not specified the fence is put into the array of the |
379 | * shared fences as well. Returns either zero or -ENOMEM. | ||
379 | */ | 380 | */ |
380 | int reservation_object_get_fences_rcu(struct reservation_object *obj, | 381 | int reservation_object_get_fences_rcu(struct reservation_object *obj, |
381 | struct dma_fence **pfence_excl, | 382 | struct dma_fence **pfence_excl, |
@@ -389,8 +390,8 @@ int reservation_object_get_fences_rcu(struct reservation_object *obj, | |||
389 | 390 | ||
390 | do { | 391 | do { |
391 | struct reservation_object_list *fobj; | 392 | struct reservation_object_list *fobj; |
392 | unsigned seq; | 393 | unsigned int i, seq; |
393 | unsigned int i; | 394 | size_t sz = 0; |
394 | 395 | ||
395 | shared_count = i = 0; | 396 | shared_count = i = 0; |
396 | 397 | ||
@@ -402,9 +403,14 @@ int reservation_object_get_fences_rcu(struct reservation_object *obj, | |||
402 | goto unlock; | 403 | goto unlock; |
403 | 404 | ||
404 | fobj = rcu_dereference(obj->fence); | 405 | fobj = rcu_dereference(obj->fence); |
405 | if (fobj) { | 406 | if (fobj) |
407 | sz += sizeof(*shared) * fobj->shared_max; | ||
408 | |||
409 | if (!pfence_excl && fence_excl) | ||
410 | sz += sizeof(*shared); | ||
411 | |||
412 | if (sz) { | ||
406 | struct dma_fence **nshared; | 413 | struct dma_fence **nshared; |
407 | size_t sz = sizeof(*shared) * fobj->shared_max; | ||
408 | 414 | ||
409 | nshared = krealloc(shared, sz, | 415 | nshared = krealloc(shared, sz, |
410 | GFP_NOWAIT | __GFP_NOWARN); | 416 | GFP_NOWAIT | __GFP_NOWARN); |
@@ -420,13 +426,19 @@ int reservation_object_get_fences_rcu(struct reservation_object *obj, | |||
420 | break; | 426 | break; |
421 | } | 427 | } |
422 | shared = nshared; | 428 | shared = nshared; |
423 | shared_count = fobj->shared_count; | 429 | shared_count = fobj ? fobj->shared_count : 0; |
424 | |||
425 | for (i = 0; i < shared_count; ++i) { | 430 | for (i = 0; i < shared_count; ++i) { |
426 | shared[i] = rcu_dereference(fobj->shared[i]); | 431 | shared[i] = rcu_dereference(fobj->shared[i]); |
427 | if (!dma_fence_get_rcu(shared[i])) | 432 | if (!dma_fence_get_rcu(shared[i])) |
428 | break; | 433 | break; |
429 | } | 434 | } |
435 | |||
436 | if (!pfence_excl && fence_excl) { | ||
437 | shared[i] = fence_excl; | ||
438 | fence_excl = NULL; | ||
439 | ++i; | ||
440 | ++shared_count; | ||
441 | } | ||
430 | } | 442 | } |
431 | 443 | ||
432 | if (i != shared_count || read_seqcount_retry(&obj->seq, seq)) { | 444 | if (i != shared_count || read_seqcount_retry(&obj->seq, seq)) { |
@@ -448,7 +460,8 @@ unlock: | |||
448 | 460 | ||
449 | *pshared_count = shared_count; | 461 | *pshared_count = shared_count; |
450 | *pshared = shared; | 462 | *pshared = shared; |
451 | *pfence_excl = fence_excl; | 463 | if (pfence_excl) |
464 | *pfence_excl = fence_excl; | ||
452 | 465 | ||
453 | return ret; | 466 | return ret; |
454 | } | 467 | } |
diff --git a/drivers/dma-buf/sw_sync.c b/drivers/dma-buf/sw_sync.c index 24f83f9eeaed..7779bdbd18d1 100644 --- a/drivers/dma-buf/sw_sync.c +++ b/drivers/dma-buf/sw_sync.c | |||
@@ -43,14 +43,14 @@ | |||
43 | * timelines. | 43 | * timelines. |
44 | * | 44 | * |
45 | * Fences can be created with SW_SYNC_IOC_CREATE_FENCE ioctl with struct | 45 | * Fences can be created with SW_SYNC_IOC_CREATE_FENCE ioctl with struct |
46 | * sw_sync_ioctl_create_fence as parameter. | 46 | * sw_sync_create_fence_data as parameter. |
47 | * | 47 | * |
48 | * To increment the timeline counter, SW_SYNC_IOC_INC ioctl should be used | 48 | * To increment the timeline counter, SW_SYNC_IOC_INC ioctl should be used |
49 | * with the increment as u32. This will update the last signaled value | 49 | * with the increment as u32. This will update the last signaled value |
50 | * from the timeline and signal any fence that has a seqno smaller or equal | 50 | * from the timeline and signal any fence that has a seqno smaller or equal |
51 | * to it. | 51 | * to it. |
52 | * | 52 | * |
53 | * struct sw_sync_ioctl_create_fence | 53 | * struct sw_sync_create_fence_data |
54 | * @value: the seqno to initialise the fence with | 54 | * @value: the seqno to initialise the fence with |
55 | * @name: the name of the new sync point | 55 | * @name: the name of the new sync point |
56 | * @fence: return the fd of the new sync_file with the created fence | 56 | * @fence: return the fd of the new sync_file with the created fence |
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu.h b/drivers/gpu/drm/amd/amdgpu/amdgpu.h index d5a2eefd6c3e..31126df06c8c 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h | |||
@@ -1504,6 +1504,7 @@ struct amdgpu_device { | |||
1504 | const struct amdgpu_asic_funcs *asic_funcs; | 1504 | const struct amdgpu_asic_funcs *asic_funcs; |
1505 | bool shutdown; | 1505 | bool shutdown; |
1506 | bool need_dma32; | 1506 | bool need_dma32; |
1507 | bool need_swiotlb; | ||
1507 | bool accel_working; | 1508 | bool accel_working; |
1508 | struct work_struct reset_work; | 1509 | struct work_struct reset_work; |
1509 | struct notifier_block acpi_nb; | 1510 | struct notifier_block acpi_nb; |
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c index e4bb435e614b..d897c4c61a01 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c | |||
@@ -1018,7 +1018,7 @@ static int amdgpu_ttm_tt_populate(struct ttm_tt *ttm, | |||
1018 | } | 1018 | } |
1019 | 1019 | ||
1020 | #ifdef CONFIG_SWIOTLB | 1020 | #ifdef CONFIG_SWIOTLB |
1021 | if (swiotlb_nr_tbl()) { | 1021 | if (adev->need_swiotlb && swiotlb_nr_tbl()) { |
1022 | return ttm_dma_populate(>t->ttm, adev->dev, ctx); | 1022 | return ttm_dma_populate(>t->ttm, adev->dev, ctx); |
1023 | } | 1023 | } |
1024 | #endif | 1024 | #endif |
@@ -1045,7 +1045,7 @@ static void amdgpu_ttm_tt_unpopulate(struct ttm_tt *ttm) | |||
1045 | adev = amdgpu_ttm_adev(ttm->bdev); | 1045 | adev = amdgpu_ttm_adev(ttm->bdev); |
1046 | 1046 | ||
1047 | #ifdef CONFIG_SWIOTLB | 1047 | #ifdef CONFIG_SWIOTLB |
1048 | if (swiotlb_nr_tbl()) { | 1048 | if (adev->need_swiotlb && swiotlb_nr_tbl()) { |
1049 | ttm_dma_unpopulate(>t->ttm, adev->dev); | 1049 | ttm_dma_unpopulate(>t->ttm, adev->dev); |
1050 | return; | 1050 | return; |
1051 | } | 1051 | } |
@@ -2010,7 +2010,7 @@ static int amdgpu_ttm_debugfs_init(struct amdgpu_device *adev) | |||
2010 | count = ARRAY_SIZE(amdgpu_ttm_debugfs_list); | 2010 | count = ARRAY_SIZE(amdgpu_ttm_debugfs_list); |
2011 | 2011 | ||
2012 | #ifdef CONFIG_SWIOTLB | 2012 | #ifdef CONFIG_SWIOTLB |
2013 | if (!swiotlb_nr_tbl()) | 2013 | if (!(adev->need_swiotlb && swiotlb_nr_tbl())) |
2014 | --count; | 2014 | --count; |
2015 | #endif | 2015 | #endif |
2016 | 2016 | ||
diff --git a/drivers/gpu/drm/amd/amdgpu/gmc_v6_0.c b/drivers/gpu/drm/amd/amdgpu/gmc_v6_0.c index 8e28270d1ea9..5f5eb15ccf4a 100644 --- a/drivers/gpu/drm/amd/amdgpu/gmc_v6_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gmc_v6_0.c | |||
@@ -22,6 +22,7 @@ | |||
22 | */ | 22 | */ |
23 | #include <linux/firmware.h> | 23 | #include <linux/firmware.h> |
24 | #include <drm/drmP.h> | 24 | #include <drm/drmP.h> |
25 | #include <drm/drm_cache.h> | ||
25 | #include "amdgpu.h" | 26 | #include "amdgpu.h" |
26 | #include "gmc_v6_0.h" | 27 | #include "gmc_v6_0.h" |
27 | #include "amdgpu_ucode.h" | 28 | #include "amdgpu_ucode.h" |
@@ -851,6 +852,7 @@ static int gmc_v6_0_sw_init(void *handle) | |||
851 | pci_set_consistent_dma_mask(adev->pdev, DMA_BIT_MASK(32)); | 852 | pci_set_consistent_dma_mask(adev->pdev, DMA_BIT_MASK(32)); |
852 | dev_warn(adev->dev, "amdgpu: No coherent DMA available.\n"); | 853 | dev_warn(adev->dev, "amdgpu: No coherent DMA available.\n"); |
853 | } | 854 | } |
855 | adev->need_swiotlb = drm_get_max_iomem() > ((u64)1 << dma_bits); | ||
854 | 856 | ||
855 | r = gmc_v6_0_init_microcode(adev); | 857 | r = gmc_v6_0_init_microcode(adev); |
856 | if (r) { | 858 | if (r) { |
diff --git a/drivers/gpu/drm/amd/amdgpu/gmc_v7_0.c b/drivers/gpu/drm/amd/amdgpu/gmc_v7_0.c index 86e9d682c59e..12e49bd8fd2d 100644 --- a/drivers/gpu/drm/amd/amdgpu/gmc_v7_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gmc_v7_0.c | |||
@@ -22,6 +22,7 @@ | |||
22 | */ | 22 | */ |
23 | #include <linux/firmware.h> | 23 | #include <linux/firmware.h> |
24 | #include <drm/drmP.h> | 24 | #include <drm/drmP.h> |
25 | #include <drm/drm_cache.h> | ||
25 | #include "amdgpu.h" | 26 | #include "amdgpu.h" |
26 | #include "cikd.h" | 27 | #include "cikd.h" |
27 | #include "cik.h" | 28 | #include "cik.h" |
@@ -999,6 +1000,7 @@ static int gmc_v7_0_sw_init(void *handle) | |||
999 | pci_set_consistent_dma_mask(adev->pdev, DMA_BIT_MASK(32)); | 1000 | pci_set_consistent_dma_mask(adev->pdev, DMA_BIT_MASK(32)); |
1000 | pr_warn("amdgpu: No coherent DMA available\n"); | 1001 | pr_warn("amdgpu: No coherent DMA available\n"); |
1001 | } | 1002 | } |
1003 | adev->need_swiotlb = drm_get_max_iomem() > ((u64)1 << dma_bits); | ||
1002 | 1004 | ||
1003 | r = gmc_v7_0_init_microcode(adev); | 1005 | r = gmc_v7_0_init_microcode(adev); |
1004 | if (r) { | 1006 | if (r) { |
diff --git a/drivers/gpu/drm/amd/amdgpu/gmc_v8_0.c b/drivers/gpu/drm/amd/amdgpu/gmc_v8_0.c index 9a813d834f1a..9a170e37fbe7 100644 --- a/drivers/gpu/drm/amd/amdgpu/gmc_v8_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gmc_v8_0.c | |||
@@ -22,6 +22,7 @@ | |||
22 | */ | 22 | */ |
23 | #include <linux/firmware.h> | 23 | #include <linux/firmware.h> |
24 | #include <drm/drmP.h> | 24 | #include <drm/drmP.h> |
25 | #include <drm/drm_cache.h> | ||
25 | #include "amdgpu.h" | 26 | #include "amdgpu.h" |
26 | #include "gmc_v8_0.h" | 27 | #include "gmc_v8_0.h" |
27 | #include "amdgpu_ucode.h" | 28 | #include "amdgpu_ucode.h" |
@@ -1085,6 +1086,7 @@ static int gmc_v8_0_sw_init(void *handle) | |||
1085 | */ | 1086 | */ |
1086 | adev->need_dma32 = false; | 1087 | adev->need_dma32 = false; |
1087 | dma_bits = adev->need_dma32 ? 32 : 40; | 1088 | dma_bits = adev->need_dma32 ? 32 : 40; |
1089 | adev->need_swiotlb = drm_get_max_iomem() > ((u64)1 << dma_bits); | ||
1088 | r = pci_set_dma_mask(adev->pdev, DMA_BIT_MASK(dma_bits)); | 1090 | r = pci_set_dma_mask(adev->pdev, DMA_BIT_MASK(dma_bits)); |
1089 | if (r) { | 1091 | if (r) { |
1090 | adev->need_dma32 = true; | 1092 | adev->need_dma32 = true; |
@@ -1096,6 +1098,7 @@ static int gmc_v8_0_sw_init(void *handle) | |||
1096 | pci_set_consistent_dma_mask(adev->pdev, DMA_BIT_MASK(32)); | 1098 | pci_set_consistent_dma_mask(adev->pdev, DMA_BIT_MASK(32)); |
1097 | pr_warn("amdgpu: No coherent DMA available\n"); | 1099 | pr_warn("amdgpu: No coherent DMA available\n"); |
1098 | } | 1100 | } |
1101 | adev->need_swiotlb = drm_get_max_iomem() > ((u64)1 << dma_bits); | ||
1099 | 1102 | ||
1100 | r = gmc_v8_0_init_microcode(adev); | 1103 | r = gmc_v8_0_init_microcode(adev); |
1101 | if (r) { | 1104 | if (r) { |
diff --git a/drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c b/drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c index 2719937e09d6..100ec69f020a 100644 --- a/drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c | |||
@@ -21,6 +21,7 @@ | |||
21 | * | 21 | * |
22 | */ | 22 | */ |
23 | #include <linux/firmware.h> | 23 | #include <linux/firmware.h> |
24 | #include <drm/drm_cache.h> | ||
24 | #include "amdgpu.h" | 25 | #include "amdgpu.h" |
25 | #include "gmc_v9_0.h" | 26 | #include "gmc_v9_0.h" |
26 | #include "amdgpu_atomfirmware.h" | 27 | #include "amdgpu_atomfirmware.h" |
@@ -852,6 +853,7 @@ static int gmc_v9_0_sw_init(void *handle) | |||
852 | pci_set_consistent_dma_mask(adev->pdev, DMA_BIT_MASK(32)); | 853 | pci_set_consistent_dma_mask(adev->pdev, DMA_BIT_MASK(32)); |
853 | printk(KERN_WARNING "amdgpu: No coherent DMA available.\n"); | 854 | printk(KERN_WARNING "amdgpu: No coherent DMA available.\n"); |
854 | } | 855 | } |
856 | adev->need_swiotlb = drm_get_max_iomem() > ((u64)1 << dma_bits); | ||
855 | 857 | ||
856 | r = gmc_v9_0_mc_init(adev); | 858 | r = gmc_v9_0_mc_init(adev); |
857 | if (r) | 859 | if (r) |
diff --git a/drivers/gpu/drm/arc/arcpgu_hdmi.c b/drivers/gpu/drm/arc/arcpgu_hdmi.c index 0ce7f398bcff..977dfa55162f 100644 --- a/drivers/gpu/drm/arc/arcpgu_hdmi.c +++ b/drivers/gpu/drm/arc/arcpgu_hdmi.c | |||
@@ -15,7 +15,8 @@ | |||
15 | */ | 15 | */ |
16 | 16 | ||
17 | #include <drm/drm_crtc.h> | 17 | #include <drm/drm_crtc.h> |
18 | #include <drm/drm_encoder_slave.h> | 18 | #include <drm/drm_encoder.h> |
19 | #include <drm/drm_device.h> | ||
19 | 20 | ||
20 | #include "arcpgu.h" | 21 | #include "arcpgu.h" |
21 | 22 | ||
diff --git a/drivers/gpu/drm/arc/arcpgu_sim.c b/drivers/gpu/drm/arc/arcpgu_sim.c index bca3a678c955..b8f6f9a5dfbe 100644 --- a/drivers/gpu/drm/arc/arcpgu_sim.c +++ b/drivers/gpu/drm/arc/arcpgu_sim.c | |||
@@ -15,7 +15,6 @@ | |||
15 | */ | 15 | */ |
16 | 16 | ||
17 | #include <drm/drm_crtc_helper.h> | 17 | #include <drm/drm_crtc_helper.h> |
18 | #include <drm/drm_encoder_slave.h> | ||
19 | #include <drm/drm_atomic_helper.h> | 18 | #include <drm/drm_atomic_helper.h> |
20 | 19 | ||
21 | #include "arcpgu.h" | 20 | #include "arcpgu.h" |
@@ -29,7 +28,6 @@ | |||
29 | 28 | ||
30 | struct arcpgu_drm_connector { | 29 | struct arcpgu_drm_connector { |
31 | struct drm_connector connector; | 30 | struct drm_connector connector; |
32 | struct drm_encoder_slave *encoder_slave; | ||
33 | }; | 31 | }; |
34 | 32 | ||
35 | static int arcpgu_drm_connector_get_modes(struct drm_connector *connector) | 33 | static int arcpgu_drm_connector_get_modes(struct drm_connector *connector) |
@@ -68,7 +66,7 @@ static struct drm_encoder_funcs arcpgu_drm_encoder_funcs = { | |||
68 | int arcpgu_drm_sim_init(struct drm_device *drm, struct device_node *np) | 66 | int arcpgu_drm_sim_init(struct drm_device *drm, struct device_node *np) |
69 | { | 67 | { |
70 | struct arcpgu_drm_connector *arcpgu_connector; | 68 | struct arcpgu_drm_connector *arcpgu_connector; |
71 | struct drm_encoder_slave *encoder; | 69 | struct drm_encoder *encoder; |
72 | struct drm_connector *connector; | 70 | struct drm_connector *connector; |
73 | int ret; | 71 | int ret; |
74 | 72 | ||
@@ -76,10 +74,10 @@ int arcpgu_drm_sim_init(struct drm_device *drm, struct device_node *np) | |||
76 | if (encoder == NULL) | 74 | if (encoder == NULL) |
77 | return -ENOMEM; | 75 | return -ENOMEM; |
78 | 76 | ||
79 | encoder->base.possible_crtcs = 1; | 77 | encoder->possible_crtcs = 1; |
80 | encoder->base.possible_clones = 0; | 78 | encoder->possible_clones = 0; |
81 | 79 | ||
82 | ret = drm_encoder_init(drm, &encoder->base, &arcpgu_drm_encoder_funcs, | 80 | ret = drm_encoder_init(drm, encoder, &arcpgu_drm_encoder_funcs, |
83 | DRM_MODE_ENCODER_VIRTUAL, NULL); | 81 | DRM_MODE_ENCODER_VIRTUAL, NULL); |
84 | if (ret) | 82 | if (ret) |
85 | return ret; | 83 | return ret; |
@@ -101,21 +99,19 @@ int arcpgu_drm_sim_init(struct drm_device *drm, struct device_node *np) | |||
101 | goto error_encoder_cleanup; | 99 | goto error_encoder_cleanup; |
102 | } | 100 | } |
103 | 101 | ||
104 | ret = drm_mode_connector_attach_encoder(connector, &encoder->base); | 102 | ret = drm_mode_connector_attach_encoder(connector, encoder); |
105 | if (ret < 0) { | 103 | if (ret < 0) { |
106 | dev_err(drm->dev, "could not attach connector to encoder\n"); | 104 | dev_err(drm->dev, "could not attach connector to encoder\n"); |
107 | drm_connector_unregister(connector); | 105 | drm_connector_unregister(connector); |
108 | goto error_connector_cleanup; | 106 | goto error_connector_cleanup; |
109 | } | 107 | } |
110 | 108 | ||
111 | arcpgu_connector->encoder_slave = encoder; | ||
112 | |||
113 | return 0; | 109 | return 0; |
114 | 110 | ||
115 | error_connector_cleanup: | 111 | error_connector_cleanup: |
116 | drm_connector_cleanup(connector); | 112 | drm_connector_cleanup(connector); |
117 | 113 | ||
118 | error_encoder_cleanup: | 114 | error_encoder_cleanup: |
119 | drm_encoder_cleanup(&encoder->base); | 115 | drm_encoder_cleanup(encoder); |
120 | return ret; | 116 | return ret; |
121 | } | 117 | } |
diff --git a/drivers/gpu/drm/arm/hdlcd_crtc.c b/drivers/gpu/drm/arm/hdlcd_crtc.c index 630721f429f7..877647ef35a9 100644 --- a/drivers/gpu/drm/arm/hdlcd_crtc.c +++ b/drivers/gpu/drm/arm/hdlcd_crtc.c | |||
@@ -249,8 +249,9 @@ static int hdlcd_plane_atomic_check(struct drm_plane *plane, | |||
249 | return -EINVAL; | 249 | return -EINVAL; |
250 | } | 250 | } |
251 | 251 | ||
252 | clip.x2 = crtc_state->adjusted_mode.hdisplay; | 252 | if (crtc_state->enable) |
253 | clip.y2 = crtc_state->adjusted_mode.vdisplay; | 253 | drm_mode_get_hv_timing(&crtc_state->mode, |
254 | &clip.x2, &clip.y2); | ||
254 | 255 | ||
255 | return drm_atomic_helper_check_plane_state(state, crtc_state, &clip, | 256 | return drm_atomic_helper_check_plane_state(state, crtc_state, &clip, |
256 | DRM_PLANE_HELPER_NO_SCALING, | 257 | DRM_PLANE_HELPER_NO_SCALING, |
diff --git a/drivers/gpu/drm/arm/malidp_planes.c b/drivers/gpu/drm/arm/malidp_planes.c index 33c5ef96ced0..2885d69af456 100644 --- a/drivers/gpu/drm/arm/malidp_planes.c +++ b/drivers/gpu/drm/arm/malidp_planes.c | |||
@@ -148,8 +148,10 @@ static int malidp_se_check_scaling(struct malidp_plane *mp, | |||
148 | if (!crtc_state) | 148 | if (!crtc_state) |
149 | return -EINVAL; | 149 | return -EINVAL; |
150 | 150 | ||
151 | clip.x2 = crtc_state->adjusted_mode.hdisplay; | 151 | if (crtc_state->enable) |
152 | clip.y2 = crtc_state->adjusted_mode.vdisplay; | 152 | drm_mode_get_hv_timing(&crtc_state->mode, |
153 | &clip.x2, &clip.y2); | ||
154 | |||
153 | ret = drm_atomic_helper_check_plane_state(state, crtc_state, &clip, | 155 | ret = drm_atomic_helper_check_plane_state(state, crtc_state, &clip, |
154 | 0, INT_MAX, true, true); | 156 | 0, INT_MAX, true, true); |
155 | if (ret) | 157 | if (ret) |
diff --git a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c index 703c2d13603f..e18800ed7cd1 100644 --- a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c +++ b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c | |||
@@ -194,20 +194,6 @@ static int atmel_hlcdc_format_to_plane_mode(u32 format, u32 *mode) | |||
194 | return 0; | 194 | return 0; |
195 | } | 195 | } |
196 | 196 | ||
197 | static bool atmel_hlcdc_format_embeds_alpha(u32 format) | ||
198 | { | ||
199 | int i; | ||
200 | |||
201 | for (i = 0; i < sizeof(format); i++) { | ||
202 | char tmp = (format >> (8 * i)) & 0xff; | ||
203 | |||
204 | if (tmp == 'A') | ||
205 | return true; | ||
206 | } | ||
207 | |||
208 | return false; | ||
209 | } | ||
210 | |||
211 | static u32 heo_downscaling_xcoef[] = { | 197 | static u32 heo_downscaling_xcoef[] = { |
212 | 0x11343311, | 198 | 0x11343311, |
213 | 0x000000f7, | 199 | 0x000000f7, |
@@ -377,13 +363,13 @@ atmel_hlcdc_plane_update_general_settings(struct atmel_hlcdc_plane *plane, | |||
377 | { | 363 | { |
378 | unsigned int cfg = ATMEL_HLCDC_LAYER_DMA_BLEN_INCR16 | state->ahb_id; | 364 | unsigned int cfg = ATMEL_HLCDC_LAYER_DMA_BLEN_INCR16 | state->ahb_id; |
379 | const struct atmel_hlcdc_layer_desc *desc = plane->layer.desc; | 365 | const struct atmel_hlcdc_layer_desc *desc = plane->layer.desc; |
380 | u32 format = state->base.fb->format->format; | 366 | const struct drm_format_info *format = state->base.fb->format; |
381 | 367 | ||
382 | /* | 368 | /* |
383 | * Rotation optimization is not working on RGB888 (rotation is still | 369 | * Rotation optimization is not working on RGB888 (rotation is still |
384 | * working but without any optimization). | 370 | * working but without any optimization). |
385 | */ | 371 | */ |
386 | if (format == DRM_FORMAT_RGB888) | 372 | if (format->format == DRM_FORMAT_RGB888) |
387 | cfg |= ATMEL_HLCDC_LAYER_DMA_ROTDIS; | 373 | cfg |= ATMEL_HLCDC_LAYER_DMA_ROTDIS; |
388 | 374 | ||
389 | atmel_hlcdc_layer_write_cfg(&plane->layer, ATMEL_HLCDC_LAYER_DMA_CFG, | 375 | atmel_hlcdc_layer_write_cfg(&plane->layer, ATMEL_HLCDC_LAYER_DMA_CFG, |
@@ -395,7 +381,7 @@ atmel_hlcdc_plane_update_general_settings(struct atmel_hlcdc_plane *plane, | |||
395 | cfg |= ATMEL_HLCDC_LAYER_OVR | ATMEL_HLCDC_LAYER_ITER2BL | | 381 | cfg |= ATMEL_HLCDC_LAYER_OVR | ATMEL_HLCDC_LAYER_ITER2BL | |
396 | ATMEL_HLCDC_LAYER_ITER; | 382 | ATMEL_HLCDC_LAYER_ITER; |
397 | 383 | ||
398 | if (atmel_hlcdc_format_embeds_alpha(format)) | 384 | if (format->has_alpha) |
399 | cfg |= ATMEL_HLCDC_LAYER_LAEN; | 385 | cfg |= ATMEL_HLCDC_LAYER_LAEN; |
400 | else | 386 | else |
401 | cfg |= ATMEL_HLCDC_LAYER_GAEN | | 387 | cfg |= ATMEL_HLCDC_LAYER_GAEN | |
@@ -566,7 +552,7 @@ atmel_hlcdc_plane_prepare_disc_area(struct drm_crtc_state *c_state) | |||
566 | ovl_state = drm_plane_state_to_atmel_hlcdc_plane_state(ovl_s); | 552 | ovl_state = drm_plane_state_to_atmel_hlcdc_plane_state(ovl_s); |
567 | 553 | ||
568 | if (!ovl_s->fb || | 554 | if (!ovl_s->fb || |
569 | atmel_hlcdc_format_embeds_alpha(ovl_s->fb->format->format) || | 555 | ovl_s->fb->format->has_alpha || |
570 | ovl_state->alpha != 255) | 556 | ovl_state->alpha != 255) |
571 | continue; | 557 | continue; |
572 | 558 | ||
@@ -769,7 +755,7 @@ static int atmel_hlcdc_plane_atomic_check(struct drm_plane *p, | |||
769 | 755 | ||
770 | if ((state->crtc_h != state->src_h || state->crtc_w != state->src_w) && | 756 | if ((state->crtc_h != state->src_h || state->crtc_w != state->src_w) && |
771 | (!desc->layout.memsize || | 757 | (!desc->layout.memsize || |
772 | atmel_hlcdc_format_embeds_alpha(state->base.fb->format->format))) | 758 | state->base.fb->format->has_alpha)) |
773 | return -EINVAL; | 759 | return -EINVAL; |
774 | 760 | ||
775 | if (state->crtc_x < 0 || state->crtc_y < 0) | 761 | if (state->crtc_x < 0 || state->crtc_y < 0) |
diff --git a/drivers/gpu/drm/bridge/analogix-anx78xx.c b/drivers/gpu/drm/bridge/analogix-anx78xx.c index ed12a7ddd64a..b49043866be6 100644 --- a/drivers/gpu/drm/bridge/analogix-anx78xx.c +++ b/drivers/gpu/drm/bridge/analogix-anx78xx.c | |||
@@ -1301,8 +1301,7 @@ static void unregister_i2c_dummy_clients(struct anx78xx *anx78xx) | |||
1301 | unsigned int i; | 1301 | unsigned int i; |
1302 | 1302 | ||
1303 | for (i = 0; i < ARRAY_SIZE(anx78xx->i2c_dummy); i++) | 1303 | for (i = 0; i < ARRAY_SIZE(anx78xx->i2c_dummy); i++) |
1304 | if (anx78xx->i2c_dummy[i]) | 1304 | i2c_unregister_device(anx78xx->i2c_dummy[i]); |
1305 | i2c_unregister_device(anx78xx->i2c_dummy[i]); | ||
1306 | } | 1305 | } |
1307 | 1306 | ||
1308 | static const struct regmap_config anx78xx_regmap_config = { | 1307 | static const struct regmap_config anx78xx_regmap_config = { |
diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c index a8905049b9da..b2756bc4225a 100644 --- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c | |||
@@ -727,7 +727,6 @@ static int analogix_dp_set_link_train(struct analogix_dp_device *dp, | |||
727 | 727 | ||
728 | static int analogix_dp_config_video(struct analogix_dp_device *dp) | 728 | static int analogix_dp_config_video(struct analogix_dp_device *dp) |
729 | { | 729 | { |
730 | int retval = 0; | ||
731 | int timeout_loop = 0; | 730 | int timeout_loop = 0; |
732 | int done_count = 0; | 731 | int done_count = 0; |
733 | 732 | ||
@@ -783,10 +782,7 @@ static int analogix_dp_config_video(struct analogix_dp_device *dp) | |||
783 | usleep_range(1000, 1001); | 782 | usleep_range(1000, 1001); |
784 | } | 783 | } |
785 | 784 | ||
786 | if (retval != 0) | 785 | return 0; |
787 | dev_err(dp->dev, "Video stream is not detected!\n"); | ||
788 | |||
789 | return retval; | ||
790 | } | 786 | } |
791 | 787 | ||
792 | static void analogix_dp_enable_scramble(struct analogix_dp_device *dp, | 788 | static void analogix_dp_enable_scramble(struct analogix_dp_device *dp, |
diff --git a/drivers/gpu/drm/bridge/dumb-vga-dac.c b/drivers/gpu/drm/bridge/dumb-vga-dac.c index de5e7dee7ad6..498d5948d1a8 100644 --- a/drivers/gpu/drm/bridge/dumb-vga-dac.c +++ b/drivers/gpu/drm/bridge/dumb-vga-dac.c | |||
@@ -11,6 +11,7 @@ | |||
11 | */ | 11 | */ |
12 | 12 | ||
13 | #include <linux/module.h> | 13 | #include <linux/module.h> |
14 | #include <linux/of_device.h> | ||
14 | #include <linux/of_graph.h> | 15 | #include <linux/of_graph.h> |
15 | #include <linux/regulator/consumer.h> | 16 | #include <linux/regulator/consumer.h> |
16 | 17 | ||
@@ -204,6 +205,7 @@ static int dumb_vga_probe(struct platform_device *pdev) | |||
204 | 205 | ||
205 | vga->bridge.funcs = &dumb_vga_bridge_funcs; | 206 | vga->bridge.funcs = &dumb_vga_bridge_funcs; |
206 | vga->bridge.of_node = pdev->dev.of_node; | 207 | vga->bridge.of_node = pdev->dev.of_node; |
208 | vga->bridge.timings = of_device_get_match_data(&pdev->dev); | ||
207 | 209 | ||
208 | drm_bridge_add(&vga->bridge); | 210 | drm_bridge_add(&vga->bridge); |
209 | 211 | ||
@@ -222,10 +224,61 @@ static int dumb_vga_remove(struct platform_device *pdev) | |||
222 | return 0; | 224 | return 0; |
223 | } | 225 | } |
224 | 226 | ||
227 | /* | ||
228 | * We assume the ADV7123 DAC is the "default" for historical reasons | ||
229 | * Information taken from the ADV7123 datasheet, revision D. | ||
230 | * NOTE: the ADV7123EP seems to have other timings and need a new timings | ||
231 | * set if used. | ||
232 | */ | ||
233 | static const struct drm_bridge_timings default_dac_timings = { | ||
234 | /* Timing specifications, datasheet page 7 */ | ||
235 | .sampling_edge = DRM_BUS_FLAG_PIXDATA_POSEDGE, | ||
236 | .setup_time_ps = 500, | ||
237 | .hold_time_ps = 1500, | ||
238 | }; | ||
239 | |||
240 | /* | ||
241 | * Information taken from the THS8134, THS8134A, THS8134B datasheet named | ||
242 | * "SLVS205D", dated May 1990, revised March 2000. | ||
243 | */ | ||
244 | static const struct drm_bridge_timings ti_ths8134_dac_timings = { | ||
245 | /* From timing diagram, datasheet page 9 */ | ||
246 | .sampling_edge = DRM_BUS_FLAG_PIXDATA_POSEDGE, | ||
247 | /* From datasheet, page 12 */ | ||
248 | .setup_time_ps = 3000, | ||
249 | /* I guess this means latched input */ | ||
250 | .hold_time_ps = 0, | ||
251 | }; | ||
252 | |||
253 | /* | ||
254 | * Information taken from the THS8135 datasheet named "SLAS343B", dated | ||
255 | * May 2001, revised April 2013. | ||
256 | */ | ||
257 | static const struct drm_bridge_timings ti_ths8135_dac_timings = { | ||
258 | /* From timing diagram, datasheet page 14 */ | ||
259 | .sampling_edge = DRM_BUS_FLAG_PIXDATA_POSEDGE, | ||
260 | /* From datasheet, page 16 */ | ||
261 | .setup_time_ps = 2000, | ||
262 | .hold_time_ps = 500, | ||
263 | }; | ||
264 | |||
225 | static const struct of_device_id dumb_vga_match[] = { | 265 | static const struct of_device_id dumb_vga_match[] = { |
226 | { .compatible = "dumb-vga-dac" }, | 266 | { |
227 | { .compatible = "adi,adv7123" }, | 267 | .compatible = "dumb-vga-dac", |
228 | { .compatible = "ti,ths8135" }, | 268 | .data = NULL, |
269 | }, | ||
270 | { | ||
271 | .compatible = "adi,adv7123", | ||
272 | .data = &default_dac_timings, | ||
273 | }, | ||
274 | { | ||
275 | .compatible = "ti,ths8135", | ||
276 | .data = &ti_ths8135_dac_timings, | ||
277 | }, | ||
278 | { | ||
279 | .compatible = "ti,ths8134", | ||
280 | .data = &ti_ths8134_dac_timings, | ||
281 | }, | ||
229 | {}, | 282 | {}, |
230 | }; | 283 | }; |
231 | MODULE_DEVICE_TABLE(of, dumb_vga_match); | 284 | MODULE_DEVICE_TABLE(of, dumb_vga_match); |
diff --git a/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c b/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c index d9cca4fd66ec..7bac101c285c 100644 --- a/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c +++ b/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c | |||
@@ -29,7 +29,10 @@ | |||
29 | #include <drm/bridge/dw_mipi_dsi.h> | 29 | #include <drm/bridge/dw_mipi_dsi.h> |
30 | #include <video/mipi_display.h> | 30 | #include <video/mipi_display.h> |
31 | 31 | ||
32 | #define HWVER_131 0x31333100 /* IP version 1.31 */ | ||
33 | |||
32 | #define DSI_VERSION 0x00 | 34 | #define DSI_VERSION 0x00 |
35 | #define VERSION GENMASK(31, 8) | ||
33 | 36 | ||
34 | #define DSI_PWR_UP 0x04 | 37 | #define DSI_PWR_UP 0x04 |
35 | #define RESET 0 | 38 | #define RESET 0 |
@@ -136,10 +139,6 @@ | |||
136 | GEN_SW_0P_TX_LP) | 139 | GEN_SW_0P_TX_LP) |
137 | 140 | ||
138 | #define DSI_GEN_HDR 0x6c | 141 | #define DSI_GEN_HDR 0x6c |
139 | /* TODO These 2 defines will be reworked thanks to mipi_dsi_create_packet() */ | ||
140 | #define GEN_HDATA(data) (((data) & 0xffff) << 8) | ||
141 | #define GEN_HTYPE(type) (((type) & 0xff) << 0) | ||
142 | |||
143 | #define DSI_GEN_PLD_DATA 0x70 | 142 | #define DSI_GEN_PLD_DATA 0x70 |
144 | 143 | ||
145 | #define DSI_CMD_PKT_STATUS 0x74 | 144 | #define DSI_CMD_PKT_STATUS 0x74 |
@@ -169,11 +168,12 @@ | |||
169 | #define PHY_CLKHS2LP_TIME(lbcc) (((lbcc) & 0x3ff) << 16) | 168 | #define PHY_CLKHS2LP_TIME(lbcc) (((lbcc) & 0x3ff) << 16) |
170 | #define PHY_CLKLP2HS_TIME(lbcc) ((lbcc) & 0x3ff) | 169 | #define PHY_CLKLP2HS_TIME(lbcc) ((lbcc) & 0x3ff) |
171 | 170 | ||
172 | /* TODO Next register is slightly different between 1.30 & 1.31 IP version */ | ||
173 | #define DSI_PHY_TMR_CFG 0x9c | 171 | #define DSI_PHY_TMR_CFG 0x9c |
174 | #define PHY_HS2LP_TIME(lbcc) (((lbcc) & 0xff) << 24) | 172 | #define PHY_HS2LP_TIME(lbcc) (((lbcc) & 0xff) << 24) |
175 | #define PHY_LP2HS_TIME(lbcc) (((lbcc) & 0xff) << 16) | 173 | #define PHY_LP2HS_TIME(lbcc) (((lbcc) & 0xff) << 16) |
176 | #define MAX_RD_TIME(lbcc) ((lbcc) & 0x7fff) | 174 | #define MAX_RD_TIME(lbcc) ((lbcc) & 0x7fff) |
175 | #define PHY_HS2LP_TIME_V131(lbcc) (((lbcc) & 0x3ff) << 16) | ||
176 | #define PHY_LP2HS_TIME_V131(lbcc) ((lbcc) & 0x3ff) | ||
177 | 177 | ||
178 | #define DSI_PHY_RSTZ 0xa0 | 178 | #define DSI_PHY_RSTZ 0xa0 |
179 | #define PHY_DISFORCEPLL 0 | 179 | #define PHY_DISFORCEPLL 0 |
@@ -212,7 +212,9 @@ | |||
212 | #define DSI_INT_ST1 0xc0 | 212 | #define DSI_INT_ST1 0xc0 |
213 | #define DSI_INT_MSK0 0xc4 | 213 | #define DSI_INT_MSK0 0xc4 |
214 | #define DSI_INT_MSK1 0xc8 | 214 | #define DSI_INT_MSK1 0xc8 |
215 | |||
215 | #define DSI_PHY_TMR_RD_CFG 0xf4 | 216 | #define DSI_PHY_TMR_RD_CFG 0xf4 |
217 | #define MAX_RD_TIME_V131(lbcc) ((lbcc) & 0x7fff) | ||
216 | 218 | ||
217 | #define PHY_STATUS_TIMEOUT_US 10000 | 219 | #define PHY_STATUS_TIMEOUT_US 10000 |
218 | #define CMD_PKT_STATUS_TIMEOUT_US 20000 | 220 | #define CMD_PKT_STATUS_TIMEOUT_US 20000 |
@@ -359,52 +361,23 @@ static int dw_mipi_dsi_gen_pkt_hdr_write(struct dw_mipi_dsi *dsi, u32 hdr_val) | |||
359 | return 0; | 361 | return 0; |
360 | } | 362 | } |
361 | 363 | ||
362 | static int dw_mipi_dsi_dcs_short_write(struct dw_mipi_dsi *dsi, | 364 | static int dw_mipi_dsi_write(struct dw_mipi_dsi *dsi, |
363 | const struct mipi_dsi_msg *msg) | 365 | const struct mipi_dsi_packet *packet) |
364 | { | 366 | { |
365 | const u8 *tx_buf = msg->tx_buf; | 367 | const u8 *tx_buf = packet->payload; |
366 | u16 data = 0; | 368 | int len = packet->payload_length, pld_data_bytes = sizeof(u32), ret; |
369 | __le32 word; | ||
367 | u32 val; | 370 | u32 val; |
368 | 371 | ||
369 | if (msg->tx_len > 0) | 372 | while (len) { |
370 | data |= tx_buf[0]; | ||
371 | if (msg->tx_len > 1) | ||
372 | data |= tx_buf[1] << 8; | ||
373 | |||
374 | if (msg->tx_len > 2) { | ||
375 | dev_err(dsi->dev, "too long tx buf length %zu for short write\n", | ||
376 | msg->tx_len); | ||
377 | return -EINVAL; | ||
378 | } | ||
379 | |||
380 | val = GEN_HDATA(data) | GEN_HTYPE(msg->type); | ||
381 | return dw_mipi_dsi_gen_pkt_hdr_write(dsi, val); | ||
382 | } | ||
383 | |||
384 | static int dw_mipi_dsi_dcs_long_write(struct dw_mipi_dsi *dsi, | ||
385 | const struct mipi_dsi_msg *msg) | ||
386 | { | ||
387 | const u8 *tx_buf = msg->tx_buf; | ||
388 | int len = msg->tx_len, pld_data_bytes = sizeof(u32), ret; | ||
389 | u32 hdr_val = GEN_HDATA(msg->tx_len) | GEN_HTYPE(msg->type); | ||
390 | u32 remainder; | ||
391 | u32 val; | ||
392 | |||
393 | if (msg->tx_len < 3) { | ||
394 | dev_err(dsi->dev, "wrong tx buf length %zu for long write\n", | ||
395 | msg->tx_len); | ||
396 | return -EINVAL; | ||
397 | } | ||
398 | |||
399 | while (DIV_ROUND_UP(len, pld_data_bytes)) { | ||
400 | if (len < pld_data_bytes) { | 373 | if (len < pld_data_bytes) { |
401 | remainder = 0; | 374 | word = 0; |
402 | memcpy(&remainder, tx_buf, len); | 375 | memcpy(&word, tx_buf, len); |
403 | dsi_write(dsi, DSI_GEN_PLD_DATA, remainder); | 376 | dsi_write(dsi, DSI_GEN_PLD_DATA, le32_to_cpu(word)); |
404 | len = 0; | 377 | len = 0; |
405 | } else { | 378 | } else { |
406 | memcpy(&remainder, tx_buf, pld_data_bytes); | 379 | memcpy(&word, tx_buf, pld_data_bytes); |
407 | dsi_write(dsi, DSI_GEN_PLD_DATA, remainder); | 380 | dsi_write(dsi, DSI_GEN_PLD_DATA, le32_to_cpu(word)); |
408 | tx_buf += pld_data_bytes; | 381 | tx_buf += pld_data_bytes; |
409 | len -= pld_data_bytes; | 382 | len -= pld_data_bytes; |
410 | } | 383 | } |
@@ -419,40 +392,74 @@ static int dw_mipi_dsi_dcs_long_write(struct dw_mipi_dsi *dsi, | |||
419 | } | 392 | } |
420 | } | 393 | } |
421 | 394 | ||
422 | return dw_mipi_dsi_gen_pkt_hdr_write(dsi, hdr_val); | 395 | word = 0; |
396 | memcpy(&word, packet->header, sizeof(packet->header)); | ||
397 | return dw_mipi_dsi_gen_pkt_hdr_write(dsi, le32_to_cpu(word)); | ||
398 | } | ||
399 | |||
400 | static int dw_mipi_dsi_read(struct dw_mipi_dsi *dsi, | ||
401 | const struct mipi_dsi_msg *msg) | ||
402 | { | ||
403 | int i, j, ret, len = msg->rx_len; | ||
404 | u8 *buf = msg->rx_buf; | ||
405 | u32 val; | ||
406 | |||
407 | /* Wait end of the read operation */ | ||
408 | ret = readl_poll_timeout(dsi->base + DSI_CMD_PKT_STATUS, | ||
409 | val, !(val & GEN_RD_CMD_BUSY), | ||
410 | 1000, CMD_PKT_STATUS_TIMEOUT_US); | ||
411 | if (ret) { | ||
412 | dev_err(dsi->dev, "Timeout during read operation\n"); | ||
413 | return ret; | ||
414 | } | ||
415 | |||
416 | for (i = 0; i < len; i += 4) { | ||
417 | /* Read fifo must not be empty before all bytes are read */ | ||
418 | ret = readl_poll_timeout(dsi->base + DSI_CMD_PKT_STATUS, | ||
419 | val, !(val & GEN_PLD_R_EMPTY), | ||
420 | 1000, CMD_PKT_STATUS_TIMEOUT_US); | ||
421 | if (ret) { | ||
422 | dev_err(dsi->dev, "Read payload FIFO is empty\n"); | ||
423 | return ret; | ||
424 | } | ||
425 | |||
426 | val = dsi_read(dsi, DSI_GEN_PLD_DATA); | ||
427 | for (j = 0; j < 4 && j + i < len; j++) | ||
428 | buf[i + j] = val >> (8 * j); | ||
429 | } | ||
430 | |||
431 | return ret; | ||
423 | } | 432 | } |
424 | 433 | ||
425 | static ssize_t dw_mipi_dsi_host_transfer(struct mipi_dsi_host *host, | 434 | static ssize_t dw_mipi_dsi_host_transfer(struct mipi_dsi_host *host, |
426 | const struct mipi_dsi_msg *msg) | 435 | const struct mipi_dsi_msg *msg) |
427 | { | 436 | { |
428 | struct dw_mipi_dsi *dsi = host_to_dsi(host); | 437 | struct dw_mipi_dsi *dsi = host_to_dsi(host); |
429 | int ret; | 438 | struct mipi_dsi_packet packet; |
439 | int ret, nb_bytes; | ||
440 | |||
441 | ret = mipi_dsi_create_packet(&packet, msg); | ||
442 | if (ret) { | ||
443 | dev_err(dsi->dev, "failed to create packet: %d\n", ret); | ||
444 | return ret; | ||
445 | } | ||
430 | 446 | ||
431 | /* | ||
432 | * TODO dw drv improvements | ||
433 | * use mipi_dsi_create_packet() instead of all following | ||
434 | * functions and code (no switch cases, no | ||
435 | * dw_mipi_dsi_dcs_short_write(), only the loop in long_write...) | ||
436 | * and use packet.header... | ||
437 | */ | ||
438 | dw_mipi_message_config(dsi, msg); | 447 | dw_mipi_message_config(dsi, msg); |
439 | 448 | ||
440 | switch (msg->type) { | 449 | ret = dw_mipi_dsi_write(dsi, &packet); |
441 | case MIPI_DSI_DCS_SHORT_WRITE: | 450 | if (ret) |
442 | case MIPI_DSI_DCS_SHORT_WRITE_PARAM: | 451 | return ret; |
443 | case MIPI_DSI_SET_MAXIMUM_RETURN_PACKET_SIZE: | 452 | |
444 | ret = dw_mipi_dsi_dcs_short_write(dsi, msg); | 453 | if (msg->rx_buf && msg->rx_len) { |
445 | break; | 454 | ret = dw_mipi_dsi_read(dsi, msg); |
446 | case MIPI_DSI_DCS_LONG_WRITE: | 455 | if (ret) |
447 | ret = dw_mipi_dsi_dcs_long_write(dsi, msg); | 456 | return ret; |
448 | break; | 457 | nb_bytes = msg->rx_len; |
449 | default: | 458 | } else { |
450 | dev_err(dsi->dev, "unsupported message type 0x%02x\n", | 459 | nb_bytes = packet.size; |
451 | msg->type); | ||
452 | ret = -EINVAL; | ||
453 | } | 460 | } |
454 | 461 | ||
455 | return ret; | 462 | return nb_bytes; |
456 | } | 463 | } |
457 | 464 | ||
458 | static const struct mipi_dsi_host_ops dw_mipi_dsi_host_ops = { | 465 | static const struct mipi_dsi_host_ops dw_mipi_dsi_host_ops = { |
@@ -658,6 +665,8 @@ static void dw_mipi_dsi_vertical_timing_config(struct dw_mipi_dsi *dsi, | |||
658 | 665 | ||
659 | static void dw_mipi_dsi_dphy_timing_config(struct dw_mipi_dsi *dsi) | 666 | static void dw_mipi_dsi_dphy_timing_config(struct dw_mipi_dsi *dsi) |
660 | { | 667 | { |
668 | u32 hw_version; | ||
669 | |||
661 | /* | 670 | /* |
662 | * TODO dw drv improvements | 671 | * TODO dw drv improvements |
663 | * data & clock lane timers should be computed according to panel | 672 | * data & clock lane timers should be computed according to panel |
@@ -665,8 +674,17 @@ static void dw_mipi_dsi_dphy_timing_config(struct dw_mipi_dsi *dsi) | |||
665 | * note: DSI_PHY_TMR_CFG.MAX_RD_TIME should be in line with | 674 | * note: DSI_PHY_TMR_CFG.MAX_RD_TIME should be in line with |
666 | * DSI_CMD_MODE_CFG.MAX_RD_PKT_SIZE_LP (see CMD_MODE_ALL_LP) | 675 | * DSI_CMD_MODE_CFG.MAX_RD_PKT_SIZE_LP (see CMD_MODE_ALL_LP) |
667 | */ | 676 | */ |
668 | dsi_write(dsi, DSI_PHY_TMR_CFG, PHY_HS2LP_TIME(0x40) | 677 | |
669 | | PHY_LP2HS_TIME(0x40) | MAX_RD_TIME(10000)); | 678 | hw_version = dsi_read(dsi, DSI_VERSION) & VERSION; |
679 | |||
680 | if (hw_version >= HWVER_131) { | ||
681 | dsi_write(dsi, DSI_PHY_TMR_CFG, PHY_HS2LP_TIME_V131(0x40) | | ||
682 | PHY_LP2HS_TIME_V131(0x40)); | ||
683 | dsi_write(dsi, DSI_PHY_TMR_RD_CFG, MAX_RD_TIME_V131(10000)); | ||
684 | } else { | ||
685 | dsi_write(dsi, DSI_PHY_TMR_CFG, PHY_HS2LP_TIME(0x40) | | ||
686 | PHY_LP2HS_TIME(0x40) | MAX_RD_TIME(10000)); | ||
687 | } | ||
670 | 688 | ||
671 | dsi_write(dsi, DSI_PHY_TMR_LPCLK_CFG, PHY_CLKHS2LP_TIME(0x40) | 689 | dsi_write(dsi, DSI_PHY_TMR_LPCLK_CFG, PHY_CLKHS2LP_TIME(0x40) |
672 | | PHY_CLKLP2HS_TIME(0x40)); | 690 | | PHY_CLKLP2HS_TIME(0x40)); |
@@ -746,9 +764,9 @@ static void dw_mipi_dsi_bridge_post_disable(struct drm_bridge *bridge) | |||
746 | pm_runtime_put(dsi->dev); | 764 | pm_runtime_put(dsi->dev); |
747 | } | 765 | } |
748 | 766 | ||
749 | void dw_mipi_dsi_bridge_mode_set(struct drm_bridge *bridge, | 767 | static void dw_mipi_dsi_bridge_mode_set(struct drm_bridge *bridge, |
750 | struct drm_display_mode *mode, | 768 | struct drm_display_mode *mode, |
751 | struct drm_display_mode *adjusted_mode) | 769 | struct drm_display_mode *adjusted_mode) |
752 | { | 770 | { |
753 | struct dw_mipi_dsi *dsi = bridge_to_dsi(bridge); | 771 | struct dw_mipi_dsi *dsi = bridge_to_dsi(bridge); |
754 | const struct dw_mipi_dsi_phy_ops *phy_ops = dsi->plat_data->phy_ops; | 772 | const struct dw_mipi_dsi_phy_ops *phy_ops = dsi->plat_data->phy_ops; |
@@ -922,8 +940,6 @@ __dw_mipi_dsi_probe(struct platform_device *pdev, | |||
922 | dsi->bridge.of_node = pdev->dev.of_node; | 940 | dsi->bridge.of_node = pdev->dev.of_node; |
923 | #endif | 941 | #endif |
924 | 942 | ||
925 | dev_set_drvdata(dev, dsi); | ||
926 | |||
927 | return dsi; | 943 | return dsi; |
928 | } | 944 | } |
929 | 945 | ||
@@ -935,23 +951,16 @@ static void __dw_mipi_dsi_remove(struct dw_mipi_dsi *dsi) | |||
935 | /* | 951 | /* |
936 | * Probe/remove API, used from platforms based on the DRM bridge API. | 952 | * Probe/remove API, used from platforms based on the DRM bridge API. |
937 | */ | 953 | */ |
938 | int dw_mipi_dsi_probe(struct platform_device *pdev, | 954 | struct dw_mipi_dsi * |
939 | const struct dw_mipi_dsi_plat_data *plat_data) | 955 | dw_mipi_dsi_probe(struct platform_device *pdev, |
956 | const struct dw_mipi_dsi_plat_data *plat_data) | ||
940 | { | 957 | { |
941 | struct dw_mipi_dsi *dsi; | 958 | return __dw_mipi_dsi_probe(pdev, plat_data); |
942 | |||
943 | dsi = __dw_mipi_dsi_probe(pdev, plat_data); | ||
944 | if (IS_ERR(dsi)) | ||
945 | return PTR_ERR(dsi); | ||
946 | |||
947 | return 0; | ||
948 | } | 959 | } |
949 | EXPORT_SYMBOL_GPL(dw_mipi_dsi_probe); | 960 | EXPORT_SYMBOL_GPL(dw_mipi_dsi_probe); |
950 | 961 | ||
951 | void dw_mipi_dsi_remove(struct platform_device *pdev) | 962 | void dw_mipi_dsi_remove(struct dw_mipi_dsi *dsi) |
952 | { | 963 | { |
953 | struct dw_mipi_dsi *dsi = platform_get_drvdata(pdev); | ||
954 | |||
955 | mipi_dsi_host_unregister(&dsi->dsi_host); | 964 | mipi_dsi_host_unregister(&dsi->dsi_host); |
956 | 965 | ||
957 | __dw_mipi_dsi_remove(dsi); | 966 | __dw_mipi_dsi_remove(dsi); |
@@ -961,31 +970,30 @@ EXPORT_SYMBOL_GPL(dw_mipi_dsi_remove); | |||
961 | /* | 970 | /* |
962 | * Bind/unbind API, used from platforms based on the component framework. | 971 | * Bind/unbind API, used from platforms based on the component framework. |
963 | */ | 972 | */ |
964 | int dw_mipi_dsi_bind(struct platform_device *pdev, struct drm_encoder *encoder, | 973 | struct dw_mipi_dsi * |
965 | const struct dw_mipi_dsi_plat_data *plat_data) | 974 | dw_mipi_dsi_bind(struct platform_device *pdev, struct drm_encoder *encoder, |
975 | const struct dw_mipi_dsi_plat_data *plat_data) | ||
966 | { | 976 | { |
967 | struct dw_mipi_dsi *dsi; | 977 | struct dw_mipi_dsi *dsi; |
968 | int ret; | 978 | int ret; |
969 | 979 | ||
970 | dsi = __dw_mipi_dsi_probe(pdev, plat_data); | 980 | dsi = __dw_mipi_dsi_probe(pdev, plat_data); |
971 | if (IS_ERR(dsi)) | 981 | if (IS_ERR(dsi)) |
972 | return PTR_ERR(dsi); | 982 | return dsi; |
973 | 983 | ||
974 | ret = drm_bridge_attach(encoder, &dsi->bridge, NULL); | 984 | ret = drm_bridge_attach(encoder, &dsi->bridge, NULL); |
975 | if (ret) { | 985 | if (ret) { |
976 | dw_mipi_dsi_remove(pdev); | 986 | dw_mipi_dsi_remove(dsi); |
977 | DRM_ERROR("Failed to initialize bridge with drm\n"); | 987 | DRM_ERROR("Failed to initialize bridge with drm\n"); |
978 | return ret; | 988 | return ERR_PTR(ret); |
979 | } | 989 | } |
980 | 990 | ||
981 | return 0; | 991 | return dsi; |
982 | } | 992 | } |
983 | EXPORT_SYMBOL_GPL(dw_mipi_dsi_bind); | 993 | EXPORT_SYMBOL_GPL(dw_mipi_dsi_bind); |
984 | 994 | ||
985 | void dw_mipi_dsi_unbind(struct device *dev) | 995 | void dw_mipi_dsi_unbind(struct dw_mipi_dsi *dsi) |
986 | { | 996 | { |
987 | struct dw_mipi_dsi *dsi = dev_get_drvdata(dev); | ||
988 | |||
989 | __dw_mipi_dsi_remove(dsi); | 997 | __dw_mipi_dsi_remove(dsi); |
990 | } | 998 | } |
991 | EXPORT_SYMBOL_GPL(dw_mipi_dsi_unbind); | 999 | EXPORT_SYMBOL_GPL(dw_mipi_dsi_unbind); |
diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c index b76d49218cf1..7d9ad20040a1 100644 --- a/drivers/gpu/drm/drm_atomic.c +++ b/drivers/gpu/drm/drm_atomic.c | |||
@@ -390,7 +390,7 @@ int drm_atomic_set_mode_prop_for_crtc(struct drm_crtc_state *state, | |||
390 | 390 | ||
391 | if (blob) { | 391 | if (blob) { |
392 | if (blob->length != sizeof(struct drm_mode_modeinfo) || | 392 | if (blob->length != sizeof(struct drm_mode_modeinfo) || |
393 | drm_mode_convert_umode(&state->mode, | 393 | drm_mode_convert_umode(state->crtc->dev, &state->mode, |
394 | (const struct drm_mode_modeinfo *) | 394 | (const struct drm_mode_modeinfo *) |
395 | blob->data)) | 395 | blob->data)) |
396 | return -EINVAL; | 396 | return -EINVAL; |
@@ -863,10 +863,10 @@ static int drm_atomic_plane_check(struct drm_plane *plane, | |||
863 | int ret; | 863 | int ret; |
864 | 864 | ||
865 | /* either *both* CRTC and FB must be set, or neither */ | 865 | /* either *both* CRTC and FB must be set, or neither */ |
866 | if (WARN_ON(state->crtc && !state->fb)) { | 866 | if (state->crtc && !state->fb) { |
867 | DRM_DEBUG_ATOMIC("CRTC set but no FB\n"); | 867 | DRM_DEBUG_ATOMIC("CRTC set but no FB\n"); |
868 | return -EINVAL; | 868 | return -EINVAL; |
869 | } else if (WARN_ON(state->fb && !state->crtc)) { | 869 | } else if (state->fb && !state->crtc) { |
870 | DRM_DEBUG_ATOMIC("FB set but no CRTC\n"); | 870 | DRM_DEBUG_ATOMIC("FB set but no CRTC\n"); |
871 | return -EINVAL; | 871 | return -EINVAL; |
872 | } | 872 | } |
diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c index ab4032167094..ae3cbfe9e01c 100644 --- a/drivers/gpu/drm/drm_atomic_helper.c +++ b/drivers/gpu/drm/drm_atomic_helper.c | |||
@@ -1878,6 +1878,8 @@ int drm_atomic_helper_setup_commit(struct drm_atomic_state *state, | |||
1878 | new_crtc_state->event->base.completion = &commit->flip_done; | 1878 | new_crtc_state->event->base.completion = &commit->flip_done; |
1879 | new_crtc_state->event->base.completion_release = release_crtc_commit; | 1879 | new_crtc_state->event->base.completion_release = release_crtc_commit; |
1880 | drm_crtc_commit_get(commit); | 1880 | drm_crtc_commit_get(commit); |
1881 | |||
1882 | commit->abort_completion = true; | ||
1881 | } | 1883 | } |
1882 | 1884 | ||
1883 | for_each_oldnew_connector_in_state(state, conn, old_conn_state, new_conn_state, i) { | 1885 | for_each_oldnew_connector_in_state(state, conn, old_conn_state, new_conn_state, i) { |
@@ -3421,8 +3423,21 @@ EXPORT_SYMBOL(drm_atomic_helper_crtc_duplicate_state); | |||
3421 | void __drm_atomic_helper_crtc_destroy_state(struct drm_crtc_state *state) | 3423 | void __drm_atomic_helper_crtc_destroy_state(struct drm_crtc_state *state) |
3422 | { | 3424 | { |
3423 | if (state->commit) { | 3425 | if (state->commit) { |
3426 | /* | ||
3427 | * In the event that a non-blocking commit returns | ||
3428 | * -ERESTARTSYS before the commit_tail work is queued, we will | ||
3429 | * have an extra reference to the commit object. Release it, if | ||
3430 | * the event has not been consumed by the worker. | ||
3431 | * | ||
3432 | * state->event may be freed, so we can't directly look at | ||
3433 | * state->event->base.completion. | ||
3434 | */ | ||
3435 | if (state->event && state->commit->abort_completion) | ||
3436 | drm_crtc_commit_put(state->commit); | ||
3437 | |||
3424 | kfree(state->commit->event); | 3438 | kfree(state->commit->event); |
3425 | state->commit->event = NULL; | 3439 | state->commit->event = NULL; |
3440 | |||
3426 | drm_crtc_commit_put(state->commit); | 3441 | drm_crtc_commit_put(state->commit); |
3427 | } | 3442 | } |
3428 | 3443 | ||
diff --git a/drivers/gpu/drm/drm_connector.c b/drivers/gpu/drm/drm_connector.c index e6a21e69059c..d6a7eba087a0 100644 --- a/drivers/gpu/drm/drm_connector.c +++ b/drivers/gpu/drm/drm_connector.c | |||
@@ -205,9 +205,14 @@ int drm_connector_init(struct drm_device *dev, | |||
205 | connector->dev = dev; | 205 | connector->dev = dev; |
206 | connector->funcs = funcs; | 206 | connector->funcs = funcs; |
207 | 207 | ||
208 | ret = ida_simple_get(&config->connector_ida, 0, 0, GFP_KERNEL); | 208 | /* connector index is used with 32bit bitmasks */ |
209 | if (ret < 0) | 209 | ret = ida_simple_get(&config->connector_ida, 0, 32, GFP_KERNEL); |
210 | if (ret < 0) { | ||
211 | DRM_DEBUG_KMS("Failed to allocate %s connector index: %d\n", | ||
212 | drm_connector_enum_list[connector_type].name, | ||
213 | ret); | ||
210 | goto out_put; | 214 | goto out_put; |
215 | } | ||
211 | connector->index = ret; | 216 | connector->index = ret; |
212 | ret = 0; | 217 | ret = 0; |
213 | 218 | ||
diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index f0556e654116..353e24fcde9e 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c | |||
@@ -282,6 +282,10 @@ int drm_crtc_init_with_planes(struct drm_device *dev, struct drm_crtc *crtc, | |||
282 | WARN_ON(primary && primary->type != DRM_PLANE_TYPE_PRIMARY); | 282 | WARN_ON(primary && primary->type != DRM_PLANE_TYPE_PRIMARY); |
283 | WARN_ON(cursor && cursor->type != DRM_PLANE_TYPE_CURSOR); | 283 | WARN_ON(cursor && cursor->type != DRM_PLANE_TYPE_CURSOR); |
284 | 284 | ||
285 | /* crtc index is used with 32bit bitmasks */ | ||
286 | if (WARN_ON(config->num_crtc >= 32)) | ||
287 | return -EINVAL; | ||
288 | |||
285 | crtc->dev = dev; | 289 | crtc->dev = dev; |
286 | crtc->funcs = funcs; | 290 | crtc->funcs = funcs; |
287 | 291 | ||
@@ -610,7 +614,7 @@ retry: | |||
610 | goto out; | 614 | goto out; |
611 | } | 615 | } |
612 | 616 | ||
613 | ret = drm_mode_convert_umode(mode, &crtc_req->mode); | 617 | ret = drm_mode_convert_umode(dev, mode, &crtc_req->mode); |
614 | if (ret) { | 618 | if (ret) { |
615 | DRM_DEBUG_KMS("Invalid mode\n"); | 619 | DRM_DEBUG_KMS("Invalid mode\n"); |
616 | goto out; | 620 | goto out; |
diff --git a/drivers/gpu/drm/drm_debugfs_crc.c b/drivers/gpu/drm/drm_debugfs_crc.c index 9dd879589a2c..9f8312137cad 100644 --- a/drivers/gpu/drm/drm_debugfs_crc.c +++ b/drivers/gpu/drm/drm_debugfs_crc.c | |||
@@ -307,10 +307,29 @@ static ssize_t crtc_crc_read(struct file *filep, char __user *user_buf, | |||
307 | return LINE_LEN(crc->values_cnt); | 307 | return LINE_LEN(crc->values_cnt); |
308 | } | 308 | } |
309 | 309 | ||
310 | static unsigned int crtc_crc_poll(struct file *file, poll_table *wait) | ||
311 | { | ||
312 | struct drm_crtc *crtc = file->f_inode->i_private; | ||
313 | struct drm_crtc_crc *crc = &crtc->crc; | ||
314 | unsigned ret; | ||
315 | |||
316 | poll_wait(file, &crc->wq, wait); | ||
317 | |||
318 | spin_lock_irq(&crc->lock); | ||
319 | if (crc->source && crtc_crc_data_count(crc)) | ||
320 | ret = POLLIN | POLLRDNORM; | ||
321 | else | ||
322 | ret = 0; | ||
323 | spin_unlock_irq(&crc->lock); | ||
324 | |||
325 | return ret; | ||
326 | } | ||
327 | |||
310 | static const struct file_operations drm_crtc_crc_data_fops = { | 328 | static const struct file_operations drm_crtc_crc_data_fops = { |
311 | .owner = THIS_MODULE, | 329 | .owner = THIS_MODULE, |
312 | .open = crtc_crc_open, | 330 | .open = crtc_crc_open, |
313 | .read = crtc_crc_read, | 331 | .read = crtc_crc_read, |
332 | .poll = crtc_crc_poll, | ||
314 | .release = crtc_crc_release, | 333 | .release = crtc_crc_release, |
315 | }; | 334 | }; |
316 | 335 | ||
diff --git a/drivers/gpu/drm/drm_dp_helper.c b/drivers/gpu/drm/drm_dp_helper.c index adf79be42c1e..ffe14ec3e7f2 100644 --- a/drivers/gpu/drm/drm_dp_helper.c +++ b/drivers/gpu/drm/drm_dp_helper.c | |||
@@ -146,6 +146,8 @@ u8 drm_dp_link_rate_to_bw_code(int link_rate) | |||
146 | return DP_LINK_BW_2_7; | 146 | return DP_LINK_BW_2_7; |
147 | case 540000: | 147 | case 540000: |
148 | return DP_LINK_BW_5_4; | 148 | return DP_LINK_BW_5_4; |
149 | case 810000: | ||
150 | return DP_LINK_BW_8_1; | ||
149 | } | 151 | } |
150 | } | 152 | } |
151 | EXPORT_SYMBOL(drm_dp_link_rate_to_bw_code); | 153 | EXPORT_SYMBOL(drm_dp_link_rate_to_bw_code); |
@@ -161,6 +163,8 @@ int drm_dp_bw_code_to_link_rate(u8 link_bw) | |||
161 | return 270000; | 163 | return 270000; |
162 | case DP_LINK_BW_5_4: | 164 | case DP_LINK_BW_5_4: |
163 | return 540000; | 165 | return 540000; |
166 | case DP_LINK_BW_8_1: | ||
167 | return 810000; | ||
164 | } | 168 | } |
165 | } | 169 | } |
166 | EXPORT_SYMBOL(drm_dp_bw_code_to_link_rate); | 170 | EXPORT_SYMBOL(drm_dp_bw_code_to_link_rate); |
diff --git a/drivers/gpu/drm/drm_dp_mst_topology.c b/drivers/gpu/drm/drm_dp_mst_topology.c index 70dcfa58d3c2..36df7df5fe1a 100644 --- a/drivers/gpu/drm/drm_dp_mst_topology.c +++ b/drivers/gpu/drm/drm_dp_mst_topology.c | |||
@@ -2087,6 +2087,9 @@ static bool drm_dp_get_vc_payload_bw(int dp_link_bw, | |||
2087 | case DP_LINK_BW_5_4: | 2087 | case DP_LINK_BW_5_4: |
2088 | *out = 10 * dp_link_count; | 2088 | *out = 10 * dp_link_count; |
2089 | break; | 2089 | break; |
2090 | case DP_LINK_BW_8_1: | ||
2091 | *out = 15 * dp_link_count; | ||
2092 | break; | ||
2090 | } | 2093 | } |
2091 | return true; | 2094 | return true; |
2092 | } | 2095 | } |
diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index ddd537914575..b1cb2627548f 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c | |||
@@ -2767,7 +2767,7 @@ do_detailed_mode(struct detailed_timing *timing, void *c) | |||
2767 | 2767 | ||
2768 | drm_mode_probed_add(closure->connector, newmode); | 2768 | drm_mode_probed_add(closure->connector, newmode); |
2769 | closure->modes++; | 2769 | closure->modes++; |
2770 | closure->preferred = 0; | 2770 | closure->preferred = false; |
2771 | } | 2771 | } |
2772 | } | 2772 | } |
2773 | 2773 | ||
@@ -2784,7 +2784,7 @@ add_detailed_modes(struct drm_connector *connector, struct edid *edid, | |||
2784 | struct detailed_mode_closure closure = { | 2784 | struct detailed_mode_closure closure = { |
2785 | .connector = connector, | 2785 | .connector = connector, |
2786 | .edid = edid, | 2786 | .edid = edid, |
2787 | .preferred = 1, | 2787 | .preferred = true, |
2788 | .quirks = quirks, | 2788 | .quirks = quirks, |
2789 | }; | 2789 | }; |
2790 | 2790 | ||
diff --git a/drivers/gpu/drm/drm_encoder.c b/drivers/gpu/drm/drm_encoder.c index 59e0ebe733f8..273e1c59c54a 100644 --- a/drivers/gpu/drm/drm_encoder.c +++ b/drivers/gpu/drm/drm_encoder.c | |||
@@ -110,6 +110,10 @@ int drm_encoder_init(struct drm_device *dev, | |||
110 | { | 110 | { |
111 | int ret; | 111 | int ret; |
112 | 112 | ||
113 | /* encoder index is used with 32bit bitmasks */ | ||
114 | if (WARN_ON(dev->mode_config.num_encoder >= 32)) | ||
115 | return -EINVAL; | ||
116 | |||
113 | ret = drm_mode_object_add(dev, &encoder->base, DRM_MODE_OBJECT_ENCODER); | 117 | ret = drm_mode_object_add(dev, &encoder->base, DRM_MODE_OBJECT_ENCODER); |
114 | if (ret) | 118 | if (ret) |
115 | return ret; | 119 | return ret; |
diff --git a/drivers/gpu/drm/drm_fourcc.c b/drivers/gpu/drm/drm_fourcc.c index 9c0152df45ad..5ca6395cd4d3 100644 --- a/drivers/gpu/drm/drm_fourcc.c +++ b/drivers/gpu/drm/drm_fourcc.c | |||
@@ -112,18 +112,18 @@ const struct drm_format_info *__drm_format_info(u32 format) | |||
112 | { .format = DRM_FORMAT_XBGR4444, .depth = 0, .num_planes = 1, .cpp = { 2, 0, 0 }, .hsub = 1, .vsub = 1 }, | 112 | { .format = DRM_FORMAT_XBGR4444, .depth = 0, .num_planes = 1, .cpp = { 2, 0, 0 }, .hsub = 1, .vsub = 1 }, |
113 | { .format = DRM_FORMAT_RGBX4444, .depth = 0, .num_planes = 1, .cpp = { 2, 0, 0 }, .hsub = 1, .vsub = 1 }, | 113 | { .format = DRM_FORMAT_RGBX4444, .depth = 0, .num_planes = 1, .cpp = { 2, 0, 0 }, .hsub = 1, .vsub = 1 }, |
114 | { .format = DRM_FORMAT_BGRX4444, .depth = 0, .num_planes = 1, .cpp = { 2, 0, 0 }, .hsub = 1, .vsub = 1 }, | 114 | { .format = DRM_FORMAT_BGRX4444, .depth = 0, .num_planes = 1, .cpp = { 2, 0, 0 }, .hsub = 1, .vsub = 1 }, |
115 | { .format = DRM_FORMAT_ARGB4444, .depth = 0, .num_planes = 1, .cpp = { 2, 0, 0 }, .hsub = 1, .vsub = 1 }, | 115 | { .format = DRM_FORMAT_ARGB4444, .depth = 0, .num_planes = 1, .cpp = { 2, 0, 0 }, .hsub = 1, .vsub = 1, .has_alpha = true }, |
116 | { .format = DRM_FORMAT_ABGR4444, .depth = 0, .num_planes = 1, .cpp = { 2, 0, 0 }, .hsub = 1, .vsub = 1 }, | 116 | { .format = DRM_FORMAT_ABGR4444, .depth = 0, .num_planes = 1, .cpp = { 2, 0, 0 }, .hsub = 1, .vsub = 1, .has_alpha = true }, |
117 | { .format = DRM_FORMAT_RGBA4444, .depth = 0, .num_planes = 1, .cpp = { 2, 0, 0 }, .hsub = 1, .vsub = 1 }, | 117 | { .format = DRM_FORMAT_RGBA4444, .depth = 0, .num_planes = 1, .cpp = { 2, 0, 0 }, .hsub = 1, .vsub = 1, .has_alpha = true }, |
118 | { .format = DRM_FORMAT_BGRA4444, .depth = 0, .num_planes = 1, .cpp = { 2, 0, 0 }, .hsub = 1, .vsub = 1 }, | 118 | { .format = DRM_FORMAT_BGRA4444, .depth = 0, .num_planes = 1, .cpp = { 2, 0, 0 }, .hsub = 1, .vsub = 1, .has_alpha = true }, |
119 | { .format = DRM_FORMAT_XRGB1555, .depth = 15, .num_planes = 1, .cpp = { 2, 0, 0 }, .hsub = 1, .vsub = 1 }, | 119 | { .format = DRM_FORMAT_XRGB1555, .depth = 15, .num_planes = 1, .cpp = { 2, 0, 0 }, .hsub = 1, .vsub = 1 }, |
120 | { .format = DRM_FORMAT_XBGR1555, .depth = 15, .num_planes = 1, .cpp = { 2, 0, 0 }, .hsub = 1, .vsub = 1 }, | 120 | { .format = DRM_FORMAT_XBGR1555, .depth = 15, .num_planes = 1, .cpp = { 2, 0, 0 }, .hsub = 1, .vsub = 1 }, |
121 | { .format = DRM_FORMAT_RGBX5551, .depth = 15, .num_planes = 1, .cpp = { 2, 0, 0 }, .hsub = 1, .vsub = 1 }, | 121 | { .format = DRM_FORMAT_RGBX5551, .depth = 15, .num_planes = 1, .cpp = { 2, 0, 0 }, .hsub = 1, .vsub = 1 }, |
122 | { .format = DRM_FORMAT_BGRX5551, .depth = 15, .num_planes = 1, .cpp = { 2, 0, 0 }, .hsub = 1, .vsub = 1 }, | 122 | { .format = DRM_FORMAT_BGRX5551, .depth = 15, .num_planes = 1, .cpp = { 2, 0, 0 }, .hsub = 1, .vsub = 1 }, |
123 | { .format = DRM_FORMAT_ARGB1555, .depth = 15, .num_planes = 1, .cpp = { 2, 0, 0 }, .hsub = 1, .vsub = 1 }, | 123 | { .format = DRM_FORMAT_ARGB1555, .depth = 15, .num_planes = 1, .cpp = { 2, 0, 0 }, .hsub = 1, .vsub = 1, .has_alpha = true }, |
124 | { .format = DRM_FORMAT_ABGR1555, .depth = 15, .num_planes = 1, .cpp = { 2, 0, 0 }, .hsub = 1, .vsub = 1 }, | 124 | { .format = DRM_FORMAT_ABGR1555, .depth = 15, .num_planes = 1, .cpp = { 2, 0, 0 }, .hsub = 1, .vsub = 1, .has_alpha = true }, |
125 | { .format = DRM_FORMAT_RGBA5551, .depth = 15, .num_planes = 1, .cpp = { 2, 0, 0 }, .hsub = 1, .vsub = 1 }, | 125 | { .format = DRM_FORMAT_RGBA5551, .depth = 15, .num_planes = 1, .cpp = { 2, 0, 0 }, .hsub = 1, .vsub = 1, .has_alpha = true }, |
126 | { .format = DRM_FORMAT_BGRA5551, .depth = 15, .num_planes = 1, .cpp = { 2, 0, 0 }, .hsub = 1, .vsub = 1 }, | 126 | { .format = DRM_FORMAT_BGRA5551, .depth = 15, .num_planes = 1, .cpp = { 2, 0, 0 }, .hsub = 1, .vsub = 1, .has_alpha = true }, |
127 | { .format = DRM_FORMAT_RGB565, .depth = 16, .num_planes = 1, .cpp = { 2, 0, 0 }, .hsub = 1, .vsub = 1 }, | 127 | { .format = DRM_FORMAT_RGB565, .depth = 16, .num_planes = 1, .cpp = { 2, 0, 0 }, .hsub = 1, .vsub = 1 }, |
128 | { .format = DRM_FORMAT_BGR565, .depth = 16, .num_planes = 1, .cpp = { 2, 0, 0 }, .hsub = 1, .vsub = 1 }, | 128 | { .format = DRM_FORMAT_BGR565, .depth = 16, .num_planes = 1, .cpp = { 2, 0, 0 }, .hsub = 1, .vsub = 1 }, |
129 | { .format = DRM_FORMAT_RGB888, .depth = 24, .num_planes = 1, .cpp = { 3, 0, 0 }, .hsub = 1, .vsub = 1 }, | 129 | { .format = DRM_FORMAT_RGB888, .depth = 24, .num_planes = 1, .cpp = { 3, 0, 0 }, .hsub = 1, .vsub = 1 }, |
@@ -132,26 +132,26 @@ const struct drm_format_info *__drm_format_info(u32 format) | |||
132 | { .format = DRM_FORMAT_XBGR8888, .depth = 24, .num_planes = 1, .cpp = { 4, 0, 0 }, .hsub = 1, .vsub = 1 }, | 132 | { .format = DRM_FORMAT_XBGR8888, .depth = 24, .num_planes = 1, .cpp = { 4, 0, 0 }, .hsub = 1, .vsub = 1 }, |
133 | { .format = DRM_FORMAT_RGBX8888, .depth = 24, .num_planes = 1, .cpp = { 4, 0, 0 }, .hsub = 1, .vsub = 1 }, | 133 | { .format = DRM_FORMAT_RGBX8888, .depth = 24, .num_planes = 1, .cpp = { 4, 0, 0 }, .hsub = 1, .vsub = 1 }, |
134 | { .format = DRM_FORMAT_BGRX8888, .depth = 24, .num_planes = 1, .cpp = { 4, 0, 0 }, .hsub = 1, .vsub = 1 }, | 134 | { .format = DRM_FORMAT_BGRX8888, .depth = 24, .num_planes = 1, .cpp = { 4, 0, 0 }, .hsub = 1, .vsub = 1 }, |
135 | { .format = DRM_FORMAT_RGB565_A8, .depth = 24, .num_planes = 2, .cpp = { 2, 1, 0 }, .hsub = 1, .vsub = 1 }, | 135 | { .format = DRM_FORMAT_RGB565_A8, .depth = 24, .num_planes = 2, .cpp = { 2, 1, 0 }, .hsub = 1, .vsub = 1, .has_alpha = true }, |
136 | { .format = DRM_FORMAT_BGR565_A8, .depth = 24, .num_planes = 2, .cpp = { 2, 1, 0 }, .hsub = 1, .vsub = 1 }, | 136 | { .format = DRM_FORMAT_BGR565_A8, .depth = 24, .num_planes = 2, .cpp = { 2, 1, 0 }, .hsub = 1, .vsub = 1, .has_alpha = true }, |
137 | { .format = DRM_FORMAT_XRGB2101010, .depth = 30, .num_planes = 1, .cpp = { 4, 0, 0 }, .hsub = 1, .vsub = 1 }, | 137 | { .format = DRM_FORMAT_XRGB2101010, .depth = 30, .num_planes = 1, .cpp = { 4, 0, 0 }, .hsub = 1, .vsub = 1 }, |
138 | { .format = DRM_FORMAT_XBGR2101010, .depth = 30, .num_planes = 1, .cpp = { 4, 0, 0 }, .hsub = 1, .vsub = 1 }, | 138 | { .format = DRM_FORMAT_XBGR2101010, .depth = 30, .num_planes = 1, .cpp = { 4, 0, 0 }, .hsub = 1, .vsub = 1 }, |
139 | { .format = DRM_FORMAT_RGBX1010102, .depth = 30, .num_planes = 1, .cpp = { 4, 0, 0 }, .hsub = 1, .vsub = 1 }, | 139 | { .format = DRM_FORMAT_RGBX1010102, .depth = 30, .num_planes = 1, .cpp = { 4, 0, 0 }, .hsub = 1, .vsub = 1 }, |
140 | { .format = DRM_FORMAT_BGRX1010102, .depth = 30, .num_planes = 1, .cpp = { 4, 0, 0 }, .hsub = 1, .vsub = 1 }, | 140 | { .format = DRM_FORMAT_BGRX1010102, .depth = 30, .num_planes = 1, .cpp = { 4, 0, 0 }, .hsub = 1, .vsub = 1 }, |
141 | { .format = DRM_FORMAT_ARGB2101010, .depth = 30, .num_planes = 1, .cpp = { 4, 0, 0 }, .hsub = 1, .vsub = 1 }, | 141 | { .format = DRM_FORMAT_ARGB2101010, .depth = 30, .num_planes = 1, .cpp = { 4, 0, 0 }, .hsub = 1, .vsub = 1, .has_alpha = true }, |
142 | { .format = DRM_FORMAT_ABGR2101010, .depth = 30, .num_planes = 1, .cpp = { 4, 0, 0 }, .hsub = 1, .vsub = 1 }, | 142 | { .format = DRM_FORMAT_ABGR2101010, .depth = 30, .num_planes = 1, .cpp = { 4, 0, 0 }, .hsub = 1, .vsub = 1, .has_alpha = true }, |
143 | { .format = DRM_FORMAT_RGBA1010102, .depth = 30, .num_planes = 1, .cpp = { 4, 0, 0 }, .hsub = 1, .vsub = 1 }, | 143 | { .format = DRM_FORMAT_RGBA1010102, .depth = 30, .num_planes = 1, .cpp = { 4, 0, 0 }, .hsub = 1, .vsub = 1, .has_alpha = true }, |
144 | { .format = DRM_FORMAT_BGRA1010102, .depth = 30, .num_planes = 1, .cpp = { 4, 0, 0 }, .hsub = 1, .vsub = 1 }, | 144 | { .format = DRM_FORMAT_BGRA1010102, .depth = 30, .num_planes = 1, .cpp = { 4, 0, 0 }, .hsub = 1, .vsub = 1, .has_alpha = true }, |
145 | { .format = DRM_FORMAT_ARGB8888, .depth = 32, .num_planes = 1, .cpp = { 4, 0, 0 }, .hsub = 1, .vsub = 1 }, | 145 | { .format = DRM_FORMAT_ARGB8888, .depth = 32, .num_planes = 1, .cpp = { 4, 0, 0 }, .hsub = 1, .vsub = 1, .has_alpha = true }, |
146 | { .format = DRM_FORMAT_ABGR8888, .depth = 32, .num_planes = 1, .cpp = { 4, 0, 0 }, .hsub = 1, .vsub = 1 }, | 146 | { .format = DRM_FORMAT_ABGR8888, .depth = 32, .num_planes = 1, .cpp = { 4, 0, 0 }, .hsub = 1, .vsub = 1, .has_alpha = true }, |
147 | { .format = DRM_FORMAT_RGBA8888, .depth = 32, .num_planes = 1, .cpp = { 4, 0, 0 }, .hsub = 1, .vsub = 1 }, | 147 | { .format = DRM_FORMAT_RGBA8888, .depth = 32, .num_planes = 1, .cpp = { 4, 0, 0 }, .hsub = 1, .vsub = 1, .has_alpha = true }, |
148 | { .format = DRM_FORMAT_BGRA8888, .depth = 32, .num_planes = 1, .cpp = { 4, 0, 0 }, .hsub = 1, .vsub = 1 }, | 148 | { .format = DRM_FORMAT_BGRA8888, .depth = 32, .num_planes = 1, .cpp = { 4, 0, 0 }, .hsub = 1, .vsub = 1, .has_alpha = true }, |
149 | { .format = DRM_FORMAT_RGB888_A8, .depth = 32, .num_planes = 2, .cpp = { 3, 1, 0 }, .hsub = 1, .vsub = 1 }, | 149 | { .format = DRM_FORMAT_RGB888_A8, .depth = 32, .num_planes = 2, .cpp = { 3, 1, 0 }, .hsub = 1, .vsub = 1, .has_alpha = true }, |
150 | { .format = DRM_FORMAT_BGR888_A8, .depth = 32, .num_planes = 2, .cpp = { 3, 1, 0 }, .hsub = 1, .vsub = 1 }, | 150 | { .format = DRM_FORMAT_BGR888_A8, .depth = 32, .num_planes = 2, .cpp = { 3, 1, 0 }, .hsub = 1, .vsub = 1, .has_alpha = true }, |
151 | { .format = DRM_FORMAT_XRGB8888_A8, .depth = 32, .num_planes = 2, .cpp = { 4, 1, 0 }, .hsub = 1, .vsub = 1 }, | 151 | { .format = DRM_FORMAT_XRGB8888_A8, .depth = 32, .num_planes = 2, .cpp = { 4, 1, 0 }, .hsub = 1, .vsub = 1, .has_alpha = true }, |
152 | { .format = DRM_FORMAT_XBGR8888_A8, .depth = 32, .num_planes = 2, .cpp = { 4, 1, 0 }, .hsub = 1, .vsub = 1 }, | 152 | { .format = DRM_FORMAT_XBGR8888_A8, .depth = 32, .num_planes = 2, .cpp = { 4, 1, 0 }, .hsub = 1, .vsub = 1, .has_alpha = true }, |
153 | { .format = DRM_FORMAT_RGBX8888_A8, .depth = 32, .num_planes = 2, .cpp = { 4, 1, 0 }, .hsub = 1, .vsub = 1 }, | 153 | { .format = DRM_FORMAT_RGBX8888_A8, .depth = 32, .num_planes = 2, .cpp = { 4, 1, 0 }, .hsub = 1, .vsub = 1, .has_alpha = true }, |
154 | { .format = DRM_FORMAT_BGRX8888_A8, .depth = 32, .num_planes = 2, .cpp = { 4, 1, 0 }, .hsub = 1, .vsub = 1 }, | 154 | { .format = DRM_FORMAT_BGRX8888_A8, .depth = 32, .num_planes = 2, .cpp = { 4, 1, 0 }, .hsub = 1, .vsub = 1, .has_alpha = true }, |
155 | { .format = DRM_FORMAT_YUV410, .depth = 0, .num_planes = 3, .cpp = { 1, 1, 1 }, .hsub = 4, .vsub = 4 }, | 155 | { .format = DRM_FORMAT_YUV410, .depth = 0, .num_planes = 3, .cpp = { 1, 1, 1 }, .hsub = 4, .vsub = 4 }, |
156 | { .format = DRM_FORMAT_YVU410, .depth = 0, .num_planes = 3, .cpp = { 1, 1, 1 }, .hsub = 4, .vsub = 4 }, | 156 | { .format = DRM_FORMAT_YVU410, .depth = 0, .num_planes = 3, .cpp = { 1, 1, 1 }, .hsub = 4, .vsub = 4 }, |
157 | { .format = DRM_FORMAT_YUV411, .depth = 0, .num_planes = 3, .cpp = { 1, 1, 1 }, .hsub = 4, .vsub = 1 }, | 157 | { .format = DRM_FORMAT_YUV411, .depth = 0, .num_planes = 3, .cpp = { 1, 1, 1 }, .hsub = 4, .vsub = 1 }, |
@@ -172,7 +172,7 @@ const struct drm_format_info *__drm_format_info(u32 format) | |||
172 | { .format = DRM_FORMAT_YVYU, .depth = 0, .num_planes = 1, .cpp = { 2, 0, 0 }, .hsub = 2, .vsub = 1 }, | 172 | { .format = DRM_FORMAT_YVYU, .depth = 0, .num_planes = 1, .cpp = { 2, 0, 0 }, .hsub = 2, .vsub = 1 }, |
173 | { .format = DRM_FORMAT_UYVY, .depth = 0, .num_planes = 1, .cpp = { 2, 0, 0 }, .hsub = 2, .vsub = 1 }, | 173 | { .format = DRM_FORMAT_UYVY, .depth = 0, .num_planes = 1, .cpp = { 2, 0, 0 }, .hsub = 2, .vsub = 1 }, |
174 | { .format = DRM_FORMAT_VYUY, .depth = 0, .num_planes = 1, .cpp = { 2, 0, 0 }, .hsub = 2, .vsub = 1 }, | 174 | { .format = DRM_FORMAT_VYUY, .depth = 0, .num_planes = 1, .cpp = { 2, 0, 0 }, .hsub = 2, .vsub = 1 }, |
175 | { .format = DRM_FORMAT_AYUV, .depth = 0, .num_planes = 1, .cpp = { 4, 0, 0 }, .hsub = 1, .vsub = 1 }, | 175 | { .format = DRM_FORMAT_AYUV, .depth = 0, .num_planes = 1, .cpp = { 4, 0, 0 }, .hsub = 1, .vsub = 1, .has_alpha = true }, |
176 | }; | 176 | }; |
177 | 177 | ||
178 | unsigned int i; | 178 | unsigned int i; |
diff --git a/drivers/gpu/drm/drm_ioctl.c b/drivers/gpu/drm/drm_ioctl.c index 4aafe4802099..af782911c505 100644 --- a/drivers/gpu/drm/drm_ioctl.c +++ b/drivers/gpu/drm/drm_ioctl.c | |||
@@ -509,7 +509,7 @@ int drm_ioctl_permit(u32 flags, struct drm_file *file_priv) | |||
509 | return -EACCES; | 509 | return -EACCES; |
510 | 510 | ||
511 | /* MASTER is only for master or control clients */ | 511 | /* MASTER is only for master or control clients */ |
512 | if (unlikely((flags & DRM_MASTER) && | 512 | if (unlikely((flags & DRM_MASTER) && |
513 | !drm_is_current_master(file_priv) && | 513 | !drm_is_current_master(file_priv) && |
514 | !drm_is_control_client(file_priv))) | 514 | !drm_is_control_client(file_priv))) |
515 | return -EACCES; | 515 | return -EACCES; |
@@ -704,7 +704,7 @@ static const struct drm_ioctl_desc drm_ioctls[] = { | |||
704 | * | 704 | * |
705 | * ##define DRM_IOCTL_MY_DRIVER_OPERATION \ | 705 | * ##define DRM_IOCTL_MY_DRIVER_OPERATION \ |
706 | * DRM_IOW(DRM_COMMAND_BASE, struct my_driver_operation) | 706 | * DRM_IOW(DRM_COMMAND_BASE, struct my_driver_operation) |
707 | * | 707 | * |
708 | * DRM driver private IOCTL must be in the range from DRM_COMMAND_BASE to | 708 | * DRM driver private IOCTL must be in the range from DRM_COMMAND_BASE to |
709 | * DRM_COMMAND_END. Finally you need an array of &struct drm_ioctl_desc to wire | 709 | * DRM_COMMAND_END. Finally you need an array of &struct drm_ioctl_desc to wire |
710 | * up the handlers and set the access rights:: | 710 | * up the handlers and set the access rights:: |
@@ -848,7 +848,7 @@ long drm_ioctl(struct file *filp, | |||
848 | if (kdata != stack_kdata) | 848 | if (kdata != stack_kdata) |
849 | kfree(kdata); | 849 | kfree(kdata); |
850 | if (retcode) | 850 | if (retcode) |
851 | DRM_DEBUG("ret = %d\n", retcode); | 851 | DRM_DEBUG("pid=%d, ret = %d\n", task_pid_nr(current), retcode); |
852 | return retcode; | 852 | return retcode; |
853 | } | 853 | } |
854 | EXPORT_SYMBOL(drm_ioctl); | 854 | EXPORT_SYMBOL(drm_ioctl); |
diff --git a/drivers/gpu/drm/drm_memory.c b/drivers/gpu/drm/drm_memory.c index fc0ebd273ef8..7ca500b8c399 100644 --- a/drivers/gpu/drm/drm_memory.c +++ b/drivers/gpu/drm/drm_memory.c | |||
@@ -149,3 +149,16 @@ void drm_legacy_ioremapfree(struct drm_local_map *map, struct drm_device *dev) | |||
149 | iounmap(map->handle); | 149 | iounmap(map->handle); |
150 | } | 150 | } |
151 | EXPORT_SYMBOL(drm_legacy_ioremapfree); | 151 | EXPORT_SYMBOL(drm_legacy_ioremapfree); |
152 | |||
153 | u64 drm_get_max_iomem(void) | ||
154 | { | ||
155 | struct resource *tmp; | ||
156 | u64 max_iomem = 0; | ||
157 | |||
158 | for (tmp = iomem_resource.child; tmp; tmp = tmp->sibling) { | ||
159 | max_iomem = max(max_iomem, tmp->end); | ||
160 | } | ||
161 | |||
162 | return max_iomem; | ||
163 | } | ||
164 | EXPORT_SYMBOL(drm_get_max_iomem); | ||
diff --git a/drivers/gpu/drm/drm_mipi_dsi.c b/drivers/gpu/drm/drm_mipi_dsi.c index 4b47226b90d4..bc73b7f5b9fc 100644 --- a/drivers/gpu/drm/drm_mipi_dsi.c +++ b/drivers/gpu/drm/drm_mipi_dsi.c | |||
@@ -498,8 +498,9 @@ int mipi_dsi_shutdown_peripheral(struct mipi_dsi_device *dsi) | |||
498 | .tx_buf = (u8 [2]) { 0, 0 }, | 498 | .tx_buf = (u8 [2]) { 0, 0 }, |
499 | .tx_len = 2, | 499 | .tx_len = 2, |
500 | }; | 500 | }; |
501 | int ret = mipi_dsi_device_transfer(dsi, &msg); | ||
501 | 502 | ||
502 | return mipi_dsi_device_transfer(dsi, &msg); | 503 | return (ret < 0) ? ret : 0; |
503 | } | 504 | } |
504 | EXPORT_SYMBOL(mipi_dsi_shutdown_peripheral); | 505 | EXPORT_SYMBOL(mipi_dsi_shutdown_peripheral); |
505 | 506 | ||
@@ -517,8 +518,9 @@ int mipi_dsi_turn_on_peripheral(struct mipi_dsi_device *dsi) | |||
517 | .tx_buf = (u8 [2]) { 0, 0 }, | 518 | .tx_buf = (u8 [2]) { 0, 0 }, |
518 | .tx_len = 2, | 519 | .tx_len = 2, |
519 | }; | 520 | }; |
521 | int ret = mipi_dsi_device_transfer(dsi, &msg); | ||
520 | 522 | ||
521 | return mipi_dsi_device_transfer(dsi, &msg); | 523 | return (ret < 0) ? ret : 0; |
522 | } | 524 | } |
523 | EXPORT_SYMBOL(mipi_dsi_turn_on_peripheral); | 525 | EXPORT_SYMBOL(mipi_dsi_turn_on_peripheral); |
524 | 526 | ||
@@ -541,8 +543,9 @@ int mipi_dsi_set_maximum_return_packet_size(struct mipi_dsi_device *dsi, | |||
541 | .tx_len = sizeof(tx), | 543 | .tx_len = sizeof(tx), |
542 | .tx_buf = tx, | 544 | .tx_buf = tx, |
543 | }; | 545 | }; |
546 | int ret = mipi_dsi_device_transfer(dsi, &msg); | ||
544 | 547 | ||
545 | return mipi_dsi_device_transfer(dsi, &msg); | 548 | return (ret < 0) ? ret : 0; |
546 | } | 549 | } |
547 | EXPORT_SYMBOL(mipi_dsi_set_maximum_return_packet_size); | 550 | EXPORT_SYMBOL(mipi_dsi_set_maximum_return_packet_size); |
548 | 551 | ||
diff --git a/drivers/gpu/drm/drm_modes.c b/drivers/gpu/drm/drm_modes.c index 4a3f68a33844..c397b523c945 100644 --- a/drivers/gpu/drm/drm_modes.c +++ b/drivers/gpu/drm/drm_modes.c | |||
@@ -833,7 +833,7 @@ EXPORT_SYMBOL(drm_mode_get_hv_timing); | |||
833 | */ | 833 | */ |
834 | void drm_mode_set_crtcinfo(struct drm_display_mode *p, int adjust_flags) | 834 | void drm_mode_set_crtcinfo(struct drm_display_mode *p, int adjust_flags) |
835 | { | 835 | { |
836 | if ((p == NULL) || ((p->type & DRM_MODE_TYPE_CRTC_C) == DRM_MODE_TYPE_BUILTIN)) | 836 | if (!p) |
837 | return; | 837 | return; |
838 | 838 | ||
839 | p->crtc_clock = p->clock; | 839 | p->crtc_clock = p->clock; |
@@ -1023,19 +1023,18 @@ bool drm_mode_equal_no_clocks_no_stereo(const struct drm_display_mode *mode1, | |||
1023 | } | 1023 | } |
1024 | EXPORT_SYMBOL(drm_mode_equal_no_clocks_no_stereo); | 1024 | EXPORT_SYMBOL(drm_mode_equal_no_clocks_no_stereo); |
1025 | 1025 | ||
1026 | /** | 1026 | static enum drm_mode_status |
1027 | * drm_mode_validate_basic - make sure the mode is somewhat sane | ||
1028 | * @mode: mode to check | ||
1029 | * | ||
1030 | * Check that the mode timings are at least somewhat reasonable. | ||
1031 | * Any hardware specific limits are left up for each driver to check. | ||
1032 | * | ||
1033 | * Returns: | ||
1034 | * The mode status | ||
1035 | */ | ||
1036 | enum drm_mode_status | ||
1037 | drm_mode_validate_basic(const struct drm_display_mode *mode) | 1027 | drm_mode_validate_basic(const struct drm_display_mode *mode) |
1038 | { | 1028 | { |
1029 | if (mode->type & ~DRM_MODE_TYPE_ALL) | ||
1030 | return MODE_BAD; | ||
1031 | |||
1032 | if (mode->flags & ~DRM_MODE_FLAG_ALL) | ||
1033 | return MODE_BAD; | ||
1034 | |||
1035 | if ((mode->flags & DRM_MODE_FLAG_3D_MASK) > DRM_MODE_FLAG_3D_MAX) | ||
1036 | return MODE_BAD; | ||
1037 | |||
1039 | if (mode->clock == 0) | 1038 | if (mode->clock == 0) |
1040 | return MODE_CLOCK_LOW; | 1039 | return MODE_CLOCK_LOW; |
1041 | 1040 | ||
@@ -1053,7 +1052,35 @@ drm_mode_validate_basic(const struct drm_display_mode *mode) | |||
1053 | 1052 | ||
1054 | return MODE_OK; | 1053 | return MODE_OK; |
1055 | } | 1054 | } |
1056 | EXPORT_SYMBOL(drm_mode_validate_basic); | 1055 | |
1056 | /** | ||
1057 | * drm_mode_validate_driver - make sure the mode is somewhat sane | ||
1058 | * @dev: drm device | ||
1059 | * @mode: mode to check | ||
1060 | * | ||
1061 | * First do basic validation on the mode, and then allow the driver | ||
1062 | * to check for device/driver specific limitations via the optional | ||
1063 | * &drm_mode_config_helper_funcs.mode_valid hook. | ||
1064 | * | ||
1065 | * Returns: | ||
1066 | * The mode status | ||
1067 | */ | ||
1068 | enum drm_mode_status | ||
1069 | drm_mode_validate_driver(struct drm_device *dev, | ||
1070 | const struct drm_display_mode *mode) | ||
1071 | { | ||
1072 | enum drm_mode_status status; | ||
1073 | |||
1074 | status = drm_mode_validate_basic(mode); | ||
1075 | if (status != MODE_OK) | ||
1076 | return status; | ||
1077 | |||
1078 | if (dev->mode_config.funcs->mode_valid) | ||
1079 | return dev->mode_config.funcs->mode_valid(dev, mode); | ||
1080 | else | ||
1081 | return MODE_OK; | ||
1082 | } | ||
1083 | EXPORT_SYMBOL(drm_mode_validate_driver); | ||
1057 | 1084 | ||
1058 | /** | 1085 | /** |
1059 | * drm_mode_validate_size - make sure modes adhere to size constraints | 1086 | * drm_mode_validate_size - make sure modes adhere to size constraints |
@@ -1555,6 +1582,7 @@ void drm_mode_convert_to_umode(struct drm_mode_modeinfo *out, | |||
1555 | 1582 | ||
1556 | /** | 1583 | /** |
1557 | * drm_crtc_convert_umode - convert a modeinfo into a drm_display_mode | 1584 | * drm_crtc_convert_umode - convert a modeinfo into a drm_display_mode |
1585 | * @dev: drm device | ||
1558 | * @out: drm_display_mode to return to the user | 1586 | * @out: drm_display_mode to return to the user |
1559 | * @in: drm_mode_modeinfo to use | 1587 | * @in: drm_mode_modeinfo to use |
1560 | * | 1588 | * |
@@ -1564,7 +1592,8 @@ void drm_mode_convert_to_umode(struct drm_mode_modeinfo *out, | |||
1564 | * Returns: | 1592 | * Returns: |
1565 | * Zero on success, negative errno on failure. | 1593 | * Zero on success, negative errno on failure. |
1566 | */ | 1594 | */ |
1567 | int drm_mode_convert_umode(struct drm_display_mode *out, | 1595 | int drm_mode_convert_umode(struct drm_device *dev, |
1596 | struct drm_display_mode *out, | ||
1568 | const struct drm_mode_modeinfo *in) | 1597 | const struct drm_mode_modeinfo *in) |
1569 | { | 1598 | { |
1570 | int ret = -EINVAL; | 1599 | int ret = -EINVAL; |
@@ -1574,9 +1603,6 @@ int drm_mode_convert_umode(struct drm_display_mode *out, | |||
1574 | goto out; | 1603 | goto out; |
1575 | } | 1604 | } |
1576 | 1605 | ||
1577 | if ((in->flags & DRM_MODE_FLAG_3D_MASK) > DRM_MODE_FLAG_3D_MAX) | ||
1578 | goto out; | ||
1579 | |||
1580 | out->clock = in->clock; | 1606 | out->clock = in->clock; |
1581 | out->hdisplay = in->hdisplay; | 1607 | out->hdisplay = in->hdisplay; |
1582 | out->hsync_start = in->hsync_start; | 1608 | out->hsync_start = in->hsync_start; |
@@ -1594,7 +1620,7 @@ int drm_mode_convert_umode(struct drm_display_mode *out, | |||
1594 | strncpy(out->name, in->name, DRM_DISPLAY_MODE_LEN); | 1620 | strncpy(out->name, in->name, DRM_DISPLAY_MODE_LEN); |
1595 | out->name[DRM_DISPLAY_MODE_LEN-1] = 0; | 1621 | out->name[DRM_DISPLAY_MODE_LEN-1] = 0; |
1596 | 1622 | ||
1597 | out->status = drm_mode_validate_basic(out); | 1623 | out->status = drm_mode_validate_driver(dev, out); |
1598 | if (out->status != MODE_OK) | 1624 | if (out->status != MODE_OK) |
1599 | goto out; | 1625 | goto out; |
1600 | 1626 | ||
diff --git a/drivers/gpu/drm/drm_plane.c b/drivers/gpu/drm/drm_plane.c index 2c90519576a3..22b54663b6e7 100644 --- a/drivers/gpu/drm/drm_plane.c +++ b/drivers/gpu/drm/drm_plane.c | |||
@@ -173,6 +173,10 @@ int drm_universal_plane_init(struct drm_device *dev, struct drm_plane *plane, | |||
173 | unsigned int format_modifier_count = 0; | 173 | unsigned int format_modifier_count = 0; |
174 | int ret; | 174 | int ret; |
175 | 175 | ||
176 | /* plane index is used with 32bit bitmasks */ | ||
177 | if (WARN_ON(config->num_total_plane >= 32)) | ||
178 | return -EINVAL; | ||
179 | |||
176 | ret = drm_mode_object_add(dev, &plane->base, DRM_MODE_OBJECT_PLANE); | 180 | ret = drm_mode_object_add(dev, &plane->base, DRM_MODE_OBJECT_PLANE); |
177 | if (ret) | 181 | if (ret) |
178 | return ret; | 182 | return ret; |
diff --git a/drivers/gpu/drm/drm_prime.c b/drivers/gpu/drm/drm_prime.c index 9a17725b0f7a..e82a976f0fba 100644 --- a/drivers/gpu/drm/drm_prime.c +++ b/drivers/gpu/drm/drm_prime.c | |||
@@ -73,6 +73,9 @@ | |||
73 | * Drivers should detect this situation and return back the gem object | 73 | * Drivers should detect this situation and return back the gem object |
74 | * from the dma-buf private. Prime will do this automatically for drivers that | 74 | * from the dma-buf private. Prime will do this automatically for drivers that |
75 | * use the drm_gem_prime_{import,export} helpers. | 75 | * use the drm_gem_prime_{import,export} helpers. |
76 | * | ||
77 | * GEM struct &dma_buf_ops symbols are now exported. They can be resued by | ||
78 | * drivers which implement GEM interface. | ||
76 | */ | 79 | */ |
77 | 80 | ||
78 | struct drm_prime_member { | 81 | struct drm_prime_member { |
@@ -180,9 +183,20 @@ static int drm_prime_lookup_buf_handle(struct drm_prime_file_private *prime_fpri | |||
180 | return -ENOENT; | 183 | return -ENOENT; |
181 | } | 184 | } |
182 | 185 | ||
183 | static int drm_gem_map_attach(struct dma_buf *dma_buf, | 186 | /** |
184 | struct device *target_dev, | 187 | * drm_gem_map_attach - dma_buf attach implementation for GEM |
185 | struct dma_buf_attachment *attach) | 188 | * @dma_buf: buffer to attach device to |
189 | * @target_dev: not used | ||
190 | * @attach: buffer attachment data | ||
191 | * | ||
192 | * Allocates &drm_prime_attachment and calls &drm_driver.gem_prime_pin for | ||
193 | * device specific attachment. This can be used as the &dma_buf_ops.attach | ||
194 | * callback. | ||
195 | * | ||
196 | * Returns 0 on success, negative error code on failure. | ||
197 | */ | ||
198 | int drm_gem_map_attach(struct dma_buf *dma_buf, struct device *target_dev, | ||
199 | struct dma_buf_attachment *attach) | ||
186 | { | 200 | { |
187 | struct drm_prime_attachment *prime_attach; | 201 | struct drm_prime_attachment *prime_attach; |
188 | struct drm_gem_object *obj = dma_buf->priv; | 202 | struct drm_gem_object *obj = dma_buf->priv; |
@@ -200,9 +214,18 @@ static int drm_gem_map_attach(struct dma_buf *dma_buf, | |||
200 | 214 | ||
201 | return dev->driver->gem_prime_pin(obj); | 215 | return dev->driver->gem_prime_pin(obj); |
202 | } | 216 | } |
217 | EXPORT_SYMBOL(drm_gem_map_attach); | ||
203 | 218 | ||
204 | static void drm_gem_map_detach(struct dma_buf *dma_buf, | 219 | /** |
205 | struct dma_buf_attachment *attach) | 220 | * drm_gem_map_detach - dma_buf detach implementation for GEM |
221 | * @dma_buf: buffer to detach from | ||
222 | * @attach: attachment to be detached | ||
223 | * | ||
224 | * Cleans up &dma_buf_attachment. This can be used as the &dma_buf_ops.detach | ||
225 | * callback. | ||
226 | */ | ||
227 | void drm_gem_map_detach(struct dma_buf *dma_buf, | ||
228 | struct dma_buf_attachment *attach) | ||
206 | { | 229 | { |
207 | struct drm_prime_attachment *prime_attach = attach->priv; | 230 | struct drm_prime_attachment *prime_attach = attach->priv; |
208 | struct drm_gem_object *obj = dma_buf->priv; | 231 | struct drm_gem_object *obj = dma_buf->priv; |
@@ -228,6 +251,7 @@ static void drm_gem_map_detach(struct dma_buf *dma_buf, | |||
228 | kfree(prime_attach); | 251 | kfree(prime_attach); |
229 | attach->priv = NULL; | 252 | attach->priv = NULL; |
230 | } | 253 | } |
254 | EXPORT_SYMBOL(drm_gem_map_detach); | ||
231 | 255 | ||
232 | void drm_prime_remove_buf_handle_locked(struct drm_prime_file_private *prime_fpriv, | 256 | void drm_prime_remove_buf_handle_locked(struct drm_prime_file_private *prime_fpriv, |
233 | struct dma_buf *dma_buf) | 257 | struct dma_buf *dma_buf) |
@@ -254,8 +278,20 @@ void drm_prime_remove_buf_handle_locked(struct drm_prime_file_private *prime_fpr | |||
254 | } | 278 | } |
255 | } | 279 | } |
256 | 280 | ||
257 | static struct sg_table *drm_gem_map_dma_buf(struct dma_buf_attachment *attach, | 281 | /** |
258 | enum dma_data_direction dir) | 282 | * drm_gem_map_dma_buf - map_dma_buf implementation for GEM |
283 | * @attach: attachment whose scatterlist is to be returned | ||
284 | * @dir: direction of DMA transfer | ||
285 | * | ||
286 | * Calls &drm_driver.gem_prime_get_sg_table and then maps the scatterlist. This | ||
287 | * can be used as the &dma_buf_ops.map_dma_buf callback. | ||
288 | * | ||
289 | * Returns sg_table containing the scatterlist to be returned; returns ERR_PTR | ||
290 | * on error. May return -EINTR if it is interrupted by a signal. | ||
291 | */ | ||
292 | |||
293 | struct sg_table *drm_gem_map_dma_buf(struct dma_buf_attachment *attach, | ||
294 | enum dma_data_direction dir) | ||
259 | { | 295 | { |
260 | struct drm_prime_attachment *prime_attach = attach->priv; | 296 | struct drm_prime_attachment *prime_attach = attach->priv; |
261 | struct drm_gem_object *obj = attach->dmabuf->priv; | 297 | struct drm_gem_object *obj = attach->dmabuf->priv; |
@@ -291,13 +327,21 @@ static struct sg_table *drm_gem_map_dma_buf(struct dma_buf_attachment *attach, | |||
291 | 327 | ||
292 | return sgt; | 328 | return sgt; |
293 | } | 329 | } |
330 | EXPORT_SYMBOL(drm_gem_map_dma_buf); | ||
294 | 331 | ||
295 | static void drm_gem_unmap_dma_buf(struct dma_buf_attachment *attach, | 332 | /** |
296 | struct sg_table *sgt, | 333 | * drm_gem_unmap_dma_buf - unmap_dma_buf implementation for GEM |
297 | enum dma_data_direction dir) | 334 | * |
335 | * Not implemented. The unmap is done at drm_gem_map_detach(). This can be | ||
336 | * used as the &dma_buf_ops.unmap_dma_buf callback. | ||
337 | */ | ||
338 | void drm_gem_unmap_dma_buf(struct dma_buf_attachment *attach, | ||
339 | struct sg_table *sgt, | ||
340 | enum dma_data_direction dir) | ||
298 | { | 341 | { |
299 | /* nothing to be done here */ | 342 | /* nothing to be done here */ |
300 | } | 343 | } |
344 | EXPORT_SYMBOL(drm_gem_unmap_dma_buf); | ||
301 | 345 | ||
302 | /** | 346 | /** |
303 | * drm_gem_dmabuf_export - dma_buf export implementation for GEM | 347 | * drm_gem_dmabuf_export - dma_buf export implementation for GEM |
@@ -348,47 +392,99 @@ void drm_gem_dmabuf_release(struct dma_buf *dma_buf) | |||
348 | } | 392 | } |
349 | EXPORT_SYMBOL(drm_gem_dmabuf_release); | 393 | EXPORT_SYMBOL(drm_gem_dmabuf_release); |
350 | 394 | ||
351 | static void *drm_gem_dmabuf_vmap(struct dma_buf *dma_buf) | 395 | /** |
396 | * drm_gem_dmabuf_vmap - dma_buf vmap implementation for GEM | ||
397 | * @dma_buf: buffer to be mapped | ||
398 | * | ||
399 | * Sets up a kernel virtual mapping. This can be used as the &dma_buf_ops.vmap | ||
400 | * callback. | ||
401 | * | ||
402 | * Returns the kernel virtual address. | ||
403 | */ | ||
404 | void *drm_gem_dmabuf_vmap(struct dma_buf *dma_buf) | ||
352 | { | 405 | { |
353 | struct drm_gem_object *obj = dma_buf->priv; | 406 | struct drm_gem_object *obj = dma_buf->priv; |
354 | struct drm_device *dev = obj->dev; | 407 | struct drm_device *dev = obj->dev; |
355 | 408 | ||
356 | return dev->driver->gem_prime_vmap(obj); | 409 | return dev->driver->gem_prime_vmap(obj); |
357 | } | 410 | } |
411 | EXPORT_SYMBOL(drm_gem_dmabuf_vmap); | ||
358 | 412 | ||
359 | static void drm_gem_dmabuf_vunmap(struct dma_buf *dma_buf, void *vaddr) | 413 | /** |
414 | * drm_gem_dmabuf_vunmap - dma_buf vunmap implementation for GEM | ||
415 | * @dma_buf: buffer to be unmapped | ||
416 | * @vaddr: the virtual address of the buffer | ||
417 | * | ||
418 | * Releases a kernel virtual mapping. This can be used as the | ||
419 | * &dma_buf_ops.vunmap callback. | ||
420 | */ | ||
421 | void drm_gem_dmabuf_vunmap(struct dma_buf *dma_buf, void *vaddr) | ||
360 | { | 422 | { |
361 | struct drm_gem_object *obj = dma_buf->priv; | 423 | struct drm_gem_object *obj = dma_buf->priv; |
362 | struct drm_device *dev = obj->dev; | 424 | struct drm_device *dev = obj->dev; |
363 | 425 | ||
364 | dev->driver->gem_prime_vunmap(obj, vaddr); | 426 | dev->driver->gem_prime_vunmap(obj, vaddr); |
365 | } | 427 | } |
428 | EXPORT_SYMBOL(drm_gem_dmabuf_vunmap); | ||
366 | 429 | ||
367 | static void *drm_gem_dmabuf_kmap_atomic(struct dma_buf *dma_buf, | 430 | /** |
368 | unsigned long page_num) | 431 | * drm_gem_dmabuf_kmap_atomic - map_atomic implementation for GEM |
432 | * | ||
433 | * Not implemented. This can be used as the &dma_buf_ops.map_atomic callback. | ||
434 | */ | ||
435 | void *drm_gem_dmabuf_kmap_atomic(struct dma_buf *dma_buf, | ||
436 | unsigned long page_num) | ||
369 | { | 437 | { |
370 | return NULL; | 438 | return NULL; |
371 | } | 439 | } |
440 | EXPORT_SYMBOL(drm_gem_dmabuf_kmap_atomic); | ||
372 | 441 | ||
373 | static void drm_gem_dmabuf_kunmap_atomic(struct dma_buf *dma_buf, | 442 | /** |
374 | unsigned long page_num, void *addr) | 443 | * drm_gem_dmabuf_kunmap_atomic - unmap_atomic implementation for GEM |
444 | * | ||
445 | * Not implemented. This can be used as the &dma_buf_ops.unmap_atomic callback. | ||
446 | */ | ||
447 | void drm_gem_dmabuf_kunmap_atomic(struct dma_buf *dma_buf, | ||
448 | unsigned long page_num, void *addr) | ||
375 | { | 449 | { |
376 | 450 | ||
377 | } | 451 | } |
378 | static void *drm_gem_dmabuf_kmap(struct dma_buf *dma_buf, | 452 | EXPORT_SYMBOL(drm_gem_dmabuf_kunmap_atomic); |
379 | unsigned long page_num) | 453 | |
454 | /** | ||
455 | * drm_gem_dmabuf_kmap - map implementation for GEM | ||
456 | * | ||
457 | * Not implemented. This can be used as the &dma_buf_ops.map callback. | ||
458 | */ | ||
459 | void *drm_gem_dmabuf_kmap(struct dma_buf *dma_buf, unsigned long page_num) | ||
380 | { | 460 | { |
381 | return NULL; | 461 | return NULL; |
382 | } | 462 | } |
463 | EXPORT_SYMBOL(drm_gem_dmabuf_kmap); | ||
383 | 464 | ||
384 | static void drm_gem_dmabuf_kunmap(struct dma_buf *dma_buf, | 465 | /** |
385 | unsigned long page_num, void *addr) | 466 | * drm_gem_dmabuf_kunmap - unmap implementation for GEM |
467 | * | ||
468 | * Not implemented. This can be used as the &dma_buf_ops.unmap callback. | ||
469 | */ | ||
470 | void drm_gem_dmabuf_kunmap(struct dma_buf *dma_buf, unsigned long page_num, | ||
471 | void *addr) | ||
386 | { | 472 | { |
387 | 473 | ||
388 | } | 474 | } |
475 | EXPORT_SYMBOL(drm_gem_dmabuf_kunmap); | ||
389 | 476 | ||
390 | static int drm_gem_dmabuf_mmap(struct dma_buf *dma_buf, | 477 | /** |
391 | struct vm_area_struct *vma) | 478 | * drm_gem_dmabuf_mmap - dma_buf mmap implementation for GEM |
479 | * @dma_buf: buffer to be mapped | ||
480 | * @vma: virtual address range | ||
481 | * | ||
482 | * Provides memory mapping for the buffer. This can be used as the | ||
483 | * &dma_buf_ops.mmap callback. | ||
484 | * | ||
485 | * Returns 0 on success or a negative error code on failure. | ||
486 | */ | ||
487 | int drm_gem_dmabuf_mmap(struct dma_buf *dma_buf, struct vm_area_struct *vma) | ||
392 | { | 488 | { |
393 | struct drm_gem_object *obj = dma_buf->priv; | 489 | struct drm_gem_object *obj = dma_buf->priv; |
394 | struct drm_device *dev = obj->dev; | 490 | struct drm_device *dev = obj->dev; |
@@ -398,6 +494,7 @@ static int drm_gem_dmabuf_mmap(struct dma_buf *dma_buf, | |||
398 | 494 | ||
399 | return dev->driver->gem_prime_mmap(obj, vma); | 495 | return dev->driver->gem_prime_mmap(obj, vma); |
400 | } | 496 | } |
497 | EXPORT_SYMBOL(drm_gem_dmabuf_mmap); | ||
401 | 498 | ||
402 | static const struct dma_buf_ops drm_gem_prime_dmabuf_ops = { | 499 | static const struct dma_buf_ops drm_gem_prime_dmabuf_ops = { |
403 | .attach = drm_gem_map_attach, | 500 | .attach = drm_gem_map_attach, |
diff --git a/drivers/gpu/drm/drm_probe_helper.c b/drivers/gpu/drm/drm_probe_helper.c index 555fbe54d6e2..2d1643bdae78 100644 --- a/drivers/gpu/drm/drm_probe_helper.c +++ b/drivers/gpu/drm/drm_probe_helper.c | |||
@@ -499,7 +499,7 @@ retry: | |||
499 | 499 | ||
500 | list_for_each_entry(mode, &connector->modes, head) { | 500 | list_for_each_entry(mode, &connector->modes, head) { |
501 | if (mode->status == MODE_OK) | 501 | if (mode->status == MODE_OK) |
502 | mode->status = drm_mode_validate_basic(mode); | 502 | mode->status = drm_mode_validate_driver(dev, mode); |
503 | 503 | ||
504 | if (mode->status == MODE_OK) | 504 | if (mode->status == MODE_OK) |
505 | mode->status = drm_mode_validate_size(mode, maxX, maxY); | 505 | mode->status = drm_mode_validate_size(mode, maxX, maxY); |
diff --git a/drivers/gpu/drm/drm_simple_kms_helper.c b/drivers/gpu/drm/drm_simple_kms_helper.c index 9f3b1c94802b..9d3f6b70812c 100644 --- a/drivers/gpu/drm/drm_simple_kms_helper.c +++ b/drivers/gpu/drm/drm_simple_kms_helper.c | |||
@@ -100,8 +100,9 @@ static int drm_simple_kms_plane_atomic_check(struct drm_plane *plane, | |||
100 | if (!crtc_state->enable) | 100 | if (!crtc_state->enable) |
101 | return 0; /* nothing to check when disabling or disabled */ | 101 | return 0; /* nothing to check when disabling or disabled */ |
102 | 102 | ||
103 | clip.x2 = crtc_state->adjusted_mode.hdisplay; | 103 | if (crtc_state->enable) |
104 | clip.y2 = crtc_state->adjusted_mode.vdisplay; | 104 | drm_mode_get_hv_timing(&crtc_state->mode, |
105 | &clip.x2, &clip.y2); | ||
105 | 106 | ||
106 | ret = drm_atomic_helper_check_plane_state(plane_state, crtc_state, | 107 | ret = drm_atomic_helper_check_plane_state(plane_state, crtc_state, |
107 | &clip, | 108 | &clip, |
diff --git a/drivers/gpu/drm/exynos/exynos_mixer.c b/drivers/gpu/drm/exynos/exynos_mixer.c index dc5d79465f9b..257299ec95c4 100644 --- a/drivers/gpu/drm/exynos/exynos_mixer.c +++ b/drivers/gpu/drm/exynos/exynos_mixer.c | |||
@@ -179,18 +179,6 @@ static const u8 filter_cr_horiz_tap4[] = { | |||
179 | 70, 59, 48, 37, 27, 19, 11, 5, | 179 | 70, 59, 48, 37, 27, 19, 11, 5, |
180 | }; | 180 | }; |
181 | 181 | ||
182 | static inline bool is_alpha_format(unsigned int pixel_format) | ||
183 | { | ||
184 | switch (pixel_format) { | ||
185 | case DRM_FORMAT_ARGB8888: | ||
186 | case DRM_FORMAT_ARGB1555: | ||
187 | case DRM_FORMAT_ARGB4444: | ||
188 | return true; | ||
189 | default: | ||
190 | return false; | ||
191 | } | ||
192 | } | ||
193 | |||
194 | static inline u32 vp_reg_read(struct mixer_context *ctx, u32 reg_id) | 182 | static inline u32 vp_reg_read(struct mixer_context *ctx, u32 reg_id) |
195 | { | 183 | { |
196 | return readl(ctx->vp_regs + reg_id); | 184 | return readl(ctx->vp_regs + reg_id); |
@@ -625,7 +613,7 @@ static void mixer_graph_buffer(struct mixer_context *ctx, | |||
625 | mixer_reg_write(ctx, MXR_GRAPHIC_BASE(win), dma_addr); | 613 | mixer_reg_write(ctx, MXR_GRAPHIC_BASE(win), dma_addr); |
626 | 614 | ||
627 | mixer_cfg_layer(ctx, win, priority, true); | 615 | mixer_cfg_layer(ctx, win, priority, true); |
628 | mixer_cfg_gfx_blend(ctx, win, is_alpha_format(fb->format->format)); | 616 | mixer_cfg_gfx_blend(ctx, win, fb->format->has_alpha); |
629 | 617 | ||
630 | /* layer update mandatory for mixer 16.0.33.0 */ | 618 | /* layer update mandatory for mixer 16.0.33.0 */ |
631 | if (ctx->mxr_ver == MXR_VER_16_0_33_0 || | 619 | if (ctx->mxr_ver == MXR_VER_16_0_33_0 || |
diff --git a/drivers/gpu/drm/i2c/sil164_drv.c b/drivers/gpu/drm/i2c/sil164_drv.c index ecaa58757529..c52d7a3af786 100644 --- a/drivers/gpu/drm/i2c/sil164_drv.c +++ b/drivers/gpu/drm/i2c/sil164_drv.c | |||
@@ -326,8 +326,7 @@ sil164_encoder_destroy(struct drm_encoder *encoder) | |||
326 | { | 326 | { |
327 | struct sil164_priv *priv = to_sil164_priv(encoder); | 327 | struct sil164_priv *priv = to_sil164_priv(encoder); |
328 | 328 | ||
329 | if (priv->duallink_slave) | 329 | i2c_unregister_device(priv->duallink_slave); |
330 | i2c_unregister_device(priv->duallink_slave); | ||
331 | 330 | ||
332 | kfree(priv); | 331 | kfree(priv); |
333 | drm_i2c_encoder_destroy(encoder); | 332 | drm_i2c_encoder_destroy(encoder); |
diff --git a/drivers/gpu/drm/i2c/tda998x_drv.c b/drivers/gpu/drm/i2c/tda998x_drv.c index cd3f0873bbdd..9e67a7b4e3a4 100644 --- a/drivers/gpu/drm/i2c/tda998x_drv.c +++ b/drivers/gpu/drm/i2c/tda998x_drv.c | |||
@@ -1600,8 +1600,7 @@ fail: | |||
1600 | /* if encoder_init fails, the encoder slave is never registered, | 1600 | /* if encoder_init fails, the encoder slave is never registered, |
1601 | * so cleanup here: | 1601 | * so cleanup here: |
1602 | */ | 1602 | */ |
1603 | if (priv->cec) | 1603 | i2c_unregister_device(priv->cec); |
1604 | i2c_unregister_device(priv->cec); | ||
1605 | return -ENXIO; | 1604 | return -ENXIO; |
1606 | } | 1605 | } |
1607 | 1606 | ||
diff --git a/drivers/gpu/drm/i915/intel_atomic_plane.c b/drivers/gpu/drm/i915/intel_atomic_plane.c index 57ee8b786cd8..0ee32275994a 100644 --- a/drivers/gpu/drm/i915/intel_atomic_plane.c +++ b/drivers/gpu/drm/i915/intel_atomic_plane.c | |||
@@ -128,14 +128,6 @@ int intel_plane_atomic_check_with_state(const struct intel_crtc_state *old_crtc_ | |||
128 | if (!intel_state->base.crtc && !old_plane_state->base.crtc) | 128 | if (!intel_state->base.crtc && !old_plane_state->base.crtc) |
129 | return 0; | 129 | return 0; |
130 | 130 | ||
131 | /* Clip all planes to CRTC size, or 0x0 if CRTC is disabled */ | ||
132 | intel_state->clip.x1 = 0; | ||
133 | intel_state->clip.y1 = 0; | ||
134 | intel_state->clip.x2 = | ||
135 | crtc_state->base.enable ? crtc_state->pipe_src_w : 0; | ||
136 | intel_state->clip.y2 = | ||
137 | crtc_state->base.enable ? crtc_state->pipe_src_h : 0; | ||
138 | |||
139 | if (state->fb && drm_rotation_90_or_270(state->rotation)) { | 131 | if (state->fb && drm_rotation_90_or_270(state->rotation)) { |
140 | struct drm_format_name_buf format_name; | 132 | struct drm_format_name_buf format_name; |
141 | 133 | ||
diff --git a/drivers/gpu/drm/i915/intel_crt.c b/drivers/gpu/drm/i915/intel_crt.c index 9f31aea51dff..1cd4a7c22bd5 100644 --- a/drivers/gpu/drm/i915/intel_crt.c +++ b/drivers/gpu/drm/i915/intel_crt.c | |||
@@ -304,9 +304,6 @@ intel_crt_mode_valid(struct drm_connector *connector, | |||
304 | int max_dotclk = dev_priv->max_dotclk_freq; | 304 | int max_dotclk = dev_priv->max_dotclk_freq; |
305 | int max_clock; | 305 | int max_clock; |
306 | 306 | ||
307 | if (mode->flags & DRM_MODE_FLAG_DBLSCAN) | ||
308 | return MODE_NO_DBLESCAN; | ||
309 | |||
310 | if (mode->clock < 25000) | 307 | if (mode->clock < 25000) |
311 | return MODE_CLOCK_LOW; | 308 | return MODE_CLOCK_LOW; |
312 | 309 | ||
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index e9bba2ab4904..15523f0e3b44 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c | |||
@@ -6404,9 +6404,18 @@ static int intel_crtc_compute_config(struct intel_crtc *crtc, | |||
6404 | * - LVDS dual channel mode | 6404 | * - LVDS dual channel mode |
6405 | * - Double wide pipe | 6405 | * - Double wide pipe |
6406 | */ | 6406 | */ |
6407 | if ((intel_crtc_has_type(pipe_config, INTEL_OUTPUT_LVDS) && | 6407 | if (pipe_config->pipe_src_w & 1) { |
6408 | intel_is_dual_link_lvds(dev)) || pipe_config->double_wide) | 6408 | if (pipe_config->double_wide) { |
6409 | pipe_config->pipe_src_w &= ~1; | 6409 | DRM_DEBUG_KMS("Odd pipe source width not supported with double wide pipe\n"); |
6410 | return -EINVAL; | ||
6411 | } | ||
6412 | |||
6413 | if (intel_crtc_has_type(pipe_config, INTEL_OUTPUT_LVDS) && | ||
6414 | intel_is_dual_link_lvds(dev)) { | ||
6415 | DRM_DEBUG_KMS("Odd pipe source width not supported with dual link LVDS\n"); | ||
6416 | return -EINVAL; | ||
6417 | } | ||
6418 | } | ||
6410 | 6419 | ||
6411 | /* Cantiga+ cannot handle modes with a hsync front porch of 0. | 6420 | /* Cantiga+ cannot handle modes with a hsync front porch of 0. |
6412 | * WaPruneModeWithIncorrectHsyncOffset:ctg,elk,ilk,snb,ivb,vlv,hsw. | 6421 | * WaPruneModeWithIncorrectHsyncOffset:ctg,elk,ilk,snb,ivb,vlv,hsw. |
@@ -9343,13 +9352,18 @@ static int intel_check_cursor(struct intel_crtc_state *crtc_state, | |||
9343 | struct intel_plane_state *plane_state) | 9352 | struct intel_plane_state *plane_state) |
9344 | { | 9353 | { |
9345 | const struct drm_framebuffer *fb = plane_state->base.fb; | 9354 | const struct drm_framebuffer *fb = plane_state->base.fb; |
9355 | struct drm_rect clip = {}; | ||
9346 | int src_x, src_y; | 9356 | int src_x, src_y; |
9347 | u32 offset; | 9357 | u32 offset; |
9348 | int ret; | 9358 | int ret; |
9349 | 9359 | ||
9360 | if (crtc_state->base.enable) | ||
9361 | drm_mode_get_hv_timing(&crtc_state->base.mode, | ||
9362 | &clip.x2, &clip.y2); | ||
9363 | |||
9350 | ret = drm_atomic_helper_check_plane_state(&plane_state->base, | 9364 | ret = drm_atomic_helper_check_plane_state(&plane_state->base, |
9351 | &crtc_state->base, | 9365 | &crtc_state->base, |
9352 | &plane_state->clip, | 9366 | &clip, |
9353 | DRM_PLANE_HELPER_NO_SCALING, | 9367 | DRM_PLANE_HELPER_NO_SCALING, |
9354 | DRM_PLANE_HELPER_NO_SCALING, | 9368 | DRM_PLANE_HELPER_NO_SCALING, |
9355 | true, true); | 9369 | true, true); |
@@ -12784,6 +12798,7 @@ intel_check_primary_plane(struct intel_plane *plane, | |||
12784 | int min_scale = DRM_PLANE_HELPER_NO_SCALING; | 12798 | int min_scale = DRM_PLANE_HELPER_NO_SCALING; |
12785 | int max_scale = DRM_PLANE_HELPER_NO_SCALING; | 12799 | int max_scale = DRM_PLANE_HELPER_NO_SCALING; |
12786 | bool can_position = false; | 12800 | bool can_position = false; |
12801 | struct drm_rect clip = {}; | ||
12787 | int ret; | 12802 | int ret; |
12788 | 12803 | ||
12789 | if (INTEL_GEN(dev_priv) >= 9) { | 12804 | if (INTEL_GEN(dev_priv) >= 9) { |
@@ -12795,9 +12810,13 @@ intel_check_primary_plane(struct intel_plane *plane, | |||
12795 | can_position = true; | 12810 | can_position = true; |
12796 | } | 12811 | } |
12797 | 12812 | ||
12813 | if (crtc_state->base.enable) | ||
12814 | drm_mode_get_hv_timing(&crtc_state->base.mode, | ||
12815 | &clip.x2, &clip.y2); | ||
12816 | |||
12798 | ret = drm_atomic_helper_check_plane_state(&state->base, | 12817 | ret = drm_atomic_helper_check_plane_state(&state->base, |
12799 | &crtc_state->base, | 12818 | &crtc_state->base, |
12800 | &state->clip, | 12819 | &clip, |
12801 | min_scale, max_scale, | 12820 | min_scale, max_scale, |
12802 | can_position, true); | 12821 | can_position, true); |
12803 | if (ret) | 12822 | if (ret) |
@@ -14097,10 +14116,37 @@ static void intel_atomic_state_free(struct drm_atomic_state *state) | |||
14097 | kfree(state); | 14116 | kfree(state); |
14098 | } | 14117 | } |
14099 | 14118 | ||
14119 | static enum drm_mode_status | ||
14120 | intel_mode_valid(struct drm_device *dev, | ||
14121 | const struct drm_display_mode *mode) | ||
14122 | { | ||
14123 | if (mode->vscan > 1) | ||
14124 | return MODE_NO_VSCAN; | ||
14125 | |||
14126 | if (mode->flags & DRM_MODE_FLAG_DBLSCAN) | ||
14127 | return MODE_NO_DBLESCAN; | ||
14128 | |||
14129 | if (mode->flags & DRM_MODE_FLAG_HSKEW) | ||
14130 | return MODE_H_ILLEGAL; | ||
14131 | |||
14132 | if (mode->flags & (DRM_MODE_FLAG_CSYNC | | ||
14133 | DRM_MODE_FLAG_NCSYNC | | ||
14134 | DRM_MODE_FLAG_PCSYNC)) | ||
14135 | return MODE_HSYNC; | ||
14136 | |||
14137 | if (mode->flags & (DRM_MODE_FLAG_BCAST | | ||
14138 | DRM_MODE_FLAG_PIXMUX | | ||
14139 | DRM_MODE_FLAG_CLKDIV2)) | ||
14140 | return MODE_BAD; | ||
14141 | |||
14142 | return MODE_OK; | ||
14143 | } | ||
14144 | |||
14100 | static const struct drm_mode_config_funcs intel_mode_funcs = { | 14145 | static const struct drm_mode_config_funcs intel_mode_funcs = { |
14101 | .fb_create = intel_user_framebuffer_create, | 14146 | .fb_create = intel_user_framebuffer_create, |
14102 | .get_format_info = intel_get_format_info, | 14147 | .get_format_info = intel_get_format_info, |
14103 | .output_poll_changed = intel_fbdev_output_poll_changed, | 14148 | .output_poll_changed = intel_fbdev_output_poll_changed, |
14149 | .mode_valid = intel_mode_valid, | ||
14104 | .atomic_check = intel_atomic_check, | 14150 | .atomic_check = intel_atomic_check, |
14105 | .atomic_commit = intel_atomic_commit, | 14151 | .atomic_commit = intel_atomic_commit, |
14106 | .atomic_state_alloc = intel_atomic_state_alloc, | 14152 | .atomic_state_alloc = intel_atomic_state_alloc, |
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 71355fdec94a..cdcbeb595bb1 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h | |||
@@ -406,7 +406,6 @@ struct intel_atomic_state { | |||
406 | 406 | ||
407 | struct intel_plane_state { | 407 | struct intel_plane_state { |
408 | struct drm_plane_state base; | 408 | struct drm_plane_state base; |
409 | struct drm_rect clip; | ||
410 | struct i915_vma *vma; | 409 | struct i915_vma *vma; |
411 | 410 | ||
412 | struct { | 411 | struct { |
diff --git a/drivers/gpu/drm/i915/intel_dsi.c b/drivers/gpu/drm/i915/intel_dsi.c index f67d321376e4..51a1d6868b1e 100644 --- a/drivers/gpu/drm/i915/intel_dsi.c +++ b/drivers/gpu/drm/i915/intel_dsi.c | |||
@@ -1266,11 +1266,6 @@ intel_dsi_mode_valid(struct drm_connector *connector, | |||
1266 | 1266 | ||
1267 | DRM_DEBUG_KMS("\n"); | 1267 | DRM_DEBUG_KMS("\n"); |
1268 | 1268 | ||
1269 | if (mode->flags & DRM_MODE_FLAG_DBLSCAN) { | ||
1270 | DRM_DEBUG_KMS("MODE_NO_DBLESCAN\n"); | ||
1271 | return MODE_NO_DBLESCAN; | ||
1272 | } | ||
1273 | |||
1274 | if (fixed_mode) { | 1269 | if (fixed_mode) { |
1275 | if (mode->hdisplay > fixed_mode->hdisplay) | 1270 | if (mode->hdisplay > fixed_mode->hdisplay) |
1276 | return MODE_PANEL; | 1271 | return MODE_PANEL; |
diff --git a/drivers/gpu/drm/i915/intel_dvo.c b/drivers/gpu/drm/i915/intel_dvo.c index 754baa00bea9..59c066ca14e5 100644 --- a/drivers/gpu/drm/i915/intel_dvo.c +++ b/drivers/gpu/drm/i915/intel_dvo.c | |||
@@ -219,9 +219,6 @@ intel_dvo_mode_valid(struct drm_connector *connector, | |||
219 | int max_dotclk = to_i915(connector->dev)->max_dotclk_freq; | 219 | int max_dotclk = to_i915(connector->dev)->max_dotclk_freq; |
220 | int target_clock = mode->clock; | 220 | int target_clock = mode->clock; |
221 | 221 | ||
222 | if (mode->flags & DRM_MODE_FLAG_DBLSCAN) | ||
223 | return MODE_NO_DBLESCAN; | ||
224 | |||
225 | /* XXX: Validate clock range */ | 222 | /* XXX: Validate clock range */ |
226 | 223 | ||
227 | if (fixed_mode) { | 224 | if (fixed_mode) { |
diff --git a/drivers/gpu/drm/i915/intel_fbc.c b/drivers/gpu/drm/i915/intel_fbc.c index 80682a418a70..d7d1ac79c38a 100644 --- a/drivers/gpu/drm/i915/intel_fbc.c +++ b/drivers/gpu/drm/i915/intel_fbc.c | |||
@@ -799,8 +799,7 @@ static bool intel_fbc_can_activate(struct intel_crtc *crtc) | |||
799 | return false; | 799 | return false; |
800 | } | 800 | } |
801 | 801 | ||
802 | if ((cache->crtc.mode_flags & DRM_MODE_FLAG_INTERLACE) || | 802 | if (cache->crtc.mode_flags & DRM_MODE_FLAG_INTERLACE) { |
803 | (cache->crtc.mode_flags & DRM_MODE_FLAG_DBLSCAN)) { | ||
804 | fbc->no_fbc_reason = "incompatible mode"; | 803 | fbc->no_fbc_reason = "incompatible mode"; |
805 | return false; | 804 | return false; |
806 | } | 805 | } |
diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c index 2df18a85c3b4..23150f598dfa 100644 --- a/drivers/gpu/drm/i915/intel_hdmi.c +++ b/drivers/gpu/drm/i915/intel_hdmi.c | |||
@@ -1314,9 +1314,6 @@ intel_hdmi_mode_valid(struct drm_connector *connector, | |||
1314 | bool force_dvi = | 1314 | bool force_dvi = |
1315 | READ_ONCE(to_intel_digital_connector_state(connector->state)->force_audio) == HDMI_AUDIO_OFF_DVI; | 1315 | READ_ONCE(to_intel_digital_connector_state(connector->state)->force_audio) == HDMI_AUDIO_OFF_DVI; |
1316 | 1316 | ||
1317 | if (mode->flags & DRM_MODE_FLAG_DBLSCAN) | ||
1318 | return MODE_NO_DBLESCAN; | ||
1319 | |||
1320 | clock = mode->clock; | 1317 | clock = mode->clock; |
1321 | 1318 | ||
1322 | if ((mode->flags & DRM_MODE_FLAG_3D_MASK) == DRM_MODE_FLAG_3D_FRAME_PACKING) | 1319 | if ((mode->flags & DRM_MODE_FLAG_3D_MASK) == DRM_MODE_FLAG_3D_FRAME_PACKING) |
diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c index 2b8764897d68..0bf97ed5ffac 100644 --- a/drivers/gpu/drm/i915/intel_sdvo.c +++ b/drivers/gpu/drm/i915/intel_sdvo.c | |||
@@ -1607,9 +1607,6 @@ intel_sdvo_mode_valid(struct drm_connector *connector, | |||
1607 | struct intel_sdvo *intel_sdvo = intel_attached_sdvo(connector); | 1607 | struct intel_sdvo *intel_sdvo = intel_attached_sdvo(connector); |
1608 | int max_dotclk = to_i915(connector->dev)->max_dotclk_freq; | 1608 | int max_dotclk = to_i915(connector->dev)->max_dotclk_freq; |
1609 | 1609 | ||
1610 | if (mode->flags & DRM_MODE_FLAG_DBLSCAN) | ||
1611 | return MODE_NO_DBLESCAN; | ||
1612 | |||
1613 | if (intel_sdvo->pixel_clock_min > mode->clock) | 1610 | if (intel_sdvo->pixel_clock_min > mode->clock) |
1614 | return MODE_CLOCK_LOW; | 1611 | return MODE_CLOCK_LOW; |
1615 | 1612 | ||
diff --git a/drivers/gpu/drm/i915/intel_sprite.c b/drivers/gpu/drm/i915/intel_sprite.c index 32f10621fac8..3be22c0fcfb5 100644 --- a/drivers/gpu/drm/i915/intel_sprite.c +++ b/drivers/gpu/drm/i915/intel_sprite.c | |||
@@ -864,7 +864,7 @@ intel_check_sprite_plane(struct intel_plane *plane, | |||
864 | uint32_t src_x, src_y, src_w, src_h; | 864 | uint32_t src_x, src_y, src_w, src_h; |
865 | struct drm_rect *src = &state->base.src; | 865 | struct drm_rect *src = &state->base.src; |
866 | struct drm_rect *dst = &state->base.dst; | 866 | struct drm_rect *dst = &state->base.dst; |
867 | const struct drm_rect *clip = &state->clip; | 867 | struct drm_rect clip = {}; |
868 | int max_stride = INTEL_GEN(dev_priv) >= 9 ? 32768 : 16384; | 868 | int max_stride = INTEL_GEN(dev_priv) >= 9 ? 32768 : 16384; |
869 | int hscale, vscale; | 869 | int hscale, vscale; |
870 | int max_scale, min_scale; | 870 | int max_scale, min_scale; |
@@ -923,7 +923,11 @@ intel_check_sprite_plane(struct intel_plane *plane, | |||
923 | vscale = drm_rect_calc_vscale_relaxed(src, dst, min_scale, max_scale); | 923 | vscale = drm_rect_calc_vscale_relaxed(src, dst, min_scale, max_scale); |
924 | BUG_ON(vscale < 0); | 924 | BUG_ON(vscale < 0); |
925 | 925 | ||
926 | state->base.visible = drm_rect_clip_scaled(src, dst, clip, hscale, vscale); | 926 | if (crtc_state->base.enable) |
927 | drm_mode_get_hv_timing(&crtc_state->base.mode, | ||
928 | &clip.x2, &clip.y2); | ||
929 | |||
930 | state->base.visible = drm_rect_clip_scaled(src, dst, &clip, hscale, vscale); | ||
927 | 931 | ||
928 | crtc_x = dst->x1; | 932 | crtc_x = dst->x1; |
929 | crtc_y = dst->y1; | 933 | crtc_y = dst->y1; |
diff --git a/drivers/gpu/drm/imx/ipuv3-plane.c b/drivers/gpu/drm/imx/ipuv3-plane.c index 57ed56d8623f..150628293c51 100644 --- a/drivers/gpu/drm/imx/ipuv3-plane.c +++ b/drivers/gpu/drm/imx/ipuv3-plane.c | |||
@@ -351,7 +351,7 @@ static int ipu_plane_atomic_check(struct drm_plane *plane, | |||
351 | struct drm_framebuffer *old_fb = old_state->fb; | 351 | struct drm_framebuffer *old_fb = old_state->fb; |
352 | unsigned long eba, ubo, vbo, old_ubo, old_vbo, alpha_eba; | 352 | unsigned long eba, ubo, vbo, old_ubo, old_vbo, alpha_eba; |
353 | bool can_position = (plane->type == DRM_PLANE_TYPE_OVERLAY); | 353 | bool can_position = (plane->type == DRM_PLANE_TYPE_OVERLAY); |
354 | struct drm_rect clip; | 354 | struct drm_rect clip = {}; |
355 | int hsub, vsub; | 355 | int hsub, vsub; |
356 | int ret; | 356 | int ret; |
357 | 357 | ||
@@ -367,10 +367,10 @@ static int ipu_plane_atomic_check(struct drm_plane *plane, | |||
367 | if (WARN_ON(!crtc_state)) | 367 | if (WARN_ON(!crtc_state)) |
368 | return -EINVAL; | 368 | return -EINVAL; |
369 | 369 | ||
370 | clip.x1 = 0; | 370 | if (crtc_state->enable) |
371 | clip.y1 = 0; | 371 | drm_mode_get_hv_timing(&crtc_state->mode, |
372 | clip.x2 = crtc_state->adjusted_mode.hdisplay; | 372 | &clip.x2, &clip.y2); |
373 | clip.y2 = crtc_state->adjusted_mode.vdisplay; | 373 | |
374 | ret = drm_atomic_helper_check_plane_state(state, crtc_state, &clip, | 374 | ret = drm_atomic_helper_check_plane_state(state, crtc_state, &clip, |
375 | DRM_PLANE_HELPER_NO_SCALING, | 375 | DRM_PLANE_HELPER_NO_SCALING, |
376 | DRM_PLANE_HELPER_NO_SCALING, | 376 | DRM_PLANE_HELPER_NO_SCALING, |
diff --git a/drivers/gpu/drm/mediatek/mtk_drm_plane.c b/drivers/gpu/drm/mediatek/mtk_drm_plane.c index 5ef898b93d8d..b5c6eec9a584 100644 --- a/drivers/gpu/drm/mediatek/mtk_drm_plane.c +++ b/drivers/gpu/drm/mediatek/mtk_drm_plane.c | |||
@@ -108,8 +108,9 @@ static int mtk_plane_atomic_check(struct drm_plane *plane, | |||
108 | if (IS_ERR(crtc_state)) | 108 | if (IS_ERR(crtc_state)) |
109 | return PTR_ERR(crtc_state); | 109 | return PTR_ERR(crtc_state); |
110 | 110 | ||
111 | clip.x2 = crtc_state->mode.hdisplay; | 111 | if (crtc_state->enable) |
112 | clip.y2 = crtc_state->mode.vdisplay; | 112 | drm_mode_get_hv_timing(&crtc_state->mode, |
113 | &clip.x2, &clip.y2); | ||
113 | 114 | ||
114 | return drm_atomic_helper_check_plane_state(state, crtc_state, &clip, | 115 | return drm_atomic_helper_check_plane_state(state, crtc_state, &clip, |
115 | DRM_PLANE_HELPER_NO_SCALING, | 116 | DRM_PLANE_HELPER_NO_SCALING, |
diff --git a/drivers/gpu/drm/meson/meson_plane.c b/drivers/gpu/drm/meson/meson_plane.c index d0a6ac8390f3..3801bee1f9e6 100644 --- a/drivers/gpu/drm/meson/meson_plane.c +++ b/drivers/gpu/drm/meson/meson_plane.c | |||
@@ -58,8 +58,9 @@ static int meson_plane_atomic_check(struct drm_plane *plane, | |||
58 | if (IS_ERR(crtc_state)) | 58 | if (IS_ERR(crtc_state)) |
59 | return PTR_ERR(crtc_state); | 59 | return PTR_ERR(crtc_state); |
60 | 60 | ||
61 | clip.x2 = crtc_state->mode.hdisplay; | 61 | if (crtc_state->enable) |
62 | clip.y2 = crtc_state->mode.vdisplay; | 62 | drm_mode_get_hv_timing(&crtc_state->mode, |
63 | &clip.x2, &clip.y2); | ||
63 | 64 | ||
64 | return drm_atomic_helper_check_plane_state(state, crtc_state, &clip, | 65 | return drm_atomic_helper_check_plane_state(state, crtc_state, &clip, |
65 | DRM_PLANE_HELPER_NO_SCALING, | 66 | DRM_PLANE_HELPER_NO_SCALING, |
diff --git a/drivers/gpu/drm/mgag200/mgag200_mode.c b/drivers/gpu/drm/mgag200/mgag200_mode.c index 68e5d9c94475..fb50a9ddaae8 100644 --- a/drivers/gpu/drm/mgag200/mgag200_mode.c +++ b/drivers/gpu/drm/mgag200/mgag200_mode.c | |||
@@ -1620,8 +1620,8 @@ static int mga_vga_mode_valid(struct drm_connector *connector, | |||
1620 | return MODE_VIRTUAL_X; | 1620 | return MODE_VIRTUAL_X; |
1621 | if (mode->vdisplay > 1024) | 1621 | if (mode->vdisplay > 1024) |
1622 | return MODE_VIRTUAL_Y; | 1622 | return MODE_VIRTUAL_Y; |
1623 | if (mga_vga_calculate_mode_bandwidth(mode, | 1623 | if (mga_vga_calculate_mode_bandwidth(mode, bpp) > |
1624 | bpp > (31877 * 1024))) | 1624 | (31877 * 1024)) |
1625 | return MODE_BANDWIDTH; | 1625 | return MODE_BANDWIDTH; |
1626 | } else if (mdev->type == G200_EV && | 1626 | } else if (mdev->type == G200_EV && |
1627 | (mga_vga_calculate_mode_bandwidth(mode, bpp) | 1627 | (mga_vga_calculate_mode_bandwidth(mode, bpp) |
diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c index 29678876fc09..98d4d7331767 100644 --- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c +++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c | |||
@@ -286,7 +286,7 @@ static int mdp5_plane_atomic_check_with_state(struct drm_crtc_state *crtc_state, | |||
286 | uint32_t max_width, max_height; | 286 | uint32_t max_width, max_height; |
287 | bool out_of_bounds = false; | 287 | bool out_of_bounds = false; |
288 | uint32_t caps = 0; | 288 | uint32_t caps = 0; |
289 | struct drm_rect clip; | 289 | struct drm_rect clip = {}; |
290 | int min_scale, max_scale; | 290 | int min_scale, max_scale; |
291 | int ret; | 291 | int ret; |
292 | 292 | ||
@@ -320,13 +320,13 @@ static int mdp5_plane_atomic_check_with_state(struct drm_crtc_state *crtc_state, | |||
320 | return -ERANGE; | 320 | return -ERANGE; |
321 | } | 321 | } |
322 | 322 | ||
323 | clip.x1 = 0; | ||
324 | clip.y1 = 0; | ||
325 | clip.x2 = crtc_state->adjusted_mode.hdisplay; | ||
326 | clip.y2 = crtc_state->adjusted_mode.vdisplay; | ||
327 | min_scale = FRAC_16_16(1, 8); | 323 | min_scale = FRAC_16_16(1, 8); |
328 | max_scale = FRAC_16_16(8, 1); | 324 | max_scale = FRAC_16_16(8, 1); |
329 | 325 | ||
326 | if (crtc_state->enable) | ||
327 | drm_mode_get_hv_timing(&crtc_state->mode, | ||
328 | &clip.x2, &clip.y2); | ||
329 | |||
330 | ret = drm_atomic_helper_check_plane_state(state, crtc_state, &clip, | 330 | ret = drm_atomic_helper_check_plane_state(state, crtc_state, &clip, |
331 | min_scale, max_scale, | 331 | min_scale, max_scale, |
332 | true, true); | 332 | true, true); |
@@ -471,7 +471,7 @@ static int mdp5_plane_atomic_async_check(struct drm_plane *plane, | |||
471 | { | 471 | { |
472 | struct mdp5_plane_state *mdp5_state = to_mdp5_plane_state(state); | 472 | struct mdp5_plane_state *mdp5_state = to_mdp5_plane_state(state); |
473 | struct drm_crtc_state *crtc_state; | 473 | struct drm_crtc_state *crtc_state; |
474 | struct drm_rect clip; | 474 | struct drm_rect clip = {}; |
475 | int min_scale, max_scale; | 475 | int min_scale, max_scale; |
476 | int ret; | 476 | int ret; |
477 | 477 | ||
@@ -499,13 +499,13 @@ static int mdp5_plane_atomic_async_check(struct drm_plane *plane, | |||
499 | plane->state->fb != state->fb) | 499 | plane->state->fb != state->fb) |
500 | return -EINVAL; | 500 | return -EINVAL; |
501 | 501 | ||
502 | clip.x1 = 0; | ||
503 | clip.y1 = 0; | ||
504 | clip.x2 = crtc_state->adjusted_mode.hdisplay; | ||
505 | clip.y2 = crtc_state->adjusted_mode.vdisplay; | ||
506 | min_scale = FRAC_16_16(1, 8); | 502 | min_scale = FRAC_16_16(1, 8); |
507 | max_scale = FRAC_16_16(8, 1); | 503 | max_scale = FRAC_16_16(8, 1); |
508 | 504 | ||
505 | if (crtc_state->enable) | ||
506 | drm_mode_get_hv_timing(&crtc_state->mode, | ||
507 | &clip.x2, &clip.y2); | ||
508 | |||
509 | ret = drm_atomic_helper_check_plane_state(state, crtc_state, &clip, | 509 | ret = drm_atomic_helper_check_plane_state(state, crtc_state, &clip, |
510 | min_scale, max_scale, | 510 | min_scale, max_scale, |
511 | true, true); | 511 | true, true); |
diff --git a/drivers/gpu/drm/nouveau/nv50_display.c b/drivers/gpu/drm/nouveau/nv50_display.c index dd8d4352ed99..1f55b3d80a56 100644 --- a/drivers/gpu/drm/nouveau/nv50_display.c +++ b/drivers/gpu/drm/nouveau/nv50_display.c | |||
@@ -232,8 +232,6 @@ struct nv50_wndw_atom { | |||
232 | struct drm_plane_state state; | 232 | struct drm_plane_state state; |
233 | u8 interval; | 233 | u8 interval; |
234 | 234 | ||
235 | struct drm_rect clip; | ||
236 | |||
237 | struct { | 235 | struct { |
238 | u32 handle; | 236 | u32 handle; |
239 | u16 offset:12; | 237 | u16 offset:12; |
@@ -848,10 +846,6 @@ nv50_wndw_atomic_check_acquire(struct nv50_wndw *wndw, | |||
848 | int ret; | 846 | int ret; |
849 | 847 | ||
850 | NV_ATOMIC(drm, "%s acquire\n", wndw->plane.name); | 848 | NV_ATOMIC(drm, "%s acquire\n", wndw->plane.name); |
851 | asyw->clip.x1 = 0; | ||
852 | asyw->clip.y1 = 0; | ||
853 | asyw->clip.x2 = asyh->state.mode.hdisplay; | ||
854 | asyw->clip.y2 = asyh->state.mode.vdisplay; | ||
855 | 849 | ||
856 | asyw->image.w = fb->base.width; | 850 | asyw->image.w = fb->base.width; |
857 | asyw->image.h = fb->base.height; | 851 | asyw->image.h = fb->base.height; |
@@ -1149,10 +1143,15 @@ static int | |||
1149 | nv50_curs_acquire(struct nv50_wndw *wndw, struct nv50_wndw_atom *asyw, | 1143 | nv50_curs_acquire(struct nv50_wndw *wndw, struct nv50_wndw_atom *asyw, |
1150 | struct nv50_head_atom *asyh) | 1144 | struct nv50_head_atom *asyh) |
1151 | { | 1145 | { |
1146 | struct drm_rect clip = {}; | ||
1152 | int ret; | 1147 | int ret; |
1153 | 1148 | ||
1149 | if (asyh->state.enable) | ||
1150 | drm_mode_get_hv_timing(&asyh->state.mode, | ||
1151 | &clip.x2, &clip.y2); | ||
1152 | |||
1154 | ret = drm_atomic_helper_check_plane_state(&asyw->state, &asyh->state, | 1153 | ret = drm_atomic_helper_check_plane_state(&asyw->state, &asyh->state, |
1155 | &asyw->clip, | 1154 | &clip, |
1156 | DRM_PLANE_HELPER_NO_SCALING, | 1155 | DRM_PLANE_HELPER_NO_SCALING, |
1157 | DRM_PLANE_HELPER_NO_SCALING, | 1156 | DRM_PLANE_HELPER_NO_SCALING, |
1158 | true, true); | 1157 | true, true); |
@@ -1436,13 +1435,18 @@ nv50_base_acquire(struct nv50_wndw *wndw, struct nv50_wndw_atom *asyw, | |||
1436 | struct nv50_head_atom *asyh) | 1435 | struct nv50_head_atom *asyh) |
1437 | { | 1436 | { |
1438 | const struct drm_framebuffer *fb = asyw->state.fb; | 1437 | const struct drm_framebuffer *fb = asyw->state.fb; |
1438 | struct drm_rect clip = {}; | ||
1439 | int ret; | 1439 | int ret; |
1440 | 1440 | ||
1441 | if (!fb->format->depth) | 1441 | if (!fb->format->depth) |
1442 | return -EINVAL; | 1442 | return -EINVAL; |
1443 | 1443 | ||
1444 | if (asyh->state.enable) | ||
1445 | drm_mode_get_hv_timing(&asyh->state.mode, | ||
1446 | &clip.x2, &clip.y2); | ||
1447 | |||
1444 | ret = drm_atomic_helper_check_plane_state(&asyw->state, &asyh->state, | 1448 | ret = drm_atomic_helper_check_plane_state(&asyw->state, &asyh->state, |
1445 | &asyw->clip, | 1449 | &clip, |
1446 | DRM_PLANE_HELPER_NO_SCALING, | 1450 | DRM_PLANE_HELPER_NO_SCALING, |
1447 | DRM_PLANE_HELPER_NO_SCALING, | 1451 | DRM_PLANE_HELPER_NO_SCALING, |
1448 | false, true); | 1452 | false, true); |
diff --git a/drivers/gpu/drm/panel/Kconfig b/drivers/gpu/drm/panel/Kconfig index 6ba4031f3919..988048ebcc22 100644 --- a/drivers/gpu/drm/panel/Kconfig +++ b/drivers/gpu/drm/panel/Kconfig | |||
@@ -7,6 +7,16 @@ config DRM_PANEL | |||
7 | menu "Display Panels" | 7 | menu "Display Panels" |
8 | depends on DRM && DRM_PANEL | 8 | depends on DRM && DRM_PANEL |
9 | 9 | ||
10 | config DRM_PANEL_ARM_VERSATILE | ||
11 | tristate "ARM Versatile panel driver" | ||
12 | depends on OF | ||
13 | depends on MFD_SYSCON | ||
14 | select VIDEOMODE_HELPERS | ||
15 | help | ||
16 | This driver supports the ARM Versatile panels connected to ARM | ||
17 | reference designs. The panel is detected using special registers | ||
18 | in the Versatile family syscon registers. | ||
19 | |||
10 | config DRM_PANEL_LVDS | 20 | config DRM_PANEL_LVDS |
11 | tristate "Generic LVDS panel driver" | 21 | tristate "Generic LVDS panel driver" |
12 | depends on OF | 22 | depends on OF |
diff --git a/drivers/gpu/drm/panel/Makefile b/drivers/gpu/drm/panel/Makefile index 6d251ebc568c..3d2a88d0e965 100644 --- a/drivers/gpu/drm/panel/Makefile +++ b/drivers/gpu/drm/panel/Makefile | |||
@@ -1,4 +1,5 @@ | |||
1 | # SPDX-License-Identifier: GPL-2.0 | 1 | # SPDX-License-Identifier: GPL-2.0 |
2 | obj-$(CONFIG_DRM_PANEL_ARM_VERSATILE) += panel-arm-versatile.o | ||
2 | obj-$(CONFIG_DRM_PANEL_LVDS) += panel-lvds.o | 3 | obj-$(CONFIG_DRM_PANEL_LVDS) += panel-lvds.o |
3 | obj-$(CONFIG_DRM_PANEL_SIMPLE) += panel-simple.o | 4 | obj-$(CONFIG_DRM_PANEL_SIMPLE) += panel-simple.o |
4 | obj-$(CONFIG_DRM_PANEL_ILITEK_IL9322) += panel-ilitek-ili9322.o | 5 | obj-$(CONFIG_DRM_PANEL_ILITEK_IL9322) += panel-ilitek-ili9322.o |
diff --git a/drivers/gpu/drm/panel/panel-arm-versatile.c b/drivers/gpu/drm/panel/panel-arm-versatile.c new file mode 100644 index 000000000000..3930b4925b15 --- /dev/null +++ b/drivers/gpu/drm/panel/panel-arm-versatile.c | |||
@@ -0,0 +1,377 @@ | |||
1 | // SPDX-License-Identifier: GPL-2.0 | ||
2 | /* | ||
3 | * Panel driver for the ARM Versatile family reference designs from | ||
4 | * ARM Limited. | ||
5 | * | ||
6 | * Author: | ||
7 | * Linus Walleij <linus.wallei@linaro.org> | ||
8 | * | ||
9 | * On the Versatile AB, these panels come mounted on daughterboards | ||
10 | * named "IB1" or "IB2" (Interface Board 1 & 2 respectively.) They | ||
11 | * are documented in ARM DUI 0225D Appendix C and D. These daughter | ||
12 | * boards support TFT display panels. | ||
13 | * | ||
14 | * - The IB1 is a passive board where the display connector defines a | ||
15 | * few wires for encoding the display type for autodetection, | ||
16 | * suitable display settings can then be looked up from this setting. | ||
17 | * The magic bits can be read out from the system controller. | ||
18 | * | ||
19 | * - The IB2 is a more complex board intended for GSM phone development | ||
20 | * with some logic and a control register, which needs to be accessed | ||
21 | * and the board display needs to be turned on explicitly. | ||
22 | * | ||
23 | * On the Versatile PB, a special CLCD adaptor board is available | ||
24 | * supporting the same displays as the Versatile AB, plus one more | ||
25 | * Epson QCIF display. | ||
26 | * | ||
27 | */ | ||
28 | #include <drm/drmP.h> | ||
29 | #include <drm/drm_panel.h> | ||
30 | |||
31 | #include <linux/bitops.h> | ||
32 | #include <linux/init.h> | ||
33 | #include <linux/kernel.h> | ||
34 | #include <linux/mfd/syscon.h> | ||
35 | #include <linux/module.h> | ||
36 | #include <linux/platform_device.h> | ||
37 | #include <linux/regmap.h> | ||
38 | |||
39 | #include <video/of_videomode.h> | ||
40 | #include <video/videomode.h> | ||
41 | |||
42 | /* | ||
43 | * This configuration register in the Versatile and RealView | ||
44 | * family is uniformly present but appears more and more | ||
45 | * unutilized starting with the RealView series. | ||
46 | */ | ||
47 | #define SYS_CLCD 0x50 | ||
48 | |||
49 | /* The Versatile can detect the connected panel type */ | ||
50 | #define SYS_CLCD_CLCDID_MASK (BIT(8)|BIT(9)|BIT(10)|BIT(11)|BIT(12)) | ||
51 | #define SYS_CLCD_ID_SANYO_3_8 (0x00 << 8) | ||
52 | #define SYS_CLCD_ID_SHARP_8_4 (0x01 << 8) | ||
53 | #define SYS_CLCD_ID_EPSON_2_2 (0x02 << 8) | ||
54 | #define SYS_CLCD_ID_SANYO_2_5 (0x07 << 8) | ||
55 | #define SYS_CLCD_ID_VGA (0x1f << 8) | ||
56 | |||
57 | /* IB2 control register for the Versatile daughterboard */ | ||
58 | #define IB2_CTRL 0x00 | ||
59 | #define IB2_CTRL_LCD_SD BIT(1) /* 1 = shut down LCD */ | ||
60 | #define IB2_CTRL_LCD_BL_ON BIT(0) | ||
61 | #define IB2_CTRL_LCD_MASK (BIT(0)|BIT(1)) | ||
62 | |||
63 | /** | ||
64 | * struct versatile_panel_type - lookup struct for the supported panels | ||
65 | */ | ||
66 | struct versatile_panel_type { | ||
67 | /** | ||
68 | * @name: the name of this panel | ||
69 | */ | ||
70 | const char *name; | ||
71 | /** | ||
72 | * @magic: the magic value from the detection register | ||
73 | */ | ||
74 | u32 magic; | ||
75 | /** | ||
76 | * @mode: the DRM display mode for this panel | ||
77 | */ | ||
78 | struct drm_display_mode mode; | ||
79 | /** | ||
80 | * @bus_flags: the DRM bus flags for this panel e.g. inverted clock | ||
81 | */ | ||
82 | u32 bus_flags; | ||
83 | /** | ||
84 | * @width_mm: the panel width in mm | ||
85 | */ | ||
86 | u32 width_mm; | ||
87 | /** | ||
88 | * @height_mm: the panel height in mm | ||
89 | */ | ||
90 | u32 height_mm; | ||
91 | /** | ||
92 | * @ib2: the panel may be connected on an IB2 daughterboard | ||
93 | */ | ||
94 | bool ib2; | ||
95 | }; | ||
96 | |||
97 | /** | ||
98 | * struct versatile_panel - state container for the Versatile panels | ||
99 | */ | ||
100 | struct versatile_panel { | ||
101 | /** | ||
102 | * @dev: the container device | ||
103 | */ | ||
104 | struct device *dev; | ||
105 | /** | ||
106 | * @panel: the DRM panel instance for this device | ||
107 | */ | ||
108 | struct drm_panel panel; | ||
109 | /** | ||
110 | * @panel_type: the Versatile panel type as detected | ||
111 | */ | ||
112 | const struct versatile_panel_type *panel_type; | ||
113 | /** | ||
114 | * @map: map to the parent syscon where the main register reside | ||
115 | */ | ||
116 | struct regmap *map; | ||
117 | /** | ||
118 | * @ib2_map: map to the IB2 syscon, if applicable | ||
119 | */ | ||
120 | struct regmap *ib2_map; | ||
121 | }; | ||
122 | |||
123 | static const struct versatile_panel_type versatile_panels[] = { | ||
124 | /* | ||
125 | * Sanyo TM38QV67A02A - 3.8 inch QVGA (320x240) Color TFT | ||
126 | * found on the Versatile AB IB1 connector or the Versatile | ||
127 | * PB adaptor board connector. | ||
128 | */ | ||
129 | { | ||
130 | .name = "Sanyo TM38QV67A02A", | ||
131 | .magic = SYS_CLCD_ID_SANYO_3_8, | ||
132 | .width_mm = 79, | ||
133 | .height_mm = 54, | ||
134 | .mode = { | ||
135 | .clock = 10000000, | ||
136 | .hdisplay = 320, | ||
137 | .hsync_start = 320 + 6, | ||
138 | .hsync_end = 320 + 6 + 6, | ||
139 | .htotal = 320 + 6 + 6 + 6, | ||
140 | .vdisplay = 240, | ||
141 | .vsync_start = 240 + 5, | ||
142 | .vsync_end = 240 + 5 + 6, | ||
143 | .vtotal = 240 + 5 + 6 + 5, | ||
144 | .vrefresh = 116, | ||
145 | .flags = DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC, | ||
146 | }, | ||
147 | }, | ||
148 | /* | ||
149 | * Sharp LQ084V1DG21 640x480 VGA Color TFT module | ||
150 | * found on the Versatile AB IB1 connector or the Versatile | ||
151 | * PB adaptor board connector. | ||
152 | */ | ||
153 | { | ||
154 | .name = "Sharp LQ084V1DG21", | ||
155 | .magic = SYS_CLCD_ID_SHARP_8_4, | ||
156 | .width_mm = 171, | ||
157 | .height_mm = 130, | ||
158 | .mode = { | ||
159 | .clock = 25000000, | ||
160 | .hdisplay = 640, | ||
161 | .hsync_start = 640 + 24, | ||
162 | .hsync_end = 640 + 24 + 96, | ||
163 | .htotal = 640 + 24 + 96 + 24, | ||
164 | .vdisplay = 480, | ||
165 | .vsync_start = 480 + 11, | ||
166 | .vsync_end = 480 + 11 + 2, | ||
167 | .vtotal = 480 + 11 + 2 + 32, | ||
168 | .vrefresh = 60, | ||
169 | .flags = DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC, | ||
170 | }, | ||
171 | }, | ||
172 | /* | ||
173 | * Epson L2F50113T00 - 2.2 inch QCIF 176x220 Color TFT | ||
174 | * found on the Versatile PB adaptor board connector. | ||
175 | */ | ||
176 | { | ||
177 | .name = "Epson L2F50113T00", | ||
178 | .magic = SYS_CLCD_ID_EPSON_2_2, | ||
179 | .width_mm = 34, | ||
180 | .height_mm = 45, | ||
181 | .mode = { | ||
182 | .clock = 625000000, | ||
183 | .hdisplay = 176, | ||
184 | .hsync_start = 176 + 2, | ||
185 | .hsync_end = 176 + 2 + 3, | ||
186 | .htotal = 176 + 2 + 3 + 3, | ||
187 | .vdisplay = 220, | ||
188 | .vsync_start = 220 + 0, | ||
189 | .vsync_end = 220 + 0 + 2, | ||
190 | .vtotal = 220 + 0 + 2 + 1, | ||
191 | .vrefresh = 390, | ||
192 | .flags = DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC, | ||
193 | }, | ||
194 | .bus_flags = DRM_BUS_FLAG_PIXDATA_NEGEDGE, | ||
195 | }, | ||
196 | /* | ||
197 | * Sanyo ALR252RGT 240x320 portrait display found on the | ||
198 | * Versatile AB IB2 daughterboard for GSM prototyping. | ||
199 | */ | ||
200 | { | ||
201 | .name = "Sanyo ALR252RGT", | ||
202 | .magic = SYS_CLCD_ID_SANYO_2_5, | ||
203 | .width_mm = 37, | ||
204 | .height_mm = 50, | ||
205 | .mode = { | ||
206 | .clock = 5400000, | ||
207 | .hdisplay = 240, | ||
208 | .hsync_start = 240 + 10, | ||
209 | .hsync_end = 240 + 10 + 10, | ||
210 | .htotal = 240 + 10 + 10 + 20, | ||
211 | .vdisplay = 320, | ||
212 | .vsync_start = 320 + 2, | ||
213 | .vsync_end = 320 + 2 + 2, | ||
214 | .vtotal = 320 + 2 + 2 + 2, | ||
215 | .vrefresh = 116, | ||
216 | .flags = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC, | ||
217 | }, | ||
218 | .bus_flags = DRM_BUS_FLAG_PIXDATA_NEGEDGE, | ||
219 | .ib2 = true, | ||
220 | }, | ||
221 | }; | ||
222 | |||
223 | static inline struct versatile_panel * | ||
224 | to_versatile_panel(struct drm_panel *panel) | ||
225 | { | ||
226 | return container_of(panel, struct versatile_panel, panel); | ||
227 | } | ||
228 | |||
229 | static int versatile_panel_disable(struct drm_panel *panel) | ||
230 | { | ||
231 | struct versatile_panel *vpanel = to_versatile_panel(panel); | ||
232 | |||
233 | /* If we're on an IB2 daughterboard, turn off display */ | ||
234 | if (vpanel->ib2_map) { | ||
235 | dev_dbg(vpanel->dev, "disable IB2 display\n"); | ||
236 | regmap_update_bits(vpanel->ib2_map, | ||
237 | IB2_CTRL, | ||
238 | IB2_CTRL_LCD_MASK, | ||
239 | IB2_CTRL_LCD_SD); | ||
240 | } | ||
241 | |||
242 | return 0; | ||
243 | } | ||
244 | |||
245 | static int versatile_panel_enable(struct drm_panel *panel) | ||
246 | { | ||
247 | struct versatile_panel *vpanel = to_versatile_panel(panel); | ||
248 | |||
249 | /* If we're on an IB2 daughterboard, turn on display */ | ||
250 | if (vpanel->ib2_map) { | ||
251 | dev_dbg(vpanel->dev, "enable IB2 display\n"); | ||
252 | regmap_update_bits(vpanel->ib2_map, | ||
253 | IB2_CTRL, | ||
254 | IB2_CTRL_LCD_MASK, | ||
255 | IB2_CTRL_LCD_BL_ON); | ||
256 | } | ||
257 | |||
258 | return 0; | ||
259 | } | ||
260 | |||
261 | static int versatile_panel_get_modes(struct drm_panel *panel) | ||
262 | { | ||
263 | struct drm_connector *connector = panel->connector; | ||
264 | struct versatile_panel *vpanel = to_versatile_panel(panel); | ||
265 | struct drm_display_mode *mode; | ||
266 | |||
267 | strncpy(connector->display_info.name, vpanel->panel_type->name, | ||
268 | DRM_DISPLAY_INFO_LEN); | ||
269 | connector->display_info.width_mm = vpanel->panel_type->width_mm; | ||
270 | connector->display_info.height_mm = vpanel->panel_type->height_mm; | ||
271 | connector->display_info.bus_flags = vpanel->panel_type->bus_flags; | ||
272 | |||
273 | mode = drm_mode_duplicate(panel->drm, &vpanel->panel_type->mode); | ||
274 | drm_mode_set_name(mode); | ||
275 | mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED; | ||
276 | |||
277 | mode->width_mm = vpanel->panel_type->width_mm; | ||
278 | mode->height_mm = vpanel->panel_type->height_mm; | ||
279 | drm_mode_probed_add(connector, mode); | ||
280 | |||
281 | return 1; | ||
282 | } | ||
283 | |||
284 | static const struct drm_panel_funcs versatile_panel_drm_funcs = { | ||
285 | .disable = versatile_panel_disable, | ||
286 | .enable = versatile_panel_enable, | ||
287 | .get_modes = versatile_panel_get_modes, | ||
288 | }; | ||
289 | |||
290 | static int versatile_panel_probe(struct platform_device *pdev) | ||
291 | { | ||
292 | struct device *dev = &pdev->dev; | ||
293 | struct versatile_panel *vpanel; | ||
294 | struct device *parent; | ||
295 | struct regmap *map; | ||
296 | int ret; | ||
297 | u32 val; | ||
298 | int i; | ||
299 | |||
300 | parent = dev->parent; | ||
301 | if (!parent) { | ||
302 | dev_err(dev, "no parent for versatile panel\n"); | ||
303 | return -ENODEV; | ||
304 | } | ||
305 | map = syscon_node_to_regmap(parent->of_node); | ||
306 | if (IS_ERR(map)) { | ||
307 | dev_err(dev, "no regmap for versatile panel parent\n"); | ||
308 | return PTR_ERR(map); | ||
309 | } | ||
310 | |||
311 | vpanel = devm_kzalloc(dev, sizeof(*vpanel), GFP_KERNEL); | ||
312 | if (!vpanel) | ||
313 | return -ENOMEM; | ||
314 | |||
315 | ret = regmap_read(map, SYS_CLCD, &val); | ||
316 | if (ret) { | ||
317 | dev_err(dev, "cannot access syscon regs\n"); | ||
318 | return ret; | ||
319 | } | ||
320 | |||
321 | val &= SYS_CLCD_CLCDID_MASK; | ||
322 | |||
323 | for (i = 0; i < ARRAY_SIZE(versatile_panels); i++) { | ||
324 | const struct versatile_panel_type *pt; | ||
325 | |||
326 | pt = &versatile_panels[i]; | ||
327 | if (pt->magic == val) { | ||
328 | vpanel->panel_type = pt; | ||
329 | break; | ||
330 | } | ||
331 | } | ||
332 | |||
333 | /* No panel detected or VGA, let's leave this show */ | ||
334 | if (i == ARRAY_SIZE(versatile_panels)) { | ||
335 | dev_info(dev, "no panel detected\n"); | ||
336 | return -ENODEV; | ||
337 | } | ||
338 | |||
339 | dev_info(dev, "detected: %s\n", vpanel->panel_type->name); | ||
340 | vpanel->dev = dev; | ||
341 | vpanel->map = map; | ||
342 | |||
343 | /* Check if the panel is mounted on an IB2 daughterboard */ | ||
344 | if (vpanel->panel_type->ib2) { | ||
345 | vpanel->ib2_map = syscon_regmap_lookup_by_compatible( | ||
346 | "arm,versatile-ib2-syscon"); | ||
347 | if (IS_ERR(vpanel->ib2_map)) | ||
348 | vpanel->ib2_map = NULL; | ||
349 | else | ||
350 | dev_info(dev, "panel mounted on IB2 daughterboard\n"); | ||
351 | } | ||
352 | |||
353 | drm_panel_init(&vpanel->panel); | ||
354 | vpanel->panel.dev = dev; | ||
355 | vpanel->panel.funcs = &versatile_panel_drm_funcs; | ||
356 | |||
357 | return drm_panel_add(&vpanel->panel); | ||
358 | } | ||
359 | |||
360 | static const struct of_device_id versatile_panel_match[] = { | ||
361 | { .compatible = "arm,versatile-tft-panel", }, | ||
362 | {}, | ||
363 | }; | ||
364 | MODULE_DEVICE_TABLE(of, versatile_panel_match); | ||
365 | |||
366 | static struct platform_driver versatile_panel_driver = { | ||
367 | .probe = versatile_panel_probe, | ||
368 | .driver = { | ||
369 | .name = "versatile-tft-panel", | ||
370 | .of_match_table = versatile_panel_match, | ||
371 | }, | ||
372 | }; | ||
373 | module_platform_driver(versatile_panel_driver); | ||
374 | |||
375 | MODULE_AUTHOR("Linus Walleij <linus.walleij@linaro.org>"); | ||
376 | MODULE_DESCRIPTION("ARM Versatile panel driver"); | ||
377 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/drivers/gpu/drm/panel/panel-panasonic-vvx10f034n00.c b/drivers/gpu/drm/panel/panel-panasonic-vvx10f034n00.c index 7f915f706fa6..74a806121f80 100644 --- a/drivers/gpu/drm/panel/panel-panasonic-vvx10f034n00.c +++ b/drivers/gpu/drm/panel/panel-panasonic-vvx10f034n00.c | |||
@@ -59,34 +59,28 @@ static inline struct wuxga_nt_panel *to_wuxga_nt_panel(struct drm_panel *panel) | |||
59 | 59 | ||
60 | static int wuxga_nt_panel_on(struct wuxga_nt_panel *wuxga_nt) | 60 | static int wuxga_nt_panel_on(struct wuxga_nt_panel *wuxga_nt) |
61 | { | 61 | { |
62 | struct mipi_dsi_device *dsi = wuxga_nt->dsi; | 62 | return mipi_dsi_turn_on_peripheral(wuxga_nt->dsi); |
63 | int ret; | ||
64 | |||
65 | ret = mipi_dsi_turn_on_peripheral(dsi); | ||
66 | if (ret < 0) | ||
67 | return ret; | ||
68 | |||
69 | return 0; | ||
70 | } | 63 | } |
71 | 64 | ||
72 | static int wuxga_nt_panel_disable(struct drm_panel *panel) | 65 | static int wuxga_nt_panel_disable(struct drm_panel *panel) |
73 | { | 66 | { |
74 | struct wuxga_nt_panel *wuxga_nt = to_wuxga_nt_panel(panel); | 67 | struct wuxga_nt_panel *wuxga_nt = to_wuxga_nt_panel(panel); |
68 | int mipi_ret, bl_ret = 0; | ||
75 | 69 | ||
76 | if (!wuxga_nt->enabled) | 70 | if (!wuxga_nt->enabled) |
77 | return 0; | 71 | return 0; |
78 | 72 | ||
79 | mipi_dsi_shutdown_peripheral(wuxga_nt->dsi); | 73 | mipi_ret = mipi_dsi_shutdown_peripheral(wuxga_nt->dsi); |
80 | 74 | ||
81 | if (wuxga_nt->backlight) { | 75 | if (wuxga_nt->backlight) { |
82 | wuxga_nt->backlight->props.power = FB_BLANK_POWERDOWN; | 76 | wuxga_nt->backlight->props.power = FB_BLANK_POWERDOWN; |
83 | wuxga_nt->backlight->props.state |= BL_CORE_FBBLANK; | 77 | wuxga_nt->backlight->props.state |= BL_CORE_FBBLANK; |
84 | backlight_update_status(wuxga_nt->backlight); | 78 | bl_ret = backlight_update_status(wuxga_nt->backlight); |
85 | } | 79 | } |
86 | 80 | ||
87 | wuxga_nt->enabled = false; | 81 | wuxga_nt->enabled = false; |
88 | 82 | ||
89 | return 0; | 83 | return mipi_ret ? mipi_ret : bl_ret; |
90 | } | 84 | } |
91 | 85 | ||
92 | static int wuxga_nt_panel_unprepare(struct drm_panel *panel) | 86 | static int wuxga_nt_panel_unprepare(struct drm_panel *panel) |
diff --git a/drivers/gpu/drm/pl111/Kconfig b/drivers/gpu/drm/pl111/Kconfig index e5e2abd66491..82cb3e60ddc8 100644 --- a/drivers/gpu/drm/pl111/Kconfig +++ b/drivers/gpu/drm/pl111/Kconfig | |||
@@ -8,6 +8,7 @@ config DRM_PL111 | |||
8 | select DRM_GEM_CMA_HELPER | 8 | select DRM_GEM_CMA_HELPER |
9 | select DRM_BRIDGE | 9 | select DRM_BRIDGE |
10 | select DRM_PANEL_BRIDGE | 10 | select DRM_PANEL_BRIDGE |
11 | select DRM_DUMB_VGA_DAC | ||
11 | select VT_HW_CONSOLE_BINDING if FRAMEBUFFER_CONSOLE | 12 | select VT_HW_CONSOLE_BINDING if FRAMEBUFFER_CONSOLE |
12 | help | 13 | help |
13 | Choose this option for DRM support for the PL111 CLCD controller. | 14 | Choose this option for DRM support for the PL111 CLCD controller. |
diff --git a/drivers/gpu/drm/pl111/pl111_display.c b/drivers/gpu/drm/pl111/pl111_display.c index 06c4bf756b69..d75923896609 100644 --- a/drivers/gpu/drm/pl111/pl111_display.c +++ b/drivers/gpu/drm/pl111/pl111_display.c | |||
@@ -94,6 +94,7 @@ static void pl111_display_enable(struct drm_simple_display_pipe *pipe, | |||
94 | const struct drm_display_mode *mode = &cstate->mode; | 94 | const struct drm_display_mode *mode = &cstate->mode; |
95 | struct drm_framebuffer *fb = plane->state->fb; | 95 | struct drm_framebuffer *fb = plane->state->fb; |
96 | struct drm_connector *connector = priv->connector; | 96 | struct drm_connector *connector = priv->connector; |
97 | struct drm_bridge *bridge = priv->bridge; | ||
97 | u32 cntl; | 98 | u32 cntl; |
98 | u32 ppl, hsw, hfp, hbp; | 99 | u32 ppl, hsw, hfp, hbp; |
99 | u32 lpp, vsw, vfp, vbp; | 100 | u32 lpp, vsw, vfp, vbp; |
@@ -137,17 +138,46 @@ static void pl111_display_enable(struct drm_simple_display_pipe *pipe, | |||
137 | tim2 = readl(priv->regs + CLCD_TIM2); | 138 | tim2 = readl(priv->regs + CLCD_TIM2); |
138 | tim2 &= (TIM2_BCD | TIM2_PCD_LO_MASK | TIM2_PCD_HI_MASK); | 139 | tim2 &= (TIM2_BCD | TIM2_PCD_LO_MASK | TIM2_PCD_HI_MASK); |
139 | 140 | ||
141 | if (priv->variant->broken_clockdivider) | ||
142 | tim2 |= TIM2_BCD; | ||
143 | |||
140 | if (mode->flags & DRM_MODE_FLAG_NHSYNC) | 144 | if (mode->flags & DRM_MODE_FLAG_NHSYNC) |
141 | tim2 |= TIM2_IHS; | 145 | tim2 |= TIM2_IHS; |
142 | 146 | ||
143 | if (mode->flags & DRM_MODE_FLAG_NVSYNC) | 147 | if (mode->flags & DRM_MODE_FLAG_NVSYNC) |
144 | tim2 |= TIM2_IVS; | 148 | tim2 |= TIM2_IVS; |
145 | 149 | ||
146 | if (connector->display_info.bus_flags & DRM_BUS_FLAG_DE_LOW) | 150 | if (connector) { |
147 | tim2 |= TIM2_IOE; | 151 | if (connector->display_info.bus_flags & DRM_BUS_FLAG_DE_LOW) |
152 | tim2 |= TIM2_IOE; | ||
148 | 153 | ||
149 | if (connector->display_info.bus_flags & DRM_BUS_FLAG_PIXDATA_NEGEDGE) | 154 | if (connector->display_info.bus_flags & |
150 | tim2 |= TIM2_IPC; | 155 | DRM_BUS_FLAG_PIXDATA_NEGEDGE) |
156 | tim2 |= TIM2_IPC; | ||
157 | } | ||
158 | |||
159 | if (bridge) { | ||
160 | const struct drm_bridge_timings *btimings = bridge->timings; | ||
161 | |||
162 | /* | ||
163 | * Here is when things get really fun. Sometimes the bridge | ||
164 | * timings are such that the signal out from PL11x is not | ||
165 | * stable before the receiving bridge (such as a dumb VGA DAC | ||
166 | * or similar) samples it. If that happens, we compensate by | ||
167 | * the only method we have: output the data on the opposite | ||
168 | * edge of the clock so it is for sure stable when it gets | ||
169 | * sampled. | ||
170 | * | ||
171 | * The PL111 manual does not contain proper timining diagrams | ||
172 | * or data for these details, but we know from experiments | ||
173 | * that the setup time is more than 3000 picoseconds (3 ns). | ||
174 | * If we have a bridge that requires the signal to be stable | ||
175 | * earlier than 3000 ps before the clock pulse, we have to | ||
176 | * output the data on the opposite edge to avoid flicker. | ||
177 | */ | ||
178 | if (btimings && btimings->setup_time_ps >= 3000) | ||
179 | tim2 ^= TIM2_IPC; | ||
180 | } | ||
151 | 181 | ||
152 | tim2 |= cpl << 16; | 182 | tim2 |= cpl << 16; |
153 | writel(tim2, priv->regs + CLCD_TIM2); | 183 | writel(tim2, priv->regs + CLCD_TIM2); |
@@ -172,10 +202,17 @@ static void pl111_display_enable(struct drm_simple_display_pipe *pipe, | |||
172 | cntl |= CNTL_LCDBPP24 | CNTL_BGR; | 202 | cntl |= CNTL_LCDBPP24 | CNTL_BGR; |
173 | break; | 203 | break; |
174 | case DRM_FORMAT_BGR565: | 204 | case DRM_FORMAT_BGR565: |
175 | cntl |= CNTL_LCDBPP16_565; | 205 | if (priv->variant->is_pl110) |
206 | cntl |= CNTL_LCDBPP16; | ||
207 | else | ||
208 | cntl |= CNTL_LCDBPP16_565; | ||
176 | break; | 209 | break; |
177 | case DRM_FORMAT_RGB565: | 210 | case DRM_FORMAT_RGB565: |
178 | cntl |= CNTL_LCDBPP16_565 | CNTL_BGR; | 211 | if (priv->variant->is_pl110) |
212 | cntl |= CNTL_LCDBPP16; | ||
213 | else | ||
214 | cntl |= CNTL_LCDBPP16_565; | ||
215 | cntl |= CNTL_BGR; | ||
179 | break; | 216 | break; |
180 | case DRM_FORMAT_ABGR1555: | 217 | case DRM_FORMAT_ABGR1555: |
181 | case DRM_FORMAT_XBGR1555: | 218 | case DRM_FORMAT_XBGR1555: |
@@ -199,6 +236,10 @@ static void pl111_display_enable(struct drm_simple_display_pipe *pipe, | |||
199 | break; | 236 | break; |
200 | } | 237 | } |
201 | 238 | ||
239 | /* The PL110 in Integrator/Versatile does the BGR routing externally */ | ||
240 | if (priv->variant->external_bgr) | ||
241 | cntl &= ~CNTL_BGR; | ||
242 | |||
202 | /* Power sequence: first enable and chill */ | 243 | /* Power sequence: first enable and chill */ |
203 | writel(cntl, priv->regs + priv->ctrl); | 244 | writel(cntl, priv->regs + priv->ctrl); |
204 | 245 | ||
@@ -215,7 +256,8 @@ static void pl111_display_enable(struct drm_simple_display_pipe *pipe, | |||
215 | cntl |= CNTL_LCDPWR; | 256 | cntl |= CNTL_LCDPWR; |
216 | writel(cntl, priv->regs + priv->ctrl); | 257 | writel(cntl, priv->regs + priv->ctrl); |
217 | 258 | ||
218 | drm_crtc_vblank_on(crtc); | 259 | if (!priv->variant->broken_vblank) |
260 | drm_crtc_vblank_on(crtc); | ||
219 | } | 261 | } |
220 | 262 | ||
221 | void pl111_display_disable(struct drm_simple_display_pipe *pipe) | 263 | void pl111_display_disable(struct drm_simple_display_pipe *pipe) |
@@ -225,7 +267,8 @@ void pl111_display_disable(struct drm_simple_display_pipe *pipe) | |||
225 | struct pl111_drm_dev_private *priv = drm->dev_private; | 267 | struct pl111_drm_dev_private *priv = drm->dev_private; |
226 | u32 cntl; | 268 | u32 cntl; |
227 | 269 | ||
228 | drm_crtc_vblank_off(crtc); | 270 | if (!priv->variant->broken_vblank) |
271 | drm_crtc_vblank_off(crtc); | ||
229 | 272 | ||
230 | /* Power Down */ | 273 | /* Power Down */ |
231 | cntl = readl(priv->regs + priv->ctrl); | 274 | cntl = readl(priv->regs + priv->ctrl); |
@@ -417,6 +460,11 @@ pl111_init_clock_divider(struct drm_device *drm) | |||
417 | dev_err(drm->dev, "CLCD: unable to get clcdclk.\n"); | 460 | dev_err(drm->dev, "CLCD: unable to get clcdclk.\n"); |
418 | return PTR_ERR(parent); | 461 | return PTR_ERR(parent); |
419 | } | 462 | } |
463 | /* If the clock divider is broken, use the parent directly */ | ||
464 | if (priv->variant->broken_clockdivider) { | ||
465 | priv->clk = parent; | ||
466 | return 0; | ||
467 | } | ||
420 | parent_name = __clk_get_name(parent); | 468 | parent_name = __clk_get_name(parent); |
421 | 469 | ||
422 | spin_lock_init(&priv->tim2_lock); | 470 | spin_lock_init(&priv->tim2_lock); |
diff --git a/drivers/gpu/drm/pl111/pl111_drm.h b/drivers/gpu/drm/pl111/pl111_drm.h index 07fa2cdb364a..6d0e450e51b1 100644 --- a/drivers/gpu/drm/pl111/pl111_drm.h +++ b/drivers/gpu/drm/pl111/pl111_drm.h | |||
@@ -36,12 +36,20 @@ struct drm_minor; | |||
36 | * struct pl111_variant_data - encodes IP differences | 36 | * struct pl111_variant_data - encodes IP differences |
37 | * @name: the name of this variant | 37 | * @name: the name of this variant |
38 | * @is_pl110: this is the early PL110 variant | 38 | * @is_pl110: this is the early PL110 variant |
39 | * @external_bgr: this is the Versatile Pl110 variant with external | ||
40 | * BGR/RGB routing | ||
41 | * @broken_clockdivider: the clock divider is broken and we need to | ||
42 | * use the supplied clock directly | ||
43 | * @broken_vblank: the vblank IRQ is broken on this variant | ||
39 | * @formats: array of supported pixel formats on this variant | 44 | * @formats: array of supported pixel formats on this variant |
40 | * @nformats: the length of the array of supported pixel formats | 45 | * @nformats: the length of the array of supported pixel formats |
41 | */ | 46 | */ |
42 | struct pl111_variant_data { | 47 | struct pl111_variant_data { |
43 | const char *name; | 48 | const char *name; |
44 | bool is_pl110; | 49 | bool is_pl110; |
50 | bool external_bgr; | ||
51 | bool broken_clockdivider; | ||
52 | bool broken_vblank; | ||
45 | const u32 *formats; | 53 | const u32 *formats; |
46 | unsigned int nformats; | 54 | unsigned int nformats; |
47 | }; | 55 | }; |
diff --git a/drivers/gpu/drm/pl111/pl111_drv.c b/drivers/gpu/drm/pl111/pl111_drv.c index acb738c69873..1231905150d0 100644 --- a/drivers/gpu/drm/pl111/pl111_drv.c +++ b/drivers/gpu/drm/pl111/pl111_drv.c | |||
@@ -58,6 +58,8 @@ | |||
58 | #include <linux/dma-buf.h> | 58 | #include <linux/dma-buf.h> |
59 | #include <linux/module.h> | 59 | #include <linux/module.h> |
60 | #include <linux/slab.h> | 60 | #include <linux/slab.h> |
61 | #include <linux/of.h> | ||
62 | #include <linux/of_graph.h> | ||
61 | 63 | ||
62 | #include <drm/drmP.h> | 64 | #include <drm/drmP.h> |
63 | #include <drm/drm_atomic_helper.h> | 65 | #include <drm/drm_atomic_helper.h> |
@@ -85,9 +87,13 @@ static int pl111_modeset_init(struct drm_device *dev) | |||
85 | { | 87 | { |
86 | struct drm_mode_config *mode_config; | 88 | struct drm_mode_config *mode_config; |
87 | struct pl111_drm_dev_private *priv = dev->dev_private; | 89 | struct pl111_drm_dev_private *priv = dev->dev_private; |
88 | struct drm_panel *panel; | 90 | struct device_node *np = dev->dev->of_node; |
89 | struct drm_bridge *bridge; | 91 | struct device_node *remote; |
92 | struct drm_panel *panel = NULL; | ||
93 | struct drm_bridge *bridge = NULL; | ||
94 | bool defer = false; | ||
90 | int ret = 0; | 95 | int ret = 0; |
96 | int i; | ||
91 | 97 | ||
92 | drm_mode_config_init(dev); | 98 | drm_mode_config_init(dev); |
93 | mode_config = &dev->mode_config; | 99 | mode_config = &dev->mode_config; |
@@ -97,10 +103,54 @@ static int pl111_modeset_init(struct drm_device *dev) | |||
97 | mode_config->min_height = 1; | 103 | mode_config->min_height = 1; |
98 | mode_config->max_height = 768; | 104 | mode_config->max_height = 768; |
99 | 105 | ||
100 | ret = drm_of_find_panel_or_bridge(dev->dev->of_node, | 106 | i = 0; |
101 | 0, 0, &panel, &bridge); | 107 | for_each_endpoint_of_node(np, remote) { |
102 | if (ret && ret != -ENODEV) | 108 | struct drm_panel *tmp_panel; |
103 | return ret; | 109 | struct drm_bridge *tmp_bridge; |
110 | |||
111 | dev_dbg(dev->dev, "checking endpoint %d\n", i); | ||
112 | |||
113 | ret = drm_of_find_panel_or_bridge(dev->dev->of_node, | ||
114 | 0, i, | ||
115 | &tmp_panel, | ||
116 | &tmp_bridge); | ||
117 | if (ret) { | ||
118 | if (ret == -EPROBE_DEFER) { | ||
119 | /* | ||
120 | * Something deferred, but that is often just | ||
121 | * another way of saying -ENODEV, but let's | ||
122 | * cast a vote for later deferral. | ||
123 | */ | ||
124 | defer = true; | ||
125 | } else if (ret != -ENODEV) { | ||
126 | /* Continue, maybe something else is working */ | ||
127 | dev_err(dev->dev, | ||
128 | "endpoint %d returns %d\n", i, ret); | ||
129 | } | ||
130 | } | ||
131 | |||
132 | if (tmp_panel) { | ||
133 | dev_info(dev->dev, | ||
134 | "found panel on endpoint %d\n", i); | ||
135 | panel = tmp_panel; | ||
136 | } | ||
137 | if (tmp_bridge) { | ||
138 | dev_info(dev->dev, | ||
139 | "found bridge on endpoint %d\n", i); | ||
140 | bridge = tmp_bridge; | ||
141 | } | ||
142 | |||
143 | i++; | ||
144 | } | ||
145 | |||
146 | /* | ||
147 | * If we can't find neither panel nor bridge on any of the | ||
148 | * endpoints, and any of them retured -EPROBE_DEFER, then | ||
149 | * let's defer this driver too. | ||
150 | */ | ||
151 | if ((!panel && !bridge) && defer) | ||
152 | return -EPROBE_DEFER; | ||
153 | |||
104 | if (panel) { | 154 | if (panel) { |
105 | bridge = drm_panel_bridge_add(panel, | 155 | bridge = drm_panel_bridge_add(panel, |
106 | DRM_MODE_CONNECTOR_Unknown); | 156 | DRM_MODE_CONNECTOR_Unknown); |
@@ -108,11 +158,17 @@ static int pl111_modeset_init(struct drm_device *dev) | |||
108 | ret = PTR_ERR(bridge); | 158 | ret = PTR_ERR(bridge); |
109 | goto out_config; | 159 | goto out_config; |
110 | } | 160 | } |
111 | /* | 161 | } else if (bridge) { |
112 | * TODO: when we are using a different bridge than a panel | 162 | dev_info(dev->dev, "Using non-panel bridge\n"); |
113 | * (such as a dumb VGA connector) we need to devise a different | 163 | } else { |
114 | * method to get the connector out of the bridge. | 164 | dev_err(dev->dev, "No bridge, exiting\n"); |
115 | */ | 165 | return -ENODEV; |
166 | } | ||
167 | |||
168 | priv->bridge = bridge; | ||
169 | if (panel) { | ||
170 | priv->panel = panel; | ||
171 | priv->connector = panel->connector; | ||
116 | } | 172 | } |
117 | 173 | ||
118 | ret = pl111_display_init(dev); | 174 | ret = pl111_display_init(dev); |
@@ -126,14 +182,12 @@ static int pl111_modeset_init(struct drm_device *dev) | |||
126 | if (ret) | 182 | if (ret) |
127 | return ret; | 183 | return ret; |
128 | 184 | ||
129 | priv->bridge = bridge; | 185 | if (!priv->variant->broken_vblank) { |
130 | priv->panel = panel; | 186 | ret = drm_vblank_init(dev, 1); |
131 | priv->connector = panel->connector; | 187 | if (ret != 0) { |
132 | 188 | dev_err(dev->dev, "Failed to init vblank\n"); | |
133 | ret = drm_vblank_init(dev, 1); | 189 | goto out_bridge; |
134 | if (ret != 0) { | 190 | } |
135 | dev_err(dev->dev, "Failed to init vblank\n"); | ||
136 | goto out_bridge; | ||
137 | } | 191 | } |
138 | 192 | ||
139 | drm_mode_config_reset(dev); | 193 | drm_mode_config_reset(dev); |
@@ -170,10 +224,6 @@ static struct drm_driver pl111_drm_driver = { | |||
170 | .dumb_create = drm_gem_cma_dumb_create, | 224 | .dumb_create = drm_gem_cma_dumb_create, |
171 | .gem_free_object_unlocked = drm_gem_cma_free_object, | 225 | .gem_free_object_unlocked = drm_gem_cma_free_object, |
172 | .gem_vm_ops = &drm_gem_cma_vm_ops, | 226 | .gem_vm_ops = &drm_gem_cma_vm_ops, |
173 | |||
174 | .enable_vblank = pl111_enable_vblank, | ||
175 | .disable_vblank = pl111_disable_vblank, | ||
176 | |||
177 | .prime_handle_to_fd = drm_gem_prime_handle_to_fd, | 227 | .prime_handle_to_fd = drm_gem_prime_handle_to_fd, |
178 | .prime_fd_to_handle = drm_gem_prime_fd_to_handle, | 228 | .prime_fd_to_handle = drm_gem_prime_fd_to_handle, |
179 | .gem_prime_import = drm_gem_prime_import, | 229 | .gem_prime_import = drm_gem_prime_import, |
@@ -191,7 +241,7 @@ static int pl111_amba_probe(struct amba_device *amba_dev, | |||
191 | { | 241 | { |
192 | struct device *dev = &amba_dev->dev; | 242 | struct device *dev = &amba_dev->dev; |
193 | struct pl111_drm_dev_private *priv; | 243 | struct pl111_drm_dev_private *priv; |
194 | struct pl111_variant_data *variant = id->data; | 244 | const struct pl111_variant_data *variant = id->data; |
195 | struct drm_device *drm; | 245 | struct drm_device *drm; |
196 | int ret; | 246 | int ret; |
197 | 247 | ||
@@ -199,6 +249,11 @@ static int pl111_amba_probe(struct amba_device *amba_dev, | |||
199 | if (!priv) | 249 | if (!priv) |
200 | return -ENOMEM; | 250 | return -ENOMEM; |
201 | 251 | ||
252 | if (!variant->broken_vblank) { | ||
253 | pl111_drm_driver.enable_vblank = pl111_enable_vblank; | ||
254 | pl111_drm_driver.disable_vblank = pl111_disable_vblank; | ||
255 | } | ||
256 | |||
202 | drm = drm_dev_alloc(&pl111_drm_driver, dev); | 257 | drm = drm_dev_alloc(&pl111_drm_driver, dev); |
203 | if (IS_ERR(drm)) | 258 | if (IS_ERR(drm)) |
204 | return PTR_ERR(drm); | 259 | return PTR_ERR(drm); |
@@ -207,27 +262,10 @@ static int pl111_amba_probe(struct amba_device *amba_dev, | |||
207 | drm->dev_private = priv; | 262 | drm->dev_private = priv; |
208 | priv->variant = variant; | 263 | priv->variant = variant; |
209 | 264 | ||
210 | /* | 265 | /* The two variants swap this register */ |
211 | * The PL110 and PL111 variants have two registers | ||
212 | * swapped: interrupt enable and control. For this reason | ||
213 | * we use offsets that we can change per variant. | ||
214 | */ | ||
215 | if (variant->is_pl110) { | 266 | if (variant->is_pl110) { |
216 | /* | 267 | priv->ienb = CLCD_PL110_IENB; |
217 | * The ARM Versatile boards are even more special: | 268 | priv->ctrl = CLCD_PL110_CNTL; |
218 | * their PrimeCell ID say they are PL110 but the | ||
219 | * control and interrupt enable registers are anyway | ||
220 | * swapped to the PL111 order so they are not following | ||
221 | * the PL110 datasheet. | ||
222 | */ | ||
223 | if (of_machine_is_compatible("arm,versatile-ab") || | ||
224 | of_machine_is_compatible("arm,versatile-pb")) { | ||
225 | priv->ienb = CLCD_PL111_IENB; | ||
226 | priv->ctrl = CLCD_PL111_CNTL; | ||
227 | } else { | ||
228 | priv->ienb = CLCD_PL110_IENB; | ||
229 | priv->ctrl = CLCD_PL110_CNTL; | ||
230 | } | ||
231 | } else { | 269 | } else { |
232 | priv->ienb = CLCD_PL111_IENB; | 270 | priv->ienb = CLCD_PL111_IENB; |
233 | priv->ctrl = CLCD_PL111_CNTL; | 271 | priv->ctrl = CLCD_PL111_CNTL; |
@@ -239,6 +277,11 @@ static int pl111_amba_probe(struct amba_device *amba_dev, | |||
239 | return PTR_ERR(priv->regs); | 277 | return PTR_ERR(priv->regs); |
240 | } | 278 | } |
241 | 279 | ||
280 | /* This may override some variant settings */ | ||
281 | ret = pl111_versatile_init(dev, priv); | ||
282 | if (ret) | ||
283 | goto dev_unref; | ||
284 | |||
242 | /* turn off interrupts before requesting the irq */ | 285 | /* turn off interrupts before requesting the irq */ |
243 | writel(0, priv->regs + priv->ienb); | 286 | writel(0, priv->regs + priv->ienb); |
244 | 287 | ||
@@ -249,10 +292,6 @@ static int pl111_amba_probe(struct amba_device *amba_dev, | |||
249 | return ret; | 292 | return ret; |
250 | } | 293 | } |
251 | 294 | ||
252 | ret = pl111_versatile_init(dev, priv); | ||
253 | if (ret) | ||
254 | goto dev_unref; | ||
255 | |||
256 | ret = pl111_modeset_init(drm); | 295 | ret = pl111_modeset_init(drm); |
257 | if (ret != 0) | 296 | if (ret != 0) |
258 | goto dev_unref; | 297 | goto dev_unref; |
@@ -284,8 +323,7 @@ static int pl111_amba_remove(struct amba_device *amba_dev) | |||
284 | } | 323 | } |
285 | 324 | ||
286 | /* | 325 | /* |
287 | * This variant exist in early versions like the ARM Integrator | 326 | * This early variant lacks the 565 and 444 pixel formats. |
288 | * and this version lacks the 565 and 444 pixel formats. | ||
289 | */ | 327 | */ |
290 | static const u32 pl110_pixel_formats[] = { | 328 | static const u32 pl110_pixel_formats[] = { |
291 | DRM_FORMAT_ABGR8888, | 329 | DRM_FORMAT_ABGR8888, |
diff --git a/drivers/gpu/drm/pl111/pl111_versatile.c b/drivers/gpu/drm/pl111/pl111_versatile.c index 97d4af6925a3..05a4b89e0934 100644 --- a/drivers/gpu/drm/pl111/pl111_versatile.c +++ b/drivers/gpu/drm/pl111/pl111_versatile.c | |||
@@ -1,3 +1,4 @@ | |||
1 | #include <linux/amba/clcd-regs.h> | ||
1 | #include <linux/device.h> | 2 | #include <linux/device.h> |
2 | #include <linux/of.h> | 3 | #include <linux/of.h> |
3 | #include <linux/regmap.h> | 4 | #include <linux/regmap.h> |
@@ -64,10 +65,8 @@ static const struct of_device_id versatile_clcd_of_match[] = { | |||
64 | #define INTEGRATOR_CLCD_LCDBIASEN BIT(8) | 65 | #define INTEGRATOR_CLCD_LCDBIASEN BIT(8) |
65 | #define INTEGRATOR_CLCD_LCDBIASUP BIT(9) | 66 | #define INTEGRATOR_CLCD_LCDBIASUP BIT(9) |
66 | #define INTEGRATOR_CLCD_LCDBIASDN BIT(10) | 67 | #define INTEGRATOR_CLCD_LCDBIASDN BIT(10) |
67 | /* Bits 11,12,13 controls the LCD type */ | 68 | /* Bits 11,12,13 controls the LCD or VGA bridge type */ |
68 | #define INTEGRATOR_CLCD_LCDMUX_MASK (BIT(11)|BIT(12)|BIT(13)) | ||
69 | #define INTEGRATOR_CLCD_LCDMUX_LCD24 BIT(11) | 69 | #define INTEGRATOR_CLCD_LCDMUX_LCD24 BIT(11) |
70 | #define INTEGRATOR_CLCD_LCDMUX_VGA565 BIT(12) | ||
71 | #define INTEGRATOR_CLCD_LCDMUX_SHARP (BIT(11)|BIT(12)) | 70 | #define INTEGRATOR_CLCD_LCDMUX_SHARP (BIT(11)|BIT(12)) |
72 | #define INTEGRATOR_CLCD_LCDMUX_VGA555 BIT(13) | 71 | #define INTEGRATOR_CLCD_LCDMUX_VGA555 BIT(13) |
73 | #define INTEGRATOR_CLCD_LCDMUX_VGA24 (BIT(11)|BIT(12)|BIT(13)) | 72 | #define INTEGRATOR_CLCD_LCDMUX_VGA24 (BIT(11)|BIT(12)|BIT(13)) |
@@ -82,16 +81,7 @@ static const struct of_device_id versatile_clcd_of_match[] = { | |||
82 | /* 0 = 24bit VGA, 1 = 18bit VGA */ | 81 | /* 0 = 24bit VGA, 1 = 18bit VGA */ |
83 | #define INTEGRATOR_CLCD_LCD_N24BITEN BIT(19) | 82 | #define INTEGRATOR_CLCD_LCD_N24BITEN BIT(19) |
84 | 83 | ||
85 | #define INTEGRATOR_CLCD_MASK (INTEGRATOR_CLCD_LCDBIASEN | \ | 84 | #define INTEGRATOR_CLCD_MASK GENMASK(19, 8) |
86 | INTEGRATOR_CLCD_LCDBIASUP | \ | ||
87 | INTEGRATOR_CLCD_LCDBIASDN | \ | ||
88 | INTEGRATOR_CLCD_LCDMUX_MASK | \ | ||
89 | INTEGRATOR_CLCD_LCD0_EN | \ | ||
90 | INTEGRATOR_CLCD_LCD1_EN | \ | ||
91 | INTEGRATOR_CLCD_LCD_STATIC1 | \ | ||
92 | INTEGRATOR_CLCD_LCD_STATIC2 | \ | ||
93 | INTEGRATOR_CLCD_LCD_STATIC | \ | ||
94 | INTEGRATOR_CLCD_LCD_N24BITEN) | ||
95 | 85 | ||
96 | static void pl111_integrator_enable(struct drm_device *drm, u32 format) | 86 | static void pl111_integrator_enable(struct drm_device *drm, u32 format) |
97 | { | 87 | { |
@@ -106,11 +96,8 @@ static void pl111_integrator_enable(struct drm_device *drm, u32 format) | |||
106 | switch (format) { | 96 | switch (format) { |
107 | case DRM_FORMAT_XBGR8888: | 97 | case DRM_FORMAT_XBGR8888: |
108 | case DRM_FORMAT_XRGB8888: | 98 | case DRM_FORMAT_XRGB8888: |
109 | break; | 99 | /* 24bit formats */ |
110 | case DRM_FORMAT_BGR565: | 100 | val |= INTEGRATOR_CLCD_LCDMUX_VGA24; |
111 | case DRM_FORMAT_RGB565: | ||
112 | /* truecolor RGB565 */ | ||
113 | val |= INTEGRATOR_CLCD_LCDMUX_VGA565; | ||
114 | break; | 101 | break; |
115 | case DRM_FORMAT_XBGR1555: | 102 | case DRM_FORMAT_XBGR1555: |
116 | case DRM_FORMAT_XRGB1555: | 103 | case DRM_FORMAT_XRGB1555: |
@@ -217,6 +204,57 @@ static void pl111_realview_clcd_enable(struct drm_device *drm, u32 format) | |||
217 | SYS_CLCD_NLCDIOON | SYS_CLCD_PWR3V5SWITCH); | 204 | SYS_CLCD_NLCDIOON | SYS_CLCD_PWR3V5SWITCH); |
218 | } | 205 | } |
219 | 206 | ||
207 | /* PL110 pixel formats for Integrator, vanilla PL110 */ | ||
208 | static const u32 pl110_integrator_pixel_formats[] = { | ||
209 | DRM_FORMAT_ABGR8888, | ||
210 | DRM_FORMAT_XBGR8888, | ||
211 | DRM_FORMAT_ARGB8888, | ||
212 | DRM_FORMAT_XRGB8888, | ||
213 | DRM_FORMAT_ABGR1555, | ||
214 | DRM_FORMAT_XBGR1555, | ||
215 | DRM_FORMAT_ARGB1555, | ||
216 | DRM_FORMAT_XRGB1555, | ||
217 | }; | ||
218 | |||
219 | /* Extended PL110 pixel formats for Integrator and Versatile */ | ||
220 | static const u32 pl110_versatile_pixel_formats[] = { | ||
221 | DRM_FORMAT_ABGR8888, | ||
222 | DRM_FORMAT_XBGR8888, | ||
223 | DRM_FORMAT_ARGB8888, | ||
224 | DRM_FORMAT_XRGB8888, | ||
225 | DRM_FORMAT_BGR565, /* Uses external PLD */ | ||
226 | DRM_FORMAT_RGB565, /* Uses external PLD */ | ||
227 | DRM_FORMAT_ABGR1555, | ||
228 | DRM_FORMAT_XBGR1555, | ||
229 | DRM_FORMAT_ARGB1555, | ||
230 | DRM_FORMAT_XRGB1555, | ||
231 | }; | ||
232 | |||
233 | /* | ||
234 | * The Integrator variant is a PL110 with a bunch of broken, or not | ||
235 | * yet implemented features | ||
236 | */ | ||
237 | static const struct pl111_variant_data pl110_integrator = { | ||
238 | .name = "PL110 Integrator", | ||
239 | .is_pl110 = true, | ||
240 | .broken_clockdivider = true, | ||
241 | .broken_vblank = true, | ||
242 | .formats = pl110_integrator_pixel_formats, | ||
243 | .nformats = ARRAY_SIZE(pl110_integrator_pixel_formats), | ||
244 | }; | ||
245 | |||
246 | /* | ||
247 | * This is the in-between PL110 variant found in the ARM Versatile, | ||
248 | * supporting RGB565/BGR565 | ||
249 | */ | ||
250 | static const struct pl111_variant_data pl110_versatile = { | ||
251 | .name = "PL110 Versatile", | ||
252 | .is_pl110 = true, | ||
253 | .external_bgr = true, | ||
254 | .formats = pl110_versatile_pixel_formats, | ||
255 | .nformats = ARRAY_SIZE(pl110_versatile_pixel_formats), | ||
256 | }; | ||
257 | |||
220 | int pl111_versatile_init(struct device *dev, struct pl111_drm_dev_private *priv) | 258 | int pl111_versatile_init(struct device *dev, struct pl111_drm_dev_private *priv) |
221 | { | 259 | { |
222 | const struct of_device_id *clcd_id; | 260 | const struct of_device_id *clcd_id; |
@@ -241,14 +279,24 @@ int pl111_versatile_init(struct device *dev, struct pl111_drm_dev_private *priv) | |||
241 | switch (versatile_clcd_type) { | 279 | switch (versatile_clcd_type) { |
242 | case INTEGRATOR_CLCD_CM: | 280 | case INTEGRATOR_CLCD_CM: |
243 | versatile_syscon_map = map; | 281 | versatile_syscon_map = map; |
282 | priv->variant = &pl110_integrator; | ||
244 | priv->variant_display_enable = pl111_integrator_enable; | 283 | priv->variant_display_enable = pl111_integrator_enable; |
245 | dev_info(dev, "set up callbacks for Integrator PL110\n"); | 284 | dev_info(dev, "set up callbacks for Integrator PL110\n"); |
246 | break; | 285 | break; |
247 | case VERSATILE_CLCD: | 286 | case VERSATILE_CLCD: |
248 | versatile_syscon_map = map; | 287 | versatile_syscon_map = map; |
288 | /* This can do RGB565 with external PLD */ | ||
289 | priv->variant = &pl110_versatile; | ||
249 | priv->variant_display_enable = pl111_versatile_enable; | 290 | priv->variant_display_enable = pl111_versatile_enable; |
250 | priv->variant_display_disable = pl111_versatile_disable; | 291 | priv->variant_display_disable = pl111_versatile_disable; |
251 | dev_info(dev, "set up callbacks for Versatile PL110+\n"); | 292 | /* |
293 | * The Versatile has a variant halfway between PL110 | ||
294 | * and PL111 where these two registers have already been | ||
295 | * swapped. | ||
296 | */ | ||
297 | priv->ienb = CLCD_PL111_IENB; | ||
298 | priv->ctrl = CLCD_PL111_CNTL; | ||
299 | dev_info(dev, "set up callbacks for Versatile PL110\n"); | ||
252 | break; | 300 | break; |
253 | case REALVIEW_CLCD_EB: | 301 | case REALVIEW_CLCD_EB: |
254 | case REALVIEW_CLCD_PB1176: | 302 | case REALVIEW_CLCD_PB1176: |
diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h index d34887873dea..4a2eb409aacc 100644 --- a/drivers/gpu/drm/radeon/radeon.h +++ b/drivers/gpu/drm/radeon/radeon.h | |||
@@ -2387,6 +2387,7 @@ struct radeon_device { | |||
2387 | struct radeon_dummy_page dummy_page; | 2387 | struct radeon_dummy_page dummy_page; |
2388 | bool shutdown; | 2388 | bool shutdown; |
2389 | bool need_dma32; | 2389 | bool need_dma32; |
2390 | bool need_swiotlb; | ||
2390 | bool accel_working; | 2391 | bool accel_working; |
2391 | bool fastfb_working; /* IGP feature*/ | 2392 | bool fastfb_working; /* IGP feature*/ |
2392 | bool needs_reset, in_reset; | 2393 | bool needs_reset, in_reset; |
diff --git a/drivers/gpu/drm/radeon/radeon_device.c b/drivers/gpu/drm/radeon/radeon_device.c index 8d3e3d2e0090..7f40c6f7c4dd 100644 --- a/drivers/gpu/drm/radeon/radeon_device.c +++ b/drivers/gpu/drm/radeon/radeon_device.c | |||
@@ -29,6 +29,7 @@ | |||
29 | #include <linux/slab.h> | 29 | #include <linux/slab.h> |
30 | #include <drm/drmP.h> | 30 | #include <drm/drmP.h> |
31 | #include <drm/drm_crtc_helper.h> | 31 | #include <drm/drm_crtc_helper.h> |
32 | #include <drm/drm_cache.h> | ||
32 | #include <drm/radeon_drm.h> | 33 | #include <drm/radeon_drm.h> |
33 | #include <linux/pm_runtime.h> | 34 | #include <linux/pm_runtime.h> |
34 | #include <linux/vgaarb.h> | 35 | #include <linux/vgaarb.h> |
@@ -1378,6 +1379,7 @@ int radeon_device_init(struct radeon_device *rdev, | |||
1378 | pci_set_consistent_dma_mask(rdev->pdev, DMA_BIT_MASK(32)); | 1379 | pci_set_consistent_dma_mask(rdev->pdev, DMA_BIT_MASK(32)); |
1379 | pr_warn("radeon: No coherent DMA available\n"); | 1380 | pr_warn("radeon: No coherent DMA available\n"); |
1380 | } | 1381 | } |
1382 | rdev->need_swiotlb = drm_get_max_iomem() > ((u64)1 << dma_bits); | ||
1381 | 1383 | ||
1382 | /* Registers mapping */ | 1384 | /* Registers mapping */ |
1383 | /* TODO: block userspace mapping of io register */ | 1385 | /* TODO: block userspace mapping of io register */ |
diff --git a/drivers/gpu/drm/radeon/radeon_ttm.c b/drivers/gpu/drm/radeon/radeon_ttm.c index a0a839bc39bf..c1e3862a48a4 100644 --- a/drivers/gpu/drm/radeon/radeon_ttm.c +++ b/drivers/gpu/drm/radeon/radeon_ttm.c | |||
@@ -756,7 +756,7 @@ static int radeon_ttm_tt_populate(struct ttm_tt *ttm, | |||
756 | #endif | 756 | #endif |
757 | 757 | ||
758 | #ifdef CONFIG_SWIOTLB | 758 | #ifdef CONFIG_SWIOTLB |
759 | if (swiotlb_nr_tbl()) { | 759 | if (rdev->need_swiotlb && swiotlb_nr_tbl()) { |
760 | return ttm_dma_populate(>t->ttm, rdev->dev, ctx); | 760 | return ttm_dma_populate(>t->ttm, rdev->dev, ctx); |
761 | } | 761 | } |
762 | #endif | 762 | #endif |
@@ -788,7 +788,7 @@ static void radeon_ttm_tt_unpopulate(struct ttm_tt *ttm) | |||
788 | #endif | 788 | #endif |
789 | 789 | ||
790 | #ifdef CONFIG_SWIOTLB | 790 | #ifdef CONFIG_SWIOTLB |
791 | if (swiotlb_nr_tbl()) { | 791 | if (rdev->need_swiotlb && swiotlb_nr_tbl()) { |
792 | ttm_dma_unpopulate(>t->ttm, rdev->dev); | 792 | ttm_dma_unpopulate(>t->ttm, rdev->dev); |
793 | return; | 793 | return; |
794 | } | 794 | } |
@@ -1155,7 +1155,7 @@ static int radeon_ttm_debugfs_init(struct radeon_device *rdev) | |||
1155 | count = ARRAY_SIZE(radeon_ttm_debugfs_list); | 1155 | count = ARRAY_SIZE(radeon_ttm_debugfs_list); |
1156 | 1156 | ||
1157 | #ifdef CONFIG_SWIOTLB | 1157 | #ifdef CONFIG_SWIOTLB |
1158 | if (!swiotlb_nr_tbl()) | 1158 | if (!(rdev->need_swiotlb && swiotlb_nr_tbl())) |
1159 | --count; | 1159 | --count; |
1160 | #endif | 1160 | #endif |
1161 | 1161 | ||
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_plane.c b/drivers/gpu/drm/rcar-du/rcar_du_plane.c index 4a3d16cf3ed6..5687a94d4cb1 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_plane.c +++ b/drivers/gpu/drm/rcar-du/rcar_du_plane.c | |||
@@ -572,7 +572,7 @@ int __rcar_du_plane_atomic_check(struct drm_plane *plane, | |||
572 | { | 572 | { |
573 | struct drm_device *dev = plane->dev; | 573 | struct drm_device *dev = plane->dev; |
574 | struct drm_crtc_state *crtc_state; | 574 | struct drm_crtc_state *crtc_state; |
575 | struct drm_rect clip; | 575 | struct drm_rect clip = {}; |
576 | int ret; | 576 | int ret; |
577 | 577 | ||
578 | if (!state->crtc) { | 578 | if (!state->crtc) { |
@@ -589,10 +589,9 @@ int __rcar_du_plane_atomic_check(struct drm_plane *plane, | |||
589 | if (IS_ERR(crtc_state)) | 589 | if (IS_ERR(crtc_state)) |
590 | return PTR_ERR(crtc_state); | 590 | return PTR_ERR(crtc_state); |
591 | 591 | ||
592 | clip.x1 = 0; | 592 | if (crtc_state->enable) |
593 | clip.y1 = 0; | 593 | drm_mode_get_hv_timing(&crtc_state->mode, |
594 | clip.x2 = crtc_state->mode.hdisplay; | 594 | &clip.x2, &clip.y2); |
595 | clip.y2 = crtc_state->mode.vdisplay; | ||
596 | 595 | ||
597 | ret = drm_atomic_helper_check_plane_state(state, crtc_state, &clip, | 596 | ret = drm_atomic_helper_check_plane_state(state, crtc_state, &clip, |
598 | DRM_PLANE_HELPER_NO_SCALING, | 597 | DRM_PLANE_HELPER_NO_SCALING, |
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c index ba7505292b78..7715853ef90a 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c | |||
@@ -253,17 +253,6 @@ static bool is_yuv_support(uint32_t format) | |||
253 | } | 253 | } |
254 | } | 254 | } |
255 | 255 | ||
256 | static bool is_alpha_support(uint32_t format) | ||
257 | { | ||
258 | switch (format) { | ||
259 | case DRM_FORMAT_ARGB8888: | ||
260 | case DRM_FORMAT_ABGR8888: | ||
261 | return true; | ||
262 | default: | ||
263 | return false; | ||
264 | } | ||
265 | } | ||
266 | |||
267 | static uint16_t scl_vop_cal_scale(enum scale_mode mode, uint32_t src, | 256 | static uint16_t scl_vop_cal_scale(enum scale_mode mode, uint32_t src, |
268 | uint32_t dst, bool is_horizontal, | 257 | uint32_t dst, bool is_horizontal, |
269 | int vsu_mode, int *vskiplines) | 258 | int vsu_mode, int *vskiplines) |
@@ -641,7 +630,7 @@ static int vop_plane_atomic_check(struct drm_plane *plane, | |||
641 | struct vop_win *vop_win = to_vop_win(plane); | 630 | struct vop_win *vop_win = to_vop_win(plane); |
642 | const struct vop_win_data *win = vop_win->data; | 631 | const struct vop_win_data *win = vop_win->data; |
643 | int ret; | 632 | int ret; |
644 | struct drm_rect clip; | 633 | struct drm_rect clip = {}; |
645 | int min_scale = win->phy->scl ? FRAC_16_16(1, 8) : | 634 | int min_scale = win->phy->scl ? FRAC_16_16(1, 8) : |
646 | DRM_PLANE_HELPER_NO_SCALING; | 635 | DRM_PLANE_HELPER_NO_SCALING; |
647 | int max_scale = win->phy->scl ? FRAC_16_16(8, 1) : | 636 | int max_scale = win->phy->scl ? FRAC_16_16(8, 1) : |
@@ -654,10 +643,9 @@ static int vop_plane_atomic_check(struct drm_plane *plane, | |||
654 | if (WARN_ON(!crtc_state)) | 643 | if (WARN_ON(!crtc_state)) |
655 | return -EINVAL; | 644 | return -EINVAL; |
656 | 645 | ||
657 | clip.x1 = 0; | 646 | if (crtc_state->enable) |
658 | clip.y1 = 0; | 647 | drm_mode_get_hv_timing(&crtc_state->mode, |
659 | clip.x2 = crtc_state->adjusted_mode.hdisplay; | 648 | &clip.x2, &clip.y2); |
660 | clip.y2 = crtc_state->adjusted_mode.vdisplay; | ||
661 | 649 | ||
662 | ret = drm_atomic_helper_check_plane_state(state, crtc_state, &clip, | 650 | ret = drm_atomic_helper_check_plane_state(state, crtc_state, &clip, |
663 | min_scale, max_scale, | 651 | min_scale, max_scale, |
@@ -790,7 +778,7 @@ static void vop_plane_atomic_update(struct drm_plane *plane, | |||
790 | rb_swap = has_rb_swapped(fb->format->format); | 778 | rb_swap = has_rb_swapped(fb->format->format); |
791 | VOP_WIN_SET(vop, win, rb_swap, rb_swap); | 779 | VOP_WIN_SET(vop, win, rb_swap, rb_swap); |
792 | 780 | ||
793 | if (is_alpha_support(fb->format->format)) { | 781 | if (fb->format->has_alpha) { |
794 | VOP_WIN_SET(vop, win, dst_alpha_ctl, | 782 | VOP_WIN_SET(vop, win, dst_alpha_ctl, |
795 | DST_FACTOR_M0(ALPHA_SRC_INVERSE)); | 783 | DST_FACTOR_M0(ALPHA_SRC_INVERSE)); |
796 | val = SRC_ALPHA_EN(1) | SRC_COLOR_M0(ALPHA_SRC_PRE_MUL) | | 784 | val = SRC_ALPHA_EN(1) | SRC_COLOR_M0(ALPHA_SRC_PRE_MUL) | |
diff --git a/drivers/gpu/drm/stm/drv.c b/drivers/gpu/drm/stm/drv.c index 8fe954c27fba..8bc7e8418b8d 100644 --- a/drivers/gpu/drm/stm/drv.c +++ b/drivers/gpu/drm/stm/drv.c | |||
@@ -31,6 +31,24 @@ static const struct drm_mode_config_funcs drv_mode_config_funcs = { | |||
31 | .atomic_commit = drm_atomic_helper_commit, | 31 | .atomic_commit = drm_atomic_helper_commit, |
32 | }; | 32 | }; |
33 | 33 | ||
34 | static int stm_gem_cma_dumb_create(struct drm_file *file, | ||
35 | struct drm_device *dev, | ||
36 | struct drm_mode_create_dumb *args) | ||
37 | { | ||
38 | #ifdef CONFIG_MMU | ||
39 | unsigned int min_pitch = DIV_ROUND_UP(args->width * args->bpp, 8); | ||
40 | |||
41 | /* | ||
42 | * in order to optimize data transfer, pitch is aligned on | ||
43 | * 128 bytes, height is aligned on 4 bytes | ||
44 | */ | ||
45 | args->pitch = roundup(min_pitch, 128); | ||
46 | args->height = roundup(args->height, 4); | ||
47 | #endif | ||
48 | |||
49 | return drm_gem_cma_dumb_create_internal(file, dev, args); | ||
50 | } | ||
51 | |||
34 | DEFINE_DRM_GEM_CMA_FOPS(drv_driver_fops); | 52 | DEFINE_DRM_GEM_CMA_FOPS(drv_driver_fops); |
35 | 53 | ||
36 | static struct drm_driver drv_driver = { | 54 | static struct drm_driver drv_driver = { |
@@ -44,7 +62,7 @@ static struct drm_driver drv_driver = { | |||
44 | .minor = 0, | 62 | .minor = 0, |
45 | .patchlevel = 0, | 63 | .patchlevel = 0, |
46 | .fops = &drv_driver_fops, | 64 | .fops = &drv_driver_fops, |
47 | .dumb_create = drm_gem_cma_dumb_create, | 65 | .dumb_create = stm_gem_cma_dumb_create, |
48 | .prime_handle_to_fd = drm_gem_prime_handle_to_fd, | 66 | .prime_handle_to_fd = drm_gem_prime_handle_to_fd, |
49 | .prime_fd_to_handle = drm_gem_prime_fd_to_handle, | 67 | .prime_fd_to_handle = drm_gem_prime_fd_to_handle, |
50 | .gem_free_object_unlocked = drm_gem_cma_free_object, | 68 | .gem_free_object_unlocked = drm_gem_cma_free_object, |
diff --git a/drivers/gpu/drm/stm/dw_mipi_dsi-stm.c b/drivers/gpu/drm/stm/dw_mipi_dsi-stm.c index fd02506274da..a514b593f37c 100644 --- a/drivers/gpu/drm/stm/dw_mipi_dsi-stm.c +++ b/drivers/gpu/drm/stm/dw_mipi_dsi-stm.c | |||
@@ -14,7 +14,14 @@ | |||
14 | #include <drm/bridge/dw_mipi_dsi.h> | 14 | #include <drm/bridge/dw_mipi_dsi.h> |
15 | #include <video/mipi_display.h> | 15 | #include <video/mipi_display.h> |
16 | 16 | ||
17 | /* DSI wrapper register & bit definitions */ | 17 | #define HWVER_130 0x31333000 /* IP version 1.30 */ |
18 | #define HWVER_131 0x31333100 /* IP version 1.31 */ | ||
19 | |||
20 | /* DSI digital registers & bit definitions */ | ||
21 | #define DSI_VERSION 0x00 | ||
22 | #define VERSION GENMASK(31, 8) | ||
23 | |||
24 | /* DSI wrapper registers & bit definitions */ | ||
18 | /* Note: registers are named as in the Reference Manual */ | 25 | /* Note: registers are named as in the Reference Manual */ |
19 | #define DSI_WCFGR 0x0400 /* Wrapper ConFiGuration Reg */ | 26 | #define DSI_WCFGR 0x0400 /* Wrapper ConFiGuration Reg */ |
20 | #define WCFGR_DSIM BIT(0) /* DSI Mode */ | 27 | #define WCFGR_DSIM BIT(0) /* DSI Mode */ |
@@ -65,6 +72,10 @@ enum dsi_color { | |||
65 | struct dw_mipi_dsi_stm { | 72 | struct dw_mipi_dsi_stm { |
66 | void __iomem *base; | 73 | void __iomem *base; |
67 | struct clk *pllref_clk; | 74 | struct clk *pllref_clk; |
75 | struct dw_mipi_dsi *dsi; | ||
76 | u32 hw_version; | ||
77 | int lane_min_kbps; | ||
78 | int lane_max_kbps; | ||
68 | }; | 79 | }; |
69 | 80 | ||
70 | static inline void dsi_write(struct dw_mipi_dsi_stm *dsi, u32 reg, u32 val) | 81 | static inline void dsi_write(struct dw_mipi_dsi_stm *dsi, u32 reg, u32 val) |
@@ -121,7 +132,8 @@ static int dsi_pll_get_clkout_khz(int clkin_khz, int idf, int ndiv, int odf) | |||
121 | return DIV_ROUND_CLOSEST(clkin_khz * ndiv, divisor); | 132 | return DIV_ROUND_CLOSEST(clkin_khz * ndiv, divisor); |
122 | } | 133 | } |
123 | 134 | ||
124 | static int dsi_pll_get_params(int clkin_khz, int clkout_khz, | 135 | static int dsi_pll_get_params(struct dw_mipi_dsi_stm *dsi, |
136 | int clkin_khz, int clkout_khz, | ||
125 | int *idf, int *ndiv, int *odf) | 137 | int *idf, int *ndiv, int *odf) |
126 | { | 138 | { |
127 | int i, o, n, n_min, n_max; | 139 | int i, o, n, n_min, n_max; |
@@ -131,8 +143,8 @@ static int dsi_pll_get_params(int clkin_khz, int clkout_khz, | |||
131 | if (clkin_khz <= 0 || clkout_khz <= 0) | 143 | if (clkin_khz <= 0 || clkout_khz <= 0) |
132 | return -EINVAL; | 144 | return -EINVAL; |
133 | 145 | ||
134 | fvco_min = LANE_MIN_KBPS * 2 * ODF_MAX; | 146 | fvco_min = dsi->lane_min_kbps * 2 * ODF_MAX; |
135 | fvco_max = LANE_MAX_KBPS * 2 * ODF_MIN; | 147 | fvco_max = dsi->lane_max_kbps * 2 * ODF_MIN; |
136 | 148 | ||
137 | best_delta = 1000000; /* big started value (1000000khz) */ | 149 | best_delta = 1000000; /* big started value (1000000khz) */ |
138 | 150 | ||
@@ -212,6 +224,15 @@ dw_mipi_dsi_get_lane_mbps(void *priv_data, struct drm_display_mode *mode, | |||
212 | int ret, bpp; | 224 | int ret, bpp; |
213 | u32 val; | 225 | u32 val; |
214 | 226 | ||
227 | /* Update lane capabilities according to hw version */ | ||
228 | dsi->hw_version = dsi_read(dsi, DSI_VERSION) & VERSION; | ||
229 | dsi->lane_min_kbps = LANE_MIN_KBPS; | ||
230 | dsi->lane_max_kbps = LANE_MAX_KBPS; | ||
231 | if (dsi->hw_version == HWVER_131) { | ||
232 | dsi->lane_min_kbps *= 2; | ||
233 | dsi->lane_max_kbps *= 2; | ||
234 | } | ||
235 | |||
215 | pll_in_khz = (unsigned int)(clk_get_rate(dsi->pllref_clk) / 1000); | 236 | pll_in_khz = (unsigned int)(clk_get_rate(dsi->pllref_clk) / 1000); |
216 | 237 | ||
217 | /* Compute requested pll out */ | 238 | /* Compute requested pll out */ |
@@ -219,12 +240,12 @@ dw_mipi_dsi_get_lane_mbps(void *priv_data, struct drm_display_mode *mode, | |||
219 | pll_out_khz = mode->clock * bpp / lanes; | 240 | pll_out_khz = mode->clock * bpp / lanes; |
220 | /* Add 20% to pll out to be higher than pixel bw (burst mode only) */ | 241 | /* Add 20% to pll out to be higher than pixel bw (burst mode only) */ |
221 | pll_out_khz = (pll_out_khz * 12) / 10; | 242 | pll_out_khz = (pll_out_khz * 12) / 10; |
222 | if (pll_out_khz > LANE_MAX_KBPS) { | 243 | if (pll_out_khz > dsi->lane_max_kbps) { |
223 | pll_out_khz = LANE_MAX_KBPS; | 244 | pll_out_khz = dsi->lane_max_kbps; |
224 | DRM_WARN("Warning max phy mbps is used\n"); | 245 | DRM_WARN("Warning max phy mbps is used\n"); |
225 | } | 246 | } |
226 | if (pll_out_khz < LANE_MIN_KBPS) { | 247 | if (pll_out_khz < dsi->lane_min_kbps) { |
227 | pll_out_khz = LANE_MIN_KBPS; | 248 | pll_out_khz = dsi->lane_min_kbps; |
228 | DRM_WARN("Warning min phy mbps is used\n"); | 249 | DRM_WARN("Warning min phy mbps is used\n"); |
229 | } | 250 | } |
230 | 251 | ||
@@ -232,7 +253,8 @@ dw_mipi_dsi_get_lane_mbps(void *priv_data, struct drm_display_mode *mode, | |||
232 | idf = 0; | 253 | idf = 0; |
233 | ndiv = 0; | 254 | ndiv = 0; |
234 | odf = 0; | 255 | odf = 0; |
235 | ret = dsi_pll_get_params(pll_in_khz, pll_out_khz, &idf, &ndiv, &odf); | 256 | ret = dsi_pll_get_params(dsi, pll_in_khz, pll_out_khz, |
257 | &idf, &ndiv, &odf); | ||
236 | if (ret) | 258 | if (ret) |
237 | DRM_WARN("Warning dsi_pll_get_params(): bad params\n"); | 259 | DRM_WARN("Warning dsi_pll_get_params(): bad params\n"); |
238 | 260 | ||
@@ -312,21 +334,24 @@ static int dw_mipi_dsi_stm_probe(struct platform_device *pdev) | |||
312 | dw_mipi_dsi_stm_plat_data.base = dsi->base; | 334 | dw_mipi_dsi_stm_plat_data.base = dsi->base; |
313 | dw_mipi_dsi_stm_plat_data.priv_data = dsi; | 335 | dw_mipi_dsi_stm_plat_data.priv_data = dsi; |
314 | 336 | ||
315 | ret = dw_mipi_dsi_probe(pdev, &dw_mipi_dsi_stm_plat_data); | 337 | platform_set_drvdata(pdev, dsi); |
316 | if (ret) { | 338 | |
339 | dsi->dsi = dw_mipi_dsi_probe(pdev, &dw_mipi_dsi_stm_plat_data); | ||
340 | if (IS_ERR(dsi->dsi)) { | ||
317 | DRM_ERROR("Failed to initialize mipi dsi host\n"); | 341 | DRM_ERROR("Failed to initialize mipi dsi host\n"); |
318 | clk_disable_unprepare(dsi->pllref_clk); | 342 | clk_disable_unprepare(dsi->pllref_clk); |
343 | return PTR_ERR(dsi->dsi); | ||
319 | } | 344 | } |
320 | 345 | ||
321 | return ret; | 346 | return 0; |
322 | } | 347 | } |
323 | 348 | ||
324 | static int dw_mipi_dsi_stm_remove(struct platform_device *pdev) | 349 | static int dw_mipi_dsi_stm_remove(struct platform_device *pdev) |
325 | { | 350 | { |
326 | struct dw_mipi_dsi_stm *dsi = dw_mipi_dsi_stm_plat_data.priv_data; | 351 | struct dw_mipi_dsi_stm *dsi = platform_get_drvdata(pdev); |
327 | 352 | ||
328 | clk_disable_unprepare(dsi->pllref_clk); | 353 | clk_disable_unprepare(dsi->pllref_clk); |
329 | dw_mipi_dsi_remove(pdev); | 354 | dw_mipi_dsi_remove(dsi->dsi); |
330 | 355 | ||
331 | return 0; | 356 | return 0; |
332 | } | 357 | } |
diff --git a/drivers/gpu/drm/stm/ltdc.c b/drivers/gpu/drm/stm/ltdc.c index 6dc5d4ec4e17..1a3277e483d5 100644 --- a/drivers/gpu/drm/stm/ltdc.c +++ b/drivers/gpu/drm/stm/ltdc.c | |||
@@ -175,6 +175,8 @@ | |||
175 | 175 | ||
176 | #define LXCFBLNR_CFBLN GENMASK(10, 0) /* Color Frame Buffer Line Number */ | 176 | #define LXCFBLNR_CFBLN GENMASK(10, 0) /* Color Frame Buffer Line Number */ |
177 | 177 | ||
178 | #define CLUT_SIZE 256 | ||
179 | |||
178 | #define CONSTA_MAX 0xFF /* CONSTant Alpha MAX= 1.0 */ | 180 | #define CONSTA_MAX 0xFF /* CONSTant Alpha MAX= 1.0 */ |
179 | #define BF1_PAXCA 0x600 /* Pixel Alpha x Constant Alpha */ | 181 | #define BF1_PAXCA 0x600 /* Pixel Alpha x Constant Alpha */ |
180 | #define BF1_CA 0x400 /* Constant Alpha */ | 182 | #define BF1_CA 0x400 /* Constant Alpha */ |
@@ -326,6 +328,26 @@ static inline u32 to_drm_pixelformat(enum ltdc_pix_fmt pf) | |||
326 | } | 328 | } |
327 | } | 329 | } |
328 | 330 | ||
331 | static inline u32 get_pixelformat_without_alpha(u32 drm) | ||
332 | { | ||
333 | switch (drm) { | ||
334 | case DRM_FORMAT_ARGB4444: | ||
335 | return DRM_FORMAT_XRGB4444; | ||
336 | case DRM_FORMAT_RGBA4444: | ||
337 | return DRM_FORMAT_RGBX4444; | ||
338 | case DRM_FORMAT_ARGB1555: | ||
339 | return DRM_FORMAT_XRGB1555; | ||
340 | case DRM_FORMAT_RGBA5551: | ||
341 | return DRM_FORMAT_RGBX5551; | ||
342 | case DRM_FORMAT_ARGB8888: | ||
343 | return DRM_FORMAT_XRGB8888; | ||
344 | case DRM_FORMAT_RGBA8888: | ||
345 | return DRM_FORMAT_RGBX8888; | ||
346 | default: | ||
347 | return 0; | ||
348 | } | ||
349 | } | ||
350 | |||
329 | static irqreturn_t ltdc_irq_thread(int irq, void *arg) | 351 | static irqreturn_t ltdc_irq_thread(int irq, void *arg) |
330 | { | 352 | { |
331 | struct drm_device *ddev = arg; | 353 | struct drm_device *ddev = arg; |
@@ -363,6 +385,28 @@ static irqreturn_t ltdc_irq(int irq, void *arg) | |||
363 | * DRM_CRTC | 385 | * DRM_CRTC |
364 | */ | 386 | */ |
365 | 387 | ||
388 | static void ltdc_crtc_update_clut(struct drm_crtc *crtc) | ||
389 | { | ||
390 | struct ltdc_device *ldev = crtc_to_ltdc(crtc); | ||
391 | struct drm_color_lut *lut; | ||
392 | u32 val; | ||
393 | int i; | ||
394 | |||
395 | if (!crtc || !crtc->state) | ||
396 | return; | ||
397 | |||
398 | if (!crtc->state->color_mgmt_changed || !crtc->state->gamma_lut) | ||
399 | return; | ||
400 | |||
401 | lut = (struct drm_color_lut *)crtc->state->gamma_lut->data; | ||
402 | |||
403 | for (i = 0; i < CLUT_SIZE; i++, lut++) { | ||
404 | val = ((lut->red << 8) & 0xff0000) | (lut->green & 0xff00) | | ||
405 | (lut->blue >> 8) | (i << 24); | ||
406 | reg_write(ldev->regs, LTDC_L1CLUTWR, val); | ||
407 | } | ||
408 | } | ||
409 | |||
366 | static void ltdc_crtc_atomic_enable(struct drm_crtc *crtc, | 410 | static void ltdc_crtc_atomic_enable(struct drm_crtc *crtc, |
367 | struct drm_crtc_state *old_state) | 411 | struct drm_crtc_state *old_state) |
368 | { | 412 | { |
@@ -404,12 +448,35 @@ static void ltdc_crtc_atomic_disable(struct drm_crtc *crtc, | |||
404 | reg_set(ldev->regs, LTDC_SRCR, SRCR_IMR); | 448 | reg_set(ldev->regs, LTDC_SRCR, SRCR_IMR); |
405 | } | 449 | } |
406 | 450 | ||
451 | static bool ltdc_crtc_mode_fixup(struct drm_crtc *crtc, | ||
452 | const struct drm_display_mode *mode, | ||
453 | struct drm_display_mode *adjusted_mode) | ||
454 | { | ||
455 | struct ltdc_device *ldev = crtc_to_ltdc(crtc); | ||
456 | int rate = mode->clock * 1000; | ||
457 | |||
458 | /* | ||
459 | * TODO clk_round_rate() does not work yet. When ready, it can | ||
460 | * be used instead of clk_set_rate() then clk_get_rate(). | ||
461 | */ | ||
462 | |||
463 | clk_disable(ldev->pixel_clk); | ||
464 | if (clk_set_rate(ldev->pixel_clk, rate) < 0) { | ||
465 | DRM_ERROR("Cannot set rate (%dHz) for pixel clk\n", rate); | ||
466 | return false; | ||
467 | } | ||
468 | clk_enable(ldev->pixel_clk); | ||
469 | |||
470 | adjusted_mode->clock = clk_get_rate(ldev->pixel_clk) / 1000; | ||
471 | |||
472 | return true; | ||
473 | } | ||
474 | |||
407 | static void ltdc_crtc_mode_set_nofb(struct drm_crtc *crtc) | 475 | static void ltdc_crtc_mode_set_nofb(struct drm_crtc *crtc) |
408 | { | 476 | { |
409 | struct ltdc_device *ldev = crtc_to_ltdc(crtc); | 477 | struct ltdc_device *ldev = crtc_to_ltdc(crtc); |
410 | struct drm_display_mode *mode = &crtc->state->adjusted_mode; | 478 | struct drm_display_mode *mode = &crtc->state->adjusted_mode; |
411 | struct videomode vm; | 479 | struct videomode vm; |
412 | int rate = mode->clock * 1000; | ||
413 | u32 hsync, vsync, accum_hbp, accum_vbp, accum_act_w, accum_act_h; | 480 | u32 hsync, vsync, accum_hbp, accum_vbp, accum_act_w, accum_act_h; |
414 | u32 total_width, total_height; | 481 | u32 total_width, total_height; |
415 | u32 val; | 482 | u32 val; |
@@ -432,15 +499,6 @@ static void ltdc_crtc_mode_set_nofb(struct drm_crtc *crtc) | |||
432 | total_width = accum_act_w + vm.hfront_porch; | 499 | total_width = accum_act_w + vm.hfront_porch; |
433 | total_height = accum_act_h + vm.vfront_porch; | 500 | total_height = accum_act_h + vm.vfront_porch; |
434 | 501 | ||
435 | clk_disable(ldev->pixel_clk); | ||
436 | |||
437 | if (clk_set_rate(ldev->pixel_clk, rate) < 0) { | ||
438 | DRM_ERROR("Cannot set rate (%dHz) for pixel clk\n", rate); | ||
439 | return; | ||
440 | } | ||
441 | |||
442 | clk_enable(ldev->pixel_clk); | ||
443 | |||
444 | /* Configures the HS, VS, DE and PC polarities. Default Active Low */ | 502 | /* Configures the HS, VS, DE and PC polarities. Default Active Low */ |
445 | val = 0; | 503 | val = 0; |
446 | 504 | ||
@@ -486,6 +544,8 @@ static void ltdc_crtc_atomic_flush(struct drm_crtc *crtc, | |||
486 | 544 | ||
487 | DRM_DEBUG_ATOMIC("\n"); | 545 | DRM_DEBUG_ATOMIC("\n"); |
488 | 546 | ||
547 | ltdc_crtc_update_clut(crtc); | ||
548 | |||
489 | /* Commit shadow registers = update planes at next vblank */ | 549 | /* Commit shadow registers = update planes at next vblank */ |
490 | reg_set(ldev->regs, LTDC_SRCR, SRCR_VBR); | 550 | reg_set(ldev->regs, LTDC_SRCR, SRCR_VBR); |
491 | 551 | ||
@@ -502,6 +562,7 @@ static void ltdc_crtc_atomic_flush(struct drm_crtc *crtc, | |||
502 | } | 562 | } |
503 | 563 | ||
504 | static const struct drm_crtc_helper_funcs ltdc_crtc_helper_funcs = { | 564 | static const struct drm_crtc_helper_funcs ltdc_crtc_helper_funcs = { |
565 | .mode_fixup = ltdc_crtc_mode_fixup, | ||
505 | .mode_set_nofb = ltdc_crtc_mode_set_nofb, | 566 | .mode_set_nofb = ltdc_crtc_mode_set_nofb, |
506 | .atomic_flush = ltdc_crtc_atomic_flush, | 567 | .atomic_flush = ltdc_crtc_atomic_flush, |
507 | .atomic_enable = ltdc_crtc_atomic_enable, | 568 | .atomic_enable = ltdc_crtc_atomic_enable, |
@@ -533,6 +594,7 @@ static const struct drm_crtc_funcs ltdc_crtc_funcs = { | |||
533 | .reset = drm_atomic_helper_crtc_reset, | 594 | .reset = drm_atomic_helper_crtc_reset, |
534 | .atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state, | 595 | .atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state, |
535 | .atomic_destroy_state = drm_atomic_helper_crtc_destroy_state, | 596 | .atomic_destroy_state = drm_atomic_helper_crtc_destroy_state, |
597 | .gamma_set = drm_atomic_helper_legacy_gamma_set, | ||
536 | }; | 598 | }; |
537 | 599 | ||
538 | /* | 600 | /* |
@@ -638,6 +700,14 @@ static void ltdc_plane_atomic_update(struct drm_plane *plane, | |||
638 | 700 | ||
639 | /* Specifies the blending factors */ | 701 | /* Specifies the blending factors */ |
640 | val = BF1_PAXCA | BF2_1PAXCA; | 702 | val = BF1_PAXCA | BF2_1PAXCA; |
703 | if (!fb->format->has_alpha) | ||
704 | val = BF1_CA | BF2_1CA; | ||
705 | |||
706 | /* Manage hw-specific capabilities */ | ||
707 | if (ldev->caps.non_alpha_only_l1 && | ||
708 | plane->type != DRM_PLANE_TYPE_PRIMARY) | ||
709 | val = BF1_PAXCA | BF2_1PAXCA; | ||
710 | |||
641 | reg_update_bits(ldev->regs, LTDC_L1BFCR + lofs, | 711 | reg_update_bits(ldev->regs, LTDC_L1BFCR + lofs, |
642 | LXBFCR_BF2 | LXBFCR_BF1, val); | 712 | LXBFCR_BF2 | LXBFCR_BF1, val); |
643 | 713 | ||
@@ -705,8 +775,8 @@ static struct drm_plane *ltdc_plane_create(struct drm_device *ddev, | |||
705 | struct device *dev = ddev->dev; | 775 | struct device *dev = ddev->dev; |
706 | struct drm_plane *plane; | 776 | struct drm_plane *plane; |
707 | unsigned int i, nb_fmt = 0; | 777 | unsigned int i, nb_fmt = 0; |
708 | u32 formats[NB_PF]; | 778 | u32 formats[NB_PF * 2]; |
709 | u32 drm_fmt; | 779 | u32 drm_fmt, drm_fmt_no_alpha; |
710 | int ret; | 780 | int ret; |
711 | 781 | ||
712 | /* Get supported pixel formats */ | 782 | /* Get supported pixel formats */ |
@@ -715,6 +785,18 @@ static struct drm_plane *ltdc_plane_create(struct drm_device *ddev, | |||
715 | if (!drm_fmt) | 785 | if (!drm_fmt) |
716 | continue; | 786 | continue; |
717 | formats[nb_fmt++] = drm_fmt; | 787 | formats[nb_fmt++] = drm_fmt; |
788 | |||
789 | /* Add the no-alpha related format if any & supported */ | ||
790 | drm_fmt_no_alpha = get_pixelformat_without_alpha(drm_fmt); | ||
791 | if (!drm_fmt_no_alpha) | ||
792 | continue; | ||
793 | |||
794 | /* Manage hw-specific capabilities */ | ||
795 | if (ldev->caps.non_alpha_only_l1 && | ||
796 | type != DRM_PLANE_TYPE_PRIMARY) | ||
797 | continue; | ||
798 | |||
799 | formats[nb_fmt++] = drm_fmt_no_alpha; | ||
718 | } | 800 | } |
719 | 801 | ||
720 | plane = devm_kzalloc(dev, sizeof(*plane), GFP_KERNEL); | 802 | plane = devm_kzalloc(dev, sizeof(*plane), GFP_KERNEL); |
@@ -765,6 +847,9 @@ static int ltdc_crtc_init(struct drm_device *ddev, struct drm_crtc *crtc) | |||
765 | 847 | ||
766 | drm_crtc_helper_add(crtc, <dc_crtc_helper_funcs); | 848 | drm_crtc_helper_add(crtc, <dc_crtc_helper_funcs); |
767 | 849 | ||
850 | drm_mode_crtc_set_gamma_size(crtc, CLUT_SIZE); | ||
851 | drm_crtc_enable_color_mgmt(crtc, 0, false, CLUT_SIZE); | ||
852 | |||
768 | DRM_DEBUG_DRIVER("CRTC:%d created\n", crtc->base.id); | 853 | DRM_DEBUG_DRIVER("CRTC:%d created\n", crtc->base.id); |
769 | 854 | ||
770 | /* Add planes. Note : the first layer is used by primary plane */ | 855 | /* Add planes. Note : the first layer is used by primary plane */ |
@@ -839,10 +924,19 @@ static int ltdc_get_caps(struct drm_device *ddev) | |||
839 | case HWVER_10300: | 924 | case HWVER_10300: |
840 | ldev->caps.reg_ofs = REG_OFS_NONE; | 925 | ldev->caps.reg_ofs = REG_OFS_NONE; |
841 | ldev->caps.pix_fmt_hw = ltdc_pix_fmt_a0; | 926 | ldev->caps.pix_fmt_hw = ltdc_pix_fmt_a0; |
927 | /* | ||
928 | * Hw older versions support non-alpha color formats derived | ||
929 | * from native alpha color formats only on the primary layer. | ||
930 | * For instance, RG16 native format without alpha works fine | ||
931 | * on 2nd layer but XR24 (derived color format from AR24) | ||
932 | * does not work on 2nd layer. | ||
933 | */ | ||
934 | ldev->caps.non_alpha_only_l1 = true; | ||
842 | break; | 935 | break; |
843 | case HWVER_20101: | 936 | case HWVER_20101: |
844 | ldev->caps.reg_ofs = REG_OFS_4; | 937 | ldev->caps.reg_ofs = REG_OFS_4; |
845 | ldev->caps.pix_fmt_hw = ltdc_pix_fmt_a1; | 938 | ldev->caps.pix_fmt_hw = ltdc_pix_fmt_a1; |
939 | ldev->caps.non_alpha_only_l1 = false; | ||
846 | break; | 940 | break; |
847 | default: | 941 | default: |
848 | return -ENODEV; | 942 | return -ENODEV; |
diff --git a/drivers/gpu/drm/stm/ltdc.h b/drivers/gpu/drm/stm/ltdc.h index edd1c0a446d1..edb268129c54 100644 --- a/drivers/gpu/drm/stm/ltdc.h +++ b/drivers/gpu/drm/stm/ltdc.h | |||
@@ -17,6 +17,7 @@ struct ltdc_caps { | |||
17 | u32 reg_ofs; /* register offset for applicable regs */ | 17 | u32 reg_ofs; /* register offset for applicable regs */ |
18 | u32 bus_width; /* bus width (32 or 64 bits) */ | 18 | u32 bus_width; /* bus width (32 or 64 bits) */ |
19 | const u32 *pix_fmt_hw; /* supported pixel formats */ | 19 | const u32 *pix_fmt_hw; /* supported pixel formats */ |
20 | bool non_alpha_only_l1; /* non-native no-alpha formats on layer 1 */ | ||
20 | }; | 21 | }; |
21 | 22 | ||
22 | struct ltdc_device { | 23 | struct ltdc_device { |
diff --git a/drivers/gpu/drm/sun4i/Makefile b/drivers/gpu/drm/sun4i/Makefile index 2b37a6abbb1d..582607c0c488 100644 --- a/drivers/gpu/drm/sun4i/Makefile +++ b/drivers/gpu/drm/sun4i/Makefile | |||
@@ -1,5 +1,6 @@ | |||
1 | # SPDX-License-Identifier: GPL-2.0 | 1 | # SPDX-License-Identifier: GPL-2.0 |
2 | sun4i-backend-y += sun4i_backend.o sun4i_layer.o | 2 | sun4i-backend-y += sun4i_backend.o sun4i_layer.o |
3 | sun4i-frontend-y += sun4i_frontend.o | ||
3 | 4 | ||
4 | sun4i-drm-y += sun4i_drv.o | 5 | sun4i-drm-y += sun4i_drv.o |
5 | sun4i-drm-y += sun4i_framebuffer.o | 6 | sun4i-drm-y += sun4i_framebuffer.o |
@@ -24,6 +25,6 @@ obj-$(CONFIG_DRM_SUN4I) += sun4i-tcon.o | |||
24 | obj-$(CONFIG_DRM_SUN4I) += sun4i_tv.o | 25 | obj-$(CONFIG_DRM_SUN4I) += sun4i_tv.o |
25 | obj-$(CONFIG_DRM_SUN4I) += sun6i_drc.o | 26 | obj-$(CONFIG_DRM_SUN4I) += sun6i_drc.o |
26 | 27 | ||
27 | obj-$(CONFIG_DRM_SUN4I_BACKEND) += sun4i-backend.o | 28 | obj-$(CONFIG_DRM_SUN4I_BACKEND) += sun4i-backend.o sun4i-frontend.o |
28 | obj-$(CONFIG_DRM_SUN4I_HDMI) += sun4i-drm-hdmi.o | 29 | obj-$(CONFIG_DRM_SUN4I_HDMI) += sun4i-drm-hdmi.o |
29 | obj-$(CONFIG_DRM_SUN8I_MIXER) += sun8i-mixer.o | 30 | obj-$(CONFIG_DRM_SUN8I_MIXER) += sun8i-mixer.o |
diff --git a/drivers/gpu/drm/sun4i/sun4i_backend.c b/drivers/gpu/drm/sun4i/sun4i_backend.c index 847eecbe4d14..245b189fc4d8 100644 --- a/drivers/gpu/drm/sun4i/sun4i_backend.c +++ b/drivers/gpu/drm/sun4i/sun4i_backend.c | |||
@@ -11,6 +11,7 @@ | |||
11 | */ | 11 | */ |
12 | 12 | ||
13 | #include <drm/drmP.h> | 13 | #include <drm/drmP.h> |
14 | #include <drm/drm_atomic.h> | ||
14 | #include <drm/drm_atomic_helper.h> | 15 | #include <drm/drm_atomic_helper.h> |
15 | #include <drm/drm_crtc.h> | 16 | #include <drm/drm_crtc.h> |
16 | #include <drm/drm_crtc_helper.h> | 17 | #include <drm/drm_crtc_helper.h> |
@@ -26,6 +27,7 @@ | |||
26 | 27 | ||
27 | #include "sun4i_backend.h" | 28 | #include "sun4i_backend.h" |
28 | #include "sun4i_drv.h" | 29 | #include "sun4i_drv.h" |
30 | #include "sun4i_frontend.h" | ||
29 | #include "sun4i_layer.h" | 31 | #include "sun4i_layer.h" |
30 | #include "sunxi_engine.h" | 32 | #include "sunxi_engine.h" |
31 | 33 | ||
@@ -93,7 +95,7 @@ void sun4i_backend_layer_enable(struct sun4i_backend *backend, | |||
93 | static int sun4i_backend_drm_format_to_layer(struct drm_plane *plane, | 95 | static int sun4i_backend_drm_format_to_layer(struct drm_plane *plane, |
94 | u32 format, u32 *mode) | 96 | u32 format, u32 *mode) |
95 | { | 97 | { |
96 | if ((plane->type == DRM_PLANE_TYPE_PRIMARY) && | 98 | if (plane && (plane->type == DRM_PLANE_TYPE_PRIMARY) && |
97 | (format == DRM_FORMAT_ARGB8888)) | 99 | (format == DRM_FORMAT_ARGB8888)) |
98 | format = DRM_FORMAT_XRGB8888; | 100 | format = DRM_FORMAT_XRGB8888; |
99 | 101 | ||
@@ -141,7 +143,6 @@ int sun4i_backend_update_layer_coord(struct sun4i_backend *backend, | |||
141 | int layer, struct drm_plane *plane) | 143 | int layer, struct drm_plane *plane) |
142 | { | 144 | { |
143 | struct drm_plane_state *state = plane->state; | 145 | struct drm_plane_state *state = plane->state; |
144 | struct drm_framebuffer *fb = state->fb; | ||
145 | 146 | ||
146 | DRM_DEBUG_DRIVER("Updating layer %d\n", layer); | 147 | DRM_DEBUG_DRIVER("Updating layer %d\n", layer); |
147 | 148 | ||
@@ -153,12 +154,6 @@ int sun4i_backend_update_layer_coord(struct sun4i_backend *backend, | |||
153 | state->crtc_h)); | 154 | state->crtc_h)); |
154 | } | 155 | } |
155 | 156 | ||
156 | /* Set the line width */ | ||
157 | DRM_DEBUG_DRIVER("Layer line width: %d bits\n", fb->pitches[0] * 8); | ||
158 | regmap_write(backend->engine.regs, | ||
159 | SUN4I_BACKEND_LAYLINEWIDTH_REG(layer), | ||
160 | fb->pitches[0] * 8); | ||
161 | |||
162 | /* Set height and width */ | 157 | /* Set height and width */ |
163 | DRM_DEBUG_DRIVER("Layer size W: %u H: %u\n", | 158 | DRM_DEBUG_DRIVER("Layer size W: %u H: %u\n", |
164 | state->crtc_w, state->crtc_h); | 159 | state->crtc_w, state->crtc_h); |
@@ -210,6 +205,30 @@ int sun4i_backend_update_layer_formats(struct sun4i_backend *backend, | |||
210 | return 0; | 205 | return 0; |
211 | } | 206 | } |
212 | 207 | ||
208 | int sun4i_backend_update_layer_frontend(struct sun4i_backend *backend, | ||
209 | int layer, uint32_t fmt) | ||
210 | { | ||
211 | u32 val; | ||
212 | int ret; | ||
213 | |||
214 | ret = sun4i_backend_drm_format_to_layer(NULL, fmt, &val); | ||
215 | if (ret) { | ||
216 | DRM_DEBUG_DRIVER("Invalid format\n"); | ||
217 | return ret; | ||
218 | } | ||
219 | |||
220 | regmap_update_bits(backend->engine.regs, | ||
221 | SUN4I_BACKEND_ATTCTL_REG0(layer), | ||
222 | SUN4I_BACKEND_ATTCTL_REG0_LAY_VDOEN, | ||
223 | SUN4I_BACKEND_ATTCTL_REG0_LAY_VDOEN); | ||
224 | |||
225 | regmap_update_bits(backend->engine.regs, | ||
226 | SUN4I_BACKEND_ATTCTL_REG1(layer), | ||
227 | SUN4I_BACKEND_ATTCTL_REG1_LAY_FBFMT, val); | ||
228 | |||
229 | return 0; | ||
230 | } | ||
231 | |||
213 | int sun4i_backend_update_layer_buffer(struct sun4i_backend *backend, | 232 | int sun4i_backend_update_layer_buffer(struct sun4i_backend *backend, |
214 | int layer, struct drm_plane *plane) | 233 | int layer, struct drm_plane *plane) |
215 | { | 234 | { |
@@ -218,6 +237,12 @@ int sun4i_backend_update_layer_buffer(struct sun4i_backend *backend, | |||
218 | u32 lo_paddr, hi_paddr; | 237 | u32 lo_paddr, hi_paddr; |
219 | dma_addr_t paddr; | 238 | dma_addr_t paddr; |
220 | 239 | ||
240 | /* Set the line width */ | ||
241 | DRM_DEBUG_DRIVER("Layer line width: %d bits\n", fb->pitches[0] * 8); | ||
242 | regmap_write(backend->engine.regs, | ||
243 | SUN4I_BACKEND_LAYLINEWIDTH_REG(layer), | ||
244 | fb->pitches[0] * 8); | ||
245 | |||
221 | /* Get the start of the displayed memory */ | 246 | /* Get the start of the displayed memory */ |
222 | paddr = drm_fb_cma_get_gem_addr(fb, state, 0); | 247 | paddr = drm_fb_cma_get_gem_addr(fb, state, 0); |
223 | DRM_DEBUG_DRIVER("Setting buffer address to %pad\n", &paddr); | 248 | DRM_DEBUG_DRIVER("Setting buffer address to %pad\n", &paddr); |
@@ -246,6 +271,176 @@ int sun4i_backend_update_layer_buffer(struct sun4i_backend *backend, | |||
246 | return 0; | 271 | return 0; |
247 | } | 272 | } |
248 | 273 | ||
274 | int sun4i_backend_update_layer_zpos(struct sun4i_backend *backend, int layer, | ||
275 | struct drm_plane *plane) | ||
276 | { | ||
277 | struct drm_plane_state *state = plane->state; | ||
278 | unsigned int priority = state->normalized_zpos; | ||
279 | |||
280 | DRM_DEBUG_DRIVER("Setting layer %d's priority to %d\n", layer, priority); | ||
281 | |||
282 | regmap_update_bits(backend->engine.regs, SUN4I_BACKEND_ATTCTL_REG0(layer), | ||
283 | SUN4I_BACKEND_ATTCTL_REG0_LAY_PRISEL_MASK, | ||
284 | SUN4I_BACKEND_ATTCTL_REG0_LAY_PRISEL(priority)); | ||
285 | |||
286 | return 0; | ||
287 | } | ||
288 | |||
289 | static bool sun4i_backend_plane_uses_scaler(struct drm_plane_state *state) | ||
290 | { | ||
291 | u16 src_h = state->src_h >> 16; | ||
292 | u16 src_w = state->src_w >> 16; | ||
293 | |||
294 | DRM_DEBUG_DRIVER("Input size %dx%d, output size %dx%d\n", | ||
295 | src_w, src_h, state->crtc_w, state->crtc_h); | ||
296 | |||
297 | if ((state->crtc_h != src_h) || (state->crtc_w != src_w)) | ||
298 | return true; | ||
299 | |||
300 | return false; | ||
301 | } | ||
302 | |||
303 | static bool sun4i_backend_plane_uses_frontend(struct drm_plane_state *state) | ||
304 | { | ||
305 | struct sun4i_layer *layer = plane_to_sun4i_layer(state->plane); | ||
306 | struct sun4i_backend *backend = layer->backend; | ||
307 | |||
308 | if (IS_ERR(backend->frontend)) | ||
309 | return false; | ||
310 | |||
311 | return sun4i_backend_plane_uses_scaler(state); | ||
312 | } | ||
313 | |||
314 | static void sun4i_backend_atomic_begin(struct sunxi_engine *engine, | ||
315 | struct drm_crtc_state *old_state) | ||
316 | { | ||
317 | u32 val; | ||
318 | |||
319 | WARN_ON(regmap_read_poll_timeout(engine->regs, | ||
320 | SUN4I_BACKEND_REGBUFFCTL_REG, | ||
321 | val, !(val & SUN4I_BACKEND_REGBUFFCTL_LOADCTL), | ||
322 | 100, 50000)); | ||
323 | } | ||
324 | |||
325 | static int sun4i_backend_atomic_check(struct sunxi_engine *engine, | ||
326 | struct drm_crtc_state *crtc_state) | ||
327 | { | ||
328 | struct drm_atomic_state *state = crtc_state->state; | ||
329 | struct drm_device *drm = state->dev; | ||
330 | struct drm_plane *plane; | ||
331 | unsigned int num_planes = 0; | ||
332 | unsigned int num_alpha_planes = 0; | ||
333 | unsigned int num_frontend_planes = 0; | ||
334 | |||
335 | DRM_DEBUG_DRIVER("Starting checking our planes\n"); | ||
336 | |||
337 | if (!crtc_state->planes_changed) | ||
338 | return 0; | ||
339 | |||
340 | drm_for_each_plane_mask(plane, drm, crtc_state->plane_mask) { | ||
341 | struct drm_plane_state *plane_state = | ||
342 | drm_atomic_get_plane_state(state, plane); | ||
343 | struct sun4i_layer_state *layer_state = | ||
344 | state_to_sun4i_layer_state(plane_state); | ||
345 | struct drm_framebuffer *fb = plane_state->fb; | ||
346 | struct drm_format_name_buf format_name; | ||
347 | |||
348 | if (sun4i_backend_plane_uses_frontend(plane_state)) { | ||
349 | DRM_DEBUG_DRIVER("Using the frontend for plane %d\n", | ||
350 | plane->index); | ||
351 | |||
352 | layer_state->uses_frontend = true; | ||
353 | num_frontend_planes++; | ||
354 | } else { | ||
355 | layer_state->uses_frontend = false; | ||
356 | } | ||
357 | |||
358 | DRM_DEBUG_DRIVER("Plane FB format is %s\n", | ||
359 | drm_get_format_name(fb->format->format, | ||
360 | &format_name)); | ||
361 | if (fb->format->has_alpha) | ||
362 | num_alpha_planes++; | ||
363 | |||
364 | num_planes++; | ||
365 | } | ||
366 | |||
367 | /* | ||
368 | * The hardware is a bit unusual here. | ||
369 | * | ||
370 | * Even though it supports 4 layers, it does the composition | ||
371 | * in two separate steps. | ||
372 | * | ||
373 | * The first one is assigning a layer to one of its two | ||
374 | * pipes. If more that 1 layer is assigned to the same pipe, | ||
375 | * and if pixels overlaps, the pipe will take the pixel from | ||
376 | * the layer with the highest priority. | ||
377 | * | ||
378 | * The second step is the actual alpha blending, that takes | ||
379 | * the two pipes as input, and uses the eventual alpha | ||
380 | * component to do the transparency between the two. | ||
381 | * | ||
382 | * This two steps scenario makes us unable to guarantee a | ||
383 | * robust alpha blending between the 4 layers in all | ||
384 | * situations, since this means that we need to have one layer | ||
385 | * with alpha at the lowest position of our two pipes. | ||
386 | * | ||
387 | * However, we cannot even do that, since the hardware has a | ||
388 | * bug where the lowest plane of the lowest pipe (pipe 0, | ||
389 | * priority 0), if it has any alpha, will discard the pixel | ||
390 | * entirely and just display the pixels in the background | ||
391 | * color (black by default). | ||
392 | * | ||
393 | * This means that we effectively have only three valid | ||
394 | * configurations with alpha, all of them with the alpha being | ||
395 | * on pipe1 with the lowest position, which can be 1, 2 or 3 | ||
396 | * depending on the number of planes and their zpos. | ||
397 | */ | ||
398 | if (num_alpha_planes > SUN4I_BACKEND_NUM_ALPHA_LAYERS) { | ||
399 | DRM_DEBUG_DRIVER("Too many planes with alpha, rejecting...\n"); | ||
400 | return -EINVAL; | ||
401 | } | ||
402 | |||
403 | if (num_frontend_planes > SUN4I_BACKEND_NUM_FRONTEND_LAYERS) { | ||
404 | DRM_DEBUG_DRIVER("Too many planes going through the frontend, rejecting\n"); | ||
405 | return -EINVAL; | ||
406 | } | ||
407 | |||
408 | DRM_DEBUG_DRIVER("State valid with %u planes, %u alpha, %u video\n", | ||
409 | num_planes, num_alpha_planes, num_frontend_planes); | ||
410 | |||
411 | return 0; | ||
412 | } | ||
413 | |||
414 | static void sun4i_backend_vblank_quirk(struct sunxi_engine *engine) | ||
415 | { | ||
416 | struct sun4i_backend *backend = engine_to_sun4i_backend(engine); | ||
417 | struct sun4i_frontend *frontend = backend->frontend; | ||
418 | |||
419 | if (!frontend) | ||
420 | return; | ||
421 | |||
422 | /* | ||
423 | * In a teardown scenario with the frontend involved, we have | ||
424 | * to keep the frontend enabled until the next vblank, and | ||
425 | * only then disable it. | ||
426 | * | ||
427 | * This is due to the fact that the backend will not take into | ||
428 | * account the new configuration (with the plane that used to | ||
429 | * be fed by the frontend now disabled) until we write to the | ||
430 | * commit bit and the hardware fetches the new configuration | ||
431 | * during the next vblank. | ||
432 | * | ||
433 | * So we keep the frontend around in order to prevent any | ||
434 | * visual artifacts. | ||
435 | */ | ||
436 | spin_lock(&backend->frontend_lock); | ||
437 | if (backend->frontend_teardown) { | ||
438 | sun4i_frontend_exit(frontend); | ||
439 | backend->frontend_teardown = false; | ||
440 | } | ||
441 | spin_unlock(&backend->frontend_lock); | ||
442 | }; | ||
443 | |||
249 | static int sun4i_backend_init_sat(struct device *dev) { | 444 | static int sun4i_backend_init_sat(struct device *dev) { |
250 | struct sun4i_backend *backend = dev_get_drvdata(dev); | 445 | struct sun4i_backend *backend = dev_get_drvdata(dev); |
251 | int ret; | 446 | int ret; |
@@ -330,11 +525,43 @@ static int sun4i_backend_of_get_id(struct device_node *node) | |||
330 | return ret; | 525 | return ret; |
331 | } | 526 | } |
332 | 527 | ||
528 | /* TODO: This needs to take multiple pipelines into account */ | ||
529 | static struct sun4i_frontend *sun4i_backend_find_frontend(struct sun4i_drv *drv, | ||
530 | struct device_node *node) | ||
531 | { | ||
532 | struct device_node *port, *ep, *remote; | ||
533 | struct sun4i_frontend *frontend; | ||
534 | |||
535 | port = of_graph_get_port_by_id(node, 0); | ||
536 | if (!port) | ||
537 | return ERR_PTR(-EINVAL); | ||
538 | |||
539 | for_each_available_child_of_node(port, ep) { | ||
540 | remote = of_graph_get_remote_port_parent(ep); | ||
541 | if (!remote) | ||
542 | continue; | ||
543 | |||
544 | /* does this node match any registered engines? */ | ||
545 | list_for_each_entry(frontend, &drv->frontend_list, list) { | ||
546 | if (remote == frontend->node) { | ||
547 | of_node_put(remote); | ||
548 | of_node_put(port); | ||
549 | return frontend; | ||
550 | } | ||
551 | } | ||
552 | } | ||
553 | |||
554 | return ERR_PTR(-EINVAL); | ||
555 | } | ||
556 | |||
333 | static const struct sunxi_engine_ops sun4i_backend_engine_ops = { | 557 | static const struct sunxi_engine_ops sun4i_backend_engine_ops = { |
558 | .atomic_begin = sun4i_backend_atomic_begin, | ||
559 | .atomic_check = sun4i_backend_atomic_check, | ||
334 | .commit = sun4i_backend_commit, | 560 | .commit = sun4i_backend_commit, |
335 | .layers_init = sun4i_layers_init, | 561 | .layers_init = sun4i_layers_init, |
336 | .apply_color_correction = sun4i_backend_apply_color_correction, | 562 | .apply_color_correction = sun4i_backend_apply_color_correction, |
337 | .disable_color_correction = sun4i_backend_disable_color_correction, | 563 | .disable_color_correction = sun4i_backend_disable_color_correction, |
564 | .vblank_quirk = sun4i_backend_vblank_quirk, | ||
338 | }; | 565 | }; |
339 | 566 | ||
340 | static struct regmap_config sun4i_backend_regmap_config = { | 567 | static struct regmap_config sun4i_backend_regmap_config = { |
@@ -360,6 +587,7 @@ static int sun4i_backend_bind(struct device *dev, struct device *master, | |||
360 | if (!backend) | 587 | if (!backend) |
361 | return -ENOMEM; | 588 | return -ENOMEM; |
362 | dev_set_drvdata(dev, backend); | 589 | dev_set_drvdata(dev, backend); |
590 | spin_lock_init(&backend->frontend_lock); | ||
363 | 591 | ||
364 | backend->engine.node = dev->of_node; | 592 | backend->engine.node = dev->of_node; |
365 | backend->engine.ops = &sun4i_backend_engine_ops; | 593 | backend->engine.ops = &sun4i_backend_engine_ops; |
@@ -367,6 +595,10 @@ static int sun4i_backend_bind(struct device *dev, struct device *master, | |||
367 | if (backend->engine.id < 0) | 595 | if (backend->engine.id < 0) |
368 | return backend->engine.id; | 596 | return backend->engine.id; |
369 | 597 | ||
598 | backend->frontend = sun4i_backend_find_frontend(drv, dev->of_node); | ||
599 | if (IS_ERR(backend->frontend)) | ||
600 | dev_warn(dev, "Couldn't find matching frontend, frontend features disabled\n"); | ||
601 | |||
370 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 602 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
371 | regs = devm_ioremap_resource(dev, res); | 603 | regs = devm_ioremap_resource(dev, res); |
372 | if (IS_ERR(regs)) | 604 | if (IS_ERR(regs)) |
diff --git a/drivers/gpu/drm/sun4i/sun4i_backend.h b/drivers/gpu/drm/sun4i/sun4i_backend.h index ac3cc029f5cd..52e77591186a 100644 --- a/drivers/gpu/drm/sun4i/sun4i_backend.h +++ b/drivers/gpu/drm/sun4i/sun4i_backend.h | |||
@@ -72,6 +72,7 @@ | |||
72 | #define SUN4I_BACKEND_ATTCTL_REG0_LAY_PIPESEL(x) ((x) << 15) | 72 | #define SUN4I_BACKEND_ATTCTL_REG0_LAY_PIPESEL(x) ((x) << 15) |
73 | #define SUN4I_BACKEND_ATTCTL_REG0_LAY_PRISEL_MASK GENMASK(11, 10) | 73 | #define SUN4I_BACKEND_ATTCTL_REG0_LAY_PRISEL_MASK GENMASK(11, 10) |
74 | #define SUN4I_BACKEND_ATTCTL_REG0_LAY_PRISEL(x) ((x) << 10) | 74 | #define SUN4I_BACKEND_ATTCTL_REG0_LAY_PRISEL(x) ((x) << 10) |
75 | #define SUN4I_BACKEND_ATTCTL_REG0_LAY_VDOEN BIT(1) | ||
75 | 76 | ||
76 | #define SUN4I_BACKEND_ATTCTL_REG1(l) (0x8a0 + (0x4 * (l))) | 77 | #define SUN4I_BACKEND_ATTCTL_REG1(l) (0x8a0 + (0x4 * (l))) |
77 | #define SUN4I_BACKEND_ATTCTL_REG1_LAY_HSCAFCT GENMASK(15, 14) | 78 | #define SUN4I_BACKEND_ATTCTL_REG1_LAY_HSCAFCT GENMASK(15, 14) |
@@ -111,7 +112,9 @@ | |||
111 | #define SUN4I_BACKEND_SPRALPHACTL_REG 0x90c | 112 | #define SUN4I_BACKEND_SPRALPHACTL_REG 0x90c |
112 | #define SUN4I_BACKEND_IYUVCTL_REG 0x920 | 113 | #define SUN4I_BACKEND_IYUVCTL_REG 0x920 |
113 | #define SUN4I_BACKEND_IYUVADD_REG(c) (0x930 + (0x4 * (c))) | 114 | #define SUN4I_BACKEND_IYUVADD_REG(c) (0x930 + (0x4 * (c))) |
114 | #define SUN4I_BACKEND_IYUVLINEWITDTH_REG(c) (0x940 + (0x4 * (c))) | 115 | |
116 | #define SUN4I_BACKEND_IYUVLINEWIDTH_REG(c) (0x940 + (0x4 * (c))) | ||
117 | |||
115 | #define SUN4I_BACKEND_YGCOEF_REG(c) (0x950 + (0x4 * (c))) | 118 | #define SUN4I_BACKEND_YGCOEF_REG(c) (0x950 + (0x4 * (c))) |
116 | #define SUN4I_BACKEND_YGCONS_REG 0x95c | 119 | #define SUN4I_BACKEND_YGCONS_REG 0x95c |
117 | #define SUN4I_BACKEND_URCOEF_REG(c) (0x960 + (0x4 * (c))) | 120 | #define SUN4I_BACKEND_URCOEF_REG(c) (0x960 + (0x4 * (c))) |
@@ -143,8 +146,13 @@ | |||
143 | #define SUN4I_BACKEND_HWCCOLORTAB_OFF 0x4c00 | 146 | #define SUN4I_BACKEND_HWCCOLORTAB_OFF 0x4c00 |
144 | #define SUN4I_BACKEND_PIPE_OFF(p) (0x5000 + (0x400 * (p))) | 147 | #define SUN4I_BACKEND_PIPE_OFF(p) (0x5000 + (0x400 * (p))) |
145 | 148 | ||
149 | #define SUN4I_BACKEND_NUM_LAYERS 4 | ||
150 | #define SUN4I_BACKEND_NUM_ALPHA_LAYERS 1 | ||
151 | #define SUN4I_BACKEND_NUM_FRONTEND_LAYERS 1 | ||
152 | |||
146 | struct sun4i_backend { | 153 | struct sun4i_backend { |
147 | struct sunxi_engine engine; | 154 | struct sunxi_engine engine; |
155 | struct sun4i_frontend *frontend; | ||
148 | 156 | ||
149 | struct reset_control *reset; | 157 | struct reset_control *reset; |
150 | 158 | ||
@@ -154,6 +162,10 @@ struct sun4i_backend { | |||
154 | 162 | ||
155 | struct clk *sat_clk; | 163 | struct clk *sat_clk; |
156 | struct reset_control *sat_reset; | 164 | struct reset_control *sat_reset; |
165 | |||
166 | /* Protects against races in the frontend teardown */ | ||
167 | spinlock_t frontend_lock; | ||
168 | bool frontend_teardown; | ||
157 | }; | 169 | }; |
158 | 170 | ||
159 | static inline struct sun4i_backend * | 171 | static inline struct sun4i_backend * |
@@ -170,5 +182,9 @@ int sun4i_backend_update_layer_formats(struct sun4i_backend *backend, | |||
170 | int layer, struct drm_plane *plane); | 182 | int layer, struct drm_plane *plane); |
171 | int sun4i_backend_update_layer_buffer(struct sun4i_backend *backend, | 183 | int sun4i_backend_update_layer_buffer(struct sun4i_backend *backend, |
172 | int layer, struct drm_plane *plane); | 184 | int layer, struct drm_plane *plane); |
185 | int sun4i_backend_update_layer_frontend(struct sun4i_backend *backend, | ||
186 | int layer, uint32_t in_fmt); | ||
187 | int sun4i_backend_update_layer_zpos(struct sun4i_backend *backend, | ||
188 | int layer, struct drm_plane *plane); | ||
173 | 189 | ||
174 | #endif /* _SUN4I_BACKEND_H_ */ | 190 | #endif /* _SUN4I_BACKEND_H_ */ |
diff --git a/drivers/gpu/drm/sun4i/sun4i_crtc.c b/drivers/gpu/drm/sun4i/sun4i_crtc.c index 5decae0069d0..3b2d11b675e8 100644 --- a/drivers/gpu/drm/sun4i/sun4i_crtc.c +++ b/drivers/gpu/drm/sun4i/sun4i_crtc.c | |||
@@ -25,6 +25,7 @@ | |||
25 | 25 | ||
26 | #include <video/videomode.h> | 26 | #include <video/videomode.h> |
27 | 27 | ||
28 | #include "sun4i_backend.h" | ||
28 | #include "sun4i_crtc.h" | 29 | #include "sun4i_crtc.h" |
29 | #include "sun4i_drv.h" | 30 | #include "sun4i_drv.h" |
30 | #include "sunxi_engine.h" | 31 | #include "sunxi_engine.h" |
@@ -46,11 +47,25 @@ static struct drm_encoder *sun4i_crtc_get_encoder(struct drm_crtc *crtc) | |||
46 | return NULL; | 47 | return NULL; |
47 | } | 48 | } |
48 | 49 | ||
50 | static int sun4i_crtc_atomic_check(struct drm_crtc *crtc, | ||
51 | struct drm_crtc_state *state) | ||
52 | { | ||
53 | struct sun4i_crtc *scrtc = drm_crtc_to_sun4i_crtc(crtc); | ||
54 | struct sunxi_engine *engine = scrtc->engine; | ||
55 | int ret = 0; | ||
56 | |||
57 | if (engine && engine->ops && engine->ops->atomic_check) | ||
58 | ret = engine->ops->atomic_check(engine, state); | ||
59 | |||
60 | return ret; | ||
61 | } | ||
62 | |||
49 | static void sun4i_crtc_atomic_begin(struct drm_crtc *crtc, | 63 | static void sun4i_crtc_atomic_begin(struct drm_crtc *crtc, |
50 | struct drm_crtc_state *old_state) | 64 | struct drm_crtc_state *old_state) |
51 | { | 65 | { |
52 | struct sun4i_crtc *scrtc = drm_crtc_to_sun4i_crtc(crtc); | 66 | struct sun4i_crtc *scrtc = drm_crtc_to_sun4i_crtc(crtc); |
53 | struct drm_device *dev = crtc->dev; | 67 | struct drm_device *dev = crtc->dev; |
68 | struct sunxi_engine *engine = scrtc->engine; | ||
54 | unsigned long flags; | 69 | unsigned long flags; |
55 | 70 | ||
56 | if (crtc->state->event) { | 71 | if (crtc->state->event) { |
@@ -60,7 +75,10 @@ static void sun4i_crtc_atomic_begin(struct drm_crtc *crtc, | |||
60 | scrtc->event = crtc->state->event; | 75 | scrtc->event = crtc->state->event; |
61 | spin_unlock_irqrestore(&dev->event_lock, flags); | 76 | spin_unlock_irqrestore(&dev->event_lock, flags); |
62 | crtc->state->event = NULL; | 77 | crtc->state->event = NULL; |
63 | } | 78 | } |
79 | |||
80 | if (engine->ops->atomic_begin) | ||
81 | engine->ops->atomic_begin(engine, old_state); | ||
64 | } | 82 | } |
65 | 83 | ||
66 | static void sun4i_crtc_atomic_flush(struct drm_crtc *crtc, | 84 | static void sun4i_crtc_atomic_flush(struct drm_crtc *crtc, |
@@ -125,6 +143,7 @@ static void sun4i_crtc_mode_set_nofb(struct drm_crtc *crtc) | |||
125 | } | 143 | } |
126 | 144 | ||
127 | static const struct drm_crtc_helper_funcs sun4i_crtc_helper_funcs = { | 145 | static const struct drm_crtc_helper_funcs sun4i_crtc_helper_funcs = { |
146 | .atomic_check = sun4i_crtc_atomic_check, | ||
128 | .atomic_begin = sun4i_crtc_atomic_begin, | 147 | .atomic_begin = sun4i_crtc_atomic_begin, |
129 | .atomic_flush = sun4i_crtc_atomic_flush, | 148 | .atomic_flush = sun4i_crtc_atomic_flush, |
130 | .atomic_enable = sun4i_crtc_atomic_enable, | 149 | .atomic_enable = sun4i_crtc_atomic_enable, |
diff --git a/drivers/gpu/drm/sun4i/sun4i_drv.c b/drivers/gpu/drm/sun4i/sun4i_drv.c index 4570da0227b4..3957c2ff6870 100644 --- a/drivers/gpu/drm/sun4i/sun4i_drv.c +++ b/drivers/gpu/drm/sun4i/sun4i_drv.c | |||
@@ -23,6 +23,7 @@ | |||
23 | #include <drm/drm_of.h> | 23 | #include <drm/drm_of.h> |
24 | 24 | ||
25 | #include "sun4i_drv.h" | 25 | #include "sun4i_drv.h" |
26 | #include "sun4i_frontend.h" | ||
26 | #include "sun4i_framebuffer.h" | 27 | #include "sun4i_framebuffer.h" |
27 | #include "sun4i_tcon.h" | 28 | #include "sun4i_tcon.h" |
28 | 29 | ||
@@ -91,6 +92,7 @@ static int sun4i_drv_bind(struct device *dev) | |||
91 | goto free_drm; | 92 | goto free_drm; |
92 | } | 93 | } |
93 | drm->dev_private = drv; | 94 | drm->dev_private = drv; |
95 | INIT_LIST_HEAD(&drv->frontend_list); | ||
94 | INIT_LIST_HEAD(&drv->engine_list); | 96 | INIT_LIST_HEAD(&drv->engine_list); |
95 | INIT_LIST_HEAD(&drv->tcon_list); | 97 | INIT_LIST_HEAD(&drv->tcon_list); |
96 | 98 | ||
@@ -177,6 +179,14 @@ static bool sun4i_drv_node_is_frontend(struct device_node *node) | |||
177 | of_device_is_compatible(node, "allwinner,sun8i-a33-display-frontend"); | 179 | of_device_is_compatible(node, "allwinner,sun8i-a33-display-frontend"); |
178 | } | 180 | } |
179 | 181 | ||
182 | static bool sun4i_drv_node_is_supported_frontend(struct device_node *node) | ||
183 | { | ||
184 | if (IS_ENABLED(CONFIG_DRM_SUN4I_BACKEND)) | ||
185 | return !!of_match_node(sun4i_frontend_of_table, node); | ||
186 | |||
187 | return false; | ||
188 | } | ||
189 | |||
180 | static bool sun4i_drv_node_is_tcon(struct device_node *node) | 190 | static bool sun4i_drv_node_is_tcon(struct device_node *node) |
181 | { | 191 | { |
182 | return !!of_match_node(sun4i_tcon_of_table, node); | 192 | return !!of_match_node(sun4i_tcon_of_table, node); |
@@ -225,9 +235,11 @@ static int sun4i_drv_add_endpoints(struct device *dev, | |||
225 | int count = 0; | 235 | int count = 0; |
226 | 236 | ||
227 | /* | 237 | /* |
228 | * We don't support the frontend for now, so we will never | 238 | * The frontend has been disabled in some of our old device |
229 | * have a device bound. Just skip over it, but we still want | 239 | * trees. If we find a node that is the frontend and is |
230 | * the rest our pipeline to be added. | 240 | * disabled, we should just follow through and parse its |
241 | * child, but without adding it to the component list. | ||
242 | * Otherwise, we obviously want to add it to the list. | ||
231 | */ | 243 | */ |
232 | if (!sun4i_drv_node_is_frontend(node) && | 244 | if (!sun4i_drv_node_is_frontend(node) && |
233 | !of_device_is_available(node)) | 245 | !of_device_is_available(node)) |
@@ -240,7 +252,14 @@ static int sun4i_drv_add_endpoints(struct device *dev, | |||
240 | if (sun4i_drv_node_is_connector(node)) | 252 | if (sun4i_drv_node_is_connector(node)) |
241 | return 0; | 253 | return 0; |
242 | 254 | ||
243 | if (!sun4i_drv_node_is_frontend(node)) { | 255 | /* |
256 | * If the device is either just a regular device, or an | ||
257 | * enabled frontend supported by the driver, we add it to our | ||
258 | * component list. | ||
259 | */ | ||
260 | if (!sun4i_drv_node_is_frontend(node) || | ||
261 | (sun4i_drv_node_is_supported_frontend(node) && | ||
262 | of_device_is_available(node))) { | ||
244 | /* Add current component */ | 263 | /* Add current component */ |
245 | DRM_DEBUG_DRIVER("Adding component %pOF\n", node); | 264 | DRM_DEBUG_DRIVER("Adding component %pOF\n", node); |
246 | drm_of_component_match_add(dev, match, compare_of, node); | 265 | drm_of_component_match_add(dev, match, compare_of, node); |
diff --git a/drivers/gpu/drm/sun4i/sun4i_drv.h b/drivers/gpu/drm/sun4i/sun4i_drv.h index 2825f140da54..5750b8ce8b31 100644 --- a/drivers/gpu/drm/sun4i/sun4i_drv.h +++ b/drivers/gpu/drm/sun4i/sun4i_drv.h | |||
@@ -19,6 +19,7 @@ | |||
19 | 19 | ||
20 | struct sun4i_drv { | 20 | struct sun4i_drv { |
21 | struct list_head engine_list; | 21 | struct list_head engine_list; |
22 | struct list_head frontend_list; | ||
22 | struct list_head tcon_list; | 23 | struct list_head tcon_list; |
23 | }; | 24 | }; |
24 | 25 | ||
diff --git a/drivers/gpu/drm/sun4i/sun4i_framebuffer.c b/drivers/gpu/drm/sun4i/sun4i_framebuffer.c index 38a36c0dfa2f..5f29850ef8ac 100644 --- a/drivers/gpu/drm/sun4i/sun4i_framebuffer.c +++ b/drivers/gpu/drm/sun4i/sun4i_framebuffer.c | |||
@@ -10,6 +10,7 @@ | |||
10 | * the License, or (at your option) any later version. | 10 | * the License, or (at your option) any later version. |
11 | */ | 11 | */ |
12 | 12 | ||
13 | #include <drm/drm_atomic.h> | ||
13 | #include <drm/drm_atomic_helper.h> | 14 | #include <drm/drm_atomic_helper.h> |
14 | #include <drm/drm_fb_helper.h> | 15 | #include <drm/drm_fb_helper.h> |
15 | #include <drm/drm_fb_cma_helper.h> | 16 | #include <drm/drm_fb_cma_helper.h> |
@@ -19,13 +20,33 @@ | |||
19 | #include "sun4i_drv.h" | 20 | #include "sun4i_drv.h" |
20 | #include "sun4i_framebuffer.h" | 21 | #include "sun4i_framebuffer.h" |
21 | 22 | ||
23 | static int sun4i_de_atomic_check(struct drm_device *dev, | ||
24 | struct drm_atomic_state *state) | ||
25 | { | ||
26 | int ret; | ||
27 | |||
28 | ret = drm_atomic_helper_check_modeset(dev, state); | ||
29 | if (ret) | ||
30 | return ret; | ||
31 | |||
32 | ret = drm_atomic_normalize_zpos(dev, state); | ||
33 | if (ret) | ||
34 | return ret; | ||
35 | |||
36 | return drm_atomic_helper_check_planes(dev, state); | ||
37 | } | ||
38 | |||
22 | static const struct drm_mode_config_funcs sun4i_de_mode_config_funcs = { | 39 | static const struct drm_mode_config_funcs sun4i_de_mode_config_funcs = { |
23 | .output_poll_changed = drm_fb_helper_output_poll_changed, | 40 | .output_poll_changed = drm_fb_helper_output_poll_changed, |
24 | .atomic_check = drm_atomic_helper_check, | 41 | .atomic_check = sun4i_de_atomic_check, |
25 | .atomic_commit = drm_atomic_helper_commit, | 42 | .atomic_commit = drm_atomic_helper_commit, |
26 | .fb_create = drm_gem_fb_create, | 43 | .fb_create = drm_gem_fb_create, |
27 | }; | 44 | }; |
28 | 45 | ||
46 | static struct drm_mode_config_helper_funcs sun4i_de_mode_config_helpers = { | ||
47 | .atomic_commit_tail = drm_atomic_helper_commit_tail_rpm, | ||
48 | }; | ||
49 | |||
29 | int sun4i_framebuffer_init(struct drm_device *drm) | 50 | int sun4i_framebuffer_init(struct drm_device *drm) |
30 | { | 51 | { |
31 | drm_mode_config_reset(drm); | 52 | drm_mode_config_reset(drm); |
@@ -34,6 +55,7 @@ int sun4i_framebuffer_init(struct drm_device *drm) | |||
34 | drm->mode_config.max_height = 8192; | 55 | drm->mode_config.max_height = 8192; |
35 | 56 | ||
36 | drm->mode_config.funcs = &sun4i_de_mode_config_funcs; | 57 | drm->mode_config.funcs = &sun4i_de_mode_config_funcs; |
58 | drm->mode_config.helper_private = &sun4i_de_mode_config_helpers; | ||
37 | 59 | ||
38 | return drm_fb_cma_fbdev_init(drm, 32, 0); | 60 | return drm_fb_cma_fbdev_init(drm, 32, 0); |
39 | } | 61 | } |
diff --git a/drivers/gpu/drm/sun4i/sun4i_frontend.c b/drivers/gpu/drm/sun4i/sun4i_frontend.c new file mode 100644 index 000000000000..ddf6cfa6dd23 --- /dev/null +++ b/drivers/gpu/drm/sun4i/sun4i_frontend.c | |||
@@ -0,0 +1,389 @@ | |||
1 | // SPDX-License-Identifier: GPL-2.0+ | ||
2 | /* | ||
3 | * Copyright (C) 2017 Free Electrons | ||
4 | * Maxime Ripard <maxime.ripard@free-electrons.com> | ||
5 | */ | ||
6 | #include <drm/drmP.h> | ||
7 | #include <drm/drm_gem_cma_helper.h> | ||
8 | #include <drm/drm_fb_cma_helper.h> | ||
9 | |||
10 | #include <linux/clk.h> | ||
11 | #include <linux/component.h> | ||
12 | #include <linux/module.h> | ||
13 | #include <linux/platform_device.h> | ||
14 | #include <linux/pm_runtime.h> | ||
15 | #include <linux/regmap.h> | ||
16 | #include <linux/reset.h> | ||
17 | |||
18 | #include "sun4i_drv.h" | ||
19 | #include "sun4i_frontend.h" | ||
20 | |||
21 | static const u32 sun4i_frontend_vert_coef[32] = { | ||
22 | 0x00004000, 0x000140ff, 0x00033ffe, 0x00043ffd, | ||
23 | 0x00063efc, 0xff083dfc, 0x000a3bfb, 0xff0d39fb, | ||
24 | 0xff0f37fb, 0xff1136fa, 0xfe1433fb, 0xfe1631fb, | ||
25 | 0xfd192ffb, 0xfd1c2cfb, 0xfd1f29fb, 0xfc2127fc, | ||
26 | 0xfc2424fc, 0xfc2721fc, 0xfb291ffd, 0xfb2c1cfd, | ||
27 | 0xfb2f19fd, 0xfb3116fe, 0xfb3314fe, 0xfa3611ff, | ||
28 | 0xfb370fff, 0xfb390dff, 0xfb3b0a00, 0xfc3d08ff, | ||
29 | 0xfc3e0600, 0xfd3f0400, 0xfe3f0300, 0xff400100, | ||
30 | }; | ||
31 | |||
32 | static const u32 sun4i_frontend_horz_coef[64] = { | ||
33 | 0x40000000, 0x00000000, 0x40fe0000, 0x0000ff03, | ||
34 | 0x3ffd0000, 0x0000ff05, 0x3ffc0000, 0x0000ff06, | ||
35 | 0x3efb0000, 0x0000ff08, 0x3dfb0000, 0x0000ff09, | ||
36 | 0x3bfa0000, 0x0000fe0d, 0x39fa0000, 0x0000fe0f, | ||
37 | 0x38fa0000, 0x0000fe10, 0x36fa0000, 0x0000fe12, | ||
38 | 0x33fa0000, 0x0000fd16, 0x31fa0000, 0x0000fd18, | ||
39 | 0x2ffa0000, 0x0000fd1a, 0x2cfa0000, 0x0000fc1e, | ||
40 | 0x29fa0000, 0x0000fc21, 0x27fb0000, 0x0000fb23, | ||
41 | 0x24fb0000, 0x0000fb26, 0x21fb0000, 0x0000fb29, | ||
42 | 0x1ffc0000, 0x0000fa2b, 0x1cfc0000, 0x0000fa2e, | ||
43 | 0x19fd0000, 0x0000fa30, 0x16fd0000, 0x0000fa33, | ||
44 | 0x14fd0000, 0x0000fa35, 0x11fe0000, 0x0000fa37, | ||
45 | 0x0ffe0000, 0x0000fa39, 0x0dfe0000, 0x0000fa3b, | ||
46 | 0x0afe0000, 0x0000fa3e, 0x08ff0000, 0x0000fb3e, | ||
47 | 0x06ff0000, 0x0000fb40, 0x05ff0000, 0x0000fc40, | ||
48 | 0x03ff0000, 0x0000fd41, 0x01ff0000, 0x0000fe42, | ||
49 | }; | ||
50 | |||
51 | static void sun4i_frontend_scaler_init(struct sun4i_frontend *frontend) | ||
52 | { | ||
53 | int i; | ||
54 | |||
55 | for (i = 0; i < 32; i++) { | ||
56 | regmap_write(frontend->regs, SUN4I_FRONTEND_CH0_HORZCOEF0_REG(i), | ||
57 | sun4i_frontend_horz_coef[2 * i]); | ||
58 | regmap_write(frontend->regs, SUN4I_FRONTEND_CH1_HORZCOEF0_REG(i), | ||
59 | sun4i_frontend_horz_coef[2 * i]); | ||
60 | regmap_write(frontend->regs, SUN4I_FRONTEND_CH0_HORZCOEF1_REG(i), | ||
61 | sun4i_frontend_horz_coef[2 * i + 1]); | ||
62 | regmap_write(frontend->regs, SUN4I_FRONTEND_CH1_HORZCOEF1_REG(i), | ||
63 | sun4i_frontend_horz_coef[2 * i + 1]); | ||
64 | regmap_write(frontend->regs, SUN4I_FRONTEND_CH0_VERTCOEF_REG(i), | ||
65 | sun4i_frontend_vert_coef[i]); | ||
66 | regmap_write(frontend->regs, SUN4I_FRONTEND_CH1_VERTCOEF_REG(i), | ||
67 | sun4i_frontend_vert_coef[i]); | ||
68 | } | ||
69 | |||
70 | regmap_update_bits(frontend->regs, SUN4I_FRONTEND_FRM_CTRL_REG, | ||
71 | SUN4I_FRONTEND_FRM_CTRL_COEF_ACCESS_CTRL, | ||
72 | SUN4I_FRONTEND_FRM_CTRL_COEF_ACCESS_CTRL); | ||
73 | } | ||
74 | |||
75 | int sun4i_frontend_init(struct sun4i_frontend *frontend) | ||
76 | { | ||
77 | return pm_runtime_get_sync(frontend->dev); | ||
78 | } | ||
79 | EXPORT_SYMBOL(sun4i_frontend_init); | ||
80 | |||
81 | void sun4i_frontend_exit(struct sun4i_frontend *frontend) | ||
82 | { | ||
83 | pm_runtime_put(frontend->dev); | ||
84 | } | ||
85 | EXPORT_SYMBOL(sun4i_frontend_exit); | ||
86 | |||
87 | void sun4i_frontend_update_buffer(struct sun4i_frontend *frontend, | ||
88 | struct drm_plane *plane) | ||
89 | { | ||
90 | struct drm_plane_state *state = plane->state; | ||
91 | struct drm_framebuffer *fb = state->fb; | ||
92 | dma_addr_t paddr; | ||
93 | |||
94 | /* Set the line width */ | ||
95 | DRM_DEBUG_DRIVER("Frontend stride: %d bytes\n", fb->pitches[0]); | ||
96 | regmap_write(frontend->regs, SUN4I_FRONTEND_LINESTRD0_REG, | ||
97 | fb->pitches[0]); | ||
98 | |||
99 | /* Set the physical address of the buffer in memory */ | ||
100 | paddr = drm_fb_cma_get_gem_addr(fb, state, 0); | ||
101 | paddr -= PHYS_OFFSET; | ||
102 | DRM_DEBUG_DRIVER("Setting buffer address to %pad\n", &paddr); | ||
103 | regmap_write(frontend->regs, SUN4I_FRONTEND_BUF_ADDR0_REG, paddr); | ||
104 | } | ||
105 | EXPORT_SYMBOL(sun4i_frontend_update_buffer); | ||
106 | |||
107 | static int sun4i_frontend_drm_format_to_input_fmt(uint32_t fmt, u32 *val) | ||
108 | { | ||
109 | switch (fmt) { | ||
110 | case DRM_FORMAT_ARGB8888: | ||
111 | *val = 5; | ||
112 | return 0; | ||
113 | |||
114 | default: | ||
115 | return -EINVAL; | ||
116 | } | ||
117 | } | ||
118 | |||
119 | static int sun4i_frontend_drm_format_to_output_fmt(uint32_t fmt, u32 *val) | ||
120 | { | ||
121 | switch (fmt) { | ||
122 | case DRM_FORMAT_XRGB8888: | ||
123 | case DRM_FORMAT_ARGB8888: | ||
124 | *val = 2; | ||
125 | return 0; | ||
126 | |||
127 | default: | ||
128 | return -EINVAL; | ||
129 | } | ||
130 | } | ||
131 | |||
132 | int sun4i_frontend_update_formats(struct sun4i_frontend *frontend, | ||
133 | struct drm_plane *plane, uint32_t out_fmt) | ||
134 | { | ||
135 | struct drm_plane_state *state = plane->state; | ||
136 | struct drm_framebuffer *fb = state->fb; | ||
137 | u32 out_fmt_val; | ||
138 | u32 in_fmt_val; | ||
139 | int ret; | ||
140 | |||
141 | ret = sun4i_frontend_drm_format_to_input_fmt(fb->format->format, | ||
142 | &in_fmt_val); | ||
143 | if (ret) { | ||
144 | DRM_DEBUG_DRIVER("Invalid input format\n"); | ||
145 | return ret; | ||
146 | } | ||
147 | |||
148 | ret = sun4i_frontend_drm_format_to_output_fmt(out_fmt, &out_fmt_val); | ||
149 | if (ret) { | ||
150 | DRM_DEBUG_DRIVER("Invalid output format\n"); | ||
151 | return ret; | ||
152 | } | ||
153 | |||
154 | /* | ||
155 | * I have no idea what this does exactly, but it seems to be | ||
156 | * related to the scaler FIR filter phase parameters. | ||
157 | */ | ||
158 | regmap_write(frontend->regs, SUN4I_FRONTEND_CH0_HORZPHASE_REG, 0x400); | ||
159 | regmap_write(frontend->regs, SUN4I_FRONTEND_CH1_HORZPHASE_REG, 0x400); | ||
160 | regmap_write(frontend->regs, SUN4I_FRONTEND_CH0_VERTPHASE0_REG, 0x400); | ||
161 | regmap_write(frontend->regs, SUN4I_FRONTEND_CH1_VERTPHASE0_REG, 0x400); | ||
162 | regmap_write(frontend->regs, SUN4I_FRONTEND_CH0_VERTPHASE1_REG, 0x400); | ||
163 | regmap_write(frontend->regs, SUN4I_FRONTEND_CH1_VERTPHASE1_REG, 0x400); | ||
164 | |||
165 | regmap_write(frontend->regs, SUN4I_FRONTEND_INPUT_FMT_REG, | ||
166 | SUN4I_FRONTEND_INPUT_FMT_DATA_MOD(1) | | ||
167 | SUN4I_FRONTEND_INPUT_FMT_DATA_FMT(in_fmt_val) | | ||
168 | SUN4I_FRONTEND_INPUT_FMT_PS(1)); | ||
169 | |||
170 | /* | ||
171 | * TODO: It look like the A31 and A80 at least will need the | ||
172 | * bit 7 (ALPHA_EN) enabled when using a format with alpha (so | ||
173 | * ARGB8888). | ||
174 | */ | ||
175 | regmap_write(frontend->regs, SUN4I_FRONTEND_OUTPUT_FMT_REG, | ||
176 | SUN4I_FRONTEND_OUTPUT_FMT_DATA_FMT(out_fmt_val)); | ||
177 | |||
178 | return 0; | ||
179 | } | ||
180 | EXPORT_SYMBOL(sun4i_frontend_update_formats); | ||
181 | |||
182 | void sun4i_frontend_update_coord(struct sun4i_frontend *frontend, | ||
183 | struct drm_plane *plane) | ||
184 | { | ||
185 | struct drm_plane_state *state = plane->state; | ||
186 | |||
187 | /* Set height and width */ | ||
188 | DRM_DEBUG_DRIVER("Frontend size W: %u H: %u\n", | ||
189 | state->crtc_w, state->crtc_h); | ||
190 | regmap_write(frontend->regs, SUN4I_FRONTEND_CH0_INSIZE_REG, | ||
191 | SUN4I_FRONTEND_INSIZE(state->src_h >> 16, | ||
192 | state->src_w >> 16)); | ||
193 | regmap_write(frontend->regs, SUN4I_FRONTEND_CH1_INSIZE_REG, | ||
194 | SUN4I_FRONTEND_INSIZE(state->src_h >> 16, | ||
195 | state->src_w >> 16)); | ||
196 | |||
197 | regmap_write(frontend->regs, SUN4I_FRONTEND_CH0_OUTSIZE_REG, | ||
198 | SUN4I_FRONTEND_OUTSIZE(state->crtc_h, state->crtc_w)); | ||
199 | regmap_write(frontend->regs, SUN4I_FRONTEND_CH1_OUTSIZE_REG, | ||
200 | SUN4I_FRONTEND_OUTSIZE(state->crtc_h, state->crtc_w)); | ||
201 | |||
202 | regmap_write(frontend->regs, SUN4I_FRONTEND_CH0_HORZFACT_REG, | ||
203 | state->src_w / state->crtc_w); | ||
204 | regmap_write(frontend->regs, SUN4I_FRONTEND_CH1_HORZFACT_REG, | ||
205 | state->src_w / state->crtc_w); | ||
206 | |||
207 | regmap_write(frontend->regs, SUN4I_FRONTEND_CH0_VERTFACT_REG, | ||
208 | state->src_h / state->crtc_h); | ||
209 | regmap_write(frontend->regs, SUN4I_FRONTEND_CH1_VERTFACT_REG, | ||
210 | state->src_h / state->crtc_h); | ||
211 | |||
212 | regmap_write_bits(frontend->regs, SUN4I_FRONTEND_FRM_CTRL_REG, | ||
213 | SUN4I_FRONTEND_FRM_CTRL_REG_RDY, | ||
214 | SUN4I_FRONTEND_FRM_CTRL_REG_RDY); | ||
215 | } | ||
216 | EXPORT_SYMBOL(sun4i_frontend_update_coord); | ||
217 | |||
218 | int sun4i_frontend_enable(struct sun4i_frontend *frontend) | ||
219 | { | ||
220 | regmap_write_bits(frontend->regs, SUN4I_FRONTEND_FRM_CTRL_REG, | ||
221 | SUN4I_FRONTEND_FRM_CTRL_FRM_START, | ||
222 | SUN4I_FRONTEND_FRM_CTRL_FRM_START); | ||
223 | |||
224 | return 0; | ||
225 | } | ||
226 | EXPORT_SYMBOL(sun4i_frontend_enable); | ||
227 | |||
228 | static struct regmap_config sun4i_frontend_regmap_config = { | ||
229 | .reg_bits = 32, | ||
230 | .val_bits = 32, | ||
231 | .reg_stride = 4, | ||
232 | .max_register = 0x0a14, | ||
233 | }; | ||
234 | |||
235 | static int sun4i_frontend_bind(struct device *dev, struct device *master, | ||
236 | void *data) | ||
237 | { | ||
238 | struct platform_device *pdev = to_platform_device(dev); | ||
239 | struct sun4i_frontend *frontend; | ||
240 | struct drm_device *drm = data; | ||
241 | struct sun4i_drv *drv = drm->dev_private; | ||
242 | struct resource *res; | ||
243 | void __iomem *regs; | ||
244 | |||
245 | frontend = devm_kzalloc(dev, sizeof(*frontend), GFP_KERNEL); | ||
246 | if (!frontend) | ||
247 | return -ENOMEM; | ||
248 | |||
249 | dev_set_drvdata(dev, frontend); | ||
250 | frontend->dev = dev; | ||
251 | frontend->node = dev->of_node; | ||
252 | |||
253 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
254 | regs = devm_ioremap_resource(dev, res); | ||
255 | if (IS_ERR(regs)) | ||
256 | return PTR_ERR(regs); | ||
257 | |||
258 | frontend->regs = devm_regmap_init_mmio(dev, regs, | ||
259 | &sun4i_frontend_regmap_config); | ||
260 | if (IS_ERR(frontend->regs)) { | ||
261 | dev_err(dev, "Couldn't create the frontend regmap\n"); | ||
262 | return PTR_ERR(frontend->regs); | ||
263 | } | ||
264 | |||
265 | frontend->reset = devm_reset_control_get(dev, NULL); | ||
266 | if (IS_ERR(frontend->reset)) { | ||
267 | dev_err(dev, "Couldn't get our reset line\n"); | ||
268 | return PTR_ERR(frontend->reset); | ||
269 | } | ||
270 | |||
271 | frontend->bus_clk = devm_clk_get(dev, "ahb"); | ||
272 | if (IS_ERR(frontend->bus_clk)) { | ||
273 | dev_err(dev, "Couldn't get our bus clock\n"); | ||
274 | return PTR_ERR(frontend->bus_clk); | ||
275 | } | ||
276 | |||
277 | frontend->mod_clk = devm_clk_get(dev, "mod"); | ||
278 | if (IS_ERR(frontend->mod_clk)) { | ||
279 | dev_err(dev, "Couldn't get our mod clock\n"); | ||
280 | return PTR_ERR(frontend->mod_clk); | ||
281 | } | ||
282 | |||
283 | frontend->ram_clk = devm_clk_get(dev, "ram"); | ||
284 | if (IS_ERR(frontend->ram_clk)) { | ||
285 | dev_err(dev, "Couldn't get our ram clock\n"); | ||
286 | return PTR_ERR(frontend->ram_clk); | ||
287 | } | ||
288 | |||
289 | list_add_tail(&frontend->list, &drv->frontend_list); | ||
290 | pm_runtime_enable(dev); | ||
291 | |||
292 | return 0; | ||
293 | } | ||
294 | |||
295 | static void sun4i_frontend_unbind(struct device *dev, struct device *master, | ||
296 | void *data) | ||
297 | { | ||
298 | struct sun4i_frontend *frontend = dev_get_drvdata(dev); | ||
299 | |||
300 | list_del(&frontend->list); | ||
301 | pm_runtime_force_suspend(dev); | ||
302 | } | ||
303 | |||
304 | static const struct component_ops sun4i_frontend_ops = { | ||
305 | .bind = sun4i_frontend_bind, | ||
306 | .unbind = sun4i_frontend_unbind, | ||
307 | }; | ||
308 | |||
309 | static int sun4i_frontend_probe(struct platform_device *pdev) | ||
310 | { | ||
311 | return component_add(&pdev->dev, &sun4i_frontend_ops); | ||
312 | } | ||
313 | |||
314 | static int sun4i_frontend_remove(struct platform_device *pdev) | ||
315 | { | ||
316 | component_del(&pdev->dev, &sun4i_frontend_ops); | ||
317 | |||
318 | return 0; | ||
319 | } | ||
320 | |||
321 | static int sun4i_frontend_runtime_resume(struct device *dev) | ||
322 | { | ||
323 | struct sun4i_frontend *frontend = dev_get_drvdata(dev); | ||
324 | int ret; | ||
325 | |||
326 | clk_set_rate(frontend->mod_clk, 300000000); | ||
327 | |||
328 | clk_prepare_enable(frontend->bus_clk); | ||
329 | clk_prepare_enable(frontend->mod_clk); | ||
330 | clk_prepare_enable(frontend->ram_clk); | ||
331 | |||
332 | ret = reset_control_reset(frontend->reset); | ||
333 | if (ret) { | ||
334 | dev_err(dev, "Couldn't reset our device\n"); | ||
335 | return ret; | ||
336 | } | ||
337 | |||
338 | regmap_update_bits(frontend->regs, SUN4I_FRONTEND_EN_REG, | ||
339 | SUN4I_FRONTEND_EN_EN, | ||
340 | SUN4I_FRONTEND_EN_EN); | ||
341 | |||
342 | regmap_update_bits(frontend->regs, SUN4I_FRONTEND_BYPASS_REG, | ||
343 | SUN4I_FRONTEND_BYPASS_CSC_EN, | ||
344 | SUN4I_FRONTEND_BYPASS_CSC_EN); | ||
345 | |||
346 | sun4i_frontend_scaler_init(frontend); | ||
347 | |||
348 | return 0; | ||
349 | } | ||
350 | |||
351 | static int sun4i_frontend_runtime_suspend(struct device *dev) | ||
352 | { | ||
353 | struct sun4i_frontend *frontend = dev_get_drvdata(dev); | ||
354 | |||
355 | clk_disable_unprepare(frontend->ram_clk); | ||
356 | clk_disable_unprepare(frontend->mod_clk); | ||
357 | clk_disable_unprepare(frontend->bus_clk); | ||
358 | |||
359 | reset_control_assert(frontend->reset); | ||
360 | |||
361 | return 0; | ||
362 | } | ||
363 | |||
364 | static const struct dev_pm_ops sun4i_frontend_pm_ops = { | ||
365 | .runtime_resume = sun4i_frontend_runtime_resume, | ||
366 | .runtime_suspend = sun4i_frontend_runtime_suspend, | ||
367 | }; | ||
368 | |||
369 | const struct of_device_id sun4i_frontend_of_table[] = { | ||
370 | { .compatible = "allwinner,sun8i-a33-display-frontend" }, | ||
371 | { } | ||
372 | }; | ||
373 | EXPORT_SYMBOL(sun4i_frontend_of_table); | ||
374 | MODULE_DEVICE_TABLE(of, sun4i_frontend_of_table); | ||
375 | |||
376 | static struct platform_driver sun4i_frontend_driver = { | ||
377 | .probe = sun4i_frontend_probe, | ||
378 | .remove = sun4i_frontend_remove, | ||
379 | .driver = { | ||
380 | .name = "sun4i-frontend", | ||
381 | .of_match_table = sun4i_frontend_of_table, | ||
382 | .pm = &sun4i_frontend_pm_ops, | ||
383 | }, | ||
384 | }; | ||
385 | module_platform_driver(sun4i_frontend_driver); | ||
386 | |||
387 | MODULE_AUTHOR("Maxime Ripard <maxime.ripard@free-electrons.com>"); | ||
388 | MODULE_DESCRIPTION("Allwinner A10 Display Engine Frontend Driver"); | ||
389 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/gpu/drm/sun4i/sun4i_frontend.h b/drivers/gpu/drm/sun4i/sun4i_frontend.h new file mode 100644 index 000000000000..02661ce81f3e --- /dev/null +++ b/drivers/gpu/drm/sun4i/sun4i_frontend.h | |||
@@ -0,0 +1,99 @@ | |||
1 | // SPDX-License-Identifier: GPL-2.0+ | ||
2 | /* | ||
3 | * Copyright (C) 2017 Free Electrons | ||
4 | * Maxime Ripard <maxime.ripard@free-electrons.com> | ||
5 | */ | ||
6 | |||
7 | #ifndef _SUN4I_FRONTEND_H_ | ||
8 | #define _SUN4I_FRONTEND_H_ | ||
9 | |||
10 | #include <linux/list.h> | ||
11 | |||
12 | #define SUN4I_FRONTEND_EN_REG 0x000 | ||
13 | #define SUN4I_FRONTEND_EN_EN BIT(0) | ||
14 | |||
15 | #define SUN4I_FRONTEND_FRM_CTRL_REG 0x004 | ||
16 | #define SUN4I_FRONTEND_FRM_CTRL_COEF_ACCESS_CTRL BIT(23) | ||
17 | #define SUN4I_FRONTEND_FRM_CTRL_FRM_START BIT(16) | ||
18 | #define SUN4I_FRONTEND_FRM_CTRL_COEF_RDY BIT(1) | ||
19 | #define SUN4I_FRONTEND_FRM_CTRL_REG_RDY BIT(0) | ||
20 | |||
21 | #define SUN4I_FRONTEND_BYPASS_REG 0x008 | ||
22 | #define SUN4I_FRONTEND_BYPASS_CSC_EN BIT(1) | ||
23 | |||
24 | #define SUN4I_FRONTEND_BUF_ADDR0_REG 0x020 | ||
25 | |||
26 | #define SUN4I_FRONTEND_LINESTRD0_REG 0x040 | ||
27 | |||
28 | #define SUN4I_FRONTEND_INPUT_FMT_REG 0x04c | ||
29 | #define SUN4I_FRONTEND_INPUT_FMT_DATA_MOD(mod) ((mod) << 8) | ||
30 | #define SUN4I_FRONTEND_INPUT_FMT_DATA_FMT(fmt) ((fmt) << 4) | ||
31 | #define SUN4I_FRONTEND_INPUT_FMT_PS(ps) (ps) | ||
32 | |||
33 | #define SUN4I_FRONTEND_OUTPUT_FMT_REG 0x05c | ||
34 | #define SUN4I_FRONTEND_OUTPUT_FMT_DATA_FMT(fmt) (fmt) | ||
35 | |||
36 | #define SUN4I_FRONTEND_CH0_INSIZE_REG 0x100 | ||
37 | #define SUN4I_FRONTEND_INSIZE(h, w) ((((h) - 1) << 16) | (((w) - 1))) | ||
38 | |||
39 | #define SUN4I_FRONTEND_CH0_OUTSIZE_REG 0x104 | ||
40 | #define SUN4I_FRONTEND_OUTSIZE(h, w) ((((h) - 1) << 16) | (((w) - 1))) | ||
41 | |||
42 | #define SUN4I_FRONTEND_CH0_HORZFACT_REG 0x108 | ||
43 | #define SUN4I_FRONTEND_HORZFACT(i, f) (((i) << 16) | (f)) | ||
44 | |||
45 | #define SUN4I_FRONTEND_CH0_VERTFACT_REG 0x10c | ||
46 | #define SUN4I_FRONTEND_VERTFACT(i, f) (((i) << 16) | (f)) | ||
47 | |||
48 | #define SUN4I_FRONTEND_CH0_HORZPHASE_REG 0x110 | ||
49 | #define SUN4I_FRONTEND_CH0_VERTPHASE0_REG 0x114 | ||
50 | #define SUN4I_FRONTEND_CH0_VERTPHASE1_REG 0x118 | ||
51 | |||
52 | #define SUN4I_FRONTEND_CH1_INSIZE_REG 0x200 | ||
53 | #define SUN4I_FRONTEND_CH1_OUTSIZE_REG 0x204 | ||
54 | #define SUN4I_FRONTEND_CH1_HORZFACT_REG 0x208 | ||
55 | #define SUN4I_FRONTEND_CH1_VERTFACT_REG 0x20c | ||
56 | |||
57 | #define SUN4I_FRONTEND_CH1_HORZPHASE_REG 0x210 | ||
58 | #define SUN4I_FRONTEND_CH1_VERTPHASE0_REG 0x214 | ||
59 | #define SUN4I_FRONTEND_CH1_VERTPHASE1_REG 0x218 | ||
60 | |||
61 | #define SUN4I_FRONTEND_CH0_HORZCOEF0_REG(i) (0x400 + i * 4) | ||
62 | #define SUN4I_FRONTEND_CH0_HORZCOEF1_REG(i) (0x480 + i * 4) | ||
63 | #define SUN4I_FRONTEND_CH0_VERTCOEF_REG(i) (0x500 + i * 4) | ||
64 | #define SUN4I_FRONTEND_CH1_HORZCOEF0_REG(i) (0x600 + i * 4) | ||
65 | #define SUN4I_FRONTEND_CH1_HORZCOEF1_REG(i) (0x680 + i * 4) | ||
66 | #define SUN4I_FRONTEND_CH1_VERTCOEF_REG(i) (0x700 + i * 4) | ||
67 | |||
68 | struct clk; | ||
69 | struct device_node; | ||
70 | struct drm_plane; | ||
71 | struct regmap; | ||
72 | struct reset_control; | ||
73 | |||
74 | struct sun4i_frontend { | ||
75 | struct list_head list; | ||
76 | struct device *dev; | ||
77 | struct device_node *node; | ||
78 | |||
79 | struct clk *bus_clk; | ||
80 | struct clk *mod_clk; | ||
81 | struct clk *ram_clk; | ||
82 | struct regmap *regs; | ||
83 | struct reset_control *reset; | ||
84 | }; | ||
85 | |||
86 | extern const struct of_device_id sun4i_frontend_of_table[]; | ||
87 | |||
88 | int sun4i_frontend_init(struct sun4i_frontend *frontend); | ||
89 | void sun4i_frontend_exit(struct sun4i_frontend *frontend); | ||
90 | int sun4i_frontend_enable(struct sun4i_frontend *frontend); | ||
91 | |||
92 | void sun4i_frontend_update_buffer(struct sun4i_frontend *frontend, | ||
93 | struct drm_plane *plane); | ||
94 | void sun4i_frontend_update_coord(struct sun4i_frontend *frontend, | ||
95 | struct drm_plane *plane); | ||
96 | int sun4i_frontend_update_formats(struct sun4i_frontend *frontend, | ||
97 | struct drm_plane *plane, uint32_t out_fmt); | ||
98 | |||
99 | #endif /* _SUN4I_FRONTEND_H_ */ | ||
diff --git a/drivers/gpu/drm/sun4i/sun4i_layer.c b/drivers/gpu/drm/sun4i/sun4i_layer.c index 7bddf12548d3..19be798e4fac 100644 --- a/drivers/gpu/drm/sun4i/sun4i_layer.c +++ b/drivers/gpu/drm/sun4i/sun4i_layer.c | |||
@@ -15,34 +15,107 @@ | |||
15 | #include <drm/drmP.h> | 15 | #include <drm/drmP.h> |
16 | 16 | ||
17 | #include "sun4i_backend.h" | 17 | #include "sun4i_backend.h" |
18 | #include "sun4i_frontend.h" | ||
18 | #include "sun4i_layer.h" | 19 | #include "sun4i_layer.h" |
19 | #include "sunxi_engine.h" | 20 | #include "sunxi_engine.h" |
20 | 21 | ||
21 | struct sun4i_plane_desc { | 22 | struct sun4i_plane_desc { |
22 | enum drm_plane_type type; | 23 | enum drm_plane_type type; |
23 | u8 pipe; | 24 | u8 pipe; |
24 | const uint32_t *formats; | 25 | const uint32_t *formats; |
25 | uint32_t nformats; | 26 | uint32_t nformats; |
26 | }; | 27 | }; |
27 | 28 | ||
29 | static void sun4i_backend_layer_reset(struct drm_plane *plane) | ||
30 | { | ||
31 | struct sun4i_layer *layer = plane_to_sun4i_layer(plane); | ||
32 | struct sun4i_layer_state *state; | ||
33 | |||
34 | if (plane->state) { | ||
35 | state = state_to_sun4i_layer_state(plane->state); | ||
36 | |||
37 | __drm_atomic_helper_plane_destroy_state(&state->state); | ||
38 | |||
39 | kfree(state); | ||
40 | plane->state = NULL; | ||
41 | } | ||
42 | |||
43 | state = kzalloc(sizeof(*state), GFP_KERNEL); | ||
44 | if (state) { | ||
45 | plane->state = &state->state; | ||
46 | plane->state->plane = plane; | ||
47 | plane->state->zpos = layer->id; | ||
48 | } | ||
49 | } | ||
50 | |||
51 | static struct drm_plane_state * | ||
52 | sun4i_backend_layer_duplicate_state(struct drm_plane *plane) | ||
53 | { | ||
54 | struct sun4i_layer_state *orig = state_to_sun4i_layer_state(plane->state); | ||
55 | struct sun4i_layer_state *copy; | ||
56 | |||
57 | copy = kzalloc(sizeof(*copy), GFP_KERNEL); | ||
58 | if (!copy) | ||
59 | return NULL; | ||
60 | |||
61 | __drm_atomic_helper_plane_duplicate_state(plane, ©->state); | ||
62 | copy->uses_frontend = orig->uses_frontend; | ||
63 | |||
64 | return ©->state; | ||
65 | } | ||
66 | |||
67 | static void sun4i_backend_layer_destroy_state(struct drm_plane *plane, | ||
68 | struct drm_plane_state *state) | ||
69 | { | ||
70 | struct sun4i_layer_state *s_state = state_to_sun4i_layer_state(state); | ||
71 | |||
72 | __drm_atomic_helper_plane_destroy_state(state); | ||
73 | |||
74 | kfree(s_state); | ||
75 | } | ||
76 | |||
28 | static void sun4i_backend_layer_atomic_disable(struct drm_plane *plane, | 77 | static void sun4i_backend_layer_atomic_disable(struct drm_plane *plane, |
29 | struct drm_plane_state *old_state) | 78 | struct drm_plane_state *old_state) |
30 | { | 79 | { |
80 | struct sun4i_layer_state *layer_state = state_to_sun4i_layer_state(old_state); | ||
31 | struct sun4i_layer *layer = plane_to_sun4i_layer(plane); | 81 | struct sun4i_layer *layer = plane_to_sun4i_layer(plane); |
32 | struct sun4i_backend *backend = layer->backend; | 82 | struct sun4i_backend *backend = layer->backend; |
33 | 83 | ||
34 | sun4i_backend_layer_enable(backend, layer->id, false); | 84 | sun4i_backend_layer_enable(backend, layer->id, false); |
85 | |||
86 | if (layer_state->uses_frontend) { | ||
87 | unsigned long flags; | ||
88 | |||
89 | spin_lock_irqsave(&backend->frontend_lock, flags); | ||
90 | backend->frontend_teardown = true; | ||
91 | spin_unlock_irqrestore(&backend->frontend_lock, flags); | ||
92 | } | ||
35 | } | 93 | } |
36 | 94 | ||
37 | static void sun4i_backend_layer_atomic_update(struct drm_plane *plane, | 95 | static void sun4i_backend_layer_atomic_update(struct drm_plane *plane, |
38 | struct drm_plane_state *old_state) | 96 | struct drm_plane_state *old_state) |
39 | { | 97 | { |
98 | struct sun4i_layer_state *layer_state = state_to_sun4i_layer_state(plane->state); | ||
40 | struct sun4i_layer *layer = plane_to_sun4i_layer(plane); | 99 | struct sun4i_layer *layer = plane_to_sun4i_layer(plane); |
41 | struct sun4i_backend *backend = layer->backend; | 100 | struct sun4i_backend *backend = layer->backend; |
101 | struct sun4i_frontend *frontend = backend->frontend; | ||
102 | |||
103 | if (layer_state->uses_frontend) { | ||
104 | sun4i_frontend_init(frontend); | ||
105 | sun4i_frontend_update_coord(frontend, plane); | ||
106 | sun4i_frontend_update_buffer(frontend, plane); | ||
107 | sun4i_frontend_update_formats(frontend, plane, | ||
108 | DRM_FORMAT_ARGB8888); | ||
109 | sun4i_backend_update_layer_frontend(backend, layer->id, | ||
110 | DRM_FORMAT_ARGB8888); | ||
111 | sun4i_frontend_enable(frontend); | ||
112 | } else { | ||
113 | sun4i_backend_update_layer_formats(backend, layer->id, plane); | ||
114 | sun4i_backend_update_layer_buffer(backend, layer->id, plane); | ||
115 | } | ||
42 | 116 | ||
43 | sun4i_backend_update_layer_coord(backend, layer->id, plane); | 117 | sun4i_backend_update_layer_coord(backend, layer->id, plane); |
44 | sun4i_backend_update_layer_formats(backend, layer->id, plane); | 118 | sun4i_backend_update_layer_zpos(backend, layer->id, plane); |
45 | sun4i_backend_update_layer_buffer(backend, layer->id, plane); | ||
46 | sun4i_backend_layer_enable(backend, layer->id, true); | 119 | sun4i_backend_layer_enable(backend, layer->id, true); |
47 | } | 120 | } |
48 | 121 | ||
@@ -52,11 +125,11 @@ static const struct drm_plane_helper_funcs sun4i_backend_layer_helper_funcs = { | |||
52 | }; | 125 | }; |
53 | 126 | ||
54 | static const struct drm_plane_funcs sun4i_backend_layer_funcs = { | 127 | static const struct drm_plane_funcs sun4i_backend_layer_funcs = { |
55 | .atomic_destroy_state = drm_atomic_helper_plane_destroy_state, | 128 | .atomic_destroy_state = sun4i_backend_layer_destroy_state, |
56 | .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state, | 129 | .atomic_duplicate_state = sun4i_backend_layer_duplicate_state, |
57 | .destroy = drm_plane_cleanup, | 130 | .destroy = drm_plane_cleanup, |
58 | .disable_plane = drm_atomic_helper_disable_plane, | 131 | .disable_plane = drm_atomic_helper_disable_plane, |
59 | .reset = drm_atomic_helper_plane_reset, | 132 | .reset = sun4i_backend_layer_reset, |
60 | .update_plane = drm_atomic_helper_update_plane, | 133 | .update_plane = drm_atomic_helper_update_plane, |
61 | }; | 134 | }; |
62 | 135 | ||
@@ -128,32 +201,12 @@ struct drm_plane **sun4i_layers_init(struct drm_device *drm, | |||
128 | struct sun4i_backend *backend = engine_to_sun4i_backend(engine); | 201 | struct sun4i_backend *backend = engine_to_sun4i_backend(engine); |
129 | int i; | 202 | int i; |
130 | 203 | ||
131 | planes = devm_kcalloc(drm->dev, ARRAY_SIZE(sun4i_backend_planes) + 1, | 204 | /* We need to have a sentinel at the need, hence the overallocation */ |
205 | planes = devm_kcalloc(drm->dev, SUN4I_BACKEND_NUM_LAYERS + 1, | ||
132 | sizeof(*planes), GFP_KERNEL); | 206 | sizeof(*planes), GFP_KERNEL); |
133 | if (!planes) | 207 | if (!planes) |
134 | return ERR_PTR(-ENOMEM); | 208 | return ERR_PTR(-ENOMEM); |
135 | 209 | ||
136 | /* | ||
137 | * The hardware is a bit unusual here. | ||
138 | * | ||
139 | * Even though it supports 4 layers, it does the composition | ||
140 | * in two separate steps. | ||
141 | * | ||
142 | * The first one is assigning a layer to one of its two | ||
143 | * pipes. If more that 1 layer is assigned to the same pipe, | ||
144 | * and if pixels overlaps, the pipe will take the pixel from | ||
145 | * the layer with the highest priority. | ||
146 | * | ||
147 | * The second step is the actual alpha blending, that takes | ||
148 | * the two pipes as input, and uses the eventual alpha | ||
149 | * component to do the transparency between the two. | ||
150 | * | ||
151 | * This two steps scenario makes us unable to guarantee a | ||
152 | * robust alpha blending between the 4 layers in all | ||
153 | * situations. So we just expose two layers, one per pipe. On | ||
154 | * SoCs that support it, sprites could fill the need for more | ||
155 | * layers. | ||
156 | */ | ||
157 | for (i = 0; i < ARRAY_SIZE(sun4i_backend_planes); i++) { | 210 | for (i = 0; i < ARRAY_SIZE(sun4i_backend_planes); i++) { |
158 | const struct sun4i_plane_desc *plane = &sun4i_backend_planes[i]; | 211 | const struct sun4i_plane_desc *plane = &sun4i_backend_planes[i]; |
159 | struct sun4i_layer *layer; | 212 | struct sun4i_layer *layer; |
@@ -165,6 +218,8 @@ struct drm_plane **sun4i_layers_init(struct drm_device *drm, | |||
165 | return ERR_CAST(layer); | 218 | return ERR_CAST(layer); |
166 | }; | 219 | }; |
167 | 220 | ||
221 | drm_plane_create_zpos_immutable_property(&layer->plane, i); | ||
222 | |||
168 | DRM_DEBUG_DRIVER("Assigning %s plane to pipe %d\n", | 223 | DRM_DEBUG_DRIVER("Assigning %s plane to pipe %d\n", |
169 | i ? "overlay" : "primary", plane->pipe); | 224 | i ? "overlay" : "primary", plane->pipe); |
170 | regmap_update_bits(engine->regs, SUN4I_BACKEND_ATTCTL_REG0(i), | 225 | regmap_update_bits(engine->regs, SUN4I_BACKEND_ATTCTL_REG0(i), |
diff --git a/drivers/gpu/drm/sun4i/sun4i_layer.h b/drivers/gpu/drm/sun4i/sun4i_layer.h index 4e84f438b346..75b4868ba87c 100644 --- a/drivers/gpu/drm/sun4i/sun4i_layer.h +++ b/drivers/gpu/drm/sun4i/sun4i_layer.h | |||
@@ -22,12 +22,23 @@ struct sun4i_layer { | |||
22 | int id; | 22 | int id; |
23 | }; | 23 | }; |
24 | 24 | ||
25 | struct sun4i_layer_state { | ||
26 | struct drm_plane_state state; | ||
27 | bool uses_frontend; | ||
28 | }; | ||
29 | |||
25 | static inline struct sun4i_layer * | 30 | static inline struct sun4i_layer * |
26 | plane_to_sun4i_layer(struct drm_plane *plane) | 31 | plane_to_sun4i_layer(struct drm_plane *plane) |
27 | { | 32 | { |
28 | return container_of(plane, struct sun4i_layer, plane); | 33 | return container_of(plane, struct sun4i_layer, plane); |
29 | } | 34 | } |
30 | 35 | ||
36 | static inline struct sun4i_layer_state * | ||
37 | state_to_sun4i_layer_state(struct drm_plane_state *state) | ||
38 | { | ||
39 | return container_of(state, struct sun4i_layer_state, state); | ||
40 | } | ||
41 | |||
31 | struct drm_plane **sun4i_layers_init(struct drm_device *drm, | 42 | struct drm_plane **sun4i_layers_init(struct drm_device *drm, |
32 | struct sunxi_engine *engine); | 43 | struct sunxi_engine *engine); |
33 | 44 | ||
diff --git a/drivers/gpu/drm/sun4i/sun4i_tcon.c b/drivers/gpu/drm/sun4i/sun4i_tcon.c index 3c15cf24b503..4b7340ee6290 100644 --- a/drivers/gpu/drm/sun4i/sun4i_tcon.c +++ b/drivers/gpu/drm/sun4i/sun4i_tcon.c | |||
@@ -540,6 +540,7 @@ static irqreturn_t sun4i_tcon_handler(int irq, void *private) | |||
540 | struct sun4i_tcon *tcon = private; | 540 | struct sun4i_tcon *tcon = private; |
541 | struct drm_device *drm = tcon->drm; | 541 | struct drm_device *drm = tcon->drm; |
542 | struct sun4i_crtc *scrtc = tcon->crtc; | 542 | struct sun4i_crtc *scrtc = tcon->crtc; |
543 | struct sunxi_engine *engine = scrtc->engine; | ||
543 | unsigned int status; | 544 | unsigned int status; |
544 | 545 | ||
545 | regmap_read(tcon->regs, SUN4I_TCON_GINT0_REG, &status); | 546 | regmap_read(tcon->regs, SUN4I_TCON_GINT0_REG, &status); |
@@ -557,6 +558,9 @@ static irqreturn_t sun4i_tcon_handler(int irq, void *private) | |||
557 | SUN4I_TCON_GINT0_VBLANK_INT(1), | 558 | SUN4I_TCON_GINT0_VBLANK_INT(1), |
558 | 0); | 559 | 0); |
559 | 560 | ||
561 | if (engine->ops->vblank_quirk) | ||
562 | engine->ops->vblank_quirk(engine); | ||
563 | |||
560 | return IRQ_HANDLED; | 564 | return IRQ_HANDLED; |
561 | } | 565 | } |
562 | 566 | ||
diff --git a/drivers/gpu/drm/sun4i/sun8i_ui_layer.c b/drivers/gpu/drm/sun4i/sun8i_ui_layer.c index 28d7c48d50fe..2f0ccd50b54d 100644 --- a/drivers/gpu/drm/sun4i/sun8i_ui_layer.c +++ b/drivers/gpu/drm/sun4i/sun8i_ui_layer.c | |||
@@ -211,7 +211,7 @@ static int sun8i_ui_layer_atomic_check(struct drm_plane *plane, | |||
211 | struct drm_crtc *crtc = state->crtc; | 211 | struct drm_crtc *crtc = state->crtc; |
212 | struct drm_crtc_state *crtc_state; | 212 | struct drm_crtc_state *crtc_state; |
213 | int min_scale, max_scale; | 213 | int min_scale, max_scale; |
214 | struct drm_rect clip; | 214 | struct drm_rect clip = {}; |
215 | 215 | ||
216 | if (!crtc) | 216 | if (!crtc) |
217 | return 0; | 217 | return 0; |
@@ -220,10 +220,9 @@ static int sun8i_ui_layer_atomic_check(struct drm_plane *plane, | |||
220 | if (WARN_ON(!crtc_state)) | 220 | if (WARN_ON(!crtc_state)) |
221 | return -EINVAL; | 221 | return -EINVAL; |
222 | 222 | ||
223 | clip.x1 = 0; | 223 | if (crtc_state->enable) |
224 | clip.y1 = 0; | 224 | drm_mode_get_hv_timing(&crtc_state->mode, |
225 | clip.x2 = crtc_state->adjusted_mode.hdisplay; | 225 | &clip.x2, &clip.y2); |
226 | clip.y2 = crtc_state->adjusted_mode.vdisplay; | ||
227 | 226 | ||
228 | min_scale = DRM_PLANE_HELPER_NO_SCALING; | 227 | min_scale = DRM_PLANE_HELPER_NO_SCALING; |
229 | max_scale = DRM_PLANE_HELPER_NO_SCALING; | 228 | max_scale = DRM_PLANE_HELPER_NO_SCALING; |
diff --git a/drivers/gpu/drm/sun4i/sun8i_vi_layer.c b/drivers/gpu/drm/sun4i/sun8i_vi_layer.c index 40c3b303068a..eb3bf2d7291a 100644 --- a/drivers/gpu/drm/sun4i/sun8i_vi_layer.c +++ b/drivers/gpu/drm/sun4i/sun8i_vi_layer.c | |||
@@ -239,7 +239,7 @@ static int sun8i_vi_layer_atomic_check(struct drm_plane *plane, | |||
239 | struct drm_crtc *crtc = state->crtc; | 239 | struct drm_crtc *crtc = state->crtc; |
240 | struct drm_crtc_state *crtc_state; | 240 | struct drm_crtc_state *crtc_state; |
241 | int min_scale, max_scale; | 241 | int min_scale, max_scale; |
242 | struct drm_rect clip; | 242 | struct drm_rect clip = {}; |
243 | 243 | ||
244 | if (!crtc) | 244 | if (!crtc) |
245 | return 0; | 245 | return 0; |
@@ -248,10 +248,9 @@ static int sun8i_vi_layer_atomic_check(struct drm_plane *plane, | |||
248 | if (WARN_ON(!crtc_state)) | 248 | if (WARN_ON(!crtc_state)) |
249 | return -EINVAL; | 249 | return -EINVAL; |
250 | 250 | ||
251 | clip.x1 = 0; | 251 | if (crtc_state->enable) |
252 | clip.y1 = 0; | 252 | drm_mode_get_hv_timing(&crtc_state->mode, |
253 | clip.x2 = crtc_state->adjusted_mode.hdisplay; | 253 | &clip.x2, &clip.y2); |
254 | clip.y2 = crtc_state->adjusted_mode.vdisplay; | ||
255 | 254 | ||
256 | min_scale = DRM_PLANE_HELPER_NO_SCALING; | 255 | min_scale = DRM_PLANE_HELPER_NO_SCALING; |
257 | max_scale = DRM_PLANE_HELPER_NO_SCALING; | 256 | max_scale = DRM_PLANE_HELPER_NO_SCALING; |
diff --git a/drivers/gpu/drm/sun4i/sunxi_engine.h b/drivers/gpu/drm/sun4i/sunxi_engine.h index 4cb70ae65c79..d317ea04b8aa 100644 --- a/drivers/gpu/drm/sun4i/sunxi_engine.h +++ b/drivers/gpu/drm/sun4i/sunxi_engine.h | |||
@@ -12,16 +12,106 @@ | |||
12 | 12 | ||
13 | struct drm_plane; | 13 | struct drm_plane; |
14 | struct drm_device; | 14 | struct drm_device; |
15 | struct drm_crtc_state; | ||
15 | 16 | ||
16 | struct sunxi_engine; | 17 | struct sunxi_engine; |
17 | 18 | ||
19 | /** | ||
20 | * struct sunxi_engine_ops - helper operations for sunXi engines | ||
21 | * | ||
22 | * These hooks are used by the common part of the DRM driver to | ||
23 | * implement the proper behaviour. | ||
24 | */ | ||
18 | struct sunxi_engine_ops { | 25 | struct sunxi_engine_ops { |
26 | /** | ||
27 | * @atomic_begin: | ||
28 | * | ||
29 | * This callback allows to prepare our engine for an atomic | ||
30 | * update. This is mirroring the | ||
31 | * &drm_crtc_helper_funcs.atomic_begin callback, so any | ||
32 | * documentation there applies. | ||
33 | * | ||
34 | * This function is optional. | ||
35 | */ | ||
36 | void (*atomic_begin)(struct sunxi_engine *engine, | ||
37 | struct drm_crtc_state *old_state); | ||
38 | |||
39 | /** | ||
40 | * @atomic_check: | ||
41 | * | ||
42 | * This callback allows to validate plane-update related CRTC | ||
43 | * constraints specific to engines. This is mirroring the | ||
44 | * &drm_crtc_helper_funcs.atomic_check callback, so any | ||
45 | * documentation there applies. | ||
46 | * | ||
47 | * This function is optional. | ||
48 | * | ||
49 | * RETURNS: | ||
50 | * | ||
51 | * 0 on success or a negative error code. | ||
52 | */ | ||
53 | int (*atomic_check)(struct sunxi_engine *engine, | ||
54 | struct drm_crtc_state *state); | ||
55 | |||
56 | /** | ||
57 | * @commit: | ||
58 | * | ||
59 | * This callback will trigger the hardware switch to commit | ||
60 | * the new configuration that has been setup during the next | ||
61 | * vblank period. | ||
62 | * | ||
63 | * This function is optional. | ||
64 | */ | ||
19 | void (*commit)(struct sunxi_engine *engine); | 65 | void (*commit)(struct sunxi_engine *engine); |
66 | |||
67 | /** | ||
68 | * @layers_init: | ||
69 | * | ||
70 | * This callback is used to allocate, initialize and register | ||
71 | * the layers supported by that engine. | ||
72 | * | ||
73 | * This function is mandatory. | ||
74 | * | ||
75 | * RETURNS: | ||
76 | * | ||
77 | * The array of struct drm_plane backing the layers, or an | ||
78 | * error pointer on failure. | ||
79 | */ | ||
20 | struct drm_plane **(*layers_init)(struct drm_device *drm, | 80 | struct drm_plane **(*layers_init)(struct drm_device *drm, |
21 | struct sunxi_engine *engine); | 81 | struct sunxi_engine *engine); |
22 | 82 | ||
83 | /** | ||
84 | * @apply_color_correction: | ||
85 | * | ||
86 | * This callback will enable the color correction in the | ||
87 | * engine. This is useful only for the composite output. | ||
88 | * | ||
89 | * This function is optional. | ||
90 | */ | ||
23 | void (*apply_color_correction)(struct sunxi_engine *engine); | 91 | void (*apply_color_correction)(struct sunxi_engine *engine); |
92 | |||
93 | /** | ||
94 | * @disable_color_correction: | ||
95 | * | ||
96 | * This callback will stop the color correction in the | ||
97 | * engine. This is useful only for the composite output. | ||
98 | * | ||
99 | * This function is optional. | ||
100 | */ | ||
24 | void (*disable_color_correction)(struct sunxi_engine *engine); | 101 | void (*disable_color_correction)(struct sunxi_engine *engine); |
102 | |||
103 | /** | ||
104 | * @vblank_quirk: | ||
105 | * | ||
106 | * This callback is used to implement engine-specific | ||
107 | * behaviour part of the VBLANK event. It is run with all the | ||
108 | * constraints of an interrupt (can't sleep, all local | ||
109 | * interrupts disabled) and therefore should be as fast as | ||
110 | * possible. | ||
111 | * | ||
112 | * This function is optional. | ||
113 | */ | ||
114 | void (*vblank_quirk)(struct sunxi_engine *engine); | ||
25 | }; | 115 | }; |
26 | 116 | ||
27 | /** | 117 | /** |
diff --git a/drivers/gpu/drm/tegra/plane.c b/drivers/gpu/drm/tegra/plane.c index 36a06a993698..7267a01e6f08 100644 --- a/drivers/gpu/drm/tegra/plane.c +++ b/drivers/gpu/drm/tegra/plane.c | |||
@@ -82,7 +82,7 @@ int tegra_plane_state_add(struct tegra_plane *plane, | |||
82 | { | 82 | { |
83 | struct drm_crtc_state *crtc_state; | 83 | struct drm_crtc_state *crtc_state; |
84 | struct tegra_dc_state *tegra; | 84 | struct tegra_dc_state *tegra; |
85 | struct drm_rect clip; | 85 | struct drm_rect clip = {}; |
86 | int err; | 86 | int err; |
87 | 87 | ||
88 | /* Propagate errors from allocation or locking failures. */ | 88 | /* Propagate errors from allocation or locking failures. */ |
@@ -90,10 +90,9 @@ int tegra_plane_state_add(struct tegra_plane *plane, | |||
90 | if (IS_ERR(crtc_state)) | 90 | if (IS_ERR(crtc_state)) |
91 | return PTR_ERR(crtc_state); | 91 | return PTR_ERR(crtc_state); |
92 | 92 | ||
93 | clip.x1 = 0; | 93 | if (crtc_state->enable) |
94 | clip.y1 = 0; | 94 | drm_mode_get_hv_timing(&crtc_state->mode, |
95 | clip.x2 = crtc_state->mode.hdisplay; | 95 | &clip.x2, &clip.y2); |
96 | clip.y2 = crtc_state->mode.vdisplay; | ||
97 | 96 | ||
98 | /* Check plane state for visibility and calculate clipping bounds */ | 97 | /* Check plane state for visibility and calculate clipping bounds */ |
99 | err = drm_atomic_helper_check_plane_state(state, crtc_state, &clip, | 98 | err = drm_atomic_helper_check_plane_state(state, crtc_state, &clip, |
diff --git a/drivers/gpu/drm/tinydrm/core/tinydrm-pipe.c b/drivers/gpu/drm/tinydrm/core/tinydrm-pipe.c index f41fc506ff87..11ae950b0fc9 100644 --- a/drivers/gpu/drm/tinydrm/core/tinydrm-pipe.c +++ b/drivers/gpu/drm/tinydrm/core/tinydrm-pipe.c | |||
@@ -15,7 +15,7 @@ | |||
15 | 15 | ||
16 | struct tinydrm_connector { | 16 | struct tinydrm_connector { |
17 | struct drm_connector base; | 17 | struct drm_connector base; |
18 | const struct drm_display_mode *mode; | 18 | struct drm_display_mode mode; |
19 | }; | 19 | }; |
20 | 20 | ||
21 | static inline struct tinydrm_connector * | 21 | static inline struct tinydrm_connector * |
@@ -29,7 +29,7 @@ static int tinydrm_connector_get_modes(struct drm_connector *connector) | |||
29 | struct tinydrm_connector *tconn = to_tinydrm_connector(connector); | 29 | struct tinydrm_connector *tconn = to_tinydrm_connector(connector); |
30 | struct drm_display_mode *mode; | 30 | struct drm_display_mode *mode; |
31 | 31 | ||
32 | mode = drm_mode_duplicate(connector->dev, tconn->mode); | 32 | mode = drm_mode_duplicate(connector->dev, &tconn->mode); |
33 | if (!mode) { | 33 | if (!mode) { |
34 | DRM_ERROR("Failed to duplicate mode\n"); | 34 | DRM_ERROR("Failed to duplicate mode\n"); |
35 | return 0; | 35 | return 0; |
@@ -92,7 +92,7 @@ tinydrm_connector_create(struct drm_device *drm, | |||
92 | if (!tconn) | 92 | if (!tconn) |
93 | return ERR_PTR(-ENOMEM); | 93 | return ERR_PTR(-ENOMEM); |
94 | 94 | ||
95 | tconn->mode = mode; | 95 | drm_mode_copy(&tconn->mode, mode); |
96 | connector = &tconn->base; | 96 | connector = &tconn->base; |
97 | 97 | ||
98 | drm_connector_helper_add(connector, &tinydrm_connector_hfuncs); | 98 | drm_connector_helper_add(connector, &tinydrm_connector_hfuncs); |
@@ -199,35 +199,27 @@ tinydrm_display_pipe_init(struct tinydrm_device *tdev, | |||
199 | unsigned int rotation) | 199 | unsigned int rotation) |
200 | { | 200 | { |
201 | struct drm_device *drm = tdev->drm; | 201 | struct drm_device *drm = tdev->drm; |
202 | struct drm_display_mode *mode_copy; | 202 | struct drm_display_mode mode_copy; |
203 | struct drm_connector *connector; | 203 | struct drm_connector *connector; |
204 | int ret; | 204 | int ret; |
205 | 205 | ||
206 | mode_copy = devm_kmalloc(drm->dev, sizeof(*mode_copy), GFP_KERNEL); | 206 | drm_mode_copy(&mode_copy, mode); |
207 | if (!mode_copy) | 207 | ret = tinydrm_rotate_mode(&mode_copy, rotation); |
208 | return -ENOMEM; | ||
209 | |||
210 | *mode_copy = *mode; | ||
211 | ret = tinydrm_rotate_mode(mode_copy, rotation); | ||
212 | if (ret) { | 208 | if (ret) { |
213 | DRM_ERROR("Illegal rotation value %u\n", rotation); | 209 | DRM_ERROR("Illegal rotation value %u\n", rotation); |
214 | return -EINVAL; | 210 | return -EINVAL; |
215 | } | 211 | } |
216 | 212 | ||
217 | drm->mode_config.min_width = mode_copy->hdisplay; | 213 | drm->mode_config.min_width = mode_copy.hdisplay; |
218 | drm->mode_config.max_width = mode_copy->hdisplay; | 214 | drm->mode_config.max_width = mode_copy.hdisplay; |
219 | drm->mode_config.min_height = mode_copy->vdisplay; | 215 | drm->mode_config.min_height = mode_copy.vdisplay; |
220 | drm->mode_config.max_height = mode_copy->vdisplay; | 216 | drm->mode_config.max_height = mode_copy.vdisplay; |
221 | 217 | ||
222 | connector = tinydrm_connector_create(drm, mode_copy, connector_type); | 218 | connector = tinydrm_connector_create(drm, &mode_copy, connector_type); |
223 | if (IS_ERR(connector)) | 219 | if (IS_ERR(connector)) |
224 | return PTR_ERR(connector); | 220 | return PTR_ERR(connector); |
225 | 221 | ||
226 | ret = drm_simple_display_pipe_init(drm, &tdev->pipe, funcs, formats, | 222 | return drm_simple_display_pipe_init(drm, &tdev->pipe, funcs, formats, |
227 | format_count, NULL, connector); | 223 | format_count, NULL, connector); |
228 | if (ret) | ||
229 | return ret; | ||
230 | |||
231 | return 0; | ||
232 | } | 224 | } |
233 | EXPORT_SYMBOL(tinydrm_display_pipe_init); | 225 | EXPORT_SYMBOL(tinydrm_display_pipe_init); |
diff --git a/drivers/gpu/drm/tinydrm/ili9225.c b/drivers/gpu/drm/tinydrm/ili9225.c index c0cf49849302..a0759502b81a 100644 --- a/drivers/gpu/drm/tinydrm/ili9225.c +++ b/drivers/gpu/drm/tinydrm/ili9225.c | |||
@@ -180,7 +180,6 @@ static void ili9225_pipe_enable(struct drm_simple_display_pipe *pipe, | |||
180 | { | 180 | { |
181 | struct tinydrm_device *tdev = pipe_to_tinydrm(pipe); | 181 | struct tinydrm_device *tdev = pipe_to_tinydrm(pipe); |
182 | struct mipi_dbi *mipi = mipi_dbi_from_tinydrm(tdev); | 182 | struct mipi_dbi *mipi = mipi_dbi_from_tinydrm(tdev); |
183 | struct drm_framebuffer *fb = pipe->plane.fb; | ||
184 | struct device *dev = tdev->drm->dev; | 183 | struct device *dev = tdev->drm->dev; |
185 | int ret; | 184 | int ret; |
186 | u8 am_id; | 185 | u8 am_id; |
@@ -269,10 +268,7 @@ static void ili9225_pipe_enable(struct drm_simple_display_pipe *pipe, | |||
269 | 268 | ||
270 | ili9225_command(mipi, ILI9225_DISPLAY_CONTROL_1, 0x1017); | 269 | ili9225_command(mipi, ILI9225_DISPLAY_CONTROL_1, 0x1017); |
271 | 270 | ||
272 | mipi->enabled = true; | 271 | mipi_dbi_enable_flush(mipi); |
273 | |||
274 | if (fb) | ||
275 | fb->funcs->dirty(fb, NULL, 0, 0, NULL, 0); | ||
276 | } | 272 | } |
277 | 273 | ||
278 | static void ili9225_pipe_disable(struct drm_simple_display_pipe *pipe) | 274 | static void ili9225_pipe_disable(struct drm_simple_display_pipe *pipe) |
diff --git a/drivers/gpu/drm/tinydrm/mi0283qt.c b/drivers/gpu/drm/tinydrm/mi0283qt.c index 674d407640be..79cb5af5abac 100644 --- a/drivers/gpu/drm/tinydrm/mi0283qt.c +++ b/drivers/gpu/drm/tinydrm/mi0283qt.c | |||
@@ -9,47 +9,59 @@ | |||
9 | * (at your option) any later version. | 9 | * (at your option) any later version. |
10 | */ | 10 | */ |
11 | 11 | ||
12 | #include <drm/drm_fb_helper.h> | ||
13 | #include <drm/drm_modeset_helper.h> | ||
14 | #include <drm/tinydrm/ili9341.h> | ||
15 | #include <drm/tinydrm/mipi-dbi.h> | ||
16 | #include <drm/tinydrm/tinydrm-helpers.h> | ||
17 | #include <linux/delay.h> | 12 | #include <linux/delay.h> |
18 | #include <linux/gpio/consumer.h> | 13 | #include <linux/gpio/consumer.h> |
19 | #include <linux/module.h> | 14 | #include <linux/module.h> |
20 | #include <linux/property.h> | 15 | #include <linux/property.h> |
21 | #include <linux/regulator/consumer.h> | 16 | #include <linux/regulator/consumer.h> |
22 | #include <linux/spi/spi.h> | 17 | #include <linux/spi/spi.h> |
18 | |||
19 | #include <drm/drm_fb_helper.h> | ||
20 | #include <drm/drm_modeset_helper.h> | ||
21 | #include <drm/tinydrm/mipi-dbi.h> | ||
22 | #include <drm/tinydrm/tinydrm-helpers.h> | ||
23 | #include <video/mipi_display.h> | 23 | #include <video/mipi_display.h> |
24 | 24 | ||
25 | static int mi0283qt_init(struct mipi_dbi *mipi) | 25 | #define ILI9341_FRMCTR1 0xb1 |
26 | #define ILI9341_DISCTRL 0xb6 | ||
27 | #define ILI9341_ETMOD 0xb7 | ||
28 | |||
29 | #define ILI9341_PWCTRL1 0xc0 | ||
30 | #define ILI9341_PWCTRL2 0xc1 | ||
31 | #define ILI9341_VMCTRL1 0xc5 | ||
32 | #define ILI9341_VMCTRL2 0xc7 | ||
33 | #define ILI9341_PWCTRLA 0xcb | ||
34 | #define ILI9341_PWCTRLB 0xcf | ||
35 | |||
36 | #define ILI9341_PGAMCTRL 0xe0 | ||
37 | #define ILI9341_NGAMCTRL 0xe1 | ||
38 | #define ILI9341_DTCTRLA 0xe8 | ||
39 | #define ILI9341_DTCTRLB 0xea | ||
40 | #define ILI9341_PWRSEQ 0xed | ||
41 | |||
42 | #define ILI9341_EN3GAM 0xf2 | ||
43 | #define ILI9341_PUMPCTRL 0xf7 | ||
44 | |||
45 | #define ILI9341_MADCTL_BGR BIT(3) | ||
46 | #define ILI9341_MADCTL_MV BIT(5) | ||
47 | #define ILI9341_MADCTL_MX BIT(6) | ||
48 | #define ILI9341_MADCTL_MY BIT(7) | ||
49 | |||
50 | static void mi0283qt_enable(struct drm_simple_display_pipe *pipe, | ||
51 | struct drm_crtc_state *crtc_state) | ||
26 | { | 52 | { |
27 | struct tinydrm_device *tdev = &mipi->tinydrm; | 53 | struct tinydrm_device *tdev = pipe_to_tinydrm(pipe); |
28 | struct device *dev = tdev->drm->dev; | 54 | struct mipi_dbi *mipi = mipi_dbi_from_tinydrm(tdev); |
29 | u8 addr_mode; | 55 | u8 addr_mode; |
30 | int ret; | 56 | int ret; |
31 | 57 | ||
32 | DRM_DEBUG_KMS("\n"); | 58 | DRM_DEBUG_KMS("\n"); |
33 | 59 | ||
34 | ret = regulator_enable(mipi->regulator); | 60 | ret = mipi_dbi_poweron_conditional_reset(mipi); |
35 | if (ret) { | 61 | if (ret < 0) |
36 | DRM_DEV_ERROR(dev, "Failed to enable regulator %d\n", ret); | 62 | return; |
37 | return ret; | 63 | if (ret == 1) |
38 | } | 64 | goto out_enable; |
39 | |||
40 | /* Avoid flicker by skipping setup if the bootloader has done it */ | ||
41 | if (mipi_dbi_display_is_on(mipi)) | ||
42 | return 0; | ||
43 | |||
44 | mipi_dbi_hw_reset(mipi); | ||
45 | ret = mipi_dbi_command(mipi, MIPI_DCS_SOFT_RESET); | ||
46 | if (ret) { | ||
47 | DRM_DEV_ERROR(dev, "Error sending command %d\n", ret); | ||
48 | regulator_disable(mipi->regulator); | ||
49 | return ret; | ||
50 | } | ||
51 | |||
52 | msleep(20); | ||
53 | 65 | ||
54 | mipi_dbi_command(mipi, MIPI_DCS_SET_DISPLAY_OFF); | 66 | mipi_dbi_command(mipi, MIPI_DCS_SET_DISPLAY_OFF); |
55 | 67 | ||
@@ -68,7 +80,7 @@ static int mi0283qt_init(struct mipi_dbi *mipi) | |||
68 | mipi_dbi_command(mipi, ILI9341_VMCTRL2, 0xbe); | 80 | mipi_dbi_command(mipi, ILI9341_VMCTRL2, 0xbe); |
69 | 81 | ||
70 | /* Memory Access Control */ | 82 | /* Memory Access Control */ |
71 | mipi_dbi_command(mipi, MIPI_DCS_SET_PIXEL_FORMAT, 0x55); | 83 | mipi_dbi_command(mipi, MIPI_DCS_SET_PIXEL_FORMAT, MIPI_DCS_PIXEL_FMT_16BIT); |
72 | 84 | ||
73 | switch (mipi->rotation) { | 85 | switch (mipi->rotation) { |
74 | default: | 86 | default: |
@@ -112,19 +124,12 @@ static int mi0283qt_init(struct mipi_dbi *mipi) | |||
112 | mipi_dbi_command(mipi, MIPI_DCS_SET_DISPLAY_ON); | 124 | mipi_dbi_command(mipi, MIPI_DCS_SET_DISPLAY_ON); |
113 | msleep(100); | 125 | msleep(100); |
114 | 126 | ||
115 | return 0; | 127 | out_enable: |
116 | } | 128 | mipi_dbi_enable_flush(mipi); |
117 | |||
118 | static void mi0283qt_fini(void *data) | ||
119 | { | ||
120 | struct mipi_dbi *mipi = data; | ||
121 | |||
122 | DRM_DEBUG_KMS("\n"); | ||
123 | regulator_disable(mipi->regulator); | ||
124 | } | 129 | } |
125 | 130 | ||
126 | static const struct drm_simple_display_pipe_funcs mi0283qt_pipe_funcs = { | 131 | static const struct drm_simple_display_pipe_funcs mi0283qt_pipe_funcs = { |
127 | .enable = mipi_dbi_pipe_enable, | 132 | .enable = mi0283qt_enable, |
128 | .disable = mipi_dbi_pipe_disable, | 133 | .disable = mipi_dbi_pipe_disable, |
129 | .update = tinydrm_display_pipe_update, | 134 | .update = tinydrm_display_pipe_update, |
130 | .prepare_fb = tinydrm_display_pipe_prepare_fb, | 135 | .prepare_fb = tinydrm_display_pipe_prepare_fb, |
@@ -205,17 +210,6 @@ static int mi0283qt_probe(struct spi_device *spi) | |||
205 | if (ret) | 210 | if (ret) |
206 | return ret; | 211 | return ret; |
207 | 212 | ||
208 | ret = mi0283qt_init(mipi); | ||
209 | if (ret) | ||
210 | return ret; | ||
211 | |||
212 | /* use devres to fini after drm unregister (drv->remove is before) */ | ||
213 | ret = devm_add_action(dev, mi0283qt_fini, mipi); | ||
214 | if (ret) { | ||
215 | mi0283qt_fini(mipi); | ||
216 | return ret; | ||
217 | } | ||
218 | |||
219 | spi_set_drvdata(spi, mipi); | 213 | spi_set_drvdata(spi, mipi); |
220 | 214 | ||
221 | return devm_tinydrm_register(&mipi->tinydrm); | 215 | return devm_tinydrm_register(&mipi->tinydrm); |
@@ -231,25 +225,13 @@ static void mi0283qt_shutdown(struct spi_device *spi) | |||
231 | static int __maybe_unused mi0283qt_pm_suspend(struct device *dev) | 225 | static int __maybe_unused mi0283qt_pm_suspend(struct device *dev) |
232 | { | 226 | { |
233 | struct mipi_dbi *mipi = dev_get_drvdata(dev); | 227 | struct mipi_dbi *mipi = dev_get_drvdata(dev); |
234 | int ret; | ||
235 | 228 | ||
236 | ret = drm_mode_config_helper_suspend(mipi->tinydrm.drm); | 229 | return drm_mode_config_helper_suspend(mipi->tinydrm.drm); |
237 | if (ret) | ||
238 | return ret; | ||
239 | |||
240 | mi0283qt_fini(mipi); | ||
241 | |||
242 | return 0; | ||
243 | } | 230 | } |
244 | 231 | ||
245 | static int __maybe_unused mi0283qt_pm_resume(struct device *dev) | 232 | static int __maybe_unused mi0283qt_pm_resume(struct device *dev) |
246 | { | 233 | { |
247 | struct mipi_dbi *mipi = dev_get_drvdata(dev); | 234 | struct mipi_dbi *mipi = dev_get_drvdata(dev); |
248 | int ret; | ||
249 | |||
250 | ret = mi0283qt_init(mipi); | ||
251 | if (ret) | ||
252 | return ret; | ||
253 | 235 | ||
254 | drm_mode_config_helper_resume(mipi->tinydrm.drm); | 236 | drm_mode_config_helper_resume(mipi->tinydrm.drm); |
255 | 237 | ||
diff --git a/drivers/gpu/drm/tinydrm/mipi-dbi.c b/drivers/gpu/drm/tinydrm/mipi-dbi.c index aa6b6ce56891..75dd65c57e74 100644 --- a/drivers/gpu/drm/tinydrm/mipi-dbi.c +++ b/drivers/gpu/drm/tinydrm/mipi-dbi.c | |||
@@ -271,21 +271,16 @@ static const struct drm_framebuffer_funcs mipi_dbi_fb_funcs = { | |||
271 | }; | 271 | }; |
272 | 272 | ||
273 | /** | 273 | /** |
274 | * mipi_dbi_pipe_enable - MIPI DBI pipe enable helper | 274 | * mipi_dbi_enable_flush - MIPI DBI enable helper |
275 | * @pipe: Display pipe | 275 | * @mipi: MIPI DBI structure |
276 | * @crtc_state: CRTC state | ||
277 | * | 276 | * |
278 | * This function enables backlight. Drivers can use this as their | 277 | * This function sets &mipi_dbi->enabled, flushes the whole framebuffer and |
278 | * enables the backlight. Drivers can use this in their | ||
279 | * &drm_simple_display_pipe_funcs->enable callback. | 279 | * &drm_simple_display_pipe_funcs->enable callback. |
280 | */ | 280 | */ |
281 | void mipi_dbi_pipe_enable(struct drm_simple_display_pipe *pipe, | 281 | void mipi_dbi_enable_flush(struct mipi_dbi *mipi) |
282 | struct drm_crtc_state *crtc_state) | ||
283 | { | 282 | { |
284 | struct tinydrm_device *tdev = pipe_to_tinydrm(pipe); | 283 | struct drm_framebuffer *fb = mipi->tinydrm.pipe.plane.fb; |
285 | struct mipi_dbi *mipi = mipi_dbi_from_tinydrm(tdev); | ||
286 | struct drm_framebuffer *fb = pipe->plane.fb; | ||
287 | |||
288 | DRM_DEBUG_KMS("\n"); | ||
289 | 284 | ||
290 | mipi->enabled = true; | 285 | mipi->enabled = true; |
291 | if (fb) | 286 | if (fb) |
@@ -293,7 +288,7 @@ void mipi_dbi_pipe_enable(struct drm_simple_display_pipe *pipe, | |||
293 | 288 | ||
294 | tinydrm_enable_backlight(mipi->backlight); | 289 | tinydrm_enable_backlight(mipi->backlight); |
295 | } | 290 | } |
296 | EXPORT_SYMBOL(mipi_dbi_pipe_enable); | 291 | EXPORT_SYMBOL(mipi_dbi_enable_flush); |
297 | 292 | ||
298 | static void mipi_dbi_blank(struct mipi_dbi *mipi) | 293 | static void mipi_dbi_blank(struct mipi_dbi *mipi) |
299 | { | 294 | { |
@@ -316,8 +311,8 @@ static void mipi_dbi_blank(struct mipi_dbi *mipi) | |||
316 | * mipi_dbi_pipe_disable - MIPI DBI pipe disable helper | 311 | * mipi_dbi_pipe_disable - MIPI DBI pipe disable helper |
317 | * @pipe: Display pipe | 312 | * @pipe: Display pipe |
318 | * | 313 | * |
319 | * This function disables backlight if present or if not the | 314 | * This function disables backlight if present, if not the display memory is |
320 | * display memory is blanked. Drivers can use this as their | 315 | * blanked. The regulator is disabled if in use. Drivers can use this as their |
321 | * &drm_simple_display_pipe_funcs->disable callback. | 316 | * &drm_simple_display_pipe_funcs->disable callback. |
322 | */ | 317 | */ |
323 | void mipi_dbi_pipe_disable(struct drm_simple_display_pipe *pipe) | 318 | void mipi_dbi_pipe_disable(struct drm_simple_display_pipe *pipe) |
@@ -333,6 +328,9 @@ void mipi_dbi_pipe_disable(struct drm_simple_display_pipe *pipe) | |||
333 | tinydrm_disable_backlight(mipi->backlight); | 328 | tinydrm_disable_backlight(mipi->backlight); |
334 | else | 329 | else |
335 | mipi_dbi_blank(mipi); | 330 | mipi_dbi_blank(mipi); |
331 | |||
332 | if (mipi->regulator) | ||
333 | regulator_disable(mipi->regulator); | ||
336 | } | 334 | } |
337 | EXPORT_SYMBOL(mipi_dbi_pipe_disable); | 335 | EXPORT_SYMBOL(mipi_dbi_pipe_disable); |
338 | 336 | ||
@@ -416,7 +414,7 @@ void mipi_dbi_hw_reset(struct mipi_dbi *mipi) | |||
416 | return; | 414 | return; |
417 | 415 | ||
418 | gpiod_set_value_cansleep(mipi->reset, 0); | 416 | gpiod_set_value_cansleep(mipi->reset, 0); |
419 | msleep(20); | 417 | usleep_range(20, 1000); |
420 | gpiod_set_value_cansleep(mipi->reset, 1); | 418 | gpiod_set_value_cansleep(mipi->reset, 1); |
421 | msleep(120); | 419 | msleep(120); |
422 | } | 420 | } |
@@ -443,6 +441,7 @@ bool mipi_dbi_display_is_on(struct mipi_dbi *mipi) | |||
443 | 441 | ||
444 | val &= ~DCS_POWER_MODE_RESERVED_MASK; | 442 | val &= ~DCS_POWER_MODE_RESERVED_MASK; |
445 | 443 | ||
444 | /* The poweron/reset value is 08h DCS_POWER_MODE_DISPLAY_NORMAL_MODE */ | ||
446 | if (val != (DCS_POWER_MODE_DISPLAY | | 445 | if (val != (DCS_POWER_MODE_DISPLAY | |
447 | DCS_POWER_MODE_DISPLAY_NORMAL_MODE | DCS_POWER_MODE_SLEEP_MODE)) | 446 | DCS_POWER_MODE_DISPLAY_NORMAL_MODE | DCS_POWER_MODE_SLEEP_MODE)) |
448 | return false; | 447 | return false; |
@@ -453,6 +452,78 @@ bool mipi_dbi_display_is_on(struct mipi_dbi *mipi) | |||
453 | } | 452 | } |
454 | EXPORT_SYMBOL(mipi_dbi_display_is_on); | 453 | EXPORT_SYMBOL(mipi_dbi_display_is_on); |
455 | 454 | ||
455 | static int mipi_dbi_poweron_reset_conditional(struct mipi_dbi *mipi, bool cond) | ||
456 | { | ||
457 | struct device *dev = mipi->tinydrm.drm->dev; | ||
458 | int ret; | ||
459 | |||
460 | if (mipi->regulator) { | ||
461 | ret = regulator_enable(mipi->regulator); | ||
462 | if (ret) { | ||
463 | DRM_DEV_ERROR(dev, "Failed to enable regulator (%d)\n", ret); | ||
464 | return ret; | ||
465 | } | ||
466 | } | ||
467 | |||
468 | if (cond && mipi_dbi_display_is_on(mipi)) | ||
469 | return 1; | ||
470 | |||
471 | mipi_dbi_hw_reset(mipi); | ||
472 | ret = mipi_dbi_command(mipi, MIPI_DCS_SOFT_RESET); | ||
473 | if (ret) { | ||
474 | DRM_DEV_ERROR(dev, "Failed to send reset command (%d)\n", ret); | ||
475 | if (mipi->regulator) | ||
476 | regulator_disable(mipi->regulator); | ||
477 | return ret; | ||
478 | } | ||
479 | |||
480 | /* | ||
481 | * If we did a hw reset, we know the controller is in Sleep mode and | ||
482 | * per MIPI DSC spec should wait 5ms after soft reset. If we didn't, | ||
483 | * we assume worst case and wait 120ms. | ||
484 | */ | ||
485 | if (mipi->reset) | ||
486 | usleep_range(5000, 20000); | ||
487 | else | ||
488 | msleep(120); | ||
489 | |||
490 | return 0; | ||
491 | } | ||
492 | |||
493 | /** | ||
494 | * mipi_dbi_poweron_reset - MIPI DBI poweron and reset | ||
495 | * @mipi: MIPI DBI structure | ||
496 | * | ||
497 | * This function enables the regulator if used and does a hardware and software | ||
498 | * reset. | ||
499 | * | ||
500 | * Returns: | ||
501 | * Zero on success, or a negative error code. | ||
502 | */ | ||
503 | int mipi_dbi_poweron_reset(struct mipi_dbi *mipi) | ||
504 | { | ||
505 | return mipi_dbi_poweron_reset_conditional(mipi, false); | ||
506 | } | ||
507 | EXPORT_SYMBOL(mipi_dbi_poweron_reset); | ||
508 | |||
509 | /** | ||
510 | * mipi_dbi_poweron_conditional_reset - MIPI DBI poweron and conditional reset | ||
511 | * @mipi: MIPI DBI structure | ||
512 | * | ||
513 | * This function enables the regulator if used and if the display is off, it | ||
514 | * does a hardware and software reset. If mipi_dbi_display_is_on() determines | ||
515 | * that the display is on, no reset is performed. | ||
516 | * | ||
517 | * Returns: | ||
518 | * Zero if the controller was reset, 1 if the display was already on, or a | ||
519 | * negative error code. | ||
520 | */ | ||
521 | int mipi_dbi_poweron_conditional_reset(struct mipi_dbi *mipi) | ||
522 | { | ||
523 | return mipi_dbi_poweron_reset_conditional(mipi, true); | ||
524 | } | ||
525 | EXPORT_SYMBOL(mipi_dbi_poweron_conditional_reset); | ||
526 | |||
456 | #if IS_ENABLED(CONFIG_SPI) | 527 | #if IS_ENABLED(CONFIG_SPI) |
457 | 528 | ||
458 | /** | 529 | /** |
diff --git a/drivers/gpu/drm/tinydrm/st7586.c b/drivers/gpu/drm/tinydrm/st7586.c index 5aebfceb740e..a6396ef9cc4a 100644 --- a/drivers/gpu/drm/tinydrm/st7586.c +++ b/drivers/gpu/drm/tinydrm/st7586.c | |||
@@ -179,20 +179,16 @@ static void st7586_pipe_enable(struct drm_simple_display_pipe *pipe, | |||
179 | { | 179 | { |
180 | struct tinydrm_device *tdev = pipe_to_tinydrm(pipe); | 180 | struct tinydrm_device *tdev = pipe_to_tinydrm(pipe); |
181 | struct mipi_dbi *mipi = mipi_dbi_from_tinydrm(tdev); | 181 | struct mipi_dbi *mipi = mipi_dbi_from_tinydrm(tdev); |
182 | struct drm_framebuffer *fb = pipe->plane.fb; | ||
183 | struct device *dev = tdev->drm->dev; | ||
184 | int ret; | 182 | int ret; |
185 | u8 addr_mode; | 183 | u8 addr_mode; |
186 | 184 | ||
187 | DRM_DEBUG_KMS("\n"); | 185 | DRM_DEBUG_KMS("\n"); |
188 | 186 | ||
189 | mipi_dbi_hw_reset(mipi); | 187 | ret = mipi_dbi_poweron_reset(mipi); |
190 | ret = mipi_dbi_command(mipi, ST7586_AUTO_READ_CTRL, 0x9f); | 188 | if (ret) |
191 | if (ret) { | ||
192 | DRM_DEV_ERROR(dev, "Error sending command %d\n", ret); | ||
193 | return; | 189 | return; |
194 | } | ||
195 | 190 | ||
191 | mipi_dbi_command(mipi, ST7586_AUTO_READ_CTRL, 0x9f); | ||
196 | mipi_dbi_command(mipi, ST7586_OTP_RW_CTRL, 0x00); | 192 | mipi_dbi_command(mipi, ST7586_OTP_RW_CTRL, 0x00); |
197 | 193 | ||
198 | msleep(10); | 194 | msleep(10); |
@@ -241,10 +237,7 @@ static void st7586_pipe_enable(struct drm_simple_display_pipe *pipe, | |||
241 | 237 | ||
242 | mipi_dbi_command(mipi, MIPI_DCS_SET_DISPLAY_ON); | 238 | mipi_dbi_command(mipi, MIPI_DCS_SET_DISPLAY_ON); |
243 | 239 | ||
244 | mipi->enabled = true; | 240 | mipi_dbi_enable_flush(mipi); |
245 | |||
246 | if (fb) | ||
247 | fb->funcs->dirty(fb, NULL, 0, 0, NULL, 0); | ||
248 | } | 241 | } |
249 | 242 | ||
250 | static void st7586_pipe_disable(struct drm_simple_display_pipe *pipe) | 243 | static void st7586_pipe_disable(struct drm_simple_display_pipe *pipe) |
diff --git a/drivers/gpu/drm/tinydrm/st7735r.c b/drivers/gpu/drm/tinydrm/st7735r.c index 98ff447f40b4..08b4fb18edb6 100644 --- a/drivers/gpu/drm/tinydrm/st7735r.c +++ b/drivers/gpu/drm/tinydrm/st7735r.c | |||
@@ -40,19 +40,14 @@ static void jd_t18003_t01_pipe_enable(struct drm_simple_display_pipe *pipe, | |||
40 | { | 40 | { |
41 | struct tinydrm_device *tdev = pipe_to_tinydrm(pipe); | 41 | struct tinydrm_device *tdev = pipe_to_tinydrm(pipe); |
42 | struct mipi_dbi *mipi = mipi_dbi_from_tinydrm(tdev); | 42 | struct mipi_dbi *mipi = mipi_dbi_from_tinydrm(tdev); |
43 | struct device *dev = tdev->drm->dev; | ||
44 | int ret; | 43 | int ret; |
45 | u8 addr_mode; | 44 | u8 addr_mode; |
46 | 45 | ||
47 | DRM_DEBUG_KMS("\n"); | 46 | DRM_DEBUG_KMS("\n"); |
48 | 47 | ||
49 | mipi_dbi_hw_reset(mipi); | 48 | ret = mipi_dbi_poweron_reset(mipi); |
50 | 49 | if (ret) | |
51 | ret = mipi_dbi_command(mipi, MIPI_DCS_SOFT_RESET); | ||
52 | if (ret) { | ||
53 | DRM_DEV_ERROR(dev, "Error sending command %d\n", ret); | ||
54 | return; | 50 | return; |
55 | } | ||
56 | 51 | ||
57 | msleep(150); | 52 | msleep(150); |
58 | 53 | ||
@@ -102,7 +97,7 @@ static void jd_t18003_t01_pipe_enable(struct drm_simple_display_pipe *pipe, | |||
102 | 97 | ||
103 | msleep(20); | 98 | msleep(20); |
104 | 99 | ||
105 | mipi_dbi_pipe_enable(pipe, crtc_state); | 100 | mipi_dbi_enable_flush(mipi); |
106 | } | 101 | } |
107 | 102 | ||
108 | static const struct drm_simple_display_pipe_funcs jd_t18003_t01_pipe_funcs = { | 103 | static const struct drm_simple_display_pipe_funcs jd_t18003_t01_pipe_funcs = { |
diff --git a/drivers/gpu/drm/vc4/Makefile b/drivers/gpu/drm/vc4/Makefile index f5500df51686..4a3a868235f8 100644 --- a/drivers/gpu/drm/vc4/Makefile +++ b/drivers/gpu/drm/vc4/Makefile | |||
@@ -15,6 +15,7 @@ vc4-y := \ | |||
15 | vc4_vec.o \ | 15 | vc4_vec.o \ |
16 | vc4_hvs.o \ | 16 | vc4_hvs.o \ |
17 | vc4_irq.o \ | 17 | vc4_irq.o \ |
18 | vc4_perfmon.o \ | ||
18 | vc4_plane.o \ | 19 | vc4_plane.o \ |
19 | vc4_render_cl.o \ | 20 | vc4_render_cl.o \ |
20 | vc4_trace_points.o \ | 21 | vc4_trace_points.o \ |
diff --git a/drivers/gpu/drm/vc4/vc4_drv.c b/drivers/gpu/drm/vc4/vc4_drv.c index ceb385fd69c5..94b99c90425a 100644 --- a/drivers/gpu/drm/vc4/vc4_drv.c +++ b/drivers/gpu/drm/vc4/vc4_drv.c | |||
@@ -101,6 +101,7 @@ static int vc4_get_param_ioctl(struct drm_device *dev, void *data, | |||
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 | case DRM_VC4_PARAM_SUPPORTS_MADVISE: |
104 | case DRM_VC4_PARAM_SUPPORTS_PERFMON: | ||
104 | args->value = true; | 105 | args->value = true; |
105 | break; | 106 | break; |
106 | default: | 107 | default: |
@@ -111,6 +112,26 @@ static int vc4_get_param_ioctl(struct drm_device *dev, void *data, | |||
111 | return 0; | 112 | return 0; |
112 | } | 113 | } |
113 | 114 | ||
115 | static int vc4_open(struct drm_device *dev, struct drm_file *file) | ||
116 | { | ||
117 | struct vc4_file *vc4file; | ||
118 | |||
119 | vc4file = kzalloc(sizeof(*vc4file), GFP_KERNEL); | ||
120 | if (!vc4file) | ||
121 | return -ENOMEM; | ||
122 | |||
123 | vc4_perfmon_open_file(vc4file); | ||
124 | file->driver_priv = vc4file; | ||
125 | return 0; | ||
126 | } | ||
127 | |||
128 | static void vc4_close(struct drm_device *dev, struct drm_file *file) | ||
129 | { | ||
130 | struct vc4_file *vc4file = file->driver_priv; | ||
131 | |||
132 | vc4_perfmon_close_file(vc4file); | ||
133 | } | ||
134 | |||
114 | static const struct vm_operations_struct vc4_vm_ops = { | 135 | static const struct vm_operations_struct vc4_vm_ops = { |
115 | .fault = vc4_fault, | 136 | .fault = vc4_fault, |
116 | .open = drm_gem_vm_open, | 137 | .open = drm_gem_vm_open, |
@@ -143,6 +164,9 @@ static const struct drm_ioctl_desc vc4_drm_ioctls[] = { | |||
143 | DRM_IOCTL_DEF_DRV(VC4_GET_TILING, vc4_get_tiling_ioctl, DRM_RENDER_ALLOW), | 164 | 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), | 165 | DRM_IOCTL_DEF_DRV(VC4_LABEL_BO, vc4_label_bo_ioctl, DRM_RENDER_ALLOW), |
145 | DRM_IOCTL_DEF_DRV(VC4_GEM_MADVISE, vc4_gem_madvise_ioctl, DRM_RENDER_ALLOW), | 166 | DRM_IOCTL_DEF_DRV(VC4_GEM_MADVISE, vc4_gem_madvise_ioctl, DRM_RENDER_ALLOW), |
167 | DRM_IOCTL_DEF_DRV(VC4_PERFMON_CREATE, vc4_perfmon_create_ioctl, DRM_RENDER_ALLOW), | ||
168 | DRM_IOCTL_DEF_DRV(VC4_PERFMON_DESTROY, vc4_perfmon_destroy_ioctl, DRM_RENDER_ALLOW), | ||
169 | DRM_IOCTL_DEF_DRV(VC4_PERFMON_GET_VALUES, vc4_perfmon_get_values_ioctl, DRM_RENDER_ALLOW), | ||
146 | }; | 170 | }; |
147 | 171 | ||
148 | static struct drm_driver vc4_drm_driver = { | 172 | static struct drm_driver vc4_drm_driver = { |
@@ -153,6 +177,8 @@ static struct drm_driver vc4_drm_driver = { | |||
153 | DRIVER_RENDER | | 177 | DRIVER_RENDER | |
154 | DRIVER_PRIME), | 178 | DRIVER_PRIME), |
155 | .lastclose = drm_fb_helper_lastclose, | 179 | .lastclose = drm_fb_helper_lastclose, |
180 | .open = vc4_open, | ||
181 | .postclose = vc4_close, | ||
156 | .irq_handler = vc4_irq, | 182 | .irq_handler = vc4_irq, |
157 | .irq_preinstall = vc4_irq_preinstall, | 183 | .irq_preinstall = vc4_irq_preinstall, |
158 | .irq_postinstall = vc4_irq_postinstall, | 184 | .irq_postinstall = vc4_irq_postinstall, |
diff --git a/drivers/gpu/drm/vc4/vc4_drv.h b/drivers/gpu/drm/vc4/vc4_drv.h index 3af22936d9b3..fefa1664a9f5 100644 --- a/drivers/gpu/drm/vc4/vc4_drv.h +++ b/drivers/gpu/drm/vc4/vc4_drv.h | |||
@@ -11,6 +11,8 @@ | |||
11 | #include <drm/drm_encoder.h> | 11 | #include <drm/drm_encoder.h> |
12 | #include <drm/drm_gem_cma_helper.h> | 12 | #include <drm/drm_gem_cma_helper.h> |
13 | 13 | ||
14 | #include "uapi/drm/vc4_drm.h" | ||
15 | |||
14 | /* Don't forget to update vc4_bo.c: bo_type_names[] when adding to | 16 | /* Don't forget to update vc4_bo.c: bo_type_names[] when adding to |
15 | * this. | 17 | * this. |
16 | */ | 18 | */ |
@@ -29,6 +31,36 @@ enum vc4_kernel_bo_type { | |||
29 | VC4_BO_TYPE_COUNT | 31 | VC4_BO_TYPE_COUNT |
30 | }; | 32 | }; |
31 | 33 | ||
34 | /* Performance monitor object. The perform lifetime is controlled by userspace | ||
35 | * using perfmon related ioctls. A perfmon can be attached to a submit_cl | ||
36 | * request, and when this is the case, HW perf counters will be activated just | ||
37 | * before the submit_cl is submitted to the GPU and disabled when the job is | ||
38 | * done. This way, only events related to a specific job will be counted. | ||
39 | */ | ||
40 | struct vc4_perfmon { | ||
41 | /* Tracks the number of users of the perfmon, when this counter reaches | ||
42 | * zero the perfmon is destroyed. | ||
43 | */ | ||
44 | refcount_t refcnt; | ||
45 | |||
46 | /* Number of counters activated in this perfmon instance | ||
47 | * (should be less than DRM_VC4_MAX_PERF_COUNTERS). | ||
48 | */ | ||
49 | u8 ncounters; | ||
50 | |||
51 | /* Events counted by the HW perf counters. */ | ||
52 | u8 events[DRM_VC4_MAX_PERF_COUNTERS]; | ||
53 | |||
54 | /* Storage for counter values. Counters are incremented by the HW | ||
55 | * perf counter values every time the perfmon is attached to a GPU job. | ||
56 | * This way, perfmon users don't have to retrieve the results after | ||
57 | * each job if they want to track events covering several submissions. | ||
58 | * Note that counter values can't be reset, but you can fake a reset by | ||
59 | * destroying the perfmon and creating a new one. | ||
60 | */ | ||
61 | u64 counters[0]; | ||
62 | }; | ||
63 | |||
32 | struct vc4_dev { | 64 | struct vc4_dev { |
33 | struct drm_device *dev; | 65 | struct drm_device *dev; |
34 | 66 | ||
@@ -121,6 +153,11 @@ struct vc4_dev { | |||
121 | wait_queue_head_t job_wait_queue; | 153 | wait_queue_head_t job_wait_queue; |
122 | struct work_struct job_done_work; | 154 | struct work_struct job_done_work; |
123 | 155 | ||
156 | /* Used to track the active perfmon if any. Access to this field is | ||
157 | * protected by job_lock. | ||
158 | */ | ||
159 | struct vc4_perfmon *active_perfmon; | ||
160 | |||
124 | /* List of struct vc4_seqno_cb for callbacks to be made from a | 161 | /* List of struct vc4_seqno_cb for callbacks to be made from a |
125 | * workqueue when the given seqno is passed. | 162 | * workqueue when the given seqno is passed. |
126 | */ | 163 | */ |
@@ -406,6 +443,21 @@ struct vc4_exec_info { | |||
406 | void *uniforms_v; | 443 | void *uniforms_v; |
407 | uint32_t uniforms_p; | 444 | uint32_t uniforms_p; |
408 | uint32_t uniforms_size; | 445 | uint32_t uniforms_size; |
446 | |||
447 | /* Pointer to a performance monitor object if the user requested it, | ||
448 | * NULL otherwise. | ||
449 | */ | ||
450 | struct vc4_perfmon *perfmon; | ||
451 | }; | ||
452 | |||
453 | /* Per-open file private data. Any driver-specific resource that has to be | ||
454 | * released when the DRM file is closed should be placed here. | ||
455 | */ | ||
456 | struct vc4_file { | ||
457 | struct { | ||
458 | struct idr idr; | ||
459 | struct mutex lock; | ||
460 | } perfmon; | ||
409 | }; | 461 | }; |
410 | 462 | ||
411 | static inline struct vc4_exec_info * | 463 | static inline struct vc4_exec_info * |
@@ -646,3 +698,19 @@ bool vc4_check_tex_size(struct vc4_exec_info *exec, | |||
646 | /* vc4_validate_shader.c */ | 698 | /* vc4_validate_shader.c */ |
647 | struct vc4_validated_shader_info * | 699 | struct vc4_validated_shader_info * |
648 | vc4_validate_shader(struct drm_gem_cma_object *shader_obj); | 700 | vc4_validate_shader(struct drm_gem_cma_object *shader_obj); |
701 | |||
702 | /* vc4_perfmon.c */ | ||
703 | void vc4_perfmon_get(struct vc4_perfmon *perfmon); | ||
704 | void vc4_perfmon_put(struct vc4_perfmon *perfmon); | ||
705 | void vc4_perfmon_start(struct vc4_dev *vc4, struct vc4_perfmon *perfmon); | ||
706 | void vc4_perfmon_stop(struct vc4_dev *vc4, struct vc4_perfmon *perfmon, | ||
707 | bool capture); | ||
708 | struct vc4_perfmon *vc4_perfmon_find(struct vc4_file *vc4file, int id); | ||
709 | void vc4_perfmon_open_file(struct vc4_file *vc4file); | ||
710 | void vc4_perfmon_close_file(struct vc4_file *vc4file); | ||
711 | int vc4_perfmon_create_ioctl(struct drm_device *dev, void *data, | ||
712 | struct drm_file *file_priv); | ||
713 | int vc4_perfmon_destroy_ioctl(struct drm_device *dev, void *data, | ||
714 | struct drm_file *file_priv); | ||
715 | int vc4_perfmon_get_values_ioctl(struct drm_device *dev, void *data, | ||
716 | struct drm_file *file_priv); | ||
diff --git a/drivers/gpu/drm/vc4/vc4_gem.c b/drivers/gpu/drm/vc4/vc4_gem.c index c94cce96544c..2107b0daf8ef 100644 --- a/drivers/gpu/drm/vc4/vc4_gem.c +++ b/drivers/gpu/drm/vc4/vc4_gem.c | |||
@@ -467,14 +467,30 @@ again: | |||
467 | 467 | ||
468 | vc4_flush_caches(dev); | 468 | vc4_flush_caches(dev); |
469 | 469 | ||
470 | /* Only start the perfmon if it was not already started by a previous | ||
471 | * job. | ||
472 | */ | ||
473 | if (exec->perfmon && vc4->active_perfmon != exec->perfmon) | ||
474 | vc4_perfmon_start(vc4, exec->perfmon); | ||
475 | |||
470 | /* Either put the job in the binner if it uses the binner, or | 476 | /* Either put the job in the binner if it uses the binner, or |
471 | * immediately move it to the to-be-rendered queue. | 477 | * immediately move it to the to-be-rendered queue. |
472 | */ | 478 | */ |
473 | if (exec->ct0ca != exec->ct0ea) { | 479 | if (exec->ct0ca != exec->ct0ea) { |
474 | submit_cl(dev, 0, exec->ct0ca, exec->ct0ea); | 480 | submit_cl(dev, 0, exec->ct0ca, exec->ct0ea); |
475 | } else { | 481 | } else { |
482 | struct vc4_exec_info *next; | ||
483 | |||
476 | vc4_move_job_to_render(dev, exec); | 484 | vc4_move_job_to_render(dev, exec); |
477 | goto again; | 485 | next = vc4_first_bin_job(vc4); |
486 | |||
487 | /* We can't start the next bin job if the previous job had a | ||
488 | * different perfmon instance attached to it. The same goes | ||
489 | * if one of them had a perfmon attached to it and the other | ||
490 | * one doesn't. | ||
491 | */ | ||
492 | if (next && next->perfmon == exec->perfmon) | ||
493 | goto again; | ||
478 | } | 494 | } |
479 | } | 495 | } |
480 | 496 | ||
@@ -642,6 +658,7 @@ vc4_queue_submit(struct drm_device *dev, struct vc4_exec_info *exec, | |||
642 | struct ww_acquire_ctx *acquire_ctx) | 658 | struct ww_acquire_ctx *acquire_ctx) |
643 | { | 659 | { |
644 | struct vc4_dev *vc4 = to_vc4_dev(dev); | 660 | struct vc4_dev *vc4 = to_vc4_dev(dev); |
661 | struct vc4_exec_info *renderjob; | ||
645 | uint64_t seqno; | 662 | uint64_t seqno; |
646 | unsigned long irqflags; | 663 | unsigned long irqflags; |
647 | struct vc4_fence *fence; | 664 | struct vc4_fence *fence; |
@@ -667,11 +684,14 @@ vc4_queue_submit(struct drm_device *dev, struct vc4_exec_info *exec, | |||
667 | 684 | ||
668 | list_add_tail(&exec->head, &vc4->bin_job_list); | 685 | list_add_tail(&exec->head, &vc4->bin_job_list); |
669 | 686 | ||
670 | /* If no job was executing, kick ours off. Otherwise, it'll | 687 | /* If no bin job was executing and if the render job (if any) has the |
671 | * get started when the previous job's flush done interrupt | 688 | * same perfmon as our job attached to it (or if both jobs don't have |
672 | * occurs. | 689 | * perfmon activated), then kick ours off. Otherwise, it'll get |
690 | * started when the previous job's flush/render done interrupt occurs. | ||
673 | */ | 691 | */ |
674 | if (vc4_first_bin_job(vc4) == exec) { | 692 | renderjob = vc4_first_render_job(vc4); |
693 | if (vc4_first_bin_job(vc4) == exec && | ||
694 | (!renderjob || renderjob->perfmon == exec->perfmon)) { | ||
675 | vc4_submit_next_bin_job(dev); | 695 | vc4_submit_next_bin_job(dev); |
676 | vc4_queue_hangcheck(dev); | 696 | vc4_queue_hangcheck(dev); |
677 | } | 697 | } |
@@ -936,6 +956,9 @@ vc4_complete_exec(struct drm_device *dev, struct vc4_exec_info *exec) | |||
936 | vc4->bin_alloc_used &= ~exec->bin_slots; | 956 | vc4->bin_alloc_used &= ~exec->bin_slots; |
937 | spin_unlock_irqrestore(&vc4->job_lock, irqflags); | 957 | spin_unlock_irqrestore(&vc4->job_lock, irqflags); |
938 | 958 | ||
959 | /* Release the reference we had on the perf monitor. */ | ||
960 | vc4_perfmon_put(exec->perfmon); | ||
961 | |||
939 | mutex_lock(&vc4->power_lock); | 962 | mutex_lock(&vc4->power_lock); |
940 | if (--vc4->power_refcount == 0) { | 963 | if (--vc4->power_refcount == 0) { |
941 | pm_runtime_mark_last_busy(&vc4->v3d->pdev->dev); | 964 | pm_runtime_mark_last_busy(&vc4->v3d->pdev->dev); |
@@ -1088,6 +1111,7 @@ vc4_submit_cl_ioctl(struct drm_device *dev, void *data, | |||
1088 | struct drm_file *file_priv) | 1111 | struct drm_file *file_priv) |
1089 | { | 1112 | { |
1090 | struct vc4_dev *vc4 = to_vc4_dev(dev); | 1113 | struct vc4_dev *vc4 = to_vc4_dev(dev); |
1114 | struct vc4_file *vc4file = file_priv->driver_priv; | ||
1091 | struct drm_vc4_submit_cl *args = data; | 1115 | struct drm_vc4_submit_cl *args = data; |
1092 | struct vc4_exec_info *exec; | 1116 | struct vc4_exec_info *exec; |
1093 | struct ww_acquire_ctx acquire_ctx; | 1117 | struct ww_acquire_ctx acquire_ctx; |
@@ -1101,6 +1125,11 @@ vc4_submit_cl_ioctl(struct drm_device *dev, void *data, | |||
1101 | return -EINVAL; | 1125 | return -EINVAL; |
1102 | } | 1126 | } |
1103 | 1127 | ||
1128 | if (args->pad2 != 0) { | ||
1129 | DRM_DEBUG("->pad2 must be set to zero\n"); | ||
1130 | return -EINVAL; | ||
1131 | } | ||
1132 | |||
1104 | exec = kcalloc(1, sizeof(*exec), GFP_KERNEL); | 1133 | exec = kcalloc(1, sizeof(*exec), GFP_KERNEL); |
1105 | if (!exec) { | 1134 | if (!exec) { |
1106 | DRM_ERROR("malloc failure on exec struct\n"); | 1135 | DRM_ERROR("malloc failure on exec struct\n"); |
@@ -1126,6 +1155,15 @@ vc4_submit_cl_ioctl(struct drm_device *dev, void *data, | |||
1126 | if (ret) | 1155 | if (ret) |
1127 | goto fail; | 1156 | goto fail; |
1128 | 1157 | ||
1158 | if (args->perfmonid) { | ||
1159 | exec->perfmon = vc4_perfmon_find(vc4file, | ||
1160 | args->perfmonid); | ||
1161 | if (!exec->perfmon) { | ||
1162 | ret = -ENOENT; | ||
1163 | goto fail; | ||
1164 | } | ||
1165 | } | ||
1166 | |||
1129 | if (exec->args->bin_cl_size != 0) { | 1167 | if (exec->args->bin_cl_size != 0) { |
1130 | ret = vc4_get_bcl(dev, exec); | 1168 | ret = vc4_get_bcl(dev, exec); |
1131 | if (ret) | 1169 | if (ret) |
diff --git a/drivers/gpu/drm/vc4/vc4_irq.c b/drivers/gpu/drm/vc4/vc4_irq.c index 3dd62d75f531..4cd2ccfe15f4 100644 --- a/drivers/gpu/drm/vc4/vc4_irq.c +++ b/drivers/gpu/drm/vc4/vc4_irq.c | |||
@@ -104,13 +104,20 @@ static void | |||
104 | vc4_irq_finish_bin_job(struct drm_device *dev) | 104 | vc4_irq_finish_bin_job(struct drm_device *dev) |
105 | { | 105 | { |
106 | struct vc4_dev *vc4 = to_vc4_dev(dev); | 106 | struct vc4_dev *vc4 = to_vc4_dev(dev); |
107 | struct vc4_exec_info *exec = vc4_first_bin_job(vc4); | 107 | struct vc4_exec_info *next, *exec = vc4_first_bin_job(vc4); |
108 | 108 | ||
109 | if (!exec) | 109 | if (!exec) |
110 | return; | 110 | return; |
111 | 111 | ||
112 | vc4_move_job_to_render(dev, exec); | 112 | vc4_move_job_to_render(dev, exec); |
113 | vc4_submit_next_bin_job(dev); | 113 | next = vc4_first_bin_job(vc4); |
114 | |||
115 | /* Only submit the next job in the bin list if it matches the perfmon | ||
116 | * attached to the one that just finished (or if both jobs don't have | ||
117 | * perfmon attached to them). | ||
118 | */ | ||
119 | if (next && next->perfmon == exec->perfmon) | ||
120 | vc4_submit_next_bin_job(dev); | ||
114 | } | 121 | } |
115 | 122 | ||
116 | static void | 123 | static void |
@@ -122,6 +129,10 @@ vc4_cancel_bin_job(struct drm_device *dev) | |||
122 | if (!exec) | 129 | if (!exec) |
123 | return; | 130 | return; |
124 | 131 | ||
132 | /* Stop the perfmon so that the next bin job can be started. */ | ||
133 | if (exec->perfmon) | ||
134 | vc4_perfmon_stop(vc4, exec->perfmon, false); | ||
135 | |||
125 | list_move_tail(&exec->head, &vc4->bin_job_list); | 136 | list_move_tail(&exec->head, &vc4->bin_job_list); |
126 | vc4_submit_next_bin_job(dev); | 137 | vc4_submit_next_bin_job(dev); |
127 | } | 138 | } |
@@ -131,18 +142,41 @@ vc4_irq_finish_render_job(struct drm_device *dev) | |||
131 | { | 142 | { |
132 | struct vc4_dev *vc4 = to_vc4_dev(dev); | 143 | struct vc4_dev *vc4 = to_vc4_dev(dev); |
133 | struct vc4_exec_info *exec = vc4_first_render_job(vc4); | 144 | struct vc4_exec_info *exec = vc4_first_render_job(vc4); |
145 | struct vc4_exec_info *nextbin, *nextrender; | ||
134 | 146 | ||
135 | if (!exec) | 147 | if (!exec) |
136 | return; | 148 | return; |
137 | 149 | ||
138 | vc4->finished_seqno++; | 150 | vc4->finished_seqno++; |
139 | list_move_tail(&exec->head, &vc4->job_done_list); | 151 | list_move_tail(&exec->head, &vc4->job_done_list); |
152 | |||
153 | nextbin = vc4_first_bin_job(vc4); | ||
154 | nextrender = vc4_first_render_job(vc4); | ||
155 | |||
156 | /* Only stop the perfmon if following jobs in the queue don't expect it | ||
157 | * to be enabled. | ||
158 | */ | ||
159 | if (exec->perfmon && !nextrender && | ||
160 | (!nextbin || nextbin->perfmon != exec->perfmon)) | ||
161 | vc4_perfmon_stop(vc4, exec->perfmon, true); | ||
162 | |||
163 | /* If there's a render job waiting, start it. If this is not the case | ||
164 | * we may have to unblock the binner if it's been stalled because of | ||
165 | * perfmon (this can be checked by comparing the perfmon attached to | ||
166 | * the finished renderjob to the one attached to the next bin job: if | ||
167 | * they don't match, this means the binner is stalled and should be | ||
168 | * restarted). | ||
169 | */ | ||
170 | if (nextrender) | ||
171 | vc4_submit_next_render_job(dev); | ||
172 | else if (nextbin && nextbin->perfmon != exec->perfmon) | ||
173 | vc4_submit_next_bin_job(dev); | ||
174 | |||
140 | if (exec->fence) { | 175 | if (exec->fence) { |
141 | dma_fence_signal_locked(exec->fence); | 176 | dma_fence_signal_locked(exec->fence); |
142 | dma_fence_put(exec->fence); | 177 | dma_fence_put(exec->fence); |
143 | exec->fence = NULL; | 178 | exec->fence = NULL; |
144 | } | 179 | } |
145 | vc4_submit_next_render_job(dev); | ||
146 | 180 | ||
147 | wake_up_all(&vc4->job_wait_queue); | 181 | wake_up_all(&vc4->job_wait_queue); |
148 | schedule_work(&vc4->job_done_work); | 182 | schedule_work(&vc4->job_done_work); |
diff --git a/drivers/gpu/drm/vc4/vc4_perfmon.c b/drivers/gpu/drm/vc4/vc4_perfmon.c new file mode 100644 index 000000000000..437e7a27f21d --- /dev/null +++ b/drivers/gpu/drm/vc4/vc4_perfmon.c | |||
@@ -0,0 +1,188 @@ | |||
1 | // SPDX-License-Identifier: GPL-2.0 | ||
2 | /* | ||
3 | * Copyright (C) 2018 Broadcom | ||
4 | */ | ||
5 | |||
6 | /** | ||
7 | * DOC: VC4 V3D performance monitor module | ||
8 | * | ||
9 | * The V3D block provides 16 hardware counters which can count various events. | ||
10 | */ | ||
11 | |||
12 | #include "vc4_drv.h" | ||
13 | #include "vc4_regs.h" | ||
14 | |||
15 | #define VC4_PERFMONID_MIN 1 | ||
16 | #define VC4_PERFMONID_MAX U32_MAX | ||
17 | |||
18 | void vc4_perfmon_get(struct vc4_perfmon *perfmon) | ||
19 | { | ||
20 | if (perfmon) | ||
21 | refcount_inc(&perfmon->refcnt); | ||
22 | } | ||
23 | |||
24 | void vc4_perfmon_put(struct vc4_perfmon *perfmon) | ||
25 | { | ||
26 | if (perfmon && refcount_dec_and_test(&perfmon->refcnt)) | ||
27 | kfree(perfmon); | ||
28 | } | ||
29 | |||
30 | void vc4_perfmon_start(struct vc4_dev *vc4, struct vc4_perfmon *perfmon) | ||
31 | { | ||
32 | unsigned int i; | ||
33 | u32 mask; | ||
34 | |||
35 | if (WARN_ON_ONCE(!perfmon || vc4->active_perfmon)) | ||
36 | return; | ||
37 | |||
38 | for (i = 0; i < perfmon->ncounters; i++) | ||
39 | V3D_WRITE(V3D_PCTRS(i), perfmon->events[i]); | ||
40 | |||
41 | mask = GENMASK(perfmon->ncounters - 1, 0); | ||
42 | V3D_WRITE(V3D_PCTRC, mask); | ||
43 | V3D_WRITE(V3D_PCTRE, V3D_PCTRE_EN | mask); | ||
44 | vc4->active_perfmon = perfmon; | ||
45 | } | ||
46 | |||
47 | void vc4_perfmon_stop(struct vc4_dev *vc4, struct vc4_perfmon *perfmon, | ||
48 | bool capture) | ||
49 | { | ||
50 | unsigned int i; | ||
51 | |||
52 | if (WARN_ON_ONCE(!vc4->active_perfmon || | ||
53 | perfmon != vc4->active_perfmon)) | ||
54 | return; | ||
55 | |||
56 | if (capture) { | ||
57 | for (i = 0; i < perfmon->ncounters; i++) | ||
58 | perfmon->counters[i] += V3D_READ(V3D_PCTR(i)); | ||
59 | } | ||
60 | |||
61 | V3D_WRITE(V3D_PCTRE, 0); | ||
62 | vc4->active_perfmon = NULL; | ||
63 | } | ||
64 | |||
65 | struct vc4_perfmon *vc4_perfmon_find(struct vc4_file *vc4file, int id) | ||
66 | { | ||
67 | struct vc4_perfmon *perfmon; | ||
68 | |||
69 | mutex_lock(&vc4file->perfmon.lock); | ||
70 | perfmon = idr_find(&vc4file->perfmon.idr, id); | ||
71 | vc4_perfmon_get(perfmon); | ||
72 | mutex_unlock(&vc4file->perfmon.lock); | ||
73 | |||
74 | return perfmon; | ||
75 | } | ||
76 | |||
77 | void vc4_perfmon_open_file(struct vc4_file *vc4file) | ||
78 | { | ||
79 | mutex_init(&vc4file->perfmon.lock); | ||
80 | idr_init(&vc4file->perfmon.idr); | ||
81 | } | ||
82 | |||
83 | static int vc4_perfmon_idr_del(int id, void *elem, void *data) | ||
84 | { | ||
85 | struct vc4_perfmon *perfmon = elem; | ||
86 | |||
87 | vc4_perfmon_put(perfmon); | ||
88 | |||
89 | return 0; | ||
90 | } | ||
91 | |||
92 | void vc4_perfmon_close_file(struct vc4_file *vc4file) | ||
93 | { | ||
94 | mutex_lock(&vc4file->perfmon.lock); | ||
95 | idr_for_each(&vc4file->perfmon.idr, vc4_perfmon_idr_del, NULL); | ||
96 | idr_destroy(&vc4file->perfmon.idr); | ||
97 | mutex_unlock(&vc4file->perfmon.lock); | ||
98 | } | ||
99 | |||
100 | int vc4_perfmon_create_ioctl(struct drm_device *dev, void *data, | ||
101 | struct drm_file *file_priv) | ||
102 | { | ||
103 | struct vc4_file *vc4file = file_priv->driver_priv; | ||
104 | struct drm_vc4_perfmon_create *req = data; | ||
105 | struct vc4_perfmon *perfmon; | ||
106 | unsigned int i; | ||
107 | int ret; | ||
108 | |||
109 | /* Number of monitored counters cannot exceed HW limits. */ | ||
110 | if (req->ncounters > DRM_VC4_MAX_PERF_COUNTERS || | ||
111 | !req->ncounters) | ||
112 | return -EINVAL; | ||
113 | |||
114 | /* Make sure all events are valid. */ | ||
115 | for (i = 0; i < req->ncounters; i++) { | ||
116 | if (req->events[i] >= VC4_PERFCNT_NUM_EVENTS) | ||
117 | return -EINVAL; | ||
118 | } | ||
119 | |||
120 | perfmon = kzalloc(sizeof(*perfmon) + (req->ncounters * sizeof(u64)), | ||
121 | GFP_KERNEL); | ||
122 | if (!perfmon) | ||
123 | return -ENOMEM; | ||
124 | |||
125 | for (i = 0; i < req->ncounters; i++) | ||
126 | perfmon->events[i] = req->events[i]; | ||
127 | |||
128 | perfmon->ncounters = req->ncounters; | ||
129 | |||
130 | refcount_set(&perfmon->refcnt, 1); | ||
131 | |||
132 | mutex_lock(&vc4file->perfmon.lock); | ||
133 | ret = idr_alloc(&vc4file->perfmon.idr, perfmon, VC4_PERFMONID_MIN, | ||
134 | VC4_PERFMONID_MAX, GFP_KERNEL); | ||
135 | mutex_unlock(&vc4file->perfmon.lock); | ||
136 | |||
137 | if (ret < 0) { | ||
138 | kfree(perfmon); | ||
139 | return ret; | ||
140 | } | ||
141 | |||
142 | req->id = ret; | ||
143 | return 0; | ||
144 | } | ||
145 | |||
146 | int vc4_perfmon_destroy_ioctl(struct drm_device *dev, void *data, | ||
147 | struct drm_file *file_priv) | ||
148 | { | ||
149 | struct vc4_file *vc4file = file_priv->driver_priv; | ||
150 | struct drm_vc4_perfmon_destroy *req = data; | ||
151 | struct vc4_perfmon *perfmon; | ||
152 | |||
153 | mutex_lock(&vc4file->perfmon.lock); | ||
154 | perfmon = idr_remove(&vc4file->perfmon.idr, req->id); | ||
155 | mutex_unlock(&vc4file->perfmon.lock); | ||
156 | |||
157 | if (!perfmon) | ||
158 | return -EINVAL; | ||
159 | |||
160 | vc4_perfmon_put(perfmon); | ||
161 | return 0; | ||
162 | } | ||
163 | |||
164 | int vc4_perfmon_get_values_ioctl(struct drm_device *dev, void *data, | ||
165 | struct drm_file *file_priv) | ||
166 | { | ||
167 | struct vc4_file *vc4file = file_priv->driver_priv; | ||
168 | struct drm_vc4_perfmon_get_values *req = data; | ||
169 | struct vc4_perfmon *perfmon; | ||
170 | int ret; | ||
171 | |||
172 | mutex_lock(&vc4file->perfmon.lock); | ||
173 | perfmon = idr_find(&vc4file->perfmon.idr, req->id); | ||
174 | vc4_perfmon_get(perfmon); | ||
175 | mutex_unlock(&vc4file->perfmon.lock); | ||
176 | |||
177 | if (!perfmon) | ||
178 | return -EINVAL; | ||
179 | |||
180 | if (copy_to_user(u64_to_user_ptr(req->values_ptr), perfmon->counters, | ||
181 | perfmon->ncounters * sizeof(u64))) | ||
182 | ret = -EFAULT; | ||
183 | else | ||
184 | ret = 0; | ||
185 | |||
186 | vc4_perfmon_put(perfmon); | ||
187 | return ret; | ||
188 | } | ||
diff --git a/drivers/gpu/drm/vc4/vc4_plane.c b/drivers/gpu/drm/vc4/vc4_plane.c index 515f97997624..61ad955645a5 100644 --- a/drivers/gpu/drm/vc4/vc4_plane.c +++ b/drivers/gpu/drm/vc4/vc4_plane.c | |||
@@ -85,47 +85,46 @@ static const struct hvs_format { | |||
85 | u32 drm; /* DRM_FORMAT_* */ | 85 | u32 drm; /* DRM_FORMAT_* */ |
86 | u32 hvs; /* HVS_FORMAT_* */ | 86 | u32 hvs; /* HVS_FORMAT_* */ |
87 | u32 pixel_order; | 87 | u32 pixel_order; |
88 | bool has_alpha; | ||
89 | } hvs_formats[] = { | 88 | } hvs_formats[] = { |
90 | { | 89 | { |
91 | .drm = DRM_FORMAT_XRGB8888, .hvs = HVS_PIXEL_FORMAT_RGBA8888, | 90 | .drm = DRM_FORMAT_XRGB8888, .hvs = HVS_PIXEL_FORMAT_RGBA8888, |
92 | .pixel_order = HVS_PIXEL_ORDER_ABGR, .has_alpha = false, | 91 | .pixel_order = HVS_PIXEL_ORDER_ABGR, |
93 | }, | 92 | }, |
94 | { | 93 | { |
95 | .drm = DRM_FORMAT_ARGB8888, .hvs = HVS_PIXEL_FORMAT_RGBA8888, | 94 | .drm = DRM_FORMAT_ARGB8888, .hvs = HVS_PIXEL_FORMAT_RGBA8888, |
96 | .pixel_order = HVS_PIXEL_ORDER_ABGR, .has_alpha = true, | 95 | .pixel_order = HVS_PIXEL_ORDER_ABGR, |
97 | }, | 96 | }, |
98 | { | 97 | { |
99 | .drm = DRM_FORMAT_ABGR8888, .hvs = HVS_PIXEL_FORMAT_RGBA8888, | 98 | .drm = DRM_FORMAT_ABGR8888, .hvs = HVS_PIXEL_FORMAT_RGBA8888, |
100 | .pixel_order = HVS_PIXEL_ORDER_ARGB, .has_alpha = true, | 99 | .pixel_order = HVS_PIXEL_ORDER_ARGB, |
101 | }, | 100 | }, |
102 | { | 101 | { |
103 | .drm = DRM_FORMAT_XBGR8888, .hvs = HVS_PIXEL_FORMAT_RGBA8888, | 102 | .drm = DRM_FORMAT_XBGR8888, .hvs = HVS_PIXEL_FORMAT_RGBA8888, |
104 | .pixel_order = HVS_PIXEL_ORDER_ARGB, .has_alpha = false, | 103 | .pixel_order = HVS_PIXEL_ORDER_ARGB, |
105 | }, | 104 | }, |
106 | { | 105 | { |
107 | .drm = DRM_FORMAT_RGB565, .hvs = HVS_PIXEL_FORMAT_RGB565, | 106 | .drm = DRM_FORMAT_RGB565, .hvs = HVS_PIXEL_FORMAT_RGB565, |
108 | .pixel_order = HVS_PIXEL_ORDER_XRGB, .has_alpha = false, | 107 | .pixel_order = HVS_PIXEL_ORDER_XRGB, |
109 | }, | 108 | }, |
110 | { | 109 | { |
111 | .drm = DRM_FORMAT_BGR565, .hvs = HVS_PIXEL_FORMAT_RGB565, | 110 | .drm = DRM_FORMAT_BGR565, .hvs = HVS_PIXEL_FORMAT_RGB565, |
112 | .pixel_order = HVS_PIXEL_ORDER_XBGR, .has_alpha = false, | 111 | .pixel_order = HVS_PIXEL_ORDER_XBGR, |
113 | }, | 112 | }, |
114 | { | 113 | { |
115 | .drm = DRM_FORMAT_ARGB1555, .hvs = HVS_PIXEL_FORMAT_RGBA5551, | 114 | .drm = DRM_FORMAT_ARGB1555, .hvs = HVS_PIXEL_FORMAT_RGBA5551, |
116 | .pixel_order = HVS_PIXEL_ORDER_ABGR, .has_alpha = true, | 115 | .pixel_order = HVS_PIXEL_ORDER_ABGR, |
117 | }, | 116 | }, |
118 | { | 117 | { |
119 | .drm = DRM_FORMAT_XRGB1555, .hvs = HVS_PIXEL_FORMAT_RGBA5551, | 118 | .drm = DRM_FORMAT_XRGB1555, .hvs = HVS_PIXEL_FORMAT_RGBA5551, |
120 | .pixel_order = HVS_PIXEL_ORDER_ABGR, .has_alpha = false, | 119 | .pixel_order = HVS_PIXEL_ORDER_ABGR, |
121 | }, | 120 | }, |
122 | { | 121 | { |
123 | .drm = DRM_FORMAT_RGB888, .hvs = HVS_PIXEL_FORMAT_RGB888, | 122 | .drm = DRM_FORMAT_RGB888, .hvs = HVS_PIXEL_FORMAT_RGB888, |
124 | .pixel_order = HVS_PIXEL_ORDER_XRGB, .has_alpha = false, | 123 | .pixel_order = HVS_PIXEL_ORDER_XRGB, |
125 | }, | 124 | }, |
126 | { | 125 | { |
127 | .drm = DRM_FORMAT_BGR888, .hvs = HVS_PIXEL_FORMAT_RGB888, | 126 | .drm = DRM_FORMAT_BGR888, .hvs = HVS_PIXEL_FORMAT_RGB888, |
128 | .pixel_order = HVS_PIXEL_ORDER_XBGR, .has_alpha = false, | 127 | .pixel_order = HVS_PIXEL_ORDER_XBGR, |
129 | }, | 128 | }, |
130 | { | 129 | { |
131 | .drm = DRM_FORMAT_YUV422, | 130 | .drm = DRM_FORMAT_YUV422, |
@@ -622,7 +621,7 @@ static int vc4_plane_mode_set(struct drm_plane *plane, | |||
622 | /* Position Word 2: Source Image Size, Alpha Mode */ | 621 | /* Position Word 2: Source Image Size, Alpha Mode */ |
623 | vc4_state->pos2_offset = vc4_state->dlist_count; | 622 | vc4_state->pos2_offset = vc4_state->dlist_count; |
624 | vc4_dlist_write(vc4_state, | 623 | vc4_dlist_write(vc4_state, |
625 | VC4_SET_FIELD(format->has_alpha ? | 624 | VC4_SET_FIELD(fb->format->has_alpha ? |
626 | SCALER_POS2_ALPHA_MODE_PIPELINE : | 625 | SCALER_POS2_ALPHA_MODE_PIPELINE : |
627 | SCALER_POS2_ALPHA_MODE_FIXED, | 626 | SCALER_POS2_ALPHA_MODE_FIXED, |
628 | SCALER_POS2_ALPHA_MODE) | | 627 | SCALER_POS2_ALPHA_MODE) | |
diff --git a/drivers/gpu/drm/vc4/vc4_regs.h b/drivers/gpu/drm/vc4/vc4_regs.h index 55677bd50f66..b9749cb24063 100644 --- a/drivers/gpu/drm/vc4/vc4_regs.h +++ b/drivers/gpu/drm/vc4/vc4_regs.h | |||
@@ -122,38 +122,9 @@ | |||
122 | #define V3D_VPMBASE 0x00504 | 122 | #define V3D_VPMBASE 0x00504 |
123 | #define V3D_PCTRC 0x00670 | 123 | #define V3D_PCTRC 0x00670 |
124 | #define V3D_PCTRE 0x00674 | 124 | #define V3D_PCTRE 0x00674 |
125 | #define V3D_PCTR0 0x00680 | 125 | # define V3D_PCTRE_EN BIT(31) |
126 | #define V3D_PCTRS0 0x00684 | 126 | #define V3D_PCTR(x) (0x00680 + ((x) * 8)) |
127 | #define V3D_PCTR1 0x00688 | 127 | #define V3D_PCTRS(x) (0x00684 + ((x) * 8)) |
128 | #define V3D_PCTRS1 0x0068c | ||
129 | #define V3D_PCTR2 0x00690 | ||
130 | #define V3D_PCTRS2 0x00694 | ||
131 | #define V3D_PCTR3 0x00698 | ||
132 | #define V3D_PCTRS3 0x0069c | ||
133 | #define V3D_PCTR4 0x006a0 | ||
134 | #define V3D_PCTRS4 0x006a4 | ||
135 | #define V3D_PCTR5 0x006a8 | ||
136 | #define V3D_PCTRS5 0x006ac | ||
137 | #define V3D_PCTR6 0x006b0 | ||
138 | #define V3D_PCTRS6 0x006b4 | ||
139 | #define V3D_PCTR7 0x006b8 | ||
140 | #define V3D_PCTRS7 0x006bc | ||
141 | #define V3D_PCTR8 0x006c0 | ||
142 | #define V3D_PCTRS8 0x006c4 | ||
143 | #define V3D_PCTR9 0x006c8 | ||
144 | #define V3D_PCTRS9 0x006cc | ||
145 | #define V3D_PCTR10 0x006d0 | ||
146 | #define V3D_PCTRS10 0x006d4 | ||
147 | #define V3D_PCTR11 0x006d8 | ||
148 | #define V3D_PCTRS11 0x006dc | ||
149 | #define V3D_PCTR12 0x006e0 | ||
150 | #define V3D_PCTRS12 0x006e4 | ||
151 | #define V3D_PCTR13 0x006e8 | ||
152 | #define V3D_PCTRS13 0x006ec | ||
153 | #define V3D_PCTR14 0x006f0 | ||
154 | #define V3D_PCTRS14 0x006f4 | ||
155 | #define V3D_PCTR15 0x006f8 | ||
156 | #define V3D_PCTRS15 0x006fc | ||
157 | #define V3D_DBGE 0x00f00 | 128 | #define V3D_DBGE 0x00f00 |
158 | #define V3D_FDBGO 0x00f04 | 129 | #define V3D_FDBGO 0x00f04 |
159 | #define V3D_FDBGB 0x00f08 | 130 | #define V3D_FDBGB 0x00f08 |
diff --git a/drivers/gpu/drm/vc4/vc4_v3d.c b/drivers/gpu/drm/vc4/vc4_v3d.c index 493f392b3a0a..bfc2fa73d2ae 100644 --- a/drivers/gpu/drm/vc4/vc4_v3d.c +++ b/drivers/gpu/drm/vc4/vc4_v3d.c | |||
@@ -68,38 +68,38 @@ static const struct { | |||
68 | REGDEF(V3D_VPMBASE), | 68 | REGDEF(V3D_VPMBASE), |
69 | REGDEF(V3D_PCTRC), | 69 | REGDEF(V3D_PCTRC), |
70 | REGDEF(V3D_PCTRE), | 70 | REGDEF(V3D_PCTRE), |
71 | REGDEF(V3D_PCTR0), | 71 | REGDEF(V3D_PCTR(0)), |
72 | REGDEF(V3D_PCTRS0), | 72 | REGDEF(V3D_PCTRS(0)), |
73 | REGDEF(V3D_PCTR1), | 73 | REGDEF(V3D_PCTR(1)), |
74 | REGDEF(V3D_PCTRS1), | 74 | REGDEF(V3D_PCTRS(1)), |
75 | REGDEF(V3D_PCTR2), | 75 | REGDEF(V3D_PCTR(2)), |
76 | REGDEF(V3D_PCTRS2), | 76 | REGDEF(V3D_PCTRS(2)), |
77 | REGDEF(V3D_PCTR3), | 77 | REGDEF(V3D_PCTR(3)), |
78 | REGDEF(V3D_PCTRS3), | 78 | REGDEF(V3D_PCTRS(3)), |
79 | REGDEF(V3D_PCTR4), | 79 | REGDEF(V3D_PCTR(4)), |
80 | REGDEF(V3D_PCTRS4), | 80 | REGDEF(V3D_PCTRS(4)), |
81 | REGDEF(V3D_PCTR5), | 81 | REGDEF(V3D_PCTR(5)), |
82 | REGDEF(V3D_PCTRS5), | 82 | REGDEF(V3D_PCTRS(5)), |
83 | REGDEF(V3D_PCTR6), | 83 | REGDEF(V3D_PCTR(6)), |
84 | REGDEF(V3D_PCTRS6), | 84 | REGDEF(V3D_PCTRS(6)), |
85 | REGDEF(V3D_PCTR7), | 85 | REGDEF(V3D_PCTR(7)), |
86 | REGDEF(V3D_PCTRS7), | 86 | REGDEF(V3D_PCTRS(7)), |
87 | REGDEF(V3D_PCTR8), | 87 | REGDEF(V3D_PCTR(8)), |
88 | REGDEF(V3D_PCTRS8), | 88 | REGDEF(V3D_PCTRS(8)), |
89 | REGDEF(V3D_PCTR9), | 89 | REGDEF(V3D_PCTR(9)), |
90 | REGDEF(V3D_PCTRS9), | 90 | REGDEF(V3D_PCTRS(9)), |
91 | REGDEF(V3D_PCTR10), | 91 | REGDEF(V3D_PCTR(10)), |
92 | REGDEF(V3D_PCTRS10), | 92 | REGDEF(V3D_PCTRS(10)), |
93 | REGDEF(V3D_PCTR11), | 93 | REGDEF(V3D_PCTR(11)), |
94 | REGDEF(V3D_PCTRS11), | 94 | REGDEF(V3D_PCTRS(11)), |
95 | REGDEF(V3D_PCTR12), | 95 | REGDEF(V3D_PCTR(12)), |
96 | REGDEF(V3D_PCTRS12), | 96 | REGDEF(V3D_PCTRS(12)), |
97 | REGDEF(V3D_PCTR13), | 97 | REGDEF(V3D_PCTR(13)), |
98 | REGDEF(V3D_PCTRS13), | 98 | REGDEF(V3D_PCTRS(13)), |
99 | REGDEF(V3D_PCTR14), | 99 | REGDEF(V3D_PCTR(14)), |
100 | REGDEF(V3D_PCTRS14), | 100 | REGDEF(V3D_PCTRS(14)), |
101 | REGDEF(V3D_PCTR15), | 101 | REGDEF(V3D_PCTR(15)), |
102 | REGDEF(V3D_PCTRS15), | 102 | REGDEF(V3D_PCTRS(15)), |
103 | REGDEF(V3D_DBGE), | 103 | REGDEF(V3D_DBGE), |
104 | REGDEF(V3D_FDBGO), | 104 | REGDEF(V3D_FDBGO), |
105 | REGDEF(V3D_FDBGB), | 105 | REGDEF(V3D_FDBGB), |
diff --git a/drivers/gpu/drm/virtio/virtgpu_ioctl.c b/drivers/gpu/drm/virtio/virtgpu_ioctl.c index 5720a0d4ac0a..355569a9b5cb 100644 --- a/drivers/gpu/drm/virtio/virtgpu_ioctl.c +++ b/drivers/gpu/drm/virtio/virtgpu_ioctl.c | |||
@@ -518,6 +518,8 @@ static int virtio_gpu_get_caps_ioctl(struct drm_device *dev, | |||
518 | 518 | ||
519 | ret = wait_event_timeout(vgdev->resp_wq, | 519 | ret = wait_event_timeout(vgdev->resp_wq, |
520 | atomic_read(&cache_ent->is_valid), 5 * HZ); | 520 | atomic_read(&cache_ent->is_valid), 5 * HZ); |
521 | if (!ret) | ||
522 | return -EBUSY; | ||
521 | 523 | ||
522 | ptr = cache_ent->caps_cache; | 524 | ptr = cache_ent->caps_cache; |
523 | 525 | ||
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c index ead61015cd79..1107d6d03506 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c | |||
@@ -449,10 +449,9 @@ int vmw_du_primary_plane_atomic_check(struct drm_plane *plane, | |||
449 | if (state->crtc) | 449 | if (state->crtc) |
450 | crtc_state = drm_atomic_get_new_crtc_state(state->state, state->crtc); | 450 | crtc_state = drm_atomic_get_new_crtc_state(state->state, state->crtc); |
451 | 451 | ||
452 | if (crtc_state && crtc_state->enable) { | 452 | if (crtc_state && crtc_state->enable) |
453 | clip.x2 = crtc_state->adjusted_mode.hdisplay; | 453 | drm_mode_get_hv_timing(&crtc_state->mode, |
454 | clip.y2 = crtc_state->adjusted_mode.vdisplay; | 454 | &clip.x2, &clip.y2); |
455 | } | ||
456 | 455 | ||
457 | ret = drm_atomic_helper_check_plane_state(state, crtc_state, &clip, | 456 | ret = drm_atomic_helper_check_plane_state(state, crtc_state, &clip, |
458 | DRM_PLANE_HELPER_NO_SCALING, | 457 | DRM_PLANE_HELPER_NO_SCALING, |
diff --git a/drivers/gpu/drm/zte/zx_plane.c b/drivers/gpu/drm/zte/zx_plane.c index 68fd2e2dc78a..8e1f34274e24 100644 --- a/drivers/gpu/drm/zte/zx_plane.c +++ b/drivers/gpu/drm/zte/zx_plane.c | |||
@@ -55,7 +55,7 @@ static int zx_vl_plane_atomic_check(struct drm_plane *plane, | |||
55 | struct drm_framebuffer *fb = plane_state->fb; | 55 | struct drm_framebuffer *fb = plane_state->fb; |
56 | struct drm_crtc *crtc = plane_state->crtc; | 56 | struct drm_crtc *crtc = plane_state->crtc; |
57 | struct drm_crtc_state *crtc_state; | 57 | struct drm_crtc_state *crtc_state; |
58 | struct drm_rect clip; | 58 | struct drm_rect clip = {}; |
59 | int min_scale = FRAC_16_16(1, 8); | 59 | int min_scale = FRAC_16_16(1, 8); |
60 | int max_scale = FRAC_16_16(8, 1); | 60 | int max_scale = FRAC_16_16(8, 1); |
61 | 61 | ||
@@ -75,10 +75,9 @@ static int zx_vl_plane_atomic_check(struct drm_plane *plane, | |||
75 | if (!plane_state->crtc) | 75 | if (!plane_state->crtc) |
76 | return -EINVAL; | 76 | return -EINVAL; |
77 | 77 | ||
78 | clip.x1 = 0; | 78 | if (crtc_state->enable) |
79 | clip.y1 = 0; | 79 | drm_mode_get_hv_timing(&crtc_state->mode, |
80 | clip.x2 = crtc_state->adjusted_mode.hdisplay; | 80 | &clip.x2, &clip.y2); |
81 | clip.y2 = crtc_state->adjusted_mode.vdisplay; | ||
82 | 81 | ||
83 | return drm_atomic_helper_check_plane_state(plane_state, crtc_state, | 82 | return drm_atomic_helper_check_plane_state(plane_state, crtc_state, |
84 | &clip, min_scale, max_scale, | 83 | &clip, min_scale, max_scale, |
@@ -292,7 +291,7 @@ static int zx_gl_plane_atomic_check(struct drm_plane *plane, | |||
292 | struct drm_framebuffer *fb = plane_state->fb; | 291 | struct drm_framebuffer *fb = plane_state->fb; |
293 | struct drm_crtc *crtc = plane_state->crtc; | 292 | struct drm_crtc *crtc = plane_state->crtc; |
294 | struct drm_crtc_state *crtc_state; | 293 | struct drm_crtc_state *crtc_state; |
295 | struct drm_rect clip; | 294 | struct drm_rect clip = {}; |
296 | 295 | ||
297 | if (!crtc || !fb) | 296 | if (!crtc || !fb) |
298 | return 0; | 297 | return 0; |
@@ -310,10 +309,9 @@ static int zx_gl_plane_atomic_check(struct drm_plane *plane, | |||
310 | if (!plane_state->crtc) | 309 | if (!plane_state->crtc) |
311 | return -EINVAL; | 310 | return -EINVAL; |
312 | 311 | ||
313 | clip.x1 = 0; | 312 | if (crtc_state->enable) |
314 | clip.y1 = 0; | 313 | drm_mode_get_hv_timing(&crtc_state->mode, |
315 | clip.x2 = crtc_state->adjusted_mode.hdisplay; | 314 | &clip.x2, &clip.y2); |
316 | clip.y2 = crtc_state->adjusted_mode.vdisplay; | ||
317 | 315 | ||
318 | return drm_atomic_helper_check_plane_state(plane_state, crtc_state, | 316 | return drm_atomic_helper_check_plane_state(plane_state, crtc_state, |
319 | &clip, | 317 | &clip, |
diff --git a/include/drm/bridge/dw_mipi_dsi.h b/include/drm/bridge/dw_mipi_dsi.h index 9b30fec302c8..d9c6d549f971 100644 --- a/include/drm/bridge/dw_mipi_dsi.h +++ b/include/drm/bridge/dw_mipi_dsi.h | |||
@@ -10,6 +10,8 @@ | |||
10 | #ifndef __DW_MIPI_DSI__ | 10 | #ifndef __DW_MIPI_DSI__ |
11 | #define __DW_MIPI_DSI__ | 11 | #define __DW_MIPI_DSI__ |
12 | 12 | ||
13 | struct dw_mipi_dsi; | ||
14 | |||
13 | struct dw_mipi_dsi_phy_ops { | 15 | struct dw_mipi_dsi_phy_ops { |
14 | int (*init)(void *priv_data); | 16 | int (*init)(void *priv_data); |
15 | int (*get_lane_mbps)(void *priv_data, struct drm_display_mode *mode, | 17 | int (*get_lane_mbps)(void *priv_data, struct drm_display_mode *mode, |
@@ -29,11 +31,14 @@ struct dw_mipi_dsi_plat_data { | |||
29 | void *priv_data; | 31 | void *priv_data; |
30 | }; | 32 | }; |
31 | 33 | ||
32 | int dw_mipi_dsi_probe(struct platform_device *pdev, | 34 | struct dw_mipi_dsi *dw_mipi_dsi_probe(struct platform_device *pdev, |
33 | const struct dw_mipi_dsi_plat_data *plat_data); | 35 | const struct dw_mipi_dsi_plat_data |
34 | void dw_mipi_dsi_remove(struct platform_device *pdev); | 36 | *plat_data); |
35 | int dw_mipi_dsi_bind(struct platform_device *pdev, struct drm_encoder *encoder, | 37 | void dw_mipi_dsi_remove(struct dw_mipi_dsi *dsi); |
36 | const struct dw_mipi_dsi_plat_data *plat_data); | 38 | struct dw_mipi_dsi *dw_mipi_dsi_bind(struct platform_device *pdev, |
37 | void dw_mipi_dsi_unbind(struct device *dev); | 39 | struct drm_encoder *encoder, |
40 | const struct dw_mipi_dsi_plat_data | ||
41 | *plat_data); | ||
42 | void dw_mipi_dsi_unbind(struct dw_mipi_dsi *dsi); | ||
38 | 43 | ||
39 | #endif /* __DW_MIPI_DSI__ */ | 44 | #endif /* __DW_MIPI_DSI__ */ |
diff --git a/include/drm/drm_atomic.h b/include/drm/drm_atomic.h index 1c27526c499e..cf13842a6dbd 100644 --- a/include/drm/drm_atomic.h +++ b/include/drm/drm_atomic.h | |||
@@ -134,6 +134,15 @@ struct drm_crtc_commit { | |||
134 | * &drm_pending_vblank_event pointer to clean up private events. | 134 | * &drm_pending_vblank_event pointer to clean up private events. |
135 | */ | 135 | */ |
136 | struct drm_pending_vblank_event *event; | 136 | struct drm_pending_vblank_event *event; |
137 | |||
138 | /** | ||
139 | * @abort_completion: | ||
140 | * | ||
141 | * A flag that's set after drm_atomic_helper_setup_commit takes a second | ||
142 | * reference for the completion of $drm_crtc_state.event. It's used by | ||
143 | * the free code to remove the second reference if commit fails. | ||
144 | */ | ||
145 | bool abort_completion; | ||
137 | }; | 146 | }; |
138 | 147 | ||
139 | struct __drm_planes_state { | 148 | struct __drm_planes_state { |
diff --git a/include/drm/drm_bridge.h b/include/drm/drm_bridge.h index 682d01ba920c..3270fec46979 100644 --- a/include/drm/drm_bridge.h +++ b/include/drm/drm_bridge.h | |||
@@ -29,6 +29,7 @@ | |||
29 | #include <drm/drm_modes.h> | 29 | #include <drm/drm_modes.h> |
30 | 30 | ||
31 | struct drm_bridge; | 31 | struct drm_bridge; |
32 | struct drm_bridge_timings; | ||
32 | struct drm_panel; | 33 | struct drm_panel; |
33 | 34 | ||
34 | /** | 35 | /** |
@@ -90,7 +91,7 @@ struct drm_bridge_funcs { | |||
90 | * | 91 | * |
91 | * drm_mode_status Enum | 92 | * drm_mode_status Enum |
92 | */ | 93 | */ |
93 | enum drm_mode_status (*mode_valid)(struct drm_bridge *crtc, | 94 | enum drm_mode_status (*mode_valid)(struct drm_bridge *bridge, |
94 | const struct drm_display_mode *mode); | 95 | const struct drm_display_mode *mode); |
95 | 96 | ||
96 | /** | 97 | /** |
@@ -223,12 +224,43 @@ struct drm_bridge_funcs { | |||
223 | }; | 224 | }; |
224 | 225 | ||
225 | /** | 226 | /** |
227 | * struct drm_bridge_timings - timing information for the bridge | ||
228 | */ | ||
229 | struct drm_bridge_timings { | ||
230 | /** | ||
231 | * @sampling_edge: | ||
232 | * | ||
233 | * Tells whether the bridge samples the digital input signal | ||
234 | * from the display engine on the positive or negative edge of the | ||
235 | * clock, this should reuse the DRM_BUS_FLAG_PIXDATA_[POS|NEG]EDGE | ||
236 | * bitwise flags from the DRM connector (bit 2 and 3 valid). | ||
237 | */ | ||
238 | u32 sampling_edge; | ||
239 | /** | ||
240 | * @setup_time_ps: | ||
241 | * | ||
242 | * Defines the time in picoseconds the input data lines must be | ||
243 | * stable before the clock edge. | ||
244 | */ | ||
245 | u32 setup_time_ps; | ||
246 | /** | ||
247 | * @hold_time_ps: | ||
248 | * | ||
249 | * Defines the time in picoseconds taken for the bridge to sample the | ||
250 | * input signal after the clock edge. | ||
251 | */ | ||
252 | u32 hold_time_ps; | ||
253 | }; | ||
254 | |||
255 | /** | ||
226 | * struct drm_bridge - central DRM bridge control structure | 256 | * struct drm_bridge - central DRM bridge control structure |
227 | * @dev: DRM device this bridge belongs to | 257 | * @dev: DRM device this bridge belongs to |
228 | * @encoder: encoder to which this bridge is connected | 258 | * @encoder: encoder to which this bridge is connected |
229 | * @next: the next bridge in the encoder chain | 259 | * @next: the next bridge in the encoder chain |
230 | * @of_node: device node pointer to the bridge | 260 | * @of_node: device node pointer to the bridge |
231 | * @list: to keep track of all added bridges | 261 | * @list: to keep track of all added bridges |
262 | * @timings: the timing specification for the bridge, if any (may | ||
263 | * be NULL) | ||
232 | * @funcs: control functions | 264 | * @funcs: control functions |
233 | * @driver_private: pointer to the bridge driver's internal context | 265 | * @driver_private: pointer to the bridge driver's internal context |
234 | */ | 266 | */ |
@@ -240,6 +272,7 @@ struct drm_bridge { | |||
240 | struct device_node *of_node; | 272 | struct device_node *of_node; |
241 | #endif | 273 | #endif |
242 | struct list_head list; | 274 | struct list_head list; |
275 | const struct drm_bridge_timings *timings; | ||
243 | 276 | ||
244 | const struct drm_bridge_funcs *funcs; | 277 | const struct drm_bridge_funcs *funcs; |
245 | void *driver_private; | 278 | void *driver_private; |
diff --git a/include/drm/drm_cache.h b/include/drm/drm_cache.h index beab0f0d0cfb..bfe1639df02d 100644 --- a/include/drm/drm_cache.h +++ b/include/drm/drm_cache.h | |||
@@ -38,6 +38,8 @@ | |||
38 | void drm_clflush_pages(struct page *pages[], unsigned long num_pages); | 38 | void drm_clflush_pages(struct page *pages[], unsigned long num_pages); |
39 | void drm_clflush_sg(struct sg_table *st); | 39 | void drm_clflush_sg(struct sg_table *st); |
40 | void drm_clflush_virt_range(void *addr, unsigned long length); | 40 | void drm_clflush_virt_range(void *addr, unsigned long length); |
41 | u64 drm_get_max_iomem(void); | ||
42 | |||
41 | 43 | ||
42 | static inline bool drm_arch_can_wc_memory(void) | 44 | static inline bool drm_arch_can_wc_memory(void) |
43 | { | 45 | { |
diff --git a/include/drm/drm_dp_helper.h b/include/drm/drm_dp_helper.h index da58a428c8d7..768d9eda06cb 100644 --- a/include/drm/drm_dp_helper.h +++ b/include/drm/drm_dp_helper.h | |||
@@ -75,6 +75,7 @@ | |||
75 | #define DP_MAX_DOWNSPREAD 0x003 | 75 | #define DP_MAX_DOWNSPREAD 0x003 |
76 | # define DP_MAX_DOWNSPREAD_0_5 (1 << 0) | 76 | # define DP_MAX_DOWNSPREAD_0_5 (1 << 0) |
77 | # define DP_NO_AUX_HANDSHAKE_LINK_TRAINING (1 << 6) | 77 | # define DP_NO_AUX_HANDSHAKE_LINK_TRAINING (1 << 6) |
78 | # define DP_TPS4_SUPPORTED (1 << 7) | ||
78 | 79 | ||
79 | #define DP_NORP 0x004 | 80 | #define DP_NORP 0x004 |
80 | 81 | ||
@@ -334,6 +335,7 @@ | |||
334 | # define DP_LINK_BW_1_62 0x06 | 335 | # define DP_LINK_BW_1_62 0x06 |
335 | # define DP_LINK_BW_2_7 0x0a | 336 | # define DP_LINK_BW_2_7 0x0a |
336 | # define DP_LINK_BW_5_4 0x14 /* 1.2 */ | 337 | # define DP_LINK_BW_5_4 0x14 /* 1.2 */ |
338 | # define DP_LINK_BW_8_1 0x1e /* 1.4 */ | ||
337 | 339 | ||
338 | #define DP_LANE_COUNT_SET 0x101 | 340 | #define DP_LANE_COUNT_SET 0x101 |
339 | # define DP_LANE_COUNT_MASK 0x0f | 341 | # define DP_LANE_COUNT_MASK 0x0f |
@@ -344,7 +346,9 @@ | |||
344 | # define DP_TRAINING_PATTERN_1 1 | 346 | # define DP_TRAINING_PATTERN_1 1 |
345 | # define DP_TRAINING_PATTERN_2 2 | 347 | # define DP_TRAINING_PATTERN_2 2 |
346 | # define DP_TRAINING_PATTERN_3 3 /* 1.2 */ | 348 | # define DP_TRAINING_PATTERN_3 3 /* 1.2 */ |
349 | # define DP_TRAINING_PATTERN_4 7 /* 1.4 */ | ||
347 | # define DP_TRAINING_PATTERN_MASK 0x3 | 350 | # define DP_TRAINING_PATTERN_MASK 0x3 |
351 | # define DP_TRAINING_PATTERN_MASK_1_4 0xf | ||
348 | 352 | ||
349 | /* DPCD 1.1 only. For DPCD >= 1.2 see per-lane DP_LINK_QUAL_LANEn_SET */ | 353 | /* DPCD 1.1 only. For DPCD >= 1.2 see per-lane DP_LINK_QUAL_LANEn_SET */ |
350 | # define DP_LINK_QUAL_PATTERN_11_DISABLE (0 << 2) | 354 | # define DP_LINK_QUAL_PATTERN_11_DISABLE (0 << 2) |
@@ -971,6 +975,20 @@ drm_dp_tps3_supported(const u8 dpcd[DP_RECEIVER_CAP_SIZE]) | |||
971 | } | 975 | } |
972 | 976 | ||
973 | static inline bool | 977 | static inline bool |
978 | drm_dp_tps4_supported(const u8 dpcd[DP_RECEIVER_CAP_SIZE]) | ||
979 | { | ||
980 | return dpcd[DP_DPCD_REV] >= 0x14 && | ||
981 | dpcd[DP_MAX_DOWNSPREAD] & DP_TPS4_SUPPORTED; | ||
982 | } | ||
983 | |||
984 | static inline u8 | ||
985 | drm_dp_training_pattern_mask(const u8 dpcd[DP_RECEIVER_CAP_SIZE]) | ||
986 | { | ||
987 | return (dpcd[DP_DPCD_REV] >= 0x14) ? DP_TRAINING_PATTERN_MASK_1_4 : | ||
988 | DP_TRAINING_PATTERN_MASK; | ||
989 | } | ||
990 | |||
991 | static inline bool | ||
974 | drm_dp_is_branch(const u8 dpcd[DP_RECEIVER_CAP_SIZE]) | 992 | drm_dp_is_branch(const u8 dpcd[DP_RECEIVER_CAP_SIZE]) |
975 | { | 993 | { |
976 | return dpcd[DP_DOWNSTREAMPORT_PRESENT] & DP_DWN_STRM_PORT_PRESENT; | 994 | return dpcd[DP_DOWNSTREAMPORT_PRESENT] & DP_DWN_STRM_PORT_PRESENT; |
diff --git a/include/drm/drm_fourcc.h b/include/drm/drm_fourcc.h index 6942e84b6edd..3e86408dac9f 100644 --- a/include/drm/drm_fourcc.h +++ b/include/drm/drm_fourcc.h | |||
@@ -38,6 +38,7 @@ struct drm_mode_fb_cmd2; | |||
38 | * @cpp: Number of bytes per pixel (per plane) | 38 | * @cpp: Number of bytes per pixel (per plane) |
39 | * @hsub: Horizontal chroma subsampling factor | 39 | * @hsub: Horizontal chroma subsampling factor |
40 | * @vsub: Vertical chroma subsampling factor | 40 | * @vsub: Vertical chroma subsampling factor |
41 | * @has_alpha: Does the format embeds an alpha component? | ||
41 | */ | 42 | */ |
42 | struct drm_format_info { | 43 | struct drm_format_info { |
43 | u32 format; | 44 | u32 format; |
@@ -46,6 +47,7 @@ struct drm_format_info { | |||
46 | u8 cpp[3]; | 47 | u8 cpp[3]; |
47 | u8 hsub; | 48 | u8 hsub; |
48 | u8 vsub; | 49 | u8 vsub; |
50 | bool has_alpha; | ||
49 | }; | 51 | }; |
50 | 52 | ||
51 | /** | 53 | /** |
diff --git a/include/drm/drm_mode_config.h b/include/drm/drm_mode_config.h index 2cb6f02df64a..7569f22ffef6 100644 --- a/include/drm/drm_mode_config.h +++ b/include/drm/drm_mode_config.h | |||
@@ -36,6 +36,7 @@ struct drm_device; | |||
36 | struct drm_atomic_state; | 36 | struct drm_atomic_state; |
37 | struct drm_mode_fb_cmd2; | 37 | struct drm_mode_fb_cmd2; |
38 | struct drm_format_info; | 38 | struct drm_format_info; |
39 | struct drm_display_mode; | ||
39 | 40 | ||
40 | /** | 41 | /** |
41 | * struct drm_mode_config_funcs - basic driver provided mode setting functions | 42 | * struct drm_mode_config_funcs - basic driver provided mode setting functions |
@@ -102,6 +103,17 @@ struct drm_mode_config_funcs { | |||
102 | void (*output_poll_changed)(struct drm_device *dev); | 103 | void (*output_poll_changed)(struct drm_device *dev); |
103 | 104 | ||
104 | /** | 105 | /** |
106 | * @mode_valid: | ||
107 | * | ||
108 | * Device specific validation of display modes. Can be used to reject | ||
109 | * modes that can never be supported. Only device wide constraints can | ||
110 | * be checked here. crtc/encoder/bridge/connector specific constraints | ||
111 | * should be checked in the .mode_valid() hook for each specific object. | ||
112 | */ | ||
113 | enum drm_mode_status (*mode_valid)(struct drm_device *dev, | ||
114 | const struct drm_display_mode *mode); | ||
115 | |||
116 | /** | ||
105 | * @atomic_check: | 117 | * @atomic_check: |
106 | * | 118 | * |
107 | * This is the only hook to validate an atomic modeset update. This | 119 | * This is the only hook to validate an atomic modeset update. This |
diff --git a/include/drm/drm_modes.h b/include/drm/drm_modes.h index 9f3421c8efcd..0d310beae6af 100644 --- a/include/drm/drm_modes.h +++ b/include/drm/drm_modes.h | |||
@@ -131,9 +131,6 @@ enum drm_mode_status { | |||
131 | MODE_ERROR = -1 | 131 | MODE_ERROR = -1 |
132 | }; | 132 | }; |
133 | 133 | ||
134 | #define DRM_MODE_TYPE_CLOCK_CRTC_C (DRM_MODE_TYPE_CLOCK_C | \ | ||
135 | DRM_MODE_TYPE_CRTC_C) | ||
136 | |||
137 | #define DRM_MODE(nm, t, c, hd, hss, hse, ht, hsk, vd, vss, vse, vt, vs, f) \ | 134 | #define DRM_MODE(nm, t, c, hd, hss, hse, ht, hsk, vd, vss, vse, vt, vs, f) \ |
138 | .name = nm, .status = 0, .type = (t), .clock = (c), \ | 135 | .name = nm, .status = 0, .type = (t), .clock = (c), \ |
139 | .hdisplay = (hd), .hsync_start = (hss), .hsync_end = (hse), \ | 136 | .hdisplay = (hd), .hsync_start = (hss), .hsync_end = (hse), \ |
@@ -245,26 +242,25 @@ struct drm_display_mode { | |||
245 | * A bitmask of flags, mostly about the source of a mode. Possible flags | 242 | * A bitmask of flags, mostly about the source of a mode. Possible flags |
246 | * are: | 243 | * are: |
247 | * | 244 | * |
248 | * - DRM_MODE_TYPE_BUILTIN: Meant for hard-coded modes, effectively | ||
249 | * unused. | ||
250 | * - DRM_MODE_TYPE_PREFERRED: Preferred mode, usually the native | 245 | * - DRM_MODE_TYPE_PREFERRED: Preferred mode, usually the native |
251 | * resolution of an LCD panel. There should only be one preferred | 246 | * resolution of an LCD panel. There should only be one preferred |
252 | * mode per connector at any given time. | 247 | * mode per connector at any given time. |
253 | * - DRM_MODE_TYPE_DRIVER: Mode created by the driver, which is all of | 248 | * - DRM_MODE_TYPE_DRIVER: Mode created by the driver, which is all of |
254 | * them really. Drivers must set this bit for all modes they create | 249 | * them really. Drivers must set this bit for all modes they create |
255 | * and expose to userspace. | 250 | * and expose to userspace. |
251 | * - DRM_MODE_TYPE_USERDEF: Mode defined via kernel command line | ||
256 | * | 252 | * |
257 | * Plus a big list of flags which shouldn't be used at all, but are | 253 | * Plus a big list of flags which shouldn't be used at all, but are |
258 | * still around since these flags are also used in the userspace ABI: | 254 | * still around since these flags are also used in the userspace ABI. |
255 | * We no longer accept modes with these types though: | ||
259 | * | 256 | * |
257 | * - DRM_MODE_TYPE_BUILTIN: Meant for hard-coded modes, unused. | ||
258 | * Use DRM_MODE_TYPE_DRIVER instead. | ||
260 | * - DRM_MODE_TYPE_DEFAULT: Again a leftover, use | 259 | * - DRM_MODE_TYPE_DEFAULT: Again a leftover, use |
261 | * DRM_MODE_TYPE_PREFERRED instead. | 260 | * DRM_MODE_TYPE_PREFERRED instead. |
262 | * - DRM_MODE_TYPE_CLOCK_C and DRM_MODE_TYPE_CRTC_C: Define leftovers | 261 | * - DRM_MODE_TYPE_CLOCK_C and DRM_MODE_TYPE_CRTC_C: Define leftovers |
263 | * which are stuck around for hysterical raisins only. No one has an | 262 | * which are stuck around for hysterical raisins only. No one has an |
264 | * idea what they were meant for. Don't use. | 263 | * idea what they were meant for. Don't use. |
265 | * - DRM_MODE_TYPE_USERDEF: Mode defined by userspace, again a vestige | ||
266 | * from older kms designs where userspace had to first add a custom | ||
267 | * mode to the kernel's mode list before it could use it. Don't use. | ||
268 | */ | 264 | */ |
269 | unsigned int type; | 265 | unsigned int type; |
270 | 266 | ||
@@ -299,8 +295,8 @@ struct drm_display_mode { | |||
299 | * - DRM_MODE_FLAG_PCSYNC: composite sync is active high. | 295 | * - DRM_MODE_FLAG_PCSYNC: composite sync is active high. |
300 | * - DRM_MODE_FLAG_NCSYNC: composite sync is active low. | 296 | * - DRM_MODE_FLAG_NCSYNC: composite sync is active low. |
301 | * - DRM_MODE_FLAG_HSKEW: hskew provided (not used?). | 297 | * - DRM_MODE_FLAG_HSKEW: hskew provided (not used?). |
302 | * - DRM_MODE_FLAG_BCAST: not used? | 298 | * - DRM_MODE_FLAG_BCAST: <deprecated> |
303 | * - DRM_MODE_FLAG_PIXMUX: not used? | 299 | * - DRM_MODE_FLAG_PIXMUX: <deprecated> |
304 | * - DRM_MODE_FLAG_DBLCLK: double-clocked mode. | 300 | * - DRM_MODE_FLAG_DBLCLK: double-clocked mode. |
305 | * - DRM_MODE_FLAG_CLKDIV2: half-clocked mode. | 301 | * - DRM_MODE_FLAG_CLKDIV2: half-clocked mode. |
306 | * | 302 | * |
@@ -448,7 +444,8 @@ struct drm_display_mode *drm_mode_create(struct drm_device *dev); | |||
448 | void drm_mode_destroy(struct drm_device *dev, struct drm_display_mode *mode); | 444 | void drm_mode_destroy(struct drm_device *dev, struct drm_display_mode *mode); |
449 | void drm_mode_convert_to_umode(struct drm_mode_modeinfo *out, | 445 | void drm_mode_convert_to_umode(struct drm_mode_modeinfo *out, |
450 | const struct drm_display_mode *in); | 446 | const struct drm_display_mode *in); |
451 | int drm_mode_convert_umode(struct drm_display_mode *out, | 447 | int drm_mode_convert_umode(struct drm_device *dev, |
448 | struct drm_display_mode *out, | ||
452 | const struct drm_mode_modeinfo *in); | 449 | const struct drm_mode_modeinfo *in); |
453 | void drm_mode_probed_add(struct drm_connector *connector, struct drm_display_mode *mode); | 450 | void drm_mode_probed_add(struct drm_connector *connector, struct drm_display_mode *mode); |
454 | void drm_mode_debug_printmodeline(const struct drm_display_mode *mode); | 451 | void drm_mode_debug_printmodeline(const struct drm_display_mode *mode); |
@@ -501,7 +498,8 @@ bool drm_mode_equal_no_clocks_no_stereo(const struct drm_display_mode *mode1, | |||
501 | const struct drm_display_mode *mode2); | 498 | const struct drm_display_mode *mode2); |
502 | 499 | ||
503 | /* for use by the crtc helper probe functions */ | 500 | /* for use by the crtc helper probe functions */ |
504 | enum drm_mode_status drm_mode_validate_basic(const struct drm_display_mode *mode); | 501 | enum drm_mode_status drm_mode_validate_driver(struct drm_device *dev, |
502 | const struct drm_display_mode *mode); | ||
505 | enum drm_mode_status drm_mode_validate_size(const struct drm_display_mode *mode, | 503 | enum drm_mode_status drm_mode_validate_size(const struct drm_display_mode *mode, |
506 | int maxX, int maxY); | 504 | int maxX, int maxY); |
507 | enum drm_mode_status | 505 | enum drm_mode_status |
diff --git a/include/drm/drm_prime.h b/include/drm/drm_prime.h index 9cd9e36f77b5..4d5f5d6cf6a6 100644 --- a/include/drm/drm_prime.h +++ b/include/drm/drm_prime.h | |||
@@ -54,6 +54,9 @@ struct device; | |||
54 | 54 | ||
55 | struct dma_buf_export_info; | 55 | struct dma_buf_export_info; |
56 | struct dma_buf; | 56 | struct dma_buf; |
57 | struct dma_buf_attachment; | ||
58 | |||
59 | enum dma_data_direction; | ||
57 | 60 | ||
58 | struct drm_device; | 61 | struct drm_device; |
59 | struct drm_gem_object; | 62 | struct drm_gem_object; |
@@ -79,6 +82,25 @@ int drm_gem_prime_fd_to_handle(struct drm_device *dev, | |||
79 | struct dma_buf *drm_gem_dmabuf_export(struct drm_device *dev, | 82 | struct dma_buf *drm_gem_dmabuf_export(struct drm_device *dev, |
80 | struct dma_buf_export_info *exp_info); | 83 | struct dma_buf_export_info *exp_info); |
81 | void drm_gem_dmabuf_release(struct dma_buf *dma_buf); | 84 | void drm_gem_dmabuf_release(struct dma_buf *dma_buf); |
85 | int drm_gem_map_attach(struct dma_buf *dma_buf, struct device *target_dev, | ||
86 | struct dma_buf_attachment *attach); | ||
87 | void drm_gem_map_detach(struct dma_buf *dma_buf, | ||
88 | struct dma_buf_attachment *attach); | ||
89 | struct sg_table *drm_gem_map_dma_buf(struct dma_buf_attachment *attach, | ||
90 | enum dma_data_direction dir); | ||
91 | void drm_gem_unmap_dma_buf(struct dma_buf_attachment *attach, | ||
92 | struct sg_table *sgt, | ||
93 | enum dma_data_direction dir); | ||
94 | void *drm_gem_dmabuf_vmap(struct dma_buf *dma_buf); | ||
95 | void drm_gem_dmabuf_vunmap(struct dma_buf *dma_buf, void *vaddr); | ||
96 | void *drm_gem_dmabuf_kmap_atomic(struct dma_buf *dma_buf, | ||
97 | unsigned long page_num); | ||
98 | void drm_gem_dmabuf_kunmap_atomic(struct dma_buf *dma_buf, | ||
99 | unsigned long page_num, void *addr); | ||
100 | void *drm_gem_dmabuf_kmap(struct dma_buf *dma_buf, unsigned long page_num); | ||
101 | void drm_gem_dmabuf_kunmap(struct dma_buf *dma_buf, unsigned long page_num, | ||
102 | void *addr); | ||
103 | int drm_gem_dmabuf_mmap(struct dma_buf *dma_buf, struct vm_area_struct *vma); | ||
82 | 104 | ||
83 | int drm_prime_sg_to_page_addr_arrays(struct sg_table *sgt, struct page **pages, | 105 | int drm_prime_sg_to_page_addr_arrays(struct sg_table *sgt, struct page **pages, |
84 | dma_addr_t *addrs, int max_pages); | 106 | dma_addr_t *addrs, int max_pages); |
diff --git a/include/drm/tinydrm/ili9341.h b/include/drm/tinydrm/ili9341.h deleted file mode 100644 index 807a09f43cad..000000000000 --- a/include/drm/tinydrm/ili9341.h +++ /dev/null | |||
@@ -1,54 +0,0 @@ | |||
1 | /* | ||
2 | * ILI9341 LCD controller | ||
3 | * | ||
4 | * Copyright 2016 Noralf Trønnes | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License as published by | ||
8 | * the Free Software Foundation; either version 2 of the License, or | ||
9 | * (at your option) any later version. | ||
10 | */ | ||
11 | |||
12 | #ifndef __LINUX_ILI9341_H | ||
13 | #define __LINUX_ILI9341_H | ||
14 | |||
15 | #define ILI9341_FRMCTR1 0xb1 | ||
16 | #define ILI9341_FRMCTR2 0xb2 | ||
17 | #define ILI9341_FRMCTR3 0xb3 | ||
18 | #define ILI9341_INVTR 0xb4 | ||
19 | #define ILI9341_PRCTR 0xb5 | ||
20 | #define ILI9341_DISCTRL 0xb6 | ||
21 | #define ILI9341_ETMOD 0xb7 | ||
22 | |||
23 | #define ILI9341_PWCTRL1 0xc0 | ||
24 | #define ILI9341_PWCTRL2 0xc1 | ||
25 | #define ILI9341_VMCTRL1 0xc5 | ||
26 | #define ILI9341_VMCTRL2 0xc7 | ||
27 | #define ILI9341_PWCTRLA 0xcb | ||
28 | #define ILI9341_PWCTRLB 0xcf | ||
29 | |||
30 | #define ILI9341_RDID1 0xda | ||
31 | #define ILI9341_RDID2 0xdb | ||
32 | #define ILI9341_RDID3 0xdc | ||
33 | #define ILI9341_RDID4 0xd3 | ||
34 | |||
35 | #define ILI9341_PGAMCTRL 0xe0 | ||
36 | #define ILI9341_NGAMCTRL 0xe1 | ||
37 | #define ILI9341_DGAMCTRL1 0xe2 | ||
38 | #define ILI9341_DGAMCTRL2 0xe3 | ||
39 | #define ILI9341_DTCTRLA 0xe8 | ||
40 | #define ILI9341_DTCTRLB 0xea | ||
41 | #define ILI9341_PWRSEQ 0xed | ||
42 | |||
43 | #define ILI9341_EN3GAM 0xf2 | ||
44 | #define ILI9341_IFCTRL 0xf6 | ||
45 | #define ILI9341_PUMPCTRL 0xf7 | ||
46 | |||
47 | #define ILI9341_MADCTL_MH BIT(2) | ||
48 | #define ILI9341_MADCTL_BGR BIT(3) | ||
49 | #define ILI9341_MADCTL_ML BIT(4) | ||
50 | #define ILI9341_MADCTL_MV BIT(5) | ||
51 | #define ILI9341_MADCTL_MX BIT(6) | ||
52 | #define ILI9341_MADCTL_MY BIT(7) | ||
53 | |||
54 | #endif /* __LINUX_ILI9341_H */ | ||
diff --git a/include/drm/tinydrm/mipi-dbi.h b/include/drm/tinydrm/mipi-dbi.h index 5d0e82b36eaf..44e824af2ef6 100644 --- a/include/drm/tinydrm/mipi-dbi.h +++ b/include/drm/tinydrm/mipi-dbi.h | |||
@@ -67,11 +67,12 @@ int mipi_dbi_init(struct device *dev, struct mipi_dbi *mipi, | |||
67 | const struct drm_simple_display_pipe_funcs *pipe_funcs, | 67 | const struct drm_simple_display_pipe_funcs *pipe_funcs, |
68 | struct drm_driver *driver, | 68 | struct drm_driver *driver, |
69 | const struct drm_display_mode *mode, unsigned int rotation); | 69 | const struct drm_display_mode *mode, unsigned int rotation); |
70 | void mipi_dbi_pipe_enable(struct drm_simple_display_pipe *pipe, | 70 | void mipi_dbi_enable_flush(struct mipi_dbi *mipi); |
71 | struct drm_crtc_state *crtc_state); | ||
72 | void mipi_dbi_pipe_disable(struct drm_simple_display_pipe *pipe); | 71 | void mipi_dbi_pipe_disable(struct drm_simple_display_pipe *pipe); |
73 | void mipi_dbi_hw_reset(struct mipi_dbi *mipi); | 72 | void mipi_dbi_hw_reset(struct mipi_dbi *mipi); |
74 | bool mipi_dbi_display_is_on(struct mipi_dbi *mipi); | 73 | bool mipi_dbi_display_is_on(struct mipi_dbi *mipi); |
74 | int mipi_dbi_poweron_reset(struct mipi_dbi *mipi); | ||
75 | int mipi_dbi_poweron_conditional_reset(struct mipi_dbi *mipi); | ||
75 | u32 mipi_dbi_spi_cmd_max_speed(struct spi_device *spi, size_t len); | 76 | u32 mipi_dbi_spi_cmd_max_speed(struct spi_device *spi, size_t len); |
76 | 77 | ||
77 | int mipi_dbi_command_read(struct mipi_dbi *mipi, u8 cmd, u8 *val); | 78 | int mipi_dbi_command_read(struct mipi_dbi *mipi, u8 cmd, u8 *val); |
diff --git a/include/uapi/drm/drm_mode.h b/include/uapi/drm/drm_mode.h index 5597a87154e5..eb9b68c7c218 100644 --- a/include/uapi/drm/drm_mode.h +++ b/include/uapi/drm/drm_mode.h | |||
@@ -38,14 +38,18 @@ extern "C" { | |||
38 | #define DRM_DISPLAY_MODE_LEN 32 | 38 | #define DRM_DISPLAY_MODE_LEN 32 |
39 | #define DRM_PROP_NAME_LEN 32 | 39 | #define DRM_PROP_NAME_LEN 32 |
40 | 40 | ||
41 | #define DRM_MODE_TYPE_BUILTIN (1<<0) | 41 | #define DRM_MODE_TYPE_BUILTIN (1<<0) /* deprecated */ |
42 | #define DRM_MODE_TYPE_CLOCK_C ((1<<1) | DRM_MODE_TYPE_BUILTIN) | 42 | #define DRM_MODE_TYPE_CLOCK_C ((1<<1) | DRM_MODE_TYPE_BUILTIN) /* deprecated */ |
43 | #define DRM_MODE_TYPE_CRTC_C ((1<<2) | DRM_MODE_TYPE_BUILTIN) | 43 | #define DRM_MODE_TYPE_CRTC_C ((1<<2) | DRM_MODE_TYPE_BUILTIN) /* deprecated */ |
44 | #define DRM_MODE_TYPE_PREFERRED (1<<3) | 44 | #define DRM_MODE_TYPE_PREFERRED (1<<3) |
45 | #define DRM_MODE_TYPE_DEFAULT (1<<4) | 45 | #define DRM_MODE_TYPE_DEFAULT (1<<4) /* deprecated */ |
46 | #define DRM_MODE_TYPE_USERDEF (1<<5) | 46 | #define DRM_MODE_TYPE_USERDEF (1<<5) |
47 | #define DRM_MODE_TYPE_DRIVER (1<<6) | 47 | #define DRM_MODE_TYPE_DRIVER (1<<6) |
48 | 48 | ||
49 | #define DRM_MODE_TYPE_ALL (DRM_MODE_TYPE_PREFERRED | \ | ||
50 | DRM_MODE_TYPE_USERDEF | \ | ||
51 | DRM_MODE_TYPE_DRIVER) | ||
52 | |||
49 | /* Video mode flags */ | 53 | /* Video mode flags */ |
50 | /* bit compatible with the xrandr RR_ definitions (bits 0-13) | 54 | /* bit compatible with the xrandr RR_ definitions (bits 0-13) |
51 | * | 55 | * |
@@ -66,8 +70,8 @@ extern "C" { | |||
66 | #define DRM_MODE_FLAG_PCSYNC (1<<7) | 70 | #define DRM_MODE_FLAG_PCSYNC (1<<7) |
67 | #define DRM_MODE_FLAG_NCSYNC (1<<8) | 71 | #define DRM_MODE_FLAG_NCSYNC (1<<8) |
68 | #define DRM_MODE_FLAG_HSKEW (1<<9) /* hskew provided */ | 72 | #define DRM_MODE_FLAG_HSKEW (1<<9) /* hskew provided */ |
69 | #define DRM_MODE_FLAG_BCAST (1<<10) | 73 | #define DRM_MODE_FLAG_BCAST (1<<10) /* deprecated */ |
70 | #define DRM_MODE_FLAG_PIXMUX (1<<11) | 74 | #define DRM_MODE_FLAG_PIXMUX (1<<11) /* deprecated */ |
71 | #define DRM_MODE_FLAG_DBLCLK (1<<12) | 75 | #define DRM_MODE_FLAG_DBLCLK (1<<12) |
72 | #define DRM_MODE_FLAG_CLKDIV2 (1<<13) | 76 | #define DRM_MODE_FLAG_CLKDIV2 (1<<13) |
73 | /* | 77 | /* |
@@ -99,6 +103,20 @@ extern "C" { | |||
99 | #define DRM_MODE_FLAG_PIC_AR_16_9 \ | 103 | #define DRM_MODE_FLAG_PIC_AR_16_9 \ |
100 | (DRM_MODE_PICTURE_ASPECT_16_9<<19) | 104 | (DRM_MODE_PICTURE_ASPECT_16_9<<19) |
101 | 105 | ||
106 | #define DRM_MODE_FLAG_ALL (DRM_MODE_FLAG_PHSYNC | \ | ||
107 | DRM_MODE_FLAG_NHSYNC | \ | ||
108 | DRM_MODE_FLAG_PVSYNC | \ | ||
109 | DRM_MODE_FLAG_NVSYNC | \ | ||
110 | DRM_MODE_FLAG_INTERLACE | \ | ||
111 | DRM_MODE_FLAG_DBLSCAN | \ | ||
112 | DRM_MODE_FLAG_CSYNC | \ | ||
113 | DRM_MODE_FLAG_PCSYNC | \ | ||
114 | DRM_MODE_FLAG_NCSYNC | \ | ||
115 | DRM_MODE_FLAG_HSKEW | \ | ||
116 | DRM_MODE_FLAG_DBLCLK | \ | ||
117 | DRM_MODE_FLAG_CLKDIV2 | \ | ||
118 | DRM_MODE_FLAG_3D_MASK) | ||
119 | |||
102 | /* DPMS flags */ | 120 | /* DPMS flags */ |
103 | /* bit compatible with the xorg definitions. */ | 121 | /* bit compatible with the xorg definitions. */ |
104 | #define DRM_MODE_DPMS_ON 0 | 122 | #define DRM_MODE_DPMS_ON 0 |
diff --git a/include/uapi/drm/vc4_drm.h b/include/uapi/drm/vc4_drm.h index 52263b575bdc..b95a0e11cb07 100644 --- a/include/uapi/drm/vc4_drm.h +++ b/include/uapi/drm/vc4_drm.h | |||
@@ -42,6 +42,9 @@ extern "C" { | |||
42 | #define DRM_VC4_GET_TILING 0x09 | 42 | #define DRM_VC4_GET_TILING 0x09 |
43 | #define DRM_VC4_LABEL_BO 0x0a | 43 | #define DRM_VC4_LABEL_BO 0x0a |
44 | #define DRM_VC4_GEM_MADVISE 0x0b | 44 | #define DRM_VC4_GEM_MADVISE 0x0b |
45 | #define DRM_VC4_PERFMON_CREATE 0x0c | ||
46 | #define DRM_VC4_PERFMON_DESTROY 0x0d | ||
47 | #define DRM_VC4_PERFMON_GET_VALUES 0x0e | ||
45 | 48 | ||
46 | #define DRM_IOCTL_VC4_SUBMIT_CL DRM_IOWR(DRM_COMMAND_BASE + DRM_VC4_SUBMIT_CL, struct drm_vc4_submit_cl) | 49 | #define DRM_IOCTL_VC4_SUBMIT_CL DRM_IOWR(DRM_COMMAND_BASE + DRM_VC4_SUBMIT_CL, struct drm_vc4_submit_cl) |
47 | #define DRM_IOCTL_VC4_WAIT_SEQNO DRM_IOWR(DRM_COMMAND_BASE + DRM_VC4_WAIT_SEQNO, struct drm_vc4_wait_seqno) | 50 | #define DRM_IOCTL_VC4_WAIT_SEQNO DRM_IOWR(DRM_COMMAND_BASE + DRM_VC4_WAIT_SEQNO, struct drm_vc4_wait_seqno) |
@@ -55,6 +58,9 @@ extern "C" { | |||
55 | #define DRM_IOCTL_VC4_GET_TILING DRM_IOWR(DRM_COMMAND_BASE + DRM_VC4_GET_TILING, struct drm_vc4_get_tiling) | 58 | #define DRM_IOCTL_VC4_GET_TILING DRM_IOWR(DRM_COMMAND_BASE + DRM_VC4_GET_TILING, struct drm_vc4_get_tiling) |
56 | #define DRM_IOCTL_VC4_LABEL_BO DRM_IOWR(DRM_COMMAND_BASE + DRM_VC4_LABEL_BO, struct drm_vc4_label_bo) | 59 | #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) | 60 | #define DRM_IOCTL_VC4_GEM_MADVISE DRM_IOWR(DRM_COMMAND_BASE + DRM_VC4_GEM_MADVISE, struct drm_vc4_gem_madvise) |
61 | #define DRM_IOCTL_VC4_PERFMON_CREATE DRM_IOWR(DRM_COMMAND_BASE + DRM_VC4_PERFMON_CREATE, struct drm_vc4_perfmon_create) | ||
62 | #define DRM_IOCTL_VC4_PERFMON_DESTROY DRM_IOWR(DRM_COMMAND_BASE + DRM_VC4_PERFMON_DESTROY, struct drm_vc4_perfmon_destroy) | ||
63 | #define DRM_IOCTL_VC4_PERFMON_GET_VALUES DRM_IOWR(DRM_COMMAND_BASE + DRM_VC4_PERFMON_GET_VALUES, struct drm_vc4_perfmon_get_values) | ||
58 | 64 | ||
59 | struct drm_vc4_submit_rcl_surface { | 65 | struct drm_vc4_submit_rcl_surface { |
60 | __u32 hindex; /* Handle index, or ~0 if not present. */ | 66 | __u32 hindex; /* Handle index, or ~0 if not present. */ |
@@ -173,6 +179,15 @@ struct drm_vc4_submit_cl { | |||
173 | * wait ioctl). | 179 | * wait ioctl). |
174 | */ | 180 | */ |
175 | __u64 seqno; | 181 | __u64 seqno; |
182 | |||
183 | /* ID of the perfmon to attach to this job. 0 means no perfmon. */ | ||
184 | __u32 perfmonid; | ||
185 | |||
186 | /* Unused field to align this struct on 64 bits. Must be set to 0. | ||
187 | * If one ever needs to add an u32 field to this struct, this field | ||
188 | * can be used. | ||
189 | */ | ||
190 | __u32 pad2; | ||
176 | }; | 191 | }; |
177 | 192 | ||
178 | /** | 193 | /** |
@@ -308,6 +323,7 @@ struct drm_vc4_get_hang_state { | |||
308 | #define DRM_VC4_PARAM_SUPPORTS_THREADED_FS 5 | 323 | #define DRM_VC4_PARAM_SUPPORTS_THREADED_FS 5 |
309 | #define DRM_VC4_PARAM_SUPPORTS_FIXED_RCL_ORDER 6 | 324 | #define DRM_VC4_PARAM_SUPPORTS_FIXED_RCL_ORDER 6 |
310 | #define DRM_VC4_PARAM_SUPPORTS_MADVISE 7 | 325 | #define DRM_VC4_PARAM_SUPPORTS_MADVISE 7 |
326 | #define DRM_VC4_PARAM_SUPPORTS_PERFMON 8 | ||
311 | 327 | ||
312 | struct drm_vc4_get_param { | 328 | struct drm_vc4_get_param { |
313 | __u32 param; | 329 | __u32 param; |
@@ -352,6 +368,66 @@ struct drm_vc4_gem_madvise { | |||
352 | __u32 pad; | 368 | __u32 pad; |
353 | }; | 369 | }; |
354 | 370 | ||
371 | enum { | ||
372 | VC4_PERFCNT_FEP_VALID_PRIMS_NO_RENDER, | ||
373 | VC4_PERFCNT_FEP_VALID_PRIMS_RENDER, | ||
374 | VC4_PERFCNT_FEP_CLIPPED_QUADS, | ||
375 | VC4_PERFCNT_FEP_VALID_QUADS, | ||
376 | VC4_PERFCNT_TLB_QUADS_NOT_PASSING_STENCIL, | ||
377 | VC4_PERFCNT_TLB_QUADS_NOT_PASSING_Z_AND_STENCIL, | ||
378 | VC4_PERFCNT_TLB_QUADS_PASSING_Z_AND_STENCIL, | ||
379 | VC4_PERFCNT_TLB_QUADS_ZERO_COVERAGE, | ||
380 | VC4_PERFCNT_TLB_QUADS_NON_ZERO_COVERAGE, | ||
381 | VC4_PERFCNT_TLB_QUADS_WRITTEN_TO_COLOR_BUF, | ||
382 | VC4_PERFCNT_PLB_PRIMS_OUTSIDE_VIEWPORT, | ||
383 | VC4_PERFCNT_PLB_PRIMS_NEED_CLIPPING, | ||
384 | VC4_PERFCNT_PSE_PRIMS_REVERSED, | ||
385 | VC4_PERFCNT_QPU_TOTAL_IDLE_CYCLES, | ||
386 | VC4_PERFCNT_QPU_TOTAL_CLK_CYCLES_VERTEX_COORD_SHADING, | ||
387 | VC4_PERFCNT_QPU_TOTAL_CLK_CYCLES_FRAGMENT_SHADING, | ||
388 | VC4_PERFCNT_QPU_TOTAL_CLK_CYCLES_EXEC_VALID_INST, | ||
389 | VC4_PERFCNT_QPU_TOTAL_CLK_CYCLES_WAITING_TMUS, | ||
390 | VC4_PERFCNT_QPU_TOTAL_CLK_CYCLES_WAITING_SCOREBOARD, | ||
391 | VC4_PERFCNT_QPU_TOTAL_CLK_CYCLES_WAITING_VARYINGS, | ||
392 | VC4_PERFCNT_QPU_TOTAL_INST_CACHE_HIT, | ||
393 | VC4_PERFCNT_QPU_TOTAL_INST_CACHE_MISS, | ||
394 | VC4_PERFCNT_QPU_TOTAL_UNIFORM_CACHE_HIT, | ||
395 | VC4_PERFCNT_QPU_TOTAL_UNIFORM_CACHE_MISS, | ||
396 | VC4_PERFCNT_TMU_TOTAL_TEXT_QUADS_PROCESSED, | ||
397 | VC4_PERFCNT_TMU_TOTAL_TEXT_CACHE_MISS, | ||
398 | VC4_PERFCNT_VPM_TOTAL_CLK_CYCLES_VDW_STALLED, | ||
399 | VC4_PERFCNT_VPM_TOTAL_CLK_CYCLES_VCD_STALLED, | ||
400 | VC4_PERFCNT_L2C_TOTAL_L2_CACHE_HIT, | ||
401 | VC4_PERFCNT_L2C_TOTAL_L2_CACHE_MISS, | ||
402 | VC4_PERFCNT_NUM_EVENTS, | ||
403 | }; | ||
404 | |||
405 | #define DRM_VC4_MAX_PERF_COUNTERS 16 | ||
406 | |||
407 | struct drm_vc4_perfmon_create { | ||
408 | __u32 id; | ||
409 | __u32 ncounters; | ||
410 | __u8 events[DRM_VC4_MAX_PERF_COUNTERS]; | ||
411 | }; | ||
412 | |||
413 | struct drm_vc4_perfmon_destroy { | ||
414 | __u32 id; | ||
415 | }; | ||
416 | |||
417 | /* | ||
418 | * Returns the values of the performance counters tracked by this | ||
419 | * perfmon (as an array of ncounters u64 values). | ||
420 | * | ||
421 | * No implicit synchronization is performed, so the user has to | ||
422 | * guarantee that any jobs using this perfmon have already been | ||
423 | * completed (probably by blocking on the seqno returned by the | ||
424 | * last exec that used the perfmon). | ||
425 | */ | ||
426 | struct drm_vc4_perfmon_get_values { | ||
427 | __u32 id; | ||
428 | __u64 values_ptr; | ||
429 | }; | ||
430 | |||
355 | #if defined(__cplusplus) | 431 | #if defined(__cplusplus) |
356 | } | 432 | } |
357 | #endif | 433 | #endif |