History

Merge tag 'drm-misc-next-2026-08-06' of https://gitlab.freedesktop.org/drm/misc/kernel into drm-next

drm-misc-next for v7.3: UAPI Changes: - Remove the default udmabuf size limit of 64MB. Cross-subsystem Changes: - Add dmemcg support for eviction, and hook it up for amdgpu and xe. Core Changes: - Changes to TTM to be more aggressive when allocating below protection limit! - Improve dt binding documentation for renesas. - Add helper to convert physical address back to buddy block, add that to and improve its kunit test. Driver Changes: - Assorted small fixes to ti-sn65dsi86, panthor, imagination, omapdrm, bridge/synopsys, panel-edp, ssd130x, panel/tdo-tl070wsh30. - Add Sharp LQ120P1JX51 panel. - Add dmemcg support to nouveau. - Various updates and improvements to sun4i, among which YUV and 4k support. Signed-off-by: Dave Airlie <airlied@redhat.com>

Dave Airlie committed 3 months ago

Commit e4d41a32 parents 7dda2a8 bd4f284113 files · +2256 −553Browse files

Unified · Split

113 files
  1. Documentation/devicetree/bindings/display/bridge/renesas,dsi.yaml +1 −0
  2. Documentation/devicetree/bindings/display/bridge/renesas,r9a08g046-lvds.yaml +120 −0
  3. Documentation/devicetree/bindings/display/panel/jadard,jd9365da-h3.yaml +1 −0
  4. Documentation/devicetree/bindings/display/panel/panel-simple.yaml +2 −0
  5. Documentation/devicetree/bindings/display/panel/rocktech,jh057n00900.yaml +2 −0
  6. Documentation/devicetree/bindings/display/renesas,rzg2l-du.yaml +25 −1
  7. Documentation/devicetree/bindings/vendor-prefixes.yaml +4 −0
  8. drivers/dma-buf/udmabuf.c +2 −2
  9. drivers/gpu/Kconfig +2 −1
  10. drivers/gpu/buddy.c +53 −0
  11. drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c +1 −1
  12. drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c +62 −3
  13. drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.h +3 −0
  14. drivers/gpu/drm/bridge/adv7511/adv7511_drv.c +5 −5
  15. drivers/gpu/drm/bridge/analogix/analogix-anx6345.c +1 −1
  16. drivers/gpu/drm/bridge/analogix/anx7625.c +2 −2
  17. drivers/gpu/drm/bridge/chipone-icn6211.c +2 −2
  18. drivers/gpu/drm/bridge/chrontel-ch7033.c +1 −1
  19. drivers/gpu/drm/bridge/imx/Kconfig +11 −0
  20. drivers/gpu/drm/bridge/imx/Makefile +1 −0
  21. drivers/gpu/drm/bridge/imx/imx93-pdfc.c +222 −0
  22. drivers/gpu/drm/bridge/ite-it6263.c +1 −1
  23. drivers/gpu/drm/bridge/ite-it6505.c +1 −1
  24. drivers/gpu/drm/bridge/lontium-lt8713sx.c +1 −1
  25. drivers/gpu/drm/bridge/lontium-lt8912b.c +3 −3
  26. drivers/gpu/drm/bridge/lontium-lt9211.c +2 −2
  27. drivers/gpu/drm/bridge/lontium-lt9611.c +2 −2
  28. drivers/gpu/drm/bridge/lontium-lt9611uxc.c +1 −1
  29. drivers/gpu/drm/bridge/megachips-stdpxxxx-ge-b850v3-fw.c +4 −4
  30. drivers/gpu/drm/bridge/nxp-ptn3460.c +2 −2
  31. drivers/gpu/drm/bridge/parade-ps8622.c +4 −4
  32. drivers/gpu/drm/bridge/sii902x.c +1 −1
  33. drivers/gpu/drm/bridge/sii9234.c +1 −1
  34. drivers/gpu/drm/bridge/sil-sii8620.c +1 −1
  35. drivers/gpu/drm/bridge/synopsys/dw-dp.c +0 −1
  36. drivers/gpu/drm/bridge/synopsys/dw-hdmi.c +2 −1
  37. drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi2.c +0 −1
  38. drivers/gpu/drm/bridge/tc358762.c +5 −14
  39. drivers/gpu/drm/bridge/tc358764.c +5 −14
  40. drivers/gpu/drm/bridge/tc358767.c +1 −1
  41. drivers/gpu/drm/bridge/tc358768.c +2 −2
  42. drivers/gpu/drm/bridge/tc358775.c +2 −2
  43. drivers/gpu/drm/bridge/tda998x_drv.c +1 −1
  44. drivers/gpu/drm/bridge/ti-dlpc3433.c +1 −1
  45. drivers/gpu/drm/bridge/ti-sn65dsi83.c +3 −3
  46. drivers/gpu/drm/bridge/ti-sn65dsi86.c +3 −3
  47. drivers/gpu/drm/bridge/ti-tfp410.c +1 −1
  48. drivers/gpu/drm/drm_drv.c +5 −3
  49. drivers/gpu/drm/imagination/pvr_ccb.c +3 −3
  50. drivers/gpu/drm/imagination/pvr_check.h +36 −0
  51. drivers/gpu/drm/imagination/pvr_device_info.h +3 −3
  52. drivers/gpu/drm/imagination/pvr_gem.h +4 −8
  53. drivers/gpu/drm/imagination/pvr_queue.c +2 −1
  54. drivers/gpu/drm/imagination/pvr_rogue_fwif_check.h +1 −25
  55. drivers/gpu/drm/imagination/pvr_rogue_fwif_client_check.h +1 −8
  56. drivers/gpu/drm/imagination/pvr_rogue_fwif_shared_check.h +1 −8
  57. drivers/gpu/drm/imagination/pvr_rogue_heap_config.h +5 −5
  58. drivers/gpu/drm/imagination/pvr_rogue_mips_check.h +24 −47
  59. drivers/gpu/drm/nouveau/dispnv50/base.h +6 −0
  60. drivers/gpu/drm/nouveau/dispnv50/base507c.c +1 −0
  61. drivers/gpu/drm/nouveau/dispnv50/base827c.c +1 −0
  62. drivers/gpu/drm/nouveau/dispnv50/base907c.c +1 −0
  63. drivers/gpu/drm/nouveau/dispnv50/curs507a.c +3 −0
  64. drivers/gpu/drm/nouveau/dispnv50/disp.c +4 −0
  65. drivers/gpu/drm/nouveau/dispnv50/wndw.c +33 −7
  66. drivers/gpu/drm/nouveau/dispnv50/wndw.h +11 −0
  67. drivers/gpu/drm/nouveau/dispnv50/wndwc37e.c +1 −0
  68. drivers/gpu/drm/nouveau/dispnv50/wndwc57e.c +1 −0
  69. drivers/gpu/drm/nouveau/dispnv50/wndwc67e.c +1 −0
  70. drivers/gpu/drm/nouveau/dispnv50/wndwca7e.c +1 −0
  71. drivers/gpu/drm/nouveau/nouveau_abi16.c +10 −4
  72. drivers/gpu/drm/nouveau/nouveau_drv.h +3 −1
  73. drivers/gpu/drm/nouveau/nouveau_ttm.c +8 −0
  74. drivers/gpu/drm/omapdrm/dss/dsi.c +1 −6
  75. drivers/gpu/drm/omapdrm/dss/dsi.h +0 −2
  76. drivers/gpu/drm/panel/panel-edp.c +39 −8
  77. drivers/gpu/drm/panel/panel-ilitek-ili9805.c +87 −125
  78. drivers/gpu/drm/panel/panel-jadard-jd9365da-h3.c +248 −1
  79. drivers/gpu/drm/panel/panel-novatek-nt36536.c +1 −3
  80. drivers/gpu/drm/panel/panel-simple.c +33 −0
  81. drivers/gpu/drm/panel/panel-sitronix-st7703.c +96 −0
  82. drivers/gpu/drm/panel/panel-tdo-tl070wsh30.c +12 −28
  83. drivers/gpu/drm/panthor/panthor_drv.c +1 −1
  84. drivers/gpu/drm/panthor/panthor_fw.c +15 −7
  85. drivers/gpu/drm/panthor/panthor_mmu.c +10 −1
  86. drivers/gpu/drm/solomon/ssd130x.c +59 −6
  87. drivers/gpu/drm/sun4i/sun4i_crtc.c +1 −1
  88. drivers/gpu/drm/sun4i/sun4i_drv.c +3 −0
  89. drivers/gpu/drm/sun4i/sun4i_framebuffer.c +2 −17
  90. drivers/gpu/drm/sun4i/sun4i_hdmi_enc.c +1 −1
  91. drivers/gpu/drm/sun4i/sun4i_tcon.c +12 −10
  92. drivers/gpu/drm/sun4i/sun8i_dw_hdmi.c +2 −0
  93. drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c +1 −1
  94. drivers/gpu/drm/sun4i/sun8i_mixer.c +1 −1
  95. drivers/gpu/drm/sun4i/sun8i_tcon_top.c +59 −12
  96. drivers/gpu/drm/sun4i/sun8i_tcon_top.h +6 −0
  97. drivers/gpu/drm/sun4i/sun8i_vi_scaler.c +14 −6
  98. drivers/gpu/drm/sun4i/sun8i_vi_scaler.h +1 −0
  99. drivers/gpu/drm/ttm/ttm_bo.c +288 −32
  100. drivers/gpu/drm/ttm/ttm_bo_util.c +2 −1
  101. drivers/gpu/drm/ttm/ttm_resource.c +88 −17
  102. drivers/gpu/drm/xe/xe_ttm_vram_mgr.c +62 −9
  103. drivers/gpu/tests/.kunitconfig +2 −0
  104. drivers/gpu/tests/gpu_buddy_test.c +78 −24
  105. include/drm/drm_bridge.h +1 −1
  106. include/drm/drm_drv.h +3 −1
  107. include/drm/ttm/ttm_bo.h +10 −0
  108. include/drm/ttm/ttm_resource.h +12 −1
  109. include/linux/cgroup.h +21 −0
  110. include/linux/cgroup_dmem.h +60 −3
  111. include/linux/gpu_buddy.h +2 −0
  112. include/uapi/drm/nouveau_drm.h +1 −0
  113. kernel/cgroup/dmem.c +178 −16
Documentation/devicetree/bindings/display/bridge/renesas,dsi.yaml+1−0
@@ -28,6 +28,7 @@ properties: · 27 unmodified lines
28 - const: renesas,r9a09g057-mipi-dsi28 - const: renesas,r9a09g057-mipi-dsi
29 29
30 - enum:30 - enum:
31 - renesas,r9a08g046-mipi-dsi # RZ/G3L
31 - renesas,r9a09g057-mipi-dsi # RZ/V2H(P)32 - renesas,r9a09g057-mipi-dsi # RZ/V2H(P)
32 33
33 reg:34 reg:
Documentation/devicetree/bindings/display/bridge/renesas,r9a08g046-lvds.yaml+120−0
@@ -0,0 +1,120 @@
1# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
2%YAML 1.2
3---
4$id: http://devicetree.org/schemas/display/bridge/renesas,r9a08g046-lvds.yaml#
5$schema: http://devicetree.org/meta-schemas/core.yaml#
6
7title: Renesas RZ/G3L LVDS Encoder
8
9maintainers:
10 - Biju Das <biju.das.jz@bp.renesas.com>
11 - Tommaso Merciai <tommaso.merciai.xr@bp.renesas.com>
12
13description: |
14 This binding describes the LVDS encoder embedded in the Renesas RZ/G3L
15 SoC. The encoder can operate in LVDS Single-link mode with 4 lanes
16 (Data) + 1 lane (Clock).
17
18properties:
19 compatible:
20 const: renesas,r9a08g046-lvds
21
22 reg:
23 maxItems: 1
24
25 clocks:
26 items:
27 - description: Peripheral clock
28 - description: PHY clock
29 - description: Dot clock
30
31 clock-names:
32 items:
33 - const: pclk
34 - const: phyclk
35 - const: dotclk
36
37 resets:
38 items:
39 - description: LVDS_RESET_N
40 - description: MIPI_DSI_PRESET_N
41 - description: MIPI_DSI_CMN_RSTB
42 - description: MIPI_DSI_ARESET_N
43
44 reset-names:
45 items:
46 - const: lvdrst
47 - const: prst
48 - const: rst
49 - const: arst
50
51 power-domains:
52 maxItems: 1
53
54 ports:
55 $ref: /schemas/graph.yaml#/properties/ports
56
57 properties:
58 port@0:
59 $ref: /schemas/graph.yaml#/properties/port
60 description: Input channel, directly connected to the Display Unit.
61
62 port@1:
63 $ref: /schemas/graph.yaml#/properties/port
64 description: |
65 Output channel, directly connected to the LVDS panel or bridge.
66
67 required:
68 - port@0
69 - port@1
70
71required:
72 - compatible
73 - reg
74 - clocks
75 - clock-names
76 - resets
77 - reset-names
78 - power-domains
79 - ports
80
81additionalProperties: false
82
83examples:
84 - |
85 #include <dt-bindings/clock/renesas,r9a08g046-cpg.h>
86
87 lvds@108a0000 {
88 compatible = "renesas,r9a08g046-lvds";
89 reg = <0x108a0000 0x10000>;
90 clocks = <&cpg CPG_MOD R9A08G046_MIPI_DSI_PCLK>,
91 <&cpg CPG_MOD R9A08G046_LVDS_PLLCLK>,
92 <&cpg CPG_MOD R9A08G046_LVDS_CLK_DOT0>;
93 clock-names = "pclk", "phyclk", "dotclk";
94 resets = <&cpg R9A08G046_LVDS_RESET_N>,
95 <&cpg R9A08G046_MIPI_DSI_PRESET_N>,
96 <&cpg R9A08G046_MIPI_DSI_CMN_RSTB>,
97 <&cpg R9A08G046_MIPI_DSI_ARESET_N>;
98 reset-names = "lvdrst", "prst", "rst", "arst";
99 power-domains = <&cpg>;
100
101 ports {
102 #address-cells = <1>;
103 #size-cells = <0>;
104
105 port@0 {
106 reg = <0>;
107 lvds0_in: endpoint {
108 remote-endpoint = <&du_out_lvds0>;
109 };
110 };
111
112 port@1 {
113 reg = <1>;
114 lvds0_out: endpoint {
115 remote-endpoint = <&panel_in>;
116 };
117 };
118 };
119 };
120...
Documentation/devicetree/bindings/display/panel/jadard,jd9365da-h3.yaml+1−0
@@ -19,6 +19,7 @@ properties: · 18 unmodified lines
19 - anbernic,rg-ds-display-bottom19 - anbernic,rg-ds-display-bottom
20 - anbernic,rg-ds-display-top20 - anbernic,rg-ds-display-top
21 - chongzhou,cz101b400121 - chongzhou,cz101b4001
22 - dcltek,dt300250
22 - kingdisplay,kd101ne3-40ti23 - kingdisplay,kd101ne3-40ti
23 - melfas,lmfbx10111748024 - melfas,lmfbx101117480
24 - radxa,display-10hd-ad00125 - radxa,display-10hd-ad001
Documentation/devicetree/bindings/display/panel/panel-simple.yaml+2−0
@@ -37,6 +37,8 @@ properties: · 36 unmodified lines
37 - ampire,am-480272h3tmqw-t01h37 - ampire,am-480272h3tmqw-t01h
38 # Ampire AM-800480L1TMQW-T00H 5" WVGA TFT LCD panel38 # Ampire AM-800480L1TMQW-T00H 5" WVGA TFT LCD panel
39 - ampire,am-800480l1tmqw-t00h39 - ampire,am-800480l1tmqw-t00h
40 # Ampire AM-800480N3TZQW-00H 5" WVGA TFT LCD panel
41 - ampire,am-800480n3tzqw-00h
40 # Ampire AM-800480R3TMQW-A1H 7.0" WVGA TFT LCD panel42 # Ampire AM-800480R3TMQW-A1H 7.0" WVGA TFT LCD panel
41 - ampire,am800480r3tmqwa1h43 - ampire,am800480r3tmqwa1h
42 # Ampire AM-800600P5TMQW-TB8H 8.0" SVGA TFT LCD panel44 # Ampire AM-800600P5TMQW-TB8H 8.0" SVGA TFT LCD panel
Documentation/devicetree/bindings/display/panel/rocktech,jh057n00900.yaml+2−0
@@ -22,6 +22,8 @@ properties: · 21 unmodified lines
22 enum:22 enum:
23 # Anberic RG353V-V2 5.0" 640x480 TFT LCD panel23 # Anberic RG353V-V2 5.0" 640x480 TFT LCD panel
24 - anbernic,rg353v-panel-v224 - anbernic,rg353v-panel-v2
25 # AYANEO Pocket DS lower 5.0" 1024x768 IPS LCD panel
26 - ayaneo,pocket-ds-lower-panel
25 # GameForce Chi 3.5" 640x480 TFT LCD panel27 # GameForce Chi 3.5" 640x480 TFT LCD panel
26 - gameforce,chi-panel28 - gameforce,chi-panel
27 # Powkiddy RGB10MAX3 5.0" 720x1280 TFT LCD panel29 # Powkiddy RGB10MAX3 5.0" 720x1280 TFT LCD panel
Documentation/devicetree/bindings/display/renesas,rzg2l-du.yaml+25−1
@@ -20,6 +20,7 @@ properties: · 19 unmodified lines
20 - enum:20 - enum:
21 - renesas,r9a07g043u-du # RZ/G2UL21 - renesas,r9a07g043u-du # RZ/G2UL
22 - renesas,r9a07g044-du # RZ/G2{L,LC}22 - renesas,r9a07g044-du # RZ/G2{L,LC}
23 - renesas,r9a08g046-du # RZ/G3L
23 - renesas,r9a09g057-du # RZ/V2H(P)24 - renesas,r9a09g057-du # RZ/V2H(P)
24 - renesas,r9a09g077-du # RZ/T2H25 - renesas,r9a09g077-du # RZ/T2H
25 - items:26 - items:
@@ -65,7 +66,7 @@ properties: · 39 unmodified lines
65 model-dependent. Each port shall have a single endpoint.66 model-dependent. Each port shall have a single endpoint.
66 67
67 patternProperties:68 patternProperties:
68 "^port@[0-1]$":69 "^port@[0-2]$":
69 $ref: /schemas/graph.yaml#/properties/port70 $ref: /schemas/graph.yaml#/properties/port
70 unevaluatedProperties: false71 unevaluatedProperties: false
71 72
@@ -108,6 +109,7 @@ allOf: · 36 unmodified lines
108 port@0:109 port@0:
109 description: DPI110 description: DPI
110 port@1: false111 port@1: false
112 port@2: false
111 113
112 required:114 required:
113 - port@0115 - port@0
@@ -124,10 +126,31 @@ allOf: · 10 unmodified lines
124 description: DSI126 description: DSI
125 port@1:127 port@1:
126 description: DPI128 description: DPI
129 port@2: false
127 130
128 required:131 required:
129 - port@0132 - port@0
130 - port@1133 - port@1
134 - if:
135 properties:
136 compatible:
137 contains:
138 const: renesas,r9a08g046-du
139 then:
140 properties:
141 ports:
142 properties:
143 port@0:
144 description: DSI
145 port@1:
146 description: DPI
147 port@2:
148 description: LVDS
149
150 required:
151 - port@0
152 - port@1
153 - port@2
131 - if:154 - if:
132 properties:155 properties:
133 compatible:156 compatible:
@@ -140,6 +163,7 @@ allOf: · 6 unmodified lines
140 port@0:163 port@0:
141 description: DSI164 description: DSI
142 port@1: false165 port@1: false
166 port@2: false
143 167
144 required:168 required:
145 - port@0169 - port@0
Documentation/devicetree/bindings/vendor-prefixes.yaml+4−0
@@ -409,6 +409,8 @@ patternProperties: · 408 unmodified lines
409 description: DataImage, Inc.409 description: DataImage, Inc.
410 "^davicom,.*":410 "^davicom,.*":
411 description: DAVICOM Semiconductor, Inc.411 description: DAVICOM Semiconductor, Inc.
412 "^dcltek,.*":
413 description: DCL Technologies Inc.
412 "^deepcomputing,.*":414 "^deepcomputing,.*":
413 description: DeepComputing (HK) Limited415 description: DeepComputing (HK) Limited
414 "^dell,.*":416 "^dell,.*":
@@ -1253,6 +1255,8 @@ patternProperties: · 838 unmodified lines
1253 description: OpenWrt1255 description: OpenWrt
1254 "^option,.*":1256 "^option,.*":
1255 description: Option NV1257 description: Option NV
1258 "^optologic,.*":
1259 description: Opto Logic S.A.
1256 "^oranth,.*":1260 "^oranth,.*":
1257 description: Shenzhen Oranth Technology Co., Ltd.1261 description: Shenzhen Oranth Technology Co., Ltd.
1258 "^ORCL,.*":1262 "^ORCL,.*":
drivers/dma-buf/udmabuf.c+2−2
@@ -20,9 +20,9 @@ static int list_limit = 1024; · 19 unmodified lines
20module_param(list_limit, int, 0644);20module_param(list_limit, int, 0644);
21MODULE_PARM_DESC(list_limit, "udmabuf_create_list->count limit. Default is 1024.");21MODULE_PARM_DESC(list_limit, "udmabuf_create_list->count limit. Default is 1024.");
22 22
23static int size_limit_mb = 64;23static int size_limit_mb = INT_MAX;
24module_param(size_limit_mb, int, 0644);24module_param(size_limit_mb, int, 0644);
25MODULE_PARM_DESC(size_limit_mb, "Max size of a dmabuf, in megabytes. Default is 64.");25MODULE_PARM_DESC(size_limit_mb, "Max size of a dmabuf, in megabytes. Default is INT_MAX.");
26 26
27struct udmabuf {27struct udmabuf {
28 pgoff_t pagecount;28 pgoff_t pagecount;
drivers/gpu/Kconfig+2−1
@@ -7,7 +7,8 @@ config GPU_BUDDY · 6 unmodified lines
7 7
8config GPU_BUDDY_KUNIT_TEST8config GPU_BUDDY_KUNIT_TEST
9 tristate "KUnit tests for GPU buddy allocator" if !KUNIT_ALL_TESTS9 tristate "KUnit tests for GPU buddy allocator" if !KUNIT_ALL_TESTS
10 depends on GPU_BUDDY && KUNIT10 depends on KUNIT
11 select GPU_BUDDY
11 default KUNIT_ALL_TESTS12 default KUNIT_ALL_TESTS
12 help13 help
13 KUnit tests for the GPU buddy allocator.14 KUnit tests for the GPU buddy allocator.
drivers/gpu/buddy.c+53−0
@@ -630,6 +630,59 @@ void gpu_buddy_free_block(struct gpu_buddy *mm, · 629 unmodified lines
630}630}
631EXPORT_SYMBOL(gpu_buddy_free_block);631EXPORT_SYMBOL(gpu_buddy_free_block);
632 632
633/**
634 * gpu_buddy_allocated_addr_to_block - given relative address find the allocated block
635 *
636 * @mm: GPU buddy manager
637 * @addr: Relative address
638 *
639 * Returns:
640 * gpu_buddy_block on success, NULL or error code on failure
641 */
642struct gpu_buddy_block *gpu_buddy_allocated_addr_to_block(struct gpu_buddy *mm, u64 addr)
643{
644 struct gpu_buddy_block *block;
645 LIST_HEAD(dfs);
646 u64 end;
647 int i;
648
649 gpu_buddy_driver_lock_held(mm);
650
651 end = addr + mm->chunk_size - 1;
652 for (i = 0; i < mm->n_roots; ++i)
653 list_add_tail(&mm->roots[i]->tmp_link, &dfs);
654
655 do {
656 u64 block_start;
657 u64 block_end;
658
659 block = list_first_entry_or_null(&dfs,
660 struct gpu_buddy_block,
661 tmp_link);
662 if (!block)
663 break;
664
665 list_del(&block->tmp_link);
666
667 block_start = gpu_buddy_block_offset(block);
668 block_end = block_start + gpu_buddy_block_size(mm, block) - 1;
669
670 if (!overlaps(addr, end, block_start, block_end))
671 continue;
672
673 if (gpu_buddy_block_is_allocated(block))
674 return block;
675 else if (gpu_buddy_block_is_free(block))
676 return NULL;
677
678 list_add(&block->right->tmp_link, &dfs);
679 list_add(&block->left->tmp_link, &dfs);
680 } while (1);
681
682 return ERR_PTR(-ENXIO);
683}
684EXPORT_SYMBOL(gpu_buddy_allocated_addr_to_block);
685
633static void __gpu_buddy_free_list(struct gpu_buddy *mm,686static void __gpu_buddy_free_list(struct gpu_buddy *mm,
634 struct list_head *objects,687 struct list_head *objects,
635 bool mark_clear,688 bool mark_clear,
drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c+1−1
@@ -1526,7 +1526,7 @@ static bool amdgpu_ttm_bo_eviction_valuable(struct ttm_buffer_object *bo, · 1525 unmodified lines
1526 dma_resv_for_each_fence(&resv_cursor, bo->base.resv,1526 dma_resv_for_each_fence(&resv_cursor, bo->base.resv,
1527 DMA_RESV_USAGE_BOOKKEEP, f) {1527 DMA_RESV_USAGE_BOOKKEEP, f) {
1528 if (amdkfd_fence_check_mm(f, current->mm) &&1528 if (amdkfd_fence_check_mm(f, current->mm) &&
1529 !(place->flags & TTM_PL_FLAG_CONTIGUOUS))1529 !(place && (place->flags & TTM_PL_FLAG_CONTIGUOUS)))
1530 return false;1530 return false;
1531 }1531 }
1532 1532
drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c+62−3
@@ -23,6 +23,8 @@ · 22 unmodified lines
23 */23 */
24 24
25#include <linux/dma-mapping.h>25#include <linux/dma-mapping.h>
26#include <linux/cgroup_dmem.h>
27#include <linux/pm_runtime.h>
26#include <drm/ttm/ttm_range_manager.h>28#include <drm/ttm/ttm_range_manager.h>
27#include <drm/drm_drv.h>29#include <drm/drm_drv.h>
28#include <drm/drm_buddy.h>30#include <drm/drm_buddy.h>
@@ -905,6 +907,38 @@ static const struct ttm_resource_manager_func amdgpu_vram_mgr_func = { · 876 unmodified lines
905 .debug = amdgpu_vram_mgr_debug907 .debug = amdgpu_vram_mgr_debug
906};908};
907 909
910static const struct dmem_cgroup_ops amdgpu_vram_mgr_dmem_ops;
911
912static int amdgpu_vram_mgr_dmem_reclaim(struct dmem_cgroup_pool_state *pool,
913 u64 target_bytes, void *priv)
914{
915 struct ttm_resource_manager *man = priv;
916 struct amdgpu_device *adev = amdgpu_ttm_adev(man->bdev);
917 int ret, idx;
918
919 if (!drm_dev_enter(adev_to_drm(adev), &idx))
920 return -ENODEV;
921
922 ret = pm_runtime_get_sync(adev_to_drm(adev)->dev);
923 if (ret < 0) {
924 pm_runtime_put_autosuspend(adev_to_drm(adev)->dev);
925 goto out;
926 }
927
928 ret = ttm_resource_manager_dmem_reclaim(pool, target_bytes, priv);
929
930 pm_runtime_mark_last_busy(adev_to_drm(adev)->dev);
931 pm_runtime_put_autosuspend(adev_to_drm(adev)->dev);
932
933out:
934 drm_dev_exit(idx);
935 return ret;
936}
937
938static const struct dmem_cgroup_ops amdgpu_vram_mgr_dmem_ops = {
939 .reclaim = amdgpu_vram_mgr_dmem_reclaim,
940};
941
908/**942/**
909 * amdgpu_vram_mgr_init - init VRAM manager and DRM MM943 * amdgpu_vram_mgr_init - init VRAM manager and DRM MM
910 *944 *
@@ -916,11 +950,9 @@ int amdgpu_vram_mgr_init(struct amdgpu_device *adev) · 5 unmodified lines
916{950{
917 struct amdgpu_vram_mgr *mgr = &adev->mman.vram_mgr;951 struct amdgpu_vram_mgr *mgr = &adev->mman.vram_mgr;
918 struct ttm_resource_manager *man = &mgr->manager;952 struct ttm_resource_manager *man = &mgr->manager;
953 struct dmem_cgroup_region *cg;
919 int err;954 int err;
920 955
921 man->cg = drmm_cgroup_register_region(adev_to_drm(adev), "vram", adev->gmc.real_vram_size);
922 if (IS_ERR(man->cg))
923 return PTR_ERR(man->cg);
924 ttm_resource_manager_init(man, &adev->mman.bdev,956 ttm_resource_manager_init(man, &adev->mman.bdev,
925 adev->gmc.real_vram_size);957 adev->gmc.real_vram_size);
926 958
@@ -935,6 +967,20 @@ int amdgpu_vram_mgr_init(struct amdgpu_device *adev) · 8 unmodified lines
935 if (err)967 if (err)
936 return err;968 return err;
937 969
970 cg = dmem_cgroup_register_region(&(struct dmem_cgroup_init){
971 .size = adev->gmc.real_vram_size,
972 .ops = &amdgpu_vram_mgr_dmem_ops,
973 .reclaim_priv = man,
974 },
975 "drm/%s/vram", adev_to_drm(adev)->unique);
976 if (IS_ERR(cg)) {
977 gpu_buddy_fini(&mgr->mm);
978 return PTR_ERR(cg);
979 }
980
981 mgr->cg_region = cg;
982 ttm_resource_manager_set_dmem_region(man, cg);
983
938 ttm_set_driver_manager(&adev->mman.bdev, TTM_PL_VRAM, &mgr->manager);984 ttm_set_driver_manager(&adev->mman.bdev, TTM_PL_VRAM, &mgr->manager);
939 ttm_resource_manager_set_used(man, true);985 ttm_resource_manager_set_used(man, true);
940 return 0;986 return 0;
@@ -958,6 +1004,19 @@ void amdgpu_vram_mgr_fini(struct amdgpu_device *adev) · 17 unmodified lines
958 ttm_resource_manager_set_used(man, false);1004 ttm_resource_manager_set_used(man, false);
959 1005
960 ret = ttm_resource_manager_evict_all(&adev->mman.bdev, man);1006 ret = ttm_resource_manager_evict_all(&adev->mman.bdev, man);
1007
1008 /*
1009 * Unregister the dmem cgroup region regardless of the evict_all()
1010 * result and before any further teardown. This drains in-flight
1011 * reclaim callbacks and blocks new ones, so no reclaim can reference
1012 * the manager once we start freeing it. It must run after evict_all()
1013 * so that ttm_resource_free() can still uncharge via man->cg during
1014 * eviction. Clear man->cg afterwards.
1015 */
1016 dmem_cgroup_unregister_region(mgr->cg_region);
1017 mgr->cg_region = NULL;
1018 ttm_resource_manager_set_dmem_region(man, NULL);
1019
961 if (ret)1020 if (ret)
962 return;1021 return;
963 1022
drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.h+3−0
@@ -26,6 +26,8 @@ · 25 unmodified lines
26 26
27#include <linux/gpu_buddy.h>27#include <linux/gpu_buddy.h>
28 28
29struct dmem_cgroup_region;
30
29struct amdgpu_vram_mgr {31struct amdgpu_vram_mgr {
30 struct ttm_resource_manager manager;32 struct ttm_resource_manager manager;
31 struct gpu_buddy mm;33 struct gpu_buddy mm;
@@ -36,6 +38,7 @@ struct amdgpu_vram_mgr { · 4 unmodified lines
36 atomic64_t vis_usage;38 atomic64_t vis_usage;
37 u64 default_page_size;39 u64 default_page_size;
38 struct list_head allocated_vres_list;40 struct list_head allocated_vres_list;
41 struct dmem_cgroup_region *cg_region;
39};42};
40 43
41struct amdgpu_vres_task {44struct amdgpu_vres_task {
drivers/gpu/drm/bridge/adv7511/adv7511_drv.c+5−5
@@ -1471,11 +1471,11 @@ static const struct adv7511_chip_info adv7535_chip_info = { · 1470 unmodified lines
1471};1471};
1472 1472
1473static const struct i2c_device_id adv7511_i2c_ids[] = {1473static const struct i2c_device_id adv7511_i2c_ids[] = {
1474 { "adv7511", (kernel_ulong_t)&adv7511_chip_info },1474 { .name = "adv7511", .driver_data = (kernel_ulong_t)&adv7511_chip_info },
1475 { "adv7511w", (kernel_ulong_t)&adv7511_chip_info },1475 { .name = "adv7511w", .driver_data = (kernel_ulong_t)&adv7511_chip_info },
1476 { "adv7513", (kernel_ulong_t)&adv7511_chip_info },1476 { .name = "adv7513", .driver_data = (kernel_ulong_t)&adv7511_chip_info },
1477 { "adv7533", (kernel_ulong_t)&adv7533_chip_info },1477 { .name = "adv7533", .driver_data = (kernel_ulong_t)&adv7533_chip_info },
1478 { "adv7535", (kernel_ulong_t)&adv7535_chip_info },1478 { .name = "adv7535", .driver_data = (kernel_ulong_t)&adv7535_chip_info },
1479 { }1479 { }
1480};1480};
1481MODULE_DEVICE_TABLE(i2c, adv7511_i2c_ids);1481MODULE_DEVICE_TABLE(i2c, adv7511_i2c_ids);
drivers/gpu/drm/bridge/analogix/analogix-anx6345.c+1−1
@@ -783,7 +783,7 @@ static void anx6345_i2c_remove(struct i2c_client *client) · 782 unmodified lines
783}783}
784 784
785static const struct i2c_device_id anx6345_id[] = {785static const struct i2c_device_id anx6345_id[] = {
786 { "anx6345" },786 { .name = "anx6345" },
787 { /* sentinel */ }787 { /* sentinel */ }
788};788};
789MODULE_DEVICE_TABLE(i2c, anx6345_id);789MODULE_DEVICE_TABLE(i2c, anx6345_id);
drivers/gpu/drm/bridge/analogix/anx7625.c+2−2
@@ -2993,8 +2993,8 @@ static void anx7625_i2c_remove(struct i2c_client *client) · 2992 unmodified lines
2993}2993}
2994 2994
2995static const struct i2c_device_id anx7625_id[] = {2995static const struct i2c_device_id anx7625_id[] = {
2996 { "anx7625" },2996 { .name = "anx7625" },
2997 {}2997 { }
2998};2998};
2999 2999
3000MODULE_DEVICE_TABLE(i2c, anx7625_id);3000MODULE_DEVICE_TABLE(i2c, anx7625_id);
drivers/gpu/drm/bridge/chipone-icn6211.c+2−2
@@ -784,8 +784,8 @@ static struct mipi_dsi_driver chipone_dsi_driver = { · 783 unmodified lines
784};784};
785 785
786static const struct i2c_device_id chipone_i2c_id[] = {786static const struct i2c_device_id chipone_i2c_id[] = {
787 { "chipone,icn6211" },787 { .name = "chipone,icn6211" },
788 {},788 { }
789};789};
790MODULE_DEVICE_TABLE(i2c, chipone_i2c_id);790MODULE_DEVICE_TABLE(i2c, chipone_i2c_id);
791 791
drivers/gpu/drm/bridge/chrontel-ch7033.c+1−1
@@ -601,7 +601,7 @@ static const struct of_device_id ch7033_dt_ids[] = { · 600 unmodified lines
601MODULE_DEVICE_TABLE(of, ch7033_dt_ids);601MODULE_DEVICE_TABLE(of, ch7033_dt_ids);
602 602
603static const struct i2c_device_id ch7033_ids[] = {603static const struct i2c_device_id ch7033_ids[] = {
604 { "ch7033" },604 { .name = "ch7033" },
605 { }605 { }
606};606};
607MODULE_DEVICE_TABLE(i2c, ch7033_ids);607MODULE_DEVICE_TABLE(i2c, ch7033_ids);
drivers/gpu/drm/bridge/imx/Kconfig+11−0
@@ -107,4 +107,15 @@ config DRM_IMX93_MIPI_DSI · 106 unmodified lines
107 Choose this to enable MIPI DSI controller found in Freescale i.MX93107 Choose this to enable MIPI DSI controller found in Freescale i.MX93
108 processor.108 processor.
109 109
110config DRM_IMX93_PARALLEL_DISP_FMT_CONVERTER
111 tristate "NXP i.MX91/i.MX93 parallel display format converter"
112 depends on OF
113 select DRM_KMS_HELPER
114 help
115 On i.MX93 and i.MX91 SoCs the parallel display format output is
116 controlled via the MEDIAMIX BLK-CTRL DISPLAY_MUX.
117
118 Say 'Y' or 'M' if you use the parallel display output path on a
119 i.MX93 or i.MX91 SoC.
120
110endif # ARCH_MXC || COMPILE_TEST121endif # ARCH_MXC || COMPILE_TEST
drivers/gpu/drm/bridge/imx/Makefile+1−0
@@ -10,3 +10,4 @@ obj-$(CONFIG_DRM_IMX8QXP_PIXEL_COMBINER) += imx8qxp-pixel-combiner.o · 9 unmodified lines
10obj-$(CONFIG_DRM_IMX8QXP_PIXEL_LINK) += imx8qxp-pixel-link.o10obj-$(CONFIG_DRM_IMX8QXP_PIXEL_LINK) += imx8qxp-pixel-link.o
11obj-$(CONFIG_DRM_IMX8QXP_PIXEL_LINK_TO_DPI) += imx8qxp-pxl2dpi.o11obj-$(CONFIG_DRM_IMX8QXP_PIXEL_LINK_TO_DPI) += imx8qxp-pxl2dpi.o
12obj-$(CONFIG_DRM_IMX93_MIPI_DSI) += imx93-mipi-dsi.o12obj-$(CONFIG_DRM_IMX93_MIPI_DSI) += imx93-mipi-dsi.o
13obj-$(CONFIG_DRM_IMX93_PARALLEL_DISP_FMT_CONVERTER) += imx93-pdfc.o
drivers/gpu/drm/bridge/imx/imx93-pdfc.c+222−0
@@ -0,0 +1,222 @@
1// SPDX-License-Identifier: GPL-2.0+
2
3/*
4 * Copyright 2022-2025 NXP
5 */
6
7#include <linux/bitfield.h>
8#include <linux/bits.h>
9#include <linux/media-bus-format.h>
10#include <linux/mfd/syscon.h>
11#include <linux/module.h>
12#include <linux/of.h>
13#include <linux/of_graph.h>
14#include <linux/platform_device.h>
15#include <linux/regmap.h>
16
17#include <drm/drm_atomic_state_helper.h>
18#include <drm/drm_bridge.h>
19
20#define IMX93_DISPLAY_MUX_REG 0x60
21#define PARALLEL_DISP_FORMAT GENMASK(10, 8)
22#define FORMAT_RGB888_TO_RGB888 FIELD_PREP(PARALLEL_DISP_FORMAT, 0)
23#define FORMAT_RGB888_TO_RGB666 FIELD_PREP(PARALLEL_DISP_FORMAT, 1)
24#define FORMAT_RGB565_TO_RGB565 FIELD_PREP(PARALLEL_DISP_FORMAT, 2)
25
26struct imx93_pdfc {
27 struct drm_bridge bridge;
28 struct device *dev;
29 struct regmap *regmap;
30 u32 phy_bus_width;
31};
32
33static struct imx93_pdfc *bridge_to_imx93_pdfc(struct drm_bridge *bridge)
34{
35 return container_of(bridge, struct imx93_pdfc, bridge);
36}
37
38static int
39imx93_pdfc_bridge_attach(struct drm_bridge *bridge, struct drm_encoder *encoder,
40 enum drm_bridge_attach_flags flags)
41{
42 return drm_bridge_attach(bridge->encoder, bridge->next_bridge, bridge, flags);
43}
44
45static void imx93_pdfc_bridge_atomic_enable(struct drm_bridge *bridge,
46 struct drm_atomic_commit *state)
47{
48 struct imx93_pdfc *pdfc = bridge_to_imx93_pdfc(bridge);
49 const struct drm_bridge_state *bridge_state;
50 unsigned int mask = PARALLEL_DISP_FORMAT;
51 unsigned int val;
52
53 bridge_state = drm_atomic_get_new_bridge_state(state, bridge);
54
55 switch (bridge_state->output_bus_cfg.format) {
56 case MEDIA_BUS_FMT_RGB888_1X24:
57 case MEDIA_BUS_FMT_FIXED:
58 val = FORMAT_RGB888_TO_RGB888;
59 if (pdfc->phy_bus_width == 18) {
60 /*
61 * Can be valid if physical bus limitation exists,
62 * therefore use dev_dbg().
63 */
64 dev_dbg(pdfc->dev, "Truncate two LSBs from each color\n");
65 val = FORMAT_RGB888_TO_RGB666;
66 }
67 break;
68 case MEDIA_BUS_FMT_RGB666_1X18:
69 val = FORMAT_RGB888_TO_RGB666;
70 break;
71 case MEDIA_BUS_FMT_RGB565_1X16:
72 val = FORMAT_RGB565_TO_RGB565;
73 break;
74 }
75
76 regmap_update_bits(pdfc->regmap, IMX93_DISPLAY_MUX_REG, mask, val);
77}
78
79/* TODO: Add YUV formats */
80static const u32 imx93_pdfc_bus_output_fmts[] = {
81 MEDIA_BUS_FMT_FIXED,
82 MEDIA_BUS_FMT_RGB888_1X24,
83 MEDIA_BUS_FMT_RGB666_1X18,
84 MEDIA_BUS_FMT_RGB565_1X16,
85};
86
87static bool imx93_pdfc_bus_output_fmt_supported(u32 fmt)
88{
89 int i;
90
91 for (i = 0; i < ARRAY_SIZE(imx93_pdfc_bus_output_fmts); i++) {
92 if (imx93_pdfc_bus_output_fmts[i] == fmt)
93 return true;
94 }
95
96 return false;
97}
98
99static u32 *
100imx93_pdfc_bridge_atomic_get_input_bus_fmts(struct drm_bridge *bridge,
101 struct drm_bridge_state *bridge_state,
102 struct drm_crtc_state *crtc_state,
103 struct drm_connector_state *conn_state,
104 u32 output_fmt,
105 unsigned int *num_input_fmts)
106{
107 u32 *input_fmts;
108
109 *num_input_fmts = 0;
110
111 if (!imx93_pdfc_bus_output_fmt_supported(output_fmt))
112 return NULL;
113
114 input_fmts = kmalloc_obj(*input_fmts);
115 if (!input_fmts)
116 return NULL;
117
118 *num_input_fmts = 1;
119
120 switch (output_fmt) {
121 case MEDIA_BUS_FMT_RGB888_1X24:
122 case MEDIA_BUS_FMT_RGB565_1X16:
123 input_fmts[0] = output_fmt;
124 break;
125 case MEDIA_BUS_FMT_RGB666_1X18:
126 case MEDIA_BUS_FMT_FIXED:
127 input_fmts[0] = MEDIA_BUS_FMT_RGB888_1X24;
128 break;
129 }
130
131 return input_fmts;
132}
133
134static int imx93_pdfc_bridge_atomic_check(struct drm_bridge *bridge,
135 struct drm_bridge_state *bridge_state,
136 struct drm_crtc_state *crtc_state,
137 struct drm_connector_state *conn_state)
138{
139 struct imx93_pdfc *pdfc = bridge_to_imx93_pdfc(bridge);
140 u32 format = bridge_state->output_bus_cfg.format;
141
142 if (imx93_pdfc_bus_output_fmt_supported(format))
143 return 0;
144
145 dev_warn(pdfc->dev, "Unsupported output bus format: 0x%x\n", format);
146
147 return -EINVAL;
148}
149
150static const struct drm_bridge_funcs funcs = {
151 .attach = imx93_pdfc_bridge_attach,
152 .atomic_enable = imx93_pdfc_bridge_atomic_enable,
153 .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state,
154 .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state,
155 .atomic_get_input_bus_fmts = imx93_pdfc_bridge_atomic_get_input_bus_fmts,
156 .atomic_check = imx93_pdfc_bridge_atomic_check,
157 .atomic_create_state = drm_atomic_helper_bridge_create_state,
158};
159
160static int imx93_pdfc_bridge_probe(struct platform_device *pdev)
161{
162 struct device *dev = &pdev->dev;
163 struct drm_bridge *next_bridge;
164 struct imx93_pdfc *pdfc;
165 struct device_node *ep;
166 int err;
167
168 pdfc = devm_drm_bridge_alloc(dev, struct imx93_pdfc, bridge, &funcs);
169 if (IS_ERR(pdfc))
170 return PTR_ERR(pdfc);
171
172 pdfc->regmap = syscon_node_to_regmap(dev->of_node->parent);
173 if (IS_ERR(pdfc->regmap))
174 return dev_err_probe(dev, PTR_ERR(pdfc->regmap),
175 "failed to get regmap\n");
176
177 /* No limits per default */
178 pdfc->phy_bus_width = 24;
179
180 /* Get output ep (port1/endpoint) */
181 ep = of_graph_get_endpoint_by_regs(dev->of_node, 1, -1);
182 if (ep) {
183 err = of_property_read_u32(ep, "bus-width", &pdfc->phy_bus_width);
184 of_node_put(ep);
185
186 /* bus-width is optional but it must have valid data if present */
187 if (err && err != -EINVAL)
188 return dev_err_probe(dev, err,
189 "failed to query bus-width\n");
190 }
191
192 next_bridge = devm_drm_of_get_bridge(dev, dev->of_node, 1, 0);
193 if (IS_ERR(next_bridge))
194 return dev_err_probe(dev, PTR_ERR(next_bridge),
195 "failed to get next bridge\n");
196 pdfc->dev = dev;
197 pdfc->bridge.of_node = dev->of_node;
198 pdfc->bridge.type = DRM_MODE_CONNECTOR_DPI;
199 pdfc->bridge.next_bridge = drm_bridge_get(next_bridge);
200
201 return devm_drm_bridge_add(dev, &pdfc->bridge);
202}
203
204static const struct of_device_id imx93_pdfc_dt_ids[] = {
205 { .compatible = "nxp,imx91-pdfc", },
206 { .compatible = "nxp,imx93-pdfc", },
207 { /* sentinel */ }
208};
209MODULE_DEVICE_TABLE(of, imx93_pdfc_dt_ids);
210
211static struct platform_driver imx93_pdfc_bridge_driver = {
212 .probe = imx93_pdfc_bridge_probe,
213 .driver = {
214 .of_match_table = imx93_pdfc_dt_ids,
215 .name = "imx93_pdfc",
216 },
217};
218module_platform_driver(imx93_pdfc_bridge_driver);
219
220MODULE_DESCRIPTION("NXP i.MX93 parallel display format configuration driver");
221MODULE_AUTHOR("Liu Ying <victor.liu@nxp.com>");
222MODULE_LICENSE("GPL");
drivers/gpu/drm/bridge/ite-it6263.c+1−1
@@ -910,7 +910,7 @@ static const struct of_device_id it6263_of_match[] = { · 909 unmodified lines
910MODULE_DEVICE_TABLE(of, it6263_of_match);910MODULE_DEVICE_TABLE(of, it6263_of_match);
911 911
912static const struct i2c_device_id it6263_i2c_ids[] = {912static const struct i2c_device_id it6263_i2c_ids[] = {
913 { "it6263" },913 { .name = "it6263" },
914 { }914 { }
915};915};
916MODULE_DEVICE_TABLE(i2c, it6263_i2c_ids);916MODULE_DEVICE_TABLE(i2c, it6263_i2c_ids);
drivers/gpu/drm/bridge/ite-it6505.c+1−1
@@ -3652,7 +3652,7 @@ static void it6505_i2c_remove(struct i2c_client *client) · 3651 unmodified lines
3652}3652}
3653 3653
3654static const struct i2c_device_id it6505_id[] = {3654static const struct i2c_device_id it6505_id[] = {
3655 { "it6505" },3655 { .name = "it6505" },
3656 { }3656 { }
3657};3657};
3658 3658
drivers/gpu/drm/bridge/lontium-lt8713sx.c+1−1
@@ -572,7 +572,7 @@ static void lt8713sx_remove(struct i2c_client *client) · 571 unmodified lines
572}572}
573 573
574static struct i2c_device_id lt8713sx_id[] = {574static struct i2c_device_id lt8713sx_id[] = {
575 { "lontium,lt8713sx", 0 },575 { .name = "lontium,lt8713sx" },
576 { /* sentinel */ }576 { /* sentinel */ }
577};577};
578 578
drivers/gpu/drm/bridge/lontium-lt8912b.c+3−3
@@ -677,7 +677,7 @@ static DEFINE_SIMPLE_DEV_PM_OPS(lt8912_bridge_pm_ops, lt8912_bridge_suspend, lt8 · 676 unmodified lines
677static int lt8912_get_regulators(struct lt8912 *lt)677static int lt8912_get_regulators(struct lt8912 *lt)
678{678{
679 unsigned int i;679 unsigned int i;
680 const char * const supply_names[] = {680 static const char * const supply_names[] = {
681 "vdd", "vccmipirx", "vccsysclk", "vcclvdstx",681 "vdd", "vccmipirx", "vccsysclk", "vcclvdstx",
682 "vcchdmitx", "vcclvdspll", "vcchdmipll"682 "vcchdmitx", "vcclvdspll", "vcchdmipll"
683 };683 };
@@ -820,8 +820,8 @@ static const struct of_device_id lt8912_dt_match[] = { · 136 unmodified lines
820MODULE_DEVICE_TABLE(of, lt8912_dt_match);820MODULE_DEVICE_TABLE(of, lt8912_dt_match);
821 821
822static const struct i2c_device_id lt8912_id[] = {822static const struct i2c_device_id lt8912_id[] = {
823 { "lt8912" },823 { .name = "lt8912" },
824 {}824 { }
825};825};
826MODULE_DEVICE_TABLE(i2c, lt8912_id);826MODULE_DEVICE_TABLE(i2c, lt8912_id);
827 827
drivers/gpu/drm/bridge/lontium-lt9211.c+2−2
@@ -773,8 +773,8 @@ static void lt9211_remove(struct i2c_client *client) · 772 unmodified lines
773}773}
774 774
775static const struct i2c_device_id lt9211_id[] = {775static const struct i2c_device_id lt9211_id[] = {
776 { "lontium,lt9211" },776 { .name = "lontium,lt9211" },
777 {},777 { }
778};778};
779MODULE_DEVICE_TABLE(i2c, lt9211_id);779MODULE_DEVICE_TABLE(i2c, lt9211_id);
780 780
drivers/gpu/drm/bridge/lontium-lt9611.c+2−2
@@ -1229,8 +1229,8 @@ static void lt9611_remove(struct i2c_client *client) · 1228 unmodified lines
1229}1229}
1230 1230
1231static const struct i2c_device_id lt9611_id[] = {1231static const struct i2c_device_id lt9611_id[] = {
1232 { "lontium,lt9611" },1232 { .name = "lontium,lt9611" },
1233 {}1233 { }
1234};1234};
1235MODULE_DEVICE_TABLE(i2c, lt9611_id);1235MODULE_DEVICE_TABLE(i2c, lt9611_id);
1236 1236
drivers/gpu/drm/bridge/lontium-lt9611uxc.c+1−1
@@ -899,7 +899,7 @@ static void lt9611uxc_remove(struct i2c_client *client) · 898 unmodified lines
899}899}
900 900
901static const struct i2c_device_id lt9611uxc_id[] = {901static const struct i2c_device_id lt9611uxc_id[] = {
902 { "lontium,lt9611uxc" },902 { .name = "lontium,lt9611uxc" },
903 { /* sentinel */ }903 { /* sentinel */ }
904};904};
905 905
drivers/gpu/drm/bridge/megachips-stdpxxxx-ge-b850v3-fw.c+4−4
@@ -317,8 +317,8 @@ static void stdp4028_ge_b850v3_fw_remove(struct i2c_client *stdp4028_i2c) · 316 unmodified lines
317}317}
318 318
319static const struct i2c_device_id stdp4028_ge_b850v3_fw_i2c_table[] = {319static const struct i2c_device_id stdp4028_ge_b850v3_fw_i2c_table[] = {
320 { "stdp4028_ge_fw" },320 { .name = "stdp4028_ge_fw" },
321 {}321 { }
322};322};
323MODULE_DEVICE_TABLE(i2c, stdp4028_ge_b850v3_fw_i2c_table);323MODULE_DEVICE_TABLE(i2c, stdp4028_ge_b850v3_fw_i2c_table);
324 324
@@ -364,8 +364,8 @@ static void stdp2690_ge_b850v3_fw_remove(struct i2c_client *stdp2690_i2c) · 39 unmodified lines
364}364}
365 365
366static const struct i2c_device_id stdp2690_ge_b850v3_fw_i2c_table[] = {366static const struct i2c_device_id stdp2690_ge_b850v3_fw_i2c_table[] = {
367 { "stdp2690_ge_fw" },367 { .name = "stdp2690_ge_fw" },
368 {}368 { }
369};369};
370MODULE_DEVICE_TABLE(i2c, stdp2690_ge_b850v3_fw_i2c_table);370MODULE_DEVICE_TABLE(i2c, stdp2690_ge_b850v3_fw_i2c_table);
371 371
drivers/gpu/drm/bridge/nxp-ptn3460.c+2−2
@@ -323,8 +323,8 @@ static void ptn3460_remove(struct i2c_client *client) · 322 unmodified lines
323}323}
324 324
325static const struct i2c_device_id ptn3460_i2c_table[] = {325static const struct i2c_device_id ptn3460_i2c_table[] = {
326 { "ptn3460" },326 { .name = "ptn3460" },
327 {}327 { }
328};328};
329MODULE_DEVICE_TABLE(i2c, ptn3460_i2c_table);329MODULE_DEVICE_TABLE(i2c, ptn3460_i2c_table);
330 330
drivers/gpu/drm/bridge/parade-ps8622.c+4−4
@@ -534,10 +534,10 @@ static void ps8622_remove(struct i2c_client *client) · 533 unmodified lines
534}534}
535 535
536static const struct i2c_device_id ps8622_i2c_table[] = {536static const struct i2c_device_id ps8622_i2c_table[] = {
537 /* Device type, max_lane_count */537 /* Device type, driver_data holds the maximal lane_count */
538 {"ps8622", 1},538 { .name = "ps8622", .driver_data = 1 },
539 {"ps8625", 2},539 { .name = "ps8625", .driver_data = 2 },
540 {},540 { }
541};541};
542MODULE_DEVICE_TABLE(i2c, ps8622_i2c_table);542MODULE_DEVICE_TABLE(i2c, ps8622_i2c_table);
543 543
drivers/gpu/drm/bridge/sii902x.c+1−1
@@ -1235,7 +1235,7 @@ static const struct of_device_id sii902x_dt_ids[] = { · 1234 unmodified lines
1235MODULE_DEVICE_TABLE(of, sii902x_dt_ids);1235MODULE_DEVICE_TABLE(of, sii902x_dt_ids);
1236 1236
1237static const struct i2c_device_id sii902x_i2c_ids[] = {1237static const struct i2c_device_id sii902x_i2c_ids[] = {
1238 { "sii9022" },1238 { .name = "sii9022" },
1239 { }1239 { }
1240};1240};
1241MODULE_DEVICE_TABLE(i2c, sii902x_i2c_ids);1241MODULE_DEVICE_TABLE(i2c, sii902x_i2c_ids);
drivers/gpu/drm/bridge/sii9234.c+1−1
@@ -944,7 +944,7 @@ static const struct of_device_id sii9234_dt_match[] = { · 943 unmodified lines
944MODULE_DEVICE_TABLE(of, sii9234_dt_match);944MODULE_DEVICE_TABLE(of, sii9234_dt_match);
945 945
946static const struct i2c_device_id sii9234_id[] = {946static const struct i2c_device_id sii9234_id[] = {
947 { "SII9234" },947 { .name = "SII9234" },
948 { }948 { }
949};949};
950MODULE_DEVICE_TABLE(i2c, sii9234_id);950MODULE_DEVICE_TABLE(i2c, sii9234_id);
drivers/gpu/drm/bridge/sil-sii8620.c+1−1
@@ -2374,7 +2374,7 @@ static const struct of_device_id sii8620_dt_match[] = { · 2373 unmodified lines
2374MODULE_DEVICE_TABLE(of, sii8620_dt_match);2374MODULE_DEVICE_TABLE(of, sii8620_dt_match);
2375 2375
2376static const struct i2c_device_id sii8620_id[] = {2376static const struct i2c_device_id sii8620_id[] = {
2377 { "sii8620" },2377 { .name = "sii8620" },
2378 { }2378 { }
2379};2379};
2380 2380
drivers/gpu/drm/bridge/synopsys/dw-dp.c+0−1
@@ -1949,7 +1949,6 @@ static const struct regmap_config dw_dp_regmap_config = { · 1948 unmodified lines
1949 .reg_bits = 32,1949 .reg_bits = 32,
1950 .reg_stride = 4,1950 .reg_stride = 4,
1951 .val_bits = 32,1951 .val_bits = 32,
1952 .fast_io = true,
1953 .max_register = DW_DP_MAX_REGISTER,1952 .max_register = DW_DP_MAX_REGISTER,
1954 .rd_table = &dw_dp_readable_table,1953 .rd_table = &dw_dp_readable_table,
1955};1954};
drivers/gpu/drm/bridge/synopsys/dw-hdmi.c+2−1
@@ -3389,7 +3389,8 @@ struct dw_hdmi *dw_hdmi_probe(struct platform_device *pdev, · 3388 unmodified lines
3389 break;3389 break;
3390 default:3390 default:
3391 dev_err(dev, "reg-io-width must be 1 or 4\n");3391 dev_err(dev, "reg-io-width must be 1 or 4\n");
3392 return ERR_PTR(-EINVAL);3392 ret = -EINVAL;
3393 goto err_res;
3393 }3394 }
3394 3395
3395 iores = platform_get_resource(pdev, IORESOURCE_MEM, 0);3396 iores = platform_get_resource(pdev, IORESOURCE_MEM, 0);
drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi2.c+0−1
@@ -907,7 +907,6 @@ static const struct regmap_config dw_mipi_dsi2_regmap_config = { · 906 unmodified lines
907 .reg_bits = 32,907 .reg_bits = 32,
908 .val_bits = 32,908 .val_bits = 32,
909 .reg_stride = 4,909 .reg_stride = 4,
910 .fast_io = true,
911};910};
912 911
913static struct dw_mipi_dsi2 *912static struct dw_mipi_dsi2 *
drivers/gpu/drm/bridge/tc358762.c+5−14
@@ -292,25 +292,17 @@ static int tc358762_probe(struct mipi_dsi_device *dsi) · 291 unmodified lines
292 ctx->bridge.of_node = dev->of_node;292 ctx->bridge.of_node = dev->of_node;
293 ctx->bridge.pre_enable_prev_first = true;293 ctx->bridge.pre_enable_prev_first = true;
294 294
295 drm_bridge_add(&ctx->bridge);295 ret = devm_drm_bridge_add(dev, &ctx->bridge);
296 if (ret < 0)
297 return ret;
296 298
297 ret = mipi_dsi_attach(dsi);299 ret = devm_mipi_dsi_attach(dev, dsi);
298 if (ret < 0) {300 if (ret < 0)
299 drm_bridge_remove(&ctx->bridge);
300 dev_err(dev, "failed to attach dsi\n");301 dev_err(dev, "failed to attach dsi\n");
301 }
302 302
303 return ret;303 return ret;
304}304}
305 305
306static void tc358762_remove(struct mipi_dsi_device *dsi)
307{
308 struct tc358762 *ctx = mipi_dsi_get_drvdata(dsi);
309
310 mipi_dsi_detach(dsi);
311 drm_bridge_remove(&ctx->bridge);
312}
313
314static const struct of_device_id tc358762_of_match[] = {306static const struct of_device_id tc358762_of_match[] = {
315 { .compatible = "toshiba,tc358762" },307 { .compatible = "toshiba,tc358762" },
316 { }308 { }
@@ -319,7 +311,6 @@ MODULE_DEVICE_TABLE(of, tc358762_of_match); · 2 unmodified lines
319 311
320static struct mipi_dsi_driver tc358762_driver = {312static struct mipi_dsi_driver tc358762_driver = {
321 .probe = tc358762_probe,313 .probe = tc358762_probe,
322 .remove = tc358762_remove,
323 .driver = {314 .driver = {
324 .name = "tc358762",315 .name = "tc358762",
325 .of_match_table = tc358762_of_match,316 .of_match_table = tc358762_of_match,
drivers/gpu/drm/bridge/tc358764.c+5−14
@@ -376,25 +376,17 @@ static int tc358764_probe(struct mipi_dsi_device *dsi) · 375 unmodified lines
376 ctx->bridge.of_node = dev->of_node;376 ctx->bridge.of_node = dev->of_node;
377 ctx->bridge.pre_enable_prev_first = true;377 ctx->bridge.pre_enable_prev_first = true;
378 378
379 drm_bridge_add(&ctx->bridge);379 ret = devm_drm_bridge_add(dev, &ctx->bridge);
380 if (ret < 0)
381 return ret;
380 382
381 ret = mipi_dsi_attach(dsi);383 ret = devm_mipi_dsi_attach(dev, dsi);
382 if (ret < 0) {384 if (ret < 0)
383 drm_bridge_remove(&ctx->bridge);
384 dev_err(dev, "failed to attach dsi\n");385 dev_err(dev, "failed to attach dsi\n");
385 }
386 386
387 return ret;387 return ret;
388}388}
389 389
390static void tc358764_remove(struct mipi_dsi_device *dsi)
391{
392 struct tc358764 *ctx = mipi_dsi_get_drvdata(dsi);
393
394 mipi_dsi_detach(dsi);
395 drm_bridge_remove(&ctx->bridge);
396}
397
398static const struct of_device_id tc358764_of_match[] = {390static const struct of_device_id tc358764_of_match[] = {
399 { .compatible = "toshiba,tc358764" },391 { .compatible = "toshiba,tc358764" },
400 { }392 { }
@@ -403,7 +395,6 @@ MODULE_DEVICE_TABLE(of, tc358764_of_match); · 2 unmodified lines
403 395
404static struct mipi_dsi_driver tc358764_driver = {396static struct mipi_dsi_driver tc358764_driver = {
405 .probe = tc358764_probe,397 .probe = tc358764_probe,
406 .remove = tc358764_remove,
407 .driver = {398 .driver = {
408 .name = "tc358764",399 .name = "tc358764",
409 .of_match_table = tc358764_of_match,400 .of_match_table = tc358764_of_match,
drivers/gpu/drm/bridge/tc358767.c+1−1
@@ -2613,7 +2613,7 @@ static void tc_remove(struct i2c_client *client) · 2612 unmodified lines
2613}2613}
2614 2614
2615static const struct i2c_device_id tc358767_i2c_ids[] = {2615static const struct i2c_device_id tc358767_i2c_ids[] = {
2616 { "tc358767" },2616 { .name = "tc358767" },
2617 { }2617 { }
2618};2618};
2619MODULE_DEVICE_TABLE(i2c, tc358767_i2c_ids);2619MODULE_DEVICE_TABLE(i2c, tc358767_i2c_ids);
drivers/gpu/drm/bridge/tc358768.c+2−2
@@ -1362,8 +1362,8 @@ static const struct regmap_config tc358768_regmap_config = { · 1361 unmodified lines
1362};1362};
1363 1363
1364static const struct i2c_device_id tc358768_i2c_ids[] = {1364static const struct i2c_device_id tc358768_i2c_ids[] = {
1365 { "tc358768" },1365 { .name = "tc358768" },
1366 { "tc358778" },1366 { .name = "tc358778" },
1367 { }1367 { }
1368};1368};
1369MODULE_DEVICE_TABLE(i2c, tc358768_i2c_ids);1369MODULE_DEVICE_TABLE(i2c, tc358768_i2c_ids);
drivers/gpu/drm/bridge/tc358775.c+2−2
@@ -727,8 +727,8 @@ static void tc_remove(struct i2c_client *client) · 726 unmodified lines
727}727}
728 728
729static const struct i2c_device_id tc358775_i2c_ids[] = {729static const struct i2c_device_id tc358775_i2c_ids[] = {
730 { "tc358765", TC358765, },730 { .name = "tc358765", .driver_data = TC358765 },
731 { "tc358775", TC358775, },731 { .name = "tc358775", .driver_data = TC358775 },
732 { }732 { }
733};733};
734MODULE_DEVICE_TABLE(i2c, tc358775_i2c_ids);734MODULE_DEVICE_TABLE(i2c, tc358775_i2c_ids);
drivers/gpu/drm/bridge/tda998x_drv.c+1−1
@@ -2064,7 +2064,7 @@ MODULE_DEVICE_TABLE(of, tda998x_dt_ids); · 2063 unmodified lines
2064#endif2064#endif
2065 2065
2066static const struct i2c_device_id tda998x_ids[] = {2066static const struct i2c_device_id tda998x_ids[] = {
2067 { "tda998x" },2067 { .name = "tda998x" },
2068 { }2068 { }
2069};2069};
2070MODULE_DEVICE_TABLE(i2c, tda998x_ids);2070MODULE_DEVICE_TABLE(i2c, tda998x_ids);
drivers/gpu/drm/bridge/ti-dlpc3433.c+1−1
@@ -389,7 +389,7 @@ static void dlpc3433_remove(struct i2c_client *client) · 388 unmodified lines
389}389}
390 390
391static const struct i2c_device_id dlpc3433_id[] = {391static const struct i2c_device_id dlpc3433_id[] = {
392 { "ti,dlpc3433" },392 { .name = "ti,dlpc3433" },
393 { /* sentinel */ }393 { /* sentinel */ }
394};394};
395MODULE_DEVICE_TABLE(i2c, dlpc3433_id);395MODULE_DEVICE_TABLE(i2c, dlpc3433_id);
drivers/gpu/drm/bridge/ti-sn65dsi83.c+3−3
@@ -1072,9 +1072,9 @@ static void sn65dsi83_remove(struct i2c_client *client) · 1071 unmodified lines
1072}1072}
1073 1073
1074static const struct i2c_device_id sn65dsi83_id[] = {1074static const struct i2c_device_id sn65dsi83_id[] = {
1075 { "ti,sn65dsi83", MODEL_SN65DSI83 },1075 { .name = "ti,sn65dsi83", .driver_data = MODEL_SN65DSI83 },
1076 { "ti,sn65dsi84", MODEL_SN65DSI84 },1076 { .name = "ti,sn65dsi84", .driver_data = MODEL_SN65DSI84 },
1077 {},1077 { }
1078};1078};
1079MODULE_DEVICE_TABLE(i2c, sn65dsi83_id);1079MODULE_DEVICE_TABLE(i2c, sn65dsi83_id);
1080 1080
drivers/gpu/drm/bridge/ti-sn65dsi86.c+3−3
@@ -2080,7 +2080,7 @@ static int ti_sn65dsi86_probe(struct i2c_client *client) · 2079 unmodified lines
2080 dev_name(pdata->dev), pdata);2080 dev_name(pdata->dev), pdata);
2081 2081
2082 if (ret)2082 if (ret)
2083 return dev_err_probe(dev, ret, "failed to request interrupt\n");2083 return ret;
2084 }2084 }
2085 2085
2086 /*2086 /*
@@ -2116,8 +2116,8 @@ static int ti_sn65dsi86_probe(struct i2c_client *client) · 29 unmodified lines
2116}2116}
2117 2117
2118static const struct i2c_device_id ti_sn65dsi86_id[] = {2118static const struct i2c_device_id ti_sn65dsi86_id[] = {
2119 { "ti,sn65dsi86" },2119 { .name = "ti,sn65dsi86" },
2120 {}2120 { }
2121};2121};
2122MODULE_DEVICE_TABLE(i2c, ti_sn65dsi86_id);2122MODULE_DEVICE_TABLE(i2c, ti_sn65dsi86_id);
2123 2123
drivers/gpu/drm/bridge/ti-tfp410.c+1−1
@@ -437,7 +437,7 @@ static void tfp410_i2c_remove(struct i2c_client *client) · 436 unmodified lines
437}437}
438 438
439static const struct i2c_device_id tfp410_i2c_ids[] = {439static const struct i2c_device_id tfp410_i2c_ids[] = {
440 { "tfp410" },440 { .name = "tfp410" },
441 { }441 { }
442};442};
443MODULE_DEVICE_TABLE(i2c, tfp410_i2c_ids);443MODULE_DEVICE_TABLE(i2c, tfp410_i2c_ids);
drivers/gpu/drm/drm_drv.c+5−3
@@ -960,17 +960,19 @@ static void drmm_cg_unregister_region(struct drm_device *dev, void *arg) · 959 unmodified lines
960 * drmm_cgroup_register_region - Register a region of a DRM device to cgroups960 * drmm_cgroup_register_region - Register a region of a DRM device to cgroups
961 * @dev: device for region961 * @dev: device for region
962 * @region_name: Region name for registering962 * @region_name: Region name for registering
963 * @size: Size of region in bytes963 * @init: Initialization parameters for the region.
964 *964 *
965 * This decreases the ref-count of @dev by one. The device is destroyed if the965 * This decreases the ref-count of @dev by one. The device is destroyed if the
966 * ref-count drops to zero.966 * ref-count drops to zero.
967 */967 */
968struct dmem_cgroup_region *drmm_cgroup_register_region(struct drm_device *dev, const char *region_name, u64 size)968struct dmem_cgroup_region *
969drmm_cgroup_register_region(struct drm_device *dev, const char *region_name,
970 const struct dmem_cgroup_init *init)
969{971{
970 struct dmem_cgroup_region *region;972 struct dmem_cgroup_region *region;
971 int ret;973 int ret;
972 974
973 region = dmem_cgroup_register_region(size, "drm/%s/%s", dev->unique, region_name);975 region = dmem_cgroup_register_region(init, "drm/%s/%s", dev->unique, region_name);
974 if (IS_ERR_OR_NULL(region))976 if (IS_ERR_OR_NULL(region))
975 return region;977 return region;
976 978
drivers/gpu/drm/imagination/pvr_ccb.c+3−3
@@ -255,7 +255,7 @@ pvr_kccb_used_slot_count_locked(struct pvr_device *pvr_dev) · 254 unmodified lines
255 * pvr_kccb_send_cmd_reserved_powered() - Send command to the KCCB, with the PM ref255 * pvr_kccb_send_cmd_reserved_powered() - Send command to the KCCB, with the PM ref
256 * held and a slot pre-reserved256 * held and a slot pre-reserved
257 * @pvr_dev: Device pointer.257 * @pvr_dev: Device pointer.
258 * @cmd: Command to sent.258 * @cmd: Command to send.
259 * @kccb_slot: Address to store the KCCB slot for this command. May be %NULL.259 * @kccb_slot: Address to store the KCCB slot for this command. May be %NULL.
260 */260 */
261void261void
@@ -361,7 +361,7 @@ static int pvr_kccb_reserve_slot_sync(struct pvr_device *pvr_dev) · 99 unmodified lines
361/**361/**
362 * pvr_kccb_send_cmd_powered() - Send command to the KCCB, with a PM ref held362 * pvr_kccb_send_cmd_powered() - Send command to the KCCB, with a PM ref held
363 * @pvr_dev: Device pointer.363 * @pvr_dev: Device pointer.
364 * @cmd: Command to sent.364 * @cmd: Command to send.
365 * @kccb_slot: Address to store the KCCB slot for this command. May be %NULL.365 * @kccb_slot: Address to store the KCCB slot for this command. May be %NULL.
366 *366 *
367 * Returns:367 * Returns:
@@ -385,7 +385,7 @@ pvr_kccb_send_cmd_powered(struct pvr_device *pvr_dev, struct rogue_fwif_kccb_cmd · 17 unmodified lines
385/**385/**
386 * pvr_kccb_send_cmd() - Send command to the KCCB386 * pvr_kccb_send_cmd() - Send command to the KCCB
387 * @pvr_dev: Device pointer.387 * @pvr_dev: Device pointer.
388 * @cmd: Command to sent.388 * @cmd: Command to send.
389 * @kccb_slot: Address to store the KCCB slot for this command. May be %NULL.389 * @kccb_slot: Address to store the KCCB slot for this command. May be %NULL.
390 *390 *
391 * Returns:391 * Returns:
drivers/gpu/drm/imagination/pvr_check.h+36−0
@@ -0,0 +1,36 @@
1/* SPDX-License-Identifier: GPL-2.0-only OR MIT */
2/* Copyright (c) 2026 Imagination Technologies Ltd. */
3
4#ifndef PVR_CHECK_H
5#define PVR_CHECK_H
6
7#include <linux/build_bug.h>
8#include <linux/overflow.h>
9#include <linux/stddef.h>
10
11#define OFFSET_CHECK(type, member, offset) \
12 static_assert(offsetof(type, member) == (offset), \
13 "offsetof(" #type ", " #member ") incorrect")
14
15#define SIZE_CHECK(type, size) \
16 static_assert(sizeof(type) == (size), #type " is incorrect size")
17
18#define ALIGN_CHECK(type, align) \
19 static_assert(__alignof__(type) <= (align), #type " has incorrect alignment")
20
21/*
22 * Where the last member of a struct is a flexible array member, using
23 * SIZE_CHECK() is pointless. If the structure is not already padded to
24 * alignment without the flexible array member, sizeof() will not match the
25 * offset of the flexible array member and the "correct" sizeof() value is
26 * completely meaningless.
27 *
28 * In those instances, use FLEX_ARRAY_CHECK() instead to assert that the final
29 * field is a flexible array member and that it behaves as expected.
30 */
31#define FLEX_ARRAY_CHECK(type, member) \
32 static_assert(flex_array_size((type *)NULL, member, 1) == \
33 sizeof_field(type, member[0]), \
34 #type "->" #member " is incorrect size")
35
36#endif /* PVR_CHECK_H */
drivers/gpu/drm/imagination/pvr_device_info.h+3−3
@@ -22,12 +22,12 @@ struct pvr_device_features { · 21 unmodified lines
22 bool has_coreid_per_os;22 bool has_coreid_per_os;
23 bool has_dynamic_dust_power;23 bool has_dynamic_dust_power;
24 bool has_ecc_rams;24 bool has_ecc_rams;
25 bool has_fb_cdc_v4;
26 bool has_fbc_max_default_descriptors;
27 bool has_fbc_max_large_descriptors;
28 bool has_fbcdc;25 bool has_fbcdc;
29 bool has_fbcdc_algorithm;26 bool has_fbcdc_algorithm;
30 bool has_fbcdc_architecture;27 bool has_fbcdc_architecture;
28 bool has_fbc_max_default_descriptors;
29 bool has_fbc_max_large_descriptors;
30 bool has_fb_cdc_v4;
31 bool has_gpu_multicore_support;31 bool has_gpu_multicore_support;
32 bool has_gpu_virtualisation;32 bool has_gpu_virtualisation;
33 bool has_gs_rta_support;33 bool has_gs_rta_support;
drivers/gpu/drm/imagination/pvr_gem.h+4−8
@@ -84,8 +84,10 @@ struct pvr_gem_object { · 83 unmodified lines
84 /**84 /**
85 * @base: The underlying &struct drm_gem_shmem_object.85 * @base: The underlying &struct drm_gem_shmem_object.
86 *86 *
87 * Do not access this member directly, instead call87 * .. note::
88 * shem_gem_from_pvr_gem().88 *
89 * This member should not be accessed directly, but instead by
90 * calling shmem_gem_from_pvr_gem().
89 */91 */
90 struct drm_gem_shmem_object base;92 struct drm_gem_shmem_object base;
91 93
@@ -97,12 +99,6 @@ struct pvr_gem_object { · 5 unmodified lines
97 * changed after creation.99 * changed after creation.
98 *100 *
99 * Must be a combination of DRM_PVR_BO_* and/or PVR_BO_* flags.101 * Must be a combination of DRM_PVR_BO_* and/or PVR_BO_* flags.
100 *
101 * .. note::
102 *
103 * This member is declared const to indicate that none of these
104 * options may change or be changed throughout the object's
105 * lifetime.
106 */102 */
107 u64 flags;103 u64 flags;
108 104
drivers/gpu/drm/imagination/pvr_queue.c+2−1
@@ -17,6 +17,7 @@ · 16 unmodified lines
17#include "pvr_rogue_fwif_client.h"17#include "pvr_rogue_fwif_client.h"
18 18
19#define MAX_DEADLINE_MS 3000019#define MAX_DEADLINE_MS 30000
20#define SCHED_TIMEOUT_PERIOD (2 * MAX_DEADLINE_MS)
20 21
21#define CTX_COMPUTE_CCCB_SIZE_LOG2 1522#define CTX_COMPUTE_CCCB_SIZE_LOG2 15
22#define CTX_FRAG_CCCB_SIZE_LOG2 1523#define CTX_FRAG_CCCB_SIZE_LOG2 15
@@ -1283,7 +1284,7 @@ struct pvr_queue *pvr_queue_create(struct pvr_context *ctx, · 1260 unmodified lines
1283 .submit_wq = pvr_dev->sched_wq,1284 .submit_wq = pvr_dev->sched_wq,
1284 .credit_limit = 64 * 1024,1285 .credit_limit = 64 * 1024,
1285 .hang_limit = 1,1286 .hang_limit = 1,
1286 .timeout = msecs_to_jiffies(500),1287 .timeout = msecs_to_jiffies(SCHED_TIMEOUT_PERIOD),
1287 .timeout_wq = pvr_dev->sched_wq,1288 .timeout_wq = pvr_dev->sched_wq,
1288 .name = "pvr-queue",1289 .name = "pvr-queue",
1289 .dev = pvr_dev->base.dev,1290 .dev = pvr_dev->base.dev,
drivers/gpu/drm/imagination/pvr_rogue_fwif_check.h+1−25
@@ -4,31 +4,7 @@ · 3 unmodified lines
4#ifndef PVR_ROGUE_FWIF_CHECK_H4#ifndef PVR_ROGUE_FWIF_CHECK_H
5#define PVR_ROGUE_FWIF_CHECK_H5#define PVR_ROGUE_FWIF_CHECK_H
6 6
7#include <linux/build_bug.h>7#include "pvr_check.h"
8#include <linux/overflow.h>
9#include <linux/stddef.h>
10
11#define OFFSET_CHECK(type, member, offset) \
12 static_assert(offsetof(type, member) == (offset), \
13 "offsetof(" #type ", " #member ") incorrect")
14
15#define SIZE_CHECK(type, size) \
16 static_assert(sizeof(type) == (size), #type " is incorrect size")
17
18/*
19 * Where the last member of a struct is a flexible array member, using
20 * SIZE_CHECK() is pointless. If the structure is not already padded to
21 * alignment without the flexible array member, sizeof() will not match the
22 * offset of the flexible array member and the "correct" sizeof() value is
23 * completely meaningless.
24 *
25 * In those instances, use FLEX_ARRAY_CHECK() instead to assert that the final
26 * field is a flexible array member and that it behaves as expected.
27 */
28#define FLEX_ARRAY_CHECK(type, member) \
29 static_assert(flex_array_size((type *)NULL, member, 1) == \
30 sizeof_field(type, member[0]), \
31 #type "->" #member " is incorrect size")
32 8
33OFFSET_CHECK(struct rogue_fwif_file_info_buf, path, 0);9OFFSET_CHECK(struct rogue_fwif_file_info_buf, path, 0);
34OFFSET_CHECK(struct rogue_fwif_file_info_buf, info, 200);10OFFSET_CHECK(struct rogue_fwif_file_info_buf, info, 200);
drivers/gpu/drm/imagination/pvr_rogue_fwif_client_check.h+1−8
@@ -4,14 +4,7 @@ · 3 unmodified lines
4#ifndef PVR_ROGUE_FWIF_CLIENT_CHECK_H4#ifndef PVR_ROGUE_FWIF_CLIENT_CHECK_H
5#define PVR_ROGUE_FWIF_CLIENT_CHECK_H5#define PVR_ROGUE_FWIF_CLIENT_CHECK_H
6 6
7#include <linux/build_bug.h>7#include "pvr_check.h"
8
9#define OFFSET_CHECK(type, member, offset) \
10 static_assert(offsetof(type, member) == (offset), \
11 "offsetof(" #type ", " #member ") incorrect")
12
13#define SIZE_CHECK(type, size) \
14 static_assert(sizeof(type) == (size), #type " is incorrect size")
15 8
16OFFSET_CHECK(struct rogue_fwif_geom_regs, vdm_ctrl_stream_base, 0);9OFFSET_CHECK(struct rogue_fwif_geom_regs, vdm_ctrl_stream_base, 0);
17OFFSET_CHECK(struct rogue_fwif_geom_regs, tpu_border_colour_table, 8);10OFFSET_CHECK(struct rogue_fwif_geom_regs, tpu_border_colour_table, 8);
drivers/gpu/drm/imagination/pvr_rogue_fwif_shared_check.h+1−8
@@ -4,14 +4,7 @@ · 3 unmodified lines
4#ifndef PVR_ROGUE_FWIF_SHARED_CHECK_H4#ifndef PVR_ROGUE_FWIF_SHARED_CHECK_H
5#define PVR_ROGUE_FWIF_SHARED_CHECK_H5#define PVR_ROGUE_FWIF_SHARED_CHECK_H
6 6
7#include <linux/build_bug.h>7#include "pvr_check.h"
8
9#define OFFSET_CHECK(type, member, offset) \
10 static_assert(offsetof(type, member) == (offset), \
11 "offsetof(" #type ", " #member ") incorrect")
12
13#define SIZE_CHECK(type, size) \
14 static_assert(sizeof(type) == (size), #type " is incorrect size")
15 8
16OFFSET_CHECK(struct rogue_fwif_dma_addr, dev_addr, 0);9OFFSET_CHECK(struct rogue_fwif_dma_addr, dev_addr, 0);
17OFFSET_CHECK(struct rogue_fwif_dma_addr, fw_addr, 8);10OFFSET_CHECK(struct rogue_fwif_dma_addr, fw_addr, 8);
drivers/gpu/drm/imagination/pvr_rogue_heap_config.h+5−5
@@ -33,12 +33,12 @@ · 32 unmodified lines
33/* 0 MiB to 4 MiB, size of 4 MiB : RESERVED */33/* 0 MiB to 4 MiB, size of 4 MiB : RESERVED */
34 34
35/* 0x00_0040_0000 - 0x7F_FFC0_0000 **/35/* 0x00_0040_0000 - 0x7F_FFC0_0000 **/
36/* 4 MiB to 512 GiB, size of 512 GiB less 4 MiB : RESERVED **/36/* 4 MiB to 512 GiB, size of 512 GiB less 4 MiB : RESERVED */
37 37
38/* 0x80_0000_0000 ************************************************************/38/* 0x80_0000_0000 ************************************************************/
39 39
40/* 0x80_0000_0000 - 0x9F_FFFF_FFFF **/40/* 0x80_0000_0000 - 0x9F_FFFF_FFFF **/
41/* 512 GiB to 640 GiB, size of 128 GiB : GENERAL_HEAP **/41/* 512 GiB to 640 GiB, size of 128 GiB : GENERAL_HEAP */
42#define ROGUE_GENERAL_HEAP_BASE 0x8000000000ull42#define ROGUE_GENERAL_HEAP_BASE 0x8000000000ull
43#define ROGUE_GENERAL_HEAP_SIZE SZ_128G43#define ROGUE_GENERAL_HEAP_SIZE SZ_128G
44 44
@@ -62,7 +62,7 @@ · 17 unmodified lines
62#define ROGUE_PDSCODEDATA_HEAP_SIZE SZ_4G62#define ROGUE_PDSCODEDATA_HEAP_SIZE SZ_4G
63 63
64/* 0xDB_0000_0000 - 0xDB_FFFF_FFFF */64/* 0xDB_0000_0000 - 0xDB_FFFF_FFFF */
65/* 876 GiB to 880 GiB, size of 256 MiB (reserved 4GiB) : BRN **/65/* 876 GiB to 880 GiB, size of 256 MiB (reserved 4GiB) : BRN */
66/*66/*
67 * The BRN63142 quirk workaround requires Region Header memory to be at the top67 * The BRN63142 quirk workaround requires Region Header memory to be at the top
68 * of a 16GiB aligned range. This is so when masked with 0x03FFFFFFFF the68 * of a 16GiB aligned range. This is so when masked with 0x03FFFFFFFF the
@@ -82,7 +82,7 @@ · 13 unmodified lines
82/* 0xE1_0000_0000 - 0xE1_BFFF_FFFF */82/* 0xE1_0000_0000 - 0xE1_BFFF_FFFF */
83/* 900 GiB to 903 GiB, size of 3 GiB : RESERVED */83/* 900 GiB to 903 GiB, size of 3 GiB : RESERVED */
84 84
85/* 0xE1_C000_000 - 0xE1_FFFF_FFFF */85/* 0xE1_C000_0000 - 0xE1_FFFF_FFFF */
86/* 903 GiB to 904 GiB, reserved 1 GiB, : FIRMWARE_HEAP */86/* 903 GiB to 904 GiB, reserved 1 GiB, : FIRMWARE_HEAP */
87#define ROGUE_FW_HEAP_BASE 0xE1C0000000ull87#define ROGUE_FW_HEAP_BASE 0xE1C0000000ull
88 88
@@ -90,7 +90,7 @@ · 1 unmodified line
90/* 904 GiB to 912 GiB, size of 8 GiB : FREE */90/* 904 GiB to 912 GiB, size of 8 GiB : FREE */
91 91
92/* 0xE4_0000_0000 - 0xE7_FFFF_FFFF */92/* 0xE4_0000_0000 - 0xE7_FFFF_FFFF */
93/* 912 GiB to 968 GiB, size of 16 GiB : TRANSFER_FRAG */93/* 912 GiB to 928 GiB, size of 16 GiB : TRANSFER_FRAG */
94#define ROGUE_TRANSFER_FRAG_HEAP_BASE 0xE400000000ull94#define ROGUE_TRANSFER_FRAG_HEAP_BASE 0xE400000000ull
95#define ROGUE_TRANSFER_FRAG_HEAP_SIZE SZ_16G95#define ROGUE_TRANSFER_FRAG_HEAP_SIZE SZ_16G
96 96
drivers/gpu/drm/imagination/pvr_rogue_mips_check.h+24−47
@@ -4,55 +4,32 @@ · 3 unmodified lines
4#ifndef PVR_ROGUE_MIPS_CHECK_H4#ifndef PVR_ROGUE_MIPS_CHECK_H
5#define PVR_ROGUE_MIPS_CHECK_H5#define PVR_ROGUE_MIPS_CHECK_H
6 6
7#include <linux/build_bug.h>7#include "pvr_check.h"
8 8
9static_assert(offsetof(struct rogue_mips_tlb_entry, tlb_page_mask) == 0,9OFFSET_CHECK(struct rogue_mips_tlb_entry, tlb_page_mask, 0);
10 "offsetof(struct rogue_mips_tlb_entry, tlb_page_mask) incorrect");10OFFSET_CHECK(struct rogue_mips_tlb_entry, tlb_hi, 4);
11static_assert(offsetof(struct rogue_mips_tlb_entry, tlb_hi) == 4,11OFFSET_CHECK(struct rogue_mips_tlb_entry, tlb_lo0, 8);
12 "offsetof(struct rogue_mips_tlb_entry, tlb_hi) incorrect");12OFFSET_CHECK(struct rogue_mips_tlb_entry, tlb_lo1, 12);
13static_assert(offsetof(struct rogue_mips_tlb_entry, tlb_lo0) == 8,13SIZE_CHECK(struct rogue_mips_tlb_entry, 16);
14 "offsetof(struct rogue_mips_tlb_entry, tlb_lo0) incorrect");
15static_assert(offsetof(struct rogue_mips_tlb_entry, tlb_lo1) == 12,
16 "offsetof(struct rogue_mips_tlb_entry, tlb_lo1) incorrect");
17static_assert(sizeof(struct rogue_mips_tlb_entry) == 16,
18 "struct rogue_mips_tlb_entry is incorrect size");
19 14
20static_assert(offsetof(struct rogue_mips_remap_entry, remap_addr_in) == 0,15OFFSET_CHECK(struct rogue_mips_remap_entry, remap_addr_in, 0);
21 "offsetof(struct rogue_mips_remap_entry, remap_addr_in) incorrect");16OFFSET_CHECK(struct rogue_mips_remap_entry, remap_addr_out, 4);
22static_assert(offsetof(struct rogue_mips_remap_entry, remap_addr_out) == 4,17OFFSET_CHECK(struct rogue_mips_remap_entry, remap_region_size, 8);
23 "offsetof(struct rogue_mips_remap_entry, remap_addr_out) incorrect");18SIZE_CHECK(struct rogue_mips_remap_entry, 12);
24static_assert(offsetof(struct rogue_mips_remap_entry, remap_region_size) == 8,
25 "offsetof(struct rogue_mips_remap_entry, remap_region_size) incorrect");
26static_assert(sizeof(struct rogue_mips_remap_entry) == 12,
27 "struct rogue_mips_remap_entry is incorrect size");
28 19
29static_assert(offsetof(struct rogue_mips_state, error_state) == 0,20OFFSET_CHECK(struct rogue_mips_state, error_state, 0);
30 "offsetof(struct rogue_mips_state, error_state) incorrect");21OFFSET_CHECK(struct rogue_mips_state, error_epc, 4);
31static_assert(offsetof(struct rogue_mips_state, error_epc) == 4,22OFFSET_CHECK(struct rogue_mips_state, status_register, 8);
32 "offsetof(struct rogue_mips_state, error_epc) incorrect");23OFFSET_CHECK(struct rogue_mips_state, cause_register, 12);
33static_assert(offsetof(struct rogue_mips_state, status_register) == 8,24OFFSET_CHECK(struct rogue_mips_state, bad_register, 16);
34 "offsetof(struct rogue_mips_state, status_register) incorrect");25OFFSET_CHECK(struct rogue_mips_state, epc, 20);
35static_assert(offsetof(struct rogue_mips_state, cause_register) == 12,26OFFSET_CHECK(struct rogue_mips_state, sp, 24);
36 "offsetof(struct rogue_mips_state, cause_register) incorrect");27OFFSET_CHECK(struct rogue_mips_state, debug, 28);
37static_assert(offsetof(struct rogue_mips_state, bad_register) == 16,28OFFSET_CHECK(struct rogue_mips_state, depc, 32);
38 "offsetof(struct rogue_mips_state, bad_register) incorrect");29OFFSET_CHECK(struct rogue_mips_state, bad_instr, 36);
39static_assert(offsetof(struct rogue_mips_state, epc) == 20,30OFFSET_CHECK(struct rogue_mips_state, unmapped_address, 40);
40 "offsetof(struct rogue_mips_state, epc) incorrect");31OFFSET_CHECK(struct rogue_mips_state, tlb, 44);
41static_assert(offsetof(struct rogue_mips_state, sp) == 24,32OFFSET_CHECK(struct rogue_mips_state, remap, 300);
42 "offsetof(struct rogue_mips_state, sp) incorrect");33SIZE_CHECK(struct rogue_mips_state, 684);
43static_assert(offsetof(struct rogue_mips_state, debug) == 28,
44 "offsetof(struct rogue_mips_state, debug) incorrect");
45static_assert(offsetof(struct rogue_mips_state, depc) == 32,
46 "offsetof(struct rogue_mips_state, depc) incorrect");
47static_assert(offsetof(struct rogue_mips_state, bad_instr) == 36,
48 "offsetof(struct rogue_mips_state, bad_instr) incorrect");
49static_assert(offsetof(struct rogue_mips_state, unmapped_address) == 40,
50 "offsetof(struct rogue_mips_state, unmapped_address) incorrect");
51static_assert(offsetof(struct rogue_mips_state, tlb) == 44,
52 "offsetof(struct rogue_mips_state, tlb) incorrect");
53static_assert(offsetof(struct rogue_mips_state, remap) == 300,
54 "offsetof(struct rogue_mips_state, remap) incorrect");
55static_assert(sizeof(struct rogue_mips_state) == 684,
56 "struct rogue_mips_state is incorrect size");
57 34
58#endif /* PVR_ROGUE_MIPS_CHECK_H */35#endif /* PVR_ROGUE_MIPS_CHECK_H */
drivers/gpu/drm/nouveau/dispnv50/base.h+6−0
@@ -1,5 +1,7 @@
1#ifndef __NV50_KMS_BASE_H__1#ifndef __NV50_KMS_BASE_H__
2#define __NV50_KMS_BASE_H__2#define __NV50_KMS_BASE_H__
3#include <drm/drm_blend.h>
4
3#include "wndw.h"5#include "wndw.h"
4 6
5int base507c_new(struct nouveau_drm *, int, s32, struct nv50_wndw **);7int base507c_new(struct nouveau_drm *, int, s32, struct nv50_wndw **);
@@ -24,4 +26,8 @@ extern const struct nv50_wndw_func base907c; · 18 unmodified lines
24int base917c_new(struct nouveau_drm *, int, s32, struct nv50_wndw **);26int base917c_new(struct nouveau_drm *, int, s32, struct nv50_wndw **);
25 27
26int nv50_base_new(struct nouveau_drm *, int head, struct nv50_wndw **);28int nv50_base_new(struct nouveau_drm *, int head, struct nv50_wndw **);
29
30/* The only blend mode supported by base channels */
31#define BASE_BLEND_MODES BIT(DRM_MODE_BLEND_PIXEL_NONE)
32
27#endif33#endif
drivers/gpu/drm/nouveau/dispnv50/base507c.c+1−0
@@ -297,6 +297,7 @@ base507c = { · 296 unmodified lines
297 .image_set = base507c_image_set,297 .image_set = base507c_image_set,
298 .image_clr = base507c_image_clr,298 .image_clr = base507c_image_clr,
299 .update = base507c_update,299 .update = base507c_update,
300 .blend_modes = BASE_BLEND_MODES,
300};301};
301 302
302int303int
drivers/gpu/drm/nouveau/dispnv50/base827c.c+1−0
@@ -93,6 +93,7 @@ base827c = { · 92 unmodified lines
93 .image_set = base827c_image_set,93 .image_set = base827c_image_set,
94 .image_clr = base507c_image_clr,94 .image_clr = base507c_image_clr,
95 .update = base507c_update,95 .update = base507c_update,
96 .blend_modes = BASE_BLEND_MODES,
96};97};
97 98
98int99int
drivers/gpu/drm/nouveau/dispnv50/base907c.c+1−0
@@ -205,6 +205,7 @@ base907c = { · 204 unmodified lines
205 .image_set = base907c_image_set,205 .image_set = base907c_image_set,
206 .image_clr = base507c_image_clr,206 .image_clr = base507c_image_clr,
207 .update = base507c_update,207 .update = base507c_update,
208 .blend_modes = BASE_BLEND_MODES,
208};209};
209 210
210int211int
drivers/gpu/drm/nouveau/dispnv50/curs507a.c+3−0
@@ -29,6 +29,7 @@ · 28 unmodified lines
29#include <nvhw/class/cl507a.h>29#include <nvhw/class/cl507a.h>
30 30
31#include <drm/drm_atomic_helper.h>31#include <drm/drm_atomic_helper.h>
32#include <drm/drm_blend.h>
32#include <drm/drm_fourcc.h>33#include <drm/drm_fourcc.h>
33 34
34bool35bool
@@ -164,6 +165,8 @@ curs507a_wndw = { · 129 unmodified lines
164 .acquire = curs507a_acquire,165 .acquire = curs507a_acquire,
165 .release = curs507a_release,166 .release = curs507a_release,
166 .prepare = curs507a_prepare,167 .prepare = curs507a_prepare,
168 // TODO: Cursors also support premulti, but we haven't hooked it up anywhere yet.
169 .blend_modes = BIT(DRM_MODE_BLEND_COVERAGE),
167};170};
168 171
169int172int
drivers/gpu/drm/nouveau/dispnv50/disp.c+4−0
@@ -2768,6 +2768,7 @@ nv50_display_read_hw_state(struct nouveau_drm *drm) · 2767 unmodified lines
2768{2768{
2769 struct drm_device *dev = drm->dev;2769 struct drm_device *dev = drm->dev;
2770 struct drm_encoder *encoder;2770 struct drm_encoder *encoder;
2771 struct drm_plane *plane;
2771 struct drm_modeset_acquire_ctx ctx;2772 struct drm_modeset_acquire_ctx ctx;
2772 struct nv50_disp *disp = nv50_disp(dev);2773 struct nv50_disp *disp = nv50_disp(dev);
2773 int ret;2774 int ret;
@@ -2781,6 +2782,9 @@ nv50_display_read_hw_state(struct nouveau_drm *drm) · 7 unmodified lines
2781 nv50_display_read_hw_or_state(dev, disp, nouveau_encoder(encoder));2782 nv50_display_read_hw_or_state(dev, disp, nouveau_encoder(encoder));
2782 }2783 }
2783 2784
2785 drm_for_each_plane(plane, dev)
2786 nv50_wndw_default_state(nv50_wndw(plane));
2787
2784 DRM_MODESET_LOCK_ALL_END(dev, ctx, ret);2788 DRM_MODESET_LOCK_ALL_END(dev, ctx, ret);
2785}2789}
2786 2790
drivers/gpu/drm/nouveau/dispnv50/wndw.c+33−7
@@ -848,6 +848,28 @@ static const u64 nv50_cursor_format_modifiers[] = { · 847 unmodified lines
848 DRM_FORMAT_MOD_INVALID,848 DRM_FORMAT_MOD_INVALID,
849};849};
850 850
851/*
852 * Setup defaults for the atomic wndw state
853 */
854void
855nv50_wndw_default_state(struct nv50_wndw *wndw)
856{
857 struct nv50_wndw_atom *armw = nv50_wndw_atom(wndw->plane.state);
858 const unsigned int blend_modes = wndw->func->blend_modes;
859
860 drm_modeset_lock_assert_held(&wndw->plane.mutex);
861
862 /* Ensure the plane's atomic state didn't default to a pixel_blend_mode we don't support */
863 if (blend_modes && (!(BIT(armw->state.pixel_blend_mode) & blend_modes))) {
864 if (blend_modes & BIT(DRM_MODE_BLEND_COVERAGE))
865 armw->state.pixel_blend_mode = DRM_MODE_BLEND_COVERAGE;
866 else if (blend_modes & BIT(DRM_MODE_BLEND_PREMULTI))
867 armw->state.pixel_blend_mode = DRM_MODE_BLEND_PREMULTI;
868 else if (blend_modes & BIT(DRM_MODE_BLEND_PIXEL_NONE))
869 armw->state.pixel_blend_mode = DRM_MODE_BLEND_PIXEL_NONE;
870 }
871}
872
851int873int
852nv50_wndw_new_(const struct nv50_wndw_func *func, struct drm_device *dev,874nv50_wndw_new_(const struct nv50_wndw_func *func, struct drm_device *dev,
853 enum drm_plane_type type, const char *name, int index,875 enum drm_plane_type type, const char *name, int index,
@@ -908,13 +930,6 @@ nv50_wndw_new_(const struct nv50_wndw_func *func, struct drm_device *dev, · 54 unmodified lines
908 ret = drm_plane_create_alpha_property(&wndw->plane);930 ret = drm_plane_create_alpha_property(&wndw->plane);
909 if (ret)931 if (ret)
910 return ret;932 return ret;
911
912 ret = drm_plane_create_blend_mode_property(&wndw->plane,
913 BIT(DRM_MODE_BLEND_PIXEL_NONE) |
914 BIT(DRM_MODE_BLEND_PREMULTI) |
915 BIT(DRM_MODE_BLEND_COVERAGE));
916 if (ret)
917 return ret;
918 } else {933 } else {
919 ret = drm_plane_create_zpos_immutable_property(&wndw->plane,934 ret = drm_plane_create_zpos_immutable_property(&wndw->plane,
920 nv50_wndw_zpos_default(&wndw->plane));935 nv50_wndw_zpos_default(&wndw->plane));
@@ -922,6 +937,17 @@ nv50_wndw_new_(const struct nv50_wndw_func *func, struct drm_device *dev, · 1 unmodified line
922 return ret;937 return ret;
923 }938 }
924 939
940 /*
941 * DRM requires that we have a blend mode property for any type of plane that exposes color
942 * formats with an alpha channel. So do this, even if we don't actually have control for the
943 * blend property hooked up with blend_set.
944 */
945 if (func->blend_modes) {
946 ret = drm_plane_create_blend_mode_property(&wndw->plane, func->blend_modes);
947 if (ret)
948 return ret;
949 }
950
925 return 0;951 return 0;
926}952}
927 953
drivers/gpu/drm/nouveau/dispnv50/wndw.h+11−0
@@ -1,6 +1,8 @@
1#ifndef __NV50_KMS_WNDW_H__1#ifndef __NV50_KMS_WNDW_H__
2#define __NV50_KMS_WNDW_H__2#define __NV50_KMS_WNDW_H__
3#define nv50_wndw(p) container_of((p), struct nv50_wndw, plane)3#define nv50_wndw(p) container_of((p), struct nv50_wndw, plane)
4#include <drm/drm_blend.h>
5
4#include "disp.h"6#include "disp.h"
5#include "atom.h"7#include "atom.h"
6#include "lut.h"8#include "lut.h"
@@ -44,6 +46,7 @@ void nv50_wndw_flush_clr(struct nv50_wndw *, u32 *interlock, bool flush, · 37 unmodified lines
44 struct nv50_wndw_atom *);46 struct nv50_wndw_atom *);
45void nv50_wndw_ntfy_enable(struct nv50_wndw *, struct nv50_wndw_atom *);47void nv50_wndw_ntfy_enable(struct nv50_wndw *, struct nv50_wndw_atom *);
46int nv50_wndw_wait_armed(struct nv50_wndw *, struct nv50_wndw_atom *);48int nv50_wndw_wait_armed(struct nv50_wndw *, struct nv50_wndw_atom *);
49void nv50_wndw_default_state(struct nv50_wndw *wndw);
47 50
48struct nv50_wndw_func {51struct nv50_wndw_func {
49 int (*acquire)(struct nv50_wndw *, struct nv50_wndw_atom *asyw,52 int (*acquire)(struct nv50_wndw *, struct nv50_wndw_atom *asyw,
@@ -74,6 +77,7 @@ struct nv50_wndw_func { · 24 unmodified lines
74 int (*image_clr)(struct nv50_wndw *);77 int (*image_clr)(struct nv50_wndw *);
75 int (*scale_set)(struct nv50_wndw *, struct nv50_wndw_atom *);78 int (*scale_set)(struct nv50_wndw *, struct nv50_wndw_atom *);
76 int (*blend_set)(struct nv50_wndw *, struct nv50_wndw_atom *);79 int (*blend_set)(struct nv50_wndw *, struct nv50_wndw_atom *);
80 unsigned int blend_modes;
77 81
78 int (*update)(struct nv50_wndw *, u32 *interlock);82 int (*update)(struct nv50_wndw *, u32 *interlock);
79};83};
@@ -139,4 +143,11 @@ int wndwca7e_new(struct nouveau_drm *, enum drm_plane_type, int, s32, · 59 unmodified lines
139 143
140int nv50_wndw_new(struct nouveau_drm *, enum drm_plane_type, int index,144int nv50_wndw_new(struct nouveau_drm *, enum drm_plane_type, int index,
141 struct nv50_wndw **);145 struct nv50_wndw **);
146
147/* A set of blend modes supported by all wndws */
148#define WNDW_BLEND_MODES \
149 ( BIT(DRM_MODE_BLEND_COVERAGE) \
150 | BIT(DRM_MODE_BLEND_PREMULTI) \
151 | BIT(DRM_MODE_BLEND_PIXEL_NONE))
152
142#endif153#endif
drivers/gpu/drm/nouveau/dispnv50/wndwc37e.c+1−0
@@ -343,6 +343,7 @@ wndwc37e = { · 342 unmodified lines
343 .image_set = wndwc37e_image_set,343 .image_set = wndwc37e_image_set,
344 .image_clr = wndwc37e_image_clr,344 .image_clr = wndwc37e_image_clr,
345 .blend_set = wndwc37e_blend_set,345 .blend_set = wndwc37e_blend_set,
346 .blend_modes = WNDW_BLEND_MODES,
346 .update = wndwc37e_update,347 .update = wndwc37e_update,
347};348};
348 349
drivers/gpu/drm/nouveau/dispnv50/wndwc57e.c+1−0
@@ -231,6 +231,7 @@ wndwc57e = { · 230 unmodified lines
231 .image_set = wndwc57e_image_set,231 .image_set = wndwc57e_image_set,
232 .image_clr = wndwc37e_image_clr,232 .image_clr = wndwc37e_image_clr,
233 .blend_set = wndwc37e_blend_set,233 .blend_set = wndwc37e_blend_set,
234 .blend_modes = WNDW_BLEND_MODES,
234 .update = wndwc37e_update,235 .update = wndwc37e_update,
235};236};
236 237
drivers/gpu/drm/nouveau/dispnv50/wndwc67e.c+1−0
@@ -95,6 +95,7 @@ wndwc67e = { · 94 unmodified lines
95 .image_set = wndwc67e_image_set,95 .image_set = wndwc67e_image_set,
96 .image_clr = wndwc37e_image_clr,96 .image_clr = wndwc37e_image_clr,
97 .blend_set = wndwc37e_blend_set,97 .blend_set = wndwc37e_blend_set,
98 .blend_modes = WNDW_BLEND_MODES,
98 .update = wndwc37e_update,99 .update = wndwc37e_update,
99};100};
100 101
drivers/gpu/drm/nouveau/dispnv50/wndwca7e.c+1−0
@@ -231,6 +231,7 @@ wndwca7e = { · 230 unmodified lines
231 .image_set = wndwca7e_image_set,231 .image_set = wndwca7e_image_set,
232 .image_clr = wndwca7e_image_clr,232 .image_clr = wndwca7e_image_clr,
233 .blend_set = wndwc37e_blend_set,233 .blend_set = wndwc37e_blend_set,
234 .blend_modes = WNDW_BLEND_MODES,
234 .update = wndwc37e_update,235 .update = wndwc37e_update,
235};236};
236 237
drivers/gpu/drm/nouveau/nouveau_abi16.c+10−4
@@ -408,6 +408,9 @@ nouveau_abi16_ioctl_channel_alloc(ABI16_IOCTL_ARGS) · 407 unmodified lines
408 case NOUVEAU_FIFO_ENGINE_CE:408 case NOUVEAU_FIFO_ENGINE_CE:
409 engine = NV_DEVICE_HOST_RUNLIST_ENGINES_CE;409 engine = NV_DEVICE_HOST_RUNLIST_ENGINES_CE;
410 break;410 break;
411 case NOUVEAU_FIFO_ENGINE_NVDEC:
412 engine = NV_DEVICE_HOST_RUNLIST_ENGINES_NVDEC;
413 break;
411 default:414 default:
412 return nouveau_abi16_put(abi16, -ENOSYS);415 return nouveau_abi16_put(abi16, -ENOSYS);
413 }416 }
@@ -485,10 +488,13 @@ nouveau_abi16_ioctl_channel_alloc(ABI16_IOCTL_ARGS) · 71 unmodified lines
485 goto done;488 goto done;
486 break;489 break;
487 case NV_DEVICE_INFO_V0_TURING:490 case NV_DEVICE_INFO_V0_TURING:
488 ret = nvif_object_ctor(&chan->chan->user, "abi16CeWar", 0, TURING_DMA_COPY_A,491 if (engine != NV_DEVICE_HOST_RUNLIST_ENGINES_NVDEC) {
489 NULL, 0, &chan->ce);492 ret = nvif_object_ctor(&chan->chan->user, "abi16CeWar",
490 if (ret)493 0, TURING_DMA_COPY_A, NULL, 0,
491 goto done;494 &chan->ce);
495 if (ret)
496 goto done;
497 }
492 break;498 break;
493 default:499 default:
494 break;500 break;
drivers/gpu/drm/nouveau/nouveau_drv.h+3−1
@@ -10,7 +10,7 @@ · 9 unmodified lines
10 10
11#define DRIVER_MAJOR 111#define DRIVER_MAJOR 1
12#define DRIVER_MINOR 412#define DRIVER_MINOR 4
13#define DRIVER_PATCHLEVEL 213#define DRIVER_PATCHLEVEL 3
14 14
15/*15/*
16 * 1.1.1:16 * 1.1.1:
@@ -39,6 +39,8 @@ · 22 unmodified lines
39 * - add variable page sizes and compression for Turing+39 * - add variable page sizes and compression for Turing+
40 * 1.4.2:40 * 1.4.2:
41 * - tell userspace LPTE/SPTE races are fixed.41 * - tell userspace LPTE/SPTE races are fixed.
42 * 1.4.3:
43 * - VDEC contexts can be created.
42 */44 */
43 45
44#include <linux/notifier.h>46#include <linux/notifier.h>
drivers/gpu/drm/nouveau/nouveau_ttm.c+8−0
@@ -23,6 +23,7 @@ · 22 unmodified lines
23 * USE OR OTHER DEALINGS IN THE SOFTWARE.23 * USE OR OTHER DEALINGS IN THE SOFTWARE.
24 */24 */
25 25
26#include <linux/cgroup_dmem.h>
26#include <linux/limits.h>27#include <linux/limits.h>
27 28
28#include <drm/ttm/ttm_range_manager.h>29#include <drm/ttm/ttm_range_manager.h>
@@ -188,6 +189,13 @@ nouveau_ttm_init_vram(struct nouveau_drm *drm) · 159 unmodified lines
188 189
189 man->func = &nouveau_vram_manager;190 man->func = &nouveau_vram_manager;
190 191
192 man->cg = drmm_cgroup_register_region(drm->dev, "vram",
193 &(struct dmem_cgroup_init){
194 .size = drm->gem.vram_available
195 });
196 if (IS_ERR(man->cg))
197 return PTR_ERR(man->cg);
198
191 ttm_resource_manager_init(man, &drm->ttm.bdev,199 ttm_resource_manager_init(man, &drm->ttm.bdev,
192 drm->gem.vram_available >> PAGE_SHIFT);200 drm->gem.vram_available >> PAGE_SHIFT);
193 ttm_set_driver_manager(&drm->ttm.bdev, TTM_PL_VRAM, man);201 ttm_set_driver_manager(&drm->ttm.bdev, TTM_PL_VRAM, man);
drivers/gpu/drm/omapdrm/dss/dsi.c+1−6
@@ -456,15 +456,10 @@ static irqreturn_t omap_dsi_irq_handler(int irq, void *arg) · 455 unmodified lines
456 timer_delete(&dsi->te_timer);456 timer_delete(&dsi->te_timer);
457#endif457#endif
458 458
459 /* make a copy and unlock, so that isrs can unregister459 dsi_handle_isrs(&dsi->isr_tables, irqstatus, vcstatus, ciostatus);
460 * themselves */
461 memcpy(&dsi->isr_tables_copy, &dsi->isr_tables,
462 sizeof(dsi->isr_tables));
463 460
464 spin_unlock(&dsi->irq_lock);461 spin_unlock(&dsi->irq_lock);
465 462
466 dsi_handle_isrs(&dsi->isr_tables_copy, irqstatus, vcstatus, ciostatus);
467
468 dsi_handle_irq_errors(dsi, irqstatus, vcstatus, ciostatus);463 dsi_handle_irq_errors(dsi, irqstatus, vcstatus, ciostatus);
469 464
470 dsi_collect_irq_stats(dsi, irqstatus, vcstatus, ciostatus);465 dsi_collect_irq_stats(dsi, irqstatus, vcstatus, ciostatus);
drivers/gpu/drm/omapdrm/dss/dsi.h+0−2
@@ -379,8 +379,6 @@ struct dsi_data { · 378 unmodified lines
379 379
380 spinlock_t irq_lock;380 spinlock_t irq_lock;
381 struct dsi_isr_tables isr_tables;381 struct dsi_isr_tables isr_tables;
382 /* space for a copy used by the interrupt handler */
383 struct dsi_isr_tables isr_tables_copy;
384 382
385 int update_vc;383 int update_vc;
386#ifdef DSI_PERF_MEASURE384#ifdef DSI_PERF_MEASURE
drivers/gpu/drm/panel/panel-edp.c+39−8
@@ -144,6 +144,16 @@ struct panel_delay { · 143 unmodified lines
144 */144 */
145 unsigned int disable;145 unsigned int disable;
146 146
147 /**
148 * @pre_unprepare: Time for the end of video data to power off.
149 *
150 * The time (in milliseconds) that it needs to have passed between
151 * the end of valid video data from source and start powering off.
152 *
153 * This is T10-min on eDP timing diagrams. It is not common to set.
154 */
155 unsigned int pre_unprepare;
156
147 /**157 /**
148 * @unprepare: Time to power down completely.158 * @unprepare: Time to power down completely.
149 *159 *
@@ -413,8 +423,12 @@ static int panel_edp_suspend(struct device *dev) · 263 unmodified lines
413 423
414static int panel_edp_unprepare(struct drm_panel *panel)424static int panel_edp_unprepare(struct drm_panel *panel)
415{425{
426 struct panel_edp *p = to_panel_edp(panel);
416 int ret;427 int ret;
417 428
429 if (p->desc->delay.pre_unprepare)
430 msleep(p->desc->delay.pre_unprepare);
431
418 ret = pm_runtime_put_sync_suspend(panel->dev);432 ret = pm_runtime_put_sync_suspend(panel->dev);
419 if (ret < 0)433 if (ret < 0)
420 return ret;434 return ret;
@@ -832,6 +846,13 @@ exit: · 411 unmodified lines
832 return 0;846 return 0;
833}847}
834 848
849static void panel_edp_put_adapter(void *_adap)
850{
851 struct i2c_adapter *adap = _adap;
852
853 i2c_put_adapter(adap);
854}
855
835static int panel_edp_probe(struct device *dev, const struct panel_desc *desc,856static int panel_edp_probe(struct device *dev, const struct panel_desc *desc,
836 struct drm_dp_aux *aux)857 struct drm_dp_aux *aux)
837{858{
@@ -874,11 +895,16 @@ static int panel_edp_probe(struct device *dev, const struct panel_desc *desc, · 36 unmodified lines
874 895
875 ddc = of_parse_phandle(dev->of_node, "ddc-i2c-bus", 0);896 ddc = of_parse_phandle(dev->of_node, "ddc-i2c-bus", 0);
876 if (ddc) {897 if (ddc) {
877 panel->ddc = of_find_i2c_adapter_by_node(ddc);898 panel->ddc = of_get_i2c_adapter_by_node(ddc);
878 of_node_put(ddc);899 of_node_put(ddc);
879 900
880 if (!panel->ddc)901 if (!panel->ddc)
881 return -EPROBE_DEFER;902 return -EPROBE_DEFER;
903
904 err = devm_add_action_or_reset(dev, panel_edp_put_adapter,
905 panel->ddc);
906 if (err)
907 return err;
882 } else if (aux) {908 } else if (aux) {
883 panel->ddc = &aux->ddc;909 panel->ddc = &aux->ddc;
884 }910 }
@@ -890,7 +916,7 @@ static int panel_edp_probe(struct device *dev, const struct panel_desc *desc, · 5 unmodified lines
890 916
891 err = drm_panel_of_backlight(&panel->base);917 err = drm_panel_of_backlight(&panel->base);
892 if (err)918 if (err)
893 goto err_finished_ddc_init;919 return err;
894 920
895 /*921 /*
896 * We use runtime PM for prepare / unprepare since those power the panel922 * We use runtime PM for prepare / unprepare since those power the panel
@@ -937,9 +963,6 @@ static int panel_edp_probe(struct device *dev, const struct panel_desc *desc, · 40 unmodified lines
937err_finished_pm_runtime:963err_finished_pm_runtime:
938 pm_runtime_dont_use_autosuspend(dev);964 pm_runtime_dont_use_autosuspend(dev);
939 pm_runtime_disable(dev);965 pm_runtime_disable(dev);
940err_finished_ddc_init:
941 if (panel->ddc && (!panel->aux || panel->ddc != &panel->aux->ddc))
942 put_device(&panel->ddc->dev);
943 966
944 return err;967 return err;
945}968}
@@ -983,8 +1006,6 @@ static void panel_edp_remove(struct device *dev) · 37 unmodified lines
983 1006
984 pm_runtime_dont_use_autosuspend(dev);1007 pm_runtime_dont_use_autosuspend(dev);
985 pm_runtime_disable(dev);1008 pm_runtime_disable(dev);
986 if (panel->ddc && (!panel->aux || panel->ddc != &panel->aux->ddc))
987 put_device(&panel->ddc->dev);
988 1009
989 drm_edid_free(panel->drm_edid);1010 drm_edid_free(panel->drm_edid);
990 panel->drm_edid = NULL;1011 panel->drm_edid = NULL;
@@ -1803,6 +1824,13 @@ static const struct panel_delay delay_80_500_e80_p2e200 = { · 812 unmodified lines
1803 .prepare_to_enable = 200,1824 .prepare_to_enable = 200,
1804};1825};
1805 1826
1827static const struct panel_delay delay_200_500_e80_pu100 = {
1828 .hpd_absent = 200,
1829 .unprepare = 500,
1830 .enable = 80,
1831 .pre_unprepare = 100,
1832};
1833
1806static const struct panel_delay delay_100_500_e200 = {1834static const struct panel_delay delay_100_500_e200 = {
1807 .hpd_absent = 100,1835 .hpd_absent = 100,
1808 .unprepare = 500,1836 .unprepare = 500,
@@ -2029,6 +2057,7 @@ static const struct edp_panel_entry edp_panels[] = { · 220 unmodified lines
2029 EDP_PANEL_ENTRY('B', 'O', 'E', 0x0a84, &delay_200_500_e50, "NV133WUM-T01"),2057 EDP_PANEL_ENTRY('B', 'O', 'E', 0x0a84, &delay_200_500_e50, "NV133WUM-T01"),
2030 EDP_PANEL_ENTRY('B', 'O', 'E', 0x0ac5, &delay_200_500_e50, "NV116WHM-N4C"),2058 EDP_PANEL_ENTRY('B', 'O', 'E', 0x0ac5, &delay_200_500_e50, "NV116WHM-N4C"),
2031 EDP_PANEL_ENTRY('B', 'O', 'E', 0x0ae8, &delay_200_500_e50_p2e80, "NV140WUM-N41"),2059 EDP_PANEL_ENTRY('B', 'O', 'E', 0x0ae8, &delay_200_500_e50_p2e80, "NV140WUM-N41"),
2060 EDP_PANEL_ENTRY('B', 'O', 'E', 0x0af2, &delay_200_500_e50_p2e80, "NE140QDM-NX2"),
2032 EDP_PANEL_ENTRY('B', 'O', 'E', 0x0b09, &delay_200_500_e50_po2e200, "NV140FHM-NZ"),2061 EDP_PANEL_ENTRY('B', 'O', 'E', 0x0b09, &delay_200_500_e50_po2e200, "NV140FHM-NZ"),
2033 EDP_PANEL_ENTRY('B', 'O', 'E', 0x0b1e, &delay_200_500_e80, "NE140QDM-N6A"),2062 EDP_PANEL_ENTRY('B', 'O', 'E', 0x0b1e, &delay_200_500_e80, "NE140QDM-N6A"),
2034 EDP_PANEL_ENTRY('B', 'O', 'E', 0x0b34, &delay_200_500_e80_d50, "NV122WUM-N41"),2063 EDP_PANEL_ENTRY('B', 'O', 'E', 0x0b34, &delay_200_500_e80_d50, "NV122WUM-N41"),
@@ -2076,6 +2105,7 @@ static const struct edp_panel_entry edp_panels[] = { · 41 unmodified lines
2076 EDP_PANEL_ENTRY('C', 'M', 'N', 0x1161, &delay_200_500_e80, "N116BCP-EA2"),2105 EDP_PANEL_ENTRY('C', 'M', 'N', 0x1161, &delay_200_500_e80, "N116BCP-EA2"),
2077 EDP_PANEL_ENTRY('C', 'M', 'N', 0x1163, &delay_200_500_e80_d50, "N116BCJ-EAK"),2106 EDP_PANEL_ENTRY('C', 'M', 'N', 0x1163, &delay_200_500_e80_d50, "N116BCJ-EAK"),
2078 EDP_PANEL_ENTRY('C', 'M', 'N', 0x1169, &delay_200_500_e80_d50, "N116BCN-EA1"),2107 EDP_PANEL_ENTRY('C', 'M', 'N', 0x1169, &delay_200_500_e80_d50, "N116BCN-EA1"),
2108 EDP_PANEL_ENTRY('C', 'M', 'N', 0x116c, &delay_200_500_e80_d50, "N116BCP-EA2"),
2079 EDP_PANEL_ENTRY('C', 'M', 'N', 0x116d, &delay_200_500_e80_d50, "N116BCP-EA2"),2109 EDP_PANEL_ENTRY('C', 'M', 'N', 0x116d, &delay_200_500_e80_d50, "N116BCP-EA2"),
2080 EDP_PANEL_ENTRY('C', 'M', 'N', 0x117a, &delay_200_500_e80_d50, "N116BCL-EAK"),2110 EDP_PANEL_ENTRY('C', 'M', 'N', 0x117a, &delay_200_500_e80_d50, "N116BCL-EAK"),
2081 EDP_PANEL_ENTRY('C', 'M', 'N', 0x1247, &delay_200_500_e80_d50, "N120ACA-EA1"),2111 EDP_PANEL_ENTRY('C', 'M', 'N', 0x1247, &delay_200_500_e80_d50, "N120ACA-EA1"),
@@ -2165,6 +2195,7 @@ static const struct edp_panel_entry edp_panels[] = { · 83 unmodified lines
2165 EDP_PANEL_ENTRY('S', 'H', 'P', 0x154c, &delay_200_500_p2e100, "LQ116M1JW10"),2195 EDP_PANEL_ENTRY('S', 'H', 'P', 0x154c, &delay_200_500_p2e100, "LQ116M1JW10"),
2166 EDP_PANEL_ENTRY('S', 'H', 'P', 0x158f, &delay_200_500_p2e100, "LQ134Z1"),2196 EDP_PANEL_ENTRY('S', 'H', 'P', 0x158f, &delay_200_500_p2e100, "LQ134Z1"),
2167 EDP_PANEL_ENTRY('S', 'H', 'P', 0x1593, &delay_200_500_p2e100, "LQ134N1"),2197 EDP_PANEL_ENTRY('S', 'H', 'P', 0x1593, &delay_200_500_p2e100, "LQ134N1"),
2198 EDP_PANEL_ENTRY('S', 'H', 'P', 0x15a7, &delay_200_500_e200, "LQ120P1JX51"),
2168 2199
2169 EDP_PANEL_ENTRY('S', 'T', 'A', 0x0004, &delay_200_500_e200, "116KHD024006"),2200 EDP_PANEL_ENTRY('S', 'T', 'A', 0x0004, &delay_200_500_e200, "116KHD024006"),
2170 EDP_PANEL_ENTRY('S', 'T', 'A', 0x0009, &delay_200_500_e250, "116QHD024002"),2201 EDP_PANEL_ENTRY('S', 'T', 'A', 0x0009, &delay_200_500_e250, "116QHD024002"),
@@ -2172,7 +2203,7 @@ static const struct edp_panel_entry edp_panels[] = { · 1 unmodified line
2172 2203
2173 EDP_PANEL_ENTRY('T', 'M', 'A', 0x0811, &delay_200_500_e80_d50, "TM140VDXP01-04"),2204 EDP_PANEL_ENTRY('T', 'M', 'A', 0x0811, &delay_200_500_e80_d50, "TM140VDXP01-04"),
2174 EDP_PANEL_ENTRY('T', 'M', 'A', 0x2094, &delay_200_500_e50_d100, "TL140VDMS03-01"),2205 EDP_PANEL_ENTRY('T', 'M', 'A', 0x2094, &delay_200_500_e50_d100, "TL140VDMS03-01"),
2175 EDP_PANEL_ENTRY('T', 'M', 'A', 0x2139, &delay_200_500_e50_d100, "TM156VDXP25"),2206 EDP_PANEL_ENTRY('T', 'M', 'A', 0x2139, &delay_200_500_e80_pu100, "TM156VDXP25"),
2176 2207
2177 { /* sentinal */ }2208 { /* sentinal */ }
2178};2209};
drivers/gpu/drm/panel/panel-ilitek-ili9805.c+87−125
@@ -25,22 +25,8 @@ · 24 unmodified lines
25#define ILI9805_SETEXTC_PARAMETER2 (0x98)25#define ILI9805_SETEXTC_PARAMETER2 (0x98)
26#define ILI9805_SETEXTC_PARAMETER3 (0x05)26#define ILI9805_SETEXTC_PARAMETER3 (0x05)
27 27
28#define ILI9805_INSTR(_delay, ...) { \
29 .delay = (_delay), \
30 .len = sizeof((u8[]) {__VA_ARGS__}), \
31 .data = (u8[]){__VA_ARGS__} \
32 }
33
34struct ili9805_instr {
35 size_t len;
36 const u8 *data;
37 u32 delay;
38};
39
40struct ili9805_desc {28struct ili9805_desc {
41 const char *name;29 void (*init)(struct mipi_dsi_multi_context *ctx);
42 const struct ili9805_instr *init;
43 const size_t init_length;
44 const struct drm_display_mode *mode;30 const struct drm_display_mode *mode;
45 u32 width_mm;31 u32 width_mm;
46 u32 height_mm;32 u32 height_mm;
@@ -56,65 +42,80 @@ struct ili9805 { · 9 unmodified lines
56 struct gpio_desc *reset_gpio;42 struct gpio_desc *reset_gpio;
57};43};
58 44
59static const struct ili9805_instr gpm1780a0_init[] = {45static void gpm1780a0_init(struct mipi_dsi_multi_context *ctx)
60 ILI9805_INSTR(100, ILI9805_EXTCMD_CMD_SET_ENABLE_REG, ILI9805_SETEXTC_PARAMETER1,46{
61 ILI9805_SETEXTC_PARAMETER2, ILI9805_SETEXTC_PARAMETER3),47 mipi_dsi_dcs_write_seq_multi(ctx, ILI9805_EXTCMD_CMD_SET_ENABLE_REG,
62 ILI9805_INSTR(100, 0xFD, 0x0F, 0x10, 0x44, 0x00),48 ILI9805_SETEXTC_PARAMETER1, ILI9805_SETEXTC_PARAMETER2,
63 ILI9805_INSTR(0, 0xf8, 0x18, 0x02, 0x02, 0x18, 0x02, 0x02, 0x30, 0x00,49 ILI9805_SETEXTC_PARAMETER3);
64 0x00, 0x30, 0x00, 0x00, 0x30, 0x00, 0x00),50 mipi_dsi_msleep(ctx, 100);
65 ILI9805_INSTR(0, 0xB8, 0x62),51 mipi_dsi_dcs_write_seq_multi(ctx, 0xfd, 0x0f, 0x10, 0x44, 0x00);
66 ILI9805_INSTR(0, 0xF1, 0x00),52 mipi_dsi_msleep(ctx, 100);
67 ILI9805_INSTR(0, 0xF2, 0x00, 0x58, 0x40),53 mipi_dsi_dcs_write_seq_multi(ctx, 0xf8, 0x18, 0x02, 0x02, 0x18, 0x02, 0x02, 0x30, 0x00,
68 ILI9805_INSTR(0, 0xF3, 0x60, 0x83, 0x04),54 0x00, 0x30, 0x00, 0x00, 0x30, 0x00, 0x00);
69 ILI9805_INSTR(0, 0xFC, 0x04, 0x0F, 0x01),55 mipi_dsi_dcs_write_seq_multi(ctx, 0xb8, 0x62);
70 ILI9805_INSTR(0, 0xEB, 0x08, 0x0F),56 mipi_dsi_dcs_write_seq_multi(ctx, 0xf1, 0x00);
71 ILI9805_INSTR(0, 0xe0, 0x00, 0x08, 0x0d, 0x0e, 0x0e, 0x0d, 0x0a, 0x08, 0x04,57 mipi_dsi_dcs_write_seq_multi(ctx, 0xf2, 0x00, 0x58, 0x40);
72 0x08, 0x0d, 0x0f, 0x0b, 0x1c, 0x14, 0x0a),58 mipi_dsi_dcs_write_seq_multi(ctx, 0xf3, 0x60, 0x83, 0x04);
73 ILI9805_INSTR(0, 0xe1, 0x00, 0x08, 0x0d, 0x0e, 0x0e, 0x0d, 0x0a, 0x08, 0x04,59 mipi_dsi_dcs_write_seq_multi(ctx, 0xfc, 0x04, 0x0f, 0x01);
74 0x08, 0x0d, 0x0f, 0x0b, 0x1c, 0x14, 0x0a),60 mipi_dsi_dcs_write_seq_multi(ctx, 0xeb, 0x08, 0x0f);
75 ILI9805_INSTR(10, 0xc1, 0x13, 0x39, 0x19, 0x06),61 mipi_dsi_dcs_write_seq_multi(ctx, 0xe0, 0x00, 0x08, 0x0d, 0x0e, 0x0e, 0x0d, 0x0a, 0x08,
76 ILI9805_INSTR(10, 0xc7, 0xe5),62 0x04, 0x08, 0x0d, 0x0f, 0x0b, 0x1c, 0x14, 0x0a);
77 ILI9805_INSTR(10, 0xB1, 0x00, 0x12, 0x14),63 mipi_dsi_dcs_write_seq_multi(ctx, 0xe1, 0x00, 0x08, 0x0d, 0x0e, 0x0e, 0x0d, 0x0a, 0x08,
78 ILI9805_INSTR(10, 0xB4, 0x02),64 0x04, 0x08, 0x0d, 0x0f, 0x0b, 0x1c, 0x14, 0x0a);
79 ILI9805_INSTR(0, 0xBB, 0x14, 0x55),65 mipi_dsi_dcs_write_seq_multi(ctx, 0xc1, 0x13, 0x39, 0x19, 0x06);
80 ILI9805_INSTR(0, MIPI_DCS_SET_ADDRESS_MODE, 0x08),66 mipi_dsi_msleep(ctx, 10);
81 ILI9805_INSTR(0, MIPI_DCS_SET_PIXEL_FORMAT, 0x77),67 mipi_dsi_dcs_write_seq_multi(ctx, 0xc7, 0xe5);
82 ILI9805_INSTR(0, 0x20),68 mipi_dsi_msleep(ctx, 10);
83 ILI9805_INSTR(0, 0xB0, 0x01),69 mipi_dsi_dcs_write_seq_multi(ctx, 0xb1, 0x00, 0x12, 0x14);
84 ILI9805_INSTR(0, 0xB6, 0x31, 0x00, 0xef),70 mipi_dsi_msleep(ctx, 10);
85 ILI9805_INSTR(0, 0xDF, 0x23),71 mipi_dsi_dcs_write_seq_multi(ctx, 0xb4, 0x02);
86 ILI9805_INSTR(0, 0xB9, 0x02, 0x00),72 mipi_dsi_msleep(ctx, 10);
87};73 mipi_dsi_dcs_write_seq_multi(ctx, 0xbb, 0x14, 0x55);
74 mipi_dsi_dcs_write_seq_multi(ctx, MIPI_DCS_SET_ADDRESS_MODE, 0x08);
75 mipi_dsi_dcs_set_pixel_format_multi(ctx, 0x77);
76 mipi_dsi_dcs_write_seq_multi(ctx, 0x20);
77 mipi_dsi_dcs_write_seq_multi(ctx, 0xb0, 0x01);
78 mipi_dsi_dcs_write_seq_multi(ctx, 0xb6, 0x31, 0x00, 0xef);
79 mipi_dsi_dcs_write_seq_multi(ctx, 0xdf, 0x23);
80 mipi_dsi_dcs_write_seq_multi(ctx, 0xb9, 0x02, 0x00);
81}
88 82
89static const struct ili9805_instr tm041xdhg01_init[] = {83static void tm041xdhg01_init(struct mipi_dsi_multi_context *ctx)
90 ILI9805_INSTR(100, ILI9805_EXTCMD_CMD_SET_ENABLE_REG, ILI9805_SETEXTC_PARAMETER1,84{
91 ILI9805_SETEXTC_PARAMETER2, ILI9805_SETEXTC_PARAMETER3),85 mipi_dsi_dcs_write_seq_multi(ctx, ILI9805_EXTCMD_CMD_SET_ENABLE_REG,
92 ILI9805_INSTR(100, 0xFD, 0x0F, 0x13, 0x44, 0x00),86 ILI9805_SETEXTC_PARAMETER1, ILI9805_SETEXTC_PARAMETER2,
93 ILI9805_INSTR(0, 0xf8, 0x18, 0x02, 0x02, 0x18, 0x02, 0x02, 0x30, 0x01,87 ILI9805_SETEXTC_PARAMETER3);
94 0x01, 0x30, 0x01, 0x01, 0x30, 0x01, 0x01),88 mipi_dsi_msleep(ctx, 100);
95 ILI9805_INSTR(0, 0xB8, 0x74),89 mipi_dsi_dcs_write_seq_multi(ctx, 0xfd, 0x0f, 0x13, 0x44, 0x00);
96 ILI9805_INSTR(0, 0xF1, 0x00),90 mipi_dsi_msleep(ctx, 100);
97 ILI9805_INSTR(0, 0xF2, 0x00, 0x58, 0x40),91 mipi_dsi_dcs_write_seq_multi(ctx, 0xf8, 0x18, 0x02, 0x02, 0x18, 0x02, 0x02, 0x30, 0x01,
98 ILI9805_INSTR(0, 0xFC, 0x04, 0x0F, 0x01),92 0x01, 0x30, 0x01, 0x01, 0x30, 0x01, 0x01);
99 ILI9805_INSTR(0, 0xEB, 0x08, 0x0F),93 mipi_dsi_dcs_write_seq_multi(ctx, 0xb8, 0x74);
100 ILI9805_INSTR(0, 0xe0, 0x01, 0x0d, 0x15, 0x0e, 0x0f, 0x0f, 0x0b, 0x08, 0x04,94 mipi_dsi_dcs_write_seq_multi(ctx, 0xf1, 0x00);
101 0x07, 0x0a, 0x0d, 0x0c, 0x15, 0x0f, 0x08),95 mipi_dsi_dcs_write_seq_multi(ctx, 0xf2, 0x00, 0x58, 0x40);
102 ILI9805_INSTR(0, 0xe1, 0x01, 0x0d, 0x15, 0x0e, 0x0f, 0x0f, 0x0b, 0x08, 0x04,96 mipi_dsi_dcs_write_seq_multi(ctx, 0xfc, 0x04, 0x0f, 0x01);
103 0x07, 0x0a, 0x0d, 0x0c, 0x15, 0x0f, 0x08),97 mipi_dsi_dcs_write_seq_multi(ctx, 0xeb, 0x08, 0x0f);
104 ILI9805_INSTR(10, 0xc1, 0x15, 0x03, 0x03, 0x31),98 mipi_dsi_dcs_write_seq_multi(ctx, 0xe0, 0x01, 0x0d, 0x15, 0x0e, 0x0f, 0x0f, 0x0b, 0x08,
105 ILI9805_INSTR(10, 0xB1, 0x00, 0x12, 0x14),99 0x04, 0x07, 0x0a, 0x0d, 0x0c, 0x15, 0x0f, 0x08);
106 ILI9805_INSTR(10, 0xB4, 0x02),100 mipi_dsi_dcs_write_seq_multi(ctx, 0xe1, 0x01, 0x0d, 0x15, 0x0e, 0x0f, 0x0f, 0x0b, 0x08,
107 ILI9805_INSTR(0, 0xBB, 0x14, 0x55),101 0x04, 0x07, 0x0a, 0x0d, 0x0c, 0x15, 0x0f, 0x08);
108 ILI9805_INSTR(0, MIPI_DCS_SET_ADDRESS_MODE, 0x0a),102 mipi_dsi_dcs_write_seq_multi(ctx, 0xc1, 0x15, 0x03, 0x03, 0x31);
109 ILI9805_INSTR(0, MIPI_DCS_SET_PIXEL_FORMAT, 0x77),103 mipi_dsi_msleep(ctx, 10);
110 ILI9805_INSTR(0, 0x20),104 mipi_dsi_dcs_write_seq_multi(ctx, 0xb1, 0x00, 0x12, 0x14);
111 ILI9805_INSTR(0, 0xB0, 0x00),105 mipi_dsi_msleep(ctx, 10);
112 ILI9805_INSTR(0, 0xB6, 0x01),106 mipi_dsi_dcs_write_seq_multi(ctx, 0xb4, 0x02);
113 ILI9805_INSTR(0, 0xc2, 0x11),107 mipi_dsi_msleep(ctx, 10);
114 ILI9805_INSTR(0, 0x51, 0xFF),108 mipi_dsi_dcs_write_seq_multi(ctx, 0xbb, 0x14, 0x55);
115 ILI9805_INSTR(0, 0x53, 0x24),109 mipi_dsi_dcs_write_seq_multi(ctx, MIPI_DCS_SET_ADDRESS_MODE, 0x0a);
116 ILI9805_INSTR(0, 0x55, 0x00),110 mipi_dsi_dcs_set_pixel_format_multi(ctx, 0x77);
117};111 mipi_dsi_dcs_write_seq_multi(ctx, 0x20);
112 mipi_dsi_dcs_write_seq_multi(ctx, 0xb0, 0x00);
113 mipi_dsi_dcs_write_seq_multi(ctx, 0xb6, 0x01);
114 mipi_dsi_dcs_write_seq_multi(ctx, 0xc2, 0x11);
115 mipi_dsi_dcs_write_seq_multi(ctx, 0x51, 0xff);
116 mipi_dsi_dcs_write_seq_multi(ctx, 0x53, 0x24);
117 mipi_dsi_dcs_write_seq_multi(ctx, 0x55, 0x00);
118}
118 119
119static inline struct ili9805 *panel_to_ili9805(struct drm_panel *panel)120static inline struct ili9805 *panel_to_ili9805(struct drm_panel *panel)
120{121{
@@ -148,47 +149,24 @@ static int ili9805_power_on(struct ili9805 *ctx) · 27 unmodified lines
148 return 0;149 return 0;
149}150}
150 151
151static int ili9805_power_off(struct ili9805 *ctx)152static void ili9805_power_off(struct ili9805 *ctx)
152{153{
153 gpiod_set_value(ctx->reset_gpio, 0);154 gpiod_set_value(ctx->reset_gpio, 0);
154 regulator_disable(ctx->dvdd);155 regulator_disable(ctx->dvdd);
155 regulator_disable(ctx->avdd);156 regulator_disable(ctx->avdd);
156
157 return 0;
158}157}
159 158
160static int ili9805_activate(struct ili9805 *ctx)159static int ili9805_activate(struct ili9805 *ctx)
161{160{
162 struct mipi_dsi_device *dsi = ctx->dsi;161 struct mipi_dsi_multi_context dsi_ctx = { .dsi = ctx->dsi };
163 struct device *dev = &dsi->dev;
164 int i, ret;
165
166 for (i = 0; i < ctx->desc->init_length; i++) {
167 const struct ili9805_instr *instr = &ctx->desc->init[i];
168
169 ret = mipi_dsi_dcs_write_buffer(ctx->dsi, instr->data, instr->len);
170 if (ret < 0)
171 return ret;
172
173 if (instr->delay > 0)
174 msleep(instr->delay);
175 }
176
177 ret = mipi_dsi_dcs_exit_sleep_mode(ctx->dsi);
178 if (ret) {
179 dev_err(dev, "Failed to exit sleep mode (%d)\n", ret);
180 return ret;
181 }
182 162
183 usleep_range(5000, 6000);163 ctx->desc->init(&dsi_ctx);
184 164
185 ret = mipi_dsi_dcs_set_display_on(ctx->dsi);165 mipi_dsi_dcs_exit_sleep_mode_multi(&dsi_ctx);
186 if (ret) {166 mipi_dsi_usleep_range(&dsi_ctx, 5000, 6000);
187 dev_err(dev, "Failed to set display ON (%d)\n", ret);167 mipi_dsi_dcs_set_display_on_multi(&dsi_ctx);
188 return ret;
189 }
190 168
191 return 0;169 return dsi_ctx.accum_err;
192}170}
193 171
194static int ili9805_prepare(struct drm_panel *panel)172static int ili9805_prepare(struct drm_panel *panel)
@@ -209,27 +187,13 @@ static int ili9805_prepare(struct drm_panel *panel) · 14 unmodified lines
209 return 0;187 return 0;
210}188}
211 189
212static int ili9805_deactivate(struct ili9805 *ctx)190static void ili9805_deactivate(struct ili9805 *ctx)
213{191{
214 struct mipi_dsi_device *dsi = ctx->dsi;192 struct mipi_dsi_multi_context dsi_ctx = { .dsi = ctx->dsi };
215 struct device *dev = &dsi->dev;
216 int ret;
217
218 ret = mipi_dsi_dcs_set_display_off(ctx->dsi);
219 if (ret < 0) {
220 dev_err(dev, "Failed to set display OFF (%d)\n", ret);
221 return ret;
222 }
223
224 usleep_range(5000, 10000);
225 193
226 ret = mipi_dsi_dcs_enter_sleep_mode(ctx->dsi);194 mipi_dsi_dcs_set_display_off_multi(&dsi_ctx);
227 if (ret < 0) {195 mipi_dsi_usleep_range(&dsi_ctx, 5000, 10000);
228 dev_err(dev, "Failed to enter sleep mode (%d)\n", ret);196 mipi_dsi_dcs_enter_sleep_mode_multi(&dsi_ctx);
229 return ret;
230 }
231
232 return 0;
233}197}
234 198
235static int ili9805_unprepare(struct drm_panel *panel)199static int ili9805_unprepare(struct drm_panel *panel)
@@ -271,7 +235,7 @@ static const struct drm_display_mode tm041xdhg01_timing = { · 35 unmodified lines
271};235};
272 236
273static int ili9805_get_modes(struct drm_panel *panel,237static int ili9805_get_modes(struct drm_panel *panel,
274 struct drm_connector *connector)238 struct drm_connector *connector)
275{239{
276 struct ili9805 *ctx = panel_to_ili9805(panel);240 struct ili9805 *ctx = panel_to_ili9805(panel);
277 struct drm_display_mode *mode;241 struct drm_display_mode *mode;
@@ -368,7 +332,6 @@ static void ili9805_dsi_remove(struct mipi_dsi_device *dsi) · 90 unmodified lines
368 332
369static const struct ili9805_desc gpm1780a0_desc = {333static const struct ili9805_desc gpm1780a0_desc = {
370 .init = gpm1780a0_init,334 .init = gpm1780a0_init,
371 .init_length = ARRAY_SIZE(gpm1780a0_init),
372 .mode = &gpm1780a0_timing,335 .mode = &gpm1780a0_timing,
373 .width_mm = 65,336 .width_mm = 65,
374 .height_mm = 65,337 .height_mm = 65,
@@ -376,7 +339,6 @@ static const struct ili9805_desc gpm1780a0_desc = { · 1 unmodified line
376 339
377static const struct ili9805_desc tm041xdhg01_desc = {340static const struct ili9805_desc tm041xdhg01_desc = {
378 .init = tm041xdhg01_init,341 .init = tm041xdhg01_init,
379 .init_length = ARRAY_SIZE(tm041xdhg01_init),
380 .mode = &tm041xdhg01_timing,342 .mode = &tm041xdhg01_timing,
381 .width_mm = 42,343 .width_mm = 42,
382 .height_mm = 96,344 .height_mm = 96,
drivers/gpu/drm/panel/panel-jadard-jd9365da-h3.c+248−1
@@ -2931,6 +2931,248 @@ static const struct jadard_panel_desc waveshare_10_1_inch_b_desc = { · 2930 unmodified lines
2931 MIPI_DSI_MODE_LPM | MIPI_DSI_CLOCK_NON_CONTINUOUS,2931 MIPI_DSI_MODE_LPM | MIPI_DSI_CLOCK_NON_CONTINUOUS,
2932};2932};
2933 2933
2934static int dcltek_dt300250_init_cmds(struct jadard *jadard)
2935{
2936 struct mipi_dsi_multi_context dsi_ctx = { .dsi = jadard->dsi };
2937
2938 jd9365da_switch_page(&dsi_ctx, 0x00);
2939 jadard_enable_standard_cmds(&dsi_ctx);
2940
2941 jd9365da_switch_page(&dsi_ctx, 0x01);
2942 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x00, 0x00);
2943 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x01, 0x2B);
2944 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x03, 0x10);
2945 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x04, 0x2B);
2946 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x0C, 0x74);
2947 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x17, 0x00);
2948 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x18, 0xCF);
2949 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x19, 0x01);
2950 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x1A, 0x00);
2951 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x1B, 0xCF);
2952 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x1C, 0x01);
2953 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x24, 0xFE);
2954 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x37, 0x09);
2955 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x38, 0x04);
2956 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x39, 0x00);
2957 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x3A, 0x01);
2958 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x3C, 0x5C);
2959 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x3D, 0xFF);
2960 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x3E, 0xFF);
2961 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x3F, 0x7F);
2962 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x40, 0x02);
2963 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x41, 0xC8);
2964 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x42, 0x66);
2965 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x43, 0x10);
2966 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x44, 0x0F);
2967 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x45, 0x28);
2968 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x55, 0x02);
2969 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x57, 0x8D);
2970 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x59, 0x0A);
2971 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x5A, 0x29);
2972 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x5B, 0x1A);
2973 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x5D, 0x7F);
2974 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x5E, 0x65);
2975 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x5F, 0x53);
2976 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x60, 0x45);
2977 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x61, 0x3E);
2978 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x62, 0x30);
2979 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x63, 0x33);
2980 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x64, 0x1F);
2981 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x65, 0x3B);
2982 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x66, 0x3C);
2983 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x67, 0x3F);
2984 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x68, 0x5D);
2985 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x69, 0x49);
2986 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x6A, 0x4D);
2987 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x6B, 0x3D);
2988 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x6C, 0x37);
2989 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x6D, 0x28);
2990 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x6E, 0x15);
2991 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x6F, 0x00);
2992 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x70, 0x7F);
2993 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x71, 0x65);
2994 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x72, 0x53);
2995 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x73, 0x45);
2996 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x74, 0x3E);
2997 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x75, 0x30);
2998 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x76, 0x33);
2999 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x77, 0x1F);
3000 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x78, 0x3B);
3001 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x79, 0x3C);
3002 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x7A, 0x3F);
3003 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x7B, 0x5D);
3004 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x7C, 0x49);
3005 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x7D, 0x4D);
3006 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x7E, 0x3D);
3007 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x7F, 0x44);
3008 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x80, 0x28);
3009 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x81, 0x15);
3010 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x82, 0x00);
3011
3012 jd9365da_switch_page(&dsi_ctx, 0x02);
3013 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x00, 0x41);
3014 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x01, 0x5F);
3015 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x02, 0x5F);
3016 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x03, 0x4B);
3017 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x04, 0x5F);
3018 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x05, 0x5C);
3019 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x06, 0x5F);
3020 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x07, 0x49);
3021 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x08, 0x5F);
3022 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x09, 0x5A);
3023 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x0A, 0x5F);
3024 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x0B, 0x47);
3025 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x0C, 0x5F);
3026 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x0D, 0x4F);
3027 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x0E, 0x5F);
3028 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x0F, 0x45);
3029 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x10, 0x5F);
3030 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x11, 0x4D);
3031 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x12, 0x5F);
3032 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x13, 0x5E);
3033 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x14, 0x51);
3034 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x15, 0x5F);
3035 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x16, 0x40);
3036 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x17, 0x5F);
3037 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x18, 0x5F);
3038 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x19, 0x4A);
3039 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x1A, 0x5F);
3040 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x1B, 0x5B);
3041 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x1C, 0x5F);
3042 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x1D, 0x48);
3043 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x1E, 0x5F);
3044 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x1F, 0x59);
3045 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x20, 0x5F);
3046 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x21, 0x46);
3047 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x22, 0x5F);
3048 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x23, 0x4E);
3049 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x24, 0x5F);
3050 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x25, 0x44);
3051 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x26, 0x5F);
3052 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x27, 0x4C);
3053 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x28, 0x5F);
3054 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x29, 0x5E);
3055 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x2A, 0x50);
3056 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x2B, 0x5F);
3057 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x2C, 0x10);
3058 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x2D, 0x1F);
3059 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x2E, 0x1F);
3060 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x2F, 0x0C);
3061 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x30, 0x1F);
3062 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x31, 0x04);
3063 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x32, 0x1F);
3064 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x33, 0x0E);
3065 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x34, 0x1F);
3066 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x35, 0x06);
3067 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x36, 0x1F);
3068 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x37, 0x19);
3069 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x38, 0x1F);
3070 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x39, 0x08);
3071 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x3A, 0x1F);
3072 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x3B, 0x1B);
3073 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x3C, 0x1F);
3074 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x3D, 0x0A);
3075 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x3E, 0x1E);
3076 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x3F, 0x1F);
3077 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x40, 0x00);
3078 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x41, 0x1F);
3079 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x42, 0x11);
3080 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x43, 0x1F);
3081 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x44, 0x1F);
3082 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x45, 0x0D);
3083 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x46, 0x1F);
3084 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x47, 0x05);
3085 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x48, 0x1F);
3086 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x49, 0x0F);
3087 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x4A, 0x1F);
3088 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x4B, 0x07);
3089 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x4C, 0x1F);
3090 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x4D, 0x1A);
3091 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x4E, 0x1F);
3092 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x4F, 0x09);
3093 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x50, 0x1F);
3094 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x51, 0x1C);
3095 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x52, 0x1F);
3096 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x53, 0x0B);
3097 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x54, 0x1E);
3098 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x55, 0x1F);
3099 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x56, 0x01);
3100 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x57, 0x1F);
3101 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x58, 0x40);
3102 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x5B, 0x10);
3103 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x5C, 0x01);
3104 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x5D, 0x70);
3105 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x5E, 0x01);
3106 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x5F, 0x02);
3107 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x60, 0x70);
3108 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x61, 0x01);
3109 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x62, 0x02);
3110 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x63, 0x06);
3111 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x64, 0x4A);
3112 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x65, 0x56);
3113 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x66, 0x4F);
3114 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x67, 0xF7);
3115 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x68, 0x01);
3116 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x69, 0x06);
3117 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x6A, 0x4A);
3118 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x6B, 0x10);
3119 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x6C, 0x00);
3120 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x6D, 0x00);
3121 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x6E, 0x00);
3122 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x6F, 0x88);
3123
3124 jd9365da_switch_page(&dsi_ctx, 0x04);
3125 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x00, 0x0E);
3126 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x02, 0xB3);
3127 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x09, 0x60);
3128 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x0e, 0x4A);
3129 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x37, 0x58);
3130 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x2b, 0x0F);
3131
3132 jd9365da_switch_page(&dsi_ctx, 0x05);
3133 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x15, 0x34);
3134 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x16, 0x76);
3135
3136 jd9365da_switch_page(&dsi_ctx, 0x00);
3137
3138 mipi_dsi_msleep(&dsi_ctx, 120);
3139
3140 mipi_dsi_dcs_exit_sleep_mode_multi(&dsi_ctx);
3141
3142 mipi_dsi_msleep(&dsi_ctx, 120);
3143
3144 mipi_dsi_dcs_set_display_on_multi(&dsi_ctx);
3145
3146 mipi_dsi_msleep(&dsi_ctx, 20);
3147
3148 mipi_dsi_dcs_set_tear_on_multi(&dsi_ctx, MIPI_DSI_DCS_TEAR_MODE_VBLANK);
3149
3150 return dsi_ctx.accum_err;
3151}
3152
3153static const struct jadard_panel_desc dcltek_dt300250_desc = {
3154 .mode_4ln = &(const struct drm_display_mode) {
3155 .clock = (600 + 48 + 32 + 80) * (1600 + 18 + 6 + 23) * 60 / 1000,
3156
3157 .hdisplay = 600,
3158 .hsync_start = 600 + 48,
3159 .hsync_end = 600 + 48 + 32,
3160 .htotal = 600 + 48 + 32 + 80,
3161
3162 .vdisplay = 1600,
3163 .vsync_start = 1600 + 18,
3164 .vsync_end = 1600 + 18 + 6,
3165 .vtotal = 1600 + 18 + 6 + 23,
3166
3167 .width_mm = 83,
3168 .height_mm = 221,
3169 .type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED,
3170 },
3171 .lanes = 4,
3172 .format = MIPI_DSI_FMT_RGB888,
3173 .init = dcltek_dt300250_init_cmds,
3174};
3175
2934static int jadard_dsi_probe(struct mipi_dsi_device *dsi)3176static int jadard_dsi_probe(struct mipi_dsi_device *dsi)
2935{3177{
2936 struct device *dev = &dsi->dev;3178 struct device *dev = &dsi->dev;
@@ -2950,7 +3192,8 @@ static int jadard_dsi_probe(struct mipi_dsi_device *dsi) · 13 unmodified lines
2950 else3192 else
2951 dsi->mode_flags = MIPI_DSI_MODE_VIDEO |3193 dsi->mode_flags = MIPI_DSI_MODE_VIDEO |
2952 MIPI_DSI_MODE_VIDEO_BURST |3194 MIPI_DSI_MODE_VIDEO_BURST |
2953 MIPI_DSI_MODE_NO_EOT_PACKET;3195 MIPI_DSI_MODE_NO_EOT_PACKET |
3196 MIPI_DSI_MODE_LPM;
2954 3197
2955 dsi->format = desc->format;3198 dsi->format = desc->format;
2956 dsi->lanes = desc->lanes;3199 dsi->lanes = desc->lanes;
@@ -3036,6 +3279,10 @@ static const struct of_device_id jadard_of_match[] = { · 79 unmodified lines
3036 .compatible = "chongzhou,cz101b4001",3279 .compatible = "chongzhou,cz101b4001",
3037 .data = &cz101b4001_desc3280 .data = &cz101b4001_desc
3038 },3281 },
3282 {
3283 .compatible = "dcltek,dt300250",
3284 .data = &dcltek_dt300250_desc
3285 },
3039 {3286 {
3040 .compatible = "kingdisplay,kd101ne3-40ti",3287 .compatible = "kingdisplay,kd101ne3-40ti",
3041 .data = &kingdisplay_kd101ne3_40ti_desc3288 .data = &kingdisplay_kd101ne3_40ti_desc
drivers/gpu/drm/panel/panel-novatek-nt36536.c+1−3
@@ -429,11 +429,9 @@ static int novatek_probe(struct mipi_dsi_device *dsi) · 428 unmodified lines
429 ctx->dsi[i]->mode_flags = desc->mode_flags;429 ctx->dsi[i]->mode_flags = desc->mode_flags;
430 ctx->dsi[i]->dsc = &ctx->dsc;430 ctx->dsi[i]->dsc = &ctx->dsc;
431 ret = devm_mipi_dsi_attach(dev, ctx->dsi[i]);431 ret = devm_mipi_dsi_attach(dev, ctx->dsi[i]);
432 if (ret < 0) {432 if (ret < 0)
433 drm_panel_remove(&ctx->panel);
434 return dev_err_probe(dev, ret,433 return dev_err_probe(dev, ret,
435 "Failed to attach to DSI host\n");434 "Failed to attach to DSI host\n");
436 }
437 }435 }
438 436
439 if (desc->has_dcs_backlight) {437 if (desc->has_dcs_backlight) {
drivers/gpu/drm/panel/panel-simple.c+33−0
@@ -912,6 +912,36 @@ static const struct panel_desc ampire_am_800480l1tmqw_t00h = { · 911 unmodified lines
912 .connector_type = DRM_MODE_CONNECTOR_DPI,912 .connector_type = DRM_MODE_CONNECTOR_DPI,
913};913};
914 914
915static const struct display_timing ampire_am_800480n3tzqw_00h_timing = {
916 .pixelclock = {23000000, 25000000, 27000000},
917 .hactive = { 800, 800, 800 },
918 .hfront_porch = { 4, 8, 48 },
919 .hback_porch = { 4, 8, 48 },
920 .hsync_len = { 2, 8, 8 },
921 .vactive = { 480, 480, 480 },
922 .vfront_porch = { 4, 8, 12 },
923 .vback_porch = { 4, 8, 12 },
924 .vsync_len = { 2, 4, 8 },
925 .flags = DISPLAY_FLAGS_HSYNC_LOW | DISPLAY_FLAGS_VSYNC_LOW |
926 DISPLAY_FLAGS_DE_HIGH | DISPLAY_FLAGS_PIXDATA_POSEDGE |
927 DISPLAY_FLAGS_SYNC_POSEDGE,
928};
929
930static const struct panel_desc ampire_am_800480n3tzqw_00h = {
931 .timings = &ampire_am_800480n3tzqw_00h_timing,
932 .num_timings = 1,
933 .bpc = 8,
934 .size = {
935 .width = 108,
936 .height = 65,
937 },
938 .bus_format = MEDIA_BUS_FMT_RGB888_1X24,
939 .bus_flags = DRM_BUS_FLAG_DE_HIGH |
940 DRM_BUS_FLAG_PIXDATA_SAMPLE_NEGEDGE |
941 DRM_BUS_FLAG_SYNC_SAMPLE_NEGEDGE,
942 .connector_type = DRM_MODE_CONNECTOR_DPI,
943};
944
915static const struct panel_desc ampire_am800480r3tmqwa1h = {945static const struct panel_desc ampire_am800480r3tmqwa1h = {
916 .modes = &ampire_am800480r3tmqwa1h_mode,946 .modes = &ampire_am800480r3tmqwa1h_mode,
917 .num_modes = 1,947 .num_modes = 1,
@@ -5648,6 +5678,9 @@ static const struct of_device_id platform_of_match[] = { · 4730 unmodified lines
5648 }, {5678 }, {
5649 .compatible = "ampire,am-800480l1tmqw-t00h",5679 .compatible = "ampire,am-800480l1tmqw-t00h",
5650 .data = &ampire_am_800480l1tmqw_t00h,5680 .data = &ampire_am_800480l1tmqw_t00h,
5681 }, {
5682 .compatible = "ampire,am-800480n3tzqw-00h",
5683 .data = &ampire_am_800480n3tzqw_00h,
5651 }, {5684 }, {
5652 .compatible = "ampire,am800480r3tmqwa1h",5685 .compatible = "ampire,am800480r3tmqwa1h",
5653 .data = &ampire_am800480r3tmqwa1h,5686 .data = &ampire_am800480r3tmqwa1h,
drivers/gpu/drm/panel/panel-sitronix-st7703.c+96−0
@@ -47,6 +47,7 @@ · 46 unmodified lines
47#define ST7703_CMD_SETCABC 0xC847#define ST7703_CMD_SETCABC 0xC8
48#define ST7703_CMD_SETPANEL 0xCC48#define ST7703_CMD_SETPANEL 0xCC
49#define ST7703_CMD_SETGAMMA 0xE049#define ST7703_CMD_SETGAMMA 0xE0
50#define ST7703_CMD_UNKNOWN_E1 0xE1
50#define ST7703_CMD_SETEQ 0xE351#define ST7703_CMD_SETEQ 0xE3
51#define ST7703_CMD_SETGIP1 0xE952#define ST7703_CMD_SETGIP1 0xE9
52#define ST7703_CMD_SETGIP2 0xEA53#define ST7703_CMD_SETGIP2 0xEA
@@ -673,6 +674,100 @@ static const struct st7703_panel_desc gameforcechi_desc = { · 620 unmodified lines
673 .init_sequence = gameforcechi_init_sequence,674 .init_sequence = gameforcechi_init_sequence,
674};675};
675 676
677static void ayaneo_pocket_ds_lower_init_sequence(struct mipi_dsi_multi_context *dsi_ctx)
678{
679 /* Init sequence extracted from the AYANEO Pocket DS BSP kernel. */
680
681 mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETEXTC, 0xf1, 0x12,
682 0x87);
683 mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETDISP, 0x00, 0x01,
684 0x78);
685 mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETRGBIF, 0x10, 0x10,
686 0x28, 0x28, 0x03, 0xff, 0x00, 0x00, 0x00,
687 0x00);
688 mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETCYC, 0x80);
689 mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETBGP, 0x0a, 0x0a);
690 mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETVCOM, 0x90, 0x90);
691 mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETPOWER_EXT, 0x76,
692 0x22, 0xf0, 0x13);
693 mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETMIPI, 0x33, 0x81,
694 0x05, 0xf9, 0x0e, 0x0e, 0x20, 0x00, 0x00,
695 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 0x25,
696 0x00, 0x91, 0x0a, 0x00, 0x00, 0x01, 0x4f,
697 0x01, 0x00, 0x00, 0x37);
698 mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETVDC, 0x47);
699 mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_UNKNOWN_BF, 0x02, 0x10,
700 0x00, 0x80, 0x04);
701 mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETSCR, 0x73, 0x73,
702 0x50, 0x50, 0x00, 0x00, 0x12, 0x73, 0x00);
703 mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETPOWER, 0x55, 0x00,
704 0x32, 0x32, 0x77, 0xf1, 0xf7, 0xf7, 0xcc,
705 0xcc, 0x7f, 0x7f, 0x11, 0x11, 0x00, 0x00,
706 0x32);
707 mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETIO, 0xb8, 0x00,
708 0x0a, 0x10, 0x01, 0x09, 0x00, 0x00, 0xed,
709 0xc5, 0x00, 0xa5);
710 mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETCABC, 0x10, 0x40,
711 0x1e, 0x03);
712 mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETPANEL, 0x0b);
713 mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETGAMMA, 0x00, 0x00,
714 0x00, 0x25, 0x31, 0x3f, 0x26, 0x29, 0x04,
715 0x08, 0x0d, 0x0e, 0x12, 0x0f, 0x11, 0x12,
716 0x18, 0x00, 0x00, 0x00, 0x25, 0x31, 0x3f,
717 0x26, 0x29, 0x04, 0x08, 0x0d, 0x0e, 0x12,
718 0x0f, 0x11, 0x12, 0x18);
719 mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_UNKNOWN_E1, 0x11, 0x11,
720 0x91, 0x00, 0x00, 0x00, 0x00);
721 mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETEQ, 0x07, 0x07,
722 0x0b, 0x0b, 0x0b, 0x0b, 0x00, 0x00, 0x00,
723 0x00, 0xff, 0x84, 0xc0, 0x10);
724 mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETGIP1, 0xc8, 0x10,
725 0x04, 0x04, 0x02, 0x80, 0x81, 0x12, 0x31,
726 0x23, 0x2f, 0x80, 0x80, 0x81, 0x27, 0x20,
727 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00,
728 0x00, 0x0f, 0x00, 0x00, 0x00, 0x44, 0x00,
729 0x88, 0xff, 0x00, 0x22, 0x44, 0x66, 0x88,
730 0x88, 0x88, 0x55, 0x11, 0x88, 0xff, 0x11,
731 0x33, 0x55, 0x77, 0x88, 0x88, 0x88, 0x00,
732 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
733 0x00, 0x00, 0x00, 0x00, 0x00);
734 mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETGIP2, 0x00, 0x00,
735 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
736 0x00, 0x00, 0x00, 0x11, 0x55, 0xff, 0x88,
737 0x77, 0x55, 0x33, 0x11, 0x88, 0x88, 0x88,
738 0x00, 0x44, 0xff, 0x88, 0x66, 0x44, 0x22,
739 0x00, 0x88, 0x88, 0x88, 0x23, 0x00, 0x00,
740 0x00, 0xec, 0x00, 0x00, 0x00, 0x00, 0x00,
741 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
742 0x00, 0x00, 0x00, 0x20, 0x80, 0x81, 0x00,
743 0x00, 0x00, 0x00);
744 mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_UNKNOWN_EF, 0xff, 0xff,
745 0x01);
746}
747
748static const struct drm_display_mode ayaneo_pocket_ds_lower_mode = {
749 .hdisplay = 768,
750 .hsync_start = 768 + 110,
751 .hsync_end = 768 + 110 + 45,
752 .htotal = 768 + 110 + 45 + 110,
753 .vdisplay = 1024,
754 .vsync_start = 1024 + 18,
755 .vsync_end = 1024 + 18 + 6,
756 .vtotal = 1024 + 18 + 6 + 16,
757 .clock = 65946,
758 .width_mm = 76,
759 .height_mm = 102,
760};
761
762static const struct st7703_panel_desc ayaneo_pocket_ds_lower_desc = {
763 .mode = &ayaneo_pocket_ds_lower_mode,
764 .lanes = 4,
765 .mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST |
766 MIPI_DSI_CLOCK_NON_CONTINUOUS | MIPI_DSI_MODE_LPM,
767 .format = MIPI_DSI_FMT_RGB888,
768 .init_sequence = ayaneo_pocket_ds_lower_init_sequence,
769};
770
676static int st7703_enable(struct drm_panel *panel)771static int st7703_enable(struct drm_panel *panel)
677{772{
678 struct st7703 *ctx = panel_to_st7703(panel);773 struct st7703 *ctx = panel_to_st7703(panel);
@@ -916,6 +1011,7 @@ static void st7703_remove(struct mipi_dsi_device *dsi) · 237 unmodified lines
916 1011
917static const struct of_device_id st7703_of_match[] = {1012static const struct of_device_id st7703_of_match[] = {
918 { .compatible = "anbernic,rg353v-panel-v2", .data = &rg353v2_desc },1013 { .compatible = "anbernic,rg353v-panel-v2", .data = &rg353v2_desc },
1014 { .compatible = "ayaneo,pocket-ds-lower-panel", .data = &ayaneo_pocket_ds_lower_desc },
919 { .compatible = "gameforce,chi-panel", .data = &gameforcechi_desc },1015 { .compatible = "gameforce,chi-panel", .data = &gameforcechi_desc },
920 { .compatible = "powkiddy,rgb10max3-panel", .data = &rgb10max3_panel_desc },1016 { .compatible = "powkiddy,rgb10max3-panel", .data = &rgb10max3_panel_desc },
921 { .compatible = "powkiddy,rgb30-panel", .data = &rgb30panel_desc },1017 { .compatible = "powkiddy,rgb30-panel", .data = &rgb30panel_desc },
drivers/gpu/drm/panel/panel-tdo-tl070wsh30.c+12−28
@@ -35,6 +35,7 @@ struct tdo_tl070wsh30_panel *to_tdo_tl070wsh30_panel(struct drm_panel *panel) · 34 unmodified lines
35static int tdo_tl070wsh30_panel_prepare(struct drm_panel *panel)35static int tdo_tl070wsh30_panel_prepare(struct drm_panel *panel)
36{36{
37 struct tdo_tl070wsh30_panel *tdo_tl070wsh30 = to_tdo_tl070wsh30_panel(panel);37 struct tdo_tl070wsh30_panel *tdo_tl070wsh30 = to_tdo_tl070wsh30_panel(panel);
38 struct mipi_dsi_multi_context dsi_ctx = { .dsi = tdo_tl070wsh30->link };
38 int err;39 int err;
39 40
40 err = regulator_enable(tdo_tl070wsh30->supply);41 err = regulator_enable(tdo_tl070wsh30->supply);
@@ -51,44 +52,27 @@ static int tdo_tl070wsh30_panel_prepare(struct drm_panel *panel) · 10 unmodified lines
51 52
52 msleep(200);53 msleep(200);
53 54
54 err = mipi_dsi_dcs_exit_sleep_mode(tdo_tl070wsh30->link);55 mipi_dsi_dcs_exit_sleep_mode_multi(&dsi_ctx);
55 if (err < 0) {56 mipi_dsi_msleep(&dsi_ctx, 200);
56 dev_err(panel->dev, "failed to exit sleep mode: %d\n", err);57 mipi_dsi_dcs_set_display_on_multi(&dsi_ctx);
57 regulator_disable(tdo_tl070wsh30->supply);58 mipi_dsi_msleep(&dsi_ctx, 20);
58 return err;
59 }
60
61 msleep(200);
62 59
63 err = mipi_dsi_dcs_set_display_on(tdo_tl070wsh30->link);60 if (dsi_ctx.accum_err)
64 if (err < 0) {
65 dev_err(panel->dev, "failed to set display on: %d\n", err);
66 regulator_disable(tdo_tl070wsh30->supply);61 regulator_disable(tdo_tl070wsh30->supply);
67 return err;
68 }
69
70 msleep(20);
71 62
72 return 0;63 return dsi_ctx.accum_err;
73}64}
74 65
75static int tdo_tl070wsh30_panel_unprepare(struct drm_panel *panel)66static int tdo_tl070wsh30_panel_unprepare(struct drm_panel *panel)
76{67{
77 struct tdo_tl070wsh30_panel *tdo_tl070wsh30 = to_tdo_tl070wsh30_panel(panel);68 struct tdo_tl070wsh30_panel *tdo_tl070wsh30 = to_tdo_tl070wsh30_panel(panel);
78 int err;69 struct mipi_dsi_multi_context dsi_ctx = { .dsi = tdo_tl070wsh30->link };
79
80 err = mipi_dsi_dcs_set_display_off(tdo_tl070wsh30->link);
81 if (err < 0)
82 dev_err(panel->dev, "failed to set display off: %d\n", err);
83 70
71 mipi_dsi_dcs_set_display_off_multi(&dsi_ctx);
72 /* Reset error to continue power-down sequence even if display off failed */
73 dsi_ctx.accum_err = 0;
84 usleep_range(10000, 11000);74 usleep_range(10000, 11000);
85 75 mipi_dsi_dcs_enter_sleep_mode_multi(&dsi_ctx);
86 err = mipi_dsi_dcs_enter_sleep_mode(tdo_tl070wsh30->link);
87 if (err < 0) {
88 dev_err(panel->dev, "failed to enter sleep mode: %d\n", err);
89 return err;
90 }
91
92 usleep_range(10000, 11000);76 usleep_range(10000, 11000);
93 77
94 regulator_disable(tdo_tl070wsh30->supply);78 regulator_disable(tdo_tl070wsh30->supply);
drivers/gpu/drm/panthor/panthor_drv.c+1−1
@@ -1824,7 +1824,7 @@ static int panthor_probe(struct platform_device *pdev) · 1823 unmodified lines
1824 ptdev = devm_drm_dev_alloc(&pdev->dev, &panthor_drm_driver,1824 ptdev = devm_drm_dev_alloc(&pdev->dev, &panthor_drm_driver,
1825 struct panthor_device, base);1825 struct panthor_device, base);
1826 if (IS_ERR(ptdev))1826 if (IS_ERR(ptdev))
1827 return -ENOMEM;1827 return PTR_ERR(ptdev);
1828 1828
1829 platform_set_drvdata(pdev, ptdev);1829 platform_set_drvdata(pdev, ptdev);
1830 1830
drivers/gpu/drm/panthor/panthor_fw.c+15−7
@@ -697,7 +697,8 @@ static int panthor_fw_read_build_info(struct panthor_device *ptdev, · 696 unmodified lines
697 return ret;697 return ret;
698 698
699 if (hdr.meta_start > fw->size ||699 if (hdr.meta_start > fw->size ||
700 hdr.meta_start + hdr.meta_size > fw->size) {700 hdr.meta_size > fw->size - hdr.meta_start ||
701 hdr.meta_size <= header_len) {
701 drm_err(&ptdev->base, "Firmware build info corrupt\n");702 drm_err(&ptdev->base, "Firmware build info corrupt\n");
702 /* We don't need the build info, so continue */703 /* We don't need the build info, so continue */
703 return 0;704 return 0;
@@ -877,14 +878,15 @@ static int panthor_init_cs_iface(struct panthor_device *ptdev, · 173 unmodified lines
877 struct panthor_fw_csg_iface *csg_iface = panthor_fw_get_csg_iface(ptdev, csg_idx);878 struct panthor_fw_csg_iface *csg_iface = panthor_fw_get_csg_iface(ptdev, csg_idx);
878 struct panthor_fw_cs_iface *cs_iface = &ptdev->fw->iface.streams[csg_idx][cs_idx];879 struct panthor_fw_cs_iface *cs_iface = &ptdev->fw->iface.streams[csg_idx][cs_idx];
879 u64 shared_section_sz = panthor_kernel_bo_size(ptdev->fw->shared_section->mem);880 u64 shared_section_sz = panthor_kernel_bo_size(ptdev->fw->shared_section->mem);
880 u32 iface_offset = CSF_GROUP_CONTROL_OFFSET +881 u64 iface_offset = CSF_GROUP_CONTROL_OFFSET +
881 (csg_idx * glb_iface->control->group_stride) +882 ((u64)csg_idx * glb_iface->control->group_stride) +
882 CSF_STREAM_CONTROL_OFFSET +883 CSF_STREAM_CONTROL_OFFSET +
883 (cs_idx * csg_iface->control->stream_stride);884 ((u64)cs_idx * csg_iface->control->stream_stride);
884 struct panthor_fw_cs_iface *first_cs_iface =885 struct panthor_fw_cs_iface *first_cs_iface =
885 panthor_fw_get_cs_iface(ptdev, 0, 0);886 panthor_fw_get_cs_iface(ptdev, 0, 0);
886 887
887 if (iface_offset + sizeof(*cs_iface) >= shared_section_sz)888 if (iface_offset > shared_section_sz ||
889 sizeof(*cs_iface->control) > shared_section_sz - iface_offset)
888 return -EINVAL;890 return -EINVAL;
889 891
890 spin_lock_init(&cs_iface->lock);892 spin_lock_init(&cs_iface->lock);
@@ -932,10 +934,12 @@ static int panthor_init_csg_iface(struct panthor_device *ptdev, · 41 unmodified lines
932 struct panthor_fw_global_iface *glb_iface = panthor_fw_get_glb_iface(ptdev);934 struct panthor_fw_global_iface *glb_iface = panthor_fw_get_glb_iface(ptdev);
933 struct panthor_fw_csg_iface *csg_iface = &ptdev->fw->iface.groups[csg_idx];935 struct panthor_fw_csg_iface *csg_iface = &ptdev->fw->iface.groups[csg_idx];
934 u64 shared_section_sz = panthor_kernel_bo_size(ptdev->fw->shared_section->mem);936 u64 shared_section_sz = panthor_kernel_bo_size(ptdev->fw->shared_section->mem);
935 u32 iface_offset = CSF_GROUP_CONTROL_OFFSET + (csg_idx * glb_iface->control->group_stride);937 u64 iface_offset = CSF_GROUP_CONTROL_OFFSET +
938 ((u64)csg_idx * glb_iface->control->group_stride);
936 unsigned int i;939 unsigned int i;
937 940
938 if (iface_offset + sizeof(*csg_iface) >= shared_section_sz)941 if (iface_offset > shared_section_sz ||
942 sizeof(*csg_iface->control) > shared_section_sz - iface_offset)
939 return -EINVAL;943 return -EINVAL;
940 944
941 spin_lock_init(&csg_iface->lock);945 spin_lock_init(&csg_iface->lock);
@@ -985,11 +989,15 @@ static u32 panthor_get_instr_features(struct panthor_device *ptdev) · 43 unmodified lines
985static int panthor_fw_init_ifaces(struct panthor_device *ptdev)989static int panthor_fw_init_ifaces(struct panthor_device *ptdev)
986{990{
987 struct panthor_fw_global_iface *glb_iface = &ptdev->fw->iface.global;991 struct panthor_fw_global_iface *glb_iface = &ptdev->fw->iface.global;
992 u64 shared_section_sz = panthor_kernel_bo_size(ptdev->fw->shared_section->mem);
988 unsigned int i;993 unsigned int i;
989 994
990 if (!ptdev->fw->shared_section->mem->kmap)995 if (!ptdev->fw->shared_section->mem->kmap)
991 return -EINVAL;996 return -EINVAL;
992 997
998 if (sizeof(*glb_iface->control) > shared_section_sz)
999 return -EINVAL;
1000
993 spin_lock_init(&glb_iface->lock);1001 spin_lock_init(&glb_iface->lock);
994 glb_iface->control = ptdev->fw->shared_section->mem->kmap;1002 glb_iface->control = ptdev->fw->shared_section->mem->kmap;
995 1003
drivers/gpu/drm/panthor/panthor_mmu.c+10−1
@@ -306,10 +306,13 @@ struct panthor_vm { · 305 unmodified lines
306 /** @kernel_auto_va.start: Start of the automatic VA-range for kernel BOs. */306 /** @kernel_auto_va.start: Start of the automatic VA-range for kernel BOs. */
307 u64 start;307 u64 start;
308 308
309 /** @kernel_auto_va.size: Size of the automatic VA-range for kernel BOs. */309 /** @kernel_auto_va.end: End of the automatic VA-range for kernel BOs. */
310 u64 end;310 u64 end;
311 } kernel_auto_va;311 } kernel_auto_va;
312 312
313 /** @user_va_range: Upper boundary of VAs VM users can map objects against. */
314 u64 user_va_range;
315
313 /** @as: Address space related fields. */316 /** @as: Address space related fields. */
314 struct {317 struct {
315 /**318 /**
@@ -2892,6 +2895,8 @@ panthor_vm_create(struct panthor_device *ptdev, bool for_mcu, · 2576 unmodified lines
2892 va_range = full_va_range;2895 va_range = full_va_range;
2893 }2896 }
2894 2897
2898 vm->user_va_range = kernel_va_start;
2899
2895 mutex_init(&vm->mm_lock);2900 mutex_init(&vm->mm_lock);
2896 drm_mm_init(&vm->mm, kernel_va_start, kernel_va_size);2901 drm_mm_init(&vm->mm, kernel_va_start, kernel_va_size);
2897 vm->kernel_auto_va.start = auto_kernel_va_start;2902 vm->kernel_auto_va.start = auto_kernel_va_start;
@@ -2980,6 +2985,10 @@ panthor_vm_bind_prepare_op_ctx(struct drm_file *file, · 82 unmodified lines
2980 if (!IS_ALIGNED(op->va | op->size | op->bo_offset, vm_pgsz))2985 if (!IS_ALIGNED(op->va | op->size | op->bo_offset, vm_pgsz))
2981 return -EINVAL;2986 return -EINVAL;
2982 2987
2988 /* We don't allow mappings that overlap with kbo's reserved range */
2989 if (range_overflows(op->va, op->size, vm->user_va_range))
2990 return -EINVAL;
2991
2983 switch (op->flags & DRM_PANTHOR_VM_BIND_OP_TYPE_MASK) {2992 switch (op->flags & DRM_PANTHOR_VM_BIND_OP_TYPE_MASK) {
2984 case DRM_PANTHOR_VM_BIND_OP_TYPE_MAP:2993 case DRM_PANTHOR_VM_BIND_OP_TYPE_MAP:
2985 if (!(op->flags & DRM_PANTHOR_VM_BIND_OP_MAP_SPARSE)) {2994 if (!(op->flags & DRM_PANTHOR_VM_BIND_OP_MAP_SPARSE)) {
drivers/gpu/drm/solomon/ssd130x.c+59−6
@@ -14,6 +14,7 @@ · 13 unmodified lines
14#include <linux/bits.h>14#include <linux/bits.h>
15#include <linux/delay.h>15#include <linux/delay.h>
16#include <linux/gpio/consumer.h>16#include <linux/gpio/consumer.h>
17#include <linux/math.h>
17#include <linux/property.h>18#include <linux/property.h>
18#include <linux/pwm.h>19#include <linux/pwm.h>
19#include <linux/regulator/consumer.h>20#include <linux/regulator/consumer.h>
@@ -140,6 +141,11 @@ · 120 unmodified lines
140#define SSD133X_SET_PRECHARGE_VOLTAGE 0xbb141#define SSD133X_SET_PRECHARGE_VOLTAGE 0xbb
141#define SSD133X_SET_VCOMH_VOLTAGE 0xbe142#define SSD133X_SET_VCOMH_VOLTAGE 0xbe
142 143
144/* ssd133x A/B/C channel contrast at full brightness (white balance) */
145#define SSD133X_DEFAULT_CONTRAST_A 0x91
146#define SSD133X_DEFAULT_CONTRAST_B 0x50
147#define SSD133X_DEFAULT_CONTRAST_C 0x7d
148
143#define MAX_CONTRAST 255149#define MAX_CONTRAST 255
144 150
145const struct ssd130x_deviceinfo ssd130x_variants[] = {151const struct ssd130x_deviceinfo ssd130x_variants[] = {
@@ -582,12 +588,37 @@ static int ssd132x_init(struct ssd130x_device *ssd130x) · 436 unmodified lines
582 return ssd130x_run_cmd_seq(ssd130x, cmds);588 return ssd130x_run_cmd_seq(ssd130x, cmds);
583}589}
584 590
591/* Scale a channel's white-balance calibration contrast by the requested brightness */
592static u8 ssd130x_scale_contrast(u8 calibration, u32 brightness)
593{
594 return DIV_ROUND_CLOSEST(calibration * brightness, MAX_CONTRAST);
595}
596
597/*
598 * The A/B/C contrast channels drive sub-pixels whose OLED materials differ
599 * in luminous efficiency, so the per-channel values are a white-balance
600 * calibration. Scale them by the requested brightness instead of
601 * overwriting them, to keep the white point while dimming.
602 */
603static int ssd133x_set_contrast(struct ssd130x_device *ssd130x, u32 brightness)
604{
605 const u8 cmds[] = {
606 2, SSD133X_CONTRAST_A,
607 ssd130x_scale_contrast(SSD133X_DEFAULT_CONTRAST_A, brightness),
608 2, SSD133X_CONTRAST_B,
609 ssd130x_scale_contrast(SSD133X_DEFAULT_CONTRAST_B, brightness),
610 2, SSD133X_CONTRAST_C,
611 ssd130x_scale_contrast(SSD133X_DEFAULT_CONTRAST_C, brightness),
612 0,
613 };
614
615 return ssd130x_run_cmd_seq(ssd130x, cmds);
616}
617
585static int ssd133x_init(struct ssd130x_device *ssd130x)618static int ssd133x_init(struct ssd130x_device *ssd130x)
586{619{
620 int ret;
587 const u8 cmds[] = {621 const u8 cmds[] = {
588 2, SSD133X_CONTRAST_A, 0x91,
589 2, SSD133X_CONTRAST_B, 0x50,
590 2, SSD133X_CONTRAST_C, 0x7d,
591 2, SSD133X_SET_MASTER_CURRENT, 0x06,622 2, SSD133X_SET_MASTER_CURRENT, 0x06,
592 3, SSD133X_SET_COL_RANGE, 0x00, ssd130x->width - 1,623 3, SSD133X_SET_COL_RANGE, 0x00, ssd130x->width - 1,
593 3, SSD133X_SET_ROW_RANGE, 0x00, ssd130x->height - 1,624 3, SSD133X_SET_ROW_RANGE, 0x00, ssd130x->height - 1,
@@ -614,6 +645,10 @@ static int ssd133x_init(struct ssd130x_device *ssd130x) · 20 unmodified lines
614 0,645 0,
615 };646 };
616 647
648 ret = ssd133x_set_contrast(ssd130x, ssd130x->contrast);
649 if (ret < 0)
650 return ret;
651
617 return ssd130x_run_cmd_seq(ssd130x, cmds);652 return ssd130x_run_cmd_seq(ssd130x, cmds);
618}653}
619 654
@@ -1676,8 +1711,25 @@ static int ssd130x_update_bl(struct backlight_device *bdev) · 1056 unmodified lines
1676 return 0;1711 return 0;
1677}1712}
1678 1713
1679static const struct backlight_ops ssd130xfb_bl_ops = {1714static int ssd133x_update_bl(struct backlight_device *bdev)
1680 .update_status = ssd130x_update_bl,1715{
1716 struct ssd130x_device *ssd130x = bl_get_data(bdev);
1717
1718 ssd130x->contrast = backlight_get_brightness(bdev);
1719
1720 return ssd133x_set_contrast(ssd130x, ssd130x->contrast);
1721}
1722
1723static const struct backlight_ops ssd130xfb_bl_ops[] = {
1724 [SSD130X_FAMILY] = {
1725 .update_status = ssd130x_update_bl,
1726 },
1727 [SSD132X_FAMILY] = {
1728 .update_status = ssd130x_update_bl,
1729 },
1730 [SSD133X_FAMILY] = {
1731 .update_status = ssd133x_update_bl,
1732 },
1681};1733};
1682 1734
1683static void ssd130x_parse_properties(struct ssd130x_device *ssd130x)1735static void ssd130x_parse_properties(struct ssd130x_device *ssd130x)
@@ -1884,7 +1936,8 @@ struct ssd130x_device *ssd130x_probe(struct device *dev, struct regmap *regmap) · 200 unmodified lines
1884 return ERR_PTR(ret);1936 return ERR_PTR(ret);
1885 1937
1886 bl = devm_backlight_device_register(dev, dev_name(dev), dev, ssd130x,1938 bl = devm_backlight_device_register(dev, dev_name(dev), dev, ssd130x,
1887 &ssd130xfb_bl_ops, NULL);1939 &ssd130xfb_bl_ops[ssd130x->device_info->family_id],
1940 NULL);
1888 if (IS_ERR(bl))1941 if (IS_ERR(bl))
1889 return ERR_PTR(dev_err_probe(dev, PTR_ERR(bl),1942 return ERR_PTR(dev_err_probe(dev, PTR_ERR(bl),
1890 "Unable to register backlight device\n"));1943 "Unable to register backlight device\n"));
drivers/gpu/drm/sun4i/sun4i_crtc.c+1−1
@@ -208,7 +208,7 @@ struct sun4i_crtc *sun4i_crtc_init(struct drm_device *drm, · 207 unmodified lines
208 planes = sunxi_engine_layers_init(drm, engine);208 planes = sunxi_engine_layers_init(drm, engine);
209 if (IS_ERR(planes)) {209 if (IS_ERR(planes)) {
210 dev_err(drm->dev, "Couldn't create the planes\n");210 dev_err(drm->dev, "Couldn't create the planes\n");
211 return NULL;211 return ERR_CAST(planes);
212 }212 }
213 213
214 /* find primary and cursor planes for drm_crtc_init_with_planes */214 /* find primary and cursor planes for drm_crtc_init_with_planes */
drivers/gpu/drm/sun4i/sun4i_drv.c+3−0
@@ -289,6 +289,8 @@ static void sun4i_drv_traverse_endpoints(struct endpoint_list *list, · 288 unmodified lines
289 289
290 kfifo_put(&list->fifo, remote);290 kfifo_put(&list->fifo, remote);
291 }291 }
292
293 of_node_put(port);
292}294}
293 295
294static int sun4i_drv_add_endpoints(struct device *dev,296static int sun4i_drv_add_endpoints(struct device *dev,
@@ -394,6 +396,7 @@ static int sun4i_drv_probe(struct platform_device *pdev) · 99 unmodified lines
394 /* process this endpoint */396 /* process this endpoint */
395 ret = sun4i_drv_add_endpoints(&pdev->dev, &list, &match,397 ret = sun4i_drv_add_endpoints(&pdev->dev, &list, &match,
396 endpoint);398 endpoint);
399 of_node_put(endpoint);
397 400
398 /* sun4i_drv_add_endpoints can fail to allocate memory */401 /* sun4i_drv_add_endpoints can fail to allocate memory */
399 if (ret < 0)402 if (ret < 0)
drivers/gpu/drm/sun4i/sun4i_framebuffer.c+2−17
@@ -14,24 +14,8 @@ · 13 unmodified lines
14#include "sun4i_drv.h"14#include "sun4i_drv.h"
15#include "sun4i_framebuffer.h"15#include "sun4i_framebuffer.h"
16 16
17static int sun4i_de_atomic_check(struct drm_device *dev,
18 struct drm_atomic_commit *state)
19{
20 int ret;
21
22 ret = drm_atomic_helper_check_modeset(dev, state);
23 if (ret)
24 return ret;
25
26 ret = drm_atomic_normalize_zpos(dev, state);
27 if (ret)
28 return ret;
29
30 return drm_atomic_helper_check_planes(dev, state);
31}
32
33static const struct drm_mode_config_funcs sun4i_de_mode_config_funcs = {17static const struct drm_mode_config_funcs sun4i_de_mode_config_funcs = {
34 .atomic_check = sun4i_de_atomic_check,18 .atomic_check = drm_atomic_helper_check,
35 .atomic_commit = drm_atomic_helper_commit,19 .atomic_commit = drm_atomic_helper_commit,
36 .fb_create = drm_gem_fb_create,20 .fb_create = drm_gem_fb_create,
37};21};
@@ -46,6 +30,7 @@ void sun4i_framebuffer_init(struct drm_device *drm) · 8 unmodified lines
46 30
47 drm->mode_config.max_width = 8192;31 drm->mode_config.max_width = 8192;
48 drm->mode_config.max_height = 8192;32 drm->mode_config.max_height = 8192;
33 drm->mode_config.normalize_zpos = true;
49 34
50 drm->mode_config.funcs = &sun4i_de_mode_config_funcs;35 drm->mode_config.funcs = &sun4i_de_mode_config_funcs;
51 drm->mode_config.helper_private = &sun4i_de_mode_config_helpers;36 drm->mode_config.helper_private = &sun4i_de_mode_config_helpers;
drivers/gpu/drm/sun4i/sun4i_hdmi_enc.c+1−1
@@ -160,7 +160,7 @@ static void sun4i_hdmi_enable(struct drm_encoder *encoder, · 159 unmodified lines
160 160
161 drm_atomic_helper_connector_hdmi_update_infoframes(connector, state);161 drm_atomic_helper_connector_hdmi_update_infoframes(connector, state);
162 162
163 val |= SUN4I_HDMI_PKT_CTRL_TYPE(0, SUN4I_HDMI_PKT_AVI);163 val = SUN4I_HDMI_PKT_CTRL_TYPE(0, SUN4I_HDMI_PKT_AVI);
164 val |= SUN4I_HDMI_PKT_CTRL_TYPE(1, SUN4I_HDMI_PKT_END);164 val |= SUN4I_HDMI_PKT_CTRL_TYPE(1, SUN4I_HDMI_PKT_END);
165 writel(val, hdmi->base + SUN4I_HDMI_PKT_CTRL_REG(0));165 writel(val, hdmi->base + SUN4I_HDMI_PKT_CTRL_REG(0));
166 166
drivers/gpu/drm/sun4i/sun4i_tcon.c+12−10
@@ -717,9 +717,11 @@ void sun4i_tcon_mode_set(struct sun4i_tcon *tcon, · 716 unmodified lines
717 case DRM_MODE_ENCODER_DSI:717 case DRM_MODE_ENCODER_DSI:
718 /* DSI is tied to special case of CPU interface */718 /* DSI is tied to special case of CPU interface */
719 sun4i_tcon0_mode_set_cpu(tcon, encoder, mode);719 sun4i_tcon0_mode_set_cpu(tcon, encoder, mode);
720 sun4i_tcon_set_mux(tcon, 0, encoder);
720 break;721 break;
721 case DRM_MODE_ENCODER_LVDS:722 case DRM_MODE_ENCODER_LVDS:
722 sun4i_tcon0_mode_set_lvds(tcon, encoder, mode);723 sun4i_tcon0_mode_set_lvds(tcon, encoder, mode);
724 sun4i_tcon_set_mux(tcon, 0, encoder);
723 break;725 break;
724 case DRM_MODE_ENCODER_NONE:726 case DRM_MODE_ENCODER_NONE:
725 sun4i_tcon0_mode_set_rgb(tcon, encoder, mode);727 sun4i_tcon0_mode_set_rgb(tcon, encoder, mode);
@@ -970,6 +972,7 @@ static int sun4i_tcon_of_get_id_from_port(struct device_node *port) · 244 unmodified lines
970 continue;972 continue;
971 973
972 ret = of_property_read_u32(remote, "reg", &reg);974 ret = of_property_read_u32(remote, "reg", &reg);
975 of_node_put(remote);
973 if (ret)976 if (ret)
974 continue;977 continue;
975 978
@@ -1409,7 +1412,7 @@ static int sun8i_r40_tcon_tv_set_mux(struct sun4i_tcon *tcon, · 433 unmodified lines
1409{1412{
1410 struct device_node *port, *remote;1413 struct device_node *port, *remote;
1411 struct platform_device *pdev;1414 struct platform_device *pdev;
1412 int id, ret;1415 int id, ret = 0;
1413 1416
1414 /* find TCON TOP platform device and TCON id */1417 /* find TCON TOP platform device and TCON id */
1415 1418
@@ -1432,21 +1435,20 @@ static int sun8i_r40_tcon_tv_set_mux(struct sun4i_tcon *tcon, · 16 unmodified lines
1432 if (IS_ENABLED(CONFIG_DRM_SUN8I_TCON_TOP) &&1435 if (IS_ENABLED(CONFIG_DRM_SUN8I_TCON_TOP) &&
1433 encoder->encoder_type == DRM_MODE_ENCODER_TMDS) {1436 encoder->encoder_type == DRM_MODE_ENCODER_TMDS) {
1434 ret = sun8i_tcon_top_set_hdmi_src(&pdev->dev, id);1437 ret = sun8i_tcon_top_set_hdmi_src(&pdev->dev, id);
1435 if (ret) {1438 if (ret)
1436 put_device(&pdev->dev);1439 goto out_put_device;
1437 return ret;
1438 }
1439 }1440 }
1440 1441
1441 if (IS_ENABLED(CONFIG_DRM_SUN8I_TCON_TOP)) {1442 if (IS_ENABLED(CONFIG_DRM_SUN8I_TCON_TOP)) {
1442 ret = sun8i_tcon_top_de_config(&pdev->dev, tcon->id, id);1443 ret = sun8i_tcon_top_de_config(&pdev->dev, tcon->id, id);
1443 if (ret) {1444 if (ret)
1444 put_device(&pdev->dev);1445 goto out_put_device;
1445 return ret;
1446 }
1447 }1446 }
1448 1447
1449 return 0;1448out_put_device:
1449 put_device(&pdev->dev);
1450
1451 return ret;
1450}1452}
1451 1453
1452static const struct sun4i_tcon_quirks sun4i_a10_quirks = {1454static const struct sun4i_tcon_quirks sun4i_a10_quirks = {
drivers/gpu/drm/sun4i/sun8i_dw_hdmi.c+2−0
@@ -86,6 +86,8 @@ static u32 sun8i_dw_hdmi_find_possible_crtcs(struct drm_device *drm, · 85 unmodified lines
86 of_node_put(remote_port);86 of_node_put(remote_port);
87 }87 }
88 }88 }
89
90 of_node_put(port);
89 } else {91 } else {
90 crtcs = drm_of_find_possible_crtcs(drm, node);92 crtcs = drm_of_find_possible_crtcs(drm, node);
91 }93 }
drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c+1−1
@@ -91,7 +91,7 @@ static const struct dw_hdmi_mpll_config sun50i_h6_mpll_cfg[] = { · 90 unmodified lines
91 },91 },
92 }, {92 }, {
93 594000000, {93 594000000, {
94 { 0x1a40, 0x0003 },94 { 0x1a7c, 0x0003 },
95 { 0x3b4c, 0x0003 },95 { 0x3b4c, 0x0003 },
96 { 0x5a64, 0x0003 },96 { 0x5a64, 0x0003 },
97 },97 },
drivers/gpu/drm/sun4i/sun8i_mixer.c+1−1
@@ -785,7 +785,7 @@ static const struct sun8i_mixer_cfg sun8i_v3s_mixer_cfg = { · 784 unmodified lines
785 .de_type = SUN8I_MIXER_DE2,785 .de_type = SUN8I_MIXER_DE2,
786 .vi_scaler_num = 2,786 .vi_scaler_num = 2,
787 .scaler_mask = 0x3,787 .scaler_mask = 0x3,
788 .scanline_yuv = 2048,788 .scanline_yuv = 1024,
789 },789 },
790 .de_type = SUN8I_MIXER_DE2,790 .de_type = SUN8I_MIXER_DE2,
791 .mod_rate = 150000000,791 .mod_rate = 150000000,
drivers/gpu/drm/sun4i/sun8i_tcon_top.c+59−12
@@ -25,6 +25,49 @@ static bool sun8i_tcon_top_node_is_tcon_top(struct device_node *node) · 24 unmodified lines
25 return !!of_match_node(sun8i_tcon_top_of_table, node);25 return !!of_match_node(sun8i_tcon_top_of_table, node);
26}26}
27 27
28static unsigned int sun8i_tcon_top_get_tcon_map(struct device_node *node)
29{
30 static const u32 out_ports[] = {
31 TCON_TOP_MIXER0_OUT_PORT,
32 TCON_TOP_MIXER1_OUT_PORT,
33 };
34 unsigned int i, map = 0;
35
36 for (i = 0; i < ARRAY_SIZE(out_ports); i++) {
37 struct device_node *port;
38
39 port = of_graph_get_port_by_id(node, out_ports[i]);
40 if (!port)
41 continue;
42
43 for_each_of_graph_port_endpoint(port, ep) {
44 struct of_endpoint endpoint;
45
46 if (of_graph_parse_endpoint(ep, &endpoint))
47 continue;
48
49 if (endpoint.id < TCON_TOP_PORT_TCON_NUM)
50 map |= BIT(endpoint.id);
51 }
52
53 of_node_put(port);
54 }
55
56 return map;
57}
58
59static unsigned int sun8i_tcon_top_park_index(struct sun8i_tcon_top *tcon_top,
60 int tcon)
61{
62 unsigned int candidates;
63
64 candidates = tcon_top->tcon_map & ~BIT(tcon);
65 if (!candidates)
66 candidates = GENMASK(TCON_TOP_PORT_TCON_NUM - 1, 0) & ~BIT(tcon);
67
68 return ffs(candidates) - 1;
69}
70
28int sun8i_tcon_top_set_hdmi_src(struct device *dev, int tcon)71int sun8i_tcon_top_set_hdmi_src(struct device *dev, int tcon)
29{72{
30 struct sun8i_tcon_top *tcon_top = dev_get_drvdata(dev);73 struct sun8i_tcon_top *tcon_top = dev_get_drvdata(dev);
@@ -57,6 +100,7 @@ EXPORT_SYMBOL(sun8i_tcon_top_set_hdmi_src); · 26 unmodified lines
57int sun8i_tcon_top_de_config(struct device *dev, int mixer, int tcon)100int sun8i_tcon_top_de_config(struct device *dev, int mixer, int tcon)
58{101{
59 struct sun8i_tcon_top *tcon_top = dev_get_drvdata(dev);102 struct sun8i_tcon_top *tcon_top = dev_get_drvdata(dev);
103 u32 mixer_msk, other_msk;
60 unsigned long flags;104 unsigned long flags;
61 u32 reg;105 u32 reg;
62 106
@@ -70,21 +114,27 @@ int sun8i_tcon_top_de_config(struct device *dev, int mixer, int tcon) · 7 unmodified lines
70 return -EINVAL;114 return -EINVAL;
71 }115 }
72 116
73 if (tcon > 3) {117 if (tcon < 0 || tcon >= TCON_TOP_PORT_TCON_NUM) {
74 dev_err(dev, "TCON index is too high!\n");118 dev_err(dev, "TCON index is invalid!\n");
75 return -EINVAL;119 return -EINVAL;
76 }120 }
77 121
122 mixer_msk = mixer ? TCON_TOP_PORT_DE1_MSK : TCON_TOP_PORT_DE0_MSK;
123 other_msk = mixer ? TCON_TOP_PORT_DE0_MSK : TCON_TOP_PORT_DE1_MSK;
124
78 spin_lock_irqsave(&tcon_top->reg_lock, flags);125 spin_lock_irqsave(&tcon_top->reg_lock, flags);
79 126
80 reg = readl(tcon_top->regs + TCON_TOP_PORT_SEL_REG);127 reg = readl(tcon_top->regs + TCON_TOP_PORT_SEL_REG);
81 if (mixer == 0) {128
82 reg &= ~TCON_TOP_PORT_DE0_MSK;129 reg &= ~mixer_msk;
83 reg |= FIELD_PREP(TCON_TOP_PORT_DE0_MSK, tcon);130 reg |= field_prep(mixer_msk, tcon);
84 } else {131
85 reg &= ~TCON_TOP_PORT_DE1_MSK;132 if (field_get(other_msk, reg) == tcon) {
86 reg |= FIELD_PREP(TCON_TOP_PORT_DE1_MSK, tcon);133 reg &= ~other_msk;
134 reg |= field_prep(other_msk,
135 sun8i_tcon_top_park_index(tcon_top, tcon));
87 }136 }
137
88 writel(reg, tcon_top->regs + TCON_TOP_PORT_SEL_REG);138 writel(reg, tcon_top->regs + TCON_TOP_PORT_SEL_REG);
89 139
90 spin_unlock_irqrestore(&tcon_top->reg_lock, flags);140 spin_unlock_irqrestore(&tcon_top->reg_lock, flags);
@@ -143,6 +193,7 @@ static int sun8i_tcon_top_bind(struct device *dev, struct device *master, · 52 unmodified lines
143 return -ENOMEM;193 return -ENOMEM;
144 clk_data->num = CLK_NUM;194 clk_data->num = CLK_NUM;
145 tcon_top->clk_data = clk_data;195 tcon_top->clk_data = clk_data;
196 tcon_top->tcon_map = sun8i_tcon_top_get_tcon_map(dev->of_node);
146 197
147 spin_lock_init(&tcon_top->reg_lock);198 spin_lock_init(&tcon_top->reg_lock);
148 199
@@ -175,10 +226,6 @@ static int sun8i_tcon_top_bind(struct device *dev, struct device *master, · 26 unmodified lines
175 goto err_assert_reset;226 goto err_assert_reset;
176 }227 }
177 228
178 /*
179 * At least on H6, some registers have some bits set by default
180 * which may cause issues. Clear them here.
181 */
182 writel(0, regs + TCON_TOP_PORT_SEL_REG);229 writel(0, regs + TCON_TOP_PORT_SEL_REG);
183 writel(0, regs + TCON_TOP_GATE_SRC_REG);230 writel(0, regs + TCON_TOP_GATE_SRC_REG);
184 231
drivers/gpu/drm/sun4i/sun8i_tcon_top.h+6−0
@@ -14,6 +14,10 @@ · 13 unmodified lines
14#define TCON_TOP_PORT_SEL_REG 0x1C14#define TCON_TOP_PORT_SEL_REG 0x1C
15#define TCON_TOP_PORT_DE0_MSK GENMASK(1, 0)15#define TCON_TOP_PORT_DE0_MSK GENMASK(1, 0)
16#define TCON_TOP_PORT_DE1_MSK GENMASK(5, 4)16#define TCON_TOP_PORT_DE1_MSK GENMASK(5, 4)
17#define TCON_TOP_PORT_TCON_NUM 4
18
19#define TCON_TOP_MIXER0_OUT_PORT 1
20#define TCON_TOP_MIXER1_OUT_PORT 3
17 21
18#define TCON_TOP_GATE_SRC_REG 0x2022#define TCON_TOP_GATE_SRC_REG 0x20
19#define TCON_TOP_HDMI_SRC_MSK GENMASK(29, 28)23#define TCON_TOP_HDMI_SRC_MSK GENMASK(29, 28)
@@ -29,6 +33,8 @@ struct sun8i_tcon_top { · 9 unmodified lines
29 void __iomem *regs;33 void __iomem *regs;
30 struct reset_control *rst;34 struct reset_control *rst;
31 35
36 unsigned int tcon_map;
37
32 /*38 /*
33 * spinlock is used to synchronize access to same39 * spinlock is used to synchronize access to same
34 * register where multiple clock gates can be set.40 * register where multiple clock gates can be set.
drivers/gpu/drm/sun4i/sun8i_vi_scaler.c+14−6
@@ -894,20 +894,26 @@ static void sun8i_vi_scaler_set_coeff(struct regmap *map, u32 base, · 893 unmodified lines
894 lan3coefftab32_left[offset + i]);894 lan3coefftab32_left[offset + i]);
895 regmap_write(map, SUN8I_SCALER_VSU_YHCOEFF1(base, i),895 regmap_write(map, SUN8I_SCALER_VSU_YHCOEFF1(base, i),
896 lan3coefftab32_right[offset + i]);896 lan3coefftab32_right[offset + i]);
897 }
898 offset = sun8i_vi_scaler_coef_index(vstep) *
899 SUN8I_VI_SCALER_COEFF_COUNT;
900 for (i = 0; i < SUN8I_VI_SCALER_COEFF_COUNT; i++)
901 regmap_write(map, SUN8I_SCALER_VSU_YVCOEFF(base, i),
902 lan2coefftab32[offset + i]);
903
904 offset = sun8i_vi_scaler_coef_index(hstep / format->hsub) *
905 SUN8I_VI_SCALER_COEFF_COUNT;
906 for (i = 0; i < SUN8I_VI_SCALER_COEFF_COUNT; i++) {
897 regmap_write(map, SUN8I_SCALER_VSU_CHCOEFF0(base, i),907 regmap_write(map, SUN8I_SCALER_VSU_CHCOEFF0(base, i),
898 ch_left[offset + i]);908 ch_left[offset + i]);
899 regmap_write(map, SUN8I_SCALER_VSU_CHCOEFF1(base, i),909 regmap_write(map, SUN8I_SCALER_VSU_CHCOEFF1(base, i),
900 ch_right[offset + i]);910 ch_right[offset + i]);
901 }911 }
902 912 offset = sun8i_vi_scaler_coef_index(vstep / format->vsub) *
903 offset = sun8i_vi_scaler_coef_index(hstep) *
904 SUN8I_VI_SCALER_COEFF_COUNT;913 SUN8I_VI_SCALER_COEFF_COUNT;
905 for (i = 0; i < SUN8I_VI_SCALER_COEFF_COUNT; i++) {914 for (i = 0; i < SUN8I_VI_SCALER_COEFF_COUNT; i++)
906 regmap_write(map, SUN8I_SCALER_VSU_YVCOEFF(base, i),
907 lan2coefftab32[offset + i]);
908 regmap_write(map, SUN8I_SCALER_VSU_CVCOEFF(base, i),915 regmap_write(map, SUN8I_SCALER_VSU_CVCOEFF(base, i),
909 cy[offset + i]);916 cy[offset + i]);
910 }
911}917}
912 918
913void sun8i_vi_scaler_enable(struct sun8i_layer *layer, bool enable)919void sun8i_vi_scaler_enable(struct sun8i_layer *layer, bool enable)
@@ -969,6 +975,8 @@ void sun8i_vi_scaler_setup(struct sun8i_layer *layer, · 55 unmodified lines
969 975
970 regmap_write(layer->regs,976 regmap_write(layer->regs,
971 SUN50I_SCALER_VSU_SCALE_MODE(base), val);977 SUN50I_SCALER_VSU_SCALE_MODE(base), val);
978 regmap_write(layer->regs,
979 SUN50I_SCALER_VSU_GLB_ALPHA(base), 0xff);
972 }980 }
973 981
974 regmap_write(layer->regs,982 regmap_write(layer->regs,
drivers/gpu/drm/sun4i/sun8i_vi_scaler.h+1−0
@@ -36,6 +36,7 @@ · 35 unmodified lines
36#define SUN50I_SCALER_VSU_EDSCL_CTRL(base) ((base) + 0x28)36#define SUN50I_SCALER_VSU_EDSCL_CTRL(base) ((base) + 0x28)
37#define SUN50I_SCALER_VSU_ANGLE_THR(base) ((base) + 0x2c)37#define SUN50I_SCALER_VSU_ANGLE_THR(base) ((base) + 0x2c)
38#define SUN8I_SCALER_VSU_OUTSIZE(base) ((base) + 0x40)38#define SUN8I_SCALER_VSU_OUTSIZE(base) ((base) + 0x40)
39#define SUN50I_SCALER_VSU_GLB_ALPHA(base) ((base) + 0x44)
39#define SUN8I_SCALER_VSU_YINSIZE(base) ((base) + 0x80)40#define SUN8I_SCALER_VSU_YINSIZE(base) ((base) + 0x80)
40#define SUN8I_SCALER_VSU_YHSTEP(base) ((base) + 0x88)41#define SUN8I_SCALER_VSU_YHSTEP(base) ((base) + 0x88)
41#define SUN8I_SCALER_VSU_YVSTEP(base) ((base) + 0x8c)42#define SUN8I_SCALER_VSU_YVSTEP(base) ((base) + 0x8c)
drivers/gpu/drm/ttm/ttm_bo.c+288−32
@@ -488,6 +488,118 @@ out_no_ref: · 487 unmodified lines
488 return ret;488 return ret;
489}489}
490 490
491struct ttm_bo_alloc_state {
492 /** @charge_pool: The memory pool the resource is charged to */
493 struct dmem_cgroup_pool_state *charge_pool;
494 /** @limit_pool: Which pool limit we should test against */
495 struct dmem_cgroup_pool_state *limit_pool;
496 /** @in_evict: Whether we are currently evicting buffers */
497 bool in_evict;
498 /** @may_try_low: If only unprotected BOs, i.e. BOs whose cgroup
499 * is exceeding its dmem low/min protection, should be considered for eviction
500 */
501 bool may_try_low;
502};
503
504/**
505 * ttm_bo_alloc_at_place - Attempt allocating a BO's backing store in a place
506 *
507 * @bo: The buffer to allocate the backing store of
508 * @place: The place to attempt allocation in
509 * @ctx: ttm_operation_ctx associated with this allocation
510 * @force_space: If we should evict buffers to force space
511 * @res: On allocation success, the resulting struct ttm_resource.
512 * @alloc_state: Object holding allocation state such as charged cgroups.
513 *
514 * Returns:
515 * -EBUSY: No space available, but allocation should be retried with ttm_bo_evict_alloc.
516 * -ENOSPC: No space available, allocation should not be retried.
517 * -ERESTARTSYS: An interruptible sleep was interrupted by a signal.
518 *
519 */
520static int ttm_bo_alloc_at_place(struct ttm_buffer_object *bo,
521 const struct ttm_place *place,
522 bool force_space,
523 struct ttm_resource **res,
524 struct ttm_bo_alloc_state *alloc_state)
525{
526 bool may_evict;
527 int ret;
528
529 may_evict = !alloc_state->in_evict && force_space &&
530 place->mem_type != TTM_PL_SYSTEM;
531 if (!alloc_state->charge_pool) {
532 ret = ttm_resource_try_charge(bo, place, &alloc_state->charge_pool,
533 force_space ? &alloc_state->limit_pool
534 : NULL);
535 if (ret) {
536 /*
537 * -EAGAIN means the charge failed, which we treat
538 * like an allocation failure. Therefore, return an
539 * error code indicating the allocation failed -
540 * either -EBUSY if the allocation should be
541 * retried with eviction, or -ENOSPC if there should
542 * be no second attempt.
543 */
544 if (!alloc_state->in_evict)
545 alloc_state->may_try_low = may_evict;
546 if (ret == -EAGAIN)
547 ret = may_evict ? -EBUSY : -ENOSPC;
548 return ret;
549 }
550 }
551
552 /*
553 * cgroup protection plays a special role in eviction.
554 * Conceptually, protection of memory via the dmem cgroup controller
555 * entitles the protected cgroup to use a certain amount of memory.
556 * There are two types of protection - the 'low' limit is a
557 * "best-effort" protection, whereas the 'min' limit provides a hard
558 * guarantee that memory within the cgroup's allowance will not be
559 * evicted under any circumstance.
560 *
561 * To faithfully model this concept in TTM, we also need to take cgroup
562 * protection into account when allocating. When allocation in one
563 * place fails, TTM will default to trying other places first before
564 * evicting.
565 * If the allocation is covered by dmem cgroup protection, however,
566 * this prevents the allocation from using the memory it is "entitled"
567 * to. To make sure unprotected allocations cannot push new protected
568 * allocations out of places they are "entitled" to use, we should
569 * evict buffers not covered by any cgroup protection, if this
570 * allocation is covered by cgroup protection.
571 *
572 * Buffers covered by 'min' protection are a special case - the 'min'
573 * limit is a stronger guarantee than 'low', and thus buffers protected
574 * by 'low' but not 'min' should also be considered for eviction.
575 * Buffers protected by 'min' will never be considered for eviction
576 * anyway, so the regular eviction path should be triggered here.
577 * Buffers protected by 'low' but not 'min' will take a special
578 * eviction path that only evicts buffers covered by neither 'low' or
579 * 'min' protections.
580 */
581 if (!alloc_state->in_evict) {
582 may_evict |= dmem_cgroup_below_min(NULL, alloc_state->charge_pool);
583 alloc_state->may_try_low = may_evict;
584
585 may_evict |= dmem_cgroup_below_low(NULL, alloc_state->charge_pool);
586 }
587
588 ret = ttm_resource_alloc(bo, place, res, alloc_state->charge_pool);
589 if (ret) {
590 if (ret == -ENOSPC && may_evict)
591 ret = -EBUSY;
592 return ret;
593 }
594
595 /*
596 * Ownership of charge_pool has been transferred to the TTM resource,
597 * don't make the caller think we still hold a reference to it.
598 */
599 alloc_state->charge_pool = NULL;
600 return 0;
601}
602
491/**603/**
492 * struct ttm_bo_evict_walk - Parameters for the evict walk.604 * struct ttm_bo_evict_walk - Parameters for the evict walk.
493 */605 */
@@ -503,24 +615,70 @@ struct ttm_bo_evict_walk { · 9 unmodified lines
503 /** @evicted: Number of successful evictions. */615 /** @evicted: Number of successful evictions. */
504 unsigned long evicted;616 unsigned long evicted;
505 617
506 /** @limit_pool: Which pool limit we should test against */
507 struct dmem_cgroup_pool_state *limit_pool;
508 /** @try_low: Whether we should attempt to evict BO's with low watermark threshold */618 /** @try_low: Whether we should attempt to evict BO's with low watermark threshold */
509 bool try_low;619 bool try_low;
510 /** @hit_low: If we cannot evict a bo when @try_low is false (first pass) */620 /** @hit_low: If we cannot evict a bo when @try_low is false (first pass) */
511 bool hit_low;621 bool hit_low;
622
623 /** @alloc_state: State associated with the allocation attempt. */
624 struct ttm_bo_alloc_state *alloc_state;
512};625};
513 626
514static s64 ttm_bo_evict_cb(struct ttm_lru_walk *walk, struct ttm_buffer_object *bo)627static s64 ttm_bo_evict_cb(struct ttm_lru_walk *walk, struct ttm_buffer_object *bo)
515{628{
516 struct ttm_bo_evict_walk *evict_walk =629 struct ttm_bo_evict_walk *evict_walk =
517 container_of(walk, typeof(*evict_walk), walk);630 container_of(walk, typeof(*evict_walk), walk);
631 struct dmem_cgroup_pool_state *limit_pool, *ancestor = NULL;
632 s64 bo_size = bo->base.size;
633 bool evict_valuable;
518 s64 lret;634 s64 lret;
519 635
520 if (!dmem_cgroup_state_evict_valuable(evict_walk->limit_pool, bo->resource->css,636 /*
521 evict_walk->try_low, &evict_walk->hit_low))637 * If may_try_low is not set, then we're trying to evict unprotected
638 * buffers in favor of a protected allocation for charge_pool. Explicitly skip
639 * buffers belonging to the same cgroup here - that cgroup is definitely protected,
640 * even though dmem_cgroup_state_evict_valuable would allow the eviction because a
641 * cgroup is always allowed to evict from itself even if it is protected.
642 */
643 if (!evict_walk->alloc_state->may_try_low &&
644 bo->resource->css == evict_walk->alloc_state->charge_pool)
522 return 0;645 return 0;
523 646
647 limit_pool = evict_walk->alloc_state->limit_pool;
648 /*
649 * If there is no explicit limit pool, find the root of the shared subtree between
650 * evictor and evictee. This is important so that recursive protection rules can
651 * apply properly: Recursive protection distributes cgroup protection afforded
652 * to a parent cgroup but not used explicitly by a child cgroup between all child
653 * cgroups (see docs of effective_protection in mm/page_counter.c). However, when
654 * direct siblings compete for memory, siblings that were explicitly protected
655 * should get prioritized over siblings that weren't. This only happens correctly
656 * when the root of the shared subtree is passed to
657 * dmem_cgroup_state_evict_valuable. Otherwise, the effective-protection
658 * calculation cannot distinguish direct siblings from unrelated subtrees and the
659 * calculated protection ends up wrong.
660 */
661 if (!limit_pool) {
662 ancestor = dmem_cgroup_get_common_ancestor(bo->resource->css,
663 evict_walk->alloc_state->charge_pool);
664 limit_pool = ancestor;
665 }
666
667 evict_valuable = dmem_cgroup_state_evict_valuable(limit_pool, bo->resource->css,
668 evict_walk->try_low,
669 &evict_walk->hit_low);
670 if (ancestor)
671 dmem_cgroup_pool_state_put(ancestor);
672
673 if (!evict_valuable)
674 return 0;
675
676 /*
677 * evict_walk->place is NULL in cgroup drain mode. Drivers'
678 * eviction_valuable() callbacks must handle a NULL place, treating it
679 * as "any placement": the TTM base implementation already does so via
680 * ttm_resource_intersects().
681 */
524 if (bo->pin_count || !bo->bdev->funcs->eviction_valuable(bo, evict_walk->place))682 if (bo->pin_count || !bo->bdev->funcs->eviction_valuable(bo, evict_walk->place))
525 return 0;683 return 0;
526 684
@@ -536,11 +694,17 @@ static s64 ttm_bo_evict_cb(struct ttm_lru_walk *walk, struct ttm_buffer_object * · 9 unmodified lines
536 goto out;694 goto out;
537 695
538 evict_walk->evicted++;696 evict_walk->evicted++;
539 if (evict_walk->res)697 if (evict_walk->res) {
540 lret = ttm_resource_alloc(evict_walk->evictor, evict_walk->place,698 lret = ttm_bo_alloc_at_place(evict_walk->evictor,
541 evict_walk->res, NULL);699 evict_walk->place, false,
542 if (lret == 0)700 evict_walk->res,
543 return 1;701 evict_walk->alloc_state);
702 if (lret == 0)
703 return 1;
704 } else {
705 /* Cgroup drain: return bytes freed for byte-denominated progress. */
706 return bo_size;
707 }
544out:708out:
545 /* Errors that should terminate the walk. */709 /* Errors that should terminate the walk. */
546 if (lret == -ENOSPC)710 if (lret == -ENOSPC)
@@ -560,7 +724,7 @@ static int ttm_bo_evict_alloc(struct ttm_device *bdev, · 13 unmodified lines
560 struct ttm_operation_ctx *ctx,724 struct ttm_operation_ctx *ctx,
561 struct ww_acquire_ctx *ticket,725 struct ww_acquire_ctx *ticket,
562 struct ttm_resource **res,726 struct ttm_resource **res,
563 struct dmem_cgroup_pool_state *limit_pool)727 struct ttm_bo_alloc_state *state)
564{728{
565 struct ttm_bo_evict_walk evict_walk = {729 struct ttm_bo_evict_walk evict_walk = {
566 .walk = {730 .walk = {
@@ -573,15 +737,21 @@ static int ttm_bo_evict_alloc(struct ttm_device *bdev, · 6 unmodified lines
573 .place = place,737 .place = place,
574 .evictor = evictor,738 .evictor = evictor,
575 .res = res,739 .res = res,
576 .limit_pool = limit_pool,740 .alloc_state = state,
577 };741 };
578 s64 lret;742 s64 lret;
579 743
744 state->in_evict = true;
745
580 evict_walk.walk.arg.trylock_only = true;746 evict_walk.walk.arg.trylock_only = true;
581 lret = ttm_lru_walk_for_evict(&evict_walk.walk, bdev, man, 1);747 lret = ttm_lru_walk_for_evict(&evict_walk.walk, bdev, man, 1);
582 748
583 /* One more attempt if we hit low limit? */749 /* If we failed to find enough BOs to evict, but we skipped over
584 if (!lret && evict_walk.hit_low) {750 * some BOs because they were covered by dmem low protection, retry
751 * evicting these protected BOs too, except if we're told not to
752 * consider protected BOs at all.
753 */
754 if (!lret && evict_walk.hit_low && state->may_try_low) {
585 evict_walk.try_low = true;755 evict_walk.try_low = true;
586 lret = ttm_lru_walk_for_evict(&evict_walk.walk, bdev, man, 1);756 lret = ttm_lru_walk_for_evict(&evict_walk.walk, bdev, man, 1);
587 }757 }
@@ -602,11 +772,13 @@ retry: · 14 unmodified lines
602 } while (!lret && evict_walk.evicted);772 } while (!lret && evict_walk.evicted);
603 773
604 /* We hit the low limit? Try once more */774 /* We hit the low limit? Try once more */
605 if (!lret && evict_walk.hit_low && !evict_walk.try_low) {775 if (!lret && evict_walk.hit_low && !evict_walk.try_low &&
776 state->may_try_low) {
606 evict_walk.try_low = true;777 evict_walk.try_low = true;
607 goto retry;778 goto retry;
608 }779 }
609out:780out:
781 state->in_evict = false;
610 if (lret < 0)782 if (lret < 0)
611 return lret;783 return lret;
612 if (lret == 0)784 if (lret == 0)
@@ -614,6 +786,86 @@ out: · 1 unmodified line
614 return 0;786 return 0;
615}787}
616 788
789/**
790 * ttm_bo_evict_cgroup() - Evict buffer objects charged to a specific cgroup.
791 * @bdev: The TTM device.
792 * @man: The resource manager whose LRU to walk.
793 * @limit_pool: The cgroup pool state whose members should be evicted.
794 * @target_bytes: Number of bytes to free.
795 * @ctx: The TTM operation context.
796 *
797 * Walk the LRU of @man and evict buffer objects that are charged to the
798 * cgroup identified by @limit_pool, until at least @target_bytes have been
799 * freed. Mirrors the two-pass (trylock -> sleeping-lock, low-watermark)
800 * strategy used by ttm_bo_evict_alloc().
801 *
802 * Return: >= @target_bytes on full success, 0..target_bytes-1 if partial,
803 * negative error code on fatal error.
804 */
805s64 ttm_bo_evict_cgroup(struct ttm_device *bdev,
806 struct ttm_resource_manager *man,
807 struct dmem_cgroup_pool_state *limit_pool,
808 s64 target_bytes,
809 struct ttm_operation_ctx *ctx)
810{
811 struct ttm_bo_evict_walk evict_walk = {
812 .walk = {
813 .ops = &ttm_evict_walk_ops,
814 .arg = { .ctx = ctx },
815 },
816 .alloc_state = &(struct ttm_bo_alloc_state) {
817 .limit_pool = limit_pool,
818 .in_evict = true,
819 },
820 /* place, evictor, res left NULL: selects cgroup drain mode */
821 };
822 s64 lret, pass;
823
824 evict_walk.walk.arg.trylock_only = true;
825 lret = ttm_lru_walk_for_evict(&evict_walk.walk, bdev, man, target_bytes);
826 if (lret < 0 || lret >= target_bytes)
827 return lret;
828
829 /* Second pass: also evict BOs at the low watermark. */
830 if (evict_walk.hit_low) {
831 evict_walk.try_low = true;
832 pass = ttm_lru_walk_for_evict(&evict_walk.walk, bdev, man,
833 target_bytes - lret);
834 if (pass < 0)
835 return pass;
836 lret += pass;
837 if (lret >= target_bytes)
838 return lret;
839 }
840
841 /* Full sleeping-lock pass for remaining target. */
842 evict_walk.try_low = evict_walk.hit_low = false;
843 evict_walk.walk.arg.trylock_only = false;
844
845retry:
846 evict_walk.walk.arg.sleeping_lock = true;
847 do {
848 evict_walk.evicted = 0;
849 pass = ttm_lru_walk_for_evict(&evict_walk.walk, bdev, man,
850 target_bytes - lret);
851 if (pass < 0) {
852 lret = pass;
853 goto out;
854 }
855 lret += pass;
856 } while (lret < target_bytes && evict_walk.evicted);
857
858 /* One more attempt if we hit the low limit during sleeping-lock pass. */
859 if (lret < target_bytes && evict_walk.hit_low && !evict_walk.try_low) {
860 evict_walk.try_low = true;
861 goto retry;
862 }
863
864out:
865 return lret;
866}
867EXPORT_SYMBOL(ttm_bo_evict_cgroup);
868
617/**869/**
618 * ttm_bo_pin - Pin the buffer object.870 * ttm_bo_pin - Pin the buffer object.
619 * @bo: The buffer object to pin871 * @bo: The buffer object to pin
@@ -724,9 +976,8 @@ static int ttm_bo_alloc_resource(struct ttm_buffer_object *bo, · 104 unmodified lines
724 976
725 for (i = 0; i < placement->num_placement; ++i) {977 for (i = 0; i < placement->num_placement; ++i) {
726 const struct ttm_place *place = &placement->placement[i];978 const struct ttm_place *place = &placement->placement[i];
727 struct dmem_cgroup_pool_state *limit_pool = NULL;979 struct ttm_bo_alloc_state alloc_state = {};
728 struct ttm_resource_manager *man;980 struct ttm_resource_manager *man;
729 bool may_evict;
730 981
731 man = ttm_manager_type(bdev, place->mem_type);982 man = ttm_manager_type(bdev, place->mem_type);
732 if (!man || !ttm_resource_manager_used(man))983 if (!man || !ttm_resource_manager_used(man))
@@ -736,25 +987,30 @@ static int ttm_bo_alloc_resource(struct ttm_buffer_object *bo, · 3 unmodified lines
736 TTM_PL_FLAG_FALLBACK))987 TTM_PL_FLAG_FALLBACK))
737 continue;988 continue;
738 989
739 may_evict = (force_space && place->mem_type != TTM_PL_SYSTEM);990 ret = ttm_bo_alloc_at_place(bo, place, force_space, res,
740 ret = ttm_resource_alloc(bo, place, res, force_space ? &limit_pool : NULL);991 &alloc_state);
741 if (ret) {
742 if (ret != -ENOSPC) {
743 dmem_cgroup_pool_state_put(limit_pool);
744 return ret;
745 }
746 if (!may_evict) {
747 dmem_cgroup_pool_state_put(limit_pool);
748 continue;
749 }
750 992
993 if (ret == -ENOSPC) {
994 dmem_cgroup_uncharge(alloc_state.charge_pool, bo->base.size);
995 dmem_cgroup_pool_state_put(alloc_state.limit_pool);
996 continue;
997 } else if (ret == -EBUSY) {
751 ret = ttm_bo_evict_alloc(bdev, man, place, bo, ctx,998 ret = ttm_bo_evict_alloc(bdev, man, place, bo, ctx,
752 ticket, res, limit_pool);999 ticket, res, &alloc_state);
753 dmem_cgroup_pool_state_put(limit_pool);1000
754 if (ret == -EBUSY)1001 dmem_cgroup_pool_state_put(alloc_state.limit_pool);
755 continue;1002
756 if (ret)1003 if (ret) {
1004 dmem_cgroup_uncharge(alloc_state.charge_pool,
1005 bo->base.size);
1006 if (ret == -EBUSY)
1007 continue;
757 return ret;1008 return ret;
1009 }
1010 } else if (ret) {
1011 dmem_cgroup_uncharge(alloc_state.charge_pool, bo->base.size);
1012 dmem_cgroup_pool_state_put(alloc_state.limit_pool);
1013 return ret;
758 }1014 }
759 1015
760 ret = ttm_bo_add_pipelined_eviction_fences(bo, man, ctx->no_wait_gpu);1016 ret = ttm_bo_add_pipelined_eviction_fences(bo, man, ctx->no_wait_gpu);
drivers/gpu/drm/ttm/ttm_bo_util.c+2−1
@@ -999,7 +999,8 @@ __ttm_bo_lru_cursor_next(struct ttm_bo_lru_cursor *curs) · 998 unmodified lines
999 bo = res->bo;999 bo = res->bo;
1000 if (ttm_lru_walk_trylock(curs, bo))1000 if (ttm_lru_walk_trylock(curs, bo))
1001 bo_locked = true;1001 bo_locked = true;
1002 else if (!arg->ticket || arg->ctx->no_wait_gpu || arg->trylock_only)1002 else if ((!arg->ticket && !arg->sleeping_lock) || arg->ctx->no_wait_gpu ||
1003 arg->trylock_only)
1003 continue;1004 continue;
1004 1005
1005 if (!ttm_bo_get_unless_zero(bo)) {1006 if (!ttm_bo_get_unless_zero(bo)) {
drivers/gpu/drm/ttm/ttm_resource.c+88−17
@@ -386,33 +386,52 @@ void ttm_resource_fini(struct ttm_resource_manager *man, · 385 unmodified lines
386}386}
387EXPORT_SYMBOL(ttm_resource_fini);387EXPORT_SYMBOL(ttm_resource_fini);
388 388
389/**
390 * ttm_resource_try_charge - charge a resource manager's cgroup pool
391 * @bo: buffer for which an allocation should be charged
392 * @place: where the allocation is attempted to be placed
393 * @ret_pool: on charge success, the pool that was charged
394 * @ret_limit_pool: on charge failure, the pool responsible for the failure
395 *
396 * Should be used to charge cgroups before attempting resource allocation.
397 * When charging succeeds, the value of ret_pool should be passed to
398 * ttm_resource_alloc.
399 *
400 * Returns: 0 on charge success, negative errno on failure.
401 */
402int ttm_resource_try_charge(struct ttm_buffer_object *bo,
403 const struct ttm_place *place,
404 struct dmem_cgroup_pool_state **ret_pool,
405 struct dmem_cgroup_pool_state **ret_limit_pool)
406{
407 struct ttm_resource_manager *man =
408 ttm_manager_type(bo->bdev, place->mem_type);
409
410 if (!man->cg) {
411 *ret_pool = NULL;
412 if (ret_limit_pool)
413 *ret_limit_pool = NULL;
414 return 0;
415 }
416
417 return dmem_cgroup_try_charge(man->cg, bo->base.size, ret_pool,
418 ret_limit_pool);
419}
420
389int ttm_resource_alloc(struct ttm_buffer_object *bo,421int ttm_resource_alloc(struct ttm_buffer_object *bo,
390 const struct ttm_place *place,422 const struct ttm_place *place,
391 struct ttm_resource **res_ptr,423 struct ttm_resource **res_ptr,
392 struct dmem_cgroup_pool_state **ret_limit_pool)424 struct dmem_cgroup_pool_state *charge_pool)
393{425{
394 struct ttm_resource_manager *man =426 struct ttm_resource_manager *man =
395 ttm_manager_type(bo->bdev, place->mem_type);427 ttm_manager_type(bo->bdev, place->mem_type);
396 struct dmem_cgroup_pool_state *pool = NULL;
397 int ret;428 int ret;
398 429
399 if (man->cg) {
400 ret = dmem_cgroup_try_charge(man->cg, bo->base.size, &pool, ret_limit_pool);
401 if (ret) {
402 if (ret == -EAGAIN)
403 ret = -ENOSPC;
404 return ret;
405 }
406 }
407
408 ret = man->func->alloc(man, bo, place, res_ptr);430 ret = man->func->alloc(man, bo, place, res_ptr);
409 if (ret) {431 if (ret)
410 if (pool)
411 dmem_cgroup_uncharge(pool, bo->base.size);
412 return ret;432 return ret;
413 }
414 433
415 (*res_ptr)->css = pool;434 (*res_ptr)->css = charge_pool;
416 435
417 spin_lock(&bo->bdev->lru_lock);436 spin_lock(&bo->bdev->lru_lock);
418 ttm_resource_add_bulk_move(*res_ptr, bo);437 ttm_resource_add_bulk_move(*res_ptr, bo);
@@ -437,7 +456,7 @@ void ttm_resource_free(struct ttm_buffer_object *bo, struct ttm_resource **res) · 18 unmodified lines
437 man = ttm_manager_type(bo->bdev, (*res)->mem_type);456 man = ttm_manager_type(bo->bdev, (*res)->mem_type);
438 man->func->free(man, *res);457 man->func->free(man, *res);
439 *res = NULL;458 *res = NULL;
440 if (man->cg)459 if (pool)
441 dmem_cgroup_uncharge(pool, bo->base.size);460 dmem_cgroup_uncharge(pool, bo->base.size);
442}461}
443EXPORT_SYMBOL(ttm_resource_free);462EXPORT_SYMBOL(ttm_resource_free);
@@ -953,3 +972,55 @@ void ttm_resource_manager_create_debugfs(struct ttm_resource_manager *man, · 509 unmodified lines
953#endif972#endif
954}973}
955EXPORT_SYMBOL(ttm_resource_manager_create_debugfs);974EXPORT_SYMBOL(ttm_resource_manager_create_debugfs);
975
976/**
977 * ttm_resource_manager_dmem_reclaim() - dmem cgroup reclaim callback for TTM
978 * resource managers.
979 * @pool: The dmem cgroup pool state for the cgroup being reclaimed.
980 * @target_bytes: Number of bytes to try to free.
981 * @priv: The &ttm_resource_manager pointer, passed as @init.reclaim_priv to
982 * dmem_cgroup_register_region().
983 *
984 * Drivers should use this as the @reclaim member of their own
985 * &struct dmem_cgroup_ops, with the &ttm_resource_manager pointer as
986 * @init.reclaim_priv.
987 *
988 * Return: 0 if some memory was freed, -ENOSPC if nothing was freed, or
989 * another negative error code on fatal failure.
990 */
991int ttm_resource_manager_dmem_reclaim(struct dmem_cgroup_pool_state *pool,
992 u64 target_bytes, void *priv)
993{
994 struct ttm_resource_manager *man = priv;
995 struct ttm_operation_ctx ctx = { .interruptible = true };
996 s64 freed;
997
998 freed = ttm_bo_evict_cgroup(man->bdev, man, pool, target_bytes, &ctx);
999 if (freed < 0)
1000 return freed;
1001
1002 return freed > 0 ? 0 : -ENOSPC;
1003}
1004EXPORT_SYMBOL(ttm_resource_manager_dmem_reclaim);
1005
1006/**
1007 * ttm_resource_manager_set_dmem_region() - Associate a dmem cgroup region with a
1008 * resource manager.
1009 * @man: The resource manager.
1010 * @region: The dmem cgroup region to associate, may be NULL or IS_ERR().
1011 *
1012 * When @region is valid, stores it in @man->cg so that TTM can look up the
1013 * associated pool during charging and eviction-target selection. When
1014 * @region is %NULL, clears @man->cg to detach the region before teardown.
1015 * An IS_ERR() @region is ignored, leaving @man->cg unchanged.
1016 * The reclaim callback must be wired up using ttm_resource_manager_dmem_reclaim()
1017 * in the driver's own &struct dmem_cgroup_ops, with the manager pointer as
1018 * @init.reclaim_priv.
1019 */
1020void ttm_resource_manager_set_dmem_region(struct ttm_resource_manager *man,
1021 struct dmem_cgroup_region *region)
1022{
1023 if (!IS_ERR(region))
1024 man->cg = region;
1025}
1026EXPORT_SYMBOL(ttm_resource_manager_set_dmem_region);
drivers/gpu/drm/xe/xe_ttm_vram_mgr.c+62−9
@@ -4,6 +4,8 @@ · 3 unmodified lines
4 * Copyright (C) 2021-2022 Red Hat4 * Copyright (C) 2021-2022 Red Hat
5 */5 */
6 6
7#include <linux/cgroup_dmem.h>
8
7#include <drm/drm_managed.h>9#include <drm/drm_managed.h>
8#include <drm/drm_drv.h>10#include <drm/drm_drv.h>
9#include <drm/drm_buddy.h>11#include <drm/drm_buddy.h>
@@ -13,6 +15,7 @@ · 3 unmodified lines
13 15
14#include "xe_bo.h"16#include "xe_bo.h"
15#include "xe_device.h"17#include "xe_device.h"
18#include "xe_pm.h"
16#include "xe_res_cursor.h"19#include "xe_res_cursor.h"
17#include "xe_ttm_vram_mgr.h"20#include "xe_ttm_vram_mgr.h"
18#include "xe_vram_types.h"21#include "xe_vram_types.h"
@@ -274,14 +277,47 @@ static const struct ttm_resource_manager_func xe_ttm_vram_mgr_func = { · 255 unmodified lines
274 .debug = xe_ttm_vram_mgr_debug277 .debug = xe_ttm_vram_mgr_debug
275};278};
276 279
280static const struct dmem_cgroup_ops xe_ttm_vram_mgr_dmem_ops;
281
282static int xe_ttm_vram_mgr_dmem_reclaim(struct dmem_cgroup_pool_state *pool,
283 u64 target_bytes, void *priv)
284{
285 struct ttm_resource_manager *man = priv;
286 struct xe_device *xe = ttm_to_xe_device(man->bdev);
287 int ret, idx;
288
289 if (!drm_dev_enter(&xe->drm, &idx))
290 return -ENODEV;
291
292 {
293 ACQUIRE(xe_pm_runtime_ioctl, pm)(xe);
294
295 ret = ACQUIRE_ERR(xe_pm_runtime_ioctl, &pm);
296 if (ret >= 0)
297 ret = ttm_resource_manager_dmem_reclaim(pool, target_bytes, priv);
298 }
299
300 drm_dev_exit(idx);
301 return ret;
302}
303
304static const struct dmem_cgroup_ops xe_ttm_vram_mgr_dmem_ops = {
305 .reclaim = xe_ttm_vram_mgr_dmem_reclaim,
306};
307
308static void xe_ttm_vram_mgr_set_unused(struct drm_device *dev, void *arg)
309{
310 struct ttm_resource_manager *man = arg;
311
312 ttm_resource_manager_set_used(man, false);
313}
314
277static void xe_ttm_vram_mgr_fini(struct drm_device *dev, void *arg)315static void xe_ttm_vram_mgr_fini(struct drm_device *dev, void *arg)
278{316{
279 struct xe_device *xe = to_xe_device(dev);317 struct xe_device *xe = to_xe_device(dev);
280 struct xe_ttm_vram_mgr *mgr = arg;318 struct xe_ttm_vram_mgr *mgr = arg;
281 struct ttm_resource_manager *man = &mgr->manager;319 struct ttm_resource_manager *man = &mgr->manager;
282 320
283 ttm_resource_manager_set_used(man, false);
284
285 if (ttm_resource_manager_evict_all(&xe->ttm, man))321 if (ttm_resource_manager_evict_all(&xe->ttm, man))
286 return;322 return;
287 323
@@ -299,14 +335,10 @@ int __xe_ttm_vram_mgr_init(struct xe_device *xe, struct xe_ttm_vram_mgr *mgr, · 11 unmodified lines
299 u64 default_page_size)335 u64 default_page_size)
300{336{
301 struct ttm_resource_manager *man = &mgr->manager;337 struct ttm_resource_manager *man = &mgr->manager;
338 struct dmem_cgroup_region *cg;
302 const char *name;339 const char *name;
303 int err;340 int err;
304 341
305 name = mem_type == XE_PL_VRAM0 ? "vram0" : "vram1";
306 man->cg = drmm_cgroup_register_region(&xe->drm, name, size);
307 if (IS_ERR(man->cg))
308 return PTR_ERR(man->cg);
309
310 man->func = &xe_ttm_vram_mgr_func;342 man->func = &xe_ttm_vram_mgr_func;
311 mgr->mem_type = mem_type;343 mgr->mem_type = mem_type;
312 err = drmm_mutex_init(&xe->drm, &mgr->lock);344 err = drmm_mutex_init(&xe->drm, &mgr->lock);
@@ -323,9 +355,30 @@ int __xe_ttm_vram_mgr_init(struct xe_device *xe, struct xe_ttm_vram_mgr *mgr, · 10 unmodified lines
323 355
324 gpu_buddy_driver_set_lock(&mgr->mm, &mgr->lock);356 gpu_buddy_driver_set_lock(&mgr->mm, &mgr->lock);
325 ttm_set_driver_manager(&xe->ttm, mem_type, &mgr->manager);357 ttm_set_driver_manager(&xe->ttm, mem_type, &mgr->manager);
326 ttm_resource_manager_set_used(&mgr->manager, true);
327 358
328 return drmm_add_action_or_reset(&xe->drm, xe_ttm_vram_mgr_fini, mgr);359 /*
360 * Register the fini action before the cgroup region so that devres
361 * LIFO teardown runs unregister_region before manager teardown
362 * (draining any in-flight reclaim callbacks) and the manager fini second.
363 */
364 err = drmm_add_action_or_reset(&xe->drm, xe_ttm_vram_mgr_fini, mgr);
365 if (err)
366 return err;
367
368 name = mem_type == XE_PL_VRAM0 ? "vram0" : "vram1";
369 cg = drmm_cgroup_register_region(&xe->drm, name,
370 &(struct dmem_cgroup_init){
371 .size = size,
372 .ops = &xe_ttm_vram_mgr_dmem_ops,
373 .reclaim_priv = man,
374 });
375 if (IS_ERR(cg))
376 return PTR_ERR(cg);
377
378 ttm_resource_manager_set_dmem_region(man, cg);
379 ttm_resource_manager_set_used(man, true);
380
381 return drmm_add_action_or_reset(&xe->drm, xe_ttm_vram_mgr_set_unused, man);
329}382}
330 383
331/**384/**
drivers/gpu/tests/.kunitconfig+2−0
@@ -0,0 +1,2 @@
1CONFIG_KUNIT=y
2CONFIG_GPU_BUDDY_KUNIT_TEST=y
drivers/gpu/tests/gpu_buddy_test.c+78−24
@@ -1004,42 +1004,51 @@ static void gpu_test_buddy_alloc_clear(struct kunit *test) · 1003 unmodified lines
1004 gpu_buddy_fini(&mm);1004 gpu_buddy_fini(&mm);
1005 1005
1006 /*1006 /*
1007 * Using a non-power-of-two mm size, allocate alternating blocks of 4KiB in an1007 * Using a non-power-of-two mm size, allocate all 4KiB blocks and split
1008 * even sequence and free them as cleared. All blocks should be marked as1008 * them across two alternating lists, then free one list as cleared and
1009 * dirty and the split blocks should be merged back to their original1009 * the other as dirty. This interleaves cleared and dirty blocks so that
1010 * size when the blocks clear reset function is called.1010 * neighbouring buddies cannot be merged, fragmenting the address space.
1011 * After gpu_buddy_reset_clear(false) every block should be marked dirty
1012 * and the split blocks should be merged back to their original size, so
1013 * clear_avail must drop to 0.
1011 */1014 */
1012 KUNIT_EXPECT_FALSE(test, gpu_buddy_init(&mm, mm_size, ps));1015 KUNIT_EXPECT_FALSE(test, gpu_buddy_init(&mm, mm_size, ps));
1013 KUNIT_EXPECT_EQ(test, mm.max_order, max_order);1016 KUNIT_EXPECT_EQ(test, mm.max_order, max_order);
1014 1017
1015 i = 0;
1016 n_pages = mm_size / ps;1018 n_pages = mm_size / ps;
1017 do {1019 for (i = 0; i < n_pages; i++) {
1018 if (i % 2 == 0)1020 struct list_head *list = (i % 2) ? &clean : &dirty;
1019 KUNIT_ASSERT_FALSE_MSG(test, gpu_buddy_alloc_blocks(&mm, 0, mm_size,
1020 ps, ps, &allocated, 0),
1021 "buddy_alloc hit an error size=%lu\n", ps);
1022 } while (++i < n_pages);
1023 1021
1024 gpu_buddy_free_list(&mm, &allocated, GPU_BUDDY_CLEARED);1022 KUNIT_ASSERT_FALSE_MSG(test, gpu_buddy_alloc_blocks(&mm, 0, mm_size,
1023 ps, ps, list, 0),
1024 "buddy_alloc hit an error size=%lu\n", ps);
1025 }
1026
1027 gpu_buddy_free_list(&mm, &clean, GPU_BUDDY_CLEARED);
1028 gpu_buddy_free_list(&mm, &dirty, 0);
1025 gpu_buddy_reset_clear(&mm, false);1029 gpu_buddy_reset_clear(&mm, false);
1026 KUNIT_EXPECT_EQ(test, mm.clear_avail, 0);1030 KUNIT_EXPECT_EQ(test, mm.clear_avail, 0);
1031 gpu_buddy_fini(&mm);
1027 1032
1028 /*1033 /*
1029 * Using a non-power-of-two mm size, allocate alternating blocks of 4KiB in an1034 * Repeat the same fragmented setup, but this time call
1030 * odd sequence and free them as cleared. All blocks should be marked as1035 * gpu_buddy_reset_clear(true). Every block should be marked cleared and
1031 * cleared and the split blocks should be merged back to their original1036 * the split blocks should be merged back to their original size, so the
1032 * size when the blocks clear reset function is called.1037 * whole address space (clear_avail) must equal mm_size.
1033 */1038 */
1034 i = 0;1039 KUNIT_EXPECT_FALSE(test, gpu_buddy_init(&mm, mm_size, ps));
1035 do {1040 KUNIT_EXPECT_EQ(test, mm.max_order, max_order);
1036 if (i % 2 != 0)
1037 KUNIT_ASSERT_FALSE_MSG(test, gpu_buddy_alloc_blocks(&mm, 0, mm_size,
1038 ps, ps, &allocated, 0),
1039 "buddy_alloc hit an error size=%lu\n", ps);
1040 } while (++i < n_pages);
1041 1041
1042 gpu_buddy_free_list(&mm, &allocated, GPU_BUDDY_CLEARED);1042 for (i = 0; i < n_pages; i++) {
1043 struct list_head *list = (i % 2) ? &clean : &dirty;
1044
1045 KUNIT_ASSERT_FALSE_MSG(test, gpu_buddy_alloc_blocks(&mm, 0, mm_size,
1046 ps, ps, list, 0),
1047 "buddy_alloc hit an error size=%lu\n", ps);
1048 }
1049
1050 gpu_buddy_free_list(&mm, &clean, GPU_BUDDY_CLEARED);
1051 gpu_buddy_free_list(&mm, &dirty, 0);
1043 gpu_buddy_reset_clear(&mm, true);1052 gpu_buddy_reset_clear(&mm, true);
1044 KUNIT_EXPECT_EQ(test, mm.clear_avail, mm_size);1053 KUNIT_EXPECT_EQ(test, mm.clear_avail, mm_size);
1045 gpu_buddy_fini(&mm);1054 gpu_buddy_fini(&mm);
@@ -1422,6 +1431,50 @@ static void gpu_test_buddy_alloc_exceeds_max_order(struct kunit *test) · 376 unmodified lines
1422 gpu_buddy_fini(&mm);1431 gpu_buddy_fini(&mm);
1423}1432}
1424 1433
1434static void gpu_test_buddy_addr_to_block(struct kunit *test)
1435{
1436 struct gpu_buddy_block *allocated_block, *found_block;
1437 LIST_HEAD(allocated_list);
1438 const u64 test_size = SZ_4M + SZ_2M;
1439 const u64 alloc_start = SZ_4M;
1440 const u64 alloc_size = SZ_4K;
1441 const u64 chunk_size = SZ_4K;
1442 struct gpu_buddy mm;
1443
1444 KUNIT_ASSERT_FALSE_MSG(test, gpu_buddy_init(&mm, test_size, chunk_size),
1445 "buddy_init failed\n");
1446
1447 KUNIT_ASSERT_FALSE_MSG(test, gpu_buddy_alloc_blocks(&mm, alloc_start,
1448 alloc_start + alloc_size,
1449 alloc_size, chunk_size,
1450 &allocated_list, 0),
1451 "buddy_alloc failed\n");
1452
1453 allocated_block = list_first_entry(&allocated_list, struct gpu_buddy_block, link);
1454 KUNIT_EXPECT_EQ(test, gpu_buddy_block_offset(allocated_block), alloc_start);
1455 KUNIT_EXPECT_EQ(test, gpu_buddy_block_size(&mm, allocated_block), alloc_size);
1456
1457 found_block = gpu_buddy_allocated_addr_to_block(&mm, alloc_start);
1458 KUNIT_EXPECT_PTR_EQ(test, found_block, allocated_block);
1459
1460 /* Unaligned address inside the allocated block (should resolve to the same block) */
1461 found_block = gpu_buddy_allocated_addr_to_block(&mm, alloc_start + 16);
1462 KUNIT_EXPECT_PTR_EQ(test, found_block, allocated_block);
1463
1464 /* An unallocated address inside the manager should return NULL. */
1465 found_block = gpu_buddy_allocated_addr_to_block(&mm,
1466 alloc_start - chunk_size);
1467 KUNIT_EXPECT_NULL(test, found_block);
1468
1469 /* An address outside the manager should return -ENXIO. */
1470 found_block = gpu_buddy_allocated_addr_to_block(&mm, test_size);
1471 KUNIT_EXPECT_EQ(test, PTR_ERR(found_block), -ENXIO);
1472
1473 /* 3. Standard inline cleanup flow */
1474 gpu_buddy_free_list(&mm, &allocated_list, 0);
1475 gpu_buddy_fini(&mm);
1476}
1477
1425static int gpu_buddy_suite_init(struct kunit_suite *suite)1478static int gpu_buddy_suite_init(struct kunit_suite *suite)
1426{1479{
1427 while (!random_seed)1480 while (!random_seed)
@@ -1446,6 +1499,7 @@ static struct kunit_case gpu_buddy_tests[] = { · 18 unmodified lines
1446 KUNIT_CASE(gpu_test_buddy_alloc_exceeds_max_order),1499 KUNIT_CASE(gpu_test_buddy_alloc_exceeds_max_order),
1447 KUNIT_CASE(gpu_test_buddy_offset_aligned_allocation),1500 KUNIT_CASE(gpu_test_buddy_offset_aligned_allocation),
1448 KUNIT_CASE(gpu_test_buddy_subtree_offset_alignment_stress),1501 KUNIT_CASE(gpu_test_buddy_subtree_offset_alignment_stress),
1502 KUNIT_CASE(gpu_test_buddy_addr_to_block),
1449 {}1503 {}
1450};1504};
1451 1505
include/drm/drm_bridge.h+1−1
@@ -40,9 +40,9 @@ struct drm_bridge; · 39 unmodified lines
40struct drm_bridge_timings;40struct drm_bridge_timings;
41struct drm_connector;41struct drm_connector;
42struct drm_display_info;42struct drm_display_info;
43struct drm_edid;
43struct drm_minor;44struct drm_minor;
44struct drm_panel;45struct drm_panel;
45struct edid;
46struct hdmi_codec_daifmt;46struct hdmi_codec_daifmt;
47struct hdmi_codec_params;47struct hdmi_codec_params;
48struct i2c_adapter;48struct i2c_adapter;
include/drm/drm_drv.h+3−1
@@ -34,6 +34,7 @@ · 33 unmodified lines
34 34
35#include <drm/drm_device.h>35#include <drm/drm_device.h>
36 36
37struct dmem_cgroup_init;
37struct dmem_cgroup_region;38struct dmem_cgroup_region;
38struct drm_fb_helper;39struct drm_fb_helper;
39struct drm_fb_helper_surface_size;40struct drm_fb_helper_surface_size;
@@ -433,7 +434,8 @@ void *__devm_drm_dev_alloc(struct device *parent, · 393 unmodified lines
433 434
434struct dmem_cgroup_region *435struct dmem_cgroup_region *
435drmm_cgroup_register_region(struct drm_device *dev,436drmm_cgroup_register_region(struct drm_device *dev,
436 const char *region_name, u64 size);437 const char *region_name,
438 const struct dmem_cgroup_init *init);
437 439
438/**440/**
439 * devm_drm_dev_alloc - Resource managed allocation of a &drm_device instance441 * devm_drm_dev_alloc - Resource managed allocation of a &drm_device instance
include/drm/ttm/ttm_bo.h+10−0
@@ -226,6 +226,11 @@ struct ttm_lru_walk_arg { · 225 unmodified lines
226 struct ww_acquire_ctx *ticket;226 struct ww_acquire_ctx *ticket;
227 /** @trylock_only: Only use trylock for locking. */227 /** @trylock_only: Only use trylock for locking. */
228 bool trylock_only;228 bool trylock_only;
229 /**
230 * @sleeping_lock: Use sleeping locks even with %NULL @ticket.
231 * @trylock_only has precedence over this field.
232 */
233 bool sleeping_lock;
229};234};
230 235
231/**236/**
@@ -431,6 +436,11 @@ void ttm_bo_unpin(struct ttm_buffer_object *bo); · 199 unmodified lines
431int ttm_bo_evict_first(struct ttm_device *bdev,436int ttm_bo_evict_first(struct ttm_device *bdev,
432 struct ttm_resource_manager *man,437 struct ttm_resource_manager *man,
433 struct ttm_operation_ctx *ctx);438 struct ttm_operation_ctx *ctx);
439s64 ttm_bo_evict_cgroup(struct ttm_device *bdev,
440 struct ttm_resource_manager *man,
441 struct dmem_cgroup_pool_state *limit_pool,
442 s64 target_bytes,
443 struct ttm_operation_ctx *ctx);
434int ttm_bo_access(struct ttm_buffer_object *bo, unsigned long offset,444int ttm_bo_access(struct ttm_buffer_object *bo, unsigned long offset,
435 void *buf, int len, int write);445 void *buf, int len, int write);
436vm_fault_t ttm_bo_vm_reserve(struct ttm_buffer_object *bo,446vm_fault_t ttm_bo_vm_reserve(struct ttm_buffer_object *bo,
include/drm/ttm/ttm_resource.h+12−1
@@ -39,6 +39,7 @@ · 38 unmodified lines
39 39
40struct dentry;40struct dentry;
41struct dmem_cgroup_device;41struct dmem_cgroup_device;
42struct dmem_cgroup_region;
42struct drm_printer;43struct drm_printer;
43struct ttm_device;44struct ttm_device;
44struct ttm_resource_manager;45struct ttm_resource_manager;
@@ -458,10 +459,14 @@ void ttm_resource_init(struct ttm_buffer_object *bo, · 413 unmodified lines
458void ttm_resource_fini(struct ttm_resource_manager *man,459void ttm_resource_fini(struct ttm_resource_manager *man,
459 struct ttm_resource *res);460 struct ttm_resource *res);
460 461
462int ttm_resource_try_charge(struct ttm_buffer_object *bo,
463 const struct ttm_place *place,
464 struct dmem_cgroup_pool_state **ret_pool,
465 struct dmem_cgroup_pool_state **ret_limit_pool);
461int ttm_resource_alloc(struct ttm_buffer_object *bo,466int ttm_resource_alloc(struct ttm_buffer_object *bo,
462 const struct ttm_place *place,467 const struct ttm_place *place,
463 struct ttm_resource **res,468 struct ttm_resource **res,
464 struct dmem_cgroup_pool_state **ret_limit_pool);469 struct dmem_cgroup_pool_state *charge_pool);
465void ttm_resource_free(struct ttm_buffer_object *bo, struct ttm_resource **res);470void ttm_resource_free(struct ttm_buffer_object *bo, struct ttm_resource **res);
466bool ttm_resource_intersects(struct ttm_device *bdev,471bool ttm_resource_intersects(struct ttm_device *bdev,
467 struct ttm_resource *res,472 struct ttm_resource *res,
@@ -477,6 +482,12 @@ void ttm_resource_manager_init(struct ttm_resource_manager *man, · 9 unmodified lines
477 struct ttm_device *bdev,482 struct ttm_device *bdev,
478 uint64_t size);483 uint64_t size);
479 484
485void ttm_resource_manager_set_dmem_region(struct ttm_resource_manager *man,
486 struct dmem_cgroup_region *region);
487
488int ttm_resource_manager_dmem_reclaim(struct dmem_cgroup_pool_state *pool,
489 u64 target_bytes, void *priv);
490
480int ttm_resource_manager_evict_all(struct ttm_device *bdev,491int ttm_resource_manager_evict_all(struct ttm_device *bdev,
481 struct ttm_resource_manager *man);492 struct ttm_resource_manager *man);
482 493
include/linux/cgroup.h+21−0
@@ -623,6 +623,27 @@ static inline struct cgroup *cgroup_ancestor(struct cgroup *cgrp, · 622 unmodified lines
623 return cgrp->ancestors[ancestor_level];623 return cgrp->ancestors[ancestor_level];
624}624}
625 625
626/**
627 * cgroup_common_ancestor - find common ancestor of two cgroups
628 * @a: first cgroup to find common ancestor of
629 * @b: second cgroup to find common ancestor of
630 *
631 * Find the first cgroup that is an ancestor of both @a and @b, if it exists
632 * and return a pointer to it. If such a cgroup doesn't exist, return NULL.
633 *
634 * This function is safe to call as long as both @a and @b are accessible.
635 */
636static inline struct cgroup *cgroup_common_ancestor(struct cgroup *a,
637 struct cgroup *b)
638{
639 int level;
640
641 for (level = min(a->level, b->level); level >= 0; level--)
642 if (a->ancestors[level] == b->ancestors[level])
643 return a->ancestors[level];
644 return NULL;
645}
646
626/**647/**
627 * task_under_cgroup_hierarchy - test task's membership of cgroup ancestry648 * task_under_cgroup_hierarchy - test task's membership of cgroup ancestry
628 * @task: the task to be tested649 * @task: the task to be tested
include/linux/cgroup_dmem.h+60−3
@@ -14,8 +14,40 @@ struct dmem_cgroup_pool_state; · 13 unmodified lines
14/* Opaque definition of a cgroup region, used internally */14/* Opaque definition of a cgroup region, used internally */
15struct dmem_cgroup_region;15struct dmem_cgroup_region;
16 16
17/**
18 * struct dmem_cgroup_ops - Operations for a dmem cgroup region.
19 * @reclaim: Optional callback invoked when dmem.max is set below the current
20 * usage of a pool. The driver should attempt to free at least
21 * @target_bytes from @pool. May be called multiple times if usage
22 * remains above the limit after returning.
23 *
24 * Return: 0 if some progress was made (even if less than
25 * @target_bytes was freed), -ENOSPC if no progress could be made
26 * (the caller will retry up to a bounded number of times), or
27 * another negative error code if a fatal error occurred (stops
28 * further reclaim attempts immediately).
29 */
30struct dmem_cgroup_ops {
31 int (*reclaim)(struct dmem_cgroup_pool_state *pool,
32 u64 target_bytes, void *priv);
33};
34
35/**
36 * struct dmem_cgroup_init - Initialization parameters for a dmem cgroup region.
37 * @size: Size of the region in bytes.
38 * @ops: Optional operations for this region. May be NULL.
39 * @reclaim_priv: Opaque pointer passed to @ops->reclaim. May be NULL.
40 */
41struct dmem_cgroup_init {
42 u64 size;
43 const struct dmem_cgroup_ops *ops;
44 void *reclaim_priv;
45};
46
17#if IS_ENABLED(CONFIG_CGROUP_DMEM)47#if IS_ENABLED(CONFIG_CGROUP_DMEM)
18struct dmem_cgroup_region *dmem_cgroup_register_region(u64 size, const char *name_fmt, ...) __printf(2,3);48struct dmem_cgroup_region *
49dmem_cgroup_register_region(const struct dmem_cgroup_init *init,
50 const char *name_fmt, ...) __printf(2, 3);
19void dmem_cgroup_unregister_region(struct dmem_cgroup_region *region);51void dmem_cgroup_unregister_region(struct dmem_cgroup_region *region);
20int dmem_cgroup_try_charge(struct dmem_cgroup_region *region, u64 size,52int dmem_cgroup_try_charge(struct dmem_cgroup_region *region, u64 size,
21 struct dmem_cgroup_pool_state **ret_pool,53 struct dmem_cgroup_pool_state **ret_pool,
@@ -24,11 +56,17 @@ void dmem_cgroup_uncharge(struct dmem_cgroup_pool_state *pool, u64 size); · 2 unmodified lines
24bool dmem_cgroup_state_evict_valuable(struct dmem_cgroup_pool_state *limit_pool,56bool dmem_cgroup_state_evict_valuable(struct dmem_cgroup_pool_state *limit_pool,
25 struct dmem_cgroup_pool_state *test_pool,57 struct dmem_cgroup_pool_state *test_pool,
26 bool ignore_low, bool *ret_hit_low);58 bool ignore_low, bool *ret_hit_low);
59bool dmem_cgroup_below_min(struct dmem_cgroup_pool_state *root,
60 struct dmem_cgroup_pool_state *test);
61bool dmem_cgroup_below_low(struct dmem_cgroup_pool_state *root,
62 struct dmem_cgroup_pool_state *test);
63struct dmem_cgroup_pool_state *dmem_cgroup_get_common_ancestor(struct dmem_cgroup_pool_state *a,
64 struct dmem_cgroup_pool_state *b);
27 65
28void dmem_cgroup_pool_state_put(struct dmem_cgroup_pool_state *pool);66void dmem_cgroup_pool_state_put(struct dmem_cgroup_pool_state *pool);
29#else67#else
30static inline __printf(2,3) struct dmem_cgroup_region *68static inline __printf(2, 3) struct dmem_cgroup_region *
31dmem_cgroup_register_region(u64 size, const char *name_fmt, ...)69dmem_cgroup_register_region(const struct dmem_cgroup_init *init, const char *name_fmt, ...)
32{70{
33 return NULL;71 return NULL;
34}72}
@@ -59,6 +97,25 @@ bool dmem_cgroup_state_evict_valuable(struct dmem_cgroup_pool_state *limit_pool, · 24 unmodified lines
59 return true;97 return true;
60}98}
61 99
100static inline bool dmem_cgroup_below_min(struct dmem_cgroup_pool_state *root,
101 struct dmem_cgroup_pool_state *test)
102{
103 return false;
104}
105
106static inline bool dmem_cgroup_below_low(struct dmem_cgroup_pool_state *root,
107 struct dmem_cgroup_pool_state *test)
108{
109 return false;
110}
111
112static inline
113struct dmem_cgroup_pool_state *dmem_cgroup_get_common_ancestor(struct dmem_cgroup_pool_state *a,
114 struct dmem_cgroup_pool_state *b)
115{
116 return NULL;
117}
118
62static inline void dmem_cgroup_pool_state_put(struct dmem_cgroup_pool_state *pool)119static inline void dmem_cgroup_pool_state_put(struct dmem_cgroup_pool_state *pool)
63{ }120{ }
64 121
include/linux/gpu_buddy.h+2−0
@@ -287,6 +287,8 @@ void gpu_buddy_reset_clear(struct gpu_buddy *mm, bool is_clear); · 286 unmodified lines
287 287
288void gpu_buddy_free_block(struct gpu_buddy *mm, struct gpu_buddy_block *block);288void gpu_buddy_free_block(struct gpu_buddy *mm, struct gpu_buddy_block *block);
289 289
290struct gpu_buddy_block *gpu_buddy_allocated_addr_to_block(struct gpu_buddy *mm, u64 addr);
291
290void gpu_buddy_free_list(struct gpu_buddy *mm,292void gpu_buddy_free_list(struct gpu_buddy *mm,
291 struct list_head *objects,293 struct list_head *objects,
292 unsigned int flags);294 unsigned int flags);
include/uapi/drm/nouveau_drm.h+1−0
@@ -89,6 +89,7 @@ struct drm_nouveau_getparam { · 88 unmodified lines
89#define NOUVEAU_FIFO_ENGINE_PPP 0x0489#define NOUVEAU_FIFO_ENGINE_PPP 0x04
90#define NOUVEAU_FIFO_ENGINE_BSP 0x0890#define NOUVEAU_FIFO_ENGINE_BSP 0x08
91#define NOUVEAU_FIFO_ENGINE_CE 0x3091#define NOUVEAU_FIFO_ENGINE_CE 0x30
92#define NOUVEAU_FIFO_ENGINE_NVDEC 0x300
92 93
93struct drm_nouveau_channel_alloc {94struct drm_nouveau_channel_alloc {
94 __u32 fb_ctxdma_handle;95 __u32 fb_ctxdma_handle;
kernel/cgroup/dmem.c+178−16
@@ -17,6 +17,13 @@ · 16 unmodified lines
17#include <linux/refcount.h>17#include <linux/refcount.h>
18#include <linux/rculist.h>18#include <linux/rculist.h>
19#include <linux/slab.h>19#include <linux/slab.h>
20#include <linux/srcu.h>
21
22/* Maximum reclaim attempts before giving up when lowering dmem.max. */
23#define DMEM_MAX_RECLAIM_RETRIES 16
24
25/* SRCU domain serialising reclaim callbacks against region unregistration. */
26DEFINE_STATIC_SRCU(dmemcg_srcu);
20 27
21struct dmem_cgroup_region {28struct dmem_cgroup_region {
22 /**29 /**
@@ -48,9 +55,18 @@ struct dmem_cgroup_region { · 25 unmodified lines
48 55
49 /**56 /**
50 * @unregistered: Whether the region is unregistered by its caller.57 * @unregistered: Whether the region is unregistered by its caller.
51 * No new pools should be added to the region afterwards.58 * No new pools should be added to the region afterwards, and no new
59 * reclaim callbacks should be invoked.
52 */60 */
53 bool unregistered;61 bool unregistered;
62
63 /**
64 * @ops: Optional driver operations for this region.
65 */
66 const struct dmem_cgroup_ops *ops;
67
68 /** @reclaim_priv: Private data passed to @ops->reclaim. */
69 void *reclaim_priv;
54};70};
55 71
56struct dmemcg_state {72struct dmemcg_state {
@@ -145,21 +161,52 @@ static void free_cg_pool(struct dmem_cgroup_pool_state *pool) · 88 unmodified lines
145}161}
146 162
147static void163static void
148set_resource_min(struct dmem_cgroup_pool_state *pool, u64 val)164set_resource_min(struct dmem_cgroup_pool_state *pool, u64 val, bool nonblock)
149{165{
150 page_counter_set_min(&pool->cnt, val);166 page_counter_set_min(&pool->cnt, val);
151}167}
152 168
153static void169static void
154set_resource_low(struct dmem_cgroup_pool_state *pool, u64 val)170set_resource_low(struct dmem_cgroup_pool_state *pool, u64 val, bool nonblock)
155{171{
156 page_counter_set_low(&pool->cnt, val);172 page_counter_set_low(&pool->cnt, val);
157}173}
158 174
159static void175static void
160set_resource_max(struct dmem_cgroup_pool_state *pool, u64 val)176set_resource_max(struct dmem_cgroup_pool_state *pool, u64 val, bool nonblock)
161{177{
162 page_counter_set_max(&pool->cnt, val);178 struct dmem_cgroup_region *region = pool->region;
179 unsigned long limit = (unsigned long)val;
180
181 /* Apply the new limit immediately so concurrent allocations are throttled. */
182 xchg(&pool->cnt.max, limit);
183
184 if (nonblock)
185 return;
186
187 int srcu_idx = srcu_read_lock(&dmemcg_srcu);
188
189 if (!READ_ONCE(region->unregistered) && region->ops && region->ops->reclaim) {
190 for (int retries = DMEM_MAX_RECLAIM_RETRIES; ; ) {
191 u64 usage = page_counter_read(&pool->cnt);
192 int ret;
193
194 if (usage <= limit)
195 break;
196
197 if (signal_pending(current))
198 break;
199
200 ret = region->ops->reclaim(pool, usage - limit, region->reclaim_priv);
201
202 /* -ENOSPC means no progress; other errors are fatal. */
203 if (ret && (ret != -ENOSPC || !retries--))
204 break;
205
206 cond_resched();
207 }
208 }
209 srcu_read_unlock(&dmemcg_srcu, srcu_idx);
163}210}
164 211
165static u64 get_resource_low(struct dmem_cgroup_pool_state *pool)212static u64 get_resource_low(struct dmem_cgroup_pool_state *pool)
@@ -189,9 +236,10 @@ static u64 get_resource_peak(struct dmem_cgroup_pool_state *pool) · 23 unmodified lines
189 236
190static void reset_all_resource_limits(struct dmem_cgroup_pool_state *rpool)237static void reset_all_resource_limits(struct dmem_cgroup_pool_state *rpool)
191{238{
192 set_resource_min(rpool, 0);239 set_resource_min(rpool, 0, false);
193 set_resource_low(rpool, 0);240 set_resource_low(rpool, 0, false);
194 set_resource_max(rpool, PAGE_COUNTER_MAX);241 /* nonblock: raising to max makes reclaim a no-op; sleeping is forbidden here. */
242 set_resource_max(rpool, PAGE_COUNTER_MAX, true);
195}243}
196 244
197static void dmemcs_offline(struct cgroup_subsys_state *css)245static void dmemcs_offline(struct cgroup_subsys_state *css)
@@ -468,7 +516,10 @@ static void dmemcg_free_region(struct kref *ref) · 270 unmodified lines
468 * dmem_cgroup_unregister_region() - Unregister a previously registered region.516 * dmem_cgroup_unregister_region() - Unregister a previously registered region.
469 * @region: The region to unregister.517 * @region: The region to unregister.
470 *518 *
471 * This function undoes dmem_cgroup_register_region.519 * This function undoes dmem_cgroup_register_region. It drains any
520 * in-flight reclaim callbacks before returning, so the caller may safely
521 * free the resources pointed to by the @reclaim_priv that was passed at
522 * registration time.
472 */523 */
473void dmem_cgroup_unregister_region(struct dmem_cgroup_region *region)524void dmem_cgroup_unregister_region(struct dmem_cgroup_region *region)
474{525{
@@ -493,16 +544,18 @@ void dmem_cgroup_unregister_region(struct dmem_cgroup_region *region) · 18 unmodified lines
493 * no new pools should be added to the dead region544 * no new pools should be added to the dead region
494 * by get_cg_pool_unlocked.545 * by get_cg_pool_unlocked.
495 */546 */
496 region->unregistered = true;547 WRITE_ONCE(region->unregistered, true);
497 spin_unlock(&dmemcg_lock);548 spin_unlock(&dmemcg_lock);
498 549
550 synchronize_srcu(&dmemcg_srcu);
551
499 kref_put(&region->ref, dmemcg_free_region);552 kref_put(&region->ref, dmemcg_free_region);
500}553}
501EXPORT_SYMBOL_GPL(dmem_cgroup_unregister_region);554EXPORT_SYMBOL_GPL(dmem_cgroup_unregister_region);
502 555
503/**556/**
504 * dmem_cgroup_register_region() - Register a regions for dev cgroup.557 * dmem_cgroup_register_region() - Register a regions for dev cgroup.
505 * @size: Size of region to register, in bytes.558 * @init: Initialization parameters for the region.
506 * @fmt: Region parameters to register559 * @fmt: Region parameters to register
507 *560 *
508 * This function registers a node in the dmem cgroup with the561 * This function registers a node in the dmem cgroup with the
@@ -511,13 +564,15 @@ EXPORT_SYMBOL_GPL(dmem_cgroup_unregister_region); · 2 unmodified lines
511 *564 *
512 * Return: NULL or a struct on success, PTR_ERR on failure.565 * Return: NULL or a struct on success, PTR_ERR on failure.
513 */566 */
514struct dmem_cgroup_region *dmem_cgroup_register_region(u64 size, const char *fmt, ...)567struct dmem_cgroup_region *
568dmem_cgroup_register_region(const struct dmem_cgroup_init *init,
569 const char *fmt, ...)
515{570{
516 struct dmem_cgroup_region *ret;571 struct dmem_cgroup_region *ret;
517 char *region_name;572 char *region_name;
518 va_list ap;573 va_list ap;
519 574
520 if (!size)575 if (!init || !init->size)
521 return NULL;576 return NULL;
522 577
523 va_start(ap, fmt);578 va_start(ap, fmt);
@@ -534,7 +589,9 @@ struct dmem_cgroup_region *dmem_cgroup_register_region(u64 size, const char *fmt · 10 unmodified lines
534 589
535 INIT_LIST_HEAD(&ret->pools);590 INIT_LIST_HEAD(&ret->pools);
536 ret->name = region_name;591 ret->name = region_name;
537 ret->size = size;592 ret->size = init->size;
593 ret->ops = init->ops;
594 ret->reclaim_priv = init->reclaim_priv;
538 kref_init(&ret->ref);595 kref_init(&ret->ref);
539 596
540 spin_lock(&dmemcg_lock);597 spin_lock(&dmemcg_lock);
@@ -700,6 +757,110 @@ err: · 159 unmodified lines
700}757}
701EXPORT_SYMBOL_GPL(dmem_cgroup_try_charge);758EXPORT_SYMBOL_GPL(dmem_cgroup_try_charge);
702 759
760/**
761 * dmem_cgroup_below_min() - Tests whether current usage is within min limit.
762 *
763 * @root: Root of the subtree to calculate protection for, or NULL to calculate global protection.
764 * @test: The pool to test the usage/min limit of.
765 *
766 * Return: true if usage is below min and the cgroup is protected, false otherwise.
767 */
768bool dmem_cgroup_below_min(struct dmem_cgroup_pool_state *root,
769 struct dmem_cgroup_pool_state *test)
770{
771 if (root == test || !pool_parent(test))
772 return false;
773
774 if (!root) {
775 for (root = test; pool_parent(root); root = pool_parent(root))
776 {}
777 }
778
779 /*
780 * In mem_cgroup_below_min(), the memcg pendant, this call is missing.
781 * mem_cgroup_below_min() gets called during traversal of the cgroup tree, where
782 * protection is already calculated as part of the traversal. dmem cgroup eviction
783 * does not traverse the cgroup tree, so we need to recalculate effective protection
784 * here.
785 */
786 dmem_cgroup_calculate_protection(root, test);
787 return page_counter_read(&test->cnt) <= READ_ONCE(test->cnt.emin);
788}
789EXPORT_SYMBOL_GPL(dmem_cgroup_below_min);
790
791/**
792 * dmem_cgroup_below_low() - Tests whether current usage is within low limit.
793 *
794 * @root: Root of the subtree to calculate protection for, or NULL to calculate global protection.
795 * @test: The pool to test the usage/low limit of.
796 *
797 * Return: true if usage is below low and the cgroup is protected, false otherwise.
798 */
799bool dmem_cgroup_below_low(struct dmem_cgroup_pool_state *root,
800 struct dmem_cgroup_pool_state *test)
801{
802 if (root == test || !pool_parent(test))
803 return false;
804
805 if (!root) {
806 for (root = test; pool_parent(root); root = pool_parent(root))
807 {}
808 }
809
810 /*
811 * In mem_cgroup_below_low(), the memcg pendant, this call is missing.
812 * mem_cgroup_below_low() gets called during traversal of the cgroup tree, where
813 * protection is already calculated as part of the traversal. dmem cgroup eviction
814 * does not traverse the cgroup tree, so we need to recalculate effective protection
815 * here.
816 */
817 dmem_cgroup_calculate_protection(root, test);
818 return page_counter_read(&test->cnt) <= READ_ONCE(test->cnt.elow);
819}
820EXPORT_SYMBOL_GPL(dmem_cgroup_below_low);
821
822/**
823 * dmem_cgroup_get_common_ancestor(): Find the first common ancestor of two pools.
824 * @a: First pool to find the common ancestor of.
825 * @b: First pool to find the common ancestor of.
826 *
827 * Return: The first pool that is a parent of both @a and @b, or NULL if either @a or @b are NULL,
828 * or if such a pool does not exist. A reference to the returned pool is grabbed and must be
829 * released by the caller when it is done using the pool.
830 */
831struct dmem_cgroup_pool_state *dmem_cgroup_get_common_ancestor(struct dmem_cgroup_pool_state *a,
832 struct dmem_cgroup_pool_state *b)
833{
834 struct cgroup *ancestor_cgroup;
835 struct cgroup_subsys_state *ancestor_css;
836 struct dmemcg_state *ancestor_dmemcs = NULL;
837 struct dmem_cgroup_pool_state *pool = NULL;
838
839 if (!a || !b)
840 return NULL;
841
842 ancestor_cgroup = cgroup_common_ancestor(a->cs->css.cgroup, b->cs->css.cgroup);
843 if (!ancestor_cgroup)
844 return NULL;
845
846 rcu_read_lock();
847 ancestor_css = cgroup_e_css(ancestor_cgroup, &dmem_cgrp_subsys);
848 if (css_tryget(ancestor_css))
849 ancestor_dmemcs = css_to_dmemcs(ancestor_css);
850 rcu_read_unlock();
851
852 if (ancestor_dmemcs) {
853 pool = get_cg_pool_unlocked(css_to_dmemcs(ancestor_css),
854 a->region);
855 if (WARN_ON(IS_ERR(pool))) {
856 pool = NULL;
857 css_put(ancestor_css);
858 }
859 }
860 return pool;
861}
862EXPORT_SYMBOL_GPL(dmem_cgroup_get_common_ancestor);
863
703static int dmem_cgroup_region_capacity_show(struct seq_file *sf, void *v)864static int dmem_cgroup_region_capacity_show(struct seq_file *sf, void *v)
704{865{
705 struct dmem_cgroup_region *region;866 struct dmem_cgroup_region *region;
@@ -731,11 +892,12 @@ static int dmemcg_parse_limit(char *options, u64 *new_limit) · 25 unmodified lines
731 892
732static ssize_t dmemcg_limit_write(struct kernfs_open_file *of,893static ssize_t dmemcg_limit_write(struct kernfs_open_file *of,
733 char *buf, size_t nbytes, loff_t off,894 char *buf, size_t nbytes, loff_t off,
734 void (*apply)(struct dmem_cgroup_pool_state *, u64))895 void (*apply)(struct dmem_cgroup_pool_state *, u64, bool))
735{896{
736 struct dmemcg_state *dmemcs = css_to_dmemcs(of_css(of));897 struct dmemcg_state *dmemcs = css_to_dmemcs(of_css(of));
737 struct dmem_cgroup_pool_state *pool;898 struct dmem_cgroup_pool_state *pool;
738 struct dmem_cgroup_region *region;899 struct dmem_cgroup_region *region;
900 bool nonblock = of->file->f_flags & O_NONBLOCK;
739 char *region_name;901 char *region_name;
740 u64 new_limit;902 u64 new_limit;
741 int err;903 int err;
@@ -761,7 +923,7 @@ static ssize_t dmemcg_limit_write(struct kernfs_open_file *of, · 19 unmodified lines
761 goto out_put;923 goto out_put;
762 }924 }
763 925
764 apply(pool, new_limit);926 apply(pool, new_limit, nonblock);
765 dmemcg_pool_put(pool);927 dmemcg_pool_put(pool);
766 928
767out_put:929out_put:

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t