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
2828 - const: renesas,r9a09g057-mipi-dsi
2929
3030 - enum:
31+ - renesas,r9a08g046-mipi-dsi # RZ/G3L
3132 - renesas,r9a09g057-mipi-dsi # RZ/V2H(P)
3233
3334 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+
7+title: Renesas RZ/G3L LVDS Encoder
8+
9+maintainers:
10+ - Biju Das <biju.das.jz@bp.renesas.com>
11+ - Tommaso Merciai <tommaso.merciai.xr@bp.renesas.com>
12+
13+description: |
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+
18+properties:
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+
71+required:
72+ - compatible
73+ - reg
74+ - clocks
75+ - clock-names
76+ - resets
77+ - reset-names
78+ - power-domains
79+ - ports
80+
81+additionalProperties: false
82+
83+examples:
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
1919 - anbernic,rg-ds-display-bottom
2020 - anbernic,rg-ds-display-top
2121 - chongzhou,cz101b4001
22+ - dcltek,dt300250
2223 - kingdisplay,kd101ne3-40ti
2324 - melfas,lmfbx101117480
2425 - radxa,display-10hd-ad001
Documentation/devicetree/bindings/display/panel/panel-simple.yaml+2−0
@@ -37,6 +37,8 @@ properties: · 36 unmodified lines
3737 - ampire,am-480272h3tmqw-t01h
3838 # Ampire AM-800480L1TMQW-T00H 5" WVGA TFT LCD panel
3939 - ampire,am-800480l1tmqw-t00h
40+ # Ampire AM-800480N3TZQW-00H 5" WVGA TFT LCD panel
41+ - ampire,am-800480n3tzqw-00h
4042 # Ampire AM-800480R3TMQW-A1H 7.0" WVGA TFT LCD panel
4143 - ampire,am800480r3tmqwa1h
4244 # 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
2222 enum:
2323 # Anberic RG353V-V2 5.0" 640x480 TFT LCD panel
2424 - anbernic,rg353v-panel-v2
25+ # AYANEO Pocket DS lower 5.0" 1024x768 IPS LCD panel
26+ - ayaneo,pocket-ds-lower-panel
2527 # GameForce Chi 3.5" 640x480 TFT LCD panel
2628 - gameforce,chi-panel
2729 # 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
2020 - enum:
2121 - renesas,r9a07g043u-du # RZ/G2UL
2222 - renesas,r9a07g044-du # RZ/G2{L,LC}
23+ - renesas,r9a08g046-du # RZ/G3L
2324 - renesas,r9a09g057-du # RZ/V2H(P)
2425 - renesas,r9a09g077-du # RZ/T2H
2526 - items:
@@ -65,7 +66,7 @@ properties: · 39 unmodified lines
6566 model-dependent. Each port shall have a single endpoint.
6667
6768 patternProperties:
68− "^port@[0-1]$":
69+ "^port@[0-2]$":
6970 $ref: /schemas/graph.yaml#/properties/port
7071 unevaluatedProperties: false
7172
@@ -108,6 +109,7 @@ allOf: · 36 unmodified lines
108109 port@0:
109110 description: DPI
110111 port@1: false
112+ port@2: false
111113
112114 required:
113115 - port@0
@@ -124,10 +126,31 @@ allOf: · 10 unmodified lines
124126 description: DSI
125127 port@1:
126128 description: DPI
129+ port@2: false
127130
128131 required:
129132 - port@0
130133 - 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
131154 - if:
132155 properties:
133156 compatible:
@@ -140,6 +163,7 @@ allOf: · 6 unmodified lines
140163 port@0:
141164 description: DSI
142165 port@1: false
166+ port@2: false
143167
144168 required:
145169 - port@0
Documentation/devicetree/bindings/vendor-prefixes.yaml+4−0
@@ -409,6 +409,8 @@ patternProperties: · 408 unmodified lines
409409 description: DataImage, Inc.
410410 "^davicom,.*":
411411 description: DAVICOM Semiconductor, Inc.
412+ "^dcltek,.*":
413+ description: DCL Technologies Inc.
412414 "^deepcomputing,.*":
413415 description: DeepComputing (HK) Limited
414416 "^dell,.*":
@@ -1253,6 +1255,8 @@ patternProperties: · 838 unmodified lines
12531255 description: OpenWrt
12541256 "^option,.*":
12551257 description: Option NV
1258+ "^optologic,.*":
1259+ description: Opto Logic S.A.
12561260 "^oranth,.*":
12571261 description: Shenzhen Oranth Technology Co., Ltd.
12581262 "^ORCL,.*":
drivers/dma-buf/udmabuf.c+2−2
@@ -20,9 +20,9 @@ static int list_limit = 1024; · 19 unmodified lines
2020 module_param(list_limit, int, 0644);
2121 MODULE_PARM_DESC(list_limit, "udmabuf_create_list->count limit. Default is 1024.");
2222
23−static int size_limit_mb = 64;
23+static int size_limit_mb = INT_MAX;
2424 module_param(size_limit_mb, int, 0644);
25−MODULE_PARM_DESC(size_limit_mb, "Max size of a dmabuf, in megabytes. Default is 64.");
25+MODULE_PARM_DESC(size_limit_mb, "Max size of a dmabuf, in megabytes. Default is INT_MAX.");
2626
2727 struct udmabuf {
2828 pgoff_t pagecount;
drivers/gpu/Kconfig+2−1
@@ -7,7 +7,8 @@ config GPU_BUDDY · 6 unmodified lines
77
88 config GPU_BUDDY_KUNIT_TEST
99 tristate "KUnit tests for GPU buddy allocator" if !KUNIT_ALL_TESTS
10− depends on GPU_BUDDY && KUNIT
10+ depends on KUNIT
11+ select GPU_BUDDY
1112 default KUNIT_ALL_TESTS
1213 help
1314 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
630630 }
631631 EXPORT_SYMBOL(gpu_buddy_free_block);
632632
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+ */
642+struct 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+}
684+EXPORT_SYMBOL(gpu_buddy_allocated_addr_to_block);
685+
633686 static void __gpu_buddy_free_list(struct gpu_buddy *mm,
634687 struct list_head *objects,
635688 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
15261526 dma_resv_for_each_fence(&resv_cursor, bo->base.resv,
15271527 DMA_RESV_USAGE_BOOKKEEP, f) {
15281528 if (amdkfd_fence_check_mm(f, current->mm) &&
1529− !(place->flags & TTM_PL_FLAG_CONTIGUOUS))
1529+ !(place && (place->flags & TTM_PL_FLAG_CONTIGUOUS)))
15301530 return false;
15311531 }
15321532
drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c+62−3
@@ -23,6 +23,8 @@ · 22 unmodified lines
2323 */
2424
2525 #include <linux/dma-mapping.h>
26+#include <linux/cgroup_dmem.h>
27+#include <linux/pm_runtime.h>
2628 #include <drm/ttm/ttm_range_manager.h>
2729 #include <drm/drm_drv.h>
2830 #include <drm/drm_buddy.h>
@@ -905,6 +907,38 @@ static const struct ttm_resource_manager_func amdgpu_vram_mgr_func = { · 876 unmodified lines
905907 .debug = amdgpu_vram_mgr_debug
906908 };
907909
910+static const struct dmem_cgroup_ops amdgpu_vram_mgr_dmem_ops;
911+
912+static 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+
933+out:
934+ drm_dev_exit(idx);
935+ return ret;
936+}
937+
938+static const struct dmem_cgroup_ops amdgpu_vram_mgr_dmem_ops = {
939+ .reclaim = amdgpu_vram_mgr_dmem_reclaim,
940+};
941+
908942 /**
909943 * amdgpu_vram_mgr_init - init VRAM manager and DRM MM
910944 *
@@ -916,11 +950,9 @@ int amdgpu_vram_mgr_init(struct amdgpu_device *adev) · 5 unmodified lines
916950 {
917951 struct amdgpu_vram_mgr *mgr = &adev->mman.vram_mgr;
918952 struct ttm_resource_manager *man = &mgr->manager;
953+ struct dmem_cgroup_region *cg;
919954 int err;
920955
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);
924956 ttm_resource_manager_init(man, &adev->mman.bdev,
925957 adev->gmc.real_vram_size);
926958
@@ -935,6 +967,20 @@ int amdgpu_vram_mgr_init(struct amdgpu_device *adev) · 8 unmodified lines
935967 if (err)
936968 return err;
937969
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+
938984 ttm_set_driver_manager(&adev->mman.bdev, TTM_PL_VRAM, &mgr->manager);
939985 ttm_resource_manager_set_used(man, true);
940986 return 0;
@@ -958,6 +1004,19 @@ void amdgpu_vram_mgr_fini(struct amdgpu_device *adev) · 17 unmodified lines
9581004 ttm_resource_manager_set_used(man, false);
9591005
9601006 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+
9611020 if (ret)
9621021 return;
9631022
drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.h+3−0
@@ -26,6 +26,8 @@ · 25 unmodified lines
2626
2727 #include <linux/gpu_buddy.h>
2828
29+struct dmem_cgroup_region;
30+
2931 struct amdgpu_vram_mgr {
3032 struct ttm_resource_manager manager;
3133 struct gpu_buddy mm;
@@ -36,6 +38,7 @@ struct amdgpu_vram_mgr { · 4 unmodified lines
3638 atomic64_t vis_usage;
3739 u64 default_page_size;
3840 struct list_head allocated_vres_list;
41+ struct dmem_cgroup_region *cg_region;
3942 };
4043
4144 struct 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
14711471 };
14721472
14731473 static const struct i2c_device_id adv7511_i2c_ids[] = {
1474− { "adv7511", (kernel_ulong_t)&adv7511_chip_info },
1475− { "adv7511w", (kernel_ulong_t)&adv7511_chip_info },
1476− { "adv7513", (kernel_ulong_t)&adv7511_chip_info },
1477− { "adv7533", (kernel_ulong_t)&adv7533_chip_info },
1478− { "adv7535", (kernel_ulong_t)&adv7535_chip_info },
1474+ { .name = "adv7511", .driver_data = (kernel_ulong_t)&adv7511_chip_info },
1475+ { .name = "adv7511w", .driver_data = (kernel_ulong_t)&adv7511_chip_info },
1476+ { .name = "adv7513", .driver_data = (kernel_ulong_t)&adv7511_chip_info },
1477+ { .name = "adv7533", .driver_data = (kernel_ulong_t)&adv7533_chip_info },
1478+ { .name = "adv7535", .driver_data = (kernel_ulong_t)&adv7535_chip_info },
14791479 { }
14801480 };
14811481 MODULE_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
783783 }
784784
785785 static const struct i2c_device_id anx6345_id[] = {
786− { "anx6345" },
786+ { .name = "anx6345" },
787787 { /* sentinel */ }
788788 };
789789 MODULE_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
29932993 }
29942994
29952995 static const struct i2c_device_id anx7625_id[] = {
2996− { "anx7625" },
2997− {}
2996+ { .name = "anx7625" },
2997+ { }
29982998 };
29992999
30003000 MODULE_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
784784 };
785785
786786 static const struct i2c_device_id chipone_i2c_id[] = {
787− { "chipone,icn6211" },
788− {},
787+ { .name = "chipone,icn6211" },
788+ { }
789789 };
790790 MODULE_DEVICE_TABLE(i2c, chipone_i2c_id);
791791
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
601601 MODULE_DEVICE_TABLE(of, ch7033_dt_ids);
602602
603603 static const struct i2c_device_id ch7033_ids[] = {
604− { "ch7033" },
604+ { .name = "ch7033" },
605605 { }
606606 };
607607 MODULE_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
107107 Choose this to enable MIPI DSI controller found in Freescale i.MX93
108108 processor.
109109
110+config 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+
110121 endif # 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
1010 obj-$(CONFIG_DRM_IMX8QXP_PIXEL_LINK) += imx8qxp-pixel-link.o
1111 obj-$(CONFIG_DRM_IMX8QXP_PIXEL_LINK_TO_DPI) += imx8qxp-pxl2dpi.o
1212 obj-$(CONFIG_DRM_IMX93_MIPI_DSI) += imx93-mipi-dsi.o
13+obj-$(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+
26+struct imx93_pdfc {
27+ struct drm_bridge bridge;
28+ struct device *dev;
29+ struct regmap *regmap;
30+ u32 phy_bus_width;
31+};
32+
33+static struct imx93_pdfc *bridge_to_imx93_pdfc(struct drm_bridge *bridge)
34+{
35+ return container_of(bridge, struct imx93_pdfc, bridge);
36+}
37+
38+static int
39+imx93_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+
45+static 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 */
80+static 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+
87+static 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+
99+static u32 *
100+imx93_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+
134+static 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+
150+static 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+
160+static 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+
204+static const struct of_device_id imx93_pdfc_dt_ids[] = {
205+ { .compatible = "nxp,imx91-pdfc", },
206+ { .compatible = "nxp,imx93-pdfc", },
207+ { /* sentinel */ }
208+};
209+MODULE_DEVICE_TABLE(of, imx93_pdfc_dt_ids);
210+
211+static 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+};
218+module_platform_driver(imx93_pdfc_bridge_driver);
219+
220+MODULE_DESCRIPTION("NXP i.MX93 parallel display format configuration driver");
221+MODULE_AUTHOR("Liu Ying <victor.liu@nxp.com>");
222+MODULE_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
910910 MODULE_DEVICE_TABLE(of, it6263_of_match);
911911
912912 static const struct i2c_device_id it6263_i2c_ids[] = {
913− { "it6263" },
913+ { .name = "it6263" },
914914 { }
915915 };
916916 MODULE_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
36523652 }
36533653
36543654 static const struct i2c_device_id it6505_id[] = {
3655− { "it6505" },
3655+ { .name = "it6505" },
36563656 { }
36573657 };
36583658
drivers/gpu/drm/bridge/lontium-lt8713sx.c+1−1
@@ -572,7 +572,7 @@ static void lt8713sx_remove(struct i2c_client *client) · 571 unmodified lines
572572 }
573573
574574 static struct i2c_device_id lt8713sx_id[] = {
575− { "lontium,lt8713sx", 0 },
575+ { .name = "lontium,lt8713sx" },
576576 { /* sentinel */ }
577577 };
578578
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
677677 static int lt8912_get_regulators(struct lt8912 *lt)
678678 {
679679 unsigned int i;
680− const char * const supply_names[] = {
680+ static const char * const supply_names[] = {
681681 "vdd", "vccmipirx", "vccsysclk", "vcclvdstx",
682682 "vcchdmitx", "vcclvdspll", "vcchdmipll"
683683 };
@@ -820,8 +820,8 @@ static const struct of_device_id lt8912_dt_match[] = { · 136 unmodified lines
820820 MODULE_DEVICE_TABLE(of, lt8912_dt_match);
821821
822822 static const struct i2c_device_id lt8912_id[] = {
823− { "lt8912" },
824− {}
823+ { .name = "lt8912" },
824+ { }
825825 };
826826 MODULE_DEVICE_TABLE(i2c, lt8912_id);
827827
drivers/gpu/drm/bridge/lontium-lt9211.c+2−2
@@ -773,8 +773,8 @@ static void lt9211_remove(struct i2c_client *client) · 772 unmodified lines
773773 }
774774
775775 static const struct i2c_device_id lt9211_id[] = {
776− { "lontium,lt9211" },
777− {},
776+ { .name = "lontium,lt9211" },
777+ { }
778778 };
779779 MODULE_DEVICE_TABLE(i2c, lt9211_id);
780780
drivers/gpu/drm/bridge/lontium-lt9611.c+2−2
@@ -1229,8 +1229,8 @@ static void lt9611_remove(struct i2c_client *client) · 1228 unmodified lines
12291229 }
12301230
12311231 static const struct i2c_device_id lt9611_id[] = {
1232− { "lontium,lt9611" },
1233− {}
1232+ { .name = "lontium,lt9611" },
1233+ { }
12341234 };
12351235 MODULE_DEVICE_TABLE(i2c, lt9611_id);
12361236
drivers/gpu/drm/bridge/lontium-lt9611uxc.c+1−1
@@ -899,7 +899,7 @@ static void lt9611uxc_remove(struct i2c_client *client) · 898 unmodified lines
899899 }
900900
901901 static const struct i2c_device_id lt9611uxc_id[] = {
902− { "lontium,lt9611uxc" },
902+ { .name = "lontium,lt9611uxc" },
903903 { /* sentinel */ }
904904 };
905905
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
317317 }
318318
319319 static const struct i2c_device_id stdp4028_ge_b850v3_fw_i2c_table[] = {
320− { "stdp4028_ge_fw" },
321− {}
320+ { .name = "stdp4028_ge_fw" },
321+ { }
322322 };
323323 MODULE_DEVICE_TABLE(i2c, stdp4028_ge_b850v3_fw_i2c_table);
324324
@@ -364,8 +364,8 @@ static void stdp2690_ge_b850v3_fw_remove(struct i2c_client *stdp2690_i2c) · 39 unmodified lines
364364 }
365365
366366 static const struct i2c_device_id stdp2690_ge_b850v3_fw_i2c_table[] = {
367− { "stdp2690_ge_fw" },
368− {}
367+ { .name = "stdp2690_ge_fw" },
368+ { }
369369 };
370370 MODULE_DEVICE_TABLE(i2c, stdp2690_ge_b850v3_fw_i2c_table);
371371
drivers/gpu/drm/bridge/nxp-ptn3460.c+2−2
@@ -323,8 +323,8 @@ static void ptn3460_remove(struct i2c_client *client) · 322 unmodified lines
323323 }
324324
325325 static const struct i2c_device_id ptn3460_i2c_table[] = {
326− { "ptn3460" },
327− {}
326+ { .name = "ptn3460" },
327+ { }
328328 };
329329 MODULE_DEVICE_TABLE(i2c, ptn3460_i2c_table);
330330
drivers/gpu/drm/bridge/parade-ps8622.c+4−4
@@ -534,10 +534,10 @@ static void ps8622_remove(struct i2c_client *client) · 533 unmodified lines
534534 }
535535
536536 static const struct i2c_device_id ps8622_i2c_table[] = {
537− /* Device type, max_lane_count */
538− {"ps8622", 1},
539− {"ps8625", 2},
540− {},
537+ /* Device type, driver_data holds the maximal lane_count */
538+ { .name = "ps8622", .driver_data = 1 },
539+ { .name = "ps8625", .driver_data = 2 },
540+ { }
541541 };
542542 MODULE_DEVICE_TABLE(i2c, ps8622_i2c_table);
543543
drivers/gpu/drm/bridge/sii902x.c+1−1
@@ -1235,7 +1235,7 @@ static const struct of_device_id sii902x_dt_ids[] = { · 1234 unmodified lines
12351235 MODULE_DEVICE_TABLE(of, sii902x_dt_ids);
12361236
12371237 static const struct i2c_device_id sii902x_i2c_ids[] = {
1238− { "sii9022" },
1238+ { .name = "sii9022" },
12391239 { }
12401240 };
12411241 MODULE_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
944944 MODULE_DEVICE_TABLE(of, sii9234_dt_match);
945945
946946 static const struct i2c_device_id sii9234_id[] = {
947− { "SII9234" },
947+ { .name = "SII9234" },
948948 { }
949949 };
950950 MODULE_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
23742374 MODULE_DEVICE_TABLE(of, sii8620_dt_match);
23752375
23762376 static const struct i2c_device_id sii8620_id[] = {
2377− { "sii8620" },
2377+ { .name = "sii8620" },
23782378 { }
23792379 };
23802380
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
19491949 .reg_bits = 32,
19501950 .reg_stride = 4,
19511951 .val_bits = 32,
1952− .fast_io = true,
19531952 .max_register = DW_DP_MAX_REGISTER,
19541953 .rd_table = &dw_dp_readable_table,
19551954 };
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
33893389 break;
33903390 default:
33913391 dev_err(dev, "reg-io-width must be 1 or 4\n");
3392− return ERR_PTR(-EINVAL);
3392+ ret = -EINVAL;
3393+ goto err_res;
33933394 }
33943395
33953396 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
907907 .reg_bits = 32,
908908 .val_bits = 32,
909909 .reg_stride = 4,
910− .fast_io = true,
911910 };
912911
913912 static 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
292292 ctx->bridge.of_node = dev->of_node;
293293 ctx->bridge.pre_enable_prev_first = true;
294294
295− drm_bridge_add(&ctx->bridge);
295+ ret = devm_drm_bridge_add(dev, &ctx->bridge);
296+ if (ret < 0)
297+ return ret;
296298
297− ret = mipi_dsi_attach(dsi);
298− if (ret < 0) {
299− drm_bridge_remove(&ctx->bridge);
299+ ret = devm_mipi_dsi_attach(dev, dsi);
300+ if (ret < 0)
300301 dev_err(dev, "failed to attach dsi\n");
301− }
302302
303303 return ret;
304304 }
305305
306−static 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−
314306 static const struct of_device_id tc358762_of_match[] = {
315307 { .compatible = "toshiba,tc358762" },
316308 { }
@@ -319,7 +311,6 @@ MODULE_DEVICE_TABLE(of, tc358762_of_match); · 2 unmodified lines
319311
320312 static struct mipi_dsi_driver tc358762_driver = {
321313 .probe = tc358762_probe,
322− .remove = tc358762_remove,
323314 .driver = {
324315 .name = "tc358762",
325316 .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
376376 ctx->bridge.of_node = dev->of_node;
377377 ctx->bridge.pre_enable_prev_first = true;
378378
379− drm_bridge_add(&ctx->bridge);
379+ ret = devm_drm_bridge_add(dev, &ctx->bridge);
380+ if (ret < 0)
381+ return ret;
380382
381− ret = mipi_dsi_attach(dsi);
382− if (ret < 0) {
383− drm_bridge_remove(&ctx->bridge);
383+ ret = devm_mipi_dsi_attach(dev, dsi);
384+ if (ret < 0)
384385 dev_err(dev, "failed to attach dsi\n");
385− }
386386
387387 return ret;
388388 }
389389
390−static 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−
398390 static const struct of_device_id tc358764_of_match[] = {
399391 { .compatible = "toshiba,tc358764" },
400392 { }
@@ -403,7 +395,6 @@ MODULE_DEVICE_TABLE(of, tc358764_of_match); · 2 unmodified lines
403395
404396 static struct mipi_dsi_driver tc358764_driver = {
405397 .probe = tc358764_probe,
406− .remove = tc358764_remove,
407398 .driver = {
408399 .name = "tc358764",
409400 .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
26132613 }
26142614
26152615 static const struct i2c_device_id tc358767_i2c_ids[] = {
2616− { "tc358767" },
2616+ { .name = "tc358767" },
26172617 { }
26182618 };
26192619 MODULE_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
13621362 };
13631363
13641364 static const struct i2c_device_id tc358768_i2c_ids[] = {
1365− { "tc358768" },
1366− { "tc358778" },
1365+ { .name = "tc358768" },
1366+ { .name = "tc358778" },
13671367 { }
13681368 };
13691369 MODULE_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
727727 }
728728
729729 static const struct i2c_device_id tc358775_i2c_ids[] = {
730− { "tc358765", TC358765, },
731− { "tc358775", TC358775, },
730+ { .name = "tc358765", .driver_data = TC358765 },
731+ { .name = "tc358775", .driver_data = TC358775 },
732732 { }
733733 };
734734 MODULE_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
20642064 #endif
20652065
20662066 static const struct i2c_device_id tda998x_ids[] = {
2067− { "tda998x" },
2067+ { .name = "tda998x" },
20682068 { }
20692069 };
20702070 MODULE_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
389389 }
390390
391391 static const struct i2c_device_id dlpc3433_id[] = {
392− { "ti,dlpc3433" },
392+ { .name = "ti,dlpc3433" },
393393 { /* sentinel */ }
394394 };
395395 MODULE_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
10721072 }
10731073
10741074 static const struct i2c_device_id sn65dsi83_id[] = {
1075− { "ti,sn65dsi83", MODEL_SN65DSI83 },
1076− { "ti,sn65dsi84", MODEL_SN65DSI84 },
1077− {},
1075+ { .name = "ti,sn65dsi83", .driver_data = MODEL_SN65DSI83 },
1076+ { .name = "ti,sn65dsi84", .driver_data = MODEL_SN65DSI84 },
1077+ { }
10781078 };
10791079 MODULE_DEVICE_TABLE(i2c, sn65dsi83_id);
10801080
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
20802080 dev_name(pdata->dev), pdata);
20812081
20822082 if (ret)
2083− return dev_err_probe(dev, ret, "failed to request interrupt\n");
2083+ return ret;
20842084 }
20852085
20862086 /*
@@ -2116,8 +2116,8 @@ static int ti_sn65dsi86_probe(struct i2c_client *client) · 29 unmodified lines
21162116 }
21172117
21182118 static const struct i2c_device_id ti_sn65dsi86_id[] = {
2119− { "ti,sn65dsi86" },
2120− {}
2119+ { .name = "ti,sn65dsi86" },
2120+ { }
21212121 };
21222122 MODULE_DEVICE_TABLE(i2c, ti_sn65dsi86_id);
21232123
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
437437 }
438438
439439 static const struct i2c_device_id tfp410_i2c_ids[] = {
440− { "tfp410" },
440+ { .name = "tfp410" },
441441 { }
442442 };
443443 MODULE_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
960960 * drmm_cgroup_register_region - Register a region of a DRM device to cgroups
961961 * @dev: device for region
962962 * @region_name: Region name for registering
963− * @size: Size of region in bytes
963+ * @init: Initialization parameters for the region.
964964 *
965965 * This decreases the ref-count of @dev by one. The device is destroyed if the
966966 * ref-count drops to zero.
967967 */
968−struct dmem_cgroup_region *drmm_cgroup_register_region(struct drm_device *dev, const char *region_name, u64 size)
968+struct dmem_cgroup_region *
969+drmm_cgroup_register_region(struct drm_device *dev, const char *region_name,
970+ const struct dmem_cgroup_init *init)
969971 {
970972 struct dmem_cgroup_region *region;
971973 int ret;
972974
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);
974976 if (IS_ERR_OR_NULL(region))
975977 return region;
976978
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
255255 * pvr_kccb_send_cmd_reserved_powered() - Send command to the KCCB, with the PM ref
256256 * held and a slot pre-reserved
257257 * @pvr_dev: Device pointer.
258− * @cmd: Command to sent.
258+ * @cmd: Command to send.
259259 * @kccb_slot: Address to store the KCCB slot for this command. May be %NULL.
260260 */
261261 void
@@ -361,7 +361,7 @@ static int pvr_kccb_reserve_slot_sync(struct pvr_device *pvr_dev) · 99 unmodified lines
361361 /**
362362 * pvr_kccb_send_cmd_powered() - Send command to the KCCB, with a PM ref held
363363 * @pvr_dev: Device pointer.
364− * @cmd: Command to sent.
364+ * @cmd: Command to send.
365365 * @kccb_slot: Address to store the KCCB slot for this command. May be %NULL.
366366 *
367367 * Returns:
@@ -385,7 +385,7 @@ pvr_kccb_send_cmd_powered(struct pvr_device *pvr_dev, struct rogue_fwif_kccb_cmd · 17 unmodified lines
385385 /**
386386 * pvr_kccb_send_cmd() - Send command to the KCCB
387387 * @pvr_dev: Device pointer.
388− * @cmd: Command to sent.
388+ * @cmd: Command to send.
389389 * @kccb_slot: Address to store the KCCB slot for this command. May be %NULL.
390390 *
391391 * 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
2222 bool has_coreid_per_os;
2323 bool has_dynamic_dust_power;
2424 bool has_ecc_rams;
25− bool has_fb_cdc_v4;
26− bool has_fbc_max_default_descriptors;
27− bool has_fbc_max_large_descriptors;
2825 bool has_fbcdc;
2926 bool has_fbcdc_algorithm;
3027 bool has_fbcdc_architecture;
28+ bool has_fbc_max_default_descriptors;
29+ bool has_fbc_max_large_descriptors;
30+ bool has_fb_cdc_v4;
3131 bool has_gpu_multicore_support;
3232 bool has_gpu_virtualisation;
3333 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
8484 /**
8585 * @base: The underlying &struct drm_gem_shmem_object.
8686 *
87− * Do not access this member directly, instead call
88− * shem_gem_from_pvr_gem().
87+ * .. note::
88+ *
89+ * This member should not be accessed directly, but instead by
90+ * calling shmem_gem_from_pvr_gem().
8991 */
9092 struct drm_gem_shmem_object base;
9193
@@ -97,12 +99,6 @@ struct pvr_gem_object { · 5 unmodified lines
9799 * changed after creation.
98100 *
99101 * 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.
106102 */
107103 u64 flags;
108104
drivers/gpu/drm/imagination/pvr_queue.c+2−1
@@ -17,6 +17,7 @@ · 16 unmodified lines
1717 #include "pvr_rogue_fwif_client.h"
1818
1919 #define MAX_DEADLINE_MS 30000
20+#define SCHED_TIMEOUT_PERIOD (2 * MAX_DEADLINE_MS)
2021
2122 #define CTX_COMPUTE_CCCB_SIZE_LOG2 15
2223 #define CTX_FRAG_CCCB_SIZE_LOG2 15
@@ -1283,7 +1284,7 @@ struct pvr_queue *pvr_queue_create(struct pvr_context *ctx, · 1260 unmodified lines
12831284 .submit_wq = pvr_dev->sched_wq,
12841285 .credit_limit = 64 * 1024,
12851286 .hang_limit = 1,
1286− .timeout = msecs_to_jiffies(500),
1287+ .timeout = msecs_to_jiffies(SCHED_TIMEOUT_PERIOD),
12871288 .timeout_wq = pvr_dev->sched_wq,
12881289 .name = "pvr-queue",
12891290 .dev = pvr_dev->base.dev,
drivers/gpu/drm/imagination/pvr_rogue_fwif_check.h+1−25
@@ -4,31 +4,7 @@ · 3 unmodified lines
44 #ifndef PVR_ROGUE_FWIF_CHECK_H
55 #define PVR_ROGUE_FWIF_CHECK_H
66
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−/*
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")
7+#include "pvr_check.h"
328
339 OFFSET_CHECK(struct rogue_fwif_file_info_buf, path, 0);
3410 OFFSET_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
44 #ifndef PVR_ROGUE_FWIF_CLIENT_CHECK_H
55 #define PVR_ROGUE_FWIF_CLIENT_CHECK_H
66
7−#include <linux/build_bug.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")
7+#include "pvr_check.h"
158
169 OFFSET_CHECK(struct rogue_fwif_geom_regs, vdm_ctrl_stream_base, 0);
1710 OFFSET_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
44 #ifndef PVR_ROGUE_FWIF_SHARED_CHECK_H
55 #define PVR_ROGUE_FWIF_SHARED_CHECK_H
66
7−#include <linux/build_bug.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")
7+#include "pvr_check.h"
158
169 OFFSET_CHECK(struct rogue_fwif_dma_addr, dev_addr, 0);
1710 OFFSET_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
3333 /* 0 MiB to 4 MiB, size of 4 MiB : RESERVED */
3434
3535 /* 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 */
3737
3838 /* 0x80_0000_0000 ************************************************************/
3939
4040 /* 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 */
4242 #define ROGUE_GENERAL_HEAP_BASE 0x8000000000ull
4343 #define ROGUE_GENERAL_HEAP_SIZE SZ_128G
4444
@@ -62,7 +62,7 @@ · 17 unmodified lines
6262 #define ROGUE_PDSCODEDATA_HEAP_SIZE SZ_4G
6363
6464 /* 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 */
6666 /*
6767 * The BRN63142 quirk workaround requires Region Header memory to be at the top
6868 * of a 16GiB aligned range. This is so when masked with 0x03FFFFFFFF the
@@ -82,7 +82,7 @@ · 13 unmodified lines
8282 /* 0xE1_0000_0000 - 0xE1_BFFF_FFFF */
8383 /* 900 GiB to 903 GiB, size of 3 GiB : RESERVED */
8484
85−/* 0xE1_C000_000 - 0xE1_FFFF_FFFF */
85+/* 0xE1_C000_0000 - 0xE1_FFFF_FFFF */
8686 /* 903 GiB to 904 GiB, reserved 1 GiB, : FIRMWARE_HEAP */
8787 #define ROGUE_FW_HEAP_BASE 0xE1C0000000ull
8888
@@ -90,7 +90,7 @@ · 1 unmodified line
9090 /* 904 GiB to 912 GiB, size of 8 GiB : FREE */
9191
9292 /* 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 */
9494 #define ROGUE_TRANSFER_FRAG_HEAP_BASE 0xE400000000ull
9595 #define ROGUE_TRANSFER_FRAG_HEAP_SIZE SZ_16G
9696
drivers/gpu/drm/imagination/pvr_rogue_mips_check.h+24−47
@@ -4,55 +4,32 @@ · 3 unmodified lines
44 #ifndef PVR_ROGUE_MIPS_CHECK_H
55 #define PVR_ROGUE_MIPS_CHECK_H
66
7−#include <linux/build_bug.h>
7+#include "pvr_check.h"
88
9−static_assert(offsetof(struct rogue_mips_tlb_entry, tlb_page_mask) == 0,
10− "offsetof(struct rogue_mips_tlb_entry, tlb_page_mask) incorrect");
11−static_assert(offsetof(struct rogue_mips_tlb_entry, tlb_hi) == 4,
12− "offsetof(struct rogue_mips_tlb_entry, tlb_hi) incorrect");
13−static_assert(offsetof(struct rogue_mips_tlb_entry, tlb_lo0) == 8,
14− "offsetof(struct rogue_mips_tlb_entry, tlb_lo0) incorrect");
15−static_assert(offsetof(struct rogue_mips_tlb_entry, tlb_lo1) == 12,
16− "offsetof(struct rogue_mips_tlb_entry, tlb_lo1) incorrect");
17−static_assert(sizeof(struct rogue_mips_tlb_entry) == 16,
18− "struct rogue_mips_tlb_entry is incorrect size");
9+OFFSET_CHECK(struct rogue_mips_tlb_entry, tlb_page_mask, 0);
10+OFFSET_CHECK(struct rogue_mips_tlb_entry, tlb_hi, 4);
11+OFFSET_CHECK(struct rogue_mips_tlb_entry, tlb_lo0, 8);
12+OFFSET_CHECK(struct rogue_mips_tlb_entry, tlb_lo1, 12);
13+SIZE_CHECK(struct rogue_mips_tlb_entry, 16);
1914
20−static_assert(offsetof(struct rogue_mips_remap_entry, remap_addr_in) == 0,
21− "offsetof(struct rogue_mips_remap_entry, remap_addr_in) incorrect");
22−static_assert(offsetof(struct rogue_mips_remap_entry, remap_addr_out) == 4,
23− "offsetof(struct rogue_mips_remap_entry, remap_addr_out) incorrect");
24−static_assert(offsetof(struct rogue_mips_remap_entry, remap_region_size) == 8,
25− "offsetof(struct rogue_mips_remap_entry, remap_region_size) incorrect");
26−static_assert(sizeof(struct rogue_mips_remap_entry) == 12,
27− "struct rogue_mips_remap_entry is incorrect size");
15+OFFSET_CHECK(struct rogue_mips_remap_entry, remap_addr_in, 0);
16+OFFSET_CHECK(struct rogue_mips_remap_entry, remap_addr_out, 4);
17+OFFSET_CHECK(struct rogue_mips_remap_entry, remap_region_size, 8);
18+SIZE_CHECK(struct rogue_mips_remap_entry, 12);
2819
29−static_assert(offsetof(struct rogue_mips_state, error_state) == 0,
30− "offsetof(struct rogue_mips_state, error_state) incorrect");
31−static_assert(offsetof(struct rogue_mips_state, error_epc) == 4,
32− "offsetof(struct rogue_mips_state, error_epc) incorrect");
33−static_assert(offsetof(struct rogue_mips_state, status_register) == 8,
34− "offsetof(struct rogue_mips_state, status_register) incorrect");
35−static_assert(offsetof(struct rogue_mips_state, cause_register) == 12,
36− "offsetof(struct rogue_mips_state, cause_register) incorrect");
37−static_assert(offsetof(struct rogue_mips_state, bad_register) == 16,
38− "offsetof(struct rogue_mips_state, bad_register) incorrect");
39−static_assert(offsetof(struct rogue_mips_state, epc) == 20,
40− "offsetof(struct rogue_mips_state, epc) incorrect");
41−static_assert(offsetof(struct rogue_mips_state, sp) == 24,
42− "offsetof(struct rogue_mips_state, sp) incorrect");
43−static_assert(offsetof(struct rogue_mips_state, debug) == 28,
44− "offsetof(struct rogue_mips_state, debug) incorrect");
45−static_assert(offsetof(struct rogue_mips_state, depc) == 32,
46− "offsetof(struct rogue_mips_state, depc) incorrect");
47−static_assert(offsetof(struct rogue_mips_state, bad_instr) == 36,
48− "offsetof(struct rogue_mips_state, bad_instr) incorrect");
49−static_assert(offsetof(struct rogue_mips_state, unmapped_address) == 40,
50− "offsetof(struct rogue_mips_state, unmapped_address) incorrect");
51−static_assert(offsetof(struct rogue_mips_state, tlb) == 44,
52− "offsetof(struct rogue_mips_state, tlb) incorrect");
53−static_assert(offsetof(struct rogue_mips_state, remap) == 300,
54− "offsetof(struct rogue_mips_state, remap) incorrect");
55−static_assert(sizeof(struct rogue_mips_state) == 684,
56− "struct rogue_mips_state is incorrect size");
20+OFFSET_CHECK(struct rogue_mips_state, error_state, 0);
21+OFFSET_CHECK(struct rogue_mips_state, error_epc, 4);
22+OFFSET_CHECK(struct rogue_mips_state, status_register, 8);
23+OFFSET_CHECK(struct rogue_mips_state, cause_register, 12);
24+OFFSET_CHECK(struct rogue_mips_state, bad_register, 16);
25+OFFSET_CHECK(struct rogue_mips_state, epc, 20);
26+OFFSET_CHECK(struct rogue_mips_state, sp, 24);
27+OFFSET_CHECK(struct rogue_mips_state, debug, 28);
28+OFFSET_CHECK(struct rogue_mips_state, depc, 32);
29+OFFSET_CHECK(struct rogue_mips_state, bad_instr, 36);
30+OFFSET_CHECK(struct rogue_mips_state, unmapped_address, 40);
31+OFFSET_CHECK(struct rogue_mips_state, tlb, 44);
32+OFFSET_CHECK(struct rogue_mips_state, remap, 300);
33+SIZE_CHECK(struct rogue_mips_state, 684);
5734
5835 #endif /* PVR_ROGUE_MIPS_CHECK_H */
drivers/gpu/drm/nouveau/dispnv50/base.h+6−0
@@ -1,5 +1,7 @@
11 #ifndef __NV50_KMS_BASE_H__
22 #define __NV50_KMS_BASE_H__
3+#include <drm/drm_blend.h>
4+
35 #include "wndw.h"
46
57 int base507c_new(struct nouveau_drm *, int, s32, struct nv50_wndw **);
@@ -24,4 +26,8 @@ extern const struct nv50_wndw_func base907c; · 18 unmodified lines
2426 int base917c_new(struct nouveau_drm *, int, s32, struct nv50_wndw **);
2527
2628 int 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+
2733 #endif
drivers/gpu/drm/nouveau/dispnv50/base507c.c+1−0
@@ -297,6 +297,7 @@ base507c = { · 296 unmodified lines
297297 .image_set = base507c_image_set,
298298 .image_clr = base507c_image_clr,
299299 .update = base507c_update,
300+ .blend_modes = BASE_BLEND_MODES,
300301 };
301302
302303 int
drivers/gpu/drm/nouveau/dispnv50/base827c.c+1−0
@@ -93,6 +93,7 @@ base827c = { · 92 unmodified lines
9393 .image_set = base827c_image_set,
9494 .image_clr = base507c_image_clr,
9595 .update = base507c_update,
96+ .blend_modes = BASE_BLEND_MODES,
9697 };
9798
9899 int
drivers/gpu/drm/nouveau/dispnv50/base907c.c+1−0
@@ -205,6 +205,7 @@ base907c = { · 204 unmodified lines
205205 .image_set = base907c_image_set,
206206 .image_clr = base507c_image_clr,
207207 .update = base507c_update,
208+ .blend_modes = BASE_BLEND_MODES,
208209 };
209210
210211 int
drivers/gpu/drm/nouveau/dispnv50/curs507a.c+3−0
@@ -29,6 +29,7 @@ · 28 unmodified lines
2929 #include <nvhw/class/cl507a.h>
3030
3131 #include <drm/drm_atomic_helper.h>
32+#include <drm/drm_blend.h>
3233 #include <drm/drm_fourcc.h>
3334
3435 bool
@@ -164,6 +165,8 @@ curs507a_wndw = { · 129 unmodified lines
164165 .acquire = curs507a_acquire,
165166 .release = curs507a_release,
166167 .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),
167170 };
168171
169172 int
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
27682768 {
27692769 struct drm_device *dev = drm->dev;
27702770 struct drm_encoder *encoder;
2771+ struct drm_plane *plane;
27712772 struct drm_modeset_acquire_ctx ctx;
27722773 struct nv50_disp *disp = nv50_disp(dev);
27732774 int ret;
@@ -2781,6 +2782,9 @@ nv50_display_read_hw_state(struct nouveau_drm *drm) · 7 unmodified lines
27812782 nv50_display_read_hw_or_state(dev, disp, nouveau_encoder(encoder));
27822783 }
27832784
2785+ drm_for_each_plane(plane, dev)
2786+ nv50_wndw_default_state(nv50_wndw(plane));
2787+
27842788 DRM_MODESET_LOCK_ALL_END(dev, ctx, ret);
27852789 }
27862790
drivers/gpu/drm/nouveau/dispnv50/wndw.c+33−7
@@ -848,6 +848,28 @@ static const u64 nv50_cursor_format_modifiers[] = { · 847 unmodified lines
848848 DRM_FORMAT_MOD_INVALID,
849849 };
850850
851+/*
852+ * Setup defaults for the atomic wndw state
853+ */
854+void
855+nv50_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+
851873 int
852874 nv50_wndw_new_(const struct nv50_wndw_func *func, struct drm_device *dev,
853875 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
908930 ret = drm_plane_create_alpha_property(&wndw->plane);
909931 if (ret)
910932 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;
918933 } else {
919934 ret = drm_plane_create_zpos_immutable_property(&wndw->plane,
920935 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
922937 return ret;
923938 }
924939
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+
925951 return 0;
926952 }
927953
drivers/gpu/drm/nouveau/dispnv50/wndw.h+11−0
@@ -1,6 +1,8 @@
11 #ifndef __NV50_KMS_WNDW_H__
22 #define __NV50_KMS_WNDW_H__
33 #define nv50_wndw(p) container_of((p), struct nv50_wndw, plane)
4+#include <drm/drm_blend.h>
5+
46 #include "disp.h"
57 #include "atom.h"
68 #include "lut.h"
@@ -44,6 +46,7 @@ void nv50_wndw_flush_clr(struct nv50_wndw *, u32 *interlock, bool flush, · 37 unmodified lines
4446 struct nv50_wndw_atom *);
4547 void nv50_wndw_ntfy_enable(struct nv50_wndw *, struct nv50_wndw_atom *);
4648 int nv50_wndw_wait_armed(struct nv50_wndw *, struct nv50_wndw_atom *);
49+void nv50_wndw_default_state(struct nv50_wndw *wndw);
4750
4851 struct nv50_wndw_func {
4952 int (*acquire)(struct nv50_wndw *, struct nv50_wndw_atom *asyw,
@@ -74,6 +77,7 @@ struct nv50_wndw_func { · 24 unmodified lines
7477 int (*image_clr)(struct nv50_wndw *);
7578 int (*scale_set)(struct nv50_wndw *, struct nv50_wndw_atom *);
7679 int (*blend_set)(struct nv50_wndw *, struct nv50_wndw_atom *);
80+ unsigned int blend_modes;
7781
7882 int (*update)(struct nv50_wndw *, u32 *interlock);
7983 };
@@ -139,4 +143,11 @@ int wndwca7e_new(struct nouveau_drm *, enum drm_plane_type, int, s32, · 59 unmodified lines
139143
140144 int nv50_wndw_new(struct nouveau_drm *, enum drm_plane_type, int index,
141145 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+
142153 #endif
drivers/gpu/drm/nouveau/dispnv50/wndwc37e.c+1−0
@@ -343,6 +343,7 @@ wndwc37e = { · 342 unmodified lines
343343 .image_set = wndwc37e_image_set,
344344 .image_clr = wndwc37e_image_clr,
345345 .blend_set = wndwc37e_blend_set,
346+ .blend_modes = WNDW_BLEND_MODES,
346347 .update = wndwc37e_update,
347348 };
348349
drivers/gpu/drm/nouveau/dispnv50/wndwc57e.c+1−0
@@ -231,6 +231,7 @@ wndwc57e = { · 230 unmodified lines
231231 .image_set = wndwc57e_image_set,
232232 .image_clr = wndwc37e_image_clr,
233233 .blend_set = wndwc37e_blend_set,
234+ .blend_modes = WNDW_BLEND_MODES,
234235 .update = wndwc37e_update,
235236 };
236237
drivers/gpu/drm/nouveau/dispnv50/wndwc67e.c+1−0
@@ -95,6 +95,7 @@ wndwc67e = { · 94 unmodified lines
9595 .image_set = wndwc67e_image_set,
9696 .image_clr = wndwc37e_image_clr,
9797 .blend_set = wndwc37e_blend_set,
98+ .blend_modes = WNDW_BLEND_MODES,
9899 .update = wndwc37e_update,
99100 };
100101
drivers/gpu/drm/nouveau/dispnv50/wndwca7e.c+1−0
@@ -231,6 +231,7 @@ wndwca7e = { · 230 unmodified lines
231231 .image_set = wndwca7e_image_set,
232232 .image_clr = wndwca7e_image_clr,
233233 .blend_set = wndwc37e_blend_set,
234+ .blend_modes = WNDW_BLEND_MODES,
234235 .update = wndwc37e_update,
235236 };
236237
drivers/gpu/drm/nouveau/nouveau_abi16.c+10−4
@@ -408,6 +408,9 @@ nouveau_abi16_ioctl_channel_alloc(ABI16_IOCTL_ARGS) · 407 unmodified lines
408408 case NOUVEAU_FIFO_ENGINE_CE:
409409 engine = NV_DEVICE_HOST_RUNLIST_ENGINES_CE;
410410 break;
411+ case NOUVEAU_FIFO_ENGINE_NVDEC:
412+ engine = NV_DEVICE_HOST_RUNLIST_ENGINES_NVDEC;
413+ break;
411414 default:
412415 return nouveau_abi16_put(abi16, -ENOSYS);
413416 }
@@ -485,10 +488,13 @@ nouveau_abi16_ioctl_channel_alloc(ABI16_IOCTL_ARGS) · 71 unmodified lines
485488 goto done;
486489 break;
487490 case NV_DEVICE_INFO_V0_TURING:
488− ret = nvif_object_ctor(&chan->chan->user, "abi16CeWar", 0, TURING_DMA_COPY_A,
489− NULL, 0, &chan->ce);
490− if (ret)
491− goto done;
491+ if (engine != NV_DEVICE_HOST_RUNLIST_ENGINES_NVDEC) {
492+ ret = nvif_object_ctor(&chan->chan->user, "abi16CeWar",
493+ 0, TURING_DMA_COPY_A, NULL, 0,
494+ &chan->ce);
495+ if (ret)
496+ goto done;
497+ }
492498 break;
493499 default:
494500 break;
drivers/gpu/drm/nouveau/nouveau_drv.h+3−1
@@ -10,7 +10,7 @@ · 9 unmodified lines
1010
1111 #define DRIVER_MAJOR 1
1212 #define DRIVER_MINOR 4
13−#define DRIVER_PATCHLEVEL 2
13+#define DRIVER_PATCHLEVEL 3
1414
1515 /*
1616 * 1.1.1:
@@ -39,6 +39,8 @@ · 22 unmodified lines
3939 * - add variable page sizes and compression for Turing+
4040 * 1.4.2:
4141 * - tell userspace LPTE/SPTE races are fixed.
42+ * 1.4.3:
43+ * - VDEC contexts can be created.
4244 */
4345
4446 #include <linux/notifier.h>
drivers/gpu/drm/nouveau/nouveau_ttm.c+8−0
@@ -23,6 +23,7 @@ · 22 unmodified lines
2323 * USE OR OTHER DEALINGS IN THE SOFTWARE.
2424 */
2525
26+#include <linux/cgroup_dmem.h>
2627 #include <linux/limits.h>
2728
2829 #include <drm/ttm/ttm_range_manager.h>
@@ -188,6 +189,13 @@ nouveau_ttm_init_vram(struct nouveau_drm *drm) · 159 unmodified lines
188189
189190 man->func = &nouveau_vram_manager;
190191
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+
191199 ttm_resource_manager_init(man, &drm->ttm.bdev,
192200 drm->gem.vram_available >> PAGE_SHIFT);
193201 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
456456 timer_delete(&dsi->te_timer);
457457 #endif
458458
459− /* make a copy and unlock, so that isrs can unregister
460− * themselves */
461− memcpy(&dsi->isr_tables_copy, &dsi->isr_tables,
462− sizeof(dsi->isr_tables));
459+ dsi_handle_isrs(&dsi->isr_tables, irqstatus, vcstatus, ciostatus);
463460
464461 spin_unlock(&dsi->irq_lock);
465462
466− dsi_handle_isrs(&dsi->isr_tables_copy, irqstatus, vcstatus, ciostatus);
467−
468463 dsi_handle_irq_errors(dsi, irqstatus, vcstatus, ciostatus);
469464
470465 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
379379
380380 spinlock_t irq_lock;
381381 struct dsi_isr_tables isr_tables;
382− /* space for a copy used by the interrupt handler */
383− struct dsi_isr_tables isr_tables_copy;
384382
385383 int update_vc;
386384 #ifdef DSI_PERF_MEASURE
drivers/gpu/drm/panel/panel-edp.c+39−8
@@ -144,6 +144,16 @@ struct panel_delay { · 143 unmodified lines
144144 */
145145 unsigned int disable;
146146
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+
147157 /**
148158 * @unprepare: Time to power down completely.
149159 *
@@ -413,8 +423,12 @@ static int panel_edp_suspend(struct device *dev) · 263 unmodified lines
413423
414424 static int panel_edp_unprepare(struct drm_panel *panel)
415425 {
426+ struct panel_edp *p = to_panel_edp(panel);
416427 int ret;
417428
429+ if (p->desc->delay.pre_unprepare)
430+ msleep(p->desc->delay.pre_unprepare);
431+
418432 ret = pm_runtime_put_sync_suspend(panel->dev);
419433 if (ret < 0)
420434 return ret;
@@ -832,6 +846,13 @@ exit: · 411 unmodified lines
832846 return 0;
833847 }
834848
849+static void panel_edp_put_adapter(void *_adap)
850+{
851+ struct i2c_adapter *adap = _adap;
852+
853+ i2c_put_adapter(adap);
854+}
855+
835856 static int panel_edp_probe(struct device *dev, const struct panel_desc *desc,
836857 struct drm_dp_aux *aux)
837858 {
@@ -874,11 +895,16 @@ static int panel_edp_probe(struct device *dev, const struct panel_desc *desc, · 36 unmodified lines
874895
875896 ddc = of_parse_phandle(dev->of_node, "ddc-i2c-bus", 0);
876897 if (ddc) {
877− panel->ddc = of_find_i2c_adapter_by_node(ddc);
898+ panel->ddc = of_get_i2c_adapter_by_node(ddc);
878899 of_node_put(ddc);
879900
880901 if (!panel->ddc)
881902 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;
882908 } else if (aux) {
883909 panel->ddc = &aux->ddc;
884910 }
@@ -890,7 +916,7 @@ static int panel_edp_probe(struct device *dev, const struct panel_desc *desc, · 5 unmodified lines
890916
891917 err = drm_panel_of_backlight(&panel->base);
892918 if (err)
893− goto err_finished_ddc_init;
919+ return err;
894920
895921 /*
896922 * 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
937963 err_finished_pm_runtime:
938964 pm_runtime_dont_use_autosuspend(dev);
939965 pm_runtime_disable(dev);
940−err_finished_ddc_init:
941− if (panel->ddc && (!panel->aux || panel->ddc != &panel->aux->ddc))
942− put_device(&panel->ddc->dev);
943966
944967 return err;
945968 }
@@ -983,8 +1006,6 @@ static void panel_edp_remove(struct device *dev) · 37 unmodified lines
9831006
9841007 pm_runtime_dont_use_autosuspend(dev);
9851008 pm_runtime_disable(dev);
986− if (panel->ddc && (!panel->aux || panel->ddc != &panel->aux->ddc))
987− put_device(&panel->ddc->dev);
9881009
9891010 drm_edid_free(panel->drm_edid);
9901011 panel->drm_edid = NULL;
@@ -1803,6 +1824,13 @@ static const struct panel_delay delay_80_500_e80_p2e200 = { · 812 unmodified lines
18031824 .prepare_to_enable = 200,
18041825 };
18051826
1827+static 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+
18061834 static const struct panel_delay delay_100_500_e200 = {
18071835 .hpd_absent = 100,
18081836 .unprepare = 500,
@@ -2029,6 +2057,7 @@ static const struct edp_panel_entry edp_panels[] = { · 220 unmodified lines
20292057 EDP_PANEL_ENTRY('B', 'O', 'E', 0x0a84, &delay_200_500_e50, "NV133WUM-T01"),
20302058 EDP_PANEL_ENTRY('B', 'O', 'E', 0x0ac5, &delay_200_500_e50, "NV116WHM-N4C"),
20312059 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"),
20322061 EDP_PANEL_ENTRY('B', 'O', 'E', 0x0b09, &delay_200_500_e50_po2e200, "NV140FHM-NZ"),
20332062 EDP_PANEL_ENTRY('B', 'O', 'E', 0x0b1e, &delay_200_500_e80, "NE140QDM-N6A"),
20342063 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
20762105 EDP_PANEL_ENTRY('C', 'M', 'N', 0x1161, &delay_200_500_e80, "N116BCP-EA2"),
20772106 EDP_PANEL_ENTRY('C', 'M', 'N', 0x1163, &delay_200_500_e80_d50, "N116BCJ-EAK"),
20782107 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"),
20792109 EDP_PANEL_ENTRY('C', 'M', 'N', 0x116d, &delay_200_500_e80_d50, "N116BCP-EA2"),
20802110 EDP_PANEL_ENTRY('C', 'M', 'N', 0x117a, &delay_200_500_e80_d50, "N116BCL-EAK"),
20812111 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
21652195 EDP_PANEL_ENTRY('S', 'H', 'P', 0x154c, &delay_200_500_p2e100, "LQ116M1JW10"),
21662196 EDP_PANEL_ENTRY('S', 'H', 'P', 0x158f, &delay_200_500_p2e100, "LQ134Z1"),
21672197 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"),
21682199
21692200 EDP_PANEL_ENTRY('S', 'T', 'A', 0x0004, &delay_200_500_e200, "116KHD024006"),
21702201 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
21722203
21732204 EDP_PANEL_ENTRY('T', 'M', 'A', 0x0811, &delay_200_500_e80_d50, "TM140VDXP01-04"),
21742205 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"),
21762207
21772208 { /* sentinal */ }
21782209 };
drivers/gpu/drm/panel/panel-ilitek-ili9805.c+87−125
@@ -25,22 +25,8 @@ · 24 unmodified lines
2525 #define ILI9805_SETEXTC_PARAMETER2 (0x98)
2626 #define ILI9805_SETEXTC_PARAMETER3 (0x05)
2727
28−#define ILI9805_INSTR(_delay, ...) { \
29− .delay = (_delay), \
30− .len = sizeof((u8[]) {__VA_ARGS__}), \
31− .data = (u8[]){__VA_ARGS__} \
32− }
33−
34−struct ili9805_instr {
35− size_t len;
36− const u8 *data;
37− u32 delay;
38−};
39−
4028 struct ili9805_desc {
41− const char *name;
42− const struct ili9805_instr *init;
43− const size_t init_length;
29+ void (*init)(struct mipi_dsi_multi_context *ctx);
4430 const struct drm_display_mode *mode;
4531 u32 width_mm;
4632 u32 height_mm;
@@ -56,65 +42,80 @@ struct ili9805 { · 9 unmodified lines
5642 struct gpio_desc *reset_gpio;
5743 };
5844
59−static const struct ili9805_instr gpm1780a0_init[] = {
60− ILI9805_INSTR(100, ILI9805_EXTCMD_CMD_SET_ENABLE_REG, ILI9805_SETEXTC_PARAMETER1,
61− ILI9805_SETEXTC_PARAMETER2, ILI9805_SETEXTC_PARAMETER3),
62− ILI9805_INSTR(100, 0xFD, 0x0F, 0x10, 0x44, 0x00),
63− ILI9805_INSTR(0, 0xf8, 0x18, 0x02, 0x02, 0x18, 0x02, 0x02, 0x30, 0x00,
64− 0x00, 0x30, 0x00, 0x00, 0x30, 0x00, 0x00),
65− ILI9805_INSTR(0, 0xB8, 0x62),
66− ILI9805_INSTR(0, 0xF1, 0x00),
67− ILI9805_INSTR(0, 0xF2, 0x00, 0x58, 0x40),
68− ILI9805_INSTR(0, 0xF3, 0x60, 0x83, 0x04),
69− ILI9805_INSTR(0, 0xFC, 0x04, 0x0F, 0x01),
70− ILI9805_INSTR(0, 0xEB, 0x08, 0x0F),
71− ILI9805_INSTR(0, 0xe0, 0x00, 0x08, 0x0d, 0x0e, 0x0e, 0x0d, 0x0a, 0x08, 0x04,
72− 0x08, 0x0d, 0x0f, 0x0b, 0x1c, 0x14, 0x0a),
73− ILI9805_INSTR(0, 0xe1, 0x00, 0x08, 0x0d, 0x0e, 0x0e, 0x0d, 0x0a, 0x08, 0x04,
74− 0x08, 0x0d, 0x0f, 0x0b, 0x1c, 0x14, 0x0a),
75− ILI9805_INSTR(10, 0xc1, 0x13, 0x39, 0x19, 0x06),
76− ILI9805_INSTR(10, 0xc7, 0xe5),
77− ILI9805_INSTR(10, 0xB1, 0x00, 0x12, 0x14),
78− ILI9805_INSTR(10, 0xB4, 0x02),
79− ILI9805_INSTR(0, 0xBB, 0x14, 0x55),
80− ILI9805_INSTR(0, MIPI_DCS_SET_ADDRESS_MODE, 0x08),
81− ILI9805_INSTR(0, MIPI_DCS_SET_PIXEL_FORMAT, 0x77),
82− ILI9805_INSTR(0, 0x20),
83− ILI9805_INSTR(0, 0xB0, 0x01),
84− ILI9805_INSTR(0, 0xB6, 0x31, 0x00, 0xef),
85− ILI9805_INSTR(0, 0xDF, 0x23),
86− ILI9805_INSTR(0, 0xB9, 0x02, 0x00),
87−};
45+static void gpm1780a0_init(struct mipi_dsi_multi_context *ctx)
46+{
47+ mipi_dsi_dcs_write_seq_multi(ctx, ILI9805_EXTCMD_CMD_SET_ENABLE_REG,
48+ ILI9805_SETEXTC_PARAMETER1, ILI9805_SETEXTC_PARAMETER2,
49+ ILI9805_SETEXTC_PARAMETER3);
50+ mipi_dsi_msleep(ctx, 100);
51+ mipi_dsi_dcs_write_seq_multi(ctx, 0xfd, 0x0f, 0x10, 0x44, 0x00);
52+ mipi_dsi_msleep(ctx, 100);
53+ mipi_dsi_dcs_write_seq_multi(ctx, 0xf8, 0x18, 0x02, 0x02, 0x18, 0x02, 0x02, 0x30, 0x00,
54+ 0x00, 0x30, 0x00, 0x00, 0x30, 0x00, 0x00);
55+ mipi_dsi_dcs_write_seq_multi(ctx, 0xb8, 0x62);
56+ mipi_dsi_dcs_write_seq_multi(ctx, 0xf1, 0x00);
57+ mipi_dsi_dcs_write_seq_multi(ctx, 0xf2, 0x00, 0x58, 0x40);
58+ mipi_dsi_dcs_write_seq_multi(ctx, 0xf3, 0x60, 0x83, 0x04);
59+ mipi_dsi_dcs_write_seq_multi(ctx, 0xfc, 0x04, 0x0f, 0x01);
60+ mipi_dsi_dcs_write_seq_multi(ctx, 0xeb, 0x08, 0x0f);
61+ mipi_dsi_dcs_write_seq_multi(ctx, 0xe0, 0x00, 0x08, 0x0d, 0x0e, 0x0e, 0x0d, 0x0a, 0x08,
62+ 0x04, 0x08, 0x0d, 0x0f, 0x0b, 0x1c, 0x14, 0x0a);
63+ mipi_dsi_dcs_write_seq_multi(ctx, 0xe1, 0x00, 0x08, 0x0d, 0x0e, 0x0e, 0x0d, 0x0a, 0x08,
64+ 0x04, 0x08, 0x0d, 0x0f, 0x0b, 0x1c, 0x14, 0x0a);
65+ mipi_dsi_dcs_write_seq_multi(ctx, 0xc1, 0x13, 0x39, 0x19, 0x06);
66+ mipi_dsi_msleep(ctx, 10);
67+ mipi_dsi_dcs_write_seq_multi(ctx, 0xc7, 0xe5);
68+ mipi_dsi_msleep(ctx, 10);
69+ mipi_dsi_dcs_write_seq_multi(ctx, 0xb1, 0x00, 0x12, 0x14);
70+ mipi_dsi_msleep(ctx, 10);
71+ mipi_dsi_dcs_write_seq_multi(ctx, 0xb4, 0x02);
72+ mipi_dsi_msleep(ctx, 10);
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+}
8882
89−static const struct ili9805_instr tm041xdhg01_init[] = {
90− ILI9805_INSTR(100, ILI9805_EXTCMD_CMD_SET_ENABLE_REG, ILI9805_SETEXTC_PARAMETER1,
91− ILI9805_SETEXTC_PARAMETER2, ILI9805_SETEXTC_PARAMETER3),
92− ILI9805_INSTR(100, 0xFD, 0x0F, 0x13, 0x44, 0x00),
93− ILI9805_INSTR(0, 0xf8, 0x18, 0x02, 0x02, 0x18, 0x02, 0x02, 0x30, 0x01,
94− 0x01, 0x30, 0x01, 0x01, 0x30, 0x01, 0x01),
95− ILI9805_INSTR(0, 0xB8, 0x74),
96− ILI9805_INSTR(0, 0xF1, 0x00),
97− ILI9805_INSTR(0, 0xF2, 0x00, 0x58, 0x40),
98− ILI9805_INSTR(0, 0xFC, 0x04, 0x0F, 0x01),
99− ILI9805_INSTR(0, 0xEB, 0x08, 0x0F),
100− ILI9805_INSTR(0, 0xe0, 0x01, 0x0d, 0x15, 0x0e, 0x0f, 0x0f, 0x0b, 0x08, 0x04,
101− 0x07, 0x0a, 0x0d, 0x0c, 0x15, 0x0f, 0x08),
102− ILI9805_INSTR(0, 0xe1, 0x01, 0x0d, 0x15, 0x0e, 0x0f, 0x0f, 0x0b, 0x08, 0x04,
103− 0x07, 0x0a, 0x0d, 0x0c, 0x15, 0x0f, 0x08),
104− ILI9805_INSTR(10, 0xc1, 0x15, 0x03, 0x03, 0x31),
105− ILI9805_INSTR(10, 0xB1, 0x00, 0x12, 0x14),
106− ILI9805_INSTR(10, 0xB4, 0x02),
107− ILI9805_INSTR(0, 0xBB, 0x14, 0x55),
108− ILI9805_INSTR(0, MIPI_DCS_SET_ADDRESS_MODE, 0x0a),
109− ILI9805_INSTR(0, MIPI_DCS_SET_PIXEL_FORMAT, 0x77),
110− ILI9805_INSTR(0, 0x20),
111− ILI9805_INSTR(0, 0xB0, 0x00),
112− ILI9805_INSTR(0, 0xB6, 0x01),
113− ILI9805_INSTR(0, 0xc2, 0x11),
114− ILI9805_INSTR(0, 0x51, 0xFF),
115− ILI9805_INSTR(0, 0x53, 0x24),
116− ILI9805_INSTR(0, 0x55, 0x00),
117−};
83+static void tm041xdhg01_init(struct mipi_dsi_multi_context *ctx)
84+{
85+ mipi_dsi_dcs_write_seq_multi(ctx, ILI9805_EXTCMD_CMD_SET_ENABLE_REG,
86+ ILI9805_SETEXTC_PARAMETER1, ILI9805_SETEXTC_PARAMETER2,
87+ ILI9805_SETEXTC_PARAMETER3);
88+ mipi_dsi_msleep(ctx, 100);
89+ mipi_dsi_dcs_write_seq_multi(ctx, 0xfd, 0x0f, 0x13, 0x44, 0x00);
90+ mipi_dsi_msleep(ctx, 100);
91+ mipi_dsi_dcs_write_seq_multi(ctx, 0xf8, 0x18, 0x02, 0x02, 0x18, 0x02, 0x02, 0x30, 0x01,
92+ 0x01, 0x30, 0x01, 0x01, 0x30, 0x01, 0x01);
93+ mipi_dsi_dcs_write_seq_multi(ctx, 0xb8, 0x74);
94+ mipi_dsi_dcs_write_seq_multi(ctx, 0xf1, 0x00);
95+ mipi_dsi_dcs_write_seq_multi(ctx, 0xf2, 0x00, 0x58, 0x40);
96+ mipi_dsi_dcs_write_seq_multi(ctx, 0xfc, 0x04, 0x0f, 0x01);
97+ mipi_dsi_dcs_write_seq_multi(ctx, 0xeb, 0x08, 0x0f);
98+ mipi_dsi_dcs_write_seq_multi(ctx, 0xe0, 0x01, 0x0d, 0x15, 0x0e, 0x0f, 0x0f, 0x0b, 0x08,
99+ 0x04, 0x07, 0x0a, 0x0d, 0x0c, 0x15, 0x0f, 0x08);
100+ mipi_dsi_dcs_write_seq_multi(ctx, 0xe1, 0x01, 0x0d, 0x15, 0x0e, 0x0f, 0x0f, 0x0b, 0x08,
101+ 0x04, 0x07, 0x0a, 0x0d, 0x0c, 0x15, 0x0f, 0x08);
102+ mipi_dsi_dcs_write_seq_multi(ctx, 0xc1, 0x15, 0x03, 0x03, 0x31);
103+ mipi_dsi_msleep(ctx, 10);
104+ mipi_dsi_dcs_write_seq_multi(ctx, 0xb1, 0x00, 0x12, 0x14);
105+ mipi_dsi_msleep(ctx, 10);
106+ mipi_dsi_dcs_write_seq_multi(ctx, 0xb4, 0x02);
107+ mipi_dsi_msleep(ctx, 10);
108+ mipi_dsi_dcs_write_seq_multi(ctx, 0xbb, 0x14, 0x55);
109+ mipi_dsi_dcs_write_seq_multi(ctx, MIPI_DCS_SET_ADDRESS_MODE, 0x0a);
110+ mipi_dsi_dcs_set_pixel_format_multi(ctx, 0x77);
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+}
118119
119120 static inline struct ili9805 *panel_to_ili9805(struct drm_panel *panel)
120121 {
@@ -148,47 +149,24 @@ static int ili9805_power_on(struct ili9805 *ctx) · 27 unmodified lines
148149 return 0;
149150 }
150151
151−static int ili9805_power_off(struct ili9805 *ctx)
152+static void ili9805_power_off(struct ili9805 *ctx)
152153 {
153154 gpiod_set_value(ctx->reset_gpio, 0);
154155 regulator_disable(ctx->dvdd);
155156 regulator_disable(ctx->avdd);
156−
157− return 0;
158157 }
159158
160159 static int ili9805_activate(struct ili9805 *ctx)
161160 {
162− struct mipi_dsi_device *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− }
161+ struct mipi_dsi_multi_context dsi_ctx = { .dsi = ctx->dsi };
182162
183− usleep_range(5000, 6000);
163+ ctx->desc->init(&dsi_ctx);
184164
185− ret = mipi_dsi_dcs_set_display_on(ctx->dsi);
186− if (ret) {
187− dev_err(dev, "Failed to set display ON (%d)\n", ret);
188− return ret;
189− }
165+ mipi_dsi_dcs_exit_sleep_mode_multi(&dsi_ctx);
166+ mipi_dsi_usleep_range(&dsi_ctx, 5000, 6000);
167+ mipi_dsi_dcs_set_display_on_multi(&dsi_ctx);
190168
191− return 0;
169+ return dsi_ctx.accum_err;
192170 }
193171
194172 static int ili9805_prepare(struct drm_panel *panel)
@@ -209,27 +187,13 @@ static int ili9805_prepare(struct drm_panel *panel) · 14 unmodified lines
209187 return 0;
210188 }
211189
212−static int ili9805_deactivate(struct ili9805 *ctx)
190+static void ili9805_deactivate(struct ili9805 *ctx)
213191 {
214− struct mipi_dsi_device *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);
192+ struct mipi_dsi_multi_context dsi_ctx = { .dsi = ctx->dsi };
225193
226− ret = mipi_dsi_dcs_enter_sleep_mode(ctx->dsi);
227− if (ret < 0) {
228− dev_err(dev, "Failed to enter sleep mode (%d)\n", ret);
229− return ret;
230− }
231−
232− return 0;
194+ mipi_dsi_dcs_set_display_off_multi(&dsi_ctx);
195+ mipi_dsi_usleep_range(&dsi_ctx, 5000, 10000);
196+ mipi_dsi_dcs_enter_sleep_mode_multi(&dsi_ctx);
233197 }
234198
235199 static int ili9805_unprepare(struct drm_panel *panel)
@@ -271,7 +235,7 @@ static const struct drm_display_mode tm041xdhg01_timing = { · 35 unmodified lines
271235 };
272236
273237 static int ili9805_get_modes(struct drm_panel *panel,
274− struct drm_connector *connector)
238+ struct drm_connector *connector)
275239 {
276240 struct ili9805 *ctx = panel_to_ili9805(panel);
277241 struct drm_display_mode *mode;
@@ -368,7 +332,6 @@ static void ili9805_dsi_remove(struct mipi_dsi_device *dsi) · 90 unmodified lines
368332
369333 static const struct ili9805_desc gpm1780a0_desc = {
370334 .init = gpm1780a0_init,
371− .init_length = ARRAY_SIZE(gpm1780a0_init),
372335 .mode = &gpm1780a0_timing,
373336 .width_mm = 65,
374337 .height_mm = 65,
@@ -376,7 +339,6 @@ static const struct ili9805_desc gpm1780a0_desc = { · 1 unmodified line
376339
377340 static const struct ili9805_desc tm041xdhg01_desc = {
378341 .init = tm041xdhg01_init,
379− .init_length = ARRAY_SIZE(tm041xdhg01_init),
380342 .mode = &tm041xdhg01_timing,
381343 .width_mm = 42,
382344 .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
29312931 MIPI_DSI_MODE_LPM | MIPI_DSI_CLOCK_NON_CONTINUOUS,
29322932 };
29332933
2934+static 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+
3153+static 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+
29343176 static int jadard_dsi_probe(struct mipi_dsi_device *dsi)
29353177 {
29363178 struct device *dev = &dsi->dev;
@@ -2950,7 +3192,8 @@ static int jadard_dsi_probe(struct mipi_dsi_device *dsi) · 13 unmodified lines
29503192 else
29513193 dsi->mode_flags = MIPI_DSI_MODE_VIDEO |
29523194 MIPI_DSI_MODE_VIDEO_BURST |
2953− MIPI_DSI_MODE_NO_EOT_PACKET;
3195+ MIPI_DSI_MODE_NO_EOT_PACKET |
3196+ MIPI_DSI_MODE_LPM;
29543197
29553198 dsi->format = desc->format;
29563199 dsi->lanes = desc->lanes;
@@ -3036,6 +3279,10 @@ static const struct of_device_id jadard_of_match[] = { · 79 unmodified lines
30363279 .compatible = "chongzhou,cz101b4001",
30373280 .data = &cz101b4001_desc
30383281 },
3282+ {
3283+ .compatible = "dcltek,dt300250",
3284+ .data = &dcltek_dt300250_desc
3285+ },
30393286 {
30403287 .compatible = "kingdisplay,kd101ne3-40ti",
30413288 .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
429429 ctx->dsi[i]->mode_flags = desc->mode_flags;
430430 ctx->dsi[i]->dsc = &ctx->dsc;
431431 ret = devm_mipi_dsi_attach(dev, ctx->dsi[i]);
432− if (ret < 0) {
433− drm_panel_remove(&ctx->panel);
432+ if (ret < 0)
434433 return dev_err_probe(dev, ret,
435434 "Failed to attach to DSI host\n");
436− }
437435 }
438436
439437 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
912912 .connector_type = DRM_MODE_CONNECTOR_DPI,
913913 };
914914
915+static 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+
930+static 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+
915945 static const struct panel_desc ampire_am800480r3tmqwa1h = {
916946 .modes = &ampire_am800480r3tmqwa1h_mode,
917947 .num_modes = 1,
@@ -5648,6 +5678,9 @@ static const struct of_device_id platform_of_match[] = { · 4730 unmodified lines
56485678 }, {
56495679 .compatible = "ampire,am-800480l1tmqw-t00h",
56505680 .data = &ampire_am_800480l1tmqw_t00h,
5681+ }, {
5682+ .compatible = "ampire,am-800480n3tzqw-00h",
5683+ .data = &ampire_am_800480n3tzqw_00h,
56515684 }, {
56525685 .compatible = "ampire,am800480r3tmqwa1h",
56535686 .data = &ampire_am800480r3tmqwa1h,
drivers/gpu/drm/panel/panel-sitronix-st7703.c+96−0
@@ -47,6 +47,7 @@ · 46 unmodified lines
4747 #define ST7703_CMD_SETCABC 0xC8
4848 #define ST7703_CMD_SETPANEL 0xCC
4949 #define ST7703_CMD_SETGAMMA 0xE0
50+#define ST7703_CMD_UNKNOWN_E1 0xE1
5051 #define ST7703_CMD_SETEQ 0xE3
5152 #define ST7703_CMD_SETGIP1 0xE9
5253 #define ST7703_CMD_SETGIP2 0xEA
@@ -673,6 +674,100 @@ static const struct st7703_panel_desc gameforcechi_desc = { · 620 unmodified lines
673674 .init_sequence = gameforcechi_init_sequence,
674675 };
675676
677+static 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+
748+static 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+
762+static 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+
676771 static int st7703_enable(struct drm_panel *panel)
677772 {
678773 struct st7703 *ctx = panel_to_st7703(panel);
@@ -916,6 +1011,7 @@ static void st7703_remove(struct mipi_dsi_device *dsi) · 237 unmodified lines
9161011
9171012 static const struct of_device_id st7703_of_match[] = {
9181013 { .compatible = "anbernic,rg353v-panel-v2", .data = &rg353v2_desc },
1014+ { .compatible = "ayaneo,pocket-ds-lower-panel", .data = &ayaneo_pocket_ds_lower_desc },
9191015 { .compatible = "gameforce,chi-panel", .data = &gameforcechi_desc },
9201016 { .compatible = "powkiddy,rgb10max3-panel", .data = &rgb10max3_panel_desc },
9211017 { .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
3535 static int tdo_tl070wsh30_panel_prepare(struct drm_panel *panel)
3636 {
3737 struct tdo_tl070wsh30_panel *tdo_tl070wsh30 = to_tdo_tl070wsh30_panel(panel);
38+ struct mipi_dsi_multi_context dsi_ctx = { .dsi = tdo_tl070wsh30->link };
3839 int err;
3940
4041 err = regulator_enable(tdo_tl070wsh30->supply);
@@ -51,44 +52,27 @@ static int tdo_tl070wsh30_panel_prepare(struct drm_panel *panel) · 10 unmodified lines
5152
5253 msleep(200);
5354
54− err = mipi_dsi_dcs_exit_sleep_mode(tdo_tl070wsh30->link);
55− if (err < 0) {
56− dev_err(panel->dev, "failed to exit sleep mode: %d\n", err);
57− regulator_disable(tdo_tl070wsh30->supply);
58− return err;
59− }
60−
61− msleep(200);
55+ mipi_dsi_dcs_exit_sleep_mode_multi(&dsi_ctx);
56+ mipi_dsi_msleep(&dsi_ctx, 200);
57+ mipi_dsi_dcs_set_display_on_multi(&dsi_ctx);
58+ mipi_dsi_msleep(&dsi_ctx, 20);
6259
63− err = mipi_dsi_dcs_set_display_on(tdo_tl070wsh30->link);
64− if (err < 0) {
65− dev_err(panel->dev, "failed to set display on: %d\n", err);
60+ if (dsi_ctx.accum_err)
6661 regulator_disable(tdo_tl070wsh30->supply);
67− return err;
68− }
69−
70− msleep(20);
7162
72− return 0;
63+ return dsi_ctx.accum_err;
7364 }
7465
7566 static int tdo_tl070wsh30_panel_unprepare(struct drm_panel *panel)
7667 {
7768 struct tdo_tl070wsh30_panel *tdo_tl070wsh30 = to_tdo_tl070wsh30_panel(panel);
78− int err;
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);
69+ struct mipi_dsi_multi_context dsi_ctx = { .dsi = tdo_tl070wsh30->link };
8370
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;
8474 usleep_range(10000, 11000);
85−
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−
75+ mipi_dsi_dcs_enter_sleep_mode_multi(&dsi_ctx);
9276 usleep_range(10000, 11000);
9377
9478 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
18241824 ptdev = devm_drm_dev_alloc(&pdev->dev, &panthor_drm_driver,
18251825 struct panthor_device, base);
18261826 if (IS_ERR(ptdev))
1827− return -ENOMEM;
1827+ return PTR_ERR(ptdev);
18281828
18291829 platform_set_drvdata(pdev, ptdev);
18301830
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
697697 return ret;
698698
699699 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) {
701702 drm_err(&ptdev->base, "Firmware build info corrupt\n");
702703 /* We don't need the build info, so continue */
703704 return 0;
@@ -877,14 +878,15 @@ static int panthor_init_cs_iface(struct panthor_device *ptdev, · 173 unmodified lines
877878 struct panthor_fw_csg_iface *csg_iface = panthor_fw_get_csg_iface(ptdev, csg_idx);
878879 struct panthor_fw_cs_iface *cs_iface = &ptdev->fw->iface.streams[csg_idx][cs_idx];
879880 u64 shared_section_sz = panthor_kernel_bo_size(ptdev->fw->shared_section->mem);
880− u32 iface_offset = CSF_GROUP_CONTROL_OFFSET +
881− (csg_idx * glb_iface->control->group_stride) +
881+ u64 iface_offset = CSF_GROUP_CONTROL_OFFSET +
882+ ((u64)csg_idx * glb_iface->control->group_stride) +
882883 CSF_STREAM_CONTROL_OFFSET +
883− (cs_idx * csg_iface->control->stream_stride);
884+ ((u64)cs_idx * csg_iface->control->stream_stride);
884885 struct panthor_fw_cs_iface *first_cs_iface =
885886 panthor_fw_get_cs_iface(ptdev, 0, 0);
886887
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)
888890 return -EINVAL;
889891
890892 spin_lock_init(&cs_iface->lock);
@@ -932,10 +934,12 @@ static int panthor_init_csg_iface(struct panthor_device *ptdev, · 41 unmodified lines
932934 struct panthor_fw_global_iface *glb_iface = panthor_fw_get_glb_iface(ptdev);
933935 struct panthor_fw_csg_iface *csg_iface = &ptdev->fw->iface.groups[csg_idx];
934936 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);
936939 unsigned int i;
937940
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)
939943 return -EINVAL;
940944
941945 spin_lock_init(&csg_iface->lock);
@@ -985,11 +989,15 @@ static u32 panthor_get_instr_features(struct panthor_device *ptdev) · 43 unmodified lines
985989 static int panthor_fw_init_ifaces(struct panthor_device *ptdev)
986990 {
987991 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);
988993 unsigned int i;
989994
990995 if (!ptdev->fw->shared_section->mem->kmap)
991996 return -EINVAL;
992997
998+ if (sizeof(*glb_iface->control) > shared_section_sz)
999+ return -EINVAL;
1000+
9931001 spin_lock_init(&glb_iface->lock);
9941002 glb_iface->control = ptdev->fw->shared_section->mem->kmap;
9951003
drivers/gpu/drm/panthor/panthor_mmu.c+10−1
@@ -306,10 +306,13 @@ struct panthor_vm { · 305 unmodified lines
306306 /** @kernel_auto_va.start: Start of the automatic VA-range for kernel BOs. */
307307 u64 start;
308308
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. */
310310 u64 end;
311311 } kernel_auto_va;
312312
313+ /** @user_va_range: Upper boundary of VAs VM users can map objects against. */
314+ u64 user_va_range;
315+
313316 /** @as: Address space related fields. */
314317 struct {
315318 /**
@@ -2892,6 +2895,8 @@ panthor_vm_create(struct panthor_device *ptdev, bool for_mcu, · 2576 unmodified lines
28922895 va_range = full_va_range;
28932896 }
28942897
2898+ vm->user_va_range = kernel_va_start;
2899+
28952900 mutex_init(&vm->mm_lock);
28962901 drm_mm_init(&vm->mm, kernel_va_start, kernel_va_size);
28972902 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
29802985 if (!IS_ALIGNED(op->va | op->size | op->bo_offset, vm_pgsz))
29812986 return -EINVAL;
29822987
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+
29832992 switch (op->flags & DRM_PANTHOR_VM_BIND_OP_TYPE_MASK) {
29842993 case DRM_PANTHOR_VM_BIND_OP_TYPE_MAP:
29852994 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
1414 #include <linux/bits.h>
1515 #include <linux/delay.h>
1616 #include <linux/gpio/consumer.h>
17+#include <linux/math.h>
1718 #include <linux/property.h>
1819 #include <linux/pwm.h>
1920 #include <linux/regulator/consumer.h>
@@ -140,6 +141,11 @@ · 120 unmodified lines
140141 #define SSD133X_SET_PRECHARGE_VOLTAGE 0xbb
141142 #define SSD133X_SET_VCOMH_VOLTAGE 0xbe
142143
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+
143149 #define MAX_CONTRAST 255
144150
145151 const struct ssd130x_deviceinfo ssd130x_variants[] = {
@@ -582,12 +588,37 @@ static int ssd132x_init(struct ssd130x_device *ssd130x) · 436 unmodified lines
582588 return ssd130x_run_cmd_seq(ssd130x, cmds);
583589 }
584590
591+/* Scale a channel's white-balance calibration contrast by the requested brightness */
592+static 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+ */
603+static 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+
585618 static int ssd133x_init(struct ssd130x_device *ssd130x)
586619 {
620+ int ret;
587621 const u8 cmds[] = {
588− 2, SSD133X_CONTRAST_A, 0x91,
589− 2, SSD133X_CONTRAST_B, 0x50,
590− 2, SSD133X_CONTRAST_C, 0x7d,
591622 2, SSD133X_SET_MASTER_CURRENT, 0x06,
592623 3, SSD133X_SET_COL_RANGE, 0x00, ssd130x->width - 1,
593624 3, SSD133X_SET_ROW_RANGE, 0x00, ssd130x->height - 1,
@@ -614,6 +645,10 @@ static int ssd133x_init(struct ssd130x_device *ssd130x) · 20 unmodified lines
614645 0,
615646 };
616647
648+ ret = ssd133x_set_contrast(ssd130x, ssd130x->contrast);
649+ if (ret < 0)
650+ return ret;
651+
617652 return ssd130x_run_cmd_seq(ssd130x, cmds);
618653 }
619654
@@ -1676,8 +1711,25 @@ static int ssd130x_update_bl(struct backlight_device *bdev) · 1056 unmodified lines
16761711 return 0;
16771712 }
16781713
1679−static const struct backlight_ops ssd130xfb_bl_ops = {
1680− .update_status = ssd130x_update_bl,
1714+static int ssd133x_update_bl(struct backlight_device *bdev)
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+
1723+static 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+ },
16811733 };
16821734
16831735 static 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
18841936 return ERR_PTR(ret);
18851937
18861938 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);
18881941 if (IS_ERR(bl))
18891942 return ERR_PTR(dev_err_probe(dev, PTR_ERR(bl),
18901943 "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
208208 planes = sunxi_engine_layers_init(drm, engine);
209209 if (IS_ERR(planes)) {
210210 dev_err(drm->dev, "Couldn't create the planes\n");
211− return NULL;
211+ return ERR_CAST(planes);
212212 }
213213
214214 /* 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
289289
290290 kfifo_put(&list->fifo, remote);
291291 }
292+
293+ of_node_put(port);
292294 }
293295
294296 static int sun4i_drv_add_endpoints(struct device *dev,
@@ -394,6 +396,7 @@ static int sun4i_drv_probe(struct platform_device *pdev) · 99 unmodified lines
394396 /* process this endpoint */
395397 ret = sun4i_drv_add_endpoints(&pdev->dev, &list, &match,
396398 endpoint);
399+ of_node_put(endpoint);
397400
398401 /* sun4i_drv_add_endpoints can fail to allocate memory */
399402 if (ret < 0)
drivers/gpu/drm/sun4i/sun4i_framebuffer.c+2−17
@@ -14,24 +14,8 @@ · 13 unmodified lines
1414 #include "sun4i_drv.h"
1515 #include "sun4i_framebuffer.h"
1616
17−static 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−
3317 static 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,
3519 .atomic_commit = drm_atomic_helper_commit,
3620 .fb_create = drm_gem_fb_create,
3721 };
@@ -46,6 +30,7 @@ void sun4i_framebuffer_init(struct drm_device *drm) · 8 unmodified lines
4630
4731 drm->mode_config.max_width = 8192;
4832 drm->mode_config.max_height = 8192;
33+ drm->mode_config.normalize_zpos = true;
4934
5035 drm->mode_config.funcs = &sun4i_de_mode_config_funcs;
5136 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
160160
161161 drm_atomic_helper_connector_hdmi_update_infoframes(connector, state);
162162
163− val |= SUN4I_HDMI_PKT_CTRL_TYPE(0, SUN4I_HDMI_PKT_AVI);
163+ val = SUN4I_HDMI_PKT_CTRL_TYPE(0, SUN4I_HDMI_PKT_AVI);
164164 val |= SUN4I_HDMI_PKT_CTRL_TYPE(1, SUN4I_HDMI_PKT_END);
165165 writel(val, hdmi->base + SUN4I_HDMI_PKT_CTRL_REG(0));
166166
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
717717 case DRM_MODE_ENCODER_DSI:
718718 /* DSI is tied to special case of CPU interface */
719719 sun4i_tcon0_mode_set_cpu(tcon, encoder, mode);
720+ sun4i_tcon_set_mux(tcon, 0, encoder);
720721 break;
721722 case DRM_MODE_ENCODER_LVDS:
722723 sun4i_tcon0_mode_set_lvds(tcon, encoder, mode);
724+ sun4i_tcon_set_mux(tcon, 0, encoder);
723725 break;
724726 case DRM_MODE_ENCODER_NONE:
725727 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
970972 continue;
971973
972974 ret = of_property_read_u32(remote, "reg", &reg);
975+ of_node_put(remote);
973976 if (ret)
974977 continue;
975978
@@ -1409,7 +1412,7 @@ static int sun8i_r40_tcon_tv_set_mux(struct sun4i_tcon *tcon, · 433 unmodified lines
14091412 {
14101413 struct device_node *port, *remote;
14111414 struct platform_device *pdev;
1412− int id, ret;
1415+ int id, ret = 0;
14131416
14141417 /* find TCON TOP platform device and TCON id */
14151418
@@ -1432,21 +1435,20 @@ static int sun8i_r40_tcon_tv_set_mux(struct sun4i_tcon *tcon, · 16 unmodified lines
14321435 if (IS_ENABLED(CONFIG_DRM_SUN8I_TCON_TOP) &&
14331436 encoder->encoder_type == DRM_MODE_ENCODER_TMDS) {
14341437 ret = sun8i_tcon_top_set_hdmi_src(&pdev->dev, id);
1435− if (ret) {
1436− put_device(&pdev->dev);
1437− return ret;
1438− }
1438+ if (ret)
1439+ goto out_put_device;
14391440 }
14401441
14411442 if (IS_ENABLED(CONFIG_DRM_SUN8I_TCON_TOP)) {
14421443 ret = sun8i_tcon_top_de_config(&pdev->dev, tcon->id, id);
1443− if (ret) {
1444− put_device(&pdev->dev);
1445− return ret;
1446− }
1444+ if (ret)
1445+ goto out_put_device;
14471446 }
14481447
1449− return 0;
1448+out_put_device:
1449+ put_device(&pdev->dev);
1450+
1451+ return ret;
14501452 }
14511453
14521454 static 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
8686 of_node_put(remote_port);
8787 }
8888 }
89+
90+ of_node_put(port);
8991 } else {
9092 crtcs = drm_of_find_possible_crtcs(drm, node);
9193 }
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
9191 },
9292 }, {
9393 594000000, {
94− { 0x1a40, 0x0003 },
94+ { 0x1a7c, 0x0003 },
9595 { 0x3b4c, 0x0003 },
9696 { 0x5a64, 0x0003 },
9797 },
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
785785 .de_type = SUN8I_MIXER_DE2,
786786 .vi_scaler_num = 2,
787787 .scaler_mask = 0x3,
788− .scanline_yuv = 2048,
788+ .scanline_yuv = 1024,
789789 },
790790 .de_type = SUN8I_MIXER_DE2,
791791 .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
2525 return !!of_match_node(sun8i_tcon_top_of_table, node);
2626 }
2727
28+static 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+
59+static 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+
2871 int sun8i_tcon_top_set_hdmi_src(struct device *dev, int tcon)
2972 {
3073 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
57100 int sun8i_tcon_top_de_config(struct device *dev, int mixer, int tcon)
58101 {
59102 struct sun8i_tcon_top *tcon_top = dev_get_drvdata(dev);
103+ u32 mixer_msk, other_msk;
60104 unsigned long flags;
61105 u32 reg;
62106
@@ -70,21 +114,27 @@ int sun8i_tcon_top_de_config(struct device *dev, int mixer, int tcon) · 7 unmodified lines
70114 return -EINVAL;
71115 }
72116
73− if (tcon > 3) {
74− dev_err(dev, "TCON index is too high!\n");
117+ if (tcon < 0 || tcon >= TCON_TOP_PORT_TCON_NUM) {
118+ dev_err(dev, "TCON index is invalid!\n");
75119 return -EINVAL;
76120 }
77121
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+
78125 spin_lock_irqsave(&tcon_top->reg_lock, flags);
79126
80127 reg = readl(tcon_top->regs + TCON_TOP_PORT_SEL_REG);
81− if (mixer == 0) {
82− reg &= ~TCON_TOP_PORT_DE0_MSK;
83− reg |= FIELD_PREP(TCON_TOP_PORT_DE0_MSK, tcon);
84− } else {
85− reg &= ~TCON_TOP_PORT_DE1_MSK;
86− reg |= FIELD_PREP(TCON_TOP_PORT_DE1_MSK, tcon);
128+
129+ reg &= ~mixer_msk;
130+ reg |= field_prep(mixer_msk, tcon);
131+
132+ if (field_get(other_msk, reg) == tcon) {
133+ reg &= ~other_msk;
134+ reg |= field_prep(other_msk,
135+ sun8i_tcon_top_park_index(tcon_top, tcon));
87136 }
137+
88138 writel(reg, tcon_top->regs + TCON_TOP_PORT_SEL_REG);
89139
90140 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
143193 return -ENOMEM;
144194 clk_data->num = CLK_NUM;
145195 tcon_top->clk_data = clk_data;
196+ tcon_top->tcon_map = sun8i_tcon_top_get_tcon_map(dev->of_node);
146197
147198 spin_lock_init(&tcon_top->reg_lock);
148199
@@ -175,10 +226,6 @@ static int sun8i_tcon_top_bind(struct device *dev, struct device *master, · 26 unmodified lines
175226 goto err_assert_reset;
176227 }
177228
178− /*
179− * At least on H6, some registers have some bits set by default
180− * which may cause issues. Clear them here.
181− */
182229 writel(0, regs + TCON_TOP_PORT_SEL_REG);
183230 writel(0, regs + TCON_TOP_GATE_SRC_REG);
184231
drivers/gpu/drm/sun4i/sun8i_tcon_top.h+6−0
@@ -14,6 +14,10 @@ · 13 unmodified lines
1414 #define TCON_TOP_PORT_SEL_REG 0x1C
1515 #define TCON_TOP_PORT_DE0_MSK GENMASK(1, 0)
1616 #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
1721
1822 #define TCON_TOP_GATE_SRC_REG 0x20
1923 #define TCON_TOP_HDMI_SRC_MSK GENMASK(29, 28)
@@ -29,6 +33,8 @@ struct sun8i_tcon_top { · 9 unmodified lines
2933 void __iomem *regs;
3034 struct reset_control *rst;
3135
36+ unsigned int tcon_map;
37+
3238 /*
3339 * spinlock is used to synchronize access to same
3440 * 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
894894 lan3coefftab32_left[offset + i]);
895895 regmap_write(map, SUN8I_SCALER_VSU_YHCOEFF1(base, i),
896896 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++) {
897907 regmap_write(map, SUN8I_SCALER_VSU_CHCOEFF0(base, i),
898908 ch_left[offset + i]);
899909 regmap_write(map, SUN8I_SCALER_VSU_CHCOEFF1(base, i),
900910 ch_right[offset + i]);
901911 }
902−
903− offset = sun8i_vi_scaler_coef_index(hstep) *
912+ offset = sun8i_vi_scaler_coef_index(vstep / format->vsub) *
904913 SUN8I_VI_SCALER_COEFF_COUNT;
905− for (i = 0; i < SUN8I_VI_SCALER_COEFF_COUNT; i++) {
906− regmap_write(map, SUN8I_SCALER_VSU_YVCOEFF(base, i),
907− lan2coefftab32[offset + i]);
914+ for (i = 0; i < SUN8I_VI_SCALER_COEFF_COUNT; i++)
908915 regmap_write(map, SUN8I_SCALER_VSU_CVCOEFF(base, i),
909916 cy[offset + i]);
910− }
911917 }
912918
913919 void 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
969975
970976 regmap_write(layer->regs,
971977 SUN50I_SCALER_VSU_SCALE_MODE(base), val);
978+ regmap_write(layer->regs,
979+ SUN50I_SCALER_VSU_GLB_ALPHA(base), 0xff);
972980 }
973981
974982 regmap_write(layer->regs,
drivers/gpu/drm/sun4i/sun8i_vi_scaler.h+1−0
@@ -36,6 +36,7 @@ · 35 unmodified lines
3636 #define SUN50I_SCALER_VSU_EDSCL_CTRL(base) ((base) + 0x28)
3737 #define SUN50I_SCALER_VSU_ANGLE_THR(base) ((base) + 0x2c)
3838 #define SUN8I_SCALER_VSU_OUTSIZE(base) ((base) + 0x40)
39+#define SUN50I_SCALER_VSU_GLB_ALPHA(base) ((base) + 0x44)
3940 #define SUN8I_SCALER_VSU_YINSIZE(base) ((base) + 0x80)
4041 #define SUN8I_SCALER_VSU_YHSTEP(base) ((base) + 0x88)
4142 #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
488488 return ret;
489489 }
490490
491+struct 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+ */
520+static 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+
491603 /**
492604 * struct ttm_bo_evict_walk - Parameters for the evict walk.
493605 */
@@ -503,24 +615,70 @@ struct ttm_bo_evict_walk { · 9 unmodified lines
503615 /** @evicted: Number of successful evictions. */
504616 unsigned long evicted;
505617
506− /** @limit_pool: Which pool limit we should test against */
507− struct dmem_cgroup_pool_state *limit_pool;
508618 /** @try_low: Whether we should attempt to evict BO's with low watermark threshold */
509619 bool try_low;
510620 /** @hit_low: If we cannot evict a bo when @try_low is false (first pass) */
511621 bool hit_low;
622+
623+ /** @alloc_state: State associated with the allocation attempt. */
624+ struct ttm_bo_alloc_state *alloc_state;
512625 };
513626
514627 static s64 ttm_bo_evict_cb(struct ttm_lru_walk *walk, struct ttm_buffer_object *bo)
515628 {
516629 struct ttm_bo_evict_walk *evict_walk =
517630 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;
518634 s64 lret;
519635
520− if (!dmem_cgroup_state_evict_valuable(evict_walk->limit_pool, bo->resource->css,
521− evict_walk->try_low, &evict_walk->hit_low))
636+ /*
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)
522645 return 0;
523646
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+ */
524682 if (bo->pin_count || !bo->bdev->funcs->eviction_valuable(bo, evict_walk->place))
525683 return 0;
526684
@@ -536,11 +694,17 @@ static s64 ttm_bo_evict_cb(struct ttm_lru_walk *walk, struct ttm_buffer_object * · 9 unmodified lines
536694 goto out;
537695
538696 evict_walk->evicted++;
539− if (evict_walk->res)
540− lret = ttm_resource_alloc(evict_walk->evictor, evict_walk->place,
541− evict_walk->res, NULL);
542− if (lret == 0)
543− return 1;
697+ if (evict_walk->res) {
698+ lret = ttm_bo_alloc_at_place(evict_walk->evictor,
699+ evict_walk->place, false,
700+ evict_walk->res,
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+ }
544708 out:
545709 /* Errors that should terminate the walk. */
546710 if (lret == -ENOSPC)
@@ -560,7 +724,7 @@ static int ttm_bo_evict_alloc(struct ttm_device *bdev, · 13 unmodified lines
560724 struct ttm_operation_ctx *ctx,
561725 struct ww_acquire_ctx *ticket,
562726 struct ttm_resource **res,
563− struct dmem_cgroup_pool_state *limit_pool)
727+ struct ttm_bo_alloc_state *state)
564728 {
565729 struct ttm_bo_evict_walk evict_walk = {
566730 .walk = {
@@ -573,15 +737,21 @@ static int ttm_bo_evict_alloc(struct ttm_device *bdev, · 6 unmodified lines
573737 .place = place,
574738 .evictor = evictor,
575739 .res = res,
576− .limit_pool = limit_pool,
740+ .alloc_state = state,
577741 };
578742 s64 lret;
579743
744+ state->in_evict = true;
745+
580746 evict_walk.walk.arg.trylock_only = true;
581747 lret = ttm_lru_walk_for_evict(&evict_walk.walk, bdev, man, 1);
582748
583− /* One more attempt if we hit low limit? */
584− if (!lret && evict_walk.hit_low) {
749+ /* If we failed to find enough BOs to evict, but we skipped over
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) {
585755 evict_walk.try_low = true;
586756 lret = ttm_lru_walk_for_evict(&evict_walk.walk, bdev, man, 1);
587757 }
@@ -602,11 +772,13 @@ retry: · 14 unmodified lines
602772 } while (!lret && evict_walk.evicted);
603773
604774 /* 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) {
606777 evict_walk.try_low = true;
607778 goto retry;
608779 }
609780 out:
781+ state->in_evict = false;
610782 if (lret < 0)
611783 return lret;
612784 if (lret == 0)
@@ -614,6 +786,86 @@ out: · 1 unmodified line
614786 return 0;
615787 }
616788
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+ */
805+s64 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+
845+retry:
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+
864+out:
865+ return lret;
866+}
867+EXPORT_SYMBOL(ttm_bo_evict_cgroup);
868+
617869 /**
618870 * ttm_bo_pin - Pin the buffer object.
619871 * @bo: The buffer object to pin
@@ -724,9 +976,8 @@ static int ttm_bo_alloc_resource(struct ttm_buffer_object *bo, · 104 unmodified lines
724976
725977 for (i = 0; i < placement->num_placement; ++i) {
726978 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 = {};
728980 struct ttm_resource_manager *man;
729− bool may_evict;
730981
731982 man = ttm_manager_type(bdev, place->mem_type);
732983 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
736987 TTM_PL_FLAG_FALLBACK))
737988 continue;
738989
739− may_evict = (force_space && place->mem_type != TTM_PL_SYSTEM);
740− ret = ttm_resource_alloc(bo, place, res, force_space ? &limit_pool : NULL);
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− }
990+ ret = ttm_bo_alloc_at_place(bo, place, force_space, res,
991+ &alloc_state);
750992
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) {
751998 ret = ttm_bo_evict_alloc(bdev, man, place, bo, ctx,
752− ticket, res, limit_pool);
753− dmem_cgroup_pool_state_put(limit_pool);
754− if (ret == -EBUSY)
755− continue;
756− if (ret)
999+ ticket, res, &alloc_state);
1000+
1001+ dmem_cgroup_pool_state_put(alloc_state.limit_pool);
1002+
1003+ if (ret) {
1004+ dmem_cgroup_uncharge(alloc_state.charge_pool,
1005+ bo->base.size);
1006+ if (ret == -EBUSY)
1007+ continue;
7571008 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;
7581014 }
7591015
7601016 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
999999 bo = res->bo;
10001000 if (ttm_lru_walk_trylock(curs, bo))
10011001 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)
10031004 continue;
10041005
10051006 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
386386 }
387387 EXPORT_SYMBOL(ttm_resource_fini);
388388
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+ */
402+int 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+
389421 int ttm_resource_alloc(struct ttm_buffer_object *bo,
390422 const struct ttm_place *place,
391423 struct ttm_resource **res_ptr,
392− struct dmem_cgroup_pool_state **ret_limit_pool)
424+ struct dmem_cgroup_pool_state *charge_pool)
393425 {
394426 struct ttm_resource_manager *man =
395427 ttm_manager_type(bo->bdev, place->mem_type);
396− struct dmem_cgroup_pool_state *pool = NULL;
397428 int ret;
398429
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−
408430 ret = man->func->alloc(man, bo, place, res_ptr);
409− if (ret) {
410− if (pool)
411− dmem_cgroup_uncharge(pool, bo->base.size);
431+ if (ret)
412432 return ret;
413− }
414433
415− (*res_ptr)->css = pool;
434+ (*res_ptr)->css = charge_pool;
416435
417436 spin_lock(&bo->bdev->lru_lock);
418437 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
437456 man = ttm_manager_type(bo->bdev, (*res)->mem_type);
438457 man->func->free(man, *res);
439458 *res = NULL;
440− if (man->cg)
459+ if (pool)
441460 dmem_cgroup_uncharge(pool, bo->base.size);
442461 }
443462 EXPORT_SYMBOL(ttm_resource_free);
@@ -953,3 +972,55 @@ void ttm_resource_manager_create_debugfs(struct ttm_resource_manager *man, · 509 unmodified lines
953972 #endif
954973 }
955974 EXPORT_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+ */
991+int 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+}
1004+EXPORT_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+ */
1020+void 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+}
1026+EXPORT_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
44 * Copyright (C) 2021-2022 Red Hat
55 */
66
7+#include <linux/cgroup_dmem.h>
8+
79 #include <drm/drm_managed.h>
810 #include <drm/drm_drv.h>
911 #include <drm/drm_buddy.h>
@@ -13,6 +15,7 @@ · 3 unmodified lines
1315
1416 #include "xe_bo.h"
1517 #include "xe_device.h"
18+#include "xe_pm.h"
1619 #include "xe_res_cursor.h"
1720 #include "xe_ttm_vram_mgr.h"
1821 #include "xe_vram_types.h"
@@ -274,14 +277,47 @@ static const struct ttm_resource_manager_func xe_ttm_vram_mgr_func = { · 255 unmodified lines
274277 .debug = xe_ttm_vram_mgr_debug
275278 };
276279
280+static const struct dmem_cgroup_ops xe_ttm_vram_mgr_dmem_ops;
281+
282+static 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+
304+static const struct dmem_cgroup_ops xe_ttm_vram_mgr_dmem_ops = {
305+ .reclaim = xe_ttm_vram_mgr_dmem_reclaim,
306+};
307+
308+static 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+
277315 static void xe_ttm_vram_mgr_fini(struct drm_device *dev, void *arg)
278316 {
279317 struct xe_device *xe = to_xe_device(dev);
280318 struct xe_ttm_vram_mgr *mgr = arg;
281319 struct ttm_resource_manager *man = &mgr->manager;
282320
283− ttm_resource_manager_set_used(man, false);
284−
285321 if (ttm_resource_manager_evict_all(&xe->ttm, man))
286322 return;
287323
@@ -299,14 +335,10 @@ int __xe_ttm_vram_mgr_init(struct xe_device *xe, struct xe_ttm_vram_mgr *mgr, · 11 unmodified lines
299335 u64 default_page_size)
300336 {
301337 struct ttm_resource_manager *man = &mgr->manager;
338+ struct dmem_cgroup_region *cg;
302339 const char *name;
303340 int err;
304341
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−
310342 man->func = &xe_ttm_vram_mgr_func;
311343 mgr->mem_type = mem_type;
312344 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
323355
324356 gpu_buddy_driver_set_lock(&mgr->mm, &mgr->lock);
325357 ttm_set_driver_manager(&xe->ttm, mem_type, &mgr->manager);
326− ttm_resource_manager_set_used(&mgr->manager, true);
327358
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);
329382 }
330383
331384 /**
drivers/gpu/tests/.kunitconfig+2−0
@@ -0,0 +1,2 @@
1+CONFIG_KUNIT=y
2+CONFIG_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
10041004 gpu_buddy_fini(&mm);
10051005
10061006 /*
1007− * Using a non-power-of-two mm size, allocate alternating blocks of 4KiB in an
1008− * even sequence and free them as cleared. All blocks should be marked as
1009− * dirty and the split blocks should be merged back to their original
1010− * size when the blocks clear reset function is called.
1007+ * Using a non-power-of-two mm size, allocate all 4KiB blocks and split
1008+ * them across two alternating lists, then free one list as cleared and
1009+ * the other as dirty. This interleaves cleared and dirty blocks so that
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.
10111014 */
10121015 KUNIT_EXPECT_FALSE(test, gpu_buddy_init(&mm, mm_size, ps));
10131016 KUNIT_EXPECT_EQ(test, mm.max_order, max_order);
10141017
1015− i = 0;
10161018 n_pages = mm_size / ps;
1017− do {
1018− if (i % 2 == 0)
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);
1019+ for (i = 0; i < n_pages; i++) {
1020+ struct list_head *list = (i % 2) ? &clean : &dirty;
10231021
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);
10251029 gpu_buddy_reset_clear(&mm, false);
10261030 KUNIT_EXPECT_EQ(test, mm.clear_avail, 0);
1031+ gpu_buddy_fini(&mm);
10271032
10281033 /*
1029− * Using a non-power-of-two mm size, allocate alternating blocks of 4KiB in an
1030− * odd sequence and free them as cleared. All blocks should be marked as
1031− * cleared and the split blocks should be merged back to their original
1032− * size when the blocks clear reset function is called.
1034+ * Repeat the same fragmented setup, but this time call
1035+ * gpu_buddy_reset_clear(true). Every block should be marked cleared and
1036+ * the split blocks should be merged back to their original size, so the
1037+ * whole address space (clear_avail) must equal mm_size.
10331038 */
1034− i = 0;
1035− do {
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);
1039+ KUNIT_EXPECT_FALSE(test, gpu_buddy_init(&mm, mm_size, ps));
1040+ KUNIT_EXPECT_EQ(test, mm.max_order, max_order);
10411041
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);
10431052 gpu_buddy_reset_clear(&mm, true);
10441053 KUNIT_EXPECT_EQ(test, mm.clear_avail, mm_size);
10451054 gpu_buddy_fini(&mm);
@@ -1422,6 +1431,50 @@ static void gpu_test_buddy_alloc_exceeds_max_order(struct kunit *test) · 376 unmodified lines
14221431 gpu_buddy_fini(&mm);
14231432 }
14241433
1434+static 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+
14251478 static int gpu_buddy_suite_init(struct kunit_suite *suite)
14261479 {
14271480 while (!random_seed)
@@ -1446,6 +1499,7 @@ static struct kunit_case gpu_buddy_tests[] = { · 18 unmodified lines
14461499 KUNIT_CASE(gpu_test_buddy_alloc_exceeds_max_order),
14471500 KUNIT_CASE(gpu_test_buddy_offset_aligned_allocation),
14481501 KUNIT_CASE(gpu_test_buddy_subtree_offset_alignment_stress),
1502+ KUNIT_CASE(gpu_test_buddy_addr_to_block),
14491503 {}
14501504 };
14511505
include/drm/drm_bridge.h+1−1
@@ -40,9 +40,9 @@ struct drm_bridge; · 39 unmodified lines
4040 struct drm_bridge_timings;
4141 struct drm_connector;
4242 struct drm_display_info;
43+struct drm_edid;
4344 struct drm_minor;
4445 struct drm_panel;
45−struct edid;
4646 struct hdmi_codec_daifmt;
4747 struct hdmi_codec_params;
4848 struct i2c_adapter;
include/drm/drm_drv.h+3−1
@@ -34,6 +34,7 @@ · 33 unmodified lines
3434
3535 #include <drm/drm_device.h>
3636
37+struct dmem_cgroup_init;
3738 struct dmem_cgroup_region;
3839 struct drm_fb_helper;
3940 struct drm_fb_helper_surface_size;
@@ -433,7 +434,8 @@ void *__devm_drm_dev_alloc(struct device *parent, · 393 unmodified lines
433434
434435 struct dmem_cgroup_region *
435436 drmm_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);
437439
438440 /**
439441 * 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
226226 struct ww_acquire_ctx *ticket;
227227 /** @trylock_only: Only use trylock for locking. */
228228 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;
229234 };
230235
231236 /**
@@ -431,6 +436,11 @@ void ttm_bo_unpin(struct ttm_buffer_object *bo); · 199 unmodified lines
431436 int ttm_bo_evict_first(struct ttm_device *bdev,
432437 struct ttm_resource_manager *man,
433438 struct ttm_operation_ctx *ctx);
439+s64 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);
434444 int ttm_bo_access(struct ttm_buffer_object *bo, unsigned long offset,
435445 void *buf, int len, int write);
436446 vm_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
3939
4040 struct dentry;
4141 struct dmem_cgroup_device;
42+struct dmem_cgroup_region;
4243 struct drm_printer;
4344 struct ttm_device;
4445 struct ttm_resource_manager;
@@ -458,10 +459,14 @@ void ttm_resource_init(struct ttm_buffer_object *bo, · 413 unmodified lines
458459 void ttm_resource_fini(struct ttm_resource_manager *man,
459460 struct ttm_resource *res);
460461
462+int 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);
461466 int ttm_resource_alloc(struct ttm_buffer_object *bo,
462467 const struct ttm_place *place,
463468 struct ttm_resource **res,
464− struct dmem_cgroup_pool_state **ret_limit_pool);
469+ struct dmem_cgroup_pool_state *charge_pool);
465470 void ttm_resource_free(struct ttm_buffer_object *bo, struct ttm_resource **res);
466471 bool ttm_resource_intersects(struct ttm_device *bdev,
467472 struct ttm_resource *res,
@@ -477,6 +482,12 @@ void ttm_resource_manager_init(struct ttm_resource_manager *man, · 9 unmodified lines
477482 struct ttm_device *bdev,
478483 uint64_t size);
479484
485+void ttm_resource_manager_set_dmem_region(struct ttm_resource_manager *man,
486+ struct dmem_cgroup_region *region);
487+
488+int ttm_resource_manager_dmem_reclaim(struct dmem_cgroup_pool_state *pool,
489+ u64 target_bytes, void *priv);
490+
480491 int ttm_resource_manager_evict_all(struct ttm_device *bdev,
481492 struct ttm_resource_manager *man);
482493
include/linux/cgroup.h+21−0
@@ -623,6 +623,27 @@ static inline struct cgroup *cgroup_ancestor(struct cgroup *cgrp, · 622 unmodified lines
623623 return cgrp->ancestors[ancestor_level];
624624 }
625625
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+ */
636+static 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+
626647 /**
627648 * task_under_cgroup_hierarchy - test task's membership of cgroup ancestry
628649 * @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
1414 /* Opaque definition of a cgroup region, used internally */
1515 struct dmem_cgroup_region;
1616
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+ */
30+struct 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+ */
41+struct dmem_cgroup_init {
42+ u64 size;
43+ const struct dmem_cgroup_ops *ops;
44+ void *reclaim_priv;
45+};
46+
1747 #if IS_ENABLED(CONFIG_CGROUP_DMEM)
18−struct dmem_cgroup_region *dmem_cgroup_register_region(u64 size, const char *name_fmt, ...) __printf(2,3);
48+struct dmem_cgroup_region *
49+dmem_cgroup_register_region(const struct dmem_cgroup_init *init,
50+ const char *name_fmt, ...) __printf(2, 3);
1951 void dmem_cgroup_unregister_region(struct dmem_cgroup_region *region);
2052 int dmem_cgroup_try_charge(struct dmem_cgroup_region *region, u64 size,
2153 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
2456 bool dmem_cgroup_state_evict_valuable(struct dmem_cgroup_pool_state *limit_pool,
2557 struct dmem_cgroup_pool_state *test_pool,
2658 bool ignore_low, bool *ret_hit_low);
59+bool dmem_cgroup_below_min(struct dmem_cgroup_pool_state *root,
60+ struct dmem_cgroup_pool_state *test);
61+bool dmem_cgroup_below_low(struct dmem_cgroup_pool_state *root,
62+ struct dmem_cgroup_pool_state *test);
63+struct dmem_cgroup_pool_state *dmem_cgroup_get_common_ancestor(struct dmem_cgroup_pool_state *a,
64+ struct dmem_cgroup_pool_state *b);
2765
2866 void dmem_cgroup_pool_state_put(struct dmem_cgroup_pool_state *pool);
2967 #else
30−static inline __printf(2,3) struct dmem_cgroup_region *
31−dmem_cgroup_register_region(u64 size, const char *name_fmt, ...)
68+static inline __printf(2, 3) struct dmem_cgroup_region *
69+dmem_cgroup_register_region(const struct dmem_cgroup_init *init, const char *name_fmt, ...)
3270 {
3371 return NULL;
3472 }
@@ -59,6 +97,25 @@ bool dmem_cgroup_state_evict_valuable(struct dmem_cgroup_pool_state *limit_pool, · 24 unmodified lines
5997 return true;
6098 }
6199
100+static 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+
106+static 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+
112+static inline
113+struct 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+
62119 static inline void dmem_cgroup_pool_state_put(struct dmem_cgroup_pool_state *pool)
63120 { }
64121
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
287287
288288 void gpu_buddy_free_block(struct gpu_buddy *mm, struct gpu_buddy_block *block);
289289
290+struct gpu_buddy_block *gpu_buddy_allocated_addr_to_block(struct gpu_buddy *mm, u64 addr);
291+
290292 void gpu_buddy_free_list(struct gpu_buddy *mm,
291293 struct list_head *objects,
292294 unsigned int flags);
include/uapi/drm/nouveau_drm.h+1−0
@@ -89,6 +89,7 @@ struct drm_nouveau_getparam { · 88 unmodified lines
8989 #define NOUVEAU_FIFO_ENGINE_PPP 0x04
9090 #define NOUVEAU_FIFO_ENGINE_BSP 0x08
9191 #define NOUVEAU_FIFO_ENGINE_CE 0x30
92+#define NOUVEAU_FIFO_ENGINE_NVDEC 0x300
9293
9394 struct drm_nouveau_channel_alloc {
9495 __u32 fb_ctxdma_handle;
kernel/cgroup/dmem.c+178−16
@@ -17,6 +17,13 @@ · 16 unmodified lines
1717 #include <linux/refcount.h>
1818 #include <linux/rculist.h>
1919 #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. */
26+DEFINE_STATIC_SRCU(dmemcg_srcu);
2027
2128 struct dmem_cgroup_region {
2229 /**
@@ -48,9 +55,18 @@ struct dmem_cgroup_region { · 25 unmodified lines
4855
4956 /**
5057 * @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.
5260 */
5361 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;
5470 };
5571
5672 struct dmemcg_state {
@@ -145,21 +161,52 @@ static void free_cg_pool(struct dmem_cgroup_pool_state *pool) · 88 unmodified lines
145161 }
146162
147163 static void
148−set_resource_min(struct dmem_cgroup_pool_state *pool, u64 val)
164+set_resource_min(struct dmem_cgroup_pool_state *pool, u64 val, bool nonblock)
149165 {
150166 page_counter_set_min(&pool->cnt, val);
151167 }
152168
153169 static void
154−set_resource_low(struct dmem_cgroup_pool_state *pool, u64 val)
170+set_resource_low(struct dmem_cgroup_pool_state *pool, u64 val, bool nonblock)
155171 {
156172 page_counter_set_low(&pool->cnt, val);
157173 }
158174
159175 static void
160−set_resource_max(struct dmem_cgroup_pool_state *pool, u64 val)
176+set_resource_max(struct dmem_cgroup_pool_state *pool, u64 val, bool nonblock)
161177 {
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);
163210 }
164211
165212 static 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
189236
190237 static void reset_all_resource_limits(struct dmem_cgroup_pool_state *rpool)
191238 {
192− set_resource_min(rpool, 0);
193− set_resource_low(rpool, 0);
194− set_resource_max(rpool, PAGE_COUNTER_MAX);
239+ set_resource_min(rpool, 0, false);
240+ set_resource_low(rpool, 0, false);
241+ /* nonblock: raising to max makes reclaim a no-op; sleeping is forbidden here. */
242+ set_resource_max(rpool, PAGE_COUNTER_MAX, true);
195243 }
196244
197245 static void dmemcs_offline(struct cgroup_subsys_state *css)
@@ -468,7 +516,10 @@ static void dmemcg_free_region(struct kref *ref) · 270 unmodified lines
468516 * dmem_cgroup_unregister_region() - Unregister a previously registered region.
469517 * @region: The region to unregister.
470518 *
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.
472523 */
473524 void dmem_cgroup_unregister_region(struct dmem_cgroup_region *region)
474525 {
@@ -493,16 +544,18 @@ void dmem_cgroup_unregister_region(struct dmem_cgroup_region *region) · 18 unmodified lines
493544 * no new pools should be added to the dead region
494545 * by get_cg_pool_unlocked.
495546 */
496− region->unregistered = true;
547+ WRITE_ONCE(region->unregistered, true);
497548 spin_unlock(&dmemcg_lock);
498549
550+ synchronize_srcu(&dmemcg_srcu);
551+
499552 kref_put(&region->ref, dmemcg_free_region);
500553 }
501554 EXPORT_SYMBOL_GPL(dmem_cgroup_unregister_region);
502555
503556 /**
504557 * 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.
506559 * @fmt: Region parameters to register
507560 *
508561 * 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
511564 *
512565 * Return: NULL or a struct on success, PTR_ERR on failure.
513566 */
514−struct dmem_cgroup_region *dmem_cgroup_register_region(u64 size, const char *fmt, ...)
567+struct dmem_cgroup_region *
568+dmem_cgroup_register_region(const struct dmem_cgroup_init *init,
569+ const char *fmt, ...)
515570 {
516571 struct dmem_cgroup_region *ret;
517572 char *region_name;
518573 va_list ap;
519574
520− if (!size)
575+ if (!init || !init->size)
521576 return NULL;
522577
523578 va_start(ap, fmt);
@@ -534,7 +589,9 @@ struct dmem_cgroup_region *dmem_cgroup_register_region(u64 size, const char *fmt · 10 unmodified lines
534589
535590 INIT_LIST_HEAD(&ret->pools);
536591 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;
538595 kref_init(&ret->ref);
539596
540597 spin_lock(&dmemcg_lock);
@@ -700,6 +757,110 @@ err: · 159 unmodified lines
700757 }
701758 EXPORT_SYMBOL_GPL(dmem_cgroup_try_charge);
702759
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+ */
768+bool 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+}
789+EXPORT_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+ */
799+bool 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+}
820+EXPORT_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+ */
831+struct 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+}
862+EXPORT_SYMBOL_GPL(dmem_cgroup_get_common_ancestor);
863+
703864 static int dmem_cgroup_region_capacity_show(struct seq_file *sf, void *v)
704865 {
705866 struct dmem_cgroup_region *region;
@@ -731,11 +892,12 @@ static int dmemcg_parse_limit(char *options, u64 *new_limit) · 25 unmodified lines
731892
732893 static ssize_t dmemcg_limit_write(struct kernfs_open_file *of,
733894 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))
735896 {
736897 struct dmemcg_state *dmemcs = css_to_dmemcs(of_css(of));
737898 struct dmem_cgroup_pool_state *pool;
738899 struct dmem_cgroup_region *region;
900+ bool nonblock = of->file->f_flags & O_NONBLOCK;
739901 char *region_name;
740902 u64 new_limit;
741903 int err;
@@ -761,7 +923,7 @@ static ssize_t dmemcg_limit_write(struct kernfs_open_file *of, · 19 unmodified lines
761923 goto out_put;
762924 }
763925
764− apply(pool, new_limit);
926+ apply(pool, new_limit, nonblock);
765927 dmemcg_pool_put(pool);
766928
767929 out_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