1 // SPDX-License-Identifier: MIT 2 /* 3 * Copyright © 2023 Intel Corporation 4 */ 5 6 #include <linux/debugfs.h> 7 8 #include <drm/drm_atomic_helper.h> 9 #include <drm/drm_print.h> 10 11 #include "intel_clock_gating.h" 12 #include "intel_cx0_phy.h" 13 #include "intel_display_core.h" 14 #include "intel_display_driver.h" 15 #include "intel_display_reset.h" 16 #include "intel_display_types.h" 17 #include "intel_display_utils.h" 18 #include "intel_hotplug.h" 19 #include "intel_pps.h" 20 21 bool intel_display_reset_supported(struct intel_display *display) 22 { 23 return display && HAS_DISPLAY(display); 24 } 25 26 bool intel_display_reset_test(struct intel_display *display) 27 { 28 return display && HAS_DISPLAY(display) && 29 display->params.force_reset_modeset_test; 30 } 31 32 void intel_display_reset_prepare(struct intel_display *display) 33 { 34 struct drm_modeset_acquire_ctx *ctx = &display->restore.reset_ctx; 35 struct drm_atomic_commit *state; 36 int ret; 37 38 /* 39 * Need mode_config.mutex so that we don't 40 * trample ongoing ->detect() and whatnot. 41 */ 42 mutex_lock(&display->drm->mode_config.mutex); 43 drm_modeset_acquire_init(ctx, 0); 44 while (1) { 45 ret = drm_modeset_lock_all_ctx(display->drm, ctx); 46 if (ret != -EDEADLK) 47 break; 48 49 drm_modeset_backoff(ctx); 50 } 51 /* 52 * Disabling the crtcs gracefully seems nicer. Also the 53 * g33 docs say we should at least disable all the planes. 54 */ 55 state = drm_atomic_helper_duplicate_state(display->drm, ctx); 56 if (IS_ERR(state)) { 57 ret = PTR_ERR(state); 58 drm_err(display->drm, "Duplicating state failed with %i\n", 59 ret); 60 return; 61 } 62 63 ret = drm_atomic_helper_disable_all(display->drm, ctx); 64 if (ret) { 65 drm_err(display->drm, "Suspending crtc's failed with %i\n", 66 ret); 67 drm_atomic_commit_put(state); 68 return; 69 } 70 71 display->reset.count++; 72 display->restore.modeset_state = state; 73 state->acquire_ctx = ctx; 74 } 75 76 void intel_display_reset_finish(struct intel_display *display, bool test_only) 77 { 78 struct drm_modeset_acquire_ctx *ctx = &display->restore.reset_ctx; 79 struct drm_atomic_commit *state; 80 int ret; 81 82 state = fetch_and_zero(&display->restore.modeset_state); 83 if (!state) 84 goto unlock; 85 86 /* reset doesn't touch the display */ 87 if (test_only) { 88 /* for testing only restore the display */ 89 ret = drm_atomic_helper_commit_duplicated_state(state, ctx); 90 if (ret) { 91 drm_WARN_ON(display->drm, ret == -EDEADLK); 92 drm_err(display->drm, 93 "Restoring old state failed with %i\n", ret); 94 } 95 } else { 96 /* 97 * The display has been reset as well, 98 * so need a full re-initialization. 99 */ 100 intel_pps_unlock_regs_wa(display); 101 intel_display_driver_init_hw(display); 102 intel_clock_gating_init(display->drm); 103 intel_cx0_pll_power_save_wa(display); 104 intel_hpd_init(display); 105 106 ret = __intel_display_driver_resume(display, state, ctx); 107 if (ret) 108 drm_err(display->drm, 109 "Restoring old state failed with %i\n", ret); 110 111 intel_hpd_poll_disable(display); 112 } 113 114 drm_atomic_commit_put(state); 115 unlock: 116 drm_modeset_drop_locks(ctx); 117 drm_modeset_acquire_fini(ctx); 118 mutex_unlock(&display->drm->mode_config.mutex); 119 } 120 121 void intel_display_reset_debugfs_register(struct intel_display *display) 122 { 123 debugfs_create_u32("intel_display_reset_count", 0400, 124 display->drm->debugfs_root, 125 &display->reset.count); 126 } 127