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