Line data Source code
1 : // SPDX-License-Identifier: GPL-2.0
2 : /*
3 : * (C) COPYRIGHT 2016 ARM Limited. All rights reserved.
4 : * Author: Brian Starkey <brian.starkey@arm.com>
5 : *
6 : * This program is free software and is provided to you under the terms of the
7 : * GNU General Public License version 2 as published by the Free Software
8 : * Foundation, and any use by you of this program is subject to the terms
9 : * of such GNU licence.
10 : */
11 :
12 : #include <linux/dma-fence.h>
13 :
14 : #include <drm/drm_crtc.h>
15 : #include <drm/drm_device.h>
16 : #include <drm/drm_drv.h>
17 : #include <drm/drm_modeset_helper_vtables.h>
18 : #include <drm/drm_property.h>
19 : #include <drm/drm_writeback.h>
20 :
21 : /**
22 : * DOC: overview
23 : *
24 : * Writeback connectors are used to expose hardware which can write the output
25 : * from a CRTC to a memory buffer. They are used and act similarly to other
26 : * types of connectors, with some important differences:
27 : *
28 : * * Writeback connectors don't provide a way to output visually to the user.
29 : *
30 : * * Writeback connectors are visible to userspace only when the client sets
31 : * DRM_CLIENT_CAP_WRITEBACK_CONNECTORS.
32 : *
33 : * * Writeback connectors don't have EDID.
34 : *
35 : * A framebuffer may only be attached to a writeback connector when the
36 : * connector is attached to a CRTC. The WRITEBACK_FB_ID property which sets the
37 : * framebuffer applies only to a single commit (see below). A framebuffer may
38 : * not be attached while the CRTC is off.
39 : *
40 : * Unlike with planes, when a writeback framebuffer is removed by userspace DRM
41 : * makes no attempt to remove it from active use by the connector. This is
42 : * because no method is provided to abort a writeback operation, and in any
43 : * case making a new commit whilst a writeback is ongoing is undefined (see
44 : * WRITEBACK_OUT_FENCE_PTR below). As soon as the current writeback is finished,
45 : * the framebuffer will automatically no longer be in active use. As it will
46 : * also have already been removed from the framebuffer list, there will be no
47 : * way for any userspace application to retrieve a reference to it in the
48 : * intervening period.
49 : *
50 : * Writeback connectors have some additional properties, which userspace
51 : * can use to query and control them:
52 : *
53 : * "WRITEBACK_FB_ID":
54 : * Write-only object property storing a DRM_MODE_OBJECT_FB: it stores the
55 : * framebuffer to be written by the writeback connector. This property is
56 : * similar to the FB_ID property on planes, but will always read as zero
57 : * and is not preserved across commits.
58 : * Userspace must set this property to an output buffer every time it
59 : * wishes the buffer to get filled.
60 : *
61 : * "WRITEBACK_PIXEL_FORMATS":
62 : * Immutable blob property to store the supported pixel formats table. The
63 : * data is an array of u32 DRM_FORMAT_* fourcc values.
64 : * Userspace can use this blob to find out what pixel formats are supported
65 : * by the connector's writeback engine.
66 : *
67 : * "WRITEBACK_OUT_FENCE_PTR":
68 : * Userspace can use this property to provide a pointer for the kernel to
69 : * fill with a sync_file file descriptor, which will signal once the
70 : * writeback is finished. The value should be the address of a 32-bit
71 : * signed integer, cast to a u64.
72 : * Userspace should wait for this fence to signal before making another
73 : * commit affecting any of the same CRTCs, Planes or Connectors.
74 : * **Failure to do so will result in undefined behaviour.**
75 : * For this reason it is strongly recommended that all userspace
76 : * applications making use of writeback connectors *always* retrieve an
77 : * out-fence for the commit and use it appropriately.
78 : * From userspace, this property will always read as zero.
79 : */
80 :
81 : #define fence_to_wb_connector(x) container_of(x->lock, \
82 : struct drm_writeback_connector, \
83 : fence_lock)
84 :
85 0 : static const char *drm_writeback_fence_get_driver_name(struct dma_fence *fence)
86 : {
87 0 : struct drm_writeback_connector *wb_connector =
88 0 : fence_to_wb_connector(fence);
89 :
90 0 : return wb_connector->base.dev->driver->name;
91 : }
92 :
93 : static const char *
94 0 : drm_writeback_fence_get_timeline_name(struct dma_fence *fence)
95 : {
96 0 : struct drm_writeback_connector *wb_connector =
97 0 : fence_to_wb_connector(fence);
98 :
99 0 : return wb_connector->timeline_name;
100 : }
101 :
102 0 : static bool drm_writeback_fence_enable_signaling(struct dma_fence *fence)
103 : {
104 0 : return true;
105 : }
106 :
107 : static const struct dma_fence_ops drm_writeback_fence_ops = {
108 : .get_driver_name = drm_writeback_fence_get_driver_name,
109 : .get_timeline_name = drm_writeback_fence_get_timeline_name,
110 : .enable_signaling = drm_writeback_fence_enable_signaling,
111 : };
112 :
113 0 : static int create_writeback_properties(struct drm_device *dev)
114 : {
115 : struct drm_property *prop;
116 :
117 0 : if (!dev->mode_config.writeback_fb_id_property) {
118 0 : prop = drm_property_create_object(dev, DRM_MODE_PROP_ATOMIC,
119 : "WRITEBACK_FB_ID",
120 : DRM_MODE_OBJECT_FB);
121 0 : if (!prop)
122 : return -ENOMEM;
123 0 : dev->mode_config.writeback_fb_id_property = prop;
124 : }
125 :
126 0 : if (!dev->mode_config.writeback_pixel_formats_property) {
127 0 : prop = drm_property_create(dev, DRM_MODE_PROP_BLOB |
128 : DRM_MODE_PROP_ATOMIC |
129 : DRM_MODE_PROP_IMMUTABLE,
130 : "WRITEBACK_PIXEL_FORMATS", 0);
131 0 : if (!prop)
132 : return -ENOMEM;
133 0 : dev->mode_config.writeback_pixel_formats_property = prop;
134 : }
135 :
136 0 : if (!dev->mode_config.writeback_out_fence_ptr_property) {
137 0 : prop = drm_property_create_range(dev, DRM_MODE_PROP_ATOMIC,
138 : "WRITEBACK_OUT_FENCE_PTR", 0,
139 : U64_MAX);
140 0 : if (!prop)
141 : return -ENOMEM;
142 0 : dev->mode_config.writeback_out_fence_ptr_property = prop;
143 : }
144 :
145 : return 0;
146 : }
147 :
148 : static const struct drm_encoder_funcs drm_writeback_encoder_funcs = {
149 : .destroy = drm_encoder_cleanup,
150 : };
151 :
152 : /**
153 : * drm_writeback_connector_init - Initialize a writeback connector and its properties
154 : * @dev: DRM device
155 : * @wb_connector: Writeback connector to initialize
156 : * @con_funcs: Connector funcs vtable
157 : * @enc_helper_funcs: Encoder helper funcs vtable to be used by the internal encoder
158 : * @formats: Array of supported pixel formats for the writeback engine
159 : * @n_formats: Length of the formats array
160 : * @possible_crtcs: possible crtcs for the internal writeback encoder
161 : *
162 : * This function creates the writeback-connector-specific properties if they
163 : * have not been already created, initializes the connector as
164 : * type DRM_MODE_CONNECTOR_WRITEBACK, and correctly initializes the property
165 : * values. It will also create an internal encoder associated with the
166 : * drm_writeback_connector and set it to use the @enc_helper_funcs vtable for
167 : * the encoder helper.
168 : *
169 : * Drivers should always use this function instead of drm_connector_init() to
170 : * set up writeback connectors.
171 : *
172 : * Returns: 0 on success, or a negative error code
173 : */
174 0 : int drm_writeback_connector_init(struct drm_device *dev,
175 : struct drm_writeback_connector *wb_connector,
176 : const struct drm_connector_funcs *con_funcs,
177 : const struct drm_encoder_helper_funcs *enc_helper_funcs,
178 : const u32 *formats, int n_formats,
179 : u32 possible_crtcs)
180 : {
181 0 : int ret = 0;
182 :
183 0 : drm_encoder_helper_add(&wb_connector->encoder, enc_helper_funcs);
184 :
185 0 : wb_connector->encoder.possible_crtcs = possible_crtcs;
186 :
187 0 : ret = drm_encoder_init(dev, &wb_connector->encoder,
188 : &drm_writeback_encoder_funcs,
189 : DRM_MODE_ENCODER_VIRTUAL, NULL);
190 0 : if (ret)
191 : return ret;
192 :
193 0 : ret = drm_writeback_connector_init_with_encoder(dev, wb_connector, &wb_connector->encoder,
194 : con_funcs, formats, n_formats);
195 :
196 0 : if (ret)
197 0 : drm_encoder_cleanup(&wb_connector->encoder);
198 :
199 : return ret;
200 : }
201 : EXPORT_SYMBOL(drm_writeback_connector_init);
202 :
203 : /**
204 : * drm_writeback_connector_init_with_encoder - Initialize a writeback connector with
205 : * a custom encoder
206 : *
207 : * @dev: DRM device
208 : * @wb_connector: Writeback connector to initialize
209 : * @enc: handle to the already initialized drm encoder
210 : * @con_funcs: Connector funcs vtable
211 : * @formats: Array of supported pixel formats for the writeback engine
212 : * @n_formats: Length of the formats array
213 : *
214 : * This function creates the writeback-connector-specific properties if they
215 : * have not been already created, initializes the connector as
216 : * type DRM_MODE_CONNECTOR_WRITEBACK, and correctly initializes the property
217 : * values.
218 : *
219 : * This function assumes that the drm_writeback_connector's encoder has already been
220 : * created and initialized before invoking this function.
221 : *
222 : * In addition, this function also assumes that callers of this API will manage
223 : * assigning the encoder helper functions, possible_crtcs and any other encoder
224 : * specific operation.
225 : *
226 : * Drivers should always use this function instead of drm_connector_init() to
227 : * set up writeback connectors if they want to manage themselves the lifetime of the
228 : * associated encoder.
229 : *
230 : * Returns: 0 on success, or a negative error code
231 : */
232 0 : int drm_writeback_connector_init_with_encoder(struct drm_device *dev,
233 : struct drm_writeback_connector *wb_connector, struct drm_encoder *enc,
234 : const struct drm_connector_funcs *con_funcs, const u32 *formats,
235 : int n_formats)
236 : {
237 : struct drm_property_blob *blob;
238 0 : struct drm_connector *connector = &wb_connector->base;
239 0 : struct drm_mode_config *config = &dev->mode_config;
240 0 : int ret = create_writeback_properties(dev);
241 :
242 0 : if (ret != 0)
243 : return ret;
244 :
245 0 : blob = drm_property_create_blob(dev, n_formats * sizeof(*formats),
246 : formats);
247 0 : if (IS_ERR(blob))
248 0 : return PTR_ERR(blob);
249 :
250 :
251 0 : connector->interlace_allowed = 0;
252 :
253 0 : ret = drm_connector_init(dev, connector, con_funcs,
254 : DRM_MODE_CONNECTOR_WRITEBACK);
255 0 : if (ret)
256 : goto connector_fail;
257 :
258 0 : ret = drm_connector_attach_encoder(connector, enc);
259 0 : if (ret)
260 : goto attach_fail;
261 :
262 0 : INIT_LIST_HEAD(&wb_connector->job_queue);
263 0 : spin_lock_init(&wb_connector->job_lock);
264 :
265 0 : wb_connector->fence_context = dma_fence_context_alloc(1);
266 0 : spin_lock_init(&wb_connector->fence_lock);
267 0 : snprintf(wb_connector->timeline_name,
268 : sizeof(wb_connector->timeline_name),
269 : "CONNECTOR:%d-%s", connector->base.id, connector->name);
270 :
271 0 : drm_object_attach_property(&connector->base,
272 : config->writeback_out_fence_ptr_property, 0);
273 :
274 0 : drm_object_attach_property(&connector->base,
275 : config->writeback_fb_id_property, 0);
276 :
277 0 : drm_object_attach_property(&connector->base,
278 : config->writeback_pixel_formats_property,
279 0 : blob->base.id);
280 0 : wb_connector->pixel_formats_blob_ptr = blob;
281 :
282 0 : return 0;
283 :
284 : attach_fail:
285 0 : drm_connector_cleanup(connector);
286 : connector_fail:
287 0 : drm_property_blob_put(blob);
288 0 : return ret;
289 : }
290 : EXPORT_SYMBOL(drm_writeback_connector_init_with_encoder);
291 :
292 0 : int drm_writeback_set_fb(struct drm_connector_state *conn_state,
293 : struct drm_framebuffer *fb)
294 : {
295 0 : WARN_ON(conn_state->connector->connector_type != DRM_MODE_CONNECTOR_WRITEBACK);
296 :
297 0 : if (!conn_state->writeback_job) {
298 0 : conn_state->writeback_job =
299 0 : kzalloc(sizeof(*conn_state->writeback_job), GFP_KERNEL);
300 0 : if (!conn_state->writeback_job)
301 : return -ENOMEM;
302 :
303 0 : conn_state->writeback_job->connector =
304 0 : drm_connector_to_writeback(conn_state->connector);
305 : }
306 :
307 0 : drm_framebuffer_assign(&conn_state->writeback_job->fb, fb);
308 0 : return 0;
309 : }
310 :
311 0 : int drm_writeback_prepare_job(struct drm_writeback_job *job)
312 : {
313 0 : struct drm_writeback_connector *connector = job->connector;
314 0 : const struct drm_connector_helper_funcs *funcs =
315 : connector->base.helper_private;
316 : int ret;
317 :
318 0 : if (funcs->prepare_writeback_job) {
319 0 : ret = funcs->prepare_writeback_job(connector, job);
320 0 : if (ret < 0)
321 : return ret;
322 : }
323 :
324 0 : job->prepared = true;
325 0 : return 0;
326 : }
327 : EXPORT_SYMBOL(drm_writeback_prepare_job);
328 :
329 : /**
330 : * drm_writeback_queue_job - Queue a writeback job for later signalling
331 : * @wb_connector: The writeback connector to queue a job on
332 : * @conn_state: The connector state containing the job to queue
333 : *
334 : * This function adds the job contained in @conn_state to the job_queue for a
335 : * writeback connector. It takes ownership of the writeback job and sets the
336 : * @conn_state->writeback_job to NULL, and so no access to the job may be
337 : * performed by the caller after this function returns.
338 : *
339 : * Drivers must ensure that for a given writeback connector, jobs are queued in
340 : * exactly the same order as they will be completed by the hardware (and
341 : * signaled via drm_writeback_signal_completion).
342 : *
343 : * For every call to drm_writeback_queue_job() there must be exactly one call to
344 : * drm_writeback_signal_completion()
345 : *
346 : * See also: drm_writeback_signal_completion()
347 : */
348 0 : void drm_writeback_queue_job(struct drm_writeback_connector *wb_connector,
349 : struct drm_connector_state *conn_state)
350 : {
351 : struct drm_writeback_job *job;
352 : unsigned long flags;
353 :
354 0 : job = conn_state->writeback_job;
355 0 : conn_state->writeback_job = NULL;
356 :
357 0 : spin_lock_irqsave(&wb_connector->job_lock, flags);
358 0 : list_add_tail(&job->list_entry, &wb_connector->job_queue);
359 0 : spin_unlock_irqrestore(&wb_connector->job_lock, flags);
360 0 : }
361 : EXPORT_SYMBOL(drm_writeback_queue_job);
362 :
363 0 : void drm_writeback_cleanup_job(struct drm_writeback_job *job)
364 : {
365 0 : struct drm_writeback_connector *connector = job->connector;
366 0 : const struct drm_connector_helper_funcs *funcs =
367 : connector->base.helper_private;
368 :
369 0 : if (job->prepared && funcs->cleanup_writeback_job)
370 0 : funcs->cleanup_writeback_job(connector, job);
371 :
372 0 : if (job->fb)
373 0 : drm_framebuffer_put(job->fb);
374 :
375 0 : if (job->out_fence)
376 0 : dma_fence_put(job->out_fence);
377 :
378 0 : kfree(job);
379 0 : }
380 : EXPORT_SYMBOL(drm_writeback_cleanup_job);
381 :
382 : /*
383 : * @cleanup_work: deferred cleanup of a writeback job
384 : *
385 : * The job cannot be cleaned up directly in drm_writeback_signal_completion,
386 : * because it may be called in interrupt context. Dropping the framebuffer
387 : * reference can sleep, and so the cleanup is deferred to a workqueue.
388 : */
389 0 : static void cleanup_work(struct work_struct *work)
390 : {
391 0 : struct drm_writeback_job *job = container_of(work,
392 : struct drm_writeback_job,
393 : cleanup_work);
394 :
395 0 : drm_writeback_cleanup_job(job);
396 0 : }
397 :
398 : /**
399 : * drm_writeback_signal_completion - Signal the completion of a writeback job
400 : * @wb_connector: The writeback connector whose job is complete
401 : * @status: Status code to set in the writeback out_fence (0 for success)
402 : *
403 : * Drivers should call this to signal the completion of a previously queued
404 : * writeback job. It should be called as soon as possible after the hardware
405 : * has finished writing, and may be called from interrupt context.
406 : * It is the driver's responsibility to ensure that for a given connector, the
407 : * hardware completes writeback jobs in the same order as they are queued.
408 : *
409 : * Unless the driver is holding its own reference to the framebuffer, it must
410 : * not be accessed after calling this function.
411 : *
412 : * See also: drm_writeback_queue_job()
413 : */
414 : void
415 0 : drm_writeback_signal_completion(struct drm_writeback_connector *wb_connector,
416 : int status)
417 : {
418 : unsigned long flags;
419 : struct drm_writeback_job *job;
420 : struct dma_fence *out_fence;
421 :
422 0 : spin_lock_irqsave(&wb_connector->job_lock, flags);
423 0 : job = list_first_entry_or_null(&wb_connector->job_queue,
424 : struct drm_writeback_job,
425 : list_entry);
426 0 : if (job)
427 0 : list_del(&job->list_entry);
428 :
429 0 : spin_unlock_irqrestore(&wb_connector->job_lock, flags);
430 :
431 0 : if (WARN_ON(!job))
432 : return;
433 :
434 0 : out_fence = job->out_fence;
435 0 : if (out_fence) {
436 0 : if (status)
437 0 : dma_fence_set_error(out_fence, status);
438 0 : dma_fence_signal(out_fence);
439 0 : dma_fence_put(out_fence);
440 0 : job->out_fence = NULL;
441 : }
442 :
443 0 : INIT_WORK(&job->cleanup_work, cleanup_work);
444 0 : queue_work(system_long_wq, &job->cleanup_work);
445 : }
446 : EXPORT_SYMBOL(drm_writeback_signal_completion);
447 :
448 : struct dma_fence *
449 0 : drm_writeback_get_out_fence(struct drm_writeback_connector *wb_connector)
450 : {
451 : struct dma_fence *fence;
452 :
453 0 : if (WARN_ON(wb_connector->base.connector_type !=
454 : DRM_MODE_CONNECTOR_WRITEBACK))
455 : return NULL;
456 :
457 0 : fence = kzalloc(sizeof(*fence), GFP_KERNEL);
458 0 : if (!fence)
459 : return NULL;
460 :
461 0 : dma_fence_init(fence, &drm_writeback_fence_ops,
462 0 : &wb_connector->fence_lock, wb_connector->fence_context,
463 0 : ++wb_connector->fence_seqno);
464 :
465 0 : return fence;
466 : }
467 : EXPORT_SYMBOL(drm_writeback_get_out_fence);
|