0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030 #include <drm/drm_atomic_uapi.h>
0031 #include <drm/drm_atomic.h>
0032 #include <drm/drm_framebuffer.h>
0033 #include <drm/drm_print.h>
0034 #include <drm/drm_drv.h>
0035 #include <drm/drm_writeback.h>
0036 #include <drm/drm_vblank.h>
0037
0038 #include <linux/dma-fence.h>
0039 #include <linux/uaccess.h>
0040 #include <linux/sync_file.h>
0041 #include <linux/file.h>
0042
0043 #include "drm_crtc_internal.h"
0044
0045
0046
0047
0048
0049
0050
0051
0052
0053
0054
0055
0056
0057
0058
0059
0060
0061
0062
0063
0064
0065
0066 int drm_atomic_set_mode_for_crtc(struct drm_crtc_state *state,
0067 const struct drm_display_mode *mode)
0068 {
0069 struct drm_crtc *crtc = state->crtc;
0070 struct drm_mode_modeinfo umode;
0071
0072
0073 if (mode && memcmp(&state->mode, mode, sizeof(*mode)) == 0)
0074 return 0;
0075
0076 drm_property_blob_put(state->mode_blob);
0077 state->mode_blob = NULL;
0078
0079 if (mode) {
0080 struct drm_property_blob *blob;
0081
0082 drm_mode_convert_to_umode(&umode, mode);
0083 blob = drm_property_create_blob(crtc->dev,
0084 sizeof(umode), &umode);
0085 if (IS_ERR(blob))
0086 return PTR_ERR(blob);
0087
0088 drm_mode_copy(&state->mode, mode);
0089
0090 state->mode_blob = blob;
0091 state->enable = true;
0092 drm_dbg_atomic(crtc->dev,
0093 "Set [MODE:%s] for [CRTC:%d:%s] state %p\n",
0094 mode->name, crtc->base.id, crtc->name, state);
0095 } else {
0096 memset(&state->mode, 0, sizeof(state->mode));
0097 state->enable = false;
0098 drm_dbg_atomic(crtc->dev,
0099 "Set [NOMODE] for [CRTC:%d:%s] state %p\n",
0100 crtc->base.id, crtc->name, state);
0101 }
0102
0103 return 0;
0104 }
0105 EXPORT_SYMBOL(drm_atomic_set_mode_for_crtc);
0106
0107
0108
0109
0110
0111
0112
0113
0114
0115
0116
0117
0118
0119
0120 int drm_atomic_set_mode_prop_for_crtc(struct drm_crtc_state *state,
0121 struct drm_property_blob *blob)
0122 {
0123 struct drm_crtc *crtc = state->crtc;
0124
0125 if (blob == state->mode_blob)
0126 return 0;
0127
0128 drm_property_blob_put(state->mode_blob);
0129 state->mode_blob = NULL;
0130
0131 memset(&state->mode, 0, sizeof(state->mode));
0132
0133 if (blob) {
0134 int ret;
0135
0136 if (blob->length != sizeof(struct drm_mode_modeinfo)) {
0137 drm_dbg_atomic(crtc->dev,
0138 "[CRTC:%d:%s] bad mode blob length: %zu\n",
0139 crtc->base.id, crtc->name,
0140 blob->length);
0141 return -EINVAL;
0142 }
0143
0144 ret = drm_mode_convert_umode(crtc->dev,
0145 &state->mode, blob->data);
0146 if (ret) {
0147 drm_dbg_atomic(crtc->dev,
0148 "[CRTC:%d:%s] invalid mode (ret=%d, status=%s):\n",
0149 crtc->base.id, crtc->name,
0150 ret, drm_get_mode_status_name(state->mode.status));
0151 drm_mode_debug_printmodeline(&state->mode);
0152 return -EINVAL;
0153 }
0154
0155 state->mode_blob = drm_property_blob_get(blob);
0156 state->enable = true;
0157 drm_dbg_atomic(crtc->dev,
0158 "Set [MODE:%s] for [CRTC:%d:%s] state %p\n",
0159 state->mode.name, crtc->base.id, crtc->name,
0160 state);
0161 } else {
0162 state->enable = false;
0163 drm_dbg_atomic(crtc->dev,
0164 "Set [NOMODE] for [CRTC:%d:%s] state %p\n",
0165 crtc->base.id, crtc->name, state);
0166 }
0167
0168 return 0;
0169 }
0170 EXPORT_SYMBOL(drm_atomic_set_mode_prop_for_crtc);
0171
0172
0173
0174
0175
0176
0177
0178
0179
0180
0181
0182
0183
0184
0185
0186 int
0187 drm_atomic_set_crtc_for_plane(struct drm_plane_state *plane_state,
0188 struct drm_crtc *crtc)
0189 {
0190 struct drm_plane *plane = plane_state->plane;
0191 struct drm_crtc_state *crtc_state;
0192
0193 if (plane_state->crtc == crtc)
0194 return 0;
0195 if (plane_state->crtc) {
0196 crtc_state = drm_atomic_get_crtc_state(plane_state->state,
0197 plane_state->crtc);
0198 if (WARN_ON(IS_ERR(crtc_state)))
0199 return PTR_ERR(crtc_state);
0200
0201 crtc_state->plane_mask &= ~drm_plane_mask(plane);
0202 }
0203
0204 plane_state->crtc = crtc;
0205
0206 if (crtc) {
0207 crtc_state = drm_atomic_get_crtc_state(plane_state->state,
0208 crtc);
0209 if (IS_ERR(crtc_state))
0210 return PTR_ERR(crtc_state);
0211 crtc_state->plane_mask |= drm_plane_mask(plane);
0212 }
0213
0214 if (crtc)
0215 drm_dbg_atomic(plane->dev,
0216 "Link [PLANE:%d:%s] state %p to [CRTC:%d:%s]\n",
0217 plane->base.id, plane->name, plane_state,
0218 crtc->base.id, crtc->name);
0219 else
0220 drm_dbg_atomic(plane->dev,
0221 "Link [PLANE:%d:%s] state %p to [NOCRTC]\n",
0222 plane->base.id, plane->name, plane_state);
0223
0224 return 0;
0225 }
0226 EXPORT_SYMBOL(drm_atomic_set_crtc_for_plane);
0227
0228
0229
0230
0231
0232
0233
0234
0235
0236
0237
0238 void
0239 drm_atomic_set_fb_for_plane(struct drm_plane_state *plane_state,
0240 struct drm_framebuffer *fb)
0241 {
0242 struct drm_plane *plane = plane_state->plane;
0243
0244 if (fb)
0245 drm_dbg_atomic(plane->dev,
0246 "Set [FB:%d] for [PLANE:%d:%s] state %p\n",
0247 fb->base.id, plane->base.id, plane->name,
0248 plane_state);
0249 else
0250 drm_dbg_atomic(plane->dev,
0251 "Set [NOFB] for [PLANE:%d:%s] state %p\n",
0252 plane->base.id, plane->name, plane_state);
0253
0254 drm_framebuffer_assign(&plane_state->fb, fb);
0255 }
0256 EXPORT_SYMBOL(drm_atomic_set_fb_for_plane);
0257
0258
0259
0260
0261
0262
0263
0264
0265
0266
0267
0268
0269
0270
0271
0272 int
0273 drm_atomic_set_crtc_for_connector(struct drm_connector_state *conn_state,
0274 struct drm_crtc *crtc)
0275 {
0276 struct drm_connector *connector = conn_state->connector;
0277 struct drm_crtc_state *crtc_state;
0278
0279 if (conn_state->crtc == crtc)
0280 return 0;
0281
0282 if (conn_state->crtc) {
0283 crtc_state = drm_atomic_get_new_crtc_state(conn_state->state,
0284 conn_state->crtc);
0285
0286 crtc_state->connector_mask &=
0287 ~drm_connector_mask(conn_state->connector);
0288
0289 drm_connector_put(conn_state->connector);
0290 conn_state->crtc = NULL;
0291 }
0292
0293 if (crtc) {
0294 crtc_state = drm_atomic_get_crtc_state(conn_state->state, crtc);
0295 if (IS_ERR(crtc_state))
0296 return PTR_ERR(crtc_state);
0297
0298 crtc_state->connector_mask |=
0299 drm_connector_mask(conn_state->connector);
0300
0301 drm_connector_get(conn_state->connector);
0302 conn_state->crtc = crtc;
0303
0304 drm_dbg_atomic(connector->dev,
0305 "Link [CONNECTOR:%d:%s] state %p to [CRTC:%d:%s]\n",
0306 connector->base.id, connector->name,
0307 conn_state, crtc->base.id, crtc->name);
0308 } else {
0309 drm_dbg_atomic(connector->dev,
0310 "Link [CONNECTOR:%d:%s] state %p to [NOCRTC]\n",
0311 connector->base.id, connector->name,
0312 conn_state);
0313 }
0314
0315 return 0;
0316 }
0317 EXPORT_SYMBOL(drm_atomic_set_crtc_for_connector);
0318
0319 static void set_out_fence_for_crtc(struct drm_atomic_state *state,
0320 struct drm_crtc *crtc, s32 __user *fence_ptr)
0321 {
0322 state->crtcs[drm_crtc_index(crtc)].out_fence_ptr = fence_ptr;
0323 }
0324
0325 static s32 __user *get_out_fence_for_crtc(struct drm_atomic_state *state,
0326 struct drm_crtc *crtc)
0327 {
0328 s32 __user *fence_ptr;
0329
0330 fence_ptr = state->crtcs[drm_crtc_index(crtc)].out_fence_ptr;
0331 state->crtcs[drm_crtc_index(crtc)].out_fence_ptr = NULL;
0332
0333 return fence_ptr;
0334 }
0335
0336 static int set_out_fence_for_connector(struct drm_atomic_state *state,
0337 struct drm_connector *connector,
0338 s32 __user *fence_ptr)
0339 {
0340 unsigned int index = drm_connector_index(connector);
0341
0342 if (!fence_ptr)
0343 return 0;
0344
0345 if (put_user(-1, fence_ptr))
0346 return -EFAULT;
0347
0348 state->connectors[index].out_fence_ptr = fence_ptr;
0349
0350 return 0;
0351 }
0352
0353 static s32 __user *get_out_fence_for_connector(struct drm_atomic_state *state,
0354 struct drm_connector *connector)
0355 {
0356 unsigned int index = drm_connector_index(connector);
0357 s32 __user *fence_ptr;
0358
0359 fence_ptr = state->connectors[index].out_fence_ptr;
0360 state->connectors[index].out_fence_ptr = NULL;
0361
0362 return fence_ptr;
0363 }
0364
0365 static int
0366 drm_atomic_replace_property_blob_from_id(struct drm_device *dev,
0367 struct drm_property_blob **blob,
0368 uint64_t blob_id,
0369 ssize_t expected_size,
0370 ssize_t expected_elem_size,
0371 bool *replaced)
0372 {
0373 struct drm_property_blob *new_blob = NULL;
0374
0375 if (blob_id != 0) {
0376 new_blob = drm_property_lookup_blob(dev, blob_id);
0377 if (new_blob == NULL)
0378 return -EINVAL;
0379
0380 if (expected_size > 0 &&
0381 new_blob->length != expected_size) {
0382 drm_property_blob_put(new_blob);
0383 return -EINVAL;
0384 }
0385 if (expected_elem_size > 0 &&
0386 new_blob->length % expected_elem_size != 0) {
0387 drm_property_blob_put(new_blob);
0388 return -EINVAL;
0389 }
0390 }
0391
0392 *replaced |= drm_property_replace_blob(blob, new_blob);
0393 drm_property_blob_put(new_blob);
0394
0395 return 0;
0396 }
0397
0398 static int drm_atomic_crtc_set_property(struct drm_crtc *crtc,
0399 struct drm_crtc_state *state, struct drm_property *property,
0400 uint64_t val)
0401 {
0402 struct drm_device *dev = crtc->dev;
0403 struct drm_mode_config *config = &dev->mode_config;
0404 bool replaced = false;
0405 int ret;
0406
0407 if (property == config->prop_active)
0408 state->active = val;
0409 else if (property == config->prop_mode_id) {
0410 struct drm_property_blob *mode =
0411 drm_property_lookup_blob(dev, val);
0412 ret = drm_atomic_set_mode_prop_for_crtc(state, mode);
0413 drm_property_blob_put(mode);
0414 return ret;
0415 } else if (property == config->prop_vrr_enabled) {
0416 state->vrr_enabled = val;
0417 } else if (property == config->degamma_lut_property) {
0418 ret = drm_atomic_replace_property_blob_from_id(dev,
0419 &state->degamma_lut,
0420 val,
0421 -1, sizeof(struct drm_color_lut),
0422 &replaced);
0423 state->color_mgmt_changed |= replaced;
0424 return ret;
0425 } else if (property == config->ctm_property) {
0426 ret = drm_atomic_replace_property_blob_from_id(dev,
0427 &state->ctm,
0428 val,
0429 sizeof(struct drm_color_ctm), -1,
0430 &replaced);
0431 state->color_mgmt_changed |= replaced;
0432 return ret;
0433 } else if (property == config->gamma_lut_property) {
0434 ret = drm_atomic_replace_property_blob_from_id(dev,
0435 &state->gamma_lut,
0436 val,
0437 -1, sizeof(struct drm_color_lut),
0438 &replaced);
0439 state->color_mgmt_changed |= replaced;
0440 return ret;
0441 } else if (property == config->prop_out_fence_ptr) {
0442 s32 __user *fence_ptr = u64_to_user_ptr(val);
0443
0444 if (!fence_ptr)
0445 return 0;
0446
0447 if (put_user(-1, fence_ptr))
0448 return -EFAULT;
0449
0450 set_out_fence_for_crtc(state->state, crtc, fence_ptr);
0451 } else if (property == crtc->scaling_filter_property) {
0452 state->scaling_filter = val;
0453 } else if (crtc->funcs->atomic_set_property) {
0454 return crtc->funcs->atomic_set_property(crtc, state, property, val);
0455 } else {
0456 drm_dbg_atomic(crtc->dev,
0457 "[CRTC:%d:%s] unknown property [PROP:%d:%s]]\n",
0458 crtc->base.id, crtc->name,
0459 property->base.id, property->name);
0460 return -EINVAL;
0461 }
0462
0463 return 0;
0464 }
0465
0466 static int
0467 drm_atomic_crtc_get_property(struct drm_crtc *crtc,
0468 const struct drm_crtc_state *state,
0469 struct drm_property *property, uint64_t *val)
0470 {
0471 struct drm_device *dev = crtc->dev;
0472 struct drm_mode_config *config = &dev->mode_config;
0473
0474 if (property == config->prop_active)
0475 *val = drm_atomic_crtc_effectively_active(state);
0476 else if (property == config->prop_mode_id)
0477 *val = (state->mode_blob) ? state->mode_blob->base.id : 0;
0478 else if (property == config->prop_vrr_enabled)
0479 *val = state->vrr_enabled;
0480 else if (property == config->degamma_lut_property)
0481 *val = (state->degamma_lut) ? state->degamma_lut->base.id : 0;
0482 else if (property == config->ctm_property)
0483 *val = (state->ctm) ? state->ctm->base.id : 0;
0484 else if (property == config->gamma_lut_property)
0485 *val = (state->gamma_lut) ? state->gamma_lut->base.id : 0;
0486 else if (property == config->prop_out_fence_ptr)
0487 *val = 0;
0488 else if (property == crtc->scaling_filter_property)
0489 *val = state->scaling_filter;
0490 else if (crtc->funcs->atomic_get_property)
0491 return crtc->funcs->atomic_get_property(crtc, state, property, val);
0492 else
0493 return -EINVAL;
0494
0495 return 0;
0496 }
0497
0498 static int drm_atomic_plane_set_property(struct drm_plane *plane,
0499 struct drm_plane_state *state, struct drm_file *file_priv,
0500 struct drm_property *property, uint64_t val)
0501 {
0502 struct drm_device *dev = plane->dev;
0503 struct drm_mode_config *config = &dev->mode_config;
0504 bool replaced = false;
0505 int ret;
0506
0507 if (property == config->prop_fb_id) {
0508 struct drm_framebuffer *fb;
0509
0510 fb = drm_framebuffer_lookup(dev, file_priv, val);
0511 drm_atomic_set_fb_for_plane(state, fb);
0512 if (fb)
0513 drm_framebuffer_put(fb);
0514 } else if (property == config->prop_in_fence_fd) {
0515 if (state->fence)
0516 return -EINVAL;
0517
0518 if (U642I64(val) == -1)
0519 return 0;
0520
0521 state->fence = sync_file_get_fence(val);
0522 if (!state->fence)
0523 return -EINVAL;
0524
0525 } else if (property == config->prop_crtc_id) {
0526 struct drm_crtc *crtc = drm_crtc_find(dev, file_priv, val);
0527
0528 if (val && !crtc)
0529 return -EACCES;
0530 return drm_atomic_set_crtc_for_plane(state, crtc);
0531 } else if (property == config->prop_crtc_x) {
0532 state->crtc_x = U642I64(val);
0533 } else if (property == config->prop_crtc_y) {
0534 state->crtc_y = U642I64(val);
0535 } else if (property == config->prop_crtc_w) {
0536 state->crtc_w = val;
0537 } else if (property == config->prop_crtc_h) {
0538 state->crtc_h = val;
0539 } else if (property == config->prop_src_x) {
0540 state->src_x = val;
0541 } else if (property == config->prop_src_y) {
0542 state->src_y = val;
0543 } else if (property == config->prop_src_w) {
0544 state->src_w = val;
0545 } else if (property == config->prop_src_h) {
0546 state->src_h = val;
0547 } else if (property == plane->alpha_property) {
0548 state->alpha = val;
0549 } else if (property == plane->blend_mode_property) {
0550 state->pixel_blend_mode = val;
0551 } else if (property == plane->rotation_property) {
0552 if (!is_power_of_2(val & DRM_MODE_ROTATE_MASK)) {
0553 drm_dbg_atomic(plane->dev,
0554 "[PLANE:%d:%s] bad rotation bitmask: 0x%llx\n",
0555 plane->base.id, plane->name, val);
0556 return -EINVAL;
0557 }
0558 state->rotation = val;
0559 } else if (property == plane->zpos_property) {
0560 state->zpos = val;
0561 } else if (property == plane->color_encoding_property) {
0562 state->color_encoding = val;
0563 } else if (property == plane->color_range_property) {
0564 state->color_range = val;
0565 } else if (property == config->prop_fb_damage_clips) {
0566 ret = drm_atomic_replace_property_blob_from_id(dev,
0567 &state->fb_damage_clips,
0568 val,
0569 -1,
0570 sizeof(struct drm_rect),
0571 &replaced);
0572 return ret;
0573 } else if (property == plane->scaling_filter_property) {
0574 state->scaling_filter = val;
0575 } else if (plane->funcs->atomic_set_property) {
0576 return plane->funcs->atomic_set_property(plane, state,
0577 property, val);
0578 } else {
0579 drm_dbg_atomic(plane->dev,
0580 "[PLANE:%d:%s] unknown property [PROP:%d:%s]]\n",
0581 plane->base.id, plane->name,
0582 property->base.id, property->name);
0583 return -EINVAL;
0584 }
0585
0586 return 0;
0587 }
0588
0589 static int
0590 drm_atomic_plane_get_property(struct drm_plane *plane,
0591 const struct drm_plane_state *state,
0592 struct drm_property *property, uint64_t *val)
0593 {
0594 struct drm_device *dev = plane->dev;
0595 struct drm_mode_config *config = &dev->mode_config;
0596
0597 if (property == config->prop_fb_id) {
0598 *val = (state->fb) ? state->fb->base.id : 0;
0599 } else if (property == config->prop_in_fence_fd) {
0600 *val = -1;
0601 } else if (property == config->prop_crtc_id) {
0602 *val = (state->crtc) ? state->crtc->base.id : 0;
0603 } else if (property == config->prop_crtc_x) {
0604 *val = I642U64(state->crtc_x);
0605 } else if (property == config->prop_crtc_y) {
0606 *val = I642U64(state->crtc_y);
0607 } else if (property == config->prop_crtc_w) {
0608 *val = state->crtc_w;
0609 } else if (property == config->prop_crtc_h) {
0610 *val = state->crtc_h;
0611 } else if (property == config->prop_src_x) {
0612 *val = state->src_x;
0613 } else if (property == config->prop_src_y) {
0614 *val = state->src_y;
0615 } else if (property == config->prop_src_w) {
0616 *val = state->src_w;
0617 } else if (property == config->prop_src_h) {
0618 *val = state->src_h;
0619 } else if (property == plane->alpha_property) {
0620 *val = state->alpha;
0621 } else if (property == plane->blend_mode_property) {
0622 *val = state->pixel_blend_mode;
0623 } else if (property == plane->rotation_property) {
0624 *val = state->rotation;
0625 } else if (property == plane->zpos_property) {
0626 *val = state->zpos;
0627 } else if (property == plane->color_encoding_property) {
0628 *val = state->color_encoding;
0629 } else if (property == plane->color_range_property) {
0630 *val = state->color_range;
0631 } else if (property == config->prop_fb_damage_clips) {
0632 *val = (state->fb_damage_clips) ?
0633 state->fb_damage_clips->base.id : 0;
0634 } else if (property == plane->scaling_filter_property) {
0635 *val = state->scaling_filter;
0636 } else if (plane->funcs->atomic_get_property) {
0637 return plane->funcs->atomic_get_property(plane, state, property, val);
0638 } else {
0639 return -EINVAL;
0640 }
0641
0642 return 0;
0643 }
0644
0645 static int drm_atomic_set_writeback_fb_for_connector(
0646 struct drm_connector_state *conn_state,
0647 struct drm_framebuffer *fb)
0648 {
0649 int ret;
0650 struct drm_connector *conn = conn_state->connector;
0651
0652 ret = drm_writeback_set_fb(conn_state, fb);
0653 if (ret < 0)
0654 return ret;
0655
0656 if (fb)
0657 drm_dbg_atomic(conn->dev,
0658 "Set [FB:%d] for connector state %p\n",
0659 fb->base.id, conn_state);
0660 else
0661 drm_dbg_atomic(conn->dev,
0662 "Set [NOFB] for connector state %p\n",
0663 conn_state);
0664
0665 return 0;
0666 }
0667
0668 static int drm_atomic_connector_set_property(struct drm_connector *connector,
0669 struct drm_connector_state *state, struct drm_file *file_priv,
0670 struct drm_property *property, uint64_t val)
0671 {
0672 struct drm_device *dev = connector->dev;
0673 struct drm_mode_config *config = &dev->mode_config;
0674 bool replaced = false;
0675 int ret;
0676
0677 if (property == config->prop_crtc_id) {
0678 struct drm_crtc *crtc = drm_crtc_find(dev, file_priv, val);
0679
0680 if (val && !crtc)
0681 return -EACCES;
0682 return drm_atomic_set_crtc_for_connector(state, crtc);
0683 } else if (property == config->dpms_property) {
0684
0685
0686
0687
0688 return -EINVAL;
0689 } else if (property == config->tv_select_subconnector_property) {
0690 state->tv.subconnector = val;
0691 } else if (property == config->tv_left_margin_property) {
0692 state->tv.margins.left = val;
0693 } else if (property == config->tv_right_margin_property) {
0694 state->tv.margins.right = val;
0695 } else if (property == config->tv_top_margin_property) {
0696 state->tv.margins.top = val;
0697 } else if (property == config->tv_bottom_margin_property) {
0698 state->tv.margins.bottom = val;
0699 } else if (property == config->tv_mode_property) {
0700 state->tv.mode = val;
0701 } else if (property == config->tv_brightness_property) {
0702 state->tv.brightness = val;
0703 } else if (property == config->tv_contrast_property) {
0704 state->tv.contrast = val;
0705 } else if (property == config->tv_flicker_reduction_property) {
0706 state->tv.flicker_reduction = val;
0707 } else if (property == config->tv_overscan_property) {
0708 state->tv.overscan = val;
0709 } else if (property == config->tv_saturation_property) {
0710 state->tv.saturation = val;
0711 } else if (property == config->tv_hue_property) {
0712 state->tv.hue = val;
0713 } else if (property == config->link_status_property) {
0714
0715
0716
0717
0718
0719
0720
0721
0722
0723
0724
0725 if (state->link_status != DRM_LINK_STATUS_GOOD)
0726 state->link_status = val;
0727 } else if (property == config->hdr_output_metadata_property) {
0728 ret = drm_atomic_replace_property_blob_from_id(dev,
0729 &state->hdr_output_metadata,
0730 val,
0731 sizeof(struct hdr_output_metadata), -1,
0732 &replaced);
0733 return ret;
0734 } else if (property == config->aspect_ratio_property) {
0735 state->picture_aspect_ratio = val;
0736 } else if (property == config->content_type_property) {
0737 state->content_type = val;
0738 } else if (property == connector->scaling_mode_property) {
0739 state->scaling_mode = val;
0740 } else if (property == config->content_protection_property) {
0741 if (val == DRM_MODE_CONTENT_PROTECTION_ENABLED) {
0742 drm_dbg_kms(dev, "only drivers can set CP Enabled\n");
0743 return -EINVAL;
0744 }
0745 state->content_protection = val;
0746 } else if (property == config->hdcp_content_type_property) {
0747 state->hdcp_content_type = val;
0748 } else if (property == connector->colorspace_property) {
0749 state->colorspace = val;
0750 } else if (property == config->writeback_fb_id_property) {
0751 struct drm_framebuffer *fb;
0752 int ret;
0753
0754 fb = drm_framebuffer_lookup(dev, file_priv, val);
0755 ret = drm_atomic_set_writeback_fb_for_connector(state, fb);
0756 if (fb)
0757 drm_framebuffer_put(fb);
0758 return ret;
0759 } else if (property == config->writeback_out_fence_ptr_property) {
0760 s32 __user *fence_ptr = u64_to_user_ptr(val);
0761
0762 return set_out_fence_for_connector(state->state, connector,
0763 fence_ptr);
0764 } else if (property == connector->max_bpc_property) {
0765 state->max_requested_bpc = val;
0766 } else if (property == connector->privacy_screen_sw_state_property) {
0767 state->privacy_screen_sw_state = val;
0768 } else if (connector->funcs->atomic_set_property) {
0769 return connector->funcs->atomic_set_property(connector,
0770 state, property, val);
0771 } else {
0772 drm_dbg_atomic(connector->dev,
0773 "[CONNECTOR:%d:%s] unknown property [PROP:%d:%s]]\n",
0774 connector->base.id, connector->name,
0775 property->base.id, property->name);
0776 return -EINVAL;
0777 }
0778
0779 return 0;
0780 }
0781
0782 static int
0783 drm_atomic_connector_get_property(struct drm_connector *connector,
0784 const struct drm_connector_state *state,
0785 struct drm_property *property, uint64_t *val)
0786 {
0787 struct drm_device *dev = connector->dev;
0788 struct drm_mode_config *config = &dev->mode_config;
0789
0790 if (property == config->prop_crtc_id) {
0791 *val = (state->crtc) ? state->crtc->base.id : 0;
0792 } else if (property == config->dpms_property) {
0793 if (state->crtc && state->crtc->state->self_refresh_active)
0794 *val = DRM_MODE_DPMS_ON;
0795 else
0796 *val = connector->dpms;
0797 } else if (property == config->tv_select_subconnector_property) {
0798 *val = state->tv.subconnector;
0799 } else if (property == config->tv_left_margin_property) {
0800 *val = state->tv.margins.left;
0801 } else if (property == config->tv_right_margin_property) {
0802 *val = state->tv.margins.right;
0803 } else if (property == config->tv_top_margin_property) {
0804 *val = state->tv.margins.top;
0805 } else if (property == config->tv_bottom_margin_property) {
0806 *val = state->tv.margins.bottom;
0807 } else if (property == config->tv_mode_property) {
0808 *val = state->tv.mode;
0809 } else if (property == config->tv_brightness_property) {
0810 *val = state->tv.brightness;
0811 } else if (property == config->tv_contrast_property) {
0812 *val = state->tv.contrast;
0813 } else if (property == config->tv_flicker_reduction_property) {
0814 *val = state->tv.flicker_reduction;
0815 } else if (property == config->tv_overscan_property) {
0816 *val = state->tv.overscan;
0817 } else if (property == config->tv_saturation_property) {
0818 *val = state->tv.saturation;
0819 } else if (property == config->tv_hue_property) {
0820 *val = state->tv.hue;
0821 } else if (property == config->link_status_property) {
0822 *val = state->link_status;
0823 } else if (property == config->aspect_ratio_property) {
0824 *val = state->picture_aspect_ratio;
0825 } else if (property == config->content_type_property) {
0826 *val = state->content_type;
0827 } else if (property == connector->colorspace_property) {
0828 *val = state->colorspace;
0829 } else if (property == connector->scaling_mode_property) {
0830 *val = state->scaling_mode;
0831 } else if (property == config->hdr_output_metadata_property) {
0832 *val = state->hdr_output_metadata ?
0833 state->hdr_output_metadata->base.id : 0;
0834 } else if (property == config->content_protection_property) {
0835 *val = state->content_protection;
0836 } else if (property == config->hdcp_content_type_property) {
0837 *val = state->hdcp_content_type;
0838 } else if (property == config->writeback_fb_id_property) {
0839
0840 *val = 0;
0841 } else if (property == config->writeback_out_fence_ptr_property) {
0842 *val = 0;
0843 } else if (property == connector->max_bpc_property) {
0844 *val = state->max_requested_bpc;
0845 } else if (property == connector->privacy_screen_sw_state_property) {
0846 *val = state->privacy_screen_sw_state;
0847 } else if (connector->funcs->atomic_get_property) {
0848 return connector->funcs->atomic_get_property(connector,
0849 state, property, val);
0850 } else {
0851 return -EINVAL;
0852 }
0853
0854 return 0;
0855 }
0856
0857 int drm_atomic_get_property(struct drm_mode_object *obj,
0858 struct drm_property *property, uint64_t *val)
0859 {
0860 struct drm_device *dev = property->dev;
0861 int ret;
0862
0863 switch (obj->type) {
0864 case DRM_MODE_OBJECT_CONNECTOR: {
0865 struct drm_connector *connector = obj_to_connector(obj);
0866
0867 WARN_ON(!drm_modeset_is_locked(&dev->mode_config.connection_mutex));
0868 ret = drm_atomic_connector_get_property(connector,
0869 connector->state, property, val);
0870 break;
0871 }
0872 case DRM_MODE_OBJECT_CRTC: {
0873 struct drm_crtc *crtc = obj_to_crtc(obj);
0874
0875 WARN_ON(!drm_modeset_is_locked(&crtc->mutex));
0876 ret = drm_atomic_crtc_get_property(crtc,
0877 crtc->state, property, val);
0878 break;
0879 }
0880 case DRM_MODE_OBJECT_PLANE: {
0881 struct drm_plane *plane = obj_to_plane(obj);
0882
0883 WARN_ON(!drm_modeset_is_locked(&plane->mutex));
0884 ret = drm_atomic_plane_get_property(plane,
0885 plane->state, property, val);
0886 break;
0887 }
0888 default:
0889 ret = -EINVAL;
0890 break;
0891 }
0892
0893 return ret;
0894 }
0895
0896
0897
0898
0899
0900 static struct drm_pending_vblank_event *create_vblank_event(
0901 struct drm_crtc *crtc, uint64_t user_data)
0902 {
0903 struct drm_pending_vblank_event *e = NULL;
0904
0905 e = kzalloc(sizeof *e, GFP_KERNEL);
0906 if (!e)
0907 return NULL;
0908
0909 e->event.base.type = DRM_EVENT_FLIP_COMPLETE;
0910 e->event.base.length = sizeof(e->event);
0911 e->event.vbl.crtc_id = crtc->base.id;
0912 e->event.vbl.user_data = user_data;
0913
0914 return e;
0915 }
0916
0917 int drm_atomic_connector_commit_dpms(struct drm_atomic_state *state,
0918 struct drm_connector *connector,
0919 int mode)
0920 {
0921 struct drm_connector *tmp_connector;
0922 struct drm_connector_state *new_conn_state;
0923 struct drm_crtc *crtc;
0924 struct drm_crtc_state *crtc_state;
0925 int i, ret, old_mode = connector->dpms;
0926 bool active = false;
0927
0928 ret = drm_modeset_lock(&state->dev->mode_config.connection_mutex,
0929 state->acquire_ctx);
0930 if (ret)
0931 return ret;
0932
0933 if (mode != DRM_MODE_DPMS_ON)
0934 mode = DRM_MODE_DPMS_OFF;
0935 connector->dpms = mode;
0936
0937 crtc = connector->state->crtc;
0938 if (!crtc)
0939 goto out;
0940 ret = drm_atomic_add_affected_connectors(state, crtc);
0941 if (ret)
0942 goto out;
0943
0944 crtc_state = drm_atomic_get_crtc_state(state, crtc);
0945 if (IS_ERR(crtc_state)) {
0946 ret = PTR_ERR(crtc_state);
0947 goto out;
0948 }
0949
0950 for_each_new_connector_in_state(state, tmp_connector, new_conn_state, i) {
0951 if (new_conn_state->crtc != crtc)
0952 continue;
0953 if (tmp_connector->dpms == DRM_MODE_DPMS_ON) {
0954 active = true;
0955 break;
0956 }
0957 }
0958
0959 crtc_state->active = active;
0960 ret = drm_atomic_commit(state);
0961 out:
0962 if (ret != 0)
0963 connector->dpms = old_mode;
0964 return ret;
0965 }
0966
0967 int drm_atomic_set_property(struct drm_atomic_state *state,
0968 struct drm_file *file_priv,
0969 struct drm_mode_object *obj,
0970 struct drm_property *prop,
0971 uint64_t prop_value)
0972 {
0973 struct drm_mode_object *ref;
0974 int ret;
0975
0976 if (!drm_property_change_valid_get(prop, prop_value, &ref))
0977 return -EINVAL;
0978
0979 switch (obj->type) {
0980 case DRM_MODE_OBJECT_CONNECTOR: {
0981 struct drm_connector *connector = obj_to_connector(obj);
0982 struct drm_connector_state *connector_state;
0983
0984 connector_state = drm_atomic_get_connector_state(state, connector);
0985 if (IS_ERR(connector_state)) {
0986 ret = PTR_ERR(connector_state);
0987 break;
0988 }
0989
0990 ret = drm_atomic_connector_set_property(connector,
0991 connector_state, file_priv,
0992 prop, prop_value);
0993 break;
0994 }
0995 case DRM_MODE_OBJECT_CRTC: {
0996 struct drm_crtc *crtc = obj_to_crtc(obj);
0997 struct drm_crtc_state *crtc_state;
0998
0999 crtc_state = drm_atomic_get_crtc_state(state, crtc);
1000 if (IS_ERR(crtc_state)) {
1001 ret = PTR_ERR(crtc_state);
1002 break;
1003 }
1004
1005 ret = drm_atomic_crtc_set_property(crtc,
1006 crtc_state, prop, prop_value);
1007 break;
1008 }
1009 case DRM_MODE_OBJECT_PLANE: {
1010 struct drm_plane *plane = obj_to_plane(obj);
1011 struct drm_plane_state *plane_state;
1012
1013 plane_state = drm_atomic_get_plane_state(state, plane);
1014 if (IS_ERR(plane_state)) {
1015 ret = PTR_ERR(plane_state);
1016 break;
1017 }
1018
1019 ret = drm_atomic_plane_set_property(plane,
1020 plane_state, file_priv,
1021 prop, prop_value);
1022 break;
1023 }
1024 default:
1025 ret = -EINVAL;
1026 break;
1027 }
1028
1029 drm_property_change_valid_put(prop, ref);
1030 return ret;
1031 }
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085 struct drm_out_fence_state {
1086 s32 __user *out_fence_ptr;
1087 struct sync_file *sync_file;
1088 int fd;
1089 };
1090
1091 static int setup_out_fence(struct drm_out_fence_state *fence_state,
1092 struct dma_fence *fence)
1093 {
1094 fence_state->fd = get_unused_fd_flags(O_CLOEXEC);
1095 if (fence_state->fd < 0)
1096 return fence_state->fd;
1097
1098 if (put_user(fence_state->fd, fence_state->out_fence_ptr))
1099 return -EFAULT;
1100
1101 fence_state->sync_file = sync_file_create(fence);
1102 if (!fence_state->sync_file)
1103 return -ENOMEM;
1104
1105 return 0;
1106 }
1107
1108 static int prepare_signaling(struct drm_device *dev,
1109 struct drm_atomic_state *state,
1110 struct drm_mode_atomic *arg,
1111 struct drm_file *file_priv,
1112 struct drm_out_fence_state **fence_state,
1113 unsigned int *num_fences)
1114 {
1115 struct drm_crtc *crtc;
1116 struct drm_crtc_state *crtc_state;
1117 struct drm_connector *conn;
1118 struct drm_connector_state *conn_state;
1119 int i, c = 0, ret;
1120
1121 if (arg->flags & DRM_MODE_ATOMIC_TEST_ONLY)
1122 return 0;
1123
1124 for_each_new_crtc_in_state(state, crtc, crtc_state, i) {
1125 s32 __user *fence_ptr;
1126
1127 fence_ptr = get_out_fence_for_crtc(crtc_state->state, crtc);
1128
1129 if (arg->flags & DRM_MODE_PAGE_FLIP_EVENT || fence_ptr) {
1130 struct drm_pending_vblank_event *e;
1131
1132 e = create_vblank_event(crtc, arg->user_data);
1133 if (!e)
1134 return -ENOMEM;
1135
1136 crtc_state->event = e;
1137 }
1138
1139 if (arg->flags & DRM_MODE_PAGE_FLIP_EVENT) {
1140 struct drm_pending_vblank_event *e = crtc_state->event;
1141
1142 if (!file_priv)
1143 continue;
1144
1145 ret = drm_event_reserve_init(dev, file_priv, &e->base,
1146 &e->event.base);
1147 if (ret) {
1148 kfree(e);
1149 crtc_state->event = NULL;
1150 return ret;
1151 }
1152 }
1153
1154 if (fence_ptr) {
1155 struct dma_fence *fence;
1156 struct drm_out_fence_state *f;
1157
1158 f = krealloc(*fence_state, sizeof(**fence_state) *
1159 (*num_fences + 1), GFP_KERNEL);
1160 if (!f)
1161 return -ENOMEM;
1162
1163 memset(&f[*num_fences], 0, sizeof(*f));
1164
1165 f[*num_fences].out_fence_ptr = fence_ptr;
1166 *fence_state = f;
1167
1168 fence = drm_crtc_create_fence(crtc);
1169 if (!fence)
1170 return -ENOMEM;
1171
1172 ret = setup_out_fence(&f[(*num_fences)++], fence);
1173 if (ret) {
1174 dma_fence_put(fence);
1175 return ret;
1176 }
1177
1178 crtc_state->event->base.fence = fence;
1179 }
1180
1181 c++;
1182 }
1183
1184 for_each_new_connector_in_state(state, conn, conn_state, i) {
1185 struct drm_writeback_connector *wb_conn;
1186 struct drm_out_fence_state *f;
1187 struct dma_fence *fence;
1188 s32 __user *fence_ptr;
1189
1190 if (!conn_state->writeback_job)
1191 continue;
1192
1193 fence_ptr = get_out_fence_for_connector(state, conn);
1194 if (!fence_ptr)
1195 continue;
1196
1197 f = krealloc(*fence_state, sizeof(**fence_state) *
1198 (*num_fences + 1), GFP_KERNEL);
1199 if (!f)
1200 return -ENOMEM;
1201
1202 memset(&f[*num_fences], 0, sizeof(*f));
1203
1204 f[*num_fences].out_fence_ptr = fence_ptr;
1205 *fence_state = f;
1206
1207 wb_conn = drm_connector_to_writeback(conn);
1208 fence = drm_writeback_get_out_fence(wb_conn);
1209 if (!fence)
1210 return -ENOMEM;
1211
1212 ret = setup_out_fence(&f[(*num_fences)++], fence);
1213 if (ret) {
1214 dma_fence_put(fence);
1215 return ret;
1216 }
1217
1218 conn_state->writeback_job->out_fence = fence;
1219 }
1220
1221
1222
1223
1224
1225 if (c == 0 && (arg->flags & DRM_MODE_PAGE_FLIP_EVENT))
1226 return -EINVAL;
1227
1228 return 0;
1229 }
1230
1231 static void complete_signaling(struct drm_device *dev,
1232 struct drm_atomic_state *state,
1233 struct drm_out_fence_state *fence_state,
1234 unsigned int num_fences,
1235 bool install_fds)
1236 {
1237 struct drm_crtc *crtc;
1238 struct drm_crtc_state *crtc_state;
1239 int i;
1240
1241 if (install_fds) {
1242 for (i = 0; i < num_fences; i++)
1243 fd_install(fence_state[i].fd,
1244 fence_state[i].sync_file->file);
1245
1246 kfree(fence_state);
1247 return;
1248 }
1249
1250 for_each_new_crtc_in_state(state, crtc, crtc_state, i) {
1251 struct drm_pending_vblank_event *event = crtc_state->event;
1252
1253
1254
1255
1256
1257 if (event && (event->base.fence || event->base.file_priv)) {
1258 drm_event_cancel_free(dev, &event->base);
1259 crtc_state->event = NULL;
1260 }
1261 }
1262
1263 if (!fence_state)
1264 return;
1265
1266 for (i = 0; i < num_fences; i++) {
1267 if (fence_state[i].sync_file)
1268 fput(fence_state[i].sync_file->file);
1269 if (fence_state[i].fd >= 0)
1270 put_unused_fd(fence_state[i].fd);
1271
1272
1273 if (fence_state[i].out_fence_ptr &&
1274 put_user(-1, fence_state[i].out_fence_ptr))
1275 drm_dbg_atomic(dev, "Couldn't clear out_fence_ptr\n");
1276 }
1277
1278 kfree(fence_state);
1279 }
1280
1281 int drm_mode_atomic_ioctl(struct drm_device *dev,
1282 void *data, struct drm_file *file_priv)
1283 {
1284 struct drm_mode_atomic *arg = data;
1285 uint32_t __user *objs_ptr = (uint32_t __user *)(unsigned long)(arg->objs_ptr);
1286 uint32_t __user *count_props_ptr = (uint32_t __user *)(unsigned long)(arg->count_props_ptr);
1287 uint32_t __user *props_ptr = (uint32_t __user *)(unsigned long)(arg->props_ptr);
1288 uint64_t __user *prop_values_ptr = (uint64_t __user *)(unsigned long)(arg->prop_values_ptr);
1289 unsigned int copied_objs, copied_props;
1290 struct drm_atomic_state *state;
1291 struct drm_modeset_acquire_ctx ctx;
1292 struct drm_out_fence_state *fence_state;
1293 int ret = 0;
1294 unsigned int i, j, num_fences;
1295
1296
1297 if (!drm_core_check_feature(dev, DRIVER_ATOMIC))
1298 return -EOPNOTSUPP;
1299
1300
1301
1302
1303
1304 if (!file_priv->atomic) {
1305 drm_dbg_atomic(dev,
1306 "commit failed: atomic cap not enabled\n");
1307 return -EINVAL;
1308 }
1309
1310 if (arg->flags & ~DRM_MODE_ATOMIC_FLAGS) {
1311 drm_dbg_atomic(dev, "commit failed: invalid flag\n");
1312 return -EINVAL;
1313 }
1314
1315 if (arg->reserved) {
1316 drm_dbg_atomic(dev, "commit failed: reserved field set\n");
1317 return -EINVAL;
1318 }
1319
1320 if (arg->flags & DRM_MODE_PAGE_FLIP_ASYNC) {
1321 drm_dbg_atomic(dev,
1322 "commit failed: invalid flag DRM_MODE_PAGE_FLIP_ASYNC\n");
1323 return -EINVAL;
1324 }
1325
1326
1327 if ((arg->flags & DRM_MODE_ATOMIC_TEST_ONLY) &&
1328 (arg->flags & DRM_MODE_PAGE_FLIP_EVENT)) {
1329 drm_dbg_atomic(dev,
1330 "commit failed: page-flip event requested with test-only commit\n");
1331 return -EINVAL;
1332 }
1333
1334 state = drm_atomic_state_alloc(dev);
1335 if (!state)
1336 return -ENOMEM;
1337
1338 drm_modeset_acquire_init(&ctx, DRM_MODESET_ACQUIRE_INTERRUPTIBLE);
1339 state->acquire_ctx = &ctx;
1340 state->allow_modeset = !!(arg->flags & DRM_MODE_ATOMIC_ALLOW_MODESET);
1341
1342 retry:
1343 copied_objs = 0;
1344 copied_props = 0;
1345 fence_state = NULL;
1346 num_fences = 0;
1347
1348 for (i = 0; i < arg->count_objs; i++) {
1349 uint32_t obj_id, count_props;
1350 struct drm_mode_object *obj;
1351
1352 if (get_user(obj_id, objs_ptr + copied_objs)) {
1353 ret = -EFAULT;
1354 goto out;
1355 }
1356
1357 obj = drm_mode_object_find(dev, file_priv, obj_id, DRM_MODE_OBJECT_ANY);
1358 if (!obj) {
1359 ret = -ENOENT;
1360 goto out;
1361 }
1362
1363 if (!obj->properties) {
1364 drm_mode_object_put(obj);
1365 ret = -ENOENT;
1366 goto out;
1367 }
1368
1369 if (get_user(count_props, count_props_ptr + copied_objs)) {
1370 drm_mode_object_put(obj);
1371 ret = -EFAULT;
1372 goto out;
1373 }
1374
1375 copied_objs++;
1376
1377 for (j = 0; j < count_props; j++) {
1378 uint32_t prop_id;
1379 uint64_t prop_value;
1380 struct drm_property *prop;
1381
1382 if (get_user(prop_id, props_ptr + copied_props)) {
1383 drm_mode_object_put(obj);
1384 ret = -EFAULT;
1385 goto out;
1386 }
1387
1388 prop = drm_mode_obj_find_prop_id(obj, prop_id);
1389 if (!prop) {
1390 drm_mode_object_put(obj);
1391 ret = -ENOENT;
1392 goto out;
1393 }
1394
1395 if (copy_from_user(&prop_value,
1396 prop_values_ptr + copied_props,
1397 sizeof(prop_value))) {
1398 drm_mode_object_put(obj);
1399 ret = -EFAULT;
1400 goto out;
1401 }
1402
1403 ret = drm_atomic_set_property(state, file_priv,
1404 obj, prop, prop_value);
1405 if (ret) {
1406 drm_mode_object_put(obj);
1407 goto out;
1408 }
1409
1410 copied_props++;
1411 }
1412
1413 drm_mode_object_put(obj);
1414 }
1415
1416 ret = prepare_signaling(dev, state, arg, file_priv, &fence_state,
1417 &num_fences);
1418 if (ret)
1419 goto out;
1420
1421 if (arg->flags & DRM_MODE_ATOMIC_TEST_ONLY) {
1422 ret = drm_atomic_check_only(state);
1423 } else if (arg->flags & DRM_MODE_ATOMIC_NONBLOCK) {
1424 ret = drm_atomic_nonblocking_commit(state);
1425 } else {
1426 ret = drm_atomic_commit(state);
1427 }
1428
1429 out:
1430 complete_signaling(dev, state, fence_state, num_fences, !ret);
1431
1432 if (ret == -EDEADLK) {
1433 drm_atomic_state_clear(state);
1434 ret = drm_modeset_backoff(&ctx);
1435 if (!ret)
1436 goto retry;
1437 }
1438
1439 drm_atomic_state_put(state);
1440
1441 drm_modeset_drop_locks(&ctx);
1442 drm_modeset_acquire_fini(&ctx);
1443
1444 return ret;
1445 }