0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012 #include <linux/dma-fence.h>
0013
0014 #include <drm/drm_crtc.h>
0015 #include <drm/drm_device.h>
0016 #include <drm/drm_drv.h>
0017 #include <drm/drm_framebuffer.h>
0018 #include <drm/drm_modeset_helper_vtables.h>
0019 #include <drm/drm_property.h>
0020 #include <drm/drm_writeback.h>
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036
0037
0038
0039
0040
0041
0042
0043
0044
0045
0046
0047
0048
0049
0050
0051
0052
0053
0054
0055
0056
0057
0058
0059
0060
0061
0062
0063
0064
0065
0066
0067
0068
0069
0070
0071
0072
0073
0074
0075
0076
0077
0078
0079
0080
0081
0082 #define fence_to_wb_connector(x) container_of(x->lock, \
0083 struct drm_writeback_connector, \
0084 fence_lock)
0085
0086 static const char *drm_writeback_fence_get_driver_name(struct dma_fence *fence)
0087 {
0088 struct drm_writeback_connector *wb_connector =
0089 fence_to_wb_connector(fence);
0090
0091 return wb_connector->base.dev->driver->name;
0092 }
0093
0094 static const char *
0095 drm_writeback_fence_get_timeline_name(struct dma_fence *fence)
0096 {
0097 struct drm_writeback_connector *wb_connector =
0098 fence_to_wb_connector(fence);
0099
0100 return wb_connector->timeline_name;
0101 }
0102
0103 static bool drm_writeback_fence_enable_signaling(struct dma_fence *fence)
0104 {
0105 return true;
0106 }
0107
0108 static const struct dma_fence_ops drm_writeback_fence_ops = {
0109 .get_driver_name = drm_writeback_fence_get_driver_name,
0110 .get_timeline_name = drm_writeback_fence_get_timeline_name,
0111 .enable_signaling = drm_writeback_fence_enable_signaling,
0112 };
0113
0114 static int create_writeback_properties(struct drm_device *dev)
0115 {
0116 struct drm_property *prop;
0117
0118 if (!dev->mode_config.writeback_fb_id_property) {
0119 prop = drm_property_create_object(dev, DRM_MODE_PROP_ATOMIC,
0120 "WRITEBACK_FB_ID",
0121 DRM_MODE_OBJECT_FB);
0122 if (!prop)
0123 return -ENOMEM;
0124 dev->mode_config.writeback_fb_id_property = prop;
0125 }
0126
0127 if (!dev->mode_config.writeback_pixel_formats_property) {
0128 prop = drm_property_create(dev, DRM_MODE_PROP_BLOB |
0129 DRM_MODE_PROP_ATOMIC |
0130 DRM_MODE_PROP_IMMUTABLE,
0131 "WRITEBACK_PIXEL_FORMATS", 0);
0132 if (!prop)
0133 return -ENOMEM;
0134 dev->mode_config.writeback_pixel_formats_property = prop;
0135 }
0136
0137 if (!dev->mode_config.writeback_out_fence_ptr_property) {
0138 prop = drm_property_create_range(dev, DRM_MODE_PROP_ATOMIC,
0139 "WRITEBACK_OUT_FENCE_PTR", 0,
0140 U64_MAX);
0141 if (!prop)
0142 return -ENOMEM;
0143 dev->mode_config.writeback_out_fence_ptr_property = prop;
0144 }
0145
0146 return 0;
0147 }
0148
0149 static const struct drm_encoder_funcs drm_writeback_encoder_funcs = {
0150 .destroy = drm_encoder_cleanup,
0151 };
0152
0153
0154
0155
0156
0157
0158
0159
0160
0161
0162
0163
0164
0165
0166
0167
0168
0169
0170
0171
0172
0173
0174
0175 int drm_writeback_connector_init(struct drm_device *dev,
0176 struct drm_writeback_connector *wb_connector,
0177 const struct drm_connector_funcs *con_funcs,
0178 const struct drm_encoder_helper_funcs *enc_helper_funcs,
0179 const u32 *formats, int n_formats,
0180 u32 possible_crtcs)
0181 {
0182 int ret = 0;
0183
0184 drm_encoder_helper_add(&wb_connector->encoder, enc_helper_funcs);
0185
0186 wb_connector->encoder.possible_crtcs = possible_crtcs;
0187
0188 ret = drm_encoder_init(dev, &wb_connector->encoder,
0189 &drm_writeback_encoder_funcs,
0190 DRM_MODE_ENCODER_VIRTUAL, NULL);
0191 if (ret)
0192 return ret;
0193
0194 ret = drm_writeback_connector_init_with_encoder(dev, wb_connector, &wb_connector->encoder,
0195 con_funcs, formats, n_formats);
0196
0197 if (ret)
0198 drm_encoder_cleanup(&wb_connector->encoder);
0199
0200 return ret;
0201 }
0202 EXPORT_SYMBOL(drm_writeback_connector_init);
0203
0204
0205
0206
0207
0208
0209
0210
0211
0212
0213
0214
0215
0216
0217
0218
0219
0220
0221
0222
0223
0224
0225
0226
0227
0228
0229
0230
0231
0232
0233 int drm_writeback_connector_init_with_encoder(struct drm_device *dev,
0234 struct drm_writeback_connector *wb_connector, struct drm_encoder *enc,
0235 const struct drm_connector_funcs *con_funcs, const u32 *formats,
0236 int n_formats)
0237 {
0238 struct drm_property_blob *blob;
0239 struct drm_connector *connector = &wb_connector->base;
0240 struct drm_mode_config *config = &dev->mode_config;
0241 int ret = create_writeback_properties(dev);
0242
0243 if (ret != 0)
0244 return ret;
0245
0246 blob = drm_property_create_blob(dev, n_formats * sizeof(*formats),
0247 formats);
0248 if (IS_ERR(blob))
0249 return PTR_ERR(blob);
0250
0251
0252 connector->interlace_allowed = 0;
0253
0254 ret = drm_connector_init(dev, connector, con_funcs,
0255 DRM_MODE_CONNECTOR_WRITEBACK);
0256 if (ret)
0257 goto connector_fail;
0258
0259 ret = drm_connector_attach_encoder(connector, enc);
0260 if (ret)
0261 goto attach_fail;
0262
0263 INIT_LIST_HEAD(&wb_connector->job_queue);
0264 spin_lock_init(&wb_connector->job_lock);
0265
0266 wb_connector->fence_context = dma_fence_context_alloc(1);
0267 spin_lock_init(&wb_connector->fence_lock);
0268 snprintf(wb_connector->timeline_name,
0269 sizeof(wb_connector->timeline_name),
0270 "CONNECTOR:%d-%s", connector->base.id, connector->name);
0271
0272 drm_object_attach_property(&connector->base,
0273 config->writeback_out_fence_ptr_property, 0);
0274
0275 drm_object_attach_property(&connector->base,
0276 config->writeback_fb_id_property, 0);
0277
0278 drm_object_attach_property(&connector->base,
0279 config->writeback_pixel_formats_property,
0280 blob->base.id);
0281 wb_connector->pixel_formats_blob_ptr = blob;
0282
0283 return 0;
0284
0285 attach_fail:
0286 drm_connector_cleanup(connector);
0287 connector_fail:
0288 drm_property_blob_put(blob);
0289 return ret;
0290 }
0291 EXPORT_SYMBOL(drm_writeback_connector_init_with_encoder);
0292
0293 int drm_writeback_set_fb(struct drm_connector_state *conn_state,
0294 struct drm_framebuffer *fb)
0295 {
0296 WARN_ON(conn_state->connector->connector_type != DRM_MODE_CONNECTOR_WRITEBACK);
0297
0298 if (!conn_state->writeback_job) {
0299 conn_state->writeback_job =
0300 kzalloc(sizeof(*conn_state->writeback_job), GFP_KERNEL);
0301 if (!conn_state->writeback_job)
0302 return -ENOMEM;
0303
0304 conn_state->writeback_job->connector =
0305 drm_connector_to_writeback(conn_state->connector);
0306 }
0307
0308 drm_framebuffer_assign(&conn_state->writeback_job->fb, fb);
0309 return 0;
0310 }
0311
0312 int drm_writeback_prepare_job(struct drm_writeback_job *job)
0313 {
0314 struct drm_writeback_connector *connector = job->connector;
0315 const struct drm_connector_helper_funcs *funcs =
0316 connector->base.helper_private;
0317 int ret;
0318
0319 if (funcs->prepare_writeback_job) {
0320 ret = funcs->prepare_writeback_job(connector, job);
0321 if (ret < 0)
0322 return ret;
0323 }
0324
0325 job->prepared = true;
0326 return 0;
0327 }
0328 EXPORT_SYMBOL(drm_writeback_prepare_job);
0329
0330
0331
0332
0333
0334
0335
0336
0337
0338
0339
0340
0341
0342
0343
0344
0345
0346
0347
0348
0349 void drm_writeback_queue_job(struct drm_writeback_connector *wb_connector,
0350 struct drm_connector_state *conn_state)
0351 {
0352 struct drm_writeback_job *job;
0353 unsigned long flags;
0354
0355 job = conn_state->writeback_job;
0356 conn_state->writeback_job = NULL;
0357
0358 spin_lock_irqsave(&wb_connector->job_lock, flags);
0359 list_add_tail(&job->list_entry, &wb_connector->job_queue);
0360 spin_unlock_irqrestore(&wb_connector->job_lock, flags);
0361 }
0362 EXPORT_SYMBOL(drm_writeback_queue_job);
0363
0364 void drm_writeback_cleanup_job(struct drm_writeback_job *job)
0365 {
0366 struct drm_writeback_connector *connector = job->connector;
0367 const struct drm_connector_helper_funcs *funcs =
0368 connector->base.helper_private;
0369
0370 if (job->prepared && funcs->cleanup_writeback_job)
0371 funcs->cleanup_writeback_job(connector, job);
0372
0373 if (job->fb)
0374 drm_framebuffer_put(job->fb);
0375
0376 if (job->out_fence)
0377 dma_fence_put(job->out_fence);
0378
0379 kfree(job);
0380 }
0381 EXPORT_SYMBOL(drm_writeback_cleanup_job);
0382
0383
0384
0385
0386
0387
0388
0389
0390 static void cleanup_work(struct work_struct *work)
0391 {
0392 struct drm_writeback_job *job = container_of(work,
0393 struct drm_writeback_job,
0394 cleanup_work);
0395
0396 drm_writeback_cleanup_job(job);
0397 }
0398
0399
0400
0401
0402
0403
0404
0405
0406
0407
0408
0409
0410
0411
0412
0413
0414
0415 void
0416 drm_writeback_signal_completion(struct drm_writeback_connector *wb_connector,
0417 int status)
0418 {
0419 unsigned long flags;
0420 struct drm_writeback_job *job;
0421 struct dma_fence *out_fence;
0422
0423 spin_lock_irqsave(&wb_connector->job_lock, flags);
0424 job = list_first_entry_or_null(&wb_connector->job_queue,
0425 struct drm_writeback_job,
0426 list_entry);
0427 if (job)
0428 list_del(&job->list_entry);
0429
0430 spin_unlock_irqrestore(&wb_connector->job_lock, flags);
0431
0432 if (WARN_ON(!job))
0433 return;
0434
0435 out_fence = job->out_fence;
0436 if (out_fence) {
0437 if (status)
0438 dma_fence_set_error(out_fence, status);
0439 dma_fence_signal(out_fence);
0440 dma_fence_put(out_fence);
0441 job->out_fence = NULL;
0442 }
0443
0444 INIT_WORK(&job->cleanup_work, cleanup_work);
0445 queue_work(system_long_wq, &job->cleanup_work);
0446 }
0447 EXPORT_SYMBOL(drm_writeback_signal_completion);
0448
0449 struct dma_fence *
0450 drm_writeback_get_out_fence(struct drm_writeback_connector *wb_connector)
0451 {
0452 struct dma_fence *fence;
0453
0454 if (WARN_ON(wb_connector->base.connector_type !=
0455 DRM_MODE_CONNECTOR_WRITEBACK))
0456 return NULL;
0457
0458 fence = kzalloc(sizeof(*fence), GFP_KERNEL);
0459 if (!fence)
0460 return NULL;
0461
0462 dma_fence_init(fence, &drm_writeback_fence_ops,
0463 &wb_connector->fence_lock, wb_connector->fence_context,
0464 ++wb_connector->fence_seqno);
0465
0466 return fence;
0467 }
0468 EXPORT_SYMBOL(drm_writeback_get_out_fence);