aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/devicetree/bindings/display/arm,komeda.txt73
-rw-r--r--Documentation/gpu/afbc.rst235
-rw-r--r--Documentation/gpu/drivers.rst2
-rw-r--r--Documentation/gpu/komeda-kms.rst488
-rw-r--r--MAINTAINERS15
-rw-r--r--drivers/gpu/drm/Makefile2
-rw-r--r--drivers/gpu/drm/arm/Kconfig12
-rw-r--r--drivers/gpu/drm/arm/Makefile1
-rw-r--r--drivers/gpu/drm/arm/display/Kbuild3
-rw-r--r--drivers/gpu/drm/arm/display/Kconfig14
-rw-r--r--drivers/gpu/drm/arm/display/include/malidp_io.h42
-rw-r--r--drivers/gpu/drm/arm/display/include/malidp_product.h23
-rw-r--r--drivers/gpu/drm/arm/display/include/malidp_utils.h16
-rw-r--r--drivers/gpu/drm/arm/display/komeda/Makefile21
-rw-r--r--drivers/gpu/drm/arm/display/komeda/d71/d71_dev.c111
-rw-r--r--drivers/gpu/drm/arm/display/komeda/komeda_crtc.c106
-rw-r--r--drivers/gpu/drm/arm/display/komeda/komeda_dev.c186
-rw-r--r--drivers/gpu/drm/arm/display/komeda/komeda_dev.h110
-rw-r--r--drivers/gpu/drm/arm/display/komeda/komeda_drv.c144
-rw-r--r--drivers/gpu/drm/arm/display/komeda/komeda_format_caps.c75
-rw-r--r--drivers/gpu/drm/arm/display/komeda/komeda_format_caps.h89
-rw-r--r--drivers/gpu/drm/arm/display/komeda/komeda_framebuffer.c165
-rw-r--r--drivers/gpu/drm/arm/display/komeda/komeda_framebuffer.h34
-rw-r--r--drivers/gpu/drm/arm/display/komeda/komeda_kms.c167
-rw-r--r--drivers/gpu/drm/arm/display/komeda/komeda_kms.h113
-rw-r--r--drivers/gpu/drm/arm/display/komeda/komeda_pipeline.c200
-rw-r--r--drivers/gpu/drm/arm/display/komeda/komeda_pipeline.h359
-rw-r--r--drivers/gpu/drm/arm/display/komeda/komeda_plane.c109
-rw-r--r--drivers/gpu/drm/arm/display/komeda/komeda_private_obj.c88
-rw-r--r--include/uapi/drm/drm_fourcc.h3
30 files changed, 2998 insertions, 8 deletions
diff --git a/Documentation/devicetree/bindings/display/arm,komeda.txt b/Documentation/devicetree/bindings/display/arm,komeda.txt
new file mode 100644
index 000000000000..02b226532ebd
--- /dev/null
+++ b/Documentation/devicetree/bindings/display/arm,komeda.txt
@@ -0,0 +1,73 @@
1Device Tree bindings for Arm Komeda display driver
2
3Required properties:
4- compatible: Should be "arm,mali-d71"
5- reg: Physical base address and length of the registers in the system
6- interrupts: the interrupt line number of the device in the system
7- clocks: A list of phandle + clock-specifier pairs, one for each entry
8 in 'clock-names'
9- clock-names: A list of clock names. It should contain:
10 - "mclk": for the main processor clock
11 - "pclk": for the APB interface clock
12- #address-cells: Must be 1
13- #size-cells: Must be 0
14
15Required properties for sub-node: pipeline@nq
16Each device contains one or two pipeline sub-nodes (at least one), each
17pipeline node should provide properties:
18- reg: Zero-indexed identifier for the pipeline
19- clocks: A list of phandle + clock-specifier pairs, one for each entry
20 in 'clock-names'
21- clock-names: should contain:
22 - "pxclk": pixel clock
23 - "aclk": AXI interface clock
24
25- port: each pipeline connect to an encoder input port. The connection is
26 modeled using the OF graph bindings specified in
27 Documentation/devicetree/bindings/graph.txt
28
29Optional properties:
30 - memory-region: phandle to a node describing memory (see
31 Documentation/devicetree/bindings/reserved-memory/reserved-memory.txt)
32 to be used for the framebuffer; if not present, the framebuffer may
33 be located anywhere in memory.
34
35Example:
36/ {
37 ...
38
39 dp0: display@c00000 {
40 #address-cells = <1>;
41 #size-cells = <0>;
42 compatible = "arm,mali-d71";
43 reg = <0xc00000 0x20000>;
44 interrupts = <0 168 4>;
45 clocks = <&dpu_mclk>, <&dpu_aclk>;
46 clock-names = "mclk", "pclk";
47
48 dp0_pipe0: pipeline@0 {
49 clocks = <&fpgaosc2>, <&dpu_aclk>;
50 clock-names = "pxclk", "aclk";
51 reg = <0>;
52
53 port {
54 dp0_pipe0_out: endpoint {
55 remote-endpoint = <&db_dvi0_in>;
56 };
57 };
58 };
59
60 dp0_pipe1: pipeline@1 {
61 clocks = <&fpgaosc2>, <&dpu_aclk>;
62 clock-names = "pxclk", "aclk";
63 reg = <1>;
64
65 port {
66 dp0_pipe1_out: endpoint {
67 remote-endpoint = <&db_dvi1_in>;
68 };
69 };
70 };
71 };
72 ...
73};
diff --git a/Documentation/gpu/afbc.rst b/Documentation/gpu/afbc.rst
new file mode 100644
index 000000000000..4d38dc49d105
--- /dev/null
+++ b/Documentation/gpu/afbc.rst
@@ -0,0 +1,235 @@
1.. SPDX-License-Identifier: GPL-2.0+
2
3===================================
4 Arm Framebuffer Compression (AFBC)
5===================================
6
7AFBC is a proprietary lossless image compression protocol and format.
8It provides fine-grained random access and minimizes the amount of
9data transferred between IP blocks.
10
11AFBC can be enabled on drivers which support it via use of the AFBC
12format modifiers defined in drm_fourcc.h. See DRM_FORMAT_MOD_ARM_AFBC(*).
13
14All users of the AFBC modifiers must follow the usage guidelines laid
15out in this document, to ensure compatibility across different AFBC
16producers and consumers.
17
18Components and Ordering
19=======================
20
21AFBC streams can contain several components - where a component
22corresponds to a color channel (i.e. R, G, B, X, A, Y, Cb, Cr).
23The assignment of input/output color channels must be consistent
24between the encoder and the decoder for correct operation, otherwise
25the consumer will interpret the decoded data incorrectly.
26
27Furthermore, when the lossless colorspace transform is used
28(AFBC_FORMAT_MOD_YTR, which should be enabled for RGB buffers for
29maximum compression efficiency), the component order must be:
30
31 * Component 0: R
32 * Component 1: G
33 * Component 2: B
34
35The component ordering is communicated via the fourcc code in the
36fourcc:modifier pair. In general, component '0' is considered to
37reside in the least-significant bits of the corresponding linear
38format. For example, COMP(bits):
39
40 * DRM_FORMAT_ABGR8888
41
42 * Component 0: R(8)
43 * Component 1: G(8)
44 * Component 2: B(8)
45 * Component 3: A(8)
46
47 * DRM_FORMAT_BGR888
48
49 * Component 0: R(8)
50 * Component 1: G(8)
51 * Component 2: B(8)
52
53 * DRM_FORMAT_YUYV
54
55 * Component 0: Y(8)
56 * Component 1: Cb(8, 2x1 subsampled)
57 * Component 2: Cr(8, 2x1 subsampled)
58
59In AFBC, 'X' components are not treated any differently from any other
60component. Therefore, an AFBC buffer with fourcc DRM_FORMAT_XBGR8888
61encodes with 4 components, like so:
62
63 * DRM_FORMAT_XBGR8888
64
65 * Component 0: R(8)
66 * Component 1: G(8)
67 * Component 2: B(8)
68 * Component 3: X(8)
69
70Please note, however, that the inclusion of a "wasted" 'X' channel is
71bad for compression efficiency, and so it's recommended to avoid
72formats containing 'X' bits. If a fourth component is
73required/expected by the encoder/decoder, then it is recommended to
74instead use an equivalent format with alpha, setting all alpha bits to
75'1'. If there is no requirement for a fourth component, then a format
76which doesn't include alpha can be used, e.g. DRM_FORMAT_BGR888.
77
78Number of Planes
79================
80
81Formats which are typically multi-planar in linear layouts (e.g. YUV
82420), can be encoded into one, or multiple, AFBC planes. As with
83component order, the encoder and decoder must agree about the number
84of planes in order to correctly decode the buffer. The fourcc code is
85used to determine the number of encoded planes in an AFBC buffer,
86matching the number of planes for the linear (unmodified) format.
87Within each plane, the component ordering also follows the fourcc
88code:
89
90For example:
91
92 * DRM_FORMAT_YUYV: nplanes = 1
93
94 * Plane 0:
95
96 * Component 0: Y(8)
97 * Component 1: Cb(8, 2x1 subsampled)
98 * Component 2: Cr(8, 2x1 subsampled)
99
100 * DRM_FORMAT_NV12: nplanes = 2
101
102 * Plane 0:
103
104 * Component 0: Y(8)
105
106 * Plane 1:
107
108 * Component 0: Cb(8, 2x1 subsampled)
109 * Component 1: Cr(8, 2x1 subsampled)
110
111Cross-device interoperability
112=============================
113
114For maximum compatibility across devices, the table below defines
115canonical formats for use between AFBC-enabled devices. Formats which
116are listed here must be used exactly as specified when using the AFBC
117modifiers. Formats which are not listed should be avoided.
118
119.. flat-table:: AFBC formats
120
121 * - Fourcc code
122 - Description
123 - Planes/Components
124
125 * - DRM_FORMAT_ABGR2101010
126 - 10-bit per component RGB, with 2-bit alpha
127 - Plane 0: 4 components
128 * Component 0: R(10)
129 * Component 1: G(10)
130 * Component 2: B(10)
131 * Component 3: A(2)
132
133 * - DRM_FORMAT_ABGR8888
134 - 8-bit per component RGB, with 8-bit alpha
135 - Plane 0: 4 components
136 * Component 0: R(8)
137 * Component 1: G(8)
138 * Component 2: B(8)
139 * Component 3: A(8)
140
141 * - DRM_FORMAT_BGR888
142 - 8-bit per component RGB
143 - Plane 0: 3 components
144 * Component 0: R(8)
145 * Component 1: G(8)
146 * Component 2: B(8)
147
148 * - DRM_FORMAT_BGR565
149 - 5/6-bit per component RGB
150 - Plane 0: 3 components
151 * Component 0: R(5)
152 * Component 1: G(6)
153 * Component 2: B(5)
154
155 * - DRM_FORMAT_ABGR1555
156 - 5-bit per component RGB, with 1-bit alpha
157 - Plane 0: 4 components
158 * Component 0: R(5)
159 * Component 1: G(5)
160 * Component 2: B(5)
161 * Component 3: A(1)
162
163 * - DRM_FORMAT_VUY888
164 - 8-bit per component YCbCr 444, single plane
165 - Plane 0: 3 components
166 * Component 0: Y(8)
167 * Component 1: Cb(8)
168 * Component 2: Cr(8)
169
170 * - DRM_FORMAT_VUY101010
171 - 10-bit per component YCbCr 444, single plane
172 - Plane 0: 3 components
173 * Component 0: Y(10)
174 * Component 1: Cb(10)
175 * Component 2: Cr(10)
176
177 * - DRM_FORMAT_YUYV
178 - 8-bit per component YCbCr 422, single plane
179 - Plane 0: 3 components
180 * Component 0: Y(8)
181 * Component 1: Cb(8, 2x1 subsampled)
182 * Component 2: Cr(8, 2x1 subsampled)
183
184 * - DRM_FORMAT_NV16
185 - 8-bit per component YCbCr 422, two plane
186 - Plane 0: 1 component
187 * Component 0: Y(8)
188 Plane 1: 2 components
189 * Component 0: Cb(8, 2x1 subsampled)
190 * Component 1: Cr(8, 2x1 subsampled)
191
192 * - DRM_FORMAT_Y210
193 - 10-bit per component YCbCr 422, single plane
194 - Plane 0: 3 components
195 * Component 0: Y(10)
196 * Component 1: Cb(10, 2x1 subsampled)
197 * Component 2: Cr(10, 2x1 subsampled)
198
199 * - DRM_FORMAT_P210
200 - 10-bit per component YCbCr 422, two plane
201 - Plane 0: 1 component
202 * Component 0: Y(10)
203 Plane 1: 2 components
204 * Component 0: Cb(10, 2x1 subsampled)
205 * Component 1: Cr(10, 2x1 subsampled)
206
207 * - DRM_FORMAT_YUV420_8BIT
208 - 8-bit per component YCbCr 420, single plane
209 - Plane 0: 3 components
210 * Component 0: Y(8)
211 * Component 1: Cb(8, 2x2 subsampled)
212 * Component 2: Cr(8, 2x2 subsampled)
213
214 * - DRM_FORMAT_YUV420_10BIT
215 - 10-bit per component YCbCr 420, single plane
216 - Plane 0: 3 components
217 * Component 0: Y(10)
218 * Component 1: Cb(10, 2x2 subsampled)
219 * Component 2: Cr(10, 2x2 subsampled)
220
221 * - DRM_FORMAT_NV12
222 - 8-bit per component YCbCr 420, two plane
223 - Plane 0: 1 component
224 * Component 0: Y(8)
225 Plane 1: 2 components
226 * Component 0: Cb(8, 2x2 subsampled)
227 * Component 1: Cr(8, 2x2 subsampled)
228
229 * - DRM_FORMAT_P010
230 - 10-bit per component YCbCr 420, two plane
231 - Plane 0: 1 component
232 * Component 0: Y(10)
233 Plane 1: 2 components
234 * Component 0: Cb(10, 2x2 subsampled)
235 * Component 1: Cr(10, 2x2 subsampled)
diff --git a/Documentation/gpu/drivers.rst b/Documentation/gpu/drivers.rst
index 7c1672118a73..044a7025477c 100644
--- a/Documentation/gpu/drivers.rst
+++ b/Documentation/gpu/drivers.rst
@@ -17,6 +17,8 @@ GPU Driver Documentation
17 vkms 17 vkms
18 bridge/dw-hdmi 18 bridge/dw-hdmi
19 xen-front 19 xen-front
20 afbc
21 komeda-kms
20 22
21.. only:: subproject and html 23.. only:: subproject and html
22 24
diff --git a/Documentation/gpu/komeda-kms.rst b/Documentation/gpu/komeda-kms.rst
new file mode 100644
index 000000000000..b08da1cffecc
--- /dev/null
+++ b/Documentation/gpu/komeda-kms.rst
@@ -0,0 +1,488 @@
1.. SPDX-License-Identifier: GPL-2.0
2
3==============================
4 drm/komeda Arm display driver
5==============================
6
7The drm/komeda driver supports the Arm display processor D71 and later products,
8this document gives a brief overview of driver design: how it works and why
9design it like that.
10
11Overview of D71 like display IPs
12================================
13
14From D71, Arm display IP begins to adopt a flexible and modularized
15architecture. A display pipeline is made up of multiple individual and
16functional pipeline stages called components, and every component has some
17specific capabilities that can give the flowed pipeline pixel data a
18particular processing.
19
20Typical D71 components:
21
22Layer
23-----
24Layer is the first pipeline stage, which prepares the pixel data for the next
25stage. It fetches the pixel from memory, decodes it if it's AFBC, rotates the
26source image, unpacks or converts YUV pixels to the device internal RGB pixels,
27then adjusts the color_space of pixels if needed.
28
29Scaler
30------
31As its name suggests, scaler takes responsibility for scaling, and D71 also
32supports image enhancements by scaler.
33The usage of scaler is very flexible and can be connected to layer output
34for layer scaling, or connected to compositor and scale the whole display
35frame and then feed the output data into wb_layer which will then write it
36into memory.
37
38Compositor (compiz)
39-------------------
40Compositor blends multiple layers or pixel data flows into one single display
41frame. its output frame can be fed into post image processor for showing it on
42the monitor or fed into wb_layer and written to memory at the same time.
43user can also insert a scaler between compositor and wb_layer to down scale
44the display frame first and and then write to memory.
45
46Writeback Layer (wb_layer)
47--------------------------
48Writeback layer does the opposite things of Layer, which connects to compiz
49and writes the composition result to memory.
50
51Post image processor (improc)
52-----------------------------
53Post image processor adjusts frame data like gamma and color space to fit the
54requirements of the monitor.
55
56Timing controller (timing_ctrlr)
57--------------------------------
58Final stage of display pipeline, Timing controller is not for the pixel
59handling, but only for controlling the display timing.
60
61Merger
62------
63D71 scaler mostly only has the half horizontal input/output capabilities
64compared with Layer, like if Layer supports 4K input size, the scaler only can
65support 2K input/output in the same time. To achieve the ful frame scaling, D71
66introduces Layer Split, which splits the whole image to two half parts and feeds
67them to two Layers A and B, and does the scaling independently. After scaling
68the result need to be fed to merger to merge two part images together, and then
69output merged result to compiz.
70
71Splitter
72--------
73Similar to Layer Split, but Splitter is used for writeback, which splits the
74compiz result to two parts and then feed them to two scalers.
75
76Possible D71 Pipeline usage
77===========================
78
79Benefitting from the modularized architecture, D71 pipelines can be easily
80adjusted to fit different usages. And D71 has two pipelines, which support two
81types of working mode:
82
83- Dual display mode
84 Two pipelines work independently and separately to drive two display outputs.
85
86- Single display mode
87 Two pipelines work together to drive only one display output.
88
89 On this mode, pipeline_B doesn't work indenpendently, but outputs its
90 composition result into pipeline_A, and its pixel timing also derived from
91 pipeline_A.timing_ctrlr. The pipeline_B works just like a "slave" of
92 pipeline_A(master)
93
94Single pipeline data flow
95-------------------------
96
97.. kernel-render:: DOT
98 :alt: Single pipeline digraph
99 :caption: Single pipeline data flow
100
101 digraph single_ppl {
102 rankdir=LR;
103
104 subgraph {
105 "Memory";
106 "Monitor";
107 }
108
109 subgraph cluster_pipeline {
110 style=dashed
111 node [shape=box]
112 {
113 node [bgcolor=grey style=dashed]
114 "Scaler-0";
115 "Scaler-1";
116 "Scaler-0/1"
117 }
118
119 node [bgcolor=grey style=filled]
120 "Layer-0" -> "Scaler-0"
121 "Layer-1" -> "Scaler-0"
122 "Layer-2" -> "Scaler-1"
123 "Layer-3" -> "Scaler-1"
124
125 "Layer-0" -> "Compiz"
126 "Layer-1" -> "Compiz"
127 "Layer-2" -> "Compiz"
128 "Layer-3" -> "Compiz"
129 "Scaler-0" -> "Compiz"
130 "Scaler-1" -> "Compiz"
131
132 "Compiz" -> "Scaler-0/1" -> "Wb_layer"
133 "Compiz" -> "Improc" -> "Timing Controller"
134 }
135
136 "Wb_layer" -> "Memory"
137 "Timing Controller" -> "Monitor"
138 }
139
140Dual pipeline with Slave enabled
141--------------------------------
142
143.. kernel-render:: DOT
144 :alt: Slave pipeline digraph
145 :caption: Slave pipeline enabled data flow
146
147 digraph slave_ppl {
148 rankdir=LR;
149
150 subgraph {
151 "Memory";
152 "Monitor";
153 }
154 node [shape=box]
155 subgraph cluster_pipeline_slave {
156 style=dashed
157 label="Slave Pipeline_B"
158 node [shape=box]
159 {
160 node [bgcolor=grey style=dashed]
161 "Slave.Scaler-0";
162 "Slave.Scaler-1";
163 }
164
165 node [bgcolor=grey style=filled]
166 "Slave.Layer-0" -> "Slave.Scaler-0"
167 "Slave.Layer-1" -> "Slave.Scaler-0"
168 "Slave.Layer-2" -> "Slave.Scaler-1"
169 "Slave.Layer-3" -> "Slave.Scaler-1"
170
171 "Slave.Layer-0" -> "Slave.Compiz"
172 "Slave.Layer-1" -> "Slave.Compiz"
173 "Slave.Layer-2" -> "Slave.Compiz"
174 "Slave.Layer-3" -> "Slave.Compiz"
175 "Slave.Scaler-0" -> "Slave.Compiz"
176 "Slave.Scaler-1" -> "Slave.Compiz"
177 }
178
179 subgraph cluster_pipeline_master {
180 style=dashed
181 label="Master Pipeline_A"
182 node [shape=box]
183 {
184 node [bgcolor=grey style=dashed]
185 "Scaler-0";
186 "Scaler-1";
187 "Scaler-0/1"
188 }
189
190 node [bgcolor=grey style=filled]
191 "Layer-0" -> "Scaler-0"
192 "Layer-1" -> "Scaler-0"
193 "Layer-2" -> "Scaler-1"
194 "Layer-3" -> "Scaler-1"
195
196 "Slave.Compiz" -> "Compiz"
197 "Layer-0" -> "Compiz"
198 "Layer-1" -> "Compiz"
199 "Layer-2" -> "Compiz"
200 "Layer-3" -> "Compiz"
201 "Scaler-0" -> "Compiz"
202 "Scaler-1" -> "Compiz"
203
204 "Compiz" -> "Scaler-0/1" -> "Wb_layer"
205 "Compiz" -> "Improc" -> "Timing Controller"
206 }
207
208 "Wb_layer" -> "Memory"
209 "Timing Controller" -> "Monitor"
210 }
211
212Sub-pipelines for input and output
213----------------------------------
214
215A complete display pipeline can be easily divided into three sub-pipelines
216according to the in/out usage.
217
218Layer(input) pipeline
219~~~~~~~~~~~~~~~~~~~~~
220
221.. kernel-render:: DOT
222 :alt: Layer data digraph
223 :caption: Layer (input) data flow
224
225 digraph layer_data_flow {
226 rankdir=LR;
227 node [shape=box]
228
229 {
230 node [bgcolor=grey style=dashed]
231 "Scaler-n";
232 }
233
234 "Layer-n" -> "Scaler-n" -> "Compiz"
235 }
236
237.. kernel-render:: DOT
238 :alt: Layer Split digraph
239 :caption: Layer Split pipeline
240
241 digraph layer_data_flow {
242 rankdir=LR;
243 node [shape=box]
244
245 "Layer-0/1" -> "Scaler-0" -> "Merger"
246 "Layer-2/3" -> "Scaler-1" -> "Merger"
247 "Merger" -> "Compiz"
248 }
249
250Writeback(output) pipeline
251~~~~~~~~~~~~~~~~~~~~~~~~~~
252.. kernel-render:: DOT
253 :alt: writeback digraph
254 :caption: Writeback(output) data flow
255
256 digraph writeback_data_flow {
257 rankdir=LR;
258 node [shape=box]
259
260 {
261 node [bgcolor=grey style=dashed]
262 "Scaler-n";
263 }
264
265 "Compiz" -> "Scaler-n" -> "Wb_layer"
266 }
267
268.. kernel-render:: DOT
269 :alt: split writeback digraph
270 :caption: Writeback(output) Split data flow
271
272 digraph writeback_data_flow {
273 rankdir=LR;
274 node [shape=box]
275
276 "Compiz" -> "Splitter"
277 "Splitter" -> "Scaler-0" -> "Merger"
278 "Splitter" -> "Scaler-1" -> "Merger"
279 "Merger" -> "Wb_layer"
280 }
281
282Display output pipeline
283~~~~~~~~~~~~~~~~~~~~~~~
284.. kernel-render:: DOT
285 :alt: display digraph
286 :caption: display output data flow
287
288 digraph single_ppl {
289 rankdir=LR;
290 node [shape=box]
291
292 "Compiz" -> "Improc" -> "Timing Controller"
293 }
294
295In the following section we'll see these three sub-pipelines will be handled
296by KMS-plane/wb_conn/crtc respectively.
297
298Komeda Resource abstraction
299===========================
300
301struct komeda_pipeline/component
302--------------------------------
303
304To fully utilize and easily access/configure the HW, the driver side also uses
305a similar architecture: Pipeline/Component to describe the HW features and
306capabilities, and a specific component includes two parts:
307
308- Data flow controlling.
309- Specific component capabilities and features.
310
311So the driver defines a common header struct komeda_component to describe the
312data flow control and all specific components are a subclass of this base
313structure.
314
315.. kernel-doc:: drivers/gpu/drm/arm/display/komeda/komeda_pipeline.h
316 :internal:
317
318Resource discovery and initialization
319=====================================
320
321Pipeline and component are used to describe how to handle the pixel data. We
322still need a @struct komeda_dev to describe the whole view of the device, and
323the control-abilites of device.
324
325We have &komeda_dev, &komeda_pipeline, &komeda_component. Now fill devices with
326pipelines. Since komeda is not for D71 only but also intended for later products,
327of course we’d better share as much as possible between different products. To
328achieve this, split the komeda device into two layers: CORE and CHIP.
329
330- CORE: for common features and capabilities handling.
331- CHIP: for register programing and HW specific feature (limitation) handling.
332
333CORE can access CHIP by three chip function structures:
334
335- struct komeda_dev_funcs
336- struct komeda_pipeline_funcs
337- struct komeda_component_funcs
338
339.. kernel-doc:: drivers/gpu/drm/arm/display/komeda/komeda_dev.h
340 :internal:
341
342Format handling
343===============
344
345.. kernel-doc:: drivers/gpu/drm/arm/display/komeda/komeda_format_caps.h
346 :internal:
347.. kernel-doc:: drivers/gpu/drm/arm/display/komeda/komeda_framebuffer.h
348 :internal:
349
350Attach komeda_dev to DRM-KMS
351============================
352
353Komeda abstracts resources by pipeline/component, but DRM-KMS uses
354crtc/plane/connector. One KMS-obj cannot represent only one single component,
355since the requirements of a single KMS object cannot simply be achieved by a
356single component, usually that needs multiple components to fit the requirement.
357Like set mode, gamma, ctm for KMS all target on CRTC-obj, but komeda needs
358compiz, improc and timing_ctrlr to work together to fit these requirements.
359And a KMS-Plane may require multiple komeda resources: layer/scaler/compiz.
360
361So, one KMS-Obj represents a sub-pipeline of komeda resources.
362
363- Plane: `Layer(input) pipeline`_
364- Wb_connector: `Writeback(output) pipeline`_
365- Crtc: `Display output pipeline`_
366
367So, for komeda, we treat KMS crtc/plane/connector as users of pipeline and
368component, and at any one time a pipeline/component only can be used by one
369user. And pipeline/component will be treated as private object of DRM-KMS; the
370state will be managed by drm_atomic_state as well.
371
372How to map plane to Layer(input) pipeline
373-----------------------------------------
374
375Komeda has multiple Layer input pipelines, see:
376- `Single pipeline data flow`_
377- `Dual pipeline with Slave enabled`_
378
379The easiest way is binding a plane to a fixed Layer pipeline, but consider the
380komeda capabilities:
381
382- Layer Split, See `Layer(input) pipeline`_
383
384 Layer_Split is quite complicated feature, which splits a big image into two
385 parts and handles it by two layers and two scalers individually. But it
386 imports an edge problem or effect in the middle of the image after the split.
387 To avoid such a problem, it needs a complicated Split calculation and some
388 special configurations to the layer and scaler. We'd better hide such HW
389 related complexity to user mode.
390
391- Slave pipeline, See `Dual pipeline with Slave enabled`_
392
393 Since the compiz component doesn't output alpha value, the slave pipeline
394 only can be used for bottom layers composition. The komeda driver wants to
395 hide this limitation to the user. The way to do this is to pick a suitable
396 Layer according to plane_state->zpos.
397
398So for komeda, the KMS-plane doesn't represent a fixed komeda layer pipeline,
399but multiple Layers with same capabilities. Komeda will select one or more
400Layers to fit the requirement of one KMS-plane.
401
402Make component/pipeline to be drm_private_obj
403---------------------------------------------
404
405Add :c:type:`drm_private_obj` to :c:type:`komeda_component`, :c:type:`komeda_pipeline`
406
407.. code-block:: c
408
409 struct komeda_component {
410 struct drm_private_obj obj;
411 ...
412 }
413
414 struct komeda_pipeline {
415 struct drm_private_obj obj;
416 ...
417 }
418
419Tracking component_state/pipeline_state by drm_atomic_state
420-----------------------------------------------------------
421
422Add :c:type:`drm_private_state` and user to :c:type:`komeda_component_state`,
423:c:type:`komeda_pipeline_state`
424
425.. code-block:: c
426
427 struct komeda_component_state {
428 struct drm_private_state obj;
429 void *binding_user;
430 ...
431 }
432
433 struct komeda_pipeline_state {
434 struct drm_private_state obj;
435 struct drm_crtc *crtc;
436 ...
437 }
438
439komeda component validation
440---------------------------
441
442Komeda has multiple types of components, but the process of validation are
443similar, usually including the following steps:
444
445.. code-block:: c
446
447 int komeda_xxxx_validate(struct komeda_component_xxx xxx_comp,
448 struct komeda_component_output *input_dflow,
449 struct drm_plane/crtc/connector *user,
450 struct drm_plane/crtc/connector_state, *user_state)
451 {
452 setup 1: check if component is needed, like the scaler is optional depending
453 on the user_state; if unneeded, just return, and the caller will
454 put the data flow into next stage.
455 Setup 2: check user_state with component features and capabilities to see
456 if requirements can be met; if not, return fail.
457 Setup 3: get component_state from drm_atomic_state, and try set to set
458 user to component; fail if component has been assigned to another
459 user already.
460 Setup 3: configure the component_state, like set its input component,
461 convert user_state to component specific state.
462 Setup 4: adjust the input_dflow and prepare it for the next stage.
463 }
464
465komeda_kms Abstraction
466----------------------
467
468.. kernel-doc:: drivers/gpu/drm/arm/display/komeda/komeda_kms.h
469 :internal:
470
471komde_kms Functions
472-------------------
473.. kernel-doc:: drivers/gpu/drm/arm/display/komeda/komeda_crtc.c
474 :internal:
475.. kernel-doc:: drivers/gpu/drm/arm/display/komeda/komeda_plane.c
476 :internal:
477
478Build komeda to be a Linux module driver
479========================================
480
481Now we have two level devices:
482
483- komeda_dev: describes the real display hardware.
484- komeda_kms_dev: attachs or connects komeda_dev to DRM-KMS.
485
486All komeda operations are supplied or operated by komeda_dev or komeda_kms_dev,
487the module driver is only a simple wrapper to pass the Linux command
488(probe/remove/pm) into komeda_dev or komeda_kms_dev.
diff --git a/MAINTAINERS b/MAINTAINERS
index 6e1cef2f21d9..4b752571fe03 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1133,13 +1133,26 @@ S: Supported
1133F: drivers/gpu/drm/arm/hdlcd_* 1133F: drivers/gpu/drm/arm/hdlcd_*
1134F: Documentation/devicetree/bindings/display/arm,hdlcd.txt 1134F: Documentation/devicetree/bindings/display/arm,hdlcd.txt
1135 1135
1136ARM KOMEDA DRM-KMS DRIVER
1137M: James (Qian) Wang <james.qian.wang@arm.com>
1138M: Liviu Dudau <liviu.dudau@arm.com>
1139L: Mali DP Maintainers <malidp@foss.arm.com>
1140S: Supported
1141T: git git://linux-arm.org/linux-ld.git for-upstream/mali-dp
1142F: drivers/gpu/drm/arm/display/include/
1143F: drivers/gpu/drm/arm/display/komeda/
1144F: Documentation/devicetree/bindings/display/arm/arm,komeda.txt
1145F: Documentation/gpu/komeda-kms.rst
1146
1136ARM MALI-DP DRM DRIVER 1147ARM MALI-DP DRM DRIVER
1137M: Liviu Dudau <liviu.dudau@arm.com> 1148M: Liviu Dudau <liviu.dudau@arm.com>
1138M: Brian Starkey <brian.starkey@arm.com> 1149M: Brian Starkey <brian.starkey@arm.com>
1139M: Mali DP Maintainers <malidp@foss.arm.com> 1150L: Mali DP Maintainers <malidp@foss.arm.com>
1140S: Supported 1151S: Supported
1152T: git git://linux-arm.org/linux-ld.git for-upstream/mali-dp
1141F: drivers/gpu/drm/arm/ 1153F: drivers/gpu/drm/arm/
1142F: Documentation/devicetree/bindings/display/arm,malidp.txt 1154F: Documentation/devicetree/bindings/display/arm,malidp.txt
1155F: Documentation/gpu/afbc.rst
1143 1156
1144ARM MFM AND FLOPPY DRIVERS 1157ARM MFM AND FLOPPY DRIVERS
1145M: Ian Molton <spyro@f2s.com> 1158M: Ian Molton <spyro@f2s.com>
diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile
index ce8d1d384319..f0c1f8731a27 100644
--- a/drivers/gpu/drm/Makefile
+++ b/drivers/gpu/drm/Makefile
@@ -51,7 +51,7 @@ obj-$(CONFIG_DRM_DEBUG_SELFTEST) += selftests/
51obj-$(CONFIG_DRM) += drm.o 51obj-$(CONFIG_DRM) += drm.o
52obj-$(CONFIG_DRM_MIPI_DSI) += drm_mipi_dsi.o 52obj-$(CONFIG_DRM_MIPI_DSI) += drm_mipi_dsi.o
53obj-$(CONFIG_DRM_PANEL_ORIENTATION_QUIRKS) += drm_panel_orientation_quirks.o 53obj-$(CONFIG_DRM_PANEL_ORIENTATION_QUIRKS) += drm_panel_orientation_quirks.o
54obj-$(CONFIG_DRM_ARM) += arm/ 54obj-y += arm/
55obj-$(CONFIG_DRM_TTM) += ttm/ 55obj-$(CONFIG_DRM_TTM) += ttm/
56obj-$(CONFIG_DRM_SCHED) += scheduler/ 56obj-$(CONFIG_DRM_SCHED) += scheduler/
57obj-$(CONFIG_DRM_TDFX) += tdfx/ 57obj-$(CONFIG_DRM_TDFX) += tdfx/
diff --git a/drivers/gpu/drm/arm/Kconfig b/drivers/gpu/drm/arm/Kconfig
index 9a18e1bd57b4..a204103b3efb 100644
--- a/drivers/gpu/drm/arm/Kconfig
+++ b/drivers/gpu/drm/arm/Kconfig
@@ -1,13 +1,10 @@
1config DRM_ARM 1# SPDX-License-Identifier: GPL-2.0
2 bool 2menu "ARM devices"
3 help
4 Choose this option to select drivers for ARM's devices
5 3
6config DRM_HDLCD 4config DRM_HDLCD
7 tristate "ARM HDLCD" 5 tristate "ARM HDLCD"
8 depends on DRM && OF && (ARM || ARM64) 6 depends on DRM && OF && (ARM || ARM64)
9 depends on COMMON_CLK 7 depends on COMMON_CLK
10 select DRM_ARM
11 select DRM_KMS_HELPER 8 select DRM_KMS_HELPER
12 select DRM_KMS_CMA_HELPER 9 select DRM_KMS_CMA_HELPER
13 help 10 help
@@ -29,7 +26,6 @@ config DRM_MALI_DISPLAY
29 tristate "ARM Mali Display Processor" 26 tristate "ARM Mali Display Processor"
30 depends on DRM && OF && (ARM || ARM64) 27 depends on DRM && OF && (ARM || ARM64)
31 depends on COMMON_CLK 28 depends on COMMON_CLK
32 select DRM_ARM
33 select DRM_KMS_HELPER 29 select DRM_KMS_HELPER
34 select DRM_KMS_CMA_HELPER 30 select DRM_KMS_CMA_HELPER
35 select DRM_GEM_CMA_HELPER 31 select DRM_GEM_CMA_HELPER
@@ -40,3 +36,7 @@ config DRM_MALI_DISPLAY
40 of the hardware. 36 of the hardware.
41 37
42 If compiled as a module it will be called mali-dp. 38 If compiled as a module it will be called mali-dp.
39
40source "drivers/gpu/drm/arm/display/Kconfig"
41
42endmenu
diff --git a/drivers/gpu/drm/arm/Makefile b/drivers/gpu/drm/arm/Makefile
index 3bf31d1a4722..120bef801fcf 100644
--- a/drivers/gpu/drm/arm/Makefile
+++ b/drivers/gpu/drm/arm/Makefile
@@ -3,3 +3,4 @@ obj-$(CONFIG_DRM_HDLCD) += hdlcd.o
3mali-dp-y := malidp_drv.o malidp_hw.o malidp_planes.o malidp_crtc.o 3mali-dp-y := malidp_drv.o malidp_hw.o malidp_planes.o malidp_crtc.o
4mali-dp-y += malidp_mw.o 4mali-dp-y += malidp_mw.o
5obj-$(CONFIG_DRM_MALI_DISPLAY) += mali-dp.o 5obj-$(CONFIG_DRM_MALI_DISPLAY) += mali-dp.o
6obj-$(CONFIG_DRM_KOMEDA) += display/
diff --git a/drivers/gpu/drm/arm/display/Kbuild b/drivers/gpu/drm/arm/display/Kbuild
new file mode 100644
index 000000000000..382f1ca831e4
--- /dev/null
+++ b/drivers/gpu/drm/arm/display/Kbuild
@@ -0,0 +1,3 @@
1# SPDX-License-Identifier: GPL-2.0
2
3obj-$(CONFIG_DRM_KOMEDA) += komeda/
diff --git a/drivers/gpu/drm/arm/display/Kconfig b/drivers/gpu/drm/arm/display/Kconfig
new file mode 100644
index 000000000000..cec0639e3aa1
--- /dev/null
+++ b/drivers/gpu/drm/arm/display/Kconfig
@@ -0,0 +1,14 @@
1# SPDX-License-Identifier: GPL-2.0
2config DRM_KOMEDA
3 tristate "ARM Komeda display driver"
4 depends on DRM && OF
5 depends on COMMON_CLK
6 select DRM_KMS_HELPER
7 select DRM_KMS_CMA_HELPER
8 select DRM_GEM_CMA_HELPER
9 select VIDEOMODE_HELPERS
10 help
11 Choose this option if you want to compile the ARM Komeda display
12 Processor driver. It supports the D71 variants of the hardware.
13
14 If compiled as a module it will be called komeda.
diff --git a/drivers/gpu/drm/arm/display/include/malidp_io.h b/drivers/gpu/drm/arm/display/include/malidp_io.h
new file mode 100644
index 000000000000..4fb3caf864ce
--- /dev/null
+++ b/drivers/gpu/drm/arm/display/include/malidp_io.h
@@ -0,0 +1,42 @@
1/* SPDX-License-Identifier: GPL-2.0 */
2/*
3 * (C) COPYRIGHT 2018 ARM Limited. All rights reserved.
4 * Author: James.Qian.Wang <james.qian.wang@arm.com>
5 *
6 */
7#ifndef _MALIDP_IO_H_
8#define _MALIDP_IO_H_
9
10#include <linux/io.h>
11
12static inline u32
13malidp_read32(u32 __iomem *base, u32 offset)
14{
15 return readl((base + (offset >> 2)));
16}
17
18static inline void
19malidp_write32(u32 __iomem *base, u32 offset, u32 v)
20{
21 writel(v, (base + (offset >> 2)));
22}
23
24static inline void
25malidp_write32_mask(u32 __iomem *base, u32 offset, u32 m, u32 v)
26{
27 u32 tmp = malidp_read32(base, offset);
28
29 tmp &= (~m);
30 malidp_write32(base, offset, v | tmp);
31}
32
33static inline void
34malidp_write_group(u32 __iomem *base, u32 offset, int num, const u32 *values)
35{
36 int i;
37
38 for (i = 0; i < num; i++)
39 malidp_write32(base, offset + i * 4, values[i]);
40}
41
42#endif /*_MALIDP_IO_H_*/
diff --git a/drivers/gpu/drm/arm/display/include/malidp_product.h b/drivers/gpu/drm/arm/display/include/malidp_product.h
new file mode 100644
index 000000000000..b35fc5db866b
--- /dev/null
+++ b/drivers/gpu/drm/arm/display/include/malidp_product.h
@@ -0,0 +1,23 @@
1/* SPDX-License-Identifier: GPL-2.0 */
2/*
3 * (C) COPYRIGHT 2018 ARM Limited. All rights reserved.
4 * Author: James.Qian.Wang <james.qian.wang@arm.com>
5 *
6 */
7#ifndef _MALIDP_PRODUCT_H_
8#define _MALIDP_PRODUCT_H_
9
10/* Product identification */
11#define MALIDP_CORE_ID(__product, __major, __minor, __status) \
12 ((((__product) & 0xFFFF) << 16) | (((__major) & 0xF) << 12) | \
13 (((__minor) & 0xF) << 8) | ((__status) & 0xFF))
14
15#define MALIDP_CORE_ID_PRODUCT_ID(__core_id) ((__u32)(__core_id) >> 16)
16#define MALIDP_CORE_ID_MAJOR(__core_id) (((__u32)(__core_id) >> 12) & 0xF)
17#define MALIDP_CORE_ID_MINOR(__core_id) (((__u32)(__core_id) >> 8) & 0xF)
18#define MALIDP_CORE_ID_STATUS(__core_id) (((__u32)(__core_id)) & 0xFF)
19
20/* Mali-display product IDs */
21#define MALIDP_D71_PRODUCT_ID 0x0071
22
23#endif /* _MALIDP_PRODUCT_H_ */
diff --git a/drivers/gpu/drm/arm/display/include/malidp_utils.h b/drivers/gpu/drm/arm/display/include/malidp_utils.h
new file mode 100644
index 000000000000..63cc47cefcf8
--- /dev/null
+++ b/drivers/gpu/drm/arm/display/include/malidp_utils.h
@@ -0,0 +1,16 @@
1/* SPDX-License-Identifier: GPL-2.0 */
2/*
3 * (C) COPYRIGHT 2018 ARM Limited. All rights reserved.
4 * Author: James.Qian.Wang <james.qian.wang@arm.com>
5 *
6 */
7#ifndef _MALIDP_UTILS_
8#define _MALIDP_UTILS_
9
10#define has_bit(nr, mask) (BIT(nr) & (mask))
11#define has_bits(bits, mask) (((bits) & (mask)) == (bits))
12
13#define dp_for_each_set_bit(bit, mask) \
14 for_each_set_bit((bit), ((unsigned long *)&(mask)), sizeof(mask) * 8)
15
16#endif /* _MALIDP_UTILS_ */
diff --git a/drivers/gpu/drm/arm/display/komeda/Makefile b/drivers/gpu/drm/arm/display/komeda/Makefile
new file mode 100644
index 000000000000..1b875e5dc0f6
--- /dev/null
+++ b/drivers/gpu/drm/arm/display/komeda/Makefile
@@ -0,0 +1,21 @@
1# SPDX-License-Identifier: GPL-2.0
2
3ccflags-y := \
4 -I$(src)/../include \
5 -I$(src)
6
7komeda-y := \
8 komeda_drv.o \
9 komeda_dev.o \
10 komeda_format_caps.o \
11 komeda_pipeline.o \
12 komeda_framebuffer.o \
13 komeda_kms.o \
14 komeda_crtc.o \
15 komeda_plane.o \
16 komeda_private_obj.o
17
18komeda-y += \
19 d71/d71_dev.o
20
21obj-$(CONFIG_DRM_KOMEDA) += komeda.o
diff --git a/drivers/gpu/drm/arm/display/komeda/d71/d71_dev.c b/drivers/gpu/drm/arm/display/komeda/d71/d71_dev.c
new file mode 100644
index 000000000000..edbf9daa1545
--- /dev/null
+++ b/drivers/gpu/drm/arm/display/komeda/d71/d71_dev.c
@@ -0,0 +1,111 @@
1// SPDX-License-Identifier: GPL-2.0
2/*
3 * (C) COPYRIGHT 2018 ARM Limited. All rights reserved.
4 * Author: James.Qian.Wang <james.qian.wang@arm.com>
5 *
6 */
7#include "malidp_io.h"
8#include "komeda_dev.h"
9
10static int d71_enum_resources(struct komeda_dev *mdev)
11{
12 /* TODO add enum resources */
13 return -1;
14}
15
16#define __HW_ID(__group, __format) \
17 ((((__group) & 0x7) << 3) | ((__format) & 0x7))
18
19#define RICH KOMEDA_FMT_RICH_LAYER
20#define SIMPLE KOMEDA_FMT_SIMPLE_LAYER
21#define RICH_SIMPLE (KOMEDA_FMT_RICH_LAYER | KOMEDA_FMT_SIMPLE_LAYER)
22#define RICH_WB (KOMEDA_FMT_RICH_LAYER | KOMEDA_FMT_WB_LAYER)
23#define RICH_SIMPLE_WB (RICH_SIMPLE | KOMEDA_FMT_WB_LAYER)
24
25#define Rot_0 DRM_MODE_ROTATE_0
26#define Flip_H_V (DRM_MODE_REFLECT_X | DRM_MODE_REFLECT_Y | Rot_0)
27#define Rot_ALL_H_V (DRM_MODE_ROTATE_MASK | Flip_H_V)
28
29#define LYT_NM BIT(AFBC_FORMAT_MOD_BLOCK_SIZE_16x16)
30#define LYT_WB BIT(AFBC_FORMAT_MOD_BLOCK_SIZE_32x8)
31#define LYT_NM_WB (LYT_NM | LYT_WB)
32
33#define AFB_TH AFBC(_TILED | _SPARSE)
34#define AFB_TH_SC_YTR AFBC(_TILED | _SC | _SPARSE | _YTR)
35#define AFB_TH_SC_YTR_BS AFBC(_TILED | _SC | _SPARSE | _YTR | _SPLIT)
36
37static struct komeda_format_caps d71_format_caps_table[] = {
38 /* HW_ID | fourcc | tile_sz | layer_types | rots | afbc_layouts | afbc_features */
39 /* ABGR_2101010*/
40 {__HW_ID(0, 0), DRM_FORMAT_ARGB2101010, 1, RICH_SIMPLE_WB, Flip_H_V, 0, 0},
41 {__HW_ID(0, 1), DRM_FORMAT_ABGR2101010, 1, RICH_SIMPLE_WB, Flip_H_V, 0, 0},
42 {__HW_ID(0, 1), DRM_FORMAT_ABGR2101010, 1, RICH_SIMPLE, Rot_ALL_H_V, LYT_NM_WB, AFB_TH_SC_YTR_BS}, /* afbc */
43 {__HW_ID(0, 2), DRM_FORMAT_RGBA1010102, 1, RICH_SIMPLE_WB, Flip_H_V, 0, 0},
44 {__HW_ID(0, 3), DRM_FORMAT_BGRA1010102, 1, RICH_SIMPLE_WB, Flip_H_V, 0, 0},
45 /* ABGR_8888*/
46 {__HW_ID(1, 0), DRM_FORMAT_ARGB8888, 1, RICH_SIMPLE_WB, Flip_H_V, 0, 0},
47 {__HW_ID(1, 1), DRM_FORMAT_ABGR8888, 1, RICH_SIMPLE_WB, Flip_H_V, 0, 0},
48 {__HW_ID(1, 1), DRM_FORMAT_ABGR8888, 1, RICH_SIMPLE, Rot_ALL_H_V, LYT_NM_WB, AFB_TH_SC_YTR_BS}, /* afbc */
49 {__HW_ID(1, 2), DRM_FORMAT_RGBA8888, 1, RICH_SIMPLE_WB, Flip_H_V, 0, 0},
50 {__HW_ID(1, 3), DRM_FORMAT_BGRA8888, 1, RICH_SIMPLE_WB, Flip_H_V, 0, 0},
51 /* XBGB_8888 */
52 {__HW_ID(2, 0), DRM_FORMAT_XRGB8888, 1, RICH_SIMPLE_WB, Flip_H_V, 0, 0},
53 {__HW_ID(2, 1), DRM_FORMAT_XBGR8888, 1, RICH_SIMPLE_WB, Flip_H_V, 0, 0},
54 {__HW_ID(2, 2), DRM_FORMAT_RGBX8888, 1, RICH_SIMPLE_WB, Flip_H_V, 0, 0},
55 {__HW_ID(2, 3), DRM_FORMAT_BGRX8888, 1, RICH_SIMPLE_WB, Flip_H_V, 0, 0},
56 /* BGR_888 */ /* none-afbc RGB888 doesn't support rotation and flip */
57 {__HW_ID(3, 0), DRM_FORMAT_RGB888, 1, RICH_SIMPLE_WB, Rot_0, 0, 0},
58 {__HW_ID(3, 1), DRM_FORMAT_BGR888, 1, RICH_SIMPLE_WB, Rot_0, 0, 0},
59 {__HW_ID(3, 1), DRM_FORMAT_BGR888, 1, RICH_SIMPLE, Rot_ALL_H_V, LYT_NM_WB, AFB_TH_SC_YTR_BS}, /* afbc */
60 /* BGR 16bpp */
61 {__HW_ID(4, 0), DRM_FORMAT_RGBA5551, 1, RICH_SIMPLE, Flip_H_V, 0, 0},
62 {__HW_ID(4, 1), DRM_FORMAT_ABGR1555, 1, RICH_SIMPLE, Flip_H_V, 0, 0},
63 {__HW_ID(4, 1), DRM_FORMAT_ABGR1555, 1, RICH_SIMPLE, Rot_ALL_H_V, LYT_NM_WB, AFB_TH_SC_YTR}, /* afbc */
64 {__HW_ID(4, 2), DRM_FORMAT_RGB565, 1, RICH_SIMPLE, Flip_H_V, 0, 0},
65 {__HW_ID(4, 3), DRM_FORMAT_BGR565, 1, RICH_SIMPLE, Flip_H_V, 0, 0},
66 {__HW_ID(4, 3), DRM_FORMAT_BGR565, 1, RICH_SIMPLE, Rot_ALL_H_V, LYT_NM_WB, AFB_TH_SC_YTR}, /* afbc */
67 {__HW_ID(4, 4), DRM_FORMAT_R8, 1, SIMPLE, Rot_0, 0, 0},
68 /* YUV 444/422/420 8bit */
69 {__HW_ID(5, 0), 0 /*XYUV8888*/, 1, 0, 0, 0, 0},
70 /* XYUV unsupported*/
71 {__HW_ID(5, 1), DRM_FORMAT_YUYV, 1, RICH, Rot_ALL_H_V, LYT_NM, AFB_TH}, /* afbc */
72 {__HW_ID(5, 2), DRM_FORMAT_YUYV, 1, RICH, Flip_H_V, 0, 0},
73 {__HW_ID(5, 3), DRM_FORMAT_UYVY, 1, RICH, Flip_H_V, 0, 0},
74 {__HW_ID(5, 4), 0, /*X0L0 */ 2, 0, 0, 0}, /* Y0L0 unsupported */
75 {__HW_ID(5, 6), DRM_FORMAT_NV12, 1, RICH, Flip_H_V, 0, 0},
76 {__HW_ID(5, 6), 0/*DRM_FORMAT_YUV420_8BIT*/, 1, RICH, Rot_ALL_H_V, LYT_NM, AFB_TH}, /* afbc */
77 {__HW_ID(5, 7), DRM_FORMAT_YUV420, 1, RICH, Flip_H_V, 0, 0},
78 /* YUV 10bit*/
79 {__HW_ID(6, 0), 0,/*XVYU2101010*/ 1, 0, 0, 0, 0},/* VYV30 unsupported */
80 {__HW_ID(6, 6), 0/*DRM_FORMAT_X0L2*/, 2, RICH, Flip_H_V, 0, 0},
81 {__HW_ID(6, 7), 0/*DRM_FORMAT_P010*/, 1, RICH, Flip_H_V, 0, 0},
82 {__HW_ID(6, 7), 0/*DRM_FORMAT_YUV420_10BIT*/, 1, RICH, Rot_ALL_H_V, LYT_NM, AFB_TH},
83};
84
85static void d71_init_fmt_tbl(struct komeda_dev *mdev)
86{
87 struct komeda_format_caps_table *table = &mdev->fmt_tbl;
88
89 table->format_caps = d71_format_caps_table;
90 table->n_formats = ARRAY_SIZE(d71_format_caps_table);
91}
92
93static struct komeda_dev_funcs d71_chip_funcs = {
94 .init_format_table = d71_init_fmt_tbl,
95 .enum_resources = d71_enum_resources,
96 .cleanup = NULL,
97};
98
99#define GLB_ARCH_ID 0x000
100#define GLB_CORE_ID 0x004
101#define GLB_CORE_INFO 0x008
102
103struct komeda_dev_funcs *
104d71_identify(u32 __iomem *reg_base, struct komeda_chip_info *chip)
105{
106 chip->arch_id = malidp_read32(reg_base, GLB_ARCH_ID);
107 chip->core_id = malidp_read32(reg_base, GLB_CORE_ID);
108 chip->core_info = malidp_read32(reg_base, GLB_CORE_INFO);
109
110 return &d71_chip_funcs;
111}
diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_crtc.c b/drivers/gpu/drm/arm/display/komeda/komeda_crtc.c
new file mode 100644
index 000000000000..5bb5a55f6b31
--- /dev/null
+++ b/drivers/gpu/drm/arm/display/komeda/komeda_crtc.c
@@ -0,0 +1,106 @@
1// SPDX-License-Identifier: GPL-2.0
2/*
3 * (C) COPYRIGHT 2018 ARM Limited. All rights reserved.
4 * Author: James.Qian.Wang <james.qian.wang@arm.com>
5 *
6 */
7#include <linux/clk.h>
8#include <linux/spinlock.h>
9#include <drm/drm_atomic.h>
10#include <drm/drm_atomic_helper.h>
11#include <drm/drm_plane_helper.h>
12#include <drm/drm_crtc_helper.h>
13#include <linux/pm_runtime.h>
14#include "komeda_dev.h"
15#include "komeda_kms.h"
16
17struct drm_crtc_helper_funcs komeda_crtc_helper_funcs = {
18};
19
20static const struct drm_crtc_funcs komeda_crtc_funcs = {
21};
22
23int komeda_kms_setup_crtcs(struct komeda_kms_dev *kms,
24 struct komeda_dev *mdev)
25{
26 struct komeda_crtc *crtc;
27 struct komeda_pipeline *master;
28 char str[16];
29 int i;
30
31 kms->n_crtcs = 0;
32
33 for (i = 0; i < mdev->n_pipelines; i++) {
34 crtc = &kms->crtcs[kms->n_crtcs];
35 master = mdev->pipelines[i];
36
37 crtc->master = master;
38 crtc->slave = NULL;
39
40 if (crtc->slave)
41 sprintf(str, "pipe-%d", crtc->slave->id);
42 else
43 sprintf(str, "None");
44
45 DRM_INFO("crtc%d: master(pipe-%d) slave(%s) output: %s.\n",
46 kms->n_crtcs, master->id, str,
47 master->of_output_dev ?
48 master->of_output_dev->full_name : "None");
49
50 kms->n_crtcs++;
51 }
52
53 return 0;
54}
55
56static struct drm_plane *
57get_crtc_primary(struct komeda_kms_dev *kms, struct komeda_crtc *crtc)
58{
59 struct komeda_plane *kplane;
60 struct drm_plane *plane;
61
62 drm_for_each_plane(plane, &kms->base) {
63 if (plane->type != DRM_PLANE_TYPE_PRIMARY)
64 continue;
65
66 kplane = to_kplane(plane);
67 /* only master can be primary */
68 if (kplane->layer->base.pipeline == crtc->master)
69 return plane;
70 }
71
72 return NULL;
73}
74
75static int komeda_crtc_add(struct komeda_kms_dev *kms,
76 struct komeda_crtc *kcrtc)
77{
78 struct drm_crtc *crtc = &kcrtc->base;
79 int err;
80
81 err = drm_crtc_init_with_planes(&kms->base, crtc,
82 get_crtc_primary(kms, kcrtc), NULL,
83 &komeda_crtc_funcs, NULL);
84 if (err)
85 return err;
86
87 drm_crtc_helper_add(crtc, &komeda_crtc_helper_funcs);
88 drm_crtc_vblank_reset(crtc);
89
90 crtc->port = kcrtc->master->of_output_port;
91
92 return 0;
93}
94
95int komeda_kms_add_crtcs(struct komeda_kms_dev *kms, struct komeda_dev *mdev)
96{
97 int i, err;
98
99 for (i = 0; i < kms->n_crtcs; i++) {
100 err = komeda_crtc_add(kms, &kms->crtcs[i]);
101 if (err)
102 return err;
103 }
104
105 return 0;
106}
diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_dev.c b/drivers/gpu/drm/arm/display/komeda/komeda_dev.c
new file mode 100644
index 000000000000..0fe6954fbbf4
--- /dev/null
+++ b/drivers/gpu/drm/arm/display/komeda/komeda_dev.c
@@ -0,0 +1,186 @@
1// SPDX-License-Identifier: GPL-2.0
2/*
3 * (C) COPYRIGHT 2018 ARM Limited. All rights reserved.
4 * Author: James.Qian.Wang <james.qian.wang@arm.com>
5 *
6 */
7#include <linux/platform_device.h>
8#include <linux/of_device.h>
9#include <linux/of_graph.h>
10#include "komeda_dev.h"
11
12static int komeda_parse_pipe_dt(struct komeda_dev *mdev, struct device_node *np)
13{
14 struct komeda_pipeline *pipe;
15 struct clk *clk;
16 u32 pipe_id;
17 int ret = 0;
18
19 ret = of_property_read_u32(np, "reg", &pipe_id);
20 if (ret != 0 || pipe_id >= mdev->n_pipelines)
21 return -EINVAL;
22
23 pipe = mdev->pipelines[pipe_id];
24
25 clk = of_clk_get_by_name(np, "aclk");
26 if (IS_ERR(clk)) {
27 DRM_ERROR("get aclk for pipeline %d failed!\n", pipe_id);
28 return PTR_ERR(clk);
29 }
30 pipe->aclk = clk;
31
32 clk = of_clk_get_by_name(np, "pxclk");
33 if (IS_ERR(clk)) {
34 DRM_ERROR("get pxclk for pipeline %d failed!\n", pipe_id);
35 return PTR_ERR(clk);
36 }
37 pipe->pxlclk = clk;
38
39 /* enum ports */
40 pipe->of_output_dev =
41 of_graph_get_remote_node(np, KOMEDA_OF_PORT_OUTPUT, 0);
42 pipe->of_output_port =
43 of_graph_get_port_by_id(np, KOMEDA_OF_PORT_OUTPUT);
44
45 pipe->of_node = np;
46
47 return 0;
48}
49
50static int komeda_parse_dt(struct device *dev, struct komeda_dev *mdev)
51{
52 struct device_node *child, *np = dev->of_node;
53 struct clk *clk;
54 int ret;
55
56 clk = devm_clk_get(dev, "mclk");
57 if (IS_ERR(clk))
58 return PTR_ERR(clk);
59
60 mdev->mclk = clk;
61
62 for_each_available_child_of_node(np, child) {
63 if (of_node_cmp(child->name, "pipeline") == 0) {
64 ret = komeda_parse_pipe_dt(mdev, child);
65 if (ret) {
66 DRM_ERROR("parse pipeline dt error!\n");
67 of_node_put(child);
68 break;
69 }
70 }
71 }
72
73 return ret;
74}
75
76struct komeda_dev *komeda_dev_create(struct device *dev)
77{
78 struct platform_device *pdev = to_platform_device(dev);
79 const struct komeda_product_data *product;
80 struct komeda_dev *mdev;
81 struct resource *io_res;
82 int err = 0;
83
84 product = of_device_get_match_data(dev);
85 if (!product)
86 return ERR_PTR(-ENODEV);
87
88 io_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
89 if (!io_res) {
90 DRM_ERROR("No registers defined.\n");
91 return ERR_PTR(-ENODEV);
92 }
93
94 mdev = devm_kzalloc(dev, sizeof(*mdev), GFP_KERNEL);
95 if (!mdev)
96 return ERR_PTR(-ENOMEM);
97
98 mdev->dev = dev;
99 mdev->reg_base = devm_ioremap_resource(dev, io_res);
100 if (IS_ERR(mdev->reg_base)) {
101 DRM_ERROR("Map register space failed.\n");
102 err = PTR_ERR(mdev->reg_base);
103 mdev->reg_base = NULL;
104 goto err_cleanup;
105 }
106
107 mdev->pclk = devm_clk_get(dev, "pclk");
108 if (IS_ERR(mdev->pclk)) {
109 DRM_ERROR("Get APB clk failed.\n");
110 err = PTR_ERR(mdev->pclk);
111 mdev->pclk = NULL;
112 goto err_cleanup;
113 }
114
115 /* Enable APB clock to access the registers */
116 clk_prepare_enable(mdev->pclk);
117
118 mdev->funcs = product->identify(mdev->reg_base, &mdev->chip);
119 if (!komeda_product_match(mdev, product->product_id)) {
120 DRM_ERROR("DT configured %x mismatch with real HW %x.\n",
121 product->product_id,
122 MALIDP_CORE_ID_PRODUCT_ID(mdev->chip.core_id));
123 err = -ENODEV;
124 goto err_cleanup;
125 }
126
127 DRM_INFO("Found ARM Mali-D%x version r%dp%d\n",
128 MALIDP_CORE_ID_PRODUCT_ID(mdev->chip.core_id),
129 MALIDP_CORE_ID_MAJOR(mdev->chip.core_id),
130 MALIDP_CORE_ID_MINOR(mdev->chip.core_id));
131
132 mdev->funcs->init_format_table(mdev);
133
134 err = mdev->funcs->enum_resources(mdev);
135 if (err) {
136 DRM_ERROR("enumerate display resource failed.\n");
137 goto err_cleanup;
138 }
139
140 err = komeda_parse_dt(dev, mdev);
141 if (err) {
142 DRM_ERROR("parse device tree failed.\n");
143 goto err_cleanup;
144 }
145
146 return mdev;
147
148err_cleanup:
149 komeda_dev_destroy(mdev);
150 return ERR_PTR(err);
151}
152
153void komeda_dev_destroy(struct komeda_dev *mdev)
154{
155 struct device *dev = mdev->dev;
156 struct komeda_dev_funcs *funcs = mdev->funcs;
157 int i;
158
159 for (i = 0; i < mdev->n_pipelines; i++) {
160 komeda_pipeline_destroy(mdev, mdev->pipelines[i]);
161 mdev->pipelines[i] = NULL;
162 }
163
164 mdev->n_pipelines = 0;
165
166 if (funcs && funcs->cleanup)
167 funcs->cleanup(mdev);
168
169 if (mdev->reg_base) {
170 devm_iounmap(dev, mdev->reg_base);
171 mdev->reg_base = NULL;
172 }
173
174 if (mdev->mclk) {
175 devm_clk_put(dev, mdev->mclk);
176 mdev->mclk = NULL;
177 }
178
179 if (mdev->pclk) {
180 clk_disable_unprepare(mdev->pclk);
181 devm_clk_put(dev, mdev->pclk);
182 mdev->pclk = NULL;
183 }
184
185 devm_kfree(dev, mdev);
186}
diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_dev.h b/drivers/gpu/drm/arm/display/komeda/komeda_dev.h
new file mode 100644
index 000000000000..0f77dead6a23
--- /dev/null
+++ b/drivers/gpu/drm/arm/display/komeda/komeda_dev.h
@@ -0,0 +1,110 @@
1/* SPDX-License-Identifier: GPL-2.0 */
2/*
3 * (C) COPYRIGHT 2018 ARM Limited. All rights reserved.
4 * Author: James.Qian.Wang <james.qian.wang@arm.com>
5 *
6 */
7#ifndef _KOMEDA_DEV_H_
8#define _KOMEDA_DEV_H_
9
10#include <linux/device.h>
11#include <linux/clk.h>
12#include "komeda_pipeline.h"
13#include "malidp_product.h"
14#include "komeda_format_caps.h"
15
16/* malidp device id */
17enum {
18 MALI_D71 = 0,
19};
20
21/* pipeline DT ports */
22enum {
23 KOMEDA_OF_PORT_OUTPUT = 0,
24 KOMEDA_OF_PORT_COPROC = 1,
25};
26
27struct komeda_chip_info {
28 u32 arch_id;
29 u32 core_id;
30 u32 core_info;
31 u32 bus_width;
32};
33
34struct komeda_product_data {
35 u32 product_id;
36 struct komeda_dev_funcs *(*identify)(u32 __iomem *reg,
37 struct komeda_chip_info *info);
38};
39
40struct komeda_dev;
41
42/**
43 * struct komeda_dev_funcs
44 *
45 * Supplied by chip level and returned by the chip entry function xxx_identify,
46 */
47struct komeda_dev_funcs {
48 /**
49 * @init_format_table:
50 *
51 * initialize &komeda_dev->format_table, this function should be called
52 * before the &enum_resource
53 */
54 void (*init_format_table)(struct komeda_dev *mdev);
55 /**
56 * @enum_resources:
57 *
58 * for CHIP to report or add pipeline and component resources to CORE
59 */
60 int (*enum_resources)(struct komeda_dev *mdev);
61 /** @cleanup: call to chip to cleanup komeda_dev->chip data */
62 void (*cleanup)(struct komeda_dev *mdev);
63};
64
65/**
66 * struct komeda_dev
67 *
68 * Pipeline and component are used to describe how to handle the pixel data.
69 * komeda_device is for describing the whole view of the device, and the
70 * control-abilites of device.
71 */
72struct komeda_dev {
73 struct device *dev;
74 u32 __iomem *reg_base;
75
76 struct komeda_chip_info chip;
77 /** @fmt_tbl: initialized by &komeda_dev_funcs->init_format_table */
78 struct komeda_format_caps_table fmt_tbl;
79 /** @pclk: APB clock for register access */
80 struct clk *pclk;
81 /** @mck: HW main engine clk */
82 struct clk *mclk;
83
84 int n_pipelines;
85 struct komeda_pipeline *pipelines[KOMEDA_MAX_PIPELINES];
86
87 /** @funcs: chip funcs to access to HW */
88 struct komeda_dev_funcs *funcs;
89 /**
90 * @chip_data:
91 *
92 * chip data will be added by &komeda_dev_funcs.enum_resources() and
93 * destroyed by &komeda_dev_funcs.cleanup()
94 */
95 void *chip_data;
96};
97
98static inline bool
99komeda_product_match(struct komeda_dev *mdev, u32 target)
100{
101 return MALIDP_CORE_ID_PRODUCT_ID(mdev->chip.core_id) == target;
102}
103
104struct komeda_dev_funcs *
105d71_identify(u32 __iomem *reg, struct komeda_chip_info *chip);
106
107struct komeda_dev *komeda_dev_create(struct device *dev);
108void komeda_dev_destroy(struct komeda_dev *mdev);
109
110#endif /*_KOMEDA_DEV_H_*/
diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_drv.c b/drivers/gpu/drm/arm/display/komeda/komeda_drv.c
new file mode 100644
index 000000000000..2bdd189b041d
--- /dev/null
+++ b/drivers/gpu/drm/arm/display/komeda/komeda_drv.c
@@ -0,0 +1,144 @@
1// SPDX-License-Identifier: GPL-2.0
2/*
3 * (C) COPYRIGHT 2018 ARM Limited. All rights reserved.
4 * Author: James.Qian.Wang <james.qian.wang@arm.com>
5 *
6 */
7#include <linux/module.h>
8#include <linux/kernel.h>
9#include <linux/platform_device.h>
10#include <linux/component.h>
11#include <drm/drm_of.h>
12#include "komeda_dev.h"
13#include "komeda_kms.h"
14
15struct komeda_drv {
16 struct komeda_dev *mdev;
17 struct komeda_kms_dev *kms;
18};
19
20static void komeda_unbind(struct device *dev)
21{
22 struct komeda_drv *mdrv = dev_get_drvdata(dev);
23
24 if (!mdrv)
25 return;
26
27 komeda_kms_detach(mdrv->kms);
28 komeda_dev_destroy(mdrv->mdev);
29
30 dev_set_drvdata(dev, NULL);
31 devm_kfree(dev, mdrv);
32}
33
34static int komeda_bind(struct device *dev)
35{
36 struct komeda_drv *mdrv;
37 int err;
38
39 mdrv = devm_kzalloc(dev, sizeof(*mdrv), GFP_KERNEL);
40 if (!mdrv)
41 return -ENOMEM;
42
43 mdrv->mdev = komeda_dev_create(dev);
44 if (IS_ERR(mdrv->mdev)) {
45 err = PTR_ERR(mdrv->mdev);
46 goto free_mdrv;
47 }
48
49 mdrv->kms = komeda_kms_attach(mdrv->mdev);
50 if (IS_ERR(mdrv->kms)) {
51 err = PTR_ERR(mdrv->kms);
52 goto destroy_mdev;
53 }
54
55 dev_set_drvdata(dev, mdrv);
56
57 return 0;
58
59destroy_mdev:
60 komeda_dev_destroy(mdrv->mdev);
61
62free_mdrv:
63 devm_kfree(dev, mdrv);
64 return err;
65}
66
67static const struct component_master_ops komeda_master_ops = {
68 .bind = komeda_bind,
69 .unbind = komeda_unbind,
70};
71
72static int compare_of(struct device *dev, void *data)
73{
74 return dev->of_node == data;
75}
76
77static void komeda_add_slave(struct device *master,
78 struct component_match **match,
79 struct device_node *np, int port)
80{
81 struct device_node *remote;
82
83 remote = of_graph_get_remote_node(np, port, 0);
84 if (remote) {
85 drm_of_component_match_add(master, match, compare_of, remote);
86 of_node_put(remote);
87 }
88}
89
90static int komeda_platform_probe(struct platform_device *pdev)
91{
92 struct device *dev = &pdev->dev;
93 struct component_match *match = NULL;
94 struct device_node *child;
95
96 if (!dev->of_node)
97 return -ENODEV;
98
99 for_each_available_child_of_node(dev->of_node, child) {
100 if (of_node_cmp(child->name, "pipeline") != 0)
101 continue;
102
103 /* add connector */
104 komeda_add_slave(dev, &match, child, KOMEDA_OF_PORT_OUTPUT);
105 }
106
107 return component_master_add_with_match(dev, &komeda_master_ops, match);
108}
109
110static int komeda_platform_remove(struct platform_device *pdev)
111{
112 component_master_del(&pdev->dev, &komeda_master_ops);
113 return 0;
114}
115
116static const struct komeda_product_data komeda_products[] = {
117 [MALI_D71] = {
118 .product_id = MALIDP_D71_PRODUCT_ID,
119 .identify = d71_identify,
120 },
121};
122
123const struct of_device_id komeda_of_match[] = {
124 { .compatible = "arm,mali-d71", .data = &komeda_products[MALI_D71], },
125 {},
126};
127
128MODULE_DEVICE_TABLE(of, komeda_of_match);
129
130static struct platform_driver komeda_platform_driver = {
131 .probe = komeda_platform_probe,
132 .remove = komeda_platform_remove,
133 .driver = {
134 .name = "komeda",
135 .of_match_table = komeda_of_match,
136 .pm = NULL,
137 },
138};
139
140module_platform_driver(komeda_platform_driver);
141
142MODULE_AUTHOR("James.Qian.Wang <james.qian.wang@arm.com>");
143MODULE_DESCRIPTION("Komeda KMS driver");
144MODULE_LICENSE("GPL v2");
diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_format_caps.c b/drivers/gpu/drm/arm/display/komeda/komeda_format_caps.c
new file mode 100644
index 000000000000..1e17bd6107a4
--- /dev/null
+++ b/drivers/gpu/drm/arm/display/komeda/komeda_format_caps.c
@@ -0,0 +1,75 @@
1// SPDX-License-Identifier: GPL-2.0
2/*
3 * (C) COPYRIGHT 2018 ARM Limited. All rights reserved.
4 * Author: James.Qian.Wang <james.qian.wang@arm.com>
5 *
6 */
7
8#include <linux/slab.h>
9#include "komeda_format_caps.h"
10#include "malidp_utils.h"
11
12const struct komeda_format_caps *
13komeda_get_format_caps(struct komeda_format_caps_table *table,
14 u32 fourcc, u64 modifier)
15{
16 const struct komeda_format_caps *caps;
17 u64 afbc_features = modifier & ~(AFBC_FORMAT_MOD_BLOCK_SIZE_MASK);
18 u32 afbc_layout = modifier & AFBC_FORMAT_MOD_BLOCK_SIZE_MASK;
19 int id;
20
21 for (id = 0; id < table->n_formats; id++) {
22 caps = &table->format_caps[id];
23
24 if (fourcc != caps->fourcc)
25 continue;
26
27 if ((modifier == 0ULL) && (caps->supported_afbc_layouts == 0))
28 return caps;
29
30 if (has_bits(afbc_features, caps->supported_afbc_features) &&
31 has_bit(afbc_layout, caps->supported_afbc_layouts))
32 return caps;
33 }
34
35 return NULL;
36}
37
38u32 *komeda_get_layer_fourcc_list(struct komeda_format_caps_table *table,
39 u32 layer_type, u32 *n_fmts)
40{
41 const struct komeda_format_caps *cap;
42 u32 *fmts;
43 int i, j, n = 0;
44
45 fmts = kcalloc(table->n_formats, sizeof(u32), GFP_KERNEL);
46 if (!fmts)
47 return NULL;
48
49 for (i = 0; i < table->n_formats; i++) {
50 cap = &table->format_caps[i];
51 if (!(layer_type & cap->supported_layer_types) ||
52 (cap->fourcc == 0))
53 continue;
54
55 /* one fourcc may has two caps items in table (afbc/none-afbc),
56 * so check the existing list to avoid adding a duplicated one.
57 */
58 for (j = n - 1; j >= 0; j--)
59 if (fmts[j] == cap->fourcc)
60 break;
61
62 if (j < 0)
63 fmts[n++] = cap->fourcc;
64 }
65
66 if (n_fmts)
67 *n_fmts = n;
68
69 return fmts;
70}
71
72void komeda_put_fourcc_list(u32 *fourcc_list)
73{
74 kfree(fourcc_list);
75}
diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_format_caps.h b/drivers/gpu/drm/arm/display/komeda/komeda_format_caps.h
new file mode 100644
index 000000000000..60f39e77b098
--- /dev/null
+++ b/drivers/gpu/drm/arm/display/komeda/komeda_format_caps.h
@@ -0,0 +1,89 @@
1/* SPDX-License-Identifier: GPL-2.0 */
2/*
3 * (C) COPYRIGHT 2018 ARM Limited. All rights reserved.
4 * Author: James.Qian.Wang <james.qian.wang@arm.com>
5 *
6 */
7
8#ifndef _KOMEDA_FORMAT_CAPS_H_
9#define _KOMEDA_FORMAT_CAPS_H_
10
11#include <linux/types.h>
12#include <uapi/drm/drm_fourcc.h>
13#include <drm/drm_fourcc.h>
14
15#define AFBC(x) DRM_FORMAT_MOD_ARM_AFBC(x)
16
17/* afbc layerout */
18#define AFBC_16x16(x) AFBC(AFBC_FORMAT_MOD_BLOCK_SIZE_16x16 | (x))
19#define AFBC_32x8(x) AFBC(AFBC_FORMAT_MOD_BLOCK_SIZE_32x8 | (x))
20
21/* afbc features */
22#define _YTR AFBC_FORMAT_MOD_YTR
23#define _SPLIT AFBC_FORMAT_MOD_SPLIT
24#define _SPARSE AFBC_FORMAT_MOD_SPARSE
25#define _CBR AFBC_FORMAT_MOD_CBR
26#define _TILED AFBC_FORMAT_MOD_TILED
27#define _SC AFBC_FORMAT_MOD_SC
28
29/* layer_type */
30#define KOMEDA_FMT_RICH_LAYER BIT(0)
31#define KOMEDA_FMT_SIMPLE_LAYER BIT(1)
32#define KOMEDA_FMT_WB_LAYER BIT(2)
33
34#define AFBC_TH_LAYOUT_ALIGNMENT 8
35#define AFBC_HEADER_SIZE 16
36#define AFBC_SUPERBLK_ALIGNMENT 128
37#define AFBC_SUPERBLK_PIXELS 256
38#define AFBC_BODY_START_ALIGNMENT 1024
39#define AFBC_TH_BODY_START_ALIGNMENT 4096
40
41/**
42 * struct komeda_format_caps
43 *
44 * komeda_format_caps is for describing ARM display specific features and
45 * limitations for a specific format, and format_caps will be linked into
46 * &komeda_framebuffer like a extension of &drm_format_info.
47 *
48 * NOTE: one fourcc may has two different format_caps items for fourcc and
49 * fourcc+modifier
50 *
51 * @hw_id: hw format id, hw specific value.
52 * @fourcc: drm fourcc format.
53 * @tile_size: format tiled size, used by ARM format X0L0/X0L2
54 * @supported_layer_types: indicate which layer supports this format
55 * @supported_rots: allowed rotations for this format
56 * @supported_afbc_layouts: supported afbc layerout
57 * @supported_afbc_features: supported afbc features
58 */
59struct komeda_format_caps {
60 u32 hw_id;
61 u32 fourcc;
62 u32 tile_size;
63 u32 supported_layer_types;
64 u32 supported_rots;
65 u32 supported_afbc_layouts;
66 u64 supported_afbc_features;
67};
68
69/**
70 * struct komeda_format_caps_table - format_caps mananger
71 *
72 * @n_formats: the size of format_caps list.
73 * @format_caps: format_caps list.
74 */
75struct komeda_format_caps_table {
76 u32 n_formats;
77 const struct komeda_format_caps *format_caps;
78};
79
80const struct komeda_format_caps *
81komeda_get_format_caps(struct komeda_format_caps_table *table,
82 u32 fourcc, u64 modifier);
83
84u32 *komeda_get_layer_fourcc_list(struct komeda_format_caps_table *table,
85 u32 layer_type, u32 *n_fmts);
86
87void komeda_put_fourcc_list(u32 *fourcc_list);
88
89#endif
diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_framebuffer.c b/drivers/gpu/drm/arm/display/komeda/komeda_framebuffer.c
new file mode 100644
index 000000000000..23ee74d42239
--- /dev/null
+++ b/drivers/gpu/drm/arm/display/komeda/komeda_framebuffer.c
@@ -0,0 +1,165 @@
1// SPDX-License-Identifier: GPL-2.0
2/*
3 * (C) COPYRIGHT 2018 ARM Limited. All rights reserved.
4 * Author: James.Qian.Wang <james.qian.wang@arm.com>
5 *
6 */
7#include <drm/drm_gem.h>
8#include <drm/drm_gem_framebuffer_helper.h>
9#include <drm/drm_fb_cma_helper.h>
10#include <drm/drm_gem_cma_helper.h>
11#include "komeda_framebuffer.h"
12#include "komeda_dev.h"
13
14static void komeda_fb_destroy(struct drm_framebuffer *fb)
15{
16 struct komeda_fb *kfb = to_kfb(fb);
17 u32 i;
18
19 for (i = 0; i < fb->format->num_planes; i++)
20 drm_gem_object_put_unlocked(fb->obj[i]);
21
22 drm_framebuffer_cleanup(fb);
23 kfree(kfb);
24}
25
26static int komeda_fb_create_handle(struct drm_framebuffer *fb,
27 struct drm_file *file, u32 *handle)
28{
29 return drm_gem_handle_create(file, fb->obj[0], handle);
30}
31
32static const struct drm_framebuffer_funcs komeda_fb_funcs = {
33 .destroy = komeda_fb_destroy,
34 .create_handle = komeda_fb_create_handle,
35};
36
37static int
38komeda_fb_none_afbc_size_check(struct komeda_dev *mdev, struct komeda_fb *kfb,
39 struct drm_file *file,
40 const struct drm_mode_fb_cmd2 *mode_cmd)
41{
42 struct drm_framebuffer *fb = &kfb->base;
43 struct drm_gem_object *obj;
44 u32 min_size = 0;
45 u32 i;
46
47 for (i = 0; i < fb->format->num_planes; i++) {
48 obj = drm_gem_object_lookup(file, mode_cmd->handles[i]);
49 if (!obj) {
50 DRM_DEBUG_KMS("Failed to lookup GEM object\n");
51 fb->obj[i] = NULL;
52
53 return -ENOENT;
54 }
55
56 kfb->aligned_w = fb->width / (i ? fb->format->hsub : 1);
57 kfb->aligned_h = fb->height / (i ? fb->format->vsub : 1);
58
59 if (fb->pitches[i] % mdev->chip.bus_width) {
60 DRM_DEBUG_KMS("Pitch[%d]: 0x%x doesn't align to 0x%x\n",
61 i, fb->pitches[i], mdev->chip.bus_width);
62 drm_gem_object_put_unlocked(obj);
63 fb->obj[i] = NULL;
64
65 return -EINVAL;
66 }
67
68 min_size = ((kfb->aligned_h / kfb->format_caps->tile_size - 1)
69 * fb->pitches[i])
70 + (kfb->aligned_w * fb->format->cpp[i]
71 * kfb->format_caps->tile_size)
72 + fb->offsets[i];
73
74 if (obj->size < min_size) {
75 DRM_DEBUG_KMS("Fail to check none afbc fb size.\n");
76 drm_gem_object_put_unlocked(obj);
77 fb->obj[i] = NULL;
78
79 return -EINVAL;
80 }
81
82 fb->obj[i] = obj;
83 }
84
85 if (fb->format->num_planes == 3) {
86 if (fb->pitches[1] != fb->pitches[2]) {
87 DRM_DEBUG_KMS("The pitch[1] and [2] are not same\n");
88 return -EINVAL;
89 }
90 }
91
92 return 0;
93}
94
95struct drm_framebuffer *
96komeda_fb_create(struct drm_device *dev, struct drm_file *file,
97 const struct drm_mode_fb_cmd2 *mode_cmd)
98{
99 struct komeda_dev *mdev = dev->dev_private;
100 struct komeda_fb *kfb;
101 int ret = 0, i;
102
103 kfb = kzalloc(sizeof(*kfb), GFP_KERNEL);
104 if (!kfb)
105 return ERR_PTR(-ENOMEM);
106
107 kfb->format_caps = komeda_get_format_caps(&mdev->fmt_tbl,
108 mode_cmd->pixel_format,
109 mode_cmd->modifier[0]);
110 if (!kfb->format_caps) {
111 DRM_DEBUG_KMS("FMT %x is not supported.\n",
112 mode_cmd->pixel_format);
113 kfree(kfb);
114 return ERR_PTR(-EINVAL);
115 }
116
117 drm_helper_mode_fill_fb_struct(dev, &kfb->base, mode_cmd);
118
119 ret = komeda_fb_none_afbc_size_check(mdev, kfb, file, mode_cmd);
120 if (ret < 0)
121 goto err_cleanup;
122
123 ret = drm_framebuffer_init(dev, &kfb->base, &komeda_fb_funcs);
124 if (ret < 0) {
125 DRM_DEBUG_KMS("failed to initialize fb\n");
126
127 goto err_cleanup;
128 }
129
130 return &kfb->base;
131
132err_cleanup:
133 for (i = 0; i < kfb->base.format->num_planes; i++)
134 drm_gem_object_put_unlocked(kfb->base.obj[i]);
135
136 kfree(kfb);
137 return ERR_PTR(ret);
138}
139
140dma_addr_t
141komeda_fb_get_pixel_addr(struct komeda_fb *kfb, int x, int y, int plane)
142{
143 struct drm_framebuffer *fb = &kfb->base;
144 const struct drm_gem_cma_object *obj;
145 u32 plane_x, plane_y, cpp, pitch, offset;
146
147 if (plane >= fb->format->num_planes) {
148 DRM_DEBUG_KMS("Out of max plane num.\n");
149 return -EINVAL;
150 }
151
152 obj = drm_fb_cma_get_gem_obj(fb, plane);
153
154 offset = fb->offsets[plane];
155 if (!fb->modifier) {
156 plane_x = x / (plane ? fb->format->hsub : 1);
157 plane_y = y / (plane ? fb->format->vsub : 1);
158 cpp = fb->format->cpp[plane];
159 pitch = fb->pitches[plane];
160 offset += plane_x * cpp * kfb->format_caps->tile_size +
161 (plane_y * pitch) / kfb->format_caps->tile_size;
162 }
163
164 return obj->paddr + offset;
165}
diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_framebuffer.h b/drivers/gpu/drm/arm/display/komeda/komeda_framebuffer.h
new file mode 100644
index 000000000000..0de2e4a2afd2
--- /dev/null
+++ b/drivers/gpu/drm/arm/display/komeda/komeda_framebuffer.h
@@ -0,0 +1,34 @@
1/* SPDX-License-Identifier: GPL-2.0 */
2/*
3 * (C) COPYRIGHT 2018 ARM Limited. All rights reserved.
4 * Author: James.Qian.Wang <james.qian.wang@arm.com>
5 *
6 */
7#ifndef _KOMEDA_FRAMEBUFFER_H_
8#define _KOMEDA_FRAMEBUFFER_H_
9
10#include <drm/drm_framebuffer.h>
11#include "komeda_format_caps.h"
12
13/** struct komeda_fb - entend drm_framebuffer with komeda attribute */
14struct komeda_fb {
15 /** @base: &drm_framebuffer */
16 struct drm_framebuffer base;
17 /* @format_caps: &komeda_format_caps */
18 const struct komeda_format_caps *format_caps;
19 /** @aligned_w: aligned frame buffer width */
20 u32 aligned_w;
21 /** @aligned_h: aligned frame buffer height */
22 u32 aligned_h;
23};
24
25#define to_kfb(dfb) container_of(dfb, struct komeda_fb, base)
26
27struct drm_framebuffer *
28komeda_fb_create(struct drm_device *dev, struct drm_file *file,
29 const struct drm_mode_fb_cmd2 *mode_cmd);
30dma_addr_t
31komeda_fb_get_pixel_addr(struct komeda_fb *kfb, int x, int y, int plane);
32bool komeda_fb_is_layer_supported(struct komeda_fb *kfb, u32 layer_type);
33
34#endif
diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_kms.c b/drivers/gpu/drm/arm/display/komeda/komeda_kms.c
new file mode 100644
index 000000000000..3fc096d3883e
--- /dev/null
+++ b/drivers/gpu/drm/arm/display/komeda/komeda_kms.c
@@ -0,0 +1,167 @@
1// SPDX-License-Identifier: GPL-2.0
2/*
3 * (C) COPYRIGHT 2018 ARM Limited. All rights reserved.
4 * Author: James.Qian.Wang <james.qian.wang@arm.com>
5 *
6 */
7#include <linux/component.h>
8#include <drm/drm_atomic.h>
9#include <drm/drm_atomic_helper.h>
10#include <drm/drm_gem_framebuffer_helper.h>
11#include <drm/drm_gem_cma_helper.h>
12#include <drm/drm_fb_helper.h>
13#include <linux/interrupt.h>
14#include "komeda_dev.h"
15#include "komeda_kms.h"
16#include "komeda_framebuffer.h"
17
18DEFINE_DRM_GEM_CMA_FOPS(komeda_cma_fops);
19
20static int komeda_gem_cma_dumb_create(struct drm_file *file,
21 struct drm_device *dev,
22 struct drm_mode_create_dumb *args)
23{
24 u32 alignment = 16; /* TODO get alignment from dev */
25
26 args->pitch = ALIGN(DIV_ROUND_UP(args->width * args->bpp, 8),
27 alignment);
28
29 return drm_gem_cma_dumb_create_internal(file, dev, args);
30}
31
32static struct drm_driver komeda_kms_driver = {
33 .driver_features = DRIVER_GEM | DRIVER_MODESET | DRIVER_ATOMIC |
34 DRIVER_PRIME,
35 .lastclose = drm_fb_helper_lastclose,
36 .gem_free_object_unlocked = drm_gem_cma_free_object,
37 .gem_vm_ops = &drm_gem_cma_vm_ops,
38 .dumb_create = komeda_gem_cma_dumb_create,
39 .prime_handle_to_fd = drm_gem_prime_handle_to_fd,
40 .prime_fd_to_handle = drm_gem_prime_fd_to_handle,
41 .gem_prime_export = drm_gem_prime_export,
42 .gem_prime_import = drm_gem_prime_import,
43 .gem_prime_get_sg_table = drm_gem_cma_prime_get_sg_table,
44 .gem_prime_import_sg_table = drm_gem_cma_prime_import_sg_table,
45 .gem_prime_vmap = drm_gem_cma_prime_vmap,
46 .gem_prime_vunmap = drm_gem_cma_prime_vunmap,
47 .gem_prime_mmap = drm_gem_cma_prime_mmap,
48 .fops = &komeda_cma_fops,
49 .name = "komeda",
50 .desc = "Arm Komeda Display Processor driver",
51 .date = "20181101",
52 .major = 0,
53 .minor = 1,
54};
55
56static void komeda_kms_commit_tail(struct drm_atomic_state *old_state)
57{
58 struct drm_device *dev = old_state->dev;
59
60 drm_atomic_helper_commit_modeset_disables(dev, old_state);
61
62 drm_atomic_helper_commit_planes(dev, old_state, 0);
63
64 drm_atomic_helper_commit_modeset_enables(dev, old_state);
65
66 drm_atomic_helper_wait_for_flip_done(dev, old_state);
67
68 drm_atomic_helper_commit_hw_done(old_state);
69
70 drm_atomic_helper_cleanup_planes(dev, old_state);
71}
72
73static const struct drm_mode_config_helper_funcs komeda_mode_config_helpers = {
74 .atomic_commit_tail = komeda_kms_commit_tail,
75};
76
77static const struct drm_mode_config_funcs komeda_mode_config_funcs = {
78 .fb_create = komeda_fb_create,
79 .atomic_check = drm_atomic_helper_check,
80 .atomic_commit = drm_atomic_helper_commit,
81};
82
83static void komeda_kms_mode_config_init(struct komeda_kms_dev *kms,
84 struct komeda_dev *mdev)
85{
86 struct drm_mode_config *config = &kms->base.mode_config;
87
88 drm_mode_config_init(&kms->base);
89
90 komeda_kms_setup_crtcs(kms, mdev);
91
92 /* Get value from dev */
93 config->min_width = 0;
94 config->min_height = 0;
95 config->max_width = 4096;
96 config->max_height = 4096;
97 config->allow_fb_modifiers = false;
98
99 config->funcs = &komeda_mode_config_funcs;
100 config->helper_private = &komeda_mode_config_helpers;
101}
102
103struct komeda_kms_dev *komeda_kms_attach(struct komeda_dev *mdev)
104{
105 struct komeda_kms_dev *kms = kzalloc(sizeof(*kms), GFP_KERNEL);
106 struct drm_device *drm;
107 int err;
108
109 if (!kms)
110 return ERR_PTR(-ENOMEM);
111
112 drm = &kms->base;
113 err = drm_dev_init(drm, &komeda_kms_driver, mdev->dev);
114 if (err)
115 goto free_kms;
116
117 drm->dev_private = mdev;
118
119 komeda_kms_mode_config_init(kms, mdev);
120
121 err = komeda_kms_add_private_objs(kms, mdev);
122 if (err)
123 goto cleanup_mode_config;
124
125 err = komeda_kms_add_planes(kms, mdev);
126 if (err)
127 goto cleanup_mode_config;
128
129 err = drm_vblank_init(drm, kms->n_crtcs);
130 if (err)
131 goto cleanup_mode_config;
132
133 err = komeda_kms_add_crtcs(kms, mdev);
134 if (err)
135 goto cleanup_mode_config;
136
137 err = component_bind_all(mdev->dev, kms);
138 if (err)
139 goto cleanup_mode_config;
140
141 drm_mode_config_reset(drm);
142
143 err = drm_dev_register(drm, 0);
144 if (err)
145 goto cleanup_mode_config;
146
147 return kms;
148
149cleanup_mode_config:
150 drm_mode_config_cleanup(drm);
151free_kms:
152 kfree(kms);
153 return ERR_PTR(err);
154}
155
156void komeda_kms_detach(struct komeda_kms_dev *kms)
157{
158 struct drm_device *drm = &kms->base;
159 struct komeda_dev *mdev = drm->dev_private;
160
161 drm_dev_unregister(drm);
162 component_unbind_all(mdev->dev, drm);
163 komeda_kms_cleanup_private_objs(mdev);
164 drm_mode_config_cleanup(drm);
165 drm->dev_private = NULL;
166 drm_dev_put(drm);
167}
diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_kms.h b/drivers/gpu/drm/arm/display/komeda/komeda_kms.h
new file mode 100644
index 000000000000..f13666004a42
--- /dev/null
+++ b/drivers/gpu/drm/arm/display/komeda/komeda_kms.h
@@ -0,0 +1,113 @@
1/* SPDX-License-Identifier: GPL-2.0 */
2/*
3 * (C) COPYRIGHT 2018 ARM Limited. All rights reserved.
4 * Author: James.Qian.Wang <james.qian.wang@arm.com>
5 *
6 */
7#ifndef _KOMEDA_KMS_H_
8#define _KOMEDA_KMS_H_
9
10#include <drm/drm_atomic.h>
11#include <drm/drm_atomic_helper.h>
12#include <drm/drm_crtc_helper.h>
13#include <drm/drm_writeback.h>
14
15/** struct komeda_plane - komeda instance of drm_plane */
16struct komeda_plane {
17 /** @base: &drm_plane */
18 struct drm_plane base;
19 /**
20 * @layer:
21 *
22 * represents available layer input pipelines for this plane.
23 *
24 * NOTE:
25 * the layer is not for a specific Layer, but indicate a group of
26 * Layers with same capabilities.
27 */
28 struct komeda_layer *layer;
29};
30
31/**
32 * struct komeda_plane_state
33 *
34 * The plane_state can be split into two data flow (left/right) and handled
35 * by two layers &komeda_plane.layer and &komeda_plane.layer.right
36 */
37struct komeda_plane_state {
38 /** @base: &drm_plane_state */
39 struct drm_plane_state base;
40
41 /* private properties */
42};
43
44/**
45 * struct komeda_wb_connector
46 */
47struct komeda_wb_connector {
48 /** @base: &drm_writeback_connector */
49 struct drm_writeback_connector base;
50
51 /** @wb_layer: represents associated writeback pipeline of komeda */
52 struct komeda_layer *wb_layer;
53};
54
55/**
56 * struct komeda_crtc
57 */
58struct komeda_crtc {
59 /** @base: &drm_crtc */
60 struct drm_crtc base;
61 /** @master: only master has display output */
62 struct komeda_pipeline *master;
63 /**
64 * @slave: optional
65 *
66 * Doesn't have its own display output, the handled data flow will
67 * merge into the master.
68 */
69 struct komeda_pipeline *slave;
70};
71
72/** struct komeda_crtc_state */
73struct komeda_crtc_state {
74 /** @base: &drm_crtc_state */
75 struct drm_crtc_state base;
76
77 /* private properties */
78
79 /* computed state which are used by validate/check */
80 u32 affected_pipes;
81 u32 active_pipes;
82};
83
84/** struct komeda_kms_dev - for gather KMS related things */
85struct komeda_kms_dev {
86 /** @base: &drm_device */
87 struct drm_device base;
88
89 /** @n_crtcs: valid numbers of crtcs in &komeda_kms_dev.crtcs */
90 int n_crtcs;
91 /** @crtcs: crtcs list */
92 struct komeda_crtc crtcs[KOMEDA_MAX_PIPELINES];
93};
94
95#define to_kplane(p) container_of(p, struct komeda_plane, base)
96#define to_kplane_st(p) container_of(p, struct komeda_plane_state, base)
97#define to_kconn(p) container_of(p, struct komeda_wb_connector, base)
98#define to_kcrtc(p) container_of(p, struct komeda_crtc, base)
99#define to_kcrtc_st(p) container_of(p, struct komeda_crtc_state, base)
100#define to_kdev(p) container_of(p, struct komeda_kms_dev, base)
101
102int komeda_kms_setup_crtcs(struct komeda_kms_dev *kms, struct komeda_dev *mdev);
103
104int komeda_kms_add_crtcs(struct komeda_kms_dev *kms, struct komeda_dev *mdev);
105int komeda_kms_add_planes(struct komeda_kms_dev *kms, struct komeda_dev *mdev);
106int komeda_kms_add_private_objs(struct komeda_kms_dev *kms,
107 struct komeda_dev *mdev);
108void komeda_kms_cleanup_private_objs(struct komeda_dev *mdev);
109
110struct komeda_kms_dev *komeda_kms_attach(struct komeda_dev *mdev);
111void komeda_kms_detach(struct komeda_kms_dev *kms);
112
113#endif /*_KOMEDA_KMS_H_*/
diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_pipeline.c b/drivers/gpu/drm/arm/display/komeda/komeda_pipeline.c
new file mode 100644
index 000000000000..edb1cd7795f9
--- /dev/null
+++ b/drivers/gpu/drm/arm/display/komeda/komeda_pipeline.c
@@ -0,0 +1,200 @@
1// SPDX-License-Identifier: GPL-2.0
2/*
3 * (C) COPYRIGHT 2018 ARM Limited. All rights reserved.
4 * Author: James.Qian.Wang <james.qian.wang@arm.com>
5 *
6 */
7#include "komeda_dev.h"
8#include "komeda_pipeline.h"
9
10/** komeda_pipeline_add - Add a pipeline to &komeda_dev */
11struct komeda_pipeline *
12komeda_pipeline_add(struct komeda_dev *mdev, size_t size,
13 struct komeda_pipeline_funcs *funcs)
14{
15 struct komeda_pipeline *pipe;
16
17 if (mdev->n_pipelines + 1 > KOMEDA_MAX_PIPELINES) {
18 DRM_ERROR("Exceed max support %d pipelines.\n",
19 KOMEDA_MAX_PIPELINES);
20 return NULL;
21 }
22
23 if (size < sizeof(*pipe)) {
24 DRM_ERROR("Request pipeline size too small.\n");
25 return NULL;
26 }
27
28 pipe = devm_kzalloc(mdev->dev, size, GFP_KERNEL);
29 if (!pipe)
30 return NULL;
31
32 pipe->mdev = mdev;
33 pipe->id = mdev->n_pipelines;
34 pipe->funcs = funcs;
35
36 mdev->pipelines[mdev->n_pipelines] = pipe;
37 mdev->n_pipelines++;
38
39 return pipe;
40}
41
42void komeda_pipeline_destroy(struct komeda_dev *mdev,
43 struct komeda_pipeline *pipe)
44{
45 struct komeda_component *c;
46 int i;
47
48 dp_for_each_set_bit(i, pipe->avail_comps) {
49 c = komeda_pipeline_get_component(pipe, i);
50 komeda_component_destroy(mdev, c);
51 }
52
53 clk_put(pipe->pxlclk);
54 clk_put(pipe->aclk);
55
56 of_node_put(pipe->of_output_dev);
57 of_node_put(pipe->of_output_port);
58 of_node_put(pipe->of_node);
59
60 devm_kfree(mdev->dev, pipe);
61}
62
63struct komeda_component **
64komeda_pipeline_get_component_pos(struct komeda_pipeline *pipe, int id)
65{
66 struct komeda_dev *mdev = pipe->mdev;
67 struct komeda_pipeline *temp = NULL;
68 struct komeda_component **pos = NULL;
69
70 switch (id) {
71 case KOMEDA_COMPONENT_LAYER0:
72 case KOMEDA_COMPONENT_LAYER1:
73 case KOMEDA_COMPONENT_LAYER2:
74 case KOMEDA_COMPONENT_LAYER3:
75 pos = to_cpos(pipe->layers[id - KOMEDA_COMPONENT_LAYER0]);
76 break;
77 case KOMEDA_COMPONENT_WB_LAYER:
78 pos = to_cpos(pipe->wb_layer);
79 break;
80 case KOMEDA_COMPONENT_COMPIZ0:
81 case KOMEDA_COMPONENT_COMPIZ1:
82 temp = mdev->pipelines[id - KOMEDA_COMPONENT_COMPIZ0];
83 if (!temp) {
84 DRM_ERROR("compiz-%d doesn't exist.\n", id);
85 return NULL;
86 }
87 pos = to_cpos(temp->compiz);
88 break;
89 case KOMEDA_COMPONENT_SCALER0:
90 case KOMEDA_COMPONENT_SCALER1:
91 pos = to_cpos(pipe->scalers[id - KOMEDA_COMPONENT_SCALER0]);
92 break;
93 case KOMEDA_COMPONENT_IPS0:
94 case KOMEDA_COMPONENT_IPS1:
95 temp = mdev->pipelines[id - KOMEDA_COMPONENT_IPS0];
96 if (!temp) {
97 DRM_ERROR("ips-%d doesn't exist.\n", id);
98 return NULL;
99 }
100 pos = to_cpos(temp->improc);
101 break;
102 case KOMEDA_COMPONENT_TIMING_CTRLR:
103 pos = to_cpos(pipe->ctrlr);
104 break;
105 default:
106 pos = NULL;
107 DRM_ERROR("Unknown pipeline resource ID: %d.\n", id);
108 break;
109 }
110
111 return pos;
112}
113
114struct komeda_component *
115komeda_pipeline_get_component(struct komeda_pipeline *pipe, int id)
116{
117 struct komeda_component **pos = NULL;
118 struct komeda_component *c = NULL;
119
120 pos = komeda_pipeline_get_component_pos(pipe, id);
121 if (pos)
122 c = *pos;
123
124 return c;
125}
126
127/** komeda_component_add - Add a component to &komeda_pipeline */
128struct komeda_component *
129komeda_component_add(struct komeda_pipeline *pipe,
130 size_t comp_sz, u32 id, u32 hw_id,
131 struct komeda_component_funcs *funcs,
132 u8 max_active_inputs, u32 supported_inputs,
133 u8 max_active_outputs, u32 __iomem *reg,
134 const char *name_fmt, ...)
135{
136 struct komeda_component **pos;
137 struct komeda_component *c;
138 int idx, *num = NULL;
139
140 if (max_active_inputs > KOMEDA_COMPONENT_N_INPUTS) {
141 WARN(1, "please large KOMEDA_COMPONENT_N_INPUTS to %d.\n",
142 max_active_inputs);
143 return NULL;
144 }
145
146 pos = komeda_pipeline_get_component_pos(pipe, id);
147 if (!pos || (*pos))
148 return NULL;
149
150 if (has_bit(id, KOMEDA_PIPELINE_LAYERS)) {
151 idx = id - KOMEDA_COMPONENT_LAYER0;
152 num = &pipe->n_layers;
153 if (idx != pipe->n_layers) {
154 DRM_ERROR("please add Layer by id sequence.\n");
155 return NULL;
156 }
157 } else if (has_bit(id, KOMEDA_PIPELINE_SCALERS)) {
158 idx = id - KOMEDA_COMPONENT_SCALER0;
159 num = &pipe->n_scalers;
160 if (idx != pipe->n_scalers) {
161 DRM_ERROR("please add Scaler by id sequence.\n");
162 return NULL;
163 }
164 }
165
166 c = devm_kzalloc(pipe->mdev->dev, comp_sz, GFP_KERNEL);
167 if (!c)
168 return NULL;
169
170 c->id = id;
171 c->hw_id = hw_id;
172 c->reg = reg;
173 c->pipeline = pipe;
174 c->max_active_inputs = max_active_inputs;
175 c->max_active_outputs = max_active_outputs;
176 c->supported_inputs = supported_inputs;
177 c->funcs = funcs;
178
179 if (name_fmt) {
180 va_list args;
181
182 va_start(args, name_fmt);
183 vsnprintf(c->name, sizeof(c->name), name_fmt, args);
184 va_end(args);
185 }
186
187 if (num)
188 *num = *num + 1;
189
190 pipe->avail_comps |= BIT(c->id);
191 *pos = c;
192
193 return c;
194}
195
196void komeda_component_destroy(struct komeda_dev *mdev,
197 struct komeda_component *c)
198{
199 devm_kfree(mdev->dev, c);
200}
diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_pipeline.h b/drivers/gpu/drm/arm/display/komeda/komeda_pipeline.h
new file mode 100644
index 000000000000..8c950bc8ae96
--- /dev/null
+++ b/drivers/gpu/drm/arm/display/komeda/komeda_pipeline.h
@@ -0,0 +1,359 @@
1/* SPDX-License-Identifier: GPL-2.0 */
2/*
3 * (C) COPYRIGHT 2018 ARM Limited. All rights reserved.
4 * Author: James.Qian.Wang <james.qian.wang@arm.com>
5 *
6 */
7#ifndef _KOMEDA_PIPELINE_H_
8#define _KOMEDA_PIPELINE_H_
9
10#include <linux/types.h>
11#include <drm/drm_atomic.h>
12#include <drm/drm_atomic_helper.h>
13#include "malidp_utils.h"
14
15#define KOMEDA_MAX_PIPELINES 2
16#define KOMEDA_PIPELINE_MAX_LAYERS 4
17#define KOMEDA_PIPELINE_MAX_SCALERS 2
18#define KOMEDA_COMPONENT_N_INPUTS 5
19
20/* pipeline component IDs */
21enum {
22 KOMEDA_COMPONENT_LAYER0 = 0,
23 KOMEDA_COMPONENT_LAYER1 = 1,
24 KOMEDA_COMPONENT_LAYER2 = 2,
25 KOMEDA_COMPONENT_LAYER3 = 3,
26 KOMEDA_COMPONENT_WB_LAYER = 7, /* write back layer */
27 KOMEDA_COMPONENT_SCALER0 = 8,
28 KOMEDA_COMPONENT_SCALER1 = 9,
29 KOMEDA_COMPONENT_SPLITTER = 12,
30 KOMEDA_COMPONENT_MERGER = 14,
31 KOMEDA_COMPONENT_COMPIZ0 = 16, /* compositor */
32 KOMEDA_COMPONENT_COMPIZ1 = 17,
33 KOMEDA_COMPONENT_IPS0 = 20, /* post image processor */
34 KOMEDA_COMPONENT_IPS1 = 21,
35 KOMEDA_COMPONENT_TIMING_CTRLR = 22, /* timing controller */
36};
37
38#define KOMEDA_PIPELINE_LAYERS (BIT(KOMEDA_COMPONENT_LAYER0) |\
39 BIT(KOMEDA_COMPONENT_LAYER1) |\
40 BIT(KOMEDA_COMPONENT_LAYER2) |\
41 BIT(KOMEDA_COMPONENT_LAYER3))
42
43#define KOMEDA_PIPELINE_SCALERS (BIT(KOMEDA_COMPONENT_SCALER0) |\
44 BIT(KOMEDA_COMPONENT_SCALER1))
45
46#define KOMEDA_PIPELINE_COMPIZS (BIT(KOMEDA_COMPONENT_COMPIZ0) |\
47 BIT(KOMEDA_COMPONENT_COMPIZ1))
48
49#define KOMEDA_PIPELINE_IMPROCS (BIT(KOMEDA_COMPONENT_IPS0) |\
50 BIT(KOMEDA_COMPONENT_IPS1))
51struct komeda_component;
52struct komeda_component_state;
53
54/** komeda_component_funcs - component control functions */
55struct komeda_component_funcs {
56 /** @validate: optional,
57 * component may has special requirements or limitations, this function
58 * supply HW the ability to do the further HW specific check.
59 */
60 int (*validate)(struct komeda_component *c,
61 struct komeda_component_state *state);
62 /** @update: update is a active update */
63 void (*update)(struct komeda_component *c,
64 struct komeda_component_state *state);
65 /** @disable: disable component */
66 void (*disable)(struct komeda_component *c);
67 /** @dump_register: Optional, dump registers to seq_file */
68 void (*dump_register)(struct komeda_component *c, struct seq_file *seq);
69};
70
71/**
72 * struct komeda_component
73 *
74 * struct komeda_component describe the data flow capabilities for how to link a
75 * component into the display pipeline.
76 * all specified components are subclass of this structure.
77 */
78struct komeda_component {
79 /** @obj: treat component as private obj */
80 struct drm_private_obj obj;
81 /** @pipeline: the komeda pipeline this component belongs to */
82 struct komeda_pipeline *pipeline;
83 /** @name: component name */
84 char name[32];
85 /**
86 * @reg:
87 * component register base,
88 * which is initialized by chip and used by chip only
89 */
90 u32 __iomem *reg;
91 /** @id: component id */
92 u32 id;
93 /** @hw_ic: component hw id,
94 * which is initialized by chip and used by chip only
95 */
96 u32 hw_id;
97
98 /**
99 * @max_active_inputs:
100 * @max_active_outpus:
101 *
102 * maximum number of inputs/outputs that can be active in the same time
103 * Note:
104 * the number isn't the bit number of @supported_inputs or
105 * @supported_outputs, but may be less than it, since component may not
106 * support enabling all @supported_inputs/outputs at the same time.
107 */
108 u8 max_active_inputs;
109 u8 max_active_outputs;
110 /**
111 * @supported_inputs:
112 * @supported_outputs:
113 *
114 * bitmask of BIT(component->id) for the supported inputs/outputs
115 * describes the possibilities of how a component is linked into a
116 * pipeline.
117 */
118 u32 supported_inputs;
119 u32 supported_outputs;
120
121 /**
122 * @funcs: chip functions to access HW
123 */
124 struct komeda_component_funcs *funcs;
125};
126
127/**
128 * struct komeda_component_output
129 *
130 * a component has multiple outputs, if want to know where the data
131 * comes from, only know the component is not enough, we still need to know
132 * its output port
133 */
134struct komeda_component_output {
135 /** @component: indicate which component the data comes from */
136 struct komeda_component *component;
137 /** @output_port:
138 * the output port of the &komeda_component_output.component
139 */
140 u8 output_port;
141};
142
143/**
144 * struct komeda_component_state
145 *
146 * component_state is the data flow configuration of the component, and it's
147 * the superclass of all specific component_state like @komeda_layer_state,
148 * @komeda_scaler_state
149 */
150struct komeda_component_state {
151 /** @obj: tracking component_state by drm_atomic_state */
152 struct drm_private_state obj;
153 struct komeda_component *component;
154 /**
155 * @binding_user:
156 * currently bound user, the user can be crtc/plane/wb_conn, which is
157 * valid decided by @component and @inputs
158 *
159 * - Layer: its user always is plane.
160 * - compiz/improc/timing_ctrlr: the user is crtc.
161 * - wb_layer: wb_conn;
162 * - scaler: plane when input is layer, wb_conn if input is compiz.
163 */
164 union {
165 struct drm_crtc *crtc;
166 struct drm_plane *plane;
167 struct drm_connector *wb_conn;
168 void *binding_user;
169 };
170 /**
171 * @active_inputs:
172 *
173 * active_inputs is bitmask of @inputs index
174 *
175 * - active_inputs = changed_active_inputs + unchanged_active_inputs
176 * - affected_inputs = old->active_inputs + new->active_inputs;
177 * - disabling_inputs = affected_inputs ^ active_inputs;
178 * - changed_inputs = disabling_inputs + changed_active_inputs;
179 *
180 * NOTE:
181 * changed_inputs doesn't include all active_input but only
182 * @changed_active_inputs, and this bitmask can be used in chip
183 * level for dirty update.
184 */
185 u16 active_inputs;
186 u16 changed_active_inputs;
187 u16 affected_inputs;
188 /**
189 * @inputs:
190 *
191 * the specific inputs[i] only valid on BIT(i) has been set in
192 * @active_inputs, if not the inputs[i] is undefined.
193 */
194 struct komeda_component_output inputs[KOMEDA_COMPONENT_N_INPUTS];
195};
196
197static inline u16 component_disabling_inputs(struct komeda_component_state *st)
198{
199 return st->affected_inputs ^ st->active_inputs;
200}
201
202static inline u16 component_changed_inputs(struct komeda_component_state *st)
203{
204 return component_disabling_inputs(st) | st->changed_active_inputs;
205}
206
207#define to_comp(__c) (((__c) == NULL) ? NULL : &((__c)->base))
208#define to_cpos(__c) ((struct komeda_component **)&(__c))
209
210/* these structures are going to be filled in in uture patches */
211struct komeda_layer {
212 struct komeda_component base;
213 /* layer specific features and caps */
214 int layer_type; /* RICH, SIMPLE or WB */
215};
216
217struct komeda_layer_state {
218 struct komeda_component_state base;
219 /* layer specific configuration state */
220};
221
222struct komeda_compiz {
223 struct komeda_component base;
224 /* compiz specific features and caps */
225};
226
227struct komeda_compiz_state {
228 struct komeda_component_state base;
229 /* compiz specific configuration state */
230};
231
232struct komeda_scaler {
233 struct komeda_component base;
234 /* scaler features and caps */
235};
236
237struct komeda_scaler_state {
238 struct komeda_component_state base;
239};
240
241struct komeda_improc {
242 struct komeda_component base;
243};
244
245struct komeda_improc_state {
246 struct komeda_component_state base;
247};
248
249/* display timing controller */
250struct komeda_timing_ctrlr {
251 struct komeda_component base;
252};
253
254struct komeda_timing_ctrlr_state {
255 struct komeda_component_state base;
256};
257
258/** struct komeda_pipeline_funcs */
259struct komeda_pipeline_funcs {
260 /* dump_register: Optional, dump registers to seq_file */
261 void (*dump_register)(struct komeda_pipeline *pipe,
262 struct seq_file *sf);
263};
264
265/**
266 * struct komeda_pipeline
267 *
268 * Represent a complete display pipeline and hold all functional components.
269 */
270struct komeda_pipeline {
271 /** @obj: link pipeline as private obj of drm_atomic_state */
272 struct drm_private_obj obj;
273 /** @mdev: the parent komeda_dev */
274 struct komeda_dev *mdev;
275 /** @pxlclk: pixel clock */
276 struct clk *pxlclk;
277 /** @aclk: AXI clock */
278 struct clk *aclk;
279 /** @id: pipeline id */
280 int id;
281 /** @avail_comps: available components mask of pipeline */
282 u32 avail_comps;
283 int n_layers;
284 struct komeda_layer *layers[KOMEDA_PIPELINE_MAX_LAYERS];
285 int n_scalers;
286 struct komeda_scaler *scalers[KOMEDA_PIPELINE_MAX_SCALERS];
287 struct komeda_compiz *compiz;
288 struct komeda_layer *wb_layer;
289 struct komeda_improc *improc;
290 struct komeda_timing_ctrlr *ctrlr;
291 struct komeda_pipeline_funcs *funcs; /* private pipeline functions */
292
293 /** @of_node: pipeline dt node */
294 struct device_node *of_node;
295 /** @of_output_port: pipeline output port */
296 struct device_node *of_output_port;
297 /** @of_output_dev: output connector device node */
298 struct device_node *of_output_dev;
299};
300
301/**
302 * struct komeda_pipeline_state
303 *
304 * NOTE:
305 * Unlike the pipeline, pipeline_state doesn’t gather any component_state
306 * into it. It because all component will be managed by drm_atomic_state.
307 */
308struct komeda_pipeline_state {
309 /** @obj: tracking pipeline_state by drm_atomic_state */
310 struct drm_private_state obj;
311 struct komeda_pipeline *pipe;
312 /** @crtc: currently bound crtc */
313 struct drm_crtc *crtc;
314 /**
315 * @active_comps:
316 *
317 * bitmask - BIT(component->id) of active components
318 */
319 u32 active_comps;
320};
321
322#define to_layer(c) container_of(c, struct komeda_layer, base)
323#define to_compiz(c) container_of(c, struct komeda_compiz, base)
324#define to_scaler(c) container_of(c, struct komeda_scaler, base)
325#define to_improc(c) container_of(c, struct komeda_improc, base)
326#define to_ctrlr(c) container_of(c, struct komeda_timing_ctrlr, base)
327
328#define to_layer_st(c) container_of(c, struct komeda_layer_state, base)
329#define to_compiz_st(c) container_of(c, struct komeda_compiz_state, base)
330#define to_scaler_st(c) container_of(c, struct komeda_scaler_state, base)
331#define to_improc_st(c) container_of(c, struct komeda_improc_state, base)
332#define to_ctrlr_st(c) container_of(c, struct komeda_timing_ctrlr_state, base)
333
334#define priv_to_comp_st(o) container_of(o, struct komeda_component_state, obj)
335#define priv_to_pipe_st(o) container_of(o, struct komeda_pipeline_state, obj)
336
337/* pipeline APIs */
338struct komeda_pipeline *
339komeda_pipeline_add(struct komeda_dev *mdev, size_t size,
340 struct komeda_pipeline_funcs *funcs);
341void komeda_pipeline_destroy(struct komeda_dev *mdev,
342 struct komeda_pipeline *pipe);
343
344struct komeda_component *
345komeda_pipeline_get_component(struct komeda_pipeline *pipe, int id);
346
347/* component APIs */
348struct komeda_component *
349komeda_component_add(struct komeda_pipeline *pipe,
350 size_t comp_sz, u32 id, u32 hw_id,
351 struct komeda_component_funcs *funcs,
352 u8 max_active_inputs, u32 supported_inputs,
353 u8 max_active_outputs, u32 __iomem *reg,
354 const char *name_fmt, ...);
355
356void komeda_component_destroy(struct komeda_dev *mdev,
357 struct komeda_component *c);
358
359#endif /* _KOMEDA_PIPELINE_H_*/
diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_plane.c b/drivers/gpu/drm/arm/display/komeda/komeda_plane.c
new file mode 100644
index 000000000000..0a4953a9a909
--- /dev/null
+++ b/drivers/gpu/drm/arm/display/komeda/komeda_plane.c
@@ -0,0 +1,109 @@
1// SPDX-License-Identifier: GPL-2.0
2/*
3 * (C) COPYRIGHT 2018 ARM Limited. All rights reserved.
4 * Author: James.Qian.Wang <james.qian.wang@arm.com>
5 *
6 */
7#include <drm/drm_atomic.h>
8#include <drm/drm_atomic_helper.h>
9#include <drm/drm_plane_helper.h>
10#include "komeda_dev.h"
11#include "komeda_kms.h"
12
13static const struct drm_plane_helper_funcs komeda_plane_helper_funcs = {
14};
15
16static void komeda_plane_destroy(struct drm_plane *plane)
17{
18 drm_plane_cleanup(plane);
19
20 kfree(to_kplane(plane));
21}
22
23static const struct drm_plane_funcs komeda_plane_funcs = {
24};
25
26/* for komeda, which is pipeline can be share between crtcs */
27static u32 get_possible_crtcs(struct komeda_kms_dev *kms,
28 struct komeda_pipeline *pipe)
29{
30 struct komeda_crtc *crtc;
31 u32 possible_crtcs = 0;
32 int i;
33
34 for (i = 0; i < kms->n_crtcs; i++) {
35 crtc = &kms->crtcs[i];
36
37 if ((pipe == crtc->master) || (pipe == crtc->slave))
38 possible_crtcs |= BIT(i);
39 }
40
41 return possible_crtcs;
42}
43
44/* use Layer0 as primary */
45static u32 get_plane_type(struct komeda_kms_dev *kms,
46 struct komeda_component *c)
47{
48 bool is_primary = (c->id == KOMEDA_COMPONENT_LAYER0);
49
50 return is_primary ? DRM_PLANE_TYPE_PRIMARY : DRM_PLANE_TYPE_OVERLAY;
51}
52
53static int komeda_plane_add(struct komeda_kms_dev *kms,
54 struct komeda_layer *layer)
55{
56 struct komeda_dev *mdev = kms->base.dev_private;
57 struct komeda_component *c = &layer->base;
58 struct komeda_plane *kplane;
59 struct drm_plane *plane;
60 u32 *formats, n_formats = 0;
61 int err;
62
63 kplane = kzalloc(sizeof(*kplane), GFP_KERNEL);
64 if (!kplane)
65 return -ENOMEM;
66
67 plane = &kplane->base;
68 kplane->layer = layer;
69
70 formats = komeda_get_layer_fourcc_list(&mdev->fmt_tbl,
71 layer->layer_type, &n_formats);
72
73 err = drm_universal_plane_init(&kms->base, plane,
74 get_possible_crtcs(kms, c->pipeline),
75 &komeda_plane_funcs,
76 formats, n_formats, NULL,
77 get_plane_type(kms, c),
78 "%s", c->name);
79
80 komeda_put_fourcc_list(formats);
81
82 if (err)
83 goto cleanup;
84
85 drm_plane_helper_add(plane, &komeda_plane_helper_funcs);
86
87 return 0;
88cleanup:
89 komeda_plane_destroy(plane);
90 return err;
91}
92
93int komeda_kms_add_planes(struct komeda_kms_dev *kms, struct komeda_dev *mdev)
94{
95 struct komeda_pipeline *pipe;
96 int i, j, err;
97
98 for (i = 0; i < mdev->n_pipelines; i++) {
99 pipe = mdev->pipelines[i];
100
101 for (j = 0; j < pipe->n_layers; j++) {
102 err = komeda_plane_add(kms, pipe->layers[j]);
103 if (err)
104 return err;
105 }
106 }
107
108 return 0;
109}
diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_private_obj.c b/drivers/gpu/drm/arm/display/komeda/komeda_private_obj.c
new file mode 100644
index 000000000000..f1c9e3fefa86
--- /dev/null
+++ b/drivers/gpu/drm/arm/display/komeda/komeda_private_obj.c
@@ -0,0 +1,88 @@
1// SPDX-License-Identifier: GPL-2.0
2/*
3 * (C) COPYRIGHT 2018 ARM Limited. All rights reserved.
4 * Author: James.Qian.Wang <james.qian.wang@arm.com>
5 *
6 */
7#include "komeda_dev.h"
8#include "komeda_kms.h"
9
10static struct drm_private_state *
11komeda_pipeline_atomic_duplicate_state(struct drm_private_obj *obj)
12{
13 struct komeda_pipeline_state *st;
14
15 st = kmemdup(obj->state, sizeof(*st), GFP_KERNEL);
16 if (!st)
17 return NULL;
18
19 st->active_comps = 0;
20
21 __drm_atomic_helper_private_obj_duplicate_state(obj, &st->obj);
22
23 return &st->obj;
24}
25
26static void
27komeda_pipeline_atomic_destroy_state(struct drm_private_obj *obj,
28 struct drm_private_state *state)
29{
30 kfree(priv_to_pipe_st(state));
31}
32
33static const struct drm_private_state_funcs komeda_pipeline_obj_funcs = {
34 .atomic_duplicate_state = komeda_pipeline_atomic_duplicate_state,
35 .atomic_destroy_state = komeda_pipeline_atomic_destroy_state,
36};
37
38static int komeda_pipeline_obj_add(struct komeda_kms_dev *kms,
39 struct komeda_pipeline *pipe)
40{
41 struct komeda_pipeline_state *st;
42
43 st = kzalloc(sizeof(*st), GFP_KERNEL);
44 if (!st)
45 return -ENOMEM;
46
47 st->pipe = pipe;
48 drm_atomic_private_obj_init(&kms->base, &pipe->obj, &st->obj,
49 &komeda_pipeline_obj_funcs);
50
51 return 0;
52}
53
54int komeda_kms_add_private_objs(struct komeda_kms_dev *kms,
55 struct komeda_dev *mdev)
56{
57 struct komeda_pipeline *pipe;
58 int i, err;
59
60 for (i = 0; i < mdev->n_pipelines; i++) {
61 pipe = mdev->pipelines[i];
62
63 err = komeda_pipeline_obj_add(kms, pipe);
64 if (err)
65 return err;
66
67 /* Add component */
68 }
69
70 return 0;
71}
72
73void komeda_kms_cleanup_private_objs(struct komeda_dev *mdev)
74{
75 struct komeda_pipeline *pipe;
76 struct komeda_component *c;
77 int i, id;
78
79 for (i = 0; i < mdev->n_pipelines; i++) {
80 pipe = mdev->pipelines[i];
81 dp_for_each_set_bit(id, pipe->avail_comps) {
82 c = komeda_pipeline_get_component(pipe, id);
83
84 drm_atomic_private_obj_fini(&c->obj);
85 }
86 drm_atomic_private_obj_fini(&pipe->obj);
87 }
88}
diff --git a/include/uapi/drm/drm_fourcc.h b/include/uapi/drm/drm_fourcc.h
index 91d08a23f125..93a341d278a6 100644
--- a/include/uapi/drm/drm_fourcc.h
+++ b/include/uapi/drm/drm_fourcc.h
@@ -574,6 +574,9 @@ extern "C" {
574 * AFBC has several features which may be supported and/or used, which are 574 * AFBC has several features which may be supported and/or used, which are
575 * represented using bits in the modifier. Not all combinations are valid, 575 * represented using bits in the modifier. Not all combinations are valid,
576 * and different devices or use-cases may support different combinations. 576 * and different devices or use-cases may support different combinations.
577 *
578 * Further information on the use of AFBC modifiers can be found in
579 * Documentation/gpu/afbc.rst
577 */ 580 */
578#define DRM_FORMAT_MOD_ARM_AFBC(__afbc_mode) fourcc_mod_code(ARM, __afbc_mode) 581#define DRM_FORMAT_MOD_ARM_AFBC(__afbc_mode) fourcc_mod_code(ARM, __afbc_mode)
579 582