diff --git a/drivers/gpu/drm/msm/sde/sde_connector.c b/drivers/gpu/drm/msm/sde/sde_connector.c index 7930cc29f7f4..83aaeee13d73 100644 --- a/drivers/gpu/drm/msm/sde/sde_connector.c +++ b/drivers/gpu/drm/msm/sde/sde_connector.c @@ -428,6 +428,7 @@ static int sde_connector_atomic_set_property(struct drm_connector *connector, struct sde_connector *c_conn; struct sde_connector_state *c_state; int idx, rc; + uint64_t fence_fd = 0; if (!connector || !state || !property) { SDE_ERROR("invalid argument(s), conn %pK, state %pK, prp %pK\n", @@ -472,6 +473,29 @@ static int sde_connector_atomic_set_property(struct drm_connector *connector, SDE_ERROR("prep fb failed, %d\n", rc); } break; + case CONNECTOR_PROP_RETIRE_FENCE: + if (!val) + goto end; + + /* + * update the the offset to a timeline for commit completion + */ + rc = sde_fence_create(&c_conn->retire_fence, &fence_fd, 1); + if (rc) { + SDE_ERROR("fence create failed rc:%d\n", rc); + goto end; + } + + rc = copy_to_user((uint64_t __user *)val, &fence_fd, + sizeof(uint64_t)); + if (rc) { + SDE_ERROR("copy to user failed rc:%d\n", rc); + /* fence will be released with timeline update */ + put_unused_fd(fence_fd); + rc = -EFAULT; + goto end; + } + break; case CONNECTOR_PROP_TOPOLOGY_CONTROL: rc = sde_rm_check_property_topctl(val); if (rc) @@ -544,12 +568,14 @@ static int sde_connector_atomic_get_property(struct drm_connector *connector, c_state = to_sde_connector_state(state); idx = msm_property_index(&c_conn->property_info, property); - if (idx == CONNECTOR_PROP_RETIRE_FENCE) - rc = sde_fence_create(&c_conn->retire_fence, val, 0); - else + if (idx == CONNECTOR_PROP_RETIRE_FENCE) { + *val = ~0; + rc = 0; + } else { /* get cached property value */ rc = msm_property_atomic_get(&c_conn->property_info, c_state->property_values, 0, property, val); + } /* allow for custom override */ if (c_conn->ops.get_property) @@ -931,8 +957,8 @@ struct drm_connector *sde_connector_init(struct drm_device *dev, "hdr_control", 0x0, 0, ~0, 0, CONNECTOR_PROP_HDR_CONTROL); - msm_property_install_range(&c_conn->property_info, "RETIRE_FENCE", - 0x0, 0, INR_OPEN_MAX, 0, CONNECTOR_PROP_RETIRE_FENCE); + msm_property_install_volatile_range(&c_conn->property_info, + "RETIRE_FENCE", 0x0, 0, ~0, 0, CONNECTOR_PROP_RETIRE_FENCE); msm_property_install_volatile_signed_range(&c_conn->property_info, "PLL_DELTA", 0x0, INT_MIN, INT_MAX, 0, diff --git a/drivers/gpu/drm/msm/sde/sde_crtc.c b/drivers/gpu/drm/msm/sde/sde_crtc.c index 733ff5f686c0..9805c8e8acb4 100644 --- a/drivers/gpu/drm/msm/sde/sde_crtc.c +++ b/drivers/gpu/drm/msm/sde/sde_crtc.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014-2018 The Linux Foundation. All rights reserved. + * Copyright (c) 2014-2019 The Linux Foundation. All rights reserved. * Copyright (C) 2013 Red Hat * Author: Rob Clark * @@ -1642,8 +1642,8 @@ static void sde_crtc_install_properties(struct drm_crtc *crtc, "input_fence_timeout", 0x0, 0, SDE_CRTC_MAX_INPUT_FENCE_TIMEOUT, SDE_CRTC_INPUT_FENCE_TIMEOUT, CRTC_PROP_INPUT_FENCE_TIMEOUT); - msm_property_install_range(&sde_crtc->property_info, "output_fence", - 0x0, 0, INR_OPEN_MAX, 0x0, CRTC_PROP_OUTPUT_FENCE); + msm_property_install_volatile_range(&sde_crtc->property_info, + "output_fence", 0x0, 0, ~0, 0, CRTC_PROP_OUTPUT_FENCE); msm_property_install_range(&sde_crtc->property_info, "output_fence_offset", 0x0, 0, 1, 0, @@ -1708,6 +1708,28 @@ static void sde_crtc_install_properties(struct drm_crtc *crtc, kfree(info); } +static int _sde_crtc_get_output_fence(struct drm_crtc *crtc, + const struct drm_crtc_state *state, uint64_t *val) +{ + struct sde_crtc *sde_crtc; + struct sde_crtc_state *cstate; + uint32_t offset; + + sde_crtc = to_sde_crtc(crtc); + cstate = to_sde_crtc_state(state); + + offset = sde_crtc_get_property(cstate, CRTC_PROP_OUTPUT_FENCE_OFFSET); + + /* + * Hwcomposer now queries the fences using the commit list in atomic + * commit ioctl. The offset should be set to next timeline + * which will be incremented during the prepare commit phase + */ + offset++; + + return sde_fence_create(&sde_crtc->output_fence, val, offset); +} + /** * sde_crtc_atomic_set_property - atomically set a crtc drm property * @crtc: Pointer to drm crtc structure @@ -1724,28 +1746,61 @@ static int sde_crtc_atomic_set_property(struct drm_crtc *crtc, struct sde_crtc *sde_crtc; struct sde_crtc_state *cstate; int idx, ret = -EINVAL; + uint64_t fence_fd = 0; if (!crtc || !state || !property) { SDE_ERROR("invalid argument(s)\n"); - } else { - sde_crtc = to_sde_crtc(crtc); - cstate = to_sde_crtc_state(state); - ret = msm_property_atomic_set(&sde_crtc->property_info, - cstate->property_values, cstate->property_blobs, - property, val); - if (!ret) { - idx = msm_property_index(&sde_crtc->property_info, - property); - if (idx == CRTC_PROP_INPUT_FENCE_TIMEOUT) - _sde_crtc_set_input_fence_timeout(cstate); - } else { - ret = sde_cp_crtc_set_property(crtc, - property, val); - } - if (ret) - DRM_ERROR("failed to set the property\n"); + return -EINVAL; } + sde_crtc = to_sde_crtc(crtc); + cstate = to_sde_crtc_state(state); + + ret = msm_property_atomic_set(&sde_crtc->property_info, + cstate->property_values, cstate->property_blobs, + property, val); + + if (!ret) { + idx = msm_property_index(&sde_crtc->property_info, + property); + switch (idx) { + case CRTC_PROP_INPUT_FENCE_TIMEOUT: + _sde_crtc_set_input_fence_timeout(cstate); + break; + case CRTC_PROP_OUTPUT_FENCE: + if (!val) + goto exit; + + ret = _sde_crtc_get_output_fence(crtc, + state, &fence_fd); + if (ret) { + SDE_ERROR("fence create failed rc:%d\n", ret); + goto exit; + } + + ret = copy_to_user((uint64_t __user *)val, &fence_fd, + sizeof(uint64_t)); + + if (ret) { + SDE_ERROR("copy to user failed rc:%d\n", ret); + put_unused_fd(fence_fd); + ret = -EFAULT; + goto exit; + } + break; + default: + /* nothing to do */ + break; + } + } else { + ret = sde_cp_crtc_set_property(crtc, + property, val); + } + +exit: + if (ret) + DRM_ERROR("failed to set the property\n"); + return ret; } @@ -1783,30 +1838,27 @@ static int sde_crtc_atomic_get_property(struct drm_crtc *crtc, if (!crtc || !state) { SDE_ERROR("invalid argument(s)\n"); - } else { - sde_crtc = to_sde_crtc(crtc); - cstate = to_sde_crtc_state(state); - - i = msm_property_index(&sde_crtc->property_info, property); - if (i == CRTC_PROP_OUTPUT_FENCE) { - int offset = sde_crtc_get_property(cstate, - CRTC_PROP_OUTPUT_FENCE_OFFSET); - - ret = sde_fence_create(&sde_crtc->output_fence, val, - offset); - if (ret) - SDE_ERROR("fence create failed\n"); - } else { - ret = msm_property_atomic_get(&sde_crtc->property_info, - cstate->property_values, - cstate->property_blobs, property, val); - if (ret) - ret = sde_cp_crtc_get_property(crtc, - property, val); - } - if (ret) - DRM_ERROR("get property failed\n"); + return -EINVAL; } + + sde_crtc = to_sde_crtc(crtc); + cstate = to_sde_crtc_state(state); + + i = msm_property_index(&sde_crtc->property_info, property); + if (i == CRTC_PROP_OUTPUT_FENCE) { + *val = ~0; + ret = 0; + } else { + ret = msm_property_atomic_get(&sde_crtc->property_info, + cstate->property_values, + cstate->property_blobs, property, val); + if (ret) + ret = sde_cp_crtc_get_property(crtc, + property, val); + } + if (ret) + DRM_ERROR("get property failed\n"); + return ret; }