1 // SPDX-License-Identifier: MIT 2 /* 3 * Copyright © 2023 Intel Corporation 4 */ 5 6 #include <drm/drm_atomic.h> 7 #include <drm/drm_atomic_helper.h> 8 #include <drm/drm_atomic_uapi.h> 9 10 #include "i915_drv.h" 11 #include "intel_atomic.h" 12 #include "intel_crtc.h" 13 #include "intel_display_types.h" 14 #include "intel_load_detect.h" 15 16 /* VESA 640x480x72Hz mode to set on the pipe */ 17 static const struct drm_display_mode load_detect_mode = { 18 DRM_MODE("640x480", DRM_MODE_TYPE_DEFAULT, 31500, 640, 664, 19 704, 832, 0, 480, 489, 491, 520, 0, DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC), 20 }; 21 22 static int intel_modeset_disable_planes(struct drm_atomic_state *state, 23 struct drm_crtc *crtc) 24 { 25 struct drm_plane *plane; 26 struct drm_plane_state *plane_state; 27 int ret, i; 28 29 ret = drm_atomic_add_affected_planes(state, crtc); 30 if (ret) 31 return ret; 32 33 for_each_new_plane_in_state(state, plane, plane_state, i) { 34 if (plane_state->crtc != crtc) 35 continue; 36 37 ret = drm_atomic_set_crtc_for_plane(plane_state, NULL); 38 if (ret) 39 return ret; 40 41 drm_atomic_set_fb_for_plane(plane_state, NULL); 42 } 43 44 return 0; 45 } 46 47 struct drm_atomic_state * 48 intel_load_detect_get_pipe(struct drm_connector *connector, 49 struct drm_modeset_acquire_ctx *ctx) 50 { 51 struct intel_display *display = to_intel_display(connector->dev); 52 struct intel_encoder *encoder = 53 intel_attached_encoder(to_intel_connector(connector)); 54 struct intel_crtc *possible_crtc; 55 struct intel_crtc *crtc = NULL; 56 struct drm_mode_config *config = &display->drm->mode_config; 57 struct drm_atomic_state *state = NULL, *restore_state = NULL; 58 struct drm_connector_state *connector_state; 59 struct intel_crtc_state *crtc_state; 60 int ret; 61 62 drm_dbg_kms(display->drm, "[CONNECTOR:%d:%s], [ENCODER:%d:%s]\n", 63 connector->base.id, connector->name, 64 encoder->base.base.id, encoder->base.name); 65 66 drm_WARN_ON(display->drm, !drm_modeset_is_locked(&config->connection_mutex)); 67 68 /* 69 * Algorithm gets a little messy: 70 * 71 * - if the connector already has an assigned crtc, use it (but make 72 * sure it's on first) 73 * 74 * - try to find the first unused crtc that can drive this connector, 75 * and use that if we find one 76 */ 77 78 /* See if we already have a CRTC for this connector */ 79 if (connector->state->crtc) { 80 crtc = to_intel_crtc(connector->state->crtc); 81 82 ret = drm_modeset_lock(&crtc->base.mutex, ctx); 83 if (ret) 84 goto fail; 85 86 /* Make sure the crtc and connector are running */ 87 goto found; 88 } 89 90 /* Find an unused one (if possible) */ 91 for_each_intel_crtc(display->drm, possible_crtc) { 92 if (!(encoder->base.possible_crtcs & 93 drm_crtc_mask(&possible_crtc->base))) 94 continue; 95 96 ret = drm_modeset_lock(&possible_crtc->base.mutex, ctx); 97 if (ret) 98 goto fail; 99 100 if (possible_crtc->base.state->enable) { 101 drm_modeset_unlock(&possible_crtc->base.mutex); 102 continue; 103 } 104 105 crtc = possible_crtc; 106 break; 107 } 108 109 /* 110 * If we didn't find an unused CRTC, don't use any. 111 */ 112 if (!crtc) { 113 drm_dbg_kms(display->drm, 114 "no pipe available for load-detect\n"); 115 ret = -ENODEV; 116 goto fail; 117 } 118 119 found: 120 state = drm_atomic_state_alloc(display->drm); 121 restore_state = drm_atomic_state_alloc(display->drm); 122 if (!state || !restore_state) { 123 ret = -ENOMEM; 124 goto fail; 125 } 126 127 state->acquire_ctx = ctx; 128 to_intel_atomic_state(state)->internal = true; 129 130 restore_state->acquire_ctx = ctx; 131 to_intel_atomic_state(restore_state)->internal = true; 132 133 connector_state = drm_atomic_get_connector_state(state, connector); 134 if (IS_ERR(connector_state)) { 135 ret = PTR_ERR(connector_state); 136 goto fail; 137 } 138 139 ret = drm_atomic_set_crtc_for_connector(connector_state, &crtc->base); 140 if (ret) 141 goto fail; 142 143 crtc_state = intel_atomic_get_crtc_state(state, crtc); 144 if (IS_ERR(crtc_state)) { 145 ret = PTR_ERR(crtc_state); 146 goto fail; 147 } 148 149 crtc_state->uapi.active = true; 150 151 ret = drm_atomic_set_mode_for_crtc(&crtc_state->uapi, 152 &load_detect_mode); 153 if (ret) 154 goto fail; 155 156 ret = intel_modeset_disable_planes(state, &crtc->base); 157 if (ret) 158 goto fail; 159 160 ret = PTR_ERR_OR_ZERO(drm_atomic_get_connector_state(restore_state, connector)); 161 if (!ret) 162 ret = PTR_ERR_OR_ZERO(drm_atomic_get_crtc_state(restore_state, &crtc->base)); 163 if (!ret) 164 ret = drm_atomic_add_affected_planes(restore_state, &crtc->base); 165 if (ret) { 166 drm_dbg_kms(display->drm, 167 "Failed to create a copy of old state to restore: %i\n", 168 ret); 169 goto fail; 170 } 171 172 ret = drm_atomic_commit(state); 173 if (ret) { 174 drm_dbg_kms(display->drm, 175 "failed to set mode on load-detect pipe\n"); 176 goto fail; 177 } 178 179 drm_atomic_state_put(state); 180 181 /* let the connector get through one full cycle before testing */ 182 intel_crtc_wait_for_next_vblank(crtc); 183 184 return restore_state; 185 186 fail: 187 if (state) { 188 drm_atomic_state_put(state); 189 state = NULL; 190 } 191 if (restore_state) { 192 drm_atomic_state_put(restore_state); 193 restore_state = NULL; 194 } 195 196 if (ret == -EDEADLK) 197 return ERR_PTR(ret); 198 199 return NULL; 200 } 201 202 void intel_load_detect_release_pipe(struct drm_connector *connector, 203 struct drm_atomic_state *state, 204 struct drm_modeset_acquire_ctx *ctx) 205 { 206 struct intel_display *display = to_intel_display(connector->dev); 207 struct intel_encoder *intel_encoder = 208 intel_attached_encoder(to_intel_connector(connector)); 209 struct drm_encoder *encoder = &intel_encoder->base; 210 int ret; 211 212 drm_dbg_kms(display->drm, "[CONNECTOR:%d:%s], [ENCODER:%d:%s]\n", 213 connector->base.id, connector->name, 214 encoder->base.id, encoder->name); 215 216 if (IS_ERR_OR_NULL(state)) 217 return; 218 219 ret = drm_atomic_helper_commit_duplicated_state(state, ctx); 220 if (ret) 221 drm_dbg_kms(display->drm, 222 "Couldn't release load detect pipe: %i\n", ret); 223 drm_atomic_state_put(state); 224 } 225